From 8c9a37a40a164dba330390af2eabf5ad05625001 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 5 Mar 2013 18:02:30 -0800 Subject: [PATCH 001/544] do not break on call/invoke to undef; fixes #914 --- src/intertyper.js | 2 +- tests/cases/invokeundef.ll | 41 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/cases/invokeundef.ll diff --git a/src/intertyper.js b/src/intertyper.js index 6c88e765caedb..2103ecfab35e2 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -677,7 +677,7 @@ function intertyper(data, sidePass, baseLineNums) { item.type = item.tokens[1].text; Types.needAnalysis[item.type] = 0; while (['@', '%'].indexOf(item.tokens[2].text[0]) == -1 && !(item.tokens[2].text in PARSABLE_LLVM_FUNCTIONS) && - item.tokens[2].text != 'null' && item.tokens[2].text != 'asm') { + item.tokens[2].text != 'null' && item.tokens[2].text != 'asm' && item.tokens[2].text != 'undef') { assert(item.tokens[2].text != 'asm', 'Inline assembly cannot be compiled to JavaScript!'); item.tokens.splice(2, 1); } diff --git a/tests/cases/invokeundef.ll b/tests/cases/invokeundef.ll new file mode 100644 index 0000000000000..9dc1f93dcc30a --- /dev/null +++ b/tests/cases/invokeundef.ll @@ -0,0 +1,41 @@ +; ModuleID = '/dev/shm/tmp/src.cpp.o' +; Just test for compilation here +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-f128:128:128-n8:16:32" +target triple = "i386-pc-linux-gnu" + +%struct.CPU_Regs = type { [8 x %union.GenReg32] } +%union.GenReg32 = type { [1 x i32] } + +@cpu_regs = unnamed_addr global %struct.CPU_Regs zeroinitializer, align 32 ; [#uses=2] +@.str = private unnamed_addr constant [14 x i8] c"hello, world!\00", align 1 ; [#uses=1] + +; [#uses=0] +define i32 @main() { +entry: + %retval = alloca i32 ; [#uses=2] + %0 = alloca i32 ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + %1 = load i32* bitcast (i32* getelementptr inbounds (%struct.CPU_Regs* @cpu_regs, i32 0, i32 0, i32 1, i32 0, i32 0) to i32*), align 2 ; [#uses=1] + store i16 %1, i16* bitcast (%struct.CPU_Regs* @cpu_regs to i16*), align 2 + %2 = call i32 @puts(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0)) ; [#uses=0] + store i32 0, i32* %0, align 4 + %3 = load i32* %0, align 4 ; [#uses=1] + store i32 %3, i32* %retval, align 4 + br label %return + + invoke void undef(%struct.CPU_Regs* noalias @cpu_regs, i32 %99) + to label %invcont33 unwind label %lpad106 + +invcont33: + ret i32 %retval1 + +lpad106: + ret i32 %retval1 + +return: ; preds = %entry + %retval1 = load i32* %retval ; [#uses=1] + ret i32 %retval1 +} + +; [#uses=1] +declare i32 @puts(i8*) From 255d0f838de04a1716c1d53632ce911412262471 Mon Sep 17 00:00:00 2001 From: "Felix H. Dahlke" Date: Sat, 30 Mar 2013 22:24:11 +0100 Subject: [PATCH 002/544] Add myself to AUTHORS --- AUTHORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 0fa41dd21554e..e5d1ac349fafe 100644 --- a/AUTHORS +++ b/AUTHORS @@ -55,4 +55,4 @@ a license to everyone to use it as detailed in LICENSE.) * Tobias Doerffel * Martin von Gagern * Ting-Yuan Huang - +* Felix H. Dahlke From 703422829c0b8de54016ed32e4905a4d51b9f7dc Mon Sep 17 00:00:00 2001 From: "Felix H. Dahlke" Date: Sat, 30 Mar 2013 22:24:15 +0100 Subject: [PATCH 003/544] Support rotozoomSurface --- src/library_sdl.js | 13 +++++++++++++ tests/sdl_rotozoom.c | 2 +- tests/sdl_rotozoom.png | Bin 338527 -> 351517 bytes 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/library_sdl.js b/src/library_sdl.js index 42207f2396bb3..71ab22778386b 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1032,6 +1032,19 @@ var LibrarySDL = { return ret; }, + rotozoomSurface: function(src, angle, zoom, smooth) { + var srcData = SDL.surfaces[src]; + var w = srcData.width * zoom; + var h = srcData.height * zoom; + var diagonal = Math.ceil(Math.sqrt(Math.pow(w, 2) + Math.pow(h, 2))); + var ret = SDL.makeSurface(diagonal, diagonal, srcData.flags, false, 'rotozoomSurface'); + var dstData = SDL.surfaces[ret]; + dstData.ctx.translate(diagonal / 2, diagonal / 2); + dstData.ctx.rotate(angle * Math.PI / 180); + dstData.ctx.drawImage(srcData.canvas, -w / 2, -h / 2, w, h); + return ret; + }, + SDL_SetAlpha: function(surf, flag, alpha) { SDL.surfaces[surf].alpha = alpha; }, diff --git a/tests/sdl_rotozoom.c b/tests/sdl_rotozoom.c index cb6295cc167ef..4bca294af006b 100644 --- a/tests/sdl_rotozoom.c +++ b/tests/sdl_rotozoom.c @@ -29,7 +29,7 @@ int main(int argc, char **argv) { sprite[1] = SDL_CreateRGBSurface(SDL_SWSURFACE, 100, 100, 32, 0xFF000000, 0xFF0000, 0xFF00, 0xFF); SDL_FillRect(sprite[1], 0, 0xA0A0A0A0); sprite[2] = zoomSurface(sprite[0], 0.5, 0.5, SMOOTHING_ON); - sprite[3] = zoomSurface(sprite[1], 0.5, 0.5, SMOOTHING_ON); + sprite[3] = rotozoomSurface(sprite[1], 45, 0.5, SMOOTHING_ON); mainloop(); diff --git a/tests/sdl_rotozoom.png b/tests/sdl_rotozoom.png index 83ec05893178158ca5bf88eaf45c9151db37b322..d78a5ea47de6cb3a37b60a88b16479fc1d3a283d 100644 GIT binary patch literal 351517 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 &n> zLv{BLKTgDakx3A*xN3t!2Bqn=cqSJPh|vYua2Dq`K4P^VMa~Qsr$sa5`*GPxn)??H zqF%qW>@vkf8i4IUABn*lTI?dF^Ud0d@}yttVP8Tbh!rjK&j_wfZH?T(1Zr;RU?qn1 zXM@Ll1g%Tf^bHMt2UtVCwr1PyugUZ}4`M<$uZqHkq78Y7OPT3GH z*AIb4t;Odt3m?tX_L3E^^WmQ!J_6ng?A~&niRY0p{?2*R=D}_DCy&odkI=d@V&mndcd5oT*1FPMJ}CHi-Rt!wQJ?vt@PGRv|F$E$9km{#n_hc= zPKn6%HCoA+B%UUNzUB? zvm+JgL7WQs0z(-oB%hP=yZA6qk%^3v6~tF5C!MBP7Zs%oLmqM}DBl=B3KepqC(Rl` z0~uR@Xist!QPR^}97_$t@FOL_!xh#(X{S)=MLj&dSF6GhU%Xe`&> zFXXpK@EpUAdQVDyTXMs>duZHgVFHRjhXpBf}KJ0hd7K0ft$E zsR|Rz4+&9oPGd2RG3h9V87n5X8AJQ_{yWp~SmQs&j1z`cJ$I&&soJSE#z8frLCinl z&`dmNGPCx^GU`FsMNp|(aoWk-bQxA!X`V%8 z`Utj)8&L}sL1|PeCozo(V+<;;2y4dfpFjYA@KY3NLAkB3lcd9H6r>Um{(1lb>_F`M zp*4f2duKt|+xsOb*dG=a78y1W8X_1P#vdZ^i##PjML;?~HfCOJZ8Toio|xdho85MF zSi!?PyS88Y4g>T2ss^`Z3vs!>Kki~rTX*-ia(2iD`Cku%(nxQ;HSn0oPeh)^x9dg1 z=+`vgFwfAau8MSm|8!jk7*NJS)EBRkvj zhV4hDi;Iif=j-O=ApeJ*_YS$YpU(Td&VJSBOV#`JeAnA(*Hy63Q}EkR^jnC{VlYL^l5<&|dy0{Edw{95`AANfrJfZ!3^)N_~p+DUw zmCw|iSk>I%Y2Fx>L3hg`i;Xnl$i2egz`aM+xqnPb+LA-PeFb2c8lo^ALQGgW84DCe zC^yidmNb5(a0-%YhIugk`J#Mu@r;o6&H>G61c2B^8=Ft7fBdzSh+veEg*4*i!GKbK zs>;wsd6r9-YA_Y`ZWJj|9FY{q(R_7%u7w1aI0z~h0!l#Wj|wz=myqs}k&ti|QNXvD zKt082q(ddffD%y1G4gV=AgMuY_^=`q*M5Q|X@PvTNU21mq{o*o@t%qe%`d5phFP8}#1I-dq$YUs>{Z^W8 zl97rfD5c`s78VwqMTHd}WEkVqC_jL)hbL7wT*M_BHBDo-nO_S(II=iz3D5hi9BPwd zg6-{6eZhCq5@W}W1kJ-LPHGvcngYcu^{DkcYC!r^ZXVVoVIOatacu z8mN%L>yYLUZo<*z8Z?@mq^j0AHgaQBS*f`_aBr~&XiydD7Cg;9$-xNPyVJd|JnpX9 zkzxo-%Nx2bCbJDf{Q3^NUx4+zwM+b3fR#+Q=^P&9dtmf_8}!Kl62WiZ4s1TiHlGIA zpB|dJ#@jACM|D2-b#4s!9}EDd?^PVO%RUfb8g$~X2b6)4=|4f8m9-y`<`fhZA|fLh zxwuZihMq9)-7|%11b_?3snU4M4pys8M|g{PFKVE!`G;oKrq8>!hR$@b%}Pxz(ESzt7K$ZEg_&tCT9Bb6arA}8EToz2x45aHWoQCYZW1HK zfZ1QP9m-k+oW zQ;4}+Ofg%~e!_IF5ZX=|YF|tO_El9f^Q81FS%tVt<;F#a`%xq*6XhlIGJY46pqNu8 zCLobmN$oM)0l&2d$w2i2Alq0se=&EtJZ79EbOo)kLV@n^*lD#s%_;33Cel6B9=IQ2 zHdBI%VV0x?Haug2f_b@+f?>rlLo-cLATCB)s+R6P0T{gjotk-?l3{*$mQG`ChUvD0 z=a{agwCX_HM(Fh~yMUoK?>6(~0r#u4i9|w!5Q# z5UhH^8v6T#H%09o2ifeduQ+lwuxUD9YlCrO$yizAaMPXIvXNQWoPQ08XY=WaR4U5q z(-2&>SsXX2{Rj?Wue?@SCX1`rfFmOx$XJ`bBLP4&HaTv4vWKHWr(<}(0<)-6^&((@ zegbgcI=dehVqmq`M_4I{LO{(kn{m ztzT!4TIU(Y2SCag|NAWe^?z09ZI}OpSm*sj#qG4BsoDFT3kYnZp`+tE8-$Dn=!}}? z<|80g`|mCwGJE0f?G49!TNf;z%9YJipoQnl!%H<;t$ynA!Q%`H?r^Lgb(wMT*`GjV zpeItf2ZnAm>@gyU$a$_-6MR2vm8C%wUUZV4B}tTwl_q;Xodk!m0qt{E)AW)cqcN}y zmh7j3f79XpQ(2rJXXhwGh*u{;y4$W;Pl_xVQ;ggrFWgtoFyAgnTQ*$^8YVZCwu=d% zd*W4V@N)88v@};h78Zup%Oa<28>p~TY1B!X-%RphK#;+oE{qrjY5n@ zQ*`8JXuET@Wb+ZSta%EP7=~7V0tkN(^&L5DD24%NE1BlaV?{ea9m=`tbib>VDN$?3j+k1>2&MD_reYLui8;Ug9*0Dfh$09>5);0f4Da6k zMDTUxyYn^~vP0yA=SVv^LRZgDxhNXZVq7aDm(zp;DLEO62q!2#azqg4a`R62Q%Ds@03{d`%N12EB1VS1*?xb<1FTOf z_453@rmkar7pN@ojT}6-YruE{kZx8r4bMZ6F>vr%u4QKUEgn2{SWsmVBoE6|CYiCBM?^WMW?&fT zdnOErG9DZnt8#e7Nukr*?!K@tELJ)=?Zb?!(Afcyv0ztjad~8W)M*>d3w~T)a~%Rk zH0MV4<>d`S7nAV8*EXJwO(PqZbpJt*_UjjgjgKL*r_}6cOz-DppVTVv`?9x<%Xd7V zYjmIP&CmDETNj^47a(WzlP~*ij~qCpiUugdG_<8M{7M_-FyVDL>8q!E#BE>-WQ`D-|f2JMX1erleXWzFTHpP zu7v`UjGoT`sKv?_)mW|iASkfE)g)S}_njA4?E+WaDvP~~r=;?+(`478UMiWDV%Vkw*{%Q$Q1F64-iiqAB@= zF|{E5);a|cI(Q1;<%8Cv0NO7~uDSde@b9r;fT$VPELG|!+=;tbMGXyy1P$Mu+g6tS zy%*FIB}x?ZZG9yw=2Ls(Q7|`6d`5m~P)WT2B2zNXm{5|}VrD3{K3tB88%F?qzbASO$qWdE6qn{d-hBNt@W^=uqc5d zAfUf}(>!(jE))MI>7`}|@#qc4Nq2(V70%_&=o-Co`aYh$p%sUK;)SmG3ERxSn)4WX zSew2Xvqlq4p8MEV)lOUj6X)J11fk}L_lkCN7Y)(A1Bwm=EJ)u?zrw<2>AJecbm#np z0C*Yul$&|Q;sP5;6Lrok9ZA|_ng5> zpWg&0OR=H{-n@=BLPl44mMrHmu+JG;IVbk|FlH5gW^i#10u7m_CfDTsd|5dV@bvy(&+g}E{cX=NkGs05HgQK6fpgObh-=}|F7tni! z()&D*dcL3P9R3H2=Xn0-pC32$pK<)ahuaR>uQ;o#tL5e8whw1&vRORGDy2Y;c^Na% z)B6JeqprGo>rkm(E;%{t(brI4-_N)XNC4^AuQ|jJ?+RJxmv^5&hKls==*3pUZFZ&?TX5sF8*wd@0ZlY7?^G-=YXe{2>DB0s?&WLSr3F+7h1=J^k>qQ z3ruyDg!~^(UmetT+cixot_6Ziafjk=1%kUaSc?<1xI@w665NXghvE*UxO;(8DDE!B z;rrdsH}4FRf0D@%&ULP{yJuIvaEpi34Q%Q4IU&t#13_5%rw3^SC?Lf}t}s{7hA=onh@Sv%+G9gvj;4VZVkx;MFPSSanLZW|!!(X;l%~%qcY( z>XKb!99u+Fc1X*t0T{V-+blT=OE)PiKB?3B zV>pr38vZ-Rowb3?k|zV{yaha_6FJDS!JT9?M~%m;$jC0gJ4IilFtt>>@vC#MJc1RI zSqVu|LgJ^-X?j^8{GkAHa(*hVA>{Z@EI@Ea{1ok2zL0q`imiR4rLt@YnEpj+JBnE1 zs%hR9k1;^R%_vUJ2S3atKCjo}s=q$Zy+mN7z-gtae$%tY)f@EQMEqQQB6Vzyx(-D9 z#;boxpDrxH5)T~pjRm8v9HwslA93mHIP!SDDegHri1$UPebg9XY4u+k*ug9fciE%mSU8a9+X7u#6OS;@8f^_*Ik8&w8X*-%r4b*(9 zNnz88D&Cdq$DAT`1q_gRu9advDth{End^DARn%3v#QA&v9Pu&jTDP{itu9F3XAIii zoP55S;Gp``J-9O<-F)?>tNAuR-amOV;Ggwv z*vDJsfTxAPoEpDvHoxnNkK2bIUqn7W{9XXO`0fZLuJUmKVeP=k2u5^tbeHJS)&6X@ znDiswK0t*-7O+x+N18VCR=0J#Lbqy*Z$449eZ1$hk;eD5^Rga_W|N#bx0 z)|5OKtFJb$1%=&Qt}Z+wY}MichtoVuCfpQ~nip{+XPOD88Ls1nYw-uhN0)fs6%Jcq zfMMv^s9bzGfM~Cpp7YxU!soq|U0D}E)POECk^ArL+wz!b1UrgG(Kp^- z7&za+h<$E}en!RG!&4Q-dpfW=7ozz}FhiB*_+C*Aby=xGXJ&q~x+aSy^Uh{6CW}EM z{;@%rN&WT_-`+nGsQVs&7T>5hSwFoZugXkBLM-c?ivZmlXMRry$~UIt|q*Xr2JkinIbVy0qJtu$=O zBdC8Lrv%;>6WhQ-#6xd16)|YP!97aa2the-iG|vdv<0(=p(CRv(!TG$=pQ|n?c*vS zajpdNsOYob7H+S;eT=q`dUtRl9I&vhdGwsP=!&qhPw6@6ga669> zBi2spoL|XmYFdWr@C^4y?=JoQyR-J~t&{*Ig7BhG9PmnYop%wvy_5hRKymh2w5kL2 zukh4r^7t*}THNRN;KaYCkAJ+LABF8lfw81q+j^Y`Tb=&qUz#tC^t+q&SJBPzCcWw@ z+h4%dY;)_8{nC}U>v=u)do@xkdF}sc0gSqaQbvg(0040R+ufwy^DFAj>G|5TxW3Te zt@CG2b)2`CTW8$rc@$?y`!xUky02&Q`)lZQ_D^17OdZh80p45p;I4m-HRqz;m!kih z{Ja0zbq`EF{h2&pnhZ!)54cF`c)maUPvbK`ubY~h`Y83S#MMjj4v;w9aaIBps-*RC zCjg`GPULI?WNlYfvq2SX*y1}d)^G*lX^@1UQ?#T9tPa0QAcpwF*T-(2o_2n{S;VEv zJy~z9jSKk-%?!xwl>AsQRM(9)R)6WU$>LODK@XBkB4lFEP|@TBDasOH;iA0h#hDFY zDZ?^H53wj@U22J9?~wkDktFciqVRn=X{?qOLp4@XJ=jGvr~!}K31!$25y~MYO0n7%wxmcOS89QjG%y^3&Xu@IZ9ZqNRZ*3Vbg3(d^mqD|d2 zr2z1hEPzlLUn;5hIYKE4>wzqyumtM?hy81r5III+=33nMY}`vVhWFx5niC{^n3}eb zoMcj3O2RUIfPX|+x}y)XkMR?b>&z~JR83Vi|6veP^~u4Zi)GBQP1IunbJ%IB+0r+@ zff&-hO&SI>*a}A{W}5FG>(<2xVkB>pDe}u2Q85;Wm-V?FK$EnzOxv_AigGP0Ar>AD z13Jw=6ga>f#nUR8a|IZkZpr5^u=*s9iLrQI{?+1XWw#tBCCTG}HEQDq0Z!t0{sD-Y0U?j4MbU3dy>2>-cLxl>o1tjz-JdoC=zMgfe<>f3#hDUgX zvrx*hsHj@+Nh&$*pVi-MXP?q?j^*FI85Q*Fc?`p0OLO<4E3XG?NIT3|Pg>ECOG;tvH{?9)*G^o-24qo2@;9OJde4N^`M zp~2!}Oe5p2vBnfOqjr~!iqW*zR*xLinib1>C;P_k?$KE$)Q-CW-c`R%(!V!A{1EUM zP^X99bf0oa-2cNp1C*zVz$o+V`MezX5O_Na({MvtfthnzlRP36N(a|#Yckk*uI>rFmP7AOR0^rr#fI#R!QTx&o zgprYP&rM|R&|Rq*9}vlP_nxAL6Yqa{DtS5W3jFBZ9k+O@arI>lj8&4?@3pp3i;Ej0 z#%Q)I0HeplLU}rzGZ$G!IiFL+oP$9uh6Y`hAK4hh zwT-4VReLg$XbLFq=&^)V>-~R6YVT5g{$rB(P4Yx5j7CLRL7-e?+@L`TJu{3sRyx^b z;9G7pGovi<1~_SEON*F^@pYnDqV9x>{a|vfQYCtY`cAV@VByZ-%D};3p0(2_Lry|X z++l`uU^pF-+dINVi_RQ_KG{^sImbg-zDBP|e{_0`X*eBU(>bAm3~s{)vX4|UFfU5= zXrj<_X;4zMk{=nnQfhD^s!D#(R<1dZoT(Tac8)?!1nhhXDmE|BepDe)Uj*QYnKGnd zi|k}fYUc$P;(B)-$mid2bQ4PJ5pO;pUiCWeO_e>K@g)STKZ1cig7#F?iN=2aj`cJz zFn(g@EtcD|+mmK0oR%f7X?l`NwjTo8j{R<-3f9Y^E93majPvEn)5Lq8{^?LsoCqHS z?Ds@RLPiUsl791g$OVD>3ZtAa=8aGgJFpQ494A_}nsod*sCQOa>}=8fp^5Wjn*u8-6A1~ekl4`p{9zwfk`kx- z(zv@9rMij6cSyx->7324g9c;9RXfkU#+)1~UUTzoQU9oIOyUo%UO^RUoG$)%7=n7K zt?vFQ?RJ7K{+l9#z!u`^j)*AkTbJ+k<2}!ur~nEe?)GEz>C`v+H1Or-ZdcO(EO0|! z@>;R$s{h?tV8GqW+RJn2OZ3b0- zZcbf~4|DuUeoBRQS0Ux1_gWrS^v-NLmfiG?a!|a@%Y>xWJ|Ka0v+16L=AmVWzgE8Gh`+968i*9Q=i^ zrIv0kJ`o=*5@PTM;;`N%edX?duN5A_f^8nv+c(Fh$*-V;4x6GY&42Gk^MxfWqMSCB z{*wYt(GP^gALtVXoO@GDJUv%;tND~rH zG5`Q$!1+VRg*yn~cukZvIEtZj7ksRcgKhR}7eFSbRPn1|_F&4PX`e4MhA+$Q0LouQ1X4RVse{FyE{t!M=;fX1DJ7MBK%Tdj4C0=Su)D6lyQljEdXVrgMNjru zbSwhl$Rt-SlJS_ILrSTYZX(Mw5^P^*MTY*Jh*T{!+by+;KR6yYcEWnA?3dWEUrXG` zyU%|~p12u2ebqKiFZHFgx$CcB?CvZdM+Tgr@5kw4OO)!NUai|X=-4Axi$+=EQ1j~Y z_Ku=hI?m`9L*C_Q-k|frDP0Thgp16!7_pci`VBN+_U?TNBCK#`?Xh)K<#qXWRAn@E z=Jtp;|20S9uR`|s+QO^tWL!+%1}8yWW+Sy@f0 zfz+Zmp(J%68NGq2WTB`xkAXUU7F-TCBMGlHxphc&v9B)5*$ZqjnF$#V#wiS&?8#t@ zyDgr3muLuEf4By=9w`XtkJs>mz@UQL+y%O93F(yoWT?T(YnQt_ARS|ig}CF}02~Mr z9?V&5SZG%*XFz#b2NSI1oo7GL-!zkW!Ft4tduUCp&S9|xE3PzZ%I0U&N1m@g{8exL z;DK|pGWfjGzS!)FI@|717kI;|MkPMBl*AYLH{bw$HQ=!Kapqk>$jdEi_hj?Sp5*z*uFJv4?T?ROB&z@R zt#0Q^B>MkrhJfO4cQS8xu1uRk#4Q5Yu&T42X9Y51Nn_&cZKi2|RYH239F_|nE4UP# z|91Hwt#)Qr88*vp-5tzVWMpO*{5_quZKOqaYT<0-<-TF6atnk(xe()MJh_R5#3sqf zygLK&q;~GX(r++SL+<>jmYe7r^Wo5Gb46IeydGy3gF~iGl=LrbX~JG=Fim1n!cAH7 zs-b0OW?X{8hOf8nHd(PzqE_`#M>xmy81wCKW?}cxI;Kqs;;})hqp(c(21=2WK|v8y z8HC4O9u6ZsJEreqNYES{B1Jdy4-F^$&yfSA!ghMGh-gco10^9Bf%6|nx{{NNfDcC);W2p=>C{t zP~is~#F?`x`WeDuK&iiuE6{d^rtt776EUdcU?o+nR3zuGFwfd2?+Ykn88F<(VmzrO zy)T)R4GbRcp-&2t(0<}Pwu;o_kY8#py@iSy(wY}B3-P%BEilFjCV$Y4H(4tFI6T8C zbfv`EStm0qxUX-V$q?-Wbn%@jC$9#-q)aB>>4`cU4KvM}pWk5Sb$c_;79zO=2azbE zziK|sW~Nj^YLmmBB#vz(mAa(*-)a2wSL&y@GeTKVHMhp9G$l$+z$ofyW2IGemSu@6 zLLbTuEn)#Q-v!}M>x^}kblC9)2k#k{{sXw|qxIFvBV#qg>IL#>O6> z(!eGJrzN_vAi&nk6?yqUs&dmHKJE9-AU9<>K|(BTnT7cuuPU=-oPvX(D88oid>U>9 zinEFQnBc}KLQF-iH(#{}aA%|b+Iy^&6K<>z&c!<5lT$0YJ}AqRvI zq;mav?Xjmqf;y1#F(WT0V}AO>cep8^fXyVjyvc$gT3EWY0>c|E^i`kD-cv#WO3{hT zlnUniun78h#LBNAtBx~JLAv3SC_-gOyA`3`LZ#_$Y8Ay|eLMkbyvx;EeyRN9UVbld zxy-Eh%(L1VTQQOdOnrDad3NTn-|}zmNzDEFRc^~YLj0dV+yyG1FKKzcnZzHx;{N;A z|L7fA6L`FP+ur>|CFs;KDjDz+c;*>+Y5e?r`W*i9@N%yWNS6Xa0OX#n82~;ON$&hz0eXb{3G%0&&)I7Xu$sbT3qT`B8K!i|0vuk9)rq7)<)>0Ax(ij}9}H`K{8+fsgt4K%;3|dIGa@F%OlJiM>AHk#maX{6r25?u0p$37Q;5Ut!io_ zQ-?AZmYn=NTS8Qq55+^xfqVPVWenQ{`30_En%_|OIbcXdt|PG z6o=DHS<96zRZf(A^TA9-`<#D>fytn!ELj*Iu=ZiwUjiBBwMp4;wgn8n1|Iz310^5$ zS|f%7^3K(wP1==eAaLDrt#{T#?W{{~QwNLea26|2RGe&yJ@3*PY0X2-!o{2`BfwU0 zRB+D^&DQMhHT%O+2z}f_HkP-mk8w?woP6kz&*GYZJ%xcp3X?>QaLltZ|gM z*0EnJRaJG$PN$4eSqBqY>5c+fQvMgFMF-SykYtr3TAFqUYnEP?o5&&&N?XU8Z!<#i znM*^L09>z;Of9cOMdj`|`uB~{9G8>Qw1%!F8ujT)5VS2a-;l(XOuLqwkX%NwumXxT zJ}^g##UGnrREve`OLFI!fs>jt(BOt;-omOy$i5<_t)n8orH^HyD#IWCG0p0m4P%sT zK^ak9r7T-{V3|MH2WaGw76P?2Yj`z%LKw2m0ZDLztoAm76d$sT{`8!bwo|F%kqW-5 zUSbk{D!^U zII=D7>KG~^oiOafg*xw9lqScez94a5VG;jyg0Jz;UN5iyd)`%UCxsZ-co^nxx^Q3| z8}Wqe-(pg#t{19YuiN*z{#!J;tv)IGxqjJ9Z(B!_;*GZFiF3D8(mrlnFPN-f<~^|g zy-RX(J=}4(vUUPS-}bTRy{|?u(=S`^UY7GN54)c${MIq^c4Gxs*M2wJO&=TpR5OK$ zM`-8lto?FVl4@3S9rW^-f_o!$7QT!?e-$2DUcnVB7{iw_8W@Uj@zPwt6aEDcQE`Yn zlu>0_NnUHOHSR^UH7S7@ohijlgc5IK{c>Gr)0?XLP|hUb%u`JhB&!*NFyOwj{y<8x zT%dDxZiFhMj~7P2t@Ucsy>x+gIG>@p(Z~+Yn#$+)8`~bo?#(=`QlF~9SUqt zTI0;1F%YuMxAfHWIV7kv2xy#G;`Cs{Z#L0eS6gSb(yMRI8tAK2eIXfg#*#8oiW zp2Xn{MW97SdIUN0t9P3eX?};M%x=Zfcfv+>N`C%47f~+xt_QEXCxpJTlv1ygs0~|MHy0Wj~9(X3Cy_j!SSc9UeyGZRanTgTHILJ zGTLuKWv4m|6cwZ?z-syXT3g8I0eEhJ%23zM0s_{WD^)fkLmV@j(wJX!KMhj+KH(Fe zAULgysa!w22c;NiEL<*fM^&z`b^F?oLR#L9rNUcU!H-Qot6)ynn~O`Q5dldB|5h<4 z6@g!yRQi@u@w#zPH}uxX&n8-0#=RCNt*YDkm-iJRNvSwN_7#NaO{h>?rYzA;VFfw} z5~HU-pwY#qj2OiX`-R+*9Z{`-b`ILVA^}UrnPc`5aKmcpbM1J=JH-39XUwEya1;OYExGf-CebeTee7@bY z#mlzZH9Grzz^C!*wARa(CYo5a)}_C0`HT7BzpA5^`e?cb+|Q3wcxqI_Befx4g~Y_i zYeP_l{2xj5ttMPg`!B`3wrO$ydWMxyb&X)Eiw#t$OAe#v28QE`yTQDCvM+Ml$WQP7ud(A6sL;}^*~tK$AFBl zR6Y?vuav!Rl8<|9{?Ze2v|1leDe75ozMISJAjpRmo*xff=_92Wwxsl`4Eg~Gh!hJ2 z?+ZXXh)uSSOL;Nj;^o@Rq`#)fXL05H96C*t-}^F=^2-QcT!$q*NzDdd2ZX%bR5+hP zuh{IIyna}}WZw|1txG8CpvgiUB6}PYo1pY5Lj*X)YZFQgSk_x{fc~kLHD^bd8B1o_ ztx&Q0O|Saf2*xG697Fu0g+|jJ5r=KAQn!s3m)X`e_kHhfJ2r{JU7EX#r0s7Pa_ ziZES*uK8R&8JJD6M`e1b+zkUN62>>4{eES(RD{*aMFPTsgdQok`fX!mtBQU*Ms`&} zqk)07T4{cs*#KY8MIu!!oFN|U=w%qWe$Zn(Qor>jT_0xilOz?^H;v5BASb7sP>&d5 z&fzpwhQxgxBA2VyUu-yu6jd3lD3ODq5||^htrcg>tqhp$b*y}vg3g>aW>DmPGUJ-~ zIqW>J%yEA#vU!a0WR>V4{=u>lNbK6iN&(pW1h_HUBV&-?qIsQhvG#fCj@t!XVV?WL zA3Kd}%C>97XdidRLxxOYU@JSLc$0(Cz*3|bYo(yy3u3L=Z&99Uy0XE^MtuFD-4D+$ zRkha4H1B;oxJrlq)av^zBfP8-ieJuRZo}HfN>{Y;UOt+YHqsfy5C-qwmDAT{$dm%< zM$><%u^EaAue8w|loN^!eY>!u!jxE`gbPQIQQrJupdoAz{QwVlWU)z&ax5ch3bs`Q zex&LFh5>rNf2fpjS7O2Uu^75~KeF~p@$&JBBPfi{)$*k@lz+0rNM$W#<0*&JD7whT zjc)jYHS@i>kkUSdrO>9t&|o-Qa0kILhRPDZjmqhNO_EO#$;d|lT)D{2VEqKg`yNlyGN1X4XlUE@nzND!uTERXkxqt2sT#18Gy992`dw!YBG=u zR+^9Q#M&>nWvsM&d=K<_H;7BMH8)+DE$kfJ9{+atWOK0f^9}SQLwNGF%$nEZ!IRk2 zkW9zp)~4TC>#o;j3bFS?W19D2O4{w2-Mh;~T>me)o&R{8`~Vlk+pxSH(ZCA_$JG|R zF9TJObY#cXU_-&XRnM2qk1vfM*GnYMopb#z%1Vj10AqkZ{x>TW;?CJmsJL}@HzrM| zi~av7+i4*ufSJ!y1C#)8=dqfFtJ?o*Nd)Fnxyc$xeRvoq@yx!PjX)NF&9bH_&GC?| z_J1Y5ZFO0BgK$K{9Lj_gC)%?qfWSSLSK5T}p4vz;EYGPLN#aq2Pc_;^usL?>vI7m_ zb$_a=#I9+HDnpwq#!a_~Kl-C65{z1RuE5&MQS)70T5n;Qq=CqlNa;6RLBa z-kwkq$JdySjtD6GFc39HtIXA1VL}gbrP*q`Bd_)NsO|m^oTH^{^<49onqIA46OMX9P zYHRx819W=^HMwYQmyj0Fq{8~aFd9W&YD6IeS159eTvR2?+JT~x_y^PNN)S+4?e??m zhBDO7``Ang9{upO2)<|mAm`Ws@TJwWnkt{Qo41*Zx&r#AulN9}{{X5nW4i;&3QE!n zN{C+A#2YD;D%$Y^RgRij&Sk7}D$I5U#$^T{{=8w2FcS{>=FDQ7(PW35VUHBYPKEmH z;%)0v5ft}@0>hCy$6=&Vre&-HZ-cJ)y#yrh_SwtZD@_*7<~Jn%t5BD7p;7ofmIyZ4 zHf_K!OwjxCn0z+CO@UmEx-MHSl!!D^ z@`l-MCFX~DHB&EF<eBb5+DK-bC*ss}F>3gYBmWMW};VD$l z#(J4?Gh}vnv{F$tUcKA`*()gRDy&&j9;<*bthz0D&7j8btObAQ2%9f>7 z6U&u;16zy>P10QY9tcn#re};KH+!dq)3L>a(v!E`Z$rQTCLeWj~+YbMU_D1$I;Yr^1}ViwIHY(rRYdT z(kq*>Y~k@@SL>FS87$lt-;BYxK3}Y<{3FtGTLuo*#e2x#Nlc2?bPtrQ`h~pnKcMV- zTvESS@{|}+54_m)yU2+@OL_N#)%_s)5*PSf5{LzlBNtpJ`s_+n{TI>dZn^u8v-@Ag zOL%<86XODvH=mM(gzF9#lX~vfP$Jz?R<6}}Lj{*G~&+CR~DFvVccjlbArG$Y)IQ@+YzKrIVT!K+%PQHwV3^2`X;y_AzZ4FkBo zM&Rx@ifXDy6qAqno;}h|P*GX$!X?P{a6Zg9)tWBRdN_TUxbHXC!?KN85Q}P(T~*N> z8)}GxD&;Cvebf3!j}fQBVYhCJ$RJ;A!>|ux2fAg_HAPj2;xLSPnFm0E_zS0oY#T0K zb!)j=in)iHi74v5rE{XU+2R{%QjjC<<<%0h4X(4+_=g3EPb4@Jd6E5;X|2&Lu0e75 zgSwkrF>8ltUl`wW(`k<}>s*js7vQC%MGNFa$&`?(P9oo<=`S|3Q{jug%0fmt=D`#tRDz~dW`9f8gK#gIU&GKDMJ-WcDMHF+m}YKRqn6XvY17L@V@U+)bs$<(-|iH1u5E#-&=ahI?07Z zJ2PT2$?eli>#a9k1gasyw3rdFP-^6@mUN}n)DH6UI>a}M)C|GD5x`2+80Vk1OVDh> zV=NDBqOPbAMuR%^Rr-e(5i{&56e9@UMy?l`gD#!<9AZB3sEMVLh4ZZT2e;k8?EhNnVXErUpIY`mYjyvp1>nE{ zi+OJ_m#9;k?~FmKjf6&D>sxtkJ^TKzmA>4Xcl^8B>^Og{?|7QQ?6`bhxc#&2bg`Z1 z^VR9;qI(B7@aFGDY~Bm&$ESMYO+2nc{BHv=G=N-jjHSXv_Qg~pQ$jVW0%o~cCA5I`ym6~~5C-zdwppLAMJE<;$!*p7wzdl(KzzE4 zd6zZy|-Mh!D_2-*#F$>|3!&JMC^G!H- zrlH(6{G<(sbB7W+CSj40)DspR3swc>2tyV%{oiy;mWQ;5vyxp=EY*wC6QM-2Dtwn$ z%V5Sfpm?zvMSw3|lpOpJxwy89*(x75G6~tEKEJ|;>CF~h>ia?pPNYn-B zd*z@z(m5LLO1mH|-PtXvoMK?_NreS6ok&QRE(bamK=6(yMnBE{IV=wr1hJ3)nBn=5 z8B$o{>>kpQugzzv1XqD1G27uIGrWf=YjGntvG3PeI%jlNU>q4_TK+9ZOoJ0&3=KDm zeYQZxr7#?CUBUD|_{o{u$~TUALuEC%!86OYJVvoJP~K0;rz-mftOb}*Dh!p;Z)D&8 z`~E_QgfGk=MH`c^5GfT_thm<}3}^cQk1HP;a>3AyF(tt-&!x`Dj?YqD-wB@A_hSz~ zq-WkCu(>Cxm5rI6M!MX6w^n_3ncn@0itdv5)1D6kZ6e<1xIA;5UA*dY!2N?(-aEaK z5dP%2+=TqUYVOTzt{zFeR|3HzWX=>A%Jy2N{JV7=KQ-pQDrd0VT|yWUqpzFr5@U%mFv<-M-Un7lT_ti5*U)9&U_O?F+K zx_a~j4>lhkcO`oR?>hrWabM0)?`Mq25)n7^XkFBZN<^ewvnvgj9Y}}%cJsP`B^CNv7p&J-J-vu%W^JMspYEV z63bUSpKy$C<-F2>5UPP_tcj~Dr0*OTpETKt=<4%#y*24Op?jrKvYdx7N{?6Db)2bX zbVc|=9zPQK4s;F1MSvAFrB($q_HcNqrr=mdy*w;iDB1G3TmKMbT;8Sd27DO)HtgPkyG#4P~*^ z`2<(yQWwU6wKak6t`H5Hp%tc!bb=2VBHp=0HHZcCyDcnW%DvJ3*c8IAH=hq!r#zr+ zS1J{L(yrMm)4@=26H#ew$NG(Z;GXA0H|W(pe(RMt{61~iB+I0JK(=J~n{FWh>vH_Q zB}JBLiLT5j%H-YCGZKjvTagR0TCy%*FzYZb{>#a;dIsIX{%x5hw*)s)+13_M<;cLosJ=JOjKxTiPBjw<+5I2{CD2XP z_$o*1$}EhX^;TDy(83g$UGZDWbaknebVBw#Rns)CX(DX!>)`p!B2i`q%*_=wbIU@B zG&Xy-QX3_@I>yq|NLU6`&!(>@vsZ==Z&Y0^C(TYW zOnRP5Jn9@FZ&ei&L13-AV0xt?=>q|T4D#~yh(XO_Zjdv3#26ld%(ecS-88?u*LyXX zQVeW(Z^$-A_JXr6HzF%KQ6&aO5}o9p1iIkXaZgTMWcD0?YySLrH};V$9+~dcyvG=m zq}A>fRNMLzj-5z))&$Iie+J(0apJt+nkkM3wz7p?(s%1PrCITg8)s=2v4sb@neDbjr#trPuYaZX|-0@N=^2wL%A!WOOl;}2iHOYM_ksE*;_{| zgBik}Q4jAvu0?)*yOzTAcJuY5SpV1Dz|8p0f3%WM0}po_fE=$oV8h&R^D=LnxEqk; zJ)w4E8|~i5KL>dR-r{yV6uw0eY~l9>_GKNpL`BKZ-U?c;6aBegR}FY+4orLZIJWC` zS4`}+wO%3i`PAR2)r*BWOXUCC>uvO*$59CXe11Y*YP7=zUckCH9J|t}6$bbg0p;B1 zG-un$3>8cp1v6!f?F7r)T(lE>IN6fonK(`Y4|!Vbj(B{P!lztlceuahHVe3|ZQXB= zDo9Xaq$~V1ls2|4UbkdV|H6?r3hb2HFVo<~gQ;q@rUxgjYiAkH7nySpWo3Oj_41dY znw*3Q3_-H&YBXsjd&EQDkewV6v5`m_NGf~X(6&3)tTet3)^JgZYq|~52La$;d_;Tf zH>gg;@RyEIV8c*<60(WE52aIAM@ZV+zeBvZl^bLE3`eUi$&psM9uhL+jpx|tY{J28 zj4Y+JguIFjIp1>e_KEGus^x~2WVMxfYc#Lv4{}vlI1-46KcUkB7w9gU4X87Phu+1$z@QPoO4np~lGTa_T} zzeTzVv&_HwlsE$hii|mU=Iy4Sw{GQB4Dtn#@62r&$928m5{r$$m$qSqln-7+q9`+E z#Wb@8C4B@YNp37C77!p*L9}=CyJ7i106{W~Ca-q5$o;4RZ;P)CAJ|Mk#0am(x{Lo2 zTWvS<9p!_pe(?{45;PeNylFSmr34K(bX`pBkW-c_H!xTqgr(b?pvwn-uT4myOp}*5 z)GAPA8|MOqp#eu~!(^&1WvaWq2Pd10w-4TFcc7?~cwI=mcw5e{I(Caw$!OAGx!>BV z^J<64FjKD4&%w7jTZQ^Q9RYPit`80-A{&=;xmc4xDDH+-%EOJ0*Zzpli6qxB>RYiN z%KC7id#jxYw}xCR`!c)0LKEm&Fd|?P^k_j$vRI5sKm0kdyrZ~5P!J1$6gzS*>FgBu z^*0^mBpF_-C<_ z6Tg!E>!bW_2Q__SKd8)tLQz4BGnICNE`|jvnCWKd&{ict@bpTVn8WmXgz!HwD+CoT z9B_m-7*DxAH@ulG>YIsr(mmFx&-wXp3Z|IbUrT`6VXYCr6ME}&0+F~s!1UXRy}3+@ z?;M}>zo2}+-j(RBc{+Oe>GZs@a98uPE$MoAkK5vWiTcCc%IPU$X$dfxz2@v$W!3n! z^0<5W**vxT?(+1ae=;C$!NfbmI?p?5kjg(D^`tX?l$W?w%r)^p@3H$Us9LsA&vfCS zkk=WS?^kUF63se`VSJR3S5;)kWRc;62?&X(e!OVr-n+S07sAgPA+&2EBL zkgz}IAC!4n0RYx|Ic*%tAkf>HFVAD}Mw&vM=!c=sBcx%KseMYZpOgz*4$$Jn!s%i) zzrS|>z-u?fSyV>scF+YL7c3)mxTuzKqTVb^v2=_8iPE}oJFo&;hQ%%+u7h|6SFCYscPc=IhSOB z_v%n&p_^q{j9IATyI`EpmTS&5y^{?qeqtq1eJi8*ZA1|Z@>7G}O_+JLjt^aOGhwpD z0_*kQoU_VnrYcm~8klrqQg5RUYXqkz5vdlrH1F#p7TN(+xZ2mjmIXil@~j!e`fY$dT$-^?W);-TDai+DyZgS zdq^wLpo+sje!g}kv;Y`I+$%(v;LdxyRg8BYYKe6$ue~NV=(rq0`snYDEqS>mE%CGl zdfPg+(F)Bf`PVMiHn=m~%U~ibI2__zA?D|Uo)*u!UfV9{dVIvmN%ePVtSm?6+K!}L zg_e*hm5h#o9uGMqIaxXZ8A((64L#C(`ivOd6n*Z{tq*I9f^*FDn)=v$5XxU%(Gk*E zf=tv(=6!>5&X+9gOkgn&VriZ@heHLenCZlJ63A!bLZJ4^AwTwp9%;UeS-V+C0R3qA zmZT}i>TrichRM6MluV6^*OX*K1&JPT?Xy^zpafwAP|s6Vm;cPmgC6W<2GgVWfM80p zS|*ArEAS2g&<0>L-~b45jPKXRgf#jgAL=3h8JwV87V_JZO8(}1H-mNaA5uo;pTLyc zF;cHC{xf>gXmfrycdhrGlU1!1p`=cM%1iQ}ppL?C2 zF#^x61IMmC0}<*^T{iC}U86lSayloffJ30=oU^{!v4_3mAzsn~aHJ1-5e&?V_uK33 zxc_-6_RzN}cE9%8D7STJto8Ce^2xAvwwOnDuRMCLO)dO@ZQhN}9;#SFy*BvL|#~vOD+h#h60!#*tffdiR-- zVp^3dTcauysBue@TH)^pooS_#>Cq=IX}P6ZjpCHb{=`r^za?d&ybEUCHj~Z%N?pK; z4}1nJM8T)pWjX~~oZ6ge8Jb!zuBDae{W22Ceis)!tZITIo2{+A*1D%%W80)k3Io}PWW z3L*E;QR3tk?2d;q3k*>^etr%y9mNUF7E#sG6DpsIcQy~Wd2F*QGyC+Bvw?vdRPsqN z*&)$Z4!*;xLm~Vj14;{Fh%1RlKIBkF`(*}+Y;u|zBA<&!IaYdOt;JS6+>X&zGR5x0 zH!88B7i(3oRl>oD!Okg?aaCwRzL0dBhn$lwf>0=Qna9XV z6Ig2N8s4WI73#L$>OkXUa&qx&TjCu>#o3-(ysyA-v6jLgm`o)tp4PGT?PL^7Gg}+0{eLU~S>Mq@+dzw4B!PScC@~W9_Gk-QIaX5ho=5NhdcFC7^^T4Jh=fBI z7Zs3L&lmSTS0&T$`q(emr9=}WCZI)LECXsy-IHo#QD!1P6=UoU=DG;6E58rn;pT=z zGW{t93O)3+a6~CQZB1q~h1?s_6@@Nx#G!Eh!^JjB-iLoDJ6nrIy_60okEx0@w-L-_pEeTUrj)c)UWKK=F# zH}FCKPurc$nuwrPNHc&?U+!Ehbon02pI*E?-gIwfy&MpGT|T{CE4I#CAC`Z+p8s&V zxp9YSB;*@6%cSPAvBw=pB_ehtCE1rN{;*hQNlq?+RC@wQSK^cPRvgph3g0&x^xydV z{f$THyK(AH|2j=e^X(7IZs&0er{h4UIMq{JS+6UPCcb0(7o(wv=BlwB0qhBWmenOf z{H}MS7Y=Lr<+gLVA6QeE0jB{)fwa-}#r@JuJxVf_dJ{&(|Hkw7`5$Uo02wc~fKG8J zgHWbd0r=VPP>LRWw^5=!J@DG6$W4+@CA3id`D?~vhO;T9cUl?9FDJsCp%7nl^@{I# zHpU;k$)dLyj_Jo^q(|pjNXgu-6@K_)6gRxF za8jhZRl@(MsyT)1M+ct95K1X$n;K%_yI^hXP~)%BbYmdv=L@S;qNxDVPs@nwt}@+y zRs^c_LY}{kf0{C#a^#tIm@WeXq$;k+QcR0{6McSt+kt{Of_C1#$@ETwJIw$XyDday zo|Yg7Ahs9*uWUzgWkBI+0s0NjavaY8cx`h>1Pl%O?jQbKLl!xws@jUKL2azxBBiHD z-}PzsBWc-U8S0(sEX91iWb5en#hXnS~^b^P@Xm-W_@;L zsW)b58_XsWV5Mwz9xA$Bw)A}vaB(Lg&zO9?87Hrg;wsa47#wF7cMM-sFxN`JX+TuC4Q% z_?;-4_}`IAJl;q99mOu(j>${(r3D-m`W^G;ZDoDDoE>0*w4m%iT%B>sI9Y=G(l#FA^^gr%$L|SNoIaJ^CNl zmzbz_Yb$UsegL~kVxGCKo_XuHiG>srpA%#N35yLNAya?*X)w;%e(`%Gz)8y+Q@c{` zG#bQemAR3B4rR)lluuIdLjA}LqBRro^S{k(Wjgec9Pk};aAUs@+j{_JIZOLpCXcW` z`)=L5Ykb*C00nj_2GD28fx5txaFrLmNUGOemTtD%3KIHUbI^pO-wgYZhUy^7=(D6@ zBu7c~n z$xt~>6cVfYy!B;dKZ(=VBh!94xe!R|TV@0#e@#a0<2`&K&XbDdTb)Q1`ec^?@{lkU|27_&}9HsE^nyHCc?z6$tB6(&*Mb@TZr@o;> zZlxxvdDvOXEtdt2b2jLf%vht=S2!r6C!wP!;%KL;3Rx>l%G+y86v%$oFX zXEXY(z4_-vgjbZ@=(pbP$S)CMK|QbaD+3dW_S`}B%8jRZs?E)JMjJ_!ChHsj7&^Qr zUrC$~%<4R0wNWTgf+14L+Vlj7Wuc)7I&Z+}nxKSGr1DHz*kD3G(*5_U>8Wj-C+iH> z;VlvmIoUS@34NMklJ9xkiOVby1xu)hxp)5Z$0J|<9UOYR;TE}&7#JW*h=@;&i3cB+ z%hJm6NXWS;*o?xy&_=$GOQqKydN^9_Iu<|KoatXP$~FbGVaXU0P;GfCrN;U7(EJhF za@N1_AF$$YS4vcB%rFoMt&C+t-Z+@JStE#_U!v!LkZq~S8}q+DzBt`$)CO!c;jT`a z$4iXO0(|!6qWoZ`z%>_FgWX%sIio{Ks#yoaD)5tP;d=0ZG%yQRq-Qk2#5We5~$ld zwpizGaM6r)eU^^%)g4(s zO_9Q;#%!7uT7J!oG$VE_>Nef)ATttb_54-U_1qn{U-NWC zA@V! zW~?HC4h>BbNZubbDQ<6N^pPSgSfB2=w`bKDp_{~Xm$n%e}3I?3KhLRbEdeY@JkNer8 zAdGO3ZMjV84=YRT(9ojc_?$_ApwC>5UdQ^7^=6kydJSG#R@J*i%!VES|BI8WwFi$ zYo_JC+TxxNfb4V?$?GoGdg($F(`i(E-|P-i2HDkUwb~`50jL3&r!+pdQGL5rFMl*o z@$xdG+{VOuvJF_aI)9bo@qgysxrLL$9fdFdj|G5_2?VRa4LAisP$mjA%9SfM3Kkz7 zS25MD%!AeJr8`;OhQUyOttWGj8xdD_|^r2VL>1>r-VEuBfFi02E5 z$9q_%GIf-6%Rk?Cg=TbP-vy8-nn;fTAmhtrKQDTjL1NVX=C98W4;rp=^Wv3(18^gh36J$pJ^7rPhq$#pqzW3RB2 zPBCN99ZAr{=W{yYcDhp_7AF4rRYFu|u?0?vy1XJqUx&IJr6s98X=*y9`rax znb<-*ia5_*6ToGWLaBAY19BXmcN8~-Pq0dbIGOM|+x63T~2nLt?+Zc0~rZpe&{Sqsq zNW8U55v}<|Tp-pnIx$*X@BE9cSkY-4X~F59?R@L;UN9BL-~o!z_b|%q@mydK&)^xJ z&}XLH>waZzFzo%p&iBgid{>s}@mu>HVB>MhyNgS(Jg2AeD$K7j`E{7urb}p{mx1$3NP|#69g+X9)U^Pj`_*gwv-WLw z`=&QuNXrqug`$2J1~4WVS|&keWOQ=0N*9CCkF zA59C%5B}`@Bbp!8pOxy*K#czD7q?&ey9p#|3=gC{dMKK~c-R?d0aZxf7To=*08hf- zTYVcw+L(~z1chQg1s7#>KEjk=)`?~~EA^#w)>=^Pp@j^J8R-3*tZGJ#@CZ# z;jxduP2et4Si7{uqKm%yvna$e7~jV-Z~n~FT9x_85?4c*Xs%QI+j?h|oPtk!EV0BK z`sj1uTC=>v7&vSGptOP)yBDDlo_HSBVe!m7GbW2cCs?csih4YU%~(IFScH(JbGn^FNhYxvS6k zpU4d5SDn?C$LHz0R=cf#u(U>N&JxDV4=>HemO)!kt9HfF*R00>Ho)Q+7k1(?&Q}z@ zk8NpGSxK4qS%zN!n{pqwGwW~rdL^wCh*3E$Bu{ymXI7T5t&%iYz>Qy@)T9jY?p|rM zXh;heq-s==U}D&{U8WMeLd((ae2inz#5}rh;D+?P0!5b?Os|N{D)evUvd=GzyE?V4 z#hP9o*?FkTicx>9=kikleKbcJA;iVfiz$^*a4`KF6_3XinmwOO7T-jL^Yh{BKi59; zhU}beoc&m*5x0S+>!O*~i*Y=!H~9tU35NZ~yGU6_H5~ov*S4?(QI(f@5zzG4pFr5g zl0VIaK?)s#PdXE{8uZg1cCr3vKB!th!ZaU&i;OHBFzo7f-gb36{cWQgoz3UFOpCT8 z@yAB8dOMti{AHbr<^z(noEzy}-*+hGZi0}C??=2vMJAs+l^8M7)35<@gb_Awtl0(+ zCgc=PTz@6*IF%x=pdG##X=Ik~nVw-WM(g7kj`KCxH_*ED1sycsyT~mIgURjwK)nwU z9I0$r8x@%F!o2U;cx=6)VA_gL6&fu!yoHTxe{^fTuHm}c^k|Dw^t)*D-83QEtP;H5 ze|b%9A4F-tbbC9_eNP7>A7*|@D--}3i@dM*UuR}mz!`qP! z|6S3-b=kU4cxvm0L5|NoTjTa#X5-sYdE-%}s-F9h6Qh80k{IB%H9A(u+>x8yM=`IV zp>3dL{(j=WSG3Q&fr=>}vf*@@|8nR{sQXH!*r2p7-j!+FA0qWy zie*0=8Ha}#HeLzuYY9J( zMm>x~lXZ>%S}^DwY29Ufp4Rh{H9Vcrmj}il&|u4IoHa9|2u@9QI-!p}z1Lc)54Kuf ztbcD!OHIpm*VdimX++;X$QWL(9qRrVECUjm6GsP0&byI|Noc6E&-LD_-JOorH41ed zbtBJXGCZ}&>&dkpa*dr6u*7xwOa4^0;M3=v$KI4lURkc)Qo^bYK~1{^vU z4j7hh)ajec;bZcpC>Ul2b#E4?*%2t`TE)OgV7*ag#+{O6_*q#mYcRgwDQ;UO+Uj3^ zfCjF?ATLm*>Igk-m2RzZyL~Z&Tp20bbfCguc3_osXop_9Zk0G6HV!h&C)`63+OTme%})o-10aR0wFGtgj3#4pP@W7yXwrF;ex% zW4QDN^gY(b{ebMA+WPR(|9msd^VG(mFLV8dckMQI;9xY0Bm@Jf1+JNQ7#T$y|%*^VhrlF8AB+jLq)Ps+Gw?snEZ~;%H zaTm`H-bhtXZ7^ONYx@@`d=A?w$5p%k(r2=oZ&YF-5GT)F;*n<*<_3q1$8_x!Wcup* z+TrOyilTc3HWt>dg9GZ<*H`vT`La3deNk+KpA9*cziZWT+?-4{`qVV{&&^n~BMQXS zKhH?O;zF!Ec3Mfo_3*d-Ys9&e;2aooY0=>cmdll>l}gokVcOuX~EUra+kwYa4e>E9u8&(0vXL^61nVNiZqp$81^ zwwuf#f^Df{vI5a}SO=vT2M!nqmBm)c0y@d~tAC+lR6@^mV!bKEXpWVb%nl(KfTX<| zJY|ebhK>Swr*!t3^R!l$!D5fkmAR*}5j5%hrj`vk1aaWLVa{hq~`pVbAX54y4lQiBGyC?L}(k*QN z9l!o*>b)6H2o80$xEe?pZR;T8{L>V<&~h7Fpd|qDc_20&WFN80*hM_G4s5qZ(wwVy zO^)9rscoXS8Xzwpo<&MtO-Dqi9YM+%)f}&MbTQb=j9cyd7d|j5oc+n?X^HD!&r9!D zwt|*4+||Cdnvdp`UjS=tbMNZ@HGL4}6WyOTKsOH=vbSSAf>9hzEm zsEHKm7D~_rIPI0>y`6G(DRqOZ5v z9kGUzYe?^ zF}OQ)qv||z@^~|rGCi?-`Pw2Nd_$tu5y}=?&|{F$-DSWpoNoTL-8bSgBe()t!M$Jm#N10C{_7vWp`H zD+S;;nmR6g537auz|oyk+YI98*S#mzJuIsfcCMi^EoUOX3HYg&40)nZ)%73@-5cp9 z7`X$tLBd+hmX~Dm^!Xoc!84*BPa5wsyx9^dy9z&jsCPLKgDu%3kDHS|UBCvT*^L~~ zkLiwihmDsl&;q!5?`BzvPO#F!JPm7&(+D1{%*9ciB_R_Dg)jvRNPHj)I}o&RH63 z&x7}Y;eR@UdR?Uya0|&%)ADpBGv=k_Y zy@GR`Gt5ck>k`1qPL^h-I@<9;RFi`|K)lDaihC#*Wj7o!^0GVQf)w*p*r=On>oWj3 z7E5b*b@{w-R5=QT`IMoSFZCow8SOair)i#{D8wnGzg!SywBuCzdsHacSt9aaOG?Ep zit`J%ES=%Weq9~`nnKUxt^>bH%#e<>6WeuS&zuQ0RhiKvrZ$aOb0o)W2C2~)M!t7f zr%Us-mS}B$qr&7?m%nUq@cMWyW_5RinYO|u-cl^%Q7Jd)JeYx7U%AC2c#+5w&uk#8j0{Kk6q|)8q6=8S&7F|3#RIB`eIw&X6Ln&4y&JeEK`5 z@DBZ@ON(BVR4YZcD@YG+r_TEOQDU$qs=P8YJAwQZv)a1D_A+u2AuMT7n+CVnf6eyt z4l7}OY2sLs-w}6oI@fEzgnay@8qNxnFdKwDf-? zS8t#6yl-GF6tlPH@gVz49;-u9Iq!OeUI!GdXBa5gi+F}3K5Lg6f>&!Em&HVn9}J&n z;;v#k9uNaw`zEee0ai=yOV9n|ZpS+w{~I^IQ~S4(_NJ!W2bz{lyiD8LuBXR=rPd2> z$3VmPt$p89+1zb{xb}#J))x{3@Ao$TeaK4FZnI6()htF9zducw=7JV)b!QjYOan6& zxZ9BY%S2z@SUvdfAAe$EVsvaQD=+&fB*#GK_RHMwG7dE{H_U&1Xd&N+Rxj=K&@IrQ zK-_S8Co7GO{qu;Jn?}@IGrKk+?+UP6y4N-JGCvv=A|Gv$SD2@uRKM43P@VABOY>uP zxt#u18u!TLtB;^ARKgH?FVnA@DVwuYw?UuADfC36020x>rA8S$ZSwfFcc~o3!vhwK zoV{uYbVi!Es<r zwIAHFVr;gwwYZ5cxiF1*%O{l}oR?&x=@8T99!jSu=XmVK_RoJC4F&~~l}li>dlbFE zPvC|_z*`r$uT{KqW4fYowv`_w3)Y_kPLCs=IEguMMnj2(ybeXCOjmvuSBZsbhE+r> zgOa?B|D%RRLA<)Ji>U_qh$d+UoW0N`MOu`{KwDRbiKqNKsZM+EKwqP2nY7(@o}M9lc+Fc@kVOijst5v!k7Z zZ(gn3o&0&aDD?PX5hAku*U>KfkA<58rCp+IOOlJWbB-9v=@fNx$=>xW{O6-xv^mju z39zVPi@af-d_YUsnnqO4nILWqW@!?3l0m5mlmjjGjLhQ{W5&-?7=J8%5p~s%j#7ix zh%3oTf3Ta=iBZ=@SWz!icl7z7B)xtfjBiNLeLxYBazCIIqBK0Cu1sQxKgu}z6b>oV zY7Q(aX{?XJ*hyXLLMB6$l=DGe`XjsicW58rVDXF+*Y?6@pvj9}3#E`gqNmyvlskt( zAp}xH7g=&;{K1o#_!7p=%r-JL$1$$wo^V{%9%-@Wk9RM0&(rz>X4)F7^5t;|=qdM_ zSXu9u6uPi~J1HRAK*)Xh*8bL{cTtOo@Iv^0T^F$ZQsw_~KlcZMVg?l4 zJRu%lre0%p*WMS~3PaeneSTa1uBWPZqW7oZ^Q)z}S2zd19vjcy9;Qw3{rZT&L}Re7 zLt|k1xZcp=h@#V0!ZyA(UvEv1BzLWQIG}I)pZlARfw7TO;N$DHoT6f##RTDhFV70^cOdC=oMTOAZu#sunGfxl|;MqL!ciT%siXu;s`Zh4%Z z@AJ8M452#pezOT7&Dnl(O*2b$*N+UrPj;>;s2DC>RiO7dU{|CxrmmGLO)J*8{+Op- zs^T~kKE+*>KTVxniV?{!gOQP3hC;pz5B%Q7lu`SQic7_&tT^?DD)9O;Mn~o-ti)Xvg^LZ8aA+Ke+~<4~CS=6*M5=NBvI>C;c^&mCHk z<5*f)rd+#n)gt~WyGgM<@`{m}`kgjcTC5(a6BILbP_n4iZt1@Ll-szLwN;!6 zDuC3ZFvfOZLvKg*QD9srQ##sU6YuUHi9U5JEd6CLV$m;Q>3(e7lYtsJ)*=yw6lz&0 zb!~Gcnak#OK|$X!())jZQnyVgD33w?)@I13ghq;gr8HzWn<(q;wwgGt7P?*JS*ubh0s9nv|sb~E49*7XE@re#bh|=?a zQL*Rt;PCk8`|V!vS)2bR|JiGm&OfdJ*pavHpLR@0uHPdIK1ZNjr{=zruRnBKJdQ7P zjK;maIXpggys>q>Jx*u^ylC1&gn(H7?(*8L`k}YDl9M~&4aydfLV0_x@%qTfKR)4q zqv*Sh5YQ#L_RL7=Ge+k**Mo93`RV?$)nc_Tn`?d4Z6C6EL^t7lcY~vl-5RY*#k4(b zlInP}$bw8HIQoCG?k<(Svb(4E~-9ta3=BD#_?r=fIEyPgC;?`I-tdPK9M5f^14{$vEjdK>%PG-kfW+f_o~6uP!N+R7AC-{L_iODW{LAlkfM^IMm_L5ZnVY>kV;8^ z_+)1Yh$P@G%?W1kYsY3p_1KLZm z3n0-G(O;&B>I1B{ax0x<;c{mqYyq7c8|SLq!E6%ILHtGO{e#CabFd(7QOw8~Jle3YHt|{0GpVC``+~<#w+a23!rSrwTMG zCh7Om)-}!T`^`)>Q`XFr-P?p|Or~`?tdhiW-J(P#$Q&q#=-|p?WtO6pN5a+UgA>Z8 zZcHQH6S5c*Si}LDLlu<+V>Ed=QWygC4D_zKZ%O>wK^DKhV@gnK^-cAgpG)4?9yO3DN$4HALpVOV+|Zy(g7JL5av-nziB{gzN_P~Z1q^qSmm)5Nemhn@-IE$L)Ur8+|XLq}Ka(-n3!=n?= zU%hl^8pXdlMRO&}tW2N@5e?7@0dW zxu`z>*S{Tgqsd-BYisM7+nL4mJ%S=1`4fmA1gIi^7QtJVZM2N4qpqmE9$S?;kjdji< zO+%t=mK5I<%G$+O;15dv>~A!2DhNBJ7oDYs9n#7OCmxnXV^G(NrnXR%$NwyRZ#uB1 zN@-E9oLX2J7@ZYl)P+-SO^AVwQUF*Jl4WIzAkixdUU)h3*M}GTph;w z{;2Z3OY}V+3Ftz3d&+z{cn+9&f7vnQ0fc))uR8*f*2xco2Y78C3I+hbbUZx4A9`9H zA3C2xt{pew7P%*?{NLE#&N2;mCxoty*522+FcGOXXdS%Z81SeXa8P6JbF(G^& zNc-akeNAg5vN7wx1P6$mj6`AIo!7lO0ioAnW z%NeS>(9a>2673g1+2>|T3%eU~?M0g&Y%6P4mr-juELot@7TkF|_jv3j8Bdz(6=S{- zE7R}re#nP5j`3xjIpmwzXWen(A>vno0xZd4<~kcxmRUdU*73ZXgsE!({(unZstYt< zyhQ;6M_TRm|5$?-tpiAkL%)DOh@(r3V&?K^_;rRH@D<))zj^+$H%9Ou`{Ixt7BTo;OjUy?I?w&w=r6A1?HDq zMuwSKM#mn}Ltydw>DgE|H?-hGcQr*hadBD83*P@93qVI_rGcz-LipFo^|P*vlUv}D zAK^eO<`SQVSz}eIz_)@Ef-`gLKb;T1B-^Z&hkbUUxj|$itE#1i+kdXmkR}RCO4-?H zy~sr7(X0QG*JpJ9N}w*~cBT!iC=7athXrUG7IZuK1Pe({LFc(9hl?2~#Gy&OQ)bgC zGUIiF&6GJ{qvM2JFt|vmmm5gW$)AO`$bXBl>r130Ce_BS-x@fU?9)G4f3~Fw%!sTh zpX+4dm=0ACNhu9SQ&<1qkLoqy$+XVLGn6{6a8>a!aVTTxyJCD(9wDXA@t=&(8GiDi z?ze1HY~q0JR9>L|&G`|yswynva#b$+-2A+kyCC?JTufXYGh5Hensk4dWZF_oYR#q* zrG!NKDqr8$3IBf+RUv^f;0^{WMJvPbyO~k^ZU_hw1Q$eYHrsh^j02xR`#l}L9-L`6td36j(0w{sifG-f12_lj~>nGcvo4N+*l4Pic5 zp!gR9%#j1?D({um6GB{btM`u(Zl{FIs+OF6{%uBsi+?_zOHo7{NLAiHg&tnHF1zkq z6BS=BpC7x6g~l7&Up}`#FBoo93B7!Lznvj+c}soYK4<2f=;{B=$;H&U$7>sZVsC2? z{h{{IN0^h-7vAO-Zv6cT>t%cW9Vz$yhU#IFs4Yy$_hzj1aW3v+FqmoYZC^0cV$}<; zVa@m3f}R_Pg<|ez8Jni_E=Dnr&l6&*zIPCrWNdZ)UCU{3U0t2rX}YPeE7zx%CxAGo zCcCTfN6KE-eQy5EdBG`Q;In@XmdSCGCoi0c>G9gmR^9Dw<>fgR)nlk&_GH@`4`YaJ zjxXavI{2-=1Xo3+V4*oWDL42~cV6;9!@9LP`z*Tld3~+Gxm8;EU3L(rd4l zJmwSzoUAG{28Mq86vn$73kDTN9C6W0i=n(iUZgZSOGH|DKJ>(HVR(X6LZnB$4Ct$h zbb@reI4Ov=JyEw zZQw@7vFYg#*kx!Thg-b3!2*N`s-I&kZ|f{t<05KEirg1?*gK-8a_Dcfq=uwb-1~kr z8FZ_gnA)KZNEwyV?3hBcpo&O|2f>L8Cl)MPXGPP*|K-q=J^T=Ecfj2o1eQs29$pXB zg4fn1vwMou*6sU+hOGi6e?>#jz>IBeB$k)=+X`welX?0LU>EP!Xd$ieqe7O`+s81Z_B-jhXi@sa1x}7~dKR0U) z2){fN{PO&KaDHs0X^8UL;+>9-XXb00bh%m(jfBL;!`Xi_i~g;kKu%t++T))4(`p;y z`H_XKW!h4k>d87+&r7@2-Fc>wk-Jb>Dzfv-AgY3)J5HEJiqcQ?Q2IO?(v(tTT)?;Q z>4S0kLFf;o-YHk1W%6kZ^24*}ud6sDs8NYB@37ME<}^5xh)97(g2{PCE9PM; z@E+*ajx`Hz>(@rdl(A-c<+SxyMmR+s;tlcv4n~&Q5oDR}mr!4a3iWGoQ0N>BZA7kr zcj(6RIh5CiV?M~SgRcBYixdn!PylSmN#?&1;H}115^QAvwdq1-!)4IEU|8zE0HP}2 z2QdFr=mIdIYK@5tczE@_QzhCiH+;cgf4$>+NF{n95PH8Sy3RCw!=Dd0<{RZ2?|DkB z)qjVc#lZ9b`}oDy-nQ1i%cG#qDd+v|@O^hA_Z^YQ@7?Edl5f4=#KG6DS~x)Po_`zp ztaVqyzU@+CJi9HDtr)T~T1wZrRXf7tasign_9JXt1ZciZFiPKu#tUU?^ErcNq@;X(?i796(GZs%;yJFk$;F~Ha0&73A9%8 zrNop`57wR^4i@SQT~wzHu(|=j@r4=yiBGUxr$-AEC=s6cVl#flzD--7teB^MCK(i$ z3n)eIPN%QuUDeOY@X$6Po=PMGiTP1DC$-;&UWlpv*KtyuDJ!AXMBm>}Ig?ieb)gWW zqc0F};=Qe5{5Cew)7g|1%CBldTR9Ums88;qJJW`eAS`A?+gN)7P2bT$ZFs2^c5OI1 zmU04`j0|E48x42)iQ36XtYjZx9`SEPHJ!zIXix24hI$%i21qV$oa zAg3{cBw09CtB=ajBr<42jp0_b(dUe8Lb*mxU@36k_YBT5D-*si+bsz6Ohwvy&O;d6 z2hAb*89UQZ2nd+hF0{MRGRvb|Uc4@N-_`lp#?YFwTZgQWQb7zrG&@Tutw7T!xR1TeFPI`D8dh^xH}kCQE`Zvxya$i0 z1INhsa#6$bJ-#`PkUzijNhAOCk;^vsw%pxZN68j%4oiF9;ja7d!F${{;~$Q(PHKX6 z%BM9Q*p|=CN{TbvbL_pB8N6FoqGOQRnk<6SOWUH6kyto5yJi=mpNlQhva^iWdkHBe z2hwnJH#%?VfvoCi>XsZF6;(k`U(L-oQ8Oo|=X}82py%;P)4-pnVb$@In1FzPMopgU z2ViaeLD*Dorns7%MuK$>q*;9|)oUW?*{d2Z{gH=)6bz-qW%-Cuj3V$mTy%M8QayJV zz6eTRlZ6lI7jBBZ@iAqQIrK)JNoLXc5^Qw9CNjC2iWekipU0HVAZ%~CN3LSyTB)J6 z2->4e;)89h-SoCk?O;eUg&zPTQ7rTFrM_1+gk<^MSg<*IW0c?Jg0)*ezfBw-QI zK3=qr@)s@>4^NN#{imW+c0d-<`^EGB272(hH_W-$jeP57GSmJpliv@lH6Ij@btgKH zHRo>)|891m(TdJ<+F#I%6%6_}d&0E!_07Dz(nCT*6nuvOg(Wth`x*=1pw%8SL=?o@ z^5RtUN`)pZZ|5gi)B1MO@eUq;-V4v>_N&St&NZzbbn<`Q-koa5xzsf6)Qv*Es|;iD z^8IooRU%I}-36XJ?$N3_{bb%2g_rNkFJ4jev&x_yMoVmDQ z7e26WKUkaQNmX7@Y@TC?my&0JG`IeeKE`++oOC_NO9{#Q<%H-QD>m*nxY$n5wymX= z5mZ@PA_^}rXG9(OE{E!IkR+b)LaWGvBNE@vztF_4Fzl+Mby5c!_6cuvgzz}Rt&uOqfjM^ ztJt#l{9a<$)?!XuDpqo4$LEMTwmQL?(N6ojB=G&02LUUj=OL|UStq5&C^M*Zinf@i zdh)yPG&rk{+D!jxnWq*KP6<+?=rC570il`+S?g(TVXI)pW^}5kEN09O3D?T!c2AQB zJf2yi<&bRR7=IvU1=8!B>VXPANXFHjxQx{GEXPf(uU0KXT_~3Mg2a~YR7W<1rTm#F)v_Ad)i(KttrI&Df#YO44Id`c$CMKhD zXJ-D^8Dg?@_&NqgZcY(@fjvfQ3b)e^wS}U=xI8deS*EMnnLmaUR84g%W7rBH%HB|Y z?fJ@LhpMj#D2p0T5s0_cqeh+Ggpdt!4{1TMkdPLenkq|R_9_fCk{9v*QTL=DIcOaE z>j(uW=WnFhWcJX4qCe-vfH&Y=jhJZ58)Nn*)@9+Y_=}HhfUgt}%v&7uwG6@!(r9;- z;%^imF!;2FePa7AI=>GvdoEpW|8qRE{txPC;CX)SxswOu^;&Mw1-ROpuf3mnTn)wf zrZM@wO+3zXwT}wh&B|NUE>*_B;A4{P4aohE{1e2a?KQ zXDBSYN&6tj+PNob>ioVL*=IFn12STs+9*t7n8O(Cy@8Q}CS&5MYnpA07F#Dr_U)*TKll+zzP@T5Lcg?EY^z{|_7VY8|VA@)ID*3X3=6csCjJ6fdcRLJ*rX5n$*bEL;vN_XpK5xit@Ql00)+KkHMyFcDx;dDl^gtR;KSe2+Q$SUdSzYK^df`== zUms&~hdh#+6rL5BUx^!2U3w;YvP)<#DC9dC=43_NQ(>%1u-3;|+Tz7aWf8;^^ct^R zMpN&eD9C^rRaAa@%8=0%S~l=g-XBHBloYysUKrdoXE zcC85U?OA6uEj%W^x(IB`-JBXP*mp!3yIQ8TZGZa@z!zX1n;b$>L`ey3PL5So+1Thu zM_G7|f+ZWDx$C{d3(9SPnB80iAihjQJHy{nU3!*W{&}C?{`0(@`{%SBb2D$_Srlnw ztrZ$%_gOWZ#OMGj2%7|Vb+hDX2^0FtV$&f_Bmlgh|@*eO5_jA;1#>%Z!dcnbHg>RVb8`|C$PB))4QeqzZM-o#|Q zVza_x(}J865*iu#3k?9Iu@ekU$7gvicf{Z-uN_oEzwKkMbH4TQf%k`C-?It9K109P z_lvgk7Y?Dv1){5C!xt>Pg2BSa z_?gt)qYs0C13QoVi586T-TC@@UX3V@!{VRCg;lWvo#PYXoctf~e8V&8?;KIq<+8rV zKWpZg(4b@lbBonzU+taGF%?5>_y}-3_6KDwmKewr$hYBo0dLQwAb-Lr+kUdl%R#f5 zgN*6JbJ$Y4iN7pJNFcq=mm=Gp z#&l*@=JWC#ZKZX{)SJKiUtRQR!jL~=Jefra6O#)Nw#AuzjZtL=(?ht5>pACm@4s@4 zsU(^5i4zvU&TgmnP~oEtO^MN{Ilpskum#Rynancl&@yLwXW}o;Pfw#PLyai`%CqWf zOR1FQWwWJENk0oaE)*Xrghg3p_?r_ge>X-9kan414QXj!Snz$?HvMVo%2$it!~D%s zCrhmsL0N8to8}2d?JgRlbjNKP09GfaXEN1QtB@sPOqscU2dk5vLdHntSyN z2g5Gb{vZQiprdL^=OgejgG+=CsilSfOsO%urT+m>(py-mI|E*(WBIZI4paKfhc>2z zW^S&sy)Le`k;2+C%1YZe$NH___FNVr)KuFm51l#o{=V)ZRRqfuetu>eD-`|S-b;M! zUA>*uJ|1x_(+dM9IRf+(V>PTDxqazgDdzj>OKd~kqxjb|GubpI>kou`#l`6>4ROIR zm`yvAMhb*2KV?yfc6X*^xt$%8kH_`;7#0jh#(=AdPQm5)?}8HD&IKaI!hE$n$L}h3 zcF;{9!BD3ho~zqWZFLfLijj5`J*1NSNp;2%w2UH;1T0bHf6Q|9BOb|N@#F-=Q*#O{ zd5XCYjIJZhHHe>>7WtZE1M-;Vv*r4au@NhYzm2d0*hKOqm~s*16de448s7zP&ef$c zpwZjem}X4{mL+(QrcjG@H!48w-T=T*h^$>bEnI~GAq6Ph`#g>o3yy1c+<3KLFRX7! zzTbR$TYrC{+RuGZpWLoF3kEsD{vdPBGF<$3QCj}}YViXnC)evPPv*-W*87-H!29{* z5!PGKf3V2bbG!DZqfM-iU(Y!%TocXLKx=x7Y2S8eZr^&x`(Jzd-#+%g3Gi*Q1&`k& zjRIjulF2}<)4^mOatMY35zwBF%01Fn1h(tn)VJ`>NNSz^aa;d-hRYf#X<|dR`JNJq zcgEMiC1S1?l3n^?{Et)8;$g&IdPF;3x zx*lf?{w(%$Q4jtc@l`LoyrGd9-(amAYrLmS)=M8e`+(C|P`oGqnIdt^lQ;IkeQN6V zcFUnXm(_gvpP>Ddl zD(+Cw^>Fd^Q`>6NwKf0-0u<~$Dn$cYhJ+oW-f}40VsP758E|jQ)_Yb~^HpeoIkn|{ zxmvjydO)0`#l=Z;>!)7^a;06aKYQN>a~DnrmUT7}=H7|06>RZxLV@f1BZ{P zklo-GC%YAlu`!HsFG^KKlIkBHcJ>~Wc{)t|lJFAuOXz!^H=zj88qjbf9=%^#UV;!$h)jphs*$s=PA?vCtBK<23LI$Qc1<+vC-#5B~PxS&q-nX%K*j5+4S@) zP+}&m*f&S)3+*ofn^qXlF)}7#$NDa@b{`hdN%giP=DW$3ySHNa4lnew=J600@XXTT z_mXN`@y?kh$oYco(mmkD$+@6C023D@pF4YWA`F{#fOqV;$^ZUZmwVOL@krNxv!r+( zao>@8&wq!xc2x$z6a%p?0GQ$yPQ&W(Dc9<(6%pdGjhNWxC7>w=Afu-WBzb%vm|;)| zO})GxX;cSuF5yC-U@X;a6d4PdbacW#piN7qyY6`u)?&xBlpuI@G2n4$MJs>!2dnf z8&##{zsN_+pQ!};l!;ZX-Ng8>@#Go@}D#9VC?0i zMc&LE6(Ed3BTb7zmK;q?Q2;xXJs5%QtS1~jfSRx(4YzU_X-l>|7ed{~a>5Ahg?H(R z-Xrsi&N5s&P@F#~5tF5o{L&Iy7Hbg9QMltyPbSUdKnix>&?c>?`i0h@3eg$#h8~dJ z^rVsF12ui$;(@Y~?Bqae^oCN5*(`&TV+qWN&Vz+B%quLz4qY!da5V#9Q{EB4_w z?{jjPI|a55pP;@{8e};|7f-YF?J(q;`U4*xMjqcZfTM!X(>VNc!)`M&f}fUdW)JY* z6&2ZlVbaz=Ju0p9!C~4|qK+gwCcZu-pb5RpwBM=6bJ*y2*$3z@b?x7KlwJnWRe@O< zY^fG8#k~V;FEImGA-Fq5h~wA5QJ$)y>dSX=X<>B?cKKsH^c?Sd^Iym%1&%PNf*y9y zG?Xk%lg}+F0X6sh1F0upruF%L*XS*rDQS~XVE8K-!4?= z9td4G8sFnpTpoSBo_!D2B}o)n|+wV#+3cM)xhJ8L5uXH{nlLhtPCT@LjIA&agF(3smY3INQ#x_ z$j?(ukr$2_on(zRg>vNr3`y+NNMwkOiQ*|5!AkTj+vRGeNoMI2MZ5-W!Y}Jf^`@^L zlC~PZG2wB3>LF7wkzmyxs1T}u{mS+kKAi{CT+z&(GqQ{Oc6I=i=gU{`G`y`~v=3l0 zviXwJPx;bw(?t?k(XU)a$Hsrtes*mWrgWh#%j&8(Gv6l+gX|ZK7QK{mQv^1J3>ax? zLtA~(&hD#s(K1i52IZ-smnNGYQQ+u~D6^XOjw$n>ogr4W`9WB@W-76~`EdyMs{B|npnl=Ve8JjmQ^}MJ0_)mw+8~125FaOX%Hm+ou zHX}zEMG~(7$`I*(f%sMkwYHH_SuvTm9i}msSGT5=>P9^NymZex`wzLqn5p-V7;^eC z8j>}%bcZ`>8t>EzKTD6}D>NfIyIF7ly!QaAKWYne;o^#&|3lMN2DSBf%|cr!+Tu=e z4enmtoj~yd!L7JUp}4zCaS!h9TA)Dj;;zA+_x_)m_XAA00~sLqVi~$`2IPHXo-NCcx=r+aA65c;By+v>f`b=bavzSk^n+49DL>J>T1VT@u}$KmH@Z z*fV^fSbG}Oy6X{neJk?1_`0({Z8+q(`r!+=ahl!58iMZYa=KpwhL;%k0{`GU;m!Sy{hmxo)%@4FU!)Slcv&=N_aHS{D% zG4MuGZr?X%_U#SQ`@SvsTjDL?P1>kYXKCLslq(I6Veq;{G5R@rAcvW zM+>@&35Pe=OkfKF!Kxk?EeeFz#)O3F48KYll1&S}rP#q#SkASY@-z&x@u@jE=B}>X zOqGCdkd3aPE;XvRrdG;ghc(`FbsvN?k4UP#as(nVWRG=c>)kc+eJURh!Fky>eTUtk zQcC0;mf@l^hn%IEP`yfF({xVc^6*1>^3p=9{M`hhd_HMg3Z6Exvo_(?LIbB6Ho`Qa z?ZS{X&w-0Ty$)LID!M^=kGo)`TvjhxW!j0WcW<=xyfr4L)z1@zEX^!Uu4sK0Jj-PL zR)d5oYmCOcQkwInE3Z`<;!n!FCz^p$9fS_7u=H{6YmFV_H2$P``3}vnO>W~RbBZ`8 z5|kmf?=~dM8V)3HhyF}q!-<2xa}nt#&@EvmGyIA`R@2Ol)h5eGGqE#^PRm+e?DWya zo^q4x@5uB#e z$wt~t*a^9jDPiK|3lECLAbe|$zol7qB`BC%xueY3;?i9aQ9n&OX;c0;xh#R6e6Du9 zWiv$;yY$?+8V9?^^?O3V>{xQ>FJ<*C7)f#1Xs-^x#Up(ay^0Q{-Q6$&rIq3_0&~j> z30k&+3tln^6p|kUV4|(=D)7yTp}CJ~+S|5yzH0NVj<&zN)t$8Q``NCkfseO!)}~1v zM{Q}5gK;{H$);7z%uW_-aDWxfm?a{*dCO%0!3Ohs;cog z1KlVh%9)I?>taee>AdV&+cNp=DPs6^Tzt2b^Gfdr45+)bA}<&*PY+#u7>`2HL+ZmO zeF&u9}DM2-^0STWqz_Q6(-h8C?89W6AvsO!wRKn|XGM1vEJbflgE_g!ro z>ivqCTmkJ~f~7?%iclDzR(m=bE=rb$?QiF2Q^(M-e+W9;JW$Gx;BxAuKUf9284QGo6Lf&N2((NL) zp$03yP2+HM0HCs>);UQE*TjBjk)D`EF_0(Mz%Wy?s1X6Ea3nF2u`l>)QBcNzpGIaJ zxw5u#IPOj!3nsOsY44ivr7pH`ga^q6fVQk3OP3dFgsi%kTb>;-hL3rvU6n-8e^qz) zJ}FVL$t$gdm6^vS@qsvEKohErmL(UU>(=0{ZPhsfkO|z_a9-JEvum`{7==Z;^C5zP zcAl|Wi7sE6RIsM3Xaaj^(ECJQ{((>I`1i!74%tHj6ivt0j!MekD(PmRTpz*_T(t7F z>DjFiLHFc96IP8kh35URiXK=k&hug4jUN<6qwpZ!nuRVpmVe|{0%qVWb0KU%xVB2l zJ(>R4hWhA(uu9sYG`wjsKI-24$6~l-E&nqDo$>4+Ivk2ReKTQIt%*Y6u%ADf`*#$= zL3U|hFeQ@+Z{zSV?r=eVdZ{HfmLg-)9Umr3`evcYV% zrTBeHYTAT0#5g6zFfT091CG9ysxgLnH8H&^4l&6{-6F(SRNC~2OW zttK|A-f%1;iPN5_pQ7elcdEXZYa)9?B2Tn00L;6yG3ghq?04SLep_k3s|fAPc|7aL zXgh0;TDJ2fo$T1~%yyaJXx|Qj_93dzs*{y$zxY*X2(U1fV?xSn$ zShTSV<8fQ1o94ECr!hN=-$bpzh7fNF{_~m~lyt5agOhysHSRd(J$DR_siPxIqxR1q z2=#R_b}eu(rOCuKRQqEnXO2urO*g1>C0EgFFj51ywS)zhY5a{OlAW}Sr4q@R71hW= zVxAm{6K0DoPUfwxaxb^q$peiuAF~IyCIxcddfhr$yo&x!*4lUJZH}{vv#S-h;=;da zo6hQ5Gy8Ld!ATU^rtjG)J$bv2Nb0j@{s{qe^XPs}Xpk>euG3RKzh8go+(Gl-(U&|_ zp%e^4^QuskiVXG{%!d5sLd`4bf=_}qm0Ylo(6l3{C= z8i=2hh)Zu?X$*{6ZOLsFcb>Z%>7FJRrc;Ow7e*wBqG3&QT_oFKP@uy+1o5rM#2OH6 zIfi$ttBYe}s^Xh4+Z{2lgY0oY_SkFQ`q83XsyfS?8F7dEr12%Ck;LhGKHi-Cx2Jtl zoY^}bO`>`=cyls-ywVe$rk<)B`i739D{wJQJ&$Z)MTyfCZXS1f4z)}$rqpbz0W~_U zc$M`$9pO25m>0A)&-L(QV%Y6~TS1Q_rfU0BkOwDq3^TJzBA1>jgehmE^{sw%MO&mU zp<G(PD_A^Hg=X`ANU;& z7k{?$)J@*^FD$vAU4i#Y!0FM838MWa`2zcbz%k8cn_yJJha@aOHvCZ~{;ihc8!Fk> zC^!k#0!|Pc`>|wMlBM}Y(YCtm$LF6iTAR831wJZa#j*SADm7>T>`Jj7y0tuUcgh|n zEvu=86uR$laq1i(QQOIm#>7ylmY-;-3OcVZ)|+sGw*6T4-E(W+lXSZ{)LI$R{dfN6 z%x7r%ZiQBOH0OEb^QG3>J&Nze)@R9nKIxgGyTSY#jax|nLVMnEIabD-S~y~no*KX+ z)?DPC?e)sduW!EViPrmICTD%?%!}vDee1}5mGNu~hs6WKt>au1z+636zCWYsU0zu? zKV6J@JiW*J{`bKA`?vqB=N2;_1aPId>d*QbPn?Ak{XO76(WkIV$`zxZS-#CVSzpMQ z>2ua=Bl}=US4{TdU`-G%@IYnYRV)208J=EWnYt~=hB-Vqy%l+pc=7)Ie{aq?S(G^= z6uT(i?zY>YCoHp6lp4;6%KdZzhoGN2x|llB5C3V9O`QiUGdR9ui8j}YUwjbS&fMJ zIYDDoH`0A+nLMfiijZoNsNCP=Ipk!-!244Lh7q|0m_@1be6w}vAGPTIQ$0j>g?|l? z5XihW?LS>T2@xzHLOA}{!I)0?pfAN5}miM z=0B~owv^a!_^O+}?#1Mpg>FPkc6^8Wpr4#V1N=h3Ps{z~0m5vebkZ3UD$3HY8Ro1A zL=1kt_w|zB@a93yqc75q8U1<)K5Ssvsg-ZAQZMJ5EeBie@K@~=lz-5U-0oit0^J9d zWKd+J#UMSRiV26rV$p3oZada(*Et}mR@_f2mG)CyFW68?N1GO3I&oNv9j~nX=5_S; zn$@p)#@;n+tYdXzxDO(5bP^bzJd+ro$j4?+^@JN5Rb@uzBtmG2m*}9tdO#n`=kI8g z-RD~{gHtu=o<+g83QjMaV$KlsC>%oDyW(?e8c&nwm)|1HikGOQ%iZV0F7(eoTqyfN zZ>?GeEzK{Nle5DmK~$e%Lkl#nm}}a?1~1oFI|t@%sYOhvM(JdE7E0Cq%Uul}by%uI z*olvz!pS49@ecOp4vCF|tQwQcj!hK$&}}B7y7HfBW_yCtzEFHwZ08W-qm-S|NGu>= zwe(W>aLzj_p`PcWNi`q&FWK0<24g6BU$$Nrp14LpKdMdG89bPM@s8?VS7+RZ%9>dg zlv~O^*}6-xa@D?f*}H7NMXmlcgt&I8)Ont!e9-_E9AA4~HN32QeGnlQxsgF8EuGwY z#ru+nM0E%sMk?^Kuj+d((zR~b^&0au(bUuc*AJqqj%e%b2j}dog0Yr!Bs|A|e0z>dKY%2qhToeO3PTYTOS+Yst+jGR zF_5`<{4-R=HFl58^{rDcW z&6fe?)NKj1mwRi<{PuzZ=usO+e)i-_LuY=ip;-E?fBW!-n9Bn#D2zjm*+m}NMq zSB;{LAj|gmgjr2mbN#_F1bnC?2 z1yRX{27DpcB1;)j8QvK&cMM%57CYWgaq>V0I?QyoM>pve<`oyioWS!C>NGtCKsw# zVds||0-Uap+A4TV(khAK$9!*tBDQ4Yg9!2>Zmji4`_V{2Li|J}NdU zBs}r~%egynG&u<=wPfX^^U3rzkdp>ARb}7$rW^z+KKLjy+0+H38XP>ncKf|blN7=LPT?p zrtCCXQGRt@J@D$5` z=l_1yH87f7;+IcALcBRPaj{HG8YrY2w=)g9)-SJMW~puGG_o}fD};p#jl~^Uubi-- z`)Ep0Y6go-84a@@f8r$kSs5yGYsD43ivFBCk-Js15cAG7d?XV!5jP>j!|cFrNOULqBcD^|ZkurE}C$5nK-)6o@w;c^yyr_p&=i{}?B5DCrihe&4URE-|jn z8yyf0-lUm~Qy{2KG?OXR)`X3kFIket?ZM~K4f_AGVYn(Pg4YgbAI0{lgGz=!PGF@} zW6~N*mzR9_1QL(X;HvRtg#EAphOjg-4asoiBI6b)2=@<^3k|I%Heyp*gJ6s^53Joz z)Aj;53>*{@c}!=yorim!ZB*L3`@40VRC?b5=7GOhUNF|4mgetM{9eer?&m0FfAA3v z#SGE64Q(DZ$;1pbM@#$0ZN*%a=e%a-yzEPR-$Fb4<~yHQb6#hM?#{gclKJ10C#m}! zW6RlTTl4c@-Da4_ywj>vb{|KMFPfIVuOz<@6=OyJ@2iW2vSvs}+{u zyIj3&?!alb2Iw>tanmBDB16Qb0^ue+le(?h2ye6v45-eR6$XK8!q!`CZFnib*_L3J zV)Tji+~@D03C%MpV**BkZ_L~P8vs%oEf_g`QYLyv&$sJly#fxmuY}iM4Rwtc&T8v< zm1yJa@JVi-yUnqKo!`cYvPAO6+J&gLUmUs#pth0Fbdcs740m4=xbTB+JdX`@0PKa* z*l$YyK55z_b}$Iqzn)rAE7d2w%Gw?A;}_{AVPT#)$7z|2V=pl8&A?_*Yc%tdN3)h; z5H%>cWR79Bd`B@sxgt{*y>i=*o1R=wM#tmuoBXVB7^aNsPRU!JLw|Wsnt0N%{VE-a zBx;cU05>P`*q0;;PVIg+wD9C;6FO|$2+tO|O1%O0ynp^yEi!XVgAK`&a>=6kdPSPf z01BI07O65k)UEXe!^t9uxRq|*ib9?wWhPlJv#YJQFhp0+wP;BDQ5^mF@RKL{b$D1Q z^1d9L;;>3RbwMvGwXPJVd36+gqjtB3QzBqMJv>vQy)Tz+);Fk9ryyl(!`QcE6=KlT zf0#G)r(~eTylSST?AQRsau$t25=&_J3%03Kyo{DS?2PZ^Z>UHY(nW9b5T(elGt19R z&EGU#UX)6kiki}LPi~4YolCQm^CoX(6k=hk5|;&l5x&uahmy#7#K4osoS<8Y?=VkE^0ww2QzS2wv4IfGv3 zH~DWOS(GLDK+`%yt5D9TtctrO{ zE1Ahj$}#r;*#S2eke8I<@=fgR0oO~)2yw~>-g&b7;0O2g_KF>H=KQ{v`>Q$QVXzD| ziQ2?5FkRbrvk2dX!g(Z^E=CRUoo#v);cE0Gg!7vqX>DtLs3COvQjmXwCgK^WBc5<3 z*iyYU_@Q&Ms!%d{NIW@29H@f?-*>>rFzXe8t9LSjKFxEiFAK!dvNv1k=yTQnidT}==;gy%IJti)8(D6Xn>h9QIa-`qw#M~I%QSqNjym3wawe{rSfvG$e4yy9q8Fa>0oWt_~+ zj2>c^|NCYI-q?<`Ay#~pDHq8DU9@m|;!4?tR)r@0;^itfWTE6> z(uhEAbJBmx0}ZTz>vj}Jb$z8^@70+AT=@1G2T6SDuFk;BD5pOi>{e~Fei?EhV`YhT z4Ti^;d*WztFDzidtg_u4Jfan7SyVB#QJ0SUIq_XmGW^3O{+D>FzY=-n1ISfBzeLI0 zhN@_qz9-Mw8zi#dY+SbAscJJA_W@cmBGNnkf6vi~|0{$(!v{>i>q@|@i09ZvmE_rR|n_<-Qls@$%Asv(;R>Crr!G1B{)FUk*k8EZF~};}Jl@ zvvx)(R&xXAZKi=4R8RNK4%K(rCo)>;LfX=H-9!~yf(Oh`HK>Yxy*@a2qN^mO{oaJA*LB{ownT4g6lb|r6XK55uJ`k>> z+r)uA@AH^9mYAQZM;t3E{!bY8pEI^&=Y2%s1Ot|be@5M`fCUGy89SHJodM(fIElrb zri`mc{fC-0D%5rh%&>fY{vUWPJ6q$dYxc!fY%Cih#=eCZwD`0&EWuUA>7ESG+08yn z&thRTY}z$AWo5>Ztq~H-+K*a=GDTK&@U0BSC77+CTt@idQj=7|Mr%pLh+jqmxQ*6Z z&644T>V8eeBj5m3;M~wi5X~ne8g{o3@7x@ z>&G)6RT~vSiak@N8eH(7xU#Vu-8qZicoC`;VY%{jkYxljg28`W5(TMez?f5EL~oPs z94IyAsB?|?8PX{vi~dr%Qf&xrhJnKh+gvjvzzi*k;po?%IO1BC4TP#TZch)#?hQ#5 z)eyErqW}EyG@D^Xc;6pM+`iB2yTL9}0OvWO?;>a3d%E`vpS@#6UY?5Y%e(IQMV{wB zJ8mwhaz~Ty^w*?*p><5Ox5w6eN#xI&>xWHo zj*&f`=zIgr^AGSbWaktja!um2yAp>D$l3GZZ>YF|vTmgIlMg3)%@e2RtCxUiFFAgZ zbnBLTa=`qJ`x)Xu+#G+048hRHW!1pY54%HAPhbNB4`g&H(P!n6Er`c*^_(3@Qsio6 zxRmg|lEi#9%w|0ddUrzOTQ16DF@vOo>M7jUISE@A7>WQ*u6UFNyE< z$~4>cz_+UF;uDYXGpfKi2ipH@0kS<74VZ<@KT0d&c^%nzTYf<4G$=!wuVEk0r|?7uZeMS7pAOAMcKW9cd-J=Z z+k~T?p8DCMYkH=mqUzZhM%tD_)!lfEKZPj-cI~E!Jbrw64tecgd)eW+y9{|vW%0h@ z@ZRqGybTB~$)J9#)`0BGa4^Eq8L{c#1$?$&pOeQ82gU6@IK{B15YMpJV=r^;Kborh zpHBs}s;0I%(UGju(*#S9VQvBpMkSsh9(GPT8If%-9btV*@7Lo!>07|G8?#MFerrFfc<>H7G)Xrmqn~GHWxdCaL<#diR-^+zsCeaYV__ zf%Dt!5vC`T)H7)yE9B1^M!n8YgACv}N&n(01T<_nm6bJKE`0FG)qRIlo3hElZ~xL@ z0WUKLsT5;@=y)J%h|fbu?7&Fq04#Q=5Gf)-71d7Is9bXX@+8T{$%x0z_Dp@j^E}RAkdCtw)@YwKZy+5$6vsBKHXf zgK{Mvi|G>yMx`-!HU)zDX$NAQAvQL}2({^g&l!I?Kh8v|R$D8S6H;!{bZSGG5 zjQ^cF4YDC-m7$gNyy@YUatlR~*5!#dL3x$y`0O}Z#m9$<#8EmUxjO6?e~ERjF-6N2 zI*c*u8Bx7#Y5M#-tg)(mF9wLe8tztzd+|CBk}HWce^ifS)gVyBQB4x_ zEFRlrQmsKv?h;y5jK{d!2@)Tw$&{g~pj&aCL1})z5oo^6PB{Z!B0##H zkmHVL=)1r5bm`VLX#a9)=zg^)vfEE7f*9@i)Sv(Kuy60~Y!YZ_Yx6ykF7J6?3bVMG zjVnxIW+=bw>HX_{g5Oq7*R6i%^&HFP)MuY;WxppA@Ac=iol1KTj*sm(b1S#CDHnMH z_ItZT_S>!ILgw=Bn+e(O^m{p8KgA#OEp7&;Q$?Z5`-t@JoYvQC2r=%PGQ6?Z<*#j({LSg&Bpc&0vfiqK;ox;a^1O!gP6RO_|pN$W4_Wc{6e*#9k_cz5Jdy3d!;7axJN&nO4Lrkl2k z&3b*Tt$~|7qEEOj87~dh6BLC2oIz5nu~la^ocPsV9%&oZ%1z5*nr5r$3GTJ{{fM`J zAc+?k`cTFFhW+=xt#*XhZK(XyK*r($>#55@5S)C32~d0dm1YuyZv0n)!x9S-e%YU) z#ZrN!tE})TcBrHs1~ThS>R*U%+Di3!Lc=boENV&c?7^dwqms0v3yu}eLAf*t^;hUF zb+KlIpm+y%HYRE}lnk02#k|{X0TbC|3Y<7PGWs|<`FKeU$sQF{XG!SsFM5fQT;f+-vsScX!@F<#HI$i!Ez3v7HJ@x+C zOWvYT24)pU98_xQ4x4XQe1|v*R&~46)KGue-PduE@gHSg$Qg?YnO(d+srDAVvGy^ryO zBi-l^16++3*nI2Yx~Sk|P1N7S_YMsr5Ya}%_9?qI@m^u-FDHm=duK0)%ibp&EU*y3 z4DIvt6r#sGunU**@6OZr77X1kWNFD*wtpnC^M1K(e&L(H7%w(VP$I(mRNx!iaZ8Lz*01VO~ z+W(9*IVb2)KyV2Vc#L;H)Rl#jfa{H1CV!f6+p5cVD4y@8j^B|2dRbRgP&uRgm8X#$ zgPTdAToCjGU_gwk8<5O!QHAJD_Ap`LebVE2H4iP>Q%`4 zW28Wqg;?05Qm^};{Xr@Zku-K=YVd`ZOi^67JrFiRkp$ipgeFtodJtQxG4QLtlXLu} zKyTa6o2ne0&w@#?T3^R?{}v_S3wK7L3SI2j&hU=o_NA(~yW;}2!)A+Ka1gM~wMd-i z{UgXbJ4h@$2zU_iMJe_Z6`JUukqEhm&JujOvZy>h3r(cC(sfR8&o*?9MK{uXp*>86 z8?~Du-bzxAx_T}|1C+N7oI9P%98s*8ySVe!jY7XC#Engw1p3(D1poV zH9eHVjLij3ec~IDho@+iQPXe8lrg)-^mRl%5kgdW^e^lwKz>*7WF{eNLzr3RFLck( z_rs0wOMJ7n+4$JTk2G2PrEi6_6$iVM;6qyu9As&*sc*WdBw7fRaR-{udf4kZ zpJpQMH2~b2CiZJ#65T{Rj^=hqD0-Q$y(cM4>ou-{>my0~MWNe8@O;zHyyaQj_-~EH?_ppPRvP1%`Vp971n<^$0l$6Ul$13$78c)WlJ@mo zB9BwFc_(0y$tpTC@Ptukdi`BI)?dpC2wAg|eufj_>gEq-^uR8;xE|R$= znx25^UrW)a=ZJAwE4NGa8BzQ9z8O*-ax9VK9-;yivEo2r{3>MSsOV{U)O|P?i~Rs? zACV+LDnfO^#DlZw2odAkPq-6Tjx6N%yJw}Lp$I>N1v{+48Hu$Bba&`n?u^~^H6?hV zWX1^lt!~$Hn12zt_^jc;%QjdxQg*0#%ggijY&|F%q17%yM5zu8|y8{CrpomwOq6f#V64uU$F*m4`2|Jp6IhzWqAZ|$?;DCOE)yp58@O>WB6)%ha z#Ne~N^rjFq7uS0G9o(4O)b@J~BjLmLdB@o@hQ8>L(;eia2xhNj#tLPIiYPhIO}MjQ zMjn$1org1D$S(={mh`V*@ZM|G_%nx?mXPf5b*hchdNdV|ubav42r#QWK(52+K( z7Ab7NFe~QDbg2d^HF|oW#3WY~flBXTp5_f7jX z&Ce>)dS@)YJx(oqe=}Nc0j_1MXzx5;0J`;(vNF7E_(&oA`eXhw=(aOGMC1;k^ZMZS z{Cd*c|Mg+R?Z+0efNP@RXMrB5a(BMX`M%Vw3#mR)CNQ@6-2?K3Vv!e~7g(F$grVlWxofE{^I;T?dLbTEwKB^9ll9lTxGA(IX&OS1ourzJg1HK zF?$s=li$uB?4+LIM3o1C(rj#Rmx-cJKuzE>rF1kt7nA1+}~stGuO*^ z6NJ8Xr0*}eG7=fMR=%3507DlO;!J(D4PqZFo6TFv8CF2W>iE9+tHc}^w!Y|JR4Pen z6^(b=lCjjtc`}W$=FBW?DNNO|DZ}B&0R^#)q2oJwL%7K7bsll=RjDa0L3I2C+JFY} zL%OVJ)5sAw-vmYZ;TtR`4We`K9va< z5A!c`WogTri>i!#zzk6Nf}3yWAUXPLgkx6zJ-=d7l5CLdnvt!Vk*%J&!>o~u<#6tv zdZ|QD!jClyRGrx|$?&2d)`y9mY<-;x@NLU_H&m(zY6lOu^sZ4i%>D{cwrO=1XaLiG=n@Nhc;!he6)q{9{9C;`8J|pjg zbj-rjLA{V7nM6IJz9}_&_u89U1tA~Bk;JP+l*!$Pa^{`Ea+bXoEyK~1$&TfO*E-tw ze*;jq;^bbdb-HZ97bLX5C}Y>EYMRLPukSXp{8RO(Xmliis?Qm{QAc zOK;Vne;X?*G2igr^U1CraUzLSP63@?qXJE`BAdbWLUNR8`ZSKbF{8t)N2x}h21u0w zH-B$vw=YjuK}1U-Z$lA_65TbipH7hi?kB`4ZuSEemY8skGT$5()S91MC)w2XbY%pn z#3@duC?8paWzLVAyh?IrL3i#aO|{S>pp$TgcOOCBU0#a_(> zr8?P9DZDQ5Ihu^&sMSnZ;`872L*z<-T5Bhgq(~J?%+=5>Bb<0*o2Zp1)3ut-4(K}4 zKH78?ETqI!RV7KMUzJP&3jG)N1l_^vg9Y zXRX{Pa0ejupcLRQUGCAXgI%zN}%e ztw>icB~ZJ0Ok5HQ7yUSNrh2MS;)+XuPe~X^t3IPO`RS}SCnEKVZh~^qcLBA7+2HbOR|SgwA-*TW{fl73ScK_ z&(Y+!ZdW3E$ZoLWSVGk|3&jac0+7Oo9FSGkn!0m7eL$n$56Ytq+P~jj-dg$MPr6HYNURr ze6taf42_C&E+zd!98qc*P@TbYumxC-Q!hoc^rvCDv=s>21Lz@tl1B6~GbWHf{+(aw z5Zvf~K+ZD5X^9oZtz&yt{StSHeQ_ycjIKHyH^$VDu|Tj}#{s!S`CuF^CdjmV8Fcro z=Xp*G7ddlO0+FO23VBUtSaye(<&C3amXsHy4Qm%5zrwPkG5})ii{syf;)H-`^vQ!s zgO0S-u@rhcs1uaaduWjKe7E0Bw%>uWonS31?sEexE`91A6C{&6tI+nS+ciJNv#whj zVb51v@2$YDp}sR;%C)C$#Cw=q*F^s7GsnWh`d!UehXDjyCE~q1n8}-`!<5&)Nxz$% zr!5iRm^1H3mb=j$->{I*b3VYJI_6^Iwj;ys`9;^mWZdUJnEXBqFvfj2%I=%Ve!$Lt zDj56kw6s5X;`KiNWX)J^nR5Ty=$MWWo7lzcVT&Co$L^uv2Thm=*8SsY@_s(qW%h~+ zLj;Q5RJiS8)1sFllZ5e zlOAXY4wNgoc~cQ+1&|f&c3bAJ*Ix?4;%wGBNovScpc()nt2bt*3pn%`I3uN_5hh8{ zX#Y}mK+*w=K}GX*`WsyI=5xO`S~N0Z+fp79&Vw0Tsro>KgpCYa`^Z(lzLjD||Jq26 z8&{tJbFOwf+Qm%@Ue3AP4@YwjDjgu!mFs=6tdoDau>YTTcY0UMN&dw9g zZw+O9ZZYJ>iq(lv3wal!P8B~{>mw)mi!D-qUW4sTu)oh&_(vB92G!PLbj<11rprrl zr(to{*8V7w{Fb0jQX4)IV8aIG9cM&G3Gb^oWi4)laN_k;Q0TZIyJkhMl38<&=-MK? zqDOavJ6bkE?XWnc9it;~J6Y4$SBe*k?GF=6x6QH41FSa2_v`r|p{!^jD$v_ho zE?Iv1r-Gle96c&rzD;$|Ui08Rlax_+)c_Juo51qc;ER5Fy*0H4c?bxC5d^ADluial z*}7r1tFOW$pMyZV?4WJ4;oZIAUA*C4+~K`iAo&A4?kki|nziF{eUv8r6*uJ=09WhlD$?gY*E)!-X1geXSjtZdJ#b z(~xa0{0Fnt{J8$&VTySJSKP_2O>cwmJ3%YH6Q(QInZ@U28QBAYES+&Y|1MAsV3G3f z*A2?MCeYRdmiBvJQqOtay9aaOLFE_N883jT^uf@$qd%K$xvxa|KG6{kecoB~y%K*p zkrr7OSbIU~eAxSVIRyAz<~(i>-7SRtoAg?Pag%z_0AMaK7d{%?sGYV038<|wkN-9) z*UK1L_GD8G(yOX|i`;%N&vBr6bUia-C*I)FJ=pNARXeO9ee}~Gxh(pzUQ=dQ+!C3f z7)UGcSH2?$$YqXl{TKE`%oE<43IW_iOob9z-T&;;J zJ%4=$8sRlzgJW9lkxFTEbK{Sb{btDwwSmH~uGRWj`Vn7#X*hmo!kXu#7vPp$9&Ajw zz@`iba)%b819x$!zl`x9G7U|h;xIEMcke+;(Dd+fg zh(_P=c(>*9G(xJA;PZ|#!~#m(t1F~na!>Ye$tV~xnpOBaX+q#$o%_<3w(v8B=I{2z z9ggh&{Ycswf#(tD$>z+BxN>dZUXJ}NC!A*|Xpz@0j`L)D=HG*q8Gi5gl{3%+hoyv4 z(&os~PTI{1!_c~ycPrNsHGi3Vb=uxpKdX%cU(B=gljKAT@cPfJMVvzO+_8QRe)>g7 zktq1nn5YLRyy+j=Tyl_WOznILDVAC?-EFGCfC5T-guLC@`EUp%q}_m~Tx;0Mv{on0 zW5U$HEiJ{?Q4XW0B#xsTl!{Yp7LhqeWAAlP5I4t&9m)T`T#-Cm&Cx8XU7OlmbHoA% zHxXI8LsrQ?mg_LIG3MK2s8XoTu}L!GLLq6PT#7MYt_Ex>iXxyOZVYF5=W_d!4><@V zMji+X550$vvdWq(#L-OA{Hm+H^B<|h{OT9k;o(kouf4bEoKnz!Hat8W85-HHyz@(e zK1oeZZgq6lM;^>D=i|0IHy2XQ(zNW_6l3T8W)L9|EwHAhr|-bW|9$X}owUUtrfELk zay-lyeRh8sA$~=0XT|ptew2nl%#(yBIsBfo$3utZO0OjPdH&scwdap3DYFR(4e)fr z#-2X=U4=aTwtvNaeTjLARrYxu!e=l=x?An1K=y?OLO_v4@1}YUFxld&H>ndeVyW>K zHBxi;$uq(!!+=!t7f6U{5Q z?RJRhO*m~ck;~RYHb+BtP2Xx#t98bCZCr^p1<=dU+6Kb=tolxz55`WsBj2*M3mOlh zGPtj0XrErT!kmSzHHd;orrux~B7SLIpLS@D$VyGjEkI-@#9)|~X+AnT*invjO`ASt z&s&F{{=VqFw>9W=AMV>CIn7$x-Wahp=yD&zX!z5%Su20vnQ&*XMWvX_gQ`e z_AiG#cRPOfb>7eBzUeHl+jw_1lP{lg?h{|S&wF^*)_0^?VCyfdw{Ny(K7+0MlgAY& zS@{LUgcE$A4YOMmXSQ0`nkXF{!k){@F;P$-cq-3)IZsN37wH~K+%U|Tp|AmC{ia4Z znht0%`Q)2e6}s8?(X?|Z2(jK!t6mlRC7Z@m4N=P8g4<@;nGoqmAg7U+IGWiVf8A6f z5&toN+9KtaHBCV#UV=G`95>80DpEOU?t>9mp2$YXR>=l$da_tVQ7k1A6_=b!6q&Vy zm<}p6rnFlA2gg+ZGK>$>NCTU6I++%N;#5MR$@G{?cvFt1c|i=YKdc8EY-)X51=575 zJb3tNsrmfeiY@HFr&I#PTp}H91ODv4+o>Tai+Vq}t64e;Rm)j3bGD4Bxgk%`-NV-x z5qH^19X%u{v)(JUH7KZcOkQ~+Z)x%A1r$Vc@1N#81jR3T5zW6Ru&`ayC8%8QjLgARVP0QgE-2Tg^ zeO3p3C!8C%3*QA4Lxu6|LI_6A26tGG`r5>dwPblT7*r}z+4%LyNn$o#T-Cy|G>Kg~ zl!^&L@;~QH2G3g$9Mx^!q&j#geDD=ujzKFPi=^|YS$h2bXtO~4mX{d!n43tm4xNrW z;(gmh_?XdB#Tj%5>EI76=S_3efs!!1+WL9}3M!ND#D^()F0pHERD16!9R7cUI2hXv*D%vhNR;mwog54Q0Oo z<<3jhe-Gz~9ce`&_#nRd<1(y}x2_}E6i+9v)o4zpo+PPIC0OVkn? zrKben%5oUG>Dem(A5B*s(`MgAH^y)n?(XgmD-3sccX#(O+}(A!yA)?wi!*GvySv-h z_m3}q(zI#Pq)pCq@9*4m&v~}@gn7oOEW2>2Bw)HG{^Qk{ns)dpqOwx|BLqzZH&Tpv z#ZiqgOh8Xlo4<2m)|ZX%0=eENY0PVe*6Q@(&p!?6>IB>826(}k?<|ydb}{V=lbq?o+~f*$T}YYO3q%8 z>^Cf}PEelaZ7KJs67m+sm=t&7)0NQ0=hWcowEJ<01}pZQ#bKOnwDoi#5D(UsKHMZ5 za+cx`Y!m;Qk1K*I${UKxogbqQXNtpF{SL>SA2vY%+Es0Mbib_k#i};IizYR_XUO=% z#%Mwqjti!jsDCEc@}uYO4O^=-#-V5nLRM@$z)gDQapLJMXqRzjDSM^{M>NrATE z6_<)cRpFYemmn{Qrc$Y(Tyl#N6a2xLMoO%BNK>WTi^iXOufPBf9@`r{xKXJ zeSGA-nQda6V5tXo4=e=iTRx7k1SIypPJOU^Jo9{Dv2@=iOzVXD0puweDPZ58%k_F; z`AA7&-FVtJ&ZrMDl!`xP(I?A*XtAz+a4p;;j+HW}x6m4wr{Bm9~@j^VQ2;)ZiW`MoL!(lOlzTLeAu8Gx0w=9^3WWw@*j8=1mz+ zZWa~3YYKwQl3>Q?JiC>ndUx|x2VfH-W*$nJ$tCUD(n)UR;APdLfVyb<)ZuQ$2+
wZokP}6(M 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 z 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 literal 338527 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 z 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 {T z$Q#WYc+O8f&~GQznErXsHB1$!XRQiSWb0I^xLl)4%RMC@w)y1p8;wahN)hqGpxQD- zs5NWvOG7%4LzdvYOpx-RM;0i7DY77}^gl7`doH<2*_}K*6HJF4K-&+rw)lTB7iP4` zND|~%8lELmlD&I!`K38TtqA8 zZzOM8ftv{4yn#V^x(hCOk4Wow9(laq6B7RDSNK2I{Yc;`sd3 zSSopnz4SO3KK;nhkpvGW$EQ|X0ZS9KN#V5!A02!0ADdNe{VRgtb0%V?_`xwazf>T+F* z2CK%%4tYj2t5oRxn#TeO!Ohxr40ZcrD7{w*Y>L?r_Y|T! zSfF(IX4UD?h7RZJd)%)Jh`+Z{KZ4_)#%MQ4K86ma;ZYcGr$&iElCalb%K|K_(^uT} zt&I=RiWBvNUUe*67MoI_AJi(BIE5sG0R-bop~#w1H20`06&r-%n7Q=nN^%EbBRS1k zec60J)+GJ5W`*IY2z(@`I~SqZ+9cIk!6h@U?Plr3@;ztY`AHsm!wU$Bf^N|OL{O68 z=0y&g#h87neA{}oP*>Eg6J;u@UXO{l>W>Y8S?Z;LCOrLTaFE>IgEksScx?@%`WM?u z%enOGOSuw1xe`(-1fEZ6uCE z9|>_JCWZSuB^+V1uT-1~Q(G2l&X@m?1MFV<-=E`0SFYhkxBQC1DpILv28 zCv2ZaP(7e=LB8j7cI@8=b*b*%a8o=KHr{4%r_;?^#QUdOX84tQ`xcoW90J6Qyje^+ zQZPykkki7al+4dLI*J0;HjLf$apFpf@R&5N$Y!Pb0onfu22gtBG744QVq>zW{)kQH|>MA*@&O70Kdh2AFCTW<3o;>t+K0|hWeW3k%g#Wi<^vf$M zyIHyfCp0sglvQChWyLB&x?GBPP}!O~6=LSArNLFB=zmW`oIvwzPz2BhN#&}&f4ANC z;!8e%iY?n#f6VEDAQ5(!q8_d^=1>*OYF1d7RgZ{BGv+e@+3MN=goNsj1p|SIevP`( zoNRer5gN?x@b*9RY%w|%aTcf20|`!V0ReeI$K37fi`kiJPqcgE#OuAllZbr@n@bak z>Pkq#@n|u4&qyG8|Krf-lmhH{*3tFs-SLEwk92jFdLi0jZe1m^2asViOcl>+b4u1m z4Mly`h5_G?BYNet^5wIN<+?m%0Ad=iapP9y+}WXo(0 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

ZQC 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

Up%dxERsJ=YPs^Tl%?taik$lXXk5*>sg;h)1## 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 Date: Mon, 1 Apr 2013 16:27:49 -0700 Subject: [PATCH 004/544] simplify and unify handling of externals --- src/jsifier.js | 154 +++++++++++++++++++++---------------------------- 1 file changed, 66 insertions(+), 88 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 69d9842a3b704..4e86b78d565b5 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -266,105 +266,83 @@ function JSify(data, functionsOnly, givenFunctions) { item.ctors.map(function(ctor) { return ' { func: function() { ' + ctor + '() } }' }).join(',\n') + '\n]);\n'; return ret; + } + + var constant = null; + var allocator = (BUILD_AS_SHARED_LIB && !item.external) ? 'ALLOC_NORMAL' : 'ALLOC_STATIC'; + var index = null; + if (item.external && BUILD_AS_SHARED_LIB) { + // External variables in shared libraries should not be declared as + // they would shadow similarly-named globals in the parent. + item.JS = ''; } else { - var constant = null; - var allocator = (BUILD_AS_SHARED_LIB && !item.external) ? 'ALLOC_NORMAL' : 'ALLOC_STATIC'; - var index = null; - if (item.external && BUILD_AS_SHARED_LIB) { - // External variables in shared libraries should not be declared as - // they would shadow similarly-named globals in the parent. - item.JS = ''; + item.JS = makeGlobalDef(item.ident); + } + + if (!NAMED_GLOBALS && isIndexableGlobal(item.ident)) { + index = makeGlobalUse(item.ident); // index !== null indicates we are indexing this + allocator = 'ALLOC_NONE'; + } + if (item.external) { + if (Runtime.isNumberType(item.type) || isPointerType(item.type)) { + constant = zeros(Runtime.getNativeFieldSize(item.type)); } else { - item.JS = makeGlobalDef(item.ident); + constant = makeEmptyStruct(item.type); } - - if (item.external && !ASM_JS) { // ASM_JS considers externs to be globals - // Import external global variables from the library if available. - var shortident = item.ident.slice(1); - if (LibraryManager.library[shortident] && - LibraryManager.library[shortident].length && - !BUILD_AS_SHARED_LIB) { - if (addedLibraryItems[shortident]) return ret; - var val = LibraryManager.library[shortident]; - var padding; - if (Runtime.isNumberType(item.type) || isPointerType(item.type)) { - padding = [item.type].concat(zeros(Runtime.getNativeFieldSize(item.type)-1)); - } else { - padding = makeEmptyStruct(item.type); - } - var padded = val.concat(padding.slice(val.length)); - var js = item.ident + '=' + makePointer(padded, null, allocator, item.type, index) + ';' - if (LibraryManager.library[shortident + '__postset']) { - js += '\n' + LibraryManager.library[shortident + '__postset']; - } + constant = JSON.stringify(constant); + } else { + constant = parseConst(item.value, item.type, item.ident); + } + if (typeof constant === 'string' && constant[0] != '[') { + constant = [constant]; // A single item. We may need a postset for it. + } + if (typeof constant === 'object') { + // This is a flattened object. We need to find its idents, so they can be assigned to later + constant.forEach(function(value, i) { + if (needsPostSet(value)) { // ident, or expression containing an ident ret.push({ intertype: 'GlobalVariablePostSet', - JS: js + JS: makeSetValue(makeGlobalUse(item.ident), i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors }); + constant[i] = '0'; } - return ret; - } else { - if (!NAMED_GLOBALS && isIndexableGlobal(item.ident)) { - index = makeGlobalUse(item.ident); // index !== null indicates we are indexing this - allocator = 'ALLOC_NONE'; - } - if (item.external) { - assert(ASM_JS); - if (Runtime.isNumberType(item.type) || isPointerType(item.type)) { - constant = zeros(Runtime.getNativeFieldSize(item.type)); - } else { - constant = makeEmptyStruct(item.type); - } - constant = JSON.stringify(constant); - } else { - constant = parseConst(item.value, item.type, item.ident); - } - if (typeof constant === 'string' && constant[0] != '[') { - constant = [constant]; // A single item. We may need a postset for it. - } - if (typeof constant === 'object') { - // This is a flattened object. We need to find its idents, so they can be assigned to later - constant.forEach(function(value, i) { - if (needsPostSet(value)) { // ident, or expression containing an ident - ret.push({ - intertype: 'GlobalVariablePostSet', - JS: makeSetValue(makeGlobalUse(item.ident), i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors - }); - constant[i] = '0'; - } - }); - } - // NOTE: This is the only place that could potentially create static - // allocations in a shared library. - constant = makePointer(constant, null, allocator, item.type, index); - var js; + }); + } - js = (index !== null ? '' : item.ident + '=') + constant + ';'; // \n Module.print("' + item.ident + ' :" + ' + makeGlobalUse(item.ident) + ');'; + if (item.external && BUILD_AS_SHARED_LIB) { + // External variables in shared libraries should not be declared as + // they would shadow similarly-named globals in the parent, so do nothing here. + return ret; + } - // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations - if (item.ident.substr(0, 5) == '__ZTV') { - if (index !== null) { - index = getFastValue(index, '+', Runtime.alignMemory(calcAllocatedSize(Variables.globals[item.ident].type))); - } - js += '\n' + makePointer([0], null, allocator, ['void*'], index) + ';'; - } - if (!ASM_JS && (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS))) { - js += '\nModule["' + item.ident + '"] = ' + item.ident + ';'; - } - if (BUILD_AS_SHARED_LIB == 2 && !item.private_) { - // TODO: make the assert conditional on ASSERTIONS - js += 'if (globalScope) { assert(!globalScope["' + item.ident + '"]); globalScope["' + item.ident + '"] = ' + item.ident + ' }'; - } - if (item.external && !NAMED_GLOBALS) { - assert(ASM_JS); - js = 'var ' + item.ident + ' = ' + js; // force an explicit naming, even if unnamed globals, for asm forwarding - } - return ret.concat({ - intertype: 'GlobalVariable', - JS: js, - }); + // NOTE: This is the only place that could potentially create static + // allocations in a shared library. + constant = makePointer(constant, null, allocator, item.type, index); + var js; + + js = (index !== null ? '' : item.ident + '=') + constant + ';'; // \n Module.print("' + item.ident + ' :" + ' + makeGlobalUse(item.ident) + ');'; + + // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations + if (item.ident.substr(0, 5) == '__ZTV') { + if (index !== null) { + index = getFastValue(index, '+', Runtime.alignMemory(calcAllocatedSize(Variables.globals[item.ident].type))); } + js += '\n' + makePointer([0], null, allocator, ['void*'], index) + ';'; + } + if (!ASM_JS && (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS))) { + js += '\nModule["' + item.ident + '"] = ' + item.ident + ';'; } + if (BUILD_AS_SHARED_LIB == 2 && !item.private_) { + // TODO: make the assert conditional on ASSERTIONS + js += 'if (globalScope) { assert(!globalScope["' + item.ident + '"]); globalScope["' + item.ident + '"] = ' + item.ident + ' }'; + } + if (item.external && !NAMED_GLOBALS) { + js = 'var ' + item.ident + ' = ' + js; // force an explicit naming, even if unnamed globals, for asm forwarding + } + return ret.concat({ + intertype: 'GlobalVariable', + JS: js, + }); } }); From 8ae983c6c1965a2d64f71aa28d990682b9a36347 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 1 Apr 2013 17:09:54 -0700 Subject: [PATCH 005/544] fix externals handling: non-library elements need nothing at all, so runtime linking works --- src/jsifier.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 4e86b78d565b5..c9476647bec50 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -309,10 +309,12 @@ function JSify(data, functionsOnly, givenFunctions) { }); } - if (item.external && BUILD_AS_SHARED_LIB) { + if (item.external) { // External variables in shared libraries should not be declared as // they would shadow similarly-named globals in the parent, so do nothing here. - return ret; + if (BUILD_AS_SHARED_LIB) return ret; + // Library items need us to emit something, but everything else requires nothing. + if (!LibraryManager.library[item.ident.slice(1)]) return ret; } // NOTE: This is the only place that could potentially create static From e6f1f4cc81c84ee5d3db49cd5f6a1b36a59ba291 Mon Sep 17 00:00:00 2001 From: "Felix H. Dahlke" Date: Tue, 2 Apr 2013 05:32:49 +0200 Subject: [PATCH 006/544] Restore old zoomSurface test, add new tests for rotozoomSurface --- tests/sdl_rotozoom.c | 8 +++++--- tests/sdl_rotozoom.png | Bin 351517 -> 360054 bytes 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/sdl_rotozoom.c b/tests/sdl_rotozoom.c index 4bca294af006b..b3970f6cdde78 100644 --- a/tests/sdl_rotozoom.c +++ b/tests/sdl_rotozoom.c @@ -7,12 +7,12 @@ #endif SDL_Surface *screen; -SDL_Surface *sprite[4]; +SDL_Surface *sprite[6]; void mainloop() { int i; SDL_Rect rect = { 0, 0, 100, 100 }; - for (i = 0; i < 4; i++) { + for (i = 0; i < 6; i++) { rect.x = i & 1 ? 200 : 0; rect.y = i & 2 ? 200 : 0; SDL_BlitSurface(sprite[i], 0, screen, &rect); @@ -29,7 +29,9 @@ int main(int argc, char **argv) { sprite[1] = SDL_CreateRGBSurface(SDL_SWSURFACE, 100, 100, 32, 0xFF000000, 0xFF0000, 0xFF00, 0xFF); SDL_FillRect(sprite[1], 0, 0xA0A0A0A0); sprite[2] = zoomSurface(sprite[0], 0.5, 0.5, SMOOTHING_ON); - sprite[3] = rotozoomSurface(sprite[1], 45, 0.5, SMOOTHING_ON); + sprite[3] = zoomSurface(sprite[1], 0.5, 0.5, SMOOTHING_ON); + sprite[4] = rotozoomSurface(sprite[0], -20, 0.3, SMOOTHING_ON); + sprite[5] = rotozoomSurface(sprite[1], 45, 0.5, SMOOTHING_ON); mainloop(); diff --git a/tests/sdl_rotozoom.png b/tests/sdl_rotozoom.png index d78a5ea47de6cb3a37b60a88b16479fc1d3a283d..3ca8da70e19637bc8a99d3d8df4e02674e0769ec 100644 GIT binary patch literal 360054 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

^g}L)q}(pSFetjFkjs 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 z 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\md7@B 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 &n> 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

wZokP}6(M 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 z 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 From e2d60d14e9c0930ab44e4d4d096fe3a2cd92ea46 Mon Sep 17 00:00:00 2001 From: Alexander Gladysh Date: Wed, 3 Apr 2013 18:34:49 +0400 Subject: [PATCH 007/544] Add ability to use versioned clang libraries Just like LLVM_ADD_VERSION. --- tools/shared.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/shared.py b/tools/shared.py index 55224ebbe294b..4501faa96f902 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -254,6 +254,7 @@ def check_sanity(force=False): # Tools/paths LLVM_ADD_VERSION = os.getenv('LLVM_ADD_VERSION') +CLANG_ADD_VERSION = os.getenv('CLANG_ADD_VERSION') # Some distributions ship with multiple llvm versions so they add # the version to the binaries, cope with that @@ -263,8 +264,16 @@ def build_llvm_tool_path(tool): else: return os.path.join(LLVM_ROOT, tool) -CLANG_CC=os.path.expanduser(os.path.join(LLVM_ROOT, 'clang')) -CLANG_CPP=os.path.expanduser(os.path.join(LLVM_ROOT, 'clang++')) +# Some distributions ship with multiple clang versions so they add +# the version to the binaries, cope with that +def build_clang_tool_path(tool): + if CLANG_ADD_VERSION: + return os.path.join(LLVM_ROOT, tool + "-" + CLANG_ADD_VERSION) + else: + return os.path.join(LLVM_ROOT, tool) + +CLANG_CC=os.path.expanduser(build_clang_tool_path('clang')) +CLANG_CPP=os.path.expanduser(build_clang_tool_path('clang++')) CLANG=CLANG_CPP LLVM_LINK=build_llvm_tool_path('llvm-link') LLVM_AR=build_llvm_tool_path('llvm-ar') From 1e30c181f04612e8be2dbcea8ae67f4698c1b0bc Mon Sep 17 00:00:00 2001 From: Alexander Gladysh Date: Wed, 3 Apr 2013 23:32:55 +0400 Subject: [PATCH 008/544] added myself to the AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 0fa41dd21554e..bbbca339f9c02 100644 --- a/AUTHORS +++ b/AUTHORS @@ -55,4 +55,5 @@ a license to everyone to use it as detailed in LICENSE.) * Tobias Doerffel * Martin von Gagern * Ting-Yuan Huang +* Alexander Gladysh From ecb57d53441c7c9670173ae4d2d094ab7b606665 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 3 Apr 2013 17:47:54 -0700 Subject: [PATCH 009/544] bump MAX_NAMES --- tools/js_optimizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index 1f1c1354e7154..4d37408c48a7d 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -34,7 +34,7 @@ def __init__(self, js, js_engine): # Create list of valid short names - MAX_NAMES = 60000 + MAX_NAMES = 80000 INVALID_2 = set(['do', 'if', 'in']) INVALID_3 = set(['for', 'new', 'try', 'var', 'env']) From 927355084b711b8aaf54668ab791a4693cf45aaf Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 3 Apr 2013 18:57:57 -0700 Subject: [PATCH 010/544] refactor/simplify constant generation --- src/jsifier.js | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index c9476647bec50..97a2518842a2e 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -231,12 +231,11 @@ function JSify(data, functionsOnly, givenFunctions) { if (value.intertype in PARSABLE_LLVM_FUNCTIONS) { return [finalizeLLVMFunctionCall(value)]; } else if (Runtime.isNumberType(type) || pointingLevels(type) >= 1) { - return makeGlobalUse(indexizeFunctions(parseNumerical(value.value), type)); + return [makeGlobalUse(indexizeFunctions(parseNumerical(value.value), type))]; } else if (value.intertype === 'emptystruct') { return makeEmptyStruct(type); } else if (value.intertype === 'string') { - return JSON.stringify(parseLLVMString(value.text)) + - ' /* ' + value.text.substr(0, 20).replace(/[*<>]/g, '_') + ' */'; // make string safe for inclusion in comment + return parseLLVMString(value.text); } else { return alignStruct(handleSegments(value.contents), type); } @@ -244,9 +243,7 @@ function JSify(data, functionsOnly, givenFunctions) { function parseConst(value, type, ident) { var constant = makeConst(value, type); - if (typeof constant === 'object') { - constant = flatten(constant).map(function(x) { return parseNumerical(x) }) - } + constant = flatten(constant).map(function(x) { return parseNumerical(x) }) return constant; } @@ -254,6 +251,7 @@ function JSify(data, functionsOnly, givenFunctions) { substrate.addActor('GlobalVariable', { processItem: function(item) { function needsPostSet(value) { + if (typeof value !== 'string') return false; return value[0] in UNDERSCORE_OPENPARENS || value.substr(0, 14) === 'CHECK_OVERFLOW' || value.substr(0, 6) === 'GLOBAL'; } @@ -289,25 +287,21 @@ function JSify(data, functionsOnly, givenFunctions) { } else { constant = makeEmptyStruct(item.type); } - constant = JSON.stringify(constant); } else { constant = parseConst(item.value, item.type, item.ident); } - if (typeof constant === 'string' && constant[0] != '[') { - constant = [constant]; // A single item. We may need a postset for it. - } - if (typeof constant === 'object') { - // This is a flattened object. We need to find its idents, so they can be assigned to later - constant.forEach(function(value, i) { - if (needsPostSet(value)) { // ident, or expression containing an ident - ret.push({ - intertype: 'GlobalVariablePostSet', - JS: makeSetValue(makeGlobalUse(item.ident), i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors - }); - constant[i] = '0'; - } - }); - } + assert(typeof constant === 'object');//, [typeof constant, JSON.stringify(constant), item.external]); + + // This is a flattened object. We need to find its idents, so they can be assigned to later + constant.forEach(function(value, i) { + if (needsPostSet(value)) { // ident, or expression containing an ident + ret.push({ + intertype: 'GlobalVariablePostSet', + JS: makeSetValue(makeGlobalUse(item.ident), i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors + }); + constant[i] = '0'; + } + }); if (item.external) { // External variables in shared libraries should not be declared as @@ -322,7 +316,7 @@ function JSify(data, functionsOnly, givenFunctions) { constant = makePointer(constant, null, allocator, item.type, index); var js; - js = (index !== null ? '' : item.ident + '=') + constant + ';'; // \n Module.print("' + item.ident + ' :" + ' + makeGlobalUse(item.ident) + ');'; + js = (index !== null ? '' : item.ident + '=') + constant + ';'; // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations if (item.ident.substr(0, 5) == '__ZTV') { From d43e5283a483e43d31dae1c8236f3499e4bbd577 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Apr 2013 16:24:14 +0700 Subject: [PATCH 011/544] Make get_configuration() a global. --- emscripten.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/emscripten.py b/emscripten.py index d41aaa2c61446..c6a08e6a6afaf 100755 --- a/emscripten.py +++ b/emscripten.py @@ -20,6 +20,15 @@ def path_from_root(*pathelems): """ return os.path.join(__rootpath__, *pathelems) +def get_configuration(): + if hasattr(get_configuration, 'configuration'): + return get_configuration.configuration + + from tools import shared + configuration = shared.Configuration(environ=os.environ) + get_configuration.configuration = configuration + return configuration + def scan(ll, settings): # blockaddress(@main, %23) blockaddrs = [] @@ -683,15 +692,6 @@ def _main(environ): else: relooper = None # use the cache - def get_configuration(): - if hasattr(get_configuration, 'configuration'): - return get_configuration.configuration - - from tools import shared - configuration = shared.Configuration(environ=os.environ) - get_configuration.configuration = configuration - return configuration - if keywords.temp_dir is None: temp_files = get_configuration().get_temp_files() else: From 83a401ae7b6180320d96e430bed7f0df8e9b03f1 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Thu, 4 Apr 2013 13:53:32 +0700 Subject: [PATCH 012/544] Work around problem with constexpr on Windows. This is for libcxx compilation on Windows and is a result of http://llvm.org/PR15651. See issue #1019 for more detail. --- tools/shared.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index c492ba49a29eb..5f3968a283340 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -374,10 +374,11 @@ def clean_temp(): # Force a simple, standard target as much as possible: target 32-bit linux, and disable various flags that hint at other platforms # -fno-ms-compatibility is passed, since on Windows, Clang enables a 'MS compatibility mode' by default, that disables char16_t and char32_t # to be MSVC header -compatible. This would cause build errors in libcxx file __config. +# -fno-delayed-template-parsing is needed on Windows due to http://llvm.org/PR15651 COMPILER_OPTS = COMPILER_OPTS + ['-m32', '-U__i386__', '-U__x86_64__', '-U__i386', '-U__x86_64', '-Ui386', '-Ux86_64', '-U__SSE__', '-U__SSE2__', '-U__MMX__', '-UX87_DOUBLE_ROUNDING', '-UHAVE_GCC_ASM_FOR_X87', '-DEMSCRIPTEN', '-U__STRICT_ANSI__', '-U__CYGWIN__', '-D__STDC__', '-Xclang', '-triple=i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno', - '-fno-ms-compatibility'] + '-fno-ms-compatibility', '-fno-delayed-template-parsing'] USE_EMSDK = not os.environ.get('EMMAKEN_NO_SDK') From 2fc27b89479caf051a7d032c4ca2e001baec2623 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Thu, 4 Apr 2013 16:11:57 +0700 Subject: [PATCH 013/544] Fix calling try_delete before importing it. Previously, the import of try_delete was after one of the blocks of code that called it, so it could result in an error at runtime. --- tools/shared.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/shared.py b/tools/shared.py index 5f3968a283340..61779c5979ed0 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -7,6 +7,9 @@ def listify(x): if type(x) is not list: return [x] return x +# Temp file utilities +from tempfiles import try_delete + # On Windows python suffers from a particularly nasty bug if python is spawning new processes while python itself is spawned from some other non-console process. # Use a custom replacement for Popen on Windows to avoid the "WindowsError: [Error 6] The handle is invalid" errors when emcc is driven through cmake or mingw32-make. # See http://bugs.python.org/issue3905 @@ -427,9 +430,6 @@ def clean_temp(): except: pass -# Temp file utilities -from tempfiles import try_delete - # Utilities def check_engine(engine): From 656bba1da1024c5b35936b0d375f27f14f8701e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Mon, 4 Mar 2013 13:11:44 +0100 Subject: [PATCH 014/544] * Added glfw headers and testcases. --- src/library_glfw.js | 406 ++++++++++++ src/modules.js | 2 +- system/include/GL/glfw.h | 518 +++++++++++++++ tests/glfw/Makefile | 56 ++ tests/glfw/boing.c | 615 ++++++++++++++++++ tests/glfw/bundle.sh | 46 ++ tests/glfw/gears.c | 373 +++++++++++ tests/glfw/getopt.c | 253 ++++++++ tests/glfw/getopt.h | 63 ++ tests/glfw/heightmap.c | 850 ++++++++++++++++++++++++ tests/glfw/listmodes.c | 48 ++ tests/glfw/mipmaps.c | 122 ++++ tests/glfw/mipmaps.tga | Bin 0 -> 66322 bytes tests/glfw/mtbench.c | 301 +++++++++ tests/glfw/mthello.c | 48 ++ tests/glfw/particles.c | 1152 +++++++++++++++++++++++++++++++++ tests/glfw/pong3d.c | 854 ++++++++++++++++++++++++ tests/glfw/pong3d_field.tga | Bin 0 -> 17816 bytes tests/glfw/pong3d_instr.tga | Bin 0 -> 21279 bytes tests/glfw/pong3d_menu.tga | Bin 0 -> 1835 bytes tests/glfw/pong3d_title.tga | Bin 0 -> 106516 bytes tests/glfw/pong3d_winner1.tga | Bin 0 -> 861 bytes tests/glfw/pong3d_winner2.tga | Bin 0 -> 891 bytes tests/glfw/splitview.c | 514 +++++++++++++++ tests/glfw/triangle.c | 94 +++ tests/glfw/wave.c | 399 ++++++++++++ 26 files changed, 6713 insertions(+), 1 deletion(-) create mode 100644 src/library_glfw.js create mode 100644 system/include/GL/glfw.h create mode 100644 tests/glfw/Makefile create mode 100644 tests/glfw/boing.c create mode 100644 tests/glfw/bundle.sh create mode 100644 tests/glfw/gears.c create mode 100644 tests/glfw/getopt.c create mode 100644 tests/glfw/getopt.h create mode 100644 tests/glfw/heightmap.c create mode 100644 tests/glfw/listmodes.c create mode 100644 tests/glfw/mipmaps.c create mode 100644 tests/glfw/mipmaps.tga create mode 100644 tests/glfw/mtbench.c create mode 100644 tests/glfw/mthello.c create mode 100644 tests/glfw/particles.c create mode 100644 tests/glfw/pong3d.c create mode 100644 tests/glfw/pong3d_field.tga create mode 100644 tests/glfw/pong3d_instr.tga create mode 100644 tests/glfw/pong3d_menu.tga create mode 100644 tests/glfw/pong3d_title.tga create mode 100644 tests/glfw/pong3d_winner1.tga create mode 100644 tests/glfw/pong3d_winner2.tga create mode 100644 tests/glfw/splitview.c create mode 100644 tests/glfw/triangle.c create mode 100644 tests/glfw/wave.c diff --git a/src/library_glfw.js b/src/library_glfw.js new file mode 100644 index 0000000000000..d171ffcbdd2f8 --- /dev/null +++ b/src/library_glfw.js @@ -0,0 +1,406 @@ + +var LibraryGLFW = { + $GLFW: { + initTime: null, + idleFunc: null, + displayFunc: null, + keyboardFunc: null, + keyboardUpFunc: null, + specialFunc: null, + specialUpFunc: null, + reshapeFunc: null, + motionFunc: null, + passiveMotionFunc: null, + mouseFunc: null, + lastX: 0, + lastY: 0, + buttons: 0, + modifiers: 0, + initWindowWidth: 256, + initWindowHeight: 256, + // Set when going fullscreen + windowX: 0, + windowY: 0, + windowWidth: 0, + windowHeight: 0, + + savePosition: function(event) { + /* TODO maybe loop here ala http://www.quirksmode.org/js/findpos.html */ + GLFW.lastX = event['clientX'] - Module['canvas'].offsetLeft; + GLFW.lastY = event['clientY'] - Module['canvas'].offsetTop; + }, + + saveModifiers: function(event) { +/* + GLFW.modifiers = 0; + if (event['shiftKey']) + GLFW.modifiers += 1; // GLFW_ACTIVE_SHIFT + if (event['ctrlKey']) + GLFW.modifiers += 2; // GLFW_ACTIVE_CTRL + if (event['altKey']) + GLFW.modifiers += 4; // GLFW_ACTIVE_ALT +*/ + }, + + onMousemove: function(event) { + /* Send motion event only if the motion changed, prevents + * spamming our app with uncessary callback call. It does happen in + * Chrome on Windows. + */ + var newX = event['clientX'] - Module['canvas'].offsetLeft; + var newY = event['clientY'] - Module['canvas'].offsetTop; + if (newX == GLFW.lastX && newY == GLFW.lastY) + return; + + GLFW.savePosition(event); +/* + if (GLFW.buttons == 0 && event.target == Module["canvas"] && GLFW.passiveMotionFunc) { + event.preventDefault(); + GLFW.saveModifiers(event); + Runtime.dynCall('vii', GLFW.passiveMotionFunc, [GLFW.lastX, GLFW.lastY]); + } else if (GLFW.buttons != 0 && GLFW.motionFunc) { + event.preventDefault(); + GLFW.saveModifiers(event); + Runtime.dynCall('vii', GLFW.motionFunc, [GLFW.lastX, GLFW.lastY]); + } +*/ + }, + + getSpecialKey: function(keycode) { + var key = null; +/* + switch (keycode) { + case 0x70 : //DOM_VK_F1 + key = 1 ;//GLUT_KEY_F1 + break; + case 0x71 : //DOM_VK_F2 + key = 2 ;//GLUT_KEY_F2 + break; + case 0x72 : //DOM_VK_F3 + key = 3 ;//GLUT_KEY_F3 + break; + case 0x73 : //DOM_VK_F4 + key = 4 ;//GLUT_KEY_F4 + break; + case 0x74 : //DOM_VK_F5 + key = 5 ;//GLUT_KEY_F5 + break; + case 0x75 : //DOM_VK_F6 + key = 6 ;//GLUT_KEY_F6 + break; + case 0x76 : //DOM_VK_F7 + key = 7 ;//GLUT_KEY_F7 + break; + case 0x77 : //DOM_VK_F8 + key = 8 ;//GLUT_KEY_F8 + break; + case 0x78 : //DOM_VK_F9 + key = 9 ;//GLUT_KEY_F9 + break; + case 0x79 : //DOM_VK_F10 + key = 10 ;//GLUT_KEY_F10 + break; + case 0x7a : //DOM_VK_F11 + key = 11 ;//GLUT_KEY_F11 + break; + case 0x7b : //DOM_VK_F12 + key = 12 ;//GLUT_KEY_F12 + break; + case 0x25 : //DOM_VK_LEFT + key = 100 ;//GLUT_KEY_LEFT + break; + case 0x26 : //DOM_VK_UP + key = 101 ;//GLUT_KEY_UP + break; + case 0x27 : //DOM_VK_RIGHT + key = 102 ;//GLUT_KEY_RIGHT + break; + case 0x28 : //DOM_VK_DOWN + key = 103 ;//GLUT_KEY_DOWN + break; + case 0x21 : //DOM_VK_PAGE_UP + key = 104 ;//GLUT_KEY_PAGE_UP + break; + case 0x22 : //DOM_VK_PAGE_DOWN + key = 105 ;//GLUT_KEY_PAGE_DOWN + break; + case 0x24 : //DOM_VK_HOME + key = 106 ;//GLUT_KEY_HOME + break; + case 0x23 : //DOM_VK_END + key = 107 ;//GLUT_KEY_END + break; + case 0x2d : //DOM_VK_INSERT + key = 108 ;//GLUT_KEY_INSERT + break; + case 16 : //DOM_VK_SHIFT + case 0x05 : //DOM_VK_LEFT_SHIFT + key = 112 ;//GLUT_KEY_SHIFT_L + break; + case 0x06 : //DOM_VK_RIGHT_SHIFT + key = 113 ;//GLUT_KEY_SHIFT_R + break; + case 17 : //DOM_VK_CONTROL + case 0x03 : //DOM_VK_LEFT_CONTROL + key = 114 ;//GLUT_KEY_CONTROL_L + break; + case 0x04 : //DOM_VK_RIGHT_CONTROL + key = 115 ;//GLUT_KEY_CONTROL_R + break; + case 18 : //DOM_VK_ALT + case 0x02 : //DOM_VK_LEFT_ALT + key = 116 ;//GLUT_KEY_ALT_L + break; + case 0x01 : //DOM_VK_RIGHT_ALT + key = 117 ;//GLUT_KEY_ALT_R + break; + }; +*/ + return key; + }, + + getASCIIKey: function(event) { + if (event['ctrlKey'] || event['altKey'] || event['metaKey']) return null; +/* + var keycode = event['keyCode']; + if (48 <= keycode && keycode <= 57) + return keycode; // numeric TODO handle shift? + if (65 <= keycode && keycode <= 90) + return event['shiftKey'] ? keycode : keycode + 32; + if (106 <= keycode && keycode <= 111) + return keycode - 106 + 42; // *,+-./ TODO handle shift? + + switch (keycode) { + case 27: // escape + case 32: // space + case 61: // equal + return keycode; + } + + var s = event['shiftKey']; + switch (keycode) { + case 186: return s ? 58 : 59; // colon / semi-colon + case 187: return s ? 43 : 61; // add / equal (these two may be wrong) + case 188: return s ? 60 : 44; // less-than / comma + case 189: return s ? 95 : 45; // dash + case 190: return s ? 62 : 46; // greater-than / period + case 191: return s ? 63 : 47; // forward slash + case 219: return s ? 123 : 91; // open bracket + case 220: return s ? 124 : 47; // back slash + case 221: return s ? 125 : 93; // close braket + case 222: return s ? 34 : 39; // single quote + } +*/ + return null; + }, + + onKeydown: function(event) { +/* + if (GLFW.specialFunc || GLFW.keyboardFunc) { + var key = GLFW.getSpecialKey(event['keyCode']); + if (key !== null) { + if( GLFW.specialFunc ) { + event.preventDefault(); + GLFW.saveModifiers(event); + Runtime.dynCall('viii', GLFW.specialFunc, [key, GLFW.lastX, GLFW.lastY]); + } + } + else + { + key = GLFW.getASCIIKey(event); + if( key !== null && GLFW.keyboardFunc ) { + event.preventDefault(); + GLFW.saveModifiers(event); + Runtime.dynCall('viii', GLFW.keyboardFunc, [key, GLFW.lastX, GLFW.lastY]); + } + } + } +*/ + }, + + onKeyup: function(event) { +/* + if (GLFW.specialUpFunc || GLFW.keyboardUpFunc) { + var key = GLFW.getSpecialKey(event['keyCode']); + if (key !== null) { + if(GLFW.specialUpFunc) { + event.preventDefault (); + GLFW.saveModifiers(event); + Runtime.dynCall('viii', GLFW.specialUpFunc, [key, GLFW.lastX, GLFW.lastY]); + } + } + else + { + key = GLFW.getASCIIKey(event); + if( key !== null && GLFW.keyboardUpFunc ) { + event.preventDefault (); + GLFW.saveModifiers(event); + Runtime.dynCall('viii', GLFW.keyboardUpFunc, [key, GLFW.lastX, GLFW.lastY]); + } + } + } +*/ + }, + + onMouseButtonDown: function(event){ +/* + GLFW.savePosition(event); + GLFW.buttons |= (1 << event['button']); + + if(event.target == Module["canvas"] && GLFW.mouseFunc){ + try { + event.target.setCapture(); + } catch (e) {} + event.preventDefault(); + GLFW.saveModifiers(event); + Runtime.dynCall('viiii', GLFW.mouseFunc, [event['button'], 0, GLFW.lastX, GLFW.lastY]); + } + }, + + onMouseButtonUp: function(event){ + GLFW.savePosition(event); + GLFW.buttons &= ~(1 << event['button']); + + if(GLFW.mouseFunc) { + event.preventDefault(); + GLFW.saveModifiers(event); + Runtime.dynCall('viiii', GLFW.mouseFunc, [event['button'], 1, GLFW.lastX, GLFW.lastY]); + } +*/ + }, + + // TODO add fullscreen API ala: + // http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/ + onFullScreenEventChange: function(event){ +/* + var width; + var height; + if (document["fullScreen"] || document["mozFullScreen"] || document["webkitIsFullScreen"]) { + width = screen["width"]; + height = screen["height"]; + } else { + width = GLFW.windowWidth; + height = GLFW.windowHeight; + // TODO set position + document.removeEventListener('fullscreenchange', GLFW.onFullScreenEventChange, true); + document.removeEventListener('mozfullscreenchange', GLFW.onFullScreenEventChange, true); + document.removeEventListener('webkitfullscreenchange', GLFW.onFullScreenEventChange, true); + } + Browser.setCanvasSize(width, height); + // Can't call _glfwReshapeWindow as that requests cancelling fullscreen. + if (GLFW.reshapeFunc) { + // console.log("GLFW.reshapeFunc (from FS): " + width + ", " + height); + Runtime.dynCall('vii', GLFW.reshapeFunc, [width, height]); + } + _glfwPostRedisplay(); +*/ + }, + + requestFullScreen: function() { + var RFS = Module["canvas"]['requestFullscreen'] || + Module["canvas"]['requestFullScreen'] || + Module["canvas"]['mozRequestFullScreen'] || + Module["canvas"]['webkitRequestFullScreen'] || + (function() {}); + RFS.apply(Module["canvas"], []); + }, + + cancelFullScreen: function() { + var CFS = document['exitFullscreen'] || + document['cancelFullScreen'] || + document['mozCancelFullScreen'] || + document['webkitCancelFullScreen'] || + (function() {}); + CFS.apply(document, []); + } + }, + + /* GLFW initialization, termination and version querying */ + glfwInit : function() { throw "glfwInit is not implemented yet."; }, + glfwTerminate : function() { throw "glfwTerminate is not implemented yet."; }, + glfwGetVersion : function( major, minor, rev ) { throw "glfwGetVersion is not implemented yet."; }, + + /* Window handling */ + glfwOpenWindow : function( width, height, redbits, greenbits, bluebits, alphabits, depthbits, stencilbits, mode ) { throw "glfwOpenWindow is not implemented yet."; }, + glfwOpenWindowHint : function( target, hint ) { throw "glfwOpenWindowHint is not implemented yet."; }, + glfwCloseWindow : function() { throw "glfwCloseWindow is not implemented yet."; }, + glfwSetWindowTitle : function( title ) { throw "glfwSetWindowTitle is not implemented yet."; }, + glfwGetWindowSize : function( width, height ) { throw "glfwGetWindowSize is not implemented yet."; }, + glfwSetWindowSize : function( width, height ) { throw "glfwSetWindowSize is not implemented yet."; }, + glfwSetWindowPos : function( x, y ) { throw "glfwSetWindowPos is not implemented yet."; }, + glfwIconifyWindow : function() { throw "glfwIconifyWindow is not implemented yet."; }, + glfwRestoreWindow : function() { throw "glfwRestoreWindow is not implemented yet."; }, + glfwSwapBuffers : function() { throw "glfwSwapBuffers is not implemented yet."; }, + glfwSwapInterval : function( interval ) { throw "glfwSwapInterval is not implemented yet."; }, + glfwGetWindowParam : function( param ) { throw "glfwGetWindowParam is not implemented yet."; }, + glfwSetWindowSizeCallback : function( cbfun ) { throw "glfwSetWindowSizeCallback is not implemented yet."; }, + glfwSetWindowCloseCallback : function( cbfun ) { throw "glfwSetWindowCloseCallback is not implemented yet."; }, + glfwSetWindowRefreshCallback : function( cbfun ) { throw "glfwSetWindowRefreshCallback is not implemented yet."; }, + + /* Video mode functions */ + glfwGetVideoModes : function( list, maxcount ) { throw "glfwGetVideoModes is not implemented yet."; }, + glfwGetDesktopMode : function( mode ) { throw "glfwGetDesktopMode is not implemented yet."; }, + + /* Input handling */ + glfwPollEvents : function() { throw "glfwPollEvents is not implemented yet."; }, + glfwWaitEvents : function() { throw "glfwWaitEvents is not implemented yet."; }, + glfwGetKey : function( key ) { throw "glfwGetKey is not implemented yet."; }, + glfwGetMouseButton : function( button ) { throw "glfwGetMouseButton is not implemented yet."; }, + glfwGetMousePos : function( xpos, ypos ) { throw "glfwGetMousePos is not implemented yet."; }, + glfwSetMousePos : function( xpos, ypos ) { throw "glfwSetMousePos is not implemented yet."; }, + glfwGetMouseWheel : function() { throw "glfwGetMouseWheel is not implemented yet."; }, + glfwSetMouseWheel : function( pos ) { throw "glfwSetMouseWheel is not implemented yet."; }, + glfwSetKeyCallback : function( cbfun ) { throw "glfwSetKeyCallback is not implemented yet."; }, + glfwSetCharCallback : function( cbfun ) { throw "glfwSetCharCallback is not implemented yet."; }, + glfwSetMouseButtonCallback : function( cbfun ) { throw "glfwSetMouseButtonCallback is not implemented yet."; }, + glfwSetMousePosCallback : function( cbfun ) { throw "glfwSetMousePosCallback is not implemented yet."; }, + glfwSetMouseWheelCallback : function( cbfun ) { throw "glfwSetMouseWheelCallback is not implemented yet."; }, + + /* Joystick input */ + glfwGetJoystickParam : function( joy, param ) { throw "glfwGetJoystickParam is not implemented yet."; }, + glfwGetJoystickPos : function( joy, pos, numaxes ) { throw "glfwGetJoystickPos is not implemented yet."; }, + glfwGetJoystickButtons : function( joy, buttons, numbuttons ) { throw "glfwGetJoystickButtons is not implemented yet."; }, + + /* Time */ + glfwGetTime : function() { throw "glfwGetTime is not implemented yet."; }, + glfwSetTime : function( time ) { throw "glfwSetTime is not implemented yet."; }, + glfwSleep : function( time ) { throw "glfwSleep is not implemented yet."; }, + + /* Extension support */ + glfwExtensionSupported : function( extension ) { throw " is not implemented yet."; }, + glfwGetProcAddress : function( procname ) { throw " is not implemented yet."; }, + glfwGetGLVersion : function( major, minor, rev ) { throw " is not implemented yet."; }, + + /* Threading support */ + glfwCreateThread : function( fun, arg ) { throw "glfwCreateThread is not implemented yet."; }, + glfwDestroyThread : function( ID ) { throw "glfwDestroyThread is not implemented yet."; }, + glfwWaitThread : function( ID, waitmode ) { throw "glfwWaitThread is not implemented yet."; }, + glfwGetThreadID : function() { throw "glfwGetThreadID is not implemented yet."; }, + glfwCreateMutex : function() { throw "glfwCreateMutex is not implemented yet."; }, + glfwDestroyMutex : function( mutex ) { throw "glfwDestroyMutex is not implemented yet."; }, + glfwLockMutex : function( mutex ) { throw "glfwLockMutex is not implemented yet."; }, + glfwUnlockMutex : function( mutex ) { throw "glfwUnlockMutex is not implemented yet."; }, + glfwCreateCond : function() { throw "glfwCreateCond is not implemented yet."; }, + glfwDestroyCond : function( cond ) { throw "glfwDestroyCond is not implemented yet."; }, + glfwWaitCond : function( cond, mutex, timeout ) { throw "glfwWaitCond is not implemented yet."; }, + glfwSignalCond : function( cond ) { throw "glfwSignalCond is not implemented yet."; }, + glfwBroadcastCond : function( cond ) { throw "glfwBroadcastCond is not implemented yet."; }, + glfwGetNumberOfProcessors : function() { throw "glfwGetNumberOfProcessors is not implemented yet."; }, + + /* Enable/disable functions */ + glfwEnable : function( token ) { throw "glfwEnable is not implemented yet."; }, + glfwDisable : function( token ) { throw "glfwDisable is not implemented yet."; }, + + /* Image/texture I/O support */ + glfwReadImage : function( name, img, flags ) { throw "glfwReadImage is not implemented yet."; }, + glfwReadMemoryImage : function( data, size, img, flags ) { throw "glfwReadMemoryImage is not implemented yet."; }, + glfwFreeImage : function( img ) { throw "glfwFreeImage is not implemented yet."; }, + glfwLoadTexture2D : function( name, flags ) { throw "glfwLoadTexture2D is not implemented yet."; }, + glfwLoadMemoryTexture2D : function( data, size, flags ) { throw "glfwLoadMemoryTexture2D is not implemented yet."; }, + glfwLoadTextureImage2D : function( img, flags ) { throw "glfwLoadTextureImage2D is not implemented yet."; }, + +}; + +autoAddDeps(LibraryGLFW, '$GLFW'); +mergeInto(LibraryManager.library, LibraryGLFW); + diff --git a/src/modules.js b/src/modules.js index bda8a605f6442..e28bff31bc8ab 100644 --- a/src/modules.js +++ b/src/modules.js @@ -374,7 +374,7 @@ var LibraryManager = { load: function() { if (this.library) return; - var libraries = ['library.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js'].concat(additionalLibraries); + var libraries = ['library.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js',.concat(additionalLibraries); for (var i = 0; i < libraries.length; i++) { eval(processMacros(preprocess(read(libraries[i])))); } diff --git a/system/include/GL/glfw.h b/system/include/GL/glfw.h new file mode 100644 index 0000000000000..e20552e47dd00 --- /dev/null +++ b/system/include/GL/glfw.h @@ -0,0 +1,518 @@ +/************************************************************************ + * GLFW - An OpenGL framework + * API version: 2.7 + * WWW: http://www.glfw.org/ + *------------------------------------------------------------------------ + * Copyright (c) 2002-2006 Marcus Geelnard + * Copyright (c) 2006-2010 Camilla Berglund + * + * 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. + * + *************************************************************************/ + +#ifndef __glfw_h_ +#define __glfw_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************************************************************* + * Global definitions + *************************************************************************/ + +/* We need a NULL pointer from time to time */ +#ifndef NULL + #ifdef __cplusplus + #define NULL 0 + #else + #define NULL ((void *)0) + #endif +#endif /* NULL */ + + +/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */ + +/* Please report any probles that you find with your compiler, which may + * be solved in this section! There are several compilers that I have not + * been able to test this file with yet. + * + * First: If we are we on Windows, we want a single define for it (_WIN32) + * (Note: For Cygwin the compiler flag -mwin32 should be used, but to + * make sure that things run smoothly for Cygwin users, we add __CYGWIN__ + * to the list of "valid Win32 identifiers", which removes the need for + * -mwin32) + */ +#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)) + #define _WIN32 +#endif /* _WIN32 */ + +/* In order for extension support to be portable, we need to define an + * OpenGL function call method. We use the keyword APIENTRY, which is + * defined for Win32. (Note: Windows also needs this for ) + */ +#ifndef APIENTRY + #ifdef _WIN32 + #define APIENTRY __stdcall + #else + #define APIENTRY + #endif + #define GL_APIENTRY_DEFINED +#endif /* APIENTRY */ + + +/* The following three defines are here solely to make some Windows-based + * files happy. Theoretically we could include , but + * it has the major drawback of severely polluting our namespace. + */ + +/* Under Windows, we need WINGDIAPI defined */ +#if !defined(WINGDIAPI) && defined(_WIN32) + #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__) + /* Microsoft Visual C++, Borland C++ Builder and Pelles C */ + #define WINGDIAPI __declspec(dllimport) + #elif defined(__LCC__) + /* LCC-Win32 */ + #define WINGDIAPI __stdcall + #else + /* Others (e.g. MinGW, Cygwin) */ + #define WINGDIAPI extern + #endif + #define GL_WINGDIAPI_DEFINED +#endif /* WINGDIAPI */ + +/* Some files also need CALLBACK defined */ +#if !defined(CALLBACK) && defined(_WIN32) + #if defined(_MSC_VER) + /* Microsoft Visual C++ */ + #if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) + #define CALLBACK __stdcall + #else + #define CALLBACK + #endif + #else + /* Other Windows compilers */ + #define CALLBACK __stdcall + #endif + #define GLU_CALLBACK_DEFINED +#endif /* CALLBACK */ + +/* Microsoft Visual C++, Borland C++ and Pelles C needs wchar_t */ +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__)) && !defined(_WCHAR_T_DEFINED) + typedef unsigned short wchar_t; + #define _WCHAR_T_DEFINED +#endif /* _WCHAR_T_DEFINED */ + + +/* ---------------- GLFW related system specific defines ----------------- */ + +#if defined(_WIN32) && defined(GLFW_BUILD_DLL) + + /* We are building a Win32 DLL */ + #define GLFWAPI __declspec(dllexport) + #define GLFWAPIENTRY __stdcall + #define GLFWCALL __stdcall + +#elif defined(_WIN32) && defined(GLFW_DLL) + + /* We are calling a Win32 DLL */ + #if defined(__LCC__) + #define GLFWAPI extern + #else + #define GLFWAPI __declspec(dllimport) + #endif + #define GLFWAPIENTRY __stdcall + #define GLFWCALL __stdcall + +#else + + /* We are either building/calling a static lib or we are non-win32 */ + #define GLFWAPIENTRY + #define GLFWAPI + #define GLFWCALL + +#endif + +/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ + +/* Include standard OpenGL headers: GLFW uses GL_FALSE/GL_TRUE, and it is + * convenient for the user to only have to include . This also + * solves the problem with Windows and needing some + * special defines which normally requires the user to include + * (which is not a nice solution for portable programs). + */ +#if defined(__APPLE_CC__) + #if defined(GLFW_INCLUDE_GL3) + #include + #else + #define GL_GLEXT_LEGACY + #include + #endif + #ifndef GLFW_NO_GLU + #include + #endif +#else + #if defined(GLFW_INCLUDE_GL3) + #include + #else + #include + #endif + #ifndef GLFW_NO_GLU + #include + #endif +#endif + + +/************************************************************************* + * GLFW version + *************************************************************************/ + +#define GLFW_VERSION_MAJOR 2 +#define GLFW_VERSION_MINOR 7 +#define GLFW_VERSION_REVISION 7 + + +/************************************************************************* + * Input handling definitions + *************************************************************************/ + +/* Key and button state/action definitions */ +#define GLFW_RELEASE 0 +#define GLFW_PRESS 1 + +/* Keyboard key definitions: 8-bit ISO-8859-1 (Latin 1) encoding is used + * for printable keys (such as A-Z, 0-9 etc), and values above 256 + * represent special (non-printable) keys (e.g. F1, Page Up etc). + */ +#define GLFW_KEY_UNKNOWN -1 +#define GLFW_KEY_SPACE 32 +#define GLFW_KEY_SPECIAL 256 +#define GLFW_KEY_ESC (GLFW_KEY_SPECIAL+1) +#define GLFW_KEY_F1 (GLFW_KEY_SPECIAL+2) +#define GLFW_KEY_F2 (GLFW_KEY_SPECIAL+3) +#define GLFW_KEY_F3 (GLFW_KEY_SPECIAL+4) +#define GLFW_KEY_F4 (GLFW_KEY_SPECIAL+5) +#define GLFW_KEY_F5 (GLFW_KEY_SPECIAL+6) +#define GLFW_KEY_F6 (GLFW_KEY_SPECIAL+7) +#define GLFW_KEY_F7 (GLFW_KEY_SPECIAL+8) +#define GLFW_KEY_F8 (GLFW_KEY_SPECIAL+9) +#define GLFW_KEY_F9 (GLFW_KEY_SPECIAL+10) +#define GLFW_KEY_F10 (GLFW_KEY_SPECIAL+11) +#define GLFW_KEY_F11 (GLFW_KEY_SPECIAL+12) +#define GLFW_KEY_F12 (GLFW_KEY_SPECIAL+13) +#define GLFW_KEY_F13 (GLFW_KEY_SPECIAL+14) +#define GLFW_KEY_F14 (GLFW_KEY_SPECIAL+15) +#define GLFW_KEY_F15 (GLFW_KEY_SPECIAL+16) +#define GLFW_KEY_F16 (GLFW_KEY_SPECIAL+17) +#define GLFW_KEY_F17 (GLFW_KEY_SPECIAL+18) +#define GLFW_KEY_F18 (GLFW_KEY_SPECIAL+19) +#define GLFW_KEY_F19 (GLFW_KEY_SPECIAL+20) +#define GLFW_KEY_F20 (GLFW_KEY_SPECIAL+21) +#define GLFW_KEY_F21 (GLFW_KEY_SPECIAL+22) +#define GLFW_KEY_F22 (GLFW_KEY_SPECIAL+23) +#define GLFW_KEY_F23 (GLFW_KEY_SPECIAL+24) +#define GLFW_KEY_F24 (GLFW_KEY_SPECIAL+25) +#define GLFW_KEY_F25 (GLFW_KEY_SPECIAL+26) +#define GLFW_KEY_UP (GLFW_KEY_SPECIAL+27) +#define GLFW_KEY_DOWN (GLFW_KEY_SPECIAL+28) +#define GLFW_KEY_LEFT (GLFW_KEY_SPECIAL+29) +#define GLFW_KEY_RIGHT (GLFW_KEY_SPECIAL+30) +#define GLFW_KEY_LSHIFT (GLFW_KEY_SPECIAL+31) +#define GLFW_KEY_RSHIFT (GLFW_KEY_SPECIAL+32) +#define GLFW_KEY_LCTRL (GLFW_KEY_SPECIAL+33) +#define GLFW_KEY_RCTRL (GLFW_KEY_SPECIAL+34) +#define GLFW_KEY_LALT (GLFW_KEY_SPECIAL+35) +#define GLFW_KEY_RALT (GLFW_KEY_SPECIAL+36) +#define GLFW_KEY_TAB (GLFW_KEY_SPECIAL+37) +#define GLFW_KEY_ENTER (GLFW_KEY_SPECIAL+38) +#define GLFW_KEY_BACKSPACE (GLFW_KEY_SPECIAL+39) +#define GLFW_KEY_INSERT (GLFW_KEY_SPECIAL+40) +#define GLFW_KEY_DEL (GLFW_KEY_SPECIAL+41) +#define GLFW_KEY_PAGEUP (GLFW_KEY_SPECIAL+42) +#define GLFW_KEY_PAGEDOWN (GLFW_KEY_SPECIAL+43) +#define GLFW_KEY_HOME (GLFW_KEY_SPECIAL+44) +#define GLFW_KEY_END (GLFW_KEY_SPECIAL+45) +#define GLFW_KEY_KP_0 (GLFW_KEY_SPECIAL+46) +#define GLFW_KEY_KP_1 (GLFW_KEY_SPECIAL+47) +#define GLFW_KEY_KP_2 (GLFW_KEY_SPECIAL+48) +#define GLFW_KEY_KP_3 (GLFW_KEY_SPECIAL+49) +#define GLFW_KEY_KP_4 (GLFW_KEY_SPECIAL+50) +#define GLFW_KEY_KP_5 (GLFW_KEY_SPECIAL+51) +#define GLFW_KEY_KP_6 (GLFW_KEY_SPECIAL+52) +#define GLFW_KEY_KP_7 (GLFW_KEY_SPECIAL+53) +#define GLFW_KEY_KP_8 (GLFW_KEY_SPECIAL+54) +#define GLFW_KEY_KP_9 (GLFW_KEY_SPECIAL+55) +#define GLFW_KEY_KP_DIVIDE (GLFW_KEY_SPECIAL+56) +#define GLFW_KEY_KP_MULTIPLY (GLFW_KEY_SPECIAL+57) +#define GLFW_KEY_KP_SUBTRACT (GLFW_KEY_SPECIAL+58) +#define GLFW_KEY_KP_ADD (GLFW_KEY_SPECIAL+59) +#define GLFW_KEY_KP_DECIMAL (GLFW_KEY_SPECIAL+60) +#define GLFW_KEY_KP_EQUAL (GLFW_KEY_SPECIAL+61) +#define GLFW_KEY_KP_ENTER (GLFW_KEY_SPECIAL+62) +#define GLFW_KEY_KP_NUM_LOCK (GLFW_KEY_SPECIAL+63) +#define GLFW_KEY_CAPS_LOCK (GLFW_KEY_SPECIAL+64) +#define GLFW_KEY_SCROLL_LOCK (GLFW_KEY_SPECIAL+65) +#define GLFW_KEY_PAUSE (GLFW_KEY_SPECIAL+66) +#define GLFW_KEY_LSUPER (GLFW_KEY_SPECIAL+67) +#define GLFW_KEY_RSUPER (GLFW_KEY_SPECIAL+68) +#define GLFW_KEY_MENU (GLFW_KEY_SPECIAL+69) +#define GLFW_KEY_LAST GLFW_KEY_MENU + +/* Mouse button definitions */ +#define GLFW_MOUSE_BUTTON_1 0 +#define GLFW_MOUSE_BUTTON_2 1 +#define GLFW_MOUSE_BUTTON_3 2 +#define GLFW_MOUSE_BUTTON_4 3 +#define GLFW_MOUSE_BUTTON_5 4 +#define GLFW_MOUSE_BUTTON_6 5 +#define GLFW_MOUSE_BUTTON_7 6 +#define GLFW_MOUSE_BUTTON_8 7 +#define GLFW_MOUSE_BUTTON_LAST GLFW_MOUSE_BUTTON_8 + +/* Mouse button aliases */ +#define GLFW_MOUSE_BUTTON_LEFT GLFW_MOUSE_BUTTON_1 +#define GLFW_MOUSE_BUTTON_RIGHT GLFW_MOUSE_BUTTON_2 +#define GLFW_MOUSE_BUTTON_MIDDLE GLFW_MOUSE_BUTTON_3 + + +/* Joystick identifiers */ +#define GLFW_JOYSTICK_1 0 +#define GLFW_JOYSTICK_2 1 +#define GLFW_JOYSTICK_3 2 +#define GLFW_JOYSTICK_4 3 +#define GLFW_JOYSTICK_5 4 +#define GLFW_JOYSTICK_6 5 +#define GLFW_JOYSTICK_7 6 +#define GLFW_JOYSTICK_8 7 +#define GLFW_JOYSTICK_9 8 +#define GLFW_JOYSTICK_10 9 +#define GLFW_JOYSTICK_11 10 +#define GLFW_JOYSTICK_12 11 +#define GLFW_JOYSTICK_13 12 +#define GLFW_JOYSTICK_14 13 +#define GLFW_JOYSTICK_15 14 +#define GLFW_JOYSTICK_16 15 +#define GLFW_JOYSTICK_LAST GLFW_JOYSTICK_16 + + +/************************************************************************* + * Other definitions + *************************************************************************/ + +/* glfwOpenWindow modes */ +#define GLFW_WINDOW 0x00010001 +#define GLFW_FULLSCREEN 0x00010002 + +/* glfwGetWindowParam tokens */ +#define GLFW_OPENED 0x00020001 +#define GLFW_ACTIVE 0x00020002 +#define GLFW_ICONIFIED 0x00020003 +#define GLFW_ACCELERATED 0x00020004 +#define GLFW_RED_BITS 0x00020005 +#define GLFW_GREEN_BITS 0x00020006 +#define GLFW_BLUE_BITS 0x00020007 +#define GLFW_ALPHA_BITS 0x00020008 +#define GLFW_DEPTH_BITS 0x00020009 +#define GLFW_STENCIL_BITS 0x0002000A + +/* The following constants are used for both glfwGetWindowParam + * and glfwOpenWindowHint + */ +#define GLFW_REFRESH_RATE 0x0002000B +#define GLFW_ACCUM_RED_BITS 0x0002000C +#define GLFW_ACCUM_GREEN_BITS 0x0002000D +#define GLFW_ACCUM_BLUE_BITS 0x0002000E +#define GLFW_ACCUM_ALPHA_BITS 0x0002000F +#define GLFW_AUX_BUFFERS 0x00020010 +#define GLFW_STEREO 0x00020011 +#define GLFW_WINDOW_NO_RESIZE 0x00020012 +#define GLFW_FSAA_SAMPLES 0x00020013 +#define GLFW_OPENGL_VERSION_MAJOR 0x00020014 +#define GLFW_OPENGL_VERSION_MINOR 0x00020015 +#define GLFW_OPENGL_FORWARD_COMPAT 0x00020016 +#define GLFW_OPENGL_DEBUG_CONTEXT 0x00020017 +#define GLFW_OPENGL_PROFILE 0x00020018 + +/* GLFW_OPENGL_PROFILE tokens */ +#define GLFW_OPENGL_CORE_PROFILE 0x00050001 +#define GLFW_OPENGL_COMPAT_PROFILE 0x00050002 + +/* glfwEnable/glfwDisable tokens */ +#define GLFW_MOUSE_CURSOR 0x00030001 +#define GLFW_STICKY_KEYS 0x00030002 +#define GLFW_STICKY_MOUSE_BUTTONS 0x00030003 +#define GLFW_SYSTEM_KEYS 0x00030004 +#define GLFW_KEY_REPEAT 0x00030005 +#define GLFW_AUTO_POLL_EVENTS 0x00030006 + +/* glfwWaitThread wait modes */ +#define GLFW_WAIT 0x00040001 +#define GLFW_NOWAIT 0x00040002 + +/* glfwGetJoystickParam tokens */ +#define GLFW_PRESENT 0x00050001 +#define GLFW_AXES 0x00050002 +#define GLFW_BUTTONS 0x00050003 + +/* glfwReadImage/glfwLoadTexture2D flags */ +#define GLFW_NO_RESCALE_BIT 0x00000001 /* Only for glfwReadImage */ +#define GLFW_ORIGIN_UL_BIT 0x00000002 +#define GLFW_BUILD_MIPMAPS_BIT 0x00000004 /* Only for glfwLoadTexture2D */ +#define GLFW_ALPHA_MAP_BIT 0x00000008 + +/* Time spans longer than this (seconds) are considered to be infinity */ +#define GLFW_INFINITY 100000.0 + + +/************************************************************************* + * Typedefs + *************************************************************************/ + +/* The video mode structure used by glfwGetVideoModes() */ +typedef struct { + int Width, Height; + int RedBits, BlueBits, GreenBits; +} GLFWvidmode; + +/* Image/texture information */ +typedef struct { + int Width, Height; + int Format; + int BytesPerPixel; + unsigned char *Data; +} GLFWimage; + +/* Thread ID */ +typedef int GLFWthread; + +/* Mutex object */ +typedef void * GLFWmutex; + +/* Condition variable object */ +typedef void * GLFWcond; + +/* Function pointer types */ +typedef void (GLFWCALL * GLFWwindowsizefun)(int,int); +typedef int (GLFWCALL * GLFWwindowclosefun)(void); +typedef void (GLFWCALL * GLFWwindowrefreshfun)(void); +typedef void (GLFWCALL * GLFWmousebuttonfun)(int,int); +typedef void (GLFWCALL * GLFWmouseposfun)(int,int); +typedef void (GLFWCALL * GLFWmousewheelfun)(int); +typedef void (GLFWCALL * GLFWkeyfun)(int,int); +typedef void (GLFWCALL * GLFWcharfun)(int,int); +typedef void (GLFWCALL * GLFWthreadfun)(void *); + + +/************************************************************************* + * Prototypes + *************************************************************************/ + +/* GLFW initialization, termination and version querying */ +GLFWAPI int GLFWAPIENTRY glfwInit( void ); +GLFWAPI void GLFWAPIENTRY glfwTerminate( void ); +GLFWAPI void GLFWAPIENTRY glfwGetVersion( int *major, int *minor, int *rev ); + +/* Window handling */ +GLFWAPI int GLFWAPIENTRY glfwOpenWindow( int width, int height, int redbits, int greenbits, int bluebits, int alphabits, int depthbits, int stencilbits, int mode ); +GLFWAPI void GLFWAPIENTRY glfwOpenWindowHint( int target, int hint ); +GLFWAPI void GLFWAPIENTRY glfwCloseWindow( void ); +GLFWAPI void GLFWAPIENTRY glfwSetWindowTitle( const char *title ); +GLFWAPI void GLFWAPIENTRY glfwGetWindowSize( int *width, int *height ); +GLFWAPI void GLFWAPIENTRY glfwSetWindowSize( int width, int height ); +GLFWAPI void GLFWAPIENTRY glfwSetWindowPos( int x, int y ); +GLFWAPI void GLFWAPIENTRY glfwIconifyWindow( void ); +GLFWAPI void GLFWAPIENTRY glfwRestoreWindow( void ); +GLFWAPI void GLFWAPIENTRY glfwSwapBuffers( void ); +GLFWAPI void GLFWAPIENTRY glfwSwapInterval( int interval ); +GLFWAPI int GLFWAPIENTRY glfwGetWindowParam( int param ); +GLFWAPI void GLFWAPIENTRY glfwSetWindowSizeCallback( GLFWwindowsizefun cbfun ); +GLFWAPI void GLFWAPIENTRY glfwSetWindowCloseCallback( GLFWwindowclosefun cbfun ); +GLFWAPI void GLFWAPIENTRY glfwSetWindowRefreshCallback( GLFWwindowrefreshfun cbfun ); + +/* Video mode functions */ +GLFWAPI int GLFWAPIENTRY glfwGetVideoModes( GLFWvidmode *list, int maxcount ); +GLFWAPI void GLFWAPIENTRY glfwGetDesktopMode( GLFWvidmode *mode ); + +/* Input handling */ +GLFWAPI void GLFWAPIENTRY glfwPollEvents( void ); +GLFWAPI void GLFWAPIENTRY glfwWaitEvents( void ); +GLFWAPI int GLFWAPIENTRY glfwGetKey( int key ); +GLFWAPI int GLFWAPIENTRY glfwGetMouseButton( int button ); +GLFWAPI void GLFWAPIENTRY glfwGetMousePos( int *xpos, int *ypos ); +GLFWAPI void GLFWAPIENTRY glfwSetMousePos( int xpos, int ypos ); +GLFWAPI int GLFWAPIENTRY glfwGetMouseWheel( void ); +GLFWAPI void GLFWAPIENTRY glfwSetMouseWheel( int pos ); +GLFWAPI void GLFWAPIENTRY glfwSetKeyCallback( GLFWkeyfun cbfun ); +GLFWAPI void GLFWAPIENTRY glfwSetCharCallback( GLFWcharfun cbfun ); +GLFWAPI void GLFWAPIENTRY glfwSetMouseButtonCallback( GLFWmousebuttonfun cbfun ); +GLFWAPI void GLFWAPIENTRY glfwSetMousePosCallback( GLFWmouseposfun cbfun ); +GLFWAPI void GLFWAPIENTRY glfwSetMouseWheelCallback( GLFWmousewheelfun cbfun ); + +/* Joystick input */ +GLFWAPI int GLFWAPIENTRY glfwGetJoystickParam( int joy, int param ); +GLFWAPI int GLFWAPIENTRY glfwGetJoystickPos( int joy, float *pos, int numaxes ); +GLFWAPI int GLFWAPIENTRY glfwGetJoystickButtons( int joy, unsigned char *buttons, int numbuttons ); + +/* Time */ +GLFWAPI double GLFWAPIENTRY glfwGetTime( void ); +GLFWAPI void GLFWAPIENTRY glfwSetTime( double time ); +GLFWAPI void GLFWAPIENTRY glfwSleep( double time ); + +/* Extension support */ +GLFWAPI int GLFWAPIENTRY glfwExtensionSupported( const char *extension ); +GLFWAPI void* GLFWAPIENTRY glfwGetProcAddress( const char *procname ); +GLFWAPI void GLFWAPIENTRY glfwGetGLVersion( int *major, int *minor, int *rev ); + +/* Threading support */ +GLFWAPI GLFWthread GLFWAPIENTRY glfwCreateThread( GLFWthreadfun fun, void *arg ); +GLFWAPI void GLFWAPIENTRY glfwDestroyThread( GLFWthread ID ); +GLFWAPI int GLFWAPIENTRY glfwWaitThread( GLFWthread ID, int waitmode ); +GLFWAPI GLFWthread GLFWAPIENTRY glfwGetThreadID( void ); +GLFWAPI GLFWmutex GLFWAPIENTRY glfwCreateMutex( void ); +GLFWAPI void GLFWAPIENTRY glfwDestroyMutex( GLFWmutex mutex ); +GLFWAPI void GLFWAPIENTRY glfwLockMutex( GLFWmutex mutex ); +GLFWAPI void GLFWAPIENTRY glfwUnlockMutex( GLFWmutex mutex ); +GLFWAPI GLFWcond GLFWAPIENTRY glfwCreateCond( void ); +GLFWAPI void GLFWAPIENTRY glfwDestroyCond( GLFWcond cond ); +GLFWAPI void GLFWAPIENTRY glfwWaitCond( GLFWcond cond, GLFWmutex mutex, double timeout ); +GLFWAPI void GLFWAPIENTRY glfwSignalCond( GLFWcond cond ); +GLFWAPI void GLFWAPIENTRY glfwBroadcastCond( GLFWcond cond ); +GLFWAPI int GLFWAPIENTRY glfwGetNumberOfProcessors( void ); + +/* Enable/disable functions */ +GLFWAPI void GLFWAPIENTRY glfwEnable( int token ); +GLFWAPI void GLFWAPIENTRY glfwDisable( int token ); + +/* Image/texture I/O support */ +GLFWAPI int GLFWAPIENTRY glfwReadImage( const char *name, GLFWimage *img, int flags ); +GLFWAPI int GLFWAPIENTRY glfwReadMemoryImage( const void *data, long size, GLFWimage *img, int flags ); +GLFWAPI void GLFWAPIENTRY glfwFreeImage( GLFWimage *img ); +GLFWAPI int GLFWAPIENTRY glfwLoadTexture2D( const char *name, int flags ); +GLFWAPI int GLFWAPIENTRY glfwLoadMemoryTexture2D( const void *data, long size, int flags ); +GLFWAPI int GLFWAPIENTRY glfwLoadTextureImage2D( GLFWimage *img, int flags ); + + +#ifdef __cplusplus +} +#endif + +#endif /* __glfw_h_ */ + diff --git a/tests/glfw/Makefile b/tests/glfw/Makefile new file mode 100644 index 0000000000000..89138d74b87ae --- /dev/null +++ b/tests/glfw/Makefile @@ -0,0 +1,56 @@ +########################################################################## +# Makefile for GLFW example programs on X11 (generated by compile.sh) +########################################################################## +CC = emcc +CFLAGS = -I../include + +LIB = -lglfw +SOLIB = +LFLAGS = $(LIB) +SO_LFLAGS = $(SOLIB) + +BINARIES = triangle.js listmodes.js mthello.js pong3d.js mtbench.js particles.js splitview.js \ + mipmaps.js gears.js boing.js heightmap.js +## wave + +all: $(BINARIES) + +triangle.js: triangle.c + $(CC) $(CFLAGS) triangle.c $(LFLAGS) -o $@ + +listmodes.js: listmodes.c + $(CC) $(CFLAGS) listmodes.c $(LFLAGS) -o $@ + +mthello.js: mthello.c + $(CC) $(CFLAGS) mthello.c $(LFLAGS) -o $@ + +pong3d.js: pong3d.c + $(CC) $(CFLAGS) pong3d.c $(LFLAGS) -o $@ + +mtbench.js: mtbench.c + $(CC) $(CFLAGS) mtbench.c $(LFLAGS) -o $@ + +particles.js: particles.c + $(CC) $(CFLAGS) particles.c $(LFLAGS) -o $@ + +splitview.js: splitview.c + $(CC) $(CFLAGS) splitview.c $(LFLAGS) -o $@ + +mipmaps.js: mipmaps.c + $(CC) $(CFLAGS) mipmaps.c $(LFLAGS) -o $@ + +gears.js: gears.c + $(CC) $(CFLAGS) gears.c $(LFLAGS) -o $@ + +boing.js: boing.c + $(CC) $(CFLAGS) boing.c $(LFLAGS) -o $@ + +wave.js: wave.c + $(CC) $(CFLAGS) wave.c $(LFLAGS) -o $@ + +heightmap.js: heightmap.c + $(CC) $(CFLAGS) heightmap.c $(LFLAGS) -o $@ + +clean: + rm -f $(BINARIES) + diff --git a/tests/glfw/boing.c b/tests/glfw/boing.c new file mode 100644 index 0000000000000..08544d1a4716b --- /dev/null +++ b/tests/glfw/boing.c @@ -0,0 +1,615 @@ +/***************************************************************************** + * Title: GLBoing + * Desc: Tribute to Amiga Boing. + * Author: Jim Brooks + * Original Amiga authors were R.J. Mical and Dale Luck. + * GLFW conversion by Marcus Geelnard + * Notes: - 360' = 2*PI [radian] + * + * - Distances between objects are created by doing a relative + * Z translations. + * + * - Although OpenGL enticingly supports alpha-blending, + * the shadow of the original Boing didn't affect the color + * of the grid. + * + * - [Marcus] Changed timing scheme from interval driven to frame- + * time based animation steps (which results in much smoother + * movement) + * + * History of Amiga Boing: + * + * Boing was demonstrated on the prototype Amiga (codenamed "Lorraine") in + * 1985. According to legend, it was written ad-hoc in one night by + * R. J. Mical and Dale Luck. Because the bouncing ball animation was so fast + * and smooth, attendees did not believe the Amiga prototype was really doing + * the rendering. Suspecting a trick, they began looking around the booth for + * a hidden computer or VCR. + *****************************************************************************/ + +#include +#include +#include +#include + + +/***************************************************************************** + * Various declarations and macros + *****************************************************************************/ + +/* Prototypes */ +void init( void ); +void display( void ); +void GLFWCALL reshape( int w, int h ); +void DrawBoingBall( void ); +void BounceBall( double dt ); +void DrawBoingBallBand( GLfloat long_lo, GLfloat long_hi ); +void DrawGrid( void ); + +#define RADIUS 70.f +#define STEP_LONGITUDE 22.5f /* 22.5 makes 8 bands like original Boing */ +#define STEP_LATITUDE 22.5f + +#define DIST_BALL (RADIUS * 2.f + RADIUS * 0.1f) + +#define VIEW_SCENE_DIST (DIST_BALL * 3.f + 200.f)/* distance from viewer to middle of boing area */ +#define GRID_SIZE (RADIUS * 4.5f) /* length (width) of grid */ +#define BOUNCE_HEIGHT (RADIUS * 2.1f) +#define BOUNCE_WIDTH (RADIUS * 2.1f) + +#define SHADOW_OFFSET_X -20.f +#define SHADOW_OFFSET_Y 10.f +#define SHADOW_OFFSET_Z 0.f + +#define WALL_L_OFFSET 0.f +#define WALL_R_OFFSET 5.f + +/* Animation speed (50.0 mimics the original GLUT demo speed) */ +#define ANIMATION_SPEED 50.f + +/* Maximum allowed delta time per physics iteration */ +#define MAX_DELTA_T 0.02f + +/* Draw ball, or its shadow */ +typedef enum { DRAW_BALL, DRAW_BALL_SHADOW } DRAW_BALL_ENUM; + +/* Vertex type */ +typedef struct {float x; float y; float z;} vertex_t; + +/* Global vars */ +GLfloat deg_rot_y = 0.f; +GLfloat deg_rot_y_inc = 2.f; +GLfloat ball_x = -RADIUS; +GLfloat ball_y = -RADIUS; +GLfloat ball_x_inc = 1.f; +GLfloat ball_y_inc = 2.f; +DRAW_BALL_ENUM drawBallHow; +double t; +double t_old = 0.f; +double dt; + +/* Random number generator */ +#ifndef RAND_MAX + #define RAND_MAX 4095 +#endif + +/* PI */ +#ifndef M_PI + #define M_PI 3.1415926535897932384626433832795 +#endif + + +/***************************************************************************** + * Truncate a degree. + *****************************************************************************/ +GLfloat TruncateDeg( GLfloat deg ) +{ + if ( deg >= 360.f ) + return (deg - 360.f); + else + return deg; +} + +/***************************************************************************** + * Convert a degree (360-based) into a radian. + * 360' = 2 * PI + *****************************************************************************/ +double deg2rad( double deg ) +{ + return deg / 360 * (2 * M_PI); +} + +/***************************************************************************** + * 360' sin(). + *****************************************************************************/ +double sin_deg( double deg ) +{ + return sin( deg2rad( deg ) ); +} + +/***************************************************************************** + * 360' cos(). + *****************************************************************************/ +double cos_deg( double deg ) +{ + return cos( deg2rad( deg ) ); +} + +/***************************************************************************** + * Compute a cross product (for a normal vector). + * + * c = a x b + *****************************************************************************/ +void CrossProduct( vertex_t a, vertex_t b, vertex_t c, vertex_t *n ) +{ + GLfloat u1, u2, u3; + GLfloat v1, v2, v3; + + u1 = b.x - a.x; + u2 = b.y - a.y; + u3 = b.y - a.z; + + v1 = c.x - a.x; + v2 = c.y - a.y; + v3 = c.z - a.z; + + n->x = u2 * v3 - v2 * v3; + n->y = u3 * v1 - v3 * u1; + n->z = u1 * v2 - v1 * u2; +} + +/***************************************************************************** + * Calculate the angle to be passed to gluPerspective() so that a scene + * is visible. This function originates from the OpenGL Red Book. + * + * Parms : size + * The size of the segment when the angle is intersected at "dist" + * (ie at the outermost edge of the angle of vision). + * + * dist + * Distance from viewpoint to scene. + *****************************************************************************/ +GLfloat PerspectiveAngle( GLfloat size, + GLfloat dist ) +{ + GLfloat radTheta, degTheta; + + radTheta = 2.f * (GLfloat) atan2( size / 2.f, dist ); + degTheta = (180.f * radTheta) / (GLfloat) M_PI; + return degTheta; +} + + + +#define BOING_DEBUG 0 + + +/***************************************************************************** + * init() + *****************************************************************************/ +void init( void ) +{ + /* + * Clear background. + */ + glClearColor( 0.55f, 0.55f, 0.55f, 0.f ); + + glShadeModel( GL_FLAT ); +} + + +/***************************************************************************** + * display() + *****************************************************************************/ +void display(void) +{ + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + glPushMatrix(); + + drawBallHow = DRAW_BALL_SHADOW; + DrawBoingBall(); + + DrawGrid(); + + drawBallHow = DRAW_BALL; + DrawBoingBall(); + + glPopMatrix(); + glFlush(); +} + + +/***************************************************************************** + * reshape() + *****************************************************************************/ +void GLFWCALL reshape( int w, int h ) +{ + glViewport( 0, 0, (GLsizei)w, (GLsizei)h ); + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + + gluPerspective( PerspectiveAngle( RADIUS * 2, 200 ), + (GLfloat)w / (GLfloat)h, + 1.0, + VIEW_SCENE_DIST ); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + gluLookAt( 0.0, 0.0, VIEW_SCENE_DIST,/* eye */ + 0.0, 0.0, 0.0, /* center of vision */ + 0.0, -1.0, 0.0 ); /* up vector */ +} + + +/***************************************************************************** + * Draw the Boing ball. + * + * The Boing ball is sphere in which each facet is a rectangle. + * Facet colors alternate between red and white. + * The ball is built by stacking latitudinal circles. Each circle is composed + * of a widely-separated set of points, so that each facet is noticably large. + *****************************************************************************/ +void DrawBoingBall( void ) +{ + GLfloat lon_deg; /* degree of longitude */ + double dt_total, dt2; + + glPushMatrix(); + glMatrixMode( GL_MODELVIEW ); + + /* + * Another relative Z translation to separate objects. + */ + glTranslatef( 0.0, 0.0, DIST_BALL ); + + /* Update ball position and rotation (iterate if necessary) */ + dt_total = dt; + while( dt_total > 0.0 ) + { + dt2 = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total; + dt_total -= dt2; + BounceBall( dt2 ); + deg_rot_y = TruncateDeg( deg_rot_y + deg_rot_y_inc*((float)dt2*ANIMATION_SPEED) ); + } + + /* Set ball position */ + glTranslatef( ball_x, ball_y, 0.0 ); + + /* + * Offset the shadow. + */ + if ( drawBallHow == DRAW_BALL_SHADOW ) + { + glTranslatef( SHADOW_OFFSET_X, + SHADOW_OFFSET_Y, + SHADOW_OFFSET_Z ); + } + + /* + * Tilt the ball. + */ + glRotatef( -20.0, 0.0, 0.0, 1.0 ); + + /* + * Continually rotate ball around Y axis. + */ + glRotatef( deg_rot_y, 0.0, 1.0, 0.0 ); + + /* + * Set OpenGL state for Boing ball. + */ + glCullFace( GL_FRONT ); + glEnable( GL_CULL_FACE ); + glEnable( GL_NORMALIZE ); + + /* + * Build a faceted latitude slice of the Boing ball, + * stepping same-sized vertical bands of the sphere. + */ + for ( lon_deg = 0; + lon_deg < 180; + lon_deg += STEP_LONGITUDE ) + { + /* + * Draw a latitude circle at this longitude. + */ + DrawBoingBallBand( lon_deg, + lon_deg + STEP_LONGITUDE ); + } + + glPopMatrix(); + + return; +} + + +/***************************************************************************** + * Bounce the ball. + *****************************************************************************/ +void BounceBall( double dt ) +{ + GLfloat sign; + GLfloat deg; + + /* Bounce on walls */ + if ( ball_x > (BOUNCE_WIDTH/2 + WALL_R_OFFSET ) ) + { + ball_x_inc = -0.5f - 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX; + deg_rot_y_inc = -deg_rot_y_inc; + } + if ( ball_x < -(BOUNCE_HEIGHT/2 + WALL_L_OFFSET) ) + { + ball_x_inc = 0.5f + 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX; + deg_rot_y_inc = -deg_rot_y_inc; + } + + /* Bounce on floor / roof */ + if ( ball_y > BOUNCE_HEIGHT/2 ) + { + ball_y_inc = -0.75f - 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX; + } + if ( ball_y < -BOUNCE_HEIGHT/2*0.85 ) + { + ball_y_inc = 0.75f + 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX; + } + + /* Update ball position */ + ball_x += ball_x_inc * ((float)dt*ANIMATION_SPEED); + ball_y += ball_y_inc * ((float)dt*ANIMATION_SPEED); + + /* + * Simulate the effects of gravity on Y movement. + */ + if ( ball_y_inc < 0 ) sign = -1.0; else sign = 1.0; + + deg = (ball_y + BOUNCE_HEIGHT/2) * 90 / BOUNCE_HEIGHT; + if ( deg > 80 ) deg = 80; + if ( deg < 10 ) deg = 10; + + ball_y_inc = sign * 4.f * (float) sin_deg( deg ); +} + + +/***************************************************************************** + * Draw a faceted latitude band of the Boing ball. + * + * Parms: long_lo, long_hi + * Low and high longitudes of slice, resp. + *****************************************************************************/ +void DrawBoingBallBand( GLfloat long_lo, + GLfloat long_hi ) +{ + vertex_t vert_ne; /* "ne" means south-east, so on */ + vertex_t vert_nw; + vertex_t vert_sw; + vertex_t vert_se; + vertex_t vert_norm; + GLfloat lat_deg; + static int colorToggle = 0; + + /* + * Iterate thru the points of a latitude circle. + * A latitude circle is a 2D set of X,Z points. + */ + for ( lat_deg = 0; + lat_deg <= (360 - STEP_LATITUDE); + lat_deg += STEP_LATITUDE ) + { + /* + * Color this polygon with red or white. + */ + if ( colorToggle ) + glColor3f( 0.8f, 0.1f, 0.1f ); + else + glColor3f( 0.95f, 0.95f, 0.95f ); +#if 0 + if ( lat_deg >= 180 ) + if ( colorToggle ) + glColor3f( 0.1f, 0.8f, 0.1f ); + else + glColor3f( 0.5f, 0.5f, 0.95f ); +#endif + colorToggle = ! colorToggle; + + /* + * Change color if drawing shadow. + */ + if ( drawBallHow == DRAW_BALL_SHADOW ) + glColor3f( 0.35f, 0.35f, 0.35f ); + + /* + * Assign each Y. + */ + vert_ne.y = vert_nw.y = (float) cos_deg(long_hi) * RADIUS; + vert_sw.y = vert_se.y = (float) cos_deg(long_lo) * RADIUS; + + /* + * Assign each X,Z with sin,cos values scaled by latitude radius indexed by longitude. + * Eg, long=0 and long=180 are at the poles, so zero scale is sin(longitude), + * while long=90 (sin(90)=1) is at equator. + */ + vert_ne.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_se.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); + vert_nw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_sw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); + + vert_ne.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_se.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); + vert_nw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_sw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); + + /* + * Draw the facet. + */ + glBegin( GL_POLYGON ); + + CrossProduct( vert_ne, vert_nw, vert_sw, &vert_norm ); + glNormal3f( vert_norm.x, vert_norm.y, vert_norm.z ); + + glVertex3f( vert_ne.x, vert_ne.y, vert_ne.z ); + glVertex3f( vert_nw.x, vert_nw.y, vert_nw.z ); + glVertex3f( vert_sw.x, vert_sw.y, vert_sw.z ); + glVertex3f( vert_se.x, vert_se.y, vert_se.z ); + + glEnd(); + +#if BOING_DEBUG + printf( "----------------------------------------------------------- \n" ); + printf( "lat = %f long_lo = %f long_hi = %f \n", lat_deg, long_lo, long_hi ); + printf( "vert_ne x = %.8f y = %.8f z = %.8f \n", vert_ne.x, vert_ne.y, vert_ne.z ); + printf( "vert_nw x = %.8f y = %.8f z = %.8f \n", vert_nw.x, vert_nw.y, vert_nw.z ); + printf( "vert_se x = %.8f y = %.8f z = %.8f \n", vert_se.x, vert_se.y, vert_se.z ); + printf( "vert_sw x = %.8f y = %.8f z = %.8f \n", vert_sw.x, vert_sw.y, vert_sw.z ); +#endif + + } + + /* + * Toggle color so that next band will opposite red/white colors than this one. + */ + colorToggle = ! colorToggle; + + /* + * This circular band is done. + */ + return; +} + + +/***************************************************************************** + * Draw the purple grid of lines, behind the Boing ball. + * When the Workbench is dropped to the bottom, Boing shows 12 rows. + *****************************************************************************/ +void DrawGrid( void ) +{ + int row, col; + const int rowTotal = 12; /* must be divisible by 2 */ + const int colTotal = rowTotal; /* must be same as rowTotal */ + const GLfloat widthLine = 2.0; /* should be divisible by 2 */ + const GLfloat sizeCell = GRID_SIZE / rowTotal; + const GLfloat z_offset = -40.0; + GLfloat xl, xr; + GLfloat yt, yb; + + glPushMatrix(); + glDisable( GL_CULL_FACE ); + + /* + * Another relative Z translation to separate objects. + */ + glTranslatef( 0.0, 0.0, DIST_BALL ); + + /* + * Draw vertical lines (as skinny 3D rectangles). + */ + for ( col = 0; col <= colTotal; col++ ) + { + /* + * Compute co-ords of line. + */ + xl = -GRID_SIZE / 2 + col * sizeCell; + xr = xl + widthLine; + + yt = GRID_SIZE / 2; + yb = -GRID_SIZE / 2 - widthLine; + + glBegin( GL_POLYGON ); + + glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */ + + glVertex3f( xr, yt, z_offset ); /* NE */ + glVertex3f( xl, yt, z_offset ); /* NW */ + glVertex3f( xl, yb, z_offset ); /* SW */ + glVertex3f( xr, yb, z_offset ); /* SE */ + + glEnd(); + } + + /* + * Draw horizontal lines (as skinny 3D rectangles). + */ + for ( row = 0; row <= rowTotal; row++ ) + { + /* + * Compute co-ords of line. + */ + yt = GRID_SIZE / 2 - row * sizeCell; + yb = yt - widthLine; + + xl = -GRID_SIZE / 2; + xr = GRID_SIZE / 2 + widthLine; + + glBegin( GL_POLYGON ); + + glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */ + + glVertex3f( xr, yt, z_offset ); /* NE */ + glVertex3f( xl, yt, z_offset ); /* NW */ + glVertex3f( xl, yb, z_offset ); /* SW */ + glVertex3f( xr, yb, z_offset ); /* SE */ + + glEnd(); + } + + glPopMatrix(); + + return; +} + + +/*======================================================================* + * main() + *======================================================================*/ + +int main( void ) +{ + int running; + + /* Init GLFW */ + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + if( !glfwOpenWindow( 400,400, 0,0,0,0, 16,0, GLFW_WINDOW ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + glfwSetWindowTitle( "Boing (classic Amiga demo)" ); + glfwSetWindowSizeCallback( reshape ); + glfwEnable( GLFW_STICKY_KEYS ); + glfwSwapInterval( 1 ); + glfwSetTime( 0.0 ); + + init(); + + /* Main loop */ + do + { + /* Timing */ + t = glfwGetTime(); + dt = t - t_old; + t_old = t; + + /* Draw one frame */ + display(); + + /* Swap buffers */ + glfwSwapBuffers(); + + /* Check if we are still running */ + running = !glfwGetKey( GLFW_KEY_ESC ) && + glfwGetWindowParam( GLFW_OPENED ); + } + while( running ); + + glfwTerminate(); + exit( EXIT_SUCCESS ); +} + diff --git a/tests/glfw/bundle.sh b/tests/glfw/bundle.sh new file mode 100644 index 0000000000000..ee4d18ddda08d --- /dev/null +++ b/tests/glfw/bundle.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# Creates application bundles for use on Mac OS X. + +if [ -z "$1" ]; then + echo "usage: `basename $0` BUNDLE-NAME" + exit 1 +fi + +bundle_name="$1" + +if [ ! -d "${bundle_name}.app/Contents/MacOS" ]; then + mkdir -p "${bundle_name}.app/Contents/MacOS" +fi + +if [ ! -d "${bundle_name}.app/Contents/Resources" ]; then + mkdir -p "${bundle_name}.app/Contents/Resources" +fi + +if [ ! -f "${bundle_name}.app/Contents/PkgInfo" ]; then + echo -n "APPL????" > "${bundle_name}.app/Contents/PkgInfo" +fi + +if [ ! -f "${bundle_name}.app/Contents/Info.plist" ]; then + cat > "${bundle_name}.app/Contents/Info.plist" < + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${bundle_name} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 0.1 + + +EOF +fi + diff --git a/tests/glfw/gears.c b/tests/glfw/gears.c new file mode 100644 index 0000000000000..d9efdf9aa6314 --- /dev/null +++ b/tests/glfw/gears.c @@ -0,0 +1,373 @@ +/* + * 3-D gear wheels. This program is in the public domain. + * + * Command line options: + * -info print GL implementation information + * -exit automatically exit after 30 seconds + * + * + * Brian Paul + * + * + * Marcus Geelnard: + * - Conversion to GLFW + * - Time based rendering (frame rate independent) + * - Slightly modified camera that should work better for stereo viewing + * + * + * Camilla Berglund: + * - Removed FPS counter (this is not a benchmark) + * - Added a few comments + * - Enabled vsync + */ + + +#include +#include +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +/* The program exits when this is zero. + */ +static int running = 1; + +/* If non-zero, the program exits after that many seconds + */ +static int autoexit = 0; + +/** + + Draw a gear wheel. You'll probably want to call this function when + building a display list since we do a lot of trig here. + + Input: inner_radius - radius of hole at center + outer_radius - radius at center of teeth + width - width of gear teeth - number of teeth + tooth_depth - depth of tooth + + **/ + +static void +gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, + GLint teeth, GLfloat tooth_depth) +{ + GLint i; + GLfloat r0, r1, r2; + GLfloat angle, da; + GLfloat u, v, len; + + r0 = inner_radius; + r1 = outer_radius - tooth_depth / 2.f; + r2 = outer_radius + tooth_depth / 2.f; + + da = 2.f * (float) M_PI / teeth / 4.f; + + glShadeModel(GL_FLAT); + + glNormal3f(0.f, 0.f, 1.f); + + /* draw front face */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); + if (i < teeth) { + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); + } + } + glEnd(); + + /* draw front sides of teeth */ + glBegin(GL_QUADS); + da = 2.f * (float) M_PI / teeth / 4.f; + for (i = 0; i < teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), width * 0.5f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); + } + glEnd(); + + glNormal3f(0.0, 0.0, -1.0); + + /* draw back face */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); + if (i < teeth) { + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); + } + } + glEnd(); + + /* draw back sides of teeth */ + glBegin(GL_QUADS); + da = 2.f * (float) M_PI / teeth / 4.f; + for (i = 0; i < teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), -width * 0.5f); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), -width * 0.5f); + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); + } + glEnd(); + + /* draw outward faces of teeth */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i < teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); + u = r2 * (float) cos(angle + da) - r1 * (float) cos(angle); + v = r2 * (float) sin(angle + da) - r1 * (float) sin(angle); + len = (float) sqrt(u * u + v * v); + u /= len; + v /= len; + glNormal3f(v, -u, 0.0); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), -width * 0.5f); + glNormal3f((float) cos(angle), (float) sin(angle), 0.f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), -width * 0.5f); + u = r1 * (float) cos(angle + 3 * da) - r2 * (float) cos(angle + 2 * da); + v = r1 * (float) sin(angle + 3 * da) - r2 * (float) sin(angle + 2 * da); + glNormal3f(v, -u, 0.f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); + glNormal3f((float) cos(angle), (float) sin(angle), 0.f); + } + + glVertex3f(r1 * (float) cos(0), r1 * (float) sin(0), width * 0.5f); + glVertex3f(r1 * (float) cos(0), r1 * (float) sin(0), -width * 0.5f); + + glEnd(); + + glShadeModel(GL_SMOOTH); + + /* draw inside radius cylinder */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + glNormal3f(-(float) cos(angle), -(float) sin(angle), 0.f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); + } + glEnd(); + +} + + +static GLfloat view_rotx = 20.f, view_roty = 30.f, view_rotz = 0.f; +static GLint gear1, gear2, gear3; +static GLfloat angle = 0.f; + +/* OpenGL draw function & timing */ +static void draw(void) +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glPushMatrix(); + glRotatef(view_rotx, 1.0, 0.0, 0.0); + glRotatef(view_roty, 0.0, 1.0, 0.0); + glRotatef(view_rotz, 0.0, 0.0, 1.0); + + glPushMatrix(); + glTranslatef(-3.0, -2.0, 0.0); + glRotatef(angle, 0.0, 0.0, 1.0); + glCallList(gear1); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(3.1f, -2.f, 0.f); + glRotatef(-2.f * angle - 9.f, 0.f, 0.f, 1.f); + glCallList(gear2); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(-3.1f, 4.2f, 0.f); + glRotatef(-2.f * angle - 25.f, 0.f, 0.f, 1.f); + glCallList(gear3); + glPopMatrix(); + + glPopMatrix(); +} + + +/* update animation parameters */ +static void animate(void) +{ + angle = 100.f * (float) glfwGetTime(); +} + + +/* change view angle, exit upon ESC */ +void GLFWCALL key( int k, int action ) +{ + if( action != GLFW_PRESS ) return; + + switch (k) { + case 'Z': + if( glfwGetKey( GLFW_KEY_LSHIFT ) ) + view_rotz -= 5.0; + else + view_rotz += 5.0; + break; + case GLFW_KEY_ESC: + running = 0; + break; + case GLFW_KEY_UP: + view_rotx += 5.0; + break; + case GLFW_KEY_DOWN: + view_rotx -= 5.0; + break; + case GLFW_KEY_LEFT: + view_roty += 5.0; + break; + case GLFW_KEY_RIGHT: + view_roty -= 5.0; + break; + default: + return; + } +} + + +/* new window size */ +void GLFWCALL reshape( int width, int height ) +{ + GLfloat h = (GLfloat) height / (GLfloat) width; + GLfloat xmax, znear, zfar; + + znear = 5.0f; + zfar = 30.0f; + xmax = znear * 0.5f; + + glViewport( 0, 0, (GLint) width, (GLint) height ); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glFrustum( -xmax, xmax, -xmax*h, xmax*h, znear, zfar ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + glTranslatef( 0.0, 0.0, -20.0 ); +} + + +/* program & OpenGL initialization */ +static void init(int argc, char *argv[]) +{ + static GLfloat pos[4] = {5.f, 5.f, 10.f, 0.f}; + static GLfloat red[4] = {0.8f, 0.1f, 0.f, 1.f}; + static GLfloat green[4] = {0.f, 0.8f, 0.2f, 1.f}; + static GLfloat blue[4] = {0.2f, 0.2f, 1.f, 1.f}; + GLint i; + + glLightfv(GL_LIGHT0, GL_POSITION, pos); + glEnable(GL_CULL_FACE); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); + + /* make the gears */ + gear1 = glGenLists(1); + glNewList(gear1, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); + gear(1.f, 4.f, 1.f, 20, 0.7f); + glEndList(); + + gear2 = glGenLists(1); + glNewList(gear2, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); + gear(0.5f, 2.f, 2.f, 10, 0.7f); + glEndList(); + + gear3 = glGenLists(1); + glNewList(gear3, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); + gear(1.3f, 2.f, 0.5f, 10, 0.7f); + glEndList(); + + glEnable(GL_NORMALIZE); + + for ( i=1; i +#include +#include +#include "getopt.h" + + +/* 2009-10-12 Camilla Berglund + * + * Removed unused global static variable 'ID'. + */ + + +char* optarg = NULL; +int optind = 0; +int opterr = 1; +int optopt = '?'; + + +static char** prev_argv = NULL; /* Keep a copy of argv and argc to */ +static int prev_argc = 0; /* tell if getopt params change */ +static int argv_index = 0; /* Option we're checking */ +static int argv_index2 = 0; /* Option argument we're checking */ +static int opt_offset = 0; /* Index into compounded "-option" */ +static int dashdash = 0; /* True if "--" option reached */ +static int nonopt = 0; /* How many nonopts we've found */ + +static void increment_index() +{ + /* Move onto the next option */ + if(argv_index < argv_index2) + { + while(prev_argv[++argv_index] && prev_argv[argv_index][0] != '-' + && argv_index < argv_index2+1); + } + else argv_index++; + opt_offset = 1; +} + + +/* +* Permutes argv[] so that the argument currently being processed is moved +* to the end. +*/ +static int permute_argv_once() +{ + /* Movability check */ + if(argv_index + nonopt >= prev_argc) return 1; + /* Move the current option to the end, bring the others to front */ + else + { + char* tmp = prev_argv[argv_index]; + + /* Move the data */ + memmove(&prev_argv[argv_index], &prev_argv[argv_index+1], + sizeof(char**) * (prev_argc - argv_index - 1)); + prev_argv[prev_argc - 1] = tmp; + + nonopt++; + return 0; + } +} + + +int getopt(int argc, char** argv, char* optstr) +{ + int c = 0; + + /* If we have new argv, reinitialize */ + if(prev_argv != argv || prev_argc != argc) + { + /* Initialize variables */ + prev_argv = argv; + prev_argc = argc; + argv_index = 1; + argv_index2 = 1; + opt_offset = 1; + dashdash = 0; + nonopt = 0; + } + + /* Jump point in case we want to ignore the current argv_index */ + getopt_top: + + /* Misc. initializations */ + optarg = NULL; + + /* Dash-dash check */ + if(argv[argv_index] && !strcmp(argv[argv_index], "--")) + { + dashdash = 1; + increment_index(); + } + + /* If we're at the end of argv, that's it. */ + if(argv[argv_index] == NULL) + { + c = -1; + } + /* Are we looking at a string? Single dash is also a string */ + else if(dashdash || argv[argv_index][0] != '-' || !strcmp(argv[argv_index], "-")) + { + /* If we want a string... */ + if(optstr[0] == '-') + { + c = 1; + optarg = argv[argv_index]; + increment_index(); + } + /* If we really don't want it (we're in POSIX mode), we're done */ + else if(optstr[0] == '+' || getenv("POSIXLY_CORRECT")) + { + c = -1; + + /* Everything else is a non-opt argument */ + nonopt = argc - argv_index; + } + /* If we mildly don't want it, then move it back */ + else + { + if(!permute_argv_once()) goto getopt_top; + else c = -1; + } + } + /* Otherwise we're looking at an option */ + else + { + char* opt_ptr = NULL; + + /* Grab the option */ + c = argv[argv_index][opt_offset++]; + + /* Is the option in the optstr? */ + if(optstr[0] == '-') opt_ptr = strchr(optstr+1, c); + else opt_ptr = strchr(optstr, c); + /* Invalid argument */ + if(!opt_ptr) + { + if(opterr) + { + fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); + } + + optopt = c; + c = '?'; + + /* Move onto the next option */ + increment_index(); + } + /* Option takes argument */ + else if(opt_ptr[1] == ':') + { + /* ie, -oARGUMENT, -xxxoARGUMENT, etc. */ + if(argv[argv_index][opt_offset] != '\0') + { + optarg = &argv[argv_index][opt_offset]; + increment_index(); + } + /* ie, -o ARGUMENT (only if it's a required argument) */ + else if(opt_ptr[2] != ':') + { + /* One of those "you're not expected to understand this" moment */ + if(argv_index2 < argv_index) argv_index2 = argv_index; + while(argv[++argv_index2] && argv[argv_index2][0] == '-'); + optarg = argv[argv_index2]; + + /* Don't cross into the non-option argument list */ + if(argv_index2 + nonopt >= prev_argc) optarg = NULL; + + /* Move onto the next option */ + increment_index(); + } + else + { + /* Move onto the next option */ + increment_index(); + } + + /* In case we got no argument for an option with required argument */ + if(optarg == NULL && opt_ptr[2] != ':') + { + optopt = c; + c = '?'; + + if(opterr) + { + fprintf(stderr,"%s: option requires an argument -- %c\n", + argv[0], optopt); + } + } + } + /* Option does not take argument */ + else + { + /* Next argv_index */ + if(argv[argv_index][opt_offset] == '\0') + { + increment_index(); + } + } + } + + /* Calculate optind */ + if(c == -1) + { + optind = argc - nonopt; + } + else + { + optind = argv_index; + } + + return c; +} + + +/* vim:ts=3 +*/ diff --git a/tests/glfw/getopt.h b/tests/glfw/getopt.h new file mode 100644 index 0000000000000..0b78650ac7ac6 --- /dev/null +++ b/tests/glfw/getopt.h @@ -0,0 +1,63 @@ +/***************************************************************************** +* getopt.h - competent and free getopt library. +* $Header: /cvsroot/freegetopt/freegetopt/getopt.h,v 1.2 2003/10/26 03:10:20 vindaci Exp $ +* +* Copyright (c)2002-2003 Mark K. Kim +* 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 original author of this software 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 OWNER 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. +*/ +#ifndef GETOPT_H_ +#define GETOPT_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +extern char* optarg; +extern int optind; +extern int opterr; +extern int optopt; + +int getopt(int argc, char** argv, char* optstr); + + +#ifdef __cplusplus +} +#endif + + +#endif /* GETOPT_H_ */ + + +/* vim:ts=3 +*/ diff --git a/tests/glfw/heightmap.c b/tests/glfw/heightmap.c new file mode 100644 index 0000000000000..7faa5d1f16859 --- /dev/null +++ b/tests/glfw/heightmap.c @@ -0,0 +1,850 @@ +//======================================================================== +// Heightmap example program using OpenGL 3 core profile +// Copyright (c) 2010 Olivier Delannoy +// +// 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. +// +//======================================================================== + +#include +#include +#include +#include +#include +#include "getopt.h" + + +#define GLFW_NO_GLU 1 +#include + +/* OpenGL 3.3 support + * Functions are effectively mapped in init_opengl() */ +#ifndef GL_VERSION_3_0 +/* no defines */ +#endif + +#ifndef GL_VERSION_2_0 + +typedef char GLchar; + +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#endif + + + +#ifndef GL_VERSION_1_5 + +typedef ptrdiff_t GLintptr; +typedef ptrdiff_t GLsizeiptr; + +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#endif + + + + +/* OpenGL 3.0 */ +typedef void (APIENTRY * PFN_glGenVertexArrays)(GLsizei n, GLuint *arrays); +typedef void (APIENTRY * PFN_glBindVertexArray)(GLuint array); +typedef void (APIENTRY * PFN_glDeleteVertexArrays)(GLsizei n, GLuint *arrays); +/* OpenGL 2.0 */ +typedef GLuint (APIENTRY * PFN_glCreateShader)(GLenum type); +typedef void (APIENTRY * PFN_glDeleteShader)(GLuint shader); +typedef void (APIENTRY * PFN_glCompileShader)(GLuint shader); +typedef void (APIENTRY * PFN_glShaderSource)(GLuint shader, GLsizei count, const GLchar* *string, const GLint *length); +typedef void (APIENTRY * PFN_glGetShaderiv)(GLuint shader, GLenum pname, GLint *params); +typedef void (APIENTRY * PFN_glGetShaderInfoLog)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef GLuint (APIENTRY * PFN_glCreateProgram)(void); +typedef void (APIENTRY * PFN_glDeleteProgram)(GLuint program); +typedef void (APIENTRY * PFN_glAttachShader)(GLuint program, GLuint shader); +typedef void (APIENTRY * PFN_glLinkProgram)(GLuint program); +typedef void (APIENTRY * PFN_glGetProgramiv)(GLuint program, GLenum pname, GLint *params); +typedef void (APIENTRY * PFN_glGetProgramInfoLog)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRY * PFN_glValidateProgram)(GLuint program); +typedef void (APIENTRY * PFN_glUseProgram)(GLuint program); +typedef GLint (APIENTRY * PFN_glGetUniformLocation)(GLuint program, const GLchar *name); +typedef void (APIENTRY * PFN_glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef GLint (APIENTRY * PFN_glGetAttribLocation)(GLuint program, const GLchar *name); +typedef void (APIENTRY * PFN_glEnableVertexAttribArray)(GLuint index); +typedef void (APIENTRY * PFN_glVertexAttrib1f)(GLuint index, GLfloat x); +typedef void (APIENTRY * PFN_glVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +/* OpenGL 1.5 */ +typedef void (APIENTRY * PFN_glBindBuffer)(GLenum target, GLuint buffer); +typedef void (APIENTRY * PFN_glDeleteBuffers)(GLsizei n, const GLuint *buffers); +typedef void (APIENTRY * PFN_glGenBuffers)(GLsizei n, GLuint *buffers); +typedef void (APIENTRY * PFN_glBufferData)(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); +typedef void (APIENTRY * PFN_glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); + +/* OpenGL function pointers */ +static PFN_glGenBuffers pglGenBuffers = NULL; +static PFN_glGenVertexArrays pglGenVertexArrays = NULL; +static PFN_glDeleteVertexArrays pglDeleteVertexArrays = NULL; +static PFN_glCreateShader pglCreateShader = NULL; +static PFN_glShaderSource pglShaderSource = NULL; +static PFN_glCompileShader pglCompileShader = NULL; +static PFN_glGetShaderiv pglGetShaderiv = NULL; +static PFN_glGetShaderInfoLog pglGetShaderInfoLog = NULL; +static PFN_glDeleteShader pglDeleteShader = NULL; +static PFN_glCreateProgram pglCreateProgram = NULL; +static PFN_glAttachShader pglAttachShader = NULL; +static PFN_glLinkProgram pglLinkProgram = NULL; +static PFN_glUseProgram pglUseProgram = NULL; +static PFN_glGetProgramiv pglGetProgramiv = NULL; +static PFN_glGetProgramInfoLog pglGetProgramInfoLog = NULL; +static PFN_glDeleteProgram pglDeleteProgram = NULL; +static PFN_glGetUniformLocation pglGetUniformLocation = NULL; +static PFN_glUniformMatrix4fv pglUniformMatrix4fv = NULL; +static PFN_glGetAttribLocation pglGetAttribLocation = NULL; + +/* Map height updates */ +#define MAX_CIRCLE_SIZE (5.0f) +#define MAX_DISPLACEMENT (1.0f) +#define DISPLACEMENT_SIGN_LIMIT (0.3f) +#define MAX_ITER (200) +#define NUM_ITER_AT_A_TIME (1) + +/* Map general information */ +#define MAP_SIZE (10.0f) +#define MAP_NUM_VERTICES (80) +#define MAP_NUM_TOTAL_VERTICES (MAP_NUM_VERTICES*MAP_NUM_VERTICES) +#define MAP_NUM_LINES (3* (MAP_NUM_VERTICES - 1) * (MAP_NUM_VERTICES - 1) + \ + 2 * (MAP_NUM_VERTICES - 1)) + + +/* OpenGL function pointers */ + +static PFN_glBindVertexArray pglBindVertexArray = NULL; +static PFN_glBufferData pglBufferData = NULL; +static PFN_glBindBuffer pglBindBuffer = NULL; +static PFN_glBufferSubData pglBufferSubData = NULL; +static PFN_glEnableVertexAttribArray pglEnableVertexAttribArray = NULL; +static PFN_glVertexAttribPointer pglVertexAttribPointer = NULL; + +#define RESOLVE_GL_FCN(type, var, name) \ + if (status == GL_TRUE) \ + {\ + var = glfwGetProcAddress((name));\ + if ((var) == NULL)\ + {\ + status = GL_FALSE;\ + }\ + } + + +static GLboolean init_opengl(void) +{ + GLboolean status = GL_TRUE; + RESOLVE_GL_FCN(PFN_glCreateShader, pglCreateShader, "glCreateShader"); + RESOLVE_GL_FCN(PFN_glShaderSource, pglShaderSource, "glShaderSource"); + RESOLVE_GL_FCN(PFN_glCompileShader, pglCompileShader, "glCompileShader"); + RESOLVE_GL_FCN(PFN_glGetShaderiv, pglGetShaderiv, "glGetShaderiv"); + RESOLVE_GL_FCN(PFN_glGetShaderInfoLog, pglGetShaderInfoLog, "glGetShaderInfoLog"); + RESOLVE_GL_FCN(PFN_glDeleteShader, pglDeleteShader, "glDeleteShader"); + RESOLVE_GL_FCN(PFN_glCreateProgram, pglCreateProgram, "glCreateProgram"); + RESOLVE_GL_FCN(PFN_glAttachShader, pglAttachShader, "glAttachShader"); + RESOLVE_GL_FCN(PFN_glLinkProgram, pglLinkProgram, "glLinkProgram"); + RESOLVE_GL_FCN(PFN_glUseProgram, pglUseProgram, "glUseProgram"); + RESOLVE_GL_FCN(PFN_glGetProgramiv, pglGetProgramiv, "glGetProgramiv"); + RESOLVE_GL_FCN(PFN_glGetProgramInfoLog, pglGetProgramInfoLog, "glGetProgramInfoLog"); + RESOLVE_GL_FCN(PFN_glDeleteProgram, pglDeleteProgram, "glDeleteProgram"); + RESOLVE_GL_FCN(PFN_glGetUniformLocation, pglGetUniformLocation, "glGetUniformLocation"); + RESOLVE_GL_FCN(PFN_glUniformMatrix4fv, pglUniformMatrix4fv, "glUniformMatrix4fv"); + RESOLVE_GL_FCN(PFN_glGetAttribLocation, pglGetAttribLocation, "glGetAttribLocation"); + RESOLVE_GL_FCN(PFN_glGenVertexArrays, pglGenVertexArrays, "glGenVertexArrays"); + RESOLVE_GL_FCN(PFN_glDeleteVertexArrays, pglDeleteVertexArrays, "glDeleteVertexArrays"); + RESOLVE_GL_FCN(PFN_glBindVertexArray, pglBindVertexArray, "glBindVertexArray"); + RESOLVE_GL_FCN(PFN_glGenBuffers, pglGenBuffers, "glGenBuffers"); + RESOLVE_GL_FCN(PFN_glBindBuffer, pglBindBuffer, "glBindBuffer"); + RESOLVE_GL_FCN(PFN_glBufferData, pglBufferData, "glBufferData"); + RESOLVE_GL_FCN(PFN_glBufferSubData, pglBufferSubData, "glBufferSubData"); + RESOLVE_GL_FCN(PFN_glEnableVertexAttribArray, pglEnableVertexAttribArray, "glEnableVertexAttribArray"); + RESOLVE_GL_FCN(PFN_glVertexAttribPointer, pglVertexAttribPointer, "glVertexAttribPointer"); + return status; +} +/********************************************************************** + * Default shader programs + *********************************************************************/ + +static const char* default_vertex_shader = +"#version 150\n" +"uniform mat4 project;\n" +"uniform mat4 modelview;\n" +"in float x;\n" +"in float y;\n" +"in float z;\n" +"\n" +"void main()\n" +"{\n" +" gl_Position = project * modelview * vec4(x, y, z, 1.0);\n" +"}\n"; + +static const char* default_fragment_shader = +"#version 150\n" +"out vec4 gl_FragColor;\n" +"void main()\n" +"{\n" +" gl_FragColor = vec4(0.2, 1.0, 0.2, 1.0); \n" +"}\n"; + +/********************************************************************** + * Values for shader uniforms + *********************************************************************/ + +/* Frustum configuration */ +static GLfloat view_angle = 45.0f; +static GLfloat aspect_ratio = 4.0f/3.0f; +static GLfloat z_near = 1.0f; +static GLfloat z_far = 100.f; + +/* Projection matrix */ +static GLfloat projection_matrix[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f +}; + +/* Model view matrix */ +static GLfloat modelview_matrix[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f +}; + +/********************************************************************** + * Heightmap vertex and index data + *********************************************************************/ + +static GLfloat map_vertices[3][MAP_NUM_TOTAL_VERTICES]; +static GLuint map_line_indices[2*MAP_NUM_LINES]; + +/* Store uniform location for the shaders + * Those values are setup as part of the process of creating + * the shader program. They should not be used before creating + * the program. + */ +static GLuint mesh; +static GLuint mesh_vbo[4]; + +/********************************************************************** + * OpenGL helper functions + *********************************************************************/ + +/* Load a (text) file into memory and return its contents + */ +static char* read_file_content(const char* filename) +{ + FILE* fd; + size_t size = 0; + char* result = NULL; + + fd = fopen(filename, "r"); + if (fd != NULL) + { + size = fseek(fd, 0, SEEK_END); + (void) fseek(fd, 0, SEEK_SET); + + result = malloc(size + 1); + result[size] = '\0'; + if (fread(result, size, 1, fd) != 1) + { + free(result); + result = NULL; + } + (void) fclose(fd); + } + return result; +} + +/* Creates a shader object of the specified type using the specified text + */ +static GLuint make_shader(GLenum type, const char* shader_src) +{ + GLuint shader; + GLint shader_ok; + GLsizei log_length; + char info_log[8192]; + + shader = pglCreateShader(type); + if (shader != 0) + { + pglShaderSource(shader, 1, (const GLchar**)&shader_src, NULL); + pglCompileShader(shader); + pglGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok); + if (shader_ok != GL_TRUE) + { + fprintf(stderr, "ERROR: Failed to compile %s shader\n", (type == GL_FRAGMENT_SHADER) ? "fragment" : "vertex" ); + pglGetShaderInfoLog(shader, 8192, &log_length,info_log); + fprintf(stderr, "ERROR: \n%s\n\n", info_log); + pglDeleteShader(shader); + shader = 0; + } + } + return shader; +} + +/* Creates a program object using the specified vertex and fragment text + */ +static GLuint make_shader_program(const char* vertex_shader_src, const char* fragment_shader_src) +{ + GLuint program = 0u; + GLint program_ok; + GLuint vertex_shader = 0u; + GLuint fragment_shader = 0u; + GLsizei log_length; + char info_log[8192]; + + vertex_shader = make_shader(GL_VERTEX_SHADER, (vertex_shader_src == NULL) ? default_vertex_shader : vertex_shader_src); + if (vertex_shader != 0u) + { + fragment_shader = make_shader(GL_FRAGMENT_SHADER, (fragment_shader_src == NULL) ? default_fragment_shader : fragment_shader_src); + if (fragment_shader != 0u) + { + /* make the program that connect the two shader and link it */ + program = pglCreateProgram(); + if (program != 0u) + { + /* attach both shader and link */ + pglAttachShader(program, vertex_shader); + pglAttachShader(program, fragment_shader); + pglLinkProgram(program); + pglGetProgramiv(program, GL_LINK_STATUS, &program_ok); + + if (program_ok != GL_TRUE) + { + fprintf(stderr, "ERROR, failed to link shader program\n"); + pglGetProgramInfoLog(program, 8192, &log_length, info_log); + fprintf(stderr, "ERROR: \n%s\n\n", info_log); + pglDeleteProgram(program); + pglDeleteShader(fragment_shader); + pglDeleteShader(vertex_shader); + program = 0u; + } + } + } + else + { + fprintf(stderr, "ERROR: Unable to load fragment shader\n"); + pglDeleteShader(vertex_shader); + } + } + else + { + fprintf(stderr, "ERROR: Unable to load vertex shader\n"); + } + return program; +} + +/********************************************************************** + * Geometry creation functions + *********************************************************************/ + +/* Generate vertices and indices for the heightmap + */ +static void init_map(void) +{ + int i; + int j; + int k; + GLfloat step = MAP_SIZE / (MAP_NUM_VERTICES - 1); + GLfloat x = 0.0f; + GLfloat z = 0.0f; + /* Create a flat grid */ + k = 0; + for (i = 0 ; i < MAP_NUM_VERTICES ; ++i) + { + for (j = 0 ; j < MAP_NUM_VERTICES ; ++j) + { + map_vertices[0][k] = x; + map_vertices[1][k] = 0.0f; + map_vertices[2][k] = z; + z += step; + ++k; + } + x += step; + z = 0.0f; + } +#if DEBUG_ENABLED + for (i = 0 ; i < MAP_NUM_TOTAL_VERTICES ; ++i) + { + printf ("Vertice %d (%f, %f, %f)\n", + i, map_vertices[0][i], map_vertices[1][i], map_vertices[2][i]); + + } +#endif + /* create indices */ + /* line fan based on i + * i+1 + * | / i + n + 1 + * | / + * |/ + * i --- i + n + */ + + /* close the top of the square */ + k = 0; + for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i) + { + map_line_indices[k++] = (i + 1) * MAP_NUM_VERTICES -1; + map_line_indices[k++] = (i + 2) * MAP_NUM_VERTICES -1; + } + /* close the right of the square */ + for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i) + { + map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i; + map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i + 1; + } + + for (i = 0 ; i < (MAP_NUM_VERTICES - 1) ; ++i) + { + for (j = 0 ; j < (MAP_NUM_VERTICES - 1) ; ++j) + { + int ref = i * (MAP_NUM_VERTICES) + j; + map_line_indices[k++] = ref; + map_line_indices[k++] = ref + 1; + + map_line_indices[k++] = ref; + map_line_indices[k++] = ref + MAP_NUM_VERTICES; + + map_line_indices[k++] = ref; + map_line_indices[k++] = ref + MAP_NUM_VERTICES + 1; + } + } + +#ifdef DEBUG_ENABLED + for (k = 0 ; k < 2 * MAP_NUM_LINES ; k += 2) + { + int beg, end; + beg = map_line_indices[k]; + end = map_line_indices[k+1]; + printf ("Line %d: %d -> %d (%f, %f, %f) -> (%f, %f, %f)\n", + k / 2, beg, end, + map_vertices[0][beg], map_vertices[1][beg], map_vertices[2][beg], + map_vertices[0][end], map_vertices[1][end], map_vertices[2][end]); + } +#endif +} + +static void generate_heightmap__circle(float* center_x, float* center_y, + float* size, float* displacement) +{ + float sign; + /* random value for element in between [0-1.0] */ + *center_x = (MAP_SIZE * rand()) / (1.0f * RAND_MAX); + *center_y = (MAP_SIZE * rand()) / (1.0f * RAND_MAX); + *size = (MAX_CIRCLE_SIZE * rand()) / (1.0f * RAND_MAX); + sign = (1.0f * rand()) / (1.0f * RAND_MAX); + sign = (sign < DISPLACEMENT_SIGN_LIMIT) ? -1.0f : 1.0f; + *displacement = (sign * (MAX_DISPLACEMENT * rand())) / (1.0f * RAND_MAX); +} + +/* Run the specified number of iterations of the generation process for the + * heightmap + */ +static void update_map(int num_iter) +{ + assert(num_iter > 0); + while(num_iter) + { + /* center of the circle */ + float center_x; + float center_z; + float circle_size; + float disp; + size_t ii; + generate_heightmap__circle(¢er_x, ¢er_z, &circle_size, &disp); + disp = disp / 2.0f; + for (ii = 0u ; ii < MAP_NUM_TOTAL_VERTICES ; ++ii) + { + GLfloat dx = center_x - map_vertices[0][ii]; + GLfloat dz = center_z - map_vertices[2][ii]; + GLfloat pd = (2.0f * sqrtf((dx * dx) + (dz * dz))) / circle_size; + if (fabs(pd) <= 1.0f) + { + /* tx,tz is within the circle */ + GLfloat new_height = disp + ((GLfloat) cos(pd*3.14f) * disp); + map_vertices[1][ii] += new_height; + } + } + --num_iter; + } +} + +/********************************************************************** + * OpenGL helper functions + *********************************************************************/ + +/* Create VBO, IBO and VAO objects for the heightmap geometry and bind them to + * the specified program object + */ +static void make_mesh(GLuint program) +{ + GLuint attrloc; + + pglGenVertexArrays(1, &mesh); + pglGenBuffers(4, mesh_vbo); + pglBindVertexArray(mesh); + /* Prepare the data for drawing through a buffer inidices */ + pglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh_vbo[3]); + pglBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)* MAP_NUM_LINES * 2, map_line_indices, GL_STATIC_DRAW); + + /* Prepare the attributes for rendering */ + attrloc = pglGetAttribLocation(program, "x"); + pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[0]); + pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[0][0], GL_STATIC_DRAW); + pglEnableVertexAttribArray(attrloc); + pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); + + attrloc = pglGetAttribLocation(program, "z"); + pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[2]); + pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[2][0], GL_STATIC_DRAW); + pglEnableVertexAttribArray(attrloc); + pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); + + attrloc = pglGetAttribLocation(program, "y"); + pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[1]); + pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0], GL_DYNAMIC_DRAW); + pglEnableVertexAttribArray(attrloc); + pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); +} + +/* Update VBO vertices from source data + */ +static void update_mesh(void) +{ + pglBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0]); +} + +/********************************************************************** + * GLFW callback functions + *********************************************************************/ + +/* The program runs as long as this is GL_TRUE + */ +static GLboolean running = GL_TRUE; + +/* GLFW Window management functions */ +static int GLFWCALL close_window_callback(void) +{ + running = GL_FALSE; + + /* Disallow window closing + * The window will be closed when the main loop terminates */ + return GL_FALSE; +} + +static void GLFWCALL key_callback(int key, int action) +{ + switch(key) + { + case GLFW_KEY_ESC: + /* Exit program on Escape */ + running = GL_FALSE; + break; + } +} + +/* Print usage information */ +static void usage(void) +{ + printf("Usage: heightmap [-v ] [-f ]\n"); + printf(" heightmap [-h]\n"); +} + +int main(int argc, char** argv) +{ + int ch, iter; + double dt; + double last_update_time; + int frame; + float f; + GLint uloc_modelview; + GLint uloc_project; + + char* vertex_shader_path = NULL; + char* fragment_shader_path = NULL; + char* vertex_shader_src = NULL; + char* fragment_shader_src = NULL; + GLuint shader_program; + + while ((ch = getopt(argc, argv, "f:v:h")) != -1) + { + switch (ch) + { + case 'f': + fragment_shader_path = optarg; + break; + case 'v': + vertex_shader_path = optarg; + break; + case 'h': + usage(); + exit(EXIT_SUCCESS); + default: + usage(); + exit(EXIT_FAILURE); + } + } + + if (fragment_shader_path) + { + vertex_shader_src = read_file_content(fragment_shader_path); + if (!fragment_shader_src) + { + fprintf(stderr, + "ERROR: unable to load fragment shader from '%s'\n", + fragment_shader_path); + exit(EXIT_FAILURE); + } + } + + if (vertex_shader_path) + { + vertex_shader_src = read_file_content(vertex_shader_path); + if (!vertex_shader_src) + { + fprintf(stderr, + "ERROR: unable to load vertex shader from '%s'\n", + fragment_shader_path); + exit(EXIT_FAILURE); + } + } + + if (GL_TRUE != glfwInit()) + { + fprintf(stderr, "ERROR: Unable to initialize GLFW\n"); + usage(); + + free(vertex_shader_src); + free(fragment_shader_src); + exit(EXIT_FAILURE); + } + + glfwEnable(GLFW_AUTO_POLL_EVENTS); /* No explicit call to glfwPollEvents() */ + + glfwOpenWindowHint(GLFW_WINDOW_NO_RESIZE, GL_TRUE); + glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3); + glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 2); + glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); + + if (GL_TRUE != glfwOpenWindow(800, 600, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) + { + fprintf(stderr, "ERROR: Unable to create the OpenGL context and associated window\n"); + usage(); + + free(vertex_shader_src); + free(fragment_shader_src); + exit(EXIT_FAILURE); + } + + glfwSetWindowTitle("GLFW OpenGL3 Heightmap demo"); + /* Register events callback */ + glfwSetWindowCloseCallback(close_window_callback); + glfwSetKeyCallback(key_callback); + + if (GL_TRUE != init_opengl()) + { + fprintf(stderr, "ERROR: unable to resolve OpenGL function pointers\n"); + free(vertex_shader_src); + free(fragment_shader_src); + exit(EXIT_FAILURE); + } + /* Prepare opengl resources for rendering */ + shader_program = make_shader_program(vertex_shader_src , fragment_shader_src); + free(vertex_shader_src); + free(fragment_shader_src); + + if (shader_program == 0u) + { + fprintf(stderr, "ERROR: during creation of the shader program\n"); + usage(); + exit(EXIT_FAILURE); + } + + pglUseProgram(shader_program); + uloc_project = pglGetUniformLocation(shader_program, "project"); + uloc_modelview = pglGetUniformLocation(shader_program, "modelview"); + + /* Compute the projection matrix */ + f = 1.0f / tanf(view_angle / 2.0f); + projection_matrix[0] = f / aspect_ratio; + projection_matrix[5] = f; + projection_matrix[10] = (z_far + z_near)/ (z_near - z_far); + projection_matrix[11] = -1.0f; + projection_matrix[14] = 2.0f * (z_far * z_near) / (z_near - z_far); + pglUniformMatrix4fv(uloc_project, 1, GL_FALSE, projection_matrix); + + /* Set the camera position */ + modelview_matrix[12] = -5.0f; + modelview_matrix[13] = -5.0f; + modelview_matrix[14] = -20.0f; + pglUniformMatrix4fv(uloc_modelview, 1, GL_FALSE, modelview_matrix); + + /* Create mesh data */ + init_map(); + make_mesh(shader_program); + + /* Create vao + vbo to store the mesh */ + /* Create the vbo to store all the information for the grid and the height */ + + /* setup the scene ready for rendering */ + glViewport(0, 0, 800, 600); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + /* main loop */ + frame = 0; + iter = 0; + dt = last_update_time = glfwGetTime(); + + while (running) + { + ++frame; + /* render the next frame */ + glClear(GL_COLOR_BUFFER_BIT); + glDrawElements(GL_LINES, 2* MAP_NUM_LINES , GL_UNSIGNED_INT, 0); + + /* display and process events through callbacks */ + glfwSwapBuffers(); + /* Check the frame rate and update the heightmap if needed */ + dt = glfwGetTime(); + if ((dt - last_update_time) > 0.2) + { + /* generate the next iteration of the heightmap */ + if (iter < MAX_ITER) + { + update_map(NUM_ITER_AT_A_TIME); + update_mesh(); + iter += NUM_ITER_AT_A_TIME; + } + last_update_time = dt; + frame = 0; + } + } + + exit(EXIT_SUCCESS); +} + diff --git a/tests/glfw/listmodes.c b/tests/glfw/listmodes.c new file mode 100644 index 0000000000000..717cfde0c66dc --- /dev/null +++ b/tests/glfw/listmodes.c @@ -0,0 +1,48 @@ +//======================================================================== +// This is a small test application for GLFW. +// The program lists all available fullscreen video modes. +//======================================================================== + +#include +#include + +// Maximum number of modes that we want to list +#define MAX_NUM_MODES 400 + + +//======================================================================== +// main() +//======================================================================== + +int main( void ) +{ + GLFWvidmode dtmode, modes[ MAX_NUM_MODES ]; + int modecount, i; + + // Initialize GLFW + if( !glfwInit() ) + { + return 0; + } + + // Show desktop video mode + glfwGetDesktopMode( &dtmode ); + printf( "Desktop mode: %d x %d x %d\n\n", + dtmode.Width, dtmode.Height, dtmode.RedBits + + dtmode.GreenBits + dtmode.BlueBits ); + + // List available video modes + modecount = glfwGetVideoModes( modes, MAX_NUM_MODES ); + printf( "Available modes:\n" ); + for( i = 0; i < modecount; i ++ ) + { + printf( "%3d: %d x %d x %d\n", i, + modes[i].Width, modes[i].Height, modes[i].RedBits + + modes[i].GreenBits + modes[i].BlueBits ); + } + + // Terminate GLFW + glfwTerminate(); + + return 0; +} diff --git a/tests/glfw/mipmaps.c b/tests/glfw/mipmaps.c new file mode 100644 index 0000000000000..59bbef2e33774 --- /dev/null +++ b/tests/glfw/mipmaps.c @@ -0,0 +1,122 @@ +//======================================================================== +// This is an example program for the GLFW library +// +// It shows texture loading with mipmap generation and rendering with +// trilienar texture filtering +//======================================================================== + +#include +#include + +#include + +int main( void ) +{ + int width, height, x; + double time; + GLboolean running; + GLuint textureID; + char* texturePath = "mipmaps.tga"; + + // Initialise GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open OpenGL window + if( !glfwOpenWindow( 640, 480, 0,0,0,0, 0,0, GLFW_WINDOW ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + glfwSetWindowTitle( "Trilinear interpolation" ); + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Enable vertical sync (on cards that support it) + glfwSwapInterval( 1 ); + + // Generate and bind our texture ID + glGenTextures( 1, &textureID ); + glBindTexture( GL_TEXTURE_2D, textureID ); + + // Load texture from file into video memory, including mipmap levels + if( !glfwLoadTexture2D( texturePath, GLFW_BUILD_MIPMAPS_BIT ) ) + { + fprintf( stderr, "Failed to load texture %s\n", texturePath ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + // Use trilinear interpolation (GL_LINEAR_MIPMAP_LINEAR) + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + GL_LINEAR ); + + // Enable plain 2D texturing + glEnable( GL_TEXTURE_2D ); + + running = GL_TRUE; + while( running ) + { + // Get time and mouse position + time = glfwGetTime(); + glfwGetMousePos( &x, NULL ); + + // Get window size (may be different than the requested size) + glfwGetWindowSize( &width, &height ); + height = height > 0 ? height : 1; + + // Set viewport + glViewport( 0, 0, width, height ); + + // Clear color buffer + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); + glClear( GL_COLOR_BUFFER_BIT ); + + // Select and setup the projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 65.0f, (GLfloat)width / (GLfloat)height, 1.0f, + 50.0f ); + + // Select and setup the modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 0.0f, 3.0f, -20.0f, // Eye-position + 0.0f, -4.0f, -11.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + + // Draw a textured quad + glRotatef( 0.05f * (GLfloat)x + (GLfloat)time * 5.0f, 0.0f, 1.0f, 0.0f ); + glBegin( GL_QUADS ); + glTexCoord2f( -20.0f, 20.0f ); + glVertex3f( -50.0f, 0.0f, -50.0f ); + glTexCoord2f( 20.0f, 20.0f ); + glVertex3f( 50.0f, 0.0f, -50.0f ); + glTexCoord2f( 20.0f, -20.0f ); + glVertex3f( 50.0f, 0.0f, 50.0f ); + glTexCoord2f( -20.0f, -20.0f ); + glVertex3f( -50.0f, 0.0f, 50.0f ); + glEnd(); + + // Swap buffers + glfwSwapBuffers(); + + // Check if the ESC key was pressed or the window was closed + running = !glfwGetKey( GLFW_KEY_ESC ) && + glfwGetWindowParam( GLFW_OPENED ); + } + + // Close OpenGL window and terminate GLFW + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/tests/glfw/mipmaps.tga b/tests/glfw/mipmaps.tga new file mode 100644 index 0000000000000000000000000000000000000000..55f913b0fa48f69b163664da1db6f9b1fe80e2ed GIT binary patch literal 66322 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 +#include + + +typedef struct { + GLFWcond cond; + GLFWmutex mutex; + int flag; +} signal_t; + + +signal_t gotoA, gotoB; + +GLFWcond threadDone; +GLFWmutex doneMutex; +int doneCount; +int gotoACount, gotoBCount; + +#define MAX_COUNT 10000 + + +//------------------------------------------------------------------------ +// InitSignal() +//------------------------------------------------------------------------ + +void InitSignal( signal_t *s ) +{ + s->cond = glfwCreateCond(); + s->mutex = glfwCreateMutex(); + s->flag = 0; +} + + +//------------------------------------------------------------------------ +// KillSignal() +//------------------------------------------------------------------------ + +void KillSignal( signal_t *s ) +{ + glfwDestroyCond( s->cond ); + glfwDestroyMutex( s->mutex ); + s->flag = 0; +} + + +//------------------------------------------------------------------------ +// WaitSignal() +//------------------------------------------------------------------------ + +void WaitSignal( signal_t *s ) +{ + glfwLockMutex( s->mutex ); + while( !s->flag ) + { + glfwWaitCond( s->cond, s->mutex, GLFW_INFINITY ); + } + s->flag = 0; + glfwUnlockMutex( s->mutex ); +} + + +//------------------------------------------------------------------------ +// SetSignal() +//------------------------------------------------------------------------ + +void SetSignal( signal_t *s ) +{ + glfwLockMutex( s->mutex ); + s->flag = 1; + glfwUnlockMutex( s->mutex ); + glfwSignalCond( s->cond ); +} + + +//------------------------------------------------------------------------ +// threadAfun() +//------------------------------------------------------------------------ + +void GLFWCALL threadAfun( void * arg ) +{ + int done; + + do + { + done = (gotoACount >= MAX_COUNT); + if( !done ) + { + gotoACount ++; + SetSignal( &gotoB ); + WaitSignal( &gotoA ); + } + } + while( !done ); + + SetSignal( &gotoB ); + + glfwLockMutex( doneMutex ); + doneCount ++; + glfwUnlockMutex( doneMutex ); + glfwSignalCond( threadDone ); +} + + +//------------------------------------------------------------------------ +// threadBfun() +//------------------------------------------------------------------------ + +void GLFWCALL threadBfun( void * arg ) +{ + int done; + + do + { + done = (gotoBCount >= MAX_COUNT); + if( !done ) + { + gotoBCount ++; + SetSignal( &gotoA ); + WaitSignal( &gotoB ); + } + } + while( !done ); + + SetSignal( &gotoA ); + + glfwLockMutex( doneMutex ); + doneCount ++; + glfwUnlockMutex( doneMutex ); + glfwSignalCond( threadDone ); +} + + + +//------------------------------------------------------------------------ +// main() +//------------------------------------------------------------------------ + +int main( void ) +{ + GLFWthread threadA, threadB; + double t1, t2, csps; + int done, count, i; + + gotoACount = gotoBCount = doneCount = 0; + + // Initialize GLFW + if( !glfwInit() ) + { + return 0; + } + + // Print some program information + printf( "\nMultithreading benchmarking program\n" ); + printf( "-----------------------------------\n\n" ); + printf( "This program consists of two tests. In the first test " ); + printf( "two threads are created,\n" ); + printf( "which continously signal/wait each other. This forces " ); + printf( "the execution to\n" ); + printf( "alternate between the two threads, and gives a measure " ); + printf( "of the thread\n" ); + printf( "synchronization granularity. In the second test, the " ); + printf( "main thread is repeatedly\n" ); + printf( "put to sleep for a very short interval using glfwSleep. " ); + printf( "The average sleep time\n" ); + printf( "is measured, which tells the minimum supported sleep " ); + printf( "interval.\n\n" ); + printf( "Results:\n" ); + printf( "--------\n\n" ); + printf( "Number of CPUs: %d\n\n", glfwGetNumberOfProcessors() ); + fflush( stdout ); + + +//------------------------------------------------------------------------ +// 1) Benchmark thread synchronization granularity +//------------------------------------------------------------------------ + + // Init mutexes and conditions + doneMutex = glfwCreateMutex(); + threadDone = glfwCreateCond(); + InitSignal( &gotoA ); + InitSignal( &gotoB ); + + // Create threads A & B + threadA = glfwCreateThread( threadAfun, NULL ); + threadB = glfwCreateThread( threadBfun, NULL ); + if( threadA == -1 || threadB == -1 ) + { + glfwLockMutex( doneMutex ); + doneCount = 2; + glfwUnlockMutex( doneMutex ); + } + + // Wait for both threads to be done + t1 = glfwGetTime(); + glfwLockMutex( doneMutex ); + do + { + done = (doneCount == 2); + if( !done ) + { + glfwWaitCond( threadDone, doneMutex, GLFW_INFINITY ); + } + } + while( !done ); + glfwUnlockMutex( doneMutex ); + t2 = glfwGetTime(); + + // Display results + count = gotoACount + gotoBCount; + csps = (double)count / (t2-t1); + printf( "Test 1: %.0f context switches / second (%.3f us/switch)\n", + csps, 1e6/csps ); + fflush( stdout ); + + // Wait for threads to die + glfwWaitThread( threadA, GLFW_WAIT ); + glfwWaitThread( threadB, GLFW_WAIT ); + + // Destroy mutexes and conditions + glfwDestroyMutex( doneMutex ); + glfwDestroyCond( threadDone ); + KillSignal( &gotoA ); + KillSignal( &gotoB ); + + +//------------------------------------------------------------------------ +// 2) Benchmark thread sleep granularity +//------------------------------------------------------------------------ + + // Find an initial estimate + t1 = glfwGetTime(); + for( i = 0; i < 10; i ++ ) + { + glfwSleep( 0.0001 ); + } + t2 = glfwGetTime(); + + // Sleep for roughly 1 s + count = (int)(1.0 / ((t2-t1)/10.0)); + t1 = glfwGetTime(); + for( i = 0; i < count; i ++ ) + { + glfwSleep( 0.0001 ); + } + t2 = glfwGetTime(); + + // Display results + printf( "Test 2: %.3f ms / sleep (mean)\n\n", + 1000.0 * (t2-t1) / (double)count ); + + // Terminate GLFW + glfwTerminate(); + + return 0; +} diff --git a/tests/glfw/mthello.c b/tests/glfw/mthello.c new file mode 100644 index 0000000000000..e12dea52551e9 --- /dev/null +++ b/tests/glfw/mthello.c @@ -0,0 +1,48 @@ +//======================================================================== +// This is a small test application for GLFW. +// The program prints "Hello world!", using two threads. +//======================================================================== + +#include +#include + + +//======================================================================== +// HelloFun() - Thread function +//======================================================================== + +void GLFWCALL HelloFun( void *arg ) +{ + // Print the first part of the message + printf( "Hello " ); +} + + +//======================================================================== +// main() - Main function (main thread) +//======================================================================== + +int main( void ) +{ + GLFWthread thread; + + // Initialise GLFW + if( !glfwInit() ) + { + return 0; + } + + // Create thread + thread = glfwCreateThread( HelloFun, NULL ); + + // Wait for thread to die + glfwWaitThread( thread, GLFW_WAIT ); + + // Print the rest of the message + printf( "world!\n" ); + + // Terminate GLFW + glfwTerminate(); + + return 0; +} diff --git a/tests/glfw/particles.c b/tests/glfw/particles.c new file mode 100644 index 0000000000000..403a99978e9fa --- /dev/null +++ b/tests/glfw/particles.c @@ -0,0 +1,1152 @@ +//======================================================================== +// This is a simple, but cool particle engine (buzz-word meaning many +// small objects that are treated as points and drawn as textures +// projected on simple geometry). +// +// This demonstration generates a colorful fountain-like animation. It +// uses several advanced OpenGL teqhniques: +// +// 1) Lighting (per vertex) +// 2) Alpha blending +// 3) Fog +// 4) Texturing +// 5) Display lists (for drawing the static environment geometry) +// 6) Vertex arrays (for drawing the particles) +// 7) GL_EXT_separate_specular_color is used (if available) +// +// Even more so, this program uses multi threading. The program is +// essentialy divided into a main rendering thread and a particle physics +// calculation thread. My benchmarks under Windows 2000 on a single +// processor system show that running this program as two threads instead +// of a single thread means no difference (there may be a very marginal +// advantage for the multi threaded case). On dual processor systems I +// have had reports of 5-25% of speed increase when running this program +// as two threads instead of one thread. +// +// The default behaviour of this program is to use two threads. To force +// a single thread to be used, use the command line switch -s. +// +// To run a fixed length benchmark (60 s), use the command line switch -b. +// +// Benchmark results (640x480x16, best of three tests): +// +// CPU GFX 1 thread 2 threads +// Athlon XP 2700+ GeForce Ti4200 (oc) 757 FPS 759 FPS +// P4 2.8 GHz (SMT) GeForce FX5600 548 FPS 550 FPS +// +// One more thing: Press 'w' during the demo to toggle wireframe mode. +//======================================================================== + +#include +#include +#include +#include +#include + +// Define tokens for GL_EXT_separate_specular_color if not already defined +#ifndef GL_EXT_separate_specular_color +#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 +#define GL_SINGLE_COLOR_EXT 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA +#endif // GL_EXT_separate_specular_color + +// Some 's do not define M_PI +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +// Desired fullscreen resolution +#define WIDTH 640 +#define HEIGHT 480 + + +//======================================================================== +// Type definitions +//======================================================================== + +typedef struct { float x,y,z; } VEC; + +// This structure is used for interleaved vertex arrays (see the +// DrawParticles function) - Note: This structure SHOULD be packed on most +// systems. It uses 32-bit fields on 32-bit boundaries, and is a multiple +// of 64 bits in total (6x32=3x64). If it does not work, try using pragmas +// or whatever to force the structure to be packed. +typedef struct { + GLfloat s, t; // Texture coordinates + GLuint rgba; // Color (four ubytes packed into an uint) + GLfloat x, y, z; // Vertex coordinates +} VERTEX; + + +//======================================================================== +// Program control global variables +//======================================================================== + +// "Running" flag (true if program shall continue to run) +int running; + +// Window dimensions +int width, height; + +// "wireframe" flag (true if we use wireframe view) +int wireframe; + +// "multithreading" flag (true if we use multithreading) +int multithreading; + +// Thread synchronization +struct { + double t; // Time (s) + float dt; // Time since last frame (s) + int p_frame; // Particle physics frame number + int d_frame; // Particle draw frame number + GLFWcond p_done; // Condition: particle physics done + GLFWcond d_done; // Condition: particle draw done + GLFWmutex particles_lock; // Particles data sharing mutex +} thread_sync; + + +//======================================================================== +// Texture declarations (we hard-code them into the source code, since +// they are so simple) +//======================================================================== + +#define P_TEX_WIDTH 8 // Particle texture dimensions +#define P_TEX_HEIGHT 8 +#define F_TEX_WIDTH 16 // Floor texture dimensions +#define F_TEX_HEIGHT 16 + +// Texture object IDs +GLuint particle_tex_id, floor_tex_id; + +// Particle texture (a simple spot) +const unsigned char particle_texture[ P_TEX_WIDTH * P_TEX_HEIGHT ] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x11, 0x22, 0x22, 0x11, 0x00, 0x00, + 0x00, 0x11, 0x33, 0x88, 0x77, 0x33, 0x11, 0x00, + 0x00, 0x22, 0x88, 0xff, 0xee, 0x77, 0x22, 0x00, + 0x00, 0x22, 0x77, 0xee, 0xff, 0x88, 0x22, 0x00, + 0x00, 0x11, 0x33, 0x77, 0x88, 0x33, 0x11, 0x00, + 0x00, 0x00, 0x11, 0x33, 0x22, 0x11, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// Floor texture (your basic checkered floor) +const unsigned char floor_texture[ F_TEX_WIDTH * F_TEX_HEIGHT ] = { + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xff, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xf0, 0xcc, 0xee, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x66, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xee, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x55, 0x30, 0x30, 0x44, 0x30, 0x30, + 0xf0, 0xdd, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x60, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, 0xf0, 0xff, 0xf0, 0xf0, 0xdd, 0xf0, 0xf0, 0xff, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x55, 0x33, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, + 0x30, 0x44, 0x66, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xaa, 0xf0, 0xf0, 0xcc, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xdd, 0xf0, + 0x30, 0x30, 0x30, 0x77, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +}; + + +//======================================================================== +// These are fixed constants that control the particle engine. In a +// modular world, these values should be variables... +//======================================================================== + +// Maximum number of particles +#define MAX_PARTICLES 3000 + +// Life span of a particle (in seconds) +#define LIFE_SPAN 8.0f + +// A new particle is born every [BIRTH_INTERVAL] second +#define BIRTH_INTERVAL (LIFE_SPAN/(float)MAX_PARTICLES) + +// Particle size (meters) +#define PARTICLE_SIZE 0.7f + +// Gravitational constant (m/s^2) +#define GRAVITY 9.8f + +// Base initial velocity (m/s) +#define VELOCITY 8.0f + +// Bounce friction (1.0 = no friction, 0.0 = maximum friction) +#define FRICTION 0.75f + +// "Fountain" height (m) +#define FOUNTAIN_HEIGHT 3.0f + +// Fountain radius (m) +#define FOUNTAIN_RADIUS 1.6f + +// Minimum delta-time for particle phisics (s) +#define MIN_DELTA_T (BIRTH_INTERVAL * 0.5f) + + +//======================================================================== +// Particle system global variables +//======================================================================== + +// This structure holds all state for a single particle +typedef struct { + float x,y,z; // Position in space + float vx,vy,vz; // Velocity vector + float r,g,b; // Color of particle + float life; // Life of particle (1.0 = newborn, < 0.0 = dead) + int active; // Tells if this particle is active +} PARTICLE; + +// Global vectors holding all particles. We use two vectors for double +// buffering. +static PARTICLE particles[ MAX_PARTICLES ]; + +// Global variable holding the age of the youngest particle +static float min_age; + +// Color of latest born particle (used for fountain lighting) +static float glow_color[4]; + +// Position of latest born particle (used for fountain lighting) +static float glow_pos[4]; + + +//======================================================================== +// Object material and fog configuration constants +//======================================================================== + +const GLfloat fountain_diffuse[4] = {0.7f,1.0f,1.0f,1.0f}; +const GLfloat fountain_specular[4] = {1.0f,1.0f,1.0f,1.0f}; +const GLfloat fountain_shininess = 12.0f; +const GLfloat floor_diffuse[4] = {1.0f,0.6f,0.6f,1.0f}; +const GLfloat floor_specular[4] = {0.6f,0.6f,0.6f,1.0f}; +const GLfloat floor_shininess = 18.0f; +const GLfloat fog_color[4] = {0.1f, 0.1f, 0.1f, 1.0f}; + + +//======================================================================== +// InitParticle() - Initialize a new particle +//======================================================================== + +void InitParticle( PARTICLE *p, double t ) +{ + float xy_angle, velocity; + + // Start position of particle is at the fountain blow-out + p->x = 0.0f; + p->y = 0.0f; + p->z = FOUNTAIN_HEIGHT; + + // Start velocity is up (Z)... + p->vz = 0.7f + (0.3f/4096.f) * (float) (rand() & 4095); + + // ...and a randomly chosen X/Y direction + xy_angle = (2.f * (float)M_PI / 4096.f) * (float) (rand() & 4095); + p->vx = 0.4f * (float) cos( xy_angle ); + p->vy = 0.4f * (float) sin( xy_angle ); + + // Scale velocity vector according to a time-varying velocity + velocity = VELOCITY*(0.8f + 0.1f*(float)(sin( 0.5*t )+sin( 1.31*t ))); + p->vx *= velocity; + p->vy *= velocity; + p->vz *= velocity; + + // Color is time-varying + p->r = 0.7f + 0.3f * (float) sin( 0.34*t + 0.1 ); + p->g = 0.6f + 0.4f * (float) sin( 0.63*t + 1.1 ); + p->b = 0.6f + 0.4f * (float) sin( 0.91*t + 2.1 ); + + // Store settings for fountain glow lighting + glow_pos[0] = 0.4f * (float) sin( 1.34*t ); + glow_pos[1] = 0.4f * (float) sin( 3.11*t ); + glow_pos[2] = FOUNTAIN_HEIGHT + 1.0f; + glow_pos[3] = 1.0f; + glow_color[0] = p->r; + glow_color[1] = p->g; + glow_color[2] = p->b; + glow_color[3] = 1.0f; + + // The particle is new-born and active + p->life = 1.0f; + p->active = 1; +} + + +//======================================================================== +// UpdateParticle() - Update a particle +//======================================================================== + +#define FOUNTAIN_R2 (FOUNTAIN_RADIUS+PARTICLE_SIZE/2)*(FOUNTAIN_RADIUS+PARTICLE_SIZE/2) + +void UpdateParticle( PARTICLE *p, float dt ) +{ + // If the particle is not active, we need not do anything + if( !p->active ) + { + return; + } + + // The particle is getting older... + p->life = p->life - dt * (1.0f / LIFE_SPAN); + + // Did the particle die? + if( p->life <= 0.0f ) + { + p->active = 0; + return; + } + + // Update particle velocity (apply gravity) + p->vz = p->vz - GRAVITY * dt; + + // Update particle position + p->x = p->x + p->vx * dt; + p->y = p->y + p->vy * dt; + p->z = p->z + p->vz * dt; + + // Simple collision detection + response + if( p->vz < 0.0f ) + { + // Particles should bounce on the fountain (with friction) + if( (p->x*p->x + p->y*p->y) < FOUNTAIN_R2 && + p->z < (FOUNTAIN_HEIGHT + PARTICLE_SIZE/2) ) + { + p->vz = -FRICTION * p->vz; + p->z = FOUNTAIN_HEIGHT + PARTICLE_SIZE/2 + + FRICTION * (FOUNTAIN_HEIGHT + + PARTICLE_SIZE/2 - p->z); + } + + // Particles should bounce on the floor (with friction) + else if( p->z < PARTICLE_SIZE/2 ) + { + p->vz = -FRICTION * p->vz; + p->z = PARTICLE_SIZE/2 + + FRICTION * (PARTICLE_SIZE/2 - p->z); + } + + } +} + + +//======================================================================== +// ParticleEngine() - The main frame for the particle engine. Called once +// per frame. +//======================================================================== + +void ParticleEngine( double t, float dt ) +{ + int i; + float dt2; + + // Update particles (iterated several times per frame if dt is too + // large) + while( dt > 0.0f ) + { + // Calculate delta time for this iteration + dt2 = dt < MIN_DELTA_T ? dt : MIN_DELTA_T; + + // Update particles + for( i = 0; i < MAX_PARTICLES; i ++ ) + { + UpdateParticle( &particles[ i ], dt2 ); + } + + // Increase minimum age + min_age += dt2; + + // Should we create any new particle(s)? + while( min_age >= BIRTH_INTERVAL ) + { + min_age -= BIRTH_INTERVAL; + + // Find a dead particle to replace with a new one + for( i = 0; i < MAX_PARTICLES; i ++ ) + { + if( !particles[ i ].active ) + { + InitParticle( &particles[ i ], t + min_age ); + UpdateParticle( &particles[ i ], min_age ); + break; + } + } + } + + // Decrease frame delta time + dt -= dt2; + } +} + + +//======================================================================== +// DrawParticles() - Draw all active particles. We use OpenGL 1.1 vertex +// arrays for this in order to accelerate the drawing. +//======================================================================== + +#define BATCH_PARTICLES 70 // Number of particles to draw in each batch + // (70 corresponds to 7.5 KB = will not blow + // the L1 data cache on most CPUs) +#define PARTICLE_VERTS 4 // Number of vertices per particle + +void DrawParticles( double t, float dt ) +{ + int i, particle_count; + VERTEX vertex_array[ BATCH_PARTICLES * PARTICLE_VERTS ], *vptr; + float alpha; + GLuint rgba; + VEC quad_lower_left, quad_lower_right; + GLfloat mat[ 16 ]; + PARTICLE *pptr; + + // Here comes the real trick with flat single primitive objects (s.c. + // "billboards"): We must rotate the textured primitive so that it + // always faces the viewer (is coplanar with the view-plane). + // We: + // 1) Create the primitive around origo (0,0,0) + // 2) Rotate it so that it is coplanar with the view plane + // 3) Translate it according to the particle position + // Note that 1) and 2) is the same for all particles (done only once). + + // Get modelview matrix. We will only use the upper left 3x3 part of + // the matrix, which represents the rotation. + glGetFloatv( GL_MODELVIEW_MATRIX, mat ); + + // 1) & 2) We do it in one swift step: + // Although not obvious, the following six lines represent two matrix/ + // vector multiplications. The matrix is the inverse 3x3 rotation + // matrix (i.e. the transpose of the same matrix), and the two vectors + // represent the lower left corner of the quad, PARTICLE_SIZE/2 * + // (-1,-1,0), and the lower right corner, PARTICLE_SIZE/2 * (1,-1,0). + // The upper left/right corners of the quad is always the negative of + // the opposite corners (regardless of rotation). + quad_lower_left.x = (-PARTICLE_SIZE/2) * (mat[0] + mat[1]); + quad_lower_left.y = (-PARTICLE_SIZE/2) * (mat[4] + mat[5]); + quad_lower_left.z = (-PARTICLE_SIZE/2) * (mat[8] + mat[9]); + quad_lower_right.x = (PARTICLE_SIZE/2) * (mat[0] - mat[1]); + quad_lower_right.y = (PARTICLE_SIZE/2) * (mat[4] - mat[5]); + quad_lower_right.z = (PARTICLE_SIZE/2) * (mat[8] - mat[9]); + + // Don't update z-buffer, since all particles are transparent! + glDepthMask( GL_FALSE ); + + // Enable blending + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE ); + + // Select particle texture + if( !wireframe ) + { + glEnable( GL_TEXTURE_2D ); + glBindTexture( GL_TEXTURE_2D, particle_tex_id ); + } + + // Set up vertex arrays. We use interleaved arrays, which is easier to + // handle (in most situations) and it gives a linear memeory access + // access pattern (which may give better performance in some + // situations). GL_T2F_C4UB_V3F means: 2 floats for texture coords, + // 4 ubytes for color and 3 floats for vertex coord (in that order). + // Most OpenGL cards / drivers are optimized for this format. + glInterleavedArrays( GL_T2F_C4UB_V3F, 0, vertex_array ); + + // Is particle physics carried out in a separate thread? + if( multithreading ) + { + // Wait for particle physics thread to be done + glfwLockMutex( thread_sync.particles_lock ); + while( running && thread_sync.p_frame <= thread_sync.d_frame ) + { + glfwWaitCond( thread_sync.p_done, thread_sync.particles_lock, + 0.1 ); + } + + // Store the frame time and delta time for the physics thread + thread_sync.t = t; + thread_sync.dt = dt; + + // Update frame counter + thread_sync.d_frame ++; + } + else + { + // Perform particle physics in this thread + ParticleEngine( t, dt ); + } + + // Loop through all particles and build vertex arrays. + particle_count = 0; + vptr = vertex_array; + pptr = particles; + for( i = 0; i < MAX_PARTICLES; i ++ ) + { + if( pptr->active ) + { + // Calculate particle intensity (we set it to max during 75% + // of its life, then it fades out) + alpha = 4.0f * pptr->life; + if( alpha > 1.0f ) + { + alpha = 1.0f; + } + + // Convert color from float to 8-bit (store it in a 32-bit + // integer using endian independent type casting) + ((GLubyte *)&rgba)[0] = (GLubyte)(pptr->r * 255.0f); + ((GLubyte *)&rgba)[1] = (GLubyte)(pptr->g * 255.0f); + ((GLubyte *)&rgba)[2] = (GLubyte)(pptr->b * 255.0f); + ((GLubyte *)&rgba)[3] = (GLubyte)(alpha * 255.0f); + + // 3) Translate the quad to the correct position in modelview + // space and store its parameters in vertex arrays (we also + // store texture coord and color information for each vertex). + + // Lower left corner + vptr->s = 0.0f; + vptr->t = 0.0f; + vptr->rgba = rgba; + vptr->x = pptr->x + quad_lower_left.x; + vptr->y = pptr->y + quad_lower_left.y; + vptr->z = pptr->z + quad_lower_left.z; + vptr ++; + + // Lower right corner + vptr->s = 1.0f; + vptr->t = 0.0f; + vptr->rgba = rgba; + vptr->x = pptr->x + quad_lower_right.x; + vptr->y = pptr->y + quad_lower_right.y; + vptr->z = pptr->z + quad_lower_right.z; + vptr ++; + + // Upper right corner + vptr->s = 1.0f; + vptr->t = 1.0f; + vptr->rgba = rgba; + vptr->x = pptr->x - quad_lower_left.x; + vptr->y = pptr->y - quad_lower_left.y; + vptr->z = pptr->z - quad_lower_left.z; + vptr ++; + + // Upper left corner + vptr->s = 0.0f; + vptr->t = 1.0f; + vptr->rgba = rgba; + vptr->x = pptr->x - quad_lower_right.x; + vptr->y = pptr->y - quad_lower_right.y; + vptr->z = pptr->z - quad_lower_right.z; + vptr ++; + + // Increase count of drawable particles + particle_count ++; + } + + // If we have filled up one batch of particles, draw it as a set + // of quads using glDrawArrays. + if( particle_count >= BATCH_PARTICLES ) + { + // The first argument tells which primitive type we use (QUAD) + // The second argument tells the index of the first vertex (0) + // The last argument is the vertex count + glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count ); + particle_count = 0; + vptr = vertex_array; + } + + // Next particle + pptr ++; + } + + // We are done with the particle data: Unlock mutex and signal physics + // thread + if( multithreading ) + { + glfwUnlockMutex( thread_sync.particles_lock ); + glfwSignalCond( thread_sync.d_done ); + } + + // Draw final batch of particles (if any) + glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count ); + + // Disable vertex arrays (Note: glInterleavedArrays implicitly called + // glEnableClientState for vertex, texture coord and color arrays) + glDisableClientState( GL_VERTEX_ARRAY ); + glDisableClientState( GL_TEXTURE_COORD_ARRAY ); + glDisableClientState( GL_COLOR_ARRAY ); + + // Disable texturing and blending + glDisable( GL_TEXTURE_2D ); + glDisable( GL_BLEND ); + + // Allow Z-buffer updates again + glDepthMask( GL_TRUE ); +} + + +//======================================================================== +// Fountain geometry specification +//======================================================================== + +#define FOUNTAIN_SIDE_POINTS 14 +#define FOUNTAIN_SWEEP_STEPS 32 + +static const float fountain_side[ FOUNTAIN_SIDE_POINTS*2 ] = { + 1.2f, 0.0f, 1.0f, 0.2f, 0.41f, 0.3f, 0.4f, 0.35f, + 0.4f, 1.95f, 0.41f, 2.0f, 0.8f, 2.2f, 1.2f, 2.4f, + 1.5f, 2.7f, 1.55f,2.95f, 1.6f, 3.0f, 1.0f, 3.0f, + 0.5f, 3.0f, 0.0f, 3.0f +}; + +static const float fountain_normal[ FOUNTAIN_SIDE_POINTS*2 ] = { + 1.0000f, 0.0000f, 0.6428f, 0.7660f, 0.3420f, 0.9397f, 1.0000f, 0.0000f, + 1.0000f, 0.0000f, 0.3420f,-0.9397f, 0.4226f,-0.9063f, 0.5000f,-0.8660f, + 0.7660f,-0.6428f, 0.9063f,-0.4226f, 0.0000f,1.00000f, 0.0000f,1.00000f, + 0.0000f,1.00000f, 0.0000f,1.00000f +}; + + +//======================================================================== +// DrawFountain() - Draw a fountain +//======================================================================== + +void DrawFountain( void ) +{ + static GLuint fountain_list = 0; + double angle; + float x, y; + int m, n; + + // The first time, we build the fountain display list + if( !fountain_list ) + { + // Start recording of a new display list + fountain_list = glGenLists( 1 ); + glNewList( fountain_list, GL_COMPILE_AND_EXECUTE ); + + // Set fountain material + glMaterialfv( GL_FRONT, GL_DIFFUSE, fountain_diffuse ); + glMaterialfv( GL_FRONT, GL_SPECULAR, fountain_specular ); + glMaterialf( GL_FRONT, GL_SHININESS, fountain_shininess ); + + // Build fountain using triangle strips + for( n = 0; n < FOUNTAIN_SIDE_POINTS-1; n ++ ) + { + glBegin( GL_TRIANGLE_STRIP ); + for( m = 0; m <= FOUNTAIN_SWEEP_STEPS; m ++ ) + { + angle = (double) m * (2.0*M_PI/(double)FOUNTAIN_SWEEP_STEPS); + x = (float) cos( angle ); + y = (float) sin( angle ); + + // Draw triangle strip + glNormal3f( x * fountain_normal[ n*2+2 ], + y * fountain_normal[ n*2+2 ], + fountain_normal[ n*2+3 ] ); + glVertex3f( x * fountain_side[ n*2+2 ], + y * fountain_side[ n*2+2 ], + fountain_side[ n*2+3 ] ); + glNormal3f( x * fountain_normal[ n*2 ], + y * fountain_normal[ n*2 ], + fountain_normal[ n*2+1 ] ); + glVertex3f( x * fountain_side[ n*2 ], + y * fountain_side[ n*2 ], + fountain_side[ n*2+1 ] ); + } + glEnd(); + } + + // End recording of display list + glEndList(); + } + else + { + // Playback display list + glCallList( fountain_list ); + } +} + + +//======================================================================== +// TesselateFloor() - Recursive function for building variable tesselated +// floor +//======================================================================== + +void TesselateFloor( float x1, float y1, float x2, float y2, + int recursion ) +{ + float delta, x, y; + + // Last recursion? + if( recursion >= 5 ) + { + delta = 999999.0f; + } + else + { + x = (float) (fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2)); + y = (float) (fabs(y1) < fabs(y2) ? fabs(y1) : fabs(y2)); + delta = x*x + y*y; + } + + // Recurse further? + if( delta < 0.1f ) + { + x = (x1+x2) * 0.5f; + y = (y1+y2) * 0.5f; + TesselateFloor( x1,y1, x, y, recursion + 1 ); + TesselateFloor( x,y1, x2, y, recursion + 1 ); + TesselateFloor( x1, y, x,y2, recursion + 1 ); + TesselateFloor( x, y, x2,y2, recursion + 1 ); + } + else + { + glTexCoord2f( x1*30.0f, y1*30.0f ); + glVertex3f( x1*80.0f, y1*80.0f , 0.0f ); + glTexCoord2f( x2*30.0f, y1*30.0f ); + glVertex3f( x2*80.0f, y1*80.0f , 0.0f ); + glTexCoord2f( x2*30.0f, y2*30.0f ); + glVertex3f( x2*80.0f, y2*80.0f , 0.0f ); + glTexCoord2f( x1*30.0f, y2*30.0f ); + glVertex3f( x1*80.0f, y2*80.0f , 0.0f ); + } +} + + +//======================================================================== +// DrawFloor() - Draw floor. We builde the floor recursively, and let the +// tesselation in the centre (near x,y=0,0) be high, while the selleation +// around the edges be low. +//======================================================================== + +void DrawFloor( void ) +{ + static GLuint floor_list = 0; + + // Select floor texture + if( !wireframe ) + { + glEnable( GL_TEXTURE_2D ); + glBindTexture( GL_TEXTURE_2D, floor_tex_id ); + } + + // The first time, we build the floor display list + if( !floor_list ) + { + // Start recording of a new display list + floor_list = glGenLists( 1 ); + glNewList( floor_list, GL_COMPILE_AND_EXECUTE ); + + // Set floor material + glMaterialfv( GL_FRONT, GL_DIFFUSE, floor_diffuse ); + glMaterialfv( GL_FRONT, GL_SPECULAR, floor_specular ); + glMaterialf( GL_FRONT, GL_SHININESS, floor_shininess ); + + // Draw floor as a bunch of triangle strips (high tesselation + // improves lighting) + glNormal3f( 0.0f, 0.0f, 1.0f ); + glBegin( GL_QUADS ); + TesselateFloor( -1.0f,-1.0f, 0.0f,0.0f, 0 ); + TesselateFloor( 0.0f,-1.0f, 1.0f,0.0f, 0 ); + TesselateFloor( 0.0f, 0.0f, 1.0f,1.0f, 0 ); + TesselateFloor( -1.0f, 0.0f, 0.0f,1.0f, 0 ); + glEnd(); + + // End recording of display list + glEndList(); + } + else + { + // Playback display list + glCallList( floor_list ); + } + + glDisable( GL_TEXTURE_2D ); + +} + + +//======================================================================== +// SetupLights() - Position and configure light sources +//======================================================================== + +void SetupLights( void ) +{ + float l1pos[4], l1amb[4], l1dif[4], l1spec[4]; + float l2pos[4], l2amb[4], l2dif[4], l2spec[4]; + + // Set light source 1 parameters + l1pos[0] = 0.0f; l1pos[1] = -9.0f; l1pos[2] = 8.0f; l1pos[3] = 1.0f; + l1amb[0] = 0.2f; l1amb[1] = 0.2f; l1amb[2] = 0.2f; l1amb[3] = 1.0f; + l1dif[0] = 0.8f; l1dif[1] = 0.4f; l1dif[2] = 0.2f; l1dif[3] = 1.0f; + l1spec[0] = 1.0f; l1spec[1] = 0.6f; l1spec[2] = 0.2f; l1spec[3] = 0.0f; + + // Set light source 2 parameters + l2pos[0] = -15.0f; l2pos[1] = 12.0f; l2pos[2] = 1.5f; l2pos[3] = 1.0f; + l2amb[0] = 0.0f; l2amb[1] = 0.0f; l2amb[2] = 0.0f; l2amb[3] = 1.0f; + l2dif[0] = 0.2f; l2dif[1] = 0.4f; l2dif[2] = 0.8f; l2dif[3] = 1.0f; + l2spec[0] = 0.2f; l2spec[1] = 0.6f; l2spec[2] = 1.0f; l2spec[3] = 0.0f; + + // Configure light sources in OpenGL + glLightfv( GL_LIGHT1, GL_POSITION, l1pos ); + glLightfv( GL_LIGHT1, GL_AMBIENT, l1amb ); + glLightfv( GL_LIGHT1, GL_DIFFUSE, l1dif ); + glLightfv( GL_LIGHT1, GL_SPECULAR, l1spec ); + glLightfv( GL_LIGHT2, GL_POSITION, l2pos ); + glLightfv( GL_LIGHT2, GL_AMBIENT, l2amb ); + glLightfv( GL_LIGHT2, GL_DIFFUSE, l2dif ); + glLightfv( GL_LIGHT2, GL_SPECULAR, l2spec ); + glLightfv( GL_LIGHT3, GL_POSITION, glow_pos ); + glLightfv( GL_LIGHT3, GL_DIFFUSE, glow_color ); + glLightfv( GL_LIGHT3, GL_SPECULAR, glow_color ); + + // Enable light sources + glEnable( GL_LIGHT1 ); + glEnable( GL_LIGHT2 ); + glEnable( GL_LIGHT3 ); +} + + +//======================================================================== +// Draw() - Main rendering function +//======================================================================== + +void Draw( double t ) +{ + double xpos, ypos, zpos, angle_x, angle_y, angle_z; + static double t_old = 0.0; + float dt; + + // Calculate frame-to-frame delta time + dt = (float)(t-t_old); + t_old = t; + + // Setup viewport + glViewport( 0, 0, width, height ); + + // Clear color and Z-buffer + glClearColor( 0.1f, 0.1f, 0.1f, 1.0f ); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + // Setup projection + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 65.0, (double)width/(double)height, 1.0, 60.0 ); + + // Setup camera + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Rotate camera + angle_x = 90.0 - 10.0; + angle_y = 10.0 * sin( 0.3 * t ); + angle_z = 10.0 * t; + glRotated( -angle_x, 1.0, 0.0, 0.0 ); + glRotated( -angle_y, 0.0, 1.0, 0.0 ); + glRotated( -angle_z, 0.0, 0.0, 1.0 ); + + // Translate camera + xpos = 15.0 * sin( (M_PI/180.0) * angle_z ) + + 2.0 * sin( (M_PI/180.0) * 3.1 * t ); + ypos = -15.0 * cos( (M_PI/180.0) * angle_z ) + + 2.0 * cos( (M_PI/180.0) * 2.9 * t ); + zpos = 4.0 + 2.0 * cos( (M_PI/180.0) * 4.9 * t ); + glTranslated( -xpos, -ypos, -zpos ); + + // Enable face culling + glFrontFace( GL_CCW ); + glCullFace( GL_BACK ); + glEnable( GL_CULL_FACE ); + + // Enable lighting + SetupLights(); + glEnable( GL_LIGHTING ); + + // Enable fog (dim details far away) + glEnable( GL_FOG ); + glFogi( GL_FOG_MODE, GL_EXP ); + glFogf( GL_FOG_DENSITY, 0.05f ); + glFogfv( GL_FOG_COLOR, fog_color ); + + // Draw floor + DrawFloor(); + + // Enable Z-buffering + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_LEQUAL ); + glDepthMask( GL_TRUE ); + + // Draw fountain + DrawFountain(); + + // Disable fog & lighting + glDisable( GL_LIGHTING ); + glDisable( GL_FOG ); + + // Draw all particles (must be drawn after all solid objects have been + // drawn!) + DrawParticles( t, dt ); + + // Z-buffer not needed anymore + glDisable( GL_DEPTH_TEST ); +} + + +//======================================================================== +// Resize() - GLFW window resize callback function +//======================================================================== + +void GLFWCALL Resize( int x, int y ) +{ + width = x; + height = y > 0 ? y : 1; // Prevent division by zero in aspect calc. +} + + +//======================================================================== +// Input callback functions +//======================================================================== + +void GLFWCALL KeyFun( int key, int action ) +{ + if( action == GLFW_PRESS ) + { + switch( key ) + { + case GLFW_KEY_ESC: + running = 0; + break; + case 'W': + wireframe = !wireframe; + glPolygonMode( GL_FRONT_AND_BACK, + wireframe ? GL_LINE : GL_FILL ); + break; + default: + break; + } + } +} + + +//======================================================================== +// PhysicsThreadFun() - Thread for updating particle physics +//======================================================================== + +void GLFWCALL PhysicsThreadFun( void *arg ) +{ + while( running ) + { + // Lock mutex + glfwLockMutex( thread_sync.particles_lock ); + + // Wait for particle drawing to be done + while( running && thread_sync.p_frame > thread_sync.d_frame ) + { + glfwWaitCond( thread_sync.d_done, thread_sync.particles_lock, + 0.1 ); + } + + // No longer running? + if( !running ) + { + break; + } + + // Update particles + ParticleEngine( thread_sync.t, thread_sync.dt ); + + // Update frame counter + thread_sync.p_frame ++; + + // Unlock mutex and signal drawing thread + glfwUnlockMutex( thread_sync.particles_lock ); + glfwSignalCond( thread_sync.p_done ); + } +} + + +//======================================================================== +// main() +//======================================================================== + +int main( int argc, char **argv ) +{ + int i, frames, benchmark; + double t0, t; + GLFWthread physics_thread = 0; + + // Use multithreading by default, but don't benchmark + multithreading = 1; + benchmark = 0; + + // Check command line arguments + for( i = 1; i < argc; i ++ ) + { + // Use benchmarking? + if( strcmp( argv[i], "-b" ) == 0 ) + { + benchmark = 1; + } + + // Force multithreading off? + else if( strcmp( argv[i], "-s" ) == 0 ) + { + multithreading = 0; + } + + // With a Finder launch on Mac OS X we get a bogus -psn_0_46268417 + // kind of argument (actual numbers vary). Ignore it. + else if( strncmp( argv[i], "-psn_", 5) == 0 ); + + // Usage + else + { + if( strcmp( argv[i], "-?" ) != 0 ) + { + printf( "Unknonwn option %s\n\n", argv[ i ] ); + } + printf( "Usage: %s [options]\n", argv[ 0 ] ); + printf( "\n"); + printf( "Options:\n" ); + printf( " -b Benchmark (run program for 60 s)\n" ); + printf( " -s Run program as single thread (default is to use two threads)\n" ); + printf( " -? Display this text\n" ); + printf( "\n"); + printf( "Program runtime controls:\n" ); + printf( " w Toggle wireframe mode\n" ); + printf( " ESC Exit program\n" ); + exit( 0 ); + } + } + + // Initialize GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open OpenGL fullscreen window + if( !glfwOpenWindow( WIDTH, HEIGHT, 0,0,0,0, 16,0, GLFW_FULLSCREEN ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + // Set window title + glfwSetWindowTitle( "Particle engine" ); + + // Disable VSync (we want to get as high FPS as possible!) + glfwSwapInterval( 0 ); + + // Window resize callback function + glfwSetWindowSizeCallback( Resize ); + + // Set keyboard input callback function + glfwSetKeyCallback( KeyFun ); + + // Upload particle texture + glGenTextures( 1, &particle_tex_id ); + glBindTexture( GL_TEXTURE_2D, particle_tex_id ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, P_TEX_WIDTH, P_TEX_HEIGHT, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, particle_texture ); + + // Upload floor texture + glGenTextures( 1, &floor_tex_id ); + glBindTexture( GL_TEXTURE_2D, floor_tex_id ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, F_TEX_WIDTH, F_TEX_HEIGHT, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, floor_texture ); + + // Check if we have GL_EXT_separate_specular_color, and if so use it + if( glfwExtensionSupported( "GL_EXT_separate_specular_color" ) ) + { + glLightModeli( GL_LIGHT_MODEL_COLOR_CONTROL_EXT, + GL_SEPARATE_SPECULAR_COLOR_EXT ); + } + + // Set filled polygon mode as default (not wireframe) + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + wireframe = 0; + + // Clear particle system + for( i = 0; i < MAX_PARTICLES; i ++ ) + { + particles[ i ].active = 0; + } + min_age = 0.0f; + + // Set "running" flag + running = 1; + + // Set initial times + thread_sync.t = 0.0; + thread_sync.dt = 0.001f; + + // Init threading + if( multithreading ) + { + thread_sync.p_frame = 0; + thread_sync.d_frame = 0; + thread_sync.particles_lock = glfwCreateMutex(); + thread_sync.p_done = glfwCreateCond(); + thread_sync.d_done = glfwCreateCond(); + physics_thread = glfwCreateThread( PhysicsThreadFun, NULL ); + } + + // Main loop + t0 = glfwGetTime(); + frames = 0; + while( running ) + { + // Get frame time + t = glfwGetTime() - t0; + + // Draw... + Draw( t ); + + // Swap buffers + glfwSwapBuffers(); + + // Check if window was closed + running = running && glfwGetWindowParam( GLFW_OPENED ); + + // Increase frame count + frames ++; + + // End of benchmark? + if( benchmark && t >= 60.0 ) + { + running = 0; + } + } + t = glfwGetTime() - t0; + + // Wait for particle physics thread to die + if( multithreading ) + { + glfwWaitThread( physics_thread, GLFW_WAIT ); + } + + // Display profiling information + printf( "%d frames in %.2f seconds = %.1f FPS", frames, t, + (double)frames / t ); + printf( " (multithreading %s)\n", multithreading ? "on" : "off" ); + + // Terminate OpenGL + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/tests/glfw/pong3d.c b/tests/glfw/pong3d.c new file mode 100644 index 0000000000000..1d1afd1f1808d --- /dev/null +++ b/tests/glfw/pong3d.c @@ -0,0 +1,854 @@ +//======================================================================== +// This is a small test application for GLFW. +// This is an OpenGL port of the famous "PONG" game (the first computer +// game ever?). It is very simple, and could be improved alot. It was +// created in order to show off the gaming capabilities of GLFW. +//======================================================================== + +#include +#include +#include +#include + + +//======================================================================== +// Constants +//======================================================================== + +// Screen resolution +#define WIDTH 640 +#define HEIGHT 480 + +// Player size (units) +#define PLAYER_XSIZE 0.05f +#define PLAYER_YSIZE 0.15f + +// Ball size (units) +#define BALL_SIZE 0.02f + +// Maximum player movement speed (units / second) +#define MAX_SPEED 1.5f + +// Player movement acceleration (units / seconds^2) +#define ACCELERATION 4.0f + +// Player movement deceleration (units / seconds^2) +#define DECELERATION 2.0f + +// Ball movement speed (units / second) +#define BALL_SPEED 0.4f + +// Menu options +#define MENU_NONE 0 +#define MENU_PLAY 1 +#define MENU_QUIT 2 + +// Game events +#define NOBODY_WINS 0 +#define PLAYER1_WINS 1 +#define PLAYER2_WINS 2 + +// Winner ID +#define NOBODY 0 +#define PLAYER1 1 +#define PLAYER2 2 + +// Camera positions +#define CAMERA_CLASSIC 0 +#define CAMERA_ABOVE 1 +#define CAMERA_SPECTATOR 2 +#define CAMERA_DEFAULT CAMERA_CLASSIC + + +//======================================================================== +// Textures +//======================================================================== + +#define TEX_TITLE 0 +#define TEX_MENU 1 +#define TEX_INSTR 2 +#define TEX_WINNER1 3 +#define TEX_WINNER2 4 +#define TEX_FIELD 5 +#define NUM_TEXTURES 6 + +// Texture names +char * tex_name[ NUM_TEXTURES ] = { + "pong3d_title.tga", + "pong3d_menu.tga", + "pong3d_instr.tga", + "pong3d_winner1.tga", + "pong3d_winner2.tga", + "pong3d_field.tga" +}; + +// OpenGL texture object IDs +GLuint tex_id[ NUM_TEXTURES ]; + + +//======================================================================== +// Global variables +//======================================================================== + +// Display information +int width, height; + +// Frame information +double thistime, oldtime, dt, starttime; + +// Camera information +int camerapos; + +// Player information +struct { + double ypos; // -1.0 to +1.0 + double yspeed; // -MAX_SPEED to +MAX_SPEED +} player1, player2; + +// Ball information +struct { + double xpos, ypos; + double xspeed, yspeed; +} ball; + +// And the winner is... +int winner; + +// Lighting configuration +const GLfloat env_ambient[4] = {1.0f,1.0f,1.0f,1.0f}; +const GLfloat light1_position[4] = {-3.0f,3.0f,2.0f,1.0f}; +const GLfloat light1_diffuse[4] = {1.0f,1.0f,1.0f,0.0f}; +const GLfloat light1_ambient[4] = {0.0f,0.0f,0.0f,0.0f}; + +// Object material properties +const GLfloat player1_diffuse[4] = {1.0f,0.3f,0.3f,1.0f}; +const GLfloat player1_ambient[4] = {0.3f,0.1f,0.0f,1.0f}; +const GLfloat player2_diffuse[4] = {0.3f,1.0f,0.3f,1.0f}; +const GLfloat player2_ambient[4] = {0.1f,0.3f,0.1f,1.0f}; +const GLfloat ball_diffuse[4] = {1.0f,1.0f,0.5f,1.0f}; +const GLfloat ball_ambient[4] = {0.3f,0.3f,0.1f,1.0f}; +const GLfloat border_diffuse[4] = {0.3f,0.3f,1.0f,1.0f}; +const GLfloat border_ambient[4] = {0.1f,0.1f,0.3f,1.0f}; +const GLfloat floor_diffuse[4] = {1.0f,1.0f,1.0f,1.0f}; +const GLfloat floor_ambient[4] = {0.3f,0.3f,0.3f,1.0f}; + + +//======================================================================== +// LoadTextures() - Load textures from disk and upload to OpenGL card +//======================================================================== + +GLboolean LoadTextures( void ) +{ + int i; + + // Generate texture objects + glGenTextures( NUM_TEXTURES, tex_id ); + + // Load textures + for( i = 0; i < NUM_TEXTURES; i ++ ) + { + // Select texture object + glBindTexture( GL_TEXTURE_2D, tex_id[ i ] ); + + // Set texture parameters + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + // Upload texture from file to texture memory + if( !glfwLoadTexture2D( tex_name[ i ], 0 ) ) + { + fprintf( stderr, "Failed to load texture %s\n", tex_name[ i ] ); + return GL_FALSE; + } + } + + return GL_TRUE; +} + + +//======================================================================== +// DrawImage() - Draw a 2D image as a texture +//======================================================================== + +void DrawImage( int texnum, float x1, float x2, float y1, float y2 ) +{ + glEnable( GL_TEXTURE_2D ); + glBindTexture( GL_TEXTURE_2D, tex_id[ texnum ] ); + glBegin( GL_QUADS ); + glTexCoord2f( 0.0f, 1.0f ); + glVertex2f( x1, y1 ); + glTexCoord2f( 1.0f, 1.0f ); + glVertex2f( x2, y1 ); + glTexCoord2f( 1.0f, 0.0f ); + glVertex2f( x2, y2 ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex2f( x1, y2 ); + glEnd(); + glDisable( GL_TEXTURE_2D ); +} + + +//======================================================================== +// GameMenu() - Game menu (returns menu option) +//======================================================================== + +int GameMenu( void ) +{ + int option; + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Wait for a game menu key to be pressed + do + { + // Get window size + glfwGetWindowSize( &width, &height ); + + // Set viewport + glViewport( 0, 0, width, height ); + + // Clear display + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + glClear( GL_COLOR_BUFFER_BIT ); + + // Setup projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f ); + + // Setup modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Display title + glColor3f( 1.0f, 1.0f, 1.0f ); + DrawImage( TEX_TITLE, 0.1f, 0.9f, 0.0f, 0.3f ); + + // Display menu + glColor3f( 1.0f, 1.0f, 0.0f ); + DrawImage( TEX_MENU, 0.38f, 0.62f, 0.35f, 0.5f ); + + // Display instructions + glColor3f( 0.0f, 1.0f, 1.0f ); + DrawImage( TEX_INSTR, 0.32f, 0.68f, 0.65f, 0.85f ); + + // Swap buffers + glfwSwapBuffers(); + + // Check for keys + if( glfwGetKey( 'Q' ) || !glfwGetWindowParam( GLFW_OPENED ) ) + { + option = MENU_QUIT; + } + else if( glfwGetKey( GLFW_KEY_F1 ) ) + { + option = MENU_PLAY; + } + else + { + option = MENU_NONE; + } + + // To avoid horrible busy waiting, sleep for at least 20 ms + glfwSleep( 0.02 ); + } + while( option == MENU_NONE ); + + // Disable sticky keys + glfwDisable( GLFW_STICKY_KEYS ); + + return option; +} + + +//======================================================================== +// NewGame() - Initialize a new game +//======================================================================== + +void NewGame( void ) +{ + // Frame information + starttime = thistime = glfwGetTime(); + + // Camera information + camerapos = CAMERA_DEFAULT; + + // Player 1 information + player1.ypos = 0.0; + player1.yspeed = 0.0; + + // Player 2 information + player2.ypos = 0.0; + player2.yspeed = 0.0; + + // Ball information + ball.xpos = -1.0 + PLAYER_XSIZE; + ball.ypos = player1.ypos; + ball.xspeed = 1.0; + ball.yspeed = 1.0; +} + + +//======================================================================== +// PlayerControl() - Player control +//======================================================================== + +void PlayerControl( void ) +{ + float joy1pos[ 2 ], joy2pos[ 2 ]; + + // Get joystick X & Y axis positions + glfwGetJoystickPos( GLFW_JOYSTICK_1, joy1pos, 2 ); + glfwGetJoystickPos( GLFW_JOYSTICK_2, joy2pos, 2 ); + + // Player 1 control + if( glfwGetKey( 'A' ) || joy1pos[ 1 ] > 0.2f ) + { + player1.yspeed += dt * ACCELERATION; + if( player1.yspeed > MAX_SPEED ) + { + player1.yspeed = MAX_SPEED; + } + } + else if( glfwGetKey( 'Z' ) || joy1pos[ 1 ] < -0.2f ) + { + player1.yspeed -= dt * ACCELERATION; + if( player1.yspeed < -MAX_SPEED ) + { + player1.yspeed = -MAX_SPEED; + } + } + else + { + player1.yspeed /= exp( DECELERATION * dt ); + } + + // Player 2 control + if( glfwGetKey( 'K' ) || joy2pos[ 1 ] > 0.2f ) + { + player2.yspeed += dt * ACCELERATION; + if( player2.yspeed > MAX_SPEED ) + { + player2.yspeed = MAX_SPEED; + } + } + else if( glfwGetKey( 'M' ) || joy2pos[ 1 ] < -0.2f ) + { + player2.yspeed -= dt * ACCELERATION; + if( player2.yspeed < -MAX_SPEED ) + { + player2.yspeed = -MAX_SPEED; + } + } + else + { + player2.yspeed /= exp( DECELERATION * dt ); + } + + // Update player 1 position + player1.ypos += dt * player1.yspeed; + if( player1.ypos > 1.0 - PLAYER_YSIZE ) + { + player1.ypos = 1.0 - PLAYER_YSIZE; + player1.yspeed = 0.0; + } + else if( player1.ypos < -1.0 + PLAYER_YSIZE ) + { + player1.ypos = -1.0 + PLAYER_YSIZE; + player1.yspeed = 0.0; + } + + // Update player 2 position + player2.ypos += dt * player2.yspeed; + if( player2.ypos > 1.0 - PLAYER_YSIZE ) + { + player2.ypos = 1.0 - PLAYER_YSIZE; + player2.yspeed = 0.0; + } + else if( player2.ypos < -1.0 + PLAYER_YSIZE ) + { + player2.ypos = -1.0 + PLAYER_YSIZE; + player2.yspeed = 0.0; + } +} + + +//======================================================================== +// BallControl() - Ball control +//======================================================================== + +int BallControl( void ) +{ + int event; + double ballspeed; + + // Calculate new ball speed + ballspeed = BALL_SPEED * (1.0 + 0.02*(thistime-starttime)); + ball.xspeed = ball.xspeed > 0 ? ballspeed : -ballspeed; + ball.yspeed = ball.yspeed > 0 ? ballspeed : -ballspeed; + ball.yspeed *= 0.74321; + + // Update ball position + ball.xpos += dt * ball.xspeed; + ball.ypos += dt * ball.yspeed; + + // Did the ball hit a top/bottom wall? + if( ball.ypos >= 1.0 ) + { + ball.ypos = 2.0 - ball.ypos; + ball.yspeed = -ball.yspeed; + } + else if( ball.ypos <= -1.0 ) + { + ball.ypos = -2.0 - ball.ypos; + ball.yspeed = -ball.yspeed; + } + + // Did the ball hit/miss a player? + event = NOBODY_WINS; + + // Is the ball entering the player 1 goal? + if( ball.xpos < -1.0 + PLAYER_XSIZE ) + { + // Did player 1 catch the ball? + if( ball.ypos > (player1.ypos-PLAYER_YSIZE) && + ball.ypos < (player1.ypos+PLAYER_YSIZE) ) + { + ball.xpos = -2.0 + 2.0*PLAYER_XSIZE - ball.xpos; + ball.xspeed = -ball.xspeed; + } + else + { + event = PLAYER2_WINS; + } + } + + // Is the ball entering the player 2 goal? + if( ball.xpos > 1.0 - PLAYER_XSIZE ) + { + // Did player 2 catch the ball? + if( ball.ypos > (player2.ypos-PLAYER_YSIZE) && + ball.ypos < (player2.ypos+PLAYER_YSIZE) ) + { + ball.xpos = 2.0 - 2.0*PLAYER_XSIZE - ball.xpos; + ball.xspeed = -ball.xspeed; + } + else + { + event = PLAYER1_WINS; + } + } + + return event; +} + + +//======================================================================== +// DrawBox() - Draw a 3D box +//======================================================================== + +#define TEX_SCALE 4.0f + + +void DrawBox( float x1, float y1, float z1, float x2, float y2, float z2 ) +{ + // Draw six sides of a cube + glBegin( GL_QUADS ); + // Side 1 (down) + glNormal3f( 0.0f, 0.0f, -1.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y2,z1 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y2,z1 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y1,z1 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y1,z1 ); + // Side 2 (up) + glNormal3f( 0.0f, 0.0f, 1.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y1,z2 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y1,z2 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y2,z2 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y2,z2 ); + // Side 3 (backward) + glNormal3f( 0.0f, -1.0f, 0.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y1,z1 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y1,z1 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y1,z2 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y1,z2 ); + // Side 4 (forward) + glNormal3f( 0.0f, 1.0f, 0.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y2,z2 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y2,z2 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y2,z1 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y2,z1 ); + // Side 5 (left) + glNormal3f( -1.0f, 0.0f, 0.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y1,z2 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x1,y2,z2 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x1,y2,z1 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y1,z1 ); + // Side 6 (right) + glNormal3f( 1.0f, 0.0f, 0.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x2,y1,z1 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y2,z1 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y2,z2 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x2,y1,z2 ); + glEnd(); +} + + +//======================================================================== +// UpdateDisplay() - Draw graphics (all game related OpenGL stuff goes +// here) +//======================================================================== + +void UpdateDisplay( void ) +{ + // Get window size + glfwGetWindowSize( &width, &height ); + + // Set viewport + glViewport( 0, 0, width, height ); + + // Clear display + glClearColor( 0.02f, 0.02f, 0.02f, 0.0f ); + glClearDepth( 1.0f ); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + // Setup projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( + 55.0f, // Angle of view + (GLfloat)width/(GLfloat)height, // Aspect + 1.0f, // Near Z + 100.0f // Far Z + ); + + // Setup modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + switch( camerapos ) + { + default: + case CAMERA_CLASSIC: + gluLookAt( + 0.0f, 0.0f, 2.5f, + 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f + ); + break; + case CAMERA_ABOVE: + gluLookAt( + 0.0f, 0.0f, 2.5f, + (float)ball.xpos, (float)ball.ypos, 0.0f, + 0.0f, 1.0f, 0.0f + ); + break; + case CAMERA_SPECTATOR: + gluLookAt( + 0.0f, -2.0, 1.2f, + (float)ball.xpos, (float)ball.ypos, 0.0f, + 0.0f, 0.0f, 1.0f + ); + break; + } + + // Enable depth testing + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_LEQUAL ); + + // Enable lighting + glEnable( GL_LIGHTING ); + glLightModelfv( GL_LIGHT_MODEL_AMBIENT, env_ambient ); + glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE ); + glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE ); + glLightfv( GL_LIGHT1, GL_POSITION, light1_position ); + glLightfv( GL_LIGHT1, GL_DIFFUSE, light1_diffuse ); + glLightfv( GL_LIGHT1, GL_AMBIENT, light1_ambient ); + glEnable( GL_LIGHT1 ); + + // Front face is counter-clock-wise + glFrontFace( GL_CCW ); + + // Enable face culling (not necessary, but speeds up rendering) + glCullFace( GL_BACK ); + glEnable( GL_CULL_FACE ); + + // Draw Player 1 + glMaterialfv( GL_FRONT, GL_DIFFUSE, player1_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, player1_ambient ); + DrawBox( -1.f, (GLfloat)player1.ypos-PLAYER_YSIZE, 0.f, + -1.f+PLAYER_XSIZE, (GLfloat)player1.ypos+PLAYER_YSIZE, 0.1f ); + + // Draw Player 2 + glMaterialfv( GL_FRONT, GL_DIFFUSE, player2_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, player2_ambient ); + DrawBox( 1.f-PLAYER_XSIZE, (GLfloat)player2.ypos-PLAYER_YSIZE, 0.f, + 1.f, (GLfloat)player2.ypos+PLAYER_YSIZE, 0.1f ); + + // Draw Ball + glMaterialfv( GL_FRONT, GL_DIFFUSE, ball_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, ball_ambient ); + DrawBox( (GLfloat)ball.xpos-BALL_SIZE, (GLfloat)ball.ypos-BALL_SIZE, 0.f, + (GLfloat)ball.xpos+BALL_SIZE, (GLfloat)ball.ypos+BALL_SIZE, BALL_SIZE*2 ); + + // Top game field border + glMaterialfv( GL_FRONT, GL_DIFFUSE, border_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, border_ambient ); + DrawBox( -1.1f, 1.0f, 0.0f, 1.1f, 1.1f, 0.1f ); + // Bottom game field border + glColor3f( 0.0f, 0.0f, 0.7f ); + DrawBox( -1.1f, -1.1f, 0.0f, 1.1f, -1.0f, 0.1f ); + // Left game field border + DrawBox( -1.1f, -1.0f, 0.0f, -1.0f, 1.0f, 0.1f ); + // Left game field border + DrawBox( 1.0f, -1.0f, 0.0f, 1.1f, 1.0f, 0.1f ); + + // Enable texturing + glEnable( GL_TEXTURE_2D ); + glBindTexture( GL_TEXTURE_2D, tex_id[ TEX_FIELD ] ); + + // Game field floor + glMaterialfv( GL_FRONT, GL_DIFFUSE, floor_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, floor_ambient ); + DrawBox( -1.01f, -1.01f, -0.01f, 1.01f, 1.01f, 0.0f ); + + // Disable texturing + glDisable( GL_TEXTURE_2D ); + + // Disable face culling + glDisable( GL_CULL_FACE ); + + // Disable lighting + glDisable( GL_LIGHTING ); + + // Disable depth testing + glDisable( GL_DEPTH_TEST ); +} + + +//======================================================================== +// GameOver() +//======================================================================== + +void GameOver( void ) +{ + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Until the user presses ESC or SPACE + while( !glfwGetKey( GLFW_KEY_ESC ) && !glfwGetKey( ' ' ) && + glfwGetWindowParam( GLFW_OPENED ) ) + { + // Draw display + UpdateDisplay(); + + // Setup projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f ); + + // Setup modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Enable blending + glEnable( GL_BLEND ); + + // Dim background + glBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA ); + glColor4f( 0.3f, 0.3f, 0.3f, 0.3f ); + glBegin( GL_QUADS ); + glVertex2f( 0.0f, 0.0f ); + glVertex2f( 1.0f, 0.0f ); + glVertex2f( 1.0f, 1.0f ); + glVertex2f( 0.0f, 1.0f ); + glEnd(); + + // Display winner text + glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_COLOR ); + if( winner == PLAYER1 ) + { + glColor4f( 1.0f, 0.5f, 0.5f, 1.0f ); + DrawImage( TEX_WINNER1, 0.35f, 0.65f, 0.46f, 0.54f ); + } + else if( winner == PLAYER2 ) + { + glColor4f( 0.5f, 1.0f, 0.5f, 1.0f ); + DrawImage( TEX_WINNER2, 0.35f, 0.65f, 0.46f, 0.54f ); + } + + // Disable blending + glDisable( GL_BLEND ); + + // Swap buffers + glfwSwapBuffers(); + } + + // Disable sticky keys + glfwDisable( GLFW_STICKY_KEYS ); +} + + +//======================================================================== +// GameLoop() - Game loop +//======================================================================== + +void GameLoop( void ) +{ + int playing, event; + + // Initialize a new game + NewGame(); + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Loop until the game ends + playing = GL_TRUE; + while( playing && glfwGetWindowParam( GLFW_OPENED ) ) + { + // Frame timer + oldtime = thistime; + thistime = glfwGetTime(); + dt = thistime - oldtime; + + // Get user input and update player positions + PlayerControl(); + + // Move the ball, and check if a player hits/misses the ball + event = BallControl(); + + // Did we have a winner? + switch( event ) + { + case PLAYER1_WINS: + winner = PLAYER1; + playing = GL_FALSE; + break; + case PLAYER2_WINS: + winner = PLAYER2; + playing = GL_FALSE; + break; + default: + break; + } + + // Did the user press ESC? + if( glfwGetKey( GLFW_KEY_ESC ) ) + { + playing = GL_FALSE; + } + + // Did the user change camera view? + if( glfwGetKey( '1' ) ) + { + camerapos = CAMERA_CLASSIC; + } + else if( glfwGetKey( '2' ) ) + { + camerapos = CAMERA_ABOVE; + } + else if( glfwGetKey( '3' ) ) + { + camerapos = CAMERA_SPECTATOR; + } + + // Draw display + UpdateDisplay(); + + // Swap buffers + glfwSwapBuffers(); + } + + // Disable sticky keys + glfwDisable( GLFW_STICKY_KEYS ); + + // Show winner + GameOver(); +} + + +//======================================================================== +// main() - Program entry point +//======================================================================== + +int main( void ) +{ + int menuoption; + + // Initialize GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open OpenGL window + if( !glfwOpenWindow( WIDTH, HEIGHT, 0,0,0,0, 16,0, GLFW_FULLSCREEN ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + glfwSwapInterval( 1 ); + + // Load all textures + if( !LoadTextures() ) + { + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + // Main loop + do + { + // Get menu option + menuoption = GameMenu(); + + // If the user wants to play, let him... + if( menuoption == MENU_PLAY ) + { + GameLoop(); + } + } + while( menuoption != MENU_QUIT ); + + // Unload all textures + if( glfwGetWindowParam( GLFW_OPENED ) ) + { + glDeleteTextures( NUM_TEXTURES, tex_id ); + } + + // Terminate GLFW + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/tests/glfw/pong3d_field.tga b/tests/glfw/pong3d_field.tga new file mode 100644 index 0000000000000000000000000000000000000000..cc20bbdb82434faa3bbc01d27fd199d5214c8b2f GIT binary patch literal 17816 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 T6XevNs>&3`i95eA{_g(;MdbFK literal 0 HcmV?d00001 diff --git a/tests/glfw/pong3d_instr.tga b/tests/glfw/pong3d_instr.tga new file mode 100644 index 0000000000000000000000000000000000000000..758eb447a97187cef812cb9100aa94631954c256 GIT binary patch literal 21279 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 literal 0 HcmV?d00001 diff --git a/tests/glfw/pong3d_menu.tga b/tests/glfw/pong3d_menu.tga new file mode 100644 index 0000000000000000000000000000000000000000..d0d6c5a431687bfd6442e43c3878a9eb905c48b8 GIT binary patch literal 1835 zcmbVMTawc-5FFd7KrLK{i*bQLe#C)-km6&1*q~+M0-Qi+$_YgGjAbh+zSu1}vefFC z>1kQyjg-Il@=jjMRenoIj~IXChe+&m7gLVsZQ6^Zkej3-2jP$yvZRY#urXlCQ#Jn=lGQ*?msDM%?fom_#3D0WLYd>| zrM8HEH4zdvDSlgLUu?J06w%uHU$F5BH?%^)6{nIMA=d zk04{L6gsNXLvPU$y7bcLR=F~R;{Yz~AoE6761IR~EZy-Sc90#?@jjEKjdZ2xgd?t2 zqtTm)Fw3kYxE=nmQqN{37J-&5_=7y4JqUx5<790bksq4`P6Xm?W2J#gsv94$c80Ep zhB(C(Tcv$%4nwfg>5lD?ncV@L-j6_|Q=WiD2HsmBQ7_k*Bwh}mIAS5_(&Zv)0+JQ*BV=)qzNL$W#l<{{t=av1 zh6fQJ3*Rf(fcY7y8DcVufs`P8r)X65U6x`6n^qTRM5LcL_vtFnz@hK-l+BKK+wK>L@83So!V-2z3xXZm}7`ZB*l$gvAC5tvMEd)H$-L j=(lM?g-Vm}Fwx!OsnJ{IV_$0Jn){}t&ktU$$5s9UqXSX} literal 0 HcmV?d00001 diff --git a/tests/glfw/pong3d_title.tga b/tests/glfw/pong3d_title.tga new file mode 100644 index 0000000000000000000000000000000000000000..d0d8e36d74011c25b908647632b4997dc0cf6456 GIT binary patch literal 106516 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 literal 0 HcmV?d00001 diff --git a/tests/glfw/pong3d_winner1.tga b/tests/glfw/pong3d_winner1.tga new file mode 100644 index 0000000000000000000000000000000000000000..f963720c5b897c01b8694a0fb2d76ad617877a7d GIT binary patch literal 861 zcmZvaO-{ow5QV29sw!Ag>q$zL$Sb2xaDZHc?={d~z#x?;&rAh7an>TNM%UG8<_V`T}Av+dQR1Q!U7Qc6{sSH8wNZP39q9qy#b$XF9@I6ez)S<6n zq_ehk;iMZ&fsh(meZGobq4LV7e~pc@d~^GlelDh;wKF}zCi`6*Je6~M>is%9SNEbW LDfk1czN>u!GHiyO literal 0 HcmV?d00001 diff --git a/tests/glfw/pong3d_winner2.tga b/tests/glfw/pong3d_winner2.tga new file mode 100644 index 0000000000000000000000000000000000000000..ea8266dea9f6ca7b261f2163b4f2bc4777a59027 GIT binary patch literal 891 zcmZvbOHRWu5Qe8Asw!Ag>q)E8}th{PDhL`jrJ%{=Jv6BL#k|RH6{>RMJ?8(;O zi#^-HZuV}m>~grW8Ozl^%t9=dzKDzE#2U(`*Z?%X-syv|S(? zK)sHv$a>wtB4Eb?Ma3Y>!sKURS)Tb0r3+%vTaEo6DJm{if#^X&j{?aT=fbk|<~&_O zt+PmDbft=sKHTt?QQd&&`CbHe)uYgASx)wtida}Bc}9?zn%(@SUw-irZBG_CWXznz z=XiOM7P58fg0$VeHnc3XW7$gDg_J8@PnncbAuX(+Ga!3cnA!amNonh?123}NqEvQz zr;kDo0gOh0x+DVBrpbD_p`wQ*Phz^)ltEEbz;t}sX=m;%O{Moj&@6$p=8wfP;J5)? zkhFgfjw0#^%tT0ME$!44Ga|_7pj0Ep>Z9on#mYG5)@84;kMi2DpOfl)jnK+)SAA~d cBD_m`U#oV84}EF9M`aSmW&0a^ddAJZ0j)ZbKmY&$ literal 0 HcmV?d00001 diff --git a/tests/glfw/splitview.c b/tests/glfw/splitview.c new file mode 100644 index 0000000000000..932cd0d6511b1 --- /dev/null +++ b/tests/glfw/splitview.c @@ -0,0 +1,514 @@ +//======================================================================== +// This is an example program for the GLFW library +// +// The program uses a "split window" view, rendering four views of the +// same scene in one window (e.g. uesful for 3D modelling software). This +// demo uses scissors to separete the four different rendering areas from +// each other. +// +// (If the code seems a little bit strange here and there, it may be +// because I am not a friend of orthogonal projections) +//======================================================================== + +#include +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +//======================================================================== +// Global variables +//======================================================================== + +// Mouse position +static int xpos = 0, ypos = 0; + +// Window size +static int width, height; + +// Active view: 0 = none, 1 = upper left, 2 = upper right, 3 = lower left, +// 4 = lower right +static int active_view = 0; + +// Rotation around each axis +static int rot_x = 0, rot_y = 0, rot_z = 0; + +// Do redraw? +static int do_redraw = 1; + + +//======================================================================== +// Draw a solid torus (use a display list for the model) +//======================================================================== + +#define TORUS_MAJOR 1.5 +#define TORUS_MINOR 0.5 +#define TORUS_MAJOR_RES 32 +#define TORUS_MINOR_RES 32 + +static void drawTorus( void ) +{ + static GLuint torus_list = 0; + int i, j, k; + double s, t, x, y, z, nx, ny, nz, scale, twopi; + + if( !torus_list ) + { + // Start recording displaylist + torus_list = glGenLists( 1 ); + glNewList( torus_list, GL_COMPILE_AND_EXECUTE ); + + // Draw torus + twopi = 2.0 * M_PI; + for( i = 0; i < TORUS_MINOR_RES; i++ ) + { + glBegin( GL_QUAD_STRIP ); + for( j = 0; j <= TORUS_MAJOR_RES; j++ ) + { + for( k = 1; k >= 0; k-- ) + { + s = (i + k) % TORUS_MINOR_RES + 0.5; + t = j % TORUS_MAJOR_RES; + + // Calculate point on surface + x = (TORUS_MAJOR+TORUS_MINOR*cos(s*twopi/TORUS_MINOR_RES))*cos(t*twopi/TORUS_MAJOR_RES); + y = TORUS_MINOR * sin(s * twopi / TORUS_MINOR_RES); + z = (TORUS_MAJOR+TORUS_MINOR*cos(s*twopi/TORUS_MINOR_RES))*sin(t*twopi/TORUS_MAJOR_RES); + + // Calculate surface normal + nx = x - TORUS_MAJOR*cos(t*twopi/TORUS_MAJOR_RES); + ny = y; + nz = z - TORUS_MAJOR*sin(t*twopi/TORUS_MAJOR_RES); + scale = 1.0 / sqrt( nx*nx + ny*ny + nz*nz ); + nx *= scale; + ny *= scale; + nz *= scale; + + glNormal3f( (float)nx, (float)ny, (float)nz ); + glVertex3f( (float)x, (float)y, (float)z ); + } + } + glEnd(); + } + + // Stop recording displaylist + glEndList(); + } + else + { + // Playback displaylist + glCallList( torus_list ); + } +} + + +//======================================================================== +// Draw the scene (a rotating torus) +//======================================================================== + +static void drawScene( void ) +{ + const GLfloat model_diffuse[4] = {1.0f, 0.8f, 0.8f, 1.0f}; + const GLfloat model_specular[4] = {0.6f, 0.6f, 0.6f, 1.0f}; + const GLfloat model_shininess = 20.0f; + + glPushMatrix(); + + // Rotate the object + glRotatef( (GLfloat)rot_x*0.5f, 1.0f, 0.0f, 0.0f ); + glRotatef( (GLfloat)rot_y*0.5f, 0.0f, 1.0f, 0.0f ); + glRotatef( (GLfloat)rot_z*0.5f, 0.0f, 0.0f, 1.0f ); + + // Set model color (used for orthogonal views, lighting disabled) + glColor4fv( model_diffuse ); + + // Set model material (used for perspective view, lighting enabled) + glMaterialfv( GL_FRONT, GL_DIFFUSE, model_diffuse ); + glMaterialfv( GL_FRONT, GL_SPECULAR, model_specular ); + glMaterialf( GL_FRONT, GL_SHININESS, model_shininess ); + + // Draw torus + drawTorus(); + + glPopMatrix(); +} + + +//======================================================================== +// Draw a 2D grid (used for orthogonal views) +//======================================================================== + +static void drawGrid( float scale, int steps ) +{ + int i; + float x, y; + + glPushMatrix(); + + // Set background to some dark bluish grey + glClearColor( 0.05f, 0.05f, 0.2f, 0.0f); + glClear( GL_COLOR_BUFFER_BIT ); + + // Setup modelview matrix (flat XY view) + glLoadIdentity(); + gluLookAt( 0.0, 0.0, 1.0, + 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0 ); + + // We don't want to update the Z-buffer + glDepthMask( GL_FALSE ); + + // Set grid color + glColor3f( 0.0f, 0.5f, 0.5f ); + + glBegin( GL_LINES ); + + // Horizontal lines + x = scale * 0.5f * (float)(steps-1); + y = -scale * 0.5f * (float)(steps-1); + for( i = 0; i < steps; i ++ ) + { + glVertex3f( -x, y, 0.0f ); + glVertex3f( x, y, 0.0f ); + y += scale; + } + + // Vertical lines + x = -scale * 0.5f * (float)(steps-1); + y = scale * 0.5f * (float)(steps-1); + for( i = 0; i < steps; i ++ ) + { + glVertex3f( x, -y, 0.0f ); + glVertex3f( x, y, 0.0f ); + x += scale; + } + + glEnd(); + + // Enable Z-buffer writing again + glDepthMask( GL_TRUE ); + + glPopMatrix(); +} + + +//======================================================================== +// Draw all views +//======================================================================== + +static void drawAllViews( void ) +{ + const GLfloat light_position[4] = {0.0f, 8.0f, 8.0f, 1.0f}; + const GLfloat light_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const GLfloat light_specular[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const GLfloat light_ambient[4] = {0.2f, 0.2f, 0.3f, 1.0f}; + double aspect; + + // Calculate aspect of window + if( height > 0 ) + { + aspect = (double)width / (double)height; + } + else + { + aspect = 1.0; + } + + // Clear screen + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + // Enable scissor test + glEnable( GL_SCISSOR_TEST ); + + // Enable depth test + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_LEQUAL ); + + + // ** ORTHOGONAL VIEWS ** + + // For orthogonal views, use wireframe rendering + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + + // Enable line anti-aliasing + glEnable( GL_LINE_SMOOTH ); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + + // Setup orthogonal projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( -3.0*aspect, 3.0*aspect, -3.0, 3.0, 1.0, 50.0 ); + + // Upper left view (TOP VIEW) + glViewport( 0, height/2, width/2, height/2 ); + glScissor( 0, height/2, width/2, height/2 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 0.0f, 10.0f, 1e-3f, // Eye-position (above) + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + drawGrid( 0.5, 12 ); + drawScene(); + + // Lower left view (FRONT VIEW) + glViewport( 0, 0, width/2, height/2 ); + glScissor( 0, 0, width/2, height/2 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 0.0f, 0.0f, 10.0f, // Eye-position (in front of) + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + drawGrid( 0.5, 12 ); + drawScene(); + + // Lower right view (SIDE VIEW) + glViewport( width/2, 0, width/2, height/2 ); + glScissor( width/2, 0, width/2, height/2 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 10.0f, 0.0f, 0.0f, // Eye-position (to the right) + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + drawGrid( 0.5, 12 ); + drawScene(); + + // Disable line anti-aliasing + glDisable( GL_LINE_SMOOTH ); + glDisable( GL_BLEND ); + + + // ** PERSPECTIVE VIEW ** + + // For perspective view, use solid rendering + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + + // Enable face culling (faster rendering) + glEnable( GL_CULL_FACE ); + glCullFace( GL_BACK ); + glFrontFace( GL_CW ); + + // Setup perspective projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 65.0f, aspect, 1.0f, 50.0f ); + + // Upper right view (PERSPECTIVE VIEW) + glViewport( width/2, height/2, width/2, height/2 ); + glScissor( width/2, height/2, width/2, height/2 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 3.0f, 1.5f, 3.0f, // Eye-position + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + + // Configure and enable light source 1 + glLightfv( GL_LIGHT1, GL_POSITION, light_position ); + glLightfv( GL_LIGHT1, GL_AMBIENT, light_ambient ); + glLightfv( GL_LIGHT1, GL_DIFFUSE, light_diffuse ); + glLightfv( GL_LIGHT1, GL_SPECULAR, light_specular ); + glEnable( GL_LIGHT1 ); + glEnable( GL_LIGHTING ); + + // Draw scene + drawScene(); + + // Disable lighting + glDisable( GL_LIGHTING ); + + // Disable face culling + glDisable( GL_CULL_FACE ); + + // Disable depth test + glDisable( GL_DEPTH_TEST ); + + // Disable scissor test + glDisable( GL_SCISSOR_TEST ); + + + // Draw a border around the active view + if( active_view > 0 && active_view != 2 ) + { + glViewport( 0, 0, width, height ); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( 0.0, 2.0, 0.0, 2.0, 0.0, 1.0 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + glColor3f( 1.0f, 1.0f, 0.6f ); + glTranslatef( (GLfloat) ((active_view - 1) & 1), (GLfloat) (1 - (active_view - 1) / 2), 0.0f ); + glBegin( GL_LINE_STRIP ); + glVertex2i( 0, 0 ); + glVertex2i( 1, 0 ); + glVertex2i( 1, 1 ); + glVertex2i( 0, 1 ); + glVertex2i( 0, 0 ); + glEnd(); + } +} + + +//======================================================================== +// Window size callback function +//======================================================================== + +static void GLFWCALL windowSizeFun( int w, int h ) +{ + width = w; + height = h > 0 ? h : 1; + do_redraw = 1; +} + + +//======================================================================== +// Window refresh callback function +//======================================================================== + +static void GLFWCALL windowRefreshFun( void ) +{ + do_redraw = 1; +} + + +//======================================================================== +// Mouse position callback function +//======================================================================== + +static void GLFWCALL mousePosFun( int x, int y ) +{ + // Depending on which view was selected, rotate around different axes + switch( active_view ) + { + case 1: + rot_x += y - ypos; + rot_z += x - xpos; + do_redraw = 1; + break; + case 3: + rot_x += y - ypos; + rot_y += x - xpos; + do_redraw = 1; + break; + case 4: + rot_y += x - xpos; + rot_z += y - ypos; + do_redraw = 1; + break; + default: + // Do nothing for perspective view, or if no view is selected + break; + } + + // Remember mouse position + xpos = x; + ypos = y; +} + + +//======================================================================== +// Mouse button callback function +//======================================================================== + +static void GLFWCALL mouseButtonFun( int button, int action ) +{ + // Button clicked? + if( ( button == GLFW_MOUSE_BUTTON_LEFT ) && action == GLFW_PRESS ) + { + // Detect which of the four views was clicked + active_view = 1; + if( xpos >= width/2 ) + { + active_view += 1; + } + if( ypos >= height/2 ) + { + active_view += 2; + } + } + + // Button released? + else if( button == GLFW_MOUSE_BUTTON_LEFT ) + { + // Deselect any previously selected view + active_view = 0; + } + + do_redraw = 1; +} + + +//======================================================================== +// main() +//======================================================================== + +int main( void ) +{ + // Initialise GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open OpenGL window + if( !glfwOpenWindow( 500, 500, 0,0,0,0, 16,0, GLFW_WINDOW ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + // Enable vsync + glfwSwapInterval( 1 ); + + // Set window title + glfwSetWindowTitle( "Split view demo" ); + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Enable mouse cursor (only needed for fullscreen mode) + glfwEnable( GLFW_MOUSE_CURSOR ); + + // Disable automatic event polling + glfwDisable( GLFW_AUTO_POLL_EVENTS ); + + // Set callback functions + glfwSetWindowSizeCallback( windowSizeFun ); + glfwSetWindowRefreshCallback( windowRefreshFun ); + glfwSetMousePosCallback( mousePosFun ); + glfwSetMouseButtonCallback( mouseButtonFun ); + + // Main loop + do + { + // Only redraw if we need to + if( do_redraw ) + { + // Draw all views + drawAllViews(); + + // Swap buffers + glfwSwapBuffers(); + + do_redraw = 0; + } + + // Wait for new events + glfwWaitEvents(); + + } // Check if the ESC key was pressed or the window was closed + while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS && + glfwGetWindowParam( GLFW_OPENED ) ); + + // Close OpenGL window and terminate GLFW + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/tests/glfw/triangle.c b/tests/glfw/triangle.c new file mode 100644 index 0000000000000..a8b737bee7fe2 --- /dev/null +++ b/tests/glfw/triangle.c @@ -0,0 +1,94 @@ +//======================================================================== +// This is a small test application for GLFW. +// The program opens a window (640x480), and renders a spinning colored +// triangle (it is controlled with both the GLFW timer and the mouse). +//======================================================================== + +#include +#include +#include + + +int main( void ) +{ + int width, height, x; + double t; + + // Initialise GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open a window and create its OpenGL context + if( !glfwOpenWindow( 640, 480, 0,0,0,0, 0,0, GLFW_WINDOW ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + glfwSetWindowTitle( "Spinning Triangle" ); + + // Ensure we can capture the escape key being pressed below + glfwEnable( GLFW_STICKY_KEYS ); + + // Enable vertical sync (on cards that support it) + glfwSwapInterval( 1 ); + + do + { + t = glfwGetTime(); + glfwGetMousePos( &x, NULL ); + + // Get window size (may be different than the requested size) + glfwGetWindowSize( &width, &height ); + + // Special case: avoid division by zero below + height = height > 0 ? height : 1; + + glViewport( 0, 0, width, height ); + + // Clear color buffer to black + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + glClear( GL_COLOR_BUFFER_BIT ); + + // Select and setup the projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 65.0f, (GLfloat)width/(GLfloat)height, 1.0f, 100.0f ); + + // Select and setup the modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 0.0f, 1.0f, 0.0f, // Eye-position + 0.0f, 20.0f, 0.0f, // View-point + 0.0f, 0.0f, 1.0f ); // Up-vector + + // Draw a rotating colorful triangle + glTranslatef( 0.0f, 14.0f, 0.0f ); + glRotatef( 0.3f*(GLfloat)x + (GLfloat)t*100.0f, 0.0f, 0.0f, 1.0f ); + glBegin( GL_TRIANGLES ); + glColor3f( 1.0f, 0.0f, 0.0f ); + glVertex3f( -5.0f, 0.0f, -4.0f ); + glColor3f( 0.0f, 1.0f, 0.0f ); + glVertex3f( 5.0f, 0.0f, -4.0f ); + glColor3f( 0.0f, 0.0f, 1.0f ); + glVertex3f( 0.0f, 0.0f, 6.0f ); + glEnd(); + + // Swap buffers + glfwSwapBuffers(); + + } // Check if the ESC key was pressed or the window was closed + while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS && + glfwGetWindowParam( GLFW_OPENED ) ); + + // Close OpenGL window and terminate GLFW + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/tests/glfw/wave.c b/tests/glfw/wave.c new file mode 100644 index 0000000000000..67f516cc094c7 --- /dev/null +++ b/tests/glfw/wave.c @@ -0,0 +1,399 @@ +/***************************************************************************** + * Wave Simulation in OpenGL + * (C) 2002 Jakob Thomsen + * http://home.in.tum.de/~thomsen + * Modified for GLFW by Sylvain Hellegouarch - sh@programmationworld.com + * Modified for variable frame rate by Marcus Geelnard + * 2003-Jan-31: Minor cleanups and speedups / MG + *****************************************************************************/ + +#include +#include +#include +#include + +#ifndef M_PI + #define M_PI 3.1415926535897932384626433832795 +#endif + +/* Maximum delta T to allow for differential calculations */ +#define MAX_DELTA_T 0.01 + +/* Animation speed (10.0 looks good) */ +#define ANIMATION_SPEED 10.0 + + +GLfloat alpha = 210.0f, beta = -70.0f; +GLfloat zoom = 2.0f; + +int running = 1; + +struct Vertex +{ + GLfloat x,y,z; + GLfloat r,g,b; +}; + +#define GRIDW 50 +#define GRIDH 50 +#define VERTEXNUM (GRIDW*GRIDH) + +#define QUADW (GRIDW-1) +#define QUADH (GRIDH-1) +#define QUADNUM (QUADW*QUADH) + +GLuint quad[4*QUADNUM]; +struct Vertex vertex[VERTEXNUM]; + +/* The grid will look like this: + * + * 3 4 5 + * *---*---* + * | | | + * | 0 | 1 | + * | | | + * *---*---* + * 0 1 2 + */ + +void initVertices( void ) +{ + int x,y,p; + + /* place the vertices in a grid */ + for(y=0;y1) zoom-=1; + break; + case GLFW_KEY_PAGEDOWN: + zoom+=1; + break; + default: + break; + } +} + + +/* Callback function for window resize events */ +void GLFWCALL handle_resize( int width, int height ) +{ + float ratio = 1.0f; + + if( height > 0 ) + { + ratio = (float) width / (float) height; + } + + /* Setup viewport (Place where the stuff will appear in the main window). */ + glViewport(0, 0, width, height); + + /* + * Change to the projection matrix and set + * our viewing volume. + */ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60.0, ratio, 1.0, 1024.0); +} + + +/* Program entry point */ +int main(int argc, char* argv[]) +{ + /* Dimensions of our window. */ + int width, height; + /* Style of our window. */ + int mode; + /* Frame time */ + double t, t_old, dt_total; + + /* Initialize GLFW */ + if(glfwInit() == GL_FALSE) + { + fprintf(stderr, "GLFW initialization failed\n"); + exit(-1); + } + + /* Desired window properties */ + width = 640; + height = 480; + mode = GLFW_WINDOW; + + /* Open window */ + if( glfwOpenWindow(width,height,0,0,0,0,16,0,mode) == GL_FALSE ) + { + fprintf(stderr, "Could not open window\n"); + glfwTerminate(); + exit(-1); + } + + /* Set title */ + glfwSetWindowTitle( "Wave Simulation" ); + + glfwSwapInterval( 1 ); + + /* Keyboard handler */ + glfwSetKeyCallback( handle_key_down ); + glfwEnable( GLFW_KEY_REPEAT ); + + /* Window resize handler */ + glfwSetWindowSizeCallback( handle_resize ); + + /* Initialize OpenGL */ + setup_opengl(); + + /* Initialize simulation */ + initVertices(); + initSurface(); + adjustGrid(); + + /* Initialize timer */ + t_old = glfwGetTime() - 0.01; + + /* Main loop */ + while(running) + { + /* Timing */ + t = glfwGetTime(); + dt_total = t - t_old; + t_old = t; + + /* Safety - iterate if dt_total is too large */ + while( dt_total > 0.0f ) + { + /* Select iteration time step */ + dt = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total; + dt_total -= dt; + + /* Calculate wave propagation */ + calc(); + } + + /* Compute height of each vertex */ + adjustGrid(); + + /* Draw wave grid to OpenGL display */ + draw_screen(); + + /* Still running? */ + running = running && glfwGetWindowParam( GLFW_OPENED ); + } + + glfwTerminate(); + + return 0; +} From 463d996cb002ccd3565088776ea6db60d54466c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Tue, 5 Mar 2013 12:21:00 +0100 Subject: [PATCH 015/544] * Edited tests so they use emscripten_main_loop. * Got triangle test about to work. * Implemented misc functions. --- src/library_glfw.js | 237 ++++++++++++++++++++++++++++++++++------- tests/glfw/Makefile | 55 +++++----- tests/glfw/boing.c | 34 +++--- tests/glfw/gears.c | 40 ++++--- tests/glfw/heightmap.c | 34 ++++-- tests/glfw/mipmaps.c | 114 +++++++++++--------- tests/glfw/particles.c | 58 ++++++---- tests/glfw/pong3d.c | 62 ++++++----- tests/glfw/splitview.c | 43 +++++--- tests/glfw/triangle.c | 152 ++++++++++++++------------ 10 files changed, 541 insertions(+), 288 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index d171ffcbdd2f8..db457bc4f8c6e 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -2,22 +2,25 @@ var LibraryGLFW = { $GLFW: { initTime: null, - idleFunc: null, - displayFunc: null, keyboardFunc: null, - keyboardUpFunc: null, - specialFunc: null, - specialUpFunc: null, - reshapeFunc: null, + charFunc: null, + mouseButtonFunc: null, + mousePosFunc: null, + mouseWheelFunc: null, + resizeFunc: null, + closeFunc: null, + refreshFunc: null, motionFunc: null, passiveMotionFunc: null, mouseFunc: null, + features: null, + params: null, lastX: 0, lastY: 0, buttons: 0, modifiers: 0, - initWindowWidth: 256, - initWindowHeight: 256, + initWindowWidth: 640, + initWindowHeight: 480, // Set when going fullscreen windowX: 0, windowY: 0, @@ -288,9 +291,9 @@ var LibraryGLFW = { } Browser.setCanvasSize(width, height); // Can't call _glfwReshapeWindow as that requests cancelling fullscreen. - if (GLFW.reshapeFunc) { - // console.log("GLFW.reshapeFunc (from FS): " + width + ", " + height); - Runtime.dynCall('vii', GLFW.reshapeFunc, [width, height]); + if (GLFW.resizeFunc) { + // console.log("GLFW.resizeFunc (from FS): " + width + ", " + height); + Runtime.dynCall('vii', GLFW.resizeFunc, [width, height]); } _glfwPostRedisplay(); */ @@ -316,26 +319,140 @@ var LibraryGLFW = { }, /* GLFW initialization, termination and version querying */ - glfwInit : function() { throw "glfwInit is not implemented yet."; }, - glfwTerminate : function() { throw "glfwTerminate is not implemented yet."; }, - glfwGetVersion : function( major, minor, rev ) { throw "glfwGetVersion is not implemented yet."; }, + glfwInit : function() { + GLFW.initTime = Date.now() / 1000; +/* + window.addEventListener("keydown", GLFW.onKeydown, true); + window.addEventListener("keyup", GLFW.onKeyup, true); +*/ window.addEventListener("mousemove", GLFW.onMousemove, true); +/* window.addEventListener("mousedown", GLFW.onMouseButtonDown, true); + window.addEventListener("mouseup", GLFW.onMouseButtonUp, true); + + __ATEXIT__.push({ func: function() { + window.removeEventListener("keydown", GLFW.onKeydown, true); + window.removeEventListener("keyup", GLFW.onKeyup, true); + window.removeEventListener("mousemove", GLFW.onMousemove, true); + window.removeEventListener("mousedown", GLFW.onMouseButtonDown, true); + window.removeEventListener("mouseup", GLFW.onMouseButtonUp, true); + Module["canvas"].width = Module["canvas"].height = 1; + } }); +*/ + GLFW.features = new Array(); + GLFW.features[0x00030001] = true; //GLFW_MOUSE_CURSOR + GLFW.features[0x00030002] = false; //GLFW_STICKY_KEYS + GLFW.features[0x00030003] = true; //GLFW_STICKY_MOUSE_BUTTONS + GLFW.features[0x00030004] = false; //GLFW_SYSTEM_KEYS + GLFW.features[0x00030005] = false; //GLFW_KEY_REPEAT + GLFW.features[0x00030006] = true; //GLFW_AUTO_POLL_EVENTS + + GLFW.params = new Array(); + GLFW.params[0x00020001] = true; //GLFW_OPENED + GLFW.params[0x00020002] = true; //GLFW_ACTIVE + GLFW.params[0x00020003] = false; //GLFW_ICONIFIED + GLFW.params[0x00020004] = true; //GLFW_ACCELERATED + GLFW.params[0x00020005] = 0; //GLFW_RED_BITS + GLFW.params[0x00020006] = 0; //GLFW_GREEN_BITS + GLFW.params[0x00020007] = 0; //GLFW_BLUE_BITS + GLFW.params[0x00020008] = 0; //GLFW_ALPHA_BITS + GLFW.params[0x00020009] = 0; //GLFW_DEPTH_BITS + GLFW.params[0x0002000A] = 0; //GLFW_STENCIL_BITS + GLFW.params[0x0002000B] = 0; //GLFW_REFRESH_RATE + GLFW.params[0x0002000C] = 0; //GLFW_ACCUM_RED_BITS + GLFW.params[0x0002000D] = 0; //GLFW_ACCUM_GREEN_BITS + GLFW.params[0x0002000E] = 0; //GLFW_ACCUM_BLUE_BITS + GLFW.params[0x0002000F] = 0; //GLFW_ACCUM_ALPHA_BITS + GLFW.params[0x00020010] = 0; //GLFW_AUX_BUFFERS + GLFW.params[0x00020011] = 0; //GLFW_STEREO + GLFW.params[0x00020012] = 0; //GLFW_WINDOW_NO_RESIZE + GLFW.params[0x00020013] = 0; //GLFW_FSAA_SAMPLES + GLFW.params[0x00020014] = 0; //GLFW_OPENGL_VERSION_MAJOR + GLFW.params[0x00020015] = 0; //GLFW_OPENGL_VERSION_MINOR + GLFW.params[0x00020016] = 0; //GLFW_OPENGL_FORWARD_COMPAT + GLFW.params[0x00020017] = 0; //GLFW_OPENGL_DEBUG_CONTEXT + GLFW.params[0x00020018] = 0; //GLFW_OPENGL_PROFILE + + return 1; //GL_TRUE + }, + + glfwTerminate : function() {}, + + glfwGetVersion : function( major, minor, rev ) { + setValue(major, 2, 'i32'); + setValue(minor, 7, 'i32'); + setValue(rev, 7, 'i32'); + }, /* Window handling */ - glfwOpenWindow : function( width, height, redbits, greenbits, bluebits, alphabits, depthbits, stencilbits, mode ) { throw "glfwOpenWindow is not implemented yet."; }, - glfwOpenWindowHint : function( target, hint ) { throw "glfwOpenWindowHint is not implemented yet."; }, - glfwCloseWindow : function() { throw "glfwCloseWindow is not implemented yet."; }, - glfwSetWindowTitle : function( title ) { throw "glfwSetWindowTitle is not implemented yet."; }, - glfwGetWindowSize : function( width, height ) { throw "glfwGetWindowSize is not implemented yet."; }, + glfwOpenWindow__deps: ['$Browser'], + glfwOpenWindow : function( width, height, redbits, greenbits, bluebits, alphabits, depthbits, stencilbits, mode ) { + if(width == 0 && height > 0) + width = 4 * height / 3; + if(width > 0 && height == 0) + height = 3 * width / 4; + + GLFW.params[0x00020005] = redbits; //GLFW_RED_BITS + GLFW.params[0x00020006] = greenbits; //GLFW_GREEN_BITS + GLFW.params[0x00020007] = bluebits; //GLFW_BLUE_BITS + GLFW.params[0x00020008] = alphabits; //GLFW_ALPHA_BITS + GLFW.params[0x00020009] = depthbits; //GLFW_DEPTH_BITS + GLFW.params[0x0002000A] = stencilbits; //GLFW_STENCIL_BITS + + if(mode == 0x00010001){//GLFW_WINDOW + Browser.setCanvasSize( GLFW.initWindowWidth = width, + GLFW.initWindowHeight = height ); + GLFW.features[0x00030003] = true; //GLFW_STICKY_MOUSE_BUTTONS + } + else if(mode == 0x00010002){//GLFW_FULLSCREEN + GLFW.features[0x00030003] = false; //GLFW_STICKY_MOUSE_BUTTONS + } + else{ + throw "Invalid glfwOpenWindow mode."; + } + + Module.ctx = Browser.createContext(Module['canvas'], true, true); + return 1; //GL_TRUE + }, + + glfwOpenWindowHint : function( target, hint ) { + GLFW.params[target] = hint; + }, + + glfwCloseWindow__deps: ['$Browser'], + glfwCloseWindow : function() { + Module.ctx = Browser.destroyContext(Module['canvas'], true, true); + }, + + glfwSetWindowTitle : function( title ) { + document.title = Pointer_stringify(title); + }, + + glfwGetWindowSize : function( width, height ) { + setValue(width, Module['canvas'].width, 'i32'); + setValue(height, Module['canvas'].height, 'i32'); + }, + glfwSetWindowSize : function( width, height ) { throw "glfwSetWindowSize is not implemented yet."; }, glfwSetWindowPos : function( x, y ) { throw "glfwSetWindowPos is not implemented yet."; }, glfwIconifyWindow : function() { throw "glfwIconifyWindow is not implemented yet."; }, glfwRestoreWindow : function() { throw "glfwRestoreWindow is not implemented yet."; }, - glfwSwapBuffers : function() { throw "glfwSwapBuffers is not implemented yet."; }, - glfwSwapInterval : function( interval ) { throw "glfwSwapInterval is not implemented yet."; }, - glfwGetWindowParam : function( param ) { throw "glfwGetWindowParam is not implemented yet."; }, - glfwSetWindowSizeCallback : function( cbfun ) { throw "glfwSetWindowSizeCallback is not implemented yet."; }, - glfwSetWindowCloseCallback : function( cbfun ) { throw "glfwSetWindowCloseCallback is not implemented yet."; }, - glfwSetWindowRefreshCallback : function( cbfun ) { throw "glfwSetWindowRefreshCallback is not implemented yet."; }, + glfwSwapBuffers : function() {}, + glfwSwapInterval : function( interval ) {}, + + glfwGetWindowParam : function( param ) { + return GLFW.params[param]; + }, + + glfwSetWindowSizeCallback : function( cbfun ) { + GLFW.resizeFunc = cbfun; + }, + + glfwSetWindowCloseCallback : function( cbfun ) { + GLFW.closeFunc = cbfun; + }, + + glfwSetWindowRefreshCallback : function( cbfun ) { + GLFW.refreshFunc = cbfun; + }, /* Video mode functions */ glfwGetVideoModes : function( list, maxcount ) { throw "glfwGetVideoModes is not implemented yet."; }, @@ -344,17 +461,45 @@ var LibraryGLFW = { /* Input handling */ glfwPollEvents : function() { throw "glfwPollEvents is not implemented yet."; }, glfwWaitEvents : function() { throw "glfwWaitEvents is not implemented yet."; }, - glfwGetKey : function( key ) { throw "glfwGetKey is not implemented yet."; }, + + glfwGetKey : function( key ) { + //TODO, actually something + return 0;//GLFW_RELEASE + }, + glfwGetMouseButton : function( button ) { throw "glfwGetMouseButton is not implemented yet."; }, - glfwGetMousePos : function( xpos, ypos ) { throw "glfwGetMousePos is not implemented yet."; }, - glfwSetMousePos : function( xpos, ypos ) { throw "glfwSetMousePos is not implemented yet."; }, + + glfwGetMousePos : function( xpos, ypos ) { + setValue(xpos, GLFW.lastX, 'i32'); + setValue(ypos, GLFW.lastY, 'i32'); + }, + + glfwSetMousePos : function( xpos, ypos ) { + throw "glfwSetMousePos is not implemented yet."; + }, + glfwGetMouseWheel : function() { throw "glfwGetMouseWheel is not implemented yet."; }, glfwSetMouseWheel : function( pos ) { throw "glfwSetMouseWheel is not implemented yet."; }, - glfwSetKeyCallback : function( cbfun ) { throw "glfwSetKeyCallback is not implemented yet."; }, - glfwSetCharCallback : function( cbfun ) { throw "glfwSetCharCallback is not implemented yet."; }, - glfwSetMouseButtonCallback : function( cbfun ) { throw "glfwSetMouseButtonCallback is not implemented yet."; }, - glfwSetMousePosCallback : function( cbfun ) { throw "glfwSetMousePosCallback is not implemented yet."; }, - glfwSetMouseWheelCallback : function( cbfun ) { throw "glfwSetMouseWheelCallback is not implemented yet."; }, + + glfwSetKeyCallback : function( cbfun ) { + GLFW.keyFunc = cbfun; + }, + + glfwSetCharCallback : function( cbfun ) { + GLFW.charFunc = cbfun; + }, + + glfwSetMouseButtonCallback : function( cbfun ) { + GLFW.mouseButtonFunc = cbfun; + }, + + glfwSetMousePosCallback : function( cbfun ) { + GLFW.mousePosFunc = cbfun; + }, + + glfwSetMouseWheelCallback : function( cbfun ) { + GLFW.mouseWheelFunc = cbfun; + }, /* Joystick input */ glfwGetJoystickParam : function( joy, param ) { throw "glfwGetJoystickParam is not implemented yet."; }, @@ -362,14 +507,20 @@ var LibraryGLFW = { glfwGetJoystickButtons : function( joy, buttons, numbuttons ) { throw "glfwGetJoystickButtons is not implemented yet."; }, /* Time */ - glfwGetTime : function() { throw "glfwGetTime is not implemented yet."; }, - glfwSetTime : function( time ) { throw "glfwSetTime is not implemented yet."; }, + glfwGetTime : function() { + return (Date.now()/1000) - GLFW.initTime; + }, + + glfwSetTime : function( time ) { + GLFW.initTime = Date.now()/1000 + time; + }, + glfwSleep : function( time ) { throw "glfwSleep is not implemented yet."; }, /* Extension support */ - glfwExtensionSupported : function( extension ) { throw " is not implemented yet."; }, - glfwGetProcAddress : function( procname ) { throw " is not implemented yet."; }, - glfwGetGLVersion : function( major, minor, rev ) { throw " is not implemented yet."; }, + glfwExtensionSupported : function( extension ) { throw "glfwExtensionSupported is not implemented yet."; }, + glfwGetProcAddress : function( procname ) { throw "glfwGetProcAddress is not implemented yet."; }, + glfwGetGLVersion : function( major, minor, rev ) { throw "glfwGetGLVersion is not implemented yet."; }, /* Threading support */ glfwCreateThread : function( fun, arg ) { throw "glfwCreateThread is not implemented yet."; }, @@ -388,8 +539,13 @@ var LibraryGLFW = { glfwGetNumberOfProcessors : function() { throw "glfwGetNumberOfProcessors is not implemented yet."; }, /* Enable/disable functions */ - glfwEnable : function( token ) { throw "glfwEnable is not implemented yet."; }, - glfwDisable : function( token ) { throw "glfwDisable is not implemented yet."; }, + glfwEnable : function( token ) { + GLFW.features[token] = false; + }, + + glfwDisable : function( token ) { + GLFW.features[token] = true; + }, /* Image/texture I/O support */ glfwReadImage : function( name, img, flags ) { throw "glfwReadImage is not implemented yet."; }, @@ -398,7 +554,6 @@ var LibraryGLFW = { glfwLoadTexture2D : function( name, flags ) { throw "glfwLoadTexture2D is not implemented yet."; }, glfwLoadMemoryTexture2D : function( data, size, flags ) { throw "glfwLoadMemoryTexture2D is not implemented yet."; }, glfwLoadTextureImage2D : function( img, flags ) { throw "glfwLoadTextureImage2D is not implemented yet."; }, - }; autoAddDeps(LibraryGLFW, '$GLFW'); diff --git a/tests/glfw/Makefile b/tests/glfw/Makefile index 89138d74b87ae..85b9067c463ef 100644 --- a/tests/glfw/Makefile +++ b/tests/glfw/Makefile @@ -2,54 +2,55 @@ # Makefile for GLFW example programs on X11 (generated by compile.sh) ########################################################################## CC = emcc -CFLAGS = -I../include +CFLAGS = -I../include -DEMSCRIPTEN LIB = -lglfw SOLIB = LFLAGS = $(LIB) SO_LFLAGS = $(SOLIB) +EXT = html -BINARIES = triangle.js listmodes.js mthello.js pong3d.js mtbench.js particles.js splitview.js \ - mipmaps.js gears.js boing.js heightmap.js +BINARIES = triangle listmodes mthello pong3d mtbench particles splitview \ + mipmaps gears boing heightmap ## wave all: $(BINARIES) -triangle.js: triangle.c - $(CC) $(CFLAGS) triangle.c $(LFLAGS) -o $@ +triangle: triangle.c + $(CC) $(CFLAGS) triangle.c $(LFLAGS) -o $@.$(EXT) -listmodes.js: listmodes.c - $(CC) $(CFLAGS) listmodes.c $(LFLAGS) -o $@ +listmodes: listmodes.c + $(CC) $(CFLAGS) listmodes.c $(LFLAGS) -o $@.$(EXT) -mthello.js: mthello.c - $(CC) $(CFLAGS) mthello.c $(LFLAGS) -o $@ +mthello: mthello.c + $(CC) $(CFLAGS) mthello.c $(LFLAGS) -o $@.$(EXT) -pong3d.js: pong3d.c - $(CC) $(CFLAGS) pong3d.c $(LFLAGS) -o $@ +pong3d: pong3d.c + $(CC) $(CFLAGS) pong3d.c $(LFLAGS) -o $@.$(EXT) -mtbench.js: mtbench.c - $(CC) $(CFLAGS) mtbench.c $(LFLAGS) -o $@ +mtbench: mtbench.c + $(CC) $(CFLAGS) mtbench.c $(LFLAGS) -o $@.$(EXT) -particles.js: particles.c - $(CC) $(CFLAGS) particles.c $(LFLAGS) -o $@ +particles: particles.c + $(CC) $(CFLAGS) particles.c $(LFLAGS) -o $@.$(EXT) -splitview.js: splitview.c - $(CC) $(CFLAGS) splitview.c $(LFLAGS) -o $@ +splitview: splitview.c + $(CC) $(CFLAGS) splitview.c $(LFLAGS) -o $@.$(EXT) -mipmaps.js: mipmaps.c - $(CC) $(CFLAGS) mipmaps.c $(LFLAGS) -o $@ +mipmaps: mipmaps.c + $(CC) $(CFLAGS) mipmaps.c $(LFLAGS) -o $@.$(EXT) -gears.js: gears.c - $(CC) $(CFLAGS) gears.c $(LFLAGS) -o $@ +gears: gears.c + $(CC) $(CFLAGS) gears.c $(LFLAGS) -o $@.$(EXT) -boing.js: boing.c - $(CC) $(CFLAGS) boing.c $(LFLAGS) -o $@ +boing: boing.c + $(CC) $(CFLAGS) boing.c $(LFLAGS) -o $@.$(EXT) -wave.js: wave.c - $(CC) $(CFLAGS) wave.c $(LFLAGS) -o $@ +wave: wave.c + $(CC) $(CFLAGS) wave.c $(LFLAGS) -o $@.$(EXT) -heightmap.js: heightmap.c - $(CC) $(CFLAGS) heightmap.c $(LFLAGS) -o $@ +heightmap: heightmap.c + $(CC) $(CFLAGS) heightmap.c $(LFLAGS) -o $@.$(EXT) clean: rm -f $(BINARIES) diff --git a/tests/glfw/boing.c b/tests/glfw/boing.c index 08544d1a4716b..36c45b19ad94e 100644 --- a/tests/glfw/boing.c +++ b/tests/glfw/boing.c @@ -32,6 +32,10 @@ #include #include +#ifdef EMSCRIPTEN +#include +#endif + /***************************************************************************** * Various declarations and macros @@ -563,6 +567,19 @@ void DrawGrid( void ) * main() *======================================================================*/ +void iteration(){ + /* Timing */ + t = glfwGetTime(); + dt = t - t_old; + t_old = t; + + /* Draw one frame */ + display(); + + /* Swap buffers */ + glfwSwapBuffers(); +} + int main( void ) { int running; @@ -590,25 +607,18 @@ int main( void ) init(); /* Main loop */ +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else do { - /* Timing */ - t = glfwGetTime(); - dt = t - t_old; - t_old = t; - - /* Draw one frame */ - display(); - - /* Swap buffers */ - glfwSwapBuffers(); - + iteration(); /* Check if we are still running */ running = !glfwGetKey( GLFW_KEY_ESC ) && glfwGetWindowParam( GLFW_OPENED ); } while( running ); - +#endif glfwTerminate(); exit( EXIT_SUCCESS ); } diff --git a/tests/glfw/gears.c b/tests/glfw/gears.c index d9efdf9aa6314..012884145c123 100644 --- a/tests/glfw/gears.c +++ b/tests/glfw/gears.c @@ -32,6 +32,10 @@ #define M_PI 3.141592654 #endif +#ifdef EMSCRIPTEN +#include +#endif + /* The program exits when this is zero. */ static int running = 1; @@ -317,6 +321,22 @@ static void init(int argc, char *argv[]) } } +void iteration(){ + // Draw gears + draw(); + + // Update animation + animate(); + + // Swap buffers + glfwSwapBuffers(); + + // Was the window closed? + if( !glfwGetWindowParam( GLFW_OPENED ) ) + { + running = 0; + } +} /* program entry */ int main(int argc, char *argv[]) @@ -345,25 +365,15 @@ int main(int argc, char *argv[]) glfwSetWindowSizeCallback( reshape ); glfwSetKeyCallback( key ); +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else // Main loop while( running ) { - // Draw gears - draw(); - - // Update animation - animate(); - - // Swap buffers - glfwSwapBuffers(); - - // Was the window closed? - if( !glfwGetWindowParam( GLFW_OPENED ) ) - { - running = 0; - } + iteration(); } - +#endif // Terminate GLFW glfwTerminate(); diff --git a/tests/glfw/heightmap.c b/tests/glfw/heightmap.c index 7faa5d1f16859..4967ea114b003 100644 --- a/tests/glfw/heightmap.c +++ b/tests/glfw/heightmap.c @@ -30,6 +30,9 @@ #include #include "getopt.h" +#ifdef EMSCRIPTEN +#include +#endif #define GLFW_NO_GLU 1 #include @@ -674,12 +677,16 @@ static void usage(void) printf(" heightmap [-h]\n"); } +void iteration(); + +double dt; +int frame; +int iter; +double last_update_time; + int main(int argc, char** argv) { - int ch, iter; - double dt; - double last_update_time; - int frame; + int ch; float f; GLint uloc_modelview; GLint uloc_project; @@ -820,9 +827,21 @@ int main(int argc, char** argv) iter = 0; dt = last_update_time = glfwGetTime(); - while (running) +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else + // Main loop + while( running ) { - ++frame; + iteration(); + } +#endif + + exit(EXIT_SUCCESS); +} + +void iteration(){ + ++frame; /* render the next frame */ glClear(GL_COLOR_BUFFER_BIT); glDrawElements(GL_LINES, 2* MAP_NUM_LINES , GL_UNSIGNED_INT, 0); @@ -843,8 +862,5 @@ int main(int argc, char** argv) last_update_time = dt; frame = 0; } - } - - exit(EXIT_SUCCESS); } diff --git a/tests/glfw/mipmaps.c b/tests/glfw/mipmaps.c index 59bbef2e33774..bfd77f0617f21 100644 --- a/tests/glfw/mipmaps.c +++ b/tests/glfw/mipmaps.c @@ -10,11 +10,66 @@ #include +#ifdef EMSCRIPTEN +#include +#endif + +int width, height, x; +double time; +GLboolean running; + +void iteration(){ + // Get time and mouse position + time = glfwGetTime(); + glfwGetMousePos( &x, NULL ); + + // Get window size (may be different than the requested size) + glfwGetWindowSize( &width, &height ); + height = height > 0 ? height : 1; + + // Set viewport + glViewport( 0, 0, width, height ); + + // Clear color buffer + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); + glClear( GL_COLOR_BUFFER_BIT ); + + // Select and setup the projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 65.0f, (GLfloat)width / (GLfloat)height, 1.0f, + 50.0f ); + + // Select and setup the modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 0.0f, 3.0f, -20.0f, // Eye-position + 0.0f, -4.0f, -11.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + + // Draw a textured quad + glRotatef( 0.05f * (GLfloat)x + (GLfloat)time * 5.0f, 0.0f, 1.0f, 0.0f ); + glBegin( GL_QUADS ); + glTexCoord2f( -20.0f, 20.0f ); + glVertex3f( -50.0f, 0.0f, -50.0f ); + glTexCoord2f( 20.0f, 20.0f ); + glVertex3f( 50.0f, 0.0f, -50.0f ); + glTexCoord2f( 20.0f, -20.0f ); + glVertex3f( 50.0f, 0.0f, 50.0f ); + glTexCoord2f( -20.0f, -20.0f ); + glVertex3f( -50.0f, 0.0f, 50.0f ); + glEnd(); + + // Swap buffers + glfwSwapBuffers(); + + // Check if the ESC key was pressed or the window was closed + running = !glfwGetKey( GLFW_KEY_ESC ) && + glfwGetWindowParam( GLFW_OPENED ); +} + int main( void ) { - int width, height, x; - double time; - GLboolean running; GLuint textureID; char* texturePath = "mipmaps.tga"; @@ -63,56 +118,15 @@ int main( void ) glEnable( GL_TEXTURE_2D ); running = GL_TRUE; +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else + // Main loop while( running ) { - // Get time and mouse position - time = glfwGetTime(); - glfwGetMousePos( &x, NULL ); - - // Get window size (may be different than the requested size) - glfwGetWindowSize( &width, &height ); - height = height > 0 ? height : 1; - - // Set viewport - glViewport( 0, 0, width, height ); - - // Clear color buffer - glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); - glClear( GL_COLOR_BUFFER_BIT ); - - // Select and setup the projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - gluPerspective( 65.0f, (GLfloat)width / (GLfloat)height, 1.0f, - 50.0f ); - - // Select and setup the modelview matrix - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - gluLookAt( 0.0f, 3.0f, -20.0f, // Eye-position - 0.0f, -4.0f, -11.0f, // View-point - 0.0f, 1.0f, 0.0f ); // Up-vector - - // Draw a textured quad - glRotatef( 0.05f * (GLfloat)x + (GLfloat)time * 5.0f, 0.0f, 1.0f, 0.0f ); - glBegin( GL_QUADS ); - glTexCoord2f( -20.0f, 20.0f ); - glVertex3f( -50.0f, 0.0f, -50.0f ); - glTexCoord2f( 20.0f, 20.0f ); - glVertex3f( 50.0f, 0.0f, -50.0f ); - glTexCoord2f( 20.0f, -20.0f ); - glVertex3f( 50.0f, 0.0f, 50.0f ); - glTexCoord2f( -20.0f, -20.0f ); - glVertex3f( -50.0f, 0.0f, 50.0f ); - glEnd(); - - // Swap buffers - glfwSwapBuffers(); - - // Check if the ESC key was pressed or the window was closed - running = !glfwGetKey( GLFW_KEY_ESC ) && - glfwGetWindowParam( GLFW_OPENED ); + iteration(); } +#endif // Close OpenGL window and terminate GLFW glfwTerminate(); diff --git a/tests/glfw/particles.c b/tests/glfw/particles.c index 403a99978e9fa..15c133a0aa921 100644 --- a/tests/glfw/particles.c +++ b/tests/glfw/particles.c @@ -43,6 +43,10 @@ #include #include +#ifdef EMSCRIPTEN +#include +#endif + // Define tokens for GL_EXT_separate_specular_color if not already defined #ifndef GL_EXT_separate_specular_color #define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 @@ -970,10 +974,34 @@ void GLFWCALL PhysicsThreadFun( void *arg ) // main() //======================================================================== +double t0, t; +int frames, benchmark; +void iteration(){ + // Get frame time + t = glfwGetTime() - t0; + + // Draw... + Draw( t ); + + // Swap buffers + glfwSwapBuffers(); + + // Check if window was closed + running = running && glfwGetWindowParam( GLFW_OPENED ); + + // Increase frame count + frames ++; + + // End of benchmark? + if( benchmark && t >= 60.0 ) + { + running = 0; + } +} + int main( int argc, char **argv ) { - int i, frames, benchmark; - double t0, t; + int i; GLFWthread physics_thread = 0; // Use multithreading by default, but don't benchmark @@ -1108,29 +1136,15 @@ int main( int argc, char **argv ) // Main loop t0 = glfwGetTime(); frames = 0; +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else + // Main loop while( running ) { - // Get frame time - t = glfwGetTime() - t0; - - // Draw... - Draw( t ); - - // Swap buffers - glfwSwapBuffers(); - - // Check if window was closed - running = running && glfwGetWindowParam( GLFW_OPENED ); - - // Increase frame count - frames ++; - - // End of benchmark? - if( benchmark && t >= 60.0 ) - { - running = 0; - } + iteration(); } +#endif t = glfwGetTime() - t0; // Wait for particle physics thread to die diff --git a/tests/glfw/pong3d.c b/tests/glfw/pong3d.c index 1d1afd1f1808d..1f136c93ffa83 100644 --- a/tests/glfw/pong3d.c +++ b/tests/glfw/pong3d.c @@ -10,6 +10,9 @@ #include #include +#ifdef EMSCRIPTEN +#include +#endif //======================================================================== // Constants @@ -719,20 +722,9 @@ void GameOver( void ) // GameLoop() - Game loop //======================================================================== -void GameLoop( void ) -{ - int playing, event; - - // Initialize a new game - NewGame(); +int playing, event; - // Enable sticky keys - glfwEnable( GLFW_STICKY_KEYS ); - - // Loop until the game ends - playing = GL_TRUE; - while( playing && glfwGetWindowParam( GLFW_OPENED ) ) - { +void iteration(){ // Frame timer oldtime = thistime; thistime = glfwGetTime(); @@ -784,7 +776,36 @@ void GameLoop( void ) // Swap buffers glfwSwapBuffers(); +} + +void GameLoop( void ) +{ + int menuoption; + + // Initialize a new game + NewGame(); + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Loop until the game ends + playing = GL_TRUE; + + menuoption = GameMenu(); + + // If the user wants to play, let him... + if( menuoption != MENU_PLAY) + playing = GL_FALSE; + +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else + // Main loop + while( playing && glfwGetWindowParam( GLFW_OPENED ) ) + { + iteration(); } +#endif // Disable sticky keys glfwDisable( GLFW_STICKY_KEYS ); @@ -800,7 +821,6 @@ void GameLoop( void ) int main( void ) { - int menuoption; // Initialize GLFW if( !glfwInit() ) @@ -826,19 +846,7 @@ int main( void ) exit( EXIT_FAILURE ); } - // Main loop - do - { - // Get menu option - menuoption = GameMenu(); - - // If the user wants to play, let him... - if( menuoption == MENU_PLAY ) - { - GameLoop(); - } - } - while( menuoption != MENU_QUIT ); + GameLoop(); // Unload all textures if( glfwGetWindowParam( GLFW_OPENED ) ) diff --git a/tests/glfw/splitview.c b/tests/glfw/splitview.c index 932cd0d6511b1..bb85a6e7be6f8 100644 --- a/tests/glfw/splitview.c +++ b/tests/glfw/splitview.c @@ -15,6 +15,10 @@ #include #include +#ifdef EMSCRIPTEN +#include +#endif + #ifndef M_PI #define M_PI 3.14159265358979323846 #endif @@ -446,6 +450,23 @@ static void GLFWCALL mouseButtonFun( int button, int action ) // main() //======================================================================== +void iteration(){ + // Only redraw if we need to + if( do_redraw ) + { + // Draw all views + drawAllViews(); + + // Swap buffers + glfwSwapBuffers(); + + do_redraw = 0; + } + + // Wait for new events + glfwWaitEvents(); +} + int main( void ) { // Initialise GLFW @@ -484,27 +505,17 @@ int main( void ) glfwSetMousePosCallback( mousePosFun ); glfwSetMouseButtonCallback( mouseButtonFun ); +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else // Main loop - do + do { - // Only redraw if we need to - if( do_redraw ) - { - // Draw all views - drawAllViews(); - - // Swap buffers - glfwSwapBuffers(); - - do_redraw = 0; - } - - // Wait for new events - glfwWaitEvents(); - + iteration(); } // Check if the ESC key was pressed or the window was closed while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS && glfwGetWindowParam( GLFW_OPENED ) ); +#endif // Close OpenGL window and terminate GLFW glfwTerminate(); diff --git a/tests/glfw/triangle.c b/tests/glfw/triangle.c index a8b737bee7fe2..db9d9ab163573 100644 --- a/tests/glfw/triangle.c +++ b/tests/glfw/triangle.c @@ -8,87 +8,101 @@ #include #include +#ifdef EMSCRIPTEN +#include +#endif -int main( void ) +void +iteration () { - int width, height, x; - double t; + int width, height, x; + double t; + + t = glfwGetTime (); + glfwGetMousePos (&x, NULL); + + // Get window size (may be different than the requested size) + glfwGetWindowSize (&width, &height); + + // Special case: avoid division by zero below + height = height > 0 ? height : 1; + + glViewport (0, 0, width, height); + + // Clear color buffer to black + glClearColor (0.0f, 0.0f, 0.0f, 0.0f); + glClear (GL_COLOR_BUFFER_BIT); + + // Select and setup the projection matrix + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + gluPerspective (65.0f, (GLfloat) width / (GLfloat) height, 1.0f, 100.0f); + + // Select and setup the modelview matrix + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + gluLookAt (0.0f, 1.0f, 0.0f, // Eye-position + 0.0f, 20.0f, 0.0f, // View-point + 0.0f, 0.0f, 1.0f); // Up-vector + + // Draw a rotating colorful triangle + //glTranslatef (0.0f, 14.0f, 0.0f); + glTranslatef (0.0f, 1.0f, 0.0f); + glRotatef (0.3f * (GLfloat) x + (GLfloat) t * 100.0f, 0.0f, 0.0f, 1.0f); + glBegin (GL_TRIANGLES); + glColor3f (1.0f, 0.0f, 0.0f); + glVertex3f (-5.0f, 0.0f, -4.0f); + glColor3f (0.0f, 1.0f, 0.0f); + glVertex3f (5.0f, 0.0f, -4.0f); + glColor3f (0.0f, 0.0f, 1.0f); + glVertex3f (0.0f, 0.0f, 6.0f); + glEnd (); + + // Swap buffers + glfwSwapBuffers (); - // Initialise GLFW - if( !glfwInit() ) +} + +int +main (void) +{ + // Initialise GLFW + if (!glfwInit ()) { - fprintf( stderr, "Failed to initialize GLFW\n" ); - exit( EXIT_FAILURE ); + fprintf (stderr, "Failed to initialize GLFW\n"); + exit (EXIT_FAILURE); } - // Open a window and create its OpenGL context - if( !glfwOpenWindow( 640, 480, 0,0,0,0, 0,0, GLFW_WINDOW ) ) + // Open a window and create its OpenGL context + if (!glfwOpenWindow (640, 480, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) { - fprintf( stderr, "Failed to open GLFW window\n" ); + fprintf (stderr, "Failed to open GLFW window\n"); - glfwTerminate(); - exit( EXIT_FAILURE ); + glfwTerminate (); + exit (EXIT_FAILURE); } - glfwSetWindowTitle( "Spinning Triangle" ); + glfwSetWindowTitle ("Spinning Triangle"); - // Ensure we can capture the escape key being pressed below - glfwEnable( GLFW_STICKY_KEYS ); + // Ensure we can capture the escape key being pressed below + glfwEnable (GLFW_STICKY_KEYS); - // Enable vertical sync (on cards that support it) - glfwSwapInterval( 1 ); + // Enable vertical sync (on cards that support it) + glfwSwapInterval (1); - do +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else + do { - t = glfwGetTime(); - glfwGetMousePos( &x, NULL ); - - // Get window size (may be different than the requested size) - glfwGetWindowSize( &width, &height ); - - // Special case: avoid division by zero below - height = height > 0 ? height : 1; - - glViewport( 0, 0, width, height ); - - // Clear color buffer to black - glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); - glClear( GL_COLOR_BUFFER_BIT ); - - // Select and setup the projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - gluPerspective( 65.0f, (GLfloat)width/(GLfloat)height, 1.0f, 100.0f ); - - // Select and setup the modelview matrix - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - gluLookAt( 0.0f, 1.0f, 0.0f, // Eye-position - 0.0f, 20.0f, 0.0f, // View-point - 0.0f, 0.0f, 1.0f ); // Up-vector - - // Draw a rotating colorful triangle - glTranslatef( 0.0f, 14.0f, 0.0f ); - glRotatef( 0.3f*(GLfloat)x + (GLfloat)t*100.0f, 0.0f, 0.0f, 1.0f ); - glBegin( GL_TRIANGLES ); - glColor3f( 1.0f, 0.0f, 0.0f ); - glVertex3f( -5.0f, 0.0f, -4.0f ); - glColor3f( 0.0f, 1.0f, 0.0f ); - glVertex3f( 5.0f, 0.0f, -4.0f ); - glColor3f( 0.0f, 0.0f, 1.0f ); - glVertex3f( 0.0f, 0.0f, 6.0f ); - glEnd(); - - // Swap buffers - glfwSwapBuffers(); - - } // Check if the ESC key was pressed or the window was closed - while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS && - glfwGetWindowParam( GLFW_OPENED ) ); - - // Close OpenGL window and terminate GLFW - glfwTerminate(); - - exit( EXIT_SUCCESS ); -} + iteration (); + } // Check if the ESC key was pressed or the window was closed + while (glfwGetKey (GLFW_KEY_ESC) != GLFW_PRESS && + glfwGetWindowParam (GLFW_OPENED)); +#endif + + // Close OpenGL window and terminate GLFW + glfwTerminate (); + exit (EXIT_SUCCESS); +} From 9d20403ebab5c87fdab6650844020024acb8fdf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Tue, 5 Mar 2013 13:17:27 +0100 Subject: [PATCH 016/544] * Misc functions. --- src/library_glfw.js | 161 ++++++++++++++++++++++---------------------- 1 file changed, 79 insertions(+), 82 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index db457bc4f8c6e..23dea5fc4d80a 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -1,7 +1,6 @@ var LibraryGLFW = { $GLFW: { - initTime: null, keyboardFunc: null, charFunc: null, mouseButtonFunc: null, @@ -10,23 +9,27 @@ var LibraryGLFW = { resizeFunc: null, closeFunc: null, refreshFunc: null, - motionFunc: null, - passiveMotionFunc: null, mouseFunc: null, - features: null, params: null, + initTime: null, lastX: 0, lastY: 0, buttons: 0, modifiers: 0, initWindowWidth: 640, initWindowHeight: 480, + +/******************************************************************************* + * DOM EVENT CALLBACKS + ******************************************************************************/ + +/* // Set when going fullscreen windowX: 0, windowY: 0, windowWidth: 0, windowHeight: 0, - +*/ savePosition: function(event) { /* TODO maybe loop here ala http://www.quirksmode.org/js/findpos.html */ GLFW.lastX = event['clientX'] - Module['canvas'].offsetLeft; @@ -197,80 +200,61 @@ var LibraryGLFW = { return null; }, - onKeydown: function(event) { -/* - if (GLFW.specialFunc || GLFW.keyboardFunc) { + onKeyChanged: function(event, status){ + if (GLFW.charFunc || GLFW.keyboardFunc) { var key = GLFW.getSpecialKey(event['keyCode']); if (key !== null) { - if( GLFW.specialFunc ) { + if( GLFW.keyboardFunc ) { event.preventDefault(); GLFW.saveModifiers(event); - Runtime.dynCall('viii', GLFW.specialFunc, [key, GLFW.lastX, GLFW.lastY]); + Runtime.dynCall('vii', GLFW.keyboardFunc, [key, status]); } } - else - { - key = GLFW.getASCIIKey(event); - if( key !== null && GLFW.keyboardFunc ) { - event.preventDefault(); - GLFW.saveModifiers(event); - Runtime.dynCall('viii', GLFW.keyboardFunc, [key, GLFW.lastX, GLFW.lastY]); - } + + key = GLFW.getASCIIKey(event); + if( key !== null && GLFW.charFunc ) { + event.preventDefault(); + GLFW.saveModifiers(event); + Runtime.dynCall('vii', GLFW.charFunc, [key, status]); } } -*/ + }, + + onKeydown: function(event) { + GLFW.onKeyChanged(event, 1);//GLFW_PRESS }, onKeyup: function(event) { -/* - if (GLFW.specialUpFunc || GLFW.keyboardUpFunc) { - var key = GLFW.getSpecialKey(event['keyCode']); - if (key !== null) { - if(GLFW.specialUpFunc) { - event.preventDefault (); - GLFW.saveModifiers(event); - Runtime.dynCall('viii', GLFW.specialUpFunc, [key, GLFW.lastX, GLFW.lastY]); - } - } - else - { - key = GLFW.getASCIIKey(event); - if( key !== null && GLFW.keyboardUpFunc ) { - event.preventDefault (); - GLFW.saveModifiers(event); - Runtime.dynCall('viii', GLFW.keyboardUpFunc, [key, GLFW.lastX, GLFW.lastY]); - } - } - } -*/ + GLFW.onKeyChanged(event, 0);//GLFW_RELEASE }, - onMouseButtonDown: function(event){ -/* - GLFW.savePosition(event); - GLFW.buttons |= (1 << event['button']); + onMouseButtonChanged: function(event, status){ + if(GLFW.mouseButtonFunc == null) + return; - if(event.target == Module["canvas"] && GLFW.mouseFunc){ - try { - event.target.setCapture(); - } catch (e) {} + GLFW.savePosition(event); + if(event.target == Module["canvas"] || status == 0){//GLFW_RELEASE + if(status == 1){//GLFW_PRESS + try { + event.target.setCapture(); + } catch (e) {} + } event.preventDefault(); GLFW.saveModifiers(event); - Runtime.dynCall('viiii', GLFW.mouseFunc, [event['button'], 0, GLFW.lastX, GLFW.lastY]); - } - }, + //DOM and glfw have the same button codes + Runtime.dynCall('vii', GLFW.mouseFunc, [event['button'], status]); + } + }, - onMouseButtonUp: function(event){ - GLFW.savePosition(event); - GLFW.buttons &= ~(1 << event['button']); + onMouseButtonDown: function(event){ + GLFW.buttons |= (1 << event['button']); + GLFW.onMouseButtonChanged(event, 1);//GLFW_PRESS + }, - if(GLFW.mouseFunc) { - event.preventDefault(); - GLFW.saveModifiers(event); - Runtime.dynCall('viiii', GLFW.mouseFunc, [event['button'], 1, GLFW.lastX, GLFW.lastY]); - } -*/ - }, + onMouseButtonUp: function(event){ + GLFW.buttons &= ~(1 << event['button']); + GLFW.onMouseButtonChanged(event, 0);//GLFW_RELEASE + }, // TODO add fullscreen API ala: // http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/ @@ -318,14 +302,18 @@ var LibraryGLFW = { } }, +/******************************************************************************* + * GLFW FUNCTIONS + ******************************************************************************/ + /* GLFW initialization, termination and version querying */ glfwInit : function() { GLFW.initTime = Date.now() / 1000; -/* + window.addEventListener("keydown", GLFW.onKeydown, true); window.addEventListener("keyup", GLFW.onKeyup, true); -*/ window.addEventListener("mousemove", GLFW.onMousemove, true); -/* window.addEventListener("mousedown", GLFW.onMouseButtonDown, true); + window.addEventListener("mousemove", GLFW.onMousemove, true); + window.addEventListener("mousedown", GLFW.onMouseButtonDown, true); window.addEventListener("mouseup", GLFW.onMouseButtonUp, true); __ATEXIT__.push({ func: function() { @@ -336,16 +324,14 @@ var LibraryGLFW = { window.removeEventListener("mouseup", GLFW.onMouseButtonUp, true); Module["canvas"].width = Module["canvas"].height = 1; } }); -*/ - GLFW.features = new Array(); - GLFW.features[0x00030001] = true; //GLFW_MOUSE_CURSOR - GLFW.features[0x00030002] = false; //GLFW_STICKY_KEYS - GLFW.features[0x00030003] = true; //GLFW_STICKY_MOUSE_BUTTONS - GLFW.features[0x00030004] = false; //GLFW_SYSTEM_KEYS - GLFW.features[0x00030005] = false; //GLFW_KEY_REPEAT - GLFW.features[0x00030006] = true; //GLFW_AUTO_POLL_EVENTS GLFW.params = new Array(); + GLFW.params[0x00030001] = true; //GLFW_MOUSE_CURSOR + GLFW.params[0x00030002] = false; //GLFW_STICKY_KEYS + GLFW.params[0x00030003] = true; //GLFW_STICKY_MOUSE_BUTTONS + GLFW.params[0x00030004] = false; //GLFW_SYSTEM_KEYS + GLFW.params[0x00030005] = false; //GLFW_KEY_REPEAT + GLFW.params[0x00030006] = true; //GLFW_AUTO_POLL_EVENTS GLFW.params[0x00020001] = true; //GLFW_OPENED GLFW.params[0x00020002] = true; //GLFW_ACTIVE GLFW.params[0x00020003] = false; //GLFW_ICONIFIED @@ -400,10 +386,10 @@ var LibraryGLFW = { if(mode == 0x00010001){//GLFW_WINDOW Browser.setCanvasSize( GLFW.initWindowWidth = width, GLFW.initWindowHeight = height ); - GLFW.features[0x00030003] = true; //GLFW_STICKY_MOUSE_BUTTONS + GLFW.params[0x00030003] = true; //GLFW_STICKY_MOUSE_BUTTONS } else if(mode == 0x00010002){//GLFW_FULLSCREEN - GLFW.features[0x00030003] = false; //GLFW_STICKY_MOUSE_BUTTONS + GLFW.params[0x00030003] = false; //GLFW_STICKY_MOUSE_BUTTONS } else{ throw "Invalid glfwOpenWindow mode."; @@ -419,6 +405,9 @@ var LibraryGLFW = { glfwCloseWindow__deps: ['$Browser'], glfwCloseWindow : function() { + if (GLFW.closeFunc) { + Runtime.dynCall('v', GLUT.closeFunc, []); + } Module.ctx = Browser.destroyContext(Module['canvas'], true, true); }, @@ -431,11 +420,20 @@ var LibraryGLFW = { setValue(height, Module['canvas'].height, 'i32'); }, - glfwSetWindowSize : function( width, height ) { throw "glfwSetWindowSize is not implemented yet."; }, + glfwSetWindowSize : function( width, height ) { + GLFW.cancelFullScreen(); + Browser.setCanvasSize(width, height); + if (GLFW.resizeFunc) { + Runtime.dynCall('vii', GLUT.resizeFunc, [width, height]); + } + }, + glfwSetWindowPos : function( x, y ) { throw "glfwSetWindowPos is not implemented yet."; }, glfwIconifyWindow : function() { throw "glfwIconifyWindow is not implemented yet."; }, glfwRestoreWindow : function() { throw "glfwRestoreWindow is not implemented yet."; }, + glfwSwapBuffers : function() {}, + glfwSwapInterval : function( interval ) {}, glfwGetWindowParam : function( param ) { @@ -467,17 +465,16 @@ var LibraryGLFW = { return 0;//GLFW_RELEASE }, - glfwGetMouseButton : function( button ) { throw "glfwGetMouseButton is not implemented yet."; }, + glfwGetMouseButton : function( button ) { + return GLUT.buttons & button; + }, glfwGetMousePos : function( xpos, ypos ) { setValue(xpos, GLFW.lastX, 'i32'); setValue(ypos, GLFW.lastY, 'i32'); }, - glfwSetMousePos : function( xpos, ypos ) { - throw "glfwSetMousePos is not implemented yet."; - }, - + glfwSetMousePos : function( xpos, ypos ) { throw "glfwSetMousePos is not implemented yet."; }, glfwGetMouseWheel : function() { throw "glfwGetMouseWheel is not implemented yet."; }, glfwSetMouseWheel : function( pos ) { throw "glfwSetMouseWheel is not implemented yet."; }, @@ -540,11 +537,11 @@ var LibraryGLFW = { /* Enable/disable functions */ glfwEnable : function( token ) { - GLFW.features[token] = false; + GLFW.params[token] = false; }, glfwDisable : function( token ) { - GLFW.features[token] = true; + GLFW.params[token] = true; }, /* Image/texture I/O support */ From e0883e3d8663362a3fa5756d0f4161fb2b00f277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Tue, 12 Mar 2013 18:25:28 +0100 Subject: [PATCH 017/544] * Added a test. * Mouse events are ok. * Keyboard events work partially. --- src/library_glfw.js | 457 ++++++++++++++++++---------------------- tests/glfw/Makefile | 5 +- tests/glfw/glfwsample.c | 375 +++++++++++++++++++++++++++++++++ 3 files changed, 587 insertions(+), 250 deletions(-) create mode 100644 tests/glfw/glfwsample.c diff --git a/src/library_glfw.js b/src/library_glfw.js index 23dea5fc4d80a..6a00025294956 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -1,51 +1,140 @@ +/******************************************************************************* + * EMSCRIPTEN GLFW 2.7.7 emulation. + * It tries to copy the behavior described in + * http://www.glfw.org/GLFWReference277.pdf + * + * What it does: + * - Creates a GL context. + * - Manage keyboard and mouse events. + * + * What it does not but should do: + * - Transmit events when glfwPollEvents, glfwWaitEvents or glfwSwapBuffers is + * called. Events callbacks are called as soon as event are received. + * - Correctly handle unicode characters + * - Thread emulation. + * - Joystick support. + * - Image/Texture I/O support. + * - GL Extensions support. + * - Video modes. + * + ******************************************************************************/ var LibraryGLFW = { $GLFW: { - keyboardFunc: null, - charFunc: null, - mouseButtonFunc: null, - mousePosFunc: null, - mouseWheelFunc: null, + keyFunc: null, + charFunc: null, + mouseButtonFunc: null, + mousePosFunc: null, + mouseWheelFunc: null, resizeFunc: null, - closeFunc: null, - refreshFunc: null, + closeFunc: null, + refreshFunc: null, mouseFunc: null, - params: null, + params: null, initTime: null, + wheelPos: 0, lastX: 0, lastY: 0, buttons: 0, - modifiers: 0, + keys: 0, initWindowWidth: 640, initWindowHeight: 480, -/******************************************************************************* - * DOM EVENT CALLBACKS - ******************************************************************************/ - -/* // Set when going fullscreen windowX: 0, windowY: 0, windowWidth: 0, windowHeight: 0, -*/ + +/******************************************************************************* + * DOM EVENT CALLBACKS + ******************************************************************************/ + savePosition: function(event) { /* TODO maybe loop here ala http://www.quirksmode.org/js/findpos.html */ GLFW.lastX = event['clientX'] - Module['canvas'].offsetLeft; GLFW.lastY = event['clientY'] - Module['canvas'].offsetTop; }, - saveModifiers: function(event) { -/* - GLFW.modifiers = 0; - if (event['shiftKey']) - GLFW.modifiers += 1; // GLFW_ACTIVE_SHIFT - if (event['ctrlKey']) - GLFW.modifiers += 2; // GLFW_ACTIVE_CTRL - if (event['altKey']) - GLFW.modifiers += 4; // GLFW_ACTIVE_ALT -*/ + DOMToGLFWKeyCode: function(keycode) { + switch (keycode) { + case 0x09 : return 295 ; //DOM_VK_TAB -> GLFW_KEY_TAB + case 0x1B : return 255 ; //DOM_VK_ESCAPE -> GLFW_KEY_ESC + case 0x6A : return 313 ; //DOM_VK_MULTIPLY -> GLFW_KEY_KP_MULTIPLY + case 0x6B : return 315 ; //DOM_VK_ADD -> GLFW_KEY_KP_ADD + case 0x6D : return 314 ; //DOM_VK_SUBTRACT -> GLFW_KEY_KP_SUBTRACT + case 0x6E : return 316 ; //DOM_VK_DECIMAL -> GLFW_KEY_KP_DECIMAL + case 0x6F : return 312 ; //DOM_VK_DIVIDE -> GLFW_KEY_KP_DIVIDE + case 0x70 : return 258 ; //DOM_VK_F1 -> GLFW_KEY_F1 + case 0x71 : return 259 ; //DOM_VK_F2 -> GLFW_KEY_F2 + case 0x72 : return 260 ; //DOM_VK_F3 -> GLFW_KEY_F3 + case 0x73 : return 261 ; //DOM_VK_F4 -> GLFW_KEY_F4 + case 0x74 : return 262 ; //DOM_VK_F5 -> GLFW_KEY_F5 + case 0x75 : return 263 ; //DOM_VK_F6 -> GLFW_KEY_F6 + case 0x76 : return 264 ; //DOM_VK_F7 -> GLFW_KEY_F7 + case 0x77 : return 265 ; //DOM_VK_F8 -> GLFW_KEY_F8 + case 0x78 : return 266 ; //DOM_VK_F9 -> GLFW_KEY_F9 + case 0x79 : return 267 ; //DOM_VK_F10 -> GLFW_KEY_F10 + case 0x7a : return 268 ; //DOM_VK_F11 -> GLFW_KEY_F11 + case 0x7b : return 269 ; //DOM_VK_F12 -> GLFW_KEY_F12 + case 0x25 : return 285 ; //DOM_VK_LEFT -> GLFW_KEY_LEFT + case 0x26 : return 283 ; //DOM_VK_UP -> GLFW_KEY_UP + case 0x27 : return 286 ; //DOM_VK_RIGHT -> GLFW_KEY_RIGHT + case 0x28 : return 284 ; //DOM_VK_DOWN -> GLFW_KEY_DOWN + case 0x21 : return 298 ; //DOM_VK_PAGE_UP -> GLFW_KEY_PAGEUP + case 0x22 : return 299 ; //DOM_VK_PAGE_DOWN -> GLFW_KEY_PAGEDOWN + case 0x24 : return 300 ; //DOM_VK_HOME -> GLFW_KEY_HOME + case 0x23 : return 301 ; //DOM_VK_END -> GLFW_KEY_END + case 0x2d : return 296 ; //DOM_VK_INSERT -> GLFW_KEY_INSERT + case 16 : return 287 ; //DOM_VK_SHIFT -> GLFW_KEY_LSHIFT + case 0x05 : return 287 ; //DOM_VK_LEFT_SHIFT -> GLFW_KEY_LSHIFT + case 0x06 : return 288 ; //DOM_VK_RIGHT_SHIFT -> GLFW_KEY_RSHIFT + case 17 : return 289 ; //DOM_VK_CONTROL -> GLFW_KEY_LCTRL + case 0x03 : return 289 ; //DOM_VK_LEFT_CONTROL -> GLFW_KEY_LCTRL + case 0x04 : return 290 ; //DOM_VK_RIGHT_CONTROL -> GLFW_KEY_RCTRL + case 18 : return 291 ; //DOM_VK_ALT -> GLFW_KEY_LALT + case 0x02 : return 291 ; //DOM_VK_LEFT_ALT -> GLFW_KEY_LALT + case 0x01 : return 292 ; //DOM_VK_RIGHT_ALT -> GLFW_KEY_RALT + case 96 : return 302 ; //GLFW_KEY_KP_0 + case 97 : return 303 ; //GLFW_KEY_KP_1 + case 98 : return 304 ; //GLFW_KEY_KP_2 + case 99 : return 305 ; //GLFW_KEY_KP_3 + case 100 : return 306 ; //GLFW_KEY_KP_4 + case 101 : return 307 ; //GLFW_KEY_KP_5 + case 102 : return 308 ; //GLFW_KEY_KP_6 + case 103 : return 309 ; //GLFW_KEY_KP_7 + case 104 : return 310 ; //GLFW_KEY_KP_8 + case 105 : return 311 ; //GLFW_KEY_KP_9 + default : return keycode; + }; + }, + + getUnicodeKey: function(event) { + //TODO: return the correct Unicode ISO 10646 character + return event['keyCode']; + }, + + onKeyChanged: function(event, status){ + var key = GLFW.DOMToGLFWKeyCode(event['keyCode']); + if(key && GLFW.keyFunc) { + GLFW.keys[key] = status; + event.preventDefault(); + Runtime.dynCall('vii', GLFW.keyFunc, [key, status]); + } + + var char = GLFW.getUnicodeKey(event); + if( char !== null && GLFW.charFunc ) { + event.preventDefault(); + Runtime.dynCall('vii', GLFW.charFunc, [char, status]); + } + }, + + onKeydown: function(event) { + GLFW.onKeyChanged(event, 1);//GLFW_PRESS + }, + + onKeyup: function(event) { + GLFW.onKeyChanged(event, 0);//GLFW_RELEASE }, onMousemove: function(event) { @@ -59,207 +148,55 @@ var LibraryGLFW = { return; GLFW.savePosition(event); -/* - if (GLFW.buttons == 0 && event.target == Module["canvas"] && GLFW.passiveMotionFunc) { + + if (event.target == Module["canvas"] && GLFW.mousePosFunc) { event.preventDefault(); - GLFW.saveModifiers(event); - Runtime.dynCall('vii', GLFW.passiveMotionFunc, [GLFW.lastX, GLFW.lastY]); - } else if (GLFW.buttons != 0 && GLFW.motionFunc) { - event.preventDefault(); - GLFW.saveModifiers(event); - Runtime.dynCall('vii', GLFW.motionFunc, [GLFW.lastX, GLFW.lastY]); - } -*/ + Runtime.dynCall('vii', GLFW.mousePosFunc, [GLFW.lastX, GLFW.lastY]); + } }, - getSpecialKey: function(keycode) { - var key = null; -/* - switch (keycode) { - case 0x70 : //DOM_VK_F1 - key = 1 ;//GLUT_KEY_F1 - break; - case 0x71 : //DOM_VK_F2 - key = 2 ;//GLUT_KEY_F2 - break; - case 0x72 : //DOM_VK_F3 - key = 3 ;//GLUT_KEY_F3 - break; - case 0x73 : //DOM_VK_F4 - key = 4 ;//GLUT_KEY_F4 - break; - case 0x74 : //DOM_VK_F5 - key = 5 ;//GLUT_KEY_F5 - break; - case 0x75 : //DOM_VK_F6 - key = 6 ;//GLUT_KEY_F6 - break; - case 0x76 : //DOM_VK_F7 - key = 7 ;//GLUT_KEY_F7 - break; - case 0x77 : //DOM_VK_F8 - key = 8 ;//GLUT_KEY_F8 - break; - case 0x78 : //DOM_VK_F9 - key = 9 ;//GLUT_KEY_F9 - break; - case 0x79 : //DOM_VK_F10 - key = 10 ;//GLUT_KEY_F10 - break; - case 0x7a : //DOM_VK_F11 - key = 11 ;//GLUT_KEY_F11 - break; - case 0x7b : //DOM_VK_F12 - key = 12 ;//GLUT_KEY_F12 - break; - case 0x25 : //DOM_VK_LEFT - key = 100 ;//GLUT_KEY_LEFT - break; - case 0x26 : //DOM_VK_UP - key = 101 ;//GLUT_KEY_UP - break; - case 0x27 : //DOM_VK_RIGHT - key = 102 ;//GLUT_KEY_RIGHT - break; - case 0x28 : //DOM_VK_DOWN - key = 103 ;//GLUT_KEY_DOWN - break; - case 0x21 : //DOM_VK_PAGE_UP - key = 104 ;//GLUT_KEY_PAGE_UP - break; - case 0x22 : //DOM_VK_PAGE_DOWN - key = 105 ;//GLUT_KEY_PAGE_DOWN - break; - case 0x24 : //DOM_VK_HOME - key = 106 ;//GLUT_KEY_HOME - break; - case 0x23 : //DOM_VK_END - key = 107 ;//GLUT_KEY_END - break; - case 0x2d : //DOM_VK_INSERT - key = 108 ;//GLUT_KEY_INSERT - break; - case 16 : //DOM_VK_SHIFT - case 0x05 : //DOM_VK_LEFT_SHIFT - key = 112 ;//GLUT_KEY_SHIFT_L - break; - case 0x06 : //DOM_VK_RIGHT_SHIFT - key = 113 ;//GLUT_KEY_SHIFT_R - break; - case 17 : //DOM_VK_CONTROL - case 0x03 : //DOM_VK_LEFT_CONTROL - key = 114 ;//GLUT_KEY_CONTROL_L - break; - case 0x04 : //DOM_VK_RIGHT_CONTROL - key = 115 ;//GLUT_KEY_CONTROL_R - break; - case 18 : //DOM_VK_ALT - case 0x02 : //DOM_VK_LEFT_ALT - key = 116 ;//GLUT_KEY_ALT_L - break; - case 0x01 : //DOM_VK_RIGHT_ALT - key = 117 ;//GLUT_KEY_ALT_R - break; - }; -*/ - return key; - }, - - getASCIIKey: function(event) { - if (event['ctrlKey'] || event['altKey'] || event['metaKey']) return null; -/* - var keycode = event['keyCode']; - if (48 <= keycode && keycode <= 57) - return keycode; // numeric TODO handle shift? - if (65 <= keycode && keycode <= 90) - return event['shiftKey'] ? keycode : keycode + 32; - if (106 <= keycode && keycode <= 111) - return keycode - 106 + 42; // *,+-./ TODO handle shift? - - switch (keycode) { - case 27: // escape - case 32: // space - case 61: // equal - return keycode; - } - - var s = event['shiftKey']; - switch (keycode) { - case 186: return s ? 58 : 59; // colon / semi-colon - case 187: return s ? 43 : 61; // add / equal (these two may be wrong) - case 188: return s ? 60 : 44; // less-than / comma - case 189: return s ? 95 : 45; // dash - case 190: return s ? 62 : 46; // greater-than / period - case 191: return s ? 63 : 47; // forward slash - case 219: return s ? 123 : 91; // open bracket - case 220: return s ? 124 : 47; // back slash - case 221: return s ? 125 : 93; // close braket - case 222: return s ? 34 : 39; // single quote - } -*/ - return null; - }, - - onKeyChanged: function(event, status){ - if (GLFW.charFunc || GLFW.keyboardFunc) { - var key = GLFW.getSpecialKey(event['keyCode']); - if (key !== null) { - if( GLFW.keyboardFunc ) { - event.preventDefault(); - GLFW.saveModifiers(event); - Runtime.dynCall('vii', GLFW.keyboardFunc, [key, status]); - } - } - - key = GLFW.getASCIIKey(event); - if( key !== null && GLFW.charFunc ) { - event.preventDefault(); - GLFW.saveModifiers(event); - Runtime.dynCall('vii', GLFW.charFunc, [key, status]); - } - } - }, - - onKeydown: function(event) { - GLFW.onKeyChanged(event, 1);//GLFW_PRESS - }, - - onKeyup: function(event) { - GLFW.onKeyChanged(event, 0);//GLFW_RELEASE - }, - - onMouseButtonChanged: function(event, status){ - if(GLFW.mouseButtonFunc == null) - return; + onMouseButtonChanged: function(event, status){ + if(GLFW.mouseButtonFunc == null) + return; GLFW.savePosition(event); if(event.target == Module["canvas"] || status == 0){//GLFW_RELEASE - if(status == 1){//GLFW_PRESS + if(status == 1){//GLFW_PRESS try { event.target.setCapture(); } catch (e) {} - } + } event.preventDefault(); - GLFW.saveModifiers(event); - //DOM and glfw have the same button codes - Runtime.dynCall('vii', GLFW.mouseFunc, [event['button'], status]); - } - }, + //DOM and glfw have the same button codes + Runtime.dynCall('vii', GLFW.mouseButtonFunc, [event['button'], status]); + } + }, onMouseButtonDown: function(event){ GLFW.buttons |= (1 << event['button']); - GLFW.onMouseButtonChanged(event, 1);//GLFW_PRESS - }, - - onMouseButtonUp: function(event){ - GLFW.buttons &= ~(1 << event['button']); - GLFW.onMouseButtonChanged(event, 0);//GLFW_RELEASE - }, + GLFW.onMouseButtonChanged(event, 1);//GLFW_PRESS + }, + + onMouseButtonUp: function(event){ + GLFW.buttons &= ~(1 << event['button']); + GLFW.onMouseButtonChanged(event, 0);//GLFW_RELEASE + }, + + onMouseWheel: function(event){ + if(event.detail > 0) + GLFW.wheelPos++; + if(event.detail < 0) + GLFW.wheelPos--; + + if(GLFW.mouseWheelFunc && event.target == Module["canvas"]){ + Runtime.dynCall('vi', GLFW.mouseWheelFunc, [GLFW.wheelPos]); + event.preventDefault(); + } + }, // TODO add fullscreen API ala: // http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/ onFullScreenEventChange: function(event){ -/* var width; var height; if (document["fullScreen"] || document["mozFullScreen"] || document["webkitIsFullScreen"]) { @@ -274,13 +211,10 @@ var LibraryGLFW = { document.removeEventListener('webkitfullscreenchange', GLFW.onFullScreenEventChange, true); } Browser.setCanvasSize(width, height); - // Can't call _glfwReshapeWindow as that requests cancelling fullscreen. - if (GLFW.resizeFunc) { - // console.log("GLFW.resizeFunc (from FS): " + width + ", " + height); + + if (GLFW.resizeFunc){ Runtime.dynCall('vii', GLFW.resizeFunc, [width, height]); } - _glfwPostRedisplay(); -*/ }, requestFullScreen: function() { @@ -315,6 +249,8 @@ var LibraryGLFW = { window.addEventListener("mousemove", GLFW.onMousemove, true); window.addEventListener("mousedown", GLFW.onMouseButtonDown, true); window.addEventListener("mouseup", GLFW.onMouseButtonUp, true); + window.addEventListener('DOMMouseScroll', GLFW.onMouseWheel, true); + window.addEventListener('mousewheel', GLFW.onMouseWheel, true); __ATEXIT__.push({ func: function() { window.removeEventListener("keydown", GLFW.onKeydown, true); @@ -322,6 +258,8 @@ var LibraryGLFW = { window.removeEventListener("mousemove", GLFW.onMousemove, true); window.removeEventListener("mousedown", GLFW.onMouseButtonDown, true); window.removeEventListener("mouseup", GLFW.onMouseButtonUp, true); + window.removeEventListener('DOMMouseScroll', GLFW.onMouseWheel, true); + window.removeEventListener('mousewheel', GLFW.onMouseWheel, true); Module["canvas"].width = Module["canvas"].height = 1; } }); @@ -333,29 +271,31 @@ var LibraryGLFW = { GLFW.params[0x00030005] = false; //GLFW_KEY_REPEAT GLFW.params[0x00030006] = true; //GLFW_AUTO_POLL_EVENTS GLFW.params[0x00020001] = true; //GLFW_OPENED - GLFW.params[0x00020002] = true; //GLFW_ACTIVE - GLFW.params[0x00020003] = false; //GLFW_ICONIFIED - GLFW.params[0x00020004] = true; //GLFW_ACCELERATED - GLFW.params[0x00020005] = 0; //GLFW_RED_BITS - GLFW.params[0x00020006] = 0; //GLFW_GREEN_BITS - GLFW.params[0x00020007] = 0; //GLFW_BLUE_BITS - GLFW.params[0x00020008] = 0; //GLFW_ALPHA_BITS - GLFW.params[0x00020009] = 0; //GLFW_DEPTH_BITS - GLFW.params[0x0002000A] = 0; //GLFW_STENCIL_BITS - GLFW.params[0x0002000B] = 0; //GLFW_REFRESH_RATE - GLFW.params[0x0002000C] = 0; //GLFW_ACCUM_RED_BITS - GLFW.params[0x0002000D] = 0; //GLFW_ACCUM_GREEN_BITS - GLFW.params[0x0002000E] = 0; //GLFW_ACCUM_BLUE_BITS - GLFW.params[0x0002000F] = 0; //GLFW_ACCUM_ALPHA_BITS - GLFW.params[0x00020010] = 0; //GLFW_AUX_BUFFERS - GLFW.params[0x00020011] = 0; //GLFW_STEREO - GLFW.params[0x00020012] = 0; //GLFW_WINDOW_NO_RESIZE - GLFW.params[0x00020013] = 0; //GLFW_FSAA_SAMPLES - GLFW.params[0x00020014] = 0; //GLFW_OPENGL_VERSION_MAJOR - GLFW.params[0x00020015] = 0; //GLFW_OPENGL_VERSION_MINOR - GLFW.params[0x00020016] = 0; //GLFW_OPENGL_FORWARD_COMPAT - GLFW.params[0x00020017] = 0; //GLFW_OPENGL_DEBUG_CONTEXT - GLFW.params[0x00020018] = 0; //GLFW_OPENGL_PROFILE + GLFW.params[0x00020002] = true; //GLFW_ACTIVE + GLFW.params[0x00020003] = false; //GLFW_ICONIFIED + GLFW.params[0x00020004] = true; //GLFW_ACCELERATED + GLFW.params[0x00020005] = 0; //GLFW_RED_BITS + GLFW.params[0x00020006] = 0; //GLFW_GREEN_BITS + GLFW.params[0x00020007] = 0; //GLFW_BLUE_BITS + GLFW.params[0x00020008] = 0; //GLFW_ALPHA_BITS + GLFW.params[0x00020009] = 0; //GLFW_DEPTH_BITS + GLFW.params[0x0002000A] = 0; //GLFW_STENCIL_BITS + GLFW.params[0x0002000B] = 0; //GLFW_REFRESH_RATE + GLFW.params[0x0002000C] = 0; //GLFW_ACCUM_RED_BITS + GLFW.params[0x0002000D] = 0; //GLFW_ACCUM_GREEN_BITS + GLFW.params[0x0002000E] = 0; //GLFW_ACCUM_BLUE_BITS + GLFW.params[0x0002000F] = 0; //GLFW_ACCUM_ALPHA_BITS + GLFW.params[0x00020010] = 0; //GLFW_AUX_BUFFERS + GLFW.params[0x00020011] = 0; //GLFW_STEREO + GLFW.params[0x00020012] = 0; //GLFW_WINDOW_NO_RESIZE + GLFW.params[0x00020013] = 0; //GLFW_FSAA_SAMPLES + GLFW.params[0x00020014] = 0; //GLFW_OPENGL_VERSION_MAJOR + GLFW.params[0x00020015] = 0; //GLFW_OPENGL_VERSION_MINOR + GLFW.params[0x00020016] = 0; //GLFW_OPENGL_FORWARD_COMPAT + GLFW.params[0x00020017] = 0; //GLFW_OPENGL_DEBUG_CONTEXT + GLFW.params[0x00020018] = 0; //GLFW_OPENGL_PROFILE + + GLFW.keys = new Array(); return 1; //GL_TRUE }, @@ -389,6 +329,7 @@ var LibraryGLFW = { GLFW.params[0x00030003] = true; //GLFW_STICKY_MOUSE_BUTTONS } else if(mode == 0x00010002){//GLFW_FULLSCREEN + GLFW.requestFullScreen(); GLFW.params[0x00030003] = false; //GLFW_STICKY_MOUSE_BUTTONS } else{ @@ -428,9 +369,11 @@ var LibraryGLFW = { } }, - glfwSetWindowPos : function( x, y ) { throw "glfwSetWindowPos is not implemented yet."; }, - glfwIconifyWindow : function() { throw "glfwIconifyWindow is not implemented yet."; }, - glfwRestoreWindow : function() { throw "glfwRestoreWindow is not implemented yet."; }, + glfwSetWindowPos : function( x, y ) {}, + + glfwIconifyWindow : function() {}, + + glfwRestoreWindow : function() {}, glfwSwapBuffers : function() {}, @@ -461,12 +404,11 @@ var LibraryGLFW = { glfwWaitEvents : function() { throw "glfwWaitEvents is not implemented yet."; }, glfwGetKey : function( key ) { - //TODO, actually something - return 0;//GLFW_RELEASE + return GLFW.keys[key]; }, glfwGetMouseButton : function( button ) { - return GLUT.buttons & button; + return GLFW.buttons & button; }, glfwGetMousePos : function( xpos, ypos ) { @@ -475,8 +417,14 @@ var LibraryGLFW = { }, glfwSetMousePos : function( xpos, ypos ) { throw "glfwSetMousePos is not implemented yet."; }, - glfwGetMouseWheel : function() { throw "glfwGetMouseWheel is not implemented yet."; }, - glfwSetMouseWheel : function( pos ) { throw "glfwSetMouseWheel is not implemented yet."; }, + + glfwGetMouseWheel : function() { + return GLFW.wheelPos; + }, + + glfwSetMouseWheel : function( pos ) { + GLFW.wheelPos = pos; + }, glfwSetKeyCallback : function( cbfun ) { GLFW.keyFunc = cbfun; @@ -515,9 +463,16 @@ var LibraryGLFW = { glfwSleep : function( time ) { throw "glfwSleep is not implemented yet."; }, /* Extension support */ - glfwExtensionSupported : function( extension ) { throw "glfwExtensionSupported is not implemented yet."; }, - glfwGetProcAddress : function( procname ) { throw "glfwGetProcAddress is not implemented yet."; }, - glfwGetGLVersion : function( major, minor, rev ) { throw "glfwGetGLVersion is not implemented yet."; }, + glfwExtensionSupported : function( extension ) { return 1; /*throw "glfwExtensionSupported is not implemented yet.";*/ }, + glfwGetProcAddress : function( procname ) { return null; /*throw "glfwGetProcAddress is not implemented yet.";*/ }, + + glfwGetGLVersion : function( major, minor, rev ) { + //TODO: Find something better here. + Module.printErr("Fake GL version"); + setValue(major, 4, 'i32'); + setValue(minor, 2, 'i32'); + setValue(rev, 0, 'i32'); + }, /* Threading support */ glfwCreateThread : function( fun, arg ) { throw "glfwCreateThread is not implemented yet."; }, @@ -533,7 +488,11 @@ var LibraryGLFW = { glfwWaitCond : function( cond, mutex, timeout ) { throw "glfwWaitCond is not implemented yet."; }, glfwSignalCond : function( cond ) { throw "glfwSignalCond is not implemented yet."; }, glfwBroadcastCond : function( cond ) { throw "glfwBroadcastCond is not implemented yet."; }, - glfwGetNumberOfProcessors : function() { throw "glfwGetNumberOfProcessors is not implemented yet."; }, + + glfwGetNumberOfProcessors : function() { + //Threads are disabled anyway… + return 1; + }, /* Enable/disable functions */ glfwEnable : function( token ) { diff --git a/tests/glfw/Makefile b/tests/glfw/Makefile index 85b9067c463ef..9bf06d802bc42 100644 --- a/tests/glfw/Makefile +++ b/tests/glfw/Makefile @@ -11,7 +11,7 @@ SO_LFLAGS = $(SOLIB) EXT = html BINARIES = triangle listmodes mthello pong3d mtbench particles splitview \ - mipmaps gears boing heightmap + mipmaps gears boing heightmap glfwsample ## wave all: $(BINARIES) @@ -51,6 +51,9 @@ wave: wave.c heightmap: heightmap.c $(CC) $(CFLAGS) heightmap.c $(LFLAGS) -o $@.$(EXT) + +glfwsample: glfwsample.c + $(CC) $(CFLAGS) glfwsample.c $(LFLAGS) -o $@.$(EXT) clean: rm -f $(BINARIES) diff --git a/tests/glfw/glfwsample.c b/tests/glfw/glfwsample.c new file mode 100644 index 0000000000000..38b37ceae1200 --- /dev/null +++ b/tests/glfw/glfwsample.c @@ -0,0 +1,375 @@ +#include +#include +#include + +#ifdef EMSCRIPTEN +#include +#endif + +void Init(void); +void Shut_Down(int return_code); +int Iteration(void); +void Draw_Square(float red, float green, float blue); +void Draw(void); +void OnKeyPressed( int key, int action ); +void OnCharPressed( int character, int action ); +char* GetKeyName(int key); +char* GetParamName(int param); +int OnClose(); +void OnResize( int width, int height ); +void OnRefresh(); +void OnMouseClick( int button, int action ); +void OnMouseMove( int x, int y ); +void OnMouseWheel( int pos ); +void PullInfo(); +void Iteration_void(); + +int params[] = {GLFW_OPENED, GLFW_ACTIVE, GLFW_ICONIFIED, GLFW_ACCELERATED, GLFW_RED_BITS, GLFW_GREEN_BITS, GLFW_BLUE_BITS, GLFW_ALPHA_BITS, GLFW_DEPTH_BITS, GLFW_STENCIL_BITS, GLFW_REFRESH_RATE, GLFW_ACCUM_RED_BITS, GLFW_ACCUM_GREEN_BITS, GLFW_ACCUM_BLUE_BITS, GLFW_ACCUM_ALPHA_BITS, GLFW_AUX_BUFFERS, GLFW_STEREO, GLFW_WINDOW_NO_RESIZE, GLFW_FSAA_SAMPLES, GLFW_OPENGL_VERSION_MAJOR, GLFW_OPENGL_VERSION_MINOR, GLFW_OPENGL_FORWARD_COMPAT, GLFW_OPENGL_DEBUG_CONTEXT, GLFW_OPENGL_PROFILE}; +unsigned int nb_params = sizeof(params) / sizeof(int); + +int features[] = {GLFW_MOUSE_CURSOR, GLFW_STICKY_KEYS, GLFW_STICKY_MOUSE_BUTTONS, GLFW_SYSTEM_KEYS, GLFW_KEY_REPEAT, GLFW_AUTO_POLL_EVENTS}; +unsigned int nb_features = sizeof(features) / sizeof(int); + +float rotate_y = 0, + rotate_z = 0; +const float rotations_per_tick = .2; +// the time of the previous frame +double old_time; + +int main(void) +{ + Init(); + old_time = glfwGetTime(); +#ifdef EMSCRIPTEN + emscripten_set_main_loop (Iteration_void, 0, 1); +#else + while(Iteration()); +#endif + Shut_Down(0); +} + +void Init() +{ + const int window_width = 800, + window_height = 600; + + if (glfwInit() != GL_TRUE) + Shut_Down(1); + // 800 x 600, 16 bit color, no depth, alpha or stencil buffers, windowed + if (glfwOpenWindow(window_width, window_height, 5, 6, 5, + 0, 0, 0, GLFW_WINDOW) != GL_TRUE) + Shut_Down(1); + glfwSetWindowTitle("The GLFW Window"); + + glfwSetKeyCallback( OnKeyPressed ); + glfwSetCharCallback( OnCharPressed ); + glfwSetWindowCloseCallback(OnClose); + glfwSetWindowSizeCallback(OnResize); + glfwSetWindowRefreshCallback(OnRefresh); + glfwSetMouseWheelCallback(OnMouseWheel); + glfwSetMousePosCallback(OnMouseMove); + glfwSetMouseButtonCallback(OnMouseClick); + + // set the projection matrix to a normal frustum with a max depth of 50 + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + float aspect_ratio = ((float)window_height) / window_width; + glFrustum(.5, -.5, -.5 * aspect_ratio, .5 * aspect_ratio, 1, 50); + glMatrixMode(GL_MODELVIEW); + + PullInfo(); +} + +void Shut_Down(int return_code) +{ + glfwTerminate(); + exit(return_code); +} + +int Iteration() +{ + // calculate time elapsed, and the amount by which stuff rotates + double current_time = glfwGetTime(), + delta_rotate = (current_time - old_time) * rotations_per_tick * 360; + old_time = current_time; + // escape to quit, arrow keys to rotate view + if (glfwGetKey(GLFW_KEY_ESC) == GLFW_PRESS) return 0; + if (glfwGetKey(GLFW_KEY_LEFT) == GLFW_PRESS) + rotate_y += delta_rotate; + if (glfwGetKey(GLFW_KEY_RIGHT) == GLFW_PRESS) + rotate_y -= delta_rotate; + // z axis always rotates + rotate_z += delta_rotate; + + // clear the buffer + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // draw the figure + Draw(); + // swap back and front buffers + glfwSwapBuffers(); + return 1; +} + +void Iteration_void(){ + Iteration(); +} + +void Draw_Square(float red, float green, float blue) +{ +#ifndef EMSCRIPTEN + // Draws a square with a gradient color at coordinates 0, 10 + glBegin(GL_QUADS); + { + glColor3f(red, green, blue); + glVertex2i(1, 11); + glColor3f(red * .8, green * .8, blue * .8); + glVertex2i(-1, 11); + glColor3f(red * .5, green * .5, blue * .5); + glVertex2i(-1, 9); + glColor3f(red * .8, green * .8, blue * .8); + glVertex2i(1, 9); + } + glEnd(); +#endif +} + +void Draw(void) +{ + // reset view matrix + glLoadIdentity(); + // move view back a bit + glTranslatef(0, 0, -30); + // apply the current rotation + glRotatef(rotate_y, 0, 1, 0); + glRotatef(rotate_z, 0, 0, 1); + // by repeatedly rotating the view matrix during drawing, the + // squares end up in a circle + int i = 0, squares = 15; + float red = 0, blue = 1; + for (; i < squares; ++i){ + glRotatef(360.0/squares, 0, 0, 1); + // colors change for each square + red += 1.0/12; + blue -= 1.0/12; + Draw_Square(red, .6, blue); + } +} + +void OnCharPressed( int character, int action ){ + if(action == GLFW_PRESS) + printf("'%c' is pressed\n", character); + if(action == GLFW_RELEASE) + printf("'%c' is released\n", character); +} + +char* GetKeyName(int key){ + switch(key){ + case GLFW_KEY_UNKNOWN: return "unknown"; + case GLFW_KEY_SPACE: return "space"; + case GLFW_KEY_SPECIAL: return "special"; + case GLFW_KEY_ESC: return "escape"; + case GLFW_KEY_F1 : return "F1"; + case GLFW_KEY_F2 : return "F2"; + case GLFW_KEY_F3 : return "F3"; + case GLFW_KEY_F4 : return "F4"; + case GLFW_KEY_F5 : return "F5"; + case GLFW_KEY_F6 : return "F6"; + case GLFW_KEY_F7 : return "F7"; + case GLFW_KEY_F8 : return "F8"; + case GLFW_KEY_F9 : return "F9"; + case GLFW_KEY_F10: return "F10"; + case GLFW_KEY_F11: return "F11"; + case GLFW_KEY_F12: return "F12"; + case GLFW_KEY_F13: return "F13"; + case GLFW_KEY_F14: return "F14"; + case GLFW_KEY_F15: return "F15"; + case GLFW_KEY_F16: return "F16"; + case GLFW_KEY_F17: return "F17"; + case GLFW_KEY_F18: return "F18"; + case GLFW_KEY_F19: return "F19"; + case GLFW_KEY_F20: return "F20"; + case GLFW_KEY_F21: return "F21"; + case GLFW_KEY_F22: return "F22"; + case GLFW_KEY_F23: return "F23"; + case GLFW_KEY_F24: return "F24"; + case GLFW_KEY_F25: return "F25"; + case GLFW_KEY_UP : return "up"; + case GLFW_KEY_DOWN: return "down"; + case GLFW_KEY_LEFT: return "left"; + case GLFW_KEY_RIGHT: return "right"; + case GLFW_KEY_LSHIFT: return "left shift"; + case GLFW_KEY_RSHIFT: return "right shift"; + case GLFW_KEY_LCTRL: return "left ctrl"; + case GLFW_KEY_RCTRL: return "right ctrl"; + case GLFW_KEY_LALT: return "left alt"; + case GLFW_KEY_RALT: return "right alt"; + case GLFW_KEY_TAB: return "tab"; + case GLFW_KEY_ENTER: return "enter"; + case GLFW_KEY_BACKSPACE: return "backspace"; + case GLFW_KEY_INSERT: return "insertr"; + case GLFW_KEY_DEL: return "del"; + case GLFW_KEY_PAGEUP: return "page up"; + case GLFW_KEY_PAGEDOWN: return "page down"; + case GLFW_KEY_HOME: return "home"; + case GLFW_KEY_END: return "end"; + case GLFW_KEY_KP_0: return "0"; + case GLFW_KEY_KP_1: return "1"; + case GLFW_KEY_KP_2: return "2"; + case GLFW_KEY_KP_3: return "3"; + case GLFW_KEY_KP_4: return "4"; + case GLFW_KEY_KP_5: return "5"; + case GLFW_KEY_KP_6: return "6"; + case GLFW_KEY_KP_7: return "7"; + case GLFW_KEY_KP_8: return "8"; + case GLFW_KEY_KP_9: return "9"; + case GLFW_KEY_KP_DIVIDE: return "/"; + case GLFW_KEY_KP_MULTIPLY: return "*"; + case GLFW_KEY_KP_SUBTRACT: return "-"; + case GLFW_KEY_KP_ADD: return "+"; + case GLFW_KEY_KP_DECIMAL: return "."; + case GLFW_KEY_KP_EQUAL: return "="; + case GLFW_KEY_KP_ENTER: return "enter"; + case GLFW_KEY_KP_NUM_LOCK: return "num lock"; + case GLFW_KEY_CAPS_LOCK: return "caps lock"; + case GLFW_KEY_SCROLL_LOCK: return "scroll lock"; + case GLFW_KEY_PAUSE: return "pause"; + case GLFW_KEY_LSUPER: return "left super"; + case GLFW_KEY_RSUPER: return "right super"; + case GLFW_KEY_MENU: return "menu"; + } + char* chr = malloc(2*sizeof(char)); + chr[0] = key; + chr[1] = '\0'; + return chr; +} + +char* GetParamName(int param){ + switch(param){ + case GLFW_WINDOW : return "GLFW_WINDOW"; + case GLFW_FULLSCREEN : return "GLFW_FULLSCREEN"; + case GLFW_OPENED : return "GLFW_OPENED"; + case GLFW_ACTIVE : return "GLFW_ACTIVE"; + case GLFW_ICONIFIED : return "GLFW_ICONIFIED"; + case GLFW_ACCELERATED : return "GLFW_ACCELERATED"; + case GLFW_RED_BITS : return "GLFW_RED_BITS"; + case GLFW_GREEN_BITS : return "GLFW_GREEN_BITS"; + case GLFW_BLUE_BITS : return "GLFW_BLUE_BITS"; + case GLFW_ALPHA_BITS : return "GLFW_ALPHA_BITS"; + case GLFW_DEPTH_BITS : return "GLFW_DEPTH_BITS"; + case GLFW_STENCIL_BITS : return "GLFW_STENCIL_BITS"; + case GLFW_REFRESH_RATE : return "GLFW_REFRESH_RATE"; + case GLFW_ACCUM_RED_BITS : return "GLFW_ACCUM_RED_BITS"; + case GLFW_ACCUM_GREEN_BITS : return "GLFW_ACCUM_GREEN_BITS"; + case GLFW_ACCUM_BLUE_BITS : return "GLFW_BLUE_BITS"; + case GLFW_ACCUM_ALPHA_BITS : return "GLFW_ALPHA_BITS"; + case GLFW_AUX_BUFFERS : return "GLFW_AUX_BUFFERS"; + case GLFW_STEREO : return "GLFW_STEREO"; + case GLFW_WINDOW_NO_RESIZE : return "GLFW_WINDOW_NO_RESIZE"; + case GLFW_FSAA_SAMPLES : return "GLFW_FSAA_SAMPLES"; + case GLFW_OPENGL_VERSION_MAJOR : return "GLFW_OPENGL_VERSION_MAJOR"; + case GLFW_OPENGL_VERSION_MINOR : return "GLFW_OPENGL_VERSION_MINOR"; + case GLFW_OPENGL_FORWARD_COMPAT : return "GLFW_OPENGL_FORWARD_COMPAT"; + case GLFW_OPENGL_DEBUG_CONTEXT : return "GLFW_OPENGL_DEBUG_CONTEXT"; + case GLFW_OPENGL_PROFILE : return "GLFW_OPENGL_PROFILE"; + case GLFW_OPENGL_CORE_PROFILE : return "GLFW_OPENGL_CORE_PROFILE | GLFW_PRESENT"; + case GLFW_OPENGL_COMPAT_PROFILE : return "GLFW_OPENGL_COMPAT_PROFILE | GLFW_AXES"; + case GLFW_MOUSE_CURSOR : return "GLFW_MOUSE_CURSOR"; + case GLFW_STICKY_KEYS : return "GLFW_STICKY_KEYS"; + case GLFW_STICKY_MOUSE_BUTTONS : return "GLFW_STICKY_MOUSE_BUTTONS"; + case GLFW_SYSTEM_KEYS : return "GLFW_SYSTEM_KEYS"; + case GLFW_KEY_REPEAT : return "GLFW_KEY_REPEAT"; + case GLFW_AUTO_POLL_EVENTS : return "GLFW_AUTO_POLL_EVENTS"; + case GLFW_WAIT : return "GLFW_WAIT"; + case GLFW_NOWAIT : return "GLFW_NOWAIT"; + case GLFW_BUTTONS : return "GLFW_BUTTONS"; + case GLFW_NO_RESCALE_BIT : return "GLFW_NO_RESCALE_BIT"; + case GLFW_ORIGIN_UL_BIT : return "GLFW_ORIGIN_UL_BIT"; + case GLFW_BUILD_MIPMAPS_BIT : return "GLFW_BUILD_MIPMAPS_BIT"; + case GLFW_ALPHA_MAP_BIT : return "GLFW_ALPHA_MAP_BIT"; + default : return "Invalid param"; + } +} +void OnKeyPressed( int key, int action ){ + const char* key_name = GetKeyName(key); + if(key_name == 0) + return; + if(action == GLFW_PRESS) + printf("%s (%i) is pressed\n", key_name, key); + if(action == GLFW_RELEASE) + printf("%s (%i) is released\n", key_name, key); + if(action == GLFW_RELEASE && key == GLFW_KEY_ENTER) + PullInfo(); +} + +int OnClose(){ + printf("Closed\n"); + return 0; +} + +void OnRefresh(){ + printf("Refresh\n"); +} + +void OnResize( int width, int height ){ + printf("Resizing to %i %i\n", width, height); +} + +void OnMouseClick( int button, int action ){ + if(action == GLFW_PRESS) + printf("Mouse button %i has been pressed\n", button); + if(action == GLFW_RELEASE) + printf("Mouse button %i has been released\n", button); +} + +void OnMouseMove( int x, int y ){ + printf("Mouse has been moved to %i %i\n", x, y); +} + +void OnMouseWheel( int pos ){ + printf("Mouse wheel has been moved to %i\n", pos); +} + +void PullInfo(){ + printf("================================================================================\n"); + int major, minor, rev; + glfwGetVersion(&major, &minor, &rev); + printf("GLFW version is %i.%i.%i\n", major, minor, rev); + + int width, height; + glfwGetWindowSize(&width, &height); + printf("Window size is %i %i\n", width, height); + + int status = glfwGetKey(GLFW_KEY_LCTRL); + if(status == GLFW_PRESS) + printf("Left control is pressed\n"); + else + printf("Left control is released\n"); + + status = glfwGetMouseButton(GLFW_MOUSE_BUTTON_1); + if(status == GLFW_PRESS) + printf("Mouse button 1 is pressed\n"); + else + printf("Mouse button 1 is released\n"); + + int x, y; + glfwGetMousePos(&x, &y); + printf("Mouse position is %i %i\n", x, y); + + int wheel = glfwGetMouseWheel(); + printf("Mouse wheel pos is %i\n", wheel); + + double time = glfwGetTime(); + printf("Time is %f\n", time); + + glfwGetGLVersion(&major, &minor, &rev); + printf("GL version is %i.%i.%i\n", major, minor, rev); + + int proc = glfwGetNumberOfProcessors(); + printf("%i processors are available\n", proc); + + unsigned int i; + for(i = 0; i Date: Wed, 13 Mar 2013 14:15:36 +0100 Subject: [PATCH 018/544] * Minor fix. --- src/library_glfw.js | 100 +++++++++++++++++++++++++++++----------- tests/glfw/glfwsample.c | 8 ++-- 2 files changed, 76 insertions(+), 32 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index 6a00025294956..4746cf020002b 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -21,6 +21,7 @@ var LibraryGLFW = { $GLFW: { + keyFunc: null, charFunc: null, mouseButtonFunc: null, @@ -39,8 +40,6 @@ var LibraryGLFW = { keys: 0, initWindowWidth: 640, initWindowHeight: 480, - - // Set when going fullscreen windowX: 0, windowY: 0, windowWidth: 0, @@ -49,12 +48,6 @@ var LibraryGLFW = { /******************************************************************************* * DOM EVENT CALLBACKS ******************************************************************************/ - - savePosition: function(event) { - /* TODO maybe loop here ala http://www.quirksmode.org/js/findpos.html */ - GLFW.lastX = event['clientX'] - Module['canvas'].offsetLeft; - GLFW.lastY = event['clientY'] - Module['canvas'].offsetTop; - }, DOMToGLFWKeyCode: function(keycode) { switch (keycode) { @@ -109,25 +102,31 @@ var LibraryGLFW = { }; }, - getUnicodeKey: function(event) { - //TODO: return the correct Unicode ISO 10646 character - return event['keyCode']; + getUnicodeChar: function(value) { + var output = ''; + if (value > 0xFFFF) { + value -= 0x10000; + output += String.fromCharCode(value >>> 10 & 0x3FF | 0xD800); + value = 0xDC00 | value & 0x3FF; + } + output += String.fromCharCode(value); + return output; + }, + + savePosition: function(event) { + /* TODO maybe loop here ala http://www.quirksmode.org/js/findpos.html */ + GLFW.lastX = event['clientX'] - Module['canvas'].offsetLeft; + GLFW.lastY = event['clientY'] - Module['canvas'].offsetTop; }, - onKeyChanged: function(event, status){ - var key = GLFW.DOMToGLFWKeyCode(event['keyCode']); + onKeyChanged: function(event, status){ + var key = GLFW.DOMToGLFWKeyCode(event.keyCode); if(key && GLFW.keyFunc) { GLFW.keys[key] = status; event.preventDefault(); Runtime.dynCall('vii', GLFW.keyFunc, [key, status]); } - - var char = GLFW.getUnicodeKey(event); - if( char !== null && GLFW.charFunc ) { - event.preventDefault(); - Runtime.dynCall('vii', GLFW.charFunc, [char, status]); - } - }, + }, onKeydown: function(event) { GLFW.onKeyChanged(event, 1);//GLFW_PRESS @@ -137,6 +136,18 @@ var LibraryGLFW = { GLFW.onKeyChanged(event, 0);//GLFW_RELEASE }, + onKeyPress: function(event) { + var char = GLFW.getUnicodeChar(event.charCode); + Module.printErr(event.charCode + " - " + char); + if(event.charCode){ + var char = GLFW.getUnicodeChar(event.charCode); + if( char !== null && GLFW.charFunc ) { + event.preventDefault(); + Runtime.dynCall('vii', GLFW.charFunc, [event.charCode, status]); + } + } + }, + onMousemove: function(event) { /* Send motion event only if the motion changed, prevents * spamming our app with uncessary callback call. It does happen in @@ -245,6 +256,7 @@ var LibraryGLFW = { GLFW.initTime = Date.now() / 1000; window.addEventListener("keydown", GLFW.onKeydown, true); + window.addEventListener("keypress", GLFW.onKeyPress, true); window.addEventListener("keyup", GLFW.onKeyup, true); window.addEventListener("mousemove", GLFW.onMousemove, true); window.addEventListener("mousedown", GLFW.onMouseButtonDown, true); @@ -254,6 +266,7 @@ var LibraryGLFW = { __ATEXIT__.push({ func: function() { window.removeEventListener("keydown", GLFW.onKeydown, true); + window.removeEventListener("keypress", GLFW.onKeyPress, true); window.removeEventListener("keyup", GLFW.onKeyup, true); window.removeEventListener("mousemove", GLFW.onMousemove, true); window.removeEventListener("mousedown", GLFW.onMouseButtonDown, true); @@ -263,6 +276,7 @@ var LibraryGLFW = { Module["canvas"].width = Module["canvas"].height = 1; } }); + //TODO: Init with correct values GLFW.params = new Array(); GLFW.params[0x00030001] = true; //GLFW_MOUSE_CURSOR GLFW.params[0x00030002] = false; //GLFW_STICKY_KEYS @@ -346,9 +360,8 @@ var LibraryGLFW = { glfwCloseWindow__deps: ['$Browser'], glfwCloseWindow : function() { - if (GLFW.closeFunc) { - Runtime.dynCall('v', GLUT.closeFunc, []); - } + if (GLFW.closeFunc) + Runtime.dynCall('v', GLFW.closeFunc, []); Module.ctx = Browser.destroyContext(Module['canvas'], true, true); }, @@ -365,7 +378,7 @@ var LibraryGLFW = { GLFW.cancelFullScreen(); Browser.setCanvasSize(width, height); if (GLFW.resizeFunc) { - Runtime.dynCall('vii', GLUT.resizeFunc, [width, height]); + Runtime.dynCall('vii', GLFW.resizeFunc, [width, height]); } }, @@ -397,10 +410,12 @@ var LibraryGLFW = { /* Video mode functions */ glfwGetVideoModes : function( list, maxcount ) { throw "glfwGetVideoModes is not implemented yet."; }, + glfwGetDesktopMode : function( mode ) { throw "glfwGetDesktopMode is not implemented yet."; }, /* Input handling */ - glfwPollEvents : function() { throw "glfwPollEvents is not implemented yet."; }, + glfwPollEvents : function() {}, + glfwWaitEvents : function() { throw "glfwWaitEvents is not implemented yet."; }, glfwGetKey : function( key ) { @@ -448,7 +463,9 @@ var LibraryGLFW = { /* Joystick input */ glfwGetJoystickParam : function( joy, param ) { throw "glfwGetJoystickParam is not implemented yet."; }, + glfwGetJoystickPos : function( joy, pos, numaxes ) { throw "glfwGetJoystickPos is not implemented yet."; }, + glfwGetJoystickButtons : function( joy, buttons, numbuttons ) { throw "glfwGetJoystickButtons is not implemented yet."; }, /* Time */ @@ -475,18 +492,40 @@ var LibraryGLFW = { }, /* Threading support */ - glfwCreateThread : function( fun, arg ) { throw "glfwCreateThread is not implemented yet."; }, + glfwCreateThread : function( fun, arg ) { + var str = 'v'; + for(i in arg) + str += 'i'; + Runtime.dynCall(str, fun, arg); + //One single thread + return 0; + }, + glfwDestroyThread : function( ID ) { throw "glfwDestroyThread is not implemented yet."; }, - glfwWaitThread : function( ID, waitmode ) { throw "glfwWaitThread is not implemented yet."; }, - glfwGetThreadID : function() { throw "glfwGetThreadID is not implemented yet."; }, + + glfwWaitThread : function( ID, waitmode ) {}, + + glfwGetThreadID : function() { + //One single thread + return 0; + }, + glfwCreateMutex : function() { throw "glfwCreateMutex is not implemented yet."; }, + glfwDestroyMutex : function( mutex ) { throw "glfwDestroyMutex is not implemented yet."; }, + glfwLockMutex : function( mutex ) { throw "glfwLockMutex is not implemented yet."; }, + glfwUnlockMutex : function( mutex ) { throw "glfwUnlockMutex is not implemented yet."; }, + glfwCreateCond : function() { throw "glfwCreateCond is not implemented yet."; }, + glfwDestroyCond : function( cond ) { throw "glfwDestroyCond is not implemented yet."; }, + glfwWaitCond : function( cond, mutex, timeout ) { throw "glfwWaitCond is not implemented yet."; }, + glfwSignalCond : function( cond ) { throw "glfwSignalCond is not implemented yet."; }, + glfwBroadcastCond : function( cond ) { throw "glfwBroadcastCond is not implemented yet."; }, glfwGetNumberOfProcessors : function() { @@ -505,10 +544,15 @@ var LibraryGLFW = { /* Image/texture I/O support */ glfwReadImage : function( name, img, flags ) { throw "glfwReadImage is not implemented yet."; }, + glfwReadMemoryImage : function( data, size, img, flags ) { throw "glfwReadMemoryImage is not implemented yet."; }, + glfwFreeImage : function( img ) { throw "glfwFreeImage is not implemented yet."; }, + glfwLoadTexture2D : function( name, flags ) { throw "glfwLoadTexture2D is not implemented yet."; }, + glfwLoadMemoryTexture2D : function( data, size, flags ) { throw "glfwLoadMemoryTexture2D is not implemented yet."; }, + glfwLoadTextureImage2D : function( img, flags ) { throw "glfwLoadTextureImage2D is not implemented yet."; }, }; diff --git a/tests/glfw/glfwsample.c b/tests/glfw/glfwsample.c index 38b37ceae1200..771537c581add 100644 --- a/tests/glfw/glfwsample.c +++ b/tests/glfw/glfwsample.c @@ -157,9 +157,9 @@ void Draw(void) void OnCharPressed( int character, int action ){ if(action == GLFW_PRESS) - printf("'%c' is pressed\n", character); + printf("'%c' (%i) char is pressed\n", character, character); if(action == GLFW_RELEASE) - printf("'%c' is released\n", character); + printf("'%c' (%i) char is released\n", character, character); } char* GetKeyName(int key){ @@ -294,9 +294,9 @@ void OnKeyPressed( int key, int action ){ if(key_name == 0) return; if(action == GLFW_PRESS) - printf("%s (%i) is pressed\n", key_name, key); + printf("%s (%i) key is pressed\n", key_name, key); if(action == GLFW_RELEASE) - printf("%s (%i) is released\n", key_name, key); + printf("%s (%i) key is released\n", key_name, key); if(action == GLFW_RELEASE && key == GLFW_KEY_ENTER) PullInfo(); } From b4786e49d4ad395300ed0fffcfaedee75906f8d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Fri, 15 Mar 2013 13:02:33 +0100 Subject: [PATCH 019/544] * OpenGL extensions. --- AUTHORS | 6 ++-- src/library_glfw.js | 64 ++++++++++++++++++++++++----------------- tests/glfw/glfwsample.c | 20 ++++++++++--- 3 files changed, 57 insertions(+), 33 deletions(-) diff --git a/AUTHORS b/AUTHORS index e5d1ac349fafe..7641b0c14de60 100644 --- a/AUTHORS +++ b/AUTHORS @@ -24,7 +24,7 @@ a license to everyone to use it as detailed in LICENSE.) * Pierre Renaux * Brian Anderson * Jon Bardin -* Jukka Jylänki +* Jukka Jylänki * Aleksander Guryanov * Chad Austin (copyright owned by IMVU) * nandhp @@ -46,7 +46,7 @@ a license to everyone to use it as detailed in LICENSE.) * Anthony Liot * Michael Riss * Jasper St. Pierre -* Manuel Schölling +* Manuel Schölling * Bruce Mitchener, Jr. * Michael Bishop * Roger Braun @@ -56,3 +56,5 @@ a license to everyone to use it as detailed in LICENSE.) * Martin von Gagern * Ting-Yuan Huang * Felix H. Dahlke +* Éloi Rivard + diff --git a/src/library_glfw.js b/src/library_glfw.js index 4746cf020002b..3dc032aa5fca3 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -6,17 +6,19 @@ * What it does: * - Creates a GL context. * - Manage keyboard and mouse events. + * - GL Extensions support. * * What it does not but should do: * - Transmit events when glfwPollEvents, glfwWaitEvents or glfwSwapBuffers is * called. Events callbacks are called as soon as event are received. - * - Correctly handle unicode characters + * - Correctly handle unicode characters. To be tested. * - Thread emulation. * - Joystick support. * - Image/Texture I/O support. - * - GL Extensions support. * - Video modes. * + * Authors: + * - Éloi Rivard ******************************************************************************/ var LibraryGLFW = { @@ -112,13 +114,20 @@ var LibraryGLFW = { output += String.fromCharCode(value); return output; }, - - savePosition: function(event) { - /* TODO maybe loop here ala http://www.quirksmode.org/js/findpos.html */ - GLFW.lastX = event['clientX'] - Module['canvas'].offsetLeft; - GLFW.lastY = event['clientY'] - Module['canvas'].offsetTop; - }, + onKeyPress: function(event) { + //charCode is only available whith onKeyPress event + var char = GLFW.getUnicodeChar(event.charCode); + + if(event.charCode){ + var char = GLFW.getUnicodeChar(event.charCode); + if( char !== null && GLFW.charFunc ) { + event.preventDefault(); + Runtime.dynCall('vii', GLFW.charFunc, [event.charCode, 1]); + } + } + }, + onKeyChanged: function(event, status){ var key = GLFW.DOMToGLFWKeyCode(event.keyCode); if(key && GLFW.keyFunc) { @@ -135,17 +144,11 @@ var LibraryGLFW = { onKeyup: function(event) { GLFW.onKeyChanged(event, 0);//GLFW_RELEASE }, - - onKeyPress: function(event) { - var char = GLFW.getUnicodeChar(event.charCode); - Module.printErr(event.charCode + " - " + char); - if(event.charCode){ - var char = GLFW.getUnicodeChar(event.charCode); - if( char !== null && GLFW.charFunc ) { - event.preventDefault(); - Runtime.dynCall('vii', GLFW.charFunc, [event.charCode, status]); - } - } + + savePosition: function(event) { + /* TODO maybe loop here ala http://www.quirksmode.org/js/findpos.html */ + GLFW.lastX = event['clientX'] - Module['canvas'].offsetLeft; + GLFW.lastY = event['clientY'] - Module['canvas'].offsetTop; }, onMousemove: function(event) { @@ -477,18 +480,25 @@ var LibraryGLFW = { GLFW.initTime = Date.now()/1000 + time; }, - glfwSleep : function( time ) { throw "glfwSleep is not implemented yet."; }, + glfwSleep__deps: ['sleep'], + glfwSleep : function( time ) { + _sleep(time); + }, /* Extension support */ - glfwExtensionSupported : function( extension ) { return 1; /*throw "glfwExtensionSupported is not implemented yet.";*/ }, - glfwGetProcAddress : function( procname ) { return null; /*throw "glfwGetProcAddress is not implemented yet.";*/ }, + glfwExtensionSupported : function( extension ) { + return Module.ctx.getSupportedExtensions().indexOf(Pointer_stringify(extension)) > -1; + }, + + glfwGetProcAddress__deps: ['glfwGetProcAddress'], + glfwGetProcAddress : function( procname ) { + return _getProcAddress(procname); + }, glfwGetGLVersion : function( major, minor, rev ) { - //TODO: Find something better here. - Module.printErr("Fake GL version"); - setValue(major, 4, 'i32'); - setValue(minor, 2, 'i32'); - setValue(rev, 0, 'i32'); + setValue(major, 0, 'i32'); + setValue(minor, 0, 'i32'); + setValue(rev, 1, 'i32'); }, /* Threading support */ diff --git a/tests/glfw/glfwsample.c b/tests/glfw/glfwsample.c index 771537c581add..3d9be100e70bd 100644 --- a/tests/glfw/glfwsample.c +++ b/tests/glfw/glfwsample.c @@ -67,8 +67,8 @@ void Init() glfwSetWindowSizeCallback(OnResize); glfwSetWindowRefreshCallback(OnRefresh); glfwSetMouseWheelCallback(OnMouseWheel); - glfwSetMousePosCallback(OnMouseMove); - glfwSetMouseButtonCallback(OnMouseClick); + //glfwSetMousePosCallback(OnMouseMove); + //glfwSetMouseButtonCallback(OnMouseClick); // set the projection matrix to a normal frustum with a max depth of 50 glMatrixMode(GL_PROJECTION); @@ -289,14 +289,15 @@ char* GetParamName(int param){ default : return "Invalid param"; } } + void OnKeyPressed( int key, int action ){ const char* key_name = GetKeyName(key); if(key_name == 0) return; if(action == GLFW_PRESS) - printf("%s (%i) key is pressed\n", key_name, key); + printf("'%s' (%i) key is pressed\n", key_name, key); if(action == GLFW_RELEASE) - printf("%s (%i) key is released\n", key_name, key); + printf("'%s' (%i) key is released\n", key_name, key); if(action == GLFW_RELEASE && key == GLFW_KEY_ENTER) PullInfo(); } @@ -331,6 +332,7 @@ void OnMouseWheel( int pos ){ void PullInfo(){ printf("================================================================================\n"); + int major, minor, rev; glfwGetVersion(&major, &minor, &rev); printf("GLFW version is %i.%i.%i\n", major, minor, rev); @@ -371,5 +373,15 @@ void PullInfo(){ for(i = 0; i Date: Mon, 18 Mar 2013 13:53:58 +0100 Subject: [PATCH 020/544] * Disabled setMousePos in library_glfw. --- src/library_glfw.js | 48 +++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index 3dc032aa5fca3..f0e96a0a73857 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -19,6 +19,7 @@ * * Authors: * - Éloi Rivard + * ******************************************************************************/ var LibraryGLFW = { @@ -412,14 +413,14 @@ var LibraryGLFW = { }, /* Video mode functions */ - glfwGetVideoModes : function( list, maxcount ) { throw "glfwGetVideoModes is not implemented yet."; }, + glfwGetVideoModes : function( list, maxcount ) { throw "glfwGetVideoModes is not implemented."; }, - glfwGetDesktopMode : function( mode ) { throw "glfwGetDesktopMode is not implemented yet."; }, + glfwGetDesktopMode : function( mode ) { throw "glfwGetDesktopMode is not implemented."; }, /* Input handling */ glfwPollEvents : function() {}, - glfwWaitEvents : function() { throw "glfwWaitEvents is not implemented yet."; }, + glfwWaitEvents : function() {}, glfwGetKey : function( key ) { return GLFW.keys[key]; @@ -434,7 +435,8 @@ var LibraryGLFW = { setValue(ypos, GLFW.lastY, 'i32'); }, - glfwSetMousePos : function( xpos, ypos ) { throw "glfwSetMousePos is not implemented yet."; }, + //I believe it is not possible to move the mouse with javascript + glfwSetMousePos : function( xpos, ypos ) {}, glfwGetMouseWheel : function() { return GLFW.wheelPos; @@ -465,11 +467,11 @@ var LibraryGLFW = { }, /* Joystick input */ - glfwGetJoystickParam : function( joy, param ) { throw "glfwGetJoystickParam is not implemented yet."; }, + glfwGetJoystickParam : function( joy, param ) { throw "glfwGetJoystickParam is not implemented."; }, - glfwGetJoystickPos : function( joy, pos, numaxes ) { throw "glfwGetJoystickPos is not implemented yet."; }, + glfwGetJoystickPos : function( joy, pos, numaxes ) { throw "glfwGetJoystickPos is not implemented."; }, - glfwGetJoystickButtons : function( joy, buttons, numbuttons ) { throw "glfwGetJoystickButtons is not implemented yet."; }, + glfwGetJoystickButtons : function( joy, buttons, numbuttons ) { throw "glfwGetJoystickButtons is not implemented."; }, /* Time */ glfwGetTime : function() { @@ -511,7 +513,7 @@ var LibraryGLFW = { return 0; }, - glfwDestroyThread : function( ID ) { throw "glfwDestroyThread is not implemented yet."; }, + glfwDestroyThread : function( ID ) {}, glfwWaitThread : function( ID, waitmode ) {}, @@ -520,23 +522,23 @@ var LibraryGLFW = { return 0; }, - glfwCreateMutex : function() { throw "glfwCreateMutex is not implemented yet."; }, + glfwCreateMutex : function() { throw "glfwCreateMutex is not implemented."; }, - glfwDestroyMutex : function( mutex ) { throw "glfwDestroyMutex is not implemented yet."; }, + glfwDestroyMutex : function( mutex ) { throw "glfwDestroyMutex is not implemented."; }, - glfwLockMutex : function( mutex ) { throw "glfwLockMutex is not implemented yet."; }, + glfwLockMutex : function( mutex ) { throw "glfwLockMutex is not implemented."; }, - glfwUnlockMutex : function( mutex ) { throw "glfwUnlockMutex is not implemented yet."; }, + glfwUnlockMutex : function( mutex ) { throw "glfwUnlockMutex is not implemented."; }, - glfwCreateCond : function() { throw "glfwCreateCond is not implemented yet."; }, + glfwCreateCond : function() { throw "glfwCreateCond is not implemented."; }, - glfwDestroyCond : function( cond ) { throw "glfwDestroyCond is not implemented yet."; }, + glfwDestroyCond : function( cond ) { throw "glfwDestroyCond is not implemented."; }, - glfwWaitCond : function( cond, mutex, timeout ) { throw "glfwWaitCond is not implemented yet."; }, + glfwWaitCond : function( cond, mutex, timeout ) { throw "glfwWaitCond is not implemented."; }, - glfwSignalCond : function( cond ) { throw "glfwSignalCond is not implemented yet."; }, + glfwSignalCond : function( cond ) { throw "glfwSignalCond is not implemented."; }, - glfwBroadcastCond : function( cond ) { throw "glfwBroadcastCond is not implemented yet."; }, + glfwBroadcastCond : function( cond ) { throw "glfwBroadcastCond is not implemented."; }, glfwGetNumberOfProcessors : function() { //Threads are disabled anyway… @@ -553,17 +555,17 @@ var LibraryGLFW = { }, /* Image/texture I/O support */ - glfwReadImage : function( name, img, flags ) { throw "glfwReadImage is not implemented yet."; }, + glfwReadImage : function( name, img, flags ) { throw "glfwReadImage is not implemented."; }, - glfwReadMemoryImage : function( data, size, img, flags ) { throw "glfwReadMemoryImage is not implemented yet."; }, + glfwReadMemoryImage : function( data, size, img, flags ) { throw "glfwReadMemoryImage is not implemented."; }, - glfwFreeImage : function( img ) { throw "glfwFreeImage is not implemented yet."; }, + glfwFreeImage : function( img ) { throw "glfwFreeImage is not implemented."; }, - glfwLoadTexture2D : function( name, flags ) { throw "glfwLoadTexture2D is not implemented yet."; }, + glfwLoadTexture2D : function( name, flags ) { throw "glfwLoadTexture2D is not implemented."; }, - glfwLoadMemoryTexture2D : function( data, size, flags ) { throw "glfwLoadMemoryTexture2D is not implemented yet."; }, + glfwLoadMemoryTexture2D : function( data, size, flags ) { throw "glfwLoadMemoryTexture2D is not implemented."; }, - glfwLoadTextureImage2D : function( img, flags ) { throw "glfwLoadTextureImage2D is not implemented yet."; }, + glfwLoadTextureImage2D : function( img, flags ) { throw "glfwLoadTextureImage2D is not implemented."; }, }; autoAddDeps(LibraryGLFW, '$GLFW'); From 26a2095480bfbf51275671695c0ac8c1c995cc7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Wed, 27 Mar 2013 14:29:57 +0100 Subject: [PATCH 021/544] * Fixed mouse position. --- src/library_glfw.js | 24 +++++++++++++----------- tests/glfw/glfwsample.c | 11 ++++++++--- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index f0e96a0a73857..41fef63fb0489 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -175,16 +175,18 @@ var LibraryGLFW = { return; GLFW.savePosition(event); - if(event.target == Module["canvas"] || status == 0){//GLFW_RELEASE - if(status == 1){//GLFW_PRESS - try { - event.target.setCapture(); - } catch (e) {} - } - event.preventDefault(); - //DOM and glfw have the same button codes - Runtime.dynCall('vii', GLFW.mouseButtonFunc, [event['button'], status]); - } + if(event.target != Module["canvas"]) + return; + + if(status == 1){//GLFW_PRESS + try { + event.target.setCapture(); + } catch (e) {} + } + + event.preventDefault(); + //DOM and glfw have the same button codes + Runtime.dynCall('vii', GLFW.mouseButtonFunc, [event['button'], status]); }, onMouseButtonDown: function(event){ @@ -427,7 +429,7 @@ var LibraryGLFW = { }, glfwGetMouseButton : function( button ) { - return GLFW.buttons & button; + return (GLFW.buttons & (1 << button)) > 0; }, glfwGetMousePos : function( xpos, ypos ) { diff --git a/tests/glfw/glfwsample.c b/tests/glfw/glfwsample.c index 3d9be100e70bd..79b504b61431e 100644 --- a/tests/glfw/glfwsample.c +++ b/tests/glfw/glfwsample.c @@ -67,8 +67,8 @@ void Init() glfwSetWindowSizeCallback(OnResize); glfwSetWindowRefreshCallback(OnRefresh); glfwSetMouseWheelCallback(OnMouseWheel); - //glfwSetMousePosCallback(OnMouseMove); - //glfwSetMouseButtonCallback(OnMouseClick); + glfwSetMousePosCallback(OnMouseMove); + glfwSetMouseButtonCallback(OnMouseClick); // set the projection matrix to a normal frustum with a max depth of 50 glMatrixMode(GL_PROJECTION); @@ -323,7 +323,12 @@ void OnMouseClick( int button, int action ){ } void OnMouseMove( int x, int y ){ - printf("Mouse has been moved to %i %i\n", x, y); + int lState = glfwGetMouseButton(GLFW_MOUSE_BUTTON_LEFT); + + if (lState == GLFW_PRESS) + printf("Dragged %i to %i %i\n", GLFW_MOUSE_BUTTON_LEFT, x, y); + if(lState == GLFW_RELEASE) + printf("Moved %i to %i %i\n", GLFW_MOUSE_BUTTON_LEFT, x, y); } void OnMouseWheel( int pos ){ From 5bc370bc702a276c3186bb7e537bffe2895fd7f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Wed, 27 Mar 2013 20:56:30 +0100 Subject: [PATCH 022/544] * Header. --- src/library_glfw.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index 41fef63fb0489..20c75a29d6327 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -1,6 +1,6 @@ /******************************************************************************* * EMSCRIPTEN GLFW 2.7.7 emulation. - * It tries to copy the behavior described in + * It tries to emulate the behavior described in * http://www.glfw.org/GLFWReference277.pdf * * What it does: @@ -8,14 +8,13 @@ * - Manage keyboard and mouse events. * - GL Extensions support. * - * What it does not but should do: + * What it does not but should probably do: * - Transmit events when glfwPollEvents, glfwWaitEvents or glfwSwapBuffers is * called. Events callbacks are called as soon as event are received. - * - Correctly handle unicode characters. To be tested. * - Thread emulation. * - Joystick support. - * - Image/Texture I/O support. - * - Video modes. + * - Image/Texture I/O support (that is deleted in GLFW 3). + * - Video modes detection. * * Authors: * - Éloi Rivard @@ -105,6 +104,7 @@ var LibraryGLFW = { }; }, + //UCS-2 to UTF16 (ISO 10646) getUnicodeChar: function(value) { var output = ''; if (value > 0xFFFF) { From d78dcc9b74ce35842b1dbe0bc31d087fb133f32f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Tue, 2 Apr 2013 12:39:55 +0200 Subject: [PATCH 023/544] * Fixed glfw test. --- tests/{glfw/glfwsample.c => glfw.c} | 107 ++- tests/glfw/Makefile | 60 -- tests/glfw/boing.c | 625 -------------- tests/glfw/bundle.sh | 46 -- tests/glfw/gears.c | 383 --------- tests/glfw/getopt.c | 253 ------ tests/glfw/getopt.h | 63 -- tests/glfw/heightmap.c | 866 -------------------- tests/glfw/listmodes.c | 48 -- tests/glfw/mipmaps.c | 136 ---- tests/glfw/mipmaps.tga | Bin 66322 -> 0 bytes tests/glfw/mtbench.c | 301 ------- tests/glfw/mthello.c | 48 -- tests/glfw/particles.c | 1166 --------------------------- tests/glfw/pong3d.c | 862 -------------------- tests/glfw/pong3d_field.tga | Bin 17816 -> 0 bytes tests/glfw/pong3d_instr.tga | Bin 21279 -> 0 bytes tests/glfw/pong3d_menu.tga | Bin 1835 -> 0 bytes tests/glfw/pong3d_title.tga | Bin 106516 -> 0 bytes tests/glfw/pong3d_winner1.tga | Bin 861 -> 0 bytes tests/glfw/pong3d_winner2.tga | Bin 891 -> 0 bytes tests/glfw/splitview.c | 525 ------------ tests/glfw/triangle.c | 108 --- tests/glfw/wave.c | 399 --------- tests/runner.py | 6 + 25 files changed, 58 insertions(+), 5944 deletions(-) rename tests/{glfw/glfwsample.c => glfw.c} (89%) delete mode 100644 tests/glfw/Makefile delete mode 100644 tests/glfw/boing.c delete mode 100644 tests/glfw/bundle.sh delete mode 100644 tests/glfw/gears.c delete mode 100644 tests/glfw/getopt.c delete mode 100644 tests/glfw/getopt.h delete mode 100644 tests/glfw/heightmap.c delete mode 100644 tests/glfw/listmodes.c delete mode 100644 tests/glfw/mipmaps.c delete mode 100644 tests/glfw/mipmaps.tga delete mode 100644 tests/glfw/mtbench.c delete mode 100644 tests/glfw/mthello.c delete mode 100644 tests/glfw/particles.c delete mode 100644 tests/glfw/pong3d.c delete mode 100644 tests/glfw/pong3d_field.tga delete mode 100644 tests/glfw/pong3d_instr.tga delete mode 100644 tests/glfw/pong3d_menu.tga delete mode 100644 tests/glfw/pong3d_title.tga delete mode 100644 tests/glfw/pong3d_winner1.tga delete mode 100644 tests/glfw/pong3d_winner2.tga delete mode 100644 tests/glfw/splitview.c delete mode 100644 tests/glfw/triangle.c delete mode 100644 tests/glfw/wave.c diff --git a/tests/glfw/glfwsample.c b/tests/glfw.c similarity index 89% rename from tests/glfw/glfwsample.c rename to tests/glfw.c index 79b504b61431e..79199d9a8b613 100644 --- a/tests/glfw/glfwsample.c +++ b/tests/glfw.c @@ -1,14 +1,11 @@ #include #include #include - -#ifdef EMSCRIPTEN #include -#endif void Init(void); void Shut_Down(int return_code); -int Iteration(void); +void Iteration(void); void Draw_Square(float red, float green, float blue); void Draw(void); void OnKeyPressed( int key, int action ); @@ -22,7 +19,6 @@ void OnMouseClick( int button, int action ); void OnMouseMove( int x, int y ); void OnMouseWheel( int pos ); void PullInfo(); -void Iteration_void(); int params[] = {GLFW_OPENED, GLFW_ACTIVE, GLFW_ICONIFIED, GLFW_ACCELERATED, GLFW_RED_BITS, GLFW_GREEN_BITS, GLFW_BLUE_BITS, GLFW_ALPHA_BITS, GLFW_DEPTH_BITS, GLFW_STENCIL_BITS, GLFW_REFRESH_RATE, GLFW_ACCUM_RED_BITS, GLFW_ACCUM_GREEN_BITS, GLFW_ACCUM_BLUE_BITS, GLFW_ACCUM_ALPHA_BITS, GLFW_AUX_BUFFERS, GLFW_STEREO, GLFW_WINDOW_NO_RESIZE, GLFW_FSAA_SAMPLES, GLFW_OPENGL_VERSION_MAJOR, GLFW_OPENGL_VERSION_MINOR, GLFW_OPENGL_FORWARD_COMPAT, GLFW_OPENGL_DEBUG_CONTEXT, GLFW_OPENGL_PROFILE}; unsigned int nb_params = sizeof(params) / sizeof(int); @@ -40,11 +36,7 @@ int main(void) { Init(); old_time = glfwGetTime(); -#ifdef EMSCRIPTEN - emscripten_set_main_loop (Iteration_void, 0, 1); -#else - while(Iteration()); -#endif + emscripten_set_main_loop (Iteration, 0, 1); Shut_Down(0); } @@ -86,14 +78,12 @@ void Shut_Down(int return_code) exit(return_code); } -int Iteration() +void Iteration() { // calculate time elapsed, and the amount by which stuff rotates double current_time = glfwGetTime(), delta_rotate = (current_time - old_time) * rotations_per_tick * 360; old_time = current_time; - // escape to quit, arrow keys to rotate view - if (glfwGetKey(GLFW_KEY_ESC) == GLFW_PRESS) return 0; if (glfwGetKey(GLFW_KEY_LEFT) == GLFW_PRESS) rotate_y += delta_rotate; if (glfwGetKey(GLFW_KEY_RIGHT) == GLFW_PRESS) @@ -107,52 +97,54 @@ int Iteration() Draw(); // swap back and front buffers glfwSwapBuffers(); - return 1; -} - -void Iteration_void(){ - Iteration(); -} - -void Draw_Square(float red, float green, float blue) -{ -#ifndef EMSCRIPTEN - // Draws a square with a gradient color at coordinates 0, 10 - glBegin(GL_QUADS); - { - glColor3f(red, green, blue); - glVertex2i(1, 11); - glColor3f(red * .8, green * .8, blue * .8); - glVertex2i(-1, 11); - glColor3f(red * .5, green * .5, blue * .5); - glVertex2i(-1, 9); - glColor3f(red * .8, green * .8, blue * .8); - glVertex2i(1, 9); - } - glEnd(); -#endif } void Draw(void) { - // reset view matrix - glLoadIdentity(); - // move view back a bit - glTranslatef(0, 0, -30); - // apply the current rotation - glRotatef(rotate_y, 0, 1, 0); - glRotatef(rotate_z, 0, 0, 1); - // by repeatedly rotating the view matrix during drawing, the - // squares end up in a circle - int i = 0, squares = 15; - float red = 0, blue = 1; - for (; i < squares; ++i){ - glRotatef(360.0/squares, 0, 0, 1); - // colors change for each square - red += 1.0/12; - blue -= 1.0/12; - Draw_Square(red, .6, blue); - } + int width, height, x; + double t; + + t = glfwGetTime (); + glfwGetMousePos (&x, NULL); + + // Get window size (may be different than the requested size) + glfwGetWindowSize (&width, &height); + + // Special case: avoid division by zero below + height = height > 0 ? height : 1; + + glViewport (0, 0, width, height); + // Clear color buffer to black + glClearColor (0.1f, 0.2f, 0.3f, 0.0f); + glClear (GL_COLOR_BUFFER_BIT); + + // Select and setup the projection matrix + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + gluPerspective (65.0f, (GLfloat) width / (GLfloat) height, 1.0f, 100.0f); + + // Select and setup the modelview matrix + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + gluLookAt (0.0f, 1.0f, 0.0f, // Eye-position + 0.0f, 20.0f, 0.0f, // View-point + 0.0f, 0.0f, 1.0f); // Up-vector + + // Draw a rotating colorful triangle + //glTranslatef (0.0f, 14.0f, 0.0f); + glTranslatef (0.0f, 1.0f, 0.0f); + glRotatef (0.3f * (GLfloat) x + (GLfloat) t * 100.0f, 0.0f, 0.0f, 1.0f); + glBegin (GL_TRIANGLES); + glColor3f (1.0f, 0.0f, 0.0f); + glVertex3f (-5.0f, 0.0f, -4.0f); + glColor3f (0.0f, 1.0f, 0.0f); + glVertex3f (5.0f, 0.0f, -4.0f); + glColor3f (0.0f, 0.0f, 1.0f); + glVertex3f (0.0f, 0.0f, 6.0f); + glEnd (); + + // Swap buffers + glfwSwapBuffers (); } void OnCharPressed( int character, int action ){ @@ -389,4 +381,9 @@ void PullInfo(){ printf("...Done.\n"); printf("================================================================================\n"); + +#ifdef REPORT_RESULT + int result = 1; + REPORT_RESULT(); +#endif } diff --git a/tests/glfw/Makefile b/tests/glfw/Makefile deleted file mode 100644 index 9bf06d802bc42..0000000000000 --- a/tests/glfw/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -########################################################################## -# Makefile for GLFW example programs on X11 (generated by compile.sh) -########################################################################## -CC = emcc -CFLAGS = -I../include -DEMSCRIPTEN - -LIB = -lglfw -SOLIB = -LFLAGS = $(LIB) -SO_LFLAGS = $(SOLIB) -EXT = html - -BINARIES = triangle listmodes mthello pong3d mtbench particles splitview \ - mipmaps gears boing heightmap glfwsample -## wave - -all: $(BINARIES) - -triangle: triangle.c - $(CC) $(CFLAGS) triangle.c $(LFLAGS) -o $@.$(EXT) - -listmodes: listmodes.c - $(CC) $(CFLAGS) listmodes.c $(LFLAGS) -o $@.$(EXT) - -mthello: mthello.c - $(CC) $(CFLAGS) mthello.c $(LFLAGS) -o $@.$(EXT) - -pong3d: pong3d.c - $(CC) $(CFLAGS) pong3d.c $(LFLAGS) -o $@.$(EXT) - -mtbench: mtbench.c - $(CC) $(CFLAGS) mtbench.c $(LFLAGS) -o $@.$(EXT) - -particles: particles.c - $(CC) $(CFLAGS) particles.c $(LFLAGS) -o $@.$(EXT) - -splitview: splitview.c - $(CC) $(CFLAGS) splitview.c $(LFLAGS) -o $@.$(EXT) - -mipmaps: mipmaps.c - $(CC) $(CFLAGS) mipmaps.c $(LFLAGS) -o $@.$(EXT) - -gears: gears.c - $(CC) $(CFLAGS) gears.c $(LFLAGS) -o $@.$(EXT) - -boing: boing.c - $(CC) $(CFLAGS) boing.c $(LFLAGS) -o $@.$(EXT) - -wave: wave.c - $(CC) $(CFLAGS) wave.c $(LFLAGS) -o $@.$(EXT) - -heightmap: heightmap.c - $(CC) $(CFLAGS) heightmap.c $(LFLAGS) -o $@.$(EXT) - -glfwsample: glfwsample.c - $(CC) $(CFLAGS) glfwsample.c $(LFLAGS) -o $@.$(EXT) - -clean: - rm -f $(BINARIES) - diff --git a/tests/glfw/boing.c b/tests/glfw/boing.c deleted file mode 100644 index 36c45b19ad94e..0000000000000 --- a/tests/glfw/boing.c +++ /dev/null @@ -1,625 +0,0 @@ -/***************************************************************************** - * Title: GLBoing - * Desc: Tribute to Amiga Boing. - * Author: Jim Brooks - * Original Amiga authors were R.J. Mical and Dale Luck. - * GLFW conversion by Marcus Geelnard - * Notes: - 360' = 2*PI [radian] - * - * - Distances between objects are created by doing a relative - * Z translations. - * - * - Although OpenGL enticingly supports alpha-blending, - * the shadow of the original Boing didn't affect the color - * of the grid. - * - * - [Marcus] Changed timing scheme from interval driven to frame- - * time based animation steps (which results in much smoother - * movement) - * - * History of Amiga Boing: - * - * Boing was demonstrated on the prototype Amiga (codenamed "Lorraine") in - * 1985. According to legend, it was written ad-hoc in one night by - * R. J. Mical and Dale Luck. Because the bouncing ball animation was so fast - * and smooth, attendees did not believe the Amiga prototype was really doing - * the rendering. Suspecting a trick, they began looking around the booth for - * a hidden computer or VCR. - *****************************************************************************/ - -#include -#include -#include -#include - -#ifdef EMSCRIPTEN -#include -#endif - - -/***************************************************************************** - * Various declarations and macros - *****************************************************************************/ - -/* Prototypes */ -void init( void ); -void display( void ); -void GLFWCALL reshape( int w, int h ); -void DrawBoingBall( void ); -void BounceBall( double dt ); -void DrawBoingBallBand( GLfloat long_lo, GLfloat long_hi ); -void DrawGrid( void ); - -#define RADIUS 70.f -#define STEP_LONGITUDE 22.5f /* 22.5 makes 8 bands like original Boing */ -#define STEP_LATITUDE 22.5f - -#define DIST_BALL (RADIUS * 2.f + RADIUS * 0.1f) - -#define VIEW_SCENE_DIST (DIST_BALL * 3.f + 200.f)/* distance from viewer to middle of boing area */ -#define GRID_SIZE (RADIUS * 4.5f) /* length (width) of grid */ -#define BOUNCE_HEIGHT (RADIUS * 2.1f) -#define BOUNCE_WIDTH (RADIUS * 2.1f) - -#define SHADOW_OFFSET_X -20.f -#define SHADOW_OFFSET_Y 10.f -#define SHADOW_OFFSET_Z 0.f - -#define WALL_L_OFFSET 0.f -#define WALL_R_OFFSET 5.f - -/* Animation speed (50.0 mimics the original GLUT demo speed) */ -#define ANIMATION_SPEED 50.f - -/* Maximum allowed delta time per physics iteration */ -#define MAX_DELTA_T 0.02f - -/* Draw ball, or its shadow */ -typedef enum { DRAW_BALL, DRAW_BALL_SHADOW } DRAW_BALL_ENUM; - -/* Vertex type */ -typedef struct {float x; float y; float z;} vertex_t; - -/* Global vars */ -GLfloat deg_rot_y = 0.f; -GLfloat deg_rot_y_inc = 2.f; -GLfloat ball_x = -RADIUS; -GLfloat ball_y = -RADIUS; -GLfloat ball_x_inc = 1.f; -GLfloat ball_y_inc = 2.f; -DRAW_BALL_ENUM drawBallHow; -double t; -double t_old = 0.f; -double dt; - -/* Random number generator */ -#ifndef RAND_MAX - #define RAND_MAX 4095 -#endif - -/* PI */ -#ifndef M_PI - #define M_PI 3.1415926535897932384626433832795 -#endif - - -/***************************************************************************** - * Truncate a degree. - *****************************************************************************/ -GLfloat TruncateDeg( GLfloat deg ) -{ - if ( deg >= 360.f ) - return (deg - 360.f); - else - return deg; -} - -/***************************************************************************** - * Convert a degree (360-based) into a radian. - * 360' = 2 * PI - *****************************************************************************/ -double deg2rad( double deg ) -{ - return deg / 360 * (2 * M_PI); -} - -/***************************************************************************** - * 360' sin(). - *****************************************************************************/ -double sin_deg( double deg ) -{ - return sin( deg2rad( deg ) ); -} - -/***************************************************************************** - * 360' cos(). - *****************************************************************************/ -double cos_deg( double deg ) -{ - return cos( deg2rad( deg ) ); -} - -/***************************************************************************** - * Compute a cross product (for a normal vector). - * - * c = a x b - *****************************************************************************/ -void CrossProduct( vertex_t a, vertex_t b, vertex_t c, vertex_t *n ) -{ - GLfloat u1, u2, u3; - GLfloat v1, v2, v3; - - u1 = b.x - a.x; - u2 = b.y - a.y; - u3 = b.y - a.z; - - v1 = c.x - a.x; - v2 = c.y - a.y; - v3 = c.z - a.z; - - n->x = u2 * v3 - v2 * v3; - n->y = u3 * v1 - v3 * u1; - n->z = u1 * v2 - v1 * u2; -} - -/***************************************************************************** - * Calculate the angle to be passed to gluPerspective() so that a scene - * is visible. This function originates from the OpenGL Red Book. - * - * Parms : size - * The size of the segment when the angle is intersected at "dist" - * (ie at the outermost edge of the angle of vision). - * - * dist - * Distance from viewpoint to scene. - *****************************************************************************/ -GLfloat PerspectiveAngle( GLfloat size, - GLfloat dist ) -{ - GLfloat radTheta, degTheta; - - radTheta = 2.f * (GLfloat) atan2( size / 2.f, dist ); - degTheta = (180.f * radTheta) / (GLfloat) M_PI; - return degTheta; -} - - - -#define BOING_DEBUG 0 - - -/***************************************************************************** - * init() - *****************************************************************************/ -void init( void ) -{ - /* - * Clear background. - */ - glClearColor( 0.55f, 0.55f, 0.55f, 0.f ); - - glShadeModel( GL_FLAT ); -} - - -/***************************************************************************** - * display() - *****************************************************************************/ -void display(void) -{ - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - glPushMatrix(); - - drawBallHow = DRAW_BALL_SHADOW; - DrawBoingBall(); - - DrawGrid(); - - drawBallHow = DRAW_BALL; - DrawBoingBall(); - - glPopMatrix(); - glFlush(); -} - - -/***************************************************************************** - * reshape() - *****************************************************************************/ -void GLFWCALL reshape( int w, int h ) -{ - glViewport( 0, 0, (GLsizei)w, (GLsizei)h ); - - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - - gluPerspective( PerspectiveAngle( RADIUS * 2, 200 ), - (GLfloat)w / (GLfloat)h, - 1.0, - VIEW_SCENE_DIST ); - - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - - gluLookAt( 0.0, 0.0, VIEW_SCENE_DIST,/* eye */ - 0.0, 0.0, 0.0, /* center of vision */ - 0.0, -1.0, 0.0 ); /* up vector */ -} - - -/***************************************************************************** - * Draw the Boing ball. - * - * The Boing ball is sphere in which each facet is a rectangle. - * Facet colors alternate between red and white. - * The ball is built by stacking latitudinal circles. Each circle is composed - * of a widely-separated set of points, so that each facet is noticably large. - *****************************************************************************/ -void DrawBoingBall( void ) -{ - GLfloat lon_deg; /* degree of longitude */ - double dt_total, dt2; - - glPushMatrix(); - glMatrixMode( GL_MODELVIEW ); - - /* - * Another relative Z translation to separate objects. - */ - glTranslatef( 0.0, 0.0, DIST_BALL ); - - /* Update ball position and rotation (iterate if necessary) */ - dt_total = dt; - while( dt_total > 0.0 ) - { - dt2 = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total; - dt_total -= dt2; - BounceBall( dt2 ); - deg_rot_y = TruncateDeg( deg_rot_y + deg_rot_y_inc*((float)dt2*ANIMATION_SPEED) ); - } - - /* Set ball position */ - glTranslatef( ball_x, ball_y, 0.0 ); - - /* - * Offset the shadow. - */ - if ( drawBallHow == DRAW_BALL_SHADOW ) - { - glTranslatef( SHADOW_OFFSET_X, - SHADOW_OFFSET_Y, - SHADOW_OFFSET_Z ); - } - - /* - * Tilt the ball. - */ - glRotatef( -20.0, 0.0, 0.0, 1.0 ); - - /* - * Continually rotate ball around Y axis. - */ - glRotatef( deg_rot_y, 0.0, 1.0, 0.0 ); - - /* - * Set OpenGL state for Boing ball. - */ - glCullFace( GL_FRONT ); - glEnable( GL_CULL_FACE ); - glEnable( GL_NORMALIZE ); - - /* - * Build a faceted latitude slice of the Boing ball, - * stepping same-sized vertical bands of the sphere. - */ - for ( lon_deg = 0; - lon_deg < 180; - lon_deg += STEP_LONGITUDE ) - { - /* - * Draw a latitude circle at this longitude. - */ - DrawBoingBallBand( lon_deg, - lon_deg + STEP_LONGITUDE ); - } - - glPopMatrix(); - - return; -} - - -/***************************************************************************** - * Bounce the ball. - *****************************************************************************/ -void BounceBall( double dt ) -{ - GLfloat sign; - GLfloat deg; - - /* Bounce on walls */ - if ( ball_x > (BOUNCE_WIDTH/2 + WALL_R_OFFSET ) ) - { - ball_x_inc = -0.5f - 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX; - deg_rot_y_inc = -deg_rot_y_inc; - } - if ( ball_x < -(BOUNCE_HEIGHT/2 + WALL_L_OFFSET) ) - { - ball_x_inc = 0.5f + 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX; - deg_rot_y_inc = -deg_rot_y_inc; - } - - /* Bounce on floor / roof */ - if ( ball_y > BOUNCE_HEIGHT/2 ) - { - ball_y_inc = -0.75f - 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX; - } - if ( ball_y < -BOUNCE_HEIGHT/2*0.85 ) - { - ball_y_inc = 0.75f + 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX; - } - - /* Update ball position */ - ball_x += ball_x_inc * ((float)dt*ANIMATION_SPEED); - ball_y += ball_y_inc * ((float)dt*ANIMATION_SPEED); - - /* - * Simulate the effects of gravity on Y movement. - */ - if ( ball_y_inc < 0 ) sign = -1.0; else sign = 1.0; - - deg = (ball_y + BOUNCE_HEIGHT/2) * 90 / BOUNCE_HEIGHT; - if ( deg > 80 ) deg = 80; - if ( deg < 10 ) deg = 10; - - ball_y_inc = sign * 4.f * (float) sin_deg( deg ); -} - - -/***************************************************************************** - * Draw a faceted latitude band of the Boing ball. - * - * Parms: long_lo, long_hi - * Low and high longitudes of slice, resp. - *****************************************************************************/ -void DrawBoingBallBand( GLfloat long_lo, - GLfloat long_hi ) -{ - vertex_t vert_ne; /* "ne" means south-east, so on */ - vertex_t vert_nw; - vertex_t vert_sw; - vertex_t vert_se; - vertex_t vert_norm; - GLfloat lat_deg; - static int colorToggle = 0; - - /* - * Iterate thru the points of a latitude circle. - * A latitude circle is a 2D set of X,Z points. - */ - for ( lat_deg = 0; - lat_deg <= (360 - STEP_LATITUDE); - lat_deg += STEP_LATITUDE ) - { - /* - * Color this polygon with red or white. - */ - if ( colorToggle ) - glColor3f( 0.8f, 0.1f, 0.1f ); - else - glColor3f( 0.95f, 0.95f, 0.95f ); -#if 0 - if ( lat_deg >= 180 ) - if ( colorToggle ) - glColor3f( 0.1f, 0.8f, 0.1f ); - else - glColor3f( 0.5f, 0.5f, 0.95f ); -#endif - colorToggle = ! colorToggle; - - /* - * Change color if drawing shadow. - */ - if ( drawBallHow == DRAW_BALL_SHADOW ) - glColor3f( 0.35f, 0.35f, 0.35f ); - - /* - * Assign each Y. - */ - vert_ne.y = vert_nw.y = (float) cos_deg(long_hi) * RADIUS; - vert_sw.y = vert_se.y = (float) cos_deg(long_lo) * RADIUS; - - /* - * Assign each X,Z with sin,cos values scaled by latitude radius indexed by longitude. - * Eg, long=0 and long=180 are at the poles, so zero scale is sin(longitude), - * while long=90 (sin(90)=1) is at equator. - */ - vert_ne.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); - vert_se.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); - vert_nw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); - vert_sw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); - - vert_ne.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); - vert_se.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); - vert_nw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); - vert_sw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); - - /* - * Draw the facet. - */ - glBegin( GL_POLYGON ); - - CrossProduct( vert_ne, vert_nw, vert_sw, &vert_norm ); - glNormal3f( vert_norm.x, vert_norm.y, vert_norm.z ); - - glVertex3f( vert_ne.x, vert_ne.y, vert_ne.z ); - glVertex3f( vert_nw.x, vert_nw.y, vert_nw.z ); - glVertex3f( vert_sw.x, vert_sw.y, vert_sw.z ); - glVertex3f( vert_se.x, vert_se.y, vert_se.z ); - - glEnd(); - -#if BOING_DEBUG - printf( "----------------------------------------------------------- \n" ); - printf( "lat = %f long_lo = %f long_hi = %f \n", lat_deg, long_lo, long_hi ); - printf( "vert_ne x = %.8f y = %.8f z = %.8f \n", vert_ne.x, vert_ne.y, vert_ne.z ); - printf( "vert_nw x = %.8f y = %.8f z = %.8f \n", vert_nw.x, vert_nw.y, vert_nw.z ); - printf( "vert_se x = %.8f y = %.8f z = %.8f \n", vert_se.x, vert_se.y, vert_se.z ); - printf( "vert_sw x = %.8f y = %.8f z = %.8f \n", vert_sw.x, vert_sw.y, vert_sw.z ); -#endif - - } - - /* - * Toggle color so that next band will opposite red/white colors than this one. - */ - colorToggle = ! colorToggle; - - /* - * This circular band is done. - */ - return; -} - - -/***************************************************************************** - * Draw the purple grid of lines, behind the Boing ball. - * When the Workbench is dropped to the bottom, Boing shows 12 rows. - *****************************************************************************/ -void DrawGrid( void ) -{ - int row, col; - const int rowTotal = 12; /* must be divisible by 2 */ - const int colTotal = rowTotal; /* must be same as rowTotal */ - const GLfloat widthLine = 2.0; /* should be divisible by 2 */ - const GLfloat sizeCell = GRID_SIZE / rowTotal; - const GLfloat z_offset = -40.0; - GLfloat xl, xr; - GLfloat yt, yb; - - glPushMatrix(); - glDisable( GL_CULL_FACE ); - - /* - * Another relative Z translation to separate objects. - */ - glTranslatef( 0.0, 0.0, DIST_BALL ); - - /* - * Draw vertical lines (as skinny 3D rectangles). - */ - for ( col = 0; col <= colTotal; col++ ) - { - /* - * Compute co-ords of line. - */ - xl = -GRID_SIZE / 2 + col * sizeCell; - xr = xl + widthLine; - - yt = GRID_SIZE / 2; - yb = -GRID_SIZE / 2 - widthLine; - - glBegin( GL_POLYGON ); - - glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */ - - glVertex3f( xr, yt, z_offset ); /* NE */ - glVertex3f( xl, yt, z_offset ); /* NW */ - glVertex3f( xl, yb, z_offset ); /* SW */ - glVertex3f( xr, yb, z_offset ); /* SE */ - - glEnd(); - } - - /* - * Draw horizontal lines (as skinny 3D rectangles). - */ - for ( row = 0; row <= rowTotal; row++ ) - { - /* - * Compute co-ords of line. - */ - yt = GRID_SIZE / 2 - row * sizeCell; - yb = yt - widthLine; - - xl = -GRID_SIZE / 2; - xr = GRID_SIZE / 2 + widthLine; - - glBegin( GL_POLYGON ); - - glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */ - - glVertex3f( xr, yt, z_offset ); /* NE */ - glVertex3f( xl, yt, z_offset ); /* NW */ - glVertex3f( xl, yb, z_offset ); /* SW */ - glVertex3f( xr, yb, z_offset ); /* SE */ - - glEnd(); - } - - glPopMatrix(); - - return; -} - - -/*======================================================================* - * main() - *======================================================================*/ - -void iteration(){ - /* Timing */ - t = glfwGetTime(); - dt = t - t_old; - t_old = t; - - /* Draw one frame */ - display(); - - /* Swap buffers */ - glfwSwapBuffers(); -} - -int main( void ) -{ - int running; - - /* Init GLFW */ - if( !glfwInit() ) - { - fprintf( stderr, "Failed to initialize GLFW\n" ); - exit( EXIT_FAILURE ); - } - - if( !glfwOpenWindow( 400,400, 0,0,0,0, 16,0, GLFW_WINDOW ) ) - { - fprintf( stderr, "Failed to open GLFW window\n" ); - glfwTerminate(); - exit( EXIT_FAILURE ); - } - - glfwSetWindowTitle( "Boing (classic Amiga demo)" ); - glfwSetWindowSizeCallback( reshape ); - glfwEnable( GLFW_STICKY_KEYS ); - glfwSwapInterval( 1 ); - glfwSetTime( 0.0 ); - - init(); - - /* Main loop */ -#ifdef EMSCRIPTEN - emscripten_set_main_loop (iteration, 0, 1); -#else - do - { - iteration(); - /* Check if we are still running */ - running = !glfwGetKey( GLFW_KEY_ESC ) && - glfwGetWindowParam( GLFW_OPENED ); - } - while( running ); -#endif - glfwTerminate(); - exit( EXIT_SUCCESS ); -} - diff --git a/tests/glfw/bundle.sh b/tests/glfw/bundle.sh deleted file mode 100644 index ee4d18ddda08d..0000000000000 --- a/tests/glfw/bundle.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh - -# Creates application bundles for use on Mac OS X. - -if [ -z "$1" ]; then - echo "usage: `basename $0` BUNDLE-NAME" - exit 1 -fi - -bundle_name="$1" - -if [ ! -d "${bundle_name}.app/Contents/MacOS" ]; then - mkdir -p "${bundle_name}.app/Contents/MacOS" -fi - -if [ ! -d "${bundle_name}.app/Contents/Resources" ]; then - mkdir -p "${bundle_name}.app/Contents/Resources" -fi - -if [ ! -f "${bundle_name}.app/Contents/PkgInfo" ]; then - echo -n "APPL????" > "${bundle_name}.app/Contents/PkgInfo" -fi - -if [ ! -f "${bundle_name}.app/Contents/Info.plist" ]; then - cat > "${bundle_name}.app/Contents/Info.plist" < - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${bundle_name} - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleSignature - ???? - CFBundleVersion - 0.1 - - -EOF -fi - diff --git a/tests/glfw/gears.c b/tests/glfw/gears.c deleted file mode 100644 index 012884145c123..0000000000000 --- a/tests/glfw/gears.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - * 3-D gear wheels. This program is in the public domain. - * - * Command line options: - * -info print GL implementation information - * -exit automatically exit after 30 seconds - * - * - * Brian Paul - * - * - * Marcus Geelnard: - * - Conversion to GLFW - * - Time based rendering (frame rate independent) - * - Slightly modified camera that should work better for stereo viewing - * - * - * Camilla Berglund: - * - Removed FPS counter (this is not a benchmark) - * - Added a few comments - * - Enabled vsync - */ - - -#include -#include -#include -#include -#include - -#ifndef M_PI -#define M_PI 3.141592654 -#endif - -#ifdef EMSCRIPTEN -#include -#endif - -/* The program exits when this is zero. - */ -static int running = 1; - -/* If non-zero, the program exits after that many seconds - */ -static int autoexit = 0; - -/** - - Draw a gear wheel. You'll probably want to call this function when - building a display list since we do a lot of trig here. - - Input: inner_radius - radius of hole at center - outer_radius - radius at center of teeth - width - width of gear teeth - number of teeth - tooth_depth - depth of tooth - - **/ - -static void -gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, - GLint teeth, GLfloat tooth_depth) -{ - GLint i; - GLfloat r0, r1, r2; - GLfloat angle, da; - GLfloat u, v, len; - - r0 = inner_radius; - r1 = outer_radius - tooth_depth / 2.f; - r2 = outer_radius + tooth_depth / 2.f; - - da = 2.f * (float) M_PI / teeth / 4.f; - - glShadeModel(GL_FLAT); - - glNormal3f(0.f, 0.f, 1.f); - - /* draw front face */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.f * (float) M_PI / teeth; - glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); - glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); - if (i < teeth) { - glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); - glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); - } - } - glEnd(); - - /* draw front sides of teeth */ - glBegin(GL_QUADS); - da = 2.f * (float) M_PI / teeth / 4.f; - for (i = 0; i < teeth; i++) { - angle = i * 2.f * (float) M_PI / teeth; - - glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); - glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), width * 0.5f); - glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), width * 0.5f); - glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); - } - glEnd(); - - glNormal3f(0.0, 0.0, -1.0); - - /* draw back face */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.f * (float) M_PI / teeth; - glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); - glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); - if (i < teeth) { - glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); - glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); - } - } - glEnd(); - - /* draw back sides of teeth */ - glBegin(GL_QUADS); - da = 2.f * (float) M_PI / teeth / 4.f; - for (i = 0; i < teeth; i++) { - angle = i * 2.f * (float) M_PI / teeth; - - glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); - glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), -width * 0.5f); - glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), -width * 0.5f); - glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); - } - glEnd(); - - /* draw outward faces of teeth */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i < teeth; i++) { - angle = i * 2.f * (float) M_PI / teeth; - - glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); - glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); - u = r2 * (float) cos(angle + da) - r1 * (float) cos(angle); - v = r2 * (float) sin(angle + da) - r1 * (float) sin(angle); - len = (float) sqrt(u * u + v * v); - u /= len; - v /= len; - glNormal3f(v, -u, 0.0); - glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), width * 0.5f); - glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), -width * 0.5f); - glNormal3f((float) cos(angle), (float) sin(angle), 0.f); - glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), width * 0.5f); - glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), -width * 0.5f); - u = r1 * (float) cos(angle + 3 * da) - r2 * (float) cos(angle + 2 * da); - v = r1 * (float) sin(angle + 3 * da) - r2 * (float) sin(angle + 2 * da); - glNormal3f(v, -u, 0.f); - glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); - glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); - glNormal3f((float) cos(angle), (float) sin(angle), 0.f); - } - - glVertex3f(r1 * (float) cos(0), r1 * (float) sin(0), width * 0.5f); - glVertex3f(r1 * (float) cos(0), r1 * (float) sin(0), -width * 0.5f); - - glEnd(); - - glShadeModel(GL_SMOOTH); - - /* draw inside radius cylinder */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.f * (float) M_PI / teeth; - glNormal3f(-(float) cos(angle), -(float) sin(angle), 0.f); - glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); - glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); - } - glEnd(); - -} - - -static GLfloat view_rotx = 20.f, view_roty = 30.f, view_rotz = 0.f; -static GLint gear1, gear2, gear3; -static GLfloat angle = 0.f; - -/* OpenGL draw function & timing */ -static void draw(void) -{ - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glPushMatrix(); - glRotatef(view_rotx, 1.0, 0.0, 0.0); - glRotatef(view_roty, 0.0, 1.0, 0.0); - glRotatef(view_rotz, 0.0, 0.0, 1.0); - - glPushMatrix(); - glTranslatef(-3.0, -2.0, 0.0); - glRotatef(angle, 0.0, 0.0, 1.0); - glCallList(gear1); - glPopMatrix(); - - glPushMatrix(); - glTranslatef(3.1f, -2.f, 0.f); - glRotatef(-2.f * angle - 9.f, 0.f, 0.f, 1.f); - glCallList(gear2); - glPopMatrix(); - - glPushMatrix(); - glTranslatef(-3.1f, 4.2f, 0.f); - glRotatef(-2.f * angle - 25.f, 0.f, 0.f, 1.f); - glCallList(gear3); - glPopMatrix(); - - glPopMatrix(); -} - - -/* update animation parameters */ -static void animate(void) -{ - angle = 100.f * (float) glfwGetTime(); -} - - -/* change view angle, exit upon ESC */ -void GLFWCALL key( int k, int action ) -{ - if( action != GLFW_PRESS ) return; - - switch (k) { - case 'Z': - if( glfwGetKey( GLFW_KEY_LSHIFT ) ) - view_rotz -= 5.0; - else - view_rotz += 5.0; - break; - case GLFW_KEY_ESC: - running = 0; - break; - case GLFW_KEY_UP: - view_rotx += 5.0; - break; - case GLFW_KEY_DOWN: - view_rotx -= 5.0; - break; - case GLFW_KEY_LEFT: - view_roty += 5.0; - break; - case GLFW_KEY_RIGHT: - view_roty -= 5.0; - break; - default: - return; - } -} - - -/* new window size */ -void GLFWCALL reshape( int width, int height ) -{ - GLfloat h = (GLfloat) height / (GLfloat) width; - GLfloat xmax, znear, zfar; - - znear = 5.0f; - zfar = 30.0f; - xmax = znear * 0.5f; - - glViewport( 0, 0, (GLint) width, (GLint) height ); - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - glFrustum( -xmax, xmax, -xmax*h, xmax*h, znear, zfar ); - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - glTranslatef( 0.0, 0.0, -20.0 ); -} - - -/* program & OpenGL initialization */ -static void init(int argc, char *argv[]) -{ - static GLfloat pos[4] = {5.f, 5.f, 10.f, 0.f}; - static GLfloat red[4] = {0.8f, 0.1f, 0.f, 1.f}; - static GLfloat green[4] = {0.f, 0.8f, 0.2f, 1.f}; - static GLfloat blue[4] = {0.2f, 0.2f, 1.f, 1.f}; - GLint i; - - glLightfv(GL_LIGHT0, GL_POSITION, pos); - glEnable(GL_CULL_FACE); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_DEPTH_TEST); - - /* make the gears */ - gear1 = glGenLists(1); - glNewList(gear1, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); - gear(1.f, 4.f, 1.f, 20, 0.7f); - glEndList(); - - gear2 = glGenLists(1); - glNewList(gear2, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); - gear(0.5f, 2.f, 2.f, 10, 0.7f); - glEndList(); - - gear3 = glGenLists(1); - glNewList(gear3, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); - gear(1.3f, 2.f, 0.5f, 10, 0.7f); - glEndList(); - - glEnable(GL_NORMALIZE); - - for ( i=1; i -#include -#include -#include "getopt.h" - - -/* 2009-10-12 Camilla Berglund - * - * Removed unused global static variable 'ID'. - */ - - -char* optarg = NULL; -int optind = 0; -int opterr = 1; -int optopt = '?'; - - -static char** prev_argv = NULL; /* Keep a copy of argv and argc to */ -static int prev_argc = 0; /* tell if getopt params change */ -static int argv_index = 0; /* Option we're checking */ -static int argv_index2 = 0; /* Option argument we're checking */ -static int opt_offset = 0; /* Index into compounded "-option" */ -static int dashdash = 0; /* True if "--" option reached */ -static int nonopt = 0; /* How many nonopts we've found */ - -static void increment_index() -{ - /* Move onto the next option */ - if(argv_index < argv_index2) - { - while(prev_argv[++argv_index] && prev_argv[argv_index][0] != '-' - && argv_index < argv_index2+1); - } - else argv_index++; - opt_offset = 1; -} - - -/* -* Permutes argv[] so that the argument currently being processed is moved -* to the end. -*/ -static int permute_argv_once() -{ - /* Movability check */ - if(argv_index + nonopt >= prev_argc) return 1; - /* Move the current option to the end, bring the others to front */ - else - { - char* tmp = prev_argv[argv_index]; - - /* Move the data */ - memmove(&prev_argv[argv_index], &prev_argv[argv_index+1], - sizeof(char**) * (prev_argc - argv_index - 1)); - prev_argv[prev_argc - 1] = tmp; - - nonopt++; - return 0; - } -} - - -int getopt(int argc, char** argv, char* optstr) -{ - int c = 0; - - /* If we have new argv, reinitialize */ - if(prev_argv != argv || prev_argc != argc) - { - /* Initialize variables */ - prev_argv = argv; - prev_argc = argc; - argv_index = 1; - argv_index2 = 1; - opt_offset = 1; - dashdash = 0; - nonopt = 0; - } - - /* Jump point in case we want to ignore the current argv_index */ - getopt_top: - - /* Misc. initializations */ - optarg = NULL; - - /* Dash-dash check */ - if(argv[argv_index] && !strcmp(argv[argv_index], "--")) - { - dashdash = 1; - increment_index(); - } - - /* If we're at the end of argv, that's it. */ - if(argv[argv_index] == NULL) - { - c = -1; - } - /* Are we looking at a string? Single dash is also a string */ - else if(dashdash || argv[argv_index][0] != '-' || !strcmp(argv[argv_index], "-")) - { - /* If we want a string... */ - if(optstr[0] == '-') - { - c = 1; - optarg = argv[argv_index]; - increment_index(); - } - /* If we really don't want it (we're in POSIX mode), we're done */ - else if(optstr[0] == '+' || getenv("POSIXLY_CORRECT")) - { - c = -1; - - /* Everything else is a non-opt argument */ - nonopt = argc - argv_index; - } - /* If we mildly don't want it, then move it back */ - else - { - if(!permute_argv_once()) goto getopt_top; - else c = -1; - } - } - /* Otherwise we're looking at an option */ - else - { - char* opt_ptr = NULL; - - /* Grab the option */ - c = argv[argv_index][opt_offset++]; - - /* Is the option in the optstr? */ - if(optstr[0] == '-') opt_ptr = strchr(optstr+1, c); - else opt_ptr = strchr(optstr, c); - /* Invalid argument */ - if(!opt_ptr) - { - if(opterr) - { - fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); - } - - optopt = c; - c = '?'; - - /* Move onto the next option */ - increment_index(); - } - /* Option takes argument */ - else if(opt_ptr[1] == ':') - { - /* ie, -oARGUMENT, -xxxoARGUMENT, etc. */ - if(argv[argv_index][opt_offset] != '\0') - { - optarg = &argv[argv_index][opt_offset]; - increment_index(); - } - /* ie, -o ARGUMENT (only if it's a required argument) */ - else if(opt_ptr[2] != ':') - { - /* One of those "you're not expected to understand this" moment */ - if(argv_index2 < argv_index) argv_index2 = argv_index; - while(argv[++argv_index2] && argv[argv_index2][0] == '-'); - optarg = argv[argv_index2]; - - /* Don't cross into the non-option argument list */ - if(argv_index2 + nonopt >= prev_argc) optarg = NULL; - - /* Move onto the next option */ - increment_index(); - } - else - { - /* Move onto the next option */ - increment_index(); - } - - /* In case we got no argument for an option with required argument */ - if(optarg == NULL && opt_ptr[2] != ':') - { - optopt = c; - c = '?'; - - if(opterr) - { - fprintf(stderr,"%s: option requires an argument -- %c\n", - argv[0], optopt); - } - } - } - /* Option does not take argument */ - else - { - /* Next argv_index */ - if(argv[argv_index][opt_offset] == '\0') - { - increment_index(); - } - } - } - - /* Calculate optind */ - if(c == -1) - { - optind = argc - nonopt; - } - else - { - optind = argv_index; - } - - return c; -} - - -/* vim:ts=3 -*/ diff --git a/tests/glfw/getopt.h b/tests/glfw/getopt.h deleted file mode 100644 index 0b78650ac7ac6..0000000000000 --- a/tests/glfw/getopt.h +++ /dev/null @@ -1,63 +0,0 @@ -/***************************************************************************** -* getopt.h - competent and free getopt library. -* $Header: /cvsroot/freegetopt/freegetopt/getopt.h,v 1.2 2003/10/26 03:10:20 vindaci Exp $ -* -* Copyright (c)2002-2003 Mark K. Kim -* 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 original author of this software 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 OWNER 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. -*/ -#ifndef GETOPT_H_ -#define GETOPT_H_ - - -#ifdef __cplusplus -extern "C" { -#endif - - -extern char* optarg; -extern int optind; -extern int opterr; -extern int optopt; - -int getopt(int argc, char** argv, char* optstr); - - -#ifdef __cplusplus -} -#endif - - -#endif /* GETOPT_H_ */ - - -/* vim:ts=3 -*/ diff --git a/tests/glfw/heightmap.c b/tests/glfw/heightmap.c deleted file mode 100644 index 4967ea114b003..0000000000000 --- a/tests/glfw/heightmap.c +++ /dev/null @@ -1,866 +0,0 @@ -//======================================================================== -// Heightmap example program using OpenGL 3 core profile -// Copyright (c) 2010 Olivier Delannoy -// -// 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. -// -//======================================================================== - -#include -#include -#include -#include -#include -#include "getopt.h" - -#ifdef EMSCRIPTEN -#include -#endif - -#define GLFW_NO_GLU 1 -#include - -/* OpenGL 3.3 support - * Functions are effectively mapped in init_opengl() */ -#ifndef GL_VERSION_3_0 -/* no defines */ -#endif - -#ifndef GL_VERSION_2_0 - -typedef char GLchar; - -#define GL_BLEND_EQUATION_RGB 0x8009 -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 -#define GL_CURRENT_VERTEX_ATTRIB 0x8626 -#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 -#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 -#define GL_STENCIL_BACK_FUNC 0x8800 -#define GL_STENCIL_BACK_FAIL 0x8801 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 -#define GL_MAX_DRAW_BUFFERS 0x8824 -#define GL_DRAW_BUFFER0 0x8825 -#define GL_DRAW_BUFFER1 0x8826 -#define GL_DRAW_BUFFER2 0x8827 -#define GL_DRAW_BUFFER3 0x8828 -#define GL_DRAW_BUFFER4 0x8829 -#define GL_DRAW_BUFFER5 0x882A -#define GL_DRAW_BUFFER6 0x882B -#define GL_DRAW_BUFFER7 0x882C -#define GL_DRAW_BUFFER8 0x882D -#define GL_DRAW_BUFFER9 0x882E -#define GL_DRAW_BUFFER10 0x882F -#define GL_DRAW_BUFFER11 0x8830 -#define GL_DRAW_BUFFER12 0x8831 -#define GL_DRAW_BUFFER13 0x8832 -#define GL_DRAW_BUFFER14 0x8833 -#define GL_DRAW_BUFFER15 0x8834 -#define GL_BLEND_EQUATION_ALPHA 0x883D -#define GL_MAX_VERTEX_ATTRIBS 0x8869 -#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A -#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_VERTEX_SHADER 0x8B31 -#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A -#define GL_MAX_VARYING_FLOATS 0x8B4B -#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D -#define GL_SHADER_TYPE 0x8B4F -#define GL_FLOAT_VEC2 0x8B50 -#define GL_FLOAT_VEC3 0x8B51 -#define GL_FLOAT_VEC4 0x8B52 -#define GL_INT_VEC2 0x8B53 -#define GL_INT_VEC3 0x8B54 -#define GL_INT_VEC4 0x8B55 -#define GL_BOOL 0x8B56 -#define GL_BOOL_VEC2 0x8B57 -#define GL_BOOL_VEC3 0x8B58 -#define GL_BOOL_VEC4 0x8B59 -#define GL_FLOAT_MAT2 0x8B5A -#define GL_FLOAT_MAT3 0x8B5B -#define GL_FLOAT_MAT4 0x8B5C -#define GL_SAMPLER_1D 0x8B5D -#define GL_SAMPLER_2D 0x8B5E -#define GL_SAMPLER_3D 0x8B5F -#define GL_SAMPLER_CUBE 0x8B60 -#define GL_SAMPLER_1D_SHADOW 0x8B61 -#define GL_SAMPLER_2D_SHADOW 0x8B62 -#define GL_DELETE_STATUS 0x8B80 -#define GL_COMPILE_STATUS 0x8B81 -#define GL_LINK_STATUS 0x8B82 -#define GL_VALIDATE_STATUS 0x8B83 -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_ATTACHED_SHADERS 0x8B85 -#define GL_ACTIVE_UNIFORMS 0x8B86 -#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 -#define GL_SHADER_SOURCE_LENGTH 0x8B88 -#define GL_ACTIVE_ATTRIBUTES 0x8B89 -#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B -#define GL_SHADING_LANGUAGE_VERSION 0x8B8C -#define GL_CURRENT_PROGRAM 0x8B8D -#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 -#define GL_LOWER_LEFT 0x8CA1 -#define GL_UPPER_LEFT 0x8CA2 -#define GL_STENCIL_BACK_REF 0x8CA3 -#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 -#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 -#endif - - - -#ifndef GL_VERSION_1_5 - -typedef ptrdiff_t GLintptr; -typedef ptrdiff_t GLsizeiptr; - -#define GL_BUFFER_SIZE 0x8764 -#define GL_BUFFER_USAGE 0x8765 -#define GL_QUERY_COUNTER_BITS 0x8864 -#define GL_CURRENT_QUERY 0x8865 -#define GL_QUERY_RESULT 0x8866 -#define GL_QUERY_RESULT_AVAILABLE 0x8867 -#define GL_ARRAY_BUFFER 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define GL_ARRAY_BUFFER_BINDING 0x8894 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 -#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F -#define GL_READ_ONLY 0x88B8 -#define GL_WRITE_ONLY 0x88B9 -#define GL_READ_WRITE 0x88BA -#define GL_BUFFER_ACCESS 0x88BB -#define GL_BUFFER_MAPPED 0x88BC -#define GL_BUFFER_MAP_POINTER 0x88BD -#define GL_STREAM_DRAW 0x88E0 -#define GL_STREAM_READ 0x88E1 -#define GL_STREAM_COPY 0x88E2 -#define GL_STATIC_DRAW 0x88E4 -#define GL_STATIC_READ 0x88E5 -#define GL_STATIC_COPY 0x88E6 -#define GL_DYNAMIC_DRAW 0x88E8 -#define GL_DYNAMIC_READ 0x88E9 -#define GL_DYNAMIC_COPY 0x88EA -#define GL_SAMPLES_PASSED 0x8914 -#endif - - - - -/* OpenGL 3.0 */ -typedef void (APIENTRY * PFN_glGenVertexArrays)(GLsizei n, GLuint *arrays); -typedef void (APIENTRY * PFN_glBindVertexArray)(GLuint array); -typedef void (APIENTRY * PFN_glDeleteVertexArrays)(GLsizei n, GLuint *arrays); -/* OpenGL 2.0 */ -typedef GLuint (APIENTRY * PFN_glCreateShader)(GLenum type); -typedef void (APIENTRY * PFN_glDeleteShader)(GLuint shader); -typedef void (APIENTRY * PFN_glCompileShader)(GLuint shader); -typedef void (APIENTRY * PFN_glShaderSource)(GLuint shader, GLsizei count, const GLchar* *string, const GLint *length); -typedef void (APIENTRY * PFN_glGetShaderiv)(GLuint shader, GLenum pname, GLint *params); -typedef void (APIENTRY * PFN_glGetShaderInfoLog)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef GLuint (APIENTRY * PFN_glCreateProgram)(void); -typedef void (APIENTRY * PFN_glDeleteProgram)(GLuint program); -typedef void (APIENTRY * PFN_glAttachShader)(GLuint program, GLuint shader); -typedef void (APIENTRY * PFN_glLinkProgram)(GLuint program); -typedef void (APIENTRY * PFN_glGetProgramiv)(GLuint program, GLenum pname, GLint *params); -typedef void (APIENTRY * PFN_glGetProgramInfoLog)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef void (APIENTRY * PFN_glValidateProgram)(GLuint program); -typedef void (APIENTRY * PFN_glUseProgram)(GLuint program); -typedef GLint (APIENTRY * PFN_glGetUniformLocation)(GLuint program, const GLchar *name); -typedef void (APIENTRY * PFN_glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef GLint (APIENTRY * PFN_glGetAttribLocation)(GLuint program, const GLchar *name); -typedef void (APIENTRY * PFN_glEnableVertexAttribArray)(GLuint index); -typedef void (APIENTRY * PFN_glVertexAttrib1f)(GLuint index, GLfloat x); -typedef void (APIENTRY * PFN_glVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); -/* OpenGL 1.5 */ -typedef void (APIENTRY * PFN_glBindBuffer)(GLenum target, GLuint buffer); -typedef void (APIENTRY * PFN_glDeleteBuffers)(GLsizei n, const GLuint *buffers); -typedef void (APIENTRY * PFN_glGenBuffers)(GLsizei n, GLuint *buffers); -typedef void (APIENTRY * PFN_glBufferData)(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); -typedef void (APIENTRY * PFN_glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); - -/* OpenGL function pointers */ -static PFN_glGenBuffers pglGenBuffers = NULL; -static PFN_glGenVertexArrays pglGenVertexArrays = NULL; -static PFN_glDeleteVertexArrays pglDeleteVertexArrays = NULL; -static PFN_glCreateShader pglCreateShader = NULL; -static PFN_glShaderSource pglShaderSource = NULL; -static PFN_glCompileShader pglCompileShader = NULL; -static PFN_glGetShaderiv pglGetShaderiv = NULL; -static PFN_glGetShaderInfoLog pglGetShaderInfoLog = NULL; -static PFN_glDeleteShader pglDeleteShader = NULL; -static PFN_glCreateProgram pglCreateProgram = NULL; -static PFN_glAttachShader pglAttachShader = NULL; -static PFN_glLinkProgram pglLinkProgram = NULL; -static PFN_glUseProgram pglUseProgram = NULL; -static PFN_glGetProgramiv pglGetProgramiv = NULL; -static PFN_glGetProgramInfoLog pglGetProgramInfoLog = NULL; -static PFN_glDeleteProgram pglDeleteProgram = NULL; -static PFN_glGetUniformLocation pglGetUniformLocation = NULL; -static PFN_glUniformMatrix4fv pglUniformMatrix4fv = NULL; -static PFN_glGetAttribLocation pglGetAttribLocation = NULL; - -/* Map height updates */ -#define MAX_CIRCLE_SIZE (5.0f) -#define MAX_DISPLACEMENT (1.0f) -#define DISPLACEMENT_SIGN_LIMIT (0.3f) -#define MAX_ITER (200) -#define NUM_ITER_AT_A_TIME (1) - -/* Map general information */ -#define MAP_SIZE (10.0f) -#define MAP_NUM_VERTICES (80) -#define MAP_NUM_TOTAL_VERTICES (MAP_NUM_VERTICES*MAP_NUM_VERTICES) -#define MAP_NUM_LINES (3* (MAP_NUM_VERTICES - 1) * (MAP_NUM_VERTICES - 1) + \ - 2 * (MAP_NUM_VERTICES - 1)) - - -/* OpenGL function pointers */ - -static PFN_glBindVertexArray pglBindVertexArray = NULL; -static PFN_glBufferData pglBufferData = NULL; -static PFN_glBindBuffer pglBindBuffer = NULL; -static PFN_glBufferSubData pglBufferSubData = NULL; -static PFN_glEnableVertexAttribArray pglEnableVertexAttribArray = NULL; -static PFN_glVertexAttribPointer pglVertexAttribPointer = NULL; - -#define RESOLVE_GL_FCN(type, var, name) \ - if (status == GL_TRUE) \ - {\ - var = glfwGetProcAddress((name));\ - if ((var) == NULL)\ - {\ - status = GL_FALSE;\ - }\ - } - - -static GLboolean init_opengl(void) -{ - GLboolean status = GL_TRUE; - RESOLVE_GL_FCN(PFN_glCreateShader, pglCreateShader, "glCreateShader"); - RESOLVE_GL_FCN(PFN_glShaderSource, pglShaderSource, "glShaderSource"); - RESOLVE_GL_FCN(PFN_glCompileShader, pglCompileShader, "glCompileShader"); - RESOLVE_GL_FCN(PFN_glGetShaderiv, pglGetShaderiv, "glGetShaderiv"); - RESOLVE_GL_FCN(PFN_glGetShaderInfoLog, pglGetShaderInfoLog, "glGetShaderInfoLog"); - RESOLVE_GL_FCN(PFN_glDeleteShader, pglDeleteShader, "glDeleteShader"); - RESOLVE_GL_FCN(PFN_glCreateProgram, pglCreateProgram, "glCreateProgram"); - RESOLVE_GL_FCN(PFN_glAttachShader, pglAttachShader, "glAttachShader"); - RESOLVE_GL_FCN(PFN_glLinkProgram, pglLinkProgram, "glLinkProgram"); - RESOLVE_GL_FCN(PFN_glUseProgram, pglUseProgram, "glUseProgram"); - RESOLVE_GL_FCN(PFN_glGetProgramiv, pglGetProgramiv, "glGetProgramiv"); - RESOLVE_GL_FCN(PFN_glGetProgramInfoLog, pglGetProgramInfoLog, "glGetProgramInfoLog"); - RESOLVE_GL_FCN(PFN_glDeleteProgram, pglDeleteProgram, "glDeleteProgram"); - RESOLVE_GL_FCN(PFN_glGetUniformLocation, pglGetUniformLocation, "glGetUniformLocation"); - RESOLVE_GL_FCN(PFN_glUniformMatrix4fv, pglUniformMatrix4fv, "glUniformMatrix4fv"); - RESOLVE_GL_FCN(PFN_glGetAttribLocation, pglGetAttribLocation, "glGetAttribLocation"); - RESOLVE_GL_FCN(PFN_glGenVertexArrays, pglGenVertexArrays, "glGenVertexArrays"); - RESOLVE_GL_FCN(PFN_glDeleteVertexArrays, pglDeleteVertexArrays, "glDeleteVertexArrays"); - RESOLVE_GL_FCN(PFN_glBindVertexArray, pglBindVertexArray, "glBindVertexArray"); - RESOLVE_GL_FCN(PFN_glGenBuffers, pglGenBuffers, "glGenBuffers"); - RESOLVE_GL_FCN(PFN_glBindBuffer, pglBindBuffer, "glBindBuffer"); - RESOLVE_GL_FCN(PFN_glBufferData, pglBufferData, "glBufferData"); - RESOLVE_GL_FCN(PFN_glBufferSubData, pglBufferSubData, "glBufferSubData"); - RESOLVE_GL_FCN(PFN_glEnableVertexAttribArray, pglEnableVertexAttribArray, "glEnableVertexAttribArray"); - RESOLVE_GL_FCN(PFN_glVertexAttribPointer, pglVertexAttribPointer, "glVertexAttribPointer"); - return status; -} -/********************************************************************** - * Default shader programs - *********************************************************************/ - -static const char* default_vertex_shader = -"#version 150\n" -"uniform mat4 project;\n" -"uniform mat4 modelview;\n" -"in float x;\n" -"in float y;\n" -"in float z;\n" -"\n" -"void main()\n" -"{\n" -" gl_Position = project * modelview * vec4(x, y, z, 1.0);\n" -"}\n"; - -static const char* default_fragment_shader = -"#version 150\n" -"out vec4 gl_FragColor;\n" -"void main()\n" -"{\n" -" gl_FragColor = vec4(0.2, 1.0, 0.2, 1.0); \n" -"}\n"; - -/********************************************************************** - * Values for shader uniforms - *********************************************************************/ - -/* Frustum configuration */ -static GLfloat view_angle = 45.0f; -static GLfloat aspect_ratio = 4.0f/3.0f; -static GLfloat z_near = 1.0f; -static GLfloat z_far = 100.f; - -/* Projection matrix */ -static GLfloat projection_matrix[16] = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f -}; - -/* Model view matrix */ -static GLfloat modelview_matrix[16] = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f -}; - -/********************************************************************** - * Heightmap vertex and index data - *********************************************************************/ - -static GLfloat map_vertices[3][MAP_NUM_TOTAL_VERTICES]; -static GLuint map_line_indices[2*MAP_NUM_LINES]; - -/* Store uniform location for the shaders - * Those values are setup as part of the process of creating - * the shader program. They should not be used before creating - * the program. - */ -static GLuint mesh; -static GLuint mesh_vbo[4]; - -/********************************************************************** - * OpenGL helper functions - *********************************************************************/ - -/* Load a (text) file into memory and return its contents - */ -static char* read_file_content(const char* filename) -{ - FILE* fd; - size_t size = 0; - char* result = NULL; - - fd = fopen(filename, "r"); - if (fd != NULL) - { - size = fseek(fd, 0, SEEK_END); - (void) fseek(fd, 0, SEEK_SET); - - result = malloc(size + 1); - result[size] = '\0'; - if (fread(result, size, 1, fd) != 1) - { - free(result); - result = NULL; - } - (void) fclose(fd); - } - return result; -} - -/* Creates a shader object of the specified type using the specified text - */ -static GLuint make_shader(GLenum type, const char* shader_src) -{ - GLuint shader; - GLint shader_ok; - GLsizei log_length; - char info_log[8192]; - - shader = pglCreateShader(type); - if (shader != 0) - { - pglShaderSource(shader, 1, (const GLchar**)&shader_src, NULL); - pglCompileShader(shader); - pglGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok); - if (shader_ok != GL_TRUE) - { - fprintf(stderr, "ERROR: Failed to compile %s shader\n", (type == GL_FRAGMENT_SHADER) ? "fragment" : "vertex" ); - pglGetShaderInfoLog(shader, 8192, &log_length,info_log); - fprintf(stderr, "ERROR: \n%s\n\n", info_log); - pglDeleteShader(shader); - shader = 0; - } - } - return shader; -} - -/* Creates a program object using the specified vertex and fragment text - */ -static GLuint make_shader_program(const char* vertex_shader_src, const char* fragment_shader_src) -{ - GLuint program = 0u; - GLint program_ok; - GLuint vertex_shader = 0u; - GLuint fragment_shader = 0u; - GLsizei log_length; - char info_log[8192]; - - vertex_shader = make_shader(GL_VERTEX_SHADER, (vertex_shader_src == NULL) ? default_vertex_shader : vertex_shader_src); - if (vertex_shader != 0u) - { - fragment_shader = make_shader(GL_FRAGMENT_SHADER, (fragment_shader_src == NULL) ? default_fragment_shader : fragment_shader_src); - if (fragment_shader != 0u) - { - /* make the program that connect the two shader and link it */ - program = pglCreateProgram(); - if (program != 0u) - { - /* attach both shader and link */ - pglAttachShader(program, vertex_shader); - pglAttachShader(program, fragment_shader); - pglLinkProgram(program); - pglGetProgramiv(program, GL_LINK_STATUS, &program_ok); - - if (program_ok != GL_TRUE) - { - fprintf(stderr, "ERROR, failed to link shader program\n"); - pglGetProgramInfoLog(program, 8192, &log_length, info_log); - fprintf(stderr, "ERROR: \n%s\n\n", info_log); - pglDeleteProgram(program); - pglDeleteShader(fragment_shader); - pglDeleteShader(vertex_shader); - program = 0u; - } - } - } - else - { - fprintf(stderr, "ERROR: Unable to load fragment shader\n"); - pglDeleteShader(vertex_shader); - } - } - else - { - fprintf(stderr, "ERROR: Unable to load vertex shader\n"); - } - return program; -} - -/********************************************************************** - * Geometry creation functions - *********************************************************************/ - -/* Generate vertices and indices for the heightmap - */ -static void init_map(void) -{ - int i; - int j; - int k; - GLfloat step = MAP_SIZE / (MAP_NUM_VERTICES - 1); - GLfloat x = 0.0f; - GLfloat z = 0.0f; - /* Create a flat grid */ - k = 0; - for (i = 0 ; i < MAP_NUM_VERTICES ; ++i) - { - for (j = 0 ; j < MAP_NUM_VERTICES ; ++j) - { - map_vertices[0][k] = x; - map_vertices[1][k] = 0.0f; - map_vertices[2][k] = z; - z += step; - ++k; - } - x += step; - z = 0.0f; - } -#if DEBUG_ENABLED - for (i = 0 ; i < MAP_NUM_TOTAL_VERTICES ; ++i) - { - printf ("Vertice %d (%f, %f, %f)\n", - i, map_vertices[0][i], map_vertices[1][i], map_vertices[2][i]); - - } -#endif - /* create indices */ - /* line fan based on i - * i+1 - * | / i + n + 1 - * | / - * |/ - * i --- i + n - */ - - /* close the top of the square */ - k = 0; - for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i) - { - map_line_indices[k++] = (i + 1) * MAP_NUM_VERTICES -1; - map_line_indices[k++] = (i + 2) * MAP_NUM_VERTICES -1; - } - /* close the right of the square */ - for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i) - { - map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i; - map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i + 1; - } - - for (i = 0 ; i < (MAP_NUM_VERTICES - 1) ; ++i) - { - for (j = 0 ; j < (MAP_NUM_VERTICES - 1) ; ++j) - { - int ref = i * (MAP_NUM_VERTICES) + j; - map_line_indices[k++] = ref; - map_line_indices[k++] = ref + 1; - - map_line_indices[k++] = ref; - map_line_indices[k++] = ref + MAP_NUM_VERTICES; - - map_line_indices[k++] = ref; - map_line_indices[k++] = ref + MAP_NUM_VERTICES + 1; - } - } - -#ifdef DEBUG_ENABLED - for (k = 0 ; k < 2 * MAP_NUM_LINES ; k += 2) - { - int beg, end; - beg = map_line_indices[k]; - end = map_line_indices[k+1]; - printf ("Line %d: %d -> %d (%f, %f, %f) -> (%f, %f, %f)\n", - k / 2, beg, end, - map_vertices[0][beg], map_vertices[1][beg], map_vertices[2][beg], - map_vertices[0][end], map_vertices[1][end], map_vertices[2][end]); - } -#endif -} - -static void generate_heightmap__circle(float* center_x, float* center_y, - float* size, float* displacement) -{ - float sign; - /* random value for element in between [0-1.0] */ - *center_x = (MAP_SIZE * rand()) / (1.0f * RAND_MAX); - *center_y = (MAP_SIZE * rand()) / (1.0f * RAND_MAX); - *size = (MAX_CIRCLE_SIZE * rand()) / (1.0f * RAND_MAX); - sign = (1.0f * rand()) / (1.0f * RAND_MAX); - sign = (sign < DISPLACEMENT_SIGN_LIMIT) ? -1.0f : 1.0f; - *displacement = (sign * (MAX_DISPLACEMENT * rand())) / (1.0f * RAND_MAX); -} - -/* Run the specified number of iterations of the generation process for the - * heightmap - */ -static void update_map(int num_iter) -{ - assert(num_iter > 0); - while(num_iter) - { - /* center of the circle */ - float center_x; - float center_z; - float circle_size; - float disp; - size_t ii; - generate_heightmap__circle(¢er_x, ¢er_z, &circle_size, &disp); - disp = disp / 2.0f; - for (ii = 0u ; ii < MAP_NUM_TOTAL_VERTICES ; ++ii) - { - GLfloat dx = center_x - map_vertices[0][ii]; - GLfloat dz = center_z - map_vertices[2][ii]; - GLfloat pd = (2.0f * sqrtf((dx * dx) + (dz * dz))) / circle_size; - if (fabs(pd) <= 1.0f) - { - /* tx,tz is within the circle */ - GLfloat new_height = disp + ((GLfloat) cos(pd*3.14f) * disp); - map_vertices[1][ii] += new_height; - } - } - --num_iter; - } -} - -/********************************************************************** - * OpenGL helper functions - *********************************************************************/ - -/* Create VBO, IBO and VAO objects for the heightmap geometry and bind them to - * the specified program object - */ -static void make_mesh(GLuint program) -{ - GLuint attrloc; - - pglGenVertexArrays(1, &mesh); - pglGenBuffers(4, mesh_vbo); - pglBindVertexArray(mesh); - /* Prepare the data for drawing through a buffer inidices */ - pglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh_vbo[3]); - pglBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)* MAP_NUM_LINES * 2, map_line_indices, GL_STATIC_DRAW); - - /* Prepare the attributes for rendering */ - attrloc = pglGetAttribLocation(program, "x"); - pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[0]); - pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[0][0], GL_STATIC_DRAW); - pglEnableVertexAttribArray(attrloc); - pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); - - attrloc = pglGetAttribLocation(program, "z"); - pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[2]); - pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[2][0], GL_STATIC_DRAW); - pglEnableVertexAttribArray(attrloc); - pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); - - attrloc = pglGetAttribLocation(program, "y"); - pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[1]); - pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0], GL_DYNAMIC_DRAW); - pglEnableVertexAttribArray(attrloc); - pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); -} - -/* Update VBO vertices from source data - */ -static void update_mesh(void) -{ - pglBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0]); -} - -/********************************************************************** - * GLFW callback functions - *********************************************************************/ - -/* The program runs as long as this is GL_TRUE - */ -static GLboolean running = GL_TRUE; - -/* GLFW Window management functions */ -static int GLFWCALL close_window_callback(void) -{ - running = GL_FALSE; - - /* Disallow window closing - * The window will be closed when the main loop terminates */ - return GL_FALSE; -} - -static void GLFWCALL key_callback(int key, int action) -{ - switch(key) - { - case GLFW_KEY_ESC: - /* Exit program on Escape */ - running = GL_FALSE; - break; - } -} - -/* Print usage information */ -static void usage(void) -{ - printf("Usage: heightmap [-v ] [-f ]\n"); - printf(" heightmap [-h]\n"); -} - -void iteration(); - -double dt; -int frame; -int iter; -double last_update_time; - -int main(int argc, char** argv) -{ - int ch; - float f; - GLint uloc_modelview; - GLint uloc_project; - - char* vertex_shader_path = NULL; - char* fragment_shader_path = NULL; - char* vertex_shader_src = NULL; - char* fragment_shader_src = NULL; - GLuint shader_program; - - while ((ch = getopt(argc, argv, "f:v:h")) != -1) - { - switch (ch) - { - case 'f': - fragment_shader_path = optarg; - break; - case 'v': - vertex_shader_path = optarg; - break; - case 'h': - usage(); - exit(EXIT_SUCCESS); - default: - usage(); - exit(EXIT_FAILURE); - } - } - - if (fragment_shader_path) - { - vertex_shader_src = read_file_content(fragment_shader_path); - if (!fragment_shader_src) - { - fprintf(stderr, - "ERROR: unable to load fragment shader from '%s'\n", - fragment_shader_path); - exit(EXIT_FAILURE); - } - } - - if (vertex_shader_path) - { - vertex_shader_src = read_file_content(vertex_shader_path); - if (!vertex_shader_src) - { - fprintf(stderr, - "ERROR: unable to load vertex shader from '%s'\n", - fragment_shader_path); - exit(EXIT_FAILURE); - } - } - - if (GL_TRUE != glfwInit()) - { - fprintf(stderr, "ERROR: Unable to initialize GLFW\n"); - usage(); - - free(vertex_shader_src); - free(fragment_shader_src); - exit(EXIT_FAILURE); - } - - glfwEnable(GLFW_AUTO_POLL_EVENTS); /* No explicit call to glfwPollEvents() */ - - glfwOpenWindowHint(GLFW_WINDOW_NO_RESIZE, GL_TRUE); - glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3); - glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 2); - glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); - - if (GL_TRUE != glfwOpenWindow(800, 600, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) - { - fprintf(stderr, "ERROR: Unable to create the OpenGL context and associated window\n"); - usage(); - - free(vertex_shader_src); - free(fragment_shader_src); - exit(EXIT_FAILURE); - } - - glfwSetWindowTitle("GLFW OpenGL3 Heightmap demo"); - /* Register events callback */ - glfwSetWindowCloseCallback(close_window_callback); - glfwSetKeyCallback(key_callback); - - if (GL_TRUE != init_opengl()) - { - fprintf(stderr, "ERROR: unable to resolve OpenGL function pointers\n"); - free(vertex_shader_src); - free(fragment_shader_src); - exit(EXIT_FAILURE); - } - /* Prepare opengl resources for rendering */ - shader_program = make_shader_program(vertex_shader_src , fragment_shader_src); - free(vertex_shader_src); - free(fragment_shader_src); - - if (shader_program == 0u) - { - fprintf(stderr, "ERROR: during creation of the shader program\n"); - usage(); - exit(EXIT_FAILURE); - } - - pglUseProgram(shader_program); - uloc_project = pglGetUniformLocation(shader_program, "project"); - uloc_modelview = pglGetUniformLocation(shader_program, "modelview"); - - /* Compute the projection matrix */ - f = 1.0f / tanf(view_angle / 2.0f); - projection_matrix[0] = f / aspect_ratio; - projection_matrix[5] = f; - projection_matrix[10] = (z_far + z_near)/ (z_near - z_far); - projection_matrix[11] = -1.0f; - projection_matrix[14] = 2.0f * (z_far * z_near) / (z_near - z_far); - pglUniformMatrix4fv(uloc_project, 1, GL_FALSE, projection_matrix); - - /* Set the camera position */ - modelview_matrix[12] = -5.0f; - modelview_matrix[13] = -5.0f; - modelview_matrix[14] = -20.0f; - pglUniformMatrix4fv(uloc_modelview, 1, GL_FALSE, modelview_matrix); - - /* Create mesh data */ - init_map(); - make_mesh(shader_program); - - /* Create vao + vbo to store the mesh */ - /* Create the vbo to store all the information for the grid and the height */ - - /* setup the scene ready for rendering */ - glViewport(0, 0, 800, 600); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - - /* main loop */ - frame = 0; - iter = 0; - dt = last_update_time = glfwGetTime(); - -#ifdef EMSCRIPTEN - emscripten_set_main_loop (iteration, 0, 1); -#else - // Main loop - while( running ) - { - iteration(); - } -#endif - - exit(EXIT_SUCCESS); -} - -void iteration(){ - ++frame; - /* render the next frame */ - glClear(GL_COLOR_BUFFER_BIT); - glDrawElements(GL_LINES, 2* MAP_NUM_LINES , GL_UNSIGNED_INT, 0); - - /* display and process events through callbacks */ - glfwSwapBuffers(); - /* Check the frame rate and update the heightmap if needed */ - dt = glfwGetTime(); - if ((dt - last_update_time) > 0.2) - { - /* generate the next iteration of the heightmap */ - if (iter < MAX_ITER) - { - update_map(NUM_ITER_AT_A_TIME); - update_mesh(); - iter += NUM_ITER_AT_A_TIME; - } - last_update_time = dt; - frame = 0; - } -} - diff --git a/tests/glfw/listmodes.c b/tests/glfw/listmodes.c deleted file mode 100644 index 717cfde0c66dc..0000000000000 --- a/tests/glfw/listmodes.c +++ /dev/null @@ -1,48 +0,0 @@ -//======================================================================== -// This is a small test application for GLFW. -// The program lists all available fullscreen video modes. -//======================================================================== - -#include -#include - -// Maximum number of modes that we want to list -#define MAX_NUM_MODES 400 - - -//======================================================================== -// main() -//======================================================================== - -int main( void ) -{ - GLFWvidmode dtmode, modes[ MAX_NUM_MODES ]; - int modecount, i; - - // Initialize GLFW - if( !glfwInit() ) - { - return 0; - } - - // Show desktop video mode - glfwGetDesktopMode( &dtmode ); - printf( "Desktop mode: %d x %d x %d\n\n", - dtmode.Width, dtmode.Height, dtmode.RedBits + - dtmode.GreenBits + dtmode.BlueBits ); - - // List available video modes - modecount = glfwGetVideoModes( modes, MAX_NUM_MODES ); - printf( "Available modes:\n" ); - for( i = 0; i < modecount; i ++ ) - { - printf( "%3d: %d x %d x %d\n", i, - modes[i].Width, modes[i].Height, modes[i].RedBits + - modes[i].GreenBits + modes[i].BlueBits ); - } - - // Terminate GLFW - glfwTerminate(); - - return 0; -} diff --git a/tests/glfw/mipmaps.c b/tests/glfw/mipmaps.c deleted file mode 100644 index bfd77f0617f21..0000000000000 --- a/tests/glfw/mipmaps.c +++ /dev/null @@ -1,136 +0,0 @@ -//======================================================================== -// This is an example program for the GLFW library -// -// It shows texture loading with mipmap generation and rendering with -// trilienar texture filtering -//======================================================================== - -#include -#include - -#include - -#ifdef EMSCRIPTEN -#include -#endif - -int width, height, x; -double time; -GLboolean running; - -void iteration(){ - // Get time and mouse position - time = glfwGetTime(); - glfwGetMousePos( &x, NULL ); - - // Get window size (may be different than the requested size) - glfwGetWindowSize( &width, &height ); - height = height > 0 ? height : 1; - - // Set viewport - glViewport( 0, 0, width, height ); - - // Clear color buffer - glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); - glClear( GL_COLOR_BUFFER_BIT ); - - // Select and setup the projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - gluPerspective( 65.0f, (GLfloat)width / (GLfloat)height, 1.0f, - 50.0f ); - - // Select and setup the modelview matrix - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - gluLookAt( 0.0f, 3.0f, -20.0f, // Eye-position - 0.0f, -4.0f, -11.0f, // View-point - 0.0f, 1.0f, 0.0f ); // Up-vector - - // Draw a textured quad - glRotatef( 0.05f * (GLfloat)x + (GLfloat)time * 5.0f, 0.0f, 1.0f, 0.0f ); - glBegin( GL_QUADS ); - glTexCoord2f( -20.0f, 20.0f ); - glVertex3f( -50.0f, 0.0f, -50.0f ); - glTexCoord2f( 20.0f, 20.0f ); - glVertex3f( 50.0f, 0.0f, -50.0f ); - glTexCoord2f( 20.0f, -20.0f ); - glVertex3f( 50.0f, 0.0f, 50.0f ); - glTexCoord2f( -20.0f, -20.0f ); - glVertex3f( -50.0f, 0.0f, 50.0f ); - glEnd(); - - // Swap buffers - glfwSwapBuffers(); - - // Check if the ESC key was pressed or the window was closed - running = !glfwGetKey( GLFW_KEY_ESC ) && - glfwGetWindowParam( GLFW_OPENED ); -} - -int main( void ) -{ - GLuint textureID; - char* texturePath = "mipmaps.tga"; - - // Initialise GLFW - if( !glfwInit() ) - { - fprintf( stderr, "Failed to initialize GLFW\n" ); - exit( EXIT_FAILURE ); - } - - // Open OpenGL window - if( !glfwOpenWindow( 640, 480, 0,0,0,0, 0,0, GLFW_WINDOW ) ) - { - fprintf( stderr, "Failed to open GLFW window\n" ); - glfwTerminate(); - exit( EXIT_FAILURE ); - } - - glfwSetWindowTitle( "Trilinear interpolation" ); - - // Enable sticky keys - glfwEnable( GLFW_STICKY_KEYS ); - - // Enable vertical sync (on cards that support it) - glfwSwapInterval( 1 ); - - // Generate and bind our texture ID - glGenTextures( 1, &textureID ); - glBindTexture( GL_TEXTURE_2D, textureID ); - - // Load texture from file into video memory, including mipmap levels - if( !glfwLoadTexture2D( texturePath, GLFW_BUILD_MIPMAPS_BIT ) ) - { - fprintf( stderr, "Failed to load texture %s\n", texturePath ); - glfwTerminate(); - exit( EXIT_FAILURE ); - } - - // Use trilinear interpolation (GL_LINEAR_MIPMAP_LINEAR) - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - GL_LINEAR_MIPMAP_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, - GL_LINEAR ); - - // Enable plain 2D texturing - glEnable( GL_TEXTURE_2D ); - - running = GL_TRUE; -#ifdef EMSCRIPTEN - emscripten_set_main_loop (iteration, 0, 1); -#else - // Main loop - while( running ) - { - iteration(); - } -#endif - - // Close OpenGL window and terminate GLFW - glfwTerminate(); - - exit( EXIT_SUCCESS ); -} - diff --git a/tests/glfw/mipmaps.tga b/tests/glfw/mipmaps.tga deleted file mode 100644 index 55f913b0fa48f69b163664da1db6f9b1fe80e2ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66322 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 -#include - - -typedef struct { - GLFWcond cond; - GLFWmutex mutex; - int flag; -} signal_t; - - -signal_t gotoA, gotoB; - -GLFWcond threadDone; -GLFWmutex doneMutex; -int doneCount; -int gotoACount, gotoBCount; - -#define MAX_COUNT 10000 - - -//------------------------------------------------------------------------ -// InitSignal() -//------------------------------------------------------------------------ - -void InitSignal( signal_t *s ) -{ - s->cond = glfwCreateCond(); - s->mutex = glfwCreateMutex(); - s->flag = 0; -} - - -//------------------------------------------------------------------------ -// KillSignal() -//------------------------------------------------------------------------ - -void KillSignal( signal_t *s ) -{ - glfwDestroyCond( s->cond ); - glfwDestroyMutex( s->mutex ); - s->flag = 0; -} - - -//------------------------------------------------------------------------ -// WaitSignal() -//------------------------------------------------------------------------ - -void WaitSignal( signal_t *s ) -{ - glfwLockMutex( s->mutex ); - while( !s->flag ) - { - glfwWaitCond( s->cond, s->mutex, GLFW_INFINITY ); - } - s->flag = 0; - glfwUnlockMutex( s->mutex ); -} - - -//------------------------------------------------------------------------ -// SetSignal() -//------------------------------------------------------------------------ - -void SetSignal( signal_t *s ) -{ - glfwLockMutex( s->mutex ); - s->flag = 1; - glfwUnlockMutex( s->mutex ); - glfwSignalCond( s->cond ); -} - - -//------------------------------------------------------------------------ -// threadAfun() -//------------------------------------------------------------------------ - -void GLFWCALL threadAfun( void * arg ) -{ - int done; - - do - { - done = (gotoACount >= MAX_COUNT); - if( !done ) - { - gotoACount ++; - SetSignal( &gotoB ); - WaitSignal( &gotoA ); - } - } - while( !done ); - - SetSignal( &gotoB ); - - glfwLockMutex( doneMutex ); - doneCount ++; - glfwUnlockMutex( doneMutex ); - glfwSignalCond( threadDone ); -} - - -//------------------------------------------------------------------------ -// threadBfun() -//------------------------------------------------------------------------ - -void GLFWCALL threadBfun( void * arg ) -{ - int done; - - do - { - done = (gotoBCount >= MAX_COUNT); - if( !done ) - { - gotoBCount ++; - SetSignal( &gotoA ); - WaitSignal( &gotoB ); - } - } - while( !done ); - - SetSignal( &gotoA ); - - glfwLockMutex( doneMutex ); - doneCount ++; - glfwUnlockMutex( doneMutex ); - glfwSignalCond( threadDone ); -} - - - -//------------------------------------------------------------------------ -// main() -//------------------------------------------------------------------------ - -int main( void ) -{ - GLFWthread threadA, threadB; - double t1, t2, csps; - int done, count, i; - - gotoACount = gotoBCount = doneCount = 0; - - // Initialize GLFW - if( !glfwInit() ) - { - return 0; - } - - // Print some program information - printf( "\nMultithreading benchmarking program\n" ); - printf( "-----------------------------------\n\n" ); - printf( "This program consists of two tests. In the first test " ); - printf( "two threads are created,\n" ); - printf( "which continously signal/wait each other. This forces " ); - printf( "the execution to\n" ); - printf( "alternate between the two threads, and gives a measure " ); - printf( "of the thread\n" ); - printf( "synchronization granularity. In the second test, the " ); - printf( "main thread is repeatedly\n" ); - printf( "put to sleep for a very short interval using glfwSleep. " ); - printf( "The average sleep time\n" ); - printf( "is measured, which tells the minimum supported sleep " ); - printf( "interval.\n\n" ); - printf( "Results:\n" ); - printf( "--------\n\n" ); - printf( "Number of CPUs: %d\n\n", glfwGetNumberOfProcessors() ); - fflush( stdout ); - - -//------------------------------------------------------------------------ -// 1) Benchmark thread synchronization granularity -//------------------------------------------------------------------------ - - // Init mutexes and conditions - doneMutex = glfwCreateMutex(); - threadDone = glfwCreateCond(); - InitSignal( &gotoA ); - InitSignal( &gotoB ); - - // Create threads A & B - threadA = glfwCreateThread( threadAfun, NULL ); - threadB = glfwCreateThread( threadBfun, NULL ); - if( threadA == -1 || threadB == -1 ) - { - glfwLockMutex( doneMutex ); - doneCount = 2; - glfwUnlockMutex( doneMutex ); - } - - // Wait for both threads to be done - t1 = glfwGetTime(); - glfwLockMutex( doneMutex ); - do - { - done = (doneCount == 2); - if( !done ) - { - glfwWaitCond( threadDone, doneMutex, GLFW_INFINITY ); - } - } - while( !done ); - glfwUnlockMutex( doneMutex ); - t2 = glfwGetTime(); - - // Display results - count = gotoACount + gotoBCount; - csps = (double)count / (t2-t1); - printf( "Test 1: %.0f context switches / second (%.3f us/switch)\n", - csps, 1e6/csps ); - fflush( stdout ); - - // Wait for threads to die - glfwWaitThread( threadA, GLFW_WAIT ); - glfwWaitThread( threadB, GLFW_WAIT ); - - // Destroy mutexes and conditions - glfwDestroyMutex( doneMutex ); - glfwDestroyCond( threadDone ); - KillSignal( &gotoA ); - KillSignal( &gotoB ); - - -//------------------------------------------------------------------------ -// 2) Benchmark thread sleep granularity -//------------------------------------------------------------------------ - - // Find an initial estimate - t1 = glfwGetTime(); - for( i = 0; i < 10; i ++ ) - { - glfwSleep( 0.0001 ); - } - t2 = glfwGetTime(); - - // Sleep for roughly 1 s - count = (int)(1.0 / ((t2-t1)/10.0)); - t1 = glfwGetTime(); - for( i = 0; i < count; i ++ ) - { - glfwSleep( 0.0001 ); - } - t2 = glfwGetTime(); - - // Display results - printf( "Test 2: %.3f ms / sleep (mean)\n\n", - 1000.0 * (t2-t1) / (double)count ); - - // Terminate GLFW - glfwTerminate(); - - return 0; -} diff --git a/tests/glfw/mthello.c b/tests/glfw/mthello.c deleted file mode 100644 index e12dea52551e9..0000000000000 --- a/tests/glfw/mthello.c +++ /dev/null @@ -1,48 +0,0 @@ -//======================================================================== -// This is a small test application for GLFW. -// The program prints "Hello world!", using two threads. -//======================================================================== - -#include -#include - - -//======================================================================== -// HelloFun() - Thread function -//======================================================================== - -void GLFWCALL HelloFun( void *arg ) -{ - // Print the first part of the message - printf( "Hello " ); -} - - -//======================================================================== -// main() - Main function (main thread) -//======================================================================== - -int main( void ) -{ - GLFWthread thread; - - // Initialise GLFW - if( !glfwInit() ) - { - return 0; - } - - // Create thread - thread = glfwCreateThread( HelloFun, NULL ); - - // Wait for thread to die - glfwWaitThread( thread, GLFW_WAIT ); - - // Print the rest of the message - printf( "world!\n" ); - - // Terminate GLFW - glfwTerminate(); - - return 0; -} diff --git a/tests/glfw/particles.c b/tests/glfw/particles.c deleted file mode 100644 index 15c133a0aa921..0000000000000 --- a/tests/glfw/particles.c +++ /dev/null @@ -1,1166 +0,0 @@ -//======================================================================== -// This is a simple, but cool particle engine (buzz-word meaning many -// small objects that are treated as points and drawn as textures -// projected on simple geometry). -// -// This demonstration generates a colorful fountain-like animation. It -// uses several advanced OpenGL teqhniques: -// -// 1) Lighting (per vertex) -// 2) Alpha blending -// 3) Fog -// 4) Texturing -// 5) Display lists (for drawing the static environment geometry) -// 6) Vertex arrays (for drawing the particles) -// 7) GL_EXT_separate_specular_color is used (if available) -// -// Even more so, this program uses multi threading. The program is -// essentialy divided into a main rendering thread and a particle physics -// calculation thread. My benchmarks under Windows 2000 on a single -// processor system show that running this program as two threads instead -// of a single thread means no difference (there may be a very marginal -// advantage for the multi threaded case). On dual processor systems I -// have had reports of 5-25% of speed increase when running this program -// as two threads instead of one thread. -// -// The default behaviour of this program is to use two threads. To force -// a single thread to be used, use the command line switch -s. -// -// To run a fixed length benchmark (60 s), use the command line switch -b. -// -// Benchmark results (640x480x16, best of three tests): -// -// CPU GFX 1 thread 2 threads -// Athlon XP 2700+ GeForce Ti4200 (oc) 757 FPS 759 FPS -// P4 2.8 GHz (SMT) GeForce FX5600 548 FPS 550 FPS -// -// One more thing: Press 'w' during the demo to toggle wireframe mode. -//======================================================================== - -#include -#include -#include -#include -#include - -#ifdef EMSCRIPTEN -#include -#endif - -// Define tokens for GL_EXT_separate_specular_color if not already defined -#ifndef GL_EXT_separate_specular_color -#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 -#define GL_SINGLE_COLOR_EXT 0x81F9 -#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA -#endif // GL_EXT_separate_specular_color - -// Some 's do not define M_PI -#ifndef M_PI -#define M_PI 3.141592654 -#endif - -// Desired fullscreen resolution -#define WIDTH 640 -#define HEIGHT 480 - - -//======================================================================== -// Type definitions -//======================================================================== - -typedef struct { float x,y,z; } VEC; - -// This structure is used for interleaved vertex arrays (see the -// DrawParticles function) - Note: This structure SHOULD be packed on most -// systems. It uses 32-bit fields on 32-bit boundaries, and is a multiple -// of 64 bits in total (6x32=3x64). If it does not work, try using pragmas -// or whatever to force the structure to be packed. -typedef struct { - GLfloat s, t; // Texture coordinates - GLuint rgba; // Color (four ubytes packed into an uint) - GLfloat x, y, z; // Vertex coordinates -} VERTEX; - - -//======================================================================== -// Program control global variables -//======================================================================== - -// "Running" flag (true if program shall continue to run) -int running; - -// Window dimensions -int width, height; - -// "wireframe" flag (true if we use wireframe view) -int wireframe; - -// "multithreading" flag (true if we use multithreading) -int multithreading; - -// Thread synchronization -struct { - double t; // Time (s) - float dt; // Time since last frame (s) - int p_frame; // Particle physics frame number - int d_frame; // Particle draw frame number - GLFWcond p_done; // Condition: particle physics done - GLFWcond d_done; // Condition: particle draw done - GLFWmutex particles_lock; // Particles data sharing mutex -} thread_sync; - - -//======================================================================== -// Texture declarations (we hard-code them into the source code, since -// they are so simple) -//======================================================================== - -#define P_TEX_WIDTH 8 // Particle texture dimensions -#define P_TEX_HEIGHT 8 -#define F_TEX_WIDTH 16 // Floor texture dimensions -#define F_TEX_HEIGHT 16 - -// Texture object IDs -GLuint particle_tex_id, floor_tex_id; - -// Particle texture (a simple spot) -const unsigned char particle_texture[ P_TEX_WIDTH * P_TEX_HEIGHT ] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x11, 0x22, 0x22, 0x11, 0x00, 0x00, - 0x00, 0x11, 0x33, 0x88, 0x77, 0x33, 0x11, 0x00, - 0x00, 0x22, 0x88, 0xff, 0xee, 0x77, 0x22, 0x00, - 0x00, 0x22, 0x77, 0xee, 0xff, 0x88, 0x22, 0x00, - 0x00, 0x11, 0x33, 0x77, 0x88, 0x33, 0x11, 0x00, - 0x00, 0x00, 0x11, 0x33, 0x22, 0x11, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -// Floor texture (your basic checkered floor) -const unsigned char floor_texture[ F_TEX_WIDTH * F_TEX_HEIGHT ] = { - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0xff, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0xf0, 0xcc, 0xee, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x66, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xee, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0xf0, 0xf0, 0xf0, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x55, 0x30, 0x30, 0x44, 0x30, 0x30, - 0xf0, 0xdd, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x60, 0x30, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, 0xf0, 0xff, 0xf0, 0xf0, 0xdd, 0xf0, 0xf0, 0xff, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x55, 0x33, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, - 0x30, 0x44, 0x66, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xaa, 0xf0, 0xf0, 0xcc, 0xf0, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xdd, 0xf0, - 0x30, 0x30, 0x30, 0x77, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -}; - - -//======================================================================== -// These are fixed constants that control the particle engine. In a -// modular world, these values should be variables... -//======================================================================== - -// Maximum number of particles -#define MAX_PARTICLES 3000 - -// Life span of a particle (in seconds) -#define LIFE_SPAN 8.0f - -// A new particle is born every [BIRTH_INTERVAL] second -#define BIRTH_INTERVAL (LIFE_SPAN/(float)MAX_PARTICLES) - -// Particle size (meters) -#define PARTICLE_SIZE 0.7f - -// Gravitational constant (m/s^2) -#define GRAVITY 9.8f - -// Base initial velocity (m/s) -#define VELOCITY 8.0f - -// Bounce friction (1.0 = no friction, 0.0 = maximum friction) -#define FRICTION 0.75f - -// "Fountain" height (m) -#define FOUNTAIN_HEIGHT 3.0f - -// Fountain radius (m) -#define FOUNTAIN_RADIUS 1.6f - -// Minimum delta-time for particle phisics (s) -#define MIN_DELTA_T (BIRTH_INTERVAL * 0.5f) - - -//======================================================================== -// Particle system global variables -//======================================================================== - -// This structure holds all state for a single particle -typedef struct { - float x,y,z; // Position in space - float vx,vy,vz; // Velocity vector - float r,g,b; // Color of particle - float life; // Life of particle (1.0 = newborn, < 0.0 = dead) - int active; // Tells if this particle is active -} PARTICLE; - -// Global vectors holding all particles. We use two vectors for double -// buffering. -static PARTICLE particles[ MAX_PARTICLES ]; - -// Global variable holding the age of the youngest particle -static float min_age; - -// Color of latest born particle (used for fountain lighting) -static float glow_color[4]; - -// Position of latest born particle (used for fountain lighting) -static float glow_pos[4]; - - -//======================================================================== -// Object material and fog configuration constants -//======================================================================== - -const GLfloat fountain_diffuse[4] = {0.7f,1.0f,1.0f,1.0f}; -const GLfloat fountain_specular[4] = {1.0f,1.0f,1.0f,1.0f}; -const GLfloat fountain_shininess = 12.0f; -const GLfloat floor_diffuse[4] = {1.0f,0.6f,0.6f,1.0f}; -const GLfloat floor_specular[4] = {0.6f,0.6f,0.6f,1.0f}; -const GLfloat floor_shininess = 18.0f; -const GLfloat fog_color[4] = {0.1f, 0.1f, 0.1f, 1.0f}; - - -//======================================================================== -// InitParticle() - Initialize a new particle -//======================================================================== - -void InitParticle( PARTICLE *p, double t ) -{ - float xy_angle, velocity; - - // Start position of particle is at the fountain blow-out - p->x = 0.0f; - p->y = 0.0f; - p->z = FOUNTAIN_HEIGHT; - - // Start velocity is up (Z)... - p->vz = 0.7f + (0.3f/4096.f) * (float) (rand() & 4095); - - // ...and a randomly chosen X/Y direction - xy_angle = (2.f * (float)M_PI / 4096.f) * (float) (rand() & 4095); - p->vx = 0.4f * (float) cos( xy_angle ); - p->vy = 0.4f * (float) sin( xy_angle ); - - // Scale velocity vector according to a time-varying velocity - velocity = VELOCITY*(0.8f + 0.1f*(float)(sin( 0.5*t )+sin( 1.31*t ))); - p->vx *= velocity; - p->vy *= velocity; - p->vz *= velocity; - - // Color is time-varying - p->r = 0.7f + 0.3f * (float) sin( 0.34*t + 0.1 ); - p->g = 0.6f + 0.4f * (float) sin( 0.63*t + 1.1 ); - p->b = 0.6f + 0.4f * (float) sin( 0.91*t + 2.1 ); - - // Store settings for fountain glow lighting - glow_pos[0] = 0.4f * (float) sin( 1.34*t ); - glow_pos[1] = 0.4f * (float) sin( 3.11*t ); - glow_pos[2] = FOUNTAIN_HEIGHT + 1.0f; - glow_pos[3] = 1.0f; - glow_color[0] = p->r; - glow_color[1] = p->g; - glow_color[2] = p->b; - glow_color[3] = 1.0f; - - // The particle is new-born and active - p->life = 1.0f; - p->active = 1; -} - - -//======================================================================== -// UpdateParticle() - Update a particle -//======================================================================== - -#define FOUNTAIN_R2 (FOUNTAIN_RADIUS+PARTICLE_SIZE/2)*(FOUNTAIN_RADIUS+PARTICLE_SIZE/2) - -void UpdateParticle( PARTICLE *p, float dt ) -{ - // If the particle is not active, we need not do anything - if( !p->active ) - { - return; - } - - // The particle is getting older... - p->life = p->life - dt * (1.0f / LIFE_SPAN); - - // Did the particle die? - if( p->life <= 0.0f ) - { - p->active = 0; - return; - } - - // Update particle velocity (apply gravity) - p->vz = p->vz - GRAVITY * dt; - - // Update particle position - p->x = p->x + p->vx * dt; - p->y = p->y + p->vy * dt; - p->z = p->z + p->vz * dt; - - // Simple collision detection + response - if( p->vz < 0.0f ) - { - // Particles should bounce on the fountain (with friction) - if( (p->x*p->x + p->y*p->y) < FOUNTAIN_R2 && - p->z < (FOUNTAIN_HEIGHT + PARTICLE_SIZE/2) ) - { - p->vz = -FRICTION * p->vz; - p->z = FOUNTAIN_HEIGHT + PARTICLE_SIZE/2 + - FRICTION * (FOUNTAIN_HEIGHT + - PARTICLE_SIZE/2 - p->z); - } - - // Particles should bounce on the floor (with friction) - else if( p->z < PARTICLE_SIZE/2 ) - { - p->vz = -FRICTION * p->vz; - p->z = PARTICLE_SIZE/2 + - FRICTION * (PARTICLE_SIZE/2 - p->z); - } - - } -} - - -//======================================================================== -// ParticleEngine() - The main frame for the particle engine. Called once -// per frame. -//======================================================================== - -void ParticleEngine( double t, float dt ) -{ - int i; - float dt2; - - // Update particles (iterated several times per frame if dt is too - // large) - while( dt > 0.0f ) - { - // Calculate delta time for this iteration - dt2 = dt < MIN_DELTA_T ? dt : MIN_DELTA_T; - - // Update particles - for( i = 0; i < MAX_PARTICLES; i ++ ) - { - UpdateParticle( &particles[ i ], dt2 ); - } - - // Increase minimum age - min_age += dt2; - - // Should we create any new particle(s)? - while( min_age >= BIRTH_INTERVAL ) - { - min_age -= BIRTH_INTERVAL; - - // Find a dead particle to replace with a new one - for( i = 0; i < MAX_PARTICLES; i ++ ) - { - if( !particles[ i ].active ) - { - InitParticle( &particles[ i ], t + min_age ); - UpdateParticle( &particles[ i ], min_age ); - break; - } - } - } - - // Decrease frame delta time - dt -= dt2; - } -} - - -//======================================================================== -// DrawParticles() - Draw all active particles. We use OpenGL 1.1 vertex -// arrays for this in order to accelerate the drawing. -//======================================================================== - -#define BATCH_PARTICLES 70 // Number of particles to draw in each batch - // (70 corresponds to 7.5 KB = will not blow - // the L1 data cache on most CPUs) -#define PARTICLE_VERTS 4 // Number of vertices per particle - -void DrawParticles( double t, float dt ) -{ - int i, particle_count; - VERTEX vertex_array[ BATCH_PARTICLES * PARTICLE_VERTS ], *vptr; - float alpha; - GLuint rgba; - VEC quad_lower_left, quad_lower_right; - GLfloat mat[ 16 ]; - PARTICLE *pptr; - - // Here comes the real trick with flat single primitive objects (s.c. - // "billboards"): We must rotate the textured primitive so that it - // always faces the viewer (is coplanar with the view-plane). - // We: - // 1) Create the primitive around origo (0,0,0) - // 2) Rotate it so that it is coplanar with the view plane - // 3) Translate it according to the particle position - // Note that 1) and 2) is the same for all particles (done only once). - - // Get modelview matrix. We will only use the upper left 3x3 part of - // the matrix, which represents the rotation. - glGetFloatv( GL_MODELVIEW_MATRIX, mat ); - - // 1) & 2) We do it in one swift step: - // Although not obvious, the following six lines represent two matrix/ - // vector multiplications. The matrix is the inverse 3x3 rotation - // matrix (i.e. the transpose of the same matrix), and the two vectors - // represent the lower left corner of the quad, PARTICLE_SIZE/2 * - // (-1,-1,0), and the lower right corner, PARTICLE_SIZE/2 * (1,-1,0). - // The upper left/right corners of the quad is always the negative of - // the opposite corners (regardless of rotation). - quad_lower_left.x = (-PARTICLE_SIZE/2) * (mat[0] + mat[1]); - quad_lower_left.y = (-PARTICLE_SIZE/2) * (mat[4] + mat[5]); - quad_lower_left.z = (-PARTICLE_SIZE/2) * (mat[8] + mat[9]); - quad_lower_right.x = (PARTICLE_SIZE/2) * (mat[0] - mat[1]); - quad_lower_right.y = (PARTICLE_SIZE/2) * (mat[4] - mat[5]); - quad_lower_right.z = (PARTICLE_SIZE/2) * (mat[8] - mat[9]); - - // Don't update z-buffer, since all particles are transparent! - glDepthMask( GL_FALSE ); - - // Enable blending - glEnable( GL_BLEND ); - glBlendFunc( GL_SRC_ALPHA, GL_ONE ); - - // Select particle texture - if( !wireframe ) - { - glEnable( GL_TEXTURE_2D ); - glBindTexture( GL_TEXTURE_2D, particle_tex_id ); - } - - // Set up vertex arrays. We use interleaved arrays, which is easier to - // handle (in most situations) and it gives a linear memeory access - // access pattern (which may give better performance in some - // situations). GL_T2F_C4UB_V3F means: 2 floats for texture coords, - // 4 ubytes for color and 3 floats for vertex coord (in that order). - // Most OpenGL cards / drivers are optimized for this format. - glInterleavedArrays( GL_T2F_C4UB_V3F, 0, vertex_array ); - - // Is particle physics carried out in a separate thread? - if( multithreading ) - { - // Wait for particle physics thread to be done - glfwLockMutex( thread_sync.particles_lock ); - while( running && thread_sync.p_frame <= thread_sync.d_frame ) - { - glfwWaitCond( thread_sync.p_done, thread_sync.particles_lock, - 0.1 ); - } - - // Store the frame time and delta time for the physics thread - thread_sync.t = t; - thread_sync.dt = dt; - - // Update frame counter - thread_sync.d_frame ++; - } - else - { - // Perform particle physics in this thread - ParticleEngine( t, dt ); - } - - // Loop through all particles and build vertex arrays. - particle_count = 0; - vptr = vertex_array; - pptr = particles; - for( i = 0; i < MAX_PARTICLES; i ++ ) - { - if( pptr->active ) - { - // Calculate particle intensity (we set it to max during 75% - // of its life, then it fades out) - alpha = 4.0f * pptr->life; - if( alpha > 1.0f ) - { - alpha = 1.0f; - } - - // Convert color from float to 8-bit (store it in a 32-bit - // integer using endian independent type casting) - ((GLubyte *)&rgba)[0] = (GLubyte)(pptr->r * 255.0f); - ((GLubyte *)&rgba)[1] = (GLubyte)(pptr->g * 255.0f); - ((GLubyte *)&rgba)[2] = (GLubyte)(pptr->b * 255.0f); - ((GLubyte *)&rgba)[3] = (GLubyte)(alpha * 255.0f); - - // 3) Translate the quad to the correct position in modelview - // space and store its parameters in vertex arrays (we also - // store texture coord and color information for each vertex). - - // Lower left corner - vptr->s = 0.0f; - vptr->t = 0.0f; - vptr->rgba = rgba; - vptr->x = pptr->x + quad_lower_left.x; - vptr->y = pptr->y + quad_lower_left.y; - vptr->z = pptr->z + quad_lower_left.z; - vptr ++; - - // Lower right corner - vptr->s = 1.0f; - vptr->t = 0.0f; - vptr->rgba = rgba; - vptr->x = pptr->x + quad_lower_right.x; - vptr->y = pptr->y + quad_lower_right.y; - vptr->z = pptr->z + quad_lower_right.z; - vptr ++; - - // Upper right corner - vptr->s = 1.0f; - vptr->t = 1.0f; - vptr->rgba = rgba; - vptr->x = pptr->x - quad_lower_left.x; - vptr->y = pptr->y - quad_lower_left.y; - vptr->z = pptr->z - quad_lower_left.z; - vptr ++; - - // Upper left corner - vptr->s = 0.0f; - vptr->t = 1.0f; - vptr->rgba = rgba; - vptr->x = pptr->x - quad_lower_right.x; - vptr->y = pptr->y - quad_lower_right.y; - vptr->z = pptr->z - quad_lower_right.z; - vptr ++; - - // Increase count of drawable particles - particle_count ++; - } - - // If we have filled up one batch of particles, draw it as a set - // of quads using glDrawArrays. - if( particle_count >= BATCH_PARTICLES ) - { - // The first argument tells which primitive type we use (QUAD) - // The second argument tells the index of the first vertex (0) - // The last argument is the vertex count - glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count ); - particle_count = 0; - vptr = vertex_array; - } - - // Next particle - pptr ++; - } - - // We are done with the particle data: Unlock mutex and signal physics - // thread - if( multithreading ) - { - glfwUnlockMutex( thread_sync.particles_lock ); - glfwSignalCond( thread_sync.d_done ); - } - - // Draw final batch of particles (if any) - glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count ); - - // Disable vertex arrays (Note: glInterleavedArrays implicitly called - // glEnableClientState for vertex, texture coord and color arrays) - glDisableClientState( GL_VERTEX_ARRAY ); - glDisableClientState( GL_TEXTURE_COORD_ARRAY ); - glDisableClientState( GL_COLOR_ARRAY ); - - // Disable texturing and blending - glDisable( GL_TEXTURE_2D ); - glDisable( GL_BLEND ); - - // Allow Z-buffer updates again - glDepthMask( GL_TRUE ); -} - - -//======================================================================== -// Fountain geometry specification -//======================================================================== - -#define FOUNTAIN_SIDE_POINTS 14 -#define FOUNTAIN_SWEEP_STEPS 32 - -static const float fountain_side[ FOUNTAIN_SIDE_POINTS*2 ] = { - 1.2f, 0.0f, 1.0f, 0.2f, 0.41f, 0.3f, 0.4f, 0.35f, - 0.4f, 1.95f, 0.41f, 2.0f, 0.8f, 2.2f, 1.2f, 2.4f, - 1.5f, 2.7f, 1.55f,2.95f, 1.6f, 3.0f, 1.0f, 3.0f, - 0.5f, 3.0f, 0.0f, 3.0f -}; - -static const float fountain_normal[ FOUNTAIN_SIDE_POINTS*2 ] = { - 1.0000f, 0.0000f, 0.6428f, 0.7660f, 0.3420f, 0.9397f, 1.0000f, 0.0000f, - 1.0000f, 0.0000f, 0.3420f,-0.9397f, 0.4226f,-0.9063f, 0.5000f,-0.8660f, - 0.7660f,-0.6428f, 0.9063f,-0.4226f, 0.0000f,1.00000f, 0.0000f,1.00000f, - 0.0000f,1.00000f, 0.0000f,1.00000f -}; - - -//======================================================================== -// DrawFountain() - Draw a fountain -//======================================================================== - -void DrawFountain( void ) -{ - static GLuint fountain_list = 0; - double angle; - float x, y; - int m, n; - - // The first time, we build the fountain display list - if( !fountain_list ) - { - // Start recording of a new display list - fountain_list = glGenLists( 1 ); - glNewList( fountain_list, GL_COMPILE_AND_EXECUTE ); - - // Set fountain material - glMaterialfv( GL_FRONT, GL_DIFFUSE, fountain_diffuse ); - glMaterialfv( GL_FRONT, GL_SPECULAR, fountain_specular ); - glMaterialf( GL_FRONT, GL_SHININESS, fountain_shininess ); - - // Build fountain using triangle strips - for( n = 0; n < FOUNTAIN_SIDE_POINTS-1; n ++ ) - { - glBegin( GL_TRIANGLE_STRIP ); - for( m = 0; m <= FOUNTAIN_SWEEP_STEPS; m ++ ) - { - angle = (double) m * (2.0*M_PI/(double)FOUNTAIN_SWEEP_STEPS); - x = (float) cos( angle ); - y = (float) sin( angle ); - - // Draw triangle strip - glNormal3f( x * fountain_normal[ n*2+2 ], - y * fountain_normal[ n*2+2 ], - fountain_normal[ n*2+3 ] ); - glVertex3f( x * fountain_side[ n*2+2 ], - y * fountain_side[ n*2+2 ], - fountain_side[ n*2+3 ] ); - glNormal3f( x * fountain_normal[ n*2 ], - y * fountain_normal[ n*2 ], - fountain_normal[ n*2+1 ] ); - glVertex3f( x * fountain_side[ n*2 ], - y * fountain_side[ n*2 ], - fountain_side[ n*2+1 ] ); - } - glEnd(); - } - - // End recording of display list - glEndList(); - } - else - { - // Playback display list - glCallList( fountain_list ); - } -} - - -//======================================================================== -// TesselateFloor() - Recursive function for building variable tesselated -// floor -//======================================================================== - -void TesselateFloor( float x1, float y1, float x2, float y2, - int recursion ) -{ - float delta, x, y; - - // Last recursion? - if( recursion >= 5 ) - { - delta = 999999.0f; - } - else - { - x = (float) (fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2)); - y = (float) (fabs(y1) < fabs(y2) ? fabs(y1) : fabs(y2)); - delta = x*x + y*y; - } - - // Recurse further? - if( delta < 0.1f ) - { - x = (x1+x2) * 0.5f; - y = (y1+y2) * 0.5f; - TesselateFloor( x1,y1, x, y, recursion + 1 ); - TesselateFloor( x,y1, x2, y, recursion + 1 ); - TesselateFloor( x1, y, x,y2, recursion + 1 ); - TesselateFloor( x, y, x2,y2, recursion + 1 ); - } - else - { - glTexCoord2f( x1*30.0f, y1*30.0f ); - glVertex3f( x1*80.0f, y1*80.0f , 0.0f ); - glTexCoord2f( x2*30.0f, y1*30.0f ); - glVertex3f( x2*80.0f, y1*80.0f , 0.0f ); - glTexCoord2f( x2*30.0f, y2*30.0f ); - glVertex3f( x2*80.0f, y2*80.0f , 0.0f ); - glTexCoord2f( x1*30.0f, y2*30.0f ); - glVertex3f( x1*80.0f, y2*80.0f , 0.0f ); - } -} - - -//======================================================================== -// DrawFloor() - Draw floor. We builde the floor recursively, and let the -// tesselation in the centre (near x,y=0,0) be high, while the selleation -// around the edges be low. -//======================================================================== - -void DrawFloor( void ) -{ - static GLuint floor_list = 0; - - // Select floor texture - if( !wireframe ) - { - glEnable( GL_TEXTURE_2D ); - glBindTexture( GL_TEXTURE_2D, floor_tex_id ); - } - - // The first time, we build the floor display list - if( !floor_list ) - { - // Start recording of a new display list - floor_list = glGenLists( 1 ); - glNewList( floor_list, GL_COMPILE_AND_EXECUTE ); - - // Set floor material - glMaterialfv( GL_FRONT, GL_DIFFUSE, floor_diffuse ); - glMaterialfv( GL_FRONT, GL_SPECULAR, floor_specular ); - glMaterialf( GL_FRONT, GL_SHININESS, floor_shininess ); - - // Draw floor as a bunch of triangle strips (high tesselation - // improves lighting) - glNormal3f( 0.0f, 0.0f, 1.0f ); - glBegin( GL_QUADS ); - TesselateFloor( -1.0f,-1.0f, 0.0f,0.0f, 0 ); - TesselateFloor( 0.0f,-1.0f, 1.0f,0.0f, 0 ); - TesselateFloor( 0.0f, 0.0f, 1.0f,1.0f, 0 ); - TesselateFloor( -1.0f, 0.0f, 0.0f,1.0f, 0 ); - glEnd(); - - // End recording of display list - glEndList(); - } - else - { - // Playback display list - glCallList( floor_list ); - } - - glDisable( GL_TEXTURE_2D ); - -} - - -//======================================================================== -// SetupLights() - Position and configure light sources -//======================================================================== - -void SetupLights( void ) -{ - float l1pos[4], l1amb[4], l1dif[4], l1spec[4]; - float l2pos[4], l2amb[4], l2dif[4], l2spec[4]; - - // Set light source 1 parameters - l1pos[0] = 0.0f; l1pos[1] = -9.0f; l1pos[2] = 8.0f; l1pos[3] = 1.0f; - l1amb[0] = 0.2f; l1amb[1] = 0.2f; l1amb[2] = 0.2f; l1amb[3] = 1.0f; - l1dif[0] = 0.8f; l1dif[1] = 0.4f; l1dif[2] = 0.2f; l1dif[3] = 1.0f; - l1spec[0] = 1.0f; l1spec[1] = 0.6f; l1spec[2] = 0.2f; l1spec[3] = 0.0f; - - // Set light source 2 parameters - l2pos[0] = -15.0f; l2pos[1] = 12.0f; l2pos[2] = 1.5f; l2pos[3] = 1.0f; - l2amb[0] = 0.0f; l2amb[1] = 0.0f; l2amb[2] = 0.0f; l2amb[3] = 1.0f; - l2dif[0] = 0.2f; l2dif[1] = 0.4f; l2dif[2] = 0.8f; l2dif[3] = 1.0f; - l2spec[0] = 0.2f; l2spec[1] = 0.6f; l2spec[2] = 1.0f; l2spec[3] = 0.0f; - - // Configure light sources in OpenGL - glLightfv( GL_LIGHT1, GL_POSITION, l1pos ); - glLightfv( GL_LIGHT1, GL_AMBIENT, l1amb ); - glLightfv( GL_LIGHT1, GL_DIFFUSE, l1dif ); - glLightfv( GL_LIGHT1, GL_SPECULAR, l1spec ); - glLightfv( GL_LIGHT2, GL_POSITION, l2pos ); - glLightfv( GL_LIGHT2, GL_AMBIENT, l2amb ); - glLightfv( GL_LIGHT2, GL_DIFFUSE, l2dif ); - glLightfv( GL_LIGHT2, GL_SPECULAR, l2spec ); - glLightfv( GL_LIGHT3, GL_POSITION, glow_pos ); - glLightfv( GL_LIGHT3, GL_DIFFUSE, glow_color ); - glLightfv( GL_LIGHT3, GL_SPECULAR, glow_color ); - - // Enable light sources - glEnable( GL_LIGHT1 ); - glEnable( GL_LIGHT2 ); - glEnable( GL_LIGHT3 ); -} - - -//======================================================================== -// Draw() - Main rendering function -//======================================================================== - -void Draw( double t ) -{ - double xpos, ypos, zpos, angle_x, angle_y, angle_z; - static double t_old = 0.0; - float dt; - - // Calculate frame-to-frame delta time - dt = (float)(t-t_old); - t_old = t; - - // Setup viewport - glViewport( 0, 0, width, height ); - - // Clear color and Z-buffer - glClearColor( 0.1f, 0.1f, 0.1f, 1.0f ); - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - - // Setup projection - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - gluPerspective( 65.0, (double)width/(double)height, 1.0, 60.0 ); - - // Setup camera - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - - // Rotate camera - angle_x = 90.0 - 10.0; - angle_y = 10.0 * sin( 0.3 * t ); - angle_z = 10.0 * t; - glRotated( -angle_x, 1.0, 0.0, 0.0 ); - glRotated( -angle_y, 0.0, 1.0, 0.0 ); - glRotated( -angle_z, 0.0, 0.0, 1.0 ); - - // Translate camera - xpos = 15.0 * sin( (M_PI/180.0) * angle_z ) + - 2.0 * sin( (M_PI/180.0) * 3.1 * t ); - ypos = -15.0 * cos( (M_PI/180.0) * angle_z ) + - 2.0 * cos( (M_PI/180.0) * 2.9 * t ); - zpos = 4.0 + 2.0 * cos( (M_PI/180.0) * 4.9 * t ); - glTranslated( -xpos, -ypos, -zpos ); - - // Enable face culling - glFrontFace( GL_CCW ); - glCullFace( GL_BACK ); - glEnable( GL_CULL_FACE ); - - // Enable lighting - SetupLights(); - glEnable( GL_LIGHTING ); - - // Enable fog (dim details far away) - glEnable( GL_FOG ); - glFogi( GL_FOG_MODE, GL_EXP ); - glFogf( GL_FOG_DENSITY, 0.05f ); - glFogfv( GL_FOG_COLOR, fog_color ); - - // Draw floor - DrawFloor(); - - // Enable Z-buffering - glEnable( GL_DEPTH_TEST ); - glDepthFunc( GL_LEQUAL ); - glDepthMask( GL_TRUE ); - - // Draw fountain - DrawFountain(); - - // Disable fog & lighting - glDisable( GL_LIGHTING ); - glDisable( GL_FOG ); - - // Draw all particles (must be drawn after all solid objects have been - // drawn!) - DrawParticles( t, dt ); - - // Z-buffer not needed anymore - glDisable( GL_DEPTH_TEST ); -} - - -//======================================================================== -// Resize() - GLFW window resize callback function -//======================================================================== - -void GLFWCALL Resize( int x, int y ) -{ - width = x; - height = y > 0 ? y : 1; // Prevent division by zero in aspect calc. -} - - -//======================================================================== -// Input callback functions -//======================================================================== - -void GLFWCALL KeyFun( int key, int action ) -{ - if( action == GLFW_PRESS ) - { - switch( key ) - { - case GLFW_KEY_ESC: - running = 0; - break; - case 'W': - wireframe = !wireframe; - glPolygonMode( GL_FRONT_AND_BACK, - wireframe ? GL_LINE : GL_FILL ); - break; - default: - break; - } - } -} - - -//======================================================================== -// PhysicsThreadFun() - Thread for updating particle physics -//======================================================================== - -void GLFWCALL PhysicsThreadFun( void *arg ) -{ - while( running ) - { - // Lock mutex - glfwLockMutex( thread_sync.particles_lock ); - - // Wait for particle drawing to be done - while( running && thread_sync.p_frame > thread_sync.d_frame ) - { - glfwWaitCond( thread_sync.d_done, thread_sync.particles_lock, - 0.1 ); - } - - // No longer running? - if( !running ) - { - break; - } - - // Update particles - ParticleEngine( thread_sync.t, thread_sync.dt ); - - // Update frame counter - thread_sync.p_frame ++; - - // Unlock mutex and signal drawing thread - glfwUnlockMutex( thread_sync.particles_lock ); - glfwSignalCond( thread_sync.p_done ); - } -} - - -//======================================================================== -// main() -//======================================================================== - -double t0, t; -int frames, benchmark; -void iteration(){ - // Get frame time - t = glfwGetTime() - t0; - - // Draw... - Draw( t ); - - // Swap buffers - glfwSwapBuffers(); - - // Check if window was closed - running = running && glfwGetWindowParam( GLFW_OPENED ); - - // Increase frame count - frames ++; - - // End of benchmark? - if( benchmark && t >= 60.0 ) - { - running = 0; - } -} - -int main( int argc, char **argv ) -{ - int i; - GLFWthread physics_thread = 0; - - // Use multithreading by default, but don't benchmark - multithreading = 1; - benchmark = 0; - - // Check command line arguments - for( i = 1; i < argc; i ++ ) - { - // Use benchmarking? - if( strcmp( argv[i], "-b" ) == 0 ) - { - benchmark = 1; - } - - // Force multithreading off? - else if( strcmp( argv[i], "-s" ) == 0 ) - { - multithreading = 0; - } - - // With a Finder launch on Mac OS X we get a bogus -psn_0_46268417 - // kind of argument (actual numbers vary). Ignore it. - else if( strncmp( argv[i], "-psn_", 5) == 0 ); - - // Usage - else - { - if( strcmp( argv[i], "-?" ) != 0 ) - { - printf( "Unknonwn option %s\n\n", argv[ i ] ); - } - printf( "Usage: %s [options]\n", argv[ 0 ] ); - printf( "\n"); - printf( "Options:\n" ); - printf( " -b Benchmark (run program for 60 s)\n" ); - printf( " -s Run program as single thread (default is to use two threads)\n" ); - printf( " -? Display this text\n" ); - printf( "\n"); - printf( "Program runtime controls:\n" ); - printf( " w Toggle wireframe mode\n" ); - printf( " ESC Exit program\n" ); - exit( 0 ); - } - } - - // Initialize GLFW - if( !glfwInit() ) - { - fprintf( stderr, "Failed to initialize GLFW\n" ); - exit( EXIT_FAILURE ); - } - - // Open OpenGL fullscreen window - if( !glfwOpenWindow( WIDTH, HEIGHT, 0,0,0,0, 16,0, GLFW_FULLSCREEN ) ) - { - fprintf( stderr, "Failed to open GLFW window\n" ); - glfwTerminate(); - exit( EXIT_FAILURE ); - } - - // Set window title - glfwSetWindowTitle( "Particle engine" ); - - // Disable VSync (we want to get as high FPS as possible!) - glfwSwapInterval( 0 ); - - // Window resize callback function - glfwSetWindowSizeCallback( Resize ); - - // Set keyboard input callback function - glfwSetKeyCallback( KeyFun ); - - // Upload particle texture - glGenTextures( 1, &particle_tex_id ); - glBindTexture( GL_TEXTURE_2D, particle_tex_id ); - glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, P_TEX_WIDTH, P_TEX_HEIGHT, - 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, particle_texture ); - - // Upload floor texture - glGenTextures( 1, &floor_tex_id ); - glBindTexture( GL_TEXTURE_2D, floor_tex_id ); - glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, F_TEX_WIDTH, F_TEX_HEIGHT, - 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, floor_texture ); - - // Check if we have GL_EXT_separate_specular_color, and if so use it - if( glfwExtensionSupported( "GL_EXT_separate_specular_color" ) ) - { - glLightModeli( GL_LIGHT_MODEL_COLOR_CONTROL_EXT, - GL_SEPARATE_SPECULAR_COLOR_EXT ); - } - - // Set filled polygon mode as default (not wireframe) - glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - wireframe = 0; - - // Clear particle system - for( i = 0; i < MAX_PARTICLES; i ++ ) - { - particles[ i ].active = 0; - } - min_age = 0.0f; - - // Set "running" flag - running = 1; - - // Set initial times - thread_sync.t = 0.0; - thread_sync.dt = 0.001f; - - // Init threading - if( multithreading ) - { - thread_sync.p_frame = 0; - thread_sync.d_frame = 0; - thread_sync.particles_lock = glfwCreateMutex(); - thread_sync.p_done = glfwCreateCond(); - thread_sync.d_done = glfwCreateCond(); - physics_thread = glfwCreateThread( PhysicsThreadFun, NULL ); - } - - // Main loop - t0 = glfwGetTime(); - frames = 0; -#ifdef EMSCRIPTEN - emscripten_set_main_loop (iteration, 0, 1); -#else - // Main loop - while( running ) - { - iteration(); - } -#endif - t = glfwGetTime() - t0; - - // Wait for particle physics thread to die - if( multithreading ) - { - glfwWaitThread( physics_thread, GLFW_WAIT ); - } - - // Display profiling information - printf( "%d frames in %.2f seconds = %.1f FPS", frames, t, - (double)frames / t ); - printf( " (multithreading %s)\n", multithreading ? "on" : "off" ); - - // Terminate OpenGL - glfwTerminate(); - - exit( EXIT_SUCCESS ); -} - diff --git a/tests/glfw/pong3d.c b/tests/glfw/pong3d.c deleted file mode 100644 index 1f136c93ffa83..0000000000000 --- a/tests/glfw/pong3d.c +++ /dev/null @@ -1,862 +0,0 @@ -//======================================================================== -// This is a small test application for GLFW. -// This is an OpenGL port of the famous "PONG" game (the first computer -// game ever?). It is very simple, and could be improved alot. It was -// created in order to show off the gaming capabilities of GLFW. -//======================================================================== - -#include -#include -#include -#include - -#ifdef EMSCRIPTEN -#include -#endif - -//======================================================================== -// Constants -//======================================================================== - -// Screen resolution -#define WIDTH 640 -#define HEIGHT 480 - -// Player size (units) -#define PLAYER_XSIZE 0.05f -#define PLAYER_YSIZE 0.15f - -// Ball size (units) -#define BALL_SIZE 0.02f - -// Maximum player movement speed (units / second) -#define MAX_SPEED 1.5f - -// Player movement acceleration (units / seconds^2) -#define ACCELERATION 4.0f - -// Player movement deceleration (units / seconds^2) -#define DECELERATION 2.0f - -// Ball movement speed (units / second) -#define BALL_SPEED 0.4f - -// Menu options -#define MENU_NONE 0 -#define MENU_PLAY 1 -#define MENU_QUIT 2 - -// Game events -#define NOBODY_WINS 0 -#define PLAYER1_WINS 1 -#define PLAYER2_WINS 2 - -// Winner ID -#define NOBODY 0 -#define PLAYER1 1 -#define PLAYER2 2 - -// Camera positions -#define CAMERA_CLASSIC 0 -#define CAMERA_ABOVE 1 -#define CAMERA_SPECTATOR 2 -#define CAMERA_DEFAULT CAMERA_CLASSIC - - -//======================================================================== -// Textures -//======================================================================== - -#define TEX_TITLE 0 -#define TEX_MENU 1 -#define TEX_INSTR 2 -#define TEX_WINNER1 3 -#define TEX_WINNER2 4 -#define TEX_FIELD 5 -#define NUM_TEXTURES 6 - -// Texture names -char * tex_name[ NUM_TEXTURES ] = { - "pong3d_title.tga", - "pong3d_menu.tga", - "pong3d_instr.tga", - "pong3d_winner1.tga", - "pong3d_winner2.tga", - "pong3d_field.tga" -}; - -// OpenGL texture object IDs -GLuint tex_id[ NUM_TEXTURES ]; - - -//======================================================================== -// Global variables -//======================================================================== - -// Display information -int width, height; - -// Frame information -double thistime, oldtime, dt, starttime; - -// Camera information -int camerapos; - -// Player information -struct { - double ypos; // -1.0 to +1.0 - double yspeed; // -MAX_SPEED to +MAX_SPEED -} player1, player2; - -// Ball information -struct { - double xpos, ypos; - double xspeed, yspeed; -} ball; - -// And the winner is... -int winner; - -// Lighting configuration -const GLfloat env_ambient[4] = {1.0f,1.0f,1.0f,1.0f}; -const GLfloat light1_position[4] = {-3.0f,3.0f,2.0f,1.0f}; -const GLfloat light1_diffuse[4] = {1.0f,1.0f,1.0f,0.0f}; -const GLfloat light1_ambient[4] = {0.0f,0.0f,0.0f,0.0f}; - -// Object material properties -const GLfloat player1_diffuse[4] = {1.0f,0.3f,0.3f,1.0f}; -const GLfloat player1_ambient[4] = {0.3f,0.1f,0.0f,1.0f}; -const GLfloat player2_diffuse[4] = {0.3f,1.0f,0.3f,1.0f}; -const GLfloat player2_ambient[4] = {0.1f,0.3f,0.1f,1.0f}; -const GLfloat ball_diffuse[4] = {1.0f,1.0f,0.5f,1.0f}; -const GLfloat ball_ambient[4] = {0.3f,0.3f,0.1f,1.0f}; -const GLfloat border_diffuse[4] = {0.3f,0.3f,1.0f,1.0f}; -const GLfloat border_ambient[4] = {0.1f,0.1f,0.3f,1.0f}; -const GLfloat floor_diffuse[4] = {1.0f,1.0f,1.0f,1.0f}; -const GLfloat floor_ambient[4] = {0.3f,0.3f,0.3f,1.0f}; - - -//======================================================================== -// LoadTextures() - Load textures from disk and upload to OpenGL card -//======================================================================== - -GLboolean LoadTextures( void ) -{ - int i; - - // Generate texture objects - glGenTextures( NUM_TEXTURES, tex_id ); - - // Load textures - for( i = 0; i < NUM_TEXTURES; i ++ ) - { - // Select texture object - glBindTexture( GL_TEXTURE_2D, tex_id[ i ] ); - - // Set texture parameters - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - - // Upload texture from file to texture memory - if( !glfwLoadTexture2D( tex_name[ i ], 0 ) ) - { - fprintf( stderr, "Failed to load texture %s\n", tex_name[ i ] ); - return GL_FALSE; - } - } - - return GL_TRUE; -} - - -//======================================================================== -// DrawImage() - Draw a 2D image as a texture -//======================================================================== - -void DrawImage( int texnum, float x1, float x2, float y1, float y2 ) -{ - glEnable( GL_TEXTURE_2D ); - glBindTexture( GL_TEXTURE_2D, tex_id[ texnum ] ); - glBegin( GL_QUADS ); - glTexCoord2f( 0.0f, 1.0f ); - glVertex2f( x1, y1 ); - glTexCoord2f( 1.0f, 1.0f ); - glVertex2f( x2, y1 ); - glTexCoord2f( 1.0f, 0.0f ); - glVertex2f( x2, y2 ); - glTexCoord2f( 0.0f, 0.0f ); - glVertex2f( x1, y2 ); - glEnd(); - glDisable( GL_TEXTURE_2D ); -} - - -//======================================================================== -// GameMenu() - Game menu (returns menu option) -//======================================================================== - -int GameMenu( void ) -{ - int option; - - // Enable sticky keys - glfwEnable( GLFW_STICKY_KEYS ); - - // Wait for a game menu key to be pressed - do - { - // Get window size - glfwGetWindowSize( &width, &height ); - - // Set viewport - glViewport( 0, 0, width, height ); - - // Clear display - glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); - glClear( GL_COLOR_BUFFER_BIT ); - - // Setup projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f ); - - // Setup modelview matrix - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - - // Display title - glColor3f( 1.0f, 1.0f, 1.0f ); - DrawImage( TEX_TITLE, 0.1f, 0.9f, 0.0f, 0.3f ); - - // Display menu - glColor3f( 1.0f, 1.0f, 0.0f ); - DrawImage( TEX_MENU, 0.38f, 0.62f, 0.35f, 0.5f ); - - // Display instructions - glColor3f( 0.0f, 1.0f, 1.0f ); - DrawImage( TEX_INSTR, 0.32f, 0.68f, 0.65f, 0.85f ); - - // Swap buffers - glfwSwapBuffers(); - - // Check for keys - if( glfwGetKey( 'Q' ) || !glfwGetWindowParam( GLFW_OPENED ) ) - { - option = MENU_QUIT; - } - else if( glfwGetKey( GLFW_KEY_F1 ) ) - { - option = MENU_PLAY; - } - else - { - option = MENU_NONE; - } - - // To avoid horrible busy waiting, sleep for at least 20 ms - glfwSleep( 0.02 ); - } - while( option == MENU_NONE ); - - // Disable sticky keys - glfwDisable( GLFW_STICKY_KEYS ); - - return option; -} - - -//======================================================================== -// NewGame() - Initialize a new game -//======================================================================== - -void NewGame( void ) -{ - // Frame information - starttime = thistime = glfwGetTime(); - - // Camera information - camerapos = CAMERA_DEFAULT; - - // Player 1 information - player1.ypos = 0.0; - player1.yspeed = 0.0; - - // Player 2 information - player2.ypos = 0.0; - player2.yspeed = 0.0; - - // Ball information - ball.xpos = -1.0 + PLAYER_XSIZE; - ball.ypos = player1.ypos; - ball.xspeed = 1.0; - ball.yspeed = 1.0; -} - - -//======================================================================== -// PlayerControl() - Player control -//======================================================================== - -void PlayerControl( void ) -{ - float joy1pos[ 2 ], joy2pos[ 2 ]; - - // Get joystick X & Y axis positions - glfwGetJoystickPos( GLFW_JOYSTICK_1, joy1pos, 2 ); - glfwGetJoystickPos( GLFW_JOYSTICK_2, joy2pos, 2 ); - - // Player 1 control - if( glfwGetKey( 'A' ) || joy1pos[ 1 ] > 0.2f ) - { - player1.yspeed += dt * ACCELERATION; - if( player1.yspeed > MAX_SPEED ) - { - player1.yspeed = MAX_SPEED; - } - } - else if( glfwGetKey( 'Z' ) || joy1pos[ 1 ] < -0.2f ) - { - player1.yspeed -= dt * ACCELERATION; - if( player1.yspeed < -MAX_SPEED ) - { - player1.yspeed = -MAX_SPEED; - } - } - else - { - player1.yspeed /= exp( DECELERATION * dt ); - } - - // Player 2 control - if( glfwGetKey( 'K' ) || joy2pos[ 1 ] > 0.2f ) - { - player2.yspeed += dt * ACCELERATION; - if( player2.yspeed > MAX_SPEED ) - { - player2.yspeed = MAX_SPEED; - } - } - else if( glfwGetKey( 'M' ) || joy2pos[ 1 ] < -0.2f ) - { - player2.yspeed -= dt * ACCELERATION; - if( player2.yspeed < -MAX_SPEED ) - { - player2.yspeed = -MAX_SPEED; - } - } - else - { - player2.yspeed /= exp( DECELERATION * dt ); - } - - // Update player 1 position - player1.ypos += dt * player1.yspeed; - if( player1.ypos > 1.0 - PLAYER_YSIZE ) - { - player1.ypos = 1.0 - PLAYER_YSIZE; - player1.yspeed = 0.0; - } - else if( player1.ypos < -1.0 + PLAYER_YSIZE ) - { - player1.ypos = -1.0 + PLAYER_YSIZE; - player1.yspeed = 0.0; - } - - // Update player 2 position - player2.ypos += dt * player2.yspeed; - if( player2.ypos > 1.0 - PLAYER_YSIZE ) - { - player2.ypos = 1.0 - PLAYER_YSIZE; - player2.yspeed = 0.0; - } - else if( player2.ypos < -1.0 + PLAYER_YSIZE ) - { - player2.ypos = -1.0 + PLAYER_YSIZE; - player2.yspeed = 0.0; - } -} - - -//======================================================================== -// BallControl() - Ball control -//======================================================================== - -int BallControl( void ) -{ - int event; - double ballspeed; - - // Calculate new ball speed - ballspeed = BALL_SPEED * (1.0 + 0.02*(thistime-starttime)); - ball.xspeed = ball.xspeed > 0 ? ballspeed : -ballspeed; - ball.yspeed = ball.yspeed > 0 ? ballspeed : -ballspeed; - ball.yspeed *= 0.74321; - - // Update ball position - ball.xpos += dt * ball.xspeed; - ball.ypos += dt * ball.yspeed; - - // Did the ball hit a top/bottom wall? - if( ball.ypos >= 1.0 ) - { - ball.ypos = 2.0 - ball.ypos; - ball.yspeed = -ball.yspeed; - } - else if( ball.ypos <= -1.0 ) - { - ball.ypos = -2.0 - ball.ypos; - ball.yspeed = -ball.yspeed; - } - - // Did the ball hit/miss a player? - event = NOBODY_WINS; - - // Is the ball entering the player 1 goal? - if( ball.xpos < -1.0 + PLAYER_XSIZE ) - { - // Did player 1 catch the ball? - if( ball.ypos > (player1.ypos-PLAYER_YSIZE) && - ball.ypos < (player1.ypos+PLAYER_YSIZE) ) - { - ball.xpos = -2.0 + 2.0*PLAYER_XSIZE - ball.xpos; - ball.xspeed = -ball.xspeed; - } - else - { - event = PLAYER2_WINS; - } - } - - // Is the ball entering the player 2 goal? - if( ball.xpos > 1.0 - PLAYER_XSIZE ) - { - // Did player 2 catch the ball? - if( ball.ypos > (player2.ypos-PLAYER_YSIZE) && - ball.ypos < (player2.ypos+PLAYER_YSIZE) ) - { - ball.xpos = 2.0 - 2.0*PLAYER_XSIZE - ball.xpos; - ball.xspeed = -ball.xspeed; - } - else - { - event = PLAYER1_WINS; - } - } - - return event; -} - - -//======================================================================== -// DrawBox() - Draw a 3D box -//======================================================================== - -#define TEX_SCALE 4.0f - - -void DrawBox( float x1, float y1, float z1, float x2, float y2, float z2 ) -{ - // Draw six sides of a cube - glBegin( GL_QUADS ); - // Side 1 (down) - glNormal3f( 0.0f, 0.0f, -1.0f ); - glTexCoord2f( 0.0f, 0.0f ); - glVertex3f( x1,y2,z1 ); - glTexCoord2f( TEX_SCALE, 0.0f ); - glVertex3f( x2,y2,z1 ); - glTexCoord2f( TEX_SCALE, TEX_SCALE ); - glVertex3f( x2,y1,z1 ); - glTexCoord2f( 0.0f, TEX_SCALE ); - glVertex3f( x1,y1,z1 ); - // Side 2 (up) - glNormal3f( 0.0f, 0.0f, 1.0f ); - glTexCoord2f( 0.0f, 0.0f ); - glVertex3f( x1,y1,z2 ); - glTexCoord2f( TEX_SCALE, 0.0f ); - glVertex3f( x2,y1,z2 ); - glTexCoord2f( TEX_SCALE, TEX_SCALE ); - glVertex3f( x2,y2,z2 ); - glTexCoord2f( 0.0f, TEX_SCALE ); - glVertex3f( x1,y2,z2 ); - // Side 3 (backward) - glNormal3f( 0.0f, -1.0f, 0.0f ); - glTexCoord2f( 0.0f, 0.0f ); - glVertex3f( x1,y1,z1 ); - glTexCoord2f( TEX_SCALE, 0.0f ); - glVertex3f( x2,y1,z1 ); - glTexCoord2f( TEX_SCALE, TEX_SCALE ); - glVertex3f( x2,y1,z2 ); - glTexCoord2f( 0.0f, TEX_SCALE ); - glVertex3f( x1,y1,z2 ); - // Side 4 (forward) - glNormal3f( 0.0f, 1.0f, 0.0f ); - glTexCoord2f( 0.0f, 0.0f ); - glVertex3f( x1,y2,z2 ); - glTexCoord2f( TEX_SCALE, 0.0f ); - glVertex3f( x2,y2,z2 ); - glTexCoord2f( TEX_SCALE, TEX_SCALE ); - glVertex3f( x2,y2,z1 ); - glTexCoord2f( 0.0f, TEX_SCALE ); - glVertex3f( x1,y2,z1 ); - // Side 5 (left) - glNormal3f( -1.0f, 0.0f, 0.0f ); - glTexCoord2f( 0.0f, 0.0f ); - glVertex3f( x1,y1,z2 ); - glTexCoord2f( TEX_SCALE, 0.0f ); - glVertex3f( x1,y2,z2 ); - glTexCoord2f( TEX_SCALE, TEX_SCALE ); - glVertex3f( x1,y2,z1 ); - glTexCoord2f( 0.0f, TEX_SCALE ); - glVertex3f( x1,y1,z1 ); - // Side 6 (right) - glNormal3f( 1.0f, 0.0f, 0.0f ); - glTexCoord2f( 0.0f, 0.0f ); - glVertex3f( x2,y1,z1 ); - glTexCoord2f( TEX_SCALE, 0.0f ); - glVertex3f( x2,y2,z1 ); - glTexCoord2f( TEX_SCALE, TEX_SCALE ); - glVertex3f( x2,y2,z2 ); - glTexCoord2f( 0.0f, TEX_SCALE ); - glVertex3f( x2,y1,z2 ); - glEnd(); -} - - -//======================================================================== -// UpdateDisplay() - Draw graphics (all game related OpenGL stuff goes -// here) -//======================================================================== - -void UpdateDisplay( void ) -{ - // Get window size - glfwGetWindowSize( &width, &height ); - - // Set viewport - glViewport( 0, 0, width, height ); - - // Clear display - glClearColor( 0.02f, 0.02f, 0.02f, 0.0f ); - glClearDepth( 1.0f ); - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - - // Setup projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - gluPerspective( - 55.0f, // Angle of view - (GLfloat)width/(GLfloat)height, // Aspect - 1.0f, // Near Z - 100.0f // Far Z - ); - - // Setup modelview matrix - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - switch( camerapos ) - { - default: - case CAMERA_CLASSIC: - gluLookAt( - 0.0f, 0.0f, 2.5f, - 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f - ); - break; - case CAMERA_ABOVE: - gluLookAt( - 0.0f, 0.0f, 2.5f, - (float)ball.xpos, (float)ball.ypos, 0.0f, - 0.0f, 1.0f, 0.0f - ); - break; - case CAMERA_SPECTATOR: - gluLookAt( - 0.0f, -2.0, 1.2f, - (float)ball.xpos, (float)ball.ypos, 0.0f, - 0.0f, 0.0f, 1.0f - ); - break; - } - - // Enable depth testing - glEnable( GL_DEPTH_TEST ); - glDepthFunc( GL_LEQUAL ); - - // Enable lighting - glEnable( GL_LIGHTING ); - glLightModelfv( GL_LIGHT_MODEL_AMBIENT, env_ambient ); - glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE ); - glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE ); - glLightfv( GL_LIGHT1, GL_POSITION, light1_position ); - glLightfv( GL_LIGHT1, GL_DIFFUSE, light1_diffuse ); - glLightfv( GL_LIGHT1, GL_AMBIENT, light1_ambient ); - glEnable( GL_LIGHT1 ); - - // Front face is counter-clock-wise - glFrontFace( GL_CCW ); - - // Enable face culling (not necessary, but speeds up rendering) - glCullFace( GL_BACK ); - glEnable( GL_CULL_FACE ); - - // Draw Player 1 - glMaterialfv( GL_FRONT, GL_DIFFUSE, player1_diffuse ); - glMaterialfv( GL_FRONT, GL_AMBIENT, player1_ambient ); - DrawBox( -1.f, (GLfloat)player1.ypos-PLAYER_YSIZE, 0.f, - -1.f+PLAYER_XSIZE, (GLfloat)player1.ypos+PLAYER_YSIZE, 0.1f ); - - // Draw Player 2 - glMaterialfv( GL_FRONT, GL_DIFFUSE, player2_diffuse ); - glMaterialfv( GL_FRONT, GL_AMBIENT, player2_ambient ); - DrawBox( 1.f-PLAYER_XSIZE, (GLfloat)player2.ypos-PLAYER_YSIZE, 0.f, - 1.f, (GLfloat)player2.ypos+PLAYER_YSIZE, 0.1f ); - - // Draw Ball - glMaterialfv( GL_FRONT, GL_DIFFUSE, ball_diffuse ); - glMaterialfv( GL_FRONT, GL_AMBIENT, ball_ambient ); - DrawBox( (GLfloat)ball.xpos-BALL_SIZE, (GLfloat)ball.ypos-BALL_SIZE, 0.f, - (GLfloat)ball.xpos+BALL_SIZE, (GLfloat)ball.ypos+BALL_SIZE, BALL_SIZE*2 ); - - // Top game field border - glMaterialfv( GL_FRONT, GL_DIFFUSE, border_diffuse ); - glMaterialfv( GL_FRONT, GL_AMBIENT, border_ambient ); - DrawBox( -1.1f, 1.0f, 0.0f, 1.1f, 1.1f, 0.1f ); - // Bottom game field border - glColor3f( 0.0f, 0.0f, 0.7f ); - DrawBox( -1.1f, -1.1f, 0.0f, 1.1f, -1.0f, 0.1f ); - // Left game field border - DrawBox( -1.1f, -1.0f, 0.0f, -1.0f, 1.0f, 0.1f ); - // Left game field border - DrawBox( 1.0f, -1.0f, 0.0f, 1.1f, 1.0f, 0.1f ); - - // Enable texturing - glEnable( GL_TEXTURE_2D ); - glBindTexture( GL_TEXTURE_2D, tex_id[ TEX_FIELD ] ); - - // Game field floor - glMaterialfv( GL_FRONT, GL_DIFFUSE, floor_diffuse ); - glMaterialfv( GL_FRONT, GL_AMBIENT, floor_ambient ); - DrawBox( -1.01f, -1.01f, -0.01f, 1.01f, 1.01f, 0.0f ); - - // Disable texturing - glDisable( GL_TEXTURE_2D ); - - // Disable face culling - glDisable( GL_CULL_FACE ); - - // Disable lighting - glDisable( GL_LIGHTING ); - - // Disable depth testing - glDisable( GL_DEPTH_TEST ); -} - - -//======================================================================== -// GameOver() -//======================================================================== - -void GameOver( void ) -{ - // Enable sticky keys - glfwEnable( GLFW_STICKY_KEYS ); - - // Until the user presses ESC or SPACE - while( !glfwGetKey( GLFW_KEY_ESC ) && !glfwGetKey( ' ' ) && - glfwGetWindowParam( GLFW_OPENED ) ) - { - // Draw display - UpdateDisplay(); - - // Setup projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f ); - - // Setup modelview matrix - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - - // Enable blending - glEnable( GL_BLEND ); - - // Dim background - glBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA ); - glColor4f( 0.3f, 0.3f, 0.3f, 0.3f ); - glBegin( GL_QUADS ); - glVertex2f( 0.0f, 0.0f ); - glVertex2f( 1.0f, 0.0f ); - glVertex2f( 1.0f, 1.0f ); - glVertex2f( 0.0f, 1.0f ); - glEnd(); - - // Display winner text - glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_COLOR ); - if( winner == PLAYER1 ) - { - glColor4f( 1.0f, 0.5f, 0.5f, 1.0f ); - DrawImage( TEX_WINNER1, 0.35f, 0.65f, 0.46f, 0.54f ); - } - else if( winner == PLAYER2 ) - { - glColor4f( 0.5f, 1.0f, 0.5f, 1.0f ); - DrawImage( TEX_WINNER2, 0.35f, 0.65f, 0.46f, 0.54f ); - } - - // Disable blending - glDisable( GL_BLEND ); - - // Swap buffers - glfwSwapBuffers(); - } - - // Disable sticky keys - glfwDisable( GLFW_STICKY_KEYS ); -} - - -//======================================================================== -// GameLoop() - Game loop -//======================================================================== - -int playing, event; - -void iteration(){ - // Frame timer - oldtime = thistime; - thistime = glfwGetTime(); - dt = thistime - oldtime; - - // Get user input and update player positions - PlayerControl(); - - // Move the ball, and check if a player hits/misses the ball - event = BallControl(); - - // Did we have a winner? - switch( event ) - { - case PLAYER1_WINS: - winner = PLAYER1; - playing = GL_FALSE; - break; - case PLAYER2_WINS: - winner = PLAYER2; - playing = GL_FALSE; - break; - default: - break; - } - - // Did the user press ESC? - if( glfwGetKey( GLFW_KEY_ESC ) ) - { - playing = GL_FALSE; - } - - // Did the user change camera view? - if( glfwGetKey( '1' ) ) - { - camerapos = CAMERA_CLASSIC; - } - else if( glfwGetKey( '2' ) ) - { - camerapos = CAMERA_ABOVE; - } - else if( glfwGetKey( '3' ) ) - { - camerapos = CAMERA_SPECTATOR; - } - - // Draw display - UpdateDisplay(); - - // Swap buffers - glfwSwapBuffers(); -} - -void GameLoop( void ) -{ - int menuoption; - - // Initialize a new game - NewGame(); - - // Enable sticky keys - glfwEnable( GLFW_STICKY_KEYS ); - - // Loop until the game ends - playing = GL_TRUE; - - menuoption = GameMenu(); - - // If the user wants to play, let him... - if( menuoption != MENU_PLAY) - playing = GL_FALSE; - -#ifdef EMSCRIPTEN - emscripten_set_main_loop (iteration, 0, 1); -#else - // Main loop - while( playing && glfwGetWindowParam( GLFW_OPENED ) ) - { - iteration(); - } -#endif - - // Disable sticky keys - glfwDisable( GLFW_STICKY_KEYS ); - - // Show winner - GameOver(); -} - - -//======================================================================== -// main() - Program entry point -//======================================================================== - -int main( void ) -{ - - // Initialize GLFW - if( !glfwInit() ) - { - fprintf( stderr, "Failed to initialize GLFW\n" ); - exit( EXIT_FAILURE ); - } - - // Open OpenGL window - if( !glfwOpenWindow( WIDTH, HEIGHT, 0,0,0,0, 16,0, GLFW_FULLSCREEN ) ) - { - fprintf( stderr, "Failed to open GLFW window\n" ); - glfwTerminate(); - exit( EXIT_FAILURE ); - } - - glfwSwapInterval( 1 ); - - // Load all textures - if( !LoadTextures() ) - { - glfwTerminate(); - exit( EXIT_FAILURE ); - } - - GameLoop(); - - // Unload all textures - if( glfwGetWindowParam( GLFW_OPENED ) ) - { - glDeleteTextures( NUM_TEXTURES, tex_id ); - } - - // Terminate GLFW - glfwTerminate(); - - exit( EXIT_SUCCESS ); -} - diff --git a/tests/glfw/pong3d_field.tga b/tests/glfw/pong3d_field.tga deleted file mode 100644 index cc20bbdb82434faa3bbc01d27fd199d5214c8b2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17816 zcmX|}e{dV;dFN%NMs0SHI?kkP%2AbGdCn*k0V?F{xhdB=r)t{su}NjqHbo+iD6^KR zvTiF8>zcy>XAvHxn34|yB_~ak&?{qiY6r*cVu%X?wHYn1v^cp+T<(I>0%TW_F6ytp z?q>Su&E!50l)L2*QzWqO^FHtMXV0F z9-Myn@}bu!Ca0#eua8Z>J^S>R4viIN2Zyug>}vLni7|b0;EjnxuVxQDKQR0DxpVJc zoGeUFyfHbJpZxr@{e!QM4Iay8U!TmrF+ISo$`|{;JaE~rPUw>py!d;UXNwo7-<}=d z?Jo>W7S8p{&Ckv9vM(OW=FiQ3?{fClv9UKM2Kjt_^64-1XIbv`vFZHm*z045ULKpA zIyX2xaj~{Erq52~C!c=y(BQF&vDYUDULLz#Tbj^kFMjXxz^fDeUm6^IV>+wP4!l13 z`7iX(BIMf_FWS{ZU(U|HbNSr6mFdFl#Hrb_H>RiGzBus0;B?{KMB&__;lauLboS)f zL}7aH)ok|E#Msp2p<@$=zC1Ad&bf(GlY=M628IVGrX~lDW&58$bgq1H?9{{{pC>1? z{PN`3(_b8@EG~WiH~S~wIrsGQ1BZ@{o%{CX$>Qu-el~k-EPHaY|AoPGSE|$RoICVF zcC5&*2WPKT#!gO5(^0^PI*;CV( zKdep`k#lS^e{S$q#G4%$9-H9%v5EfY2M140XZiW$3=C%{rltpujrBi2aISoL49$!3+1>QO$%)VZ=ArD#>8CN6W0PYir!RiEGj-UPOj-NfZ<7Yc|{LI<$*ufqD`&V{6j)k8o{KCqP>Ob%JKX2}M^Iv!D z_~DKn|Fq+iZ|>MJaQV@P{@2GIdHgY6vul?%7baIT$&=Y+GE9Y*6~?Q!ZC_|{*yH6mTiZM zWfhZ_r8{n^;X1w_nYw8@?#00Ib+-}(nt=?ic8woPLCG{~`b@Q6h&5hn#i6fQBbLQ` z6g`g+o`(>M7sg7cgx1KN@J=TD)<<8pFW6ygt<_3q;!r_4FScXLw&z=QB=9Uf@-55P z^OoiY4OY~A$I)EPbUd$M2JIl|bu`m(O)hx_Uw(CYCgpP}itjsoA&l>PzMt2sOca~;!cyUFvXXJX&+70>cjGvY8(RvcTN?bscO6%HDG6%k@V;vNB8dC%S^VyFxlF;a^*-o z8Yz+Qx_+{Vs^o3l7OB||`|vDOsQ7ZqvK91Wasoj)Fnz0Fc?hBV7WT$b#OtTmJN06o z*Tsm9K12%6Le05>>o}1TwobMd7qe;gz{kJ!@m6aUCrGZHUcS;%lo2KAY^gX!C=!I- zGerw24v14?BiIG2N4n?h=t4sgF7}bP@;=UDB8n%Xd7brYb-f;=8;`?KIEXzlhM>Bx z<2vX+Oj;wY#kEX&H2tl6C+#qed$bnMzjb;o8Cyx;Rh48{1TV#|x!8o|r}(fG4|zP@ zk+Vk!PL7|@goZrw8~$Z#2`go~zE^)3Av%~B>-v6NXGgxD;03%YLJcRvlZ%T<(&NN2PiCD%H8 z&;vfA4zYW*Fr+BF0A-qNIxs{7m}nF@@w{JloxlxB>|HYn5d_j85YrHir1m7y2Ua1z z<)AcuX)BLJOutuu~#+G@U(i_DD8! zXJsY))W(sP6{%6=_z~}qvz_SWh0#{`D3IZ}ycaEUu&<#7)S$B*YG*^Zp;miSn_t&8 zU&|4yUBf7Nx`~bqQ;)rZmNR*2&aZdkJm%uKTI8xu#9C@Po%z&}Ph~TickhImBWGu_ zR+`^#x$c(gCzDFM*&vt1Z2Yy>9;8U_;aFaKEh&e|@pA^I$A3sZzSFq04LpM#Ec9 z+*#{%s>{otSUyv&$1HA|1Xxxz*($e^U_hE6U^kjePSNL=Zm>^uWaRjn|B%}`lv<6z zar@i9`ghAS1Wb~rFKL6o5N5Ki?1+evyqnDmG+1ldNpgcef?HUTJLbe}y)(1^%KF25 zyhJWY7af39=bbjYaYxFuUnt{quJ22%0don52K2oTCrR>II0 zZIG1l1x4LC<@yPf$Sw7JuVHW_?%MsvscT}2Dmh2OqV6m-%OoVztyFqS2*Im($IsvJ zOiSE&RQj-P`8Oqsm7R4G@q!}ImJ;2)&s9X@bU ziIT~*nnvNeGwKtC!6YkujgTn>BnVdN+ujU(H(>WBiy9^O8oM!YJib6*^K}pj02Lsl zdydvva`oGmY3w63gC~R1KEbpYM9Cb4Xf|o|aPp6LqzK1mN7bcE6T4 zD{PCi;FEim#OL`D&h-vVREWl?NkAz-hd)qa;(ER@kfranWazUWqwvmA4$t#*U zt^@J4g|;inL$oEj`nfflW~pZ?sLvClz;BXnETXXLD~J#$t*wS?TY5;W46XEv0DEf$ z8EljwHtRR9wtYj+7CFd2;$bXcmdb&SZQ)_4)uBefFCABJ)B;mSJl?_Ci7j&V7IdRh zGoCxjD}ig>Z0S1*WbYom{1R`D#w~ksG3=H-{Gn?Jis^^37u?_UjGjuV!o~;+To^?V zRBC0vNX{nCI-`#2I~vO1v)mwd^Px$Qq~(?1CZsFCdZ(v33U`WDaXRebLzln+g_cs?Zve)0!s**AV-7OP=~p_ z=^8nSN*pidWp;0>RT{lX$-MGfKBR8+$0OZoH+0SopFmOqsiEb%Vg&B(>Us?9mA#J& zq7#c$rOuSH%Kq-gn*tDz++Pa znG_uviZQp+vCBr;_e?3TBtDC}I6O{-b9k!bb&I+#{2Sr|%L9YJ<6&$+I(c{8np>4x zhN4y>S94-wj%=@PwI8dQ*YPk@JY0MOTQ6vVL&e7#5Sc^?RK=E+)+4J?c49rKRj6%x zv4t**GPIzlxB8tr^+*aAP=-cF6I~d}q2SECJ+vQs_xFBxj_N(^=Bg0_Xt!!eg<;B0 z1)DX$fCQpdISt9hKs2H)1&t%F97{Ce606eML0mKgA~b=4YO_Lc#58Z1>(!Xb2UANa zqv{jtaet`(3K7B~*Ag67=kAP;V~{Hfo|!x@i~zM;S4mc~;5J_@h((DMTw)R!gg3w5 z@hG?niy=mf0FfTrm{Nn3OtoDq$>E78qPohIzy6*_5yMS!bnxqMANSXmXJQNBN3gP5 znQ$DA!x{(IORduC;1A#g@!;5ZH=DjeniMf`Lhh&;P93SD%v}I8m2Y~;~o_CzM?+45br(p z{a=q$L+E5Q(YL$lS~_*x8fB5y&CWFNh&7k z{d%{i$;WxOzWi`1w(_`IOl`G(d!FQ1{QffKCRLsiSG7+Yd28=0wkIO^k+bzvL=ZZI*g4i-YA(1(PcMIM`7N%h)oyF0 zQt(XWn$g?a%faIH2N(Q}(=9=In8E{Fu+rm@Vitu8^_vf@Fs_>hYA68Yg21ic`bu1{ zch);d4gS`#=vuITYkiNRr$|wBw!qM-6j<(X%$ z8PAp~&m62gQ>xUWnW}Art^ojGJP}0@7Z&X_0@D+(1Tl~@F-$k8^t9s-m#b&0XDG6X z(WaZH3Tao8x2ko8dYfqFG}xb`gU64je0OKFErNuzB(Tz#)YyaVo1aiaxN zUAeG#x#Q)ABfg@537bQeFfmT5Kk|eK5);7IfjfD$jh~b=R=0KvtaZr&4!W}*W_HX-tbm@lZ)-1!Qwc;?T zko%mzT65L?M1HUW1rpL{n+;B?tku)t4j-kN^~zk%~jf) z+mGx%=8PbM9q+Ovq3FH65MTk>O49{v-j_B@2=(iLW($;%e6N@ z`^Y25B1_Z&7w1%_YPH(bW^=0fe*gWeyQdmvp-yb4tf0)sMTps02^JFAkKgi>9lsMs z>fyscSQ1%`2wI+^%-9F533kpE2kQorATgB74JC%3P!sO(lg-`RSKq(7*}!l7T;LjR zPwkKTAKB@T5EdM_Tx$+&PEBntUD{mQexHNuzrXF)3$8)hLGSx!e=&?O%E1NeA|%(OzKpwQ{4))oAnuTkY-pKiFo+W}^pN_OF|{eE>m%hUvM( zXCA-xTD+!^VkItcSQJiuE*TNL8thA$*RKab{lme6p%JJOxdb8%K|Cg09Cv54*@F_O zw};7F?cw3w{r7LGs@8Y2R<5+mluNj30(_{t?WND&$2DAvI>9?QNw6;{v)(_`X1>o=L;pntdt)d@U{3|1#-8V1R{8)XUH z?O^%wc#o2HtYS`D>DbNz$#-lI zejP1S2?w~TcUuJ4%y~}2XALZ9m?Nht=5AS38y3wg5GF^#U+E24ihHw9wUV@Rpo@yo z{wQH6k?@Dw+gEGAf3~I*u?te`pa!f_L2@g2;D2N5`^@2gb(xJa~bIS)yg;u-@lt2m6q43qd=JwRW z(&p6W=H^tz@Yq?o5rAyiuoBhFA^YV_aaoHkDOM%@!~+ue^2;)v@l#7 zCUAkWU`~awqJ`Gw{G`#u1wnGN&&kZpTmTwL8;bQU2_t=t-3vHzd#bs4b>eC>DBNa4 zq6J``M&YHF&f46DOQn#P8*x9)yg$$w@&9MMlQWL*Muxzff2Fnnbs_ixu==&?w*mzJULn(gx5 zAHVRN2L}e5j0DndqSe4hNfcagEuyvC2+Fv5^J@S7&5G0{CN0B&*wF6%`#<tEBfu1e}&Xz;xB#gAE_0svL;00Fg*2c$XKlZWDAjVvJ<>ba^u3R}gvu4}k z6%S4mIGJ5xUtx3-Oa2ne)=1~^jrV*vG2B4?}V#IHqM@{uC+QznqjmH ziFkBRA^3^fmY9SXh}Pbmm^f6{y>^AP;A;cgVRl^+6D4=(olenC-o`X@@RMH5QiMal ze*V@OsWnjmCDbY$z}6O$WiSW2&a0DW{{k8Au0pNf%`UDXnGlD-HfToaNeT-@1+37H z;0IsRwA!Wnmzwjo(1)&humse?{tSScHXIZ?#oKXApO|9-oC~KIx{cA!^5rvCDv=D1 zpA4a5qETrmgqaLI=aoD6RzLkqvy&G@h71J1ot0Y4gN!BQb&06R9~bAr->`elEl*7~ zFI}xI&$q3js~;>isC7CPO&d+p&KwnLcD0KOh z^ysLP9yxI$ed6xM-8++i`LT@)cQbI<2$7Md0!5Cr3PcDe8i$050NlvK7qGH?W9jPu zXmsX@f@T9UfJEa;U`B?(DvBwHQ%6+R60<_osaiw_X;)-dGi0`uB77|$BX>sbM0cP6 z?&RcmpMPo5#xrPd@(Nx<=eURr1m5m3AOiFtR-vh&TAY3A($yV7RS)9*UD7g#7T^wC zPQ>dZF=Q@BAHwj& zojaM#$%jtdYkV{}b0M6wL!rHpK#8Q@o?`~%3-vG9yDYeS$^KXc5TsFZ@oPnow2Oh} zaN?|JnhETbtYUy52%&*_US=>@QrJ;wF?v6uLk3fDv~JT^p=e0bYCo}ZC-czCy{?W~^qJ_Ee!pz1InS6o0q(a4c z#DADk;Uv20hh`lr=YsQ0L&(tOl|Tg&>E>=cK-xNvsfc3i>hkG2&GZun|EsjU*jmkGCck_BNODCw&uSE6mbAY`4Aj6WV073PD1f~Y zo^TFK!(_yUZl+dp0Y8F`QAVCZ5jnh>{muGkb!!JJOR%2txPNP=%b4= z5_I4|I7zfvwHD95b$*d>Mroq@8Hr=!LyRf03@mL*@C6^Z7)mG-|Wzs@teMX`o?@c@Gi5Pd`<;f{)5vw#7a35H$`}r<+I8j*P@YeM zRsHT{3%2OP9;29UuXXX!jl1EU6H#=+URqDoF95^75F6s6(t>+C;c=}xpB zJ$v>pAmP9tpJ;LNX`*%V$oXH~n4#^N9obUp{3At%UYB?mayZB#vWPzP$Rs8^f?G^y zzaC3WU@#~_kASF{(2#_GBe4fh*r}87%oMzo3}MLUgDjQKoW1gy#XISH2V^9LsTdWV zXIdLGi>~ggmOCq+=^0f~3i_pZN^-NPmyGoDI_-Wkw=e@o1!#T}wu)vbc6+v9p*Q z@nn8Q=5P=M&$a<10?r6Rs)6ZSy%&GSt8?BApumPv{~$y{(iWIjUP%NaDn1PFO|K{c zPoHo`nXf?vAkx{hjKQQop3WTESR`e1EhGsen_O$9$JCLSfsXtb+_#f`I* z#D~mCm_57E8uX|w(M=5eiWKpBhdzrh75}+1OW==4Jv9U;_)!Axn zX_VMuR=K%T&8)34Jh+HCF%G~9>}g?Ghyz=|0+<~>;S;&F@^&o&Htnw7#dh64(@-!F z!vMzQT<;SYLWVtT<@oTjqt*mXuhK`B}| zLnI^&&{P60J_>GKyukdPG`ehm%Uy7REkz-~*WZhK-4ZSMuC5{J_tEsNxZ)7UJya{h z2e5v0-Qj-SUdbHYK|(nR;m8Vf-R$+-ejIvCK^_iUlZ%s!Ya3^?pIZA=as>8wL_}C+ z@*%U@T9oM!L05Ezn>Qdl;U-J8s!VC0O9Q@Fx&%fJxQGPQ*F%opyI+sWZ?=6fBgAa2 z2J=W+2ky)}Mt3NL*;dW0&&LRcA;LqnF09S87LT0m5CEk24U|28mr!UkHOcxi6O)M< zjxZNC%O<3bFdD#gs0FAtQ+|X_l7lb_*+Yw-T%;T z1gJALrje0KTA3=N5aci4pFt?Z< zQ7h+k4~iDCYZy%SR&=Z|&fBrCQiim*REFVX0Akc_M1o}019BSRSym2LEUVkGq5WXB zCoZ{kR*|5r3_Nh$?6)r*#S(OnQVK%Mad6hQQLc|FodeG}Z~7>YEv ztOR(a&sB$%k(A7Xx(h*U>x!d-lq4uJ2SR~?7MOsL!CAk#U51&EULj}SwTo*H=q~=L zBLSID21!XFj^>wTBFA(~m?T<42rb}^=qsq*D0QmEJSl>EI;@)*6?lC-_7&&JGF@d$ zL~tUsKz9gX0G3qNAidacT-}7DK>czn;qXeh0a}oWKq++~Q-DtUjQwwIJrqOqfK9Z3&U5tToPOFpc09NSJ5DJ&J zrGCRFWSYQ0!`C#E4m|$JIe5}ACV5ag>*FNEpa}ybOg(RK3EoKE%@PLV-Fu3$nWK$4 zLTQ(9hDL|bg9O?rDD!5ZqU1=M`BdrNGWftqf=wTl%-GykSrX<~JX2^#?&}f}DuG_4 zN5E~^mE!=OG|GHhQIe!l1aHZa3=pFb7aY^T7(FF{2r0%7=$**>xR`k+;z|$Tqj8J5 zF?zN>g^Z6&NSy&a5yp+}hQlpO@*&HcG#mLZVYt9C&>d#7hbnKJn*dZAP(V32CcJ=t zE8hv(oKempC`bz_K{?IjgE=~+&=hb4h*97aY5GIFFhU?BYK}S@aYo0*5WtLa%e}M{ zHHaR9fQTpqE-2S5*EDuVF2JZ1cEW6sLns&yd}cJ67L=|#8uLYHor?SD`npF#Q%C(# zh9%Vms$j5;Vwb)-!}Js@U2lZ_uwefkxh>E{=2Al2e{;#@cIbdl1{x$iu|T^55YoZ= z%vUSA1N+8lm>R<{%mr4;8hit6JUvDUlJwI$)iu1ASPGy(4u4dlssm9;1!-aZ{AaEx z>{12Im zBtmC~b3h9O!}YI#+EPQuM~*8)U4sy|U&b$_)MThT+Aq@!97SlyQjHNdKq%l`o`A63 zCCNr8Rm9+&i4n4P0fJfZoP~3frljEFw?PdJ(PG_6VB;4*IBBi*2 zrBm^ytvN`vHvGozT!prKLC^E@QiV5_r`+myUh}z9ipN9}8*JIt^Hm!)P*M>IGt6)Z zn<7Ws9oJ+mhx`!%DUT|L z>(>dlTeL1JP1EFKcp%&ca?apTJ^0@e~lWtYlb}K5w0-9unUi5vYC5QMiQ7t zMllGIR`kn#be6c~b1i({?e5-ppDouWbUqAVfQ%@X*iqlZ6B8;w|1c;Cqj3u z{*?}E52dI9xc3?w(A>BFZmlzy#0S#R$cnOJLu5e1sQ&0E$J=@9txm{D$bqyHXVjP9 zbRZE7*1zswr%hJraooV#I1f)u&B>5!YnT3$E-^!)=WJ=D2|Tz2tPuaL7`=4a>&vgj zv4HJtXKk(e$&FWRzioed`8>EJlcbR0)4p&Rv=QMeqg%h+Zr%E|y}#ZGaUQa#`tnUN zEv6YjU8ARTChCA2*HEtIKS63Xw~j39sTig-R4n; z4if{EcgH==YxFJu4Z|#CgAvAbx12e9mp;d6Od{=XE$m)u`>!l7f9En^=hu~XjpkX! z-A9BnQ3tjF6xIv?~V9q=Rlgc3g zNF(c~mJdZ}(OS4L9%zU4(!ts_4OM6u<+Em~PzWf%aHnpPMTUau2THkp`4pqfHfg}Y z7K#>}nvN?fLtA~sw%|I`+qs?_?I7<x)MDgszXwJzOkxctRYU>c#soAy<7M%x zw6*BAIEN|Q5u~< zJ}gC4FENeU8g~-((!C7f3Q4If5H$V0FLax=9BaJ9Q)6bzPRe90!|MbTY%gc@ z7=_wnn~yzq^)W_4e*cZ%@9+QI=k9;doGL>Hdp_*2%zQiXvc20BF`!4d6p_0}2>7qvJD9&xftjZ$Eyjw@R-f=fO!hyw1uppw6x zyHTsXSgYN5u`9{;RkSfNvAxi6(-6v3Ps8ozo7;~xUE#P}R;;_VcJ0RIz~%>6(Omzf z4>k`PL@PN>iQ2pYEQKNh&wR4J_skxm1?>?hD%v_V4y}51xNl1`5`1dGV{D@0J&Y!# z-96my5lMQU+}!TJ-~WT{skTP9fjb(B_SELD+;6G^i)iMRr#3(MVBp4$4=!z9`qBUF z|JyhEH!Hn)bDwl=3W6U5e{k=-U-9r&#bdOGQh(Lf_Ztq-dWd?9!cT@R5rIDU?WYU- z{9F$5hEafEc(~Hjq-Q!YarIKOPg?JiHW(w?e&mst6N3Fbfqf}%7qXyx`N-jmif zl&za!u>`{yE~mfLTza!%3e3+jO%arz{G-oqxBG_2`fj%AXfiy*f_Q`(1huJ4Z%lCS z3PUyj57}dl%niO@gmz#|)()2`0Iz@4XCua(teuv2~4d z6RKb8qz8p5f^dM^;H|nxeqz!Cs!XCQ08NgCiB7s3sZ{>o?bF|6oVt4;v9Q3;^8Ml01VN(mt1#Hf<6nhoAWyY*fSU=q$Be${or`0`*0KT)Il=5;IuS}$QRAGPF?wIBtEHcUrSv`FYQeRbhx zT))lkU9G|?Tx0AHZL#kO@+V$d8paqwDbtkaYwzMBpOB~QQ)Cuio%mK z7qQ*iLW6b^g(*{fa60@Y1uvOs@BXts#&2*)Pp$%TaVM!pOv5w!E`Plmn+?sH17A>! zNKc`AI|8f6JTm9zy!ZVxdq}##C5ccuS)Fs(08?&Sp{0vbg<)_7UIH+8}MbOI?280aJ0sTG;#a3ZEY!0W3|ZOnjv=jK*d zzw|ECI|89Uitb$4_%2WLN$k)bicg)H z_pl{#L)pJ%)8Hae%AxR}G7x-ml(UEdF^rWk55zNS4A6&bSI)0dNwikK`OPo=&0juc z&)KU{xH_}(-KREMJU@t6pkC2}l=FZ<89i_TuZ$^QeZPNGuj>rN1il~C+MPie#jmwl zn*b~{w^GtN#UH$8q{@Y*tr~f?rU=xl81QiGdGd3WK9`w#pOtFD=CNvRjeh)ixd`VhD9?;0ahM=Zhd@ z4w{Sn1bv~J@eD+G(i)0<9vqdYVbYGOhAo;%i+AsQ^P7Kt`Wye@w>~z>qn$ioYA<%= zARz3Hij@(@NLngUwM)I?(L9slE=*nRZ*+=4G#7Jdd)J9ZL~U>a-M!*`$Cjgo!lmUb z!~w$l@?2(Bn21$rtdGD$H2NHcnv;&gx4!keZx8PYmtN~PmEuvP`K)9eA zBBb)dLi_#xVBTXwjHh>ns74s_pcb?P$1Bo;vSBdz|2BZry{_UKR_FBjjhUH6R1Y)C T6XevNs>&3`i95eA{_g(;MdbFK diff --git a/tests/glfw/pong3d_instr.tga b/tests/glfw/pong3d_instr.tga deleted file mode 100644 index 758eb447a97187cef812cb9100aa94631954c256..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21279 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 diff --git a/tests/glfw/pong3d_menu.tga b/tests/glfw/pong3d_menu.tga deleted file mode 100644 index d0d6c5a431687bfd6442e43c3878a9eb905c48b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1835 zcmbVMTawc-5FFd7KrLK{i*bQLe#C)-km6&1*q~+M0-Qi+$_YgGjAbh+zSu1}vefFC z>1kQyjg-Il@=jjMRenoIj~IXChe+&m7gLVsZQ6^Zkej3-2jP$yvZRY#urXlCQ#Jn=lGQ*?msDM%?fom_#3D0WLYd>| zrM8HEH4zdvDSlgLUu?J06w%uHU$F5BH?%^)6{nIMA=d zk04{L6gsNXLvPU$y7bcLR=F~R;{Yz~AoE6761IR~EZy-Sc90#?@jjEKjdZ2xgd?t2 zqtTm)Fw3kYxE=nmQqN{37J-&5_=7y4JqUx5<790bksq4`P6Xm?W2J#gsv94$c80Ep zhB(C(Tcv$%4nwfg>5lD?ncV@L-j6_|Q=WiD2HsmBQ7_k*Bwh}mIAS5_(&Zv)0+JQ*BV=)qzNL$W#l<{{t=av1 zh6fQJ3*Rf(fcY7y8DcVufs`P8r)X65U6x`6n^qTRM5LcL_vtFnz@hK-l+BKK+wK>L@83So!V-2z3xXZm}7`ZB*l$gvAC5tvMEd)H$-L j=(lM?g-Vm}Fwx!OsnJ{IV_$0Jn){}t&ktU$$5s9UqXSX} diff --git a/tests/glfw/pong3d_title.tga b/tests/glfw/pong3d_title.tga deleted file mode 100644 index d0d8e36d74011c25b908647632b4997dc0cf6456..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 106516 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 diff --git a/tests/glfw/pong3d_winner1.tga b/tests/glfw/pong3d_winner1.tga deleted file mode 100644 index f963720c5b897c01b8694a0fb2d76ad617877a7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 861 zcmZvaO-{ow5QV29sw!Ag>q$zL$Sb2xaDZHc?={d~z#x?;&rAh7an>TNM%UG8<_V`T}Av+dQR1Q!U7Qc6{sSH8wNZP39q9qy#b$XF9@I6ez)S<6n zq_ehk;iMZ&fsh(meZGobq4LV7e~pc@d~^GlelDh;wKF}zCi`6*Je6~M>is%9SNEbW LDfk1czN>u!GHiyO diff --git a/tests/glfw/pong3d_winner2.tga b/tests/glfw/pong3d_winner2.tga deleted file mode 100644 index ea8266dea9f6ca7b261f2163b4f2bc4777a59027..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 891 zcmZvbOHRWu5Qe8Asw!Ag>q)E8}th{PDhL`jrJ%{=Jv6BL#k|RH6{>RMJ?8(;O zi#^-HZuV}m>~grW8Ozl^%t9=dzKDzE#2U(`*Z?%X-syv|S(? zK)sHv$a>wtB4Eb?Ma3Y>!sKURS)Tb0r3+%vTaEo6DJm{if#^X&j{?aT=fbk|<~&_O zt+PmDbft=sKHTt?QQd&&`CbHe)uYgASx)wtida}Bc}9?zn%(@SUw-irZBG_CWXznz z=XiOM7P58fg0$VeHnc3XW7$gDg_J8@PnncbAuX(+Ga!3cnA!amNonh?123}NqEvQz zr;kDo0gOh0x+DVBrpbD_p`wQ*Phz^)ltEEbz;t}sX=m;%O{Moj&@6$p=8wfP;J5)? zkhFgfjw0#^%tT0ME$!44Ga|_7pj0Ep>Z9on#mYG5)@84;kMi2DpOfl)jnK+)SAA~d cBD_m`U#oV84}EF9M`aSmW&0a^ddAJZ0j)ZbKmY&$ diff --git a/tests/glfw/splitview.c b/tests/glfw/splitview.c deleted file mode 100644 index bb85a6e7be6f8..0000000000000 --- a/tests/glfw/splitview.c +++ /dev/null @@ -1,525 +0,0 @@ -//======================================================================== -// This is an example program for the GLFW library -// -// The program uses a "split window" view, rendering four views of the -// same scene in one window (e.g. uesful for 3D modelling software). This -// demo uses scissors to separete the four different rendering areas from -// each other. -// -// (If the code seems a little bit strange here and there, it may be -// because I am not a friend of orthogonal projections) -//======================================================================== - -#include -#include -#include -#include - -#ifdef EMSCRIPTEN -#include -#endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - - -//======================================================================== -// Global variables -//======================================================================== - -// Mouse position -static int xpos = 0, ypos = 0; - -// Window size -static int width, height; - -// Active view: 0 = none, 1 = upper left, 2 = upper right, 3 = lower left, -// 4 = lower right -static int active_view = 0; - -// Rotation around each axis -static int rot_x = 0, rot_y = 0, rot_z = 0; - -// Do redraw? -static int do_redraw = 1; - - -//======================================================================== -// Draw a solid torus (use a display list for the model) -//======================================================================== - -#define TORUS_MAJOR 1.5 -#define TORUS_MINOR 0.5 -#define TORUS_MAJOR_RES 32 -#define TORUS_MINOR_RES 32 - -static void drawTorus( void ) -{ - static GLuint torus_list = 0; - int i, j, k; - double s, t, x, y, z, nx, ny, nz, scale, twopi; - - if( !torus_list ) - { - // Start recording displaylist - torus_list = glGenLists( 1 ); - glNewList( torus_list, GL_COMPILE_AND_EXECUTE ); - - // Draw torus - twopi = 2.0 * M_PI; - for( i = 0; i < TORUS_MINOR_RES; i++ ) - { - glBegin( GL_QUAD_STRIP ); - for( j = 0; j <= TORUS_MAJOR_RES; j++ ) - { - for( k = 1; k >= 0; k-- ) - { - s = (i + k) % TORUS_MINOR_RES + 0.5; - t = j % TORUS_MAJOR_RES; - - // Calculate point on surface - x = (TORUS_MAJOR+TORUS_MINOR*cos(s*twopi/TORUS_MINOR_RES))*cos(t*twopi/TORUS_MAJOR_RES); - y = TORUS_MINOR * sin(s * twopi / TORUS_MINOR_RES); - z = (TORUS_MAJOR+TORUS_MINOR*cos(s*twopi/TORUS_MINOR_RES))*sin(t*twopi/TORUS_MAJOR_RES); - - // Calculate surface normal - nx = x - TORUS_MAJOR*cos(t*twopi/TORUS_MAJOR_RES); - ny = y; - nz = z - TORUS_MAJOR*sin(t*twopi/TORUS_MAJOR_RES); - scale = 1.0 / sqrt( nx*nx + ny*ny + nz*nz ); - nx *= scale; - ny *= scale; - nz *= scale; - - glNormal3f( (float)nx, (float)ny, (float)nz ); - glVertex3f( (float)x, (float)y, (float)z ); - } - } - glEnd(); - } - - // Stop recording displaylist - glEndList(); - } - else - { - // Playback displaylist - glCallList( torus_list ); - } -} - - -//======================================================================== -// Draw the scene (a rotating torus) -//======================================================================== - -static void drawScene( void ) -{ - const GLfloat model_diffuse[4] = {1.0f, 0.8f, 0.8f, 1.0f}; - const GLfloat model_specular[4] = {0.6f, 0.6f, 0.6f, 1.0f}; - const GLfloat model_shininess = 20.0f; - - glPushMatrix(); - - // Rotate the object - glRotatef( (GLfloat)rot_x*0.5f, 1.0f, 0.0f, 0.0f ); - glRotatef( (GLfloat)rot_y*0.5f, 0.0f, 1.0f, 0.0f ); - glRotatef( (GLfloat)rot_z*0.5f, 0.0f, 0.0f, 1.0f ); - - // Set model color (used for orthogonal views, lighting disabled) - glColor4fv( model_diffuse ); - - // Set model material (used for perspective view, lighting enabled) - glMaterialfv( GL_FRONT, GL_DIFFUSE, model_diffuse ); - glMaterialfv( GL_FRONT, GL_SPECULAR, model_specular ); - glMaterialf( GL_FRONT, GL_SHININESS, model_shininess ); - - // Draw torus - drawTorus(); - - glPopMatrix(); -} - - -//======================================================================== -// Draw a 2D grid (used for orthogonal views) -//======================================================================== - -static void drawGrid( float scale, int steps ) -{ - int i; - float x, y; - - glPushMatrix(); - - // Set background to some dark bluish grey - glClearColor( 0.05f, 0.05f, 0.2f, 0.0f); - glClear( GL_COLOR_BUFFER_BIT ); - - // Setup modelview matrix (flat XY view) - glLoadIdentity(); - gluLookAt( 0.0, 0.0, 1.0, - 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0 ); - - // We don't want to update the Z-buffer - glDepthMask( GL_FALSE ); - - // Set grid color - glColor3f( 0.0f, 0.5f, 0.5f ); - - glBegin( GL_LINES ); - - // Horizontal lines - x = scale * 0.5f * (float)(steps-1); - y = -scale * 0.5f * (float)(steps-1); - for( i = 0; i < steps; i ++ ) - { - glVertex3f( -x, y, 0.0f ); - glVertex3f( x, y, 0.0f ); - y += scale; - } - - // Vertical lines - x = -scale * 0.5f * (float)(steps-1); - y = scale * 0.5f * (float)(steps-1); - for( i = 0; i < steps; i ++ ) - { - glVertex3f( x, -y, 0.0f ); - glVertex3f( x, y, 0.0f ); - x += scale; - } - - glEnd(); - - // Enable Z-buffer writing again - glDepthMask( GL_TRUE ); - - glPopMatrix(); -} - - -//======================================================================== -// Draw all views -//======================================================================== - -static void drawAllViews( void ) -{ - const GLfloat light_position[4] = {0.0f, 8.0f, 8.0f, 1.0f}; - const GLfloat light_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - const GLfloat light_specular[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - const GLfloat light_ambient[4] = {0.2f, 0.2f, 0.3f, 1.0f}; - double aspect; - - // Calculate aspect of window - if( height > 0 ) - { - aspect = (double)width / (double)height; - } - else - { - aspect = 1.0; - } - - // Clear screen - glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - - // Enable scissor test - glEnable( GL_SCISSOR_TEST ); - - // Enable depth test - glEnable( GL_DEPTH_TEST ); - glDepthFunc( GL_LEQUAL ); - - - // ** ORTHOGONAL VIEWS ** - - // For orthogonal views, use wireframe rendering - glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); - - // Enable line anti-aliasing - glEnable( GL_LINE_SMOOTH ); - glEnable( GL_BLEND ); - glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - - // Setup orthogonal projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - glOrtho( -3.0*aspect, 3.0*aspect, -3.0, 3.0, 1.0, 50.0 ); - - // Upper left view (TOP VIEW) - glViewport( 0, height/2, width/2, height/2 ); - glScissor( 0, height/2, width/2, height/2 ); - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - gluLookAt( 0.0f, 10.0f, 1e-3f, // Eye-position (above) - 0.0f, 0.0f, 0.0f, // View-point - 0.0f, 1.0f, 0.0f ); // Up-vector - drawGrid( 0.5, 12 ); - drawScene(); - - // Lower left view (FRONT VIEW) - glViewport( 0, 0, width/2, height/2 ); - glScissor( 0, 0, width/2, height/2 ); - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - gluLookAt( 0.0f, 0.0f, 10.0f, // Eye-position (in front of) - 0.0f, 0.0f, 0.0f, // View-point - 0.0f, 1.0f, 0.0f ); // Up-vector - drawGrid( 0.5, 12 ); - drawScene(); - - // Lower right view (SIDE VIEW) - glViewport( width/2, 0, width/2, height/2 ); - glScissor( width/2, 0, width/2, height/2 ); - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - gluLookAt( 10.0f, 0.0f, 0.0f, // Eye-position (to the right) - 0.0f, 0.0f, 0.0f, // View-point - 0.0f, 1.0f, 0.0f ); // Up-vector - drawGrid( 0.5, 12 ); - drawScene(); - - // Disable line anti-aliasing - glDisable( GL_LINE_SMOOTH ); - glDisable( GL_BLEND ); - - - // ** PERSPECTIVE VIEW ** - - // For perspective view, use solid rendering - glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - - // Enable face culling (faster rendering) - glEnable( GL_CULL_FACE ); - glCullFace( GL_BACK ); - glFrontFace( GL_CW ); - - // Setup perspective projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - gluPerspective( 65.0f, aspect, 1.0f, 50.0f ); - - // Upper right view (PERSPECTIVE VIEW) - glViewport( width/2, height/2, width/2, height/2 ); - glScissor( width/2, height/2, width/2, height/2 ); - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - gluLookAt( 3.0f, 1.5f, 3.0f, // Eye-position - 0.0f, 0.0f, 0.0f, // View-point - 0.0f, 1.0f, 0.0f ); // Up-vector - - // Configure and enable light source 1 - glLightfv( GL_LIGHT1, GL_POSITION, light_position ); - glLightfv( GL_LIGHT1, GL_AMBIENT, light_ambient ); - glLightfv( GL_LIGHT1, GL_DIFFUSE, light_diffuse ); - glLightfv( GL_LIGHT1, GL_SPECULAR, light_specular ); - glEnable( GL_LIGHT1 ); - glEnable( GL_LIGHTING ); - - // Draw scene - drawScene(); - - // Disable lighting - glDisable( GL_LIGHTING ); - - // Disable face culling - glDisable( GL_CULL_FACE ); - - // Disable depth test - glDisable( GL_DEPTH_TEST ); - - // Disable scissor test - glDisable( GL_SCISSOR_TEST ); - - - // Draw a border around the active view - if( active_view > 0 && active_view != 2 ) - { - glViewport( 0, 0, width, height ); - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - glOrtho( 0.0, 2.0, 0.0, 2.0, 0.0, 1.0 ); - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - glColor3f( 1.0f, 1.0f, 0.6f ); - glTranslatef( (GLfloat) ((active_view - 1) & 1), (GLfloat) (1 - (active_view - 1) / 2), 0.0f ); - glBegin( GL_LINE_STRIP ); - glVertex2i( 0, 0 ); - glVertex2i( 1, 0 ); - glVertex2i( 1, 1 ); - glVertex2i( 0, 1 ); - glVertex2i( 0, 0 ); - glEnd(); - } -} - - -//======================================================================== -// Window size callback function -//======================================================================== - -static void GLFWCALL windowSizeFun( int w, int h ) -{ - width = w; - height = h > 0 ? h : 1; - do_redraw = 1; -} - - -//======================================================================== -// Window refresh callback function -//======================================================================== - -static void GLFWCALL windowRefreshFun( void ) -{ - do_redraw = 1; -} - - -//======================================================================== -// Mouse position callback function -//======================================================================== - -static void GLFWCALL mousePosFun( int x, int y ) -{ - // Depending on which view was selected, rotate around different axes - switch( active_view ) - { - case 1: - rot_x += y - ypos; - rot_z += x - xpos; - do_redraw = 1; - break; - case 3: - rot_x += y - ypos; - rot_y += x - xpos; - do_redraw = 1; - break; - case 4: - rot_y += x - xpos; - rot_z += y - ypos; - do_redraw = 1; - break; - default: - // Do nothing for perspective view, or if no view is selected - break; - } - - // Remember mouse position - xpos = x; - ypos = y; -} - - -//======================================================================== -// Mouse button callback function -//======================================================================== - -static void GLFWCALL mouseButtonFun( int button, int action ) -{ - // Button clicked? - if( ( button == GLFW_MOUSE_BUTTON_LEFT ) && action == GLFW_PRESS ) - { - // Detect which of the four views was clicked - active_view = 1; - if( xpos >= width/2 ) - { - active_view += 1; - } - if( ypos >= height/2 ) - { - active_view += 2; - } - } - - // Button released? - else if( button == GLFW_MOUSE_BUTTON_LEFT ) - { - // Deselect any previously selected view - active_view = 0; - } - - do_redraw = 1; -} - - -//======================================================================== -// main() -//======================================================================== - -void iteration(){ - // Only redraw if we need to - if( do_redraw ) - { - // Draw all views - drawAllViews(); - - // Swap buffers - glfwSwapBuffers(); - - do_redraw = 0; - } - - // Wait for new events - glfwWaitEvents(); -} - -int main( void ) -{ - // Initialise GLFW - if( !glfwInit() ) - { - fprintf( stderr, "Failed to initialize GLFW\n" ); - exit( EXIT_FAILURE ); - } - - // Open OpenGL window - if( !glfwOpenWindow( 500, 500, 0,0,0,0, 16,0, GLFW_WINDOW ) ) - { - fprintf( stderr, "Failed to open GLFW window\n" ); - glfwTerminate(); - exit( EXIT_FAILURE ); - } - - // Enable vsync - glfwSwapInterval( 1 ); - - // Set window title - glfwSetWindowTitle( "Split view demo" ); - - // Enable sticky keys - glfwEnable( GLFW_STICKY_KEYS ); - - // Enable mouse cursor (only needed for fullscreen mode) - glfwEnable( GLFW_MOUSE_CURSOR ); - - // Disable automatic event polling - glfwDisable( GLFW_AUTO_POLL_EVENTS ); - - // Set callback functions - glfwSetWindowSizeCallback( windowSizeFun ); - glfwSetWindowRefreshCallback( windowRefreshFun ); - glfwSetMousePosCallback( mousePosFun ); - glfwSetMouseButtonCallback( mouseButtonFun ); - -#ifdef EMSCRIPTEN - emscripten_set_main_loop (iteration, 0, 1); -#else - // Main loop - do - { - iteration(); - } // Check if the ESC key was pressed or the window was closed - while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS && - glfwGetWindowParam( GLFW_OPENED ) ); -#endif - - // Close OpenGL window and terminate GLFW - glfwTerminate(); - - exit( EXIT_SUCCESS ); -} - diff --git a/tests/glfw/triangle.c b/tests/glfw/triangle.c deleted file mode 100644 index db9d9ab163573..0000000000000 --- a/tests/glfw/triangle.c +++ /dev/null @@ -1,108 +0,0 @@ -//======================================================================== -// This is a small test application for GLFW. -// The program opens a window (640x480), and renders a spinning colored -// triangle (it is controlled with both the GLFW timer and the mouse). -//======================================================================== - -#include -#include -#include - -#ifdef EMSCRIPTEN -#include -#endif - -void -iteration () -{ - int width, height, x; - double t; - - t = glfwGetTime (); - glfwGetMousePos (&x, NULL); - - // Get window size (may be different than the requested size) - glfwGetWindowSize (&width, &height); - - // Special case: avoid division by zero below - height = height > 0 ? height : 1; - - glViewport (0, 0, width, height); - - // Clear color buffer to black - glClearColor (0.0f, 0.0f, 0.0f, 0.0f); - glClear (GL_COLOR_BUFFER_BIT); - - // Select and setup the projection matrix - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - gluPerspective (65.0f, (GLfloat) width / (GLfloat) height, 1.0f, 100.0f); - - // Select and setup the modelview matrix - glMatrixMode (GL_MODELVIEW); - glLoadIdentity (); - gluLookAt (0.0f, 1.0f, 0.0f, // Eye-position - 0.0f, 20.0f, 0.0f, // View-point - 0.0f, 0.0f, 1.0f); // Up-vector - - // Draw a rotating colorful triangle - //glTranslatef (0.0f, 14.0f, 0.0f); - glTranslatef (0.0f, 1.0f, 0.0f); - glRotatef (0.3f * (GLfloat) x + (GLfloat) t * 100.0f, 0.0f, 0.0f, 1.0f); - glBegin (GL_TRIANGLES); - glColor3f (1.0f, 0.0f, 0.0f); - glVertex3f (-5.0f, 0.0f, -4.0f); - glColor3f (0.0f, 1.0f, 0.0f); - glVertex3f (5.0f, 0.0f, -4.0f); - glColor3f (0.0f, 0.0f, 1.0f); - glVertex3f (0.0f, 0.0f, 6.0f); - glEnd (); - - // Swap buffers - glfwSwapBuffers (); - -} - -int -main (void) -{ - // Initialise GLFW - if (!glfwInit ()) - { - fprintf (stderr, "Failed to initialize GLFW\n"); - exit (EXIT_FAILURE); - } - - // Open a window and create its OpenGL context - if (!glfwOpenWindow (640, 480, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) - { - fprintf (stderr, "Failed to open GLFW window\n"); - - glfwTerminate (); - exit (EXIT_FAILURE); - } - - glfwSetWindowTitle ("Spinning Triangle"); - - // Ensure we can capture the escape key being pressed below - glfwEnable (GLFW_STICKY_KEYS); - - // Enable vertical sync (on cards that support it) - glfwSwapInterval (1); - -#ifdef EMSCRIPTEN - emscripten_set_main_loop (iteration, 0, 1); -#else - do - { - iteration (); - } // Check if the ESC key was pressed or the window was closed - while (glfwGetKey (GLFW_KEY_ESC) != GLFW_PRESS && - glfwGetWindowParam (GLFW_OPENED)); -#endif - - // Close OpenGL window and terminate GLFW - glfwTerminate (); - - exit (EXIT_SUCCESS); -} diff --git a/tests/glfw/wave.c b/tests/glfw/wave.c deleted file mode 100644 index 67f516cc094c7..0000000000000 --- a/tests/glfw/wave.c +++ /dev/null @@ -1,399 +0,0 @@ -/***************************************************************************** - * Wave Simulation in OpenGL - * (C) 2002 Jakob Thomsen - * http://home.in.tum.de/~thomsen - * Modified for GLFW by Sylvain Hellegouarch - sh@programmationworld.com - * Modified for variable frame rate by Marcus Geelnard - * 2003-Jan-31: Minor cleanups and speedups / MG - *****************************************************************************/ - -#include -#include -#include -#include - -#ifndef M_PI - #define M_PI 3.1415926535897932384626433832795 -#endif - -/* Maximum delta T to allow for differential calculations */ -#define MAX_DELTA_T 0.01 - -/* Animation speed (10.0 looks good) */ -#define ANIMATION_SPEED 10.0 - - -GLfloat alpha = 210.0f, beta = -70.0f; -GLfloat zoom = 2.0f; - -int running = 1; - -struct Vertex -{ - GLfloat x,y,z; - GLfloat r,g,b; -}; - -#define GRIDW 50 -#define GRIDH 50 -#define VERTEXNUM (GRIDW*GRIDH) - -#define QUADW (GRIDW-1) -#define QUADH (GRIDH-1) -#define QUADNUM (QUADW*QUADH) - -GLuint quad[4*QUADNUM]; -struct Vertex vertex[VERTEXNUM]; - -/* The grid will look like this: - * - * 3 4 5 - * *---*---* - * | | | - * | 0 | 1 | - * | | | - * *---*---* - * 0 1 2 - */ - -void initVertices( void ) -{ - int x,y,p; - - /* place the vertices in a grid */ - for(y=0;y1) zoom-=1; - break; - case GLFW_KEY_PAGEDOWN: - zoom+=1; - break; - default: - break; - } -} - - -/* Callback function for window resize events */ -void GLFWCALL handle_resize( int width, int height ) -{ - float ratio = 1.0f; - - if( height > 0 ) - { - ratio = (float) width / (float) height; - } - - /* Setup viewport (Place where the stuff will appear in the main window). */ - glViewport(0, 0, width, height); - - /* - * Change to the projection matrix and set - * our viewing volume. - */ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(60.0, ratio, 1.0, 1024.0); -} - - -/* Program entry point */ -int main(int argc, char* argv[]) -{ - /* Dimensions of our window. */ - int width, height; - /* Style of our window. */ - int mode; - /* Frame time */ - double t, t_old, dt_total; - - /* Initialize GLFW */ - if(glfwInit() == GL_FALSE) - { - fprintf(stderr, "GLFW initialization failed\n"); - exit(-1); - } - - /* Desired window properties */ - width = 640; - height = 480; - mode = GLFW_WINDOW; - - /* Open window */ - if( glfwOpenWindow(width,height,0,0,0,0,16,0,mode) == GL_FALSE ) - { - fprintf(stderr, "Could not open window\n"); - glfwTerminate(); - exit(-1); - } - - /* Set title */ - glfwSetWindowTitle( "Wave Simulation" ); - - glfwSwapInterval( 1 ); - - /* Keyboard handler */ - glfwSetKeyCallback( handle_key_down ); - glfwEnable( GLFW_KEY_REPEAT ); - - /* Window resize handler */ - glfwSetWindowSizeCallback( handle_resize ); - - /* Initialize OpenGL */ - setup_opengl(); - - /* Initialize simulation */ - initVertices(); - initSurface(); - adjustGrid(); - - /* Initialize timer */ - t_old = glfwGetTime() - 0.01; - - /* Main loop */ - while(running) - { - /* Timing */ - t = glfwGetTime(); - dt_total = t - t_old; - t_old = t; - - /* Safety - iterate if dt_total is too large */ - while( dt_total > 0.0f ) - { - /* Select iteration time step */ - dt = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total; - dt_total -= dt; - - /* Calculate wave propagation */ - calc(); - } - - /* Compute height of each vertex */ - adjustGrid(); - - /* Draw wave grid to OpenGL display */ - draw_screen(); - - /* Still running? */ - running = running && glfwGetWindowParam( GLFW_OPENED ); - } - - glfwTerminate(); - - return 0; -} diff --git a/tests/runner.py b/tests/runner.py index ef014a1879bb0..7c19010b2d7e8 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -11241,6 +11241,12 @@ def test_openal_playback(self): Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'openal_playback.cpp'), '--preload-file', 'audio.wav', '-o', 'page.html']).communicate() self.run_browser('page.html', '', '/report_result?1') + def test_glfw(self): + open(os.path.join(self.get_dir(), 'glfw.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'glfw.c')).read())) + + Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'glfw.c'), '-o', 'page.html']).communicate() + self.run_browser('page.html', '', '/report_result?1') + def test_worker(self): # Test running in a web worker output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_worker.cpp'), '-o', 'worker.js'], stdout=PIPE, stderr=PIPE).communicate() From 94b3f0a6927efda744a5b2e1222645bcd4dd6ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Mon, 4 Mar 2013 13:11:44 +0100 Subject: [PATCH 024/544] * Added glfw headers and testcases. --- src/library_glfw.js | 1 + tests/glfw/Makefile | 56 ++ tests/glfw/boing.c | 615 ++++++++++++++++++ tests/glfw/bundle.sh | 46 ++ tests/glfw/gears.c | 373 +++++++++++ tests/glfw/getopt.c | 253 ++++++++ tests/glfw/getopt.h | 63 ++ tests/glfw/heightmap.c | 850 ++++++++++++++++++++++++ tests/glfw/listmodes.c | 48 ++ tests/glfw/mipmaps.c | 122 ++++ tests/glfw/mipmaps.tga | Bin 0 -> 66322 bytes tests/glfw/mtbench.c | 301 +++++++++ tests/glfw/mthello.c | 48 ++ tests/glfw/particles.c | 1152 +++++++++++++++++++++++++++++++++ tests/glfw/pong3d.c | 854 ++++++++++++++++++++++++ tests/glfw/pong3d_field.tga | Bin 0 -> 17816 bytes tests/glfw/pong3d_instr.tga | Bin 0 -> 21279 bytes tests/glfw/pong3d_menu.tga | Bin 0 -> 1835 bytes tests/glfw/pong3d_title.tga | Bin 0 -> 106516 bytes tests/glfw/pong3d_winner1.tga | Bin 0 -> 861 bytes tests/glfw/pong3d_winner2.tga | Bin 0 -> 891 bytes tests/glfw/splitview.c | 514 +++++++++++++++ tests/glfw/triangle.c | 94 +++ tests/glfw/wave.c | 399 ++++++++++++ 24 files changed, 5789 insertions(+) create mode 100644 tests/glfw/Makefile create mode 100644 tests/glfw/boing.c create mode 100644 tests/glfw/bundle.sh create mode 100644 tests/glfw/gears.c create mode 100644 tests/glfw/getopt.c create mode 100644 tests/glfw/getopt.h create mode 100644 tests/glfw/heightmap.c create mode 100644 tests/glfw/listmodes.c create mode 100644 tests/glfw/mipmaps.c create mode 100644 tests/glfw/mipmaps.tga create mode 100644 tests/glfw/mtbench.c create mode 100644 tests/glfw/mthello.c create mode 100644 tests/glfw/particles.c create mode 100644 tests/glfw/pong3d.c create mode 100644 tests/glfw/pong3d_field.tga create mode 100644 tests/glfw/pong3d_instr.tga create mode 100644 tests/glfw/pong3d_menu.tga create mode 100644 tests/glfw/pong3d_title.tga create mode 100644 tests/glfw/pong3d_winner1.tga create mode 100644 tests/glfw/pong3d_winner2.tga create mode 100644 tests/glfw/splitview.c create mode 100644 tests/glfw/triangle.c create mode 100644 tests/glfw/wave.c diff --git a/src/library_glfw.js b/src/library_glfw.js index 20c75a29d6327..e197efd29f69e 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -573,3 +573,4 @@ var LibraryGLFW = { autoAddDeps(LibraryGLFW, '$GLFW'); mergeInto(LibraryManager.library, LibraryGLFW); + diff --git a/tests/glfw/Makefile b/tests/glfw/Makefile new file mode 100644 index 0000000000000..89138d74b87ae --- /dev/null +++ b/tests/glfw/Makefile @@ -0,0 +1,56 @@ +########################################################################## +# Makefile for GLFW example programs on X11 (generated by compile.sh) +########################################################################## +CC = emcc +CFLAGS = -I../include + +LIB = -lglfw +SOLIB = +LFLAGS = $(LIB) +SO_LFLAGS = $(SOLIB) + +BINARIES = triangle.js listmodes.js mthello.js pong3d.js mtbench.js particles.js splitview.js \ + mipmaps.js gears.js boing.js heightmap.js +## wave + +all: $(BINARIES) + +triangle.js: triangle.c + $(CC) $(CFLAGS) triangle.c $(LFLAGS) -o $@ + +listmodes.js: listmodes.c + $(CC) $(CFLAGS) listmodes.c $(LFLAGS) -o $@ + +mthello.js: mthello.c + $(CC) $(CFLAGS) mthello.c $(LFLAGS) -o $@ + +pong3d.js: pong3d.c + $(CC) $(CFLAGS) pong3d.c $(LFLAGS) -o $@ + +mtbench.js: mtbench.c + $(CC) $(CFLAGS) mtbench.c $(LFLAGS) -o $@ + +particles.js: particles.c + $(CC) $(CFLAGS) particles.c $(LFLAGS) -o $@ + +splitview.js: splitview.c + $(CC) $(CFLAGS) splitview.c $(LFLAGS) -o $@ + +mipmaps.js: mipmaps.c + $(CC) $(CFLAGS) mipmaps.c $(LFLAGS) -o $@ + +gears.js: gears.c + $(CC) $(CFLAGS) gears.c $(LFLAGS) -o $@ + +boing.js: boing.c + $(CC) $(CFLAGS) boing.c $(LFLAGS) -o $@ + +wave.js: wave.c + $(CC) $(CFLAGS) wave.c $(LFLAGS) -o $@ + +heightmap.js: heightmap.c + $(CC) $(CFLAGS) heightmap.c $(LFLAGS) -o $@ + +clean: + rm -f $(BINARIES) + diff --git a/tests/glfw/boing.c b/tests/glfw/boing.c new file mode 100644 index 0000000000000..08544d1a4716b --- /dev/null +++ b/tests/glfw/boing.c @@ -0,0 +1,615 @@ +/***************************************************************************** + * Title: GLBoing + * Desc: Tribute to Amiga Boing. + * Author: Jim Brooks + * Original Amiga authors were R.J. Mical and Dale Luck. + * GLFW conversion by Marcus Geelnard + * Notes: - 360' = 2*PI [radian] + * + * - Distances between objects are created by doing a relative + * Z translations. + * + * - Although OpenGL enticingly supports alpha-blending, + * the shadow of the original Boing didn't affect the color + * of the grid. + * + * - [Marcus] Changed timing scheme from interval driven to frame- + * time based animation steps (which results in much smoother + * movement) + * + * History of Amiga Boing: + * + * Boing was demonstrated on the prototype Amiga (codenamed "Lorraine") in + * 1985. According to legend, it was written ad-hoc in one night by + * R. J. Mical and Dale Luck. Because the bouncing ball animation was so fast + * and smooth, attendees did not believe the Amiga prototype was really doing + * the rendering. Suspecting a trick, they began looking around the booth for + * a hidden computer or VCR. + *****************************************************************************/ + +#include +#include +#include +#include + + +/***************************************************************************** + * Various declarations and macros + *****************************************************************************/ + +/* Prototypes */ +void init( void ); +void display( void ); +void GLFWCALL reshape( int w, int h ); +void DrawBoingBall( void ); +void BounceBall( double dt ); +void DrawBoingBallBand( GLfloat long_lo, GLfloat long_hi ); +void DrawGrid( void ); + +#define RADIUS 70.f +#define STEP_LONGITUDE 22.5f /* 22.5 makes 8 bands like original Boing */ +#define STEP_LATITUDE 22.5f + +#define DIST_BALL (RADIUS * 2.f + RADIUS * 0.1f) + +#define VIEW_SCENE_DIST (DIST_BALL * 3.f + 200.f)/* distance from viewer to middle of boing area */ +#define GRID_SIZE (RADIUS * 4.5f) /* length (width) of grid */ +#define BOUNCE_HEIGHT (RADIUS * 2.1f) +#define BOUNCE_WIDTH (RADIUS * 2.1f) + +#define SHADOW_OFFSET_X -20.f +#define SHADOW_OFFSET_Y 10.f +#define SHADOW_OFFSET_Z 0.f + +#define WALL_L_OFFSET 0.f +#define WALL_R_OFFSET 5.f + +/* Animation speed (50.0 mimics the original GLUT demo speed) */ +#define ANIMATION_SPEED 50.f + +/* Maximum allowed delta time per physics iteration */ +#define MAX_DELTA_T 0.02f + +/* Draw ball, or its shadow */ +typedef enum { DRAW_BALL, DRAW_BALL_SHADOW } DRAW_BALL_ENUM; + +/* Vertex type */ +typedef struct {float x; float y; float z;} vertex_t; + +/* Global vars */ +GLfloat deg_rot_y = 0.f; +GLfloat deg_rot_y_inc = 2.f; +GLfloat ball_x = -RADIUS; +GLfloat ball_y = -RADIUS; +GLfloat ball_x_inc = 1.f; +GLfloat ball_y_inc = 2.f; +DRAW_BALL_ENUM drawBallHow; +double t; +double t_old = 0.f; +double dt; + +/* Random number generator */ +#ifndef RAND_MAX + #define RAND_MAX 4095 +#endif + +/* PI */ +#ifndef M_PI + #define M_PI 3.1415926535897932384626433832795 +#endif + + +/***************************************************************************** + * Truncate a degree. + *****************************************************************************/ +GLfloat TruncateDeg( GLfloat deg ) +{ + if ( deg >= 360.f ) + return (deg - 360.f); + else + return deg; +} + +/***************************************************************************** + * Convert a degree (360-based) into a radian. + * 360' = 2 * PI + *****************************************************************************/ +double deg2rad( double deg ) +{ + return deg / 360 * (2 * M_PI); +} + +/***************************************************************************** + * 360' sin(). + *****************************************************************************/ +double sin_deg( double deg ) +{ + return sin( deg2rad( deg ) ); +} + +/***************************************************************************** + * 360' cos(). + *****************************************************************************/ +double cos_deg( double deg ) +{ + return cos( deg2rad( deg ) ); +} + +/***************************************************************************** + * Compute a cross product (for a normal vector). + * + * c = a x b + *****************************************************************************/ +void CrossProduct( vertex_t a, vertex_t b, vertex_t c, vertex_t *n ) +{ + GLfloat u1, u2, u3; + GLfloat v1, v2, v3; + + u1 = b.x - a.x; + u2 = b.y - a.y; + u3 = b.y - a.z; + + v1 = c.x - a.x; + v2 = c.y - a.y; + v3 = c.z - a.z; + + n->x = u2 * v3 - v2 * v3; + n->y = u3 * v1 - v3 * u1; + n->z = u1 * v2 - v1 * u2; +} + +/***************************************************************************** + * Calculate the angle to be passed to gluPerspective() so that a scene + * is visible. This function originates from the OpenGL Red Book. + * + * Parms : size + * The size of the segment when the angle is intersected at "dist" + * (ie at the outermost edge of the angle of vision). + * + * dist + * Distance from viewpoint to scene. + *****************************************************************************/ +GLfloat PerspectiveAngle( GLfloat size, + GLfloat dist ) +{ + GLfloat radTheta, degTheta; + + radTheta = 2.f * (GLfloat) atan2( size / 2.f, dist ); + degTheta = (180.f * radTheta) / (GLfloat) M_PI; + return degTheta; +} + + + +#define BOING_DEBUG 0 + + +/***************************************************************************** + * init() + *****************************************************************************/ +void init( void ) +{ + /* + * Clear background. + */ + glClearColor( 0.55f, 0.55f, 0.55f, 0.f ); + + glShadeModel( GL_FLAT ); +} + + +/***************************************************************************** + * display() + *****************************************************************************/ +void display(void) +{ + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + glPushMatrix(); + + drawBallHow = DRAW_BALL_SHADOW; + DrawBoingBall(); + + DrawGrid(); + + drawBallHow = DRAW_BALL; + DrawBoingBall(); + + glPopMatrix(); + glFlush(); +} + + +/***************************************************************************** + * reshape() + *****************************************************************************/ +void GLFWCALL reshape( int w, int h ) +{ + glViewport( 0, 0, (GLsizei)w, (GLsizei)h ); + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + + gluPerspective( PerspectiveAngle( RADIUS * 2, 200 ), + (GLfloat)w / (GLfloat)h, + 1.0, + VIEW_SCENE_DIST ); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + gluLookAt( 0.0, 0.0, VIEW_SCENE_DIST,/* eye */ + 0.0, 0.0, 0.0, /* center of vision */ + 0.0, -1.0, 0.0 ); /* up vector */ +} + + +/***************************************************************************** + * Draw the Boing ball. + * + * The Boing ball is sphere in which each facet is a rectangle. + * Facet colors alternate between red and white. + * The ball is built by stacking latitudinal circles. Each circle is composed + * of a widely-separated set of points, so that each facet is noticably large. + *****************************************************************************/ +void DrawBoingBall( void ) +{ + GLfloat lon_deg; /* degree of longitude */ + double dt_total, dt2; + + glPushMatrix(); + glMatrixMode( GL_MODELVIEW ); + + /* + * Another relative Z translation to separate objects. + */ + glTranslatef( 0.0, 0.0, DIST_BALL ); + + /* Update ball position and rotation (iterate if necessary) */ + dt_total = dt; + while( dt_total > 0.0 ) + { + dt2 = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total; + dt_total -= dt2; + BounceBall( dt2 ); + deg_rot_y = TruncateDeg( deg_rot_y + deg_rot_y_inc*((float)dt2*ANIMATION_SPEED) ); + } + + /* Set ball position */ + glTranslatef( ball_x, ball_y, 0.0 ); + + /* + * Offset the shadow. + */ + if ( drawBallHow == DRAW_BALL_SHADOW ) + { + glTranslatef( SHADOW_OFFSET_X, + SHADOW_OFFSET_Y, + SHADOW_OFFSET_Z ); + } + + /* + * Tilt the ball. + */ + glRotatef( -20.0, 0.0, 0.0, 1.0 ); + + /* + * Continually rotate ball around Y axis. + */ + glRotatef( deg_rot_y, 0.0, 1.0, 0.0 ); + + /* + * Set OpenGL state for Boing ball. + */ + glCullFace( GL_FRONT ); + glEnable( GL_CULL_FACE ); + glEnable( GL_NORMALIZE ); + + /* + * Build a faceted latitude slice of the Boing ball, + * stepping same-sized vertical bands of the sphere. + */ + for ( lon_deg = 0; + lon_deg < 180; + lon_deg += STEP_LONGITUDE ) + { + /* + * Draw a latitude circle at this longitude. + */ + DrawBoingBallBand( lon_deg, + lon_deg + STEP_LONGITUDE ); + } + + glPopMatrix(); + + return; +} + + +/***************************************************************************** + * Bounce the ball. + *****************************************************************************/ +void BounceBall( double dt ) +{ + GLfloat sign; + GLfloat deg; + + /* Bounce on walls */ + if ( ball_x > (BOUNCE_WIDTH/2 + WALL_R_OFFSET ) ) + { + ball_x_inc = -0.5f - 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX; + deg_rot_y_inc = -deg_rot_y_inc; + } + if ( ball_x < -(BOUNCE_HEIGHT/2 + WALL_L_OFFSET) ) + { + ball_x_inc = 0.5f + 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX; + deg_rot_y_inc = -deg_rot_y_inc; + } + + /* Bounce on floor / roof */ + if ( ball_y > BOUNCE_HEIGHT/2 ) + { + ball_y_inc = -0.75f - 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX; + } + if ( ball_y < -BOUNCE_HEIGHT/2*0.85 ) + { + ball_y_inc = 0.75f + 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX; + } + + /* Update ball position */ + ball_x += ball_x_inc * ((float)dt*ANIMATION_SPEED); + ball_y += ball_y_inc * ((float)dt*ANIMATION_SPEED); + + /* + * Simulate the effects of gravity on Y movement. + */ + if ( ball_y_inc < 0 ) sign = -1.0; else sign = 1.0; + + deg = (ball_y + BOUNCE_HEIGHT/2) * 90 / BOUNCE_HEIGHT; + if ( deg > 80 ) deg = 80; + if ( deg < 10 ) deg = 10; + + ball_y_inc = sign * 4.f * (float) sin_deg( deg ); +} + + +/***************************************************************************** + * Draw a faceted latitude band of the Boing ball. + * + * Parms: long_lo, long_hi + * Low and high longitudes of slice, resp. + *****************************************************************************/ +void DrawBoingBallBand( GLfloat long_lo, + GLfloat long_hi ) +{ + vertex_t vert_ne; /* "ne" means south-east, so on */ + vertex_t vert_nw; + vertex_t vert_sw; + vertex_t vert_se; + vertex_t vert_norm; + GLfloat lat_deg; + static int colorToggle = 0; + + /* + * Iterate thru the points of a latitude circle. + * A latitude circle is a 2D set of X,Z points. + */ + for ( lat_deg = 0; + lat_deg <= (360 - STEP_LATITUDE); + lat_deg += STEP_LATITUDE ) + { + /* + * Color this polygon with red or white. + */ + if ( colorToggle ) + glColor3f( 0.8f, 0.1f, 0.1f ); + else + glColor3f( 0.95f, 0.95f, 0.95f ); +#if 0 + if ( lat_deg >= 180 ) + if ( colorToggle ) + glColor3f( 0.1f, 0.8f, 0.1f ); + else + glColor3f( 0.5f, 0.5f, 0.95f ); +#endif + colorToggle = ! colorToggle; + + /* + * Change color if drawing shadow. + */ + if ( drawBallHow == DRAW_BALL_SHADOW ) + glColor3f( 0.35f, 0.35f, 0.35f ); + + /* + * Assign each Y. + */ + vert_ne.y = vert_nw.y = (float) cos_deg(long_hi) * RADIUS; + vert_sw.y = vert_se.y = (float) cos_deg(long_lo) * RADIUS; + + /* + * Assign each X,Z with sin,cos values scaled by latitude radius indexed by longitude. + * Eg, long=0 and long=180 are at the poles, so zero scale is sin(longitude), + * while long=90 (sin(90)=1) is at equator. + */ + vert_ne.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_se.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); + vert_nw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_sw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); + + vert_ne.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_se.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); + vert_nw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_sw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); + + /* + * Draw the facet. + */ + glBegin( GL_POLYGON ); + + CrossProduct( vert_ne, vert_nw, vert_sw, &vert_norm ); + glNormal3f( vert_norm.x, vert_norm.y, vert_norm.z ); + + glVertex3f( vert_ne.x, vert_ne.y, vert_ne.z ); + glVertex3f( vert_nw.x, vert_nw.y, vert_nw.z ); + glVertex3f( vert_sw.x, vert_sw.y, vert_sw.z ); + glVertex3f( vert_se.x, vert_se.y, vert_se.z ); + + glEnd(); + +#if BOING_DEBUG + printf( "----------------------------------------------------------- \n" ); + printf( "lat = %f long_lo = %f long_hi = %f \n", lat_deg, long_lo, long_hi ); + printf( "vert_ne x = %.8f y = %.8f z = %.8f \n", vert_ne.x, vert_ne.y, vert_ne.z ); + printf( "vert_nw x = %.8f y = %.8f z = %.8f \n", vert_nw.x, vert_nw.y, vert_nw.z ); + printf( "vert_se x = %.8f y = %.8f z = %.8f \n", vert_se.x, vert_se.y, vert_se.z ); + printf( "vert_sw x = %.8f y = %.8f z = %.8f \n", vert_sw.x, vert_sw.y, vert_sw.z ); +#endif + + } + + /* + * Toggle color so that next band will opposite red/white colors than this one. + */ + colorToggle = ! colorToggle; + + /* + * This circular band is done. + */ + return; +} + + +/***************************************************************************** + * Draw the purple grid of lines, behind the Boing ball. + * When the Workbench is dropped to the bottom, Boing shows 12 rows. + *****************************************************************************/ +void DrawGrid( void ) +{ + int row, col; + const int rowTotal = 12; /* must be divisible by 2 */ + const int colTotal = rowTotal; /* must be same as rowTotal */ + const GLfloat widthLine = 2.0; /* should be divisible by 2 */ + const GLfloat sizeCell = GRID_SIZE / rowTotal; + const GLfloat z_offset = -40.0; + GLfloat xl, xr; + GLfloat yt, yb; + + glPushMatrix(); + glDisable( GL_CULL_FACE ); + + /* + * Another relative Z translation to separate objects. + */ + glTranslatef( 0.0, 0.0, DIST_BALL ); + + /* + * Draw vertical lines (as skinny 3D rectangles). + */ + for ( col = 0; col <= colTotal; col++ ) + { + /* + * Compute co-ords of line. + */ + xl = -GRID_SIZE / 2 + col * sizeCell; + xr = xl + widthLine; + + yt = GRID_SIZE / 2; + yb = -GRID_SIZE / 2 - widthLine; + + glBegin( GL_POLYGON ); + + glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */ + + glVertex3f( xr, yt, z_offset ); /* NE */ + glVertex3f( xl, yt, z_offset ); /* NW */ + glVertex3f( xl, yb, z_offset ); /* SW */ + glVertex3f( xr, yb, z_offset ); /* SE */ + + glEnd(); + } + + /* + * Draw horizontal lines (as skinny 3D rectangles). + */ + for ( row = 0; row <= rowTotal; row++ ) + { + /* + * Compute co-ords of line. + */ + yt = GRID_SIZE / 2 - row * sizeCell; + yb = yt - widthLine; + + xl = -GRID_SIZE / 2; + xr = GRID_SIZE / 2 + widthLine; + + glBegin( GL_POLYGON ); + + glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */ + + glVertex3f( xr, yt, z_offset ); /* NE */ + glVertex3f( xl, yt, z_offset ); /* NW */ + glVertex3f( xl, yb, z_offset ); /* SW */ + glVertex3f( xr, yb, z_offset ); /* SE */ + + glEnd(); + } + + glPopMatrix(); + + return; +} + + +/*======================================================================* + * main() + *======================================================================*/ + +int main( void ) +{ + int running; + + /* Init GLFW */ + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + if( !glfwOpenWindow( 400,400, 0,0,0,0, 16,0, GLFW_WINDOW ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + glfwSetWindowTitle( "Boing (classic Amiga demo)" ); + glfwSetWindowSizeCallback( reshape ); + glfwEnable( GLFW_STICKY_KEYS ); + glfwSwapInterval( 1 ); + glfwSetTime( 0.0 ); + + init(); + + /* Main loop */ + do + { + /* Timing */ + t = glfwGetTime(); + dt = t - t_old; + t_old = t; + + /* Draw one frame */ + display(); + + /* Swap buffers */ + glfwSwapBuffers(); + + /* Check if we are still running */ + running = !glfwGetKey( GLFW_KEY_ESC ) && + glfwGetWindowParam( GLFW_OPENED ); + } + while( running ); + + glfwTerminate(); + exit( EXIT_SUCCESS ); +} + diff --git a/tests/glfw/bundle.sh b/tests/glfw/bundle.sh new file mode 100644 index 0000000000000..ee4d18ddda08d --- /dev/null +++ b/tests/glfw/bundle.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# Creates application bundles for use on Mac OS X. + +if [ -z "$1" ]; then + echo "usage: `basename $0` BUNDLE-NAME" + exit 1 +fi + +bundle_name="$1" + +if [ ! -d "${bundle_name}.app/Contents/MacOS" ]; then + mkdir -p "${bundle_name}.app/Contents/MacOS" +fi + +if [ ! -d "${bundle_name}.app/Contents/Resources" ]; then + mkdir -p "${bundle_name}.app/Contents/Resources" +fi + +if [ ! -f "${bundle_name}.app/Contents/PkgInfo" ]; then + echo -n "APPL????" > "${bundle_name}.app/Contents/PkgInfo" +fi + +if [ ! -f "${bundle_name}.app/Contents/Info.plist" ]; then + cat > "${bundle_name}.app/Contents/Info.plist" < + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${bundle_name} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 0.1 + + +EOF +fi + diff --git a/tests/glfw/gears.c b/tests/glfw/gears.c new file mode 100644 index 0000000000000..d9efdf9aa6314 --- /dev/null +++ b/tests/glfw/gears.c @@ -0,0 +1,373 @@ +/* + * 3-D gear wheels. This program is in the public domain. + * + * Command line options: + * -info print GL implementation information + * -exit automatically exit after 30 seconds + * + * + * Brian Paul + * + * + * Marcus Geelnard: + * - Conversion to GLFW + * - Time based rendering (frame rate independent) + * - Slightly modified camera that should work better for stereo viewing + * + * + * Camilla Berglund: + * - Removed FPS counter (this is not a benchmark) + * - Added a few comments + * - Enabled vsync + */ + + +#include +#include +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +/* The program exits when this is zero. + */ +static int running = 1; + +/* If non-zero, the program exits after that many seconds + */ +static int autoexit = 0; + +/** + + Draw a gear wheel. You'll probably want to call this function when + building a display list since we do a lot of trig here. + + Input: inner_radius - radius of hole at center + outer_radius - radius at center of teeth + width - width of gear teeth - number of teeth + tooth_depth - depth of tooth + + **/ + +static void +gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, + GLint teeth, GLfloat tooth_depth) +{ + GLint i; + GLfloat r0, r1, r2; + GLfloat angle, da; + GLfloat u, v, len; + + r0 = inner_radius; + r1 = outer_radius - tooth_depth / 2.f; + r2 = outer_radius + tooth_depth / 2.f; + + da = 2.f * (float) M_PI / teeth / 4.f; + + glShadeModel(GL_FLAT); + + glNormal3f(0.f, 0.f, 1.f); + + /* draw front face */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); + if (i < teeth) { + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); + } + } + glEnd(); + + /* draw front sides of teeth */ + glBegin(GL_QUADS); + da = 2.f * (float) M_PI / teeth / 4.f; + for (i = 0; i < teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), width * 0.5f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); + } + glEnd(); + + glNormal3f(0.0, 0.0, -1.0); + + /* draw back face */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); + if (i < teeth) { + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); + } + } + glEnd(); + + /* draw back sides of teeth */ + glBegin(GL_QUADS); + da = 2.f * (float) M_PI / teeth / 4.f; + for (i = 0; i < teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), -width * 0.5f); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), -width * 0.5f); + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); + } + glEnd(); + + /* draw outward faces of teeth */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i < teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); + u = r2 * (float) cos(angle + da) - r1 * (float) cos(angle); + v = r2 * (float) sin(angle + da) - r1 * (float) sin(angle); + len = (float) sqrt(u * u + v * v); + u /= len; + v /= len; + glNormal3f(v, -u, 0.0); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), -width * 0.5f); + glNormal3f((float) cos(angle), (float) sin(angle), 0.f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), -width * 0.5f); + u = r1 * (float) cos(angle + 3 * da) - r2 * (float) cos(angle + 2 * da); + v = r1 * (float) sin(angle + 3 * da) - r2 * (float) sin(angle + 2 * da); + glNormal3f(v, -u, 0.f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); + glNormal3f((float) cos(angle), (float) sin(angle), 0.f); + } + + glVertex3f(r1 * (float) cos(0), r1 * (float) sin(0), width * 0.5f); + glVertex3f(r1 * (float) cos(0), r1 * (float) sin(0), -width * 0.5f); + + glEnd(); + + glShadeModel(GL_SMOOTH); + + /* draw inside radius cylinder */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + glNormal3f(-(float) cos(angle), -(float) sin(angle), 0.f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); + } + glEnd(); + +} + + +static GLfloat view_rotx = 20.f, view_roty = 30.f, view_rotz = 0.f; +static GLint gear1, gear2, gear3; +static GLfloat angle = 0.f; + +/* OpenGL draw function & timing */ +static void draw(void) +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glPushMatrix(); + glRotatef(view_rotx, 1.0, 0.0, 0.0); + glRotatef(view_roty, 0.0, 1.0, 0.0); + glRotatef(view_rotz, 0.0, 0.0, 1.0); + + glPushMatrix(); + glTranslatef(-3.0, -2.0, 0.0); + glRotatef(angle, 0.0, 0.0, 1.0); + glCallList(gear1); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(3.1f, -2.f, 0.f); + glRotatef(-2.f * angle - 9.f, 0.f, 0.f, 1.f); + glCallList(gear2); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(-3.1f, 4.2f, 0.f); + glRotatef(-2.f * angle - 25.f, 0.f, 0.f, 1.f); + glCallList(gear3); + glPopMatrix(); + + glPopMatrix(); +} + + +/* update animation parameters */ +static void animate(void) +{ + angle = 100.f * (float) glfwGetTime(); +} + + +/* change view angle, exit upon ESC */ +void GLFWCALL key( int k, int action ) +{ + if( action != GLFW_PRESS ) return; + + switch (k) { + case 'Z': + if( glfwGetKey( GLFW_KEY_LSHIFT ) ) + view_rotz -= 5.0; + else + view_rotz += 5.0; + break; + case GLFW_KEY_ESC: + running = 0; + break; + case GLFW_KEY_UP: + view_rotx += 5.0; + break; + case GLFW_KEY_DOWN: + view_rotx -= 5.0; + break; + case GLFW_KEY_LEFT: + view_roty += 5.0; + break; + case GLFW_KEY_RIGHT: + view_roty -= 5.0; + break; + default: + return; + } +} + + +/* new window size */ +void GLFWCALL reshape( int width, int height ) +{ + GLfloat h = (GLfloat) height / (GLfloat) width; + GLfloat xmax, znear, zfar; + + znear = 5.0f; + zfar = 30.0f; + xmax = znear * 0.5f; + + glViewport( 0, 0, (GLint) width, (GLint) height ); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glFrustum( -xmax, xmax, -xmax*h, xmax*h, znear, zfar ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + glTranslatef( 0.0, 0.0, -20.0 ); +} + + +/* program & OpenGL initialization */ +static void init(int argc, char *argv[]) +{ + static GLfloat pos[4] = {5.f, 5.f, 10.f, 0.f}; + static GLfloat red[4] = {0.8f, 0.1f, 0.f, 1.f}; + static GLfloat green[4] = {0.f, 0.8f, 0.2f, 1.f}; + static GLfloat blue[4] = {0.2f, 0.2f, 1.f, 1.f}; + GLint i; + + glLightfv(GL_LIGHT0, GL_POSITION, pos); + glEnable(GL_CULL_FACE); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); + + /* make the gears */ + gear1 = glGenLists(1); + glNewList(gear1, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); + gear(1.f, 4.f, 1.f, 20, 0.7f); + glEndList(); + + gear2 = glGenLists(1); + glNewList(gear2, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); + gear(0.5f, 2.f, 2.f, 10, 0.7f); + glEndList(); + + gear3 = glGenLists(1); + glNewList(gear3, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); + gear(1.3f, 2.f, 0.5f, 10, 0.7f); + glEndList(); + + glEnable(GL_NORMALIZE); + + for ( i=1; i +#include +#include +#include "getopt.h" + + +/* 2009-10-12 Camilla Berglund + * + * Removed unused global static variable 'ID'. + */ + + +char* optarg = NULL; +int optind = 0; +int opterr = 1; +int optopt = '?'; + + +static char** prev_argv = NULL; /* Keep a copy of argv and argc to */ +static int prev_argc = 0; /* tell if getopt params change */ +static int argv_index = 0; /* Option we're checking */ +static int argv_index2 = 0; /* Option argument we're checking */ +static int opt_offset = 0; /* Index into compounded "-option" */ +static int dashdash = 0; /* True if "--" option reached */ +static int nonopt = 0; /* How many nonopts we've found */ + +static void increment_index() +{ + /* Move onto the next option */ + if(argv_index < argv_index2) + { + while(prev_argv[++argv_index] && prev_argv[argv_index][0] != '-' + && argv_index < argv_index2+1); + } + else argv_index++; + opt_offset = 1; +} + + +/* +* Permutes argv[] so that the argument currently being processed is moved +* to the end. +*/ +static int permute_argv_once() +{ + /* Movability check */ + if(argv_index + nonopt >= prev_argc) return 1; + /* Move the current option to the end, bring the others to front */ + else + { + char* tmp = prev_argv[argv_index]; + + /* Move the data */ + memmove(&prev_argv[argv_index], &prev_argv[argv_index+1], + sizeof(char**) * (prev_argc - argv_index - 1)); + prev_argv[prev_argc - 1] = tmp; + + nonopt++; + return 0; + } +} + + +int getopt(int argc, char** argv, char* optstr) +{ + int c = 0; + + /* If we have new argv, reinitialize */ + if(prev_argv != argv || prev_argc != argc) + { + /* Initialize variables */ + prev_argv = argv; + prev_argc = argc; + argv_index = 1; + argv_index2 = 1; + opt_offset = 1; + dashdash = 0; + nonopt = 0; + } + + /* Jump point in case we want to ignore the current argv_index */ + getopt_top: + + /* Misc. initializations */ + optarg = NULL; + + /* Dash-dash check */ + if(argv[argv_index] && !strcmp(argv[argv_index], "--")) + { + dashdash = 1; + increment_index(); + } + + /* If we're at the end of argv, that's it. */ + if(argv[argv_index] == NULL) + { + c = -1; + } + /* Are we looking at a string? Single dash is also a string */ + else if(dashdash || argv[argv_index][0] != '-' || !strcmp(argv[argv_index], "-")) + { + /* If we want a string... */ + if(optstr[0] == '-') + { + c = 1; + optarg = argv[argv_index]; + increment_index(); + } + /* If we really don't want it (we're in POSIX mode), we're done */ + else if(optstr[0] == '+' || getenv("POSIXLY_CORRECT")) + { + c = -1; + + /* Everything else is a non-opt argument */ + nonopt = argc - argv_index; + } + /* If we mildly don't want it, then move it back */ + else + { + if(!permute_argv_once()) goto getopt_top; + else c = -1; + } + } + /* Otherwise we're looking at an option */ + else + { + char* opt_ptr = NULL; + + /* Grab the option */ + c = argv[argv_index][opt_offset++]; + + /* Is the option in the optstr? */ + if(optstr[0] == '-') opt_ptr = strchr(optstr+1, c); + else opt_ptr = strchr(optstr, c); + /* Invalid argument */ + if(!opt_ptr) + { + if(opterr) + { + fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); + } + + optopt = c; + c = '?'; + + /* Move onto the next option */ + increment_index(); + } + /* Option takes argument */ + else if(opt_ptr[1] == ':') + { + /* ie, -oARGUMENT, -xxxoARGUMENT, etc. */ + if(argv[argv_index][opt_offset] != '\0') + { + optarg = &argv[argv_index][opt_offset]; + increment_index(); + } + /* ie, -o ARGUMENT (only if it's a required argument) */ + else if(opt_ptr[2] != ':') + { + /* One of those "you're not expected to understand this" moment */ + if(argv_index2 < argv_index) argv_index2 = argv_index; + while(argv[++argv_index2] && argv[argv_index2][0] == '-'); + optarg = argv[argv_index2]; + + /* Don't cross into the non-option argument list */ + if(argv_index2 + nonopt >= prev_argc) optarg = NULL; + + /* Move onto the next option */ + increment_index(); + } + else + { + /* Move onto the next option */ + increment_index(); + } + + /* In case we got no argument for an option with required argument */ + if(optarg == NULL && opt_ptr[2] != ':') + { + optopt = c; + c = '?'; + + if(opterr) + { + fprintf(stderr,"%s: option requires an argument -- %c\n", + argv[0], optopt); + } + } + } + /* Option does not take argument */ + else + { + /* Next argv_index */ + if(argv[argv_index][opt_offset] == '\0') + { + increment_index(); + } + } + } + + /* Calculate optind */ + if(c == -1) + { + optind = argc - nonopt; + } + else + { + optind = argv_index; + } + + return c; +} + + +/* vim:ts=3 +*/ diff --git a/tests/glfw/getopt.h b/tests/glfw/getopt.h new file mode 100644 index 0000000000000..0b78650ac7ac6 --- /dev/null +++ b/tests/glfw/getopt.h @@ -0,0 +1,63 @@ +/***************************************************************************** +* getopt.h - competent and free getopt library. +* $Header: /cvsroot/freegetopt/freegetopt/getopt.h,v 1.2 2003/10/26 03:10:20 vindaci Exp $ +* +* Copyright (c)2002-2003 Mark K. Kim +* 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 original author of this software 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 OWNER 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. +*/ +#ifndef GETOPT_H_ +#define GETOPT_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +extern char* optarg; +extern int optind; +extern int opterr; +extern int optopt; + +int getopt(int argc, char** argv, char* optstr); + + +#ifdef __cplusplus +} +#endif + + +#endif /* GETOPT_H_ */ + + +/* vim:ts=3 +*/ diff --git a/tests/glfw/heightmap.c b/tests/glfw/heightmap.c new file mode 100644 index 0000000000000..7faa5d1f16859 --- /dev/null +++ b/tests/glfw/heightmap.c @@ -0,0 +1,850 @@ +//======================================================================== +// Heightmap example program using OpenGL 3 core profile +// Copyright (c) 2010 Olivier Delannoy +// +// 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. +// +//======================================================================== + +#include +#include +#include +#include +#include +#include "getopt.h" + + +#define GLFW_NO_GLU 1 +#include + +/* OpenGL 3.3 support + * Functions are effectively mapped in init_opengl() */ +#ifndef GL_VERSION_3_0 +/* no defines */ +#endif + +#ifndef GL_VERSION_2_0 + +typedef char GLchar; + +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#endif + + + +#ifndef GL_VERSION_1_5 + +typedef ptrdiff_t GLintptr; +typedef ptrdiff_t GLsizeiptr; + +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#endif + + + + +/* OpenGL 3.0 */ +typedef void (APIENTRY * PFN_glGenVertexArrays)(GLsizei n, GLuint *arrays); +typedef void (APIENTRY * PFN_glBindVertexArray)(GLuint array); +typedef void (APIENTRY * PFN_glDeleteVertexArrays)(GLsizei n, GLuint *arrays); +/* OpenGL 2.0 */ +typedef GLuint (APIENTRY * PFN_glCreateShader)(GLenum type); +typedef void (APIENTRY * PFN_glDeleteShader)(GLuint shader); +typedef void (APIENTRY * PFN_glCompileShader)(GLuint shader); +typedef void (APIENTRY * PFN_glShaderSource)(GLuint shader, GLsizei count, const GLchar* *string, const GLint *length); +typedef void (APIENTRY * PFN_glGetShaderiv)(GLuint shader, GLenum pname, GLint *params); +typedef void (APIENTRY * PFN_glGetShaderInfoLog)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef GLuint (APIENTRY * PFN_glCreateProgram)(void); +typedef void (APIENTRY * PFN_glDeleteProgram)(GLuint program); +typedef void (APIENTRY * PFN_glAttachShader)(GLuint program, GLuint shader); +typedef void (APIENTRY * PFN_glLinkProgram)(GLuint program); +typedef void (APIENTRY * PFN_glGetProgramiv)(GLuint program, GLenum pname, GLint *params); +typedef void (APIENTRY * PFN_glGetProgramInfoLog)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRY * PFN_glValidateProgram)(GLuint program); +typedef void (APIENTRY * PFN_glUseProgram)(GLuint program); +typedef GLint (APIENTRY * PFN_glGetUniformLocation)(GLuint program, const GLchar *name); +typedef void (APIENTRY * PFN_glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef GLint (APIENTRY * PFN_glGetAttribLocation)(GLuint program, const GLchar *name); +typedef void (APIENTRY * PFN_glEnableVertexAttribArray)(GLuint index); +typedef void (APIENTRY * PFN_glVertexAttrib1f)(GLuint index, GLfloat x); +typedef void (APIENTRY * PFN_glVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +/* OpenGL 1.5 */ +typedef void (APIENTRY * PFN_glBindBuffer)(GLenum target, GLuint buffer); +typedef void (APIENTRY * PFN_glDeleteBuffers)(GLsizei n, const GLuint *buffers); +typedef void (APIENTRY * PFN_glGenBuffers)(GLsizei n, GLuint *buffers); +typedef void (APIENTRY * PFN_glBufferData)(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); +typedef void (APIENTRY * PFN_glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); + +/* OpenGL function pointers */ +static PFN_glGenBuffers pglGenBuffers = NULL; +static PFN_glGenVertexArrays pglGenVertexArrays = NULL; +static PFN_glDeleteVertexArrays pglDeleteVertexArrays = NULL; +static PFN_glCreateShader pglCreateShader = NULL; +static PFN_glShaderSource pglShaderSource = NULL; +static PFN_glCompileShader pglCompileShader = NULL; +static PFN_glGetShaderiv pglGetShaderiv = NULL; +static PFN_glGetShaderInfoLog pglGetShaderInfoLog = NULL; +static PFN_glDeleteShader pglDeleteShader = NULL; +static PFN_glCreateProgram pglCreateProgram = NULL; +static PFN_glAttachShader pglAttachShader = NULL; +static PFN_glLinkProgram pglLinkProgram = NULL; +static PFN_glUseProgram pglUseProgram = NULL; +static PFN_glGetProgramiv pglGetProgramiv = NULL; +static PFN_glGetProgramInfoLog pglGetProgramInfoLog = NULL; +static PFN_glDeleteProgram pglDeleteProgram = NULL; +static PFN_glGetUniformLocation pglGetUniformLocation = NULL; +static PFN_glUniformMatrix4fv pglUniformMatrix4fv = NULL; +static PFN_glGetAttribLocation pglGetAttribLocation = NULL; + +/* Map height updates */ +#define MAX_CIRCLE_SIZE (5.0f) +#define MAX_DISPLACEMENT (1.0f) +#define DISPLACEMENT_SIGN_LIMIT (0.3f) +#define MAX_ITER (200) +#define NUM_ITER_AT_A_TIME (1) + +/* Map general information */ +#define MAP_SIZE (10.0f) +#define MAP_NUM_VERTICES (80) +#define MAP_NUM_TOTAL_VERTICES (MAP_NUM_VERTICES*MAP_NUM_VERTICES) +#define MAP_NUM_LINES (3* (MAP_NUM_VERTICES - 1) * (MAP_NUM_VERTICES - 1) + \ + 2 * (MAP_NUM_VERTICES - 1)) + + +/* OpenGL function pointers */ + +static PFN_glBindVertexArray pglBindVertexArray = NULL; +static PFN_glBufferData pglBufferData = NULL; +static PFN_glBindBuffer pglBindBuffer = NULL; +static PFN_glBufferSubData pglBufferSubData = NULL; +static PFN_glEnableVertexAttribArray pglEnableVertexAttribArray = NULL; +static PFN_glVertexAttribPointer pglVertexAttribPointer = NULL; + +#define RESOLVE_GL_FCN(type, var, name) \ + if (status == GL_TRUE) \ + {\ + var = glfwGetProcAddress((name));\ + if ((var) == NULL)\ + {\ + status = GL_FALSE;\ + }\ + } + + +static GLboolean init_opengl(void) +{ + GLboolean status = GL_TRUE; + RESOLVE_GL_FCN(PFN_glCreateShader, pglCreateShader, "glCreateShader"); + RESOLVE_GL_FCN(PFN_glShaderSource, pglShaderSource, "glShaderSource"); + RESOLVE_GL_FCN(PFN_glCompileShader, pglCompileShader, "glCompileShader"); + RESOLVE_GL_FCN(PFN_glGetShaderiv, pglGetShaderiv, "glGetShaderiv"); + RESOLVE_GL_FCN(PFN_glGetShaderInfoLog, pglGetShaderInfoLog, "glGetShaderInfoLog"); + RESOLVE_GL_FCN(PFN_glDeleteShader, pglDeleteShader, "glDeleteShader"); + RESOLVE_GL_FCN(PFN_glCreateProgram, pglCreateProgram, "glCreateProgram"); + RESOLVE_GL_FCN(PFN_glAttachShader, pglAttachShader, "glAttachShader"); + RESOLVE_GL_FCN(PFN_glLinkProgram, pglLinkProgram, "glLinkProgram"); + RESOLVE_GL_FCN(PFN_glUseProgram, pglUseProgram, "glUseProgram"); + RESOLVE_GL_FCN(PFN_glGetProgramiv, pglGetProgramiv, "glGetProgramiv"); + RESOLVE_GL_FCN(PFN_glGetProgramInfoLog, pglGetProgramInfoLog, "glGetProgramInfoLog"); + RESOLVE_GL_FCN(PFN_glDeleteProgram, pglDeleteProgram, "glDeleteProgram"); + RESOLVE_GL_FCN(PFN_glGetUniformLocation, pglGetUniformLocation, "glGetUniformLocation"); + RESOLVE_GL_FCN(PFN_glUniformMatrix4fv, pglUniformMatrix4fv, "glUniformMatrix4fv"); + RESOLVE_GL_FCN(PFN_glGetAttribLocation, pglGetAttribLocation, "glGetAttribLocation"); + RESOLVE_GL_FCN(PFN_glGenVertexArrays, pglGenVertexArrays, "glGenVertexArrays"); + RESOLVE_GL_FCN(PFN_glDeleteVertexArrays, pglDeleteVertexArrays, "glDeleteVertexArrays"); + RESOLVE_GL_FCN(PFN_glBindVertexArray, pglBindVertexArray, "glBindVertexArray"); + RESOLVE_GL_FCN(PFN_glGenBuffers, pglGenBuffers, "glGenBuffers"); + RESOLVE_GL_FCN(PFN_glBindBuffer, pglBindBuffer, "glBindBuffer"); + RESOLVE_GL_FCN(PFN_glBufferData, pglBufferData, "glBufferData"); + RESOLVE_GL_FCN(PFN_glBufferSubData, pglBufferSubData, "glBufferSubData"); + RESOLVE_GL_FCN(PFN_glEnableVertexAttribArray, pglEnableVertexAttribArray, "glEnableVertexAttribArray"); + RESOLVE_GL_FCN(PFN_glVertexAttribPointer, pglVertexAttribPointer, "glVertexAttribPointer"); + return status; +} +/********************************************************************** + * Default shader programs + *********************************************************************/ + +static const char* default_vertex_shader = +"#version 150\n" +"uniform mat4 project;\n" +"uniform mat4 modelview;\n" +"in float x;\n" +"in float y;\n" +"in float z;\n" +"\n" +"void main()\n" +"{\n" +" gl_Position = project * modelview * vec4(x, y, z, 1.0);\n" +"}\n"; + +static const char* default_fragment_shader = +"#version 150\n" +"out vec4 gl_FragColor;\n" +"void main()\n" +"{\n" +" gl_FragColor = vec4(0.2, 1.0, 0.2, 1.0); \n" +"}\n"; + +/********************************************************************** + * Values for shader uniforms + *********************************************************************/ + +/* Frustum configuration */ +static GLfloat view_angle = 45.0f; +static GLfloat aspect_ratio = 4.0f/3.0f; +static GLfloat z_near = 1.0f; +static GLfloat z_far = 100.f; + +/* Projection matrix */ +static GLfloat projection_matrix[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f +}; + +/* Model view matrix */ +static GLfloat modelview_matrix[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f +}; + +/********************************************************************** + * Heightmap vertex and index data + *********************************************************************/ + +static GLfloat map_vertices[3][MAP_NUM_TOTAL_VERTICES]; +static GLuint map_line_indices[2*MAP_NUM_LINES]; + +/* Store uniform location for the shaders + * Those values are setup as part of the process of creating + * the shader program. They should not be used before creating + * the program. + */ +static GLuint mesh; +static GLuint mesh_vbo[4]; + +/********************************************************************** + * OpenGL helper functions + *********************************************************************/ + +/* Load a (text) file into memory and return its contents + */ +static char* read_file_content(const char* filename) +{ + FILE* fd; + size_t size = 0; + char* result = NULL; + + fd = fopen(filename, "r"); + if (fd != NULL) + { + size = fseek(fd, 0, SEEK_END); + (void) fseek(fd, 0, SEEK_SET); + + result = malloc(size + 1); + result[size] = '\0'; + if (fread(result, size, 1, fd) != 1) + { + free(result); + result = NULL; + } + (void) fclose(fd); + } + return result; +} + +/* Creates a shader object of the specified type using the specified text + */ +static GLuint make_shader(GLenum type, const char* shader_src) +{ + GLuint shader; + GLint shader_ok; + GLsizei log_length; + char info_log[8192]; + + shader = pglCreateShader(type); + if (shader != 0) + { + pglShaderSource(shader, 1, (const GLchar**)&shader_src, NULL); + pglCompileShader(shader); + pglGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok); + if (shader_ok != GL_TRUE) + { + fprintf(stderr, "ERROR: Failed to compile %s shader\n", (type == GL_FRAGMENT_SHADER) ? "fragment" : "vertex" ); + pglGetShaderInfoLog(shader, 8192, &log_length,info_log); + fprintf(stderr, "ERROR: \n%s\n\n", info_log); + pglDeleteShader(shader); + shader = 0; + } + } + return shader; +} + +/* Creates a program object using the specified vertex and fragment text + */ +static GLuint make_shader_program(const char* vertex_shader_src, const char* fragment_shader_src) +{ + GLuint program = 0u; + GLint program_ok; + GLuint vertex_shader = 0u; + GLuint fragment_shader = 0u; + GLsizei log_length; + char info_log[8192]; + + vertex_shader = make_shader(GL_VERTEX_SHADER, (vertex_shader_src == NULL) ? default_vertex_shader : vertex_shader_src); + if (vertex_shader != 0u) + { + fragment_shader = make_shader(GL_FRAGMENT_SHADER, (fragment_shader_src == NULL) ? default_fragment_shader : fragment_shader_src); + if (fragment_shader != 0u) + { + /* make the program that connect the two shader and link it */ + program = pglCreateProgram(); + if (program != 0u) + { + /* attach both shader and link */ + pglAttachShader(program, vertex_shader); + pglAttachShader(program, fragment_shader); + pglLinkProgram(program); + pglGetProgramiv(program, GL_LINK_STATUS, &program_ok); + + if (program_ok != GL_TRUE) + { + fprintf(stderr, "ERROR, failed to link shader program\n"); + pglGetProgramInfoLog(program, 8192, &log_length, info_log); + fprintf(stderr, "ERROR: \n%s\n\n", info_log); + pglDeleteProgram(program); + pglDeleteShader(fragment_shader); + pglDeleteShader(vertex_shader); + program = 0u; + } + } + } + else + { + fprintf(stderr, "ERROR: Unable to load fragment shader\n"); + pglDeleteShader(vertex_shader); + } + } + else + { + fprintf(stderr, "ERROR: Unable to load vertex shader\n"); + } + return program; +} + +/********************************************************************** + * Geometry creation functions + *********************************************************************/ + +/* Generate vertices and indices for the heightmap + */ +static void init_map(void) +{ + int i; + int j; + int k; + GLfloat step = MAP_SIZE / (MAP_NUM_VERTICES - 1); + GLfloat x = 0.0f; + GLfloat z = 0.0f; + /* Create a flat grid */ + k = 0; + for (i = 0 ; i < MAP_NUM_VERTICES ; ++i) + { + for (j = 0 ; j < MAP_NUM_VERTICES ; ++j) + { + map_vertices[0][k] = x; + map_vertices[1][k] = 0.0f; + map_vertices[2][k] = z; + z += step; + ++k; + } + x += step; + z = 0.0f; + } +#if DEBUG_ENABLED + for (i = 0 ; i < MAP_NUM_TOTAL_VERTICES ; ++i) + { + printf ("Vertice %d (%f, %f, %f)\n", + i, map_vertices[0][i], map_vertices[1][i], map_vertices[2][i]); + + } +#endif + /* create indices */ + /* line fan based on i + * i+1 + * | / i + n + 1 + * | / + * |/ + * i --- i + n + */ + + /* close the top of the square */ + k = 0; + for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i) + { + map_line_indices[k++] = (i + 1) * MAP_NUM_VERTICES -1; + map_line_indices[k++] = (i + 2) * MAP_NUM_VERTICES -1; + } + /* close the right of the square */ + for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i) + { + map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i; + map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i + 1; + } + + for (i = 0 ; i < (MAP_NUM_VERTICES - 1) ; ++i) + { + for (j = 0 ; j < (MAP_NUM_VERTICES - 1) ; ++j) + { + int ref = i * (MAP_NUM_VERTICES) + j; + map_line_indices[k++] = ref; + map_line_indices[k++] = ref + 1; + + map_line_indices[k++] = ref; + map_line_indices[k++] = ref + MAP_NUM_VERTICES; + + map_line_indices[k++] = ref; + map_line_indices[k++] = ref + MAP_NUM_VERTICES + 1; + } + } + +#ifdef DEBUG_ENABLED + for (k = 0 ; k < 2 * MAP_NUM_LINES ; k += 2) + { + int beg, end; + beg = map_line_indices[k]; + end = map_line_indices[k+1]; + printf ("Line %d: %d -> %d (%f, %f, %f) -> (%f, %f, %f)\n", + k / 2, beg, end, + map_vertices[0][beg], map_vertices[1][beg], map_vertices[2][beg], + map_vertices[0][end], map_vertices[1][end], map_vertices[2][end]); + } +#endif +} + +static void generate_heightmap__circle(float* center_x, float* center_y, + float* size, float* displacement) +{ + float sign; + /* random value for element in between [0-1.0] */ + *center_x = (MAP_SIZE * rand()) / (1.0f * RAND_MAX); + *center_y = (MAP_SIZE * rand()) / (1.0f * RAND_MAX); + *size = (MAX_CIRCLE_SIZE * rand()) / (1.0f * RAND_MAX); + sign = (1.0f * rand()) / (1.0f * RAND_MAX); + sign = (sign < DISPLACEMENT_SIGN_LIMIT) ? -1.0f : 1.0f; + *displacement = (sign * (MAX_DISPLACEMENT * rand())) / (1.0f * RAND_MAX); +} + +/* Run the specified number of iterations of the generation process for the + * heightmap + */ +static void update_map(int num_iter) +{ + assert(num_iter > 0); + while(num_iter) + { + /* center of the circle */ + float center_x; + float center_z; + float circle_size; + float disp; + size_t ii; + generate_heightmap__circle(¢er_x, ¢er_z, &circle_size, &disp); + disp = disp / 2.0f; + for (ii = 0u ; ii < MAP_NUM_TOTAL_VERTICES ; ++ii) + { + GLfloat dx = center_x - map_vertices[0][ii]; + GLfloat dz = center_z - map_vertices[2][ii]; + GLfloat pd = (2.0f * sqrtf((dx * dx) + (dz * dz))) / circle_size; + if (fabs(pd) <= 1.0f) + { + /* tx,tz is within the circle */ + GLfloat new_height = disp + ((GLfloat) cos(pd*3.14f) * disp); + map_vertices[1][ii] += new_height; + } + } + --num_iter; + } +} + +/********************************************************************** + * OpenGL helper functions + *********************************************************************/ + +/* Create VBO, IBO and VAO objects for the heightmap geometry and bind them to + * the specified program object + */ +static void make_mesh(GLuint program) +{ + GLuint attrloc; + + pglGenVertexArrays(1, &mesh); + pglGenBuffers(4, mesh_vbo); + pglBindVertexArray(mesh); + /* Prepare the data for drawing through a buffer inidices */ + pglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh_vbo[3]); + pglBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)* MAP_NUM_LINES * 2, map_line_indices, GL_STATIC_DRAW); + + /* Prepare the attributes for rendering */ + attrloc = pglGetAttribLocation(program, "x"); + pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[0]); + pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[0][0], GL_STATIC_DRAW); + pglEnableVertexAttribArray(attrloc); + pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); + + attrloc = pglGetAttribLocation(program, "z"); + pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[2]); + pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[2][0], GL_STATIC_DRAW); + pglEnableVertexAttribArray(attrloc); + pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); + + attrloc = pglGetAttribLocation(program, "y"); + pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[1]); + pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0], GL_DYNAMIC_DRAW); + pglEnableVertexAttribArray(attrloc); + pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); +} + +/* Update VBO vertices from source data + */ +static void update_mesh(void) +{ + pglBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0]); +} + +/********************************************************************** + * GLFW callback functions + *********************************************************************/ + +/* The program runs as long as this is GL_TRUE + */ +static GLboolean running = GL_TRUE; + +/* GLFW Window management functions */ +static int GLFWCALL close_window_callback(void) +{ + running = GL_FALSE; + + /* Disallow window closing + * The window will be closed when the main loop terminates */ + return GL_FALSE; +} + +static void GLFWCALL key_callback(int key, int action) +{ + switch(key) + { + case GLFW_KEY_ESC: + /* Exit program on Escape */ + running = GL_FALSE; + break; + } +} + +/* Print usage information */ +static void usage(void) +{ + printf("Usage: heightmap [-v ] [-f ]\n"); + printf(" heightmap [-h]\n"); +} + +int main(int argc, char** argv) +{ + int ch, iter; + double dt; + double last_update_time; + int frame; + float f; + GLint uloc_modelview; + GLint uloc_project; + + char* vertex_shader_path = NULL; + char* fragment_shader_path = NULL; + char* vertex_shader_src = NULL; + char* fragment_shader_src = NULL; + GLuint shader_program; + + while ((ch = getopt(argc, argv, "f:v:h")) != -1) + { + switch (ch) + { + case 'f': + fragment_shader_path = optarg; + break; + case 'v': + vertex_shader_path = optarg; + break; + case 'h': + usage(); + exit(EXIT_SUCCESS); + default: + usage(); + exit(EXIT_FAILURE); + } + } + + if (fragment_shader_path) + { + vertex_shader_src = read_file_content(fragment_shader_path); + if (!fragment_shader_src) + { + fprintf(stderr, + "ERROR: unable to load fragment shader from '%s'\n", + fragment_shader_path); + exit(EXIT_FAILURE); + } + } + + if (vertex_shader_path) + { + vertex_shader_src = read_file_content(vertex_shader_path); + if (!vertex_shader_src) + { + fprintf(stderr, + "ERROR: unable to load vertex shader from '%s'\n", + fragment_shader_path); + exit(EXIT_FAILURE); + } + } + + if (GL_TRUE != glfwInit()) + { + fprintf(stderr, "ERROR: Unable to initialize GLFW\n"); + usage(); + + free(vertex_shader_src); + free(fragment_shader_src); + exit(EXIT_FAILURE); + } + + glfwEnable(GLFW_AUTO_POLL_EVENTS); /* No explicit call to glfwPollEvents() */ + + glfwOpenWindowHint(GLFW_WINDOW_NO_RESIZE, GL_TRUE); + glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3); + glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 2); + glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); + + if (GL_TRUE != glfwOpenWindow(800, 600, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) + { + fprintf(stderr, "ERROR: Unable to create the OpenGL context and associated window\n"); + usage(); + + free(vertex_shader_src); + free(fragment_shader_src); + exit(EXIT_FAILURE); + } + + glfwSetWindowTitle("GLFW OpenGL3 Heightmap demo"); + /* Register events callback */ + glfwSetWindowCloseCallback(close_window_callback); + glfwSetKeyCallback(key_callback); + + if (GL_TRUE != init_opengl()) + { + fprintf(stderr, "ERROR: unable to resolve OpenGL function pointers\n"); + free(vertex_shader_src); + free(fragment_shader_src); + exit(EXIT_FAILURE); + } + /* Prepare opengl resources for rendering */ + shader_program = make_shader_program(vertex_shader_src , fragment_shader_src); + free(vertex_shader_src); + free(fragment_shader_src); + + if (shader_program == 0u) + { + fprintf(stderr, "ERROR: during creation of the shader program\n"); + usage(); + exit(EXIT_FAILURE); + } + + pglUseProgram(shader_program); + uloc_project = pglGetUniformLocation(shader_program, "project"); + uloc_modelview = pglGetUniformLocation(shader_program, "modelview"); + + /* Compute the projection matrix */ + f = 1.0f / tanf(view_angle / 2.0f); + projection_matrix[0] = f / aspect_ratio; + projection_matrix[5] = f; + projection_matrix[10] = (z_far + z_near)/ (z_near - z_far); + projection_matrix[11] = -1.0f; + projection_matrix[14] = 2.0f * (z_far * z_near) / (z_near - z_far); + pglUniformMatrix4fv(uloc_project, 1, GL_FALSE, projection_matrix); + + /* Set the camera position */ + modelview_matrix[12] = -5.0f; + modelview_matrix[13] = -5.0f; + modelview_matrix[14] = -20.0f; + pglUniformMatrix4fv(uloc_modelview, 1, GL_FALSE, modelview_matrix); + + /* Create mesh data */ + init_map(); + make_mesh(shader_program); + + /* Create vao + vbo to store the mesh */ + /* Create the vbo to store all the information for the grid and the height */ + + /* setup the scene ready for rendering */ + glViewport(0, 0, 800, 600); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + /* main loop */ + frame = 0; + iter = 0; + dt = last_update_time = glfwGetTime(); + + while (running) + { + ++frame; + /* render the next frame */ + glClear(GL_COLOR_BUFFER_BIT); + glDrawElements(GL_LINES, 2* MAP_NUM_LINES , GL_UNSIGNED_INT, 0); + + /* display and process events through callbacks */ + glfwSwapBuffers(); + /* Check the frame rate and update the heightmap if needed */ + dt = glfwGetTime(); + if ((dt - last_update_time) > 0.2) + { + /* generate the next iteration of the heightmap */ + if (iter < MAX_ITER) + { + update_map(NUM_ITER_AT_A_TIME); + update_mesh(); + iter += NUM_ITER_AT_A_TIME; + } + last_update_time = dt; + frame = 0; + } + } + + exit(EXIT_SUCCESS); +} + diff --git a/tests/glfw/listmodes.c b/tests/glfw/listmodes.c new file mode 100644 index 0000000000000..717cfde0c66dc --- /dev/null +++ b/tests/glfw/listmodes.c @@ -0,0 +1,48 @@ +//======================================================================== +// This is a small test application for GLFW. +// The program lists all available fullscreen video modes. +//======================================================================== + +#include +#include + +// Maximum number of modes that we want to list +#define MAX_NUM_MODES 400 + + +//======================================================================== +// main() +//======================================================================== + +int main( void ) +{ + GLFWvidmode dtmode, modes[ MAX_NUM_MODES ]; + int modecount, i; + + // Initialize GLFW + if( !glfwInit() ) + { + return 0; + } + + // Show desktop video mode + glfwGetDesktopMode( &dtmode ); + printf( "Desktop mode: %d x %d x %d\n\n", + dtmode.Width, dtmode.Height, dtmode.RedBits + + dtmode.GreenBits + dtmode.BlueBits ); + + // List available video modes + modecount = glfwGetVideoModes( modes, MAX_NUM_MODES ); + printf( "Available modes:\n" ); + for( i = 0; i < modecount; i ++ ) + { + printf( "%3d: %d x %d x %d\n", i, + modes[i].Width, modes[i].Height, modes[i].RedBits + + modes[i].GreenBits + modes[i].BlueBits ); + } + + // Terminate GLFW + glfwTerminate(); + + return 0; +} diff --git a/tests/glfw/mipmaps.c b/tests/glfw/mipmaps.c new file mode 100644 index 0000000000000..59bbef2e33774 --- /dev/null +++ b/tests/glfw/mipmaps.c @@ -0,0 +1,122 @@ +//======================================================================== +// This is an example program for the GLFW library +// +// It shows texture loading with mipmap generation and rendering with +// trilienar texture filtering +//======================================================================== + +#include +#include + +#include + +int main( void ) +{ + int width, height, x; + double time; + GLboolean running; + GLuint textureID; + char* texturePath = "mipmaps.tga"; + + // Initialise GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open OpenGL window + if( !glfwOpenWindow( 640, 480, 0,0,0,0, 0,0, GLFW_WINDOW ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + glfwSetWindowTitle( "Trilinear interpolation" ); + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Enable vertical sync (on cards that support it) + glfwSwapInterval( 1 ); + + // Generate and bind our texture ID + glGenTextures( 1, &textureID ); + glBindTexture( GL_TEXTURE_2D, textureID ); + + // Load texture from file into video memory, including mipmap levels + if( !glfwLoadTexture2D( texturePath, GLFW_BUILD_MIPMAPS_BIT ) ) + { + fprintf( stderr, "Failed to load texture %s\n", texturePath ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + // Use trilinear interpolation (GL_LINEAR_MIPMAP_LINEAR) + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + GL_LINEAR ); + + // Enable plain 2D texturing + glEnable( GL_TEXTURE_2D ); + + running = GL_TRUE; + while( running ) + { + // Get time and mouse position + time = glfwGetTime(); + glfwGetMousePos( &x, NULL ); + + // Get window size (may be different than the requested size) + glfwGetWindowSize( &width, &height ); + height = height > 0 ? height : 1; + + // Set viewport + glViewport( 0, 0, width, height ); + + // Clear color buffer + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); + glClear( GL_COLOR_BUFFER_BIT ); + + // Select and setup the projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 65.0f, (GLfloat)width / (GLfloat)height, 1.0f, + 50.0f ); + + // Select and setup the modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 0.0f, 3.0f, -20.0f, // Eye-position + 0.0f, -4.0f, -11.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + + // Draw a textured quad + glRotatef( 0.05f * (GLfloat)x + (GLfloat)time * 5.0f, 0.0f, 1.0f, 0.0f ); + glBegin( GL_QUADS ); + glTexCoord2f( -20.0f, 20.0f ); + glVertex3f( -50.0f, 0.0f, -50.0f ); + glTexCoord2f( 20.0f, 20.0f ); + glVertex3f( 50.0f, 0.0f, -50.0f ); + glTexCoord2f( 20.0f, -20.0f ); + glVertex3f( 50.0f, 0.0f, 50.0f ); + glTexCoord2f( -20.0f, -20.0f ); + glVertex3f( -50.0f, 0.0f, 50.0f ); + glEnd(); + + // Swap buffers + glfwSwapBuffers(); + + // Check if the ESC key was pressed or the window was closed + running = !glfwGetKey( GLFW_KEY_ESC ) && + glfwGetWindowParam( GLFW_OPENED ); + } + + // Close OpenGL window and terminate GLFW + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/tests/glfw/mipmaps.tga b/tests/glfw/mipmaps.tga new file mode 100644 index 0000000000000000000000000000000000000000..55f913b0fa48f69b163664da1db6f9b1fe80e2ed GIT binary patch literal 66322 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 +#include + + +typedef struct { + GLFWcond cond; + GLFWmutex mutex; + int flag; +} signal_t; + + +signal_t gotoA, gotoB; + +GLFWcond threadDone; +GLFWmutex doneMutex; +int doneCount; +int gotoACount, gotoBCount; + +#define MAX_COUNT 10000 + + +//------------------------------------------------------------------------ +// InitSignal() +//------------------------------------------------------------------------ + +void InitSignal( signal_t *s ) +{ + s->cond = glfwCreateCond(); + s->mutex = glfwCreateMutex(); + s->flag = 0; +} + + +//------------------------------------------------------------------------ +// KillSignal() +//------------------------------------------------------------------------ + +void KillSignal( signal_t *s ) +{ + glfwDestroyCond( s->cond ); + glfwDestroyMutex( s->mutex ); + s->flag = 0; +} + + +//------------------------------------------------------------------------ +// WaitSignal() +//------------------------------------------------------------------------ + +void WaitSignal( signal_t *s ) +{ + glfwLockMutex( s->mutex ); + while( !s->flag ) + { + glfwWaitCond( s->cond, s->mutex, GLFW_INFINITY ); + } + s->flag = 0; + glfwUnlockMutex( s->mutex ); +} + + +//------------------------------------------------------------------------ +// SetSignal() +//------------------------------------------------------------------------ + +void SetSignal( signal_t *s ) +{ + glfwLockMutex( s->mutex ); + s->flag = 1; + glfwUnlockMutex( s->mutex ); + glfwSignalCond( s->cond ); +} + + +//------------------------------------------------------------------------ +// threadAfun() +//------------------------------------------------------------------------ + +void GLFWCALL threadAfun( void * arg ) +{ + int done; + + do + { + done = (gotoACount >= MAX_COUNT); + if( !done ) + { + gotoACount ++; + SetSignal( &gotoB ); + WaitSignal( &gotoA ); + } + } + while( !done ); + + SetSignal( &gotoB ); + + glfwLockMutex( doneMutex ); + doneCount ++; + glfwUnlockMutex( doneMutex ); + glfwSignalCond( threadDone ); +} + + +//------------------------------------------------------------------------ +// threadBfun() +//------------------------------------------------------------------------ + +void GLFWCALL threadBfun( void * arg ) +{ + int done; + + do + { + done = (gotoBCount >= MAX_COUNT); + if( !done ) + { + gotoBCount ++; + SetSignal( &gotoA ); + WaitSignal( &gotoB ); + } + } + while( !done ); + + SetSignal( &gotoA ); + + glfwLockMutex( doneMutex ); + doneCount ++; + glfwUnlockMutex( doneMutex ); + glfwSignalCond( threadDone ); +} + + + +//------------------------------------------------------------------------ +// main() +//------------------------------------------------------------------------ + +int main( void ) +{ + GLFWthread threadA, threadB; + double t1, t2, csps; + int done, count, i; + + gotoACount = gotoBCount = doneCount = 0; + + // Initialize GLFW + if( !glfwInit() ) + { + return 0; + } + + // Print some program information + printf( "\nMultithreading benchmarking program\n" ); + printf( "-----------------------------------\n\n" ); + printf( "This program consists of two tests. In the first test " ); + printf( "two threads are created,\n" ); + printf( "which continously signal/wait each other. This forces " ); + printf( "the execution to\n" ); + printf( "alternate between the two threads, and gives a measure " ); + printf( "of the thread\n" ); + printf( "synchronization granularity. In the second test, the " ); + printf( "main thread is repeatedly\n" ); + printf( "put to sleep for a very short interval using glfwSleep. " ); + printf( "The average sleep time\n" ); + printf( "is measured, which tells the minimum supported sleep " ); + printf( "interval.\n\n" ); + printf( "Results:\n" ); + printf( "--------\n\n" ); + printf( "Number of CPUs: %d\n\n", glfwGetNumberOfProcessors() ); + fflush( stdout ); + + +//------------------------------------------------------------------------ +// 1) Benchmark thread synchronization granularity +//------------------------------------------------------------------------ + + // Init mutexes and conditions + doneMutex = glfwCreateMutex(); + threadDone = glfwCreateCond(); + InitSignal( &gotoA ); + InitSignal( &gotoB ); + + // Create threads A & B + threadA = glfwCreateThread( threadAfun, NULL ); + threadB = glfwCreateThread( threadBfun, NULL ); + if( threadA == -1 || threadB == -1 ) + { + glfwLockMutex( doneMutex ); + doneCount = 2; + glfwUnlockMutex( doneMutex ); + } + + // Wait for both threads to be done + t1 = glfwGetTime(); + glfwLockMutex( doneMutex ); + do + { + done = (doneCount == 2); + if( !done ) + { + glfwWaitCond( threadDone, doneMutex, GLFW_INFINITY ); + } + } + while( !done ); + glfwUnlockMutex( doneMutex ); + t2 = glfwGetTime(); + + // Display results + count = gotoACount + gotoBCount; + csps = (double)count / (t2-t1); + printf( "Test 1: %.0f context switches / second (%.3f us/switch)\n", + csps, 1e6/csps ); + fflush( stdout ); + + // Wait for threads to die + glfwWaitThread( threadA, GLFW_WAIT ); + glfwWaitThread( threadB, GLFW_WAIT ); + + // Destroy mutexes and conditions + glfwDestroyMutex( doneMutex ); + glfwDestroyCond( threadDone ); + KillSignal( &gotoA ); + KillSignal( &gotoB ); + + +//------------------------------------------------------------------------ +// 2) Benchmark thread sleep granularity +//------------------------------------------------------------------------ + + // Find an initial estimate + t1 = glfwGetTime(); + for( i = 0; i < 10; i ++ ) + { + glfwSleep( 0.0001 ); + } + t2 = glfwGetTime(); + + // Sleep for roughly 1 s + count = (int)(1.0 / ((t2-t1)/10.0)); + t1 = glfwGetTime(); + for( i = 0; i < count; i ++ ) + { + glfwSleep( 0.0001 ); + } + t2 = glfwGetTime(); + + // Display results + printf( "Test 2: %.3f ms / sleep (mean)\n\n", + 1000.0 * (t2-t1) / (double)count ); + + // Terminate GLFW + glfwTerminate(); + + return 0; +} diff --git a/tests/glfw/mthello.c b/tests/glfw/mthello.c new file mode 100644 index 0000000000000..e12dea52551e9 --- /dev/null +++ b/tests/glfw/mthello.c @@ -0,0 +1,48 @@ +//======================================================================== +// This is a small test application for GLFW. +// The program prints "Hello world!", using two threads. +//======================================================================== + +#include +#include + + +//======================================================================== +// HelloFun() - Thread function +//======================================================================== + +void GLFWCALL HelloFun( void *arg ) +{ + // Print the first part of the message + printf( "Hello " ); +} + + +//======================================================================== +// main() - Main function (main thread) +//======================================================================== + +int main( void ) +{ + GLFWthread thread; + + // Initialise GLFW + if( !glfwInit() ) + { + return 0; + } + + // Create thread + thread = glfwCreateThread( HelloFun, NULL ); + + // Wait for thread to die + glfwWaitThread( thread, GLFW_WAIT ); + + // Print the rest of the message + printf( "world!\n" ); + + // Terminate GLFW + glfwTerminate(); + + return 0; +} diff --git a/tests/glfw/particles.c b/tests/glfw/particles.c new file mode 100644 index 0000000000000..403a99978e9fa --- /dev/null +++ b/tests/glfw/particles.c @@ -0,0 +1,1152 @@ +//======================================================================== +// This is a simple, but cool particle engine (buzz-word meaning many +// small objects that are treated as points and drawn as textures +// projected on simple geometry). +// +// This demonstration generates a colorful fountain-like animation. It +// uses several advanced OpenGL teqhniques: +// +// 1) Lighting (per vertex) +// 2) Alpha blending +// 3) Fog +// 4) Texturing +// 5) Display lists (for drawing the static environment geometry) +// 6) Vertex arrays (for drawing the particles) +// 7) GL_EXT_separate_specular_color is used (if available) +// +// Even more so, this program uses multi threading. The program is +// essentialy divided into a main rendering thread and a particle physics +// calculation thread. My benchmarks under Windows 2000 on a single +// processor system show that running this program as two threads instead +// of a single thread means no difference (there may be a very marginal +// advantage for the multi threaded case). On dual processor systems I +// have had reports of 5-25% of speed increase when running this program +// as two threads instead of one thread. +// +// The default behaviour of this program is to use two threads. To force +// a single thread to be used, use the command line switch -s. +// +// To run a fixed length benchmark (60 s), use the command line switch -b. +// +// Benchmark results (640x480x16, best of three tests): +// +// CPU GFX 1 thread 2 threads +// Athlon XP 2700+ GeForce Ti4200 (oc) 757 FPS 759 FPS +// P4 2.8 GHz (SMT) GeForce FX5600 548 FPS 550 FPS +// +// One more thing: Press 'w' during the demo to toggle wireframe mode. +//======================================================================== + +#include +#include +#include +#include +#include + +// Define tokens for GL_EXT_separate_specular_color if not already defined +#ifndef GL_EXT_separate_specular_color +#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 +#define GL_SINGLE_COLOR_EXT 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA +#endif // GL_EXT_separate_specular_color + +// Some 's do not define M_PI +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +// Desired fullscreen resolution +#define WIDTH 640 +#define HEIGHT 480 + + +//======================================================================== +// Type definitions +//======================================================================== + +typedef struct { float x,y,z; } VEC; + +// This structure is used for interleaved vertex arrays (see the +// DrawParticles function) - Note: This structure SHOULD be packed on most +// systems. It uses 32-bit fields on 32-bit boundaries, and is a multiple +// of 64 bits in total (6x32=3x64). If it does not work, try using pragmas +// or whatever to force the structure to be packed. +typedef struct { + GLfloat s, t; // Texture coordinates + GLuint rgba; // Color (four ubytes packed into an uint) + GLfloat x, y, z; // Vertex coordinates +} VERTEX; + + +//======================================================================== +// Program control global variables +//======================================================================== + +// "Running" flag (true if program shall continue to run) +int running; + +// Window dimensions +int width, height; + +// "wireframe" flag (true if we use wireframe view) +int wireframe; + +// "multithreading" flag (true if we use multithreading) +int multithreading; + +// Thread synchronization +struct { + double t; // Time (s) + float dt; // Time since last frame (s) + int p_frame; // Particle physics frame number + int d_frame; // Particle draw frame number + GLFWcond p_done; // Condition: particle physics done + GLFWcond d_done; // Condition: particle draw done + GLFWmutex particles_lock; // Particles data sharing mutex +} thread_sync; + + +//======================================================================== +// Texture declarations (we hard-code them into the source code, since +// they are so simple) +//======================================================================== + +#define P_TEX_WIDTH 8 // Particle texture dimensions +#define P_TEX_HEIGHT 8 +#define F_TEX_WIDTH 16 // Floor texture dimensions +#define F_TEX_HEIGHT 16 + +// Texture object IDs +GLuint particle_tex_id, floor_tex_id; + +// Particle texture (a simple spot) +const unsigned char particle_texture[ P_TEX_WIDTH * P_TEX_HEIGHT ] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x11, 0x22, 0x22, 0x11, 0x00, 0x00, + 0x00, 0x11, 0x33, 0x88, 0x77, 0x33, 0x11, 0x00, + 0x00, 0x22, 0x88, 0xff, 0xee, 0x77, 0x22, 0x00, + 0x00, 0x22, 0x77, 0xee, 0xff, 0x88, 0x22, 0x00, + 0x00, 0x11, 0x33, 0x77, 0x88, 0x33, 0x11, 0x00, + 0x00, 0x00, 0x11, 0x33, 0x22, 0x11, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// Floor texture (your basic checkered floor) +const unsigned char floor_texture[ F_TEX_WIDTH * F_TEX_HEIGHT ] = { + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xff, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xf0, 0xcc, 0xee, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x66, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xee, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x55, 0x30, 0x30, 0x44, 0x30, 0x30, + 0xf0, 0xdd, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x60, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, 0xf0, 0xff, 0xf0, 0xf0, 0xdd, 0xf0, 0xf0, 0xff, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x55, 0x33, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, + 0x30, 0x44, 0x66, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xaa, 0xf0, 0xf0, 0xcc, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xdd, 0xf0, + 0x30, 0x30, 0x30, 0x77, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +}; + + +//======================================================================== +// These are fixed constants that control the particle engine. In a +// modular world, these values should be variables... +//======================================================================== + +// Maximum number of particles +#define MAX_PARTICLES 3000 + +// Life span of a particle (in seconds) +#define LIFE_SPAN 8.0f + +// A new particle is born every [BIRTH_INTERVAL] second +#define BIRTH_INTERVAL (LIFE_SPAN/(float)MAX_PARTICLES) + +// Particle size (meters) +#define PARTICLE_SIZE 0.7f + +// Gravitational constant (m/s^2) +#define GRAVITY 9.8f + +// Base initial velocity (m/s) +#define VELOCITY 8.0f + +// Bounce friction (1.0 = no friction, 0.0 = maximum friction) +#define FRICTION 0.75f + +// "Fountain" height (m) +#define FOUNTAIN_HEIGHT 3.0f + +// Fountain radius (m) +#define FOUNTAIN_RADIUS 1.6f + +// Minimum delta-time for particle phisics (s) +#define MIN_DELTA_T (BIRTH_INTERVAL * 0.5f) + + +//======================================================================== +// Particle system global variables +//======================================================================== + +// This structure holds all state for a single particle +typedef struct { + float x,y,z; // Position in space + float vx,vy,vz; // Velocity vector + float r,g,b; // Color of particle + float life; // Life of particle (1.0 = newborn, < 0.0 = dead) + int active; // Tells if this particle is active +} PARTICLE; + +// Global vectors holding all particles. We use two vectors for double +// buffering. +static PARTICLE particles[ MAX_PARTICLES ]; + +// Global variable holding the age of the youngest particle +static float min_age; + +// Color of latest born particle (used for fountain lighting) +static float glow_color[4]; + +// Position of latest born particle (used for fountain lighting) +static float glow_pos[4]; + + +//======================================================================== +// Object material and fog configuration constants +//======================================================================== + +const GLfloat fountain_diffuse[4] = {0.7f,1.0f,1.0f,1.0f}; +const GLfloat fountain_specular[4] = {1.0f,1.0f,1.0f,1.0f}; +const GLfloat fountain_shininess = 12.0f; +const GLfloat floor_diffuse[4] = {1.0f,0.6f,0.6f,1.0f}; +const GLfloat floor_specular[4] = {0.6f,0.6f,0.6f,1.0f}; +const GLfloat floor_shininess = 18.0f; +const GLfloat fog_color[4] = {0.1f, 0.1f, 0.1f, 1.0f}; + + +//======================================================================== +// InitParticle() - Initialize a new particle +//======================================================================== + +void InitParticle( PARTICLE *p, double t ) +{ + float xy_angle, velocity; + + // Start position of particle is at the fountain blow-out + p->x = 0.0f; + p->y = 0.0f; + p->z = FOUNTAIN_HEIGHT; + + // Start velocity is up (Z)... + p->vz = 0.7f + (0.3f/4096.f) * (float) (rand() & 4095); + + // ...and a randomly chosen X/Y direction + xy_angle = (2.f * (float)M_PI / 4096.f) * (float) (rand() & 4095); + p->vx = 0.4f * (float) cos( xy_angle ); + p->vy = 0.4f * (float) sin( xy_angle ); + + // Scale velocity vector according to a time-varying velocity + velocity = VELOCITY*(0.8f + 0.1f*(float)(sin( 0.5*t )+sin( 1.31*t ))); + p->vx *= velocity; + p->vy *= velocity; + p->vz *= velocity; + + // Color is time-varying + p->r = 0.7f + 0.3f * (float) sin( 0.34*t + 0.1 ); + p->g = 0.6f + 0.4f * (float) sin( 0.63*t + 1.1 ); + p->b = 0.6f + 0.4f * (float) sin( 0.91*t + 2.1 ); + + // Store settings for fountain glow lighting + glow_pos[0] = 0.4f * (float) sin( 1.34*t ); + glow_pos[1] = 0.4f * (float) sin( 3.11*t ); + glow_pos[2] = FOUNTAIN_HEIGHT + 1.0f; + glow_pos[3] = 1.0f; + glow_color[0] = p->r; + glow_color[1] = p->g; + glow_color[2] = p->b; + glow_color[3] = 1.0f; + + // The particle is new-born and active + p->life = 1.0f; + p->active = 1; +} + + +//======================================================================== +// UpdateParticle() - Update a particle +//======================================================================== + +#define FOUNTAIN_R2 (FOUNTAIN_RADIUS+PARTICLE_SIZE/2)*(FOUNTAIN_RADIUS+PARTICLE_SIZE/2) + +void UpdateParticle( PARTICLE *p, float dt ) +{ + // If the particle is not active, we need not do anything + if( !p->active ) + { + return; + } + + // The particle is getting older... + p->life = p->life - dt * (1.0f / LIFE_SPAN); + + // Did the particle die? + if( p->life <= 0.0f ) + { + p->active = 0; + return; + } + + // Update particle velocity (apply gravity) + p->vz = p->vz - GRAVITY * dt; + + // Update particle position + p->x = p->x + p->vx * dt; + p->y = p->y + p->vy * dt; + p->z = p->z + p->vz * dt; + + // Simple collision detection + response + if( p->vz < 0.0f ) + { + // Particles should bounce on the fountain (with friction) + if( (p->x*p->x + p->y*p->y) < FOUNTAIN_R2 && + p->z < (FOUNTAIN_HEIGHT + PARTICLE_SIZE/2) ) + { + p->vz = -FRICTION * p->vz; + p->z = FOUNTAIN_HEIGHT + PARTICLE_SIZE/2 + + FRICTION * (FOUNTAIN_HEIGHT + + PARTICLE_SIZE/2 - p->z); + } + + // Particles should bounce on the floor (with friction) + else if( p->z < PARTICLE_SIZE/2 ) + { + p->vz = -FRICTION * p->vz; + p->z = PARTICLE_SIZE/2 + + FRICTION * (PARTICLE_SIZE/2 - p->z); + } + + } +} + + +//======================================================================== +// ParticleEngine() - The main frame for the particle engine. Called once +// per frame. +//======================================================================== + +void ParticleEngine( double t, float dt ) +{ + int i; + float dt2; + + // Update particles (iterated several times per frame if dt is too + // large) + while( dt > 0.0f ) + { + // Calculate delta time for this iteration + dt2 = dt < MIN_DELTA_T ? dt : MIN_DELTA_T; + + // Update particles + for( i = 0; i < MAX_PARTICLES; i ++ ) + { + UpdateParticle( &particles[ i ], dt2 ); + } + + // Increase minimum age + min_age += dt2; + + // Should we create any new particle(s)? + while( min_age >= BIRTH_INTERVAL ) + { + min_age -= BIRTH_INTERVAL; + + // Find a dead particle to replace with a new one + for( i = 0; i < MAX_PARTICLES; i ++ ) + { + if( !particles[ i ].active ) + { + InitParticle( &particles[ i ], t + min_age ); + UpdateParticle( &particles[ i ], min_age ); + break; + } + } + } + + // Decrease frame delta time + dt -= dt2; + } +} + + +//======================================================================== +// DrawParticles() - Draw all active particles. We use OpenGL 1.1 vertex +// arrays for this in order to accelerate the drawing. +//======================================================================== + +#define BATCH_PARTICLES 70 // Number of particles to draw in each batch + // (70 corresponds to 7.5 KB = will not blow + // the L1 data cache on most CPUs) +#define PARTICLE_VERTS 4 // Number of vertices per particle + +void DrawParticles( double t, float dt ) +{ + int i, particle_count; + VERTEX vertex_array[ BATCH_PARTICLES * PARTICLE_VERTS ], *vptr; + float alpha; + GLuint rgba; + VEC quad_lower_left, quad_lower_right; + GLfloat mat[ 16 ]; + PARTICLE *pptr; + + // Here comes the real trick with flat single primitive objects (s.c. + // "billboards"): We must rotate the textured primitive so that it + // always faces the viewer (is coplanar with the view-plane). + // We: + // 1) Create the primitive around origo (0,0,0) + // 2) Rotate it so that it is coplanar with the view plane + // 3) Translate it according to the particle position + // Note that 1) and 2) is the same for all particles (done only once). + + // Get modelview matrix. We will only use the upper left 3x3 part of + // the matrix, which represents the rotation. + glGetFloatv( GL_MODELVIEW_MATRIX, mat ); + + // 1) & 2) We do it in one swift step: + // Although not obvious, the following six lines represent two matrix/ + // vector multiplications. The matrix is the inverse 3x3 rotation + // matrix (i.e. the transpose of the same matrix), and the two vectors + // represent the lower left corner of the quad, PARTICLE_SIZE/2 * + // (-1,-1,0), and the lower right corner, PARTICLE_SIZE/2 * (1,-1,0). + // The upper left/right corners of the quad is always the negative of + // the opposite corners (regardless of rotation). + quad_lower_left.x = (-PARTICLE_SIZE/2) * (mat[0] + mat[1]); + quad_lower_left.y = (-PARTICLE_SIZE/2) * (mat[4] + mat[5]); + quad_lower_left.z = (-PARTICLE_SIZE/2) * (mat[8] + mat[9]); + quad_lower_right.x = (PARTICLE_SIZE/2) * (mat[0] - mat[1]); + quad_lower_right.y = (PARTICLE_SIZE/2) * (mat[4] - mat[5]); + quad_lower_right.z = (PARTICLE_SIZE/2) * (mat[8] - mat[9]); + + // Don't update z-buffer, since all particles are transparent! + glDepthMask( GL_FALSE ); + + // Enable blending + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE ); + + // Select particle texture + if( !wireframe ) + { + glEnable( GL_TEXTURE_2D ); + glBindTexture( GL_TEXTURE_2D, particle_tex_id ); + } + + // Set up vertex arrays. We use interleaved arrays, which is easier to + // handle (in most situations) and it gives a linear memeory access + // access pattern (which may give better performance in some + // situations). GL_T2F_C4UB_V3F means: 2 floats for texture coords, + // 4 ubytes for color and 3 floats for vertex coord (in that order). + // Most OpenGL cards / drivers are optimized for this format. + glInterleavedArrays( GL_T2F_C4UB_V3F, 0, vertex_array ); + + // Is particle physics carried out in a separate thread? + if( multithreading ) + { + // Wait for particle physics thread to be done + glfwLockMutex( thread_sync.particles_lock ); + while( running && thread_sync.p_frame <= thread_sync.d_frame ) + { + glfwWaitCond( thread_sync.p_done, thread_sync.particles_lock, + 0.1 ); + } + + // Store the frame time and delta time for the physics thread + thread_sync.t = t; + thread_sync.dt = dt; + + // Update frame counter + thread_sync.d_frame ++; + } + else + { + // Perform particle physics in this thread + ParticleEngine( t, dt ); + } + + // Loop through all particles and build vertex arrays. + particle_count = 0; + vptr = vertex_array; + pptr = particles; + for( i = 0; i < MAX_PARTICLES; i ++ ) + { + if( pptr->active ) + { + // Calculate particle intensity (we set it to max during 75% + // of its life, then it fades out) + alpha = 4.0f * pptr->life; + if( alpha > 1.0f ) + { + alpha = 1.0f; + } + + // Convert color from float to 8-bit (store it in a 32-bit + // integer using endian independent type casting) + ((GLubyte *)&rgba)[0] = (GLubyte)(pptr->r * 255.0f); + ((GLubyte *)&rgba)[1] = (GLubyte)(pptr->g * 255.0f); + ((GLubyte *)&rgba)[2] = (GLubyte)(pptr->b * 255.0f); + ((GLubyte *)&rgba)[3] = (GLubyte)(alpha * 255.0f); + + // 3) Translate the quad to the correct position in modelview + // space and store its parameters in vertex arrays (we also + // store texture coord and color information for each vertex). + + // Lower left corner + vptr->s = 0.0f; + vptr->t = 0.0f; + vptr->rgba = rgba; + vptr->x = pptr->x + quad_lower_left.x; + vptr->y = pptr->y + quad_lower_left.y; + vptr->z = pptr->z + quad_lower_left.z; + vptr ++; + + // Lower right corner + vptr->s = 1.0f; + vptr->t = 0.0f; + vptr->rgba = rgba; + vptr->x = pptr->x + quad_lower_right.x; + vptr->y = pptr->y + quad_lower_right.y; + vptr->z = pptr->z + quad_lower_right.z; + vptr ++; + + // Upper right corner + vptr->s = 1.0f; + vptr->t = 1.0f; + vptr->rgba = rgba; + vptr->x = pptr->x - quad_lower_left.x; + vptr->y = pptr->y - quad_lower_left.y; + vptr->z = pptr->z - quad_lower_left.z; + vptr ++; + + // Upper left corner + vptr->s = 0.0f; + vptr->t = 1.0f; + vptr->rgba = rgba; + vptr->x = pptr->x - quad_lower_right.x; + vptr->y = pptr->y - quad_lower_right.y; + vptr->z = pptr->z - quad_lower_right.z; + vptr ++; + + // Increase count of drawable particles + particle_count ++; + } + + // If we have filled up one batch of particles, draw it as a set + // of quads using glDrawArrays. + if( particle_count >= BATCH_PARTICLES ) + { + // The first argument tells which primitive type we use (QUAD) + // The second argument tells the index of the first vertex (0) + // The last argument is the vertex count + glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count ); + particle_count = 0; + vptr = vertex_array; + } + + // Next particle + pptr ++; + } + + // We are done with the particle data: Unlock mutex and signal physics + // thread + if( multithreading ) + { + glfwUnlockMutex( thread_sync.particles_lock ); + glfwSignalCond( thread_sync.d_done ); + } + + // Draw final batch of particles (if any) + glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count ); + + // Disable vertex arrays (Note: glInterleavedArrays implicitly called + // glEnableClientState for vertex, texture coord and color arrays) + glDisableClientState( GL_VERTEX_ARRAY ); + glDisableClientState( GL_TEXTURE_COORD_ARRAY ); + glDisableClientState( GL_COLOR_ARRAY ); + + // Disable texturing and blending + glDisable( GL_TEXTURE_2D ); + glDisable( GL_BLEND ); + + // Allow Z-buffer updates again + glDepthMask( GL_TRUE ); +} + + +//======================================================================== +// Fountain geometry specification +//======================================================================== + +#define FOUNTAIN_SIDE_POINTS 14 +#define FOUNTAIN_SWEEP_STEPS 32 + +static const float fountain_side[ FOUNTAIN_SIDE_POINTS*2 ] = { + 1.2f, 0.0f, 1.0f, 0.2f, 0.41f, 0.3f, 0.4f, 0.35f, + 0.4f, 1.95f, 0.41f, 2.0f, 0.8f, 2.2f, 1.2f, 2.4f, + 1.5f, 2.7f, 1.55f,2.95f, 1.6f, 3.0f, 1.0f, 3.0f, + 0.5f, 3.0f, 0.0f, 3.0f +}; + +static const float fountain_normal[ FOUNTAIN_SIDE_POINTS*2 ] = { + 1.0000f, 0.0000f, 0.6428f, 0.7660f, 0.3420f, 0.9397f, 1.0000f, 0.0000f, + 1.0000f, 0.0000f, 0.3420f,-0.9397f, 0.4226f,-0.9063f, 0.5000f,-0.8660f, + 0.7660f,-0.6428f, 0.9063f,-0.4226f, 0.0000f,1.00000f, 0.0000f,1.00000f, + 0.0000f,1.00000f, 0.0000f,1.00000f +}; + + +//======================================================================== +// DrawFountain() - Draw a fountain +//======================================================================== + +void DrawFountain( void ) +{ + static GLuint fountain_list = 0; + double angle; + float x, y; + int m, n; + + // The first time, we build the fountain display list + if( !fountain_list ) + { + // Start recording of a new display list + fountain_list = glGenLists( 1 ); + glNewList( fountain_list, GL_COMPILE_AND_EXECUTE ); + + // Set fountain material + glMaterialfv( GL_FRONT, GL_DIFFUSE, fountain_diffuse ); + glMaterialfv( GL_FRONT, GL_SPECULAR, fountain_specular ); + glMaterialf( GL_FRONT, GL_SHININESS, fountain_shininess ); + + // Build fountain using triangle strips + for( n = 0; n < FOUNTAIN_SIDE_POINTS-1; n ++ ) + { + glBegin( GL_TRIANGLE_STRIP ); + for( m = 0; m <= FOUNTAIN_SWEEP_STEPS; m ++ ) + { + angle = (double) m * (2.0*M_PI/(double)FOUNTAIN_SWEEP_STEPS); + x = (float) cos( angle ); + y = (float) sin( angle ); + + // Draw triangle strip + glNormal3f( x * fountain_normal[ n*2+2 ], + y * fountain_normal[ n*2+2 ], + fountain_normal[ n*2+3 ] ); + glVertex3f( x * fountain_side[ n*2+2 ], + y * fountain_side[ n*2+2 ], + fountain_side[ n*2+3 ] ); + glNormal3f( x * fountain_normal[ n*2 ], + y * fountain_normal[ n*2 ], + fountain_normal[ n*2+1 ] ); + glVertex3f( x * fountain_side[ n*2 ], + y * fountain_side[ n*2 ], + fountain_side[ n*2+1 ] ); + } + glEnd(); + } + + // End recording of display list + glEndList(); + } + else + { + // Playback display list + glCallList( fountain_list ); + } +} + + +//======================================================================== +// TesselateFloor() - Recursive function for building variable tesselated +// floor +//======================================================================== + +void TesselateFloor( float x1, float y1, float x2, float y2, + int recursion ) +{ + float delta, x, y; + + // Last recursion? + if( recursion >= 5 ) + { + delta = 999999.0f; + } + else + { + x = (float) (fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2)); + y = (float) (fabs(y1) < fabs(y2) ? fabs(y1) : fabs(y2)); + delta = x*x + y*y; + } + + // Recurse further? + if( delta < 0.1f ) + { + x = (x1+x2) * 0.5f; + y = (y1+y2) * 0.5f; + TesselateFloor( x1,y1, x, y, recursion + 1 ); + TesselateFloor( x,y1, x2, y, recursion + 1 ); + TesselateFloor( x1, y, x,y2, recursion + 1 ); + TesselateFloor( x, y, x2,y2, recursion + 1 ); + } + else + { + glTexCoord2f( x1*30.0f, y1*30.0f ); + glVertex3f( x1*80.0f, y1*80.0f , 0.0f ); + glTexCoord2f( x2*30.0f, y1*30.0f ); + glVertex3f( x2*80.0f, y1*80.0f , 0.0f ); + glTexCoord2f( x2*30.0f, y2*30.0f ); + glVertex3f( x2*80.0f, y2*80.0f , 0.0f ); + glTexCoord2f( x1*30.0f, y2*30.0f ); + glVertex3f( x1*80.0f, y2*80.0f , 0.0f ); + } +} + + +//======================================================================== +// DrawFloor() - Draw floor. We builde the floor recursively, and let the +// tesselation in the centre (near x,y=0,0) be high, while the selleation +// around the edges be low. +//======================================================================== + +void DrawFloor( void ) +{ + static GLuint floor_list = 0; + + // Select floor texture + if( !wireframe ) + { + glEnable( GL_TEXTURE_2D ); + glBindTexture( GL_TEXTURE_2D, floor_tex_id ); + } + + // The first time, we build the floor display list + if( !floor_list ) + { + // Start recording of a new display list + floor_list = glGenLists( 1 ); + glNewList( floor_list, GL_COMPILE_AND_EXECUTE ); + + // Set floor material + glMaterialfv( GL_FRONT, GL_DIFFUSE, floor_diffuse ); + glMaterialfv( GL_FRONT, GL_SPECULAR, floor_specular ); + glMaterialf( GL_FRONT, GL_SHININESS, floor_shininess ); + + // Draw floor as a bunch of triangle strips (high tesselation + // improves lighting) + glNormal3f( 0.0f, 0.0f, 1.0f ); + glBegin( GL_QUADS ); + TesselateFloor( -1.0f,-1.0f, 0.0f,0.0f, 0 ); + TesselateFloor( 0.0f,-1.0f, 1.0f,0.0f, 0 ); + TesselateFloor( 0.0f, 0.0f, 1.0f,1.0f, 0 ); + TesselateFloor( -1.0f, 0.0f, 0.0f,1.0f, 0 ); + glEnd(); + + // End recording of display list + glEndList(); + } + else + { + // Playback display list + glCallList( floor_list ); + } + + glDisable( GL_TEXTURE_2D ); + +} + + +//======================================================================== +// SetupLights() - Position and configure light sources +//======================================================================== + +void SetupLights( void ) +{ + float l1pos[4], l1amb[4], l1dif[4], l1spec[4]; + float l2pos[4], l2amb[4], l2dif[4], l2spec[4]; + + // Set light source 1 parameters + l1pos[0] = 0.0f; l1pos[1] = -9.0f; l1pos[2] = 8.0f; l1pos[3] = 1.0f; + l1amb[0] = 0.2f; l1amb[1] = 0.2f; l1amb[2] = 0.2f; l1amb[3] = 1.0f; + l1dif[0] = 0.8f; l1dif[1] = 0.4f; l1dif[2] = 0.2f; l1dif[3] = 1.0f; + l1spec[0] = 1.0f; l1spec[1] = 0.6f; l1spec[2] = 0.2f; l1spec[3] = 0.0f; + + // Set light source 2 parameters + l2pos[0] = -15.0f; l2pos[1] = 12.0f; l2pos[2] = 1.5f; l2pos[3] = 1.0f; + l2amb[0] = 0.0f; l2amb[1] = 0.0f; l2amb[2] = 0.0f; l2amb[3] = 1.0f; + l2dif[0] = 0.2f; l2dif[1] = 0.4f; l2dif[2] = 0.8f; l2dif[3] = 1.0f; + l2spec[0] = 0.2f; l2spec[1] = 0.6f; l2spec[2] = 1.0f; l2spec[3] = 0.0f; + + // Configure light sources in OpenGL + glLightfv( GL_LIGHT1, GL_POSITION, l1pos ); + glLightfv( GL_LIGHT1, GL_AMBIENT, l1amb ); + glLightfv( GL_LIGHT1, GL_DIFFUSE, l1dif ); + glLightfv( GL_LIGHT1, GL_SPECULAR, l1spec ); + glLightfv( GL_LIGHT2, GL_POSITION, l2pos ); + glLightfv( GL_LIGHT2, GL_AMBIENT, l2amb ); + glLightfv( GL_LIGHT2, GL_DIFFUSE, l2dif ); + glLightfv( GL_LIGHT2, GL_SPECULAR, l2spec ); + glLightfv( GL_LIGHT3, GL_POSITION, glow_pos ); + glLightfv( GL_LIGHT3, GL_DIFFUSE, glow_color ); + glLightfv( GL_LIGHT3, GL_SPECULAR, glow_color ); + + // Enable light sources + glEnable( GL_LIGHT1 ); + glEnable( GL_LIGHT2 ); + glEnable( GL_LIGHT3 ); +} + + +//======================================================================== +// Draw() - Main rendering function +//======================================================================== + +void Draw( double t ) +{ + double xpos, ypos, zpos, angle_x, angle_y, angle_z; + static double t_old = 0.0; + float dt; + + // Calculate frame-to-frame delta time + dt = (float)(t-t_old); + t_old = t; + + // Setup viewport + glViewport( 0, 0, width, height ); + + // Clear color and Z-buffer + glClearColor( 0.1f, 0.1f, 0.1f, 1.0f ); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + // Setup projection + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 65.0, (double)width/(double)height, 1.0, 60.0 ); + + // Setup camera + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Rotate camera + angle_x = 90.0 - 10.0; + angle_y = 10.0 * sin( 0.3 * t ); + angle_z = 10.0 * t; + glRotated( -angle_x, 1.0, 0.0, 0.0 ); + glRotated( -angle_y, 0.0, 1.0, 0.0 ); + glRotated( -angle_z, 0.0, 0.0, 1.0 ); + + // Translate camera + xpos = 15.0 * sin( (M_PI/180.0) * angle_z ) + + 2.0 * sin( (M_PI/180.0) * 3.1 * t ); + ypos = -15.0 * cos( (M_PI/180.0) * angle_z ) + + 2.0 * cos( (M_PI/180.0) * 2.9 * t ); + zpos = 4.0 + 2.0 * cos( (M_PI/180.0) * 4.9 * t ); + glTranslated( -xpos, -ypos, -zpos ); + + // Enable face culling + glFrontFace( GL_CCW ); + glCullFace( GL_BACK ); + glEnable( GL_CULL_FACE ); + + // Enable lighting + SetupLights(); + glEnable( GL_LIGHTING ); + + // Enable fog (dim details far away) + glEnable( GL_FOG ); + glFogi( GL_FOG_MODE, GL_EXP ); + glFogf( GL_FOG_DENSITY, 0.05f ); + glFogfv( GL_FOG_COLOR, fog_color ); + + // Draw floor + DrawFloor(); + + // Enable Z-buffering + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_LEQUAL ); + glDepthMask( GL_TRUE ); + + // Draw fountain + DrawFountain(); + + // Disable fog & lighting + glDisable( GL_LIGHTING ); + glDisable( GL_FOG ); + + // Draw all particles (must be drawn after all solid objects have been + // drawn!) + DrawParticles( t, dt ); + + // Z-buffer not needed anymore + glDisable( GL_DEPTH_TEST ); +} + + +//======================================================================== +// Resize() - GLFW window resize callback function +//======================================================================== + +void GLFWCALL Resize( int x, int y ) +{ + width = x; + height = y > 0 ? y : 1; // Prevent division by zero in aspect calc. +} + + +//======================================================================== +// Input callback functions +//======================================================================== + +void GLFWCALL KeyFun( int key, int action ) +{ + if( action == GLFW_PRESS ) + { + switch( key ) + { + case GLFW_KEY_ESC: + running = 0; + break; + case 'W': + wireframe = !wireframe; + glPolygonMode( GL_FRONT_AND_BACK, + wireframe ? GL_LINE : GL_FILL ); + break; + default: + break; + } + } +} + + +//======================================================================== +// PhysicsThreadFun() - Thread for updating particle physics +//======================================================================== + +void GLFWCALL PhysicsThreadFun( void *arg ) +{ + while( running ) + { + // Lock mutex + glfwLockMutex( thread_sync.particles_lock ); + + // Wait for particle drawing to be done + while( running && thread_sync.p_frame > thread_sync.d_frame ) + { + glfwWaitCond( thread_sync.d_done, thread_sync.particles_lock, + 0.1 ); + } + + // No longer running? + if( !running ) + { + break; + } + + // Update particles + ParticleEngine( thread_sync.t, thread_sync.dt ); + + // Update frame counter + thread_sync.p_frame ++; + + // Unlock mutex and signal drawing thread + glfwUnlockMutex( thread_sync.particles_lock ); + glfwSignalCond( thread_sync.p_done ); + } +} + + +//======================================================================== +// main() +//======================================================================== + +int main( int argc, char **argv ) +{ + int i, frames, benchmark; + double t0, t; + GLFWthread physics_thread = 0; + + // Use multithreading by default, but don't benchmark + multithreading = 1; + benchmark = 0; + + // Check command line arguments + for( i = 1; i < argc; i ++ ) + { + // Use benchmarking? + if( strcmp( argv[i], "-b" ) == 0 ) + { + benchmark = 1; + } + + // Force multithreading off? + else if( strcmp( argv[i], "-s" ) == 0 ) + { + multithreading = 0; + } + + // With a Finder launch on Mac OS X we get a bogus -psn_0_46268417 + // kind of argument (actual numbers vary). Ignore it. + else if( strncmp( argv[i], "-psn_", 5) == 0 ); + + // Usage + else + { + if( strcmp( argv[i], "-?" ) != 0 ) + { + printf( "Unknonwn option %s\n\n", argv[ i ] ); + } + printf( "Usage: %s [options]\n", argv[ 0 ] ); + printf( "\n"); + printf( "Options:\n" ); + printf( " -b Benchmark (run program for 60 s)\n" ); + printf( " -s Run program as single thread (default is to use two threads)\n" ); + printf( " -? Display this text\n" ); + printf( "\n"); + printf( "Program runtime controls:\n" ); + printf( " w Toggle wireframe mode\n" ); + printf( " ESC Exit program\n" ); + exit( 0 ); + } + } + + // Initialize GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open OpenGL fullscreen window + if( !glfwOpenWindow( WIDTH, HEIGHT, 0,0,0,0, 16,0, GLFW_FULLSCREEN ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + // Set window title + glfwSetWindowTitle( "Particle engine" ); + + // Disable VSync (we want to get as high FPS as possible!) + glfwSwapInterval( 0 ); + + // Window resize callback function + glfwSetWindowSizeCallback( Resize ); + + // Set keyboard input callback function + glfwSetKeyCallback( KeyFun ); + + // Upload particle texture + glGenTextures( 1, &particle_tex_id ); + glBindTexture( GL_TEXTURE_2D, particle_tex_id ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, P_TEX_WIDTH, P_TEX_HEIGHT, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, particle_texture ); + + // Upload floor texture + glGenTextures( 1, &floor_tex_id ); + glBindTexture( GL_TEXTURE_2D, floor_tex_id ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, F_TEX_WIDTH, F_TEX_HEIGHT, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, floor_texture ); + + // Check if we have GL_EXT_separate_specular_color, and if so use it + if( glfwExtensionSupported( "GL_EXT_separate_specular_color" ) ) + { + glLightModeli( GL_LIGHT_MODEL_COLOR_CONTROL_EXT, + GL_SEPARATE_SPECULAR_COLOR_EXT ); + } + + // Set filled polygon mode as default (not wireframe) + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + wireframe = 0; + + // Clear particle system + for( i = 0; i < MAX_PARTICLES; i ++ ) + { + particles[ i ].active = 0; + } + min_age = 0.0f; + + // Set "running" flag + running = 1; + + // Set initial times + thread_sync.t = 0.0; + thread_sync.dt = 0.001f; + + // Init threading + if( multithreading ) + { + thread_sync.p_frame = 0; + thread_sync.d_frame = 0; + thread_sync.particles_lock = glfwCreateMutex(); + thread_sync.p_done = glfwCreateCond(); + thread_sync.d_done = glfwCreateCond(); + physics_thread = glfwCreateThread( PhysicsThreadFun, NULL ); + } + + // Main loop + t0 = glfwGetTime(); + frames = 0; + while( running ) + { + // Get frame time + t = glfwGetTime() - t0; + + // Draw... + Draw( t ); + + // Swap buffers + glfwSwapBuffers(); + + // Check if window was closed + running = running && glfwGetWindowParam( GLFW_OPENED ); + + // Increase frame count + frames ++; + + // End of benchmark? + if( benchmark && t >= 60.0 ) + { + running = 0; + } + } + t = glfwGetTime() - t0; + + // Wait for particle physics thread to die + if( multithreading ) + { + glfwWaitThread( physics_thread, GLFW_WAIT ); + } + + // Display profiling information + printf( "%d frames in %.2f seconds = %.1f FPS", frames, t, + (double)frames / t ); + printf( " (multithreading %s)\n", multithreading ? "on" : "off" ); + + // Terminate OpenGL + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/tests/glfw/pong3d.c b/tests/glfw/pong3d.c new file mode 100644 index 0000000000000..1d1afd1f1808d --- /dev/null +++ b/tests/glfw/pong3d.c @@ -0,0 +1,854 @@ +//======================================================================== +// This is a small test application for GLFW. +// This is an OpenGL port of the famous "PONG" game (the first computer +// game ever?). It is very simple, and could be improved alot. It was +// created in order to show off the gaming capabilities of GLFW. +//======================================================================== + +#include +#include +#include +#include + + +//======================================================================== +// Constants +//======================================================================== + +// Screen resolution +#define WIDTH 640 +#define HEIGHT 480 + +// Player size (units) +#define PLAYER_XSIZE 0.05f +#define PLAYER_YSIZE 0.15f + +// Ball size (units) +#define BALL_SIZE 0.02f + +// Maximum player movement speed (units / second) +#define MAX_SPEED 1.5f + +// Player movement acceleration (units / seconds^2) +#define ACCELERATION 4.0f + +// Player movement deceleration (units / seconds^2) +#define DECELERATION 2.0f + +// Ball movement speed (units / second) +#define BALL_SPEED 0.4f + +// Menu options +#define MENU_NONE 0 +#define MENU_PLAY 1 +#define MENU_QUIT 2 + +// Game events +#define NOBODY_WINS 0 +#define PLAYER1_WINS 1 +#define PLAYER2_WINS 2 + +// Winner ID +#define NOBODY 0 +#define PLAYER1 1 +#define PLAYER2 2 + +// Camera positions +#define CAMERA_CLASSIC 0 +#define CAMERA_ABOVE 1 +#define CAMERA_SPECTATOR 2 +#define CAMERA_DEFAULT CAMERA_CLASSIC + + +//======================================================================== +// Textures +//======================================================================== + +#define TEX_TITLE 0 +#define TEX_MENU 1 +#define TEX_INSTR 2 +#define TEX_WINNER1 3 +#define TEX_WINNER2 4 +#define TEX_FIELD 5 +#define NUM_TEXTURES 6 + +// Texture names +char * tex_name[ NUM_TEXTURES ] = { + "pong3d_title.tga", + "pong3d_menu.tga", + "pong3d_instr.tga", + "pong3d_winner1.tga", + "pong3d_winner2.tga", + "pong3d_field.tga" +}; + +// OpenGL texture object IDs +GLuint tex_id[ NUM_TEXTURES ]; + + +//======================================================================== +// Global variables +//======================================================================== + +// Display information +int width, height; + +// Frame information +double thistime, oldtime, dt, starttime; + +// Camera information +int camerapos; + +// Player information +struct { + double ypos; // -1.0 to +1.0 + double yspeed; // -MAX_SPEED to +MAX_SPEED +} player1, player2; + +// Ball information +struct { + double xpos, ypos; + double xspeed, yspeed; +} ball; + +// And the winner is... +int winner; + +// Lighting configuration +const GLfloat env_ambient[4] = {1.0f,1.0f,1.0f,1.0f}; +const GLfloat light1_position[4] = {-3.0f,3.0f,2.0f,1.0f}; +const GLfloat light1_diffuse[4] = {1.0f,1.0f,1.0f,0.0f}; +const GLfloat light1_ambient[4] = {0.0f,0.0f,0.0f,0.0f}; + +// Object material properties +const GLfloat player1_diffuse[4] = {1.0f,0.3f,0.3f,1.0f}; +const GLfloat player1_ambient[4] = {0.3f,0.1f,0.0f,1.0f}; +const GLfloat player2_diffuse[4] = {0.3f,1.0f,0.3f,1.0f}; +const GLfloat player2_ambient[4] = {0.1f,0.3f,0.1f,1.0f}; +const GLfloat ball_diffuse[4] = {1.0f,1.0f,0.5f,1.0f}; +const GLfloat ball_ambient[4] = {0.3f,0.3f,0.1f,1.0f}; +const GLfloat border_diffuse[4] = {0.3f,0.3f,1.0f,1.0f}; +const GLfloat border_ambient[4] = {0.1f,0.1f,0.3f,1.0f}; +const GLfloat floor_diffuse[4] = {1.0f,1.0f,1.0f,1.0f}; +const GLfloat floor_ambient[4] = {0.3f,0.3f,0.3f,1.0f}; + + +//======================================================================== +// LoadTextures() - Load textures from disk and upload to OpenGL card +//======================================================================== + +GLboolean LoadTextures( void ) +{ + int i; + + // Generate texture objects + glGenTextures( NUM_TEXTURES, tex_id ); + + // Load textures + for( i = 0; i < NUM_TEXTURES; i ++ ) + { + // Select texture object + glBindTexture( GL_TEXTURE_2D, tex_id[ i ] ); + + // Set texture parameters + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + // Upload texture from file to texture memory + if( !glfwLoadTexture2D( tex_name[ i ], 0 ) ) + { + fprintf( stderr, "Failed to load texture %s\n", tex_name[ i ] ); + return GL_FALSE; + } + } + + return GL_TRUE; +} + + +//======================================================================== +// DrawImage() - Draw a 2D image as a texture +//======================================================================== + +void DrawImage( int texnum, float x1, float x2, float y1, float y2 ) +{ + glEnable( GL_TEXTURE_2D ); + glBindTexture( GL_TEXTURE_2D, tex_id[ texnum ] ); + glBegin( GL_QUADS ); + glTexCoord2f( 0.0f, 1.0f ); + glVertex2f( x1, y1 ); + glTexCoord2f( 1.0f, 1.0f ); + glVertex2f( x2, y1 ); + glTexCoord2f( 1.0f, 0.0f ); + glVertex2f( x2, y2 ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex2f( x1, y2 ); + glEnd(); + glDisable( GL_TEXTURE_2D ); +} + + +//======================================================================== +// GameMenu() - Game menu (returns menu option) +//======================================================================== + +int GameMenu( void ) +{ + int option; + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Wait for a game menu key to be pressed + do + { + // Get window size + glfwGetWindowSize( &width, &height ); + + // Set viewport + glViewport( 0, 0, width, height ); + + // Clear display + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + glClear( GL_COLOR_BUFFER_BIT ); + + // Setup projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f ); + + // Setup modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Display title + glColor3f( 1.0f, 1.0f, 1.0f ); + DrawImage( TEX_TITLE, 0.1f, 0.9f, 0.0f, 0.3f ); + + // Display menu + glColor3f( 1.0f, 1.0f, 0.0f ); + DrawImage( TEX_MENU, 0.38f, 0.62f, 0.35f, 0.5f ); + + // Display instructions + glColor3f( 0.0f, 1.0f, 1.0f ); + DrawImage( TEX_INSTR, 0.32f, 0.68f, 0.65f, 0.85f ); + + // Swap buffers + glfwSwapBuffers(); + + // Check for keys + if( glfwGetKey( 'Q' ) || !glfwGetWindowParam( GLFW_OPENED ) ) + { + option = MENU_QUIT; + } + else if( glfwGetKey( GLFW_KEY_F1 ) ) + { + option = MENU_PLAY; + } + else + { + option = MENU_NONE; + } + + // To avoid horrible busy waiting, sleep for at least 20 ms + glfwSleep( 0.02 ); + } + while( option == MENU_NONE ); + + // Disable sticky keys + glfwDisable( GLFW_STICKY_KEYS ); + + return option; +} + + +//======================================================================== +// NewGame() - Initialize a new game +//======================================================================== + +void NewGame( void ) +{ + // Frame information + starttime = thistime = glfwGetTime(); + + // Camera information + camerapos = CAMERA_DEFAULT; + + // Player 1 information + player1.ypos = 0.0; + player1.yspeed = 0.0; + + // Player 2 information + player2.ypos = 0.0; + player2.yspeed = 0.0; + + // Ball information + ball.xpos = -1.0 + PLAYER_XSIZE; + ball.ypos = player1.ypos; + ball.xspeed = 1.0; + ball.yspeed = 1.0; +} + + +//======================================================================== +// PlayerControl() - Player control +//======================================================================== + +void PlayerControl( void ) +{ + float joy1pos[ 2 ], joy2pos[ 2 ]; + + // Get joystick X & Y axis positions + glfwGetJoystickPos( GLFW_JOYSTICK_1, joy1pos, 2 ); + glfwGetJoystickPos( GLFW_JOYSTICK_2, joy2pos, 2 ); + + // Player 1 control + if( glfwGetKey( 'A' ) || joy1pos[ 1 ] > 0.2f ) + { + player1.yspeed += dt * ACCELERATION; + if( player1.yspeed > MAX_SPEED ) + { + player1.yspeed = MAX_SPEED; + } + } + else if( glfwGetKey( 'Z' ) || joy1pos[ 1 ] < -0.2f ) + { + player1.yspeed -= dt * ACCELERATION; + if( player1.yspeed < -MAX_SPEED ) + { + player1.yspeed = -MAX_SPEED; + } + } + else + { + player1.yspeed /= exp( DECELERATION * dt ); + } + + // Player 2 control + if( glfwGetKey( 'K' ) || joy2pos[ 1 ] > 0.2f ) + { + player2.yspeed += dt * ACCELERATION; + if( player2.yspeed > MAX_SPEED ) + { + player2.yspeed = MAX_SPEED; + } + } + else if( glfwGetKey( 'M' ) || joy2pos[ 1 ] < -0.2f ) + { + player2.yspeed -= dt * ACCELERATION; + if( player2.yspeed < -MAX_SPEED ) + { + player2.yspeed = -MAX_SPEED; + } + } + else + { + player2.yspeed /= exp( DECELERATION * dt ); + } + + // Update player 1 position + player1.ypos += dt * player1.yspeed; + if( player1.ypos > 1.0 - PLAYER_YSIZE ) + { + player1.ypos = 1.0 - PLAYER_YSIZE; + player1.yspeed = 0.0; + } + else if( player1.ypos < -1.0 + PLAYER_YSIZE ) + { + player1.ypos = -1.0 + PLAYER_YSIZE; + player1.yspeed = 0.0; + } + + // Update player 2 position + player2.ypos += dt * player2.yspeed; + if( player2.ypos > 1.0 - PLAYER_YSIZE ) + { + player2.ypos = 1.0 - PLAYER_YSIZE; + player2.yspeed = 0.0; + } + else if( player2.ypos < -1.0 + PLAYER_YSIZE ) + { + player2.ypos = -1.0 + PLAYER_YSIZE; + player2.yspeed = 0.0; + } +} + + +//======================================================================== +// BallControl() - Ball control +//======================================================================== + +int BallControl( void ) +{ + int event; + double ballspeed; + + // Calculate new ball speed + ballspeed = BALL_SPEED * (1.0 + 0.02*(thistime-starttime)); + ball.xspeed = ball.xspeed > 0 ? ballspeed : -ballspeed; + ball.yspeed = ball.yspeed > 0 ? ballspeed : -ballspeed; + ball.yspeed *= 0.74321; + + // Update ball position + ball.xpos += dt * ball.xspeed; + ball.ypos += dt * ball.yspeed; + + // Did the ball hit a top/bottom wall? + if( ball.ypos >= 1.0 ) + { + ball.ypos = 2.0 - ball.ypos; + ball.yspeed = -ball.yspeed; + } + else if( ball.ypos <= -1.0 ) + { + ball.ypos = -2.0 - ball.ypos; + ball.yspeed = -ball.yspeed; + } + + // Did the ball hit/miss a player? + event = NOBODY_WINS; + + // Is the ball entering the player 1 goal? + if( ball.xpos < -1.0 + PLAYER_XSIZE ) + { + // Did player 1 catch the ball? + if( ball.ypos > (player1.ypos-PLAYER_YSIZE) && + ball.ypos < (player1.ypos+PLAYER_YSIZE) ) + { + ball.xpos = -2.0 + 2.0*PLAYER_XSIZE - ball.xpos; + ball.xspeed = -ball.xspeed; + } + else + { + event = PLAYER2_WINS; + } + } + + // Is the ball entering the player 2 goal? + if( ball.xpos > 1.0 - PLAYER_XSIZE ) + { + // Did player 2 catch the ball? + if( ball.ypos > (player2.ypos-PLAYER_YSIZE) && + ball.ypos < (player2.ypos+PLAYER_YSIZE) ) + { + ball.xpos = 2.0 - 2.0*PLAYER_XSIZE - ball.xpos; + ball.xspeed = -ball.xspeed; + } + else + { + event = PLAYER1_WINS; + } + } + + return event; +} + + +//======================================================================== +// DrawBox() - Draw a 3D box +//======================================================================== + +#define TEX_SCALE 4.0f + + +void DrawBox( float x1, float y1, float z1, float x2, float y2, float z2 ) +{ + // Draw six sides of a cube + glBegin( GL_QUADS ); + // Side 1 (down) + glNormal3f( 0.0f, 0.0f, -1.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y2,z1 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y2,z1 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y1,z1 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y1,z1 ); + // Side 2 (up) + glNormal3f( 0.0f, 0.0f, 1.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y1,z2 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y1,z2 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y2,z2 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y2,z2 ); + // Side 3 (backward) + glNormal3f( 0.0f, -1.0f, 0.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y1,z1 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y1,z1 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y1,z2 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y1,z2 ); + // Side 4 (forward) + glNormal3f( 0.0f, 1.0f, 0.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y2,z2 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y2,z2 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y2,z1 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y2,z1 ); + // Side 5 (left) + glNormal3f( -1.0f, 0.0f, 0.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y1,z2 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x1,y2,z2 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x1,y2,z1 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y1,z1 ); + // Side 6 (right) + glNormal3f( 1.0f, 0.0f, 0.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x2,y1,z1 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y2,z1 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y2,z2 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x2,y1,z2 ); + glEnd(); +} + + +//======================================================================== +// UpdateDisplay() - Draw graphics (all game related OpenGL stuff goes +// here) +//======================================================================== + +void UpdateDisplay( void ) +{ + // Get window size + glfwGetWindowSize( &width, &height ); + + // Set viewport + glViewport( 0, 0, width, height ); + + // Clear display + glClearColor( 0.02f, 0.02f, 0.02f, 0.0f ); + glClearDepth( 1.0f ); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + // Setup projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( + 55.0f, // Angle of view + (GLfloat)width/(GLfloat)height, // Aspect + 1.0f, // Near Z + 100.0f // Far Z + ); + + // Setup modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + switch( camerapos ) + { + default: + case CAMERA_CLASSIC: + gluLookAt( + 0.0f, 0.0f, 2.5f, + 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f + ); + break; + case CAMERA_ABOVE: + gluLookAt( + 0.0f, 0.0f, 2.5f, + (float)ball.xpos, (float)ball.ypos, 0.0f, + 0.0f, 1.0f, 0.0f + ); + break; + case CAMERA_SPECTATOR: + gluLookAt( + 0.0f, -2.0, 1.2f, + (float)ball.xpos, (float)ball.ypos, 0.0f, + 0.0f, 0.0f, 1.0f + ); + break; + } + + // Enable depth testing + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_LEQUAL ); + + // Enable lighting + glEnable( GL_LIGHTING ); + glLightModelfv( GL_LIGHT_MODEL_AMBIENT, env_ambient ); + glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE ); + glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE ); + glLightfv( GL_LIGHT1, GL_POSITION, light1_position ); + glLightfv( GL_LIGHT1, GL_DIFFUSE, light1_diffuse ); + glLightfv( GL_LIGHT1, GL_AMBIENT, light1_ambient ); + glEnable( GL_LIGHT1 ); + + // Front face is counter-clock-wise + glFrontFace( GL_CCW ); + + // Enable face culling (not necessary, but speeds up rendering) + glCullFace( GL_BACK ); + glEnable( GL_CULL_FACE ); + + // Draw Player 1 + glMaterialfv( GL_FRONT, GL_DIFFUSE, player1_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, player1_ambient ); + DrawBox( -1.f, (GLfloat)player1.ypos-PLAYER_YSIZE, 0.f, + -1.f+PLAYER_XSIZE, (GLfloat)player1.ypos+PLAYER_YSIZE, 0.1f ); + + // Draw Player 2 + glMaterialfv( GL_FRONT, GL_DIFFUSE, player2_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, player2_ambient ); + DrawBox( 1.f-PLAYER_XSIZE, (GLfloat)player2.ypos-PLAYER_YSIZE, 0.f, + 1.f, (GLfloat)player2.ypos+PLAYER_YSIZE, 0.1f ); + + // Draw Ball + glMaterialfv( GL_FRONT, GL_DIFFUSE, ball_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, ball_ambient ); + DrawBox( (GLfloat)ball.xpos-BALL_SIZE, (GLfloat)ball.ypos-BALL_SIZE, 0.f, + (GLfloat)ball.xpos+BALL_SIZE, (GLfloat)ball.ypos+BALL_SIZE, BALL_SIZE*2 ); + + // Top game field border + glMaterialfv( GL_FRONT, GL_DIFFUSE, border_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, border_ambient ); + DrawBox( -1.1f, 1.0f, 0.0f, 1.1f, 1.1f, 0.1f ); + // Bottom game field border + glColor3f( 0.0f, 0.0f, 0.7f ); + DrawBox( -1.1f, -1.1f, 0.0f, 1.1f, -1.0f, 0.1f ); + // Left game field border + DrawBox( -1.1f, -1.0f, 0.0f, -1.0f, 1.0f, 0.1f ); + // Left game field border + DrawBox( 1.0f, -1.0f, 0.0f, 1.1f, 1.0f, 0.1f ); + + // Enable texturing + glEnable( GL_TEXTURE_2D ); + glBindTexture( GL_TEXTURE_2D, tex_id[ TEX_FIELD ] ); + + // Game field floor + glMaterialfv( GL_FRONT, GL_DIFFUSE, floor_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, floor_ambient ); + DrawBox( -1.01f, -1.01f, -0.01f, 1.01f, 1.01f, 0.0f ); + + // Disable texturing + glDisable( GL_TEXTURE_2D ); + + // Disable face culling + glDisable( GL_CULL_FACE ); + + // Disable lighting + glDisable( GL_LIGHTING ); + + // Disable depth testing + glDisable( GL_DEPTH_TEST ); +} + + +//======================================================================== +// GameOver() +//======================================================================== + +void GameOver( void ) +{ + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Until the user presses ESC or SPACE + while( !glfwGetKey( GLFW_KEY_ESC ) && !glfwGetKey( ' ' ) && + glfwGetWindowParam( GLFW_OPENED ) ) + { + // Draw display + UpdateDisplay(); + + // Setup projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f ); + + // Setup modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Enable blending + glEnable( GL_BLEND ); + + // Dim background + glBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA ); + glColor4f( 0.3f, 0.3f, 0.3f, 0.3f ); + glBegin( GL_QUADS ); + glVertex2f( 0.0f, 0.0f ); + glVertex2f( 1.0f, 0.0f ); + glVertex2f( 1.0f, 1.0f ); + glVertex2f( 0.0f, 1.0f ); + glEnd(); + + // Display winner text + glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_COLOR ); + if( winner == PLAYER1 ) + { + glColor4f( 1.0f, 0.5f, 0.5f, 1.0f ); + DrawImage( TEX_WINNER1, 0.35f, 0.65f, 0.46f, 0.54f ); + } + else if( winner == PLAYER2 ) + { + glColor4f( 0.5f, 1.0f, 0.5f, 1.0f ); + DrawImage( TEX_WINNER2, 0.35f, 0.65f, 0.46f, 0.54f ); + } + + // Disable blending + glDisable( GL_BLEND ); + + // Swap buffers + glfwSwapBuffers(); + } + + // Disable sticky keys + glfwDisable( GLFW_STICKY_KEYS ); +} + + +//======================================================================== +// GameLoop() - Game loop +//======================================================================== + +void GameLoop( void ) +{ + int playing, event; + + // Initialize a new game + NewGame(); + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Loop until the game ends + playing = GL_TRUE; + while( playing && glfwGetWindowParam( GLFW_OPENED ) ) + { + // Frame timer + oldtime = thistime; + thistime = glfwGetTime(); + dt = thistime - oldtime; + + // Get user input and update player positions + PlayerControl(); + + // Move the ball, and check if a player hits/misses the ball + event = BallControl(); + + // Did we have a winner? + switch( event ) + { + case PLAYER1_WINS: + winner = PLAYER1; + playing = GL_FALSE; + break; + case PLAYER2_WINS: + winner = PLAYER2; + playing = GL_FALSE; + break; + default: + break; + } + + // Did the user press ESC? + if( glfwGetKey( GLFW_KEY_ESC ) ) + { + playing = GL_FALSE; + } + + // Did the user change camera view? + if( glfwGetKey( '1' ) ) + { + camerapos = CAMERA_CLASSIC; + } + else if( glfwGetKey( '2' ) ) + { + camerapos = CAMERA_ABOVE; + } + else if( glfwGetKey( '3' ) ) + { + camerapos = CAMERA_SPECTATOR; + } + + // Draw display + UpdateDisplay(); + + // Swap buffers + glfwSwapBuffers(); + } + + // Disable sticky keys + glfwDisable( GLFW_STICKY_KEYS ); + + // Show winner + GameOver(); +} + + +//======================================================================== +// main() - Program entry point +//======================================================================== + +int main( void ) +{ + int menuoption; + + // Initialize GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open OpenGL window + if( !glfwOpenWindow( WIDTH, HEIGHT, 0,0,0,0, 16,0, GLFW_FULLSCREEN ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + glfwSwapInterval( 1 ); + + // Load all textures + if( !LoadTextures() ) + { + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + // Main loop + do + { + // Get menu option + menuoption = GameMenu(); + + // If the user wants to play, let him... + if( menuoption == MENU_PLAY ) + { + GameLoop(); + } + } + while( menuoption != MENU_QUIT ); + + // Unload all textures + if( glfwGetWindowParam( GLFW_OPENED ) ) + { + glDeleteTextures( NUM_TEXTURES, tex_id ); + } + + // Terminate GLFW + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/tests/glfw/pong3d_field.tga b/tests/glfw/pong3d_field.tga new file mode 100644 index 0000000000000000000000000000000000000000..cc20bbdb82434faa3bbc01d27fd199d5214c8b2f GIT binary patch literal 17816 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 T6XevNs>&3`i95eA{_g(;MdbFK literal 0 HcmV?d00001 diff --git a/tests/glfw/pong3d_instr.tga b/tests/glfw/pong3d_instr.tga new file mode 100644 index 0000000000000000000000000000000000000000..758eb447a97187cef812cb9100aa94631954c256 GIT binary patch literal 21279 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 literal 0 HcmV?d00001 diff --git a/tests/glfw/pong3d_menu.tga b/tests/glfw/pong3d_menu.tga new file mode 100644 index 0000000000000000000000000000000000000000..d0d6c5a431687bfd6442e43c3878a9eb905c48b8 GIT binary patch literal 1835 zcmbVMTawc-5FFd7KrLK{i*bQLe#C)-km6&1*q~+M0-Qi+$_YgGjAbh+zSu1}vefFC z>1kQyjg-Il@=jjMRenoIj~IXChe+&m7gLVsZQ6^Zkej3-2jP$yvZRY#urXlCQ#Jn=lGQ*?msDM%?fom_#3D0WLYd>| zrM8HEH4zdvDSlgLUu?J06w%uHU$F5BH?%^)6{nIMA=d zk04{L6gsNXLvPU$y7bcLR=F~R;{Yz~AoE6761IR~EZy-Sc90#?@jjEKjdZ2xgd?t2 zqtTm)Fw3kYxE=nmQqN{37J-&5_=7y4JqUx5<790bksq4`P6Xm?W2J#gsv94$c80Ep zhB(C(Tcv$%4nwfg>5lD?ncV@L-j6_|Q=WiD2HsmBQ7_k*Bwh}mIAS5_(&Zv)0+JQ*BV=)qzNL$W#l<{{t=av1 zh6fQJ3*Rf(fcY7y8DcVufs`P8r)X65U6x`6n^qTRM5LcL_vtFnz@hK-l+BKK+wK>L@83So!V-2z3xXZm}7`ZB*l$gvAC5tvMEd)H$-L j=(lM?g-Vm}Fwx!OsnJ{IV_$0Jn){}t&ktU$$5s9UqXSX} literal 0 HcmV?d00001 diff --git a/tests/glfw/pong3d_title.tga b/tests/glfw/pong3d_title.tga new file mode 100644 index 0000000000000000000000000000000000000000..d0d8e36d74011c25b908647632b4997dc0cf6456 GIT binary patch literal 106516 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 literal 0 HcmV?d00001 diff --git a/tests/glfw/pong3d_winner1.tga b/tests/glfw/pong3d_winner1.tga new file mode 100644 index 0000000000000000000000000000000000000000..f963720c5b897c01b8694a0fb2d76ad617877a7d GIT binary patch literal 861 zcmZvaO-{ow5QV29sw!Ag>q$zL$Sb2xaDZHc?={d~z#x?;&rAh7an>TNM%UG8<_V`T}Av+dQR1Q!U7Qc6{sSH8wNZP39q9qy#b$XF9@I6ez)S<6n zq_ehk;iMZ&fsh(meZGobq4LV7e~pc@d~^GlelDh;wKF}zCi`6*Je6~M>is%9SNEbW LDfk1czN>u!GHiyO literal 0 HcmV?d00001 diff --git a/tests/glfw/pong3d_winner2.tga b/tests/glfw/pong3d_winner2.tga new file mode 100644 index 0000000000000000000000000000000000000000..ea8266dea9f6ca7b261f2163b4f2bc4777a59027 GIT binary patch literal 891 zcmZvbOHRWu5Qe8Asw!Ag>q)E8}th{PDhL`jrJ%{=Jv6BL#k|RH6{>RMJ?8(;O zi#^-HZuV}m>~grW8Ozl^%t9=dzKDzE#2U(`*Z?%X-syv|S(? zK)sHv$a>wtB4Eb?Ma3Y>!sKURS)Tb0r3+%vTaEo6DJm{if#^X&j{?aT=fbk|<~&_O zt+PmDbft=sKHTt?QQd&&`CbHe)uYgASx)wtida}Bc}9?zn%(@SUw-irZBG_CWXznz z=XiOM7P58fg0$VeHnc3XW7$gDg_J8@PnncbAuX(+Ga!3cnA!amNonh?123}NqEvQz zr;kDo0gOh0x+DVBrpbD_p`wQ*Phz^)ltEEbz;t}sX=m;%O{Moj&@6$p=8wfP;J5)? zkhFgfjw0#^%tT0ME$!44Ga|_7pj0Ep>Z9on#mYG5)@84;kMi2DpOfl)jnK+)SAA~d cBD_m`U#oV84}EF9M`aSmW&0a^ddAJZ0j)ZbKmY&$ literal 0 HcmV?d00001 diff --git a/tests/glfw/splitview.c b/tests/glfw/splitview.c new file mode 100644 index 0000000000000..932cd0d6511b1 --- /dev/null +++ b/tests/glfw/splitview.c @@ -0,0 +1,514 @@ +//======================================================================== +// This is an example program for the GLFW library +// +// The program uses a "split window" view, rendering four views of the +// same scene in one window (e.g. uesful for 3D modelling software). This +// demo uses scissors to separete the four different rendering areas from +// each other. +// +// (If the code seems a little bit strange here and there, it may be +// because I am not a friend of orthogonal projections) +//======================================================================== + +#include +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +//======================================================================== +// Global variables +//======================================================================== + +// Mouse position +static int xpos = 0, ypos = 0; + +// Window size +static int width, height; + +// Active view: 0 = none, 1 = upper left, 2 = upper right, 3 = lower left, +// 4 = lower right +static int active_view = 0; + +// Rotation around each axis +static int rot_x = 0, rot_y = 0, rot_z = 0; + +// Do redraw? +static int do_redraw = 1; + + +//======================================================================== +// Draw a solid torus (use a display list for the model) +//======================================================================== + +#define TORUS_MAJOR 1.5 +#define TORUS_MINOR 0.5 +#define TORUS_MAJOR_RES 32 +#define TORUS_MINOR_RES 32 + +static void drawTorus( void ) +{ + static GLuint torus_list = 0; + int i, j, k; + double s, t, x, y, z, nx, ny, nz, scale, twopi; + + if( !torus_list ) + { + // Start recording displaylist + torus_list = glGenLists( 1 ); + glNewList( torus_list, GL_COMPILE_AND_EXECUTE ); + + // Draw torus + twopi = 2.0 * M_PI; + for( i = 0; i < TORUS_MINOR_RES; i++ ) + { + glBegin( GL_QUAD_STRIP ); + for( j = 0; j <= TORUS_MAJOR_RES; j++ ) + { + for( k = 1; k >= 0; k-- ) + { + s = (i + k) % TORUS_MINOR_RES + 0.5; + t = j % TORUS_MAJOR_RES; + + // Calculate point on surface + x = (TORUS_MAJOR+TORUS_MINOR*cos(s*twopi/TORUS_MINOR_RES))*cos(t*twopi/TORUS_MAJOR_RES); + y = TORUS_MINOR * sin(s * twopi / TORUS_MINOR_RES); + z = (TORUS_MAJOR+TORUS_MINOR*cos(s*twopi/TORUS_MINOR_RES))*sin(t*twopi/TORUS_MAJOR_RES); + + // Calculate surface normal + nx = x - TORUS_MAJOR*cos(t*twopi/TORUS_MAJOR_RES); + ny = y; + nz = z - TORUS_MAJOR*sin(t*twopi/TORUS_MAJOR_RES); + scale = 1.0 / sqrt( nx*nx + ny*ny + nz*nz ); + nx *= scale; + ny *= scale; + nz *= scale; + + glNormal3f( (float)nx, (float)ny, (float)nz ); + glVertex3f( (float)x, (float)y, (float)z ); + } + } + glEnd(); + } + + // Stop recording displaylist + glEndList(); + } + else + { + // Playback displaylist + glCallList( torus_list ); + } +} + + +//======================================================================== +// Draw the scene (a rotating torus) +//======================================================================== + +static void drawScene( void ) +{ + const GLfloat model_diffuse[4] = {1.0f, 0.8f, 0.8f, 1.0f}; + const GLfloat model_specular[4] = {0.6f, 0.6f, 0.6f, 1.0f}; + const GLfloat model_shininess = 20.0f; + + glPushMatrix(); + + // Rotate the object + glRotatef( (GLfloat)rot_x*0.5f, 1.0f, 0.0f, 0.0f ); + glRotatef( (GLfloat)rot_y*0.5f, 0.0f, 1.0f, 0.0f ); + glRotatef( (GLfloat)rot_z*0.5f, 0.0f, 0.0f, 1.0f ); + + // Set model color (used for orthogonal views, lighting disabled) + glColor4fv( model_diffuse ); + + // Set model material (used for perspective view, lighting enabled) + glMaterialfv( GL_FRONT, GL_DIFFUSE, model_diffuse ); + glMaterialfv( GL_FRONT, GL_SPECULAR, model_specular ); + glMaterialf( GL_FRONT, GL_SHININESS, model_shininess ); + + // Draw torus + drawTorus(); + + glPopMatrix(); +} + + +//======================================================================== +// Draw a 2D grid (used for orthogonal views) +//======================================================================== + +static void drawGrid( float scale, int steps ) +{ + int i; + float x, y; + + glPushMatrix(); + + // Set background to some dark bluish grey + glClearColor( 0.05f, 0.05f, 0.2f, 0.0f); + glClear( GL_COLOR_BUFFER_BIT ); + + // Setup modelview matrix (flat XY view) + glLoadIdentity(); + gluLookAt( 0.0, 0.0, 1.0, + 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0 ); + + // We don't want to update the Z-buffer + glDepthMask( GL_FALSE ); + + // Set grid color + glColor3f( 0.0f, 0.5f, 0.5f ); + + glBegin( GL_LINES ); + + // Horizontal lines + x = scale * 0.5f * (float)(steps-1); + y = -scale * 0.5f * (float)(steps-1); + for( i = 0; i < steps; i ++ ) + { + glVertex3f( -x, y, 0.0f ); + glVertex3f( x, y, 0.0f ); + y += scale; + } + + // Vertical lines + x = -scale * 0.5f * (float)(steps-1); + y = scale * 0.5f * (float)(steps-1); + for( i = 0; i < steps; i ++ ) + { + glVertex3f( x, -y, 0.0f ); + glVertex3f( x, y, 0.0f ); + x += scale; + } + + glEnd(); + + // Enable Z-buffer writing again + glDepthMask( GL_TRUE ); + + glPopMatrix(); +} + + +//======================================================================== +// Draw all views +//======================================================================== + +static void drawAllViews( void ) +{ + const GLfloat light_position[4] = {0.0f, 8.0f, 8.0f, 1.0f}; + const GLfloat light_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const GLfloat light_specular[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const GLfloat light_ambient[4] = {0.2f, 0.2f, 0.3f, 1.0f}; + double aspect; + + // Calculate aspect of window + if( height > 0 ) + { + aspect = (double)width / (double)height; + } + else + { + aspect = 1.0; + } + + // Clear screen + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + // Enable scissor test + glEnable( GL_SCISSOR_TEST ); + + // Enable depth test + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_LEQUAL ); + + + // ** ORTHOGONAL VIEWS ** + + // For orthogonal views, use wireframe rendering + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + + // Enable line anti-aliasing + glEnable( GL_LINE_SMOOTH ); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + + // Setup orthogonal projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( -3.0*aspect, 3.0*aspect, -3.0, 3.0, 1.0, 50.0 ); + + // Upper left view (TOP VIEW) + glViewport( 0, height/2, width/2, height/2 ); + glScissor( 0, height/2, width/2, height/2 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 0.0f, 10.0f, 1e-3f, // Eye-position (above) + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + drawGrid( 0.5, 12 ); + drawScene(); + + // Lower left view (FRONT VIEW) + glViewport( 0, 0, width/2, height/2 ); + glScissor( 0, 0, width/2, height/2 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 0.0f, 0.0f, 10.0f, // Eye-position (in front of) + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + drawGrid( 0.5, 12 ); + drawScene(); + + // Lower right view (SIDE VIEW) + glViewport( width/2, 0, width/2, height/2 ); + glScissor( width/2, 0, width/2, height/2 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 10.0f, 0.0f, 0.0f, // Eye-position (to the right) + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + drawGrid( 0.5, 12 ); + drawScene(); + + // Disable line anti-aliasing + glDisable( GL_LINE_SMOOTH ); + glDisable( GL_BLEND ); + + + // ** PERSPECTIVE VIEW ** + + // For perspective view, use solid rendering + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + + // Enable face culling (faster rendering) + glEnable( GL_CULL_FACE ); + glCullFace( GL_BACK ); + glFrontFace( GL_CW ); + + // Setup perspective projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 65.0f, aspect, 1.0f, 50.0f ); + + // Upper right view (PERSPECTIVE VIEW) + glViewport( width/2, height/2, width/2, height/2 ); + glScissor( width/2, height/2, width/2, height/2 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 3.0f, 1.5f, 3.0f, // Eye-position + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + + // Configure and enable light source 1 + glLightfv( GL_LIGHT1, GL_POSITION, light_position ); + glLightfv( GL_LIGHT1, GL_AMBIENT, light_ambient ); + glLightfv( GL_LIGHT1, GL_DIFFUSE, light_diffuse ); + glLightfv( GL_LIGHT1, GL_SPECULAR, light_specular ); + glEnable( GL_LIGHT1 ); + glEnable( GL_LIGHTING ); + + // Draw scene + drawScene(); + + // Disable lighting + glDisable( GL_LIGHTING ); + + // Disable face culling + glDisable( GL_CULL_FACE ); + + // Disable depth test + glDisable( GL_DEPTH_TEST ); + + // Disable scissor test + glDisable( GL_SCISSOR_TEST ); + + + // Draw a border around the active view + if( active_view > 0 && active_view != 2 ) + { + glViewport( 0, 0, width, height ); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( 0.0, 2.0, 0.0, 2.0, 0.0, 1.0 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + glColor3f( 1.0f, 1.0f, 0.6f ); + glTranslatef( (GLfloat) ((active_view - 1) & 1), (GLfloat) (1 - (active_view - 1) / 2), 0.0f ); + glBegin( GL_LINE_STRIP ); + glVertex2i( 0, 0 ); + glVertex2i( 1, 0 ); + glVertex2i( 1, 1 ); + glVertex2i( 0, 1 ); + glVertex2i( 0, 0 ); + glEnd(); + } +} + + +//======================================================================== +// Window size callback function +//======================================================================== + +static void GLFWCALL windowSizeFun( int w, int h ) +{ + width = w; + height = h > 0 ? h : 1; + do_redraw = 1; +} + + +//======================================================================== +// Window refresh callback function +//======================================================================== + +static void GLFWCALL windowRefreshFun( void ) +{ + do_redraw = 1; +} + + +//======================================================================== +// Mouse position callback function +//======================================================================== + +static void GLFWCALL mousePosFun( int x, int y ) +{ + // Depending on which view was selected, rotate around different axes + switch( active_view ) + { + case 1: + rot_x += y - ypos; + rot_z += x - xpos; + do_redraw = 1; + break; + case 3: + rot_x += y - ypos; + rot_y += x - xpos; + do_redraw = 1; + break; + case 4: + rot_y += x - xpos; + rot_z += y - ypos; + do_redraw = 1; + break; + default: + // Do nothing for perspective view, or if no view is selected + break; + } + + // Remember mouse position + xpos = x; + ypos = y; +} + + +//======================================================================== +// Mouse button callback function +//======================================================================== + +static void GLFWCALL mouseButtonFun( int button, int action ) +{ + // Button clicked? + if( ( button == GLFW_MOUSE_BUTTON_LEFT ) && action == GLFW_PRESS ) + { + // Detect which of the four views was clicked + active_view = 1; + if( xpos >= width/2 ) + { + active_view += 1; + } + if( ypos >= height/2 ) + { + active_view += 2; + } + } + + // Button released? + else if( button == GLFW_MOUSE_BUTTON_LEFT ) + { + // Deselect any previously selected view + active_view = 0; + } + + do_redraw = 1; +} + + +//======================================================================== +// main() +//======================================================================== + +int main( void ) +{ + // Initialise GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open OpenGL window + if( !glfwOpenWindow( 500, 500, 0,0,0,0, 16,0, GLFW_WINDOW ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + // Enable vsync + glfwSwapInterval( 1 ); + + // Set window title + glfwSetWindowTitle( "Split view demo" ); + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Enable mouse cursor (only needed for fullscreen mode) + glfwEnable( GLFW_MOUSE_CURSOR ); + + // Disable automatic event polling + glfwDisable( GLFW_AUTO_POLL_EVENTS ); + + // Set callback functions + glfwSetWindowSizeCallback( windowSizeFun ); + glfwSetWindowRefreshCallback( windowRefreshFun ); + glfwSetMousePosCallback( mousePosFun ); + glfwSetMouseButtonCallback( mouseButtonFun ); + + // Main loop + do + { + // Only redraw if we need to + if( do_redraw ) + { + // Draw all views + drawAllViews(); + + // Swap buffers + glfwSwapBuffers(); + + do_redraw = 0; + } + + // Wait for new events + glfwWaitEvents(); + + } // Check if the ESC key was pressed or the window was closed + while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS && + glfwGetWindowParam( GLFW_OPENED ) ); + + // Close OpenGL window and terminate GLFW + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/tests/glfw/triangle.c b/tests/glfw/triangle.c new file mode 100644 index 0000000000000..a8b737bee7fe2 --- /dev/null +++ b/tests/glfw/triangle.c @@ -0,0 +1,94 @@ +//======================================================================== +// This is a small test application for GLFW. +// The program opens a window (640x480), and renders a spinning colored +// triangle (it is controlled with both the GLFW timer and the mouse). +//======================================================================== + +#include +#include +#include + + +int main( void ) +{ + int width, height, x; + double t; + + // Initialise GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open a window and create its OpenGL context + if( !glfwOpenWindow( 640, 480, 0,0,0,0, 0,0, GLFW_WINDOW ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + glfwSetWindowTitle( "Spinning Triangle" ); + + // Ensure we can capture the escape key being pressed below + glfwEnable( GLFW_STICKY_KEYS ); + + // Enable vertical sync (on cards that support it) + glfwSwapInterval( 1 ); + + do + { + t = glfwGetTime(); + glfwGetMousePos( &x, NULL ); + + // Get window size (may be different than the requested size) + glfwGetWindowSize( &width, &height ); + + // Special case: avoid division by zero below + height = height > 0 ? height : 1; + + glViewport( 0, 0, width, height ); + + // Clear color buffer to black + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + glClear( GL_COLOR_BUFFER_BIT ); + + // Select and setup the projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 65.0f, (GLfloat)width/(GLfloat)height, 1.0f, 100.0f ); + + // Select and setup the modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 0.0f, 1.0f, 0.0f, // Eye-position + 0.0f, 20.0f, 0.0f, // View-point + 0.0f, 0.0f, 1.0f ); // Up-vector + + // Draw a rotating colorful triangle + glTranslatef( 0.0f, 14.0f, 0.0f ); + glRotatef( 0.3f*(GLfloat)x + (GLfloat)t*100.0f, 0.0f, 0.0f, 1.0f ); + glBegin( GL_TRIANGLES ); + glColor3f( 1.0f, 0.0f, 0.0f ); + glVertex3f( -5.0f, 0.0f, -4.0f ); + glColor3f( 0.0f, 1.0f, 0.0f ); + glVertex3f( 5.0f, 0.0f, -4.0f ); + glColor3f( 0.0f, 0.0f, 1.0f ); + glVertex3f( 0.0f, 0.0f, 6.0f ); + glEnd(); + + // Swap buffers + glfwSwapBuffers(); + + } // Check if the ESC key was pressed or the window was closed + while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS && + glfwGetWindowParam( GLFW_OPENED ) ); + + // Close OpenGL window and terminate GLFW + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/tests/glfw/wave.c b/tests/glfw/wave.c new file mode 100644 index 0000000000000..67f516cc094c7 --- /dev/null +++ b/tests/glfw/wave.c @@ -0,0 +1,399 @@ +/***************************************************************************** + * Wave Simulation in OpenGL + * (C) 2002 Jakob Thomsen + * http://home.in.tum.de/~thomsen + * Modified for GLFW by Sylvain Hellegouarch - sh@programmationworld.com + * Modified for variable frame rate by Marcus Geelnard + * 2003-Jan-31: Minor cleanups and speedups / MG + *****************************************************************************/ + +#include +#include +#include +#include + +#ifndef M_PI + #define M_PI 3.1415926535897932384626433832795 +#endif + +/* Maximum delta T to allow for differential calculations */ +#define MAX_DELTA_T 0.01 + +/* Animation speed (10.0 looks good) */ +#define ANIMATION_SPEED 10.0 + + +GLfloat alpha = 210.0f, beta = -70.0f; +GLfloat zoom = 2.0f; + +int running = 1; + +struct Vertex +{ + GLfloat x,y,z; + GLfloat r,g,b; +}; + +#define GRIDW 50 +#define GRIDH 50 +#define VERTEXNUM (GRIDW*GRIDH) + +#define QUADW (GRIDW-1) +#define QUADH (GRIDH-1) +#define QUADNUM (QUADW*QUADH) + +GLuint quad[4*QUADNUM]; +struct Vertex vertex[VERTEXNUM]; + +/* The grid will look like this: + * + * 3 4 5 + * *---*---* + * | | | + * | 0 | 1 | + * | | | + * *---*---* + * 0 1 2 + */ + +void initVertices( void ) +{ + int x,y,p; + + /* place the vertices in a grid */ + for(y=0;y1) zoom-=1; + break; + case GLFW_KEY_PAGEDOWN: + zoom+=1; + break; + default: + break; + } +} + + +/* Callback function for window resize events */ +void GLFWCALL handle_resize( int width, int height ) +{ + float ratio = 1.0f; + + if( height > 0 ) + { + ratio = (float) width / (float) height; + } + + /* Setup viewport (Place where the stuff will appear in the main window). */ + glViewport(0, 0, width, height); + + /* + * Change to the projection matrix and set + * our viewing volume. + */ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60.0, ratio, 1.0, 1024.0); +} + + +/* Program entry point */ +int main(int argc, char* argv[]) +{ + /* Dimensions of our window. */ + int width, height; + /* Style of our window. */ + int mode; + /* Frame time */ + double t, t_old, dt_total; + + /* Initialize GLFW */ + if(glfwInit() == GL_FALSE) + { + fprintf(stderr, "GLFW initialization failed\n"); + exit(-1); + } + + /* Desired window properties */ + width = 640; + height = 480; + mode = GLFW_WINDOW; + + /* Open window */ + if( glfwOpenWindow(width,height,0,0,0,0,16,0,mode) == GL_FALSE ) + { + fprintf(stderr, "Could not open window\n"); + glfwTerminate(); + exit(-1); + } + + /* Set title */ + glfwSetWindowTitle( "Wave Simulation" ); + + glfwSwapInterval( 1 ); + + /* Keyboard handler */ + glfwSetKeyCallback( handle_key_down ); + glfwEnable( GLFW_KEY_REPEAT ); + + /* Window resize handler */ + glfwSetWindowSizeCallback( handle_resize ); + + /* Initialize OpenGL */ + setup_opengl(); + + /* Initialize simulation */ + initVertices(); + initSurface(); + adjustGrid(); + + /* Initialize timer */ + t_old = glfwGetTime() - 0.01; + + /* Main loop */ + while(running) + { + /* Timing */ + t = glfwGetTime(); + dt_total = t - t_old; + t_old = t; + + /* Safety - iterate if dt_total is too large */ + while( dt_total > 0.0f ) + { + /* Select iteration time step */ + dt = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total; + dt_total -= dt; + + /* Calculate wave propagation */ + calc(); + } + + /* Compute height of each vertex */ + adjustGrid(); + + /* Draw wave grid to OpenGL display */ + draw_screen(); + + /* Still running? */ + running = running && glfwGetWindowParam( GLFW_OPENED ); + } + + glfwTerminate(); + + return 0; +} From 0d05320324426dc268aad503f9883a68cb6af849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Tue, 5 Mar 2013 12:21:00 +0100 Subject: [PATCH 025/544] * Edited tests so they use emscripten_main_loop. * Got triangle test about to work. * Implemented misc functions. --- tests/glfw/Makefile | 55 +++++++-------- tests/glfw/boing.c | 34 +++++---- tests/glfw/gears.c | 40 +++++++---- tests/glfw/heightmap.c | 34 ++++++--- tests/glfw/mipmaps.c | 114 +++++++++++++++++-------------- tests/glfw/particles.c | 58 ++++++++++------ tests/glfw/pong3d.c | 62 +++++++++-------- tests/glfw/splitview.c | 43 +++++++----- tests/glfw/triangle.c | 152 ++++++++++++++++++++++------------------- 9 files changed, 345 insertions(+), 247 deletions(-) diff --git a/tests/glfw/Makefile b/tests/glfw/Makefile index 89138d74b87ae..85b9067c463ef 100644 --- a/tests/glfw/Makefile +++ b/tests/glfw/Makefile @@ -2,54 +2,55 @@ # Makefile for GLFW example programs on X11 (generated by compile.sh) ########################################################################## CC = emcc -CFLAGS = -I../include +CFLAGS = -I../include -DEMSCRIPTEN LIB = -lglfw SOLIB = LFLAGS = $(LIB) SO_LFLAGS = $(SOLIB) +EXT = html -BINARIES = triangle.js listmodes.js mthello.js pong3d.js mtbench.js particles.js splitview.js \ - mipmaps.js gears.js boing.js heightmap.js +BINARIES = triangle listmodes mthello pong3d mtbench particles splitview \ + mipmaps gears boing heightmap ## wave all: $(BINARIES) -triangle.js: triangle.c - $(CC) $(CFLAGS) triangle.c $(LFLAGS) -o $@ +triangle: triangle.c + $(CC) $(CFLAGS) triangle.c $(LFLAGS) -o $@.$(EXT) -listmodes.js: listmodes.c - $(CC) $(CFLAGS) listmodes.c $(LFLAGS) -o $@ +listmodes: listmodes.c + $(CC) $(CFLAGS) listmodes.c $(LFLAGS) -o $@.$(EXT) -mthello.js: mthello.c - $(CC) $(CFLAGS) mthello.c $(LFLAGS) -o $@ +mthello: mthello.c + $(CC) $(CFLAGS) mthello.c $(LFLAGS) -o $@.$(EXT) -pong3d.js: pong3d.c - $(CC) $(CFLAGS) pong3d.c $(LFLAGS) -o $@ +pong3d: pong3d.c + $(CC) $(CFLAGS) pong3d.c $(LFLAGS) -o $@.$(EXT) -mtbench.js: mtbench.c - $(CC) $(CFLAGS) mtbench.c $(LFLAGS) -o $@ +mtbench: mtbench.c + $(CC) $(CFLAGS) mtbench.c $(LFLAGS) -o $@.$(EXT) -particles.js: particles.c - $(CC) $(CFLAGS) particles.c $(LFLAGS) -o $@ +particles: particles.c + $(CC) $(CFLAGS) particles.c $(LFLAGS) -o $@.$(EXT) -splitview.js: splitview.c - $(CC) $(CFLAGS) splitview.c $(LFLAGS) -o $@ +splitview: splitview.c + $(CC) $(CFLAGS) splitview.c $(LFLAGS) -o $@.$(EXT) -mipmaps.js: mipmaps.c - $(CC) $(CFLAGS) mipmaps.c $(LFLAGS) -o $@ +mipmaps: mipmaps.c + $(CC) $(CFLAGS) mipmaps.c $(LFLAGS) -o $@.$(EXT) -gears.js: gears.c - $(CC) $(CFLAGS) gears.c $(LFLAGS) -o $@ +gears: gears.c + $(CC) $(CFLAGS) gears.c $(LFLAGS) -o $@.$(EXT) -boing.js: boing.c - $(CC) $(CFLAGS) boing.c $(LFLAGS) -o $@ +boing: boing.c + $(CC) $(CFLAGS) boing.c $(LFLAGS) -o $@.$(EXT) -wave.js: wave.c - $(CC) $(CFLAGS) wave.c $(LFLAGS) -o $@ +wave: wave.c + $(CC) $(CFLAGS) wave.c $(LFLAGS) -o $@.$(EXT) -heightmap.js: heightmap.c - $(CC) $(CFLAGS) heightmap.c $(LFLAGS) -o $@ +heightmap: heightmap.c + $(CC) $(CFLAGS) heightmap.c $(LFLAGS) -o $@.$(EXT) clean: rm -f $(BINARIES) diff --git a/tests/glfw/boing.c b/tests/glfw/boing.c index 08544d1a4716b..36c45b19ad94e 100644 --- a/tests/glfw/boing.c +++ b/tests/glfw/boing.c @@ -32,6 +32,10 @@ #include #include +#ifdef EMSCRIPTEN +#include +#endif + /***************************************************************************** * Various declarations and macros @@ -563,6 +567,19 @@ void DrawGrid( void ) * main() *======================================================================*/ +void iteration(){ + /* Timing */ + t = glfwGetTime(); + dt = t - t_old; + t_old = t; + + /* Draw one frame */ + display(); + + /* Swap buffers */ + glfwSwapBuffers(); +} + int main( void ) { int running; @@ -590,25 +607,18 @@ int main( void ) init(); /* Main loop */ +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else do { - /* Timing */ - t = glfwGetTime(); - dt = t - t_old; - t_old = t; - - /* Draw one frame */ - display(); - - /* Swap buffers */ - glfwSwapBuffers(); - + iteration(); /* Check if we are still running */ running = !glfwGetKey( GLFW_KEY_ESC ) && glfwGetWindowParam( GLFW_OPENED ); } while( running ); - +#endif glfwTerminate(); exit( EXIT_SUCCESS ); } diff --git a/tests/glfw/gears.c b/tests/glfw/gears.c index d9efdf9aa6314..012884145c123 100644 --- a/tests/glfw/gears.c +++ b/tests/glfw/gears.c @@ -32,6 +32,10 @@ #define M_PI 3.141592654 #endif +#ifdef EMSCRIPTEN +#include +#endif + /* The program exits when this is zero. */ static int running = 1; @@ -317,6 +321,22 @@ static void init(int argc, char *argv[]) } } +void iteration(){ + // Draw gears + draw(); + + // Update animation + animate(); + + // Swap buffers + glfwSwapBuffers(); + + // Was the window closed? + if( !glfwGetWindowParam( GLFW_OPENED ) ) + { + running = 0; + } +} /* program entry */ int main(int argc, char *argv[]) @@ -345,25 +365,15 @@ int main(int argc, char *argv[]) glfwSetWindowSizeCallback( reshape ); glfwSetKeyCallback( key ); +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else // Main loop while( running ) { - // Draw gears - draw(); - - // Update animation - animate(); - - // Swap buffers - glfwSwapBuffers(); - - // Was the window closed? - if( !glfwGetWindowParam( GLFW_OPENED ) ) - { - running = 0; - } + iteration(); } - +#endif // Terminate GLFW glfwTerminate(); diff --git a/tests/glfw/heightmap.c b/tests/glfw/heightmap.c index 7faa5d1f16859..4967ea114b003 100644 --- a/tests/glfw/heightmap.c +++ b/tests/glfw/heightmap.c @@ -30,6 +30,9 @@ #include #include "getopt.h" +#ifdef EMSCRIPTEN +#include +#endif #define GLFW_NO_GLU 1 #include @@ -674,12 +677,16 @@ static void usage(void) printf(" heightmap [-h]\n"); } +void iteration(); + +double dt; +int frame; +int iter; +double last_update_time; + int main(int argc, char** argv) { - int ch, iter; - double dt; - double last_update_time; - int frame; + int ch; float f; GLint uloc_modelview; GLint uloc_project; @@ -820,9 +827,21 @@ int main(int argc, char** argv) iter = 0; dt = last_update_time = glfwGetTime(); - while (running) +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else + // Main loop + while( running ) { - ++frame; + iteration(); + } +#endif + + exit(EXIT_SUCCESS); +} + +void iteration(){ + ++frame; /* render the next frame */ glClear(GL_COLOR_BUFFER_BIT); glDrawElements(GL_LINES, 2* MAP_NUM_LINES , GL_UNSIGNED_INT, 0); @@ -843,8 +862,5 @@ int main(int argc, char** argv) last_update_time = dt; frame = 0; } - } - - exit(EXIT_SUCCESS); } diff --git a/tests/glfw/mipmaps.c b/tests/glfw/mipmaps.c index 59bbef2e33774..bfd77f0617f21 100644 --- a/tests/glfw/mipmaps.c +++ b/tests/glfw/mipmaps.c @@ -10,11 +10,66 @@ #include +#ifdef EMSCRIPTEN +#include +#endif + +int width, height, x; +double time; +GLboolean running; + +void iteration(){ + // Get time and mouse position + time = glfwGetTime(); + glfwGetMousePos( &x, NULL ); + + // Get window size (may be different than the requested size) + glfwGetWindowSize( &width, &height ); + height = height > 0 ? height : 1; + + // Set viewport + glViewport( 0, 0, width, height ); + + // Clear color buffer + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); + glClear( GL_COLOR_BUFFER_BIT ); + + // Select and setup the projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 65.0f, (GLfloat)width / (GLfloat)height, 1.0f, + 50.0f ); + + // Select and setup the modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 0.0f, 3.0f, -20.0f, // Eye-position + 0.0f, -4.0f, -11.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + + // Draw a textured quad + glRotatef( 0.05f * (GLfloat)x + (GLfloat)time * 5.0f, 0.0f, 1.0f, 0.0f ); + glBegin( GL_QUADS ); + glTexCoord2f( -20.0f, 20.0f ); + glVertex3f( -50.0f, 0.0f, -50.0f ); + glTexCoord2f( 20.0f, 20.0f ); + glVertex3f( 50.0f, 0.0f, -50.0f ); + glTexCoord2f( 20.0f, -20.0f ); + glVertex3f( 50.0f, 0.0f, 50.0f ); + glTexCoord2f( -20.0f, -20.0f ); + glVertex3f( -50.0f, 0.0f, 50.0f ); + glEnd(); + + // Swap buffers + glfwSwapBuffers(); + + // Check if the ESC key was pressed or the window was closed + running = !glfwGetKey( GLFW_KEY_ESC ) && + glfwGetWindowParam( GLFW_OPENED ); +} + int main( void ) { - int width, height, x; - double time; - GLboolean running; GLuint textureID; char* texturePath = "mipmaps.tga"; @@ -63,56 +118,15 @@ int main( void ) glEnable( GL_TEXTURE_2D ); running = GL_TRUE; +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else + // Main loop while( running ) { - // Get time and mouse position - time = glfwGetTime(); - glfwGetMousePos( &x, NULL ); - - // Get window size (may be different than the requested size) - glfwGetWindowSize( &width, &height ); - height = height > 0 ? height : 1; - - // Set viewport - glViewport( 0, 0, width, height ); - - // Clear color buffer - glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); - glClear( GL_COLOR_BUFFER_BIT ); - - // Select and setup the projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - gluPerspective( 65.0f, (GLfloat)width / (GLfloat)height, 1.0f, - 50.0f ); - - // Select and setup the modelview matrix - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - gluLookAt( 0.0f, 3.0f, -20.0f, // Eye-position - 0.0f, -4.0f, -11.0f, // View-point - 0.0f, 1.0f, 0.0f ); // Up-vector - - // Draw a textured quad - glRotatef( 0.05f * (GLfloat)x + (GLfloat)time * 5.0f, 0.0f, 1.0f, 0.0f ); - glBegin( GL_QUADS ); - glTexCoord2f( -20.0f, 20.0f ); - glVertex3f( -50.0f, 0.0f, -50.0f ); - glTexCoord2f( 20.0f, 20.0f ); - glVertex3f( 50.0f, 0.0f, -50.0f ); - glTexCoord2f( 20.0f, -20.0f ); - glVertex3f( 50.0f, 0.0f, 50.0f ); - glTexCoord2f( -20.0f, -20.0f ); - glVertex3f( -50.0f, 0.0f, 50.0f ); - glEnd(); - - // Swap buffers - glfwSwapBuffers(); - - // Check if the ESC key was pressed or the window was closed - running = !glfwGetKey( GLFW_KEY_ESC ) && - glfwGetWindowParam( GLFW_OPENED ); + iteration(); } +#endif // Close OpenGL window and terminate GLFW glfwTerminate(); diff --git a/tests/glfw/particles.c b/tests/glfw/particles.c index 403a99978e9fa..15c133a0aa921 100644 --- a/tests/glfw/particles.c +++ b/tests/glfw/particles.c @@ -43,6 +43,10 @@ #include #include +#ifdef EMSCRIPTEN +#include +#endif + // Define tokens for GL_EXT_separate_specular_color if not already defined #ifndef GL_EXT_separate_specular_color #define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 @@ -970,10 +974,34 @@ void GLFWCALL PhysicsThreadFun( void *arg ) // main() //======================================================================== +double t0, t; +int frames, benchmark; +void iteration(){ + // Get frame time + t = glfwGetTime() - t0; + + // Draw... + Draw( t ); + + // Swap buffers + glfwSwapBuffers(); + + // Check if window was closed + running = running && glfwGetWindowParam( GLFW_OPENED ); + + // Increase frame count + frames ++; + + // End of benchmark? + if( benchmark && t >= 60.0 ) + { + running = 0; + } +} + int main( int argc, char **argv ) { - int i, frames, benchmark; - double t0, t; + int i; GLFWthread physics_thread = 0; // Use multithreading by default, but don't benchmark @@ -1108,29 +1136,15 @@ int main( int argc, char **argv ) // Main loop t0 = glfwGetTime(); frames = 0; +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else + // Main loop while( running ) { - // Get frame time - t = glfwGetTime() - t0; - - // Draw... - Draw( t ); - - // Swap buffers - glfwSwapBuffers(); - - // Check if window was closed - running = running && glfwGetWindowParam( GLFW_OPENED ); - - // Increase frame count - frames ++; - - // End of benchmark? - if( benchmark && t >= 60.0 ) - { - running = 0; - } + iteration(); } +#endif t = glfwGetTime() - t0; // Wait for particle physics thread to die diff --git a/tests/glfw/pong3d.c b/tests/glfw/pong3d.c index 1d1afd1f1808d..1f136c93ffa83 100644 --- a/tests/glfw/pong3d.c +++ b/tests/glfw/pong3d.c @@ -10,6 +10,9 @@ #include #include +#ifdef EMSCRIPTEN +#include +#endif //======================================================================== // Constants @@ -719,20 +722,9 @@ void GameOver( void ) // GameLoop() - Game loop //======================================================================== -void GameLoop( void ) -{ - int playing, event; - - // Initialize a new game - NewGame(); +int playing, event; - // Enable sticky keys - glfwEnable( GLFW_STICKY_KEYS ); - - // Loop until the game ends - playing = GL_TRUE; - while( playing && glfwGetWindowParam( GLFW_OPENED ) ) - { +void iteration(){ // Frame timer oldtime = thistime; thistime = glfwGetTime(); @@ -784,7 +776,36 @@ void GameLoop( void ) // Swap buffers glfwSwapBuffers(); +} + +void GameLoop( void ) +{ + int menuoption; + + // Initialize a new game + NewGame(); + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Loop until the game ends + playing = GL_TRUE; + + menuoption = GameMenu(); + + // If the user wants to play, let him... + if( menuoption != MENU_PLAY) + playing = GL_FALSE; + +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else + // Main loop + while( playing && glfwGetWindowParam( GLFW_OPENED ) ) + { + iteration(); } +#endif // Disable sticky keys glfwDisable( GLFW_STICKY_KEYS ); @@ -800,7 +821,6 @@ void GameLoop( void ) int main( void ) { - int menuoption; // Initialize GLFW if( !glfwInit() ) @@ -826,19 +846,7 @@ int main( void ) exit( EXIT_FAILURE ); } - // Main loop - do - { - // Get menu option - menuoption = GameMenu(); - - // If the user wants to play, let him... - if( menuoption == MENU_PLAY ) - { - GameLoop(); - } - } - while( menuoption != MENU_QUIT ); + GameLoop(); // Unload all textures if( glfwGetWindowParam( GLFW_OPENED ) ) diff --git a/tests/glfw/splitview.c b/tests/glfw/splitview.c index 932cd0d6511b1..bb85a6e7be6f8 100644 --- a/tests/glfw/splitview.c +++ b/tests/glfw/splitview.c @@ -15,6 +15,10 @@ #include #include +#ifdef EMSCRIPTEN +#include +#endif + #ifndef M_PI #define M_PI 3.14159265358979323846 #endif @@ -446,6 +450,23 @@ static void GLFWCALL mouseButtonFun( int button, int action ) // main() //======================================================================== +void iteration(){ + // Only redraw if we need to + if( do_redraw ) + { + // Draw all views + drawAllViews(); + + // Swap buffers + glfwSwapBuffers(); + + do_redraw = 0; + } + + // Wait for new events + glfwWaitEvents(); +} + int main( void ) { // Initialise GLFW @@ -484,27 +505,17 @@ int main( void ) glfwSetMousePosCallback( mousePosFun ); glfwSetMouseButtonCallback( mouseButtonFun ); +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else // Main loop - do + do { - // Only redraw if we need to - if( do_redraw ) - { - // Draw all views - drawAllViews(); - - // Swap buffers - glfwSwapBuffers(); - - do_redraw = 0; - } - - // Wait for new events - glfwWaitEvents(); - + iteration(); } // Check if the ESC key was pressed or the window was closed while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS && glfwGetWindowParam( GLFW_OPENED ) ); +#endif // Close OpenGL window and terminate GLFW glfwTerminate(); diff --git a/tests/glfw/triangle.c b/tests/glfw/triangle.c index a8b737bee7fe2..db9d9ab163573 100644 --- a/tests/glfw/triangle.c +++ b/tests/glfw/triangle.c @@ -8,87 +8,101 @@ #include #include +#ifdef EMSCRIPTEN +#include +#endif -int main( void ) +void +iteration () { - int width, height, x; - double t; + int width, height, x; + double t; + + t = glfwGetTime (); + glfwGetMousePos (&x, NULL); + + // Get window size (may be different than the requested size) + glfwGetWindowSize (&width, &height); + + // Special case: avoid division by zero below + height = height > 0 ? height : 1; + + glViewport (0, 0, width, height); + + // Clear color buffer to black + glClearColor (0.0f, 0.0f, 0.0f, 0.0f); + glClear (GL_COLOR_BUFFER_BIT); + + // Select and setup the projection matrix + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + gluPerspective (65.0f, (GLfloat) width / (GLfloat) height, 1.0f, 100.0f); + + // Select and setup the modelview matrix + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + gluLookAt (0.0f, 1.0f, 0.0f, // Eye-position + 0.0f, 20.0f, 0.0f, // View-point + 0.0f, 0.0f, 1.0f); // Up-vector + + // Draw a rotating colorful triangle + //glTranslatef (0.0f, 14.0f, 0.0f); + glTranslatef (0.0f, 1.0f, 0.0f); + glRotatef (0.3f * (GLfloat) x + (GLfloat) t * 100.0f, 0.0f, 0.0f, 1.0f); + glBegin (GL_TRIANGLES); + glColor3f (1.0f, 0.0f, 0.0f); + glVertex3f (-5.0f, 0.0f, -4.0f); + glColor3f (0.0f, 1.0f, 0.0f); + glVertex3f (5.0f, 0.0f, -4.0f); + glColor3f (0.0f, 0.0f, 1.0f); + glVertex3f (0.0f, 0.0f, 6.0f); + glEnd (); + + // Swap buffers + glfwSwapBuffers (); - // Initialise GLFW - if( !glfwInit() ) +} + +int +main (void) +{ + // Initialise GLFW + if (!glfwInit ()) { - fprintf( stderr, "Failed to initialize GLFW\n" ); - exit( EXIT_FAILURE ); + fprintf (stderr, "Failed to initialize GLFW\n"); + exit (EXIT_FAILURE); } - // Open a window and create its OpenGL context - if( !glfwOpenWindow( 640, 480, 0,0,0,0, 0,0, GLFW_WINDOW ) ) + // Open a window and create its OpenGL context + if (!glfwOpenWindow (640, 480, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) { - fprintf( stderr, "Failed to open GLFW window\n" ); + fprintf (stderr, "Failed to open GLFW window\n"); - glfwTerminate(); - exit( EXIT_FAILURE ); + glfwTerminate (); + exit (EXIT_FAILURE); } - glfwSetWindowTitle( "Spinning Triangle" ); + glfwSetWindowTitle ("Spinning Triangle"); - // Ensure we can capture the escape key being pressed below - glfwEnable( GLFW_STICKY_KEYS ); + // Ensure we can capture the escape key being pressed below + glfwEnable (GLFW_STICKY_KEYS); - // Enable vertical sync (on cards that support it) - glfwSwapInterval( 1 ); + // Enable vertical sync (on cards that support it) + glfwSwapInterval (1); - do +#ifdef EMSCRIPTEN + emscripten_set_main_loop (iteration, 0, 1); +#else + do { - t = glfwGetTime(); - glfwGetMousePos( &x, NULL ); - - // Get window size (may be different than the requested size) - glfwGetWindowSize( &width, &height ); - - // Special case: avoid division by zero below - height = height > 0 ? height : 1; - - glViewport( 0, 0, width, height ); - - // Clear color buffer to black - glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); - glClear( GL_COLOR_BUFFER_BIT ); - - // Select and setup the projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - gluPerspective( 65.0f, (GLfloat)width/(GLfloat)height, 1.0f, 100.0f ); - - // Select and setup the modelview matrix - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - gluLookAt( 0.0f, 1.0f, 0.0f, // Eye-position - 0.0f, 20.0f, 0.0f, // View-point - 0.0f, 0.0f, 1.0f ); // Up-vector - - // Draw a rotating colorful triangle - glTranslatef( 0.0f, 14.0f, 0.0f ); - glRotatef( 0.3f*(GLfloat)x + (GLfloat)t*100.0f, 0.0f, 0.0f, 1.0f ); - glBegin( GL_TRIANGLES ); - glColor3f( 1.0f, 0.0f, 0.0f ); - glVertex3f( -5.0f, 0.0f, -4.0f ); - glColor3f( 0.0f, 1.0f, 0.0f ); - glVertex3f( 5.0f, 0.0f, -4.0f ); - glColor3f( 0.0f, 0.0f, 1.0f ); - glVertex3f( 0.0f, 0.0f, 6.0f ); - glEnd(); - - // Swap buffers - glfwSwapBuffers(); - - } // Check if the ESC key was pressed or the window was closed - while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS && - glfwGetWindowParam( GLFW_OPENED ) ); - - // Close OpenGL window and terminate GLFW - glfwTerminate(); - - exit( EXIT_SUCCESS ); -} + iteration (); + } // Check if the ESC key was pressed or the window was closed + while (glfwGetKey (GLFW_KEY_ESC) != GLFW_PRESS && + glfwGetWindowParam (GLFW_OPENED)); +#endif + + // Close OpenGL window and terminate GLFW + glfwTerminate (); + exit (EXIT_SUCCESS); +} From 6530ca0ac9f02daf28dcb9e6dc953d9ad9b520b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Tue, 12 Mar 2013 18:25:28 +0100 Subject: [PATCH 026/544] * Added a test. * Mouse events are ok. * Keyboard events work partially. --- tests/glfw/Makefile | 5 +- tests/glfw/glfwsample.c | 375 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 379 insertions(+), 1 deletion(-) create mode 100644 tests/glfw/glfwsample.c diff --git a/tests/glfw/Makefile b/tests/glfw/Makefile index 85b9067c463ef..9bf06d802bc42 100644 --- a/tests/glfw/Makefile +++ b/tests/glfw/Makefile @@ -11,7 +11,7 @@ SO_LFLAGS = $(SOLIB) EXT = html BINARIES = triangle listmodes mthello pong3d mtbench particles splitview \ - mipmaps gears boing heightmap + mipmaps gears boing heightmap glfwsample ## wave all: $(BINARIES) @@ -51,6 +51,9 @@ wave: wave.c heightmap: heightmap.c $(CC) $(CFLAGS) heightmap.c $(LFLAGS) -o $@.$(EXT) + +glfwsample: glfwsample.c + $(CC) $(CFLAGS) glfwsample.c $(LFLAGS) -o $@.$(EXT) clean: rm -f $(BINARIES) diff --git a/tests/glfw/glfwsample.c b/tests/glfw/glfwsample.c new file mode 100644 index 0000000000000..38b37ceae1200 --- /dev/null +++ b/tests/glfw/glfwsample.c @@ -0,0 +1,375 @@ +#include +#include +#include + +#ifdef EMSCRIPTEN +#include +#endif + +void Init(void); +void Shut_Down(int return_code); +int Iteration(void); +void Draw_Square(float red, float green, float blue); +void Draw(void); +void OnKeyPressed( int key, int action ); +void OnCharPressed( int character, int action ); +char* GetKeyName(int key); +char* GetParamName(int param); +int OnClose(); +void OnResize( int width, int height ); +void OnRefresh(); +void OnMouseClick( int button, int action ); +void OnMouseMove( int x, int y ); +void OnMouseWheel( int pos ); +void PullInfo(); +void Iteration_void(); + +int params[] = {GLFW_OPENED, GLFW_ACTIVE, GLFW_ICONIFIED, GLFW_ACCELERATED, GLFW_RED_BITS, GLFW_GREEN_BITS, GLFW_BLUE_BITS, GLFW_ALPHA_BITS, GLFW_DEPTH_BITS, GLFW_STENCIL_BITS, GLFW_REFRESH_RATE, GLFW_ACCUM_RED_BITS, GLFW_ACCUM_GREEN_BITS, GLFW_ACCUM_BLUE_BITS, GLFW_ACCUM_ALPHA_BITS, GLFW_AUX_BUFFERS, GLFW_STEREO, GLFW_WINDOW_NO_RESIZE, GLFW_FSAA_SAMPLES, GLFW_OPENGL_VERSION_MAJOR, GLFW_OPENGL_VERSION_MINOR, GLFW_OPENGL_FORWARD_COMPAT, GLFW_OPENGL_DEBUG_CONTEXT, GLFW_OPENGL_PROFILE}; +unsigned int nb_params = sizeof(params) / sizeof(int); + +int features[] = {GLFW_MOUSE_CURSOR, GLFW_STICKY_KEYS, GLFW_STICKY_MOUSE_BUTTONS, GLFW_SYSTEM_KEYS, GLFW_KEY_REPEAT, GLFW_AUTO_POLL_EVENTS}; +unsigned int nb_features = sizeof(features) / sizeof(int); + +float rotate_y = 0, + rotate_z = 0; +const float rotations_per_tick = .2; +// the time of the previous frame +double old_time; + +int main(void) +{ + Init(); + old_time = glfwGetTime(); +#ifdef EMSCRIPTEN + emscripten_set_main_loop (Iteration_void, 0, 1); +#else + while(Iteration()); +#endif + Shut_Down(0); +} + +void Init() +{ + const int window_width = 800, + window_height = 600; + + if (glfwInit() != GL_TRUE) + Shut_Down(1); + // 800 x 600, 16 bit color, no depth, alpha or stencil buffers, windowed + if (glfwOpenWindow(window_width, window_height, 5, 6, 5, + 0, 0, 0, GLFW_WINDOW) != GL_TRUE) + Shut_Down(1); + glfwSetWindowTitle("The GLFW Window"); + + glfwSetKeyCallback( OnKeyPressed ); + glfwSetCharCallback( OnCharPressed ); + glfwSetWindowCloseCallback(OnClose); + glfwSetWindowSizeCallback(OnResize); + glfwSetWindowRefreshCallback(OnRefresh); + glfwSetMouseWheelCallback(OnMouseWheel); + glfwSetMousePosCallback(OnMouseMove); + glfwSetMouseButtonCallback(OnMouseClick); + + // set the projection matrix to a normal frustum with a max depth of 50 + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + float aspect_ratio = ((float)window_height) / window_width; + glFrustum(.5, -.5, -.5 * aspect_ratio, .5 * aspect_ratio, 1, 50); + glMatrixMode(GL_MODELVIEW); + + PullInfo(); +} + +void Shut_Down(int return_code) +{ + glfwTerminate(); + exit(return_code); +} + +int Iteration() +{ + // calculate time elapsed, and the amount by which stuff rotates + double current_time = glfwGetTime(), + delta_rotate = (current_time - old_time) * rotations_per_tick * 360; + old_time = current_time; + // escape to quit, arrow keys to rotate view + if (glfwGetKey(GLFW_KEY_ESC) == GLFW_PRESS) return 0; + if (glfwGetKey(GLFW_KEY_LEFT) == GLFW_PRESS) + rotate_y += delta_rotate; + if (glfwGetKey(GLFW_KEY_RIGHT) == GLFW_PRESS) + rotate_y -= delta_rotate; + // z axis always rotates + rotate_z += delta_rotate; + + // clear the buffer + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // draw the figure + Draw(); + // swap back and front buffers + glfwSwapBuffers(); + return 1; +} + +void Iteration_void(){ + Iteration(); +} + +void Draw_Square(float red, float green, float blue) +{ +#ifndef EMSCRIPTEN + // Draws a square with a gradient color at coordinates 0, 10 + glBegin(GL_QUADS); + { + glColor3f(red, green, blue); + glVertex2i(1, 11); + glColor3f(red * .8, green * .8, blue * .8); + glVertex2i(-1, 11); + glColor3f(red * .5, green * .5, blue * .5); + glVertex2i(-1, 9); + glColor3f(red * .8, green * .8, blue * .8); + glVertex2i(1, 9); + } + glEnd(); +#endif +} + +void Draw(void) +{ + // reset view matrix + glLoadIdentity(); + // move view back a bit + glTranslatef(0, 0, -30); + // apply the current rotation + glRotatef(rotate_y, 0, 1, 0); + glRotatef(rotate_z, 0, 0, 1); + // by repeatedly rotating the view matrix during drawing, the + // squares end up in a circle + int i = 0, squares = 15; + float red = 0, blue = 1; + for (; i < squares; ++i){ + glRotatef(360.0/squares, 0, 0, 1); + // colors change for each square + red += 1.0/12; + blue -= 1.0/12; + Draw_Square(red, .6, blue); + } +} + +void OnCharPressed( int character, int action ){ + if(action == GLFW_PRESS) + printf("'%c' is pressed\n", character); + if(action == GLFW_RELEASE) + printf("'%c' is released\n", character); +} + +char* GetKeyName(int key){ + switch(key){ + case GLFW_KEY_UNKNOWN: return "unknown"; + case GLFW_KEY_SPACE: return "space"; + case GLFW_KEY_SPECIAL: return "special"; + case GLFW_KEY_ESC: return "escape"; + case GLFW_KEY_F1 : return "F1"; + case GLFW_KEY_F2 : return "F2"; + case GLFW_KEY_F3 : return "F3"; + case GLFW_KEY_F4 : return "F4"; + case GLFW_KEY_F5 : return "F5"; + case GLFW_KEY_F6 : return "F6"; + case GLFW_KEY_F7 : return "F7"; + case GLFW_KEY_F8 : return "F8"; + case GLFW_KEY_F9 : return "F9"; + case GLFW_KEY_F10: return "F10"; + case GLFW_KEY_F11: return "F11"; + case GLFW_KEY_F12: return "F12"; + case GLFW_KEY_F13: return "F13"; + case GLFW_KEY_F14: return "F14"; + case GLFW_KEY_F15: return "F15"; + case GLFW_KEY_F16: return "F16"; + case GLFW_KEY_F17: return "F17"; + case GLFW_KEY_F18: return "F18"; + case GLFW_KEY_F19: return "F19"; + case GLFW_KEY_F20: return "F20"; + case GLFW_KEY_F21: return "F21"; + case GLFW_KEY_F22: return "F22"; + case GLFW_KEY_F23: return "F23"; + case GLFW_KEY_F24: return "F24"; + case GLFW_KEY_F25: return "F25"; + case GLFW_KEY_UP : return "up"; + case GLFW_KEY_DOWN: return "down"; + case GLFW_KEY_LEFT: return "left"; + case GLFW_KEY_RIGHT: return "right"; + case GLFW_KEY_LSHIFT: return "left shift"; + case GLFW_KEY_RSHIFT: return "right shift"; + case GLFW_KEY_LCTRL: return "left ctrl"; + case GLFW_KEY_RCTRL: return "right ctrl"; + case GLFW_KEY_LALT: return "left alt"; + case GLFW_KEY_RALT: return "right alt"; + case GLFW_KEY_TAB: return "tab"; + case GLFW_KEY_ENTER: return "enter"; + case GLFW_KEY_BACKSPACE: return "backspace"; + case GLFW_KEY_INSERT: return "insertr"; + case GLFW_KEY_DEL: return "del"; + case GLFW_KEY_PAGEUP: return "page up"; + case GLFW_KEY_PAGEDOWN: return "page down"; + case GLFW_KEY_HOME: return "home"; + case GLFW_KEY_END: return "end"; + case GLFW_KEY_KP_0: return "0"; + case GLFW_KEY_KP_1: return "1"; + case GLFW_KEY_KP_2: return "2"; + case GLFW_KEY_KP_3: return "3"; + case GLFW_KEY_KP_4: return "4"; + case GLFW_KEY_KP_5: return "5"; + case GLFW_KEY_KP_6: return "6"; + case GLFW_KEY_KP_7: return "7"; + case GLFW_KEY_KP_8: return "8"; + case GLFW_KEY_KP_9: return "9"; + case GLFW_KEY_KP_DIVIDE: return "/"; + case GLFW_KEY_KP_MULTIPLY: return "*"; + case GLFW_KEY_KP_SUBTRACT: return "-"; + case GLFW_KEY_KP_ADD: return "+"; + case GLFW_KEY_KP_DECIMAL: return "."; + case GLFW_KEY_KP_EQUAL: return "="; + case GLFW_KEY_KP_ENTER: return "enter"; + case GLFW_KEY_KP_NUM_LOCK: return "num lock"; + case GLFW_KEY_CAPS_LOCK: return "caps lock"; + case GLFW_KEY_SCROLL_LOCK: return "scroll lock"; + case GLFW_KEY_PAUSE: return "pause"; + case GLFW_KEY_LSUPER: return "left super"; + case GLFW_KEY_RSUPER: return "right super"; + case GLFW_KEY_MENU: return "menu"; + } + char* chr = malloc(2*sizeof(char)); + chr[0] = key; + chr[1] = '\0'; + return chr; +} + +char* GetParamName(int param){ + switch(param){ + case GLFW_WINDOW : return "GLFW_WINDOW"; + case GLFW_FULLSCREEN : return "GLFW_FULLSCREEN"; + case GLFW_OPENED : return "GLFW_OPENED"; + case GLFW_ACTIVE : return "GLFW_ACTIVE"; + case GLFW_ICONIFIED : return "GLFW_ICONIFIED"; + case GLFW_ACCELERATED : return "GLFW_ACCELERATED"; + case GLFW_RED_BITS : return "GLFW_RED_BITS"; + case GLFW_GREEN_BITS : return "GLFW_GREEN_BITS"; + case GLFW_BLUE_BITS : return "GLFW_BLUE_BITS"; + case GLFW_ALPHA_BITS : return "GLFW_ALPHA_BITS"; + case GLFW_DEPTH_BITS : return "GLFW_DEPTH_BITS"; + case GLFW_STENCIL_BITS : return "GLFW_STENCIL_BITS"; + case GLFW_REFRESH_RATE : return "GLFW_REFRESH_RATE"; + case GLFW_ACCUM_RED_BITS : return "GLFW_ACCUM_RED_BITS"; + case GLFW_ACCUM_GREEN_BITS : return "GLFW_ACCUM_GREEN_BITS"; + case GLFW_ACCUM_BLUE_BITS : return "GLFW_BLUE_BITS"; + case GLFW_ACCUM_ALPHA_BITS : return "GLFW_ALPHA_BITS"; + case GLFW_AUX_BUFFERS : return "GLFW_AUX_BUFFERS"; + case GLFW_STEREO : return "GLFW_STEREO"; + case GLFW_WINDOW_NO_RESIZE : return "GLFW_WINDOW_NO_RESIZE"; + case GLFW_FSAA_SAMPLES : return "GLFW_FSAA_SAMPLES"; + case GLFW_OPENGL_VERSION_MAJOR : return "GLFW_OPENGL_VERSION_MAJOR"; + case GLFW_OPENGL_VERSION_MINOR : return "GLFW_OPENGL_VERSION_MINOR"; + case GLFW_OPENGL_FORWARD_COMPAT : return "GLFW_OPENGL_FORWARD_COMPAT"; + case GLFW_OPENGL_DEBUG_CONTEXT : return "GLFW_OPENGL_DEBUG_CONTEXT"; + case GLFW_OPENGL_PROFILE : return "GLFW_OPENGL_PROFILE"; + case GLFW_OPENGL_CORE_PROFILE : return "GLFW_OPENGL_CORE_PROFILE | GLFW_PRESENT"; + case GLFW_OPENGL_COMPAT_PROFILE : return "GLFW_OPENGL_COMPAT_PROFILE | GLFW_AXES"; + case GLFW_MOUSE_CURSOR : return "GLFW_MOUSE_CURSOR"; + case GLFW_STICKY_KEYS : return "GLFW_STICKY_KEYS"; + case GLFW_STICKY_MOUSE_BUTTONS : return "GLFW_STICKY_MOUSE_BUTTONS"; + case GLFW_SYSTEM_KEYS : return "GLFW_SYSTEM_KEYS"; + case GLFW_KEY_REPEAT : return "GLFW_KEY_REPEAT"; + case GLFW_AUTO_POLL_EVENTS : return "GLFW_AUTO_POLL_EVENTS"; + case GLFW_WAIT : return "GLFW_WAIT"; + case GLFW_NOWAIT : return "GLFW_NOWAIT"; + case GLFW_BUTTONS : return "GLFW_BUTTONS"; + case GLFW_NO_RESCALE_BIT : return "GLFW_NO_RESCALE_BIT"; + case GLFW_ORIGIN_UL_BIT : return "GLFW_ORIGIN_UL_BIT"; + case GLFW_BUILD_MIPMAPS_BIT : return "GLFW_BUILD_MIPMAPS_BIT"; + case GLFW_ALPHA_MAP_BIT : return "GLFW_ALPHA_MAP_BIT"; + default : return "Invalid param"; + } +} +void OnKeyPressed( int key, int action ){ + const char* key_name = GetKeyName(key); + if(key_name == 0) + return; + if(action == GLFW_PRESS) + printf("%s (%i) is pressed\n", key_name, key); + if(action == GLFW_RELEASE) + printf("%s (%i) is released\n", key_name, key); + if(action == GLFW_RELEASE && key == GLFW_KEY_ENTER) + PullInfo(); +} + +int OnClose(){ + printf("Closed\n"); + return 0; +} + +void OnRefresh(){ + printf("Refresh\n"); +} + +void OnResize( int width, int height ){ + printf("Resizing to %i %i\n", width, height); +} + +void OnMouseClick( int button, int action ){ + if(action == GLFW_PRESS) + printf("Mouse button %i has been pressed\n", button); + if(action == GLFW_RELEASE) + printf("Mouse button %i has been released\n", button); +} + +void OnMouseMove( int x, int y ){ + printf("Mouse has been moved to %i %i\n", x, y); +} + +void OnMouseWheel( int pos ){ + printf("Mouse wheel has been moved to %i\n", pos); +} + +void PullInfo(){ + printf("================================================================================\n"); + int major, minor, rev; + glfwGetVersion(&major, &minor, &rev); + printf("GLFW version is %i.%i.%i\n", major, minor, rev); + + int width, height; + glfwGetWindowSize(&width, &height); + printf("Window size is %i %i\n", width, height); + + int status = glfwGetKey(GLFW_KEY_LCTRL); + if(status == GLFW_PRESS) + printf("Left control is pressed\n"); + else + printf("Left control is released\n"); + + status = glfwGetMouseButton(GLFW_MOUSE_BUTTON_1); + if(status == GLFW_PRESS) + printf("Mouse button 1 is pressed\n"); + else + printf("Mouse button 1 is released\n"); + + int x, y; + glfwGetMousePos(&x, &y); + printf("Mouse position is %i %i\n", x, y); + + int wheel = glfwGetMouseWheel(); + printf("Mouse wheel pos is %i\n", wheel); + + double time = glfwGetTime(); + printf("Time is %f\n", time); + + glfwGetGLVersion(&major, &minor, &rev); + printf("GL version is %i.%i.%i\n", major, minor, rev); + + int proc = glfwGetNumberOfProcessors(); + printf("%i processors are available\n", proc); + + unsigned int i; + for(i = 0; i Date: Wed, 13 Mar 2013 14:15:36 +0100 Subject: [PATCH 027/544] * Minor fix. --- tests/glfw/glfwsample.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/glfw/glfwsample.c b/tests/glfw/glfwsample.c index 38b37ceae1200..771537c581add 100644 --- a/tests/glfw/glfwsample.c +++ b/tests/glfw/glfwsample.c @@ -157,9 +157,9 @@ void Draw(void) void OnCharPressed( int character, int action ){ if(action == GLFW_PRESS) - printf("'%c' is pressed\n", character); + printf("'%c' (%i) char is pressed\n", character, character); if(action == GLFW_RELEASE) - printf("'%c' is released\n", character); + printf("'%c' (%i) char is released\n", character, character); } char* GetKeyName(int key){ @@ -294,9 +294,9 @@ void OnKeyPressed( int key, int action ){ if(key_name == 0) return; if(action == GLFW_PRESS) - printf("%s (%i) is pressed\n", key_name, key); + printf("%s (%i) key is pressed\n", key_name, key); if(action == GLFW_RELEASE) - printf("%s (%i) is released\n", key_name, key); + printf("%s (%i) key is released\n", key_name, key); if(action == GLFW_RELEASE && key == GLFW_KEY_ENTER) PullInfo(); } From c670dde7c62d1e0c2e69ca0720b1b11a3464beba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Fri, 15 Mar 2013 13:02:33 +0100 Subject: [PATCH 028/544] * OpenGL extensions. --- AUTHORS | 1 + tests/glfw/glfwsample.c | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 7641b0c14de60..9eda98519ef32 100644 --- a/AUTHORS +++ b/AUTHORS @@ -58,3 +58,4 @@ a license to everyone to use it as detailed in LICENSE.) * Felix H. Dahlke * Éloi Rivard +>>>>>>> * OpenGL extensions. diff --git a/tests/glfw/glfwsample.c b/tests/glfw/glfwsample.c index 771537c581add..3d9be100e70bd 100644 --- a/tests/glfw/glfwsample.c +++ b/tests/glfw/glfwsample.c @@ -67,8 +67,8 @@ void Init() glfwSetWindowSizeCallback(OnResize); glfwSetWindowRefreshCallback(OnRefresh); glfwSetMouseWheelCallback(OnMouseWheel); - glfwSetMousePosCallback(OnMouseMove); - glfwSetMouseButtonCallback(OnMouseClick); + //glfwSetMousePosCallback(OnMouseMove); + //glfwSetMouseButtonCallback(OnMouseClick); // set the projection matrix to a normal frustum with a max depth of 50 glMatrixMode(GL_PROJECTION); @@ -289,14 +289,15 @@ char* GetParamName(int param){ default : return "Invalid param"; } } + void OnKeyPressed( int key, int action ){ const char* key_name = GetKeyName(key); if(key_name == 0) return; if(action == GLFW_PRESS) - printf("%s (%i) key is pressed\n", key_name, key); + printf("'%s' (%i) key is pressed\n", key_name, key); if(action == GLFW_RELEASE) - printf("%s (%i) key is released\n", key_name, key); + printf("'%s' (%i) key is released\n", key_name, key); if(action == GLFW_RELEASE && key == GLFW_KEY_ENTER) PullInfo(); } @@ -331,6 +332,7 @@ void OnMouseWheel( int pos ){ void PullInfo(){ printf("================================================================================\n"); + int major, minor, rev; glfwGetVersion(&major, &minor, &rev); printf("GLFW version is %i.%i.%i\n", major, minor, rev); @@ -371,5 +373,15 @@ void PullInfo(){ for(i = 0; i Date: Wed, 27 Mar 2013 14:29:57 +0100 Subject: [PATCH 029/544] * Fixed mouse position. --- tests/glfw/glfwsample.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/glfw/glfwsample.c b/tests/glfw/glfwsample.c index 3d9be100e70bd..79b504b61431e 100644 --- a/tests/glfw/glfwsample.c +++ b/tests/glfw/glfwsample.c @@ -67,8 +67,8 @@ void Init() glfwSetWindowSizeCallback(OnResize); glfwSetWindowRefreshCallback(OnRefresh); glfwSetMouseWheelCallback(OnMouseWheel); - //glfwSetMousePosCallback(OnMouseMove); - //glfwSetMouseButtonCallback(OnMouseClick); + glfwSetMousePosCallback(OnMouseMove); + glfwSetMouseButtonCallback(OnMouseClick); // set the projection matrix to a normal frustum with a max depth of 50 glMatrixMode(GL_PROJECTION); @@ -323,7 +323,12 @@ void OnMouseClick( int button, int action ){ } void OnMouseMove( int x, int y ){ - printf("Mouse has been moved to %i %i\n", x, y); + int lState = glfwGetMouseButton(GLFW_MOUSE_BUTTON_LEFT); + + if (lState == GLFW_PRESS) + printf("Dragged %i to %i %i\n", GLFW_MOUSE_BUTTON_LEFT, x, y); + if(lState == GLFW_RELEASE) + printf("Moved %i to %i %i\n", GLFW_MOUSE_BUTTON_LEFT, x, y); } void OnMouseWheel( int pos ){ From 9479779ef45b9273ecfb51fe95b99d13b6cfdf76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Tue, 2 Apr 2013 12:39:55 +0200 Subject: [PATCH 030/544] * Fixed glfw test. --- tests/glfw/Makefile | 60 -- tests/glfw/boing.c | 625 ------------------ tests/glfw/bundle.sh | 46 -- tests/glfw/gears.c | 383 ----------- tests/glfw/getopt.c | 253 ------- tests/glfw/getopt.h | 63 -- tests/glfw/glfwsample.c | 392 ----------- tests/glfw/heightmap.c | 866 ------------------------ tests/glfw/listmodes.c | 48 -- tests/glfw/mipmaps.c | 136 ---- tests/glfw/mipmaps.tga | Bin 66322 -> 0 bytes tests/glfw/mtbench.c | 301 --------- tests/glfw/mthello.c | 48 -- tests/glfw/particles.c | 1166 --------------------------------- tests/glfw/pong3d.c | 862 ------------------------ tests/glfw/pong3d_field.tga | Bin 17816 -> 0 bytes tests/glfw/pong3d_instr.tga | Bin 21279 -> 0 bytes tests/glfw/pong3d_menu.tga | Bin 1835 -> 0 bytes tests/glfw/pong3d_title.tga | Bin 106516 -> 0 bytes tests/glfw/pong3d_winner1.tga | Bin 861 -> 0 bytes tests/glfw/pong3d_winner2.tga | Bin 891 -> 0 bytes tests/glfw/splitview.c | 525 --------------- tests/glfw/triangle.c | 108 --- tests/glfw/wave.c | 399 ----------- 24 files changed, 6281 deletions(-) delete mode 100644 tests/glfw/Makefile delete mode 100644 tests/glfw/boing.c delete mode 100644 tests/glfw/bundle.sh delete mode 100644 tests/glfw/gears.c delete mode 100644 tests/glfw/getopt.c delete mode 100644 tests/glfw/getopt.h delete mode 100644 tests/glfw/glfwsample.c delete mode 100644 tests/glfw/heightmap.c delete mode 100644 tests/glfw/listmodes.c delete mode 100644 tests/glfw/mipmaps.c delete mode 100644 tests/glfw/mipmaps.tga delete mode 100644 tests/glfw/mtbench.c delete mode 100644 tests/glfw/mthello.c delete mode 100644 tests/glfw/particles.c delete mode 100644 tests/glfw/pong3d.c delete mode 100644 tests/glfw/pong3d_field.tga delete mode 100644 tests/glfw/pong3d_instr.tga delete mode 100644 tests/glfw/pong3d_menu.tga delete mode 100644 tests/glfw/pong3d_title.tga delete mode 100644 tests/glfw/pong3d_winner1.tga delete mode 100644 tests/glfw/pong3d_winner2.tga delete mode 100644 tests/glfw/splitview.c delete mode 100644 tests/glfw/triangle.c delete mode 100644 tests/glfw/wave.c diff --git a/tests/glfw/Makefile b/tests/glfw/Makefile deleted file mode 100644 index 9bf06d802bc42..0000000000000 --- a/tests/glfw/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -########################################################################## -# Makefile for GLFW example programs on X11 (generated by compile.sh) -########################################################################## -CC = emcc -CFLAGS = -I../include -DEMSCRIPTEN - -LIB = -lglfw -SOLIB = -LFLAGS = $(LIB) -SO_LFLAGS = $(SOLIB) -EXT = html - -BINARIES = triangle listmodes mthello pong3d mtbench particles splitview \ - mipmaps gears boing heightmap glfwsample -## wave - -all: $(BINARIES) - -triangle: triangle.c - $(CC) $(CFLAGS) triangle.c $(LFLAGS) -o $@.$(EXT) - -listmodes: listmodes.c - $(CC) $(CFLAGS) listmodes.c $(LFLAGS) -o $@.$(EXT) - -mthello: mthello.c - $(CC) $(CFLAGS) mthello.c $(LFLAGS) -o $@.$(EXT) - -pong3d: pong3d.c - $(CC) $(CFLAGS) pong3d.c $(LFLAGS) -o $@.$(EXT) - -mtbench: mtbench.c - $(CC) $(CFLAGS) mtbench.c $(LFLAGS) -o $@.$(EXT) - -particles: particles.c - $(CC) $(CFLAGS) particles.c $(LFLAGS) -o $@.$(EXT) - -splitview: splitview.c - $(CC) $(CFLAGS) splitview.c $(LFLAGS) -o $@.$(EXT) - -mipmaps: mipmaps.c - $(CC) $(CFLAGS) mipmaps.c $(LFLAGS) -o $@.$(EXT) - -gears: gears.c - $(CC) $(CFLAGS) gears.c $(LFLAGS) -o $@.$(EXT) - -boing: boing.c - $(CC) $(CFLAGS) boing.c $(LFLAGS) -o $@.$(EXT) - -wave: wave.c - $(CC) $(CFLAGS) wave.c $(LFLAGS) -o $@.$(EXT) - -heightmap: heightmap.c - $(CC) $(CFLAGS) heightmap.c $(LFLAGS) -o $@.$(EXT) - -glfwsample: glfwsample.c - $(CC) $(CFLAGS) glfwsample.c $(LFLAGS) -o $@.$(EXT) - -clean: - rm -f $(BINARIES) - diff --git a/tests/glfw/boing.c b/tests/glfw/boing.c deleted file mode 100644 index 36c45b19ad94e..0000000000000 --- a/tests/glfw/boing.c +++ /dev/null @@ -1,625 +0,0 @@ -/***************************************************************************** - * Title: GLBoing - * Desc: Tribute to Amiga Boing. - * Author: Jim Brooks - * Original Amiga authors were R.J. Mical and Dale Luck. - * GLFW conversion by Marcus Geelnard - * Notes: - 360' = 2*PI [radian] - * - * - Distances between objects are created by doing a relative - * Z translations. - * - * - Although OpenGL enticingly supports alpha-blending, - * the shadow of the original Boing didn't affect the color - * of the grid. - * - * - [Marcus] Changed timing scheme from interval driven to frame- - * time based animation steps (which results in much smoother - * movement) - * - * History of Amiga Boing: - * - * Boing was demonstrated on the prototype Amiga (codenamed "Lorraine") in - * 1985. According to legend, it was written ad-hoc in one night by - * R. J. Mical and Dale Luck. Because the bouncing ball animation was so fast - * and smooth, attendees did not believe the Amiga prototype was really doing - * the rendering. Suspecting a trick, they began looking around the booth for - * a hidden computer or VCR. - *****************************************************************************/ - -#include -#include -#include -#include - -#ifdef EMSCRIPTEN -#include -#endif - - -/***************************************************************************** - * Various declarations and macros - *****************************************************************************/ - -/* Prototypes */ -void init( void ); -void display( void ); -void GLFWCALL reshape( int w, int h ); -void DrawBoingBall( void ); -void BounceBall( double dt ); -void DrawBoingBallBand( GLfloat long_lo, GLfloat long_hi ); -void DrawGrid( void ); - -#define RADIUS 70.f -#define STEP_LONGITUDE 22.5f /* 22.5 makes 8 bands like original Boing */ -#define STEP_LATITUDE 22.5f - -#define DIST_BALL (RADIUS * 2.f + RADIUS * 0.1f) - -#define VIEW_SCENE_DIST (DIST_BALL * 3.f + 200.f)/* distance from viewer to middle of boing area */ -#define GRID_SIZE (RADIUS * 4.5f) /* length (width) of grid */ -#define BOUNCE_HEIGHT (RADIUS * 2.1f) -#define BOUNCE_WIDTH (RADIUS * 2.1f) - -#define SHADOW_OFFSET_X -20.f -#define SHADOW_OFFSET_Y 10.f -#define SHADOW_OFFSET_Z 0.f - -#define WALL_L_OFFSET 0.f -#define WALL_R_OFFSET 5.f - -/* Animation speed (50.0 mimics the original GLUT demo speed) */ -#define ANIMATION_SPEED 50.f - -/* Maximum allowed delta time per physics iteration */ -#define MAX_DELTA_T 0.02f - -/* Draw ball, or its shadow */ -typedef enum { DRAW_BALL, DRAW_BALL_SHADOW } DRAW_BALL_ENUM; - -/* Vertex type */ -typedef struct {float x; float y; float z;} vertex_t; - -/* Global vars */ -GLfloat deg_rot_y = 0.f; -GLfloat deg_rot_y_inc = 2.f; -GLfloat ball_x = -RADIUS; -GLfloat ball_y = -RADIUS; -GLfloat ball_x_inc = 1.f; -GLfloat ball_y_inc = 2.f; -DRAW_BALL_ENUM drawBallHow; -double t; -double t_old = 0.f; -double dt; - -/* Random number generator */ -#ifndef RAND_MAX - #define RAND_MAX 4095 -#endif - -/* PI */ -#ifndef M_PI - #define M_PI 3.1415926535897932384626433832795 -#endif - - -/***************************************************************************** - * Truncate a degree. - *****************************************************************************/ -GLfloat TruncateDeg( GLfloat deg ) -{ - if ( deg >= 360.f ) - return (deg - 360.f); - else - return deg; -} - -/***************************************************************************** - * Convert a degree (360-based) into a radian. - * 360' = 2 * PI - *****************************************************************************/ -double deg2rad( double deg ) -{ - return deg / 360 * (2 * M_PI); -} - -/***************************************************************************** - * 360' sin(). - *****************************************************************************/ -double sin_deg( double deg ) -{ - return sin( deg2rad( deg ) ); -} - -/***************************************************************************** - * 360' cos(). - *****************************************************************************/ -double cos_deg( double deg ) -{ - return cos( deg2rad( deg ) ); -} - -/***************************************************************************** - * Compute a cross product (for a normal vector). - * - * c = a x b - *****************************************************************************/ -void CrossProduct( vertex_t a, vertex_t b, vertex_t c, vertex_t *n ) -{ - GLfloat u1, u2, u3; - GLfloat v1, v2, v3; - - u1 = b.x - a.x; - u2 = b.y - a.y; - u3 = b.y - a.z; - - v1 = c.x - a.x; - v2 = c.y - a.y; - v3 = c.z - a.z; - - n->x = u2 * v3 - v2 * v3; - n->y = u3 * v1 - v3 * u1; - n->z = u1 * v2 - v1 * u2; -} - -/***************************************************************************** - * Calculate the angle to be passed to gluPerspective() so that a scene - * is visible. This function originates from the OpenGL Red Book. - * - * Parms : size - * The size of the segment when the angle is intersected at "dist" - * (ie at the outermost edge of the angle of vision). - * - * dist - * Distance from viewpoint to scene. - *****************************************************************************/ -GLfloat PerspectiveAngle( GLfloat size, - GLfloat dist ) -{ - GLfloat radTheta, degTheta; - - radTheta = 2.f * (GLfloat) atan2( size / 2.f, dist ); - degTheta = (180.f * radTheta) / (GLfloat) M_PI; - return degTheta; -} - - - -#define BOING_DEBUG 0 - - -/***************************************************************************** - * init() - *****************************************************************************/ -void init( void ) -{ - /* - * Clear background. - */ - glClearColor( 0.55f, 0.55f, 0.55f, 0.f ); - - glShadeModel( GL_FLAT ); -} - - -/***************************************************************************** - * display() - *****************************************************************************/ -void display(void) -{ - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - glPushMatrix(); - - drawBallHow = DRAW_BALL_SHADOW; - DrawBoingBall(); - - DrawGrid(); - - drawBallHow = DRAW_BALL; - DrawBoingBall(); - - glPopMatrix(); - glFlush(); -} - - -/***************************************************************************** - * reshape() - *****************************************************************************/ -void GLFWCALL reshape( int w, int h ) -{ - glViewport( 0, 0, (GLsizei)w, (GLsizei)h ); - - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - - gluPerspective( PerspectiveAngle( RADIUS * 2, 200 ), - (GLfloat)w / (GLfloat)h, - 1.0, - VIEW_SCENE_DIST ); - - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - - gluLookAt( 0.0, 0.0, VIEW_SCENE_DIST,/* eye */ - 0.0, 0.0, 0.0, /* center of vision */ - 0.0, -1.0, 0.0 ); /* up vector */ -} - - -/***************************************************************************** - * Draw the Boing ball. - * - * The Boing ball is sphere in which each facet is a rectangle. - * Facet colors alternate between red and white. - * The ball is built by stacking latitudinal circles. Each circle is composed - * of a widely-separated set of points, so that each facet is noticably large. - *****************************************************************************/ -void DrawBoingBall( void ) -{ - GLfloat lon_deg; /* degree of longitude */ - double dt_total, dt2; - - glPushMatrix(); - glMatrixMode( GL_MODELVIEW ); - - /* - * Another relative Z translation to separate objects. - */ - glTranslatef( 0.0, 0.0, DIST_BALL ); - - /* Update ball position and rotation (iterate if necessary) */ - dt_total = dt; - while( dt_total > 0.0 ) - { - dt2 = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total; - dt_total -= dt2; - BounceBall( dt2 ); - deg_rot_y = TruncateDeg( deg_rot_y + deg_rot_y_inc*((float)dt2*ANIMATION_SPEED) ); - } - - /* Set ball position */ - glTranslatef( ball_x, ball_y, 0.0 ); - - /* - * Offset the shadow. - */ - if ( drawBallHow == DRAW_BALL_SHADOW ) - { - glTranslatef( SHADOW_OFFSET_X, - SHADOW_OFFSET_Y, - SHADOW_OFFSET_Z ); - } - - /* - * Tilt the ball. - */ - glRotatef( -20.0, 0.0, 0.0, 1.0 ); - - /* - * Continually rotate ball around Y axis. - */ - glRotatef( deg_rot_y, 0.0, 1.0, 0.0 ); - - /* - * Set OpenGL state for Boing ball. - */ - glCullFace( GL_FRONT ); - glEnable( GL_CULL_FACE ); - glEnable( GL_NORMALIZE ); - - /* - * Build a faceted latitude slice of the Boing ball, - * stepping same-sized vertical bands of the sphere. - */ - for ( lon_deg = 0; - lon_deg < 180; - lon_deg += STEP_LONGITUDE ) - { - /* - * Draw a latitude circle at this longitude. - */ - DrawBoingBallBand( lon_deg, - lon_deg + STEP_LONGITUDE ); - } - - glPopMatrix(); - - return; -} - - -/***************************************************************************** - * Bounce the ball. - *****************************************************************************/ -void BounceBall( double dt ) -{ - GLfloat sign; - GLfloat deg; - - /* Bounce on walls */ - if ( ball_x > (BOUNCE_WIDTH/2 + WALL_R_OFFSET ) ) - { - ball_x_inc = -0.5f - 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX; - deg_rot_y_inc = -deg_rot_y_inc; - } - if ( ball_x < -(BOUNCE_HEIGHT/2 + WALL_L_OFFSET) ) - { - ball_x_inc = 0.5f + 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX; - deg_rot_y_inc = -deg_rot_y_inc; - } - - /* Bounce on floor / roof */ - if ( ball_y > BOUNCE_HEIGHT/2 ) - { - ball_y_inc = -0.75f - 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX; - } - if ( ball_y < -BOUNCE_HEIGHT/2*0.85 ) - { - ball_y_inc = 0.75f + 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX; - } - - /* Update ball position */ - ball_x += ball_x_inc * ((float)dt*ANIMATION_SPEED); - ball_y += ball_y_inc * ((float)dt*ANIMATION_SPEED); - - /* - * Simulate the effects of gravity on Y movement. - */ - if ( ball_y_inc < 0 ) sign = -1.0; else sign = 1.0; - - deg = (ball_y + BOUNCE_HEIGHT/2) * 90 / BOUNCE_HEIGHT; - if ( deg > 80 ) deg = 80; - if ( deg < 10 ) deg = 10; - - ball_y_inc = sign * 4.f * (float) sin_deg( deg ); -} - - -/***************************************************************************** - * Draw a faceted latitude band of the Boing ball. - * - * Parms: long_lo, long_hi - * Low and high longitudes of slice, resp. - *****************************************************************************/ -void DrawBoingBallBand( GLfloat long_lo, - GLfloat long_hi ) -{ - vertex_t vert_ne; /* "ne" means south-east, so on */ - vertex_t vert_nw; - vertex_t vert_sw; - vertex_t vert_se; - vertex_t vert_norm; - GLfloat lat_deg; - static int colorToggle = 0; - - /* - * Iterate thru the points of a latitude circle. - * A latitude circle is a 2D set of X,Z points. - */ - for ( lat_deg = 0; - lat_deg <= (360 - STEP_LATITUDE); - lat_deg += STEP_LATITUDE ) - { - /* - * Color this polygon with red or white. - */ - if ( colorToggle ) - glColor3f( 0.8f, 0.1f, 0.1f ); - else - glColor3f( 0.95f, 0.95f, 0.95f ); -#if 0 - if ( lat_deg >= 180 ) - if ( colorToggle ) - glColor3f( 0.1f, 0.8f, 0.1f ); - else - glColor3f( 0.5f, 0.5f, 0.95f ); -#endif - colorToggle = ! colorToggle; - - /* - * Change color if drawing shadow. - */ - if ( drawBallHow == DRAW_BALL_SHADOW ) - glColor3f( 0.35f, 0.35f, 0.35f ); - - /* - * Assign each Y. - */ - vert_ne.y = vert_nw.y = (float) cos_deg(long_hi) * RADIUS; - vert_sw.y = vert_se.y = (float) cos_deg(long_lo) * RADIUS; - - /* - * Assign each X,Z with sin,cos values scaled by latitude radius indexed by longitude. - * Eg, long=0 and long=180 are at the poles, so zero scale is sin(longitude), - * while long=90 (sin(90)=1) is at equator. - */ - vert_ne.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); - vert_se.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); - vert_nw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); - vert_sw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); - - vert_ne.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); - vert_se.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); - vert_nw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); - vert_sw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); - - /* - * Draw the facet. - */ - glBegin( GL_POLYGON ); - - CrossProduct( vert_ne, vert_nw, vert_sw, &vert_norm ); - glNormal3f( vert_norm.x, vert_norm.y, vert_norm.z ); - - glVertex3f( vert_ne.x, vert_ne.y, vert_ne.z ); - glVertex3f( vert_nw.x, vert_nw.y, vert_nw.z ); - glVertex3f( vert_sw.x, vert_sw.y, vert_sw.z ); - glVertex3f( vert_se.x, vert_se.y, vert_se.z ); - - glEnd(); - -#if BOING_DEBUG - printf( "----------------------------------------------------------- \n" ); - printf( "lat = %f long_lo = %f long_hi = %f \n", lat_deg, long_lo, long_hi ); - printf( "vert_ne x = %.8f y = %.8f z = %.8f \n", vert_ne.x, vert_ne.y, vert_ne.z ); - printf( "vert_nw x = %.8f y = %.8f z = %.8f \n", vert_nw.x, vert_nw.y, vert_nw.z ); - printf( "vert_se x = %.8f y = %.8f z = %.8f \n", vert_se.x, vert_se.y, vert_se.z ); - printf( "vert_sw x = %.8f y = %.8f z = %.8f \n", vert_sw.x, vert_sw.y, vert_sw.z ); -#endif - - } - - /* - * Toggle color so that next band will opposite red/white colors than this one. - */ - colorToggle = ! colorToggle; - - /* - * This circular band is done. - */ - return; -} - - -/***************************************************************************** - * Draw the purple grid of lines, behind the Boing ball. - * When the Workbench is dropped to the bottom, Boing shows 12 rows. - *****************************************************************************/ -void DrawGrid( void ) -{ - int row, col; - const int rowTotal = 12; /* must be divisible by 2 */ - const int colTotal = rowTotal; /* must be same as rowTotal */ - const GLfloat widthLine = 2.0; /* should be divisible by 2 */ - const GLfloat sizeCell = GRID_SIZE / rowTotal; - const GLfloat z_offset = -40.0; - GLfloat xl, xr; - GLfloat yt, yb; - - glPushMatrix(); - glDisable( GL_CULL_FACE ); - - /* - * Another relative Z translation to separate objects. - */ - glTranslatef( 0.0, 0.0, DIST_BALL ); - - /* - * Draw vertical lines (as skinny 3D rectangles). - */ - for ( col = 0; col <= colTotal; col++ ) - { - /* - * Compute co-ords of line. - */ - xl = -GRID_SIZE / 2 + col * sizeCell; - xr = xl + widthLine; - - yt = GRID_SIZE / 2; - yb = -GRID_SIZE / 2 - widthLine; - - glBegin( GL_POLYGON ); - - glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */ - - glVertex3f( xr, yt, z_offset ); /* NE */ - glVertex3f( xl, yt, z_offset ); /* NW */ - glVertex3f( xl, yb, z_offset ); /* SW */ - glVertex3f( xr, yb, z_offset ); /* SE */ - - glEnd(); - } - - /* - * Draw horizontal lines (as skinny 3D rectangles). - */ - for ( row = 0; row <= rowTotal; row++ ) - { - /* - * Compute co-ords of line. - */ - yt = GRID_SIZE / 2 - row * sizeCell; - yb = yt - widthLine; - - xl = -GRID_SIZE / 2; - xr = GRID_SIZE / 2 + widthLine; - - glBegin( GL_POLYGON ); - - glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */ - - glVertex3f( xr, yt, z_offset ); /* NE */ - glVertex3f( xl, yt, z_offset ); /* NW */ - glVertex3f( xl, yb, z_offset ); /* SW */ - glVertex3f( xr, yb, z_offset ); /* SE */ - - glEnd(); - } - - glPopMatrix(); - - return; -} - - -/*======================================================================* - * main() - *======================================================================*/ - -void iteration(){ - /* Timing */ - t = glfwGetTime(); - dt = t - t_old; - t_old = t; - - /* Draw one frame */ - display(); - - /* Swap buffers */ - glfwSwapBuffers(); -} - -int main( void ) -{ - int running; - - /* Init GLFW */ - if( !glfwInit() ) - { - fprintf( stderr, "Failed to initialize GLFW\n" ); - exit( EXIT_FAILURE ); - } - - if( !glfwOpenWindow( 400,400, 0,0,0,0, 16,0, GLFW_WINDOW ) ) - { - fprintf( stderr, "Failed to open GLFW window\n" ); - glfwTerminate(); - exit( EXIT_FAILURE ); - } - - glfwSetWindowTitle( "Boing (classic Amiga demo)" ); - glfwSetWindowSizeCallback( reshape ); - glfwEnable( GLFW_STICKY_KEYS ); - glfwSwapInterval( 1 ); - glfwSetTime( 0.0 ); - - init(); - - /* Main loop */ -#ifdef EMSCRIPTEN - emscripten_set_main_loop (iteration, 0, 1); -#else - do - { - iteration(); - /* Check if we are still running */ - running = !glfwGetKey( GLFW_KEY_ESC ) && - glfwGetWindowParam( GLFW_OPENED ); - } - while( running ); -#endif - glfwTerminate(); - exit( EXIT_SUCCESS ); -} - diff --git a/tests/glfw/bundle.sh b/tests/glfw/bundle.sh deleted file mode 100644 index ee4d18ddda08d..0000000000000 --- a/tests/glfw/bundle.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh - -# Creates application bundles for use on Mac OS X. - -if [ -z "$1" ]; then - echo "usage: `basename $0` BUNDLE-NAME" - exit 1 -fi - -bundle_name="$1" - -if [ ! -d "${bundle_name}.app/Contents/MacOS" ]; then - mkdir -p "${bundle_name}.app/Contents/MacOS" -fi - -if [ ! -d "${bundle_name}.app/Contents/Resources" ]; then - mkdir -p "${bundle_name}.app/Contents/Resources" -fi - -if [ ! -f "${bundle_name}.app/Contents/PkgInfo" ]; then - echo -n "APPL????" > "${bundle_name}.app/Contents/PkgInfo" -fi - -if [ ! -f "${bundle_name}.app/Contents/Info.plist" ]; then - cat > "${bundle_name}.app/Contents/Info.plist" < - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${bundle_name} - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleSignature - ???? - CFBundleVersion - 0.1 - - -EOF -fi - diff --git a/tests/glfw/gears.c b/tests/glfw/gears.c deleted file mode 100644 index 012884145c123..0000000000000 --- a/tests/glfw/gears.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - * 3-D gear wheels. This program is in the public domain. - * - * Command line options: - * -info print GL implementation information - * -exit automatically exit after 30 seconds - * - * - * Brian Paul - * - * - * Marcus Geelnard: - * - Conversion to GLFW - * - Time based rendering (frame rate independent) - * - Slightly modified camera that should work better for stereo viewing - * - * - * Camilla Berglund: - * - Removed FPS counter (this is not a benchmark) - * - Added a few comments - * - Enabled vsync - */ - - -#include -#include -#include -#include -#include - -#ifndef M_PI -#define M_PI 3.141592654 -#endif - -#ifdef EMSCRIPTEN -#include -#endif - -/* The program exits when this is zero. - */ -static int running = 1; - -/* If non-zero, the program exits after that many seconds - */ -static int autoexit = 0; - -/** - - Draw a gear wheel. You'll probably want to call this function when - building a display list since we do a lot of trig here. - - Input: inner_radius - radius of hole at center - outer_radius - radius at center of teeth - width - width of gear teeth - number of teeth - tooth_depth - depth of tooth - - **/ - -static void -gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, - GLint teeth, GLfloat tooth_depth) -{ - GLint i; - GLfloat r0, r1, r2; - GLfloat angle, da; - GLfloat u, v, len; - - r0 = inner_radius; - r1 = outer_radius - tooth_depth / 2.f; - r2 = outer_radius + tooth_depth / 2.f; - - da = 2.f * (float) M_PI / teeth / 4.f; - - glShadeModel(GL_FLAT); - - glNormal3f(0.f, 0.f, 1.f); - - /* draw front face */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.f * (float) M_PI / teeth; - glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); - glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); - if (i < teeth) { - glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); - glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); - } - } - glEnd(); - - /* draw front sides of teeth */ - glBegin(GL_QUADS); - da = 2.f * (float) M_PI / teeth / 4.f; - for (i = 0; i < teeth; i++) { - angle = i * 2.f * (float) M_PI / teeth; - - glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); - glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), width * 0.5f); - glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), width * 0.5f); - glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); - } - glEnd(); - - glNormal3f(0.0, 0.0, -1.0); - - /* draw back face */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.f * (float) M_PI / teeth; - glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); - glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); - if (i < teeth) { - glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); - glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); - } - } - glEnd(); - - /* draw back sides of teeth */ - glBegin(GL_QUADS); - da = 2.f * (float) M_PI / teeth / 4.f; - for (i = 0; i < teeth; i++) { - angle = i * 2.f * (float) M_PI / teeth; - - glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); - glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), -width * 0.5f); - glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), -width * 0.5f); - glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); - } - glEnd(); - - /* draw outward faces of teeth */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i < teeth; i++) { - angle = i * 2.f * (float) M_PI / teeth; - - glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); - glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); - u = r2 * (float) cos(angle + da) - r1 * (float) cos(angle); - v = r2 * (float) sin(angle + da) - r1 * (float) sin(angle); - len = (float) sqrt(u * u + v * v); - u /= len; - v /= len; - glNormal3f(v, -u, 0.0); - glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), width * 0.5f); - glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), -width * 0.5f); - glNormal3f((float) cos(angle), (float) sin(angle), 0.f); - glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), width * 0.5f); - glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), -width * 0.5f); - u = r1 * (float) cos(angle + 3 * da) - r2 * (float) cos(angle + 2 * da); - v = r1 * (float) sin(angle + 3 * da) - r2 * (float) sin(angle + 2 * da); - glNormal3f(v, -u, 0.f); - glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); - glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); - glNormal3f((float) cos(angle), (float) sin(angle), 0.f); - } - - glVertex3f(r1 * (float) cos(0), r1 * (float) sin(0), width * 0.5f); - glVertex3f(r1 * (float) cos(0), r1 * (float) sin(0), -width * 0.5f); - - glEnd(); - - glShadeModel(GL_SMOOTH); - - /* draw inside radius cylinder */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.f * (float) M_PI / teeth; - glNormal3f(-(float) cos(angle), -(float) sin(angle), 0.f); - glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); - glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); - } - glEnd(); - -} - - -static GLfloat view_rotx = 20.f, view_roty = 30.f, view_rotz = 0.f; -static GLint gear1, gear2, gear3; -static GLfloat angle = 0.f; - -/* OpenGL draw function & timing */ -static void draw(void) -{ - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glPushMatrix(); - glRotatef(view_rotx, 1.0, 0.0, 0.0); - glRotatef(view_roty, 0.0, 1.0, 0.0); - glRotatef(view_rotz, 0.0, 0.0, 1.0); - - glPushMatrix(); - glTranslatef(-3.0, -2.0, 0.0); - glRotatef(angle, 0.0, 0.0, 1.0); - glCallList(gear1); - glPopMatrix(); - - glPushMatrix(); - glTranslatef(3.1f, -2.f, 0.f); - glRotatef(-2.f * angle - 9.f, 0.f, 0.f, 1.f); - glCallList(gear2); - glPopMatrix(); - - glPushMatrix(); - glTranslatef(-3.1f, 4.2f, 0.f); - glRotatef(-2.f * angle - 25.f, 0.f, 0.f, 1.f); - glCallList(gear3); - glPopMatrix(); - - glPopMatrix(); -} - - -/* update animation parameters */ -static void animate(void) -{ - angle = 100.f * (float) glfwGetTime(); -} - - -/* change view angle, exit upon ESC */ -void GLFWCALL key( int k, int action ) -{ - if( action != GLFW_PRESS ) return; - - switch (k) { - case 'Z': - if( glfwGetKey( GLFW_KEY_LSHIFT ) ) - view_rotz -= 5.0; - else - view_rotz += 5.0; - break; - case GLFW_KEY_ESC: - running = 0; - break; - case GLFW_KEY_UP: - view_rotx += 5.0; - break; - case GLFW_KEY_DOWN: - view_rotx -= 5.0; - break; - case GLFW_KEY_LEFT: - view_roty += 5.0; - break; - case GLFW_KEY_RIGHT: - view_roty -= 5.0; - break; - default: - return; - } -} - - -/* new window size */ -void GLFWCALL reshape( int width, int height ) -{ - GLfloat h = (GLfloat) height / (GLfloat) width; - GLfloat xmax, znear, zfar; - - znear = 5.0f; - zfar = 30.0f; - xmax = znear * 0.5f; - - glViewport( 0, 0, (GLint) width, (GLint) height ); - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - glFrustum( -xmax, xmax, -xmax*h, xmax*h, znear, zfar ); - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - glTranslatef( 0.0, 0.0, -20.0 ); -} - - -/* program & OpenGL initialization */ -static void init(int argc, char *argv[]) -{ - static GLfloat pos[4] = {5.f, 5.f, 10.f, 0.f}; - static GLfloat red[4] = {0.8f, 0.1f, 0.f, 1.f}; - static GLfloat green[4] = {0.f, 0.8f, 0.2f, 1.f}; - static GLfloat blue[4] = {0.2f, 0.2f, 1.f, 1.f}; - GLint i; - - glLightfv(GL_LIGHT0, GL_POSITION, pos); - glEnable(GL_CULL_FACE); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_DEPTH_TEST); - - /* make the gears */ - gear1 = glGenLists(1); - glNewList(gear1, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); - gear(1.f, 4.f, 1.f, 20, 0.7f); - glEndList(); - - gear2 = glGenLists(1); - glNewList(gear2, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); - gear(0.5f, 2.f, 2.f, 10, 0.7f); - glEndList(); - - gear3 = glGenLists(1); - glNewList(gear3, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); - gear(1.3f, 2.f, 0.5f, 10, 0.7f); - glEndList(); - - glEnable(GL_NORMALIZE); - - for ( i=1; i -#include -#include -#include "getopt.h" - - -/* 2009-10-12 Camilla Berglund - * - * Removed unused global static variable 'ID'. - */ - - -char* optarg = NULL; -int optind = 0; -int opterr = 1; -int optopt = '?'; - - -static char** prev_argv = NULL; /* Keep a copy of argv and argc to */ -static int prev_argc = 0; /* tell if getopt params change */ -static int argv_index = 0; /* Option we're checking */ -static int argv_index2 = 0; /* Option argument we're checking */ -static int opt_offset = 0; /* Index into compounded "-option" */ -static int dashdash = 0; /* True if "--" option reached */ -static int nonopt = 0; /* How many nonopts we've found */ - -static void increment_index() -{ - /* Move onto the next option */ - if(argv_index < argv_index2) - { - while(prev_argv[++argv_index] && prev_argv[argv_index][0] != '-' - && argv_index < argv_index2+1); - } - else argv_index++; - opt_offset = 1; -} - - -/* -* Permutes argv[] so that the argument currently being processed is moved -* to the end. -*/ -static int permute_argv_once() -{ - /* Movability check */ - if(argv_index + nonopt >= prev_argc) return 1; - /* Move the current option to the end, bring the others to front */ - else - { - char* tmp = prev_argv[argv_index]; - - /* Move the data */ - memmove(&prev_argv[argv_index], &prev_argv[argv_index+1], - sizeof(char**) * (prev_argc - argv_index - 1)); - prev_argv[prev_argc - 1] = tmp; - - nonopt++; - return 0; - } -} - - -int getopt(int argc, char** argv, char* optstr) -{ - int c = 0; - - /* If we have new argv, reinitialize */ - if(prev_argv != argv || prev_argc != argc) - { - /* Initialize variables */ - prev_argv = argv; - prev_argc = argc; - argv_index = 1; - argv_index2 = 1; - opt_offset = 1; - dashdash = 0; - nonopt = 0; - } - - /* Jump point in case we want to ignore the current argv_index */ - getopt_top: - - /* Misc. initializations */ - optarg = NULL; - - /* Dash-dash check */ - if(argv[argv_index] && !strcmp(argv[argv_index], "--")) - { - dashdash = 1; - increment_index(); - } - - /* If we're at the end of argv, that's it. */ - if(argv[argv_index] == NULL) - { - c = -1; - } - /* Are we looking at a string? Single dash is also a string */ - else if(dashdash || argv[argv_index][0] != '-' || !strcmp(argv[argv_index], "-")) - { - /* If we want a string... */ - if(optstr[0] == '-') - { - c = 1; - optarg = argv[argv_index]; - increment_index(); - } - /* If we really don't want it (we're in POSIX mode), we're done */ - else if(optstr[0] == '+' || getenv("POSIXLY_CORRECT")) - { - c = -1; - - /* Everything else is a non-opt argument */ - nonopt = argc - argv_index; - } - /* If we mildly don't want it, then move it back */ - else - { - if(!permute_argv_once()) goto getopt_top; - else c = -1; - } - } - /* Otherwise we're looking at an option */ - else - { - char* opt_ptr = NULL; - - /* Grab the option */ - c = argv[argv_index][opt_offset++]; - - /* Is the option in the optstr? */ - if(optstr[0] == '-') opt_ptr = strchr(optstr+1, c); - else opt_ptr = strchr(optstr, c); - /* Invalid argument */ - if(!opt_ptr) - { - if(opterr) - { - fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); - } - - optopt = c; - c = '?'; - - /* Move onto the next option */ - increment_index(); - } - /* Option takes argument */ - else if(opt_ptr[1] == ':') - { - /* ie, -oARGUMENT, -xxxoARGUMENT, etc. */ - if(argv[argv_index][opt_offset] != '\0') - { - optarg = &argv[argv_index][opt_offset]; - increment_index(); - } - /* ie, -o ARGUMENT (only if it's a required argument) */ - else if(opt_ptr[2] != ':') - { - /* One of those "you're not expected to understand this" moment */ - if(argv_index2 < argv_index) argv_index2 = argv_index; - while(argv[++argv_index2] && argv[argv_index2][0] == '-'); - optarg = argv[argv_index2]; - - /* Don't cross into the non-option argument list */ - if(argv_index2 + nonopt >= prev_argc) optarg = NULL; - - /* Move onto the next option */ - increment_index(); - } - else - { - /* Move onto the next option */ - increment_index(); - } - - /* In case we got no argument for an option with required argument */ - if(optarg == NULL && opt_ptr[2] != ':') - { - optopt = c; - c = '?'; - - if(opterr) - { - fprintf(stderr,"%s: option requires an argument -- %c\n", - argv[0], optopt); - } - } - } - /* Option does not take argument */ - else - { - /* Next argv_index */ - if(argv[argv_index][opt_offset] == '\0') - { - increment_index(); - } - } - } - - /* Calculate optind */ - if(c == -1) - { - optind = argc - nonopt; - } - else - { - optind = argv_index; - } - - return c; -} - - -/* vim:ts=3 -*/ diff --git a/tests/glfw/getopt.h b/tests/glfw/getopt.h deleted file mode 100644 index 0b78650ac7ac6..0000000000000 --- a/tests/glfw/getopt.h +++ /dev/null @@ -1,63 +0,0 @@ -/***************************************************************************** -* getopt.h - competent and free getopt library. -* $Header: /cvsroot/freegetopt/freegetopt/getopt.h,v 1.2 2003/10/26 03:10:20 vindaci Exp $ -* -* Copyright (c)2002-2003 Mark K. Kim -* 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 original author of this software 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 OWNER 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. -*/ -#ifndef GETOPT_H_ -#define GETOPT_H_ - - -#ifdef __cplusplus -extern "C" { -#endif - - -extern char* optarg; -extern int optind; -extern int opterr; -extern int optopt; - -int getopt(int argc, char** argv, char* optstr); - - -#ifdef __cplusplus -} -#endif - - -#endif /* GETOPT_H_ */ - - -/* vim:ts=3 -*/ diff --git a/tests/glfw/glfwsample.c b/tests/glfw/glfwsample.c deleted file mode 100644 index 79b504b61431e..0000000000000 --- a/tests/glfw/glfwsample.c +++ /dev/null @@ -1,392 +0,0 @@ -#include -#include -#include - -#ifdef EMSCRIPTEN -#include -#endif - -void Init(void); -void Shut_Down(int return_code); -int Iteration(void); -void Draw_Square(float red, float green, float blue); -void Draw(void); -void OnKeyPressed( int key, int action ); -void OnCharPressed( int character, int action ); -char* GetKeyName(int key); -char* GetParamName(int param); -int OnClose(); -void OnResize( int width, int height ); -void OnRefresh(); -void OnMouseClick( int button, int action ); -void OnMouseMove( int x, int y ); -void OnMouseWheel( int pos ); -void PullInfo(); -void Iteration_void(); - -int params[] = {GLFW_OPENED, GLFW_ACTIVE, GLFW_ICONIFIED, GLFW_ACCELERATED, GLFW_RED_BITS, GLFW_GREEN_BITS, GLFW_BLUE_BITS, GLFW_ALPHA_BITS, GLFW_DEPTH_BITS, GLFW_STENCIL_BITS, GLFW_REFRESH_RATE, GLFW_ACCUM_RED_BITS, GLFW_ACCUM_GREEN_BITS, GLFW_ACCUM_BLUE_BITS, GLFW_ACCUM_ALPHA_BITS, GLFW_AUX_BUFFERS, GLFW_STEREO, GLFW_WINDOW_NO_RESIZE, GLFW_FSAA_SAMPLES, GLFW_OPENGL_VERSION_MAJOR, GLFW_OPENGL_VERSION_MINOR, GLFW_OPENGL_FORWARD_COMPAT, GLFW_OPENGL_DEBUG_CONTEXT, GLFW_OPENGL_PROFILE}; -unsigned int nb_params = sizeof(params) / sizeof(int); - -int features[] = {GLFW_MOUSE_CURSOR, GLFW_STICKY_KEYS, GLFW_STICKY_MOUSE_BUTTONS, GLFW_SYSTEM_KEYS, GLFW_KEY_REPEAT, GLFW_AUTO_POLL_EVENTS}; -unsigned int nb_features = sizeof(features) / sizeof(int); - -float rotate_y = 0, - rotate_z = 0; -const float rotations_per_tick = .2; -// the time of the previous frame -double old_time; - -int main(void) -{ - Init(); - old_time = glfwGetTime(); -#ifdef EMSCRIPTEN - emscripten_set_main_loop (Iteration_void, 0, 1); -#else - while(Iteration()); -#endif - Shut_Down(0); -} - -void Init() -{ - const int window_width = 800, - window_height = 600; - - if (glfwInit() != GL_TRUE) - Shut_Down(1); - // 800 x 600, 16 bit color, no depth, alpha or stencil buffers, windowed - if (glfwOpenWindow(window_width, window_height, 5, 6, 5, - 0, 0, 0, GLFW_WINDOW) != GL_TRUE) - Shut_Down(1); - glfwSetWindowTitle("The GLFW Window"); - - glfwSetKeyCallback( OnKeyPressed ); - glfwSetCharCallback( OnCharPressed ); - glfwSetWindowCloseCallback(OnClose); - glfwSetWindowSizeCallback(OnResize); - glfwSetWindowRefreshCallback(OnRefresh); - glfwSetMouseWheelCallback(OnMouseWheel); - glfwSetMousePosCallback(OnMouseMove); - glfwSetMouseButtonCallback(OnMouseClick); - - // set the projection matrix to a normal frustum with a max depth of 50 - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - float aspect_ratio = ((float)window_height) / window_width; - glFrustum(.5, -.5, -.5 * aspect_ratio, .5 * aspect_ratio, 1, 50); - glMatrixMode(GL_MODELVIEW); - - PullInfo(); -} - -void Shut_Down(int return_code) -{ - glfwTerminate(); - exit(return_code); -} - -int Iteration() -{ - // calculate time elapsed, and the amount by which stuff rotates - double current_time = glfwGetTime(), - delta_rotate = (current_time - old_time) * rotations_per_tick * 360; - old_time = current_time; - // escape to quit, arrow keys to rotate view - if (glfwGetKey(GLFW_KEY_ESC) == GLFW_PRESS) return 0; - if (glfwGetKey(GLFW_KEY_LEFT) == GLFW_PRESS) - rotate_y += delta_rotate; - if (glfwGetKey(GLFW_KEY_RIGHT) == GLFW_PRESS) - rotate_y -= delta_rotate; - // z axis always rotates - rotate_z += delta_rotate; - - // clear the buffer - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // draw the figure - Draw(); - // swap back and front buffers - glfwSwapBuffers(); - return 1; -} - -void Iteration_void(){ - Iteration(); -} - -void Draw_Square(float red, float green, float blue) -{ -#ifndef EMSCRIPTEN - // Draws a square with a gradient color at coordinates 0, 10 - glBegin(GL_QUADS); - { - glColor3f(red, green, blue); - glVertex2i(1, 11); - glColor3f(red * .8, green * .8, blue * .8); - glVertex2i(-1, 11); - glColor3f(red * .5, green * .5, blue * .5); - glVertex2i(-1, 9); - glColor3f(red * .8, green * .8, blue * .8); - glVertex2i(1, 9); - } - glEnd(); -#endif -} - -void Draw(void) -{ - // reset view matrix - glLoadIdentity(); - // move view back a bit - glTranslatef(0, 0, -30); - // apply the current rotation - glRotatef(rotate_y, 0, 1, 0); - glRotatef(rotate_z, 0, 0, 1); - // by repeatedly rotating the view matrix during drawing, the - // squares end up in a circle - int i = 0, squares = 15; - float red = 0, blue = 1; - for (; i < squares; ++i){ - glRotatef(360.0/squares, 0, 0, 1); - // colors change for each square - red += 1.0/12; - blue -= 1.0/12; - Draw_Square(red, .6, blue); - } -} - -void OnCharPressed( int character, int action ){ - if(action == GLFW_PRESS) - printf("'%c' (%i) char is pressed\n", character, character); - if(action == GLFW_RELEASE) - printf("'%c' (%i) char is released\n", character, character); -} - -char* GetKeyName(int key){ - switch(key){ - case GLFW_KEY_UNKNOWN: return "unknown"; - case GLFW_KEY_SPACE: return "space"; - case GLFW_KEY_SPECIAL: return "special"; - case GLFW_KEY_ESC: return "escape"; - case GLFW_KEY_F1 : return "F1"; - case GLFW_KEY_F2 : return "F2"; - case GLFW_KEY_F3 : return "F3"; - case GLFW_KEY_F4 : return "F4"; - case GLFW_KEY_F5 : return "F5"; - case GLFW_KEY_F6 : return "F6"; - case GLFW_KEY_F7 : return "F7"; - case GLFW_KEY_F8 : return "F8"; - case GLFW_KEY_F9 : return "F9"; - case GLFW_KEY_F10: return "F10"; - case GLFW_KEY_F11: return "F11"; - case GLFW_KEY_F12: return "F12"; - case GLFW_KEY_F13: return "F13"; - case GLFW_KEY_F14: return "F14"; - case GLFW_KEY_F15: return "F15"; - case GLFW_KEY_F16: return "F16"; - case GLFW_KEY_F17: return "F17"; - case GLFW_KEY_F18: return "F18"; - case GLFW_KEY_F19: return "F19"; - case GLFW_KEY_F20: return "F20"; - case GLFW_KEY_F21: return "F21"; - case GLFW_KEY_F22: return "F22"; - case GLFW_KEY_F23: return "F23"; - case GLFW_KEY_F24: return "F24"; - case GLFW_KEY_F25: return "F25"; - case GLFW_KEY_UP : return "up"; - case GLFW_KEY_DOWN: return "down"; - case GLFW_KEY_LEFT: return "left"; - case GLFW_KEY_RIGHT: return "right"; - case GLFW_KEY_LSHIFT: return "left shift"; - case GLFW_KEY_RSHIFT: return "right shift"; - case GLFW_KEY_LCTRL: return "left ctrl"; - case GLFW_KEY_RCTRL: return "right ctrl"; - case GLFW_KEY_LALT: return "left alt"; - case GLFW_KEY_RALT: return "right alt"; - case GLFW_KEY_TAB: return "tab"; - case GLFW_KEY_ENTER: return "enter"; - case GLFW_KEY_BACKSPACE: return "backspace"; - case GLFW_KEY_INSERT: return "insertr"; - case GLFW_KEY_DEL: return "del"; - case GLFW_KEY_PAGEUP: return "page up"; - case GLFW_KEY_PAGEDOWN: return "page down"; - case GLFW_KEY_HOME: return "home"; - case GLFW_KEY_END: return "end"; - case GLFW_KEY_KP_0: return "0"; - case GLFW_KEY_KP_1: return "1"; - case GLFW_KEY_KP_2: return "2"; - case GLFW_KEY_KP_3: return "3"; - case GLFW_KEY_KP_4: return "4"; - case GLFW_KEY_KP_5: return "5"; - case GLFW_KEY_KP_6: return "6"; - case GLFW_KEY_KP_7: return "7"; - case GLFW_KEY_KP_8: return "8"; - case GLFW_KEY_KP_9: return "9"; - case GLFW_KEY_KP_DIVIDE: return "/"; - case GLFW_KEY_KP_MULTIPLY: return "*"; - case GLFW_KEY_KP_SUBTRACT: return "-"; - case GLFW_KEY_KP_ADD: return "+"; - case GLFW_KEY_KP_DECIMAL: return "."; - case GLFW_KEY_KP_EQUAL: return "="; - case GLFW_KEY_KP_ENTER: return "enter"; - case GLFW_KEY_KP_NUM_LOCK: return "num lock"; - case GLFW_KEY_CAPS_LOCK: return "caps lock"; - case GLFW_KEY_SCROLL_LOCK: return "scroll lock"; - case GLFW_KEY_PAUSE: return "pause"; - case GLFW_KEY_LSUPER: return "left super"; - case GLFW_KEY_RSUPER: return "right super"; - case GLFW_KEY_MENU: return "menu"; - } - char* chr = malloc(2*sizeof(char)); - chr[0] = key; - chr[1] = '\0'; - return chr; -} - -char* GetParamName(int param){ - switch(param){ - case GLFW_WINDOW : return "GLFW_WINDOW"; - case GLFW_FULLSCREEN : return "GLFW_FULLSCREEN"; - case GLFW_OPENED : return "GLFW_OPENED"; - case GLFW_ACTIVE : return "GLFW_ACTIVE"; - case GLFW_ICONIFIED : return "GLFW_ICONIFIED"; - case GLFW_ACCELERATED : return "GLFW_ACCELERATED"; - case GLFW_RED_BITS : return "GLFW_RED_BITS"; - case GLFW_GREEN_BITS : return "GLFW_GREEN_BITS"; - case GLFW_BLUE_BITS : return "GLFW_BLUE_BITS"; - case GLFW_ALPHA_BITS : return "GLFW_ALPHA_BITS"; - case GLFW_DEPTH_BITS : return "GLFW_DEPTH_BITS"; - case GLFW_STENCIL_BITS : return "GLFW_STENCIL_BITS"; - case GLFW_REFRESH_RATE : return "GLFW_REFRESH_RATE"; - case GLFW_ACCUM_RED_BITS : return "GLFW_ACCUM_RED_BITS"; - case GLFW_ACCUM_GREEN_BITS : return "GLFW_ACCUM_GREEN_BITS"; - case GLFW_ACCUM_BLUE_BITS : return "GLFW_BLUE_BITS"; - case GLFW_ACCUM_ALPHA_BITS : return "GLFW_ALPHA_BITS"; - case GLFW_AUX_BUFFERS : return "GLFW_AUX_BUFFERS"; - case GLFW_STEREO : return "GLFW_STEREO"; - case GLFW_WINDOW_NO_RESIZE : return "GLFW_WINDOW_NO_RESIZE"; - case GLFW_FSAA_SAMPLES : return "GLFW_FSAA_SAMPLES"; - case GLFW_OPENGL_VERSION_MAJOR : return "GLFW_OPENGL_VERSION_MAJOR"; - case GLFW_OPENGL_VERSION_MINOR : return "GLFW_OPENGL_VERSION_MINOR"; - case GLFW_OPENGL_FORWARD_COMPAT : return "GLFW_OPENGL_FORWARD_COMPAT"; - case GLFW_OPENGL_DEBUG_CONTEXT : return "GLFW_OPENGL_DEBUG_CONTEXT"; - case GLFW_OPENGL_PROFILE : return "GLFW_OPENGL_PROFILE"; - case GLFW_OPENGL_CORE_PROFILE : return "GLFW_OPENGL_CORE_PROFILE | GLFW_PRESENT"; - case GLFW_OPENGL_COMPAT_PROFILE : return "GLFW_OPENGL_COMPAT_PROFILE | GLFW_AXES"; - case GLFW_MOUSE_CURSOR : return "GLFW_MOUSE_CURSOR"; - case GLFW_STICKY_KEYS : return "GLFW_STICKY_KEYS"; - case GLFW_STICKY_MOUSE_BUTTONS : return "GLFW_STICKY_MOUSE_BUTTONS"; - case GLFW_SYSTEM_KEYS : return "GLFW_SYSTEM_KEYS"; - case GLFW_KEY_REPEAT : return "GLFW_KEY_REPEAT"; - case GLFW_AUTO_POLL_EVENTS : return "GLFW_AUTO_POLL_EVENTS"; - case GLFW_WAIT : return "GLFW_WAIT"; - case GLFW_NOWAIT : return "GLFW_NOWAIT"; - case GLFW_BUTTONS : return "GLFW_BUTTONS"; - case GLFW_NO_RESCALE_BIT : return "GLFW_NO_RESCALE_BIT"; - case GLFW_ORIGIN_UL_BIT : return "GLFW_ORIGIN_UL_BIT"; - case GLFW_BUILD_MIPMAPS_BIT : return "GLFW_BUILD_MIPMAPS_BIT"; - case GLFW_ALPHA_MAP_BIT : return "GLFW_ALPHA_MAP_BIT"; - default : return "Invalid param"; - } -} - -void OnKeyPressed( int key, int action ){ - const char* key_name = GetKeyName(key); - if(key_name == 0) - return; - if(action == GLFW_PRESS) - printf("'%s' (%i) key is pressed\n", key_name, key); - if(action == GLFW_RELEASE) - printf("'%s' (%i) key is released\n", key_name, key); - if(action == GLFW_RELEASE && key == GLFW_KEY_ENTER) - PullInfo(); -} - -int OnClose(){ - printf("Closed\n"); - return 0; -} - -void OnRefresh(){ - printf("Refresh\n"); -} - -void OnResize( int width, int height ){ - printf("Resizing to %i %i\n", width, height); -} - -void OnMouseClick( int button, int action ){ - if(action == GLFW_PRESS) - printf("Mouse button %i has been pressed\n", button); - if(action == GLFW_RELEASE) - printf("Mouse button %i has been released\n", button); -} - -void OnMouseMove( int x, int y ){ - int lState = glfwGetMouseButton(GLFW_MOUSE_BUTTON_LEFT); - - if (lState == GLFW_PRESS) - printf("Dragged %i to %i %i\n", GLFW_MOUSE_BUTTON_LEFT, x, y); - if(lState == GLFW_RELEASE) - printf("Moved %i to %i %i\n", GLFW_MOUSE_BUTTON_LEFT, x, y); -} - -void OnMouseWheel( int pos ){ - printf("Mouse wheel has been moved to %i\n", pos); -} - -void PullInfo(){ - printf("================================================================================\n"); - - int major, minor, rev; - glfwGetVersion(&major, &minor, &rev); - printf("GLFW version is %i.%i.%i\n", major, minor, rev); - - int width, height; - glfwGetWindowSize(&width, &height); - printf("Window size is %i %i\n", width, height); - - int status = glfwGetKey(GLFW_KEY_LCTRL); - if(status == GLFW_PRESS) - printf("Left control is pressed\n"); - else - printf("Left control is released\n"); - - status = glfwGetMouseButton(GLFW_MOUSE_BUTTON_1); - if(status == GLFW_PRESS) - printf("Mouse button 1 is pressed\n"); - else - printf("Mouse button 1 is released\n"); - - int x, y; - glfwGetMousePos(&x, &y); - printf("Mouse position is %i %i\n", x, y); - - int wheel = glfwGetMouseWheel(); - printf("Mouse wheel pos is %i\n", wheel); - - double time = glfwGetTime(); - printf("Time is %f\n", time); - - glfwGetGLVersion(&major, &minor, &rev); - printf("GL version is %i.%i.%i\n", major, minor, rev); - - int proc = glfwGetNumberOfProcessors(); - printf("%i processors are available\n", proc); - - unsigned int i; - for(i = 0; i -#include -#include -#include -#include -#include "getopt.h" - -#ifdef EMSCRIPTEN -#include -#endif - -#define GLFW_NO_GLU 1 -#include - -/* OpenGL 3.3 support - * Functions are effectively mapped in init_opengl() */ -#ifndef GL_VERSION_3_0 -/* no defines */ -#endif - -#ifndef GL_VERSION_2_0 - -typedef char GLchar; - -#define GL_BLEND_EQUATION_RGB 0x8009 -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 -#define GL_CURRENT_VERTEX_ATTRIB 0x8626 -#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 -#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 -#define GL_STENCIL_BACK_FUNC 0x8800 -#define GL_STENCIL_BACK_FAIL 0x8801 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 -#define GL_MAX_DRAW_BUFFERS 0x8824 -#define GL_DRAW_BUFFER0 0x8825 -#define GL_DRAW_BUFFER1 0x8826 -#define GL_DRAW_BUFFER2 0x8827 -#define GL_DRAW_BUFFER3 0x8828 -#define GL_DRAW_BUFFER4 0x8829 -#define GL_DRAW_BUFFER5 0x882A -#define GL_DRAW_BUFFER6 0x882B -#define GL_DRAW_BUFFER7 0x882C -#define GL_DRAW_BUFFER8 0x882D -#define GL_DRAW_BUFFER9 0x882E -#define GL_DRAW_BUFFER10 0x882F -#define GL_DRAW_BUFFER11 0x8830 -#define GL_DRAW_BUFFER12 0x8831 -#define GL_DRAW_BUFFER13 0x8832 -#define GL_DRAW_BUFFER14 0x8833 -#define GL_DRAW_BUFFER15 0x8834 -#define GL_BLEND_EQUATION_ALPHA 0x883D -#define GL_MAX_VERTEX_ATTRIBS 0x8869 -#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A -#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_VERTEX_SHADER 0x8B31 -#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A -#define GL_MAX_VARYING_FLOATS 0x8B4B -#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D -#define GL_SHADER_TYPE 0x8B4F -#define GL_FLOAT_VEC2 0x8B50 -#define GL_FLOAT_VEC3 0x8B51 -#define GL_FLOAT_VEC4 0x8B52 -#define GL_INT_VEC2 0x8B53 -#define GL_INT_VEC3 0x8B54 -#define GL_INT_VEC4 0x8B55 -#define GL_BOOL 0x8B56 -#define GL_BOOL_VEC2 0x8B57 -#define GL_BOOL_VEC3 0x8B58 -#define GL_BOOL_VEC4 0x8B59 -#define GL_FLOAT_MAT2 0x8B5A -#define GL_FLOAT_MAT3 0x8B5B -#define GL_FLOAT_MAT4 0x8B5C -#define GL_SAMPLER_1D 0x8B5D -#define GL_SAMPLER_2D 0x8B5E -#define GL_SAMPLER_3D 0x8B5F -#define GL_SAMPLER_CUBE 0x8B60 -#define GL_SAMPLER_1D_SHADOW 0x8B61 -#define GL_SAMPLER_2D_SHADOW 0x8B62 -#define GL_DELETE_STATUS 0x8B80 -#define GL_COMPILE_STATUS 0x8B81 -#define GL_LINK_STATUS 0x8B82 -#define GL_VALIDATE_STATUS 0x8B83 -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_ATTACHED_SHADERS 0x8B85 -#define GL_ACTIVE_UNIFORMS 0x8B86 -#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 -#define GL_SHADER_SOURCE_LENGTH 0x8B88 -#define GL_ACTIVE_ATTRIBUTES 0x8B89 -#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B -#define GL_SHADING_LANGUAGE_VERSION 0x8B8C -#define GL_CURRENT_PROGRAM 0x8B8D -#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 -#define GL_LOWER_LEFT 0x8CA1 -#define GL_UPPER_LEFT 0x8CA2 -#define GL_STENCIL_BACK_REF 0x8CA3 -#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 -#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 -#endif - - - -#ifndef GL_VERSION_1_5 - -typedef ptrdiff_t GLintptr; -typedef ptrdiff_t GLsizeiptr; - -#define GL_BUFFER_SIZE 0x8764 -#define GL_BUFFER_USAGE 0x8765 -#define GL_QUERY_COUNTER_BITS 0x8864 -#define GL_CURRENT_QUERY 0x8865 -#define GL_QUERY_RESULT 0x8866 -#define GL_QUERY_RESULT_AVAILABLE 0x8867 -#define GL_ARRAY_BUFFER 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define GL_ARRAY_BUFFER_BINDING 0x8894 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 -#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F -#define GL_READ_ONLY 0x88B8 -#define GL_WRITE_ONLY 0x88B9 -#define GL_READ_WRITE 0x88BA -#define GL_BUFFER_ACCESS 0x88BB -#define GL_BUFFER_MAPPED 0x88BC -#define GL_BUFFER_MAP_POINTER 0x88BD -#define GL_STREAM_DRAW 0x88E0 -#define GL_STREAM_READ 0x88E1 -#define GL_STREAM_COPY 0x88E2 -#define GL_STATIC_DRAW 0x88E4 -#define GL_STATIC_READ 0x88E5 -#define GL_STATIC_COPY 0x88E6 -#define GL_DYNAMIC_DRAW 0x88E8 -#define GL_DYNAMIC_READ 0x88E9 -#define GL_DYNAMIC_COPY 0x88EA -#define GL_SAMPLES_PASSED 0x8914 -#endif - - - - -/* OpenGL 3.0 */ -typedef void (APIENTRY * PFN_glGenVertexArrays)(GLsizei n, GLuint *arrays); -typedef void (APIENTRY * PFN_glBindVertexArray)(GLuint array); -typedef void (APIENTRY * PFN_glDeleteVertexArrays)(GLsizei n, GLuint *arrays); -/* OpenGL 2.0 */ -typedef GLuint (APIENTRY * PFN_glCreateShader)(GLenum type); -typedef void (APIENTRY * PFN_glDeleteShader)(GLuint shader); -typedef void (APIENTRY * PFN_glCompileShader)(GLuint shader); -typedef void (APIENTRY * PFN_glShaderSource)(GLuint shader, GLsizei count, const GLchar* *string, const GLint *length); -typedef void (APIENTRY * PFN_glGetShaderiv)(GLuint shader, GLenum pname, GLint *params); -typedef void (APIENTRY * PFN_glGetShaderInfoLog)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef GLuint (APIENTRY * PFN_glCreateProgram)(void); -typedef void (APIENTRY * PFN_glDeleteProgram)(GLuint program); -typedef void (APIENTRY * PFN_glAttachShader)(GLuint program, GLuint shader); -typedef void (APIENTRY * PFN_glLinkProgram)(GLuint program); -typedef void (APIENTRY * PFN_glGetProgramiv)(GLuint program, GLenum pname, GLint *params); -typedef void (APIENTRY * PFN_glGetProgramInfoLog)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef void (APIENTRY * PFN_glValidateProgram)(GLuint program); -typedef void (APIENTRY * PFN_glUseProgram)(GLuint program); -typedef GLint (APIENTRY * PFN_glGetUniformLocation)(GLuint program, const GLchar *name); -typedef void (APIENTRY * PFN_glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef GLint (APIENTRY * PFN_glGetAttribLocation)(GLuint program, const GLchar *name); -typedef void (APIENTRY * PFN_glEnableVertexAttribArray)(GLuint index); -typedef void (APIENTRY * PFN_glVertexAttrib1f)(GLuint index, GLfloat x); -typedef void (APIENTRY * PFN_glVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); -/* OpenGL 1.5 */ -typedef void (APIENTRY * PFN_glBindBuffer)(GLenum target, GLuint buffer); -typedef void (APIENTRY * PFN_glDeleteBuffers)(GLsizei n, const GLuint *buffers); -typedef void (APIENTRY * PFN_glGenBuffers)(GLsizei n, GLuint *buffers); -typedef void (APIENTRY * PFN_glBufferData)(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); -typedef void (APIENTRY * PFN_glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); - -/* OpenGL function pointers */ -static PFN_glGenBuffers pglGenBuffers = NULL; -static PFN_glGenVertexArrays pglGenVertexArrays = NULL; -static PFN_glDeleteVertexArrays pglDeleteVertexArrays = NULL; -static PFN_glCreateShader pglCreateShader = NULL; -static PFN_glShaderSource pglShaderSource = NULL; -static PFN_glCompileShader pglCompileShader = NULL; -static PFN_glGetShaderiv pglGetShaderiv = NULL; -static PFN_glGetShaderInfoLog pglGetShaderInfoLog = NULL; -static PFN_glDeleteShader pglDeleteShader = NULL; -static PFN_glCreateProgram pglCreateProgram = NULL; -static PFN_glAttachShader pglAttachShader = NULL; -static PFN_glLinkProgram pglLinkProgram = NULL; -static PFN_glUseProgram pglUseProgram = NULL; -static PFN_glGetProgramiv pglGetProgramiv = NULL; -static PFN_glGetProgramInfoLog pglGetProgramInfoLog = NULL; -static PFN_glDeleteProgram pglDeleteProgram = NULL; -static PFN_glGetUniformLocation pglGetUniformLocation = NULL; -static PFN_glUniformMatrix4fv pglUniformMatrix4fv = NULL; -static PFN_glGetAttribLocation pglGetAttribLocation = NULL; - -/* Map height updates */ -#define MAX_CIRCLE_SIZE (5.0f) -#define MAX_DISPLACEMENT (1.0f) -#define DISPLACEMENT_SIGN_LIMIT (0.3f) -#define MAX_ITER (200) -#define NUM_ITER_AT_A_TIME (1) - -/* Map general information */ -#define MAP_SIZE (10.0f) -#define MAP_NUM_VERTICES (80) -#define MAP_NUM_TOTAL_VERTICES (MAP_NUM_VERTICES*MAP_NUM_VERTICES) -#define MAP_NUM_LINES (3* (MAP_NUM_VERTICES - 1) * (MAP_NUM_VERTICES - 1) + \ - 2 * (MAP_NUM_VERTICES - 1)) - - -/* OpenGL function pointers */ - -static PFN_glBindVertexArray pglBindVertexArray = NULL; -static PFN_glBufferData pglBufferData = NULL; -static PFN_glBindBuffer pglBindBuffer = NULL; -static PFN_glBufferSubData pglBufferSubData = NULL; -static PFN_glEnableVertexAttribArray pglEnableVertexAttribArray = NULL; -static PFN_glVertexAttribPointer pglVertexAttribPointer = NULL; - -#define RESOLVE_GL_FCN(type, var, name) \ - if (status == GL_TRUE) \ - {\ - var = glfwGetProcAddress((name));\ - if ((var) == NULL)\ - {\ - status = GL_FALSE;\ - }\ - } - - -static GLboolean init_opengl(void) -{ - GLboolean status = GL_TRUE; - RESOLVE_GL_FCN(PFN_glCreateShader, pglCreateShader, "glCreateShader"); - RESOLVE_GL_FCN(PFN_glShaderSource, pglShaderSource, "glShaderSource"); - RESOLVE_GL_FCN(PFN_glCompileShader, pglCompileShader, "glCompileShader"); - RESOLVE_GL_FCN(PFN_glGetShaderiv, pglGetShaderiv, "glGetShaderiv"); - RESOLVE_GL_FCN(PFN_glGetShaderInfoLog, pglGetShaderInfoLog, "glGetShaderInfoLog"); - RESOLVE_GL_FCN(PFN_glDeleteShader, pglDeleteShader, "glDeleteShader"); - RESOLVE_GL_FCN(PFN_glCreateProgram, pglCreateProgram, "glCreateProgram"); - RESOLVE_GL_FCN(PFN_glAttachShader, pglAttachShader, "glAttachShader"); - RESOLVE_GL_FCN(PFN_glLinkProgram, pglLinkProgram, "glLinkProgram"); - RESOLVE_GL_FCN(PFN_glUseProgram, pglUseProgram, "glUseProgram"); - RESOLVE_GL_FCN(PFN_glGetProgramiv, pglGetProgramiv, "glGetProgramiv"); - RESOLVE_GL_FCN(PFN_glGetProgramInfoLog, pglGetProgramInfoLog, "glGetProgramInfoLog"); - RESOLVE_GL_FCN(PFN_glDeleteProgram, pglDeleteProgram, "glDeleteProgram"); - RESOLVE_GL_FCN(PFN_glGetUniformLocation, pglGetUniformLocation, "glGetUniformLocation"); - RESOLVE_GL_FCN(PFN_glUniformMatrix4fv, pglUniformMatrix4fv, "glUniformMatrix4fv"); - RESOLVE_GL_FCN(PFN_glGetAttribLocation, pglGetAttribLocation, "glGetAttribLocation"); - RESOLVE_GL_FCN(PFN_glGenVertexArrays, pglGenVertexArrays, "glGenVertexArrays"); - RESOLVE_GL_FCN(PFN_glDeleteVertexArrays, pglDeleteVertexArrays, "glDeleteVertexArrays"); - RESOLVE_GL_FCN(PFN_glBindVertexArray, pglBindVertexArray, "glBindVertexArray"); - RESOLVE_GL_FCN(PFN_glGenBuffers, pglGenBuffers, "glGenBuffers"); - RESOLVE_GL_FCN(PFN_glBindBuffer, pglBindBuffer, "glBindBuffer"); - RESOLVE_GL_FCN(PFN_glBufferData, pglBufferData, "glBufferData"); - RESOLVE_GL_FCN(PFN_glBufferSubData, pglBufferSubData, "glBufferSubData"); - RESOLVE_GL_FCN(PFN_glEnableVertexAttribArray, pglEnableVertexAttribArray, "glEnableVertexAttribArray"); - RESOLVE_GL_FCN(PFN_glVertexAttribPointer, pglVertexAttribPointer, "glVertexAttribPointer"); - return status; -} -/********************************************************************** - * Default shader programs - *********************************************************************/ - -static const char* default_vertex_shader = -"#version 150\n" -"uniform mat4 project;\n" -"uniform mat4 modelview;\n" -"in float x;\n" -"in float y;\n" -"in float z;\n" -"\n" -"void main()\n" -"{\n" -" gl_Position = project * modelview * vec4(x, y, z, 1.0);\n" -"}\n"; - -static const char* default_fragment_shader = -"#version 150\n" -"out vec4 gl_FragColor;\n" -"void main()\n" -"{\n" -" gl_FragColor = vec4(0.2, 1.0, 0.2, 1.0); \n" -"}\n"; - -/********************************************************************** - * Values for shader uniforms - *********************************************************************/ - -/* Frustum configuration */ -static GLfloat view_angle = 45.0f; -static GLfloat aspect_ratio = 4.0f/3.0f; -static GLfloat z_near = 1.0f; -static GLfloat z_far = 100.f; - -/* Projection matrix */ -static GLfloat projection_matrix[16] = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f -}; - -/* Model view matrix */ -static GLfloat modelview_matrix[16] = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f -}; - -/********************************************************************** - * Heightmap vertex and index data - *********************************************************************/ - -static GLfloat map_vertices[3][MAP_NUM_TOTAL_VERTICES]; -static GLuint map_line_indices[2*MAP_NUM_LINES]; - -/* Store uniform location for the shaders - * Those values are setup as part of the process of creating - * the shader program. They should not be used before creating - * the program. - */ -static GLuint mesh; -static GLuint mesh_vbo[4]; - -/********************************************************************** - * OpenGL helper functions - *********************************************************************/ - -/* Load a (text) file into memory and return its contents - */ -static char* read_file_content(const char* filename) -{ - FILE* fd; - size_t size = 0; - char* result = NULL; - - fd = fopen(filename, "r"); - if (fd != NULL) - { - size = fseek(fd, 0, SEEK_END); - (void) fseek(fd, 0, SEEK_SET); - - result = malloc(size + 1); - result[size] = '\0'; - if (fread(result, size, 1, fd) != 1) - { - free(result); - result = NULL; - } - (void) fclose(fd); - } - return result; -} - -/* Creates a shader object of the specified type using the specified text - */ -static GLuint make_shader(GLenum type, const char* shader_src) -{ - GLuint shader; - GLint shader_ok; - GLsizei log_length; - char info_log[8192]; - - shader = pglCreateShader(type); - if (shader != 0) - { - pglShaderSource(shader, 1, (const GLchar**)&shader_src, NULL); - pglCompileShader(shader); - pglGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok); - if (shader_ok != GL_TRUE) - { - fprintf(stderr, "ERROR: Failed to compile %s shader\n", (type == GL_FRAGMENT_SHADER) ? "fragment" : "vertex" ); - pglGetShaderInfoLog(shader, 8192, &log_length,info_log); - fprintf(stderr, "ERROR: \n%s\n\n", info_log); - pglDeleteShader(shader); - shader = 0; - } - } - return shader; -} - -/* Creates a program object using the specified vertex and fragment text - */ -static GLuint make_shader_program(const char* vertex_shader_src, const char* fragment_shader_src) -{ - GLuint program = 0u; - GLint program_ok; - GLuint vertex_shader = 0u; - GLuint fragment_shader = 0u; - GLsizei log_length; - char info_log[8192]; - - vertex_shader = make_shader(GL_VERTEX_SHADER, (vertex_shader_src == NULL) ? default_vertex_shader : vertex_shader_src); - if (vertex_shader != 0u) - { - fragment_shader = make_shader(GL_FRAGMENT_SHADER, (fragment_shader_src == NULL) ? default_fragment_shader : fragment_shader_src); - if (fragment_shader != 0u) - { - /* make the program that connect the two shader and link it */ - program = pglCreateProgram(); - if (program != 0u) - { - /* attach both shader and link */ - pglAttachShader(program, vertex_shader); - pglAttachShader(program, fragment_shader); - pglLinkProgram(program); - pglGetProgramiv(program, GL_LINK_STATUS, &program_ok); - - if (program_ok != GL_TRUE) - { - fprintf(stderr, "ERROR, failed to link shader program\n"); - pglGetProgramInfoLog(program, 8192, &log_length, info_log); - fprintf(stderr, "ERROR: \n%s\n\n", info_log); - pglDeleteProgram(program); - pglDeleteShader(fragment_shader); - pglDeleteShader(vertex_shader); - program = 0u; - } - } - } - else - { - fprintf(stderr, "ERROR: Unable to load fragment shader\n"); - pglDeleteShader(vertex_shader); - } - } - else - { - fprintf(stderr, "ERROR: Unable to load vertex shader\n"); - } - return program; -} - -/********************************************************************** - * Geometry creation functions - *********************************************************************/ - -/* Generate vertices and indices for the heightmap - */ -static void init_map(void) -{ - int i; - int j; - int k; - GLfloat step = MAP_SIZE / (MAP_NUM_VERTICES - 1); - GLfloat x = 0.0f; - GLfloat z = 0.0f; - /* Create a flat grid */ - k = 0; - for (i = 0 ; i < MAP_NUM_VERTICES ; ++i) - { - for (j = 0 ; j < MAP_NUM_VERTICES ; ++j) - { - map_vertices[0][k] = x; - map_vertices[1][k] = 0.0f; - map_vertices[2][k] = z; - z += step; - ++k; - } - x += step; - z = 0.0f; - } -#if DEBUG_ENABLED - for (i = 0 ; i < MAP_NUM_TOTAL_VERTICES ; ++i) - { - printf ("Vertice %d (%f, %f, %f)\n", - i, map_vertices[0][i], map_vertices[1][i], map_vertices[2][i]); - - } -#endif - /* create indices */ - /* line fan based on i - * i+1 - * | / i + n + 1 - * | / - * |/ - * i --- i + n - */ - - /* close the top of the square */ - k = 0; - for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i) - { - map_line_indices[k++] = (i + 1) * MAP_NUM_VERTICES -1; - map_line_indices[k++] = (i + 2) * MAP_NUM_VERTICES -1; - } - /* close the right of the square */ - for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i) - { - map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i; - map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i + 1; - } - - for (i = 0 ; i < (MAP_NUM_VERTICES - 1) ; ++i) - { - for (j = 0 ; j < (MAP_NUM_VERTICES - 1) ; ++j) - { - int ref = i * (MAP_NUM_VERTICES) + j; - map_line_indices[k++] = ref; - map_line_indices[k++] = ref + 1; - - map_line_indices[k++] = ref; - map_line_indices[k++] = ref + MAP_NUM_VERTICES; - - map_line_indices[k++] = ref; - map_line_indices[k++] = ref + MAP_NUM_VERTICES + 1; - } - } - -#ifdef DEBUG_ENABLED - for (k = 0 ; k < 2 * MAP_NUM_LINES ; k += 2) - { - int beg, end; - beg = map_line_indices[k]; - end = map_line_indices[k+1]; - printf ("Line %d: %d -> %d (%f, %f, %f) -> (%f, %f, %f)\n", - k / 2, beg, end, - map_vertices[0][beg], map_vertices[1][beg], map_vertices[2][beg], - map_vertices[0][end], map_vertices[1][end], map_vertices[2][end]); - } -#endif -} - -static void generate_heightmap__circle(float* center_x, float* center_y, - float* size, float* displacement) -{ - float sign; - /* random value for element in between [0-1.0] */ - *center_x = (MAP_SIZE * rand()) / (1.0f * RAND_MAX); - *center_y = (MAP_SIZE * rand()) / (1.0f * RAND_MAX); - *size = (MAX_CIRCLE_SIZE * rand()) / (1.0f * RAND_MAX); - sign = (1.0f * rand()) / (1.0f * RAND_MAX); - sign = (sign < DISPLACEMENT_SIGN_LIMIT) ? -1.0f : 1.0f; - *displacement = (sign * (MAX_DISPLACEMENT * rand())) / (1.0f * RAND_MAX); -} - -/* Run the specified number of iterations of the generation process for the - * heightmap - */ -static void update_map(int num_iter) -{ - assert(num_iter > 0); - while(num_iter) - { - /* center of the circle */ - float center_x; - float center_z; - float circle_size; - float disp; - size_t ii; - generate_heightmap__circle(¢er_x, ¢er_z, &circle_size, &disp); - disp = disp / 2.0f; - for (ii = 0u ; ii < MAP_NUM_TOTAL_VERTICES ; ++ii) - { - GLfloat dx = center_x - map_vertices[0][ii]; - GLfloat dz = center_z - map_vertices[2][ii]; - GLfloat pd = (2.0f * sqrtf((dx * dx) + (dz * dz))) / circle_size; - if (fabs(pd) <= 1.0f) - { - /* tx,tz is within the circle */ - GLfloat new_height = disp + ((GLfloat) cos(pd*3.14f) * disp); - map_vertices[1][ii] += new_height; - } - } - --num_iter; - } -} - -/********************************************************************** - * OpenGL helper functions - *********************************************************************/ - -/* Create VBO, IBO and VAO objects for the heightmap geometry and bind them to - * the specified program object - */ -static void make_mesh(GLuint program) -{ - GLuint attrloc; - - pglGenVertexArrays(1, &mesh); - pglGenBuffers(4, mesh_vbo); - pglBindVertexArray(mesh); - /* Prepare the data for drawing through a buffer inidices */ - pglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh_vbo[3]); - pglBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)* MAP_NUM_LINES * 2, map_line_indices, GL_STATIC_DRAW); - - /* Prepare the attributes for rendering */ - attrloc = pglGetAttribLocation(program, "x"); - pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[0]); - pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[0][0], GL_STATIC_DRAW); - pglEnableVertexAttribArray(attrloc); - pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); - - attrloc = pglGetAttribLocation(program, "z"); - pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[2]); - pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[2][0], GL_STATIC_DRAW); - pglEnableVertexAttribArray(attrloc); - pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); - - attrloc = pglGetAttribLocation(program, "y"); - pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[1]); - pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0], GL_DYNAMIC_DRAW); - pglEnableVertexAttribArray(attrloc); - pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); -} - -/* Update VBO vertices from source data - */ -static void update_mesh(void) -{ - pglBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0]); -} - -/********************************************************************** - * GLFW callback functions - *********************************************************************/ - -/* The program runs as long as this is GL_TRUE - */ -static GLboolean running = GL_TRUE; - -/* GLFW Window management functions */ -static int GLFWCALL close_window_callback(void) -{ - running = GL_FALSE; - - /* Disallow window closing - * The window will be closed when the main loop terminates */ - return GL_FALSE; -} - -static void GLFWCALL key_callback(int key, int action) -{ - switch(key) - { - case GLFW_KEY_ESC: - /* Exit program on Escape */ - running = GL_FALSE; - break; - } -} - -/* Print usage information */ -static void usage(void) -{ - printf("Usage: heightmap [-v ] [-f ]\n"); - printf(" heightmap [-h]\n"); -} - -void iteration(); - -double dt; -int frame; -int iter; -double last_update_time; - -int main(int argc, char** argv) -{ - int ch; - float f; - GLint uloc_modelview; - GLint uloc_project; - - char* vertex_shader_path = NULL; - char* fragment_shader_path = NULL; - char* vertex_shader_src = NULL; - char* fragment_shader_src = NULL; - GLuint shader_program; - - while ((ch = getopt(argc, argv, "f:v:h")) != -1) - { - switch (ch) - { - case 'f': - fragment_shader_path = optarg; - break; - case 'v': - vertex_shader_path = optarg; - break; - case 'h': - usage(); - exit(EXIT_SUCCESS); - default: - usage(); - exit(EXIT_FAILURE); - } - } - - if (fragment_shader_path) - { - vertex_shader_src = read_file_content(fragment_shader_path); - if (!fragment_shader_src) - { - fprintf(stderr, - "ERROR: unable to load fragment shader from '%s'\n", - fragment_shader_path); - exit(EXIT_FAILURE); - } - } - - if (vertex_shader_path) - { - vertex_shader_src = read_file_content(vertex_shader_path); - if (!vertex_shader_src) - { - fprintf(stderr, - "ERROR: unable to load vertex shader from '%s'\n", - fragment_shader_path); - exit(EXIT_FAILURE); - } - } - - if (GL_TRUE != glfwInit()) - { - fprintf(stderr, "ERROR: Unable to initialize GLFW\n"); - usage(); - - free(vertex_shader_src); - free(fragment_shader_src); - exit(EXIT_FAILURE); - } - - glfwEnable(GLFW_AUTO_POLL_EVENTS); /* No explicit call to glfwPollEvents() */ - - glfwOpenWindowHint(GLFW_WINDOW_NO_RESIZE, GL_TRUE); - glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3); - glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 2); - glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); - - if (GL_TRUE != glfwOpenWindow(800, 600, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) - { - fprintf(stderr, "ERROR: Unable to create the OpenGL context and associated window\n"); - usage(); - - free(vertex_shader_src); - free(fragment_shader_src); - exit(EXIT_FAILURE); - } - - glfwSetWindowTitle("GLFW OpenGL3 Heightmap demo"); - /* Register events callback */ - glfwSetWindowCloseCallback(close_window_callback); - glfwSetKeyCallback(key_callback); - - if (GL_TRUE != init_opengl()) - { - fprintf(stderr, "ERROR: unable to resolve OpenGL function pointers\n"); - free(vertex_shader_src); - free(fragment_shader_src); - exit(EXIT_FAILURE); - } - /* Prepare opengl resources for rendering */ - shader_program = make_shader_program(vertex_shader_src , fragment_shader_src); - free(vertex_shader_src); - free(fragment_shader_src); - - if (shader_program == 0u) - { - fprintf(stderr, "ERROR: during creation of the shader program\n"); - usage(); - exit(EXIT_FAILURE); - } - - pglUseProgram(shader_program); - uloc_project = pglGetUniformLocation(shader_program, "project"); - uloc_modelview = pglGetUniformLocation(shader_program, "modelview"); - - /* Compute the projection matrix */ - f = 1.0f / tanf(view_angle / 2.0f); - projection_matrix[0] = f / aspect_ratio; - projection_matrix[5] = f; - projection_matrix[10] = (z_far + z_near)/ (z_near - z_far); - projection_matrix[11] = -1.0f; - projection_matrix[14] = 2.0f * (z_far * z_near) / (z_near - z_far); - pglUniformMatrix4fv(uloc_project, 1, GL_FALSE, projection_matrix); - - /* Set the camera position */ - modelview_matrix[12] = -5.0f; - modelview_matrix[13] = -5.0f; - modelview_matrix[14] = -20.0f; - pglUniformMatrix4fv(uloc_modelview, 1, GL_FALSE, modelview_matrix); - - /* Create mesh data */ - init_map(); - make_mesh(shader_program); - - /* Create vao + vbo to store the mesh */ - /* Create the vbo to store all the information for the grid and the height */ - - /* setup the scene ready for rendering */ - glViewport(0, 0, 800, 600); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - - /* main loop */ - frame = 0; - iter = 0; - dt = last_update_time = glfwGetTime(); - -#ifdef EMSCRIPTEN - emscripten_set_main_loop (iteration, 0, 1); -#else - // Main loop - while( running ) - { - iteration(); - } -#endif - - exit(EXIT_SUCCESS); -} - -void iteration(){ - ++frame; - /* render the next frame */ - glClear(GL_COLOR_BUFFER_BIT); - glDrawElements(GL_LINES, 2* MAP_NUM_LINES , GL_UNSIGNED_INT, 0); - - /* display and process events through callbacks */ - glfwSwapBuffers(); - /* Check the frame rate and update the heightmap if needed */ - dt = glfwGetTime(); - if ((dt - last_update_time) > 0.2) - { - /* generate the next iteration of the heightmap */ - if (iter < MAX_ITER) - { - update_map(NUM_ITER_AT_A_TIME); - update_mesh(); - iter += NUM_ITER_AT_A_TIME; - } - last_update_time = dt; - frame = 0; - } -} - diff --git a/tests/glfw/listmodes.c b/tests/glfw/listmodes.c deleted file mode 100644 index 717cfde0c66dc..0000000000000 --- a/tests/glfw/listmodes.c +++ /dev/null @@ -1,48 +0,0 @@ -//======================================================================== -// This is a small test application for GLFW. -// The program lists all available fullscreen video modes. -//======================================================================== - -#include -#include - -// Maximum number of modes that we want to list -#define MAX_NUM_MODES 400 - - -//======================================================================== -// main() -//======================================================================== - -int main( void ) -{ - GLFWvidmode dtmode, modes[ MAX_NUM_MODES ]; - int modecount, i; - - // Initialize GLFW - if( !glfwInit() ) - { - return 0; - } - - // Show desktop video mode - glfwGetDesktopMode( &dtmode ); - printf( "Desktop mode: %d x %d x %d\n\n", - dtmode.Width, dtmode.Height, dtmode.RedBits + - dtmode.GreenBits + dtmode.BlueBits ); - - // List available video modes - modecount = glfwGetVideoModes( modes, MAX_NUM_MODES ); - printf( "Available modes:\n" ); - for( i = 0; i < modecount; i ++ ) - { - printf( "%3d: %d x %d x %d\n", i, - modes[i].Width, modes[i].Height, modes[i].RedBits + - modes[i].GreenBits + modes[i].BlueBits ); - } - - // Terminate GLFW - glfwTerminate(); - - return 0; -} diff --git a/tests/glfw/mipmaps.c b/tests/glfw/mipmaps.c deleted file mode 100644 index bfd77f0617f21..0000000000000 --- a/tests/glfw/mipmaps.c +++ /dev/null @@ -1,136 +0,0 @@ -//======================================================================== -// This is an example program for the GLFW library -// -// It shows texture loading with mipmap generation and rendering with -// trilienar texture filtering -//======================================================================== - -#include -#include - -#include - -#ifdef EMSCRIPTEN -#include -#endif - -int width, height, x; -double time; -GLboolean running; - -void iteration(){ - // Get time and mouse position - time = glfwGetTime(); - glfwGetMousePos( &x, NULL ); - - // Get window size (may be different than the requested size) - glfwGetWindowSize( &width, &height ); - height = height > 0 ? height : 1; - - // Set viewport - glViewport( 0, 0, width, height ); - - // Clear color buffer - glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); - glClear( GL_COLOR_BUFFER_BIT ); - - // Select and setup the projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - gluPerspective( 65.0f, (GLfloat)width / (GLfloat)height, 1.0f, - 50.0f ); - - // Select and setup the modelview matrix - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - gluLookAt( 0.0f, 3.0f, -20.0f, // Eye-position - 0.0f, -4.0f, -11.0f, // View-point - 0.0f, 1.0f, 0.0f ); // Up-vector - - // Draw a textured quad - glRotatef( 0.05f * (GLfloat)x + (GLfloat)time * 5.0f, 0.0f, 1.0f, 0.0f ); - glBegin( GL_QUADS ); - glTexCoord2f( -20.0f, 20.0f ); - glVertex3f( -50.0f, 0.0f, -50.0f ); - glTexCoord2f( 20.0f, 20.0f ); - glVertex3f( 50.0f, 0.0f, -50.0f ); - glTexCoord2f( 20.0f, -20.0f ); - glVertex3f( 50.0f, 0.0f, 50.0f ); - glTexCoord2f( -20.0f, -20.0f ); - glVertex3f( -50.0f, 0.0f, 50.0f ); - glEnd(); - - // Swap buffers - glfwSwapBuffers(); - - // Check if the ESC key was pressed or the window was closed - running = !glfwGetKey( GLFW_KEY_ESC ) && - glfwGetWindowParam( GLFW_OPENED ); -} - -int main( void ) -{ - GLuint textureID; - char* texturePath = "mipmaps.tga"; - - // Initialise GLFW - if( !glfwInit() ) - { - fprintf( stderr, "Failed to initialize GLFW\n" ); - exit( EXIT_FAILURE ); - } - - // Open OpenGL window - if( !glfwOpenWindow( 640, 480, 0,0,0,0, 0,0, GLFW_WINDOW ) ) - { - fprintf( stderr, "Failed to open GLFW window\n" ); - glfwTerminate(); - exit( EXIT_FAILURE ); - } - - glfwSetWindowTitle( "Trilinear interpolation" ); - - // Enable sticky keys - glfwEnable( GLFW_STICKY_KEYS ); - - // Enable vertical sync (on cards that support it) - glfwSwapInterval( 1 ); - - // Generate and bind our texture ID - glGenTextures( 1, &textureID ); - glBindTexture( GL_TEXTURE_2D, textureID ); - - // Load texture from file into video memory, including mipmap levels - if( !glfwLoadTexture2D( texturePath, GLFW_BUILD_MIPMAPS_BIT ) ) - { - fprintf( stderr, "Failed to load texture %s\n", texturePath ); - glfwTerminate(); - exit( EXIT_FAILURE ); - } - - // Use trilinear interpolation (GL_LINEAR_MIPMAP_LINEAR) - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - GL_LINEAR_MIPMAP_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, - GL_LINEAR ); - - // Enable plain 2D texturing - glEnable( GL_TEXTURE_2D ); - - running = GL_TRUE; -#ifdef EMSCRIPTEN - emscripten_set_main_loop (iteration, 0, 1); -#else - // Main loop - while( running ) - { - iteration(); - } -#endif - - // Close OpenGL window and terminate GLFW - glfwTerminate(); - - exit( EXIT_SUCCESS ); -} - diff --git a/tests/glfw/mipmaps.tga b/tests/glfw/mipmaps.tga deleted file mode 100644 index 55f913b0fa48f69b163664da1db6f9b1fe80e2ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66322 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 -#include - - -typedef struct { - GLFWcond cond; - GLFWmutex mutex; - int flag; -} signal_t; - - -signal_t gotoA, gotoB; - -GLFWcond threadDone; -GLFWmutex doneMutex; -int doneCount; -int gotoACount, gotoBCount; - -#define MAX_COUNT 10000 - - -//------------------------------------------------------------------------ -// InitSignal() -//------------------------------------------------------------------------ - -void InitSignal( signal_t *s ) -{ - s->cond = glfwCreateCond(); - s->mutex = glfwCreateMutex(); - s->flag = 0; -} - - -//------------------------------------------------------------------------ -// KillSignal() -//------------------------------------------------------------------------ - -void KillSignal( signal_t *s ) -{ - glfwDestroyCond( s->cond ); - glfwDestroyMutex( s->mutex ); - s->flag = 0; -} - - -//------------------------------------------------------------------------ -// WaitSignal() -//------------------------------------------------------------------------ - -void WaitSignal( signal_t *s ) -{ - glfwLockMutex( s->mutex ); - while( !s->flag ) - { - glfwWaitCond( s->cond, s->mutex, GLFW_INFINITY ); - } - s->flag = 0; - glfwUnlockMutex( s->mutex ); -} - - -//------------------------------------------------------------------------ -// SetSignal() -//------------------------------------------------------------------------ - -void SetSignal( signal_t *s ) -{ - glfwLockMutex( s->mutex ); - s->flag = 1; - glfwUnlockMutex( s->mutex ); - glfwSignalCond( s->cond ); -} - - -//------------------------------------------------------------------------ -// threadAfun() -//------------------------------------------------------------------------ - -void GLFWCALL threadAfun( void * arg ) -{ - int done; - - do - { - done = (gotoACount >= MAX_COUNT); - if( !done ) - { - gotoACount ++; - SetSignal( &gotoB ); - WaitSignal( &gotoA ); - } - } - while( !done ); - - SetSignal( &gotoB ); - - glfwLockMutex( doneMutex ); - doneCount ++; - glfwUnlockMutex( doneMutex ); - glfwSignalCond( threadDone ); -} - - -//------------------------------------------------------------------------ -// threadBfun() -//------------------------------------------------------------------------ - -void GLFWCALL threadBfun( void * arg ) -{ - int done; - - do - { - done = (gotoBCount >= MAX_COUNT); - if( !done ) - { - gotoBCount ++; - SetSignal( &gotoA ); - WaitSignal( &gotoB ); - } - } - while( !done ); - - SetSignal( &gotoA ); - - glfwLockMutex( doneMutex ); - doneCount ++; - glfwUnlockMutex( doneMutex ); - glfwSignalCond( threadDone ); -} - - - -//------------------------------------------------------------------------ -// main() -//------------------------------------------------------------------------ - -int main( void ) -{ - GLFWthread threadA, threadB; - double t1, t2, csps; - int done, count, i; - - gotoACount = gotoBCount = doneCount = 0; - - // Initialize GLFW - if( !glfwInit() ) - { - return 0; - } - - // Print some program information - printf( "\nMultithreading benchmarking program\n" ); - printf( "-----------------------------------\n\n" ); - printf( "This program consists of two tests. In the first test " ); - printf( "two threads are created,\n" ); - printf( "which continously signal/wait each other. This forces " ); - printf( "the execution to\n" ); - printf( "alternate between the two threads, and gives a measure " ); - printf( "of the thread\n" ); - printf( "synchronization granularity. In the second test, the " ); - printf( "main thread is repeatedly\n" ); - printf( "put to sleep for a very short interval using glfwSleep. " ); - printf( "The average sleep time\n" ); - printf( "is measured, which tells the minimum supported sleep " ); - printf( "interval.\n\n" ); - printf( "Results:\n" ); - printf( "--------\n\n" ); - printf( "Number of CPUs: %d\n\n", glfwGetNumberOfProcessors() ); - fflush( stdout ); - - -//------------------------------------------------------------------------ -// 1) Benchmark thread synchronization granularity -//------------------------------------------------------------------------ - - // Init mutexes and conditions - doneMutex = glfwCreateMutex(); - threadDone = glfwCreateCond(); - InitSignal( &gotoA ); - InitSignal( &gotoB ); - - // Create threads A & B - threadA = glfwCreateThread( threadAfun, NULL ); - threadB = glfwCreateThread( threadBfun, NULL ); - if( threadA == -1 || threadB == -1 ) - { - glfwLockMutex( doneMutex ); - doneCount = 2; - glfwUnlockMutex( doneMutex ); - } - - // Wait for both threads to be done - t1 = glfwGetTime(); - glfwLockMutex( doneMutex ); - do - { - done = (doneCount == 2); - if( !done ) - { - glfwWaitCond( threadDone, doneMutex, GLFW_INFINITY ); - } - } - while( !done ); - glfwUnlockMutex( doneMutex ); - t2 = glfwGetTime(); - - // Display results - count = gotoACount + gotoBCount; - csps = (double)count / (t2-t1); - printf( "Test 1: %.0f context switches / second (%.3f us/switch)\n", - csps, 1e6/csps ); - fflush( stdout ); - - // Wait for threads to die - glfwWaitThread( threadA, GLFW_WAIT ); - glfwWaitThread( threadB, GLFW_WAIT ); - - // Destroy mutexes and conditions - glfwDestroyMutex( doneMutex ); - glfwDestroyCond( threadDone ); - KillSignal( &gotoA ); - KillSignal( &gotoB ); - - -//------------------------------------------------------------------------ -// 2) Benchmark thread sleep granularity -//------------------------------------------------------------------------ - - // Find an initial estimate - t1 = glfwGetTime(); - for( i = 0; i < 10; i ++ ) - { - glfwSleep( 0.0001 ); - } - t2 = glfwGetTime(); - - // Sleep for roughly 1 s - count = (int)(1.0 / ((t2-t1)/10.0)); - t1 = glfwGetTime(); - for( i = 0; i < count; i ++ ) - { - glfwSleep( 0.0001 ); - } - t2 = glfwGetTime(); - - // Display results - printf( "Test 2: %.3f ms / sleep (mean)\n\n", - 1000.0 * (t2-t1) / (double)count ); - - // Terminate GLFW - glfwTerminate(); - - return 0; -} diff --git a/tests/glfw/mthello.c b/tests/glfw/mthello.c deleted file mode 100644 index e12dea52551e9..0000000000000 --- a/tests/glfw/mthello.c +++ /dev/null @@ -1,48 +0,0 @@ -//======================================================================== -// This is a small test application for GLFW. -// The program prints "Hello world!", using two threads. -//======================================================================== - -#include -#include - - -//======================================================================== -// HelloFun() - Thread function -//======================================================================== - -void GLFWCALL HelloFun( void *arg ) -{ - // Print the first part of the message - printf( "Hello " ); -} - - -//======================================================================== -// main() - Main function (main thread) -//======================================================================== - -int main( void ) -{ - GLFWthread thread; - - // Initialise GLFW - if( !glfwInit() ) - { - return 0; - } - - // Create thread - thread = glfwCreateThread( HelloFun, NULL ); - - // Wait for thread to die - glfwWaitThread( thread, GLFW_WAIT ); - - // Print the rest of the message - printf( "world!\n" ); - - // Terminate GLFW - glfwTerminate(); - - return 0; -} diff --git a/tests/glfw/particles.c b/tests/glfw/particles.c deleted file mode 100644 index 15c133a0aa921..0000000000000 --- a/tests/glfw/particles.c +++ /dev/null @@ -1,1166 +0,0 @@ -//======================================================================== -// This is a simple, but cool particle engine (buzz-word meaning many -// small objects that are treated as points and drawn as textures -// projected on simple geometry). -// -// This demonstration generates a colorful fountain-like animation. It -// uses several advanced OpenGL teqhniques: -// -// 1) Lighting (per vertex) -// 2) Alpha blending -// 3) Fog -// 4) Texturing -// 5) Display lists (for drawing the static environment geometry) -// 6) Vertex arrays (for drawing the particles) -// 7) GL_EXT_separate_specular_color is used (if available) -// -// Even more so, this program uses multi threading. The program is -// essentialy divided into a main rendering thread and a particle physics -// calculation thread. My benchmarks under Windows 2000 on a single -// processor system show that running this program as two threads instead -// of a single thread means no difference (there may be a very marginal -// advantage for the multi threaded case). On dual processor systems I -// have had reports of 5-25% of speed increase when running this program -// as two threads instead of one thread. -// -// The default behaviour of this program is to use two threads. To force -// a single thread to be used, use the command line switch -s. -// -// To run a fixed length benchmark (60 s), use the command line switch -b. -// -// Benchmark results (640x480x16, best of three tests): -// -// CPU GFX 1 thread 2 threads -// Athlon XP 2700+ GeForce Ti4200 (oc) 757 FPS 759 FPS -// P4 2.8 GHz (SMT) GeForce FX5600 548 FPS 550 FPS -// -// One more thing: Press 'w' during the demo to toggle wireframe mode. -//======================================================================== - -#include -#include -#include -#include -#include - -#ifdef EMSCRIPTEN -#include -#endif - -// Define tokens for GL_EXT_separate_specular_color if not already defined -#ifndef GL_EXT_separate_specular_color -#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 -#define GL_SINGLE_COLOR_EXT 0x81F9 -#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA -#endif // GL_EXT_separate_specular_color - -// Some 's do not define M_PI -#ifndef M_PI -#define M_PI 3.141592654 -#endif - -// Desired fullscreen resolution -#define WIDTH 640 -#define HEIGHT 480 - - -//======================================================================== -// Type definitions -//======================================================================== - -typedef struct { float x,y,z; } VEC; - -// This structure is used for interleaved vertex arrays (see the -// DrawParticles function) - Note: This structure SHOULD be packed on most -// systems. It uses 32-bit fields on 32-bit boundaries, and is a multiple -// of 64 bits in total (6x32=3x64). If it does not work, try using pragmas -// or whatever to force the structure to be packed. -typedef struct { - GLfloat s, t; // Texture coordinates - GLuint rgba; // Color (four ubytes packed into an uint) - GLfloat x, y, z; // Vertex coordinates -} VERTEX; - - -//======================================================================== -// Program control global variables -//======================================================================== - -// "Running" flag (true if program shall continue to run) -int running; - -// Window dimensions -int width, height; - -// "wireframe" flag (true if we use wireframe view) -int wireframe; - -// "multithreading" flag (true if we use multithreading) -int multithreading; - -// Thread synchronization -struct { - double t; // Time (s) - float dt; // Time since last frame (s) - int p_frame; // Particle physics frame number - int d_frame; // Particle draw frame number - GLFWcond p_done; // Condition: particle physics done - GLFWcond d_done; // Condition: particle draw done - GLFWmutex particles_lock; // Particles data sharing mutex -} thread_sync; - - -//======================================================================== -// Texture declarations (we hard-code them into the source code, since -// they are so simple) -//======================================================================== - -#define P_TEX_WIDTH 8 // Particle texture dimensions -#define P_TEX_HEIGHT 8 -#define F_TEX_WIDTH 16 // Floor texture dimensions -#define F_TEX_HEIGHT 16 - -// Texture object IDs -GLuint particle_tex_id, floor_tex_id; - -// Particle texture (a simple spot) -const unsigned char particle_texture[ P_TEX_WIDTH * P_TEX_HEIGHT ] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x11, 0x22, 0x22, 0x11, 0x00, 0x00, - 0x00, 0x11, 0x33, 0x88, 0x77, 0x33, 0x11, 0x00, - 0x00, 0x22, 0x88, 0xff, 0xee, 0x77, 0x22, 0x00, - 0x00, 0x22, 0x77, 0xee, 0xff, 0x88, 0x22, 0x00, - 0x00, 0x11, 0x33, 0x77, 0x88, 0x33, 0x11, 0x00, - 0x00, 0x00, 0x11, 0x33, 0x22, 0x11, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -// Floor texture (your basic checkered floor) -const unsigned char floor_texture[ F_TEX_WIDTH * F_TEX_HEIGHT ] = { - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0xff, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0xf0, 0xcc, 0xee, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x66, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xee, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0xf0, 0xf0, 0xf0, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x55, 0x30, 0x30, 0x44, 0x30, 0x30, - 0xf0, 0xdd, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x60, 0x30, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, 0xf0, 0xff, 0xf0, 0xf0, 0xdd, 0xf0, 0xf0, 0xff, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x55, 0x33, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, - 0x30, 0x44, 0x66, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xaa, 0xf0, 0xf0, 0xcc, 0xf0, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xdd, 0xf0, - 0x30, 0x30, 0x30, 0x77, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -}; - - -//======================================================================== -// These are fixed constants that control the particle engine. In a -// modular world, these values should be variables... -//======================================================================== - -// Maximum number of particles -#define MAX_PARTICLES 3000 - -// Life span of a particle (in seconds) -#define LIFE_SPAN 8.0f - -// A new particle is born every [BIRTH_INTERVAL] second -#define BIRTH_INTERVAL (LIFE_SPAN/(float)MAX_PARTICLES) - -// Particle size (meters) -#define PARTICLE_SIZE 0.7f - -// Gravitational constant (m/s^2) -#define GRAVITY 9.8f - -// Base initial velocity (m/s) -#define VELOCITY 8.0f - -// Bounce friction (1.0 = no friction, 0.0 = maximum friction) -#define FRICTION 0.75f - -// "Fountain" height (m) -#define FOUNTAIN_HEIGHT 3.0f - -// Fountain radius (m) -#define FOUNTAIN_RADIUS 1.6f - -// Minimum delta-time for particle phisics (s) -#define MIN_DELTA_T (BIRTH_INTERVAL * 0.5f) - - -//======================================================================== -// Particle system global variables -//======================================================================== - -// This structure holds all state for a single particle -typedef struct { - float x,y,z; // Position in space - float vx,vy,vz; // Velocity vector - float r,g,b; // Color of particle - float life; // Life of particle (1.0 = newborn, < 0.0 = dead) - int active; // Tells if this particle is active -} PARTICLE; - -// Global vectors holding all particles. We use two vectors for double -// buffering. -static PARTICLE particles[ MAX_PARTICLES ]; - -// Global variable holding the age of the youngest particle -static float min_age; - -// Color of latest born particle (used for fountain lighting) -static float glow_color[4]; - -// Position of latest born particle (used for fountain lighting) -static float glow_pos[4]; - - -//======================================================================== -// Object material and fog configuration constants -//======================================================================== - -const GLfloat fountain_diffuse[4] = {0.7f,1.0f,1.0f,1.0f}; -const GLfloat fountain_specular[4] = {1.0f,1.0f,1.0f,1.0f}; -const GLfloat fountain_shininess = 12.0f; -const GLfloat floor_diffuse[4] = {1.0f,0.6f,0.6f,1.0f}; -const GLfloat floor_specular[4] = {0.6f,0.6f,0.6f,1.0f}; -const GLfloat floor_shininess = 18.0f; -const GLfloat fog_color[4] = {0.1f, 0.1f, 0.1f, 1.0f}; - - -//======================================================================== -// InitParticle() - Initialize a new particle -//======================================================================== - -void InitParticle( PARTICLE *p, double t ) -{ - float xy_angle, velocity; - - // Start position of particle is at the fountain blow-out - p->x = 0.0f; - p->y = 0.0f; - p->z = FOUNTAIN_HEIGHT; - - // Start velocity is up (Z)... - p->vz = 0.7f + (0.3f/4096.f) * (float) (rand() & 4095); - - // ...and a randomly chosen X/Y direction - xy_angle = (2.f * (float)M_PI / 4096.f) * (float) (rand() & 4095); - p->vx = 0.4f * (float) cos( xy_angle ); - p->vy = 0.4f * (float) sin( xy_angle ); - - // Scale velocity vector according to a time-varying velocity - velocity = VELOCITY*(0.8f + 0.1f*(float)(sin( 0.5*t )+sin( 1.31*t ))); - p->vx *= velocity; - p->vy *= velocity; - p->vz *= velocity; - - // Color is time-varying - p->r = 0.7f + 0.3f * (float) sin( 0.34*t + 0.1 ); - p->g = 0.6f + 0.4f * (float) sin( 0.63*t + 1.1 ); - p->b = 0.6f + 0.4f * (float) sin( 0.91*t + 2.1 ); - - // Store settings for fountain glow lighting - glow_pos[0] = 0.4f * (float) sin( 1.34*t ); - glow_pos[1] = 0.4f * (float) sin( 3.11*t ); - glow_pos[2] = FOUNTAIN_HEIGHT + 1.0f; - glow_pos[3] = 1.0f; - glow_color[0] = p->r; - glow_color[1] = p->g; - glow_color[2] = p->b; - glow_color[3] = 1.0f; - - // The particle is new-born and active - p->life = 1.0f; - p->active = 1; -} - - -//======================================================================== -// UpdateParticle() - Update a particle -//======================================================================== - -#define FOUNTAIN_R2 (FOUNTAIN_RADIUS+PARTICLE_SIZE/2)*(FOUNTAIN_RADIUS+PARTICLE_SIZE/2) - -void UpdateParticle( PARTICLE *p, float dt ) -{ - // If the particle is not active, we need not do anything - if( !p->active ) - { - return; - } - - // The particle is getting older... - p->life = p->life - dt * (1.0f / LIFE_SPAN); - - // Did the particle die? - if( p->life <= 0.0f ) - { - p->active = 0; - return; - } - - // Update particle velocity (apply gravity) - p->vz = p->vz - GRAVITY * dt; - - // Update particle position - p->x = p->x + p->vx * dt; - p->y = p->y + p->vy * dt; - p->z = p->z + p->vz * dt; - - // Simple collision detection + response - if( p->vz < 0.0f ) - { - // Particles should bounce on the fountain (with friction) - if( (p->x*p->x + p->y*p->y) < FOUNTAIN_R2 && - p->z < (FOUNTAIN_HEIGHT + PARTICLE_SIZE/2) ) - { - p->vz = -FRICTION * p->vz; - p->z = FOUNTAIN_HEIGHT + PARTICLE_SIZE/2 + - FRICTION * (FOUNTAIN_HEIGHT + - PARTICLE_SIZE/2 - p->z); - } - - // Particles should bounce on the floor (with friction) - else if( p->z < PARTICLE_SIZE/2 ) - { - p->vz = -FRICTION * p->vz; - p->z = PARTICLE_SIZE/2 + - FRICTION * (PARTICLE_SIZE/2 - p->z); - } - - } -} - - -//======================================================================== -// ParticleEngine() - The main frame for the particle engine. Called once -// per frame. -//======================================================================== - -void ParticleEngine( double t, float dt ) -{ - int i; - float dt2; - - // Update particles (iterated several times per frame if dt is too - // large) - while( dt > 0.0f ) - { - // Calculate delta time for this iteration - dt2 = dt < MIN_DELTA_T ? dt : MIN_DELTA_T; - - // Update particles - for( i = 0; i < MAX_PARTICLES; i ++ ) - { - UpdateParticle( &particles[ i ], dt2 ); - } - - // Increase minimum age - min_age += dt2; - - // Should we create any new particle(s)? - while( min_age >= BIRTH_INTERVAL ) - { - min_age -= BIRTH_INTERVAL; - - // Find a dead particle to replace with a new one - for( i = 0; i < MAX_PARTICLES; i ++ ) - { - if( !particles[ i ].active ) - { - InitParticle( &particles[ i ], t + min_age ); - UpdateParticle( &particles[ i ], min_age ); - break; - } - } - } - - // Decrease frame delta time - dt -= dt2; - } -} - - -//======================================================================== -// DrawParticles() - Draw all active particles. We use OpenGL 1.1 vertex -// arrays for this in order to accelerate the drawing. -//======================================================================== - -#define BATCH_PARTICLES 70 // Number of particles to draw in each batch - // (70 corresponds to 7.5 KB = will not blow - // the L1 data cache on most CPUs) -#define PARTICLE_VERTS 4 // Number of vertices per particle - -void DrawParticles( double t, float dt ) -{ - int i, particle_count; - VERTEX vertex_array[ BATCH_PARTICLES * PARTICLE_VERTS ], *vptr; - float alpha; - GLuint rgba; - VEC quad_lower_left, quad_lower_right; - GLfloat mat[ 16 ]; - PARTICLE *pptr; - - // Here comes the real trick with flat single primitive objects (s.c. - // "billboards"): We must rotate the textured primitive so that it - // always faces the viewer (is coplanar with the view-plane). - // We: - // 1) Create the primitive around origo (0,0,0) - // 2) Rotate it so that it is coplanar with the view plane - // 3) Translate it according to the particle position - // Note that 1) and 2) is the same for all particles (done only once). - - // Get modelview matrix. We will only use the upper left 3x3 part of - // the matrix, which represents the rotation. - glGetFloatv( GL_MODELVIEW_MATRIX, mat ); - - // 1) & 2) We do it in one swift step: - // Although not obvious, the following six lines represent two matrix/ - // vector multiplications. The matrix is the inverse 3x3 rotation - // matrix (i.e. the transpose of the same matrix), and the two vectors - // represent the lower left corner of the quad, PARTICLE_SIZE/2 * - // (-1,-1,0), and the lower right corner, PARTICLE_SIZE/2 * (1,-1,0). - // The upper left/right corners of the quad is always the negative of - // the opposite corners (regardless of rotation). - quad_lower_left.x = (-PARTICLE_SIZE/2) * (mat[0] + mat[1]); - quad_lower_left.y = (-PARTICLE_SIZE/2) * (mat[4] + mat[5]); - quad_lower_left.z = (-PARTICLE_SIZE/2) * (mat[8] + mat[9]); - quad_lower_right.x = (PARTICLE_SIZE/2) * (mat[0] - mat[1]); - quad_lower_right.y = (PARTICLE_SIZE/2) * (mat[4] - mat[5]); - quad_lower_right.z = (PARTICLE_SIZE/2) * (mat[8] - mat[9]); - - // Don't update z-buffer, since all particles are transparent! - glDepthMask( GL_FALSE ); - - // Enable blending - glEnable( GL_BLEND ); - glBlendFunc( GL_SRC_ALPHA, GL_ONE ); - - // Select particle texture - if( !wireframe ) - { - glEnable( GL_TEXTURE_2D ); - glBindTexture( GL_TEXTURE_2D, particle_tex_id ); - } - - // Set up vertex arrays. We use interleaved arrays, which is easier to - // handle (in most situations) and it gives a linear memeory access - // access pattern (which may give better performance in some - // situations). GL_T2F_C4UB_V3F means: 2 floats for texture coords, - // 4 ubytes for color and 3 floats for vertex coord (in that order). - // Most OpenGL cards / drivers are optimized for this format. - glInterleavedArrays( GL_T2F_C4UB_V3F, 0, vertex_array ); - - // Is particle physics carried out in a separate thread? - if( multithreading ) - { - // Wait for particle physics thread to be done - glfwLockMutex( thread_sync.particles_lock ); - while( running && thread_sync.p_frame <= thread_sync.d_frame ) - { - glfwWaitCond( thread_sync.p_done, thread_sync.particles_lock, - 0.1 ); - } - - // Store the frame time and delta time for the physics thread - thread_sync.t = t; - thread_sync.dt = dt; - - // Update frame counter - thread_sync.d_frame ++; - } - else - { - // Perform particle physics in this thread - ParticleEngine( t, dt ); - } - - // Loop through all particles and build vertex arrays. - particle_count = 0; - vptr = vertex_array; - pptr = particles; - for( i = 0; i < MAX_PARTICLES; i ++ ) - { - if( pptr->active ) - { - // Calculate particle intensity (we set it to max during 75% - // of its life, then it fades out) - alpha = 4.0f * pptr->life; - if( alpha > 1.0f ) - { - alpha = 1.0f; - } - - // Convert color from float to 8-bit (store it in a 32-bit - // integer using endian independent type casting) - ((GLubyte *)&rgba)[0] = (GLubyte)(pptr->r * 255.0f); - ((GLubyte *)&rgba)[1] = (GLubyte)(pptr->g * 255.0f); - ((GLubyte *)&rgba)[2] = (GLubyte)(pptr->b * 255.0f); - ((GLubyte *)&rgba)[3] = (GLubyte)(alpha * 255.0f); - - // 3) Translate the quad to the correct position in modelview - // space and store its parameters in vertex arrays (we also - // store texture coord and color information for each vertex). - - // Lower left corner - vptr->s = 0.0f; - vptr->t = 0.0f; - vptr->rgba = rgba; - vptr->x = pptr->x + quad_lower_left.x; - vptr->y = pptr->y + quad_lower_left.y; - vptr->z = pptr->z + quad_lower_left.z; - vptr ++; - - // Lower right corner - vptr->s = 1.0f; - vptr->t = 0.0f; - vptr->rgba = rgba; - vptr->x = pptr->x + quad_lower_right.x; - vptr->y = pptr->y + quad_lower_right.y; - vptr->z = pptr->z + quad_lower_right.z; - vptr ++; - - // Upper right corner - vptr->s = 1.0f; - vptr->t = 1.0f; - vptr->rgba = rgba; - vptr->x = pptr->x - quad_lower_left.x; - vptr->y = pptr->y - quad_lower_left.y; - vptr->z = pptr->z - quad_lower_left.z; - vptr ++; - - // Upper left corner - vptr->s = 0.0f; - vptr->t = 1.0f; - vptr->rgba = rgba; - vptr->x = pptr->x - quad_lower_right.x; - vptr->y = pptr->y - quad_lower_right.y; - vptr->z = pptr->z - quad_lower_right.z; - vptr ++; - - // Increase count of drawable particles - particle_count ++; - } - - // If we have filled up one batch of particles, draw it as a set - // of quads using glDrawArrays. - if( particle_count >= BATCH_PARTICLES ) - { - // The first argument tells which primitive type we use (QUAD) - // The second argument tells the index of the first vertex (0) - // The last argument is the vertex count - glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count ); - particle_count = 0; - vptr = vertex_array; - } - - // Next particle - pptr ++; - } - - // We are done with the particle data: Unlock mutex and signal physics - // thread - if( multithreading ) - { - glfwUnlockMutex( thread_sync.particles_lock ); - glfwSignalCond( thread_sync.d_done ); - } - - // Draw final batch of particles (if any) - glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count ); - - // Disable vertex arrays (Note: glInterleavedArrays implicitly called - // glEnableClientState for vertex, texture coord and color arrays) - glDisableClientState( GL_VERTEX_ARRAY ); - glDisableClientState( GL_TEXTURE_COORD_ARRAY ); - glDisableClientState( GL_COLOR_ARRAY ); - - // Disable texturing and blending - glDisable( GL_TEXTURE_2D ); - glDisable( GL_BLEND ); - - // Allow Z-buffer updates again - glDepthMask( GL_TRUE ); -} - - -//======================================================================== -// Fountain geometry specification -//======================================================================== - -#define FOUNTAIN_SIDE_POINTS 14 -#define FOUNTAIN_SWEEP_STEPS 32 - -static const float fountain_side[ FOUNTAIN_SIDE_POINTS*2 ] = { - 1.2f, 0.0f, 1.0f, 0.2f, 0.41f, 0.3f, 0.4f, 0.35f, - 0.4f, 1.95f, 0.41f, 2.0f, 0.8f, 2.2f, 1.2f, 2.4f, - 1.5f, 2.7f, 1.55f,2.95f, 1.6f, 3.0f, 1.0f, 3.0f, - 0.5f, 3.0f, 0.0f, 3.0f -}; - -static const float fountain_normal[ FOUNTAIN_SIDE_POINTS*2 ] = { - 1.0000f, 0.0000f, 0.6428f, 0.7660f, 0.3420f, 0.9397f, 1.0000f, 0.0000f, - 1.0000f, 0.0000f, 0.3420f,-0.9397f, 0.4226f,-0.9063f, 0.5000f,-0.8660f, - 0.7660f,-0.6428f, 0.9063f,-0.4226f, 0.0000f,1.00000f, 0.0000f,1.00000f, - 0.0000f,1.00000f, 0.0000f,1.00000f -}; - - -//======================================================================== -// DrawFountain() - Draw a fountain -//======================================================================== - -void DrawFountain( void ) -{ - static GLuint fountain_list = 0; - double angle; - float x, y; - int m, n; - - // The first time, we build the fountain display list - if( !fountain_list ) - { - // Start recording of a new display list - fountain_list = glGenLists( 1 ); - glNewList( fountain_list, GL_COMPILE_AND_EXECUTE ); - - // Set fountain material - glMaterialfv( GL_FRONT, GL_DIFFUSE, fountain_diffuse ); - glMaterialfv( GL_FRONT, GL_SPECULAR, fountain_specular ); - glMaterialf( GL_FRONT, GL_SHININESS, fountain_shininess ); - - // Build fountain using triangle strips - for( n = 0; n < FOUNTAIN_SIDE_POINTS-1; n ++ ) - { - glBegin( GL_TRIANGLE_STRIP ); - for( m = 0; m <= FOUNTAIN_SWEEP_STEPS; m ++ ) - { - angle = (double) m * (2.0*M_PI/(double)FOUNTAIN_SWEEP_STEPS); - x = (float) cos( angle ); - y = (float) sin( angle ); - - // Draw triangle strip - glNormal3f( x * fountain_normal[ n*2+2 ], - y * fountain_normal[ n*2+2 ], - fountain_normal[ n*2+3 ] ); - glVertex3f( x * fountain_side[ n*2+2 ], - y * fountain_side[ n*2+2 ], - fountain_side[ n*2+3 ] ); - glNormal3f( x * fountain_normal[ n*2 ], - y * fountain_normal[ n*2 ], - fountain_normal[ n*2+1 ] ); - glVertex3f( x * fountain_side[ n*2 ], - y * fountain_side[ n*2 ], - fountain_side[ n*2+1 ] ); - } - glEnd(); - } - - // End recording of display list - glEndList(); - } - else - { - // Playback display list - glCallList( fountain_list ); - } -} - - -//======================================================================== -// TesselateFloor() - Recursive function for building variable tesselated -// floor -//======================================================================== - -void TesselateFloor( float x1, float y1, float x2, float y2, - int recursion ) -{ - float delta, x, y; - - // Last recursion? - if( recursion >= 5 ) - { - delta = 999999.0f; - } - else - { - x = (float) (fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2)); - y = (float) (fabs(y1) < fabs(y2) ? fabs(y1) : fabs(y2)); - delta = x*x + y*y; - } - - // Recurse further? - if( delta < 0.1f ) - { - x = (x1+x2) * 0.5f; - y = (y1+y2) * 0.5f; - TesselateFloor( x1,y1, x, y, recursion + 1 ); - TesselateFloor( x,y1, x2, y, recursion + 1 ); - TesselateFloor( x1, y, x,y2, recursion + 1 ); - TesselateFloor( x, y, x2,y2, recursion + 1 ); - } - else - { - glTexCoord2f( x1*30.0f, y1*30.0f ); - glVertex3f( x1*80.0f, y1*80.0f , 0.0f ); - glTexCoord2f( x2*30.0f, y1*30.0f ); - glVertex3f( x2*80.0f, y1*80.0f , 0.0f ); - glTexCoord2f( x2*30.0f, y2*30.0f ); - glVertex3f( x2*80.0f, y2*80.0f , 0.0f ); - glTexCoord2f( x1*30.0f, y2*30.0f ); - glVertex3f( x1*80.0f, y2*80.0f , 0.0f ); - } -} - - -//======================================================================== -// DrawFloor() - Draw floor. We builde the floor recursively, and let the -// tesselation in the centre (near x,y=0,0) be high, while the selleation -// around the edges be low. -//======================================================================== - -void DrawFloor( void ) -{ - static GLuint floor_list = 0; - - // Select floor texture - if( !wireframe ) - { - glEnable( GL_TEXTURE_2D ); - glBindTexture( GL_TEXTURE_2D, floor_tex_id ); - } - - // The first time, we build the floor display list - if( !floor_list ) - { - // Start recording of a new display list - floor_list = glGenLists( 1 ); - glNewList( floor_list, GL_COMPILE_AND_EXECUTE ); - - // Set floor material - glMaterialfv( GL_FRONT, GL_DIFFUSE, floor_diffuse ); - glMaterialfv( GL_FRONT, GL_SPECULAR, floor_specular ); - glMaterialf( GL_FRONT, GL_SHININESS, floor_shininess ); - - // Draw floor as a bunch of triangle strips (high tesselation - // improves lighting) - glNormal3f( 0.0f, 0.0f, 1.0f ); - glBegin( GL_QUADS ); - TesselateFloor( -1.0f,-1.0f, 0.0f,0.0f, 0 ); - TesselateFloor( 0.0f,-1.0f, 1.0f,0.0f, 0 ); - TesselateFloor( 0.0f, 0.0f, 1.0f,1.0f, 0 ); - TesselateFloor( -1.0f, 0.0f, 0.0f,1.0f, 0 ); - glEnd(); - - // End recording of display list - glEndList(); - } - else - { - // Playback display list - glCallList( floor_list ); - } - - glDisable( GL_TEXTURE_2D ); - -} - - -//======================================================================== -// SetupLights() - Position and configure light sources -//======================================================================== - -void SetupLights( void ) -{ - float l1pos[4], l1amb[4], l1dif[4], l1spec[4]; - float l2pos[4], l2amb[4], l2dif[4], l2spec[4]; - - // Set light source 1 parameters - l1pos[0] = 0.0f; l1pos[1] = -9.0f; l1pos[2] = 8.0f; l1pos[3] = 1.0f; - l1amb[0] = 0.2f; l1amb[1] = 0.2f; l1amb[2] = 0.2f; l1amb[3] = 1.0f; - l1dif[0] = 0.8f; l1dif[1] = 0.4f; l1dif[2] = 0.2f; l1dif[3] = 1.0f; - l1spec[0] = 1.0f; l1spec[1] = 0.6f; l1spec[2] = 0.2f; l1spec[3] = 0.0f; - - // Set light source 2 parameters - l2pos[0] = -15.0f; l2pos[1] = 12.0f; l2pos[2] = 1.5f; l2pos[3] = 1.0f; - l2amb[0] = 0.0f; l2amb[1] = 0.0f; l2amb[2] = 0.0f; l2amb[3] = 1.0f; - l2dif[0] = 0.2f; l2dif[1] = 0.4f; l2dif[2] = 0.8f; l2dif[3] = 1.0f; - l2spec[0] = 0.2f; l2spec[1] = 0.6f; l2spec[2] = 1.0f; l2spec[3] = 0.0f; - - // Configure light sources in OpenGL - glLightfv( GL_LIGHT1, GL_POSITION, l1pos ); - glLightfv( GL_LIGHT1, GL_AMBIENT, l1amb ); - glLightfv( GL_LIGHT1, GL_DIFFUSE, l1dif ); - glLightfv( GL_LIGHT1, GL_SPECULAR, l1spec ); - glLightfv( GL_LIGHT2, GL_POSITION, l2pos ); - glLightfv( GL_LIGHT2, GL_AMBIENT, l2amb ); - glLightfv( GL_LIGHT2, GL_DIFFUSE, l2dif ); - glLightfv( GL_LIGHT2, GL_SPECULAR, l2spec ); - glLightfv( GL_LIGHT3, GL_POSITION, glow_pos ); - glLightfv( GL_LIGHT3, GL_DIFFUSE, glow_color ); - glLightfv( GL_LIGHT3, GL_SPECULAR, glow_color ); - - // Enable light sources - glEnable( GL_LIGHT1 ); - glEnable( GL_LIGHT2 ); - glEnable( GL_LIGHT3 ); -} - - -//======================================================================== -// Draw() - Main rendering function -//======================================================================== - -void Draw( double t ) -{ - double xpos, ypos, zpos, angle_x, angle_y, angle_z; - static double t_old = 0.0; - float dt; - - // Calculate frame-to-frame delta time - dt = (float)(t-t_old); - t_old = t; - - // Setup viewport - glViewport( 0, 0, width, height ); - - // Clear color and Z-buffer - glClearColor( 0.1f, 0.1f, 0.1f, 1.0f ); - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - - // Setup projection - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - gluPerspective( 65.0, (double)width/(double)height, 1.0, 60.0 ); - - // Setup camera - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - - // Rotate camera - angle_x = 90.0 - 10.0; - angle_y = 10.0 * sin( 0.3 * t ); - angle_z = 10.0 * t; - glRotated( -angle_x, 1.0, 0.0, 0.0 ); - glRotated( -angle_y, 0.0, 1.0, 0.0 ); - glRotated( -angle_z, 0.0, 0.0, 1.0 ); - - // Translate camera - xpos = 15.0 * sin( (M_PI/180.0) * angle_z ) + - 2.0 * sin( (M_PI/180.0) * 3.1 * t ); - ypos = -15.0 * cos( (M_PI/180.0) * angle_z ) + - 2.0 * cos( (M_PI/180.0) * 2.9 * t ); - zpos = 4.0 + 2.0 * cos( (M_PI/180.0) * 4.9 * t ); - glTranslated( -xpos, -ypos, -zpos ); - - // Enable face culling - glFrontFace( GL_CCW ); - glCullFace( GL_BACK ); - glEnable( GL_CULL_FACE ); - - // Enable lighting - SetupLights(); - glEnable( GL_LIGHTING ); - - // Enable fog (dim details far away) - glEnable( GL_FOG ); - glFogi( GL_FOG_MODE, GL_EXP ); - glFogf( GL_FOG_DENSITY, 0.05f ); - glFogfv( GL_FOG_COLOR, fog_color ); - - // Draw floor - DrawFloor(); - - // Enable Z-buffering - glEnable( GL_DEPTH_TEST ); - glDepthFunc( GL_LEQUAL ); - glDepthMask( GL_TRUE ); - - // Draw fountain - DrawFountain(); - - // Disable fog & lighting - glDisable( GL_LIGHTING ); - glDisable( GL_FOG ); - - // Draw all particles (must be drawn after all solid objects have been - // drawn!) - DrawParticles( t, dt ); - - // Z-buffer not needed anymore - glDisable( GL_DEPTH_TEST ); -} - - -//======================================================================== -// Resize() - GLFW window resize callback function -//======================================================================== - -void GLFWCALL Resize( int x, int y ) -{ - width = x; - height = y > 0 ? y : 1; // Prevent division by zero in aspect calc. -} - - -//======================================================================== -// Input callback functions -//======================================================================== - -void GLFWCALL KeyFun( int key, int action ) -{ - if( action == GLFW_PRESS ) - { - switch( key ) - { - case GLFW_KEY_ESC: - running = 0; - break; - case 'W': - wireframe = !wireframe; - glPolygonMode( GL_FRONT_AND_BACK, - wireframe ? GL_LINE : GL_FILL ); - break; - default: - break; - } - } -} - - -//======================================================================== -// PhysicsThreadFun() - Thread for updating particle physics -//======================================================================== - -void GLFWCALL PhysicsThreadFun( void *arg ) -{ - while( running ) - { - // Lock mutex - glfwLockMutex( thread_sync.particles_lock ); - - // Wait for particle drawing to be done - while( running && thread_sync.p_frame > thread_sync.d_frame ) - { - glfwWaitCond( thread_sync.d_done, thread_sync.particles_lock, - 0.1 ); - } - - // No longer running? - if( !running ) - { - break; - } - - // Update particles - ParticleEngine( thread_sync.t, thread_sync.dt ); - - // Update frame counter - thread_sync.p_frame ++; - - // Unlock mutex and signal drawing thread - glfwUnlockMutex( thread_sync.particles_lock ); - glfwSignalCond( thread_sync.p_done ); - } -} - - -//======================================================================== -// main() -//======================================================================== - -double t0, t; -int frames, benchmark; -void iteration(){ - // Get frame time - t = glfwGetTime() - t0; - - // Draw... - Draw( t ); - - // Swap buffers - glfwSwapBuffers(); - - // Check if window was closed - running = running && glfwGetWindowParam( GLFW_OPENED ); - - // Increase frame count - frames ++; - - // End of benchmark? - if( benchmark && t >= 60.0 ) - { - running = 0; - } -} - -int main( int argc, char **argv ) -{ - int i; - GLFWthread physics_thread = 0; - - // Use multithreading by default, but don't benchmark - multithreading = 1; - benchmark = 0; - - // Check command line arguments - for( i = 1; i < argc; i ++ ) - { - // Use benchmarking? - if( strcmp( argv[i], "-b" ) == 0 ) - { - benchmark = 1; - } - - // Force multithreading off? - else if( strcmp( argv[i], "-s" ) == 0 ) - { - multithreading = 0; - } - - // With a Finder launch on Mac OS X we get a bogus -psn_0_46268417 - // kind of argument (actual numbers vary). Ignore it. - else if( strncmp( argv[i], "-psn_", 5) == 0 ); - - // Usage - else - { - if( strcmp( argv[i], "-?" ) != 0 ) - { - printf( "Unknonwn option %s\n\n", argv[ i ] ); - } - printf( "Usage: %s [options]\n", argv[ 0 ] ); - printf( "\n"); - printf( "Options:\n" ); - printf( " -b Benchmark (run program for 60 s)\n" ); - printf( " -s Run program as single thread (default is to use two threads)\n" ); - printf( " -? Display this text\n" ); - printf( "\n"); - printf( "Program runtime controls:\n" ); - printf( " w Toggle wireframe mode\n" ); - printf( " ESC Exit program\n" ); - exit( 0 ); - } - } - - // Initialize GLFW - if( !glfwInit() ) - { - fprintf( stderr, "Failed to initialize GLFW\n" ); - exit( EXIT_FAILURE ); - } - - // Open OpenGL fullscreen window - if( !glfwOpenWindow( WIDTH, HEIGHT, 0,0,0,0, 16,0, GLFW_FULLSCREEN ) ) - { - fprintf( stderr, "Failed to open GLFW window\n" ); - glfwTerminate(); - exit( EXIT_FAILURE ); - } - - // Set window title - glfwSetWindowTitle( "Particle engine" ); - - // Disable VSync (we want to get as high FPS as possible!) - glfwSwapInterval( 0 ); - - // Window resize callback function - glfwSetWindowSizeCallback( Resize ); - - // Set keyboard input callback function - glfwSetKeyCallback( KeyFun ); - - // Upload particle texture - glGenTextures( 1, &particle_tex_id ); - glBindTexture( GL_TEXTURE_2D, particle_tex_id ); - glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, P_TEX_WIDTH, P_TEX_HEIGHT, - 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, particle_texture ); - - // Upload floor texture - glGenTextures( 1, &floor_tex_id ); - glBindTexture( GL_TEXTURE_2D, floor_tex_id ); - glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, F_TEX_WIDTH, F_TEX_HEIGHT, - 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, floor_texture ); - - // Check if we have GL_EXT_separate_specular_color, and if so use it - if( glfwExtensionSupported( "GL_EXT_separate_specular_color" ) ) - { - glLightModeli( GL_LIGHT_MODEL_COLOR_CONTROL_EXT, - GL_SEPARATE_SPECULAR_COLOR_EXT ); - } - - // Set filled polygon mode as default (not wireframe) - glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - wireframe = 0; - - // Clear particle system - for( i = 0; i < MAX_PARTICLES; i ++ ) - { - particles[ i ].active = 0; - } - min_age = 0.0f; - - // Set "running" flag - running = 1; - - // Set initial times - thread_sync.t = 0.0; - thread_sync.dt = 0.001f; - - // Init threading - if( multithreading ) - { - thread_sync.p_frame = 0; - thread_sync.d_frame = 0; - thread_sync.particles_lock = glfwCreateMutex(); - thread_sync.p_done = glfwCreateCond(); - thread_sync.d_done = glfwCreateCond(); - physics_thread = glfwCreateThread( PhysicsThreadFun, NULL ); - } - - // Main loop - t0 = glfwGetTime(); - frames = 0; -#ifdef EMSCRIPTEN - emscripten_set_main_loop (iteration, 0, 1); -#else - // Main loop - while( running ) - { - iteration(); - } -#endif - t = glfwGetTime() - t0; - - // Wait for particle physics thread to die - if( multithreading ) - { - glfwWaitThread( physics_thread, GLFW_WAIT ); - } - - // Display profiling information - printf( "%d frames in %.2f seconds = %.1f FPS", frames, t, - (double)frames / t ); - printf( " (multithreading %s)\n", multithreading ? "on" : "off" ); - - // Terminate OpenGL - glfwTerminate(); - - exit( EXIT_SUCCESS ); -} - diff --git a/tests/glfw/pong3d.c b/tests/glfw/pong3d.c deleted file mode 100644 index 1f136c93ffa83..0000000000000 --- a/tests/glfw/pong3d.c +++ /dev/null @@ -1,862 +0,0 @@ -//======================================================================== -// This is a small test application for GLFW. -// This is an OpenGL port of the famous "PONG" game (the first computer -// game ever?). It is very simple, and could be improved alot. It was -// created in order to show off the gaming capabilities of GLFW. -//======================================================================== - -#include -#include -#include -#include - -#ifdef EMSCRIPTEN -#include -#endif - -//======================================================================== -// Constants -//======================================================================== - -// Screen resolution -#define WIDTH 640 -#define HEIGHT 480 - -// Player size (units) -#define PLAYER_XSIZE 0.05f -#define PLAYER_YSIZE 0.15f - -// Ball size (units) -#define BALL_SIZE 0.02f - -// Maximum player movement speed (units / second) -#define MAX_SPEED 1.5f - -// Player movement acceleration (units / seconds^2) -#define ACCELERATION 4.0f - -// Player movement deceleration (units / seconds^2) -#define DECELERATION 2.0f - -// Ball movement speed (units / second) -#define BALL_SPEED 0.4f - -// Menu options -#define MENU_NONE 0 -#define MENU_PLAY 1 -#define MENU_QUIT 2 - -// Game events -#define NOBODY_WINS 0 -#define PLAYER1_WINS 1 -#define PLAYER2_WINS 2 - -// Winner ID -#define NOBODY 0 -#define PLAYER1 1 -#define PLAYER2 2 - -// Camera positions -#define CAMERA_CLASSIC 0 -#define CAMERA_ABOVE 1 -#define CAMERA_SPECTATOR 2 -#define CAMERA_DEFAULT CAMERA_CLASSIC - - -//======================================================================== -// Textures -//======================================================================== - -#define TEX_TITLE 0 -#define TEX_MENU 1 -#define TEX_INSTR 2 -#define TEX_WINNER1 3 -#define TEX_WINNER2 4 -#define TEX_FIELD 5 -#define NUM_TEXTURES 6 - -// Texture names -char * tex_name[ NUM_TEXTURES ] = { - "pong3d_title.tga", - "pong3d_menu.tga", - "pong3d_instr.tga", - "pong3d_winner1.tga", - "pong3d_winner2.tga", - "pong3d_field.tga" -}; - -// OpenGL texture object IDs -GLuint tex_id[ NUM_TEXTURES ]; - - -//======================================================================== -// Global variables -//======================================================================== - -// Display information -int width, height; - -// Frame information -double thistime, oldtime, dt, starttime; - -// Camera information -int camerapos; - -// Player information -struct { - double ypos; // -1.0 to +1.0 - double yspeed; // -MAX_SPEED to +MAX_SPEED -} player1, player2; - -// Ball information -struct { - double xpos, ypos; - double xspeed, yspeed; -} ball; - -// And the winner is... -int winner; - -// Lighting configuration -const GLfloat env_ambient[4] = {1.0f,1.0f,1.0f,1.0f}; -const GLfloat light1_position[4] = {-3.0f,3.0f,2.0f,1.0f}; -const GLfloat light1_diffuse[4] = {1.0f,1.0f,1.0f,0.0f}; -const GLfloat light1_ambient[4] = {0.0f,0.0f,0.0f,0.0f}; - -// Object material properties -const GLfloat player1_diffuse[4] = {1.0f,0.3f,0.3f,1.0f}; -const GLfloat player1_ambient[4] = {0.3f,0.1f,0.0f,1.0f}; -const GLfloat player2_diffuse[4] = {0.3f,1.0f,0.3f,1.0f}; -const GLfloat player2_ambient[4] = {0.1f,0.3f,0.1f,1.0f}; -const GLfloat ball_diffuse[4] = {1.0f,1.0f,0.5f,1.0f}; -const GLfloat ball_ambient[4] = {0.3f,0.3f,0.1f,1.0f}; -const GLfloat border_diffuse[4] = {0.3f,0.3f,1.0f,1.0f}; -const GLfloat border_ambient[4] = {0.1f,0.1f,0.3f,1.0f}; -const GLfloat floor_diffuse[4] = {1.0f,1.0f,1.0f,1.0f}; -const GLfloat floor_ambient[4] = {0.3f,0.3f,0.3f,1.0f}; - - -//======================================================================== -// LoadTextures() - Load textures from disk and upload to OpenGL card -//======================================================================== - -GLboolean LoadTextures( void ) -{ - int i; - - // Generate texture objects - glGenTextures( NUM_TEXTURES, tex_id ); - - // Load textures - for( i = 0; i < NUM_TEXTURES; i ++ ) - { - // Select texture object - glBindTexture( GL_TEXTURE_2D, tex_id[ i ] ); - - // Set texture parameters - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - - // Upload texture from file to texture memory - if( !glfwLoadTexture2D( tex_name[ i ], 0 ) ) - { - fprintf( stderr, "Failed to load texture %s\n", tex_name[ i ] ); - return GL_FALSE; - } - } - - return GL_TRUE; -} - - -//======================================================================== -// DrawImage() - Draw a 2D image as a texture -//======================================================================== - -void DrawImage( int texnum, float x1, float x2, float y1, float y2 ) -{ - glEnable( GL_TEXTURE_2D ); - glBindTexture( GL_TEXTURE_2D, tex_id[ texnum ] ); - glBegin( GL_QUADS ); - glTexCoord2f( 0.0f, 1.0f ); - glVertex2f( x1, y1 ); - glTexCoord2f( 1.0f, 1.0f ); - glVertex2f( x2, y1 ); - glTexCoord2f( 1.0f, 0.0f ); - glVertex2f( x2, y2 ); - glTexCoord2f( 0.0f, 0.0f ); - glVertex2f( x1, y2 ); - glEnd(); - glDisable( GL_TEXTURE_2D ); -} - - -//======================================================================== -// GameMenu() - Game menu (returns menu option) -//======================================================================== - -int GameMenu( void ) -{ - int option; - - // Enable sticky keys - glfwEnable( GLFW_STICKY_KEYS ); - - // Wait for a game menu key to be pressed - do - { - // Get window size - glfwGetWindowSize( &width, &height ); - - // Set viewport - glViewport( 0, 0, width, height ); - - // Clear display - glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); - glClear( GL_COLOR_BUFFER_BIT ); - - // Setup projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f ); - - // Setup modelview matrix - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - - // Display title - glColor3f( 1.0f, 1.0f, 1.0f ); - DrawImage( TEX_TITLE, 0.1f, 0.9f, 0.0f, 0.3f ); - - // Display menu - glColor3f( 1.0f, 1.0f, 0.0f ); - DrawImage( TEX_MENU, 0.38f, 0.62f, 0.35f, 0.5f ); - - // Display instructions - glColor3f( 0.0f, 1.0f, 1.0f ); - DrawImage( TEX_INSTR, 0.32f, 0.68f, 0.65f, 0.85f ); - - // Swap buffers - glfwSwapBuffers(); - - // Check for keys - if( glfwGetKey( 'Q' ) || !glfwGetWindowParam( GLFW_OPENED ) ) - { - option = MENU_QUIT; - } - else if( glfwGetKey( GLFW_KEY_F1 ) ) - { - option = MENU_PLAY; - } - else - { - option = MENU_NONE; - } - - // To avoid horrible busy waiting, sleep for at least 20 ms - glfwSleep( 0.02 ); - } - while( option == MENU_NONE ); - - // Disable sticky keys - glfwDisable( GLFW_STICKY_KEYS ); - - return option; -} - - -//======================================================================== -// NewGame() - Initialize a new game -//======================================================================== - -void NewGame( void ) -{ - // Frame information - starttime = thistime = glfwGetTime(); - - // Camera information - camerapos = CAMERA_DEFAULT; - - // Player 1 information - player1.ypos = 0.0; - player1.yspeed = 0.0; - - // Player 2 information - player2.ypos = 0.0; - player2.yspeed = 0.0; - - // Ball information - ball.xpos = -1.0 + PLAYER_XSIZE; - ball.ypos = player1.ypos; - ball.xspeed = 1.0; - ball.yspeed = 1.0; -} - - -//======================================================================== -// PlayerControl() - Player control -//======================================================================== - -void PlayerControl( void ) -{ - float joy1pos[ 2 ], joy2pos[ 2 ]; - - // Get joystick X & Y axis positions - glfwGetJoystickPos( GLFW_JOYSTICK_1, joy1pos, 2 ); - glfwGetJoystickPos( GLFW_JOYSTICK_2, joy2pos, 2 ); - - // Player 1 control - if( glfwGetKey( 'A' ) || joy1pos[ 1 ] > 0.2f ) - { - player1.yspeed += dt * ACCELERATION; - if( player1.yspeed > MAX_SPEED ) - { - player1.yspeed = MAX_SPEED; - } - } - else if( glfwGetKey( 'Z' ) || joy1pos[ 1 ] < -0.2f ) - { - player1.yspeed -= dt * ACCELERATION; - if( player1.yspeed < -MAX_SPEED ) - { - player1.yspeed = -MAX_SPEED; - } - } - else - { - player1.yspeed /= exp( DECELERATION * dt ); - } - - // Player 2 control - if( glfwGetKey( 'K' ) || joy2pos[ 1 ] > 0.2f ) - { - player2.yspeed += dt * ACCELERATION; - if( player2.yspeed > MAX_SPEED ) - { - player2.yspeed = MAX_SPEED; - } - } - else if( glfwGetKey( 'M' ) || joy2pos[ 1 ] < -0.2f ) - { - player2.yspeed -= dt * ACCELERATION; - if( player2.yspeed < -MAX_SPEED ) - { - player2.yspeed = -MAX_SPEED; - } - } - else - { - player2.yspeed /= exp( DECELERATION * dt ); - } - - // Update player 1 position - player1.ypos += dt * player1.yspeed; - if( player1.ypos > 1.0 - PLAYER_YSIZE ) - { - player1.ypos = 1.0 - PLAYER_YSIZE; - player1.yspeed = 0.0; - } - else if( player1.ypos < -1.0 + PLAYER_YSIZE ) - { - player1.ypos = -1.0 + PLAYER_YSIZE; - player1.yspeed = 0.0; - } - - // Update player 2 position - player2.ypos += dt * player2.yspeed; - if( player2.ypos > 1.0 - PLAYER_YSIZE ) - { - player2.ypos = 1.0 - PLAYER_YSIZE; - player2.yspeed = 0.0; - } - else if( player2.ypos < -1.0 + PLAYER_YSIZE ) - { - player2.ypos = -1.0 + PLAYER_YSIZE; - player2.yspeed = 0.0; - } -} - - -//======================================================================== -// BallControl() - Ball control -//======================================================================== - -int BallControl( void ) -{ - int event; - double ballspeed; - - // Calculate new ball speed - ballspeed = BALL_SPEED * (1.0 + 0.02*(thistime-starttime)); - ball.xspeed = ball.xspeed > 0 ? ballspeed : -ballspeed; - ball.yspeed = ball.yspeed > 0 ? ballspeed : -ballspeed; - ball.yspeed *= 0.74321; - - // Update ball position - ball.xpos += dt * ball.xspeed; - ball.ypos += dt * ball.yspeed; - - // Did the ball hit a top/bottom wall? - if( ball.ypos >= 1.0 ) - { - ball.ypos = 2.0 - ball.ypos; - ball.yspeed = -ball.yspeed; - } - else if( ball.ypos <= -1.0 ) - { - ball.ypos = -2.0 - ball.ypos; - ball.yspeed = -ball.yspeed; - } - - // Did the ball hit/miss a player? - event = NOBODY_WINS; - - // Is the ball entering the player 1 goal? - if( ball.xpos < -1.0 + PLAYER_XSIZE ) - { - // Did player 1 catch the ball? - if( ball.ypos > (player1.ypos-PLAYER_YSIZE) && - ball.ypos < (player1.ypos+PLAYER_YSIZE) ) - { - ball.xpos = -2.0 + 2.0*PLAYER_XSIZE - ball.xpos; - ball.xspeed = -ball.xspeed; - } - else - { - event = PLAYER2_WINS; - } - } - - // Is the ball entering the player 2 goal? - if( ball.xpos > 1.0 - PLAYER_XSIZE ) - { - // Did player 2 catch the ball? - if( ball.ypos > (player2.ypos-PLAYER_YSIZE) && - ball.ypos < (player2.ypos+PLAYER_YSIZE) ) - { - ball.xpos = 2.0 - 2.0*PLAYER_XSIZE - ball.xpos; - ball.xspeed = -ball.xspeed; - } - else - { - event = PLAYER1_WINS; - } - } - - return event; -} - - -//======================================================================== -// DrawBox() - Draw a 3D box -//======================================================================== - -#define TEX_SCALE 4.0f - - -void DrawBox( float x1, float y1, float z1, float x2, float y2, float z2 ) -{ - // Draw six sides of a cube - glBegin( GL_QUADS ); - // Side 1 (down) - glNormal3f( 0.0f, 0.0f, -1.0f ); - glTexCoord2f( 0.0f, 0.0f ); - glVertex3f( x1,y2,z1 ); - glTexCoord2f( TEX_SCALE, 0.0f ); - glVertex3f( x2,y2,z1 ); - glTexCoord2f( TEX_SCALE, TEX_SCALE ); - glVertex3f( x2,y1,z1 ); - glTexCoord2f( 0.0f, TEX_SCALE ); - glVertex3f( x1,y1,z1 ); - // Side 2 (up) - glNormal3f( 0.0f, 0.0f, 1.0f ); - glTexCoord2f( 0.0f, 0.0f ); - glVertex3f( x1,y1,z2 ); - glTexCoord2f( TEX_SCALE, 0.0f ); - glVertex3f( x2,y1,z2 ); - glTexCoord2f( TEX_SCALE, TEX_SCALE ); - glVertex3f( x2,y2,z2 ); - glTexCoord2f( 0.0f, TEX_SCALE ); - glVertex3f( x1,y2,z2 ); - // Side 3 (backward) - glNormal3f( 0.0f, -1.0f, 0.0f ); - glTexCoord2f( 0.0f, 0.0f ); - glVertex3f( x1,y1,z1 ); - glTexCoord2f( TEX_SCALE, 0.0f ); - glVertex3f( x2,y1,z1 ); - glTexCoord2f( TEX_SCALE, TEX_SCALE ); - glVertex3f( x2,y1,z2 ); - glTexCoord2f( 0.0f, TEX_SCALE ); - glVertex3f( x1,y1,z2 ); - // Side 4 (forward) - glNormal3f( 0.0f, 1.0f, 0.0f ); - glTexCoord2f( 0.0f, 0.0f ); - glVertex3f( x1,y2,z2 ); - glTexCoord2f( TEX_SCALE, 0.0f ); - glVertex3f( x2,y2,z2 ); - glTexCoord2f( TEX_SCALE, TEX_SCALE ); - glVertex3f( x2,y2,z1 ); - glTexCoord2f( 0.0f, TEX_SCALE ); - glVertex3f( x1,y2,z1 ); - // Side 5 (left) - glNormal3f( -1.0f, 0.0f, 0.0f ); - glTexCoord2f( 0.0f, 0.0f ); - glVertex3f( x1,y1,z2 ); - glTexCoord2f( TEX_SCALE, 0.0f ); - glVertex3f( x1,y2,z2 ); - glTexCoord2f( TEX_SCALE, TEX_SCALE ); - glVertex3f( x1,y2,z1 ); - glTexCoord2f( 0.0f, TEX_SCALE ); - glVertex3f( x1,y1,z1 ); - // Side 6 (right) - glNormal3f( 1.0f, 0.0f, 0.0f ); - glTexCoord2f( 0.0f, 0.0f ); - glVertex3f( x2,y1,z1 ); - glTexCoord2f( TEX_SCALE, 0.0f ); - glVertex3f( x2,y2,z1 ); - glTexCoord2f( TEX_SCALE, TEX_SCALE ); - glVertex3f( x2,y2,z2 ); - glTexCoord2f( 0.0f, TEX_SCALE ); - glVertex3f( x2,y1,z2 ); - glEnd(); -} - - -//======================================================================== -// UpdateDisplay() - Draw graphics (all game related OpenGL stuff goes -// here) -//======================================================================== - -void UpdateDisplay( void ) -{ - // Get window size - glfwGetWindowSize( &width, &height ); - - // Set viewport - glViewport( 0, 0, width, height ); - - // Clear display - glClearColor( 0.02f, 0.02f, 0.02f, 0.0f ); - glClearDepth( 1.0f ); - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - - // Setup projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - gluPerspective( - 55.0f, // Angle of view - (GLfloat)width/(GLfloat)height, // Aspect - 1.0f, // Near Z - 100.0f // Far Z - ); - - // Setup modelview matrix - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - switch( camerapos ) - { - default: - case CAMERA_CLASSIC: - gluLookAt( - 0.0f, 0.0f, 2.5f, - 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f - ); - break; - case CAMERA_ABOVE: - gluLookAt( - 0.0f, 0.0f, 2.5f, - (float)ball.xpos, (float)ball.ypos, 0.0f, - 0.0f, 1.0f, 0.0f - ); - break; - case CAMERA_SPECTATOR: - gluLookAt( - 0.0f, -2.0, 1.2f, - (float)ball.xpos, (float)ball.ypos, 0.0f, - 0.0f, 0.0f, 1.0f - ); - break; - } - - // Enable depth testing - glEnable( GL_DEPTH_TEST ); - glDepthFunc( GL_LEQUAL ); - - // Enable lighting - glEnable( GL_LIGHTING ); - glLightModelfv( GL_LIGHT_MODEL_AMBIENT, env_ambient ); - glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE ); - glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE ); - glLightfv( GL_LIGHT1, GL_POSITION, light1_position ); - glLightfv( GL_LIGHT1, GL_DIFFUSE, light1_diffuse ); - glLightfv( GL_LIGHT1, GL_AMBIENT, light1_ambient ); - glEnable( GL_LIGHT1 ); - - // Front face is counter-clock-wise - glFrontFace( GL_CCW ); - - // Enable face culling (not necessary, but speeds up rendering) - glCullFace( GL_BACK ); - glEnable( GL_CULL_FACE ); - - // Draw Player 1 - glMaterialfv( GL_FRONT, GL_DIFFUSE, player1_diffuse ); - glMaterialfv( GL_FRONT, GL_AMBIENT, player1_ambient ); - DrawBox( -1.f, (GLfloat)player1.ypos-PLAYER_YSIZE, 0.f, - -1.f+PLAYER_XSIZE, (GLfloat)player1.ypos+PLAYER_YSIZE, 0.1f ); - - // Draw Player 2 - glMaterialfv( GL_FRONT, GL_DIFFUSE, player2_diffuse ); - glMaterialfv( GL_FRONT, GL_AMBIENT, player2_ambient ); - DrawBox( 1.f-PLAYER_XSIZE, (GLfloat)player2.ypos-PLAYER_YSIZE, 0.f, - 1.f, (GLfloat)player2.ypos+PLAYER_YSIZE, 0.1f ); - - // Draw Ball - glMaterialfv( GL_FRONT, GL_DIFFUSE, ball_diffuse ); - glMaterialfv( GL_FRONT, GL_AMBIENT, ball_ambient ); - DrawBox( (GLfloat)ball.xpos-BALL_SIZE, (GLfloat)ball.ypos-BALL_SIZE, 0.f, - (GLfloat)ball.xpos+BALL_SIZE, (GLfloat)ball.ypos+BALL_SIZE, BALL_SIZE*2 ); - - // Top game field border - glMaterialfv( GL_FRONT, GL_DIFFUSE, border_diffuse ); - glMaterialfv( GL_FRONT, GL_AMBIENT, border_ambient ); - DrawBox( -1.1f, 1.0f, 0.0f, 1.1f, 1.1f, 0.1f ); - // Bottom game field border - glColor3f( 0.0f, 0.0f, 0.7f ); - DrawBox( -1.1f, -1.1f, 0.0f, 1.1f, -1.0f, 0.1f ); - // Left game field border - DrawBox( -1.1f, -1.0f, 0.0f, -1.0f, 1.0f, 0.1f ); - // Left game field border - DrawBox( 1.0f, -1.0f, 0.0f, 1.1f, 1.0f, 0.1f ); - - // Enable texturing - glEnable( GL_TEXTURE_2D ); - glBindTexture( GL_TEXTURE_2D, tex_id[ TEX_FIELD ] ); - - // Game field floor - glMaterialfv( GL_FRONT, GL_DIFFUSE, floor_diffuse ); - glMaterialfv( GL_FRONT, GL_AMBIENT, floor_ambient ); - DrawBox( -1.01f, -1.01f, -0.01f, 1.01f, 1.01f, 0.0f ); - - // Disable texturing - glDisable( GL_TEXTURE_2D ); - - // Disable face culling - glDisable( GL_CULL_FACE ); - - // Disable lighting - glDisable( GL_LIGHTING ); - - // Disable depth testing - glDisable( GL_DEPTH_TEST ); -} - - -//======================================================================== -// GameOver() -//======================================================================== - -void GameOver( void ) -{ - // Enable sticky keys - glfwEnable( GLFW_STICKY_KEYS ); - - // Until the user presses ESC or SPACE - while( !glfwGetKey( GLFW_KEY_ESC ) && !glfwGetKey( ' ' ) && - glfwGetWindowParam( GLFW_OPENED ) ) - { - // Draw display - UpdateDisplay(); - - // Setup projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f ); - - // Setup modelview matrix - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - - // Enable blending - glEnable( GL_BLEND ); - - // Dim background - glBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA ); - glColor4f( 0.3f, 0.3f, 0.3f, 0.3f ); - glBegin( GL_QUADS ); - glVertex2f( 0.0f, 0.0f ); - glVertex2f( 1.0f, 0.0f ); - glVertex2f( 1.0f, 1.0f ); - glVertex2f( 0.0f, 1.0f ); - glEnd(); - - // Display winner text - glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_COLOR ); - if( winner == PLAYER1 ) - { - glColor4f( 1.0f, 0.5f, 0.5f, 1.0f ); - DrawImage( TEX_WINNER1, 0.35f, 0.65f, 0.46f, 0.54f ); - } - else if( winner == PLAYER2 ) - { - glColor4f( 0.5f, 1.0f, 0.5f, 1.0f ); - DrawImage( TEX_WINNER2, 0.35f, 0.65f, 0.46f, 0.54f ); - } - - // Disable blending - glDisable( GL_BLEND ); - - // Swap buffers - glfwSwapBuffers(); - } - - // Disable sticky keys - glfwDisable( GLFW_STICKY_KEYS ); -} - - -//======================================================================== -// GameLoop() - Game loop -//======================================================================== - -int playing, event; - -void iteration(){ - // Frame timer - oldtime = thistime; - thistime = glfwGetTime(); - dt = thistime - oldtime; - - // Get user input and update player positions - PlayerControl(); - - // Move the ball, and check if a player hits/misses the ball - event = BallControl(); - - // Did we have a winner? - switch( event ) - { - case PLAYER1_WINS: - winner = PLAYER1; - playing = GL_FALSE; - break; - case PLAYER2_WINS: - winner = PLAYER2; - playing = GL_FALSE; - break; - default: - break; - } - - // Did the user press ESC? - if( glfwGetKey( GLFW_KEY_ESC ) ) - { - playing = GL_FALSE; - } - - // Did the user change camera view? - if( glfwGetKey( '1' ) ) - { - camerapos = CAMERA_CLASSIC; - } - else if( glfwGetKey( '2' ) ) - { - camerapos = CAMERA_ABOVE; - } - else if( glfwGetKey( '3' ) ) - { - camerapos = CAMERA_SPECTATOR; - } - - // Draw display - UpdateDisplay(); - - // Swap buffers - glfwSwapBuffers(); -} - -void GameLoop( void ) -{ - int menuoption; - - // Initialize a new game - NewGame(); - - // Enable sticky keys - glfwEnable( GLFW_STICKY_KEYS ); - - // Loop until the game ends - playing = GL_TRUE; - - menuoption = GameMenu(); - - // If the user wants to play, let him... - if( menuoption != MENU_PLAY) - playing = GL_FALSE; - -#ifdef EMSCRIPTEN - emscripten_set_main_loop (iteration, 0, 1); -#else - // Main loop - while( playing && glfwGetWindowParam( GLFW_OPENED ) ) - { - iteration(); - } -#endif - - // Disable sticky keys - glfwDisable( GLFW_STICKY_KEYS ); - - // Show winner - GameOver(); -} - - -//======================================================================== -// main() - Program entry point -//======================================================================== - -int main( void ) -{ - - // Initialize GLFW - if( !glfwInit() ) - { - fprintf( stderr, "Failed to initialize GLFW\n" ); - exit( EXIT_FAILURE ); - } - - // Open OpenGL window - if( !glfwOpenWindow( WIDTH, HEIGHT, 0,0,0,0, 16,0, GLFW_FULLSCREEN ) ) - { - fprintf( stderr, "Failed to open GLFW window\n" ); - glfwTerminate(); - exit( EXIT_FAILURE ); - } - - glfwSwapInterval( 1 ); - - // Load all textures - if( !LoadTextures() ) - { - glfwTerminate(); - exit( EXIT_FAILURE ); - } - - GameLoop(); - - // Unload all textures - if( glfwGetWindowParam( GLFW_OPENED ) ) - { - glDeleteTextures( NUM_TEXTURES, tex_id ); - } - - // Terminate GLFW - glfwTerminate(); - - exit( EXIT_SUCCESS ); -} - diff --git a/tests/glfw/pong3d_field.tga b/tests/glfw/pong3d_field.tga deleted file mode 100644 index cc20bbdb82434faa3bbc01d27fd199d5214c8b2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17816 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 T6XevNs>&3`i95eA{_g(;MdbFK diff --git a/tests/glfw/pong3d_instr.tga b/tests/glfw/pong3d_instr.tga deleted file mode 100644 index 758eb447a97187cef812cb9100aa94631954c256..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21279 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 diff --git a/tests/glfw/pong3d_menu.tga b/tests/glfw/pong3d_menu.tga deleted file mode 100644 index d0d6c5a431687bfd6442e43c3878a9eb905c48b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1835 zcmbVMTawc-5FFd7KrLK{i*bQLe#C)-km6&1*q~+M0-Qi+$_YgGjAbh+zSu1}vefFC z>1kQyjg-Il@=jjMRenoIj~IXChe+&m7gLVsZQ6^Zkej3-2jP$yvZRY#urXlCQ#Jn=lGQ*?msDM%?fom_#3D0WLYd>| zrM8HEH4zdvDSlgLUu?J06w%uHU$F5BH?%^)6{nIMA=d zk04{L6gsNXLvPU$y7bcLR=F~R;{Yz~AoE6761IR~EZy-Sc90#?@jjEKjdZ2xgd?t2 zqtTm)Fw3kYxE=nmQqN{37J-&5_=7y4JqUx5<790bksq4`P6Xm?W2J#gsv94$c80Ep zhB(C(Tcv$%4nwfg>5lD?ncV@L-j6_|Q=WiD2HsmBQ7_k*Bwh}mIAS5_(&Zv)0+JQ*BV=)qzNL$W#l<{{t=av1 zh6fQJ3*Rf(fcY7y8DcVufs`P8r)X65U6x`6n^qTRM5LcL_vtFnz@hK-l+BKK+wK>L@83So!V-2z3xXZm}7`ZB*l$gvAC5tvMEd)H$-L j=(lM?g-Vm}Fwx!OsnJ{IV_$0Jn){}t&ktU$$5s9UqXSX} diff --git a/tests/glfw/pong3d_title.tga b/tests/glfw/pong3d_title.tga deleted file mode 100644 index d0d8e36d74011c25b908647632b4997dc0cf6456..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 106516 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 diff --git a/tests/glfw/pong3d_winner1.tga b/tests/glfw/pong3d_winner1.tga deleted file mode 100644 index f963720c5b897c01b8694a0fb2d76ad617877a7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 861 zcmZvaO-{ow5QV29sw!Ag>q$zL$Sb2xaDZHc?={d~z#x?;&rAh7an>TNM%UG8<_V`T}Av+dQR1Q!U7Qc6{sSH8wNZP39q9qy#b$XF9@I6ez)S<6n zq_ehk;iMZ&fsh(meZGobq4LV7e~pc@d~^GlelDh;wKF}zCi`6*Je6~M>is%9SNEbW LDfk1czN>u!GHiyO diff --git a/tests/glfw/pong3d_winner2.tga b/tests/glfw/pong3d_winner2.tga deleted file mode 100644 index ea8266dea9f6ca7b261f2163b4f2bc4777a59027..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 891 zcmZvbOHRWu5Qe8Asw!Ag>q)E8}th{PDhL`jrJ%{=Jv6BL#k|RH6{>RMJ?8(;O zi#^-HZuV}m>~grW8Ozl^%t9=dzKDzE#2U(`*Z?%X-syv|S(? zK)sHv$a>wtB4Eb?Ma3Y>!sKURS)Tb0r3+%vTaEo6DJm{if#^X&j{?aT=fbk|<~&_O zt+PmDbft=sKHTt?QQd&&`CbHe)uYgASx)wtida}Bc}9?zn%(@SUw-irZBG_CWXznz z=XiOM7P58fg0$VeHnc3XW7$gDg_J8@PnncbAuX(+Ga!3cnA!amNonh?123}NqEvQz zr;kDo0gOh0x+DVBrpbD_p`wQ*Phz^)ltEEbz;t}sX=m;%O{Moj&@6$p=8wfP;J5)? zkhFgfjw0#^%tT0ME$!44Ga|_7pj0Ep>Z9on#mYG5)@84;kMi2DpOfl)jnK+)SAA~d cBD_m`U#oV84}EF9M`aSmW&0a^ddAJZ0j)ZbKmY&$ diff --git a/tests/glfw/splitview.c b/tests/glfw/splitview.c deleted file mode 100644 index bb85a6e7be6f8..0000000000000 --- a/tests/glfw/splitview.c +++ /dev/null @@ -1,525 +0,0 @@ -//======================================================================== -// This is an example program for the GLFW library -// -// The program uses a "split window" view, rendering four views of the -// same scene in one window (e.g. uesful for 3D modelling software). This -// demo uses scissors to separete the four different rendering areas from -// each other. -// -// (If the code seems a little bit strange here and there, it may be -// because I am not a friend of orthogonal projections) -//======================================================================== - -#include -#include -#include -#include - -#ifdef EMSCRIPTEN -#include -#endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - - -//======================================================================== -// Global variables -//======================================================================== - -// Mouse position -static int xpos = 0, ypos = 0; - -// Window size -static int width, height; - -// Active view: 0 = none, 1 = upper left, 2 = upper right, 3 = lower left, -// 4 = lower right -static int active_view = 0; - -// Rotation around each axis -static int rot_x = 0, rot_y = 0, rot_z = 0; - -// Do redraw? -static int do_redraw = 1; - - -//======================================================================== -// Draw a solid torus (use a display list for the model) -//======================================================================== - -#define TORUS_MAJOR 1.5 -#define TORUS_MINOR 0.5 -#define TORUS_MAJOR_RES 32 -#define TORUS_MINOR_RES 32 - -static void drawTorus( void ) -{ - static GLuint torus_list = 0; - int i, j, k; - double s, t, x, y, z, nx, ny, nz, scale, twopi; - - if( !torus_list ) - { - // Start recording displaylist - torus_list = glGenLists( 1 ); - glNewList( torus_list, GL_COMPILE_AND_EXECUTE ); - - // Draw torus - twopi = 2.0 * M_PI; - for( i = 0; i < TORUS_MINOR_RES; i++ ) - { - glBegin( GL_QUAD_STRIP ); - for( j = 0; j <= TORUS_MAJOR_RES; j++ ) - { - for( k = 1; k >= 0; k-- ) - { - s = (i + k) % TORUS_MINOR_RES + 0.5; - t = j % TORUS_MAJOR_RES; - - // Calculate point on surface - x = (TORUS_MAJOR+TORUS_MINOR*cos(s*twopi/TORUS_MINOR_RES))*cos(t*twopi/TORUS_MAJOR_RES); - y = TORUS_MINOR * sin(s * twopi / TORUS_MINOR_RES); - z = (TORUS_MAJOR+TORUS_MINOR*cos(s*twopi/TORUS_MINOR_RES))*sin(t*twopi/TORUS_MAJOR_RES); - - // Calculate surface normal - nx = x - TORUS_MAJOR*cos(t*twopi/TORUS_MAJOR_RES); - ny = y; - nz = z - TORUS_MAJOR*sin(t*twopi/TORUS_MAJOR_RES); - scale = 1.0 / sqrt( nx*nx + ny*ny + nz*nz ); - nx *= scale; - ny *= scale; - nz *= scale; - - glNormal3f( (float)nx, (float)ny, (float)nz ); - glVertex3f( (float)x, (float)y, (float)z ); - } - } - glEnd(); - } - - // Stop recording displaylist - glEndList(); - } - else - { - // Playback displaylist - glCallList( torus_list ); - } -} - - -//======================================================================== -// Draw the scene (a rotating torus) -//======================================================================== - -static void drawScene( void ) -{ - const GLfloat model_diffuse[4] = {1.0f, 0.8f, 0.8f, 1.0f}; - const GLfloat model_specular[4] = {0.6f, 0.6f, 0.6f, 1.0f}; - const GLfloat model_shininess = 20.0f; - - glPushMatrix(); - - // Rotate the object - glRotatef( (GLfloat)rot_x*0.5f, 1.0f, 0.0f, 0.0f ); - glRotatef( (GLfloat)rot_y*0.5f, 0.0f, 1.0f, 0.0f ); - glRotatef( (GLfloat)rot_z*0.5f, 0.0f, 0.0f, 1.0f ); - - // Set model color (used for orthogonal views, lighting disabled) - glColor4fv( model_diffuse ); - - // Set model material (used for perspective view, lighting enabled) - glMaterialfv( GL_FRONT, GL_DIFFUSE, model_diffuse ); - glMaterialfv( GL_FRONT, GL_SPECULAR, model_specular ); - glMaterialf( GL_FRONT, GL_SHININESS, model_shininess ); - - // Draw torus - drawTorus(); - - glPopMatrix(); -} - - -//======================================================================== -// Draw a 2D grid (used for orthogonal views) -//======================================================================== - -static void drawGrid( float scale, int steps ) -{ - int i; - float x, y; - - glPushMatrix(); - - // Set background to some dark bluish grey - glClearColor( 0.05f, 0.05f, 0.2f, 0.0f); - glClear( GL_COLOR_BUFFER_BIT ); - - // Setup modelview matrix (flat XY view) - glLoadIdentity(); - gluLookAt( 0.0, 0.0, 1.0, - 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0 ); - - // We don't want to update the Z-buffer - glDepthMask( GL_FALSE ); - - // Set grid color - glColor3f( 0.0f, 0.5f, 0.5f ); - - glBegin( GL_LINES ); - - // Horizontal lines - x = scale * 0.5f * (float)(steps-1); - y = -scale * 0.5f * (float)(steps-1); - for( i = 0; i < steps; i ++ ) - { - glVertex3f( -x, y, 0.0f ); - glVertex3f( x, y, 0.0f ); - y += scale; - } - - // Vertical lines - x = -scale * 0.5f * (float)(steps-1); - y = scale * 0.5f * (float)(steps-1); - for( i = 0; i < steps; i ++ ) - { - glVertex3f( x, -y, 0.0f ); - glVertex3f( x, y, 0.0f ); - x += scale; - } - - glEnd(); - - // Enable Z-buffer writing again - glDepthMask( GL_TRUE ); - - glPopMatrix(); -} - - -//======================================================================== -// Draw all views -//======================================================================== - -static void drawAllViews( void ) -{ - const GLfloat light_position[4] = {0.0f, 8.0f, 8.0f, 1.0f}; - const GLfloat light_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - const GLfloat light_specular[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - const GLfloat light_ambient[4] = {0.2f, 0.2f, 0.3f, 1.0f}; - double aspect; - - // Calculate aspect of window - if( height > 0 ) - { - aspect = (double)width / (double)height; - } - else - { - aspect = 1.0; - } - - // Clear screen - glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - - // Enable scissor test - glEnable( GL_SCISSOR_TEST ); - - // Enable depth test - glEnable( GL_DEPTH_TEST ); - glDepthFunc( GL_LEQUAL ); - - - // ** ORTHOGONAL VIEWS ** - - // For orthogonal views, use wireframe rendering - glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); - - // Enable line anti-aliasing - glEnable( GL_LINE_SMOOTH ); - glEnable( GL_BLEND ); - glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - - // Setup orthogonal projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - glOrtho( -3.0*aspect, 3.0*aspect, -3.0, 3.0, 1.0, 50.0 ); - - // Upper left view (TOP VIEW) - glViewport( 0, height/2, width/2, height/2 ); - glScissor( 0, height/2, width/2, height/2 ); - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - gluLookAt( 0.0f, 10.0f, 1e-3f, // Eye-position (above) - 0.0f, 0.0f, 0.0f, // View-point - 0.0f, 1.0f, 0.0f ); // Up-vector - drawGrid( 0.5, 12 ); - drawScene(); - - // Lower left view (FRONT VIEW) - glViewport( 0, 0, width/2, height/2 ); - glScissor( 0, 0, width/2, height/2 ); - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - gluLookAt( 0.0f, 0.0f, 10.0f, // Eye-position (in front of) - 0.0f, 0.0f, 0.0f, // View-point - 0.0f, 1.0f, 0.0f ); // Up-vector - drawGrid( 0.5, 12 ); - drawScene(); - - // Lower right view (SIDE VIEW) - glViewport( width/2, 0, width/2, height/2 ); - glScissor( width/2, 0, width/2, height/2 ); - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - gluLookAt( 10.0f, 0.0f, 0.0f, // Eye-position (to the right) - 0.0f, 0.0f, 0.0f, // View-point - 0.0f, 1.0f, 0.0f ); // Up-vector - drawGrid( 0.5, 12 ); - drawScene(); - - // Disable line anti-aliasing - glDisable( GL_LINE_SMOOTH ); - glDisable( GL_BLEND ); - - - // ** PERSPECTIVE VIEW ** - - // For perspective view, use solid rendering - glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - - // Enable face culling (faster rendering) - glEnable( GL_CULL_FACE ); - glCullFace( GL_BACK ); - glFrontFace( GL_CW ); - - // Setup perspective projection matrix - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - gluPerspective( 65.0f, aspect, 1.0f, 50.0f ); - - // Upper right view (PERSPECTIVE VIEW) - glViewport( width/2, height/2, width/2, height/2 ); - glScissor( width/2, height/2, width/2, height/2 ); - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - gluLookAt( 3.0f, 1.5f, 3.0f, // Eye-position - 0.0f, 0.0f, 0.0f, // View-point - 0.0f, 1.0f, 0.0f ); // Up-vector - - // Configure and enable light source 1 - glLightfv( GL_LIGHT1, GL_POSITION, light_position ); - glLightfv( GL_LIGHT1, GL_AMBIENT, light_ambient ); - glLightfv( GL_LIGHT1, GL_DIFFUSE, light_diffuse ); - glLightfv( GL_LIGHT1, GL_SPECULAR, light_specular ); - glEnable( GL_LIGHT1 ); - glEnable( GL_LIGHTING ); - - // Draw scene - drawScene(); - - // Disable lighting - glDisable( GL_LIGHTING ); - - // Disable face culling - glDisable( GL_CULL_FACE ); - - // Disable depth test - glDisable( GL_DEPTH_TEST ); - - // Disable scissor test - glDisable( GL_SCISSOR_TEST ); - - - // Draw a border around the active view - if( active_view > 0 && active_view != 2 ) - { - glViewport( 0, 0, width, height ); - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - glOrtho( 0.0, 2.0, 0.0, 2.0, 0.0, 1.0 ); - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - glColor3f( 1.0f, 1.0f, 0.6f ); - glTranslatef( (GLfloat) ((active_view - 1) & 1), (GLfloat) (1 - (active_view - 1) / 2), 0.0f ); - glBegin( GL_LINE_STRIP ); - glVertex2i( 0, 0 ); - glVertex2i( 1, 0 ); - glVertex2i( 1, 1 ); - glVertex2i( 0, 1 ); - glVertex2i( 0, 0 ); - glEnd(); - } -} - - -//======================================================================== -// Window size callback function -//======================================================================== - -static void GLFWCALL windowSizeFun( int w, int h ) -{ - width = w; - height = h > 0 ? h : 1; - do_redraw = 1; -} - - -//======================================================================== -// Window refresh callback function -//======================================================================== - -static void GLFWCALL windowRefreshFun( void ) -{ - do_redraw = 1; -} - - -//======================================================================== -// Mouse position callback function -//======================================================================== - -static void GLFWCALL mousePosFun( int x, int y ) -{ - // Depending on which view was selected, rotate around different axes - switch( active_view ) - { - case 1: - rot_x += y - ypos; - rot_z += x - xpos; - do_redraw = 1; - break; - case 3: - rot_x += y - ypos; - rot_y += x - xpos; - do_redraw = 1; - break; - case 4: - rot_y += x - xpos; - rot_z += y - ypos; - do_redraw = 1; - break; - default: - // Do nothing for perspective view, or if no view is selected - break; - } - - // Remember mouse position - xpos = x; - ypos = y; -} - - -//======================================================================== -// Mouse button callback function -//======================================================================== - -static void GLFWCALL mouseButtonFun( int button, int action ) -{ - // Button clicked? - if( ( button == GLFW_MOUSE_BUTTON_LEFT ) && action == GLFW_PRESS ) - { - // Detect which of the four views was clicked - active_view = 1; - if( xpos >= width/2 ) - { - active_view += 1; - } - if( ypos >= height/2 ) - { - active_view += 2; - } - } - - // Button released? - else if( button == GLFW_MOUSE_BUTTON_LEFT ) - { - // Deselect any previously selected view - active_view = 0; - } - - do_redraw = 1; -} - - -//======================================================================== -// main() -//======================================================================== - -void iteration(){ - // Only redraw if we need to - if( do_redraw ) - { - // Draw all views - drawAllViews(); - - // Swap buffers - glfwSwapBuffers(); - - do_redraw = 0; - } - - // Wait for new events - glfwWaitEvents(); -} - -int main( void ) -{ - // Initialise GLFW - if( !glfwInit() ) - { - fprintf( stderr, "Failed to initialize GLFW\n" ); - exit( EXIT_FAILURE ); - } - - // Open OpenGL window - if( !glfwOpenWindow( 500, 500, 0,0,0,0, 16,0, GLFW_WINDOW ) ) - { - fprintf( stderr, "Failed to open GLFW window\n" ); - glfwTerminate(); - exit( EXIT_FAILURE ); - } - - // Enable vsync - glfwSwapInterval( 1 ); - - // Set window title - glfwSetWindowTitle( "Split view demo" ); - - // Enable sticky keys - glfwEnable( GLFW_STICKY_KEYS ); - - // Enable mouse cursor (only needed for fullscreen mode) - glfwEnable( GLFW_MOUSE_CURSOR ); - - // Disable automatic event polling - glfwDisable( GLFW_AUTO_POLL_EVENTS ); - - // Set callback functions - glfwSetWindowSizeCallback( windowSizeFun ); - glfwSetWindowRefreshCallback( windowRefreshFun ); - glfwSetMousePosCallback( mousePosFun ); - glfwSetMouseButtonCallback( mouseButtonFun ); - -#ifdef EMSCRIPTEN - emscripten_set_main_loop (iteration, 0, 1); -#else - // Main loop - do - { - iteration(); - } // Check if the ESC key was pressed or the window was closed - while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS && - glfwGetWindowParam( GLFW_OPENED ) ); -#endif - - // Close OpenGL window and terminate GLFW - glfwTerminate(); - - exit( EXIT_SUCCESS ); -} - diff --git a/tests/glfw/triangle.c b/tests/glfw/triangle.c deleted file mode 100644 index db9d9ab163573..0000000000000 --- a/tests/glfw/triangle.c +++ /dev/null @@ -1,108 +0,0 @@ -//======================================================================== -// This is a small test application for GLFW. -// The program opens a window (640x480), and renders a spinning colored -// triangle (it is controlled with both the GLFW timer and the mouse). -//======================================================================== - -#include -#include -#include - -#ifdef EMSCRIPTEN -#include -#endif - -void -iteration () -{ - int width, height, x; - double t; - - t = glfwGetTime (); - glfwGetMousePos (&x, NULL); - - // Get window size (may be different than the requested size) - glfwGetWindowSize (&width, &height); - - // Special case: avoid division by zero below - height = height > 0 ? height : 1; - - glViewport (0, 0, width, height); - - // Clear color buffer to black - glClearColor (0.0f, 0.0f, 0.0f, 0.0f); - glClear (GL_COLOR_BUFFER_BIT); - - // Select and setup the projection matrix - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - gluPerspective (65.0f, (GLfloat) width / (GLfloat) height, 1.0f, 100.0f); - - // Select and setup the modelview matrix - glMatrixMode (GL_MODELVIEW); - glLoadIdentity (); - gluLookAt (0.0f, 1.0f, 0.0f, // Eye-position - 0.0f, 20.0f, 0.0f, // View-point - 0.0f, 0.0f, 1.0f); // Up-vector - - // Draw a rotating colorful triangle - //glTranslatef (0.0f, 14.0f, 0.0f); - glTranslatef (0.0f, 1.0f, 0.0f); - glRotatef (0.3f * (GLfloat) x + (GLfloat) t * 100.0f, 0.0f, 0.0f, 1.0f); - glBegin (GL_TRIANGLES); - glColor3f (1.0f, 0.0f, 0.0f); - glVertex3f (-5.0f, 0.0f, -4.0f); - glColor3f (0.0f, 1.0f, 0.0f); - glVertex3f (5.0f, 0.0f, -4.0f); - glColor3f (0.0f, 0.0f, 1.0f); - glVertex3f (0.0f, 0.0f, 6.0f); - glEnd (); - - // Swap buffers - glfwSwapBuffers (); - -} - -int -main (void) -{ - // Initialise GLFW - if (!glfwInit ()) - { - fprintf (stderr, "Failed to initialize GLFW\n"); - exit (EXIT_FAILURE); - } - - // Open a window and create its OpenGL context - if (!glfwOpenWindow (640, 480, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) - { - fprintf (stderr, "Failed to open GLFW window\n"); - - glfwTerminate (); - exit (EXIT_FAILURE); - } - - glfwSetWindowTitle ("Spinning Triangle"); - - // Ensure we can capture the escape key being pressed below - glfwEnable (GLFW_STICKY_KEYS); - - // Enable vertical sync (on cards that support it) - glfwSwapInterval (1); - -#ifdef EMSCRIPTEN - emscripten_set_main_loop (iteration, 0, 1); -#else - do - { - iteration (); - } // Check if the ESC key was pressed or the window was closed - while (glfwGetKey (GLFW_KEY_ESC) != GLFW_PRESS && - glfwGetWindowParam (GLFW_OPENED)); -#endif - - // Close OpenGL window and terminate GLFW - glfwTerminate (); - - exit (EXIT_SUCCESS); -} diff --git a/tests/glfw/wave.c b/tests/glfw/wave.c deleted file mode 100644 index 67f516cc094c7..0000000000000 --- a/tests/glfw/wave.c +++ /dev/null @@ -1,399 +0,0 @@ -/***************************************************************************** - * Wave Simulation in OpenGL - * (C) 2002 Jakob Thomsen - * http://home.in.tum.de/~thomsen - * Modified for GLFW by Sylvain Hellegouarch - sh@programmationworld.com - * Modified for variable frame rate by Marcus Geelnard - * 2003-Jan-31: Minor cleanups and speedups / MG - *****************************************************************************/ - -#include -#include -#include -#include - -#ifndef M_PI - #define M_PI 3.1415926535897932384626433832795 -#endif - -/* Maximum delta T to allow for differential calculations */ -#define MAX_DELTA_T 0.01 - -/* Animation speed (10.0 looks good) */ -#define ANIMATION_SPEED 10.0 - - -GLfloat alpha = 210.0f, beta = -70.0f; -GLfloat zoom = 2.0f; - -int running = 1; - -struct Vertex -{ - GLfloat x,y,z; - GLfloat r,g,b; -}; - -#define GRIDW 50 -#define GRIDH 50 -#define VERTEXNUM (GRIDW*GRIDH) - -#define QUADW (GRIDW-1) -#define QUADH (GRIDH-1) -#define QUADNUM (QUADW*QUADH) - -GLuint quad[4*QUADNUM]; -struct Vertex vertex[VERTEXNUM]; - -/* The grid will look like this: - * - * 3 4 5 - * *---*---* - * | | | - * | 0 | 1 | - * | | | - * *---*---* - * 0 1 2 - */ - -void initVertices( void ) -{ - int x,y,p; - - /* place the vertices in a grid */ - for(y=0;y1) zoom-=1; - break; - case GLFW_KEY_PAGEDOWN: - zoom+=1; - break; - default: - break; - } -} - - -/* Callback function for window resize events */ -void GLFWCALL handle_resize( int width, int height ) -{ - float ratio = 1.0f; - - if( height > 0 ) - { - ratio = (float) width / (float) height; - } - - /* Setup viewport (Place where the stuff will appear in the main window). */ - glViewport(0, 0, width, height); - - /* - * Change to the projection matrix and set - * our viewing volume. - */ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(60.0, ratio, 1.0, 1024.0); -} - - -/* Program entry point */ -int main(int argc, char* argv[]) -{ - /* Dimensions of our window. */ - int width, height; - /* Style of our window. */ - int mode; - /* Frame time */ - double t, t_old, dt_total; - - /* Initialize GLFW */ - if(glfwInit() == GL_FALSE) - { - fprintf(stderr, "GLFW initialization failed\n"); - exit(-1); - } - - /* Desired window properties */ - width = 640; - height = 480; - mode = GLFW_WINDOW; - - /* Open window */ - if( glfwOpenWindow(width,height,0,0,0,0,16,0,mode) == GL_FALSE ) - { - fprintf(stderr, "Could not open window\n"); - glfwTerminate(); - exit(-1); - } - - /* Set title */ - glfwSetWindowTitle( "Wave Simulation" ); - - glfwSwapInterval( 1 ); - - /* Keyboard handler */ - glfwSetKeyCallback( handle_key_down ); - glfwEnable( GLFW_KEY_REPEAT ); - - /* Window resize handler */ - glfwSetWindowSizeCallback( handle_resize ); - - /* Initialize OpenGL */ - setup_opengl(); - - /* Initialize simulation */ - initVertices(); - initSurface(); - adjustGrid(); - - /* Initialize timer */ - t_old = glfwGetTime() - 0.01; - - /* Main loop */ - while(running) - { - /* Timing */ - t = glfwGetTime(); - dt_total = t - t_old; - t_old = t; - - /* Safety - iterate if dt_total is too large */ - while( dt_total > 0.0f ) - { - /* Select iteration time step */ - dt = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total; - dt_total -= dt; - - /* Calculate wave propagation */ - calc(); - } - - /* Compute height of each vertex */ - adjustGrid(); - - /* Draw wave grid to OpenGL display */ - draw_screen(); - - /* Still running? */ - running = running && glfwGetWindowParam( GLFW_OPENED ); - } - - glfwTerminate(); - - return 0; -} From e646c6db2b518dd3f734e0fe33fe337334ce94c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Tue, 2 Apr 2013 14:25:32 +0300 Subject: [PATCH 031/544] Update AUTHORS --- AUTHORS | 2 -- 1 file changed, 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 9eda98519ef32..401b408a2f1d4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -57,5 +57,3 @@ a license to everyone to use it as detailed in LICENSE.) * Ting-Yuan Huang * Felix H. Dahlke * Éloi Rivard - ->>>>>>> * OpenGL extensions. From 0dceb188613dafb0dc68d79a34480377ff6a0c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Tue, 2 Apr 2013 14:26:28 +0300 Subject: [PATCH 032/544] Update AUTHORS --- src/modules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules.js b/src/modules.js index e28bff31bc8ab..f2994adae31db 100644 --- a/src/modules.js +++ b/src/modules.js @@ -374,7 +374,7 @@ var LibraryManager = { load: function() { if (this.library) return; - var libraries = ['library.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js',.concat(additionalLibraries); + var libraries = ['library.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js'].concat(additionalLibraries); for (var i = 0; i < libraries.length; i++) { eval(processMacros(preprocess(read(libraries[i])))); } From 6d7a967e5f5e53d10f1c87e23ca1a3aced9114d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Wed, 3 Apr 2013 22:55:24 +0200 Subject: [PATCH 033/544] * Indentation and brackets. --- src/library_glfw.js | 644 ++++++++++++++++++++++---------------------- 1 file changed, 327 insertions(+), 317 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index e197efd29f69e..fc051ce6b0715 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -1,6 +1,6 @@ /******************************************************************************* * EMSCRIPTEN GLFW 2.7.7 emulation. - * It tries to emulate the behavior described in + * It tries to emulate the behavior described in * http://www.glfw.org/GLFWReference277.pdf * * What it does: @@ -23,17 +23,17 @@ var LibraryGLFW = { $GLFW: { - + keyFunc: null, - charFunc: null, - mouseButtonFunc: null, - mousePosFunc: null, - mouseWheelFunc: null, + charFunc: null, + mouseButtonFunc: null, + mousePosFunc: null, + mouseWheelFunc: null, resizeFunc: null, - closeFunc: null, - refreshFunc: null, + closeFunc: null, + refreshFunc: null, mouseFunc: null, - params: null, + params: null, initTime: null, wheelPos: 0, lastX: 0, @@ -86,7 +86,7 @@ var LibraryGLFW = { case 0x06 : return 288 ; //DOM_VK_RIGHT_SHIFT -> GLFW_KEY_RSHIFT case 17 : return 289 ; //DOM_VK_CONTROL -> GLFW_KEY_LCTRL case 0x03 : return 289 ; //DOM_VK_LEFT_CONTROL -> GLFW_KEY_LCTRL - case 0x04 : return 290 ; //DOM_VK_RIGHT_CONTROL -> GLFW_KEY_RCTRL + case 0x04 : return 290 ; //DOM_VK_RIGHT_CONTROL -> GLFW_KEY_RCTRL case 18 : return 291 ; //DOM_VK_ALT -> GLFW_KEY_LALT case 0x02 : return 291 ; //DOM_VK_LEFT_ALT -> GLFW_KEY_LALT case 0x01 : return 292 ; //DOM_VK_RIGHT_ALT -> GLFW_KEY_RALT @@ -113,14 +113,14 @@ var LibraryGLFW = { value = 0xDC00 | value & 0x3FF; } output += String.fromCharCode(value); - return output; + return output; }, onKeyPress: function(event) { //charCode is only available whith onKeyPress event var char = GLFW.getUnicodeChar(event.charCode); - - if(event.charCode){ + + if(event.charCode) { var char = GLFW.getUnicodeChar(event.charCode); if( char !== null && GLFW.charFunc ) { event.preventDefault(); @@ -128,24 +128,24 @@ var LibraryGLFW = { } } }, - - onKeyChanged: function(event, status){ - var key = GLFW.DOMToGLFWKeyCode(event.keyCode); + + onKeyChanged: function(event, status) { + var key = GLFW.DOMToGLFWKeyCode(event.keyCode); if(key && GLFW.keyFunc) { GLFW.keys[key] = status; event.preventDefault(); Runtime.dynCall('vii', GLFW.keyFunc, [key, status]); - } + } }, onKeydown: function(event) { - GLFW.onKeyChanged(event, 1);//GLFW_PRESS + GLFW.onKeyChanged(event, 1);//GLFW_PRESS }, onKeyup: function(event) { - GLFW.onKeyChanged(event, 0);//GLFW_RELEASE + GLFW.onKeyChanged(event, 0);//GLFW_RELEASE }, - + savePosition: function(event) { /* TODO maybe loop here ala http://www.quirksmode.org/js/findpos.html */ GLFW.lastX = event['clientX'] - Module['canvas'].offsetLeft; @@ -159,53 +159,59 @@ var LibraryGLFW = { */ var newX = event['clientX'] - Module['canvas'].offsetLeft; var newY = event['clientY'] - Module['canvas'].offsetTop; - if (newX == GLFW.lastX && newY == GLFW.lastY) + if (newX == GLFW.lastX && newY == GLFW.lastY) { return; + } GLFW.savePosition(event); - + if (event.target == Module["canvas"] && GLFW.mousePosFunc) { event.preventDefault(); Runtime.dynCall('vii', GLFW.mousePosFunc, [GLFW.lastX, GLFW.lastY]); - } + } }, - onMouseButtonChanged: function(event, status){ - if(GLFW.mouseButtonFunc == null) + onMouseButtonChanged: function(event, status) { + if(GLFW.mouseButtonFunc == null) { return; + } GLFW.savePosition(event); - if(event.target != Module["canvas"]) + if(event.target != Module["canvas"]) { return; - - if(status == 1){//GLFW_PRESS + } + + if(status == 1) {//GLFW_PRESS try { event.target.setCapture(); } catch (e) {} } event.preventDefault(); - //DOM and glfw have the same button codes + //DOM and glfw have the same button codes Runtime.dynCall('vii', GLFW.mouseButtonFunc, [event['button'], status]); - }, + }, - onMouseButtonDown: function(event){ + onMouseButtonDown: function(event) { GLFW.buttons |= (1 << event['button']); - GLFW.onMouseButtonChanged(event, 1);//GLFW_PRESS - }, + GLFW.onMouseButtonChanged(event, 1);//GLFW_PRESS + }, - onMouseButtonUp: function(event){ - GLFW.buttons &= ~(1 << event['button']); - GLFW.onMouseButtonChanged(event, 0);//GLFW_RELEASE - }, + onMouseButtonUp: function(event) { + GLFW.buttons &= ~(1 << event['button']); + GLFW.onMouseButtonChanged(event, 0);//GLFW_RELEASE + }, - onMouseWheel: function(event){ - if(event.detail > 0) + onMouseWheel: function(event) { + if(event.detail > 0) { GLFW.wheelPos++; - if(event.detail < 0) + } + + if(event.detail < 0) { GLFW.wheelPos--; - - if(GLFW.mouseWheelFunc && event.target == Module["canvas"]){ + } + + if(GLFW.mouseWheelFunc && event.target == Module["canvas"]) { Runtime.dynCall('vi', GLFW.mouseWheelFunc, [GLFW.wheelPos]); event.preventDefault(); } @@ -213,23 +219,24 @@ var LibraryGLFW = { // TODO add fullscreen API ala: // http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/ - onFullScreenEventChange: function(event){ + onFullScreenEventChange: function(event) { var width; var height; if (document["fullScreen"] || document["mozFullScreen"] || document["webkitIsFullScreen"]) { width = screen["width"]; height = screen["height"]; - } else { + } + else { width = GLFW.windowWidth; height = GLFW.windowHeight; - // TODO set position + // TODO set position document.removeEventListener('fullscreenchange', GLFW.onFullScreenEventChange, true); document.removeEventListener('mozfullscreenchange', GLFW.onFullScreenEventChange, true); document.removeEventListener('webkitfullscreenchange', GLFW.onFullScreenEventChange, true); } Browser.setCanvasSize(width, height); - - if (GLFW.resizeFunc){ + + if (GLFW.resizeFunc) { Runtime.dynCall('vii', GLFW.resizeFunc, [width, height]); } }, @@ -248,7 +255,7 @@ var LibraryGLFW = { document['cancelFullScreen'] || document['mozCancelFullScreen'] || document['webkitCancelFullScreen'] || - (function() {}); + (function() {}); CFS.apply(document, []); } }, @@ -257,50 +264,50 @@ var LibraryGLFW = { * GLFW FUNCTIONS ******************************************************************************/ - /* GLFW initialization, termination and version querying */ - glfwInit : function() { - GLFW.initTime = Date.now() / 1000; - - window.addEventListener("keydown", GLFW.onKeydown, true); - window.addEventListener("keypress", GLFW.onKeyPress, true); - window.addEventListener("keyup", GLFW.onKeyup, true); - window.addEventListener("mousemove", GLFW.onMousemove, true); - window.addEventListener("mousedown", GLFW.onMouseButtonDown, true); - window.addEventListener("mouseup", GLFW.onMouseButtonUp, true); - window.addEventListener('DOMMouseScroll', GLFW.onMouseWheel, true); + /* GLFW initialization, termination and version querying */ + glfwInit : function() { + GLFW.initTime = Date.now() / 1000; + + window.addEventListener("keydown", GLFW.onKeydown, true); + window.addEventListener("keypress", GLFW.onKeyPress, true); + window.addEventListener("keyup", GLFW.onKeyup, true); + window.addEventListener("mousemove", GLFW.onMousemove, true); + window.addEventListener("mousedown", GLFW.onMouseButtonDown, true); + window.addEventListener("mouseup", GLFW.onMouseButtonUp, true); + window.addEventListener('DOMMouseScroll', GLFW.onMouseWheel, true); window.addEventListener('mousewheel', GLFW.onMouseWheel, true); - __ATEXIT__.push({ func: function() { - window.removeEventListener("keydown", GLFW.onKeydown, true); - window.removeEventListener("keypress", GLFW.onKeyPress, true); - window.removeEventListener("keyup", GLFW.onKeyup, true); - window.removeEventListener("mousemove", GLFW.onMousemove, true); - window.removeEventListener("mousedown", GLFW.onMouseButtonDown, true); - window.removeEventListener("mouseup", GLFW.onMouseButtonUp, true); - window.removeEventListener('DOMMouseScroll', GLFW.onMouseWheel, true); + __ATEXIT__.push({ func: function() { + window.removeEventListener("keydown", GLFW.onKeydown, true); + window.removeEventListener("keypress", GLFW.onKeyPress, true); + window.removeEventListener("keyup", GLFW.onKeyup, true); + window.removeEventListener("mousemove", GLFW.onMousemove, true); + window.removeEventListener("mousedown", GLFW.onMouseButtonDown, true); + window.removeEventListener("mouseup", GLFW.onMouseButtonUp, true); + window.removeEventListener('DOMMouseScroll', GLFW.onMouseWheel, true); window.removeEventListener('mousewheel', GLFW.onMouseWheel, true); - Module["canvas"].width = Module["canvas"].height = 1; - } }); + Module["canvas"].width = Module["canvas"].height = 1; + } }); //TODO: Init with correct values - GLFW.params = new Array(); - GLFW.params[0x00030001] = true; //GLFW_MOUSE_CURSOR - GLFW.params[0x00030002] = false; //GLFW_STICKY_KEYS - GLFW.params[0x00030003] = true; //GLFW_STICKY_MOUSE_BUTTONS - GLFW.params[0x00030004] = false; //GLFW_SYSTEM_KEYS - GLFW.params[0x00030005] = false; //GLFW_KEY_REPEAT - GLFW.params[0x00030006] = true; //GLFW_AUTO_POLL_EVENTS - GLFW.params[0x00020001] = true; //GLFW_OPENED + GLFW.params = new Array(); + GLFW.params[0x00030001] = true; //GLFW_MOUSE_CURSOR + GLFW.params[0x00030002] = false; //GLFW_STICKY_KEYS + GLFW.params[0x00030003] = true; //GLFW_STICKY_MOUSE_BUTTONS + GLFW.params[0x00030004] = false; //GLFW_SYSTEM_KEYS + GLFW.params[0x00030005] = false; //GLFW_KEY_REPEAT + GLFW.params[0x00030006] = true; //GLFW_AUTO_POLL_EVENTS + GLFW.params[0x00020001] = true; //GLFW_OPENED GLFW.params[0x00020002] = true; //GLFW_ACTIVE GLFW.params[0x00020003] = false; //GLFW_ICONIFIED - GLFW.params[0x00020004] = true; //GLFW_ACCELERATED + GLFW.params[0x00020004] = true; //GLFW_ACCELERATED GLFW.params[0x00020005] = 0; //GLFW_RED_BITS - GLFW.params[0x00020006] = 0; //GLFW_GREEN_BITS + GLFW.params[0x00020006] = 0; //GLFW_GREEN_BITS GLFW.params[0x00020007] = 0; //GLFW_BLUE_BITS GLFW.params[0x00020008] = 0; //GLFW_ALPHA_BITS GLFW.params[0x00020009] = 0; //GLFW_DEPTH_BITS GLFW.params[0x0002000A] = 0; //GLFW_STENCIL_BITS - GLFW.params[0x0002000B] = 0; //GLFW_REFRESH_RATE + GLFW.params[0x0002000B] = 0; //GLFW_REFRESH_RATE GLFW.params[0x0002000C] = 0; //GLFW_ACCUM_RED_BITS GLFW.params[0x0002000D] = 0; //GLFW_ACCUM_GREEN_BITS GLFW.params[0x0002000E] = 0; //GLFW_ACCUM_BLUE_BITS @@ -309,265 +316,268 @@ var LibraryGLFW = { GLFW.params[0x00020011] = 0; //GLFW_STEREO GLFW.params[0x00020012] = 0; //GLFW_WINDOW_NO_RESIZE GLFW.params[0x00020013] = 0; //GLFW_FSAA_SAMPLES - GLFW.params[0x00020014] = 0; //GLFW_OPENGL_VERSION_MAJOR - GLFW.params[0x00020015] = 0; //GLFW_OPENGL_VERSION_MINOR - GLFW.params[0x00020016] = 0; //GLFW_OPENGL_FORWARD_COMPAT - GLFW.params[0x00020017] = 0; //GLFW_OPENGL_DEBUG_CONTEXT + GLFW.params[0x00020014] = 0; //GLFW_OPENGL_VERSION_MAJOR + GLFW.params[0x00020015] = 0; //GLFW_OPENGL_VERSION_MINOR + GLFW.params[0x00020016] = 0; //GLFW_OPENGL_FORWARD_COMPAT + GLFW.params[0x00020017] = 0; //GLFW_OPENGL_DEBUG_CONTEXT GLFW.params[0x00020018] = 0; //GLFW_OPENGL_PROFILE GLFW.keys = new Array(); - return 1; //GL_TRUE - }, - - glfwTerminate : function() {}, + return 1; //GL_TRUE + }, - glfwGetVersion : function( major, minor, rev ) { - setValue(major, 2, 'i32'); - setValue(minor, 7, 'i32'); - setValue(rev, 7, 'i32'); - }, + glfwTerminate : function() {}, - /* Window handling */ - glfwOpenWindow__deps: ['$Browser'], - glfwOpenWindow : function( width, height, redbits, greenbits, bluebits, alphabits, depthbits, stencilbits, mode ) { - if(width == 0 && height > 0) - width = 4 * height / 3; - if(width > 0 && height == 0) - height = 3 * width / 4; + glfwGetVersion : function( major, minor, rev ) { + setValue(major, 2, 'i32'); + setValue(minor, 7, 'i32'); + setValue(rev, 7, 'i32'); + }, + /* Window handling */ + glfwOpenWindow__deps: ['$Browser'], + glfwOpenWindow : function( width, height, redbits, greenbits, bluebits, alphabits, depthbits, stencilbits, mode ) { + if(width == 0 && height > 0) { + width = 4 * height / 3; + } + if(width > 0 && height == 0) { + height = 3 * width / 4; + } GLFW.params[0x00020005] = redbits; //GLFW_RED_BITS - GLFW.params[0x00020006] = greenbits; //GLFW_GREEN_BITS + GLFW.params[0x00020006] = greenbits; //GLFW_GREEN_BITS GLFW.params[0x00020007] = bluebits; //GLFW_BLUE_BITS GLFW.params[0x00020008] = alphabits; //GLFW_ALPHA_BITS GLFW.params[0x00020009] = depthbits; //GLFW_DEPTH_BITS GLFW.params[0x0002000A] = stencilbits; //GLFW_STENCIL_BITS - if(mode == 0x00010001){//GLFW_WINDOW - Browser.setCanvasSize( GLFW.initWindowWidth = width, + if(mode == 0x00010001) {//GLFW_WINDOW + Browser.setCanvasSize( GLFW.initWindowWidth = width, GLFW.initWindowHeight = height ); - GLFW.params[0x00030003] = true; //GLFW_STICKY_MOUSE_BUTTONS - } - else if(mode == 0x00010002){//GLFW_FULLSCREEN - GLFW.requestFullScreen(); - GLFW.params[0x00030003] = false; //GLFW_STICKY_MOUSE_BUTTONS - } - else{ - throw "Invalid glfwOpenWindow mode."; - } - - Module.ctx = Browser.createContext(Module['canvas'], true, true); - return 1; //GL_TRUE - }, - - glfwOpenWindowHint : function( target, hint ) { - GLFW.params[target] = hint; - }, - - glfwCloseWindow__deps: ['$Browser'], - glfwCloseWindow : function() { - if (GLFW.closeFunc) - Runtime.dynCall('v', GLFW.closeFunc, []); - Module.ctx = Browser.destroyContext(Module['canvas'], true, true); - }, - - glfwSetWindowTitle : function( title ) { - document.title = Pointer_stringify(title); - }, - - glfwGetWindowSize : function( width, height ) { - setValue(width, Module['canvas'].width, 'i32'); - setValue(height, Module['canvas'].height, 'i32'); - }, - - glfwSetWindowSize : function( width, height ) { - GLFW.cancelFullScreen(); - Browser.setCanvasSize(width, height); - if (GLFW.resizeFunc) { - Runtime.dynCall('vii', GLFW.resizeFunc, [width, height]); - } - }, - - glfwSetWindowPos : function( x, y ) {}, - - glfwIconifyWindow : function() {}, - - glfwRestoreWindow : function() {}, - - glfwSwapBuffers : function() {}, - - glfwSwapInterval : function( interval ) {}, - - glfwGetWindowParam : function( param ) { - return GLFW.params[param]; - }, - - glfwSetWindowSizeCallback : function( cbfun ) { - GLFW.resizeFunc = cbfun; - }, - - glfwSetWindowCloseCallback : function( cbfun ) { - GLFW.closeFunc = cbfun; - }, - - glfwSetWindowRefreshCallback : function( cbfun ) { - GLFW.refreshFunc = cbfun; - }, - - /* Video mode functions */ - glfwGetVideoModes : function( list, maxcount ) { throw "glfwGetVideoModes is not implemented."; }, - - glfwGetDesktopMode : function( mode ) { throw "glfwGetDesktopMode is not implemented."; }, - - /* Input handling */ - glfwPollEvents : function() {}, - - glfwWaitEvents : function() {}, - - glfwGetKey : function( key ) { - return GLFW.keys[key]; - }, - - glfwGetMouseButton : function( button ) { - return (GLFW.buttons & (1 << button)) > 0; - }, - - glfwGetMousePos : function( xpos, ypos ) { - setValue(xpos, GLFW.lastX, 'i32'); - setValue(ypos, GLFW.lastY, 'i32'); - }, + GLFW.params[0x00030003] = true; //GLFW_STICKY_MOUSE_BUTTONS + } + else if(mode == 0x00010002) {//GLFW_FULLSCREEN + GLFW.requestFullScreen(); + GLFW.params[0x00030003] = false; //GLFW_STICKY_MOUSE_BUTTONS + } + else{ + throw "Invalid glfwOpenWindow mode."; + } + + Module.ctx = Browser.createContext(Module['canvas'], true, true); + return 1; //GL_TRUE + }, + + glfwOpenWindowHint : function( target, hint ) { + GLFW.params[target] = hint; + }, + + glfwCloseWindow__deps: ['$Browser'], + glfwCloseWindow : function() { + if (GLFW.closeFunc) { + Runtime.dynCall('v', GLFW.closeFunc, []); + } + Module.ctx = Browser.destroyContext(Module['canvas'], true, true); + }, + + glfwSetWindowTitle : function( title ) { + document.title = Pointer_stringify(title); + }, + + glfwGetWindowSize : function( width, height ) { + setValue(width, Module['canvas'].width, 'i32'); + setValue(height, Module['canvas'].height, 'i32'); + }, + + glfwSetWindowSize : function( width, height ) { + GLFW.cancelFullScreen(); + Browser.setCanvasSize(width, height); + if (GLFW.resizeFunc) { + Runtime.dynCall('vii', GLFW.resizeFunc, [width, height]); + } + }, + + glfwSetWindowPos : function( x, y ) {}, + + glfwIconifyWindow : function() {}, + + glfwRestoreWindow : function() {}, + + glfwSwapBuffers : function() {}, + + glfwSwapInterval : function( interval ) {}, + + glfwGetWindowParam : function( param ) { + return GLFW.params[param]; + }, + + glfwSetWindowSizeCallback : function( cbfun ) { + GLFW.resizeFunc = cbfun; + }, + + glfwSetWindowCloseCallback : function( cbfun ) { + GLFW.closeFunc = cbfun; + }, + + glfwSetWindowRefreshCallback : function( cbfun ) { + GLFW.refreshFunc = cbfun; + }, + + /* Video mode functions */ + glfwGetVideoModes : function( list, maxcount ) { throw "glfwGetVideoModes is not implemented."; }, + + glfwGetDesktopMode : function( mode ) { throw "glfwGetDesktopMode is not implemented."; }, + + /* Input handling */ + glfwPollEvents : function() {}, + + glfwWaitEvents : function() {}, + + glfwGetKey : function( key ) { + return GLFW.keys[key]; + }, + + glfwGetMouseButton : function( button ) { + return (GLFW.buttons & (1 << button)) > 0; + }, + + glfwGetMousePos : function( xpos, ypos ) { + setValue(xpos, GLFW.lastX, 'i32'); + setValue(ypos, GLFW.lastY, 'i32'); + }, //I believe it is not possible to move the mouse with javascript - glfwSetMousePos : function( xpos, ypos ) {}, - - glfwGetMouseWheel : function() { - return GLFW.wheelPos; - }, - - glfwSetMouseWheel : function( pos ) { - GLFW.wheelPos = pos; - }, - - glfwSetKeyCallback : function( cbfun ) { - GLFW.keyFunc = cbfun; - }, - - glfwSetCharCallback : function( cbfun ) { - GLFW.charFunc = cbfun; - }, - - glfwSetMouseButtonCallback : function( cbfun ) { - GLFW.mouseButtonFunc = cbfun; - }, - - glfwSetMousePosCallback : function( cbfun ) { - GLFW.mousePosFunc = cbfun; - }, - - glfwSetMouseWheelCallback : function( cbfun ) { - GLFW.mouseWheelFunc = cbfun; - }, - - /* Joystick input */ - glfwGetJoystickParam : function( joy, param ) { throw "glfwGetJoystickParam is not implemented."; }, - - glfwGetJoystickPos : function( joy, pos, numaxes ) { throw "glfwGetJoystickPos is not implemented."; }, - - glfwGetJoystickButtons : function( joy, buttons, numbuttons ) { throw "glfwGetJoystickButtons is not implemented."; }, - - /* Time */ - glfwGetTime : function() { - return (Date.now()/1000) - GLFW.initTime; - }, - - glfwSetTime : function( time ) { - GLFW.initTime = Date.now()/1000 + time; - }, + glfwSetMousePos : function( xpos, ypos ) {}, + + glfwGetMouseWheel : function() { + return GLFW.wheelPos; + }, + + glfwSetMouseWheel : function( pos ) { + GLFW.wheelPos = pos; + }, + + glfwSetKeyCallback : function( cbfun ) { + GLFW.keyFunc = cbfun; + }, + + glfwSetCharCallback : function( cbfun ) { + GLFW.charFunc = cbfun; + }, + + glfwSetMouseButtonCallback : function( cbfun ) { + GLFW.mouseButtonFunc = cbfun; + }, + + glfwSetMousePosCallback : function( cbfun ) { + GLFW.mousePosFunc = cbfun; + }, + + glfwSetMouseWheelCallback : function( cbfun ) { + GLFW.mouseWheelFunc = cbfun; + }, + + /* Joystick input */ + glfwGetJoystickParam : function( joy, param ) { throw "glfwGetJoystickParam is not implemented."; }, + + glfwGetJoystickPos : function( joy, pos, numaxes ) { throw "glfwGetJoystickPos is not implemented."; }, + + glfwGetJoystickButtons : function( joy, buttons, numbuttons ) { throw "glfwGetJoystickButtons is not implemented."; }, + + /* Time */ + glfwGetTime : function() { + return (Date.now()/1000) - GLFW.initTime; + }, + + glfwSetTime : function( time ) { + GLFW.initTime = Date.now()/1000 + time; + }, glfwSleep__deps: ['sleep'], - glfwSleep : function( time ) { - _sleep(time); - }, - - /* Extension support */ - glfwExtensionSupported : function( extension ) { - return Module.ctx.getSupportedExtensions().indexOf(Pointer_stringify(extension)) > -1; - }, - - glfwGetProcAddress__deps: ['glfwGetProcAddress'], - glfwGetProcAddress : function( procname ) { - return _getProcAddress(procname); - }, - - glfwGetGLVersion : function( major, minor, rev ) { - setValue(major, 0, 'i32'); - setValue(minor, 0, 'i32'); - setValue(rev, 1, 'i32'); - }, - - /* Threading support */ - glfwCreateThread : function( fun, arg ) { + glfwSleep : function( time ) { + _sleep(time); + }, + + /* Extension support */ + glfwExtensionSupported : function( extension ) { + return Module.ctx.getSupportedExtensions().indexOf(Pointer_stringify(extension)) > -1; + }, + + glfwGetProcAddress__deps: ['glfwGetProcAddress'], + glfwGetProcAddress : function( procname ) { + return _getProcAddress(procname); + }, + + glfwGetGLVersion : function( major, minor, rev ) { + setValue(major, 0, 'i32'); + setValue(minor, 0, 'i32'); + setValue(rev, 1, 'i32'); + }, + + /* Threading support */ + glfwCreateThread : function( fun, arg ) { var str = 'v'; - for(i in arg) + for(i in arg) { str += 'i'; + } Runtime.dynCall(str, fun, arg); //One single thread - return 0; - }, - - glfwDestroyThread : function( ID ) {}, - - glfwWaitThread : function( ID, waitmode ) {}, - - glfwGetThreadID : function() { - //One single thread - return 0; - }, - - glfwCreateMutex : function() { throw "glfwCreateMutex is not implemented."; }, - - glfwDestroyMutex : function( mutex ) { throw "glfwDestroyMutex is not implemented."; }, - - glfwLockMutex : function( mutex ) { throw "glfwLockMutex is not implemented."; }, - - glfwUnlockMutex : function( mutex ) { throw "glfwUnlockMutex is not implemented."; }, - - glfwCreateCond : function() { throw "glfwCreateCond is not implemented."; }, - - glfwDestroyCond : function( cond ) { throw "glfwDestroyCond is not implemented."; }, - - glfwWaitCond : function( cond, mutex, timeout ) { throw "glfwWaitCond is not implemented."; }, - - glfwSignalCond : function( cond ) { throw "glfwSignalCond is not implemented."; }, - - glfwBroadcastCond : function( cond ) { throw "glfwBroadcastCond is not implemented."; }, - - glfwGetNumberOfProcessors : function() { - //Threads are disabled anyway… - return 1; - }, - - /* Enable/disable functions */ - glfwEnable : function( token ) { - GLFW.params[token] = false; - }, - - glfwDisable : function( token ) { - GLFW.params[token] = true; - }, - - /* Image/texture I/O support */ - glfwReadImage : function( name, img, flags ) { throw "glfwReadImage is not implemented."; }, - - glfwReadMemoryImage : function( data, size, img, flags ) { throw "glfwReadMemoryImage is not implemented."; }, - - glfwFreeImage : function( img ) { throw "glfwFreeImage is not implemented."; }, - - glfwLoadTexture2D : function( name, flags ) { throw "glfwLoadTexture2D is not implemented."; }, - - glfwLoadMemoryTexture2D : function( data, size, flags ) { throw "glfwLoadMemoryTexture2D is not implemented."; }, - - glfwLoadTextureImage2D : function( img, flags ) { throw "glfwLoadTextureImage2D is not implemented."; }, + return 0; + }, + + glfwDestroyThread : function( ID ) {}, + + glfwWaitThread : function( ID, waitmode ) {}, + + glfwGetThreadID : function() { + //One single thread + return 0; + }, + + glfwCreateMutex : function() { throw "glfwCreateMutex is not implemented."; }, + + glfwDestroyMutex : function( mutex ) { throw "glfwDestroyMutex is not implemented."; }, + + glfwLockMutex : function( mutex ) { throw "glfwLockMutex is not implemented."; }, + + glfwUnlockMutex : function( mutex ) { throw "glfwUnlockMutex is not implemented."; }, + + glfwCreateCond : function() { throw "glfwCreateCond is not implemented."; }, + + glfwDestroyCond : function( cond ) { throw "glfwDestroyCond is not implemented."; }, + + glfwWaitCond : function( cond, mutex, timeout ) { throw "glfwWaitCond is not implemented."; }, + + glfwSignalCond : function( cond ) { throw "glfwSignalCond is not implemented."; }, + + glfwBroadcastCond : function( cond ) { throw "glfwBroadcastCond is not implemented."; }, + + glfwGetNumberOfProcessors : function() { + //Threads are disabled anyway… + return 1; + }, + + /* Enable/disable functions */ + glfwEnable : function( token ) { + GLFW.params[token] = false; + }, + + glfwDisable : function( token ) { + GLFW.params[token] = true; + }, + + /* Image/texture I/O support */ + glfwReadImage : function( name, img, flags ) { throw "glfwReadImage is not implemented."; }, + + glfwReadMemoryImage : function( data, size, img, flags ) { throw "glfwReadMemoryImage is not implemented."; }, + + glfwFreeImage : function( img ) { throw "glfwFreeImage is not implemented."; }, + + glfwLoadTexture2D : function( name, flags ) { throw "glfwLoadTexture2D is not implemented."; }, + + glfwLoadMemoryTexture2D : function( data, size, flags ) { throw "glfwLoadMemoryTexture2D is not implemented."; }, + + glfwLoadTextureImage2D : function( img, flags ) { throw "glfwLoadTextureImage2D is not implemented."; }, }; autoAddDeps(LibraryGLFW, '$GLFW'); From 9017c0a8dccf38f128c18ac0e99cda6cb5752c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Thu, 4 Apr 2013 11:17:05 +0200 Subject: [PATCH 034/544] * Spaces and indentation. --- src/library_glfw.js | 274 ++++++++++++++++++++++---------------------- 1 file changed, 137 insertions(+), 137 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index fc051ce6b0715..a709161a25e7f 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -53,54 +53,54 @@ var LibraryGLFW = { DOMToGLFWKeyCode: function(keycode) { switch (keycode) { - case 0x09 : return 295 ; //DOM_VK_TAB -> GLFW_KEY_TAB - case 0x1B : return 255 ; //DOM_VK_ESCAPE -> GLFW_KEY_ESC - case 0x6A : return 313 ; //DOM_VK_MULTIPLY -> GLFW_KEY_KP_MULTIPLY - case 0x6B : return 315 ; //DOM_VK_ADD -> GLFW_KEY_KP_ADD - case 0x6D : return 314 ; //DOM_VK_SUBTRACT -> GLFW_KEY_KP_SUBTRACT - case 0x6E : return 316 ; //DOM_VK_DECIMAL -> GLFW_KEY_KP_DECIMAL - case 0x6F : return 312 ; //DOM_VK_DIVIDE -> GLFW_KEY_KP_DIVIDE - case 0x70 : return 258 ; //DOM_VK_F1 -> GLFW_KEY_F1 - case 0x71 : return 259 ; //DOM_VK_F2 -> GLFW_KEY_F2 - case 0x72 : return 260 ; //DOM_VK_F3 -> GLFW_KEY_F3 - case 0x73 : return 261 ; //DOM_VK_F4 -> GLFW_KEY_F4 - case 0x74 : return 262 ; //DOM_VK_F5 -> GLFW_KEY_F5 - case 0x75 : return 263 ; //DOM_VK_F6 -> GLFW_KEY_F6 - case 0x76 : return 264 ; //DOM_VK_F7 -> GLFW_KEY_F7 - case 0x77 : return 265 ; //DOM_VK_F8 -> GLFW_KEY_F8 - case 0x78 : return 266 ; //DOM_VK_F9 -> GLFW_KEY_F9 - case 0x79 : return 267 ; //DOM_VK_F10 -> GLFW_KEY_F10 - case 0x7a : return 268 ; //DOM_VK_F11 -> GLFW_KEY_F11 - case 0x7b : return 269 ; //DOM_VK_F12 -> GLFW_KEY_F12 - case 0x25 : return 285 ; //DOM_VK_LEFT -> GLFW_KEY_LEFT - case 0x26 : return 283 ; //DOM_VK_UP -> GLFW_KEY_UP - case 0x27 : return 286 ; //DOM_VK_RIGHT -> GLFW_KEY_RIGHT - case 0x28 : return 284 ; //DOM_VK_DOWN -> GLFW_KEY_DOWN - case 0x21 : return 298 ; //DOM_VK_PAGE_UP -> GLFW_KEY_PAGEUP - case 0x22 : return 299 ; //DOM_VK_PAGE_DOWN -> GLFW_KEY_PAGEDOWN - case 0x24 : return 300 ; //DOM_VK_HOME -> GLFW_KEY_HOME - case 0x23 : return 301 ; //DOM_VK_END -> GLFW_KEY_END - case 0x2d : return 296 ; //DOM_VK_INSERT -> GLFW_KEY_INSERT - case 16 : return 287 ; //DOM_VK_SHIFT -> GLFW_KEY_LSHIFT - case 0x05 : return 287 ; //DOM_VK_LEFT_SHIFT -> GLFW_KEY_LSHIFT - case 0x06 : return 288 ; //DOM_VK_RIGHT_SHIFT -> GLFW_KEY_RSHIFT - case 17 : return 289 ; //DOM_VK_CONTROL -> GLFW_KEY_LCTRL - case 0x03 : return 289 ; //DOM_VK_LEFT_CONTROL -> GLFW_KEY_LCTRL - case 0x04 : return 290 ; //DOM_VK_RIGHT_CONTROL -> GLFW_KEY_RCTRL - case 18 : return 291 ; //DOM_VK_ALT -> GLFW_KEY_LALT - case 0x02 : return 291 ; //DOM_VK_LEFT_ALT -> GLFW_KEY_LALT - case 0x01 : return 292 ; //DOM_VK_RIGHT_ALT -> GLFW_KEY_RALT - case 96 : return 302 ; //GLFW_KEY_KP_0 - case 97 : return 303 ; //GLFW_KEY_KP_1 - case 98 : return 304 ; //GLFW_KEY_KP_2 - case 99 : return 305 ; //GLFW_KEY_KP_3 - case 100 : return 306 ; //GLFW_KEY_KP_4 - case 101 : return 307 ; //GLFW_KEY_KP_5 - case 102 : return 308 ; //GLFW_KEY_KP_6 - case 103 : return 309 ; //GLFW_KEY_KP_7 - case 104 : return 310 ; //GLFW_KEY_KP_8 - case 105 : return 311 ; //GLFW_KEY_KP_9 - default : return keycode; + case 0x09: return 295 ; //DOM_VK_TAB -> GLFW_KEY_TAB + case 0x1B: return 255 ; //DOM_VK_ESCAPE -> GLFW_KEY_ESC + case 0x6A: return 313 ; //DOM_VK_MULTIPLY -> GLFW_KEY_KP_MULTIPLY + case 0x6B: return 315 ; //DOM_VK_ADD -> GLFW_KEY_KP_ADD + case 0x6D: return 314 ; //DOM_VK_SUBTRACT -> GLFW_KEY_KP_SUBTRACT + case 0x6E: return 316 ; //DOM_VK_DECIMAL -> GLFW_KEY_KP_DECIMAL + case 0x6F: return 312 ; //DOM_VK_DIVIDE -> GLFW_KEY_KP_DIVIDE + case 0x70: return 258 ; //DOM_VK_F1 -> GLFW_KEY_F1 + case 0x71: return 259 ; //DOM_VK_F2 -> GLFW_KEY_F2 + case 0x72: return 260 ; //DOM_VK_F3 -> GLFW_KEY_F3 + case 0x73: return 261 ; //DOM_VK_F4 -> GLFW_KEY_F4 + case 0x74: return 262 ; //DOM_VK_F5 -> GLFW_KEY_F5 + case 0x75: return 263 ; //DOM_VK_F6 -> GLFW_KEY_F6 + case 0x76: return 264 ; //DOM_VK_F7 -> GLFW_KEY_F7 + case 0x77: return 265 ; //DOM_VK_F8 -> GLFW_KEY_F8 + case 0x78: return 266 ; //DOM_VK_F9 -> GLFW_KEY_F9 + case 0x79: return 267 ; //DOM_VK_F10 -> GLFW_KEY_F10 + case 0x7a: return 268 ; //DOM_VK_F11 -> GLFW_KEY_F11 + case 0x7b: return 269 ; //DOM_VK_F12 -> GLFW_KEY_F12 + case 0x25: return 285 ; //DOM_VK_LEFT -> GLFW_KEY_LEFT + case 0x26: return 283 ; //DOM_VK_UP -> GLFW_KEY_UP + case 0x27: return 286 ; //DOM_VK_RIGHT -> GLFW_KEY_RIGHT + case 0x28: return 284 ; //DOM_VK_DOWN -> GLFW_KEY_DOWN + case 0x21: return 298 ; //DOM_VK_PAGE_UP -> GLFW_KEY_PAGEUP + case 0x22: return 299 ; //DOM_VK_PAGE_DOWN -> GLFW_KEY_PAGEDOWN + case 0x24: return 300 ; //DOM_VK_HOME -> GLFW_KEY_HOME + case 0x23: return 301 ; //DOM_VK_END -> GLFW_KEY_END + case 0x2d: return 296 ; //DOM_VK_INSERT -> GLFW_KEY_INSERT + case 16 : return 287 ; //DOM_VK_SHIFT -> GLFW_KEY_LSHIFT + case 0x05: return 287 ; //DOM_VK_LEFT_SHIFT -> GLFW_KEY_LSHIFT + case 0x06: return 288 ; //DOM_VK_RIGHT_SHIFT -> GLFW_KEY_RSHIFT + case 17 : return 289 ; //DOM_VK_CONTROL -> GLFW_KEY_LCTRL + case 0x03: return 289 ; //DOM_VK_LEFT_CONTROL -> GLFW_KEY_LCTRL + case 0x04: return 290 ; //DOM_VK_RIGHT_CONTROL -> GLFW_KEY_RCTRL + case 18 : return 291 ; //DOM_VK_ALT -> GLFW_KEY_LALT + case 0x02: return 291 ; //DOM_VK_LEFT_ALT -> GLFW_KEY_LALT + case 0x01: return 292 ; //DOM_VK_RIGHT_ALT -> GLFW_KEY_RALT + case 96 : return 302 ; //GLFW_KEY_KP_0 + case 97 : return 303 ; //GLFW_KEY_KP_1 + case 98 : return 304 ; //GLFW_KEY_KP_2 + case 99 : return 305 ; //GLFW_KEY_KP_3 + case 100 : return 306 ; //GLFW_KEY_KP_4 + case 101 : return 307 ; //GLFW_KEY_KP_5 + case 102 : return 308 ; //GLFW_KEY_KP_6 + case 103 : return 309 ; //GLFW_KEY_KP_7 + case 104 : return 310 ; //GLFW_KEY_KP_8 + case 105 : return 311 ; //GLFW_KEY_KP_9 + default : return keycode; }; }, @@ -120,9 +120,9 @@ var LibraryGLFW = { //charCode is only available whith onKeyPress event var char = GLFW.getUnicodeChar(event.charCode); - if(event.charCode) { + if (event.charCode) { var char = GLFW.getUnicodeChar(event.charCode); - if( char !== null && GLFW.charFunc ) { + if (char !== null && GLFW.charFunc) { event.preventDefault(); Runtime.dynCall('vii', GLFW.charFunc, [event.charCode, 1]); } @@ -131,7 +131,7 @@ var LibraryGLFW = { onKeyChanged: function(event, status) { var key = GLFW.DOMToGLFWKeyCode(event.keyCode); - if(key && GLFW.keyFunc) { + if (key && GLFW.keyFunc) { GLFW.keys[key] = status; event.preventDefault(); Runtime.dynCall('vii', GLFW.keyFunc, [key, status]); @@ -172,16 +172,16 @@ var LibraryGLFW = { }, onMouseButtonChanged: function(event, status) { - if(GLFW.mouseButtonFunc == null) { + if (GLFW.mouseButtonFunc == null) { return; } GLFW.savePosition(event); - if(event.target != Module["canvas"]) { + if (event.target != Module["canvas"]) { return; } - if(status == 1) {//GLFW_PRESS + if (status == 1) {//GLFW_PRESS try { event.target.setCapture(); } catch (e) {} @@ -203,15 +203,15 @@ var LibraryGLFW = { }, onMouseWheel: function(event) { - if(event.detail > 0) { + if (event.detail > 0) { GLFW.wheelPos++; } - if(event.detail < 0) { + if (event.detail < 0) { GLFW.wheelPos--; } - if(GLFW.mouseWheelFunc && event.target == Module["canvas"]) { + if (GLFW.mouseWheelFunc && event.target == Module["canvas"]) { Runtime.dynCall('vi', GLFW.mouseWheelFunc, [GLFW.wheelPos]); event.preventDefault(); } @@ -265,7 +265,7 @@ var LibraryGLFW = { ******************************************************************************/ /* GLFW initialization, termination and version querying */ - glfwInit : function() { + glfwInit: function() { GLFW.initTime = Date.now() / 1000; window.addEventListener("keydown", GLFW.onKeydown, true); @@ -287,7 +287,7 @@ var LibraryGLFW = { window.removeEventListener('DOMMouseScroll', GLFW.onMouseWheel, true); window.removeEventListener('mousewheel', GLFW.onMouseWheel, true); Module["canvas"].width = Module["canvas"].height = 1; - } }); + }}); //TODO: Init with correct values GLFW.params = new Array(); @@ -327,9 +327,9 @@ var LibraryGLFW = { return 1; //GL_TRUE }, - glfwTerminate : function() {}, + glfwTerminate: function() {}, - glfwGetVersion : function( major, minor, rev ) { + glfwGetVersion: function(major, minor, rev) { setValue(major, 2, 'i32'); setValue(minor, 7, 'i32'); setValue(rev, 7, 'i32'); @@ -337,26 +337,26 @@ var LibraryGLFW = { /* Window handling */ glfwOpenWindow__deps: ['$Browser'], - glfwOpenWindow : function( width, height, redbits, greenbits, bluebits, alphabits, depthbits, stencilbits, mode ) { - if(width == 0 && height > 0) { + glfwOpenWindow: function(width, height, redbits, greenbits, bluebits, alphabits, depthbits, stencilbits, mode) { + if (width == 0 && height > 0) { width = 4 * height / 3; } - if(width > 0 && height == 0) { + if (width > 0 && height == 0) { height = 3 * width / 4; } - GLFW.params[0x00020005] = redbits; //GLFW_RED_BITS - GLFW.params[0x00020006] = greenbits; //GLFW_GREEN_BITS - GLFW.params[0x00020007] = bluebits; //GLFW_BLUE_BITS - GLFW.params[0x00020008] = alphabits; //GLFW_ALPHA_BITS - GLFW.params[0x00020009] = depthbits; //GLFW_DEPTH_BITS - GLFW.params[0x0002000A] = stencilbits; //GLFW_STENCIL_BITS - - if(mode == 0x00010001) {//GLFW_WINDOW - Browser.setCanvasSize( GLFW.initWindowWidth = width, - GLFW.initWindowHeight = height ); + GLFW.params[0x00020005] = redbits; //GLFW_RED_BITS + GLFW.params[0x00020006] = greenbits; //GLFW_GREEN_BITS + GLFW.params[0x00020007] = bluebits; //GLFW_BLUE_BITS + GLFW.params[0x00020008] = alphabits; //GLFW_ALPHA_BITS + GLFW.params[0x00020009] = depthbits; //GLFW_DEPTH_BITS + GLFW.params[0x0002000A] = stencilbits; //GLFW_STENCIL_BITS + + if (mode == 0x00010001) {//GLFW_WINDOW + Browser.setCanvasSize(GLFW.initWindowWidth = width, + GLFW.initWindowHeight = height); GLFW.params[0x00030003] = true; //GLFW_STICKY_MOUSE_BUTTONS } - else if(mode == 0x00010002) {//GLFW_FULLSCREEN + else if (mode == 0x00010002) {//GLFW_FULLSCREEN GLFW.requestFullScreen(); GLFW.params[0x00030003] = false; //GLFW_STICKY_MOUSE_BUTTONS } @@ -368,28 +368,28 @@ var LibraryGLFW = { return 1; //GL_TRUE }, - glfwOpenWindowHint : function( target, hint ) { + glfwOpenWindowHint: function(target, hint) { GLFW.params[target] = hint; }, glfwCloseWindow__deps: ['$Browser'], - glfwCloseWindow : function() { + glfwCloseWindow: function() { if (GLFW.closeFunc) { Runtime.dynCall('v', GLFW.closeFunc, []); } Module.ctx = Browser.destroyContext(Module['canvas'], true, true); }, - glfwSetWindowTitle : function( title ) { + glfwSetWindowTitle: function(title) { document.title = Pointer_stringify(title); }, - glfwGetWindowSize : function( width, height ) { + glfwGetWindowSize: function(width, height) { setValue(width, Module['canvas'].width, 'i32'); setValue(height, Module['canvas'].height, 'i32'); }, - glfwSetWindowSize : function( width, height ) { + glfwSetWindowSize: function(width, height) { GLFW.cancelFullScreen(); Browser.setCanvasSize(width, height); if (GLFW.resizeFunc) { @@ -397,127 +397,127 @@ var LibraryGLFW = { } }, - glfwSetWindowPos : function( x, y ) {}, + glfwSetWindowPos: function(x, y) {}, - glfwIconifyWindow : function() {}, + glfwIconifyWindow: function() {}, - glfwRestoreWindow : function() {}, + glfwRestoreWindow: function() {}, - glfwSwapBuffers : function() {}, + glfwSwapBuffers: function() {}, - glfwSwapInterval : function( interval ) {}, + glfwSwapInterval: function(interval) {}, - glfwGetWindowParam : function( param ) { + glfwGetWindowParam: function(param) { return GLFW.params[param]; }, - glfwSetWindowSizeCallback : function( cbfun ) { + glfwSetWindowSizeCallback: function(cbfun) { GLFW.resizeFunc = cbfun; }, - glfwSetWindowCloseCallback : function( cbfun ) { + glfwSetWindowCloseCallback: function(cbfun) { GLFW.closeFunc = cbfun; }, - glfwSetWindowRefreshCallback : function( cbfun ) { + glfwSetWindowRefreshCallback: function(cbfun) { GLFW.refreshFunc = cbfun; }, /* Video mode functions */ - glfwGetVideoModes : function( list, maxcount ) { throw "glfwGetVideoModes is not implemented."; }, + glfwGetVideoModes: function(list, maxcount) { throw "glfwGetVideoModes is not implemented."; }, - glfwGetDesktopMode : function( mode ) { throw "glfwGetDesktopMode is not implemented."; }, + glfwGetDesktopMode: function(mode) { throw "glfwGetDesktopMode is not implemented."; }, /* Input handling */ - glfwPollEvents : function() {}, + glfwPollEvents: function() {}, - glfwWaitEvents : function() {}, + glfwWaitEvents: function() {}, - glfwGetKey : function( key ) { + glfwGetKey: function(key) { return GLFW.keys[key]; }, - glfwGetMouseButton : function( button ) { + glfwGetMouseButton: function(button) { return (GLFW.buttons & (1 << button)) > 0; }, - glfwGetMousePos : function( xpos, ypos ) { + glfwGetMousePos: function(xpos, ypos) { setValue(xpos, GLFW.lastX, 'i32'); setValue(ypos, GLFW.lastY, 'i32'); }, //I believe it is not possible to move the mouse with javascript - glfwSetMousePos : function( xpos, ypos ) {}, + glfwSetMousePos: function(xpos, ypos) {}, - glfwGetMouseWheel : function() { + glfwGetMouseWheel: function() { return GLFW.wheelPos; }, - glfwSetMouseWheel : function( pos ) { + glfwSetMouseWheel: function(pos) { GLFW.wheelPos = pos; }, - glfwSetKeyCallback : function( cbfun ) { + glfwSetKeyCallback: function(cbfun) { GLFW.keyFunc = cbfun; }, - glfwSetCharCallback : function( cbfun ) { + glfwSetCharCallback: function(cbfun) { GLFW.charFunc = cbfun; }, - glfwSetMouseButtonCallback : function( cbfun ) { + glfwSetMouseButtonCallback: function(cbfun) { GLFW.mouseButtonFunc = cbfun; }, - glfwSetMousePosCallback : function( cbfun ) { - GLFW.mousePosFunc = cbfun; + glfwSetMousePosCallback: function(cbfun) { + GLFW.mouse Func = cbfun; }, - glfwSetMouseWheelCallback : function( cbfun ) { + glfwSetMouseWheelCallback: function(cbfun) { GLFW.mouseWheelFunc = cbfun; }, /* Joystick input */ - glfwGetJoystickParam : function( joy, param ) { throw "glfwGetJoystickParam is not implemented."; }, + glfwGetJoystickParam: function(joy, param) { throw "glfwGetJoystickParam is not implemented."; }, - glfwGetJoystickPos : function( joy, pos, numaxes ) { throw "glfwGetJoystickPos is not implemented."; }, + glfwGetJoystickPos: function(joy, pos, numaxes) { throw "glfwGetJoystickPos is not implemented."; }, - glfwGetJoystickButtons : function( joy, buttons, numbuttons ) { throw "glfwGetJoystickButtons is not implemented."; }, + glfwGetJoystickButtons: function(joy, buttons, numbuttons) { throw "glfwGetJoystickButtons is not implemented."; }, /* Time */ - glfwGetTime : function() { + glfwGetTime: function() { return (Date.now()/1000) - GLFW.initTime; }, - glfwSetTime : function( time ) { + glfwSetTime: function(time) { GLFW.initTime = Date.now()/1000 + time; }, glfwSleep__deps: ['sleep'], - glfwSleep : function( time ) { + glfwSleep: function(time) { _sleep(time); }, /* Extension support */ - glfwExtensionSupported : function( extension ) { + glfwExtensionSupported: function(extension) { return Module.ctx.getSupportedExtensions().indexOf(Pointer_stringify(extension)) > -1; }, glfwGetProcAddress__deps: ['glfwGetProcAddress'], - glfwGetProcAddress : function( procname ) { + glfwGetProcAddress: function(procname) { return _getProcAddress(procname); }, - glfwGetGLVersion : function( major, minor, rev ) { + glfwGetGLVersion: function(major, minor, rev) { setValue(major, 0, 'i32'); setValue(minor, 0, 'i32'); setValue(rev, 1, 'i32'); }, /* Threading support */ - glfwCreateThread : function( fun, arg ) { + glfwCreateThread: function(fun, arg) { var str = 'v'; - for(i in arg) { + for (var i in arg) { str += 'i'; } Runtime.dynCall(str, fun, arg); @@ -525,59 +525,59 @@ var LibraryGLFW = { return 0; }, - glfwDestroyThread : function( ID ) {}, + glfwDestroyThread: function(ID) {}, - glfwWaitThread : function( ID, waitmode ) {}, + glfwWaitThread: function(ID, waitmode) {}, - glfwGetThreadID : function() { + glfwGetThreadID: function() { //One single thread return 0; }, - glfwCreateMutex : function() { throw "glfwCreateMutex is not implemented."; }, + glfwCreateMutex: function() { throw "glfwCreateMutex is not implemented."; }, - glfwDestroyMutex : function( mutex ) { throw "glfwDestroyMutex is not implemented."; }, + glfwDestroyMutex: function(mutex) { throw "glfwDestroyMutex is not implemented."; }, - glfwLockMutex : function( mutex ) { throw "glfwLockMutex is not implemented."; }, + glfwLockMutex: function(mutex) { throw "glfwLockMutex is not implemented."; }, - glfwUnlockMutex : function( mutex ) { throw "glfwUnlockMutex is not implemented."; }, + glfwUnlockMutex: function(mutex) { throw "glfwUnlockMutex is not implemented."; }, - glfwCreateCond : function() { throw "glfwCreateCond is not implemented."; }, + glfwCreateCond: function() { throw "glfwCreateCond is not implemented."; }, - glfwDestroyCond : function( cond ) { throw "glfwDestroyCond is not implemented."; }, + glfwDestroyCond: function(cond) { throw "glfwDestroyCond is not implemented."; }, - glfwWaitCond : function( cond, mutex, timeout ) { throw "glfwWaitCond is not implemented."; }, + glfwWaitCond: function(cond, mutex, timeout) { throw "glfwWaitCond is not implemented."; }, - glfwSignalCond : function( cond ) { throw "glfwSignalCond is not implemented."; }, + glfwSignalCond: function(cond) { throw "glfwSignalCond is not implemented."; }, - glfwBroadcastCond : function( cond ) { throw "glfwBroadcastCond is not implemented."; }, + glfwBroadcastCond: function(cond) { throw "glfwBroadcastCond is not implemented."; }, - glfwGetNumberOfProcessors : function() { + glfwGetNumberOfProcessors: function() { //Threads are disabled anyway… return 1; }, /* Enable/disable functions */ - glfwEnable : function( token ) { + glfwEnable: function(token) { GLFW.params[token] = false; }, - glfwDisable : function( token ) { + glfwDisable: function(token) { GLFW.params[token] = true; }, /* Image/texture I/O support */ - glfwReadImage : function( name, img, flags ) { throw "glfwReadImage is not implemented."; }, + glfwReadImage: function(name, img, flags) { throw "glfwReadImage is not implemented."; }, - glfwReadMemoryImage : function( data, size, img, flags ) { throw "glfwReadMemoryImage is not implemented."; }, + glfwReadMemoryImage: function(data, size, img, flags) { throw "glfwReadMemoryImage is not implemented."; }, - glfwFreeImage : function( img ) { throw "glfwFreeImage is not implemented."; }, + glfwFreeImage: function(img) { throw "glfwFreeImage is not implemented."; }, - glfwLoadTexture2D : function( name, flags ) { throw "glfwLoadTexture2D is not implemented."; }, + glfwLoadTexture2D: function(name, flags) { throw "glfwLoadTexture2D is not implemented."; }, - glfwLoadMemoryTexture2D : function( data, size, flags ) { throw "glfwLoadMemoryTexture2D is not implemented."; }, + glfwLoadMemoryTexture2D: function(data, size, flags) { throw "glfwLoadMemoryTexture2D is not implemented."; }, - glfwLoadTextureImage2D : function( img, flags ) { throw "glfwLoadTextureImage2D is not implemented."; }, + glfwLoadTextureImage2D: function(img, flags) { throw "glfwLoadTextureImage2D is not implemented."; }, }; autoAddDeps(LibraryGLFW, '$GLFW'); From cbc15905a139ba81249aed4c8f3d5196e89a0784 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 10:10:40 -0700 Subject: [PATCH 035/544] compress in makePointer only in non-ta2, in preparation for consolidating all ta2 allocations --- src/parseTools.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/parseTools.js b/src/parseTools.js index 6818e44256ea5..671aed6920559 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1472,19 +1472,19 @@ function makePointer(slab, pos, allocator, type, ptr) { } } // compress type info and data if possible - var de; - try { - // compress all-zeros into a number (which will become zeros(..)). - // note that we cannot always eval the slab, e.g., if it contains ident,0,0 etc. In that case, no compression TODO: ensure we get arrays here, not str - var evaled = typeof slab === 'string' ? eval(slab) : slab; - de = dedup(evaled); - if (de.length === 1 && de[0] == 0) { - slab = types.length; - } - // TODO: if not all zeros, at least filter out items with type === 0. requires cleverness to know how to skip at runtime though. also - // be careful of structure padding - } catch(e){} if (USE_TYPED_ARRAYS != 2) { + var de; + try { + // compress all-zeros into a number (which will become zeros(..)). + // note that we cannot always eval the slab, e.g., if it contains ident,0,0 etc. In that case, no compression TODO: ensure we get arrays here, not str + var evaled = typeof slab === 'string' ? eval(slab) : slab; + de = dedup(evaled); + if (de.length === 1 && de[0] == 0) { + slab = types.length; + } + // TODO: if not all zeros, at least filter out items with type === 0. requires cleverness to know how to skip at runtime though. also + // be careful of structure padding + } catch(e){} de = dedup(types); if (de.length === 1) { types = de[0]; From 61cab495da3dd69cc46bef0ae8786ecec8050481 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 10:26:13 -0700 Subject: [PATCH 036/544] refactor vtable extension --- src/jsifier.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 97a2518842a2e..a583da1e016b2 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -311,20 +311,17 @@ function JSify(data, functionsOnly, givenFunctions) { if (!LibraryManager.library[item.ident.slice(1)]) return ret; } + // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations + if (item.ident.substr(0, 5) == '__ZTV') { + constant = constant.concat(zeros(Runtime.alignMemory(constant.length + QUANTUM_SIZE) - constant.length)); + } + // NOTE: This is the only place that could potentially create static // allocations in a shared library. constant = makePointer(constant, null, allocator, item.type, index); - var js; - js = (index !== null ? '' : item.ident + '=') + constant + ';'; + var js = (index !== null ? '' : item.ident + '=') + constant + ';'; - // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations - if (item.ident.substr(0, 5) == '__ZTV') { - if (index !== null) { - index = getFastValue(index, '+', Runtime.alignMemory(calcAllocatedSize(Variables.globals[item.ident].type))); - } - js += '\n' + makePointer([0], null, allocator, ['void*'], index) + ';'; - } if (!ASM_JS && (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS))) { js += '\nModule["' + item.ident + '"] = ' + item.ident + ';'; } From 1e7414017b599d7b3b990922ca905ee679b81ff9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 10:26:32 -0700 Subject: [PATCH 037/544] refactor chunkifying in makePointer --- src/parseTools.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/parseTools.js b/src/parseTools.js index 671aed6920559..2d0be3022cdb5 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1539,7 +1539,6 @@ function makePointer(slab, pos, allocator, type, ptr) { } if (!fail) types = 'i8'; } - if (typeof slab == 'object') slab = '[' + slab.join(',') + ']'; // JS engines sometimes say array initializers are too large. Work around that by chunking and calling concat to combine at runtime var chunkSize = 10240; function chunkify(array) { @@ -1552,9 +1551,10 @@ function makePointer(slab, pos, allocator, type, ptr) { } return ret; } - if (typeof slab == 'string' && evaled && evaled.length > chunkSize && slab.length > chunkSize) { - slab = chunkify(evaled); + if (typeof slab == 'object' && slab.length > chunkSize) { + slab = chunkify(slab); } + if (typeof slab == 'object') slab = '[' + slab.join(',') + ']'; if (typeof types != 'string' && types.length > chunkSize) { types = chunkify(types); } else { From a61d054621e06f41dd760552a6db3d2a38006f90 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 10:31:44 -0700 Subject: [PATCH 038/544] ensure aligned sizes for all constants --- src/jsifier.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/jsifier.js b/src/jsifier.js index a583da1e016b2..88f86d5ba8d9f 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -311,9 +311,12 @@ function JSify(data, functionsOnly, givenFunctions) { if (!LibraryManager.library[item.ident.slice(1)]) return ret; } + // ensure alignment + constant = constant.concat(zeros(Runtime.alignMemory(constant.length) - constant.length)); + // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations if (item.ident.substr(0, 5) == '__ZTV') { - constant = constant.concat(zeros(Runtime.alignMemory(constant.length + QUANTUM_SIZE) - constant.length)); + constant = constant.concat(zeros(Runtime.alignMemory(QUANTUM_SIZE))); } // NOTE: This is the only place that could potentially create static From f1369af42ba67251a291436a1d50494b9c49fe29 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 12:22:21 -0700 Subject: [PATCH 039/544] write out all the initial global allocations as one big ALLOC_NONE --- src/jsifier.js | 15 ++++++++++++--- src/parseTools.js | 23 +++++++++++++++++++++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 88f86d5ba8d9f..aab3296bd7127 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -323,7 +323,8 @@ function JSify(data, functionsOnly, givenFunctions) { // allocations in a shared library. constant = makePointer(constant, null, allocator, item.type, index); - var js = (index !== null ? '' : item.ident + '=') + constant + ';'; + var js = (index !== null ? '' : item.ident + '=') + constant; + if (js) js += ';'; if (!ASM_JS && (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS))) { js += '\nModule["' + item.ident + '"] = ' + item.ident + ';'; @@ -1497,8 +1498,17 @@ function JSify(data, functionsOnly, givenFunctions) { print('assert(STATICTOP < TOTAL_MEMORY);\n'); } } - var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable).concat(itemsDict.GlobalVariablePostSet); + var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable); if (!DEBUG_MEMORY) print(generated.map(function(item) { return item.JS }).join('\n')); + + if (phase == 'pre') { + if (memoryInitialization.length > 0) { + // write out the singleton big memory initialization value + print('/* teh global */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'TOTAL_STACK', true)); // we assert on TOTAL_STACK == GLOBAL_BASE + } + } + + if (!DEBUG_MEMORY) print(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n')); return; } @@ -1520,7 +1530,6 @@ function JSify(data, functionsOnly, givenFunctions) { } }); } - JSify(globalsData, true, Functions); globalsData = null; data.unparsedGlobalss = null; diff --git a/src/parseTools.js b/src/parseTools.js index 2d0be3022cdb5..f5087aa6f3c5e 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1457,7 +1457,9 @@ function makeGetPos(ptr) { var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP'); -function makePointer(slab, pos, allocator, type, ptr) { +var memoryInitialization = []; + +function makePointer(slab, pos, allocator, type, ptr, finalMemoryInitialization) { assert(type, 'makePointer requires type info'); if (typeof slab == 'string' && (slab.substr(0, 4) === 'HEAP' || (USE_TYPED_ARRAYS == 1 && slab in IHEAP_FHEAP))) return pos; var types = generateStructTypes(type); @@ -1515,6 +1517,7 @@ function makePointer(slab, pos, allocator, type, ptr) { if (!currType) { i++; continue } var currSize = 0, currValue = slab[i]; switch (currType) { + case 'i1': case 'i8': i++; continue; case 'i16': temp16[0] = currValue; currSize = 2; break; case 'i64': // fall through, i64 is two i32 chunks @@ -1539,6 +1542,22 @@ function makePointer(slab, pos, allocator, type, ptr) { } if (!fail) types = 'i8'; } + if (allocator == 'ALLOC_NONE') { + if (!finalMemoryInitialization) { + // writing out into memory, without a normal allocation. We put all of these into a single big chunk. + assert(USE_TYPED_ARRAYS == 2); + assert(typeof slab == 'object'); + assert(slab.length % QUANTUM_SIZE == 0, slab.length); // must be aligned already + var offset = ptr - TOTAL_STACK; // we assert on GLOBAL_BASE being equal to TOTAL_STACK + for (var i = 0; i < slab.length; i++) { + memoryInitialization[offset + i] = slab[i]; + } + return ''; + } + // This is the final memory initialization + types = 'i8'; + } + // JS engines sometimes say array initializers are too large. Work around that by chunking and calling concat to combine at runtime var chunkSize = 10240; function chunkify(array) { @@ -1554,12 +1573,12 @@ function makePointer(slab, pos, allocator, type, ptr) { if (typeof slab == 'object' && slab.length > chunkSize) { slab = chunkify(slab); } - if (typeof slab == 'object') slab = '[' + slab.join(',') + ']'; if (typeof types != 'string' && types.length > chunkSize) { types = chunkify(types); } else { types = JSON.stringify(types); } + if (typeof slab == 'object') slab = '[' + slab.join(',') + ']'; return 'allocate(' + slab + ', ' + types + (allocator ? ', ' + allocator : '') + (allocator == 'ALLOC_NONE' ? ', ' + ptr : '') + ')'; } From cce94969bdda8d209dddd69ad68cf883ab085333 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 13:29:49 -0700 Subject: [PATCH 040/544] always flatten out ta2 allocate()ions --- src/parseTools.js | 73 +++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/src/parseTools.js b/src/parseTools.js index f5087aa6f3c5e..6c6a04d43c01f 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1498,49 +1498,46 @@ function makePointer(slab, pos, allocator, type, ptr, finalMemoryInitialization) } } } else { // USE_TYPED_ARRAYS == 2 - var fail = false; - if (typeof slab === 'object') { - // flatten out into i8 values, so we can just to typed array .set() - for (var i = 0; i < slab.length; i++) { - if (!isNumber(slab[i])) { fail = true; break } - } - if (!fail) { - // XXX This heavily assumes the target endianness is the same as our current endianness! XXX - var i = 0; - var temp64f = new Float64Array(1); - var temp32f = new Float32Array(temp64f.buffer); - var temp32 = new Uint32Array(temp64f.buffer); - var temp16 = new Uint16Array(temp64f.buffer); - var temp8 = new Uint8Array(temp64f.buffer); - while (i < slab.length) { - var currType = types[i]; - if (!currType) { i++; continue } - var currSize = 0, currValue = slab[i]; - switch (currType) { - case 'i1': - case 'i8': i++; continue; - case 'i16': temp16[0] = currValue; currSize = 2; break; - case 'i64': // fall through, i64 is two i32 chunks - case 'i32': temp32[0] = currValue; currSize = 4; break; - case 'float': temp32f[0] = currValue; currSize = 4; break; - case 'double': temp64f[0] = currValue; currSize = 8; break; - default: { - if (currType[currType.length-1] == '*') { - temp32[0] = currValue; - currSize = 4; - } else { - throw 'what? ' + types[i]; - } + // XXX This heavily assumes the target endianness is the same as our current endianness! XXX + var i = 0; + var temp64f = new Float64Array(1); + var temp32f = new Float32Array(temp64f.buffer); + var temp32 = new Uint32Array(temp64f.buffer); + var temp16 = new Uint16Array(temp64f.buffer); + var temp8 = new Uint8Array(temp64f.buffer); + while (i < slab.length) { + var currType = types[i]; + if (!currType) { i++; continue } + var currSize = 0, currValue = slab[i]; + switch (currType) { + case 'i1': + case 'i8': i++; continue; + case 'i16': temp16[0] = currValue; currSize = 2; break; + case 'i64': // fall through, i64 is two i32 chunks + case 'i32': temp32[0] = currValue; currSize = 4; break; + case 'float': temp32f[0] = currValue; currSize = 4; break; + case 'double': temp64f[0] = currValue; currSize = 8; break; + default: { + if (currType[currType.length-1] == '*') { + if (!isNumber(currValue)) { // function table stuff, etc. + slab[i] = currValue; + slab[i+1] = slab[i+2] = slab[i+3] = 0; + i += 4; + continue; } + temp32[0] = currValue; + currSize = 4; + } else { + throw 'what? ' + types[i]; } - for (var j = 0; j < currSize; j++) { - slab[i+j] = temp8[j]; - } - i += currSize; } } + for (var j = 0; j < currSize; j++) { + slab[i+j] = temp8[j]; + } + i += currSize; } - if (!fail) types = 'i8'; + types = 'i8'; } if (allocator == 'ALLOC_NONE') { if (!finalMemoryInitialization) { From 93aa89e9e9d8ffe93393bb19e61cf98b5ec298db Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 14:32:21 -0700 Subject: [PATCH 041/544] split function table indexings into 4 Uint8 when in the singleton global allocation --- emscripten.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/emscripten.py b/emscripten.py index c6a08e6a6afaf..a42fe116f5c87 100755 --- a/emscripten.py +++ b/emscripten.py @@ -308,7 +308,12 @@ def load_from_cache(chunk): indexing = forwarded_json['Functions']['indexedFunctions'] def indexize(js): - return re.sub(r"'{{ FI_([\w\d_$]+) }}'", lambda m: str(indexing.get(m.groups(0)[0]) or 0), js) + # In the global initial allocation, we need to split up into Uint8 format + def split_32(x): + x = int(x) + return '%d,%d,%d,%d' % (x&255, (x >> 8)&255, (x >> 16)&255, (x >> 24)&255) + ret = re.sub(r"\"'{{ FI_([\w\d_$]+) }}'\",0,0,0", lambda m: split_32(indexing.get(m.groups(0)[0]) or 0), js) + return re.sub(r"'{{ FI_([\w\d_$]+) }}'", lambda m: str(indexing.get(m.groups(0)[0]) or 0), ret) blockaddrs = forwarded_json['Functions']['blockAddresses'] def blockaddrsize(js): From 538b6b0bcc12c58d841fd11130a9b16cfaf3d81e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 15:46:21 -0700 Subject: [PATCH 042/544] fix s_x_x --- src/parseTools.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/parseTools.js b/src/parseTools.js index 6c6a04d43c01f..95dc46e0881dc 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1539,10 +1539,9 @@ function makePointer(slab, pos, allocator, type, ptr, finalMemoryInitialization) } types = 'i8'; } - if (allocator == 'ALLOC_NONE') { + if (allocator == 'ALLOC_NONE' && USE_TYPED_ARRAYS == 2) { if (!finalMemoryInitialization) { // writing out into memory, without a normal allocation. We put all of these into a single big chunk. - assert(USE_TYPED_ARRAYS == 2); assert(typeof slab == 'object'); assert(slab.length % QUANTUM_SIZE == 0, slab.length); // must be aligned already var offset = ptr - TOTAL_STACK; // we assert on GLOBAL_BASE being equal to TOTAL_STACK From 4fbbfb2d27b64a3eb96851e60d453d59e1e2d6a0 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 15:55:46 -0700 Subject: [PATCH 043/544] make sure allocate() types have the same length as the slab --- src/parseTools.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/parseTools.js b/src/parseTools.js index 95dc46e0881dc..cec9afb34fba5 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1569,6 +1569,9 @@ function makePointer(slab, pos, allocator, type, ptr, finalMemoryInitialization) if (typeof slab == 'object' && slab.length > chunkSize) { slab = chunkify(slab); } + if (typeof types == 'object') { + while (types.length < slab.length) types.push(0); + } if (typeof types != 'string' && types.length > chunkSize) { types = chunkify(types); } else { From 783a1be067b07e311622c8f3263e6e69dc08856e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 16:07:18 -0700 Subject: [PATCH 044/544] be less silly --- src/jsifier.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jsifier.js b/src/jsifier.js index aab3296bd7127..4ad5a76cc7bcf 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1504,7 +1504,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (phase == 'pre') { if (memoryInitialization.length > 0) { // write out the singleton big memory initialization value - print('/* teh global */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'TOTAL_STACK', true)); // we assert on TOTAL_STACK == GLOBAL_BASE + print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'TOTAL_STACK', true)); // we assert on TOTAL_STACK == GLOBAL_BASE } } From 6bf571940d90914453b820153f7f2e2dd5c26e21 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 17:26:59 -0700 Subject: [PATCH 045/544] refactor slab writing in makePointer --- src/jsifier.js | 18 +++++++++++-- src/parseTools.js | 69 ++++++++++++++++++++++++----------------------- 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 4ad5a76cc7bcf..f22d3d883eaed 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1499,16 +1499,30 @@ function JSify(data, functionsOnly, givenFunctions) { } } var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable); - if (!DEBUG_MEMORY) print(generated.map(function(item) { return item.JS }).join('\n')); + print(generated.map(function(item) { return item.JS }).join('\n')); if (phase == 'pre') { if (memoryInitialization.length > 0) { + /* + // apply postsets directly into the big memory initialization + itemsDict.GlobalVariablePostSet = itemsDict.GlobalVariablePostSet.filter(function(item) { + var m + if (m = /^HEAPU?(\d+)\[([()>\d]+)\] *= *([()|\d]+);?$/.exec(item.JS)) { + var bits = +m[1]; + var target = eval(m[2]) << log2(bits/8); + var value = eval(m[3]); + writeInt8s(memoryInitialization, target - TOTAL_STACK, value, 'i' + bits); // XXX floats + return false; + } + return true; + }); + */ // write out the singleton big memory initialization value print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'TOTAL_STACK', true)); // we assert on TOTAL_STACK == GLOBAL_BASE } } - if (!DEBUG_MEMORY) print(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n')); + print(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n')); return; } diff --git a/src/parseTools.js b/src/parseTools.js index cec9afb34fba5..a3b6f79c155d5 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1457,8 +1457,43 @@ function makeGetPos(ptr) { var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP'); +var temp64f = new Float64Array(1); +var temp32f = new Float32Array(temp64f.buffer); +var temp32 = new Uint32Array(temp64f.buffer); +var temp16 = new Uint16Array(temp64f.buffer); +var temp8 = new Uint8Array(temp64f.buffer); var memoryInitialization = []; +function writeInt8s(slab, i, value, type) { + var currSize; + switch (type) { + case 'i1': + case 'i8': temp8[0] = value; currSize = 1; break; + case 'i16': temp16[0] = value; currSize = 2; break; + case 'i64': // fall through, i64 is two i32 chunks + case 'i32': temp32[0] = value; currSize = 4; break; + case 'float': temp32f[0] = value; currSize = 4; break; + case 'double': temp64f[0] = value; currSize = 8; break; + default: { + if (type[type.length-1] == '*') { + if (!isNumber(value)) { // function table stuff, etc. + slab[i] = value; + slab[i+1] = slab[i+2] = slab[i+3] = 0; + return 4; + } + temp32[0] = value; + currSize = 4; + } else { + throw 'what? ' + types[i]; + } + } + } + for (var j = 0; j < currSize; j++) { + slab[i+j] = temp8[j]; + } + return currSize; +} + function makePointer(slab, pos, allocator, type, ptr, finalMemoryInitialization) { assert(type, 'makePointer requires type info'); if (typeof slab == 'string' && (slab.substr(0, 4) === 'HEAP' || (USE_TYPED_ARRAYS == 1 && slab in IHEAP_FHEAP))) return pos; @@ -1500,42 +1535,10 @@ function makePointer(slab, pos, allocator, type, ptr, finalMemoryInitialization) } else { // USE_TYPED_ARRAYS == 2 // XXX This heavily assumes the target endianness is the same as our current endianness! XXX var i = 0; - var temp64f = new Float64Array(1); - var temp32f = new Float32Array(temp64f.buffer); - var temp32 = new Uint32Array(temp64f.buffer); - var temp16 = new Uint16Array(temp64f.buffer); - var temp8 = new Uint8Array(temp64f.buffer); while (i < slab.length) { var currType = types[i]; if (!currType) { i++; continue } - var currSize = 0, currValue = slab[i]; - switch (currType) { - case 'i1': - case 'i8': i++; continue; - case 'i16': temp16[0] = currValue; currSize = 2; break; - case 'i64': // fall through, i64 is two i32 chunks - case 'i32': temp32[0] = currValue; currSize = 4; break; - case 'float': temp32f[0] = currValue; currSize = 4; break; - case 'double': temp64f[0] = currValue; currSize = 8; break; - default: { - if (currType[currType.length-1] == '*') { - if (!isNumber(currValue)) { // function table stuff, etc. - slab[i] = currValue; - slab[i+1] = slab[i+2] = slab[i+3] = 0; - i += 4; - continue; - } - temp32[0] = currValue; - currSize = 4; - } else { - throw 'what? ' + types[i]; - } - } - } - for (var j = 0; j < currSize; j++) { - slab[i+j] = temp8[j]; - } - i += currSize; + i += writeInt8s(slab, i, slab[i], currType); } types = 'i8'; } From b050710a1faa841eb3b0069675059a3fafc36e68 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 17:39:11 -0700 Subject: [PATCH 046/544] do not emit the memory initialization into itself --- src/parseTools.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/parseTools.js b/src/parseTools.js index a3b6f79c155d5..5459fc678f612 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1533,14 +1533,16 @@ function makePointer(slab, pos, allocator, type, ptr, finalMemoryInitialization) } } } else { // USE_TYPED_ARRAYS == 2 - // XXX This heavily assumes the target endianness is the same as our current endianness! XXX - var i = 0; - while (i < slab.length) { - var currType = types[i]; - if (!currType) { i++; continue } - i += writeInt8s(slab, i, slab[i], currType); + if (!finalMemoryInitialization) { + // XXX This heavily assumes the target endianness is the same as our current endianness! XXX + var i = 0; + while (i < slab.length) { + var currType = types[i]; + if (!currType) { i++; continue } + i += writeInt8s(slab, i, slab[i], currType); + } + types = 'i8'; } - types = 'i8'; } if (allocator == 'ALLOC_NONE' && USE_TYPED_ARRAYS == 2) { if (!finalMemoryInitialization) { From 1454df888cd83ad73a84f0c0d2e65ced86ca536a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 18:00:32 -0700 Subject: [PATCH 047/544] pre-apply simple postSets --- src/jsifier.js | 11 +++++------ src/parseTools.js | 11 +++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index f22d3d883eaed..ac3d195534f95 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1503,20 +1503,19 @@ function JSify(data, functionsOnly, givenFunctions) { if (phase == 'pre') { if (memoryInitialization.length > 0) { - /* // apply postsets directly into the big memory initialization itemsDict.GlobalVariablePostSet = itemsDict.GlobalVariablePostSet.filter(function(item) { var m - if (m = /^HEAPU?(\d+)\[([()>\d]+)\] *= *([()|\d]+);?$/.exec(item.JS)) { - var bits = +m[1]; - var target = eval(m[2]) << log2(bits/8); + if (m = /^HEAP([\dFU]+)\[([()>\d]+)\] *= *([()|\d]+);?$/.exec(item.JS)) { + var type = getTypeFromHeap(m[1]); + var bytes = Runtime.getNativeTypeSize(type); + var target = eval(m[2]) << log2(bytes); var value = eval(m[3]); - writeInt8s(memoryInitialization, target - TOTAL_STACK, value, 'i' + bits); // XXX floats + writeInt8s(memoryInitialization, target - TOTAL_STACK, value, type); return false; } return true; }); - */ // write out the singleton big memory initialization value print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'TOTAL_STACK', true)); // we assert on TOTAL_STACK == GLOBAL_BASE } diff --git a/src/parseTools.js b/src/parseTools.js index 5459fc678f612..639c583b0b765 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -2349,3 +2349,14 @@ function charCode(char) { return char.charCodeAt(0); } +function getTypeFromHeap(suffix) { + switch (suffix) { + case '8': return 'i8'; + case '16': return 'i16'; + case '32': return 'i32'; + case 'F32': return 'float'; + case 'F64': return 'double'; + default: throw 'getTypeFromHeap? ' + suffix; + } +} + From 10f70b2a9bd7b0a1fdc3c140bf3c00ebad8420a9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 18:18:18 -0700 Subject: [PATCH 048/544] fix test_strings --- tests/runner.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/runner.py b/tests/runner.py index ef014a1879bb0..b03148f6d6dbf 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -1977,7 +1977,6 @@ def test_strings(self): if self.emcc_args == []: gen = open(self.in_dir('src.cpp.o.js')).read() assert ('var __str1;' in gen) == named - assert (gen.count('ALLOC_NONE') < 8) == named def test_strcmp_uni(self): src = ''' From bae4c91d0acf4fd70e0c17ad178b07d2eb6345d9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 18:37:00 -0700 Subject: [PATCH 049/544] pre-apply {{{ FI_* }}} as well --- emscripten.py | 2 +- src/jsifier.js | 12 +++++++++--- src/parseTools.js | 6 +++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/emscripten.py b/emscripten.py index a42fe116f5c87..8f68ee77e87bf 100755 --- a/emscripten.py +++ b/emscripten.py @@ -312,7 +312,7 @@ def indexize(js): def split_32(x): x = int(x) return '%d,%d,%d,%d' % (x&255, (x >> 8)&255, (x >> 16)&255, (x >> 24)&255) - ret = re.sub(r"\"'{{ FI_([\w\d_$]+) }}'\",0,0,0", lambda m: split_32(indexing.get(m.groups(0)[0]) or 0), js) + ret = re.sub(r"\"?'?{{ FI_([\w\d_$]+) }}'?\"?,0,0,0", lambda m: split_32(indexing.get(m.groups(0)[0]) or 0), js) return re.sub(r"'{{ FI_([\w\d_$]+) }}'", lambda m: str(indexing.get(m.groups(0)[0]) or 0), ret) blockaddrs = forwarded_json['Functions']['blockAddresses'] diff --git a/src/jsifier.js b/src/jsifier.js index ac3d195534f95..ce0893347fb8b 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1505,12 +1505,18 @@ function JSify(data, functionsOnly, givenFunctions) { if (memoryInitialization.length > 0) { // apply postsets directly into the big memory initialization itemsDict.GlobalVariablePostSet = itemsDict.GlobalVariablePostSet.filter(function(item) { - var m - if (m = /^HEAP([\dFU]+)\[([()>\d]+)\] *= *([()|\d]+);?$/.exec(item.JS)) { + var m; + if (m = /^HEAP([\dFU]+)\[([()>\d]+)\] *= *([()|\d{}\w_' ]+);?$/.exec(item.JS)) { var type = getTypeFromHeap(m[1]); var bytes = Runtime.getNativeTypeSize(type); var target = eval(m[2]) << log2(bytes); - var value = eval(m[3]); + var value = m[3]; + try { + value = eval(value); + } catch(e) { + // possibly function table {{{ FT_* }}} etc. + if (value.indexOf('{{ ') < 0) return true; + } writeInt8s(memoryInitialization, target - TOTAL_STACK, value, type); return false; } diff --git a/src/parseTools.js b/src/parseTools.js index 639c583b0b765..200490942030c 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1470,12 +1470,12 @@ function writeInt8s(slab, i, value, type) { case 'i1': case 'i8': temp8[0] = value; currSize = 1; break; case 'i16': temp16[0] = value; currSize = 2; break; - case 'i64': // fall through, i64 is two i32 chunks - case 'i32': temp32[0] = value; currSize = 4; break; case 'float': temp32f[0] = value; currSize = 4; break; case 'double': temp64f[0] = value; currSize = 8; break; + case 'i64': // fall through, i64 is two i32 chunks + case 'i32': // fall through, i32 can be a pointer default: { - if (type[type.length-1] == '*') { + if (type == 'i32' || type == 'i64' || type[type.length-1] == '*') { if (!isNumber(value)) { // function table stuff, etc. slab[i] = value; slab[i+1] = slab[i+2] = slab[i+3] = 0; From 875f21cc7d636b35332f36b87e479c9848bdb4ca Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 20:58:18 -0700 Subject: [PATCH 050/544] fix --- src/library_glfw.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index a709161a25e7f..71552cd8eafc6 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -470,7 +470,7 @@ var LibraryGLFW = { }, glfwSetMousePosCallback: function(cbfun) { - GLFW.mouse Func = cbfun; + GLFW.mouseFunc = cbfun; }, glfwSetMouseWheelCallback: function(cbfun) { From ef96768ac8a4ef3af360e0d0ad32706e21eb4d11 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Apr 2013 21:02:49 -0700 Subject: [PATCH 051/544] detect file suffixes of all lengths --- src/library_browser.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/library_browser.js b/src/library_browser.js index b1e4190b4c9a4..099516a864553 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -75,8 +75,7 @@ mergeInto(LibraryManager.library, { 'ogg': 'audio/ogg', 'wav': 'audio/wav', 'mp3': 'audio/mpeg' - }[name.substr(-3)]; - return ret; + }[name.substr(name.lastIndexOf('.')+1)]; } if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; From cfdcb60c150ca586ad010e634eccc0f7336707e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Fri, 29 Mar 2013 13:07:26 +0100 Subject: [PATCH 052/544] Added alcGetContextsDevice and alcGetCurrentContext functions. Added alcMakeContextCurrent return values. --- src/library_openal.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/library_openal.js b/src/library_openal.js index 0b6e9b2f2e1f0..2f657f4f07aba 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -13,11 +13,23 @@ var LibraryOpenAL = { alcMakeContextCurrent: function(context) { if (context == 0) { AL.currentContext = null; + return 0; } else { AL.currentContext = AL.contexts[context - 1]; + return 1; } }, + alcGetContextsDevice: function(context){ + if(context < Al.contexts.length && context >= 0) + return 1; + return 0; + }, + + alcGetCurrentContext: function(){ + return AL.currentContext; + }, + alcDestroyContext: function(context) { // Stop playback, etc }, From 727c68db5fcd62fa797ef8cf72e57b6b7746dc9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Tue, 2 Apr 2013 11:42:23 +0200 Subject: [PATCH 053/544] * Spaces and indentation. --- src/library_openal.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/library_openal.js b/src/library_openal.js index 2f657f4f07aba..5e76eee6a9fa9 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -20,13 +20,15 @@ var LibraryOpenAL = { } }, - alcGetContextsDevice: function(context){ - if(context < Al.contexts.length && context >= 0) + alcGetContextsDevice: function(context) { + if (context < AL.contexts.length && context >= 0) { + // Returns the only one audio device return 1; + } return 0; }, - alcGetCurrentContext: function(){ + alcGetCurrentContext: function() { return AL.currentContext; }, From 1ccc910e34f9c6e874848cecdd2c5d48eb27a981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Tue, 2 Apr 2013 16:03:00 +0200 Subject: [PATCH 054/544] * Fixed alcGetCurrentContext. --- src/library_openal.js | 187 ++++++++++++++++++++---------------------- 1 file changed, 91 insertions(+), 96 deletions(-) diff --git a/src/library_openal.js b/src/library_openal.js index 5e76eee6a9fa9..87393291ca027 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -4,24 +4,19 @@ var LibraryOpenAL = { $AL__deps: ['$Browser'], $AL: { contexts: [], - currentContext: null, + currentContext: 0, }, alcProcessContext: function(context) {}, alcSuspendContext: function(context) {}, alcMakeContextCurrent: function(context) { - if (context == 0) { - AL.currentContext = null; - return 0; - } else { - AL.currentContext = AL.contexts[context - 1]; - return 1; - } + AL.currentContext = context; + return (context > 0); }, alcGetContextsDevice: function(context) { - if (context < AL.contexts.length && context >= 0) { + if (context <= AL.contexts.length && context > 0) { // Returns the only one audio device return 1; } @@ -79,10 +74,10 @@ var LibraryOpenAL = { }, alGetError: function() { - if (!AL.currentContext) { + if (AL.currentContext == 0) { return 0xA004 /* AL_INVALID_OPERATION */; } else { - return AL.currentContext.err; + return AL.contexts[AL.currentContext -1].err; } }, @@ -94,7 +89,7 @@ var LibraryOpenAL = { alDeleteSources: function(count, sources) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alDeleteSources called without a valid context"); #endif @@ -102,26 +97,26 @@ var LibraryOpenAL = { } for (var i = 0; i < count; ++i) { var sourceIdx = {{{ makeGetValue('sources', 'i*4', 'i32') }}} - 1; - delete AL.currentContext.src[sourceIdx]; + delete AL.contexts[AL.currentContext -1].src[sourceIdx]; } }, alGenSources: function(count, sources) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alGenSources called without a valid context"); #endif return; } for (var i = 0; i < count; ++i) { - var gain = AL.currentContext.ctx.createGain(); - var panner = AL.currentContext.ctx.createPanner(); + var gain = AL.contexts[AL.currentContext -1].ctx.createGain(); + var panner = AL.contexts[AL.currentContext -1].ctx.createPanner(); panner.panningModel = "equalpower"; panner.distanceModel = "linear"; panner.rolloffFactor = 0.3; gain.connect(panner); - panner.connect(AL.currentContext.ctx.destination); - AL.currentContext.src.push({ + panner.connect(AL.contexts[AL.currentContext -1].ctx.destination); + AL.contexts[AL.currentContext -1].src.push({ loop: false, buffer: null, gain: gain, @@ -130,18 +125,18 @@ var LibraryOpenAL = { playTime: -1, pausedTime: 0 }); - {{{ makeSetValue('sources', 'i*4', 'AL.currentContext.src.length', 'i32') }}}; + {{{ makeSetValue('sources', 'i*4', 'AL.contexts[AL.currentContext -1].src.length', 'i32') }}}; } }, alSourcei: function(source, param, value) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alSourcei called without a valid context"); #endif return; } - if (source > AL.currentContext.src.length) { + if (source > AL.contexts[AL.currentContext -1].src.length) { #if OPENAL_DEBUG console.error("alSourcei called with an invalid source"); #endif @@ -149,13 +144,13 @@ var LibraryOpenAL = { } switch (param) { case 0x1007 /* AL_LOOPING */: - AL.currentContext.src[source - 1].loop = (value != 0 /* AL_FALSE */); + AL.contexts[AL.currentContext -1].src[source - 1].loop = (value != 0 /* AL_FALSE */); break; case 0x1009 /* AL_BUFFER */: if (value == 0) { - AL.currentContext.src[source - 1].buffer = null; + AL.contexts[AL.currentContext -1].src[source - 1].buffer = null; } else { - AL.currentContext.src[source - 1].buffer = AL.currentContext.buf[value - 1].buf; + AL.contexts[AL.currentContext -1].src[source - 1].buffer = AL.contexts[AL.currentContext -1].buf[value - 1].buf; } break; default: @@ -167,13 +162,13 @@ var LibraryOpenAL = { }, alSourcef: function(source, param, value) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alSourcef called without a valid context"); #endif return; } - if (source > AL.currentContext.src.length) { + if (source > AL.contexts[AL.currentContext -1].src.length) { #if OPENAL_DEBUG console.error("alSourcef called with an invalid source"); #endif @@ -181,7 +176,7 @@ var LibraryOpenAL = { } switch (param) { case 0x100A /* AL_GAIN */: - AL.currentContext.src[source - 1].gain.gain.value = value; + AL.contexts[AL.currentContext -1].src[source - 1].gain.gain.value = value; break; case 0x1003 /* AL_PITCH */: #if OPENAL_DEBUG @@ -197,13 +192,13 @@ var LibraryOpenAL = { }, alSourcefv: function(source, param, value) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alSourcefv called without a valid context"); #endif return; } - if (source > AL.currentContext.src.length) { + if (source > AL.contexts[AL.currentContext -1].src.length) { #if OPENAL_DEBUG console.error("alSourcefv called with an invalid source"); #endif @@ -211,14 +206,14 @@ var LibraryOpenAL = { } switch (param) { case 0x1004 /* AL_POSITION */: - AL.currentContext.src[source - 1].panner.setPosition( + AL.contexts[AL.currentContext -1].src[source - 1].panner.setPosition( {{{ makeGetValue('value', '0', 'float') }}}, {{{ makeGetValue('value', '4', 'float') }}}, {{{ makeGetValue('value', '8', 'float') }}} ); break; case 0x1006 /* AL_VELOCITY */: - AL.currentContext.src[source - 1].panner.setVelocity( + AL.contexts[AL.currentContext -1].src[source - 1].panner.setVelocity( {{{ makeGetValue('value', '0', 'float') }}}, {{{ makeGetValue('value', '4', 'float') }}}, {{{ makeGetValue('value', '8', 'float') }}} @@ -233,13 +228,13 @@ var LibraryOpenAL = { }, alSourceQueueBuffers: function(source, count, buffers) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alSourceQueueBuffers called without a valid context"); #endif return; } - if (source > AL.currentContext.src.length) { + if (source > AL.contexts[AL.currentContext -1].src.length) { #if OPENAL_DEBUG console.error("alSourceQueueBuffers called with an invalid source"); #endif @@ -253,25 +248,25 @@ var LibraryOpenAL = { } for (var i = 0; i < count; ++i) { var buffer = {{{ makeGetValue('buffers', 'i*4', 'i32') }}}; - if (buffer > AL.currentContext.buf.length) { + if (buffer > AL.contexts[AL.currentContext -1].buf.length) { #if OPENAL_DEBUG console.error("alSourceQueueBuffers called with an invalid buffer"); #endif return; } - AL.currentContext.src[source - 1].buffer = AL.currentContext.buf[buffer - 1].buf; + AL.contexts[AL.currentContext -1].src[source - 1].buffer = AL.contexts[AL.currentContext -1].buf[buffer - 1].buf; } }, alSourceUnqueueBuffers: function(source, count, buffers) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alSourceUnqueueBuffers called without a valid context"); #endif return; } - if (source > AL.currentContext.src.length) { + if (source > AL.contexts[AL.currentContext -1].src.length) { #if OPENAL_DEBUG console.error("alSourceUnqueueBuffers called with an invalid source"); #endif @@ -284,11 +279,11 @@ var LibraryOpenAL = { return; } for (var i = 0; i < count; ++i) { - var buffer = AL.currentContext.src[source - 1].buffer; - for (var j = 0; j < AL.currentContext.buf.length; ++j) { - if (buffer == AL.currentContext.buf[j].buf) { + var buffer = AL.contexts[AL.currentContext -1].src[source - 1].buffer; + for (var j = 0; j < AL.contexts[AL.currentContext -1].buf.length; ++j) { + if (buffer == AL.contexts[AL.currentContext -1].buf[j].buf) { {{{ makeSetValue('buffers', 'i*4', 'j+1', 'i32') }}}; - AL.currentContext.src[source - 1].buffer = null; + AL.contexts[AL.currentContext -1].src[source - 1].buffer = null; break; } } @@ -297,7 +292,7 @@ var LibraryOpenAL = { alDeleteBuffers: function(count, buffers) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alDeleteBuffers called without a valid context"); #endif @@ -305,38 +300,38 @@ var LibraryOpenAL = { } for (var i = 0; i < count; ++i) { var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}} - 1; - var buffer = AL.currentContext.buf[bufferIdx].buf; - for (var j = 0; j < AL.currentContext.src.length; ++j) { - if (buffer == AL.currentContext.src[j].buffer) { - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; + var buffer = AL.contexts[AL.currentContext -1].buf[bufferIdx].buf; + for (var j = 0; j < AL.contexts[AL.currentContext -1].src.length; ++j) { + if (buffer == AL.contexts[AL.currentContext -1].src[j].buffer) { + AL.contexts[AL.currentContext -1].err = 0xA004 /* AL_INVALID_OPERATION */; return; } } - delete AL.currentContext.buf[bufferIdx]; + delete AL.contexts[AL.currentContext -1].buf[bufferIdx]; } }, alGenBuffers: function(count, buffers) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alGenBuffers called without a valid context"); #endif return; } for (var i = 0; i < count; ++i) { - AL.currentContext.buf.push({buf: null}); - {{{ makeSetValue('buffers', 'i*4', 'AL.currentContext.buf.length', 'i32') }}}; + AL.contexts[AL.currentContext -1].buf.push({buf: null}); + {{{ makeSetValue('buffers', 'i*4', 'AL.contexts[AL.currentContext -1].buf.length', 'i32') }}}; } }, alBufferData: function(buffer, format, data, size, freq) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alBufferData called without a valid context"); #endif return; } - if (buffer > AL.currentContext.buf.length) { + if (buffer > AL.contexts[AL.currentContext -1].buf.length) { #if OPENAL_DEBUG console.error("alBufferData called with an invalid buffer"); #endif @@ -366,10 +361,10 @@ var LibraryOpenAL = { #endif return; } - AL.currentContext.buf[buffer - 1].buf = AL.currentContext.ctx.createBuffer(channels, size / (bytes * channels), freq); + AL.contexts[AL.currentContext -1].buf[buffer - 1].buf = AL.contexts[AL.currentContext -1].ctx.createBuffer(channels, size / (bytes * channels), freq); var buf = new Array(channels); for (var i = 0; i < channels; ++i) { - buf[i] = AL.currentContext.buf[buffer - 1].buf.getChannelData(i); + buf[i] = AL.contexts[AL.currentContext -1].buf[buffer - 1].buf.getChannelData(i); } for (var i = 0; i < size / (bytes * channels); ++i) { for (var j = 0; j < channels; ++j) { @@ -389,91 +384,91 @@ var LibraryOpenAL = { alSourcePlay__deps: ["alSourceStop"], alSourcePlay: function(source) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alSourcePlay called without a valid context"); #endif return; } - if (source > AL.currentContext.src.length) { + if (source > AL.contexts[AL.currentContext -1].src.length) { #if OPENAL_DEBUG console.error("alSourcePlay called with an invalid source"); #endif return; } var offset = 0; - if ("src" in AL.currentContext.src[source - 1] && - AL.currentContext.src[source - 1]["src"].buffer == - AL.currentContext.src[source - 1].buffer) { - if (AL.currentContext.src[source - 1].paused) { + if ("src" in AL.contexts[AL.currentContext -1].src[source - 1] && + AL.contexts[AL.currentContext -1].src[source - 1]["src"].buffer == + AL.contexts[AL.currentContext -1].src[source - 1].buffer) { + if (AL.contexts[AL.currentContext -1].src[source - 1].paused) { // So now we have to resume playback, remember the offset here. - offset = AL.currentContext.src[source - 1].pausedTime - - AL.currentContext.src[source - 1].playTime; + offset = AL.contexts[AL.currentContext -1].src[source - 1].pausedTime - + AL.contexts[AL.currentContext -1].src[source - 1].playTime; } else { // If the source is already playing, we need to resume from beginning. // We do that by stopping the current source and replaying it. _alSourceStop(source); } } - var src = AL.currentContext.ctx.createBufferSource(); - src.loop = AL.currentContext.src[source - 1].loop; - src.buffer = AL.currentContext.src[source - 1].buffer; - src.connect(AL.currentContext.src[source - 1].gain); + var src = AL.contexts[AL.currentContext -1].ctx.createBufferSource(); + src.loop = AL.contexts[AL.currentContext -1].src[source - 1].loop; + src.buffer = AL.contexts[AL.currentContext -1].src[source - 1].buffer; + src.connect(AL.contexts[AL.currentContext -1].src[source - 1].gain); src.start(0, offset); - AL.currentContext.src[source - 1].playTime = AL.currentContext.ctx.currentTime; - AL.currentContext.src[source - 1].paused = false; - AL.currentContext.src[source - 1]['src'] = src; + AL.contexts[AL.currentContext -1].src[source - 1].playTime = AL.contexts[AL.currentContext -1].ctx.currentTime; + AL.contexts[AL.currentContext -1].src[source - 1].paused = false; + AL.contexts[AL.currentContext -1].src[source - 1]['src'] = src; }, alSourceStop: function(source) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alSourceStop called without a valid context"); #endif return; } - if (source > AL.currentContext.src.length) { + if (source > AL.contexts[AL.currentContext -1].src.length) { #if OPENAL_DEBUG console.error("alSourceStop called with an invalid source"); #endif return; } - if ("src" in AL.currentContext.src[source - 1]) { - AL.currentContext.src[source - 1]["src"].stop(0); - delete AL.currentContext.src[source - 1]["src"]; + if ("src" in AL.contexts[AL.currentContext -1].src[source - 1]) { + AL.contexts[AL.currentContext -1].src[source - 1]["src"].stop(0); + delete AL.contexts[AL.currentContext -1].src[source - 1]["src"]; } }, alSourcePause: function(source) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alSourcePause called without a valid context"); #endif return; } - if (source > AL.currentContext.src.length) { + if (source > AL.contexts[AL.currentContext -1].src.length) { #if OPENAL_DEBUG console.error("alSourcePause called with an invalid source"); #endif return; } - if ("src" in AL.currentContext.src[source - 1] && - !AL.currentContext.src[source - 1].paused) { - AL.currentContext.src[source - 1].paused = true; - AL.currentContext.src[source - 1].pausedTime = AL.currentContext.ctx.currentTime; - AL.currentContext.src[source - 1]["src"].stop(0); - delete AL.currentContext.src[source - 1].src; + if ("src" in AL.contexts[AL.currentContext -1].src[source - 1] && + !AL.contexts[AL.currentContext -1].src[source - 1].paused) { + AL.contexts[AL.currentContext -1].src[source - 1].paused = true; + AL.contexts[AL.currentContext -1].src[source - 1].pausedTime = AL.contexts[AL.currentContext -1].ctx.currentTime; + AL.contexts[AL.currentContext -1].src[source - 1]["src"].stop(0); + delete AL.contexts[AL.currentContext -1].src[source - 1].src; } }, alGetSourcei: function(source, param, value) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alGetSourcei called without a valid context"); #endif return; } - if (source > AL.currentContext.src.length) { + if (source > AL.contexts[AL.currentContext -1].src.length) { #if OPENAL_DEBUG console.error("alGetSourcei called with an invalid source"); #endif @@ -485,12 +480,12 @@ var LibraryOpenAL = { {{{ makeSetValue('value', '0', '1', 'i32') }}}; break; case 0x1009 /* AL_BUFFER */: - if (AL.currentContext.src[source - 1].buffer == null) { + if (AL.contexts[AL.currentContext -1].src[source - 1].buffer == null) { {{{ makeSetValue('value', '0', '0', 'i32') }}}; } else { - var buf = AL.currentContext.src[source - 1].buffer; - for (var i = 0; i < AL.currentContext.buf.length; ++i) { - if (buf == AL.currentContext.buf[i].buf) { + var buf = AL.contexts[AL.currentContext -1].src[source - 1].buffer; + for (var i = 0; i < AL.contexts[AL.currentContext -1].buf.length; ++i) { + if (buf == AL.contexts[AL.currentContext -1].buf[i].buf) { {{{ makeSetValue('value', '0', 'i+1', 'i32') }}}; return; } @@ -499,18 +494,18 @@ var LibraryOpenAL = { } break; case 0x1010 /* AL_SOURCE_STATE */: - if ("src" in AL.currentContext.src[source - 1]) { + if ("src" in AL.contexts[AL.currentContext -1].src[source - 1]) { {{{ makeSetValue('value', '0', '0x1012', 'i32') }}} /* AL_PLAYING */; - } else if (AL.currentContext.src[source - 1].paused) { + } else if (AL.contexts[AL.currentContext -1].src[source - 1].paused) { {{{ makeSetValue('value', '0', '0x1013', 'i32') }}} /* AL_PAUSED */; - } else if (AL.currentContext.src[source - 1].playTime == -1) { + } else if (AL.contexts[AL.currentContext -1].src[source - 1].playTime == -1) { {{{ makeSetValue('value', '0', '0x1011', 'i32') }}} /* AL_INITIAL */; } else { {{{ makeSetValue('value', '0', '0x1014', 'i32') }}} /* AL_STOPPED */; } break; case 0x1015 /* AL_BUFFERS_QUEUED */: - if (AL.currentContext.src[source - 1].buffer) { + if (AL.contexts[AL.currentContext -1].src[source - 1].buffer) { {{{ makeSetValue('value', '0', '1', 'i32') }}} } else { {{{ makeSetValue('value', '0', '0', 'i32') }}} @@ -532,7 +527,7 @@ var LibraryOpenAL = { }, alListenerfv: function(param, values) { - if (!AL.currentContext) { + if (AL.currentContext == 0) { #if OPENAL_DEBUG console.error("alListenerfv called without a valid context"); #endif @@ -540,21 +535,21 @@ var LibraryOpenAL = { } switch (param) { case 0x1004 /* AL_POSITION */: - AL.currentContext.ctx.listener.setPosition( + AL.contexts[AL.currentContext -1].ctx.listener.setPosition( {{{ makeGetValue('values', '0', 'float') }}}, {{{ makeGetValue('values', '4', 'float') }}}, {{{ makeGetValue('values', '8', 'float') }}} ); break; case 0x1006 /* AL_VELOCITY */: - AL.currentContext.ctx.listener.setVelocity( + AL.contexts[AL.currentContext -1].ctx.listener.setVelocity( {{{ makeGetValue('values', '0', 'float') }}}, {{{ makeGetValue('values', '4', 'float') }}}, {{{ makeGetValue('values', '8', 'float') }}} ); break; case 0x100F /* AL_ORIENTATION */: - AL.currentContext.ctx.listener.setOrientation( + AL.contexts[AL.currentContext -1].ctx.listener.setOrientation( {{{ makeGetValue('values', '0', 'float') }}}, {{{ makeGetValue('values', '4', 'float') }}}, {{{ makeGetValue('values', '8', 'float') }}}, From 783959338a8ea3f380c7287efd7d2bf151b6e140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Wed, 3 Apr 2013 11:20:35 +0200 Subject: [PATCH 055/544] * Added some guards. --- src/library_openal.js | 56 ++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/library_openal.js b/src/library_openal.js index 87393291ca027..3141974eaeeed 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -74,7 +74,7 @@ var LibraryOpenAL = { }, alGetError: function() { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { return 0xA004 /* AL_INVALID_OPERATION */; } else { return AL.contexts[AL.currentContext -1].err; @@ -89,7 +89,7 @@ var LibraryOpenAL = { alDeleteSources: function(count, sources) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alDeleteSources called without a valid context"); #endif @@ -102,7 +102,7 @@ var LibraryOpenAL = { }, alGenSources: function(count, sources) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alGenSources called without a valid context"); #endif @@ -130,7 +130,7 @@ var LibraryOpenAL = { }, alSourcei: function(source, param, value) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alSourcei called without a valid context"); #endif @@ -162,7 +162,7 @@ var LibraryOpenAL = { }, alSourcef: function(source, param, value) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alSourcef called without a valid context"); #endif @@ -176,7 +176,9 @@ var LibraryOpenAL = { } switch (param) { case 0x100A /* AL_GAIN */: - AL.contexts[AL.currentContext -1].src[source - 1].gain.gain.value = value; + if (AL.contexts[AL.currentContext -1].src[source - 1]) { + AL.contexts[AL.currentContext -1].src[source - 1].gain.gain.value = value; + } break; case 0x1003 /* AL_PITCH */: #if OPENAL_DEBUG @@ -192,7 +194,7 @@ var LibraryOpenAL = { }, alSourcefv: function(source, param, value) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alSourcefv called without a valid context"); #endif @@ -228,7 +230,7 @@ var LibraryOpenAL = { }, alSourceQueueBuffers: function(source, count, buffers) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alSourceQueueBuffers called without a valid context"); #endif @@ -260,7 +262,7 @@ var LibraryOpenAL = { alSourceUnqueueBuffers: function(source, count, buffers) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alSourceUnqueueBuffers called without a valid context"); #endif @@ -292,7 +294,7 @@ var LibraryOpenAL = { alDeleteBuffers: function(count, buffers) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alDeleteBuffers called without a valid context"); #endif @@ -300,19 +302,21 @@ var LibraryOpenAL = { } for (var i = 0; i < count; ++i) { var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}} - 1; - var buffer = AL.contexts[AL.currentContext -1].buf[bufferIdx].buf; - for (var j = 0; j < AL.contexts[AL.currentContext -1].src.length; ++j) { - if (buffer == AL.contexts[AL.currentContext -1].src[j].buffer) { - AL.contexts[AL.currentContext -1].err = 0xA004 /* AL_INVALID_OPERATION */; - return; + if (bufferIdx < AL.contexts[AL.currentContext -1].buf.length && AL.contexts[AL.currentContext -1].buf[bufferIdx]) { + var buffer = AL.contexts[AL.currentContext -1].buf[bufferIdx].buf; + for (var j = 0; j < AL.contexts[AL.currentContext -1].src.length; ++j) { + if (buffer == AL.contexts[AL.currentContext -1].src[j].buffer) { + AL.contexts[AL.currentContext -1].err = 0xA004 /* AL_INVALID_OPERATION */; + return; + } } + delete AL.contexts[AL.currentContext -1].buf[bufferIdx]; } - delete AL.contexts[AL.currentContext -1].buf[bufferIdx]; } }, alGenBuffers: function(count, buffers) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alGenBuffers called without a valid context"); #endif @@ -325,7 +329,7 @@ var LibraryOpenAL = { }, alBufferData: function(buffer, format, data, size, freq) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alBufferData called without a valid context"); #endif @@ -384,7 +388,7 @@ var LibraryOpenAL = { alSourcePlay__deps: ["alSourceStop"], alSourcePlay: function(source) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alSourcePlay called without a valid context"); #endif @@ -421,7 +425,7 @@ var LibraryOpenAL = { }, alSourceStop: function(source) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0|| !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alSourceStop called without a valid context"); #endif @@ -433,14 +437,14 @@ var LibraryOpenAL = { #endif return; } - if ("src" in AL.contexts[AL.currentContext -1].src[source - 1]) { + if (AL.contexts[AL.currentContext -1].src[source - 1] && "src" in AL.contexts[AL.currentContext -1].src[source - 1]) { AL.contexts[AL.currentContext -1].src[source - 1]["src"].stop(0); delete AL.contexts[AL.currentContext -1].src[source - 1]["src"]; } }, alSourcePause: function(source) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alSourcePause called without a valid context"); #endif @@ -462,7 +466,7 @@ var LibraryOpenAL = { }, alGetSourcei: function(source, param, value) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alGetSourcei called without a valid context"); #endif @@ -527,7 +531,7 @@ var LibraryOpenAL = { }, alListenerfv: function(param, values) { - if (AL.currentContext == 0) { + if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { #if OPENAL_DEBUG console.error("alListenerfv called without a valid context"); #endif @@ -581,6 +585,10 @@ var LibraryOpenAL = { alcGetProcAddress: function(device, fname) { return 0; }, + + alSourceRewind: function(source) { + + } }; autoAddDeps(LibraryOpenAL, '$AL'); From 4aa4db6f10f3a065a0f20942fa671ffff5b9ae05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Thu, 4 Apr 2013 23:28:51 +0200 Subject: [PATCH 056/544] * Added freealut testcase. --- tests/freealut/AUTHORS | 14 + tests/freealut/CMakeLists.txt | 208 + tests/freealut/COPYING | 483 + tests/freealut/ChangeLog | 786 + tests/freealut/INSTALL | 236 + tests/freealut/Makefile.am | 57 + tests/freealut/Makefile.in | 690 + tests/freealut/NEWS | 34 + tests/freealut/README | 188 + tests/freealut/aclocal.m4 | 6886 +++++ .../CMakeModules/FindCompilerAttribute.cmake | 11 + .../CMakeModules/FindCompilerFlagsSet.cmake | 34 + .../CMakeModules/FindCompilerVisibility.cmake | 37 + .../admin/CMakeModules/FindConfigHelper.cmake | 22 + .../CMakeModules/FindSleepFunction.cmake | 40 + tests/freealut/admin/Makefile.am | 2 + tests/freealut/admin/Makefile.in | 484 + tests/freealut/admin/RPM/freealut.spec | 103 + tests/freealut/admin/RPM/freealut.spec.in | 103 + tests/freealut/admin/VisualStudio6/alut.dsw | 59 + .../admin/VisualStudio6/alut/alut.dsp | 150 + .../VisualStudio6/hello_world/hello_world.dsp | 93 + .../admin/VisualStudio6/playfile/playfile.dsp | 93 + .../admin/VisualStudioDotNET/alut.sln | 35 + .../admin/VisualStudioDotNET/alut/alut.vcproj | 161 + .../hello_world/hello_world.vcproj | 118 + .../playfile/playfile.vcproj | 118 + tests/freealut/admin/autotools/.indent.pro | 46 + tests/freealut/admin/autotools/compile | 142 + tests/freealut/admin/autotools/config.guess | 1469 + tests/freealut/admin/autotools/config.sub | 1563 ++ tests/freealut/admin/autotools/depcomp | 529 + tests/freealut/admin/autotools/install-sh | 323 + tests/freealut/admin/autotools/ltmain.sh | 6460 +++++ .../admin/autotools/m4/alut_c__attribute.m4 | 16 + .../autotools/m4/alut_check_cflags_wall.m4 | 120 + .../admin/autotools/m4/alut_check_flag.m4 | 28 + .../admin/autotools/m4/alut_check_func.m4 | 15 + .../admin/autotools/m4/alut_eval_stderr.m4 | 11 + tests/freealut/admin/autotools/missing | 357 + tests/freealut/admin/pkgconfig/Makefile.am | 3 + tests/freealut/admin/pkgconfig/Makefile.in | 388 + .../admin/pkgconfig/freealut-config.in | 174 + tests/freealut/admin/pkgconfig/freealut.pc.in | 11 + tests/freealut/autogen.sh | 2 + tests/freealut/config.h.in | 116 + tests/freealut/configure | 22839 ++++++++++++++++ tests/freealut/configure.ac | 219 + tests/freealut/doc/alut.css | 45 + tests/freealut/doc/alut.html | 1399 + tests/freealut/examples/Makefile.am | 8 + tests/freealut/examples/Makefile.in | 451 + tests/freealut/examples/hello_world.c | 23 + tests/freealut/examples/playfile.c | 81 + tests/freealut/include/AL/alut.h | 133 + tests/freealut/include/Makefile.am | 1 + tests/freealut/include/Makefile.in | 408 + tests/freealut/src/Makefile.am | 32 + tests/freealut/src/Makefile.in | 584 + tests/freealut/src/README | 13 + tests/freealut/src/alutBufferData.c | 136 + tests/freealut/src/alutCodec.c | 119 + tests/freealut/src/alutError.c | 92 + tests/freealut/src/alutInit.c | 154 + tests/freealut/src/alutInputStream.c | 236 + tests/freealut/src/alutInternal.h | 121 + tests/freealut/src/alutLoader.c | 493 + tests/freealut/src/alutOutputStream.c | 89 + tests/freealut/src/alutUtil.c | 141 + tests/freealut/src/alutVersion.c | 11 + tests/freealut/src/alutWaveform.c | 912 + tests/freealut/src/helloworld.wav | Bin 0 -> 65462 bytes tests/freealut/test_suite/Makefile.am | 27 + tests/freealut/test_suite/Makefile.in | 513 + tests/freealut/test_suite/README | 33 + tests/freealut/test_suite/file1.wav | Bin 0 -> 6246 bytes tests/freealut/test_suite/file2.au | Bin 0 -> 6400 bytes tests/freealut/test_suite/file3.raw | 1 + tests/freealut/test_suite/test_errorstuff.c | 23 + tests/freealut/test_suite/test_fileloader.c | 74 + tests/freealut/test_suite/test_memoryloader.c | 98 + tests/freealut/test_suite/test_retrostuff.c | 79 + tests/freealut/test_suite/test_version.c | 36 + tests/freealut/test_suite/test_waveforms.c | 31 + tests/runner.py | 6 + 85 files changed, 52679 insertions(+) create mode 100644 tests/freealut/AUTHORS create mode 100644 tests/freealut/CMakeLists.txt create mode 100644 tests/freealut/COPYING create mode 100644 tests/freealut/ChangeLog create mode 100644 tests/freealut/INSTALL create mode 100644 tests/freealut/Makefile.am create mode 100644 tests/freealut/Makefile.in create mode 100644 tests/freealut/NEWS create mode 100644 tests/freealut/README create mode 100644 tests/freealut/aclocal.m4 create mode 100644 tests/freealut/admin/CMakeModules/FindCompilerAttribute.cmake create mode 100644 tests/freealut/admin/CMakeModules/FindCompilerFlagsSet.cmake create mode 100644 tests/freealut/admin/CMakeModules/FindCompilerVisibility.cmake create mode 100644 tests/freealut/admin/CMakeModules/FindConfigHelper.cmake create mode 100644 tests/freealut/admin/CMakeModules/FindSleepFunction.cmake create mode 100644 tests/freealut/admin/Makefile.am create mode 100644 tests/freealut/admin/Makefile.in create mode 100644 tests/freealut/admin/RPM/freealut.spec create mode 100644 tests/freealut/admin/RPM/freealut.spec.in create mode 100644 tests/freealut/admin/VisualStudio6/alut.dsw create mode 100644 tests/freealut/admin/VisualStudio6/alut/alut.dsp create mode 100644 tests/freealut/admin/VisualStudio6/hello_world/hello_world.dsp create mode 100644 tests/freealut/admin/VisualStudio6/playfile/playfile.dsp create mode 100644 tests/freealut/admin/VisualStudioDotNET/alut.sln create mode 100644 tests/freealut/admin/VisualStudioDotNET/alut/alut.vcproj create mode 100644 tests/freealut/admin/VisualStudioDotNET/hello_world/hello_world.vcproj create mode 100644 tests/freealut/admin/VisualStudioDotNET/playfile/playfile.vcproj create mode 100644 tests/freealut/admin/autotools/.indent.pro create mode 100755 tests/freealut/admin/autotools/compile create mode 100755 tests/freealut/admin/autotools/config.guess create mode 100755 tests/freealut/admin/autotools/config.sub create mode 100755 tests/freealut/admin/autotools/depcomp create mode 100755 tests/freealut/admin/autotools/install-sh create mode 100644 tests/freealut/admin/autotools/ltmain.sh create mode 100644 tests/freealut/admin/autotools/m4/alut_c__attribute.m4 create mode 100644 tests/freealut/admin/autotools/m4/alut_check_cflags_wall.m4 create mode 100644 tests/freealut/admin/autotools/m4/alut_check_flag.m4 create mode 100644 tests/freealut/admin/autotools/m4/alut_check_func.m4 create mode 100644 tests/freealut/admin/autotools/m4/alut_eval_stderr.m4 create mode 100755 tests/freealut/admin/autotools/missing create mode 100644 tests/freealut/admin/pkgconfig/Makefile.am create mode 100644 tests/freealut/admin/pkgconfig/Makefile.in create mode 100644 tests/freealut/admin/pkgconfig/freealut-config.in create mode 100644 tests/freealut/admin/pkgconfig/freealut.pc.in create mode 100755 tests/freealut/autogen.sh create mode 100644 tests/freealut/config.h.in create mode 100755 tests/freealut/configure create mode 100644 tests/freealut/configure.ac create mode 100644 tests/freealut/doc/alut.css create mode 100644 tests/freealut/doc/alut.html create mode 100644 tests/freealut/examples/Makefile.am create mode 100644 tests/freealut/examples/Makefile.in create mode 100644 tests/freealut/examples/hello_world.c create mode 100644 tests/freealut/examples/playfile.c create mode 100644 tests/freealut/include/AL/alut.h create mode 100644 tests/freealut/include/Makefile.am create mode 100644 tests/freealut/include/Makefile.in create mode 100644 tests/freealut/src/Makefile.am create mode 100644 tests/freealut/src/Makefile.in create mode 100644 tests/freealut/src/README create mode 100644 tests/freealut/src/alutBufferData.c create mode 100644 tests/freealut/src/alutCodec.c create mode 100644 tests/freealut/src/alutError.c create mode 100644 tests/freealut/src/alutInit.c create mode 100644 tests/freealut/src/alutInputStream.c create mode 100644 tests/freealut/src/alutInternal.h create mode 100644 tests/freealut/src/alutLoader.c create mode 100644 tests/freealut/src/alutOutputStream.c create mode 100644 tests/freealut/src/alutUtil.c create mode 100644 tests/freealut/src/alutVersion.c create mode 100644 tests/freealut/src/alutWaveform.c create mode 100644 tests/freealut/src/helloworld.wav create mode 100644 tests/freealut/test_suite/Makefile.am create mode 100644 tests/freealut/test_suite/Makefile.in create mode 100644 tests/freealut/test_suite/README create mode 100644 tests/freealut/test_suite/file1.wav create mode 100644 tests/freealut/test_suite/file2.au create mode 100644 tests/freealut/test_suite/file3.raw create mode 100644 tests/freealut/test_suite/test_errorstuff.c create mode 100644 tests/freealut/test_suite/test_fileloader.c create mode 100644 tests/freealut/test_suite/test_memoryloader.c create mode 100644 tests/freealut/test_suite/test_retrostuff.c create mode 100644 tests/freealut/test_suite/test_version.c create mode 100644 tests/freealut/test_suite/test_waveforms.c diff --git a/tests/freealut/AUTHORS b/tests/freealut/AUTHORS new file mode 100644 index 0000000000000..92890c937f586 --- /dev/null +++ b/tests/freealut/AUTHORS @@ -0,0 +1,14 @@ +Steve Baker + Initial version of the sources and the specification + +Sven Panne + Build system + General hacking + Specification maintenance + +Erik Hofman + Fixes and additions to the sound file loaders + playfile demo + +Prakash Punnoor + CMake build system diff --git a/tests/freealut/CMakeLists.txt b/tests/freealut/CMakeLists.txt new file mode 100644 index 0000000000000..640f35bf1bcad --- /dev/null +++ b/tests/freealut/CMakeLists.txt @@ -0,0 +1,208 @@ +# cmake project file by Prakash Punnoor +CMAKE_MINIMUM_REQUIRED(VERSION 2.0) + +SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/admin/CMakeModules") +PROJECT(Alut C) +SET(PACKAGE "freealut") +SET(PACKAGE_TARNAME "freealut") +SET(PACKAGE_NAME "freealut library") +SET(PACKAGE_MAJOR_VERSION "1") +SET(PACKAGE_MINOR_VERSION "0") +SET(PACKAGE_BUILD_VERSION "1") +SET(PACKAGE_VERSION "${PACKAGE_MAJOR_VERSION}.${PACKAGE_MINOR_VERSION}.${PACKAGE_BUILD_VERSION}") +SET(MAJOR_VERSION "0") +SET(MINOR_VERSION "0") +SET(BUILD_VERSION "0") +SET(VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${BUILD_VERSION}") +SET(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") +SET(PACKAGE_BUGREPORT "openal-devel@opensource.creative.com") +SET(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}") + +INCLUDE(${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) +INCLUDE(${CMAKE_ROOT}/Modules/CheckIncludeFiles.cmake) +INCLUDE(${CMAKE_ROOT}/Modules/CheckCSourceCompiles.cmake) + +FIND_PACKAGE(ConfigHelper) + +SET(ALUT_SOURCES src/alutBufferData.c + src/alutCodec.c + src/alutError.c + src/alutInit.c + src/alutInputStream.c + src/alutInternal.h + src/alutLoader.c + src/alutOutputStream.c + src/alutUtil.c + src/alutVersion.c + src/alutWaveform.c) + +INCLUDE_DIRECTORIES(${Alut_SOURCE_DIR}/include) + +SET(ADD_WFLAGS "") +SET(ADD_CFLAGS "") +SET(ADD_LDFLAGS "") +SET(ADD_LIBS "") + +OPTION(BUILD_STATIC "build static library too" ON) +OPTION(PROFILE "enable profile" OFF) +OPTION(OPTIMIZATION "enable optimization" ON) +OPTION(WARNINGS "enable warnings" ON) +IF(WARNINGS) + OPTION(MORE_WARNINGS "enable more warnings" OFF) + OPTION(USE_WERROR "enable fail on all warning" OFF) +ENDIF(WARNINGS) + +#want test-suit? +OPTION(BUILD_TESTS "build the test-suite" OFF) + + +ADD_DEFINE(ALUT_BUILD_LIBRARY) +# We could possibly need struct timespec and random(), which are not ANSI. +# Define to 500 if Single Unix conformance is wanted, 600 for sixth revision. +ADD_DEFINE("_XOPEN_SOURCE 500") +# We might need nanosleep, which is a POSIX IEEE Std 1003.1b-1993 feature. +# Define to the POSIX version that should be used. +ADD_DEFINE("_POSIX_C_SOURCE 199309") +# Without __NO_CTYPE tolower and friends are macros which introduce a GLIBC 2.3 +# dependency. By defining this identifier we are currently backwards compatible +# to GLIBC 2.1.3, which is a good thing. In addition, the macros lead to code +# which triggers warnings with -Wunreachable-code. +ADD_DEFINE("__NO_CTYPE 1") + +ADD_DEFINITIONS(-DHAVE_CONFIG_H) +ADD_DEFINITIONS(-DNDEBUG) + +FIND_LIBRARY(OPENAL_LIB NAMES openal openal32 PATHS /usr/lib /usr/local/lib ${OPENAL_LIB_DIR}) +IF(OPENAL_LIB MATCHES "NOTFOUND") + MESSAGE(FATAL_ERROR "OpenAL not installed, cannot build alut - aborting.") +ENDIF(OPENAL_LIB MATCHES "NOTFOUND") + +IF(UNIX) + SET(ADD_LIBS ${ADD_LIBS} m) +ENDIF(UNIX) + +SET(CMAKE_REQUIRED_INCLUDES ${OPENAL_INCLUDE_DIR}) +CHECK_INCLUDE_FILES("AL/alc.h;AL/al.h" AL_HEADERS) +IF(NOT AL_HEADERS) + MESSAGE(FATAL_ERROR "OpenAL header files not found - aborting.") +ENDIF(NOT AL_HEADERS) + +IF(DEFINED OPENAL_INCLUDE_DIR) + INCLUDE_DIRECTORIES(${OPENAL_INCLUDE_DIR}) +ENDIF(DEFINED OPENAL_INCLUDE_DIR) + +FIND_PACKAGE(SleepFunction) + +CHECK_INCLUDE_FILE_DEFINE(stdint.h HAVE_STDINT_H) + +IF(WIN32) + CHECK_INCLUDE_FILE_DEFINE(basetsd.h HAVE_BASETSD_H) +ENDIF(WIN32) + +# FindSleepFunction will check for unistd.h if time.h wasn't found +IF(HAVE_TIME_H) + CHECK_INCLUDE_FILE_DEFINE(unistd.h HAVE_UNISTD_H) +ENDIF(HAVE_TIME_H) + +IF(HAVE_UNISTD_H) + CHECK_FUNCTION_DEFINE(" + #include + #include + #include + " stat "(\"\", (struct stat*)0)" HAVE_STAT) +ENDIF(HAVE_UNISTD_H) + +IF(NOT HAVE_STAT) + CHECK_FUNCTION_DEFINE(" + #include + #include + " _stat "(\"\", (struct _stat*)0)" HAVE__STAT) +ENDIF(NOT HAVE_STAT) + +# compiler specific settings +FIND_PACKAGE(CompilerAttribute) +FIND_PACKAGE(CompilerVisibility) +FIND_PACKAGE(CompilerFlagsSet) + +GENERATE_CONFIG_H() + +SET(CMAKE_C_FLAGS "${ADD_WFLAGS} ${ADD_CFLAGS} ${CMAKE_C_FLAGS}") +SET(CMAKE_CXX_FLAGS "${ADD_CFLAGS} ${CMAKE_CXX_FLAGS}") +SET(CMAKE_SHARED_LINKER_FLAGS "${ADD_LDFLAGS} ${CMAKE_SHARED_LINKER_FLAGS}") +SET(CMAKE_MODULE_LINKER_FLAGS "${ADD_LDFLAGS} ${CMAKE_MODULE_LINKER_FLAGS}") + +IF(BUILD_STATIC) + # we can't create a static library with the same name + # as the shared one, so we copy it over after creation + ADD_LIBRARY(alut_static STATIC ${ALUT_SOURCES}) + TARGET_LINK_LIBRARIES(alut_static ${OPENAL_LIB} ${ADD_LIBS}) + IF(NOT WIN32) + ADD_CUSTOM_COMMAND( + TARGET alut_static + POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS -E copy + ${CMAKE_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}alut_static${CMAKE_STATIC_LIBRARY_SUFFIX} + ${CMAKE_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}alut${CMAKE_STATIC_LIBRARY_SUFFIX}) + INSTALL_FILES(/lib FILES ${CMAKE_STATIC_LIBRARY_PREFIX}alut${CMAKE_STATIC_LIBRARY_SUFFIX}) + ENDIF(NOT WIN32) +ENDIF(BUILD_STATIC) + + +ADD_LIBRARY(alut SHARED ${ALUT_SOURCES}) +SET_TARGET_PROPERTIES(alut PROPERTIES VERSION ${VERSION} SOVERSION ${MAJOR_VERSION}) +TARGET_LINK_LIBRARIES(alut ${OPENAL_LIB} ${ADD_LIBS}) + +INSTALL_TARGETS(/lib alut) +INSTALL_FILES(/include/AL FILES include/AL/alut.h) + +# needed for openal.pc.in and openal-config.in +SET(prefix ${CMAKE_INSTALL_PREFIX}) +SET(exec_prefix "\${prefix}") +SET(libdir "\${exec_prefix}/lib") +SET(bindir "\${exec_prefix}/bin") +SET(includedir "\${prefix}/include") +SET(requirements "") +# static linking dependecies are broken, so pthread isn't needed currently +SET(PTHREAD_LIBS ${CMAKE_THREAD_LIBS_INIT}) + +CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/admin/pkgconfig/freealut.pc.in + ${CMAKE_BINARY_DIR}/admin/pkgconfig/freealut.pc @ONLY) +CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/admin/pkgconfig/freealut-config.in + ${CMAKE_BINARY_DIR}/admin/pkgconfig/freealut-config @ONLY) +INSTALL_PROGRAMS(/bin FILES admin/pkgconfig/freealut-config) +INSTALL_FILES(/lib/pkgconfig FILES admin/pkgconfig/freealut.pc) + + +# test-suite +IF(BUILD_TESTS) + # examples + ADD_EXECUTABLE(hello_world examples/hello_world.c) + TARGET_LINK_LIBRARIES(hello_world ${OPENAL_LIB} ${ADD_LIBS} alut) + + ADD_EXECUTABLE(playfile examples/playfile.c) + TARGET_LINK_LIBRARIES(playfile ${OPENAL_LIB} ${ADD_LIBS} alut) + + + SET(TESTS errorstuff + fileloader + memoryloader + version + waveforms) + + FOREACH(TEST ${TESTS}) + SET(TEST_SRC test_suite/test_${TEST}.c) + SET_SOURCE_FILES_PROPERTIES(${TEST_SRC} PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations") + ADD_EXECUTABLE(test_${TEST} ${TEST_SRC}) + TARGET_LINK_LIBRARIES(test_${TEST} ${OPENAL_LIB} ${ADD_LIBS} alut) + ENDFOREACH(TEST) + + #copy over testdata, so test-suite can be used in binary dir + SET(TESTDATA file1.wav + file2.au + file3.raw) + + FOREACH(TESTDATUM ${TESTDATA}) + CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/test_suite/${TESTDATUM} ${CMAKE_BINARY_DIR}/${TESTDATUM} COPYONLY) + ENDFOREACH(TESTDATUM) +ENDIF(BUILD_TESTS) diff --git a/tests/freealut/COPYING b/tests/freealut/COPYING new file mode 100644 index 0000000000000..e463f46230799 --- /dev/null +++ b/tests/freealut/COPYING @@ -0,0 +1,483 @@ + + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/tests/freealut/ChangeLog b/tests/freealut/ChangeLog new file mode 100644 index 0000000000000..c1c689303d0b6 --- /dev/null +++ b/tests/freealut/ChangeLog @@ -0,0 +1,786 @@ +2006-05-22 Sven Panne + + * Prepared release candidate 1 for 1.1.0, tag is "freealut_1_1_0_RC1". + + * NEWS: Added news for 1.1.0. + +2006-05-11 Sven Panne + + * README, admin/VisualStudio6/alut/alut.dsp, + admin/VisualStudio6/hello_world/hello_world.dsp, + admin/VisualStudio6/playfile/playfile.dsp, + admin/VisualStudioDotNET/alut/alut.vcproj, + admin/VisualStudioDotNET/hello_world/hello_world.vcproj, + admin/VisualStudioDotNET/playfile/playfile.vcproj: Changed the paths to + the headers and the library to conform to the default of the current + OpenAL SDK installer from Creative. + + * src/alutWaveform.c(getWaveformFunction): To avoid warnings on VC6, add + some redundant '&' operators. + + * include/AL/alut.h: Added some fragile logic to find the right path to + the OpenAL headers. + +2006-04-12 Sven Panne + + * configure.ac: To guarantee version consistency, generate .spec + file via configure. + + * admin/RPM/.cvsignore, admin/RPM/freealut.spec.in: Added. + + * admin/RPM/freealut.spec: Removed. + + * CMakeLists.txt, admin/VisualStudio6/alut/alut.dsp, + admin/VisualStudioDotNET/alut/alut.vcproj, admin/autotools/.indent.pro, + configure.ac, include/AL/alut.h, src/Makefile.am, src/alutBufferData.c, + src/alutInternal.h, src/alutLoader.c, src/alutUtil.c, + src/alutWaveform.c: Implemented alutLoadMemoryHelloWorld and + alutLoadMemoryWaveform. Refactored things internally a bit, mainly by + making an InputStream the central kind of sound data source. Introduced + the OutputStream type for generating built-in sounds. Bumped the package + version to 1.1.0 and the library version to 1:0:1 (i.e. a backwards + compatible version, only with new features). Added --enable-efence + configure option. + + * src/alutOutputStream.c: Added. + + * doc/alut.html: Added a few missing ALUT_ERROR_OUT_OF_MEMORY error + conditions in the descriptions of the loaders. Added + alutLoadMemoryHelloWorld and alutLoadMemoryWaveform. Bumped spec version + to 1.1.0. + + * doc/alut.css: Added a remark how to make the headers stand out a + little bit more. + +2006-04-10 Sven Panne + + * doc/alut.html: Fixed foo-config documentation. Minor cleanup. + +2006-03-05 Prakash Punnoor + + * admin/CMakeModules/FindSleepFunction.cmake: sync to OpenAL version + + * Makefile.am: add CMake Modules to EXTRA_DIST + + * CMakeLists.txt: make more windows friendly; variables + OPENAL_INCLUDE_DIR and OPENAL_LIB_DIR introduced + +2006-02-13 Sven Panne + + * configure.ac, src/Makefile.am: Added version info. + +2006-02-16 Prakash Punnoor + + * CMakeLists.txt: don't check for unistd.h twice + +2006-02-13 Prakash Punnoor + + * CMakeLists.txt: forgot to delete old visibility macro; use OpenAL + module for sleep function detection; define _POSIX_C_SOURCE and add + comments from configure.ac + +2006-02-13 Sven Panne + + * configure.ac: We might need nanosleep, which is a POSIX IEEE Std + 1003.1b-1993 feature, so tell our system headers about that. Fixes the + build e.g. on an old SuSE 8.2 distro. + + * NEWS: Fixed release date. + + * doc/alut.html: Fixed broken link. + +2006-02-11 Sven Panne + + * Released Version 1.0.1, CVS tag is "freealut_1_0_1". + +2006-02-07 Prakash Punnoor + + * CMakeLists.txt: Define __NO_CTYPE + +2006-02-07 Sven Panne + + * admin/RPM/freealut.spec: Bumped to 1.0.1, too. We should really + automate this. + + * NEWS, src/alutUtil.c: When nanosleep returns early due to a signal, + continue sleeping, otherwise return AL_FALSE from alutSleep. + + * NEWS: Prepared for 1.0.1 release, probably more to come. + + * configure.ac: Use AC_DEFINE instead of specifying preprocessor defines + by hand. Added a tiny comment. + +2006-02-06 Prakash Punnoor + + * CMakeLists.txt: Use modules written for OpenAL, fixing various issues; + bumped version. + + * admin/CMakeModules/FindCompilerAttribute.cmake, + admin/CMakeModules/FindCompilerFlagsSet.cmake, + admin/CMakeModules/FindCompilerVisibility.cmake, + admin/CMakeModules/admin/CMakeModules/FindConfigHelper.cmake, + admin/CMakeModules/FindSleepFunction.cmake: added + + * configure.ac: Added symbol visibility support. + +2006-02-06 Sven Panne + + * admin/pkgconfig/Makefile.am: Use a more portable way of defining + pkgconfdir (by Andreas Bierfert). + +2006-02-04 Sven Panne + + * include/AL/alut.h: Use visibility attribute only when building ALUT + library. + + * configure.ac: Fixed CR/LF vs. LF issue in configure on Windows. Bumped + version to 1.0.1. + +2005-12-17 Prakash Punnoor + + * CMakeLists.txt, include/AL/alut.h: GCC visibility support. + +2005-12-16 Sven Panne + + * Released Version 1.0.0, CVS tag is "freealut_1_0_0". + + * admin/pkgconfig/freealut-config.in, admin/pkgconfig/freealut.pc.in: + Fixed copy-n-paste typo. Somehow this fix didn't make into RC2... + +2005-12-15 Sven Panne + + * Makefile.am, admin/RPM/freealut.spec, configure.ac: Build and install + freealut-config and a pkg-config description. + + * admin/.cvsignore, admin/Makefile.am, admin/pkgconfig/.cvsignore, + admin/pkgconfig/Makefile.am, admin/pkgconfig/freealut-config.in, + admin/pkgconfig/freealut.pc.in: Added. + +2005-12-15 Prakash Punnoor + + * README: CMake cache clearing typos + + * CMakeLists.txt: also make freealut-config and freealut.pc; sync + VERSION to configure.ac + +2005-12-12 Prakash Punnoor + + * README: CMake cache clearing + +2005-12-10 Sven Panne + + * src/alutInit.c (alutExit): Do a full sanity check only when ALUT + itself owns the context, an external context might have been destroyed + before alutExit is called. + +2005-12-05 Prakash Punnoor + + * Makefile.am: add CMakeLists.txt to EXTRA_DIST + + * README: add CMake use instructions + +2005-12-04 Prakash Punnoor + + * CMakeLists.txt: add -DNDEBUG + + * AUTHORS: add myself + +2005-12-03 Sven Panne + + * configure.ac, include/AL/alut.h, src/alutBufferData.c, + src/alutInputStream.c, src/alutLoader.c src/alutWaveform.c: Avoid + generating a depedency on GLIBC 2.3. Added --enable-more-warnings + configure flag and fixed the resulting warnings. + +2005-12-03 Prakash Punnoor + + * CMakeLists.txt: made pretty feature-complete + +2005-12-02 Prakash Punnoor + + * src/alutCodec.c, src/alutLoader.c: fix warnings + + * CMakeLists.txt: added; doesn't build examples/tests yet + +2005-11-28 Sven Panne + + * test_suite\Makefile.am: Distribute example sounds, too. + + * admin/RPM/freealut.spec: Updated build dependencies. + +2005-11-27 Sven Panne + + * src/alutCodec.c, src/alutLoader.c, src/alutWaveform.c: Re-indented. + + * Makefile.am, README, configure.ac: Rearranged the admin subdirectory a + little bit, making it hopefully clearer which files belong to which + build system. + + * admin/RPM/freealut.spec, admin/autotools/.cvsignore, + admin/autotools/.indent.pro, admin/autotools/m4/alut_c__attribute.m4, + admin/autotools/m4/alut_check_cflags_wall.m4, + admin/autotools/m4/alut_check_flag.m4, + admin/autotools/m4/alut_check_func.m4, + admin/autotools/m4/alut_eval_stderr.m4: Added. + + * admin/.cvsignore, admin/.indent.pro, admin/freealut.spec, + admin/m4/alut_c__attribute.m4, admin/m4/alut_check_cflags_wall.m4, + admin/m4/alut_check_flag.m4, admin/m4/alut_check_func.m4, + admin/m4/alut_eval_stderr.m4: Removed. + + * src/alutBufferData.c, src/alutCodec.c, src/alutInputStream.c, + src/alutInternal.h, src/alutLoader.c, src/alutWaveform.c: Consistently + use size_t for sizes internally, because ALsizei is signed and we don't + want to lose a bit (2GB vs. 4GB limits). + + * admin/VisualStudioDotNET/.cvsignore, + admin/VisualStudioDotNET/alut.sln, + admin/VisualStudioDotNET/alut/.cvsignore, + admin/VisualStudioDotNET/alut/alut.vcproj, + admin/VisualStudioDotNET/hello_world/.cvsignore, + admin/VisualStudioDotNET/hello_world/hello_world.vcproj, + admin/VisualStudioDotNET/playfile/.cvsignore, + admin/VisualStudioDotNET/playfile/playfile.vcproj: Added. The structure + is now similar to the Visual Studio 6 directory and the + solution/projects are now usable with older versions of Visual Studio + .NET. + + * admin/alut.sln, admin/alut.vcproj, admin/hello_world.vcproj, + admin/playfile.vcproj: Removed. + + * admin/VisualStudio6/.cvsignore, admin/VisualStudio6/alut.dsw, + admin/VisualStudio6/alut/.cvsignore, admin/VisualStudio6/alut/alut.dsp, + admin/VisualStudio6/hello_world/.cvsignore, + admin/VisualStudio6/hello_world/hello_world.dsp, + admin/VisualStudio6/playfile/.cvsignore, + admin/VisualStudio6/playfile/playfile.dsp: Added Visual Studio 6 + workspace and projects. + + * src/alutCodec.c: Silence a useless Visual C 6 warning. + + * src/alutInternal.h: Visual C 6's basetsd.h has no definitions for + sized integral types, so let's define them by hand. + +2005-11-25 Sven Panne + + * admin/alut.vcproj: Use "Multi-threaded DLL (/MD)" and "Multi-threaded + Debug DLL (/MDd)" as the runtime library, bringing down the size of + alut.dll to something sensible. + + * examples/playfile.c, test_suite/test_fileloader.c, + test_suite/test_memoryloader.c, test_suite/test_retrostuff.c: Changed + literal ALfloat constants from 0.1 to 0.1f, silencing Visual C. + + * configure.ac: Tell the system headers that we might use POSIX/XPG + entitites like struct timespec or random(), which are not in the ANSI + standard. Do not define any user variables like CFLAGS. Split the old + configure flag --enable-warnings into a pair --enable-warnings and + --enable-werror. Use a (modified) macro from the autoconf archive to + detect strict warning flags. + + * admin/m4/alut_check_cflags_wall.m4: Added. It is a modified version of + ax_cflags_warn_all_ansi.m4 from the autoconf archive, updated to conform + to more recent autoconf standards. + +2005-11-21 Sven Panne + + * configure.ac: Removed --enable-debug option, it was unused. + +2005-11-19 Sven Panne + + * doc/alut.html: Added a remark about LD_PRELOAD to use old + binaries with the new ALUT. + +2005-11-17 Sven Panne + + * src/alutInit.c: Fixed alutInitWithoutContext initialisation + state check. + +2005-10-29 Sven Panne + + * examples/hello_world.c, examples/playfile.c ,include/AL/alut.h, + src/alutUtil.c, test_suite/test_fileloader.c, + test_suite/test_memoryloader.c, test_suite/test_retrostuff.c, + test_suite/test_waveforms.c: Synched implementation with latest spec + changes. + + * doc/alut.html: As discussed on the mailing list, sleeping is now done + via an ALfloat. This is more consinstent with physical reality and + alutCreateBufferWaveform. Note that alutSleep can actually fail now, + something which the former alutMicroSleep never did. + + * src/alutLoader.c: Re-indented. + +2005-10-24 Sven Panne + + * src/alutLoader.c, src/alutWaveform.c: Added a few harmless casts where + Visual Studio was complaining about a possible loss of precision. + + * admin/alut.vcproj: Added the recently introduced source files. + +2005-10-10 Sven Panne + + * examples/playfile.c: Added missing alutExit call. + +2005-10-21 Sven Panne + + * admin/freealut.spec: Added. Note that the neededforbuild and + BuildRequires info is not yet correct, need to figure out how to compute + those. + + * Makefile.am: Unbreak "make dist". Added documentation. + +2005-10-05 Sven Panne + + * src/Makefile.am, src/alutInputStream.c, src/alutInternal.h, + src/alutLoader.c: Factored out codecs. Simplified stream interface. + + * src/alutCodec.c: Added. + + * src/alutBufferData.c, src/alutInputStream.c, src/alutInternal.h, + src/alutLoader.c, src/alutUtil.c, src/alutWaveform.c: More heavy + refactoring, mainly making the buffer data an abstract data type. + + * test_suite/test_errorstuff.c, test_suite/test_fileloader.c, + test_suite/test_memoryloader.c, test_suite/test_retrostuff.c, + test_suite/test_version.c, test_suite/test_waveforms.c: Cleaned up and + fixed the test suite (always call alutExit before exiting, test for + AL_NONE instead of 0, no repetitions, more error checks, return + EXIT_FAILURE on failure). + + * src/alutBufferData.c, src/alutInputStream.c: Forgot to re-indent + these... + +2005-09-30 Sven Panne + + * admin/.indent.pro,examples/playfile.c, include/AL/alut.h, + src/Makefile.am, src/alutInit.c, src/alutInternal.h, src/alutLoader.c, + src/alutWaveform.c: Some heavy refactoring of the input streams and + buffer data types, we are moving towards common OO techniques here. Not + completely finished, but much better than before. + + * src/alutBufferData.c, src/alutInputStream.c: Added. + + * src/alutWaveform.c: Instead of the 44.1kHz 16bit PCM data, use + 11.025kHz 8-bit ISDN u-law for the "Hello, world!" sound, saving 56kB in + the resulting ALUT library. + +2005-09-28 Sven Panne + + * examples/playfile.c, include/AL/alut.h, src/alutError.c, + src/alutInit.c, src/alutLoader.c: Adapted to spec changes. + + * doc/alut.html: Updated list of error tokens. Replaced + alutEnumerateSupportedFileTypes with alutGetMIMETypes. More reformatting + and clarifications. + +2005-09-27 Sven Panne + + * include/AL/alut.h, src/alutError.c, src/alutInit.c, + src/alutInternal.h, src/alutLoader.c, src/alutWaveform.c: Adapted to + spec changes. Added a few missing error checks. Improved SampleAttribs a + bit. + + * doc/alut.css, doc/alut.html: Make descriptions of API entries more + formal, following the usual manual page style (not finished yet). Added + some clarifications. Changed the set of possible ALUT errors. + +2005-09-26 Sven Panne + + * doc/alut.html, include/AL/alut.h, src/alutError.c, src/alutInit.c, + src/alutInternal.h, src/alutLoader.c, src/alutUtil.c: Clarified and + changed the ALUT error handling and reporting after the corresponding + discussion on the mailing list. + +2005-09-23 Sven Panne + + * admin/.cvsignore: Ignore mkinstalldirs. + + * src/alutLoader.c: Make the endianess test dynamic. + +2005-09-21 Sven Panne + + * src/alutLoader.c: Removed evil byte-swapping. Fixed WAV loading + (still not 100% bullet-proof, I think). Cleanup. + + * admin/.indent.pro: Added new typedef. + + * src/alutInternal.h: Handle 32bit sized types on Windows. + +2005-09-18 Sven Panne + + * src/alutInit.c, src/alutLoader.c: Added a few error checks. Made + testing for errors more consistent, it should be of the form: + + if (!) + { _alutSetError(); return ; } + + * admin/.indent.pro, examples/.cvsignore, examples/Makefile.am, + src/alutLoader.c: Merged and heavily modified Erik Hofman's fixes for + AU/WAV loaders. Some more cleanup + minor fixes. + + * examples/playfile.c: Added. + +2005-09-17 Sven Panne + + * configure.ac, include/AL/alut.h, test_suite/Makefile.am: Flag + deprecated functions if possible (VisualC++ .NET and GCC >= 3.1.1), but + be careful to avoid those warnings in our test suite. + + * admin/m4/alut_check_flag.m4, admin/m4/alut_eval_stderr.m4: Added. + + * configure.ac, admin/alut.vcproj, include/AL/alut.h: Use AL_ALUT_H + instead of _AL_ALUT_H, macros starting with "_" are reserved by the C + standard. For the same reason, rename _ALUTLIB to ALUT_BUILD_LIBRARY. + + * README: Added building instructions using VisualStudio. + + * admin/.cvsignore: Ignore files generated by VisualStudio. + + * AUTHORS: Added Erik Hofman. Small reformatting. + + * alut.sln, alut.vcproj, hello_world.vcproj: Added. I have access to + VisualStudio .NET only, so I can't maintain project files for older + versions. Note that the OpenAL SDK is assumed to live under + C:\OpenALSDK, not nice to hardwire this, but I don't see another + solution currently. Help would be appreciated. + + * alut.dsp, alut.dsw, hello_world.dsp: Removed. + + * configure.ac, src/alutInternal.h, src/alutLoader.c, + src/alutWaveform.c: As usual, Microsoft chooses to ignore standards, + this time C99: VisualC doesn't have stdint.h, so hack around this + omission. + + * Makefile.am: Moved m4 subdirectory to admin where it belongs. + + * admin/m4/alut_c__attribute.m4, admin/m4/alut_check_func.m4: Added. + + * m4/alut_c__attribute.m4, m4/alut_check_func.m4: Removed. + + * src/Makefile.am: Fixed headers. + + * .cvsignore: Ignore distribution archives. + +2005-09-14 Sven Panne + + * src/alutError.c, src/alutInit.c, src/alutLoader.c, src/alutUtil.c, + src/alutVersion.c, src/alutWaveform.c: Use alutInternal.h. + + * src/alutInternal.h: Added. This file should be #included as the first + header in all *.c files. + + * src/alutError.h, src/alutInit.h: Removed + + * Makefile.am, examples/Makefile.am, src/Makefile.am, + test_suite/Makefile.am: Automatically build examples and test suite + now. Moved local autoconf macros to a separate directory. Added a few + comments. + + * m4/alut_c__attribute.m4, m4/alut_check_func.m4: Added. + + * acinclude.m4: Removed + +2005-09-13 Sven Panne + + * configure.ac, src/alutLoader.c, src/alutWaveform.c: A few + compatibility hacks to make it compile on Linux, MinGW/MSYS and Cygwin. + + * acinclude.m4: Added. + +2005-09-12 Sven Panne + + * admin/.cvsignore: Improved ignorance. + + * src/Makefile.am: Cleaned up and fixed include paths. Added + -no-undefined to libtool linker flags to prepare for building a Windows + DLL. Added some comments. + +2005-09-11 Sven Panne + + * configure.ac, src/alutWaveform.c: Cleaned up alutCreateBufferWaveform. + + * configure.ac, src/alutInit.c: Header cleanup. + + * src/alutUtil.c: Fixed braino in alutMicroSleep using nanosleep. + + * src/alutInit.c: _alutSanityCheck doesn't terminate the program in case + of an error anymore, it simply sets the error condition. Some additional + cleanup. + + * src/alutError.c: Print a message to stderr when an error condition is + set and the ALUT_DEBUG environment variable is defined. + + * src/Makefile.am: Include src/helloworld.wav and src/README in + distributions. + + * src/README: A few additions and corrections. + + * doc/alut.html: A few clarifications and a little reformatting. + +2005-09-10 Sven Panne + + * configure.ac, doc/alut.html, examples/hello_world.c, + include/AL/alut.h, src/Makefile.am, src/alutUtil.c, + test_suite/test_fileloader.c, test_suite/test_memoryloader.c, + test_suite/test_retrostuff.c, test_suite/test_waveforms.c: Added + alutMicroSleep and use it. + + * include/AL/alut.h: Renamed ALUTAPI/ALUTAPIENTRY to + ALUT_API/ALUT_APIENTRY, so we only #define macros with the ALUT_ prefix. + + * doc/alut.html, include/AL/alut.h, src/alutLoader.c, + src/alutWaveform.c, test_suite/test_retrostuff.c: Frequencies are + ALfloat again. + + * doc/alut.html: Mention openal-config and pkg-config. Reformatted a + bit. + + * doc/alut.css: The body should have the same font-family as the + headers. + +2005-09-09 Sven Panne + + * src/Makefile.am: Added libm dependencies. + + * configure.ac, include/AL/alut.h, admin/alut.dsp: Consistently use + _ALUTLIB when building the ALUT DLL. + + * configure.ac, include/Makefile.am: Install header directly from + include subdirectory, it is more logical this way. + + * include/AL/Makefile.am: Removed. + + * configure.ac, src/Makefile.am, examples/Makefile.am, + test_suite/Makefile.am: Hardwire the library name, that kind of + flexibility is not needed as it would break the ABI. + + * Makefile.am: Added rule to update libtool. + + * configure.ac: Don't change the default prefix (principle of least + surprise). The alut library should be able to be used by dlopen, it + doesn't use dlopen (yet). Removed obscure includedir adjustment, it is + not needed. Removed dead code. Improved logic to choose OpenAL library + (still not completely right). + +2005-09-08 Sven Panne + + * src/Makefile.am: Distribute internal headers, too. + + * Makefile.am: Include the Windows stuff in the distribution. + + * autogen.sh: Simply us autoreconf, as recommended in the + automake/autoconf documentation. + + * README: Fixed typo. + + * .cvsignore, configure.ac, Makefile.am: Put all administrative files + into admin subdirectory. + + * .indent.pro, INSTALL, install-sh, mkinstalldirs, win_build/alut.dsp, + win_build/alut.dsw, win_build/hello_world.dsp: Removed. + + * admin/alut.dsp, admin/alut.dsw, admin/.cvsignore, + admin/hello_world.dsp, admin/.indent.pro: Added. + + * README: Synched with reality. + +2005-09-07 Sven Panne + + * autogen.sh: Use -Wall for automake to catch some buglets, deprecated + stuff, etc. + +2005-09-03 Sven Panne + + * src/alutLoader.c: Merged patches for AU format from Erik Hofman + , including some changes to the original patch. + +2005-09-01 Sven Panne + + * doc/alut.html, include/AL/alut.h, src/alutError.c, src/alutInit.c, + src/alutLoader.c, src/alutVersion.c, src/alutWaveform.c: Moved internal + function prototypes out of the public header. Fixed function prototypes, + i.e. foo() (C++) vs. foo(void) (C). + + * src/alutError.h, src/alutInit.h: Added. + + * .indent.pro, src/alutInit.c, src/alutLoader.c, src/alutWaveform.c, + test_suite/test_errorstuff.c, test_suite/test_fileloader.c, + test_suite/test_memoryloader.c, test_suite/test_retrostuff.c, + test_suite/test_version.c, test_suite/test_waveforms.c: Don't use TABs. + + * test_suite/test_fileloader.c, test_suite/test_memoryloader.c, + test_suite/test_retrostuff.c, test_suite/test_version.c, + test_suite/test_waveforms.c: Hopefully make the examples compile on + WinDoze. Play sounds only a finite number of times, which is better for + automating things. + + * src/alutError.c, src/alutInit.c, src/alutLoader.c, src/alutVersion.c, + src/alutWaveform.c, test_suite/test_errorstuff.c, + test_suite/test_fileloader.c, test_suite/test_memoryloader.c, + test_suite/test_retrostuff.c, test_suite/test_version.c, + test_suite/test_waveforms.c: Reformatted conforming to GNU + standards. Please keep it that way... + + * Makefile.am: Added a target "permissions" to fix the broken + permissions after a checkout. Added a target "indent" to automagically + indent all C sources and headers according to GNU standards. + + * .indent.pro: Added. + + * doc/alut.html, include/AL/alut.h, src/alutError.c, src/alutInit.c, + src/alutLoader.c, test_suite/test_memoryloader.c, + test_suite/test_retrostuff.c: A bunch of API cleanups: + + Changed the first parameter of alutInit and alutInitWithoutContext to + int*, not ALint*. argc is an int, after all. + + Changed return type of alutGetError to ALenum, this is more consistent + with alGetError. + + Changed the argument of alutGetErrorString to ALenum for the same + reason. + + Changed the first parameter of alutLoadMemoryFromFileImage and + alutCreateBufferFromFileImage to "const ALvoid*", this is more + convenient and more consistent with alBufferData. + + Changed the first parameter of alutLoadWAVFile and alutLoadWAVMemory + back to ALbyte*, like it was before. + + Changed the frequency parameter of alutLoadMemoryFromFile and + alutLoadMemoryFromFileImage to an ALuint*, this is more consistent with + the way AL handles frequencies. + + Changed the return type of alutLoadMemoryFromFile and + alutLoadMemoryFromFileImage to an ALvoid* for more consistency. + + * doc/alut.html: Added myself. Fixed a few typos and synched examples + with actual sources. Use code formatting conforming to the GNU coding + standards. + + * AUTHORS: Added myself. + + * doc/alut.html: Converted spec to XHTML + CSS, no changes to the + content itself. This is a first step towards using DocBook, which is far + more flexible regarding the possible output formats + (XHTML, PDF, PS, ...). + + * doc/alut.css: Added. + + * doc/noise.gif: Removed. + + * include/AL/alut.h: Synched platform-specific parts with the AL/ALC + headers. Reformatted according to GNU standards. + + * Makefile.am, examples/Makefile.am, src/Makefile.am, + test_suite/Makefile.am: Do not hardwire any obscure paths into the build + process, the normal way of using headers/libraries in non-standard + places is to set CPPFLAGS/LDFLAGS when configuring and building. + + * autogen.sh: Small cleanup: Be a good *nix citizen and be quiet when + everything works. Furthermore, terminate immediately when a tool fails. + +2005-09-01 Steve Baker + + * examples/Makefile.am, examples/hello_world.c, include/AL/alut.h, + src/alutLoader.c, src/alutWaveform.c, test_suite/Makefile.am: + + 1) Replaced '//' C++ style comments with /*...*/ style for portability. + + 2) According to the OpenAL headers, the third argument of alGetSourcei + should be ALint - not ALuint. So 'hello_world.c' wouldn't + compile. Fixed. + + 3) It's a bad idea to sit in a tight loop doing nothing but + alGetSourcei. On some OS's, this could lock out any other AL threads - + with disasterous consequences. + + Rather than get into all that complexity in a 'Hello World' example, I + elected to simply sleep for plenty of time. + + However, I did fixup the 'sleep(seconds)' versus 'Sleep(microseconds)' + issue (good way to be non-portable Mr Gates). + + 4) Makefile.am had been changed around so that ALUT demo's and + test_suite would link to the OpenAL library in the current build + tree. This is bad for many reasons discussed via email - so I reverted + that change. + + 5) Evidently 'strcasecmp' doesn't exist under Windows/MSVC and + strcasecmp had been replaced with 'strcmp' for Windows. I think + 'stricmp' is the Windows version of strcmp that's case insensitive. + + 6) I fixed up the lack of a 'random()' function in Windows used 'rand()' + instead. Not the ideal fix but definitely 'good enough'. + +2005-08-31 Garin Hiebert + + * win_build/alut.dsp, win_build/hello_world.dsp: Fixed Release Build + Issues. + + * doc/alut.html, examples/hello_world.c, include/AL/alut.h, + src/alutLoader.c, src/alutWaveform.c: First Stab At Moving To Windows. + + * win_build/alut.dsp, win_build/alut.dsw, win_build/hello_world.dsp: + Added. + +2005-08-30 Sven Panne + + * src/alutError.c: Namespace hygiene: Make lastError static + + * examples/.cvsignore, examples/Makefile.am, test_suite/.cvsignore, + test_suite/Makefile.am: More tweaks to the build environment, still a + bit hacky... + + * Makefile.am, configure.ac, src/Makefile.am, src/alutError.c, + src/alutInit.c, src/alutLoader.c, src/alutVersion.c, src/alutWaveform.c: + Move alut.h to include/AL, so we can always use the same kind of + #includes and always use the headers from the SI, not any installed + ones. Things are not perfect yet, but better... + + * src/alut.h: Removed. + + * .cvsignore, examples/.cvsignore, include/.cvsignore, + include/Makefile.am, include/AL/.cvsignore, include/AL/Makefile.am, + include/AL/alut.h, src/.cvsignore, test_suite/.cvsignore: Added. + +2005-08-30 Steve Baker + + * src/Makefile.am: Jason Daly said: The current build system makes the + assumption that OpenAL is installed. This just adds -I../../include to + pick up the AL headers in the top-level directory. ALUT wouldn't build + on my system without this (we use OpenAL from an NFS-mounted directory). + +2005-08-29 Steve Baker + + * README, examples/hello_world.c: Added some more build instructions. + + * configure.ac, examples/Makefile.am, src/Makefile.am, + test_suite/Makefile.am: Fixed up makefiles so they find OpenAL in either + /usr/local/lib or /usr/lib also fixed ALUT to install in /usr/include/AL + and /usr/lib/. + + * Makefile.am, README, test_suite/test_memoryloader.c, + test_suite/test_retrostuff.c: More minor cleanup. + + * src/alutError.c, src/alutInit.c, src/alutLoader.c, src/alutWaveform.c: + Cleaned up some warning messages when -pedantic is enabled. + + * src/alut.h: Added. + + * autogen.sh, configure.ac, install-sh, mkinstalldirs: Added autoconf + stuff. + +2005-08-27 Steve Baker + + * AUTHORS, COPYING, ChangeLog, INSTALL, Makefile.am, NEWS, README, + doc/alut.html, doc/noise.gif, examples/Makefile.am, + examples/hello_world.c, src/Makefile.am, src/README, src/alutError.c, + src/alutInit.c, src/alutLoader.c, src/alutVersion.c, src/alutWaveform.c, + src/helloworld.wav, test_suite/Makefile.am, test_suite/README, + test_suite/file1.wav, test_suite/file2.au, test_suite/file3.raw, + test_suite/test_errorstuff.c, test_suite/test_fileloader.c, + test_suite/test_memoryloader.c, test_suite/test_retrostuff.c, + test_suite/test_version.c, test_suite/test_waveforms.c: Added ALUT 1.0.0 + Alpha. diff --git a/tests/freealut/INSTALL b/tests/freealut/INSTALL new file mode 100644 index 0000000000000..56b077d6a0b87 --- /dev/null +++ b/tests/freealut/INSTALL @@ -0,0 +1,236 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PREFIX', the package will +use PREFIX as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). Here is a another example: + + /bin/bash ./configure CONFIG_SHELL=/bin/bash + +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/tests/freealut/Makefile.am b/tests/freealut/Makefile.am new file mode 100644 index 0000000000000..a5ac942f4d408 --- /dev/null +++ b/tests/freealut/Makefile.am @@ -0,0 +1,57 @@ +# Build, install and distribute the following subdirectories: +SUBDIRS = admin src include examples test_suite + +# We keep our local autoconf macros in a separate 'm4'subdirectory. +ACLOCAL_AMFLAGS = -I admin/autotools/m4 + +# The following files should be in our source distribution in addition to the +# standard ones included by automake itself: +EXTRA_DIST = \ + admin/autotools/.indent.pro \ + admin/RPM/freealut.spec \ + admin/VisualStudio6/alut/alut.dsp \ + admin/VisualStudio6/alut.dsw \ + admin/VisualStudio6/hello_world/hello_world.dsp \ + admin/VisualStudio6/playfile/playfile.dsp \ + admin/VisualStudioDotNET/alut/alut.vcproj \ + admin/VisualStudioDotNET/alut.sln \ + admin/VisualStudioDotNET/hello_world/hello_world.vcproj \ + admin/VisualStudioDotNET/playfile/playfile.vcproj \ + admin/CMakeModules/FindCompilerAttribute.cmake \ + admin/CMakeModules/FindCompilerFlagsSet.cmake \ + admin/CMakeModules/FindCompilerVisibility.cmake \ + admin/CMakeModules/FindConfigHelper.cmake \ + admin/CMakeModules/FindSleepFunction.cmake \ + autogen.sh \ + doc/alut.css \ + doc/alut.html \ + CMakeLists.txt + +# Automatically rebuild libtool if it becomes out-of-date. +libtool: $(LIBTOOL_DEPS) + $(SHELL) ./config.status --recheck + +# The Creative repository has some broken permissions, let's fix this. +permissions: + find . -type f \! -perm +222 \! -name "*.sh" -exec chmod +w {} \; + +# Automatically reformat all C headers and sources with indent according to +# admin/autotools/.indent.pro, but be make-friendly and take some precautions to +# leave those files untouched which wouldn't change. Do not reformat the public +# ALUT header, it won't look the way we want it due to the 'extern "C" { ... }' +# wrapper in it. +indent: + @for i in `find . \( -name "*.c" -o -name "*.h" \) \! -name alut.h -print` ; do \ + cat $$i | ( cd admin/autotools ; indent ) > indent.tmp ; \ + if diff $$i indent.tmp > /dev/null 2>&1 ; then \ + : ; \ + else \ + echo Reformatted $$i ; \ + $(RM) $$i ; \ + mv indent.tmp $$i ; \ + fi ; \ + done + @$(RM) indent.tmp + +# Targets which are no files +.PHONY: permissions indent diff --git a/tests/freealut/Makefile.in b/tests/freealut/Makefile.in new file mode 100644 index 0000000000000..9a3f483a3499c --- /dev/null +++ b/tests/freealut/Makefile.in @@ -0,0 +1,690 @@ +# Makefile.in generated by automake 1.9.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = . +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/config.h.in \ + $(top_srcdir)/admin/RPM/freealut.spec.in \ + $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \ + admin/autotools/compile admin/autotools/config.guess \ + admin/autotools/config.sub admin/autotools/depcomp \ + admin/autotools/install-sh admin/autotools/ltmain.sh \ + admin/autotools/missing +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = \ + $(top_srcdir)/admin/autotools/m4/alut_c__attribute.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_cflags_wall.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_flag.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_func.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_eval_stderr.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno configure.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = admin/RPM/freealut.spec +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBM = @LIBM@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VERSIONINFO = @VERSIONINFO@ +WNO_DEPRECATED_DECLARATIONS_FALSE = @WNO_DEPRECATED_DECLARATIONS_FALSE@ +WNO_DEPRECATED_DECLARATIONS_TRUE = @WNO_DEPRECATED_DECLARATIONS_TRUE@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_AS = @ac_ct_AS@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ + +# Build, install and distribute the following subdirectories: +SUBDIRS = admin src include examples test_suite + +# We keep our local autoconf macros in a separate 'm4'subdirectory. +ACLOCAL_AMFLAGS = -I admin/autotools/m4 + +# The following files should be in our source distribution in addition to the +# standard ones included by automake itself: +EXTRA_DIST = \ + admin/autotools/.indent.pro \ + admin/RPM/freealut.spec \ + admin/VisualStudio6/alut/alut.dsp \ + admin/VisualStudio6/alut.dsw \ + admin/VisualStudio6/hello_world/hello_world.dsp \ + admin/VisualStudio6/playfile/playfile.dsp \ + admin/VisualStudioDotNET/alut/alut.vcproj \ + admin/VisualStudioDotNET/alut.sln \ + admin/VisualStudioDotNET/hello_world/hello_world.vcproj \ + admin/VisualStudioDotNET/playfile/playfile.vcproj \ + admin/CMakeModules/FindCompilerAttribute.cmake \ + admin/CMakeModules/FindCompilerFlagsSet.cmake \ + admin/CMakeModules/FindCompilerVisibility.cmake \ + admin/CMakeModules/FindConfigHelper.cmake \ + admin/CMakeModules/FindSleepFunction.cmake \ + autogen.sh \ + doc/alut.css \ + doc/alut.html \ + CMakeLists.txt + +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ + cd $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: $(am__configure_deps) + cd $(top_srcdir) && $(AUTOHEADER) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +admin/RPM/freealut.spec: $(top_builddir)/config.status $(top_srcdir)/admin/RPM/freealut.spec.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + $(mkdir_p) $(distdir)/admin/CMakeModules $(distdir)/admin/RPM $(distdir)/admin/VisualStudio6 $(distdir)/admin/VisualStudio6/alut $(distdir)/admin/VisualStudio6/hello_world $(distdir)/admin/VisualStudio6/playfile $(distdir)/admin/VisualStudioDotNET $(distdir)/admin/VisualStudioDotNET/alut $(distdir)/admin/VisualStudioDotNET/hello_world $(distdir)/admin/VisualStudioDotNET/playfile $(distdir)/admin/autotools $(distdir)/admin/autotools/m4 $(distdir)/admin/pkgconfig $(distdir)/doc + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(mkdir_p) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile config.h +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-hdr \ + distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-info-am + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \ + check-am clean clean-generic clean-libtool clean-recursive \ + ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \ + dist-shar dist-tarZ dist-zip distcheck distclean \ + distclean-generic distclean-hdr distclean-libtool \ + distclean-recursive distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-generic \ + mostlyclean-libtool mostlyclean-recursive pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am uninstall-info-am + + +# Automatically rebuild libtool if it becomes out-of-date. +libtool: $(LIBTOOL_DEPS) + $(SHELL) ./config.status --recheck + +# The Creative repository has some broken permissions, let's fix this. +permissions: + find . -type f \! -perm +222 \! -name "*.sh" -exec chmod +w {} \; + +# Automatically reformat all C headers and sources with indent according to +# admin/autotools/.indent.pro, but be make-friendly and take some precautions to +# leave those files untouched which wouldn't change. Do not reformat the public +# ALUT header, it won't look the way we want it due to the 'extern "C" { ... }' +# wrapper in it. +indent: + @for i in `find . \( -name "*.c" -o -name "*.h" \) \! -name alut.h -print` ; do \ + cat $$i | ( cd admin/autotools ; indent ) > indent.tmp ; \ + if diff $$i indent.tmp > /dev/null 2>&1 ; then \ + : ; \ + else \ + echo Reformatted $$i ; \ + $(RM) $$i ; \ + mv indent.tmp $$i ; \ + fi ; \ + done + @$(RM) indent.tmp + +# Targets which are no files +.PHONY: permissions indent +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tests/freealut/NEWS b/tests/freealut/NEWS new file mode 100644 index 0000000000000..5ad9c63d58061 --- /dev/null +++ b/tests/freealut/NEWS @@ -0,0 +1,34 @@ +Release 1.1.0 (2006-05-22, tag "freealut_1_1_0") +------------------------------------------------ + + * Improved build under Visual Studio (warnings and paths to OpenAL SDK). + + * Added some fragile logic to find the right path to the OpenAL headers. + + * To guarantee version consistency, generate .spec file via configure. + + * Bumped the package version to 1.1.0 and the library version to 1:0:1 + (i.e. a backwards compatible version, only with new features). + + * Conforms to the ALUT specification 1.1.0 now (added two memory loaders). + + * Fixed build on old Linux distros. + +Release 1.0.1 (2006-02-11, tag "freealut_1_0_1") +------------------------------------------------ + +Bugfix release only, no change in functionality. + + * Install freealut.pc into the correct directory. + + * Fixed CR/LF vs. LF issue in configure on Windows. + + * Added symbol visibility support when using GCC 4.x. + + * When nanosleep returns early due to a signal, continue sleeping, otherwise + return AL_FALSE from alutSleep. + +Release 1.0.0 (2005-12-16, CVS "freealut_1_0_0") +------------------------------------------------ + +Initial release. diff --git a/tests/freealut/README b/tests/freealut/README new file mode 100644 index 0000000000000..c7a7e204a32ae --- /dev/null +++ b/tests/freealut/README @@ -0,0 +1,188 @@ +The freealut library +===================== + +freealut is a free implementation of OpenAL's ALUT standard. See the file +AUTHORS for the people involved. + + +Building and installing on *nix-alikes using autotools +====================================================== + +To build and run ALUT, you need an OpenAL somewhere (and a sound card, of course +:-). If OpenAL is not installed in a standard place (let's say ${OPENAL_PREFIX}) +you'll have to tell the build system about it: + + CPPFLAGS="-I${OPENAL_PREFIX}/include" + LDFLAGS="-L${OPENAL_PREFIX}/lib" + export CPPFLAGS LDFLAGS + +If you install ALUT from the CVS repository, you'll have to call + + ./autogen.sh + +first, this will generate some necessary files for building ALUT. + +If these initial preparations are done, you can simply run: + + ./configure + make + make install + +The last step is optional and must be done as 'root', you can build and use the +test programs in 'test_suite' and the example programs in 'examples' without +installing ALUT. To build these, just go to the respective subdirectories and +run 'make'. + +Alternatively, there is a spec file in the admin/RPM subdirectory, which can be +used to build an RPM. + + +Building with VisualStudio +========================== + +The admin subdirectory contains VisualStudio6 and VisualStudioDotNET +subdirectories, which contain a Visual Studio 6 workspace and a Visual Studio +.NET solution, respectively. These expect the OpenAL SDK (header and import +library) at the standard path "C:\Program Files\OpenAL 1.1 with EFX SDK". If +this is not the case for your setup, you can change this either directly with a +text editor in the project files (the only way for *real* men ;-) or via the +project settings within Visual Studio. When everything is OK, just build +e.g. the hello_world project and you should get the ALUT library itself and a +demo with Steve Baker saying an immortal phrase. + + +Building with CMake +=================== + +The CMake build files are maintained by prakash@punnoor.de, so +if you have troubles building Alut using CMake, please contact +me and not the Alut devs, as the official build system is still +the one using autotools. The CMake build files are currenty +meant as an additional possibility to build Alut. + +The aim of using CMake is making portable development easier, as +CMake containg generators for various build systems. On eg. Unix +Makefiles will be built, and on Windows MS VC++ project files, if +you wish. You can get CMake at cmake.org. + +Current status: +The build system is feature complete, so it (should) build every- +thing as the default one does. + + +This document explains briefly how to build with CMake on Linux via out- +of-tree build: + +- Change to the alut dir. +- Create a dir, eg "default", and change into it. +- Now (eg.) run: + +cmake .. -DCMAKE_INSTALL_PREFIX:STRING="/usr" -DCMAKE_C_FLAGS:STRING="-march=athlon-xp -O2" +make +make install + + If you exported your CFLAGS, there is no need to specify them + explicitly, as CMake will pick them up. + +- OpenAL should get installed as you got used to it. + + +I really would like to get CMake building Alut on every +supported platform. So please contact me if it doesn't build +on yours. I'll try to fix this with your help. + + +Some Tips: + +- You can use a console GUI named ccmake for configuring cmake. + This also comes in handy, to find out about available options. + You can also set options via command-line: + +ccmake .. -DCMAKE_INSTALL_PREFIX:STRING="/usr" -DCMAKE_C_FLAGS:STRING="-march=athlon-xp -O2" + + sets the two variables defined on command line and then starts + the GUI. Press 'c' the first time and every time you want to commit + changes in the config. Finally press 'g' to run the generator. + Btw, to set boolean vars from the command line, use -DVAR:BOOL=X, + where X is eg. ON or OFF. + +- If you want more output at compile time, use + +make VERBOSE=1 + +- If you want to install to a different directory (using same prefix), + use + +make install DESTDIR=/foo/bar + +- CMake doesn't has a distclean target by default, so you better + really do an out-of-tree build, then you can simply delete its + content when you want a distclean... Furthermore it is easier to + have different builds using different parameters via out-of-tree + builds. + +- If you are interested in variables to set, take a look into + CMakeCache.txt after having run the configuring stage. + +- If you update your source tree via cvs and want to rebuild an pre- + viously built lib without cleaning, you better at least clear the + CMake cache (remove CMakeCache.txt) otherwise a modified CMake project + file could result to unwanted behaviour. + + +Support +======= + +Please don't email me the authors directly, sign up to the OpenAL user's mailing +list. Instructions can be found here: + + http://www.openal.org/ + + +Licensing +========= + +These libraries are offered as OpenSource freeware under the provisions of the +GNU Library Public License (LGPL). Those terms and conditions are detailed in +the file 'COPYING' in this directory. + + +Portability and Dependencies +============================ + +This library is designed to be easily portable (and more importantly so that +programs using it can be UTTERLY portable). + + +Compiling/Linking with ALUT +=========================== + +In your source code, simply add: + + #include + +On *nix-alikes, use + + openal-config --cflags + openal-config --libs + +to find out the compiler and linker flags needed for OpenAL, the flags needed +for ALUT itself depend on the --prefix option given to configure. + +In a VisualStudio project, add the path to the ALUT header, import library and +DLL to your project settings as usual. + + +Directories +=========== + +Within this distribution, you will find the following directories: + +admin -- Administrative files needed for building ALUT +doc -- The ALUT documentation +examples -- For application authors, here is a small collection of example + programs that you can use to get you started +include -- The ALUT header +src -- The source code for the ALUT library itself +test_suite -- A small suite of test programs to check that ALUT is installed and + working correctly diff --git a/tests/freealut/aclocal.m4 b/tests/freealut/aclocal.m4 new file mode 100644 index 0000000000000..be67a7d701da8 --- /dev/null +++ b/tests/freealut/aclocal.m4 @@ -0,0 +1,6886 @@ +# generated automatically by aclocal 1.9.5 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- + +# serial 47 AC_PROG_LIBTOOL + + +# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) +# ----------------------------------------------------------- +# If this macro is not defined by Autoconf, define it here. +m4_ifdef([AC_PROVIDE_IFELSE], + [], + [m4_define([AC_PROVIDE_IFELSE], + [m4_ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + + +# AC_PROG_LIBTOOL +# --------------- +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX + ])]) +dnl And a similar setup for Fortran 77 support + AC_PROVIDE_IFELSE([AC_PROG_F77], + [AC_LIBTOOL_F77], + [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], + defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) +])])# AC_PROG_LIBTOOL + + +# _AC_PROG_LIBTOOL +# ---------------- +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +])# _AC_PROG_LIBTOOL + + +# AC_LIBTOOL_SETUP +# ---------------- +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl + +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +AC_LIBTOOL_SYS_MAX_CMD_LEN +AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +AC_LIBTOOL_OBJDIR + +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +_LT_AC_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +AC_CHECK_TOOL(AR, ar, false) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" + ;; + *) + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +AC_ARG_WITH([pic], + [AC_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +AC_LIBTOOL_LANG_C_CONFIG +_LT_AC_TAGCONFIG +])# AC_LIBTOOL_SETUP + + +# _LT_AC_SYS_COMPILER +# ------------------- +AC_DEFUN([_LT_AC_SYS_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_AC_SYS_COMPILER + + +# _LT_AC_SYS_LIBPATH_AIX +# ---------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], +[AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_AC_SYS_LIBPATH_AIX + + +# _LT_AC_SHELL_INIT(ARG) +# ---------------------- +AC_DEFUN([_LT_AC_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_AC_SHELL_INIT + + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[_LT_AC_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1 && unset CDPATH + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string="`eval $cmd`") 2>/dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +])])# _LT_AC_PROG_ECHO_BACKSLASH + + +# _LT_AC_LOCK +# ----------- +AC_DEFUN([_LT_AC_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; + ]) +esac + +need_locks="$enable_libtool_lock" + +])# _LT_AC_LOCK + + +# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED]) +AC_CACHE_CHECK([$1], [$2], + [$2=no + ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s conftest.err; then + $2=yes + fi + fi + $rm conftest* +]) + +if test x"[$]$2" = xyes; then + ifelse([$5], , :, [$5]) +else + ifelse([$6], , :, [$6]) +fi +])# AC_LIBTOOL_COMPILER_OPTION + + +# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ------------------------------------------------------------ +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], +[AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + else + $2=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$4], , :, [$4]) +else + ifelse([$5], , :, [$5]) +fi +])# AC_LIBTOOL_LINKER_OPTION + + +# AC_LIBTOOL_SYS_MAX_CMD_LEN +# -------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], +[# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for *BSD + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + ;; + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \ + = "XX$teststring") >/dev/null 2>&1 && + new_result=`expr "X$teststring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + teststring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +])# AC_LIBTOOL_SYS_MAX_CMD_LEN + + +# _LT_AC_CHECK_DLFCN +# -------------------- +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h)dnl +])# _LT_AC_CHECK_DLFCN + + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ------------------------------------------------------------------ +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_unknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + + +# AC_LIBTOOL_DLOPEN_SELF +# ------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + + +# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) +# --------------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler +AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s out/conftest.err; then + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* +]) +])# AC_LIBTOOL_PROG_CC_C_O + + +# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) +# ----------------------------------------- +# Check to see if we can do hard links to lock some files if needed +AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], +[AC_REQUIRE([_LT_AC_LOCK])dnl + +hard_links="nottested" +if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS + + +# AC_LIBTOOL_OBJDIR +# ----------------- +AC_DEFUN([AC_LIBTOOL_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +])# AC_LIBTOOL_OBJDIR + + +# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) +# ---------------------------------------------- +# Check hardcoding attributes. +AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_AC_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ + test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \ + test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_AC_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_AC_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_AC_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH + + +# AC_LIBTOOL_SYS_LIB_STRIP +# ------------------------ +AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], +[striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +])# AC_LIBTOOL_SYS_LIB_STRIP + + +# AC_LIBTOOL_SYS_DYNAMIC_LINKER +# ----------------------------- +# PORTME Fill in your ld.so characteristics +AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], +[AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + *) # from 3.2 on + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case "$host_cpu" in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:,\t]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no +])# AC_LIBTOOL_SYS_DYNAMIC_LINKER + + +# _LT_AC_TAGCONFIG +# ---------------- +AC_DEFUN([_LT_AC_TAGCONFIG], +[AC_ARG_WITH([tags], + [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], + [include additional configurations @<:@automatic@:>@])], + [tagnames="$withval"]) + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in + "") ;; + *) AC_MSG_ERROR([invalid tag name: $tagname]) + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + AC_MSG_ERROR([tag name \"$tagname\" already exists]) + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_LIBTOOL_LANG_CXX_CONFIG + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + else + tagname="" + fi + ;; + + RC) + AC_LIBTOOL_LANG_RC_CONFIG + ;; + + *) + AC_MSG_ERROR([Unsupported tag name: $tagname]) + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + fi +fi +])# _LT_AC_TAGCONFIG + + +# AC_LIBTOOL_DLOPEN +# ----------------- +# enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], + [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_DLOPEN + + +# AC_LIBTOOL_WIN32_DLL +# -------------------- +# declare package support for building win32 dll's +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_WIN32_DLL + + +# AC_ENABLE_SHARED([DEFAULT]) +# --------------------------- +# implement the --enable-shared flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([shared], + [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]AC_ENABLE_SHARED_DEFAULT) +])# AC_ENABLE_SHARED + + +# AC_DISABLE_SHARED +# ----------------- +#- set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no) +])# AC_DISABLE_SHARED + + +# AC_ENABLE_STATIC([DEFAULT]) +# --------------------------- +# implement the --enable-static flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([static], + [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]AC_ENABLE_STATIC_DEFAULT) +])# AC_ENABLE_STATIC + + +# AC_DISABLE_STATIC +# ----------------- +# set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no) +])# AC_DISABLE_STATIC + + +# AC_ENABLE_FAST_INSTALL([DEFAULT]) +# --------------------------------- +# implement the --enable-fast-install flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([fast-install], + [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) +])# AC_ENABLE_FAST_INSTALL + + +# AC_DISABLE_FAST_INSTALL +# ----------------------- +# set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no) +])# AC_DISABLE_FAST_INSTALL + + +# AC_LIBTOOL_PICMODE([MODE]) +# -------------------------- +# implement the --with-pic flag +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default) +])# AC_LIBTOOL_PICMODE + + +# AC_PROG_EGREP +# ------------- +# This is predefined starting with Autoconf 2.54, so this conditional +# definition can be removed once we require Autoconf 2.54 or later. +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], +[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], + [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi]) + EGREP=$ac_cv_prog_egrep + AC_SUBST([EGREP]) +])]) + + +# AC_PATH_TOOL_PREFIX +# ------------------- +# find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +])# AC_PATH_TOOL_PREFIX + + +# AC_PATH_MAGIC +# ------------- +# find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# AC_PATH_MAGIC + + +# AC_PROG_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH([gnu-ld], + [AC_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no]) +AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case "$host_cpu" in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown +])# AC_DEPLIBS_CHECK_METHOD + + +# AC_PROG_NM +# ---------- +# find the pathname to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/${ac_tool_prefix}nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + esac + fi + done + IFS="$lt_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +])# AC_PROG_NM + + +# AC_CHECK_LIBM +# ------------- +# check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +])# AC_CHECK_LIBM + + +# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that LIBLTDL +# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If +# DIRECTORY is not provided, it is assumed to be `libltdl'. LIBLTDL will +# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_CONVENIENCE + + +# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl installable library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that LIBLTDL +# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If +# DIRECTORY is not provided and an installed libltdl is not found, it is +# assumed to be `libltdl'. LIBLTDL will be prefixed with '${top_builddir}/' +# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single +# quotes!). If your package is not flat and you're not using automake, +# define top_builddir and top_srcdir appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, lt_dlinit, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_INSTALLABLE + + +# AC_LIBTOOL_CXX +# -------------- +# enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], +[AC_REQUIRE([_LT_AC_LANG_CXX]) +])# AC_LIBTOOL_CXX + + +# _LT_AC_LANG_CXX +# --------------- +AC_DEFUN([_LT_AC_LANG_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) +])# _LT_AC_LANG_CXX + +# _LT_AC_PROG_CXXCPP +# --------------- +AC_DEFUN([_LT_AC_PROG_CXXCPP], +[ +AC_REQUIRE([AC_PROG_CXX]) +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +fi +])# _LT_AC_PROG_CXXCPP + +# AC_LIBTOOL_F77 +# -------------- +# enable support for Fortran 77 libraries +AC_DEFUN([AC_LIBTOOL_F77], +[AC_REQUIRE([_LT_AC_LANG_F77]) +])# AC_LIBTOOL_F77 + + +# _LT_AC_LANG_F77 +# --------------- +AC_DEFUN([_LT_AC_LANG_F77], +[AC_REQUIRE([AC_PROG_F77]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) +])# _LT_AC_LANG_F77 + + +# AC_LIBTOOL_GCJ +# -------------- +# enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ], +[AC_REQUIRE([_LT_AC_LANG_GCJ]) +])# AC_LIBTOOL_GCJ + + +# _LT_AC_LANG_GCJ +# --------------- +AC_DEFUN([_LT_AC_LANG_GCJ], +[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) +])# _LT_AC_LANG_GCJ + + +# AC_LIBTOOL_RC +# -------------- +# enable support for Windows resource files +AC_DEFUN([AC_LIBTOOL_RC], +[AC_REQUIRE([LT_AC_PROG_RC]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) +])# AC_LIBTOOL_RC + + +# AC_LIBTOOL_LANG_C_CONFIG +# ------------------------ +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) +AC_DEFUN([_LT_AC_LANG_C_CONFIG], +[lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}\n' + +_LT_AC_SYS_COMPILER + +# +# Check for any special shared library compilation flags. +# +_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)= +if test "$GCC" = no; then + case $host_os in + sco3.2v5*) + _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf' + ;; + esac +fi +if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then + AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries]) + if echo "$old_CC $old_CFLAGS " | grep "[[ ]]$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[ ]]" >/dev/null; then : + else + AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure]) + _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no + fi +fi + + +# +# Check to make sure the static flag actually works. +# +AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), + $_LT_AC_TAGVAR(lt_prog_compiler_static, $1), + [], + [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) + + +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF($1) + +# Report which librarie types wil actually be built +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_C_CONFIG + + +# AC_LIBTOOL_LANG_CXX_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) +AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], +[AC_LANG_PUSH(C++) +AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Dependencies to place before and after the object being linked: +_LT_AC_TAGVAR(predep_objects, $1)= +_LT_AC_TAGVAR(postdep_objects, $1)= +_LT_AC_TAGVAR(predeps, $1)= +_LT_AC_TAGVAR(postdeps, $1)= +_LT_AC_TAGVAR(compiler_lib_search_path, $1)= + +# Source file extension for C++ test sources. +ac_ext=cc + +# Object file extension for compiled C++ test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' +else + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + AC_PROG_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +_LT_AC_TAGVAR(ld_shlibs, $1)=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds it's shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes ; then + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case "$cc_basename" in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + case $cc_basename in + ec++) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + freebsd-elf*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + ;; + gnu*) + ;; + hpux9*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + ;; + *) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC) + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case "$host_cpu" in + ia64*|hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + irix5* | irix6*) + case $cc_basename in + CC) + # SGI C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + linux*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC) + # Portland Group C++ compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + ;; + cxx) + # Compaq C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + m88k*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + mvs*) + case $cc_basename in + cxx) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + openbsd2*) + # C++ shared libraries are fairly broken + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd='echo' + ;; + osf3*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~ + $rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + sco*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + lcc) + # Lucid + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[[LR]]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; +esac +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_AC_TAGVAR(GCC, $1)="$GXX" +_LT_AC_TAGVAR(LD, $1)="$LD" + +AC_LIBTOOL_POSTDEP_PREDEP($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +])# AC_LIBTOOL_LANG_CXX_CONFIG + +# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) +# ------------------------ +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" +ifelse([$1], [], +[#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# 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. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG], +[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# A language-specific compiler. +CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) + +# Is the compiler the GNU C compiler? +with_gcc=$_LT_AC_TAGVAR(GCC, $1) + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_[]_LT_AC_TAGVAR(LD, $1) + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS=$lt_AS + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) + +# Commands used to build and install a shared archive. +archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) +archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) +module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" + +# Set to yes if exported symbols are required. +always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) + +# The commands to list exported symbols. +export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) + +# Symbols that must always be exported. +include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) + +ifelse([$1],[], +[# ### END LIBTOOL CONFIG], +[# ### END LIBTOOL TAG CONFIG: $tagname]) + +__EOF__ + +ifelse([$1],[], [ + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +]) +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi +])# AC_LIBTOOL_CONFIG + + +# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl + +_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI + + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +linux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDGIRSTW]]' + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris* | sysv5*) + symcode='[[BDRT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[[]] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + + +# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) +# --------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], +[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) + ifelse([$1],[CXX],[ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case "$cc_basename" in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux*) + case $cc_basename in + KCC) + # KAI C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + icpc* | ecpc*) + # Intel C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC) + # Portland Group C++ compiler. + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + cxx) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC) + # Rational C++ 2.4.1 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx) + # Digital/Compaq C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + sco*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + *) + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc) + # Lucid + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + unixware*) + ;; + vxworks*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case "$cc_basename" in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + newsos6) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + linux*) + case $cc_basename in + icc* | ecc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgcc | pgf77 | pgf90) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + ccc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + sco3.2v5*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn' + ;; + + solaris*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sunos4*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + unicos*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then + AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), + [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +case "$host_os" in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" + ;; +esac +]) + + +# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) +# ------------------------------------ +# See if the linker supports building shared libraries. +AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], +[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +ifelse([$1],[CXX],[ + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +],[ + runpath_var= + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)= + _LT_AC_TAGVAR(archive_expsym_cmds, $1)= + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown + _LT_AC_TAGVAR(hardcode_automatic, $1)=no + _LT_AC_TAGVAR(module_cmds, $1)= + _LT_AC_TAGVAR(module_expsym_cmds, $1)= + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_AC_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sunos4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $CC,$host_cpu in + pgf77* | pgf90* ) # Portland Group f77 and f90 compilers + tmp_addflag=' -fpic' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + if test $supports_anon_versioning = yes; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~ +cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ +$echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)=$_LT_AC_TAGVAR(archive_cmds, $1) + fi + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = yes; then + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds it's shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + # see comment about different semantics on the GNU ld section + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + bsdi[[45]]*) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' + _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case "$cc_basename" in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | kfreebsd*-gnu | dragonfly*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10* | hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + *) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + sco3.2v5*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ;; + + solaris*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4.2uw2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text' + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv5*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +# +# Do we need to explicitly link libc? +# +case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_AC_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac +])# AC_LIBTOOL_PROG_LD_SHLIBS + + +# _LT_AC_FILE_LTDLL_C +# ------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ +])# _LT_AC_FILE_LTDLL_C + + +# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) +# --------------------------------- +AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) + + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +AC_DEFUN([LT_AC_PROG_RC], +[AC_CHECK_TOOL(RC, windres, no) +]) + +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_MSG_RESULT([$SED]) +]) + +# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.9.5])]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 7 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH]) +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 3 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 12 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.58])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $1 | $1:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. +# +# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories +# created by `make install' are always world readable, even if the +# installer happens to have an overly restrictive umask (e.g. 077). +# This was a mistake. There are at least two reasons why we must not +# use `-m 0755': +# - it causes special bits like SGID to be ignored, +# - it may be too restrictive (some setups expect 775 directories). +# +# Do not use -m 0755 and let people choose whatever they expect by +# setting umask. +# +# We cannot accept any implementation of `mkdir' that recognizes `-p'. +# Some implementations (such as Solaris 8's) are not thread-safe: if a +# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c' +# concurrently, both version can detect that a/ is missing, but only +# one can create it and the other will error out. Consequently we +# restrict ourselves to GNU make (using the --version option ensures +# this.) +AC_DEFUN([AM_PROG_MKDIR_P], +[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi +AC_SUBST([mkdir_p])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([admin/autotools/m4/alut_c__attribute.m4]) +m4_include([admin/autotools/m4/alut_check_cflags_wall.m4]) +m4_include([admin/autotools/m4/alut_check_flag.m4]) +m4_include([admin/autotools/m4/alut_check_func.m4]) +m4_include([admin/autotools/m4/alut_eval_stderr.m4]) diff --git a/tests/freealut/admin/CMakeModules/FindCompilerAttribute.cmake b/tests/freealut/admin/CMakeModules/FindCompilerAttribute.cmake new file mode 100644 index 0000000000000..c16188aeb8261 --- /dev/null +++ b/tests/freealut/admin/CMakeModules/FindCompilerAttribute.cmake @@ -0,0 +1,11 @@ +SET(VAR HAVE_ATTRIBUTE) + +CHECK_C_SOURCE_COMPILES( +"void foo (int bar __attribute__((unused)) ) { } +static void baz (void) __attribute__((unused)); +static void baz (void) { } +int main(){} +" ${VAR}) +IF(${VAR}) + ADD_DEFINE("HAVE___ATTRIBUTE__ 1") +ENDIF(${VAR}) diff --git a/tests/freealut/admin/CMakeModules/FindCompilerFlagsSet.cmake b/tests/freealut/admin/CMakeModules/FindCompilerFlagsSet.cmake new file mode 100644 index 0000000000000..1e31daae56367 --- /dev/null +++ b/tests/freealut/admin/CMakeModules/FindCompilerFlagsSet.cmake @@ -0,0 +1,34 @@ +IF(CMAKE_COMPILER_IS_GNUCC) + #ADD_DEFINITIONS(-std=c99) + + IF(WARNINGS) + SET(ADD_WFLAGS "${ADD_WFLAGS} -Wall -ansi -pedantic -W") + + IF(MORE_WARNINGS) + SET(ADD_WFLAGS "${ADD_WFLAGS} -Waggregate-return -Wbad-function-cast -Wcast-align -Wcast-qual -Wdisabled-optimization -Wendif-labels -Winline -Wlong-long -Wmissing-declarations -Wmissing-noreturn -Wmissing-prototypes -Wnested-externs -Wpacked -Wpointer-arith -Wredundant-decls -Wshadow -Wsign-compare -Wstrict-prototypes -Wwrite-strings") + ENDIF(MORE_WARNINGS) + + # Should we use turn warnings into errors? + IF(USE_WERROR) + SET(ADD_WFLAGS "${ADD_WFLAGS} -Werror -pedantic-errors") + ENDIF(USE_WERROR) + ENDIF(WARNINGS) + + IF(OPTIMIZATION) + SET(ADD_CFLAGS "${ADD_CFLAGS} -O2 -finline-functions -ffast-math") + ENDIF(OPTIMIZATION) + + IF(PROFILE) + SET(ADD_CFLAGS "${ADD_CFLAGS} -pg") + SET(ADD_LDFLAGS "-pg") + ELSE(PROFILE) + + IF(OPTIMIZATION) + # -pg and -fomit-frame-pointer are incompatible + SET(ADD_CFLAGS "${ADD_CFLAGS} -fomit-frame-pointer") + ENDIF(OPTIMIZATION) + ENDIF(PROFILE) +ELSE(CMAKE_COMPILER_IS_GNUCC) + + MESSAGE("Your compiler isn't fully supported yet - no flags set.") +ENDIF(CMAKE_COMPILER_IS_GNUCC) diff --git a/tests/freealut/admin/CMakeModules/FindCompilerVisibility.cmake b/tests/freealut/admin/CMakeModules/FindCompilerVisibility.cmake new file mode 100644 index 0000000000000..2d5282bd4b50b --- /dev/null +++ b/tests/freealut/admin/CMakeModules/FindCompilerVisibility.cmake @@ -0,0 +1,37 @@ +SET(VAR HAVE_VISIBILITY) + +IF(NOT DEFINED ${VAR}) + SET(SOURCE +"void __attribute__((visibility(\"default\"))) test() {} +#ifdef __INTEL_COMPILER +#error ICC breaks with binutils and visibility +#endif +int main(){} +") + FILE(WRITE "${CMAKE_BINARY_DIR}/CMakeTmp/src.c" "${SOURCE}") + + MESSAGE(STATUS "Performing Test ${VAR}") + TRY_COMPILE(${VAR} + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}/CMakeTmp/src.c + CMAKE_FLAGS + "-DCOMPILE_DEFINITIONS:STRING=-fvisibility=hidden" + OUTPUT_VARIABLE OUTPUT) + + WRITE_FILE(${CMAKE_BINARY_DIR}/CMakeOutput.log + "Performing manual C SOURCE FILE Test ${VAR} with the following output:\n" + "${OUTPUT}\n" + "Source file was:\n${SOURCE}\n" APPEND) + + SET(${VAR} ${${VAR}} CACHE INTERNAL "Test Visibility") + IF(${VAR}) + MESSAGE(STATUS "Performing Test ${VAR} - Success") + ELSE(${VAR}) + MESSAGE(STATUS "Performing Test ${VAR} - Failed") + ENDIF(${VAR}) +ENDIF(NOT DEFINED ${VAR}) + +IF(${VAR}) + ADD_DEFINITIONS(-fvisibility=hidden) + ADD_DEFINITIONS(-DHAVE_GCC_VISIBILITY) +ENDIF(${VAR}) diff --git a/tests/freealut/admin/CMakeModules/FindConfigHelper.cmake b/tests/freealut/admin/CMakeModules/FindConfigHelper.cmake new file mode 100644 index 0000000000000..1f3a6faa4b8fc --- /dev/null +++ b/tests/freealut/admin/CMakeModules/FindConfigHelper.cmake @@ -0,0 +1,22 @@ +# config.h magic +SET(CONFIG_H_VALS_OLD "${CONFIG_H_VALS}") +SET(CONFIG_H_VALS "" CACHE INTERNAL "") +SET(CONFIG_H_FILE ${CMAKE_BINARY_DIR}/config.h) +INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}) + + +MACRO(ADD_DEFINE ARG) +SET(CONFIG_H_CONTENT "${CONFIG_H_CONTENT}#define ${ARG} + +") +# can't cache mulitline values +SET(CONFIG_H_VALS "${CONFIG_H_VALS}${ARG}" CACHE INTERNAL "") +ENDMACRO(ADD_DEFINE ARG) + +MACRO(GENERATE_CONFIG_H) +# Generate config.h only if values differ +IF(NOT CONFIG_H_VALS_OLD STREQUAL CONFIG_H_VALS OR NOT EXISTS ${CONFIG_H_FILE}) + MESSAGE(STATUS "Writing config.h") + FILE(WRITE ${CONFIG_H_FILE} "${CONFIG_H_CONTENT}") +ENDIF(NOT CONFIG_H_VALS_OLD STREQUAL CONFIG_H_VALS OR NOT EXISTS ${CONFIG_H_FILE}) +ENDMACRO(GENERATE_CONFIG_H) \ No newline at end of file diff --git a/tests/freealut/admin/CMakeModules/FindSleepFunction.cmake b/tests/freealut/admin/CMakeModules/FindSleepFunction.cmake new file mode 100644 index 0000000000000..ebb823fe590a5 --- /dev/null +++ b/tests/freealut/admin/CMakeModules/FindSleepFunction.cmake @@ -0,0 +1,40 @@ +MACRO(CHECK_INCLUDE_FILE_DEFINE HEADER VAR) +CHECK_INCLUDE_FILE(${HEADER} HAVE_INCLUDE_FILE) +IF(HAVE_INCLUDE_FILE) + ADD_DEFINE("${VAR} 1") + SET(${VAR} 1 CACHE INTERNAL "") +ENDIF(HAVE_INCLUDE_FILE) +ENDMACRO(CHECK_INCLUDE_FILE_DEFINE ARG) + +MACRO(CHECK_FUNCTION_DEFINE HEADERS FUNC PARAM VAR) +CHECK_C_SOURCE_COMPILES( +" +${HEADERS} +int main(){ +${FUNC} ${PARAM}; +} +" ${VAR}) +IF(${VAR}) + ADD_DEFINE("${VAR} 1") +ENDIF(${VAR}) +ENDMACRO(CHECK_FUNCTION_DEFINE HEADERS FUNC PARAM VAR) + + +IF(WIN32) + CHECK_INCLUDE_FILE_DEFINE(windows.h HAVE_WINDOWS_H) + IF(HAVE_WINDOWS_H) + CHECK_FUNCTION_DEFINE("#include " Sleep "(0)" HAVE_SLEEP) + ENDIF(HAVE_WINDOWS_H) +ELSE(WIN32) + + CHECK_INCLUDE_FILE_DEFINE(time.h HAVE_TIME_H) + IF(HAVE_TIME_H) + CHECK_FUNCTION_DEFINE("#include " nanosleep "((struct timespec*)0, (struct timespec*)0)" HAVE_NANOSLEEP) + ELSE(HAVE_TIME_H) + + CHECK_INCLUDE_FILE_DEFINE(unistd.h HAVE_UNISTD_H) + IF(HAVE_UNISTD_H) + CHECK_FUNCTION_DEFINE("#include " usleep "(0)" HAVE_USLEEP) + ENDIF(HAVE_UNISTD_H) + ENDIF(HAVE_TIME_H) +ENDIF(WIN32) \ No newline at end of file diff --git a/tests/freealut/admin/Makefile.am b/tests/freealut/admin/Makefile.am new file mode 100644 index 0000000000000..1060db7c7a691 --- /dev/null +++ b/tests/freealut/admin/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = pkgconfig + diff --git a/tests/freealut/admin/Makefile.in b/tests/freealut/admin/Makefile.in new file mode 100644 index 0000000000000..c97654ae9e0fd --- /dev/null +++ b/tests/freealut/admin/Makefile.in @@ -0,0 +1,484 @@ +# Makefile.in generated by automake 1.9.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = admin +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = \ + $(top_srcdir)/admin/autotools/m4/alut_c__attribute.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_cflags_wall.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_flag.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_func.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_eval_stderr.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBM = @LIBM@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VERSIONINFO = @VERSIONINFO@ +WNO_DEPRECATED_DECLARATIONS_FALSE = @WNO_DEPRECATED_DECLARATIONS_FALSE@ +WNO_DEPRECATED_DECLARATIONS_TRUE = @WNO_DEPRECATED_DECLARATIONS_TRUE@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_AS = @ac_ct_AS@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +SUBDIRS = pkgconfig +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu admin/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu admin/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(mkdir_p) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-info-am + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \ + clean clean-generic clean-libtool clean-recursive ctags \ + ctags-recursive distclean distclean-generic distclean-libtool \ + distclean-recursive distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic maintainer-clean-recursive \ + mostlyclean mostlyclean-generic mostlyclean-libtool \ + mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tests/freealut/admin/RPM/freealut.spec b/tests/freealut/admin/RPM/freealut.spec new file mode 100644 index 0000000000000..3c84fde35017a --- /dev/null +++ b/tests/freealut/admin/RPM/freealut.spec @@ -0,0 +1,103 @@ +# +# spec file for package freealut (1.1.0) +# + +# norootforbuild +# neededforbuild SDL SDL-devel aalib aalib-devel alsa alsa-devel arts audiofile esound esound-devel glib2 glib2-devel libogg libogg-devel libstdc++-devel libvorbis libvorbis-devel openal openal-devel pkgconfig resmgr slang slang-devel smpeg smpeg-devel xorg-x11-devel xorg-x11-libs + +BuildRequires: aaa_base acl attr bash bind-utils bison bzip2 coreutils cpio cpp cracklib cvs cyrus-sasl db devs diffutils e2fsprogs file filesystem fillup findutils flex gawk gdbm-devel glibc glibc-devel glibc-locale gpm grep groff gzip info insserv klogd less libacl libattr libgcc libnscd libselinux libstdc++ libxcrypt libzio m4 make man mktemp module-init-tools ncurses ncurses-devel net-tools netcfg openldap2-client openssl pam pam-modules patch permissions popt procinfo procps psmisc pwdutils rcs readline sed strace syslogd sysvinit tar tcpd texinfo timezone unzip util-linux vim zlib zlib-devel autoconf automake binutils gcc gdbm gettext libtool perl rpm SDL SDL-devel aalib aalib-devel alsa alsa-devel arts audiofile esound esound-devel glib2 glib2-devel libogg libogg-devel libstdc++-devel libvorbis libvorbis-devel openal openal-devel resmgr slang slang-devel smpeg smpeg-devel xorg-x11-devel xorg-x11-libs dialog expat fontconfig fontconfig-devel freetype2 freetype2-devel gnome-filesystem jack liblcms libjpeg libmng libpng libsndfile libtiff pciutils pkgconfig qt3 aaa_skel ash bind-libs gpg libgcj logrotate openslp suse-build-key suse-release tcsh + +Name: freealut +License: LGPL +Group: System/Libraries +Autoreqprov: on +Version: 1.1.0 +Release: 1 +URL: http://www.openal.org/ +Summary: Open Audio Library Utility Toolkit +Source: freealut-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-build + +%description +freealut is a highly portable Open Source implementation of ALUT, a +utility toolkit for OpenAL. ALUT makes managing of OpenAL contexts, +loading sounds in various formats and creating waveforms very easy. + + + +Authors: +-------- + Erik Hofman + Steve Baker + Sven Panne + +%package devel +Summary: Static libraries, header files and tests for the freealut library +Requires: freealut = %{version} +Group: Development/Libraries/C and C++ + +%description devel +freealut is a highly portable Open Source implementation of ALUT, a +utility toolkit for OpenAL. ALUT makes managing of OpenAL contexts, +loading sounds in various formats and creating waveforms very easy. + + + +Authors: +-------- + Erik Hofman + Steve Baker + Sven Panne + +%debug_package +%prep +%setup -q + +%build +%{?suse_update_config:%{suse_update_config -f admin/autotools}} +test -f configure || ./autogen.sh +export CFLAGS="$RPM_OPT_FLAGS" +./configure --prefix=%{_prefix} +make + +%install +rm -rf $RPM_BUILD_ROOT +make DESTDIR=$RPM_BUILD_ROOT install + +# documentation +install -m 755 -d $RPM_BUILD_ROOT%{_defaultdocdir}/%{name} +install -m 644 AUTHORS COPYING ChangeLog NEWS README doc/alut.css doc/alut.html \ + $RPM_BUILD_ROOT%{_defaultdocdir}/%{name} + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%doc %{_defaultdocdir}/%{name}/AUTHORS +%doc %{_defaultdocdir}/%{name}/COPYING +%doc %{_defaultdocdir}/%{name}/ChangeLog +%doc %{_defaultdocdir}/%{name}/NEWS +%doc %{_defaultdocdir}/%{name}/README +%{_libdir}/libalut.so.* + +%files devel +%defattr(-,root,root) +%doc %{_defaultdocdir}/%{name}/alut.html +%doc %{_defaultdocdir}/%{name}/alut.css +%{_prefix}/bin/freealut-config +%{_includedir}/AL/alut.h +%{_libdir}/libalut.a +%{_libdir}/libalut.la +%{_libdir}/libalut.so +%{_libdir}/pkgconfig/freealut.pc + +%changelog -n freealut +* Wed Apr 12 2006 - sven.panne@aedion.de +- Handle version via configure +* Thu Dec 15 2005 - sven.panne@aedion.de +- Added freealut-config and freealut.pc +* Mon Nov 28 2005 - sven.panne@aedion.de +- Fixed build dependencies +* Mon Oct 10 2005 - sven.panne@aedion.de +- Initial version diff --git a/tests/freealut/admin/RPM/freealut.spec.in b/tests/freealut/admin/RPM/freealut.spec.in new file mode 100644 index 0000000000000..bfde367cf8be7 --- /dev/null +++ b/tests/freealut/admin/RPM/freealut.spec.in @@ -0,0 +1,103 @@ +# +# spec file for package freealut (@PACKAGE_VERSION@) +# + +# norootforbuild +# neededforbuild SDL SDL-devel aalib aalib-devel alsa alsa-devel arts audiofile esound esound-devel glib2 glib2-devel libogg libogg-devel libstdc++-devel libvorbis libvorbis-devel openal openal-devel pkgconfig resmgr slang slang-devel smpeg smpeg-devel xorg-x11-devel xorg-x11-libs + +BuildRequires: aaa_base acl attr bash bind-utils bison bzip2 coreutils cpio cpp cracklib cvs cyrus-sasl db devs diffutils e2fsprogs file filesystem fillup findutils flex gawk gdbm-devel glibc glibc-devel glibc-locale gpm grep groff gzip info insserv klogd less libacl libattr libgcc libnscd libselinux libstdc++ libxcrypt libzio m4 make man mktemp module-init-tools ncurses ncurses-devel net-tools netcfg openldap2-client openssl pam pam-modules patch permissions popt procinfo procps psmisc pwdutils rcs readline sed strace syslogd sysvinit tar tcpd texinfo timezone unzip util-linux vim zlib zlib-devel autoconf automake binutils gcc gdbm gettext libtool perl rpm SDL SDL-devel aalib aalib-devel alsa alsa-devel arts audiofile esound esound-devel glib2 glib2-devel libogg libogg-devel libstdc++-devel libvorbis libvorbis-devel openal openal-devel resmgr slang slang-devel smpeg smpeg-devel xorg-x11-devel xorg-x11-libs dialog expat fontconfig fontconfig-devel freetype2 freetype2-devel gnome-filesystem jack liblcms libjpeg libmng libpng libsndfile libtiff pciutils pkgconfig qt3 aaa_skel ash bind-libs gpg libgcj logrotate openslp suse-build-key suse-release tcsh + +Name: freealut +License: LGPL +Group: System/Libraries +Autoreqprov: on +Version: @PACKAGE_VERSION@ +Release: 1 +URL: http://www.openal.org/ +Summary: Open Audio Library Utility Toolkit +Source: freealut-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-build + +%description +freealut is a highly portable Open Source implementation of ALUT, a +utility toolkit for OpenAL. ALUT makes managing of OpenAL contexts, +loading sounds in various formats and creating waveforms very easy. + + + +Authors: +-------- + Erik Hofman + Steve Baker + Sven Panne + +%package devel +Summary: Static libraries, header files and tests for the freealut library +Requires: freealut = %{version} +Group: Development/Libraries/C and C++ + +%description devel +freealut is a highly portable Open Source implementation of ALUT, a +utility toolkit for OpenAL. ALUT makes managing of OpenAL contexts, +loading sounds in various formats and creating waveforms very easy. + + + +Authors: +-------- + Erik Hofman + Steve Baker + Sven Panne + +%debug_package +%prep +%setup -q + +%build +%{?suse_update_config:%{suse_update_config -f admin/autotools}} +test -f configure || ./autogen.sh +export CFLAGS="$RPM_OPT_FLAGS" +./configure --prefix=%{_prefix} +make + +%install +rm -rf $RPM_BUILD_ROOT +make DESTDIR=$RPM_BUILD_ROOT install + +# documentation +install -m 755 -d $RPM_BUILD_ROOT%{_defaultdocdir}/%{name} +install -m 644 AUTHORS COPYING ChangeLog NEWS README doc/alut.css doc/alut.html \ + $RPM_BUILD_ROOT%{_defaultdocdir}/%{name} + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%doc %{_defaultdocdir}/%{name}/AUTHORS +%doc %{_defaultdocdir}/%{name}/COPYING +%doc %{_defaultdocdir}/%{name}/ChangeLog +%doc %{_defaultdocdir}/%{name}/NEWS +%doc %{_defaultdocdir}/%{name}/README +%{_libdir}/libalut.so.* + +%files devel +%defattr(-,root,root) +%doc %{_defaultdocdir}/%{name}/alut.html +%doc %{_defaultdocdir}/%{name}/alut.css +%{_prefix}/bin/freealut-config +%{_includedir}/AL/alut.h +%{_libdir}/libalut.a +%{_libdir}/libalut.la +%{_libdir}/libalut.so +%{_libdir}/pkgconfig/freealut.pc + +%changelog -n freealut +* Wed Apr 12 2006 - sven.panne@aedion.de +- Handle version via configure +* Thu Dec 15 2005 - sven.panne@aedion.de +- Added freealut-config and freealut.pc +* Mon Nov 28 2005 - sven.panne@aedion.de +- Fixed build dependencies +* Mon Oct 10 2005 - sven.panne@aedion.de +- Initial version diff --git a/tests/freealut/admin/VisualStudio6/alut.dsw b/tests/freealut/admin/VisualStudio6/alut.dsw new file mode 100644 index 0000000000000..0754c4fafee7a --- /dev/null +++ b/tests/freealut/admin/VisualStudio6/alut.dsw @@ -0,0 +1,59 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELÖSCHT WERDEN! + +############################################################################### + +Project: "alut"=.\alut\alut.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "hello_world"=.\hello_world\hello_world.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name alut + End Project Dependency +}}} + +############################################################################### + +Project: "playfile"=.\playfile\playfile.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name alut + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/tests/freealut/admin/VisualStudio6/alut/alut.dsp b/tests/freealut/admin/VisualStudio6/alut/alut.dsp new file mode 100644 index 0000000000000..ee2a91c4f826c --- /dev/null +++ b/tests/freealut/admin/VisualStudio6/alut/alut.dsp @@ -0,0 +1,150 @@ +# Microsoft Developer Studio Project File - Name="alut" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** NICHT BEARBEITEN ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=alut - Win32 Debug +!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE +!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl +!MESSAGE +!MESSAGE NMAKE /f "alut.mak". +!MESSAGE +!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben +!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: +!MESSAGE +!MESSAGE NMAKE /f "alut.mak" CFG="alut - Win32 Debug" +!MESSAGE +!MESSAGE Für die Konfiguration stehen zur Auswahl: +!MESSAGE +!MESSAGE "alut - Win32 Release" (basierend auf "Win32 (x86) Dynamic-Link Library") +!MESSAGE "alut - Win32 Debug" (basierend auf "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "alut - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ALUT_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\include" /I "C:\Program Files\OpenAL 1.1 with EFX SDK\include" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "ALUT_EXPORTS" /D "WIN32" /D "_MBCS" /D "ALUT_BUILD_LIBRARY" /D "HAVE__STAT" /D "HAVE_BASETSD_H" /D "HAVE_SLEEP" /D "HAVE_WINDOWS_H" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib openal32.lib /nologo /dll /machine:I386 /libpath:"C:\Program Files\OpenAL 1.1 with EFX SDK\libs\Win32" + +!ELSEIF "$(CFG)" == "alut - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ALUT_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\include" /I "C:\Program Files\OpenAL 1.1 with EFX SDK\include" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "ALUT_EXPORTS" /D "WIN32" /D "_MBCS" /D "ALUT_BUILD_LIBRARY" /D "HAVE__STAT" /D "HAVE_BASETSD_H" /D "HAVE_SLEEP" /D "HAVE_WINDOWS_H" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib openal32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"C:\Program Files\OpenAL 1.1 with EFX SDK\libs\Win32" + +!ENDIF + +# Begin Target + +# Name "alut - Win32 Release" +# Name "alut - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\src\alutBufferData.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\alutCodec.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\alutError.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\alutInit.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\alutInputStream.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\alutLoader.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\alutOutputStream.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\alutUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\alutVersion.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\alutWaveform.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\src\alutInternal.h +# End Source File +# End Group +# Begin Group "ALUT Header" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\include\AL\alut.h +# End Source File +# End Group +# End Target +# End Project diff --git a/tests/freealut/admin/VisualStudio6/hello_world/hello_world.dsp b/tests/freealut/admin/VisualStudio6/hello_world/hello_world.dsp new file mode 100644 index 0000000000000..49fbbb6e02052 --- /dev/null +++ b/tests/freealut/admin/VisualStudio6/hello_world/hello_world.dsp @@ -0,0 +1,93 @@ +# Microsoft Developer Studio Project File - Name="hello_world" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** NICHT BEARBEITEN ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=hello_world - Win32 Debug +!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE +!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl +!MESSAGE +!MESSAGE NMAKE /f "hello_world.mak". +!MESSAGE +!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben +!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: +!MESSAGE +!MESSAGE NMAKE /f "hello_world.mak" CFG="hello_world - Win32 Debug" +!MESSAGE +!MESSAGE Für die Konfiguration stehen zur Auswahl: +!MESSAGE +!MESSAGE "hello_world - Win32 Release" (basierend auf "Win32 (x86) Console Application") +!MESSAGE "hello_world - Win32 Debug" (basierend auf "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "hello_world - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\include" /I "C:\Program Files\OpenAL 1.1 with EFX SDK\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 openal32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /libpath:"C:\Program Files\OpenAL 1.1 with EFX SDK\libs\Win32" + +!ELSEIF "$(CFG)" == "hello_world - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\include" /I "C:\Program Files\OpenAL 1.1 with EFX SDK\include" /D "_CONSOLE" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "ALUT_BUILD_LIBRARY" /D "HAVE__STAT" /D "HAVE_BASETSD_H" /D "HAVE_SLEEP" /D "HAVE_WINDOWS_H" /YX /FD /GZ /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib openal32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"C:\Program Files\OpenAL 1.1 with EFX SDK\libs\Win32" + +!ENDIF + +# Begin Target + +# Name "hello_world - Win32 Release" +# Name "hello_world - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\examples\hello_world.c +# End Source File +# End Group +# End Target +# End Project diff --git a/tests/freealut/admin/VisualStudio6/playfile/playfile.dsp b/tests/freealut/admin/VisualStudio6/playfile/playfile.dsp new file mode 100644 index 0000000000000..a423b8992c617 --- /dev/null +++ b/tests/freealut/admin/VisualStudio6/playfile/playfile.dsp @@ -0,0 +1,93 @@ +# Microsoft Developer Studio Project File - Name="playfile" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** NICHT BEARBEITEN ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=playfile - Win32 Debug +!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE +!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl +!MESSAGE +!MESSAGE NMAKE /f "playfile.mak". +!MESSAGE +!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben +!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: +!MESSAGE +!MESSAGE NMAKE /f "playfile.mak" CFG="playfile - Win32 Debug" +!MESSAGE +!MESSAGE Für die Konfiguration stehen zur Auswahl: +!MESSAGE +!MESSAGE "playfile - Win32 Release" (basierend auf "Win32 (x86) Console Application") +!MESSAGE "playfile - Win32 Debug" (basierend auf "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "playfile - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\include" /I "C:\Program Files\OpenAL 1.1 with EFX SDK\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib openal32.lib /nologo /subsystem:console /machine:I386 /libpath:"C:\Program Files\OpenAL 1.1 with EFX SDK\libs\Win32" + +!ELSEIF "$(CFG)" == "playfile - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\include" /I "C:\Program Files\OpenAL 1.1 with EFX SDK\include" /D "_CONSOLE" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "ALUT_BUILD_LIBRARY" /D "HAVE__STAT" /D "HAVE_BASETSD_H" /D "HAVE_SLEEP" /D "HAVE_WINDOWS_H" /YX /FD /GZ /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib openal32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"C:\Program Files\OpenAL 1.1 with EFX SDK\libs\Win32" + +!ENDIF + +# Begin Target + +# Name "playfile - Win32 Release" +# Name "playfile - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\examples\playfile.c +# End Source File +# End Group +# End Target +# End Project diff --git a/tests/freealut/admin/VisualStudioDotNET/alut.sln b/tests/freealut/admin/VisualStudioDotNET/alut.sln new file mode 100644 index 0000000000000..2eebb8595eb81 --- /dev/null +++ b/tests/freealut/admin/VisualStudioDotNET/alut.sln @@ -0,0 +1,35 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "alut", "alut\alut.vcproj", "{07149BCB-BE8A-4503-BE18-815D64233116}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hello_world", "hello_world\hello_world.vcproj", "{64A0E948-E88A-4F4E-9039-43E539F5DF77}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "playfile", "playfile\playfile.vcproj", "{6E63082A-187E-4F18-9E54-C8A7C1CE1D0B}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + {64A0E948-E88A-4F4E-9039-43E539F5DF77}.0 = {07149BCB-BE8A-4503-BE18-815D64233116} + {6E63082A-187E-4F18-9E54-C8A7C1CE1D0B}.0 = {07149BCB-BE8A-4503-BE18-815D64233116} + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {07149BCB-BE8A-4503-BE18-815D64233116}.Debug.ActiveCfg = Debug|Win32 + {07149BCB-BE8A-4503-BE18-815D64233116}.Debug.Build.0 = Debug|Win32 + {07149BCB-BE8A-4503-BE18-815D64233116}.Release.ActiveCfg = Release|Win32 + {07149BCB-BE8A-4503-BE18-815D64233116}.Release.Build.0 = Release|Win32 + {64A0E948-E88A-4F4E-9039-43E539F5DF77}.Debug.ActiveCfg = Debug|Win32 + {64A0E948-E88A-4F4E-9039-43E539F5DF77}.Debug.Build.0 = Debug|Win32 + {64A0E948-E88A-4F4E-9039-43E539F5DF77}.Release.ActiveCfg = Release|Win32 + {64A0E948-E88A-4F4E-9039-43E539F5DF77}.Release.Build.0 = Release|Win32 + {6E63082A-187E-4F18-9E54-C8A7C1CE1D0B}.Debug.ActiveCfg = Debug|Win32 + {6E63082A-187E-4F18-9E54-C8A7C1CE1D0B}.Debug.Build.0 = Debug|Win32 + {6E63082A-187E-4F18-9E54-C8A7C1CE1D0B}.Release.ActiveCfg = Release|Win32 + {6E63082A-187E-4F18-9E54-C8A7C1CE1D0B}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/tests/freealut/admin/VisualStudioDotNET/alut/alut.vcproj b/tests/freealut/admin/VisualStudioDotNET/alut/alut.vcproj new file mode 100644 index 0000000000000..0988235b8d11a --- /dev/null +++ b/tests/freealut/admin/VisualStudioDotNET/alut/alut.vcproj @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/freealut/admin/VisualStudioDotNET/hello_world/hello_world.vcproj b/tests/freealut/admin/VisualStudioDotNET/hello_world/hello_world.vcproj new file mode 100644 index 0000000000000..64efde1791ef1 --- /dev/null +++ b/tests/freealut/admin/VisualStudioDotNET/hello_world/hello_world.vcproj @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/freealut/admin/VisualStudioDotNET/playfile/playfile.vcproj b/tests/freealut/admin/VisualStudioDotNET/playfile/playfile.vcproj new file mode 100644 index 0000000000000..746cafedef327 --- /dev/null +++ b/tests/freealut/admin/VisualStudioDotNET/playfile/playfile.vcproj @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/freealut/admin/autotools/.indent.pro b/tests/freealut/admin/autotools/.indent.pro new file mode 100644 index 0000000000000..fed34fdc763f0 --- /dev/null +++ b/tests/freealut/admin/autotools/.indent.pro @@ -0,0 +1,46 @@ +/* use GNU coding style */ +--gnu-style + +/* TABs are evil! */ +--no-tabs + +/* for more consistency */ +--swallow-optional-blank-lines + +/* OpenAL typedefs */ +-T ALCboolean +-T ALCbyte +-T ALCchar +-T ALCcontext +-T ALCdevice +-T ALCdouble +-T ALCenum +-T ALCfloat +-T ALCint +-T ALCshort +-T ALCsizei +-T ALCubyte +-T ALCuint +-T ALCushort +-T ALCvoid +-T ALboolean +-T ALbyte +-T ALchar +-T ALdouble +-T ALenum +-T ALfloat +-T ALint +-T ALshort +-T ALsizei +-T ALubyte +-T ALuint +-T ALushort +-T ALvoid +-T BufferData +-T InputStream +-T Int32BigEndian +-T OutputStream +-T Status +-T UInt16LittleEndian +-T UInt32LittleEndian +-T size_t diff --git a/tests/freealut/admin/autotools/compile b/tests/freealut/admin/autotools/compile new file mode 100755 index 0000000000000..ad57e2f687554 --- /dev/null +++ b/tests/freealut/admin/autotools/compile @@ -0,0 +1,142 @@ +#! /bin/sh +# Wrapper for compilers which do not understand `-c -o'. + +scriptversion=2005-02-03.08 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# 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, 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. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand `-c -o'. +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file `INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; +esac + +ofile= +cfile= +eat= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as `compile cc -o foo foo.c'. + # So we strip `-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no `-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # `.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` + +# Create the lock directory. +# Note: use `[/.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/tests/freealut/admin/autotools/config.guess b/tests/freealut/admin/autotools/config.guess new file mode 100755 index 0000000000000..44f30e6c1a315 --- /dev/null +++ b/tests/freealut/admin/autotools/config.guess @@ -0,0 +1,1469 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-02-10' + +# This file 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. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_MACHINE}" in + i?86) + test -z "$VENDOR" && VENDOR=pc + ;; + *) + test -z "$VENDOR" && VENDOR=unknown + ;; +esac +test -f /etc/SuSE-release -o -f /.buildenv && VENDOR=suse + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + amd64:OpenBSD:*:*) + echo x86_64-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + cats:OpenBSD:*:*) + echo arm-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + luna88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + macppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvmeppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips64-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit 0 ;; + macppc:MirBSD:*:*) + echo powerppc-unknown-mirbsd${UNAME_RELEASE} + exit 0 ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit 0 ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit 0 ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit 0 ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7 && exit 0 ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c \ + && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && exit 0 + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit 0 ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + # avoid double evaluation of $set_cc_for_build + test -n "$CC_FOR_BUILD" || eval $set_cc_for_build + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit 0 ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + amd64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux + exit 0 ;; + cris:Linux:*:*) + echo cris-axis-linux + exit 0 ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux + exit 0 ;; + frv:Linux:*:*) + echo frv-${VENDOR}-linux + exit 0 ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux + exit 0 ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux + exit 0 ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux + exit 0 ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-${VENDOR}-linux" && exit 0 + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-${VENDOR}-linux" && exit 0 + ;; + ppc:Linux:*:*) + echo powerpc-${VENDOR}-linux + exit 0 ;; + ppc64:Linux:*:*) + echo powerpc64-${VENDOR}-linux + exit 0 ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="-libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-${VENDOR}-linux${LIBC} + exit 0 ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-${VENDOR}-linux ;; + PA8*) echo hppa2.0-${VENDOR}-linux ;; + *) echo hppa-${VENDOR}-linux ;; + esac + exit 0 ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-${VENDOR}-linux + exit 0 ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit 0 ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux + exit 0 ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux + exit 0 ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux + exit 0 ;; + x86_64:Linux:*:*) + echo x86_64-${VENDOR}-linux + exit 0 ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-${VENDOR}-linux" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-${VENDOR}-linuxaout" + exit 0 ;; + coff-i386) + echo "${UNAME_MACHINE}-${VENDOR}-linuxcoff" + exit 0 ;; + "") + # Either a pre-BFD a.out linker (linuxoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-${VENDOR}-linuxoldld" + exit 0 ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + test x"${LIBC}" != x && echo "${UNAME_MACHINE}-${VENDOR}-linux-${LIBC}" | sed 's/linux-gnu/linux/' && exit 0 + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit 0 ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit 0 ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit 0 ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit 0 ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit 0 ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i*86:*:5:[78]*) + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit 0 ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit 0 ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit 0 ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit 0 ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + *86) UNAME_PROCESSOR=i686 ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit 0 ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit 0 ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit 0 ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit 0 ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit 0 ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit 0 ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit 0 ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit 0 ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms && exit 0 ;; + I*) echo ia64-dec-vms && exit 0 ;; + V*) echo vax-dec-vms && exit 0 ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/tests/freealut/admin/autotools/config.sub b/tests/freealut/admin/autotools/config.sub new file mode 100755 index 0000000000000..c884ad4e34816 --- /dev/null +++ b/tests/freealut/admin/autotools/config.sub @@ -0,0 +1,1563 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-02-10' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | msp430 \ + | ns16k | ns32k \ + | openrisc | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | msp430-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + or32 | or32-*) + basic_machine=or32-unknown + os=-coff + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/tests/freealut/admin/autotools/depcomp b/tests/freealut/admin/autotools/depcomp new file mode 100755 index 0000000000000..ffcd540c3366d --- /dev/null +++ b/tests/freealut/admin/autotools/depcomp @@ -0,0 +1,529 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2005-02-09.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, 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, 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. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + stat=$? + + if test -f "$tmpdepfile"; then : + else + stripped=`echo "$stripped" | sed 's,^.*/,,'` + tmpdepfile="$stripped.u" + fi + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + outname="$stripped.o" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mecanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/tests/freealut/admin/autotools/install-sh b/tests/freealut/admin/autotools/install-sh new file mode 100755 index 0000000000000..1a8353401c422 --- /dev/null +++ b/tests/freealut/admin/autotools/install-sh @@ -0,0 +1,323 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2005-02-02.21 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# 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 +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +chmodcmd="$chmodprog 0755" +chowncmd= +chgrpcmd= +stripcmd= +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src= +dst= +dir_arg= +dstarg= +no_target_directory= + +usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: +-c (ignored) +-d create directories instead of installing files. +-g GROUP $chgrpprog installed files to GROUP. +-m MODE $chmodprog installed files to MODE. +-o USER $chownprog installed files to USER. +-s $stripprog installed files. +-t DIRECTORY install into DIRECTORY. +-T report an error if DSTFILE is a directory. +--help display this help and exit. +--version display version info and exit. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG +" + +while test -n "$1"; do + case $1 in + -c) shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + --help) echo "$usage"; exit $?;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t) dstarg=$2 + shift + shift + continue;; + + -T) no_target_directory=true + shift + continue;; + + --version) echo "$0 $scriptversion"; exit $?;; + + *) # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + test -n "$dir_arg$dstarg" && break + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dstarg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dstarg" + shift # fnord + fi + shift # arg + dstarg=$arg + done + break;; + esac +done + +if test -z "$1"; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src ;; + esac + + if test -n "$dir_arg"; then + dst=$src + src= + + if test -d "$dst"; then + mkdircmd=: + chmodcmd= + else + mkdircmd=$mkdirprog + fi + else + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dstarg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dstarg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst ;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dstarg: Is a directory" >&2 + exit 1 + fi + dst=$dst/`basename "$src"` + fi + fi + + # This sed command emulates the dirname command. + dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` + + # Make sure that the destination directory exists. + + # Skip lots of stat calls in the usual case. + if test ! -d "$dstdir"; then + defaultIFS=' + ' + IFS="${IFS-$defaultIFS}" + + oIFS=$IFS + # Some sh's can't handle IFS=/ for some reason. + IFS='%' + set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` + shift + IFS=$oIFS + + pathcomp= + + while test $# -ne 0 ; do + pathcomp=$pathcomp$1 + shift + if test ! -d "$pathcomp"; then + $mkdirprog "$pathcomp" + # mkdir can fail with a `File exist' error in case several + # install-sh are creating the directory concurrently. This + # is OK. + test -d "$pathcomp" || exit + fi + pathcomp=$pathcomp/ + done + fi + + if test -n "$dir_arg"; then + $doit $mkdircmd "$dst" \ + && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } + + else + dstfile=`basename "$dst"` + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + trap '(exit $?); exit' 1 2 13 15 + + # Copy the file name to the temp name. + $doit $cpprog "$src" "$dsttmp" && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && + + # Now rename the file to the real destination. + { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ + || { + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + if test -f "$dstdir/$dstfile"; then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ + || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ + || { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit 1 + } + else + : + fi + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + } + } + fi || { (exit 1); exit 1; } +done + +# The final little trick to "correctly" pass the exit status to the exit trap. +{ + (exit 0); exit 0 +} + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/tests/freealut/admin/autotools/ltmain.sh b/tests/freealut/admin/autotools/ltmain.sh new file mode 100644 index 0000000000000..3d0710108d7e0 --- /dev/null +++ b/tests/freealut/admin/autotools/ltmain.sh @@ -0,0 +1,6460 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun configure. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# 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. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +basename="s,^.*/,,g" + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +progname=`echo "$progpath" | $SED $basename` +modename="$progname" + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION=1.5.14 +TIMESTAMP=" (1.1220.2.195 2005/02/12 12:12:33)" + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes. +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +quote_scanset='[[~#^*{};<>?'"'"' ]' + +##################################### +# Shell function definitions: +# This seems to be the best place for them + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ + $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | \ + sed -n -e '1,100{/ I /{x;/import/!{s/^/import/;h;p;};x;};}'` + if test "X$win32_nmres" = "Ximport" ; then + win32_libid_type="x86 archive import" + else + win32_libid_type="x86 archive static" + fi + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $echo $win32_libid_type +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + case $arg in + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + case $arg in + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case "$@ " in + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + $echo "$modename: unable to infer tagged configuration" + $echo "$modename: specify a tag with \`--tag'" 1>&2 + exit $EXIT_FAILURE +# else +# $echo "$modename: using $tagname tagged configuration" + fi + ;; + esac + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + f_ex_an_ar_lib=`$echo "X$f_ex_an_ar_oldlib" | $Xsed -e 's%^.*/%%'` + + $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)" + $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $? + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 + $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 + $show "cp $f_ex_an_ar_oldlib $f_ex_an_ar_dir/$f_ex_an_ar_lib" + $run eval "cp \$f_ex_an_ar_oldlib \$f_ex_an_ar_dir/\$f_ex_an_ar_lib" + $AR t "$f_ex_an_ar_oldlib" | sort | uniq -c \ + | $EGREP -v '^[ ]*1[ ]' | while read count name + do + i=1 + while test "$i" -le "$count" + do + # Put our $i before any first dot (extension) + # Never overwrite any file + name_to="$name" + while test "X$name_to" = "X$name" || test -f "$f_ex_an_ar_dir/$name_to" + do + name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` + done + $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_lib '$name' && $mv '$name' '$name_to')" + $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_lib '$name' && $mv '$name' '$name_to' && $AR -d \$f_ex_an_ar_lib '$name')" || exit $? + i=`expr $i + 1` + done + done + $show "$rm $f_ex_an_ar_dir/$f_ex_an_ar_lib" + $run eval "$rm \$f_ex_an_ar_dir/\$f_ex_an_ar_lib" + fi +} + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + my_status="" + + $show "${rm}r $my_gentop" + $run ${rm}r "$my_gentop" + $show "$mkdir $my_gentop" + $run $mkdir "$my_gentop" + my_status=$? + if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then + exit $my_status + fi + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'` + my_xdir="$my_gentop/$my_xlib" + + $show "${rm}r $my_xdir" + $run ${rm}r "$my_xdir" + $show "$mkdir $my_xdir" + $run $mkdir "$my_xdir" + status=$? + if test "$status" -ne 0 && test ! -d "$my_xdir"; then + exit $status + fi + case $host in + *-darwin*) + $show "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + if test -z "$run"; then + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'` + darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null` + if test -n "$darwin_arches"; then + darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + $show "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we have a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + lipo -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + ${rm}r unfat-$$ + cd "$darwin_orig_dir" + else + cd "$darwin_orig_dir" + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + fi # $run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + func_extract_archives_result="$my_oldobjs" +} +# End of Shell function definitions +##################################### + +# Darwin sucks +eval std_shrext=\"$shrext_cmds\" + +# Parse our command line options once, thoroughly. +while test "$#" -gt 0 +do + arg="$1" + shift + + case $arg in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + execute_dlfiles) + execute_dlfiles="$execute_dlfiles $arg" + ;; + tag) + tagname="$arg" + preserve_args="${preserve_args}=$arg" + + # Check whether tagname contains only valid characters + case $tagname in + *[!-_A-Za-z0-9,/]*) + $echo "$progname: invalid tag name: $tagname" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $tagname in + CC) + # Don't test for the "default" C tag, as we know, it's there, but + # not specially marked. + ;; + *) + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then + taglist="$taglist $tagname" + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`" + else + $echo "$progname: ignoring unknown tag $tagname" 1>&2 + fi + ;; + esac + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case $arg in + --help) + show_help=yes + ;; + + --version) + $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" + $echo + $echo "Copyright (C) 2005 Free Software Foundation, Inc." + $echo "This is free software; see the source for copying conditions. There is NO" + $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + exit $? + ;; + + --config) + ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath + # Now print the configurations for the tags. + for tagname in $taglist; do + ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath" + done + exit $? + ;; + + --debug) + $echo "$progname: enabling shell trace mode" + set -x + preserve_args="$preserve_args $arg" + ;; + + --dry-run | -n) + run=: + ;; + + --features) + $echo "host: $host" + if test "$build_libtool_libs" = yes; then + $echo "enable shared libraries" + else + $echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $echo "enable static libraries" + else + $echo "disable static libraries" + fi + exit $? + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --preserve-dup-deps) duplicate_deps="yes" ;; + + --quiet | --silent) + show=: + preserve_args="$preserve_args $arg" + ;; + + --tag) prevopt="--tag" prev=tag ;; + --tag=*) + set tag "$optarg" ${1+"$@"} + shift + prev=tag + preserve_args="$preserve_args --tag" + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE +fi + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 + $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2 + case $nonopt in + *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) + mode=link + for arg + do + case $arg in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case $mode in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + + for arg + do + case "$arg_mode" in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + if test -n "$libobj" ; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit $EXIT_FAILURE + fi + arg_mode=target + continue + ;; + + -static | -prefer-pic | -prefer-non-pic) + later="$later $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $arg in + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + arg="\"$arg\"" + ;; + esac + lastarg="$lastarg $arg" + done + IFS="$save_ifs" + lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` + + # Add the arguments to base_compile. + base_compile="$base_compile $lastarg" + continue + ;; + + * ) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + case $lastarg in + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, and some SunOS ksh mistreat backslash-escaping + # in scan sets (worked around with variable expansion), + # and furthermore cannot handle '|' '&' '(' ')' in scan sets + # at all, so we specify them separately. + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + lastarg="\"$lastarg\"" + ;; + esac + + base_compile="$base_compile $lastarg" + done # for arg + + case $arg_mode in + arg) + $echo "$modename: you must specify an argument for -Xcompile" + exit $EXIT_FAILURE + ;; + target) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit $EXIT_FAILURE + ;; + *) + # Get the name of the library object. + [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSifmso]' + case $libobj in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.ii) xform=ii ;; + *.class) xform=class ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + *.java) xform=java ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case $libobj in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -static) + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir= + else + xdir=$xdir/ + fi + lobj=${xdir}$objdir/$objname + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $run ln "$progpath" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + $echo $srcfile > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + + $run $rm "$libobj" "${libobj}T" + + # Create a libtool object file (analogous to a ".la" file), + # but don't create it if we're doing a dry run. + test -z "$run" && cat > ${libobj}T </dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + $show "$mv $output_obj $lobj" + if $run $mv $output_obj $lobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the PIC object to the libtool object file. + test -z "$run" && cat >> ${libobj}T <> ${libobj}T </dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the non-PIC object the libtool object file. + # Only append if the libtool object file exists. + test -z "$run" && cat >> ${libobj}T <> ${libobj}T <&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + else + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + fi + build_libtool_libs=no + build_old_libs=yes + prefer_static_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + case $arg in + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test + ;; + *) qarg=$arg ;; + esac + libtool_args="$libtool_args $qarg" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit $EXIT_FAILURE + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat $save_arg` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + done + else + $echo "$modename: link input file \`$save_arg' does not exist" + exit $EXIT_FAILURE + fi + arg=$save_arg + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + compile_command="$compile_command $wl$qarg" + finalize_command="$finalize_command $wl$qarg" + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + darwin_framework) + compiler_flags="$compiler_flags $arg" + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: more than one -exported-symbols argument is not allowed" + exit $EXIT_FAILURE + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=darwin_framework + compiler_flags="$compiler_flags $arg" + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + ;; + esac + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 + exit $EXIT_FAILURE + fi + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + case :$dllsearchpath: in + *":$dir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-pw32* | *-*-beos*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-mingw* | *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs -framework System" + continue + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + -model) + compile_command="$compile_command $arg" + compiler_flags="$compiler_flags $arg" + finalize_command="$finalize_command $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) + compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m* pass through architecture-specific compiler args for GCC + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*) + + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + arg="\"$arg\"" + ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + if test "$with_gcc" = "yes" ; then + compiler_flags="$compiler_flags $arg" + fi + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # The PATH hackery in wrapper scripts is required on Windows + # in order for the loader to find any dlls it needs. + $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 + $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Wl,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $wl$flag" + linker_flags="$linker_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + arg="\"$arg\"" + ;; + esac + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + arg="\"$arg\"" + ;; + esac + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done # argument parsing loop + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + # Create the object directory. + if test ! -d "$output_objdir"; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + status=$? + if test "$status" -ne 0 && test ! -d "$output_objdir"; then + exit $status + fi + fi + + # Determine the type of output + case $output in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + case $host in + *cygwin* | *mingw* | *pw32*) + # don't eliminate duplications in $postdeps and $predeps + duplicate_compiler_generated_deps=yes + ;; + *) + duplicate_compiler_generated_deps=$duplicate_deps + ;; + esac + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if test "X$duplicate_deps" = "Xyes" ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + case $linkmode in + lib) + passes="conv link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + for pass in $passes; do + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 + continue + fi + name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` + for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if (${SED} -e '2q' $lib | + grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + library_names= + old_library= + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + *) + $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + if eval $echo \"$deplib\" 2>/dev/null \ + | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $echo + $echo "*** Warning: Trying to link with static lib archive $deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because the file extensions .$libext of this argument makes me believe" + $echo "*** that it is just a static archive that I should not used here." + else + $echo + $echo "*** Warning: Linking the shared library $output against the" + $echo "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + if test "$found" = yes || test -f "$lib"; then : + else + $echo "$modename: cannot find the library \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + $echo "$modename: \`$lib' is not a convenience library" 1>&2 + exit $EXIT_FAILURE + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + abs_ladir="$ladir" + fi + ;; + esac + laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + $echo "$modename: warning: library \`$lib' was moved." 1>&2 + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *" $absdir "*) ;; + *) temp_rpath="$temp_rpath $dir" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + # This is a shared library + + # Warn about portability, can't link against -module's on + # some systems (darwin) + if test "$shouldnotlink" = yes && test "$pass" = link ; then + $echo + if test "$linkmode" = prog; then + $echo "*** Warning: Linking the executable $output against the loadable module" + else + $echo "*** Warning: Linking the shared library $output against the loadable module" + fi + $echo "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + realname="$2" + shift; shift + libname=`eval \\$echo \"$libname_spec\"` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw*) + major=`expr $current - $age` + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + soname=`$echo $soroot | ${SED} -e 's/^.*\///'` + newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + $show "extracting exported symbol list from \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$extract_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + $show "generating import library for \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$old_archive_from_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5* ) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a module then we can not link against + # it, someone is ignoring the new warnings I added + if /usr/bin/file -L $add 2> /dev/null | $EGREP "bundle" >/dev/null ; then + $echo "** Warning, lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $echo + $echo "** And there doesn't seem to be a static archive available" + $echo "** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case "$libdir" in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit $EXIT_FAILURE + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case "$libdir" in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $echo + $echo "*** Warning: This system can not link to static lib archive $lib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $echo "*** But as you try to build a module library, libtool will still create " + $echo "*** a static module, that should work as long as the dlopening application" + $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + convenience="$convenience $dir/$old_library" + old_convenience="$old_convenience $dir/$old_library" + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$deplib" && dir="." + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + fi + ;; + esac + if grep "^installed=no" $deplib > /dev/null; then + path="$absdir/$objdir" + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + if test "$absdir" != "$libdir"; then + $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 + fi + path="$absdir" + fi + depdepl= + case $host in + *-*-darwin*) + # we do not want to link against static libs, + # but need to link against shared + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$path/$depdepl" ; then + depdepl="$path/$depdepl" + fi + # do not add paths which are already there + case " $newlib_search_path " in + *" $path "*) ;; + *) newlib_search_path="$newlib_search_path $path";; + esac + fi + path="" + ;; + *) + path="-L$path" + ;; + esac + ;; + -l*) + case $host in + *-*-darwin*) + # Again, we only want to link against shared libraries + eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` + for tmp in $newlib_search_path ; do + if test -f "$tmp/lib$tmp_libs.dylib" ; then + eval depdepl="$tmp/lib$tmp_libs.dylib" + break + fi + done + path="" + ;; + *) continue ;; + esac + ;; + *) continue ;; + esac + case " $deplibs " in + *" $depdepl "*) ;; + *) deplibs="$depdepl $deplibs" ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$deplibs $path" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 + exit $EXIT_FAILURE + else + $echo + $echo "*** Warning: Linking the shared library $output against the non-libtool" + $echo "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + if test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test "$#" -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$2" + number_minor="$3" + number_revision="$4" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows) + current=`expr $number_major + $number_minor` + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + current=`expr $number_major + $number_minor - 1` + age="$number_minor" + revision="$number_minor" + ;; + esac + ;; + no) + current="$2" + revision="$3" + age="$4" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test "$age" -gt "$current"; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + minor_current=`expr $current + 1` + verstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + irix | nonstopux) + major=`expr $current - $age + 1` + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=.`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + major=`expr $current - $age` + versuffix="-$major" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + fi + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$echo "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + if test -n "$removelist"; then + $show "${rm}r $removelist" + $run ${rm}r $removelist + fi + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + for path in $notinst_path; do + lib_search_path=`$echo "$lib_search_path " | ${SED} -e 's% $path % %g'` + deplibs=`$echo "$deplibs " | ${SED} -e 's% -L$path % %g'` + dependency_libs=`$echo "$dependency_libs " | ${SED} -e 's% -L$path % %g'` + done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs -framework System" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for file magic test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a file magic. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name="`expr $a_deplib : '-l\(.*\)'`" + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval $echo \"$potent_lib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a regex pattern. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` + done + fi + if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ + | grep . >/dev/null; then + $echo + if test "X$deplibs_check_method" = "Xnone"; then + $echo "*** Warning: inter-library dependencies are not supported in this platform." + else + $echo "*** Warning: inter-library dependencies are not known to be supported." + fi + $echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $echo + $echo "*** Warning: libtool could not satisfy all declared inter-library" + $echo "*** dependencies of module $libname. Therefore, libtool will create" + $echo "*** a static module, that should work as long as the dlopening" + $echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $echo "*** The inter-library dependencies that have been dropped here will be" + $echo "*** automatically added whenever a program is linked with this library" + $echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $echo + $echo "*** Since this library must not contain undefined symbols," + $echo "*** because either the platform does not support them or" + $echo "*** it was explicitly requested with -no-undefined," + $echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + if len=`expr "X$cmd" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + $show "$cmd" + $run eval "$cmd" || exit $? + skipped_export=false + else + # The command line is too long to execute in one step. + $show "using reloadable object file for export list..." + skipped_export=: + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && len=`expr "X$test_cmds" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise. + $echo "creating reloadable object files..." + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$echo "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + delfiles= + last_robj= + k=1 + output=$output_objdir/$output_la-${k}.$objext + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + eval test_cmds=\"$reload_cmds $objlist $last_robj\" + if test "X$objlist" = X || + { len=`expr "X$test_cmds" : ".*"` && + test "$len" -le "$max_cmd_len"; }; then + objlist="$objlist $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + k=`expr $k + 1` + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + len=1 + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + + if ${skipped_export-false}; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + libobjs=$output + # Append the command to create the export file. + eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" + fi + + # Set up a command to remove the reloadable object files + # after they are used. + i=0 + while test "$i" -lt "$k" + do + i=`expr $i + 1` + delfiles="$delfiles $output_objdir/$output_la-${i}.$objext" + done + + $echo "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + + # Append the command to remove the reloadable object files + # to the just-reset $cmds. + eval cmds=\"\$cmds~\$rm $delfiles\" + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case $output in + *.lo) + if test -n "$objs$old_deplibs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit $EXIT_FAILURE + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $run eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; + esac + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + case $host in + *darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + if test "$tagname" = CXX ; then + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + fi + ;; + esac + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + case :$dllsearchpath: in + *":$libdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case $dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $run $rm $export_symbols + $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + else + $run eval "${SED} -e 's/\([ ][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` + $run eval '$echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + $echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +" + + case $host in + *cygwin* | *mingw* ) + $echo >> "$output_objdir/$dlsyms" "\ +/* DATA imports from DLLs on WIN32 can't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs */ +struct { +" + ;; + * ) + $echo >> "$output_objdir/$dlsyms" "\ +const struct { +" + ;; + esac + + + $echo >> "$output_objdir/$dlsyms" "\ + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[] = +{\ +" + + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $run $rm $output + # Link the executable and exit + $show "$link_command" + $run eval "$link_command" || exit $? + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + cwrappersource=`$echo ${objdir}/lt-${outputname}.c` + cwrapper=`$echo ${output}.exe` + $rm $cwrappersource $cwrapper + trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + cat > $cwrappersource <> $cwrappersource<<"EOF" +#include +#include +#include +#include +#include +#include + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef DIR_SEPARATOR +#define DIR_SEPARATOR '/' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +#define HAVE_DOS_BASED_FILE_SYSTEM +#ifndef DIR_SEPARATOR_2 +#define DIR_SEPARATOR_2 '\\' +#endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +const char *program_name = NULL; + +void * xmalloc (size_t num); +char * xstrdup (const char *string); +char * basename (const char *name); +char * fnqualify(const char *path); +char * strendzap(char *str, const char *pat); +void lt_fatal (const char *message, ...); + +int +main (int argc, char *argv[]) +{ + char **newargz; + int i; + + program_name = (char *) xstrdup ((char *) basename (argv[0])); + newargz = XMALLOC(char *, argc+2); +EOF + + cat >> $cwrappersource <> $cwrappersource <<"EOF" + newargz[1] = fnqualify(argv[0]); + /* we know the script has the same name, without the .exe */ + /* so make sure newargz[1] doesn't end in .exe */ + strendzap(newargz[1],".exe"); + for (i = 1; i < argc; i++) + newargz[i+1] = xstrdup(argv[i]); + newargz[argc+1] = NULL; +EOF + + cat >> $cwrappersource <> $cwrappersource <<"EOF" +} + +void * +xmalloc (size_t num) +{ + void * p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL +; +} + +char * +basename (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha (name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return (char *) base; +} + +char * +fnqualify(const char *path) +{ + size_t size; + char *p; + char tmp[LT_PATHMAX + 1]; + + assert(path != NULL); + + /* Is it qualified already? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha (path[0]) && path[1] == ':') + return xstrdup (path); +#endif + if (IS_DIR_SEPARATOR (path[0])) + return xstrdup (path); + + /* prepend the current directory */ + /* doesn't handle '~' */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + size = strlen(tmp) + 1 + strlen(path) + 1; /* +2 for '/' and '\0' */ + p = XMALLOC(char, size); + sprintf(p, "%s%c%s", tmp, DIR_SEPARATOR, path); + return p; +} + +char * +strendzap(char *str, const char *pat) +{ + size_t len, patlen; + + assert(str != NULL); + assert(pat != NULL); + + len = strlen(str); + patlen = strlen(pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp(str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char * mode, + const char * message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} +EOF + # we should really use a build-platform specific compiler + # here, but OTOH, the wrappers (shell script and this C one) + # are only useful if you want to execute the "real" binary. + # Since the "real" binary is built for $host, then this + # wrapper might as well be built for $host, too. + $run $LTCC -s -o $cwrapper $cwrappersource + ;; + esac + $rm $output + trap "$rm $output; exit $EXIT_FAILURE" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $echo >> $output "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + $echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $echo \"\$relink_command_output\" >&2 + $rm \"\$progdir/\$file\" + exit $EXIT_FAILURE + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + $echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \$progdir\\\\\$program \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + exec \$progdir/\$program \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" + exit $EXIT_FAILURE + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + $echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit $EXIT_FAILURE + fi +fi\ +" + chmod +x $output + fi + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + eval cmds=\"$old_archive_cmds\" + + if len=`expr "X$cmds" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + $echo "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + # GNU ar 2.10+ was changed to match POSIX; thus no paths are + # encoded into archives. This makes 'ar r' malfunction in + # this piecewise linking case whenever conflicting object + # names appear in distinct ar calls; check, warn and compensate. + if (for obj in $save_oldobjs + do + $echo "X$obj" | $Xsed -e 's%^.*/%%' + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: warning: object name conflicts; overriding AR_FLAGS to 'cq'" 1>&2 + $echo "$modename: warning: to ensure that POSIX-compatible ar will work" 1>&2 + AR_FLAGS=cq + fi + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + for obj in $save_oldobjs + do + oldobjs="$objlist $obj" + objlist="$objlist $obj" + eval test_cmds=\"$old_archive_cmds\" + if len=`expr "X$test_cmds" : ".*"` && + test "$len" -le "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + eval cmd=\"$cmd\" + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + for lib in $dlfiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlfiles="$newdlfiles $libdir/$name" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlprefiles="$newdlprefiles $libdir/$name" + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $rm $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $echo >> $output "\ +relink_command=\"$relink_command\"" + fi + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? + ;; + esac + exit $EXIT_SUCCESS + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case $arg in + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg="$nonopt" + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest="$arg" + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) prev="-f" ;; + -g) prev="-g" ;; + -m) prev="-m" ;; + -o) prev="-o" ;; + -s) + stripme=" -s" + continue + ;; + -*) ;; + + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest="$arg" + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test "$#" -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + library_names= + old_library= + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + if test "$inst_prefix_dir" = "$destdir"; then + $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + $echo "$modename: warning: relinking \`$file'" 1>&2 + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + exit $EXIT_FAILURE + fi + fi + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$srcname $destdir/$realname" + $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? + if test -n "$stripme" && test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run eval "$striplib $destdir/$realname" || exit $? + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + cmds=$postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + file=`$echo $file|${SED} 's,.exe$,,'` + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin*|*mingw*) + wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` + ;; + *) + wrapper=$file + ;; + esac + if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then + notinst_deplibs= + relink_command= + + # To insure that "foo" is sourced, and not "foo.exe", + # finese the cygwin/MSYS system by explicitly sourcing "foo." + # which disallows the automatic-append-.exe behavior. + case $build in + *cygwin* | *mingw*) wrapperdot=${wrapper}. ;; + *) wrapperdot=${wrapper} ;; + esac + # If there is no directory component, then add one. + case $file in + */* | *\\*) . ${wrapperdot} ;; + *) . ./${wrapperdot} ;; + esac + + # Check the variables that should have been set. + if test -z "$notinst_deplibs"; then + $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 + exit $EXIT_FAILURE + fi + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + relink_command= + # To insure that "foo" is sourced, and not "foo.exe", + # finese the cygwin/MSYS system by explicitly sourcing "foo." + # which disallows the automatic-append-.exe behavior. + case $build in + *cygwin* | *mingw*) wrapperdot=${wrapper}. ;; + *) wrapperdot=${wrapper} ;; + esac + # If there is no directory component, then add one. + case $file in + */* | *\\*) . ${wrapperdot} ;; + *) . ./${wrapperdot} ;; + esac + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir="/tmp" + test -n "$TMPDIR" && tmpdir="$TMPDIR" + tmpdir="$tmpdir/libtool-$$" + save_umask=`umask` + umask 0077 + if $mkdir "$tmpdir"; then + umask $save_umask + else + umask $save_umask + $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 + continue + fi + file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyways + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` + ;; + esac + ;; + esac + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + if test -n "$stripme" && test -n "$old_striplib"; then + $show "$old_striplib $oldlib" + $run eval "$old_striplib $oldlib" || exit $? + fi + + # Do each command in the postinstall commands. + cmds=$old_postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + cmds=$finish_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = : && exit $EXIT_SUCCESS + + $echo "----------------------------------------------------------------------" + $echo "Libraries have been installed in:" + for libdir in $libdirs; do + $echo " $libdir" + done + $echo + $echo "If you ever happen to want to link against installed libraries" + $echo "in a given directory, LIBDIR, you must either use libtool, and" + $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + $echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + $echo " during execution" + fi + if test -n "$runpath_var"; then + $echo " - add LIBDIR to the \`$runpath_var' environment variable" + $echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $echo + $echo "See any operating system documentation about shared libraries for" + $echo "more information, such as the ld(1) and ld.so(8) manual pages." + $echo "----------------------------------------------------------------------" + exit $EXIT_SUCCESS + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit $EXIT_FAILURE + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit $EXIT_FAILURE + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + if test "${save_LC_ALL+set}" = set; then + LC_ALL="$save_LC_ALL"; export LC_ALL + fi + if test "${save_LANG+set}" = set; then + LANG="$save_LANG"; export LANG + fi + + # Now prepare to actually exec the command. + exec_cmd="\"\$cmd\"$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + eval \$echo \"\$cmd\"$args + exit $EXIT_SUCCESS + fi + ;; + + # libtool clean and uninstall mode + clean | uninstall) + modename="$modename: $mode" + rm="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) rm="$rm $arg"; rmforce=yes ;; + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$file"; then + dir=. + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if (test -L "$file") >/dev/null 2>&1 \ + || (test -h "$file") >/dev/null 2>&1 \ + || test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + test "$mode" = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + + if test "$mode" = uninstall; then + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + cmds=$postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + cmds=$old_postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + # FIXME: should reinstall the best remaining shared library. + fi + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + + # Read the .lo file + . $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" \ + && test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" \ + && test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + file=`$echo $file|${SED} 's,.exe$,,'` + noexename=`$echo $name|${SED} 's,.exe$,,'` + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + relink_command= + . $dir/$noexename + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + $show "$rm $rmfiles" + $run $rm $rmfiles || exit_status=1 + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + $show "rmdir $dir" + $run rmdir $dir >/dev/null 2>&1 + fi + done + + exit $exit_status + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test -z "$exec_cmd"; then + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + fi +fi # test -z "$show_help" + +if test -n "$exec_cmd"; then + eval exec $exec_cmd + exit $EXIT_FAILURE +fi + +# We need to display help for each of the modes. +case $mode in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --tag=TAG use configuration variables from tag TAG + --version print version information + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE. + +Report bugs to ." + exit $EXIT_SUCCESS + ;; + +clean) + $echo \ +"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; +esac + +$echo +$echo "Try \`$modename --help' for more information about other modes." + +exit $? + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) $echo no;; *) $echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/tests/freealut/admin/autotools/m4/alut_c__attribute.m4 b/tests/freealut/admin/autotools/m4/alut_c__attribute.m4 new file mode 100644 index 0000000000000..ed5083f113492 --- /dev/null +++ b/tests/freealut/admin/autotools/m4/alut_c__attribute.m4 @@ -0,0 +1,16 @@ +# ALUT_C__ATTRIBUTE__ +# ------------------- +AC_DEFUN([ALUT_C__ATTRIBUTE__], +[AC_CACHE_CHECK([whether the C compiler supports __attribute__], + [alut_cv___attribute__], + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ + void foo (int bar __attribute__((unused)) ) { } + static void baz (void) __attribute__((unused)); + static void baz (void) { }]])], + [alut_cv___attribute__=yes], + [alut_cv___attribute__=no])]) +if test "$alut_cv___attribute__" = yes; then + AC_DEFINE([HAVE___ATTRIBUTE__], [1], + [Define to 1 if your C compiler supports __attribute__.]) +fi +])# ALUT_C__ATTRIBUTE__ diff --git a/tests/freealut/admin/autotools/m4/alut_check_cflags_wall.m4 b/tests/freealut/admin/autotools/m4/alut_check_cflags_wall.m4 new file mode 100644 index 0000000000000..adb2741a33c0a --- /dev/null +++ b/tests/freealut/admin/autotools/m4/alut_check_cflags_wall.m4 @@ -0,0 +1,120 @@ +dnl NOTE: This is a modified version of ax_cflags_warn_all_ansi.m4 +dnl from the autoconf archive, updated to conform to more recent +dnl autoconf standards. The original header follows... + +dnl @synopsis AX_CFLAGS_WARN_ALL_ANSI [(shellvar [,default, [A/NA]])] +dnl +dnl Try to find a compiler option that enables most reasonable +dnl warnings. This macro is directly derived from VL_PROG_CC_WARNINGS +dnl which is split up into two AX_CFLAGS_WARN_ALL and +dnl AX_CFLAGS_WARN_ALL_ANSI +dnl +dnl For the GNU CC compiler it will be -Wall (and -ansi -pedantic) The +dnl result is added to the shellvar being CFLAGS by default. +dnl +dnl Currently this macro knows about GCC, Solaris C compiler, Digital +dnl Unix C compiler, C for AIX Compiler, HP-UX C compiler, IRIX C +dnl compiler, NEC SX-5 (Super-UX 10) C compiler, and Cray J90 (Unicos +dnl 10.0.0.8) C compiler. +dnl +dnl - $1 shell-variable-to-add-to : CFLAGS +dnl - $2 add-value-if-not-found : nothing +dnl - $3 action-if-found : add value to shellvariable +dnl - $4 action-if-not-found : nothing +dnl +dnl @category C +dnl @author Guido Draheim +dnl @version 2003-01-06 +dnl @license GPLWithACException + +AC_DEFUN([AX_CFLAGS_WARN_ALL_ANSI],[dnl +AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl +AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_warn_all_ansi])dnl +AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum ANSI warnings], +VAR,[VAR="no, unknown" + AC_LANG_PUSH([C]) + ac_save_[]FLAGS="$[]FLAGS" +# IRIX C compiler: +# -use_readonly_const is the default for IRIX C, +# puts them into .rodata, but they are copied later. +# need to be "-G0 -rdatashared" for strictmode but +# I am not sure what effect that has really. - guidod +for ac_arg dnl +in "-pedantic % -Wall -ansi -pedantic" dnl GCC + "-xstrconst % -v -Xc" dnl Solaris C + "-std1 % -verbose -w0 -warnprotos -std1" dnl Digital Unix + " % -qlanglvl=ansi -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX + " % -ansi -ansiE -fullwarn" dnl IRIX + "+ESlit % +w1 -Aa" dnl HP-UX C + "-Xc % -pvctl[,]fullmsg -Xc" dnl NEC SX-5 (Super-UX 10) + "-h conform % -h msglevel 2 -h conform" dnl Cray C (Unicos) + # +do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])], + [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) +done + FLAGS="$ac_save_[]FLAGS" + AC_LANG_POP([C]) +]) +case ".$VAR" in + .ok|.ok,*) m4_ifvaln($3,$3) ;; + .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[ + AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"]) + m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;; + *) m4_ifvaln($3,$3,[ + if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null + then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) + else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) + m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" + fi ]) ;; +esac +AS_VAR_POPDEF([VAR])dnl +AS_VAR_POPDEF([FLAGS])dnl +]) + +dnl the only difference - the LANG selection... and the default FLAGS + +AC_DEFUN([AX_CXXFLAGS_WARN_ALL_ANSI],[dnl +AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl +AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_warn_all_ansi])dnl +AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum ANSI warnings], +VAR,[VAR="no, unknown" + AC_LANG_PUSH([C++]) + ac_save_[]FLAGS="$[]FLAGS" +# IRIX C compiler: +# -use_readonly_const is the default for IRIX C, +# puts them into .rodata, but they are copied later. +# need to be "-G0 -rdatashared" for strictmode but +# I am not sure what effect that has really. - guidod +for ac_arg dnl +in "-pedantic % -Wall -ansi -pedantic" dnl GCC + "-xstrconst % -v -Xc" dnl Solaris C + "-std1 % -verbose -w0 -warnprotos -std1" dnl Digital Unix + " % -qlanglvl=ansi -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX + " % -ansi -ansiE -fullwarn" dnl IRIX + "+ESlit % +w1 -Aa" dnl HP-UX C + "-Xc % -pvctl[,]fullmsg -Xc" dnl NEC SX-5 (Super-UX 10) + "-h conform % -h msglevel 2 -h conform" dnl Cray C (Unicos) + # +do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])], + [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) +done + FLAGS="$ac_save_[]FLAGS" + AC_LANG_POP([C++]) +]) +case ".$VAR" in + .ok|.ok,*) m4_ifvaln($3,$3) ;; + .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[ + AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"]) + m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;; + *) m4_ifvaln($3,$3,[ + if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null + then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) + else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) + m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" + fi ]) ;; +esac +AS_VAR_POPDEF([VAR])dnl +AS_VAR_POPDEF([FLAGS])dnl +]) diff --git a/tests/freealut/admin/autotools/m4/alut_check_flag.m4 b/tests/freealut/admin/autotools/m4/alut_check_flag.m4 new file mode 100644 index 0000000000000..1f4161c4cf141 --- /dev/null +++ b/tests/freealut/admin/autotools/m4/alut_check_flag.m4 @@ -0,0 +1,28 @@ +# ALUT_CHECK_FLAG(FLAG, [ACTION-IF-SUPPORTED], [ACTION-IF-NOT-SUPPORTED]) +# ----------------------------------------------------------------------- +# Check to see whether the compiler for the current language supports a +# particular option. +# +# Implementation note: When given an unkown option, some GCC versions issue an +# warning on stderr only, but return an exit value of 0 nevertheless. +# Consequently we have to check stderr *and* the exit value. +AC_DEFUN([ALUT_CHECK_FLAG], +[AC_LANG_COMPILER_REQUIRE()dnl +AC_LANG_CASE([C], [alut_compiler="$CC" m4_pushdef([alut_Flags], [CFLAGS])], + [C++], [alut_compiler="$CXX" m4_pushdef([alut_Flags], [CXXFLAGS])], + [Fortran 77], [alut_compiler="$F77" m4_pushdef([alut_Flags], [FFLAGS])]) +m4_pushdef([alut_Cache], [alut_cv_[]alut_Flags[]AS_TR_SH([$1])])[]dnl +AC_CACHE_CHECK([whether $alut_compiler accepts $1], [alut_Cache], +[AC_LANG_CONFTEST([AC_LANG_PROGRAM()]) +alut_save_flags="$alut_Flags" +alut_Flags="$alut_Flags $1" +alut_Cache=no +if ALUT_EVAL_STDERR([$ac_compile conftest.$ac_ext]) >/dev/null; then + test -s conftest.err || alut_Cache=yes +fi +alut_Flags="$alut_save_flags" +rm -f conftest.err conftest.$ac_ext]) +AS_IF([test $alut_Cache = yes], [$2], [$3])[]dnl +m4_popdef([alut_Cache])[]dnl +m4_popdef([alut_Flags])[]dnl +])# ALUT_CHECK_FLAG diff --git a/tests/freealut/admin/autotools/m4/alut_check_func.m4 b/tests/freealut/admin/autotools/m4/alut_check_func.m4 new file mode 100644 index 0000000000000..2b2db14e882f7 --- /dev/null +++ b/tests/freealut/admin/autotools/m4/alut_check_func.m4 @@ -0,0 +1,15 @@ +# ALUT_CHECK_FUNC(PROLOGUE, FUNCTION, ARGUMENTS) +# ----------------------------------------- +AC_DEFUN([ALUT_CHECK_FUNC], +[AS_VAR_PUSHDEF([alut_var], [alut_cv_func_$2])dnl +AC_CACHE_CHECK([for $2], + alut_var, + [AC_LINK_IFELSE([AC_LANG_PROGRAM([$1], [$2 $3;])], + [AS_VAR_SET(alut_var, yes)], + [AS_VAR_SET(alut_var, no)])]) +if test AS_VAR_GET(alut_var) = yes; then + AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$2]), [1], + [Define to 1 if you have the `$2' function.]) +fi +AS_VAR_POPDEF([alut_var])dnl +])# ALUT_CHECK_FUNC diff --git a/tests/freealut/admin/autotools/m4/alut_eval_stderr.m4 b/tests/freealut/admin/autotools/m4/alut_eval_stderr.m4 new file mode 100644 index 0000000000000..7391551fd126a --- /dev/null +++ b/tests/freealut/admin/autotools/m4/alut_eval_stderr.m4 @@ -0,0 +1,11 @@ +# ALUT_EVAL_STDERR(COMMAND) +# ------------------------- +# Eval COMMAND, save its stderr (without lines resulting from shell tracing) +# into the file conftest.err and the exit status in the variable alut_status. +AC_DEFUN([ALUT_EVAL_STDERR], +[{ (eval $1) 2>conftest.er1 + alut_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + (exit $alut_status); }[]dnl +])# ALUT_EVAL_STDERR diff --git a/tests/freealut/admin/autotools/missing b/tests/freealut/admin/autotools/missing new file mode 100755 index 0000000000000..09edd8844dedc --- /dev/null +++ b/tests/freealut/admin/autotools/missing @@ -0,0 +1,357 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2005-02-08.22 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# 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, 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. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case "$1" in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/tests/freealut/admin/pkgconfig/Makefile.am b/tests/freealut/admin/pkgconfig/Makefile.am new file mode 100644 index 0000000000000..6b6cec2422c32 --- /dev/null +++ b/tests/freealut/admin/pkgconfig/Makefile.am @@ -0,0 +1,3 @@ +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = freealut.pc +bin_SCRIPTS = freealut-config diff --git a/tests/freealut/admin/pkgconfig/Makefile.in b/tests/freealut/admin/pkgconfig/Makefile.in new file mode 100644 index 0000000000000..787f712babd60 --- /dev/null +++ b/tests/freealut/admin/pkgconfig/Makefile.in @@ -0,0 +1,388 @@ +# Makefile.in generated by automake 1.9.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = admin/pkgconfig +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/freealut-config.in $(srcdir)/freealut.pc.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = \ + $(top_srcdir)/admin/autotools/m4/alut_c__attribute.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_cflags_wall.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_flag.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_func.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_eval_stderr.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = freealut-config freealut.pc +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgconfigdir)" +binSCRIPT_INSTALL = $(INSTALL_SCRIPT) +SCRIPTS = $(bin_SCRIPTS) +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +pkgconfigDATA_INSTALL = $(INSTALL_DATA) +DATA = $(pkgconfig_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBM = @LIBM@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VERSIONINFO = @VERSIONINFO@ +WNO_DEPRECATED_DECLARATIONS_FALSE = @WNO_DEPRECATED_DECLARATIONS_FALSE@ +WNO_DEPRECATED_DECLARATIONS_TRUE = @WNO_DEPRECATED_DECLARATIONS_TRUE@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_AS = @ac_ct_AS@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = freealut.pc +bin_SCRIPTS = freealut-config +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu admin/pkgconfig/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu admin/pkgconfig/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +freealut-config: $(top_builddir)/config.status $(srcdir)/freealut-config.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +freealut.pc: $(top_builddir)/config.status $(srcdir)/freealut.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-binSCRIPTS: $(bin_SCRIPTS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f $$d$$p; then \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " $(binSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(binSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(bindir)/$$f"; \ + else :; fi; \ + done + +uninstall-binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgconfigdir)" || $(mkdir_p) "$(DESTDIR)$(pkgconfigdir)" + @list='$(pkgconfig_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(pkgconfigDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgconfigdir)/$$f'"; \ + $(pkgconfigDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgconfigdir)/$$f"; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(pkgconfigdir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgconfigdir)/$$f"; \ + done +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(SCRIPTS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgconfigdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pkgconfigDATA + +install-exec-am: install-binSCRIPTS + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binSCRIPTS uninstall-info-am \ + uninstall-pkgconfigDATA + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binSCRIPTS install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgconfigDATA install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am \ + uninstall-binSCRIPTS uninstall-info-am uninstall-pkgconfigDATA + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tests/freealut/admin/pkgconfig/freealut-config.in b/tests/freealut/admin/pkgconfig/freealut-config.in new file mode 100644 index 0000000000000..74e287a7886bc --- /dev/null +++ b/tests/freealut/admin/pkgconfig/freealut-config.in @@ -0,0 +1,174 @@ +#!/bin/sh + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +bindir="@bindir@" +includedir="@includedir@" +libdir="@libdir@" +PACKAGE_VERSION="@PACKAGE_VERSION@" + +freealut_dynamic_ldflags="-lalut" +# TODO: configure should provide the following... +freealut_static_ldflags="-lalut" + +prefix_set=no +echo_prefix=no +exec_prefix_set=no +echo_exec_prefix=no +bindir_set=no +echo_bindir=no +includedir_set=no +echo_includedir=no +libdir_set=no +echo_libdir=no +echo_version=no +echo_cflags=no +static_libs=no +echo_libs=no + +usage() +{ + cat <&2 +Usage: freealut-config [OPTIONS] +Options: + --prefix[=DIR] print/set default prefix + --exec-prefix[=DIR] print/set prefix for machine-specific files + --bindir[=DIR] print/set prefix for executable programs + --includedir[=DIR] print/set prefix for include files + --libdir[=DIR] print/set prefix for libraries + --version print freealut package version + --cflags print flags for C compiler + --static specify that static linker flags are wanted + --libs print flags for linker +EOF + exit 1 +} + +if test $# -eq 0; then + usage +fi + +while test $# -gt 0; do + case "$1" in + -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg="" ;; + esac + + case $1 in + --prefix=*) + prefix="${optarg}" + prefix_set="yes" + ;; + --prefix) + echo_prefix="yes" + ;; + --exec-prefix=*) + exec_prefix="${optarg}" + exec_prefix_set="yes" + ;; + --exec-prefix) + echo_exec_prefix="yes" + ;; + --bindir=*) + bindir="${optarg}" + bindir_set="yes" + ;; + --bindir) + echo_bindir="yes" + ;; + --includedir=*) + includedir="${optarg}" + includedir_set="yes" + ;; + --includedir) + echo_includedir="yes" + ;; + --libdir=*) + libdir="${optarg}" + libdir_set="yes" + ;; + --libdir) + echo_libdir="yes" + ;; + --version) + echo_version="yes" + ;; + --cflags) + echo_cflags="yes" + ;; + --static) + static_libs="yes" + ;; + --libs) + echo_libs="yes" + ;; + *) + usage + ;; + esac + shift +done + +if test "${echo_prefix}" = "yes"; then + echo "${prefix}" +fi + +if test "${exec_prefix_set}" = "no" && test "${prefix_set}" = "yes"; then + exec_prefix="$prefix" + exec_prefix_set="yes" +fi + +if test "$echo_exec_prefix" = "yes"; then + echo "${exec_prefix}" +fi + +if test "${bindir_set}" = "no" && test "${exec_prefix_set}" = "yes"; then + bindir="${exec_prefix}/bin" +fi + +if test "$echo_bindir" = "yes"; then + echo "${bindir}" +fi + +if test "${includedir_set}" = "no" && test "${prefix_set}" = "yes"; then + includedir="${prefix}/include" +fi + +if test "$echo_includedir" = "yes"; then + echo "${includedir}" +fi + +if test "${libdir_set}" = "no" && test "${exec_prefix_set}" = "yes"; then + libdir="${exec_prefix}/lib" +fi + +if test "$echo_libdir" = "yes"; then + echo "${libdir}" +fi + +if test "$echo_version" = "yes"; then + echo "${PACKAGE_VERSION}" +fi + +if test "$echo_cflags" = "yes"; then + if test "${includedir}" = "/usr/include" ; then + incpath="" + else + incpath="-I${includedir}" + fi + echo "${incpath}" +fi + +if test "$echo_libs" = "yes"; then + if test "${libdir}" = "/usr/lib" ; then + libpathflag="" + else + libpathflag="-L${libdir}" + fi + if test "${static_libs}" = "yes"; then + ldflags="${freealut_static_ldflags}" + else + ldflags="${freealut_dynamic_ldflags}" + fi + echo "${libpathflag} ${ldflags}" +fi diff --git a/tests/freealut/admin/pkgconfig/freealut.pc.in b/tests/freealut/admin/pkgconfig/freealut.pc.in new file mode 100644 index 0000000000000..d40877f187685 --- /dev/null +++ b/tests/freealut/admin/pkgconfig/freealut.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: freealut +Description: freealut is a free implementation of the OpenAL utility toolkit. +Requires: openal +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lalut +Cflags: -I${includedir} diff --git a/tests/freealut/autogen.sh b/tests/freealut/autogen.sh new file mode 100755 index 0000000000000..e9ea9942dcbc0 --- /dev/null +++ b/tests/freealut/autogen.sh @@ -0,0 +1,2 @@ +#! /bin/sh +autoreconf --install --force --warnings=all diff --git a/tests/freealut/config.h.in b/tests/freealut/config.h.in new file mode 100644 index 0000000000000..6bb73f914f17f --- /dev/null +++ b/tests/freealut/config.h.in @@ -0,0 +1,116 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you want to build the ALUT DLL. */ +#undef ALUT_BUILD_LIBRARY + +/* Define to 1 if you have the header file. */ +#undef HAVE_AL_ALC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_AL_AL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_BASETSD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_CTYPE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if we are using a GCC with symbol visibility support. */ +#undef HAVE_GCC_VISIBILITY + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MATH_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `nanosleep' function. */ +#undef HAVE_NANOSLEEP + +/* Define to 1 if you have the `Sleep' function. */ +#undef HAVE_SLEEP + +/* Define to 1 if you have the `stat' function. */ +#undef HAVE_STAT + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `usleep' function. */ +#undef HAVE_USLEEP + +/* Define to 1 if you have the header file. */ +#undef HAVE_WINDOWS_H + +/* Define to 1 if you have the `_stat' function. */ +#undef HAVE__STAT + +/* Define to 1 if your C compiler supports __attribute__. */ +#undef HAVE___ATTRIBUTE__ + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to the POSIX version that should be used. */ +#undef _POSIX_C_SOURCE + +/* Define to 500 if Single Unix conformance is wanted, 600 for sixth revision. + */ +#undef _XOPEN_SOURCE + +/* Define to 1 if tolower and friends should not be macros. */ +#undef __NO_CTYPE + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const diff --git a/tests/freealut/configure b/tests/freealut/configure new file mode 100755 index 0000000000000..881340499f1c0 --- /dev/null +++ b/tests/freealut/configure @@ -0,0 +1,22839 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59 for freealut library 1.1.0. +# +# Report bugs to . +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +echo=${ECHO-echo} +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1 && unset CDPATH + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string="`eval $cmd`") 2>/dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL $0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + + + + +tagnames=${tagnames+${tagnames},}CXX + +tagnames=${tagnames+${tagnames},}F77 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME='freealut library' +PACKAGE_TARNAME='freealut' +PACKAGE_VERSION='1.1.0' +PACKAGE_STRING='freealut library 1.1.0' +PACKAGE_BUGREPORT='openal-devel@opensource.creative.com' + +ac_unique_file="AUTHORS" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar VERSIONINFO CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE WNO_DEPRECATED_DECLARATIONS_TRUE WNO_DEPRECATED_DECLARATIONS_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB DLLTOOL ac_ct_DLLTOOL AS ac_ct_AS OBJDUMP ac_ct_OBJDUMP CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL LIBTOOL_DEPS LIBM AM_CFLAGS LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP +ac_env_CXX_set=${CXX+set} +ac_env_CXX_value=$CXX +ac_cv_env_CXX_set=${CXX+set} +ac_cv_env_CXX_value=$CXX +ac_env_CXXFLAGS_set=${CXXFLAGS+set} +ac_env_CXXFLAGS_value=$CXXFLAGS +ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set} +ac_cv_env_CXXFLAGS_value=$CXXFLAGS +ac_env_CXXCPP_set=${CXXCPP+set} +ac_env_CXXCPP_value=$CXXCPP +ac_cv_env_CXXCPP_set=${CXXCPP+set} +ac_cv_env_CXXCPP_value=$CXXCPP +ac_env_F77_set=${F77+set} +ac_env_F77_value=$F77 +ac_cv_env_F77_set=${F77+set} +ac_cv_env_F77_value=$F77 +ac_env_FFLAGS_set=${FFLAGS+set} +ac_env_FFLAGS_value=$FFLAGS +ac_cv_env_FFLAGS_set=${FFLAGS+set} +ac_cv_env_FFLAGS_value=$FFLAGS + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures freealut library 1.1.0 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of freealut library 1.1.0:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-shared[=PKGS] + build shared libraries [default=yes] + --enable-static[=PKGS] + build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --enable-warnings enable pedantic compiler warnings + [default=yes] + --enable-more-warnings enable even more compiler warnings + [default=no] + --enable-werror enable failure on all warnings [default=no] + --enable-efence enable Electric Fence support [default=no] + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-tags[=TAGS] + include additional configurations [automatic] + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CXXCPP C++ preprocessor + F77 Fortran 77 compiler command + FFLAGS Fortran 77 compiler flags + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF +freealut library configure 1.1.0 +generated by GNU Autoconf 2.59 + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by freealut library $as_me 1.1.0, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + + + + + + + +ac_aux_dir= +for ac_dir in admin/autotools $srcdir/admin/autotools; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in admin/autotools $srcdir/admin/autotools" >&5 +echo "$as_me: error: cannot find install-sh or install.sh in admin/autotools $srcdir/admin/autotools" >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +am__api_version="1.9" +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +test "$program_prefix" != NONE && + program_transform_name="s,^,$program_prefix,;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$,$program_suffix,;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm conftest.sed + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$AWK" && break +done + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='freealut' + VERSION='1.1.0' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +install_sh=${install_sh-"$am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + + + + ac_config_headers="$ac_config_headers config.h" + + +# Compatibility hack for older autoconf versions + + +################################################################################ +## libtool shared library version. +################################################################################ + +# Some information from the libtool info pages and the autobook regarding how to +# handle the library version info: +# +# 1. Start with version information of `0:0:0' for each libtool library. +# +# 2. Update the version information only immediately before a public release of +# your software. More frequent updates are unnecessary, and only guarantee +# that the current interface number gets larger faster. +# +# 3. If the library source code has changed at all since the last update, then +# increment REVISION (`C:R:A' becomes `C:r+1:A'). This is a new revision of +# the current interface. +# +# 4. If any interfaces have been added, removed, or changed since the last +# update, increment CURRENT, and set REVISION to 0. This is the first +# revision of a new interface. +# +# 5. If any interfaces have been added since the last public release, then +# increment AGE. This release is backwards compatible with the previous +# release. +# +# 6. If any interfaces have been removed since the last public release, then set +# AGE to 0. This release has a new, but backwards incompatible interface. +# +# NEVER try to set the interface numbers so that they correspond to the release +# number of your package. This is an abuse that only fosters misunderstanding of +# the purpose of library versions. Furthermore, do not confuse those versions +# with the version of the specification which is implemented. + +CURRENT=1 +REVISION=0 +AGE=1 + +VERSIONINFO="$CURRENT:$REVISION:$AGE" + + +################################################################################ +# Checks for programs. +################################################################################ + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + + ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6 +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6 +rm -f confinc confmf + +# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval="$enable_dependency_tracking" + +fi; +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + + +if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + + +depcc="$CC" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +echo "$as_me:$LINENO: checking whether the C compiler supports __attribute__" >&5 +echo $ECHO_N "checking whether the C compiler supports __attribute__... $ECHO_C" >&6 +if test "${alut_cv___attribute__+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + void foo (int bar __attribute__((unused)) ) { } + static void baz (void) __attribute__((unused)); + static void baz (void) { } +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + alut_cv___attribute__=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +alut_cv___attribute__=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $alut_cv___attribute__" >&5 +echo "${ECHO_T}$alut_cv___attribute__" >&6 +if test "$alut_cv___attribute__" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE___ATTRIBUTE__ 1 +_ACEOF + +fi + + +# Note that -fvisibility=... support implies __attribute__((visibility(...))) +# support. +alut_compiler="$CC" +echo "$as_me:$LINENO: checking whether $alut_compiler accepts -fvisibility=hidden" >&5 +echo $ECHO_N "checking whether $alut_compiler accepts -fvisibility=hidden... $ECHO_C" >&6 +if test "${alut_cv_CFLAGS_fvisibility_hidden+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +alut_save_flags="$CFLAGS" +CFLAGS="$CFLAGS -fvisibility=hidden" +alut_cv_CFLAGS_fvisibility_hidden=no +if { (eval $ac_compile conftest.$ac_ext) 2>conftest.er1 + alut_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + (exit $alut_status); } >/dev/null; then + test -s conftest.err || alut_cv_CFLAGS_fvisibility_hidden=yes +fi +CFLAGS="$alut_save_flags" +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $alut_cv_CFLAGS_fvisibility_hidden" >&5 +echo "${ECHO_T}$alut_cv_CFLAGS_fvisibility_hidden" >&6 +if test $alut_cv_CFLAGS_fvisibility_hidden = yes; then + AM_CFLAGS="$AM_CFLAGS -fvisibility=hidden" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_GCC_VISIBILITY 1 +_ACEOF + +fi + + +# test_suite/test_retrostuff tests deprecated functions, but we don't want to +# get compiler warnings because of that. +alut_compiler="$CC" +echo "$as_me:$LINENO: checking whether $alut_compiler accepts -Wno-deprecated-declarations" >&5 +echo $ECHO_N "checking whether $alut_compiler accepts -Wno-deprecated-declarations... $ECHO_C" >&6 +if test "${alut_cv_CFLAGS_Wno_deprecated_declarations+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +alut_save_flags="$CFLAGS" +CFLAGS="$CFLAGS -Wno-deprecated-declarations" +alut_cv_CFLAGS_Wno_deprecated_declarations=no +if { (eval $ac_compile conftest.$ac_ext) 2>conftest.er1 + alut_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + (exit $alut_status); } >/dev/null; then + test -s conftest.err || alut_cv_CFLAGS_Wno_deprecated_declarations=yes +fi +CFLAGS="$alut_save_flags" +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $alut_cv_CFLAGS_Wno_deprecated_declarations" >&5 +echo "${ECHO_T}$alut_cv_CFLAGS_Wno_deprecated_declarations" >&6 +if test $alut_cv_CFLAGS_Wno_deprecated_declarations = yes; then + alut_wno_deprecated_declarations=yes +else + alut_wno_deprecated_declarations=no +fi + + + +if test x"$alut_wno_deprecated_declarations" = xyes; then + WNO_DEPRECATED_DECLARATIONS_TRUE= + WNO_DEPRECATED_DECLARATIONS_FALSE='#' +else + WNO_DEPRECATED_DECLARATIONS_TRUE='#' + WNO_DEPRECATED_DECLARATIONS_FALSE= +fi + + + + + +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi; + +# Check whether --enable-static or --disable-static was given. +if test "${enable_static+set}" = set; then + enableval="$enable_static" + p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi; + +# Check whether --enable-fast-install or --disable-fast-install was given. +if test "${enable_fast_install+set}" = set; then + enableval="$enable_fast_install" + p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi; + +# Make sure we can run config.sub. +$ac_config_sub sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 +echo "$as_me: error: cannot run $ac_config_sub" >&2;} + { (exit 1); exit 1; }; } + +echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6 +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_build_alias=$build_alias +test -z "$ac_cv_build_alias" && + ac_cv_build_alias=`$ac_config_guess` +test -z "$ac_cv_build_alias" && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6 +build=$ac_cv_build +build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6 +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_host_alias=$host_alias +test -z "$ac_cv_host_alias" && + ac_cv_host_alias=$ac_cv_build_alias +ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6 +host=$ac_cv_host +host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5 +echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6 +if test "${lt_cv_path_SED+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done + +fi + +SED=$lt_cv_path_SED +echo "$as_me:$LINENO: result: $SED" >&5 +echo "${ECHO_T}$SED" >&6 + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi; +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo "$as_me:$LINENO: checking for ld used by $CC" >&5 +echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6 + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6 +else + echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6 +fi +if test "${lt_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +echo "${ECHO_T}$LD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6 +if test "${lt_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +case `$LD -v 2>&1 &5 +echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6 +with_gnu_ld=$lt_cv_prog_gnu_ld + + +echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5 +echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6 +if test "${lt_cv_ld_reload_flag+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_ld_reload_flag='-r' +fi +echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5 +echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6 +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$CC -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + +echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5 +echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6 +if test "${lt_cv_path_NM+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/${ac_tool_prefix}nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + esac + fi + done + IFS="$lt_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi +fi +echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5 +echo "${ECHO_T}$lt_cv_path_NM" >&6 +NM="$lt_cv_path_NM" + +echo "$as_me:$LINENO: checking whether ln -s works" >&5 +echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:$LINENO: result: no, using $LN_S" >&5 +echo "${ECHO_T}no, using $LN_S" >&6 +fi + +echo "$as_me:$LINENO: checking how to recognise dependent libraries" >&5 +echo $ECHO_N "checking how to recognise dependent libraries... $ECHO_C" >&6 +if test "${lt_cv_deplibs_check_method+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix4* | aix5*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump'. + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | kfreebsd*-gnu | dragonfly*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case "$host_cpu" in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5 +echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6 +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Check whether --enable-libtool-lock or --disable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval="$enable_libtool_lock" + +fi; +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 3987 "configure"' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5 +echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6 +if test "${lt_cv_cc_needs_belf+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + lt_cv_cc_needs_belf=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +lt_cv_cc_needs_belf=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5 +echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6 + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +*-*-cygwin* | *-*-mingw* | *-*-pw32*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_DLLTOOL+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + echo "$as_me:$LINENO: result: $DLLTOOL" >&5 +echo "${ECHO_T}$DLLTOOL" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_DLLTOOL+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_DLLTOOL" && ac_cv_prog_ac_ct_DLLTOOL="false" +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + echo "$as_me:$LINENO: result: $ac_ct_DLLTOOL" >&5 +echo "${ECHO_T}$ac_ct_DLLTOOL" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + DLLTOOL=$ac_ct_DLLTOOL +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. +set dummy ${ac_tool_prefix}as; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AS+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AS"; then + ac_cv_prog_AS="$AS" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AS="${ac_tool_prefix}as" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AS=$ac_cv_prog_AS +if test -n "$AS"; then + echo "$as_me:$LINENO: result: $AS" >&5 +echo "${ECHO_T}$AS" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_AS"; then + ac_ct_AS=$AS + # Extract the first word of "as", so it can be a program name with args. +set dummy as; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_AS+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_AS"; then + ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AS="as" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_AS" && ac_cv_prog_ac_ct_AS="false" +fi +fi +ac_ct_AS=$ac_cv_prog_ac_ct_AS +if test -n "$ac_ct_AS"; then + echo "$as_me:$LINENO: result: $ac_ct_AS" >&5 +echo "${ECHO_T}$ac_ct_AS" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + AS=$ac_ct_AS +else + AS="$ac_cv_prog_AS" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_OBJDUMP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + echo "$as_me:$LINENO: result: $OBJDUMP" >&5 +echo "${ECHO_T}$OBJDUMP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_OBJDUMP" && ac_cv_prog_ac_ct_OBJDUMP="false" +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + echo "$as_me:$LINENO: result: $ac_ct_OBJDUMP" >&5 +echo "${ECHO_T}$ac_ct_OBJDUMP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + OBJDUMP=$ac_ct_OBJDUMP +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + + ;; + +esac + +need_locks="$enable_libtool_lock" + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in dlfcn.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## --------------------------------------------------- ## +## Report this to openal-devel@opensource.creative.com ## +## --------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CXX" && break +done +test -n "$ac_ct_CXX" || ac_ct_CXX="g++" + + CXX=$ac_ct_CXX +fi + + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6 +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6 +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +CXXFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cxx_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +depcc="$CXX" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6 +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + + +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 +echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6 +if test -z "$CXXCPP"; then + if test "${ac_cv_prog_CXXCPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_cxx_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_cxx_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +echo "$as_me:$LINENO: result: $CXXCPP" >&5 +echo "${ECHO_T}$CXXCPP" >&6 +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_cxx_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_cxx_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +fi + + +ac_ext=f +ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' +ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_f77_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$F77"; then + ac_cv_prog_F77="$F77" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_F77="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +F77=$ac_cv_prog_F77 +if test -n "$F77"; then + echo "$as_me:$LINENO: result: $F77" >&5 +echo "${ECHO_T}$F77" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$F77" && break + done +fi +if test -z "$F77"; then + ac_ct_F77=$F77 + for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_F77"; then + ac_cv_prog_ac_ct_F77="$ac_ct_F77" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_F77="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_F77=$ac_cv_prog_ac_ct_F77 +if test -n "$ac_ct_F77"; then + echo "$as_me:$LINENO: result: $ac_ct_F77" >&5 +echo "${ECHO_T}$ac_ct_F77" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_F77" && break +done + + F77=$ac_ct_F77 +fi + + +# Provide some information about the compiler. +echo "$as_me:5808:" \ + "checking for Fortran 77 compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +rm -f a.out + +# If we don't use `.F' as extension, the preprocessor is not run on the +# input file. (Note that this only needs to work for GNU compilers.) +ac_save_ext=$ac_ext +ac_ext=F +echo "$as_me:$LINENO: checking whether we are using the GNU Fortran 77 compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU Fortran 77 compiler... $ECHO_C" >&6 +if test "${ac_cv_f77_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF + program main +#ifndef __GNUC__ + choke me +#endif + + end +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_f77_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_f77_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_f77_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_f77_compiler_gnu" >&6 +ac_ext=$ac_save_ext +ac_test_FFLAGS=${FFLAGS+set} +ac_save_FFLAGS=$FFLAGS +FFLAGS= +echo "$as_me:$LINENO: checking whether $F77 accepts -g" >&5 +echo $ECHO_N "checking whether $F77 accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_f77_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + FFLAGS=-g +cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_f77_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_f77_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_f77_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_f77_g" >&5 +echo "${ECHO_T}$ac_cv_prog_f77_g" >&6 +if test "$ac_test_FFLAGS" = set; then + FFLAGS=$ac_save_FFLAGS +elif test $ac_cv_prog_f77_g = yes; then + if test "x$ac_cv_f77_compiler_gnu" = xyes; then + FFLAGS="-g -O2" + else + FFLAGS="-g" + fi +else + if test "x$ac_cv_f77_compiler_gnu" = xyes; then + FFLAGS="-O2" + else + FFLAGS= + fi +fi + +G77=`test $ac_compiler_gnu = yes && echo yes` +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! + +# find the maximum length of command line arguments +echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5 +echo $ECHO_N "checking the maximum length of command line arguments... $ECHO_C" >&6 +if test "${lt_cv_sys_max_cmd_len+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for *BSD + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + ;; + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + while (test "X"`$SHELL $0 --fallback-echo "X$teststring" 2>/dev/null` \ + = "XX$teststring") >/dev/null 2>&1 && + new_result=`expr "X$teststring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + teststring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5 +echo "${ECHO_T}$lt_cv_sys_max_cmd_len" >&6 +else + echo "$as_me:$LINENO: result: none" >&5 +echo "${ECHO_T}none" >&6 +fi + + + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5 +echo $ECHO_N "checking command to parse $NM output from $compiler object... $ECHO_C" >&6 +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32*) + symcode='[ABCDGISTW]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +linux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDGIRSTW]' + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris* | sysv5*) + symcode='[BDRT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + echo "$as_me:$LINENO: result: failed" >&5 +echo "${ECHO_T}failed" >&6 +else + echo "$as_me:$LINENO: result: ok" >&5 +echo "${ECHO_T}ok" >&6 +fi + +echo "$as_me:$LINENO: checking for objdir" >&5 +echo $ECHO_N "checking for objdir... $ECHO_C" >&6 +if test "${lt_cv_objdir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5 +echo "${ECHO_T}$lt_cv_objdir" >&6 +objdir=$lt_cv_objdir + + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + echo "$as_me:$LINENO: result: $AR" >&5 +echo "${ECHO_T}$AR" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_AR" && ac_cv_prog_ac_ct_AR="false" +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + echo "$as_me:$LINENO: result: $ac_ct_AR" >&5 +echo "${ECHO_T}$ac_ct_AR" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + AR=$ac_ct_AR +else + AR="$ac_cv_prog_AR" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" + ;; + *) + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5 +echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6 +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + echo "$as_me:$LINENO: checking for file" >&5 +echo $ECHO_N "checking for file... $ECHO_C" >&6 +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +enable_dlopen=no +enable_win32_dll=yes + +# Check whether --enable-libtool-lock or --disable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval="$enable_libtool_lock" + +fi; +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + + +# Check whether --with-pic or --without-pic was given. +if test "${with_pic+set}" = set; then + withval="$with_pic" + pic_mode="$withval" +else + pic_mode=default +fi; +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}\n' + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# +# Check for any special shared library compilation flags. +# +lt_prog_cc_shlib= +if test "$GCC" = no; then + case $host_os in + sco3.2v5*) + lt_prog_cc_shlib='-belf' + ;; + esac +fi +if test -n "$lt_prog_cc_shlib"; then + { echo "$as_me:$LINENO: WARNING: \`$CC' requires \`$lt_prog_cc_shlib' to build shared libraries" >&5 +echo "$as_me: WARNING: \`$CC' requires \`$lt_prog_cc_shlib' to build shared libraries" >&2;} + if echo "$old_CC $old_CFLAGS " | grep "[ ]$lt_prog_cc_shlib[ ]" >/dev/null; then : + else + { echo "$as_me:$LINENO: WARNING: add \`$lt_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&5 +echo "$as_me: WARNING: add \`$lt_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&2;} + lt_cv_prog_cc_can_build_shared=no + fi +fi + + +# +# Check to make sure the static flag actually works. +# +echo "$as_me:$LINENO: checking if $compiler static flag $lt_prog_compiler_static works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_prog_compiler_static works... $ECHO_C" >&6 +if test "${lt_prog_compiler_static_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_prog_compiler_static" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + else + lt_prog_compiler_static_works=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works" >&5 +echo "${ECHO_T}$lt_prog_compiler_static_works" >&6 + +if test x"$lt_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag=' -fno-builtin' + + +echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:6877: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:6881: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s conftest.err; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6 + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + +lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + +echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case "$cc_basename" in + xlc*) + lt_prog_compiler_pic='-qnocommon' + lt_prog_compiler_wl='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + linux*) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + pgcc | pgf77 | pgf90) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-static' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + sco3.2v5*) + lt_prog_compiler_pic='-Kpic' + lt_prog_compiler_static='-dn' + ;; + + solaris*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic" >&6 + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + +echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic works... $ECHO_C" >&6 +if test "${lt_prog_compiler_pic_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:7132: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:7136: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s conftest.err; then + lt_prog_compiler_pic_works=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works" >&6 + +if test x"$lt_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi +case "$host_os" in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_c_o+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:7192: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:7196: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s out/conftest.err; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o" >&6 + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 + + runpath_var= + allow_undefined_flag= + enable_shared_with_static_runtimes=no + archive_cmds= + archive_expsym_cmds= + old_archive_From_new_cmds= + old_archive_from_expsyms_cmds= + export_dynamic_flag_spec= + whole_archive_flag_spec= + thread_safe_flag_spec= + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_direct=no + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + link_all_deplibs=unknown + hardcode_automatic=no + module_cmds= + module_expsym_cmds= + always_export_symbols=no + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $CC,$host_cpu in + pgf77* | pgf90* ) # Portland Group f77 and f90 compilers + tmp_addflag=' -fpic' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + archive_cmds='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + if test $supports_anon_versioning = yes; then + archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~ +cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ +$echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + else + archive_expsym_cmds=$archive_cmds + fi + else + ld_shlibs=no + fi + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = yes; then + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct=yes + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + always_export_symbols=yes + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec=' ' + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds it's shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + case "$host_os" in + rhapsody* | darwin1.[012]) + allow_undefined_flag='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + whole_archive_flag_spec='' + link_all_deplibs=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case "$cc_basename" in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | kfreebsd*-gnu | dragonfly*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10* | hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*|ia64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case "$host_cpu" in + hppa*64*|ia64*) + archive_cmds='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' + ;; + *) + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*) + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_libdir_separator=: + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + ia64*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=no + hardcode_shlibpath_var=no + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + *) + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld='-rpath $libdir' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + openbsd*) + hardcode_direct=yes + hardcode_shlibpath_var=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + + sco3.2v5*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ;; + + solaris*) + no_undefined_flag=' -z text' + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4.2uw2*) + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=no + hardcode_shlibpath_var=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*) + no_undefined_flag='${wl}-z ${wl}text' + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv5*) + no_undefined_flag=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + hardcode_libdir_flag_spec= + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $ld_shlibs" >&5 +echo "${ECHO_T}$ld_shlibs" >&6 +test "$ld_shlibs" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc=no + else + archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5 +echo "${ECHO_T}$archive_cmds_need_lc" >&6 + ;; + esac + fi + ;; +esac + +echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + *) # from 3.2 on + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case "$host_cpu" in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:,\t]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no + +echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test -n "$runpath_var" || \ + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +echo "$as_me:$LINENO: result: $hardcode_action" >&5 +echo "${ECHO_T}$hardcode_action" >&6 + +if test "$hardcode_action" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +striplib= +old_striplib= +echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 +echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6 +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + ;; + *) + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + ;; + esac +fi + +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + echo "$as_me:$LINENO: checking for shl_load" >&5 +echo $ECHO_N "checking for shl_load... $ECHO_C" >&6 +if test "${ac_cv_func_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define shl_load to an innocuous variant, in case declares shl_load. + For example, HP-UX 11i declares gettimeofday. */ +#define shl_load innocuous_shl_load + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shl_load (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef shl_load + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shl_load (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_shl_load) || defined (__stub___shl_load) +choke me +#else +char (*f) () = shl_load; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != shl_load; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_shl_load=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 +echo "${ECHO_T}$ac_cv_func_shl_load" >&6 +if test $ac_cv_func_shl_load = yes; then + lt_cv_dlopen="shl_load" +else + echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 +echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shl_load (); +int +main () +{ +shl_load (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dld_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dld_shl_load=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6 +if test $ac_cv_lib_dld_shl_load = yes; then + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" +else + echo "$as_me:$LINENO: checking for dlopen" >&5 +echo $ECHO_N "checking for dlopen... $ECHO_C" >&6 +if test "${ac_cv_func_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define dlopen to an innocuous variant, in case declares dlopen. + For example, HP-UX 11i declares gettimeofday. */ +#define dlopen innocuous_dlopen + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char dlopen (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef dlopen + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_dlopen) || defined (__stub___dlopen) +choke me +#else +char (*f) () = dlopen; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != dlopen; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 +echo "${ECHO_T}$ac_cv_func_dlopen" >&6 +if test $ac_cv_func_dlopen = yes; then + lt_cv_dlopen="dlopen" +else + echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 +echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6 +if test "${ac_cv_lib_svld_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_svld_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_svld_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6 +if test $ac_cv_lib_svld_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 +echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_dld_link+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dld_link (); +int +main () +{ +dld_link (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dld_dld_link=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dld_dld_link=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6 +if test $ac_cv_lib_dld_dld_link = yes; then + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 +echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_unknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self" >&6 + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 +echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self_static+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6 + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + +# Report which librarie types wil actually be built +echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 +echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $can_build_shared" >&5 +echo "${ECHO_T}$can_build_shared" >&6 + +echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 +echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6 +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +echo "$as_me:$LINENO: result: $enable_shared" >&5 +echo "${ECHO_T}$enable_shared" >&6 + +echo "$as_me:$LINENO: checking whether to build static libraries" >&5 +echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6 +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +echo "$as_me:$LINENO: result: $enable_static" >&5 +echo "${ECHO_T}$enable_static" >&6 + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS AS EGREP RANLIB LN_S LTCC NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler \ + CC \ + LD \ + lt_prog_compiler_wl \ + lt_prog_compiler_pic \ + lt_prog_compiler_static \ + lt_prog_compiler_no_builtin_flag \ + export_dynamic_flag_spec \ + thread_safe_flag_spec \ + whole_archive_flag_spec \ + enable_shared_with_static_runtimes \ + old_archive_cmds \ + old_archive_from_new_cmds \ + predep_objects \ + postdep_objects \ + predeps \ + postdeps \ + compiler_lib_search_path \ + archive_cmds \ + archive_expsym_cmds \ + postinstall_cmds \ + postuninstall_cmds \ + old_archive_from_expsyms_cmds \ + allow_undefined_flag \ + no_undefined_flag \ + export_symbols_cmds \ + hardcode_libdir_flag_spec \ + hardcode_libdir_flag_spec_ld \ + hardcode_libdir_separator \ + hardcode_automatic \ + module_cmds \ + module_expsym_cmds \ + lt_cv_prog_compiler_c_o \ + exclude_expsyms \ + include_expsyms; do + + case $var in + old_archive_cmds | \ + old_archive_from_new_cmds | \ + archive_cmds | \ + archive_expsym_cmds | \ + module_cmds | \ + module_expsym_cmds | \ + old_archive_from_expsyms_cmds | \ + export_symbols_cmds | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="${ofile}T" + trap "$rm \"$cfgfile\"; exit 1" 1 2 15 + $rm -f "$cfgfile" + { echo "$as_me:$LINENO: creating $ofile" >&5 +echo "$as_me: creating $ofile" >&6;} + + cat <<__EOF__ >> "$cfgfile" +#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# 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. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# A language-specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU C compiler? +with_gcc=$GCC + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS=$lt_AS + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# ### END LIBTOOL CONFIG + +__EOF__ + + + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + +# Check whether --with-tags or --without-tags was given. +if test "${with_tags+set}" = set; then + withval="$with_tags" + tagnames="$withval" +fi; + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not exist" >&5 +echo "$as_me: WARNING: output file \`$ofile' does not exist" >&2;} + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not look like a libtool script" >&5 +echo "$as_me: WARNING: output file \`$ofile' does not look like a libtool script" >&2;} + else + { echo "$as_me:$LINENO: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&5 +echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;} + fi + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]::g'` in + "") ;; + *) { { echo "$as_me:$LINENO: error: invalid tag name: $tagname" >&5 +echo "$as_me: error: invalid tag name: $tagname" >&2;} + { (exit 1); exit 1; }; } + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + { { echo "$as_me:$LINENO: error: tag name \"$tagname\" already exists" >&5 +echo "$as_me: error: tag name \"$tagname\" already exists" >&2;} + { (exit 1); exit 1; }; } + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_flag_spec_ld_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_automatic_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +# Source file extension for C++ test sources. +ac_ext=cc + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *) { return(0); }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +compiler_CXX=$CC +cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' +else + lt_prog_compiler_no_builtin_flag_CXX= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi; +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo "$as_me:$LINENO: checking for ld used by $CC" >&5 +echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6 + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6 +else + echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6 +fi +if test "${lt_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +echo "${ECHO_T}$LD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6 +if test "${lt_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +case `$LD -v 2>&1 &5 +echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6 +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 +ld_shlibs_CXX=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct_CXX=yes + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + always_export_symbols_CXX=yes + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX=' ' + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds it's shared libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + ld_shlibs_CXX=no + fi + ;; + darwin* | rhapsody*) + case "$host_os" in + rhapsody* | darwin1.[012]) + allow_undefined_flag_CXX='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag_CXX='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + whole_archive_flag_spec_CXX='' + link_all_deplibs_CXX=yes + + if test "$GXX" = yes ; then + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + archive_cmds_CXX='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + archive_cmds_CXX='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case "$cc_basename" in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_CXX='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_CXX=no + ;; + esac + fi + ;; + + dgux*) + case $cc_basename in + ec++) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + freebsd[12]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + ld_shlibs_CXX=no + ;; + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + gnu*) + ;; + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC) + archive_cmds_CXX='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[-]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + case "$host_cpu" in + hppa*64*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld_CXX='+b $libdir' + hardcode_libdir_separator_CXX=: + ;; + ia64*) + hardcode_libdir_flag_spec_CXX='-L$libdir' + ;; + *) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case "$host_cpu" in + hppa*64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + *) + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC) + case "$host_cpu" in + hppa*64*|ia64*) + archive_cmds_CXX='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case "$host_cpu" in + ia64*|hppa*64*) + archive_cmds_CXX='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + irix5* | irix6*) + case $cc_basename in + CC) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + ;; + linux*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC) + # Portland Group C++ compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + ;; + cxx) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + mvs*) + case $cc_basename in + cxx) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + openbsd*) + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd='echo' + ;; + osf3*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~ + $rm $lib.exp' + + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + sco*) + archive_cmds_need_lc_CXX=no + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[LR]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*) + archive_cmds_need_lc_CXX=no + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; +esac +echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 +echo "${ECHO_T}$ld_shlibs_CXX" >&6 +test "$ld_shlibs_CXX" = no && can_build_shared=no + +GCC_CXX="$GXX" +LD_CXX="$LD" + + +cat > conftest.$ac_ext <&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + # The `*' in the case matches for architectures that use `case' in + # $output_verbose_cmd can trigger glob expansion during the loop + # eval without this substitution. + output_verbose_link_cmd="`$echo \"X$output_verbose_link_cmd\" | $Xsed -e \"$no_glob_subst\"`" + + for p in `eval $output_verbose_link_cmd`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" \ + || test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$rm -f confest.$objext + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + +lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + +echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case "$cc_basename" in + xlc*) + lt_prog_compiler_pic_CXX='-qnocommon' + lt_prog_compiler_wl_CXX='-Wl,' + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux*) + case $cc_basename in + KCC) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + icpc* | ecpc*) + # Intel C++ + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC) + # Portland Group C++ compiler. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-static' + ;; + cxx) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + sco*) + case $cc_basename in + CC) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + *) + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + unixware*) + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_CXX" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_CXX" >&6 + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + +echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... $ECHO_C" >&6 +if test "${lt_prog_compiler_pic_works_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:11710: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:11714: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s conftest.err; then + lt_prog_compiler_pic_works_CXX=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_CXX" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works_CXX" >&6 + +if test x"$lt_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi +case "$host_os" in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac + +echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:11770: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:11774: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s out/conftest.err; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_CXX" >&6 + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw*) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([^ ]*\) [^ ]*/\1 DATA/;/^I /d;/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + +echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 +echo "${ECHO_T}$ld_shlibs_CXX" >&6 +test "$ld_shlibs_CXX" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_CXX=no + else + archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + echo "$as_me:$LINENO: result: $archive_cmds_need_lc_CXX" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_CXX" >&6 + ;; + esac + fi + ;; +esac + +echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + *) # from 3.2 on + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case "$host_cpu" in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:,\t]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no + +echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || \ + test -n "$runpath_var_CXX" || \ + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +echo "$as_me:$LINENO: result: $hardcode_action_CXX" >&5 +echo "${ECHO_T}$hardcode_action_CXX" >&6 + +if test "$hardcode_action_CXX" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +striplib= +old_striplib= +echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 +echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6 +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + ;; + *) + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + ;; + esac +fi + +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + echo "$as_me:$LINENO: checking for shl_load" >&5 +echo $ECHO_N "checking for shl_load... $ECHO_C" >&6 +if test "${ac_cv_func_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define shl_load to an innocuous variant, in case declares shl_load. + For example, HP-UX 11i declares gettimeofday. */ +#define shl_load innocuous_shl_load + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shl_load (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef shl_load + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shl_load (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_shl_load) || defined (__stub___shl_load) +choke me +#else +char (*f) () = shl_load; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != shl_load; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_shl_load=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 +echo "${ECHO_T}$ac_cv_func_shl_load" >&6 +if test $ac_cv_func_shl_load = yes; then + lt_cv_dlopen="shl_load" +else + echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 +echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shl_load (); +int +main () +{ +shl_load (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dld_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dld_shl_load=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6 +if test $ac_cv_lib_dld_shl_load = yes; then + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" +else + echo "$as_me:$LINENO: checking for dlopen" >&5 +echo $ECHO_N "checking for dlopen... $ECHO_C" >&6 +if test "${ac_cv_func_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define dlopen to an innocuous variant, in case declares dlopen. + For example, HP-UX 11i declares gettimeofday. */ +#define dlopen innocuous_dlopen + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char dlopen (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef dlopen + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_dlopen) || defined (__stub___dlopen) +choke me +#else +char (*f) () = dlopen; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != dlopen; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 +echo "${ECHO_T}$ac_cv_func_dlopen" >&6 +if test $ac_cv_func_dlopen = yes; then + lt_cv_dlopen="dlopen" +else + echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 +echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6 +if test "${ac_cv_lib_svld_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_svld_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_svld_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6 +if test $ac_cv_lib_svld_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 +echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_dld_link+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dld_link (); +int +main () +{ +dld_link (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dld_dld_link=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dld_dld_link=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6 +if test $ac_cv_lib_dld_dld_link = yes; then + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 +echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_unknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self" >&6 + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 +echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self_static+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6 + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS AS EGREP RANLIB LN_S LTCC NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_CXX \ + CC_CXX \ + LD_CXX \ + lt_prog_compiler_wl_CXX \ + lt_prog_compiler_pic_CXX \ + lt_prog_compiler_static_CXX \ + lt_prog_compiler_no_builtin_flag_CXX \ + export_dynamic_flag_spec_CXX \ + thread_safe_flag_spec_CXX \ + whole_archive_flag_spec_CXX \ + enable_shared_with_static_runtimes_CXX \ + old_archive_cmds_CXX \ + old_archive_from_new_cmds_CXX \ + predep_objects_CXX \ + postdep_objects_CXX \ + predeps_CXX \ + postdeps_CXX \ + compiler_lib_search_path_CXX \ + archive_cmds_CXX \ + archive_expsym_cmds_CXX \ + postinstall_cmds_CXX \ + postuninstall_cmds_CXX \ + old_archive_from_expsyms_cmds_CXX \ + allow_undefined_flag_CXX \ + no_undefined_flag_CXX \ + export_symbols_cmds_CXX \ + hardcode_libdir_flag_spec_CXX \ + hardcode_libdir_flag_spec_ld_CXX \ + hardcode_libdir_separator_CXX \ + hardcode_automatic_CXX \ + module_cmds_CXX \ + module_expsym_cmds_CXX \ + lt_cv_prog_compiler_c_o_CXX \ + exclude_expsyms_CXX \ + include_expsyms_CXX; do + + case $var in + old_archive_cmds_CXX | \ + old_archive_from_new_cmds_CXX | \ + archive_cmds_CXX | \ + archive_expsym_cmds_CXX | \ + module_cmds_CXX | \ + module_expsym_cmds_CXX | \ + old_archive_from_expsyms_cmds_CXX | \ + export_symbols_cmds_CXX | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# A language-specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_CXX + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS=$lt_AS + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_CXX + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_CXX +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_CXX + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_CXX + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_CXX + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path_CXX" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld + + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + +ac_ext=f +ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' +ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_f77_compiler_gnu + + +archive_cmds_need_lc_F77=no +allow_undefined_flag_F77= +always_export_symbols_F77=no +archive_expsym_cmds_F77= +export_dynamic_flag_spec_F77= +hardcode_direct_F77=no +hardcode_libdir_flag_spec_F77= +hardcode_libdir_flag_spec_ld_F77= +hardcode_libdir_separator_F77= +hardcode_minus_L_F77=no +hardcode_automatic_F77=no +module_cmds_F77= +module_expsym_cmds_F77= +link_all_deplibs_F77=unknown +old_archive_cmds_F77=$old_archive_cmds +no_undefined_flag_F77= +whole_archive_flag_spec_F77= +enable_shared_with_static_runtimes_F77=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +objext_F77=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code=" subroutine t\n return\n end\n" + +# Code to be used in simple link tests +lt_simple_link_test_code=" program t\n end\n" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${F77-"f77"} +compiler=$CC +compiler_F77=$CC +cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` + +echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 +echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $can_build_shared" >&5 +echo "${ECHO_T}$can_build_shared" >&6 + +echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 +echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6 +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; +aix4* | aix5*) + test "$enable_shared" = yes && enable_static=no + ;; +esac +echo "$as_me:$LINENO: result: $enable_shared" >&5 +echo "${ECHO_T}$enable_shared" >&6 + +echo "$as_me:$LINENO: checking whether to build static libraries" >&5 +echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6 +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +echo "$as_me:$LINENO: result: $enable_static" >&5 +echo "${ECHO_T}$enable_static" >&6 + +test "$ld_shlibs_F77" = no && can_build_shared=no + +GCC_F77="$G77" +LD_F77="$LD" + +lt_prog_compiler_wl_F77= +lt_prog_compiler_pic_F77= +lt_prog_compiler_static_F77= + +echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 + + if test "$GCC" = yes; then + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_static_F77='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_F77='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_F77='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_F77='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_F77='-fno-common' + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared_F77=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_F77=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_F77='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic_F77='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl_F77='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_F77='-Bstatic' + else + lt_prog_compiler_static_F77='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case "$cc_basename" in + xlc*) + lt_prog_compiler_pic_F77='-qnocommon' + lt_prog_compiler_wl_F77='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_F77='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl_F77='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_F77='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static_F77='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl_F77='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static_F77='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + linux*) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-static' + ;; + pgcc | pgf77 | pgf90) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-fpic' + lt_prog_compiler_static_F77='-static' + ;; + ccc*) + lt_prog_compiler_wl_F77='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static_F77='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl_F77='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static_F77='-non_shared' + ;; + + sco3.2v5*) + lt_prog_compiler_pic_F77='-Kpic' + lt_prog_compiler_static_F77='-dn' + ;; + + solaris*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + sunos4*) + lt_prog_compiler_wl_F77='-Qoption ld ' + lt_prog_compiler_pic_F77='-PIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic_F77='-Kconform_pic' + lt_prog_compiler_static_F77='-Bstatic' + fi + ;; + + unicos*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_can_build_shared_F77=no + ;; + + uts4*) + lt_prog_compiler_pic_F77='-pic' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared_F77=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_F77" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_F77" >&6 + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_F77"; then + +echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works... $ECHO_C" >&6 +if test "${lt_prog_compiler_pic_works_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works_F77=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_F77" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:14086: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:14090: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s conftest.err; then + lt_prog_compiler_pic_works_F77=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_F77" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works_F77" >&6 + +if test x"$lt_prog_compiler_pic_works_F77" = xyes; then + case $lt_prog_compiler_pic_F77 in + "" | " "*) ;; + *) lt_prog_compiler_pic_F77=" $lt_prog_compiler_pic_F77" ;; + esac +else + lt_prog_compiler_pic_F77= + lt_prog_compiler_can_build_shared_F77=no +fi + +fi +case "$host_os" in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_F77= + ;; + *) + lt_prog_compiler_pic_F77="$lt_prog_compiler_pic_F77" + ;; +esac + +echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_c_o_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_F77=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:14146: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:14150: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s out/conftest.err; then + lt_cv_prog_compiler_c_o_F77=yes + fi + fi + chmod u+w . + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_F77" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_F77" >&6 + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_F77" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 + + runpath_var= + allow_undefined_flag_F77= + enable_shared_with_static_runtimes_F77=no + archive_cmds_F77= + archive_expsym_cmds_F77= + old_archive_From_new_cmds_F77= + old_archive_from_expsyms_cmds_F77= + export_dynamic_flag_spec_F77= + whole_archive_flag_spec_F77= + thread_safe_flag_spec_F77= + hardcode_libdir_flag_spec_F77= + hardcode_libdir_flag_spec_ld_F77= + hardcode_libdir_separator_F77= + hardcode_direct_F77=no + hardcode_minus_L_F77=no + hardcode_shlibpath_var_F77=unsupported + link_all_deplibs_F77=unknown + hardcode_automatic_F77=no + module_cmds_F77= + module_expsym_cmds_F77= + always_export_symbols_F77=no + export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms_F77= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms_F77="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs_F77=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs_F77=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs_F77=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_F77=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_F77='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_F77=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, F77) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_F77='-L$libdir' + allow_undefined_flag_F77=unsupported + always_export_symbols_F77=no + enable_shared_with_static_runtimes_F77=yes + export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + ld_shlibs_F77=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_F77='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs_F77=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_F77=no + fi + ;; + + sunos4*) + archive_cmds_F77='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $CC,$host_cpu in + pgf77* | pgf90* ) # Portland Group f77 and f90 compilers + tmp_addflag=' -fpic' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + archive_cmds_F77='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + if test $supports_anon_versioning = yes; then + archive_expsym_cmds_F77='$echo "{ global:" > $output_objdir/$libname.ver~ +cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ +$echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + else + archive_expsym_cmds_F77=$archive_cmds_F77 + fi + else + ld_shlibs_F77=no + fi + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_F77=no + fi + ;; + esac + + if test "$ld_shlibs_F77" = yes; then + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_F77='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_F77='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_F77= + fi + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag_F77=unsupported + always_export_symbols_F77=yes + archive_expsym_cmds_F77='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L_F77=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct_F77=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_F77='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_F77='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_F77='' + hardcode_direct_F77=yes + hardcode_libdir_separator_F77=':' + link_all_deplibs_F77=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct_F77=yes + else + # We have old collect2 + hardcode_direct_F77=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_F77=yes + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_libdir_separator_F77= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_F77=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_F77='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_f77_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds_F77="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_F77='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_F77="-z nodefs" + archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_f77_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_F77=' ${wl}-bernotok' + allow_undefined_flag_F77=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + always_export_symbols_F77=yes + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_F77=' ' + archive_cmds_need_lc_F77=yes + # This is similar to how AIX traditionally builds it's shared libraries. + archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + # see comment about different semantics on the GNU ld section + ld_shlibs_F77=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec_F77=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_F77=' ' + allow_undefined_flag_F77=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds_F77='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds_F77='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds_F77='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path_F77='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes_F77=yes + ;; + + darwin* | rhapsody*) + case "$host_os" in + rhapsody* | darwin1.[012]) + allow_undefined_flag_F77='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag_F77='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc_F77=no + hardcode_direct_F77=no + hardcode_automatic_F77=yes + hardcode_shlibpath_var_F77=unsupported + whole_archive_flag_spec_F77='' + link_all_deplibs_F77=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds_F77='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case "$cc_basename" in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_F77='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_F77=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_shlibpath_var_F77=no + ;; + + freebsd1*) + ld_shlibs_F77=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes + hardcode_minus_L_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | kfreebsd*-gnu | dragonfly*) + archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds_F77='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds_F77='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_F77=: + hardcode_direct_F77=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + export_dynamic_flag_spec_F77='${wl}-E' + ;; + + hpux10* | hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*|ia64*) + archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case "$host_cpu" in + hppa*64*|ia64*) + archive_cmds_F77='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' + ;; + *) + archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*) + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld_F77='+b $libdir' + hardcode_libdir_separator_F77=: + hardcode_direct_F77=no + hardcode_shlibpath_var_F77=no + ;; + ia64*) + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_direct_F77=no + hardcode_shlibpath_var_F77=no + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + ;; + *) + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_F77=: + hardcode_direct_F77=yes + export_dynamic_flag_spec_F77='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_F77='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld_F77='-rpath $libdir' + fi + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + link_all_deplibs_F77=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds_F77='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + newsos6) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + hardcode_shlibpath_var_F77=no + ;; + + openbsd*) + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' + export_dynamic_flag_spec_F77='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-R$libdir' + ;; + *) + archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + allow_undefined_flag_F77=unsupported + archive_cmds_F77='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds_F77='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag_F77=' -expect_unresolved \*' + archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag_F77=' -expect_unresolved \*' + archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_F77='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec_F77='-rpath $libdir' + fi + hardcode_libdir_separator_F77=: + ;; + + sco3.2v5*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_F77=no + export_dynamic_flag_spec_F77='${wl}-Bexport' + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ;; + + solaris*) + no_undefined_flag_F77=' -z text' + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_shlibpath_var_F77=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_F77='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; + esac + link_all_deplibs_F77=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds_F77='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_direct_F77=yes + hardcode_minus_L_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds_F77='$CC -r -o $output$reload_objs' + hardcode_direct_F77=no + ;; + motorola) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var_F77=no + ;; + + sysv4.3*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_F77=no + export_dynamic_flag_spec_F77='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_F77=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs_F77=yes + fi + ;; + + sysv4.2uw2*) + archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes + hardcode_minus_L_F77=no + hardcode_shlibpath_var_F77=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*) + no_undefined_flag_F77='${wl}-z ${wl}text' + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var_F77=no + ;; + + sysv5*) + no_undefined_flag_F77=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + hardcode_libdir_flag_spec_F77= + hardcode_shlibpath_var_F77=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_shlibpath_var_F77=no + ;; + + *) + ld_shlibs_F77=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $ld_shlibs_F77" >&5 +echo "${ECHO_T}$ld_shlibs_F77" >&6 +test "$ld_shlibs_F77" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_F77" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_F77=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_F77 in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_F77 + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_F77 + allow_undefined_flag_F77= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_F77=no + else + archive_cmds_need_lc_F77=yes + fi + allow_undefined_flag_F77=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + echo "$as_me:$LINENO: result: $archive_cmds_need_lc_F77" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_F77" >&6 + ;; + esac + fi + ;; +esac + +echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + *) # from 3.2 on + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case "$host_cpu" in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:,\t]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no + +echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 +hardcode_action_F77= +if test -n "$hardcode_libdir_flag_spec_F77" || \ + test -n "$runpath_var_F77" || \ + test "X$hardcode_automatic_F77" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_F77" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, F77)" != no && + test "$hardcode_minus_L_F77" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_F77=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_F77=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_F77=unsupported +fi +echo "$as_me:$LINENO: result: $hardcode_action_F77" >&5 +echo "${ECHO_T}$hardcode_action_F77" >&6 + +if test "$hardcode_action_F77" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +striplib= +old_striplib= +echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 +echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6 +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + ;; + *) + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + ;; + esac +fi + + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS AS EGREP RANLIB LN_S LTCC NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_F77 \ + CC_F77 \ + LD_F77 \ + lt_prog_compiler_wl_F77 \ + lt_prog_compiler_pic_F77 \ + lt_prog_compiler_static_F77 \ + lt_prog_compiler_no_builtin_flag_F77 \ + export_dynamic_flag_spec_F77 \ + thread_safe_flag_spec_F77 \ + whole_archive_flag_spec_F77 \ + enable_shared_with_static_runtimes_F77 \ + old_archive_cmds_F77 \ + old_archive_from_new_cmds_F77 \ + predep_objects_F77 \ + postdep_objects_F77 \ + predeps_F77 \ + postdeps_F77 \ + compiler_lib_search_path_F77 \ + archive_cmds_F77 \ + archive_expsym_cmds_F77 \ + postinstall_cmds_F77 \ + postuninstall_cmds_F77 \ + old_archive_from_expsyms_cmds_F77 \ + allow_undefined_flag_F77 \ + no_undefined_flag_F77 \ + export_symbols_cmds_F77 \ + hardcode_libdir_flag_spec_F77 \ + hardcode_libdir_flag_spec_ld_F77 \ + hardcode_libdir_separator_F77 \ + hardcode_automatic_F77 \ + module_cmds_F77 \ + module_expsym_cmds_F77 \ + lt_cv_prog_compiler_c_o_F77 \ + exclude_expsyms_F77 \ + include_expsyms_F77; do + + case $var in + old_archive_cmds_F77 | \ + old_archive_from_new_cmds_F77 | \ + archive_cmds_F77 | \ + archive_expsym_cmds_F77 | \ + module_cmds_F77 | \ + module_expsym_cmds_F77 | \ + old_archive_from_expsyms_cmds_F77 | \ + export_symbols_cmds_F77 | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_F77 + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_F77 + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# A language-specific compiler. +CC=$lt_compiler_F77 + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_F77 + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_F77 + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS=$lt_AS + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_F77 + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_F77 +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_F77 + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_F77 + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_F77 + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_F77 + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_F77 + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_F77 + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_F77 +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_F77 + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_F77 + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_F77 +archive_expsym_cmds=$lt_archive_expsym_cmds_F77 +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_F77 +module_expsym_cmds=$lt_module_expsym_cmds_F77 + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_F77 + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_F77 + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_F77 + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_F77 + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_F77 + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_F77 + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_F77 + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_F77 + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_F77 + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_F77 + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_F77 + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_F77 + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_F77 + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_F77 + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_F77 + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_F77 + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path_F77" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_F77 + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_F77 + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_F77 + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_F77 + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + + + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +objext_GCJ=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[] argv) {}; }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${GCJ-"gcj"} +compiler=$CC +compiler_GCJ=$CC + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +archive_cmds_need_lc_GCJ=no + + +lt_prog_compiler_no_builtin_flag_GCJ= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag_GCJ=' -fno-builtin' + + +echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:16202: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:16206: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s conftest.err; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6 + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag_GCJ="$lt_prog_compiler_no_builtin_flag_GCJ -fno-rtti -fno-exceptions" +else + : +fi + +fi + +lt_prog_compiler_wl_GCJ= +lt_prog_compiler_pic_GCJ= +lt_prog_compiler_static_GCJ= + +echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 + + if test "$GCC" = yes; then + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_static_GCJ='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_GCJ='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_GCJ='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_GCJ='-fno-common' + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared_GCJ=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_GCJ=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_GCJ='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic_GCJ='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl_GCJ='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_GCJ='-Bstatic' + else + lt_prog_compiler_static_GCJ='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case "$cc_basename" in + xlc*) + lt_prog_compiler_pic_GCJ='-qnocommon' + lt_prog_compiler_wl_GCJ='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl_GCJ='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_GCJ='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static_GCJ='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl_GCJ='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + linux*) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-static' + ;; + pgcc | pgf77 | pgf90) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-fpic' + lt_prog_compiler_static_GCJ='-static' + ;; + ccc*) + lt_prog_compiler_wl_GCJ='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl_GCJ='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + + sco3.2v5*) + lt_prog_compiler_pic_GCJ='-Kpic' + lt_prog_compiler_static_GCJ='-dn' + ;; + + solaris*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + sunos4*) + lt_prog_compiler_wl_GCJ='-Qoption ld ' + lt_prog_compiler_pic_GCJ='-PIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic_GCJ='-Kconform_pic' + lt_prog_compiler_static_GCJ='-Bstatic' + fi + ;; + + unicos*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_can_build_shared_GCJ=no + ;; + + uts4*) + lt_prog_compiler_pic_GCJ='-pic' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared_GCJ=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_GCJ" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_GCJ" >&6 + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_GCJ"; then + +echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works... $ECHO_C" >&6 +if test "${lt_prog_compiler_pic_works_GCJ+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works_GCJ=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_GCJ" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:16457: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:16461: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s conftest.err; then + lt_prog_compiler_pic_works_GCJ=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_GCJ" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works_GCJ" >&6 + +if test x"$lt_prog_compiler_pic_works_GCJ" = xyes; then + case $lt_prog_compiler_pic_GCJ in + "" | " "*) ;; + *) lt_prog_compiler_pic_GCJ=" $lt_prog_compiler_pic_GCJ" ;; + esac +else + lt_prog_compiler_pic_GCJ= + lt_prog_compiler_can_build_shared_GCJ=no +fi + +fi +case "$host_os" in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_GCJ= + ;; + *) + lt_prog_compiler_pic_GCJ="$lt_prog_compiler_pic_GCJ" + ;; +esac + +echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_c_o_GCJ+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_GCJ=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:16517: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:16521: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s out/conftest.err; then + lt_cv_prog_compiler_c_o_GCJ=yes + fi + fi + chmod u+w . + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_GCJ" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_GCJ" >&6 + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_GCJ" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 + + runpath_var= + allow_undefined_flag_GCJ= + enable_shared_with_static_runtimes_GCJ=no + archive_cmds_GCJ= + archive_expsym_cmds_GCJ= + old_archive_From_new_cmds_GCJ= + old_archive_from_expsyms_cmds_GCJ= + export_dynamic_flag_spec_GCJ= + whole_archive_flag_spec_GCJ= + thread_safe_flag_spec_GCJ= + hardcode_libdir_flag_spec_GCJ= + hardcode_libdir_flag_spec_ld_GCJ= + hardcode_libdir_separator_GCJ= + hardcode_direct_GCJ=no + hardcode_minus_L_GCJ=no + hardcode_shlibpath_var_GCJ=unsupported + link_all_deplibs_GCJ=unknown + hardcode_automatic_GCJ=no + module_cmds_GCJ= + module_expsym_cmds_GCJ= + always_export_symbols_GCJ=no + export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms_GCJ= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms_GCJ="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs_GCJ=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs_GCJ=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs_GCJ=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_GCJ=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_GCJ='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, GCJ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_GCJ='-L$libdir' + allow_undefined_flag_GCJ=unsupported + always_export_symbols_GCJ=no + enable_shared_with_static_runtimes_GCJ=yes + export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_GCJ='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + ld_shlibs_GCJ=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_GCJ='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs_GCJ=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + + sunos4*) + archive_cmds_GCJ='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $CC,$host_cpu in + pgf77* | pgf90* ) # Portland Group f77 and f90 compilers + tmp_addflag=' -fpic' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + archive_cmds_GCJ='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + if test $supports_anon_versioning = yes; then + archive_expsym_cmds_GCJ='$echo "{ global:" > $output_objdir/$libname.ver~ +cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ +$echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + else + archive_expsym_cmds_GCJ=$archive_cmds_GCJ + fi + else + ld_shlibs_GCJ=no + fi + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + esac + + if test "$ld_shlibs_GCJ" = yes; then + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_GCJ='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_GCJ='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_GCJ="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_GCJ= + fi + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag_GCJ=unsupported + always_export_symbols_GCJ=yes + archive_expsym_cmds_GCJ='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L_GCJ=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct_GCJ=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_GCJ='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_GCJ='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_GCJ='' + hardcode_direct_GCJ=yes + hardcode_libdir_separator_GCJ=':' + link_all_deplibs_GCJ=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct_GCJ=yes + else + # We have old collect2 + hardcode_direct_GCJ=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_GCJ=yes + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_libdir_separator_GCJ= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_GCJ=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_GCJ='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds_GCJ="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_GCJ='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_GCJ="-z nodefs" + archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_GCJ=' ${wl}-bernotok' + allow_undefined_flag_GCJ=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + always_export_symbols_GCJ=yes + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_GCJ=' ' + archive_cmds_need_lc_GCJ=yes + # This is similar to how AIX traditionally builds it's shared libraries. + archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + # see comment about different semantics on the GNU ld section + ld_shlibs_GCJ=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec_GCJ=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_GCJ=' ' + allow_undefined_flag_GCJ=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds_GCJ='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds_GCJ='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds_GCJ='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path_GCJ='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes_GCJ=yes + ;; + + darwin* | rhapsody*) + case "$host_os" in + rhapsody* | darwin1.[012]) + allow_undefined_flag_GCJ='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag_GCJ='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc_GCJ=no + hardcode_direct_GCJ=no + hardcode_automatic_GCJ=yes + hardcode_shlibpath_var_GCJ=unsupported + whole_archive_flag_spec_GCJ='' + link_all_deplibs_GCJ=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds_GCJ='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case "$cc_basename" in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_GCJ='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_GCJ=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_shlibpath_var_GCJ=no + ;; + + freebsd1*) + ld_shlibs_GCJ=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes + hardcode_minus_L_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | kfreebsd*-gnu | dragonfly*) + archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds_GCJ='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds_GCJ='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + hardcode_direct_GCJ=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-E' + ;; + + hpux10* | hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*|ia64*) + archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case "$host_cpu" in + hppa*64*|ia64*) + archive_cmds_GCJ='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' + ;; + *) + archive_cmds_GCJ='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*) + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld_GCJ='+b $libdir' + hardcode_libdir_separator_GCJ=: + hardcode_direct_GCJ=no + hardcode_shlibpath_var_GCJ=no + ;; + ia64*) + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_direct_GCJ=no + hardcode_shlibpath_var_GCJ=no + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + ;; + *) + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + hardcode_direct_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_GCJ='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld_GCJ='-rpath $libdir' + fi + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + link_all_deplibs_GCJ=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds_GCJ='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + newsos6) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + hardcode_shlibpath_var_GCJ=no + ;; + + openbsd*) + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' + export_dynamic_flag_spec_GCJ='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + ;; + *) + archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + allow_undefined_flag_GCJ=unsupported + archive_cmds_GCJ='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds_GCJ='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag_GCJ=' -expect_unresolved \*' + archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag_GCJ=' -expect_unresolved \*' + archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_GCJ='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec_GCJ='-rpath $libdir' + fi + hardcode_libdir_separator_GCJ=: + ;; + + sco3.2v5*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_GCJ=no + export_dynamic_flag_spec_GCJ='${wl}-Bexport' + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ;; + + solaris*) + no_undefined_flag_GCJ=' -z text' + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_shlibpath_var_GCJ=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_GCJ='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; + esac + link_all_deplibs_GCJ=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds_GCJ='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_direct_GCJ=yes + hardcode_minus_L_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds_GCJ='$CC -r -o $output$reload_objs' + hardcode_direct_GCJ=no + ;; + motorola) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var_GCJ=no + ;; + + sysv4.3*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_GCJ=no + export_dynamic_flag_spec_GCJ='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_GCJ=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs_GCJ=yes + fi + ;; + + sysv4.2uw2*) + archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes + hardcode_minus_L_GCJ=no + hardcode_shlibpath_var_GCJ=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*) + no_undefined_flag_GCJ='${wl}-z ${wl}text' + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var_GCJ=no + ;; + + sysv5*) + no_undefined_flag_GCJ=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + hardcode_libdir_flag_spec_GCJ= + hardcode_shlibpath_var_GCJ=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_shlibpath_var_GCJ=no + ;; + + *) + ld_shlibs_GCJ=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $ld_shlibs_GCJ" >&5 +echo "${ECHO_T}$ld_shlibs_GCJ" >&6 +test "$ld_shlibs_GCJ" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_GCJ" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_GCJ=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_GCJ in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_GCJ + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_GCJ + allow_undefined_flag_GCJ= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_GCJ=no + else + archive_cmds_need_lc_GCJ=yes + fi + allow_undefined_flag_GCJ=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + echo "$as_me:$LINENO: result: $archive_cmds_need_lc_GCJ" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_GCJ" >&6 + ;; + esac + fi + ;; +esac + +echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + *) # from 3.2 on + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case "$host_cpu" in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:,\t]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no + +echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 +hardcode_action_GCJ= +if test -n "$hardcode_libdir_flag_spec_GCJ" || \ + test -n "$runpath_var_GCJ" || \ + test "X$hardcode_automatic_GCJ" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_GCJ" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, GCJ)" != no && + test "$hardcode_minus_L_GCJ" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_GCJ=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_GCJ=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_GCJ=unsupported +fi +echo "$as_me:$LINENO: result: $hardcode_action_GCJ" >&5 +echo "${ECHO_T}$hardcode_action_GCJ" >&6 + +if test "$hardcode_action_GCJ" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +striplib= +old_striplib= +echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 +echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6 +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + ;; + *) + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + ;; + esac +fi + +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + echo "$as_me:$LINENO: checking for shl_load" >&5 +echo $ECHO_N "checking for shl_load... $ECHO_C" >&6 +if test "${ac_cv_func_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define shl_load to an innocuous variant, in case declares shl_load. + For example, HP-UX 11i declares gettimeofday. */ +#define shl_load innocuous_shl_load + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shl_load (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef shl_load + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shl_load (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_shl_load) || defined (__stub___shl_load) +choke me +#else +char (*f) () = shl_load; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != shl_load; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_shl_load=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 +echo "${ECHO_T}$ac_cv_func_shl_load" >&6 +if test $ac_cv_func_shl_load = yes; then + lt_cv_dlopen="shl_load" +else + echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 +echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shl_load (); +int +main () +{ +shl_load (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dld_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dld_shl_load=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6 +if test $ac_cv_lib_dld_shl_load = yes; then + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" +else + echo "$as_me:$LINENO: checking for dlopen" >&5 +echo $ECHO_N "checking for dlopen... $ECHO_C" >&6 +if test "${ac_cv_func_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define dlopen to an innocuous variant, in case declares dlopen. + For example, HP-UX 11i declares gettimeofday. */ +#define dlopen innocuous_dlopen + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char dlopen (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef dlopen + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_dlopen) || defined (__stub___dlopen) +choke me +#else +char (*f) () = dlopen; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != dlopen; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 +echo "${ECHO_T}$ac_cv_func_dlopen" >&6 +if test $ac_cv_func_dlopen = yes; then + lt_cv_dlopen="dlopen" +else + echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 +echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6 +if test "${ac_cv_lib_svld_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_svld_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_svld_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6 +if test $ac_cv_lib_svld_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 +echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_dld_link+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dld_link (); +int +main () +{ +dld_link (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dld_dld_link=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dld_dld_link=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6 +if test $ac_cv_lib_dld_dld_link = yes; then + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 +echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_unknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self" >&6 + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 +echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self_static+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6 + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS AS EGREP RANLIB LN_S LTCC NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_GCJ \ + CC_GCJ \ + LD_GCJ \ + lt_prog_compiler_wl_GCJ \ + lt_prog_compiler_pic_GCJ \ + lt_prog_compiler_static_GCJ \ + lt_prog_compiler_no_builtin_flag_GCJ \ + export_dynamic_flag_spec_GCJ \ + thread_safe_flag_spec_GCJ \ + whole_archive_flag_spec_GCJ \ + enable_shared_with_static_runtimes_GCJ \ + old_archive_cmds_GCJ \ + old_archive_from_new_cmds_GCJ \ + predep_objects_GCJ \ + postdep_objects_GCJ \ + predeps_GCJ \ + postdeps_GCJ \ + compiler_lib_search_path_GCJ \ + archive_cmds_GCJ \ + archive_expsym_cmds_GCJ \ + postinstall_cmds_GCJ \ + postuninstall_cmds_GCJ \ + old_archive_from_expsyms_cmds_GCJ \ + allow_undefined_flag_GCJ \ + no_undefined_flag_GCJ \ + export_symbols_cmds_GCJ \ + hardcode_libdir_flag_spec_GCJ \ + hardcode_libdir_flag_spec_ld_GCJ \ + hardcode_libdir_separator_GCJ \ + hardcode_automatic_GCJ \ + module_cmds_GCJ \ + module_expsym_cmds_GCJ \ + lt_cv_prog_compiler_c_o_GCJ \ + exclude_expsyms_GCJ \ + include_expsyms_GCJ; do + + case $var in + old_archive_cmds_GCJ | \ + old_archive_from_new_cmds_GCJ | \ + archive_cmds_GCJ | \ + archive_expsym_cmds_GCJ | \ + module_cmds_GCJ | \ + module_expsym_cmds_GCJ | \ + old_archive_from_expsyms_cmds_GCJ | \ + export_symbols_cmds_GCJ | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_GCJ + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_GCJ + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# A language-specific compiler. +CC=$lt_compiler_GCJ + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_GCJ + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_GCJ + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS=$lt_AS + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_GCJ + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_GCJ +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GCJ + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_GCJ + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_GCJ + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_GCJ + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_GCJ + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_GCJ + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_GCJ +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_GCJ + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_GCJ + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_GCJ +archive_expsym_cmds=$lt_archive_expsym_cmds_GCJ +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_GCJ +module_expsym_cmds=$lt_module_expsym_cmds_GCJ + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_GCJ + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_GCJ + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_GCJ + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_GCJ + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_GCJ + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_GCJ + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_GCJ + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_GCJ + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_GCJ + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_GCJ + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_GCJ + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_GCJ + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_GCJ + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_GCJ + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_GCJ + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_GCJ + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path_GCJ" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_GCJ + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_GCJ + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_GCJ + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_GCJ + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + else + tagname="" + fi + ;; + + RC) + + + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +objext_RC=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${RC-"windres"} +compiler=$CC +compiler_RC=$CC +lt_cv_prog_compiler_c_o_RC=yes + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS AS EGREP RANLIB LN_S LTCC NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_RC \ + CC_RC \ + LD_RC \ + lt_prog_compiler_wl_RC \ + lt_prog_compiler_pic_RC \ + lt_prog_compiler_static_RC \ + lt_prog_compiler_no_builtin_flag_RC \ + export_dynamic_flag_spec_RC \ + thread_safe_flag_spec_RC \ + whole_archive_flag_spec_RC \ + enable_shared_with_static_runtimes_RC \ + old_archive_cmds_RC \ + old_archive_from_new_cmds_RC \ + predep_objects_RC \ + postdep_objects_RC \ + predeps_RC \ + postdeps_RC \ + compiler_lib_search_path_RC \ + archive_cmds_RC \ + archive_expsym_cmds_RC \ + postinstall_cmds_RC \ + postuninstall_cmds_RC \ + old_archive_from_expsyms_cmds_RC \ + allow_undefined_flag_RC \ + no_undefined_flag_RC \ + export_symbols_cmds_RC \ + hardcode_libdir_flag_spec_RC \ + hardcode_libdir_flag_spec_ld_RC \ + hardcode_libdir_separator_RC \ + hardcode_automatic_RC \ + module_cmds_RC \ + module_expsym_cmds_RC \ + lt_cv_prog_compiler_c_o_RC \ + exclude_expsyms_RC \ + include_expsyms_RC; do + + case $var in + old_archive_cmds_RC | \ + old_archive_from_new_cmds_RC | \ + archive_cmds_RC | \ + archive_expsym_cmds_RC | \ + module_cmds_RC | \ + module_expsym_cmds_RC | \ + old_archive_from_expsyms_cmds_RC | \ + export_symbols_cmds_RC | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_RC + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_RC + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# A language-specific compiler. +CC=$lt_compiler_RC + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_RC + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_RC + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS=$lt_AS + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_RC + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_RC +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_RC + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_RC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_RC + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_RC + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_RC + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_RC + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_RC +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_RC + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_RC + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_RC +archive_expsym_cmds=$lt_archive_expsym_cmds_RC +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_RC +module_expsym_cmds=$lt_module_expsym_cmds_RC + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_RC + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_RC + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_RC + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_RC + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_RC + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_RC + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_RC + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_RC + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_RC + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_RC + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_RC + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_RC + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_RC + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_RC + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_RC + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_RC + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path_RC" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_RC + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_RC + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_RC + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_RC + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + ;; + + *) + { { echo "$as_me:$LINENO: error: Unsupported tag name: $tagname" >&5 +echo "$as_me: error: Unsupported tag name: $tagname" >&2;} + { (exit 1); exit 1; }; } + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + { { echo "$as_me:$LINENO: error: unable to update list of available tagged configurations." >&5 +echo "$as_me: error: unable to update list of available tagged configurations." >&2;} + { (exit 1); exit 1; }; } + fi +fi + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + +# Prevent multiple expansion + + + + + + + + + + + + + + + + + + + + + + + +cat >>confdefs.h <<\_ACEOF +#define ALUT_BUILD_LIBRARY 1 +_ACEOF + + +# Checks for libraries. (not perfect yet) +echo "$as_me:$LINENO: checking for library containing pthread_self" >&5 +echo $ECHO_N "checking for library containing pthread_self... $ECHO_C" >&6 +if test "${ac_cv_search_pthread_self+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +ac_cv_search_pthread_self=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char pthread_self (); +int +main () +{ +pthread_self (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_pthread_self="none required" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "$ac_cv_search_pthread_self" = no; then + for ac_lib in pthread; do + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char pthread_self (); +int +main () +{ +pthread_self (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_pthread_self="-l$ac_lib" +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done +fi +LIBS=$ac_func_search_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_search_pthread_self" >&5 +echo "${ECHO_T}$ac_cv_search_pthread_self" >&6 +if test "$ac_cv_search_pthread_self" != no; then + test "$ac_cv_search_pthread_self" = "none required" || LIBS="$ac_cv_search_pthread_self $LIBS" + +fi + +echo "$as_me:$LINENO: checking for library containing alGetError" >&5 +echo $ECHO_N "checking for library containing alGetError... $ECHO_C" >&6 +if test "${ac_cv_search_alGetError+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +ac_cv_search_alGetError=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char alGetError (); +int +main () +{ +alGetError (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_alGetError="none required" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "$ac_cv_search_alGetError" = no; then + for ac_lib in openal32 openal; do + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char alGetError (); +int +main () +{ +alGetError (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_alGetError="-l$ac_lib" +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done +fi +LIBS=$ac_func_search_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_search_alGetError" >&5 +echo "${ECHO_T}$ac_cv_search_alGetError" >&6 +if test "$ac_cv_search_alGetError" != no; then + test "$ac_cv_search_alGetError" = "none required" || LIBS="$ac_cv_search_alGetError $LIBS" + +fi + + +################################################################################ +# Checks for header files. +################################################################################ + +# We could possibly need struct timespec and random(), which are not ANSI. + +cat >>confdefs.h <<\_ACEOF +#define _XOPEN_SOURCE 500 +_ACEOF + + +# We might need nanosleep, which is a POSIX IEEE Std 1003.1b-1993 feature. + +cat >>confdefs.h <<\_ACEOF +#define _POSIX_C_SOURCE 199309 +_ACEOF + + +# Without __NO_CTYPE tolower and friends are macros which introduce a GLIBC 2.3 +# dependency. By defining this identifier we are currently backwards compatible +# to GLIBC 2.1.3, which is a good thing. In addition, the macros lead to code +# which triggers warnings with -Wunreachable-code. + +cat >>confdefs.h <<\_ACEOF +#define __NO_CTYPE 1 +_ACEOF + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + + + + + + + + + +for ac_header in AL/alc.h AL/al.h basetsd.h ctype.h math.h stdio.h time.h windows.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## --------------------------------------------------- ## +## Report this to openal-devel@opensource.creative.com ## +## --------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# Checks for library functions. +echo "$as_me:$LINENO: checking for nanosleep" >&5 +echo $ECHO_N "checking for nanosleep... $ECHO_C" >&6 +if test "${alut_cv_func_nanosleep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +nanosleep ((struct timespec*)0, (struct timespec*)0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + alut_cv_func_nanosleep=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +alut_cv_func_nanosleep=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $alut_cv_func_nanosleep" >&5 +echo "${ECHO_T}$alut_cv_func_nanosleep" >&6 +if test $alut_cv_func_nanosleep = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_NANOSLEEP 1 +_ACEOF + +fi + + +echo "$as_me:$LINENO: checking for usleep" >&5 +echo $ECHO_N "checking for usleep... $ECHO_C" >&6 +if test "${alut_cv_func_usleep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +usleep (0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + alut_cv_func_usleep=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +alut_cv_func_usleep=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $alut_cv_func_usleep" >&5 +echo "${ECHO_T}$alut_cv_func_usleep" >&6 +if test $alut_cv_func_usleep = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_USLEEP 1 +_ACEOF + +fi + + +echo "$as_me:$LINENO: checking for Sleep" >&5 +echo $ECHO_N "checking for Sleep... $ECHO_C" >&6 +if test "${alut_cv_func_Sleep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +Sleep (0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + alut_cv_func_Sleep=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +alut_cv_func_Sleep=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $alut_cv_func_Sleep" >&5 +echo "${ECHO_T}$alut_cv_func_Sleep" >&6 +if test $alut_cv_func_Sleep = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_SLEEP 1 +_ACEOF + +fi + + +echo "$as_me:$LINENO: checking for stat" >&5 +echo $ECHO_N "checking for stat... $ECHO_C" >&6 +if test "${alut_cv_func_stat+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + #include + #include +int +main () +{ +stat ("", (struct stat*)0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + alut_cv_func_stat=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +alut_cv_func_stat=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $alut_cv_func_stat" >&5 +echo "${ECHO_T}$alut_cv_func_stat" >&6 +if test $alut_cv_func_stat = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STAT 1 +_ACEOF + +fi + + +echo "$as_me:$LINENO: checking for _stat" >&5 +echo $ECHO_N "checking for _stat... $ECHO_C" >&6 +if test "${alut_cv_func__stat+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + #include +int +main () +{ +_stat ("", (struct _stat*)0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + alut_cv_func__stat=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +alut_cv_func__stat=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $alut_cv_func__stat" >&5 +echo "${ECHO_T}$alut_cv_func__stat" >&6 +if test $alut_cv_func__stat = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE__STAT 1 +_ACEOF + +fi + + +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + echo "$as_me:$LINENO: checking for _mwvalidcheckl in -lmw" >&5 +echo $ECHO_N "checking for _mwvalidcheckl in -lmw... $ECHO_C" >&6 +if test "${ac_cv_lib_mw__mwvalidcheckl+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lmw $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _mwvalidcheckl (); +int +main () +{ +_mwvalidcheckl (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_mw__mwvalidcheckl=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_mw__mwvalidcheckl=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_mw__mwvalidcheckl" >&5 +echo "${ECHO_T}$ac_cv_lib_mw__mwvalidcheckl" >&6 +if test $ac_cv_lib_mw__mwvalidcheckl = yes; then + LIBM="-lmw" +fi + + echo "$as_me:$LINENO: checking for cos in -lm" >&5 +echo $ECHO_N "checking for cos in -lm... $ECHO_C" >&6 +if test "${ac_cv_lib_m_cos+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char cos (); +int +main () +{ +cos (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_m_cos=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_m_cos=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_m_cos" >&5 +echo "${ECHO_T}$ac_cv_lib_m_cos" >&6 +if test $ac_cv_lib_m_cos = yes; then + LIBM="$LIBM -lm" +fi + + ;; +*) + echo "$as_me:$LINENO: checking for cos in -lm" >&5 +echo $ECHO_N "checking for cos in -lm... $ECHO_C" >&6 +if test "${ac_cv_lib_m_cos+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char cos (); +int +main () +{ +cos (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_m_cos=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_m_cos=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_m_cos" >&5 +echo "${ECHO_T}$ac_cv_lib_m_cos" >&6 +if test $ac_cv_lib_m_cos = yes; then + LIBM="-lm" +fi + + ;; +esac + + + +################################################################################ +# Build time configuration. +################################################################################ + +# Check whether --enable-warnings or --disable-warnings was given. +if test "${enable_warnings+set}" = set; then + enableval="$enable_warnings" + +fi; + +if test "x$enable_warnings" != xno; then + # Doing it in two steps gives a nicer message... + echo "$as_me:$LINENO: checking flags for maximum ANSI warnings" >&5 +echo $ECHO_N "checking flags for maximum ANSI warnings... $ECHO_C" >&6 +if test "${ac_cv_cflags_warn_all_ansi+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_cflags_warn_all_ansi="no, unknown" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + ac_save_CFLAGS="$CFLAGS" +# IRIX C compiler: +# -use_readonly_const is the default for IRIX C, +# puts them into .rodata, but they are copied later. +# need to be "-G0 -rdatashared" for strictmode but +# I am not sure what effect that has really. - guidod +for ac_arg in "-pedantic % -Wall -ansi -pedantic" "-xstrconst % -v -Xc" "-std1 % -verbose -w0 -warnprotos -std1" " % -qlanglvl=ansi -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" " % -ansi -ansiE -fullwarn" "+ESlit % +w1 -Aa" "-Xc % -pvctl,fullmsg -Xc" "-h conform % -h msglevel 2 -h conform" # +do CFLAGS="$ac_save_CFLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_cflags_warn_all_ansi=`echo $ac_arg | sed -e 's,.*% *,,'` ; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done + CFLAGS="$ac_save_CFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi +echo "$as_me:$LINENO: result: $ac_cv_cflags_warn_all_ansi" >&5 +echo "${ECHO_T}$ac_cv_cflags_warn_all_ansi" >&6 +case ".$ac_cv_cflags_warn_all_ansi" in + .ok|.ok,*) ;; + .|.no|.no,*) + ;; + *) + if echo " $flags " | grep " $ac_cv_cflags_warn_all_ansi " 2>&1 >/dev/null + then { (echo "$as_me:$LINENO: : flags does contain \$ac_cv_cflags_warn_all_ansi") >&5 + (: flags does contain $ac_cv_cflags_warn_all_ansi) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + else { (echo "$as_me:$LINENO: : flags=\"\$flags \$ac_cv_cflags_warn_all_ansi\"") >&5 + (: flags="$flags $ac_cv_cflags_warn_all_ansi") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + flags="$flags $ac_cv_cflags_warn_all_ansi" + fi + ;; +esac + + AM_CFLAGS="$AM_CFLAGS $flags" +fi + +# Check whether --enable-more-warnings or --disable-more-warnings was given. +if test "${enable_more_warnings+set}" = set; then + enableval="$enable_more_warnings" + +fi; + +if test "x$enable_more_warnings" = xyes; then + if test "x$enable_warnings" = xno; then + { echo "$as_me:$LINENO: WARNING: --enable-more-warnings ignored because of --disable-warnings" >&5 +echo "$as_me: WARNING: --enable-more-warnings ignored because of --disable-warnings" >&2;} + elif test "x$GCC" != xyes; then + { echo "$as_me:$LINENO: WARNING: --enable-more-warnings ignored because no GCC was detected" >&5 +echo "$as_me: WARNING: --enable-more-warnings ignored because no GCC was detected" >&2;} + else + # The long list of warning options below contains every GCC warning option + # which is not automatically enabled with -Wall. The only exceptions to this + # rule are: + # + # -Wpadded: + # Perhaps good for optimizing out data layout, but not in general. + # + # -Wconversion: + # Passing e.g. float as an argument is fine, we always have prototypes. + # + # Note that some older GCC versions give false positives about unreachable + # code. + AM_CFLAGS="$AM_CFLAGS -W -Waggregate-return -Wbad-function-cast -Wcast-align -Wcast-qual -Wdisabled-optimization -Wendif-labels -Wfloat-equal -Winline -Wlong-long -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wnested-externs -Wpacked -Wpointer-arith -Wredundant-decls -Wshadow -Wsign-compare -Wstrict-prototypes -Wundef -Wunreachable-code -Wwrite-strings" + + # Check for GCC 4.x-only warning options. + alut_compiler="$CC" +echo "$as_me:$LINENO: checking whether $alut_compiler accepts -Wdeclaration-after-statement" >&5 +echo $ECHO_N "checking whether $alut_compiler accepts -Wdeclaration-after-statement... $ECHO_C" >&6 +if test "${alut_cv_CFLAGS_Wdeclaration_after_statement+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +alut_save_flags="$CFLAGS" +CFLAGS="$CFLAGS -Wdeclaration-after-statement" +alut_cv_CFLAGS_Wdeclaration_after_statement=no +if { (eval $ac_compile conftest.$ac_ext) 2>conftest.er1 + alut_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + (exit $alut_status); } >/dev/null; then + test -s conftest.err || alut_cv_CFLAGS_Wdeclaration_after_statement=yes +fi +CFLAGS="$alut_save_flags" +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $alut_cv_CFLAGS_Wdeclaration_after_statement" >&5 +echo "${ECHO_T}$alut_cv_CFLAGS_Wdeclaration_after_statement" >&6 +if test $alut_cv_CFLAGS_Wdeclaration_after_statement = yes; then + AM_CFLAGS="$AM_CFLAGS -Wdeclaration-after-statement" +fi + + alut_compiler="$CC" +echo "$as_me:$LINENO: checking whether $alut_compiler accepts -Winvalid-pch" >&5 +echo $ECHO_N "checking whether $alut_compiler accepts -Winvalid-pch... $ECHO_C" >&6 +if test "${alut_cv_CFLAGS_Winvalid_pch+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +alut_save_flags="$CFLAGS" +CFLAGS="$CFLAGS -Winvalid-pch" +alut_cv_CFLAGS_Winvalid_pch=no +if { (eval $ac_compile conftest.$ac_ext) 2>conftest.er1 + alut_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + (exit $alut_status); } >/dev/null; then + test -s conftest.err || alut_cv_CFLAGS_Winvalid_pch=yes +fi +CFLAGS="$alut_save_flags" +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $alut_cv_CFLAGS_Winvalid_pch" >&5 +echo "${ECHO_T}$alut_cv_CFLAGS_Winvalid_pch" >&6 +if test $alut_cv_CFLAGS_Winvalid_pch = yes; then + AM_CFLAGS="$AM_CFLAGS -Winvalid-pch" +fi + + alut_compiler="$CC" +echo "$as_me:$LINENO: checking whether $alut_compiler accepts -Wmissing-field-initializers" >&5 +echo $ECHO_N "checking whether $alut_compiler accepts -Wmissing-field-initializers... $ECHO_C" >&6 +if test "${alut_cv_CFLAGS_Wmissing_field_initializers+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +alut_save_flags="$CFLAGS" +CFLAGS="$CFLAGS -Wmissing-field-initializers" +alut_cv_CFLAGS_Wmissing_field_initializers=no +if { (eval $ac_compile conftest.$ac_ext) 2>conftest.er1 + alut_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + (exit $alut_status); } >/dev/null; then + test -s conftest.err || alut_cv_CFLAGS_Wmissing_field_initializers=yes +fi +CFLAGS="$alut_save_flags" +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $alut_cv_CFLAGS_Wmissing_field_initializers" >&5 +echo "${ECHO_T}$alut_cv_CFLAGS_Wmissing_field_initializers" >&6 +if test $alut_cv_CFLAGS_Wmissing_field_initializers = yes; then + AM_CFLAGS="$AM_CFLAGS -Wmissing-field-initializers" +fi + + # We cheat here a bit: The code generated by AC_LANG_PROGRAM triggers a + # warning with -Wold-style-definition, so we assume that this flag is + # supported whenever -Wvariadic-macros is. + alut_compiler="$CC" +echo "$as_me:$LINENO: checking whether $alut_compiler accepts -Wvariadic-macros" >&5 +echo $ECHO_N "checking whether $alut_compiler accepts -Wvariadic-macros... $ECHO_C" >&6 +if test "${alut_cv_CFLAGS_Wvariadic_macros+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +alut_save_flags="$CFLAGS" +CFLAGS="$CFLAGS -Wvariadic-macros" +alut_cv_CFLAGS_Wvariadic_macros=no +if { (eval $ac_compile conftest.$ac_ext) 2>conftest.er1 + alut_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + (exit $alut_status); } >/dev/null; then + test -s conftest.err || alut_cv_CFLAGS_Wvariadic_macros=yes +fi +CFLAGS="$alut_save_flags" +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $alut_cv_CFLAGS_Wvariadic_macros" >&5 +echo "${ECHO_T}$alut_cv_CFLAGS_Wvariadic_macros" >&6 +if test $alut_cv_CFLAGS_Wvariadic_macros = yes; then + AM_CFLAGS="$AM_CFLAGS -Wvariadic-macros -Wold-style-definition" +fi + + fi +fi + +# Check whether --enable-werror or --disable-werror was given. +if test "${enable_werror+set}" = set; then + enableval="$enable_werror" + +fi; + +if test "x$enable_werror" = xyes; then + if test "x$enable_warnings" = xno; then + { echo "$as_me:$LINENO: WARNING: --enable-werror ignored because of --disable-warnings" >&5 +echo "$as_me: WARNING: --enable-werror ignored because of --disable-warnings" >&2;} + elif test "x$GCC" != xyes; then + { echo "$as_me:$LINENO: WARNING: --enable-werror ignored because no GCC was detected" >&5 +echo "$as_me: WARNING: --enable-werror ignored because no GCC was detected" >&2;} + else + AM_CFLAGS="$AM_CFLAGS -Werror" + fi +fi + +# Check whether --enable-efence or --disable-efence was given. +if test "${enable_efence+set}" = set; then + enableval="$enable_efence" + +fi; + +if test "x$enable_efence" = xyes; then + alut_saved_LIBS=$LIBS + LIBS="-lefence $LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +extern int EF_ALIGNMENT; +int +main () +{ +EF_ALIGNMENT = 8; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ echo "$as_me:$LINENO: WARNING: --enable-efence ignored because the Electric Fence library was not found." >&5 +echo "$as_me: WARNING: --enable-efence ignored because the Electric Fence library was not found." >&2;} + LIBS=$alut_saved_LIBS +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +################################################################################ +# Generate output. +################################################################################ + + + +# NOTE: Do not break the following line, otherwise we are into CR/LF vs. LF +# trouble! This is a buglet in autoconf IMHO, but easy to work around. + ac_config_files="$ac_config_files Makefile admin/Makefile admin/pkgconfig/Makefile admin/pkgconfig/freealut-config admin/pkgconfig/freealut.pc admin/RPM/freealut.spec examples/Makefile include/Makefile src/Makefile test_suite/Makefile" + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${WNO_DEPRECATED_DECLARATIONS_TRUE}" && test -z "${WNO_DEPRECATED_DECLARATIONS_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"WNO_DEPRECATED_DECLARATIONS\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"WNO_DEPRECATED_DECLARATIONS\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by freealut library $as_me 1.1.0, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +freealut library config.status 1.1.0 +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS section. +# + +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "admin/Makefile" ) CONFIG_FILES="$CONFIG_FILES admin/Makefile" ;; + "admin/pkgconfig/Makefile" ) CONFIG_FILES="$CONFIG_FILES admin/pkgconfig/Makefile" ;; + "admin/pkgconfig/freealut-config" ) CONFIG_FILES="$CONFIG_FILES admin/pkgconfig/freealut-config" ;; + "admin/pkgconfig/freealut.pc" ) CONFIG_FILES="$CONFIG_FILES admin/pkgconfig/freealut.pc" ;; + "admin/RPM/freealut.spec" ) CONFIG_FILES="$CONFIG_FILES admin/RPM/freealut.spec" ;; + "examples/Makefile" ) CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;; + "include/Makefile" ) CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; + "src/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "test_suite/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_suite/Makefile" ;; + "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@CYGPATH_W@,$CYGPATH_W,;t t +s,@PACKAGE@,$PACKAGE,;t t +s,@VERSION@,$VERSION,;t t +s,@ACLOCAL@,$ACLOCAL,;t t +s,@AUTOCONF@,$AUTOCONF,;t t +s,@AUTOMAKE@,$AUTOMAKE,;t t +s,@AUTOHEADER@,$AUTOHEADER,;t t +s,@MAKEINFO@,$MAKEINFO,;t t +s,@install_sh@,$install_sh,;t t +s,@STRIP@,$STRIP,;t t +s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t +s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t +s,@mkdir_p@,$mkdir_p,;t t +s,@AWK@,$AWK,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@am__leading_dot@,$am__leading_dot,;t t +s,@AMTAR@,$AMTAR,;t t +s,@am__tar@,$am__tar,;t t +s,@am__untar@,$am__untar,;t t +s,@VERSIONINFO@,$VERSIONINFO,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@DEPDIR@,$DEPDIR,;t t +s,@am__include@,$am__include,;t t +s,@am__quote@,$am__quote,;t t +s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t +s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t +s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t +s,@CCDEPMODE@,$CCDEPMODE,;t t +s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t +s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t +s,@WNO_DEPRECATED_DECLARATIONS_TRUE@,$WNO_DEPRECATED_DECLARATIONS_TRUE,;t t +s,@WNO_DEPRECATED_DECLARATIONS_FALSE@,$WNO_DEPRECATED_DECLARATIONS_FALSE,;t t +s,@build@,$build,;t t +s,@build_cpu@,$build_cpu,;t t +s,@build_vendor@,$build_vendor,;t t +s,@build_os@,$build_os,;t t +s,@host@,$host,;t t +s,@host_cpu@,$host_cpu,;t t +s,@host_vendor@,$host_vendor,;t t +s,@host_os@,$host_os,;t t +s,@EGREP@,$EGREP,;t t +s,@LN_S@,$LN_S,;t t +s,@ECHO@,$ECHO,;t t +s,@AR@,$AR,;t t +s,@ac_ct_AR@,$ac_ct_AR,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@DLLTOOL@,$DLLTOOL,;t t +s,@ac_ct_DLLTOOL@,$ac_ct_DLLTOOL,;t t +s,@AS@,$AS,;t t +s,@ac_ct_AS@,$ac_ct_AS,;t t +s,@OBJDUMP@,$OBJDUMP,;t t +s,@ac_ct_OBJDUMP@,$ac_ct_OBJDUMP,;t t +s,@CPP@,$CPP,;t t +s,@CXX@,$CXX,;t t +s,@CXXFLAGS@,$CXXFLAGS,;t t +s,@ac_ct_CXX@,$ac_ct_CXX,;t t +s,@CXXDEPMODE@,$CXXDEPMODE,;t t +s,@am__fastdepCXX_TRUE@,$am__fastdepCXX_TRUE,;t t +s,@am__fastdepCXX_FALSE@,$am__fastdepCXX_FALSE,;t t +s,@CXXCPP@,$CXXCPP,;t t +s,@F77@,$F77,;t t +s,@FFLAGS@,$FFLAGS,;t t +s,@ac_ct_F77@,$ac_ct_F77,;t t +s,@LIBTOOL@,$LIBTOOL,;t t +s,@LIBTOOL_DEPS@,$LIBTOOL_DEPS,;t t +s,@LIBM@,$LIBM,;t t +s,@AM_CFLAGS@,$AM_CFLAGS,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +# Compute $ac_file's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $ac_file | $ac_file:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $ac_file" >`(dirname $ac_file) 2>/dev/null || +$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X$ac_file : 'X\(//\)[^/]' \| \ + X$ac_file : 'X\(//\)$' \| \ + X$ac_file : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X$ac_file | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'`/stamp-h$_am_stamp_count +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_COMMANDS section. +# +for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue + ac_dest=`echo "$ac_file" | sed 's,:.*,,'` + ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_dir=`(dirname "$ac_dest") 2>/dev/null || +$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_dest" : 'X\(//\)[^/]' \| \ + X"$ac_dest" : 'X\(//\)$' \| \ + X"$ac_dest" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_dest" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 +echo "$as_me: executing $ac_dest commands" >&6;} + case $ac_dest in + depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`(dirname "$mf") 2>/dev/null || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`(dirname "$file") 2>/dev/null || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p $dirpart/$fdir + else + as_dir=$dirpart/$fdir + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5 +echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;} + { (exit 1); exit 1; }; }; } + + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + esac +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/tests/freealut/configure.ac b/tests/freealut/configure.ac new file mode 100644 index 0000000000000..2b26d6dcdc70b --- /dev/null +++ b/tests/freealut/configure.ac @@ -0,0 +1,219 @@ +################################################################################ +# Process this file with autoconf to produce a configure script. +################################################################################ + +AC_INIT([freealut library], [1.1.0], [openal-devel@opensource.creative.com], [freealut]) +AC_CONFIG_AUX_DIR([admin/autotools]) +AM_INIT_AUTOMAKE +AC_PREREQ([2.56]) +AC_CONFIG_SRCDIR([AUTHORS]) +AC_CONFIG_HEADERS([config.h]) + +# Compatibility hack for older autoconf versions +m4_ifdef([AS_HELP_STRING], [], [AC_DEFUN([AS_HELP_STRING], [AC_HELP_STRING($][@)])]) + +################################################################################ +## libtool shared library version. +################################################################################ + +# Some information from the libtool info pages and the autobook regarding how to +# handle the library version info: +# +# 1. Start with version information of `0:0:0' for each libtool library. +# +# 2. Update the version information only immediately before a public release of +# your software. More frequent updates are unnecessary, and only guarantee +# that the current interface number gets larger faster. +# +# 3. If the library source code has changed at all since the last update, then +# increment REVISION (`C:R:A' becomes `C:r+1:A'). This is a new revision of +# the current interface. +# +# 4. If any interfaces have been added, removed, or changed since the last +# update, increment CURRENT, and set REVISION to 0. This is the first +# revision of a new interface. +# +# 5. If any interfaces have been added since the last public release, then +# increment AGE. This release is backwards compatible with the previous +# release. +# +# 6. If any interfaces have been removed since the last public release, then set +# AGE to 0. This release has a new, but backwards incompatible interface. +# +# NEVER try to set the interface numbers so that they correspond to the release +# number of your package. This is an abuse that only fosters misunderstanding of +# the purpose of library versions. Furthermore, do not confuse those versions +# with the version of the specification which is implemented. + +CURRENT=1 +REVISION=0 +AGE=1 + +AC_SUBST([VERSIONINFO], ["$CURRENT:$REVISION:$AGE"]) + +################################################################################ +# Checks for programs. +################################################################################ + +AC_PROG_CC +AC_C_CONST +ALUT_C__ATTRIBUTE__ + +# Note that -fvisibility=... support implies __attribute__((visibility(...))) +# support. +ALUT_CHECK_FLAG([-fvisibility=hidden], + [AM_CFLAGS="$AM_CFLAGS -fvisibility=hidden" + AC_DEFINE([HAVE_GCC_VISIBILITY], [1], + [Define to 1 if we are using a GCC with symbol visibility support.])]) + +# test_suite/test_retrostuff tests deprecated functions, but we don't want to +# get compiler warnings because of that. +ALUT_CHECK_FLAG([-Wno-deprecated-declarations], + [alut_wno_deprecated_declarations=yes], + [alut_wno_deprecated_declarations=no]) +AM_CONDITIONAL([WNO_DEPRECATED_DECLARATIONS], + [test x"$alut_wno_deprecated_declarations" = xyes]) + +AC_EXEEXT +AC_LIBTOOL_WIN32_DLL +AC_PROG_LIBTOOL +AC_SUBST([LIBTOOL_DEPS]) + +AC_DEFINE([ALUT_BUILD_LIBRARY], [1], [Define to 1 if you want to build the ALUT DLL.]) + +# Checks for libraries. (not perfect yet) +AC_SEARCH_LIBS([pthread_self], [pthread]) +AC_SEARCH_LIBS([alGetError], [openal32 openal]) + +################################################################################ +# Checks for header files. +################################################################################ + +# We could possibly need struct timespec and random(), which are not ANSI. +AC_DEFINE([_XOPEN_SOURCE], [500], [Define to 500 if Single Unix conformance is wanted, 600 for sixth revision.]) + +# We might need nanosleep, which is a POSIX IEEE Std 1003.1b-1993 feature. +AC_DEFINE([_POSIX_C_SOURCE], [199309], [Define to the POSIX version that should be used.]) + +# Without __NO_CTYPE tolower and friends are macros which introduce a GLIBC 2.3 +# dependency. By defining this identifier we are currently backwards compatible +# to GLIBC 2.1.3, which is a good thing. In addition, the macros lead to code +# which triggers warnings with -Wunreachable-code. +AC_DEFINE([__NO_CTYPE], [1], [Define to 1 if tolower and friends should not be macros.]) + +AC_HEADER_STDC +AC_CHECK_HEADERS([AL/alc.h AL/al.h basetsd.h ctype.h math.h stdio.h time.h windows.h]) + +# Checks for library functions. +ALUT_CHECK_FUNC([[@%:@include ]], + [nanosleep], [[((struct timespec*)0, (struct timespec*)0)]]) + +ALUT_CHECK_FUNC([[@%:@include ]], + [usleep], [[(0)]]) + +ALUT_CHECK_FUNC([[@%:@include ]], + [Sleep], [[(0)]]) + +ALUT_CHECK_FUNC([[@%:@include + @%:@include + @%:@include ]], + [stat], [[("", (struct stat*)0)]]) + +ALUT_CHECK_FUNC([[@%:@include + @%:@include ]], + [_stat], [[("", (struct _stat*)0)]]) + +AC_CHECK_LIBM +AC_SUBST([LIBM]) + +################################################################################ +# Build time configuration. +################################################################################ + +AC_ARG_ENABLE([warnings], +[AS_HELP_STRING([--enable-warnings], + [enable pedantic compiler warnings @<:@default=yes@:>@])]) + +if test "x$enable_warnings" != xno; then + # Doing it in two steps gives a nicer message... + AX_CFLAGS_WARN_ALL_ANSI([flags]) + AM_CFLAGS="$AM_CFLAGS $flags" +fi + +AC_ARG_ENABLE([more-warnings], +[AS_HELP_STRING([--enable-more-warnings], + [enable even more compiler warnings @<:@default=no@:>@])]) + +if test "x$enable_more_warnings" = xyes; then + if test "x$enable_warnings" = xno; then + AC_MSG_WARN([--enable-more-warnings ignored because of --disable-warnings]) + elif test "x$GCC" != xyes; then + AC_MSG_WARN([--enable-more-warnings ignored because no GCC was detected]) + else + # The long list of warning options below contains every GCC warning option + # which is not automatically enabled with -Wall. The only exceptions to this + # rule are: + # + # -Wpadded: + # Perhaps good for optimizing out data layout, but not in general. + # + # -Wconversion: + # Passing e.g. float as an argument is fine, we always have prototypes. + # + # Note that some older GCC versions give false positives about unreachable + # code. + AM_CFLAGS="$AM_CFLAGS -W -Waggregate-return -Wbad-function-cast -Wcast-align -Wcast-qual -Wdisabled-optimization -Wendif-labels -Wfloat-equal -Winline -Wlong-long -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wnested-externs -Wpacked -Wpointer-arith -Wredundant-decls -Wshadow -Wsign-compare -Wstrict-prototypes -Wundef -Wunreachable-code -Wwrite-strings" + + # Check for GCC 4.x-only warning options. + ALUT_CHECK_FLAG([-Wdeclaration-after-statement], + [AM_CFLAGS="$AM_CFLAGS -Wdeclaration-after-statement"]) + ALUT_CHECK_FLAG([-Winvalid-pch], + [AM_CFLAGS="$AM_CFLAGS -Winvalid-pch"]) + ALUT_CHECK_FLAG([-Wmissing-field-initializers], + [AM_CFLAGS="$AM_CFLAGS -Wmissing-field-initializers"]) + # We cheat here a bit: The code generated by AC_LANG_PROGRAM triggers a + # warning with -Wold-style-definition, so we assume that this flag is + # supported whenever -Wvariadic-macros is. + ALUT_CHECK_FLAG([-Wvariadic-macros], + [AM_CFLAGS="$AM_CFLAGS -Wvariadic-macros -Wold-style-definition"]) + fi +fi + +AC_ARG_ENABLE([werror], +[AS_HELP_STRING([--enable-werror], + [enable failure on all warnings @<:@default=no@:>@])]) + +if test "x$enable_werror" = xyes; then + if test "x$enable_warnings" = xno; then + AC_MSG_WARN([--enable-werror ignored because of --disable-warnings]) + elif test "x$GCC" != xyes; then + AC_MSG_WARN([--enable-werror ignored because no GCC was detected]) + else + AM_CFLAGS="$AM_CFLAGS -Werror" + fi +fi + +AC_ARG_ENABLE([efence], +[AS_HELP_STRING([--enable-efence], + [enable Electric Fence support @<:@default=no@:>@])]) + +if test "x$enable_efence" = xyes; then + alut_saved_LIBS=$LIBS + LIBS="-lefence $LIBS" + AC_LINK_IFELSE([AC_LANG_PROGRAM([extern int EF_ALIGNMENT;], [EF_ALIGNMENT = 8;])], + [:], + [AC_MSG_WARN([--enable-efence ignored because the Electric Fence library was not found.]) + LIBS=$alut_saved_LIBS]) +fi + +################################################################################ +# Generate output. +################################################################################ + +AC_SUBST([AM_CFLAGS]) + +# NOTE: Do not break the following line, otherwise we are into CR/LF vs. LF +# trouble! This is a buglet in autoconf IMHO, but easy to work around. +AC_CONFIG_FILES([Makefile admin/Makefile admin/pkgconfig/Makefile admin/pkgconfig/freealut-config admin/pkgconfig/freealut.pc admin/RPM/freealut.spec examples/Makefile include/Makefile src/Makefile test_suite/Makefile]) + +AC_OUTPUT diff --git a/tests/freealut/doc/alut.css b/tests/freealut/doc/alut.css new file mode 100644 index 0000000000000..556d79f9de7ba --- /dev/null +++ b/tests/freealut/doc/alut.css @@ -0,0 +1,45 @@ +body, div { + font-family: sans-serif; + color: black; + background: white +} + +h1, h2, h3, h4, h5, h6, p.title { color: #005A9C } + +/* + * We could use the following to make the headers stand out a little bit more: + * + * h1 { background-color: #b8bec2 } + * h2 { background-color: #cfd5da } + */ + +h3.manpage { background-color: #e6edf2 } + +h1 { font: 170% sans-serif } +h2 { font: 140% sans-serif } +h3 { font: 120% sans-serif } +h4 { font: bold 100% sans-serif } +h5 { font: italic 100% sans-serif } +h6 { font: small-caps 100% sans-serif } + +pre { + font-family: monospace; + border-width: 1px; + border-style: solid; + padding: 0.3em +} + +pre.screen { color: #006400 } +pre.programlisting { color: maroon } + +div.example { + background-color: #fffcf5; + margin: 1ex 0em; + border: solid #412e25 1px; + padding: 0ex 0.4em +} + +a:link { color: #0000C8 } +a:hover { background: #FFFFA8 } +a:active { color: #D00000 } +a:visited { color: #680098 } diff --git a/tests/freealut/doc/alut.html b/tests/freealut/doc/alut.html new file mode 100644 index 0000000000000..2f1fca9d3f7c5 --- /dev/null +++ b/tests/freealut/doc/alut.html @@ -0,0 +1,1399 @@ + + + + + + + The OpenAL Utility Toolkit + + + +

The OpenAL Utility Toolkit (ALUT)

+ +

Contents

+ +
+ +

Release History

+ +

Discussion of the API is done via the openal-devel mailing + list.

+ +
    +
  • 2005-08-14: Version 1.0.0 by Steve Baker
  • +
  • 2005-09-02: Version 1.0.1 by Sven Panne
  • +
  • 2005-09-10: Version 1.0.2 by Sven Panne
  • +
  • 2005-09-26: Version 1.0.3 by Sven Panne
  • +
  • 2005-09-28: Version 1.0.4 by Sven Panne
  • +
  • 2005-10-29: Version 1.0.5 by Sven Panne
  • +
  • 2005-11-19: Version 1.0.6 by Sven Panne
  • +
  • 2006-04-10: Version 1.0.7 by Sven Panne
  • +
  • 2006-04-11: Version 1.1.0 by Sven Panne
  • +
+ +

Introduction

+ +

This is the OpenAL Utility Toolkit + (ALUT) Reference Manual.

+ +

Licensing

+ +

Some previous versions of ALUT were released under the BSD license - + others under LGPL. This version will be released exclusively under LGPL.

+ +

Some History

+ +

At the time of the first writing of this document (August 2005), ALUT was + a set of undocumented semi-portable functions that were mixed up in the + OpenAL library distribution. The intent had always been that ALUT would be a + cleanly separated library that would be portable between systems. It was + hoped that it would be well suited to producing succinct demo programs and + to help new developers to get started with OpenAL. It was to do this by + removing the annoying details of getting an audio application started - + allowing developers to learn OpenAL without distractions such as loading + sound samples from disk.

+ +

In order to move from this initial implementation to a clean API that + would meet the original goals of ALUT, it was necessary to break from the + past and make a clean start. The original version(s) were unnumbered - so we + will arbitarily label all previous versions as 0.x.x and start this cleaned + up version at release 1.0.0 to reflect changed API and implementations.

+ +

Backwards Compatibility with Version 0.x.x

+ +

There are no formal guarantees of reverse compatibility with the various + versions of ALUT prior to 1.0.0. Having said that, some effort has been made + to at least allow these programs to continue to run if they are recompiled + against ALUT 1.0.0 or later.

+ +

The old Linux implementation of OpenAL poses a special compatibility + problem: ALUT 0.x.x was not a physically separate library on this platform, + it was actually part of libopenal itself. This is bad for at least two + reasons: It was handled differently on other platforms and much more + seriously it locked together OpenAL and ALUT releases. So a deliberate + decision was made to break binary compatibility in this respect and cleanly + split the libraries into an OpenAL (i.e. AL and ALC) part and an ALUT + one.

+ +

If you have a program which needs such an old, deprecated "combined + OpenAL/ALUT" and you are not able to recompile it for some reason + (e.g. it is available in binary format only), then temporarily setting the + environment variable LD_PRELOAD to the full path of your installed + ALUT dynamic library can help. If this really works depends on the platform, + but e.g. Linux, FreeBSD, NetBSD, Solaris etc. support this mechanism. On Mac + OS X there is a similar environment variable called + DYLD_INSERT_LIBRARIES, but this has not been tested yet.

+ +
+

Example: Using a legacy program with the new ALUT

+ +

Let's assume that your ALUT dynamic library is at the usual location + /usr/lib/libalut.so and you have an old program called + myOldProg, then the following commandline in Bash syntax does the + trick:

+ +
+LD_PRELOAD="/usr/lib/libalut.so" myOldProg
+
+ +

Note that setting LD_PRELOAD globally might not be a good idea, + because in that case the new ALUT would be loaded before every + dynamically linked executable.

+ +
+ +

OpenGL, GLUT and using what you already know

+ +

If you are already familiar with OpenGL and its utility toolkit GLUT, + then you should feel very familiar with ALUT. Wherever GLUT has 'GL', ALUT + has 'AL' and wherever GLUT has 'glut', ALUT has 'alut'. 'Window' is replaced + with 'Context' throughout the API.

+ +
+

Example: 'Hello, world' in ALUT

+ +

Here is the traditional first program for any language or library, but + this time it is actually saying 'Hello, world!' instead of + printing it:

+ +
+#include <stdlib.h>
+#include <AL/alut.h>
+
+int
+main (int argc, char **argv)
+{
+  ALuint helloBuffer, helloSource;
+  alutInit (&argc, argv);
+  helloBuffer = alutCreateBufferHelloWorld ();
+  alGenSources (1, &helloSource);
+  alSourcei (helloSource, AL_BUFFER, helloBuffer);
+  alSourcePlay (helloSource);
+  alutSleep (1);
+  alutExit ();
+  return EXIT_SUCCESS;
+}
+
+ +

Note that there error checks are missing in the program above to keep + it simple.

+ +
+ +

Compiling and Linking

+ +

All ALUT programs should contain:

+ +
+#include <AL/alut.h>
+
+ +

The ALUT header includes <AL/al.h> and + <AL/alc.h> for you so you don't need to include them again - + although it does not hurt to do so. ALUT reserves the + "ALUT_" prefix for preprocessor macros, so you should + never define such a macro in your own program. Furthermore, you should not + rely on any macro starting with "ALUT_" not mentioned in + this specification.

+ +

If you are using the freealut implementation of ALUT, which is available + via the OpenAL homepage, you can find + out the necessary compilation flags by using one of the following + commands:

+ +
+pkg-config --cflags freealut
+freealut-config --cflags
+
+ +

To find out the necessary flags for linking, use one of the following + commands:

+ +
+pkg-config --libs freealut
+freealut-config --libs
+
+ +

On Windows, link with alut.dll and openal32.dll.

+ +

ALUT reserves the "alut" prefix for globally visible + functions and variables, so you should never define such a function or + variable in your own program. Furthermore, you should not rely on any such + function or variable not mentioned in this specification.

+ +

The ALUT API

+ +

Error Handling

+ +

ALUT's error handling and reporting is a little bit different from the + one used in OpenAL and OpenGL: All functions which can fail report + success/failure via a return value, where AL_FALSE / + AL_NONE / NULL mean failure. alutGetError can be + used to find out what exactly went wrong.

+ +

It is guaranteed that if a function fails, no data pointed to by pointer + arguments has been changed.

+ +

alutGetError

+ +

Name

+ +

alutGetError - return and clear the current error state

+ +

Synopsis

+ +
+ALenum alutGetError (void);
+
+ +

Description

+ +

Any ALUT routine that fails will return AL_FALSE / + AL_NONE / NULL and set the global error state. If a + subsequent error occurs while there is still an error recorded internally, + the second error will simply be ignored. Calling alutGetError will + reset the error code to ALUT_ERROR_NO_ERROR. Note that the error + state is not cleared by other successful ALUT calls.

+ +

Return Value

+ +

alutGetError returns the contents of the global error state, + which can be one of the following values:

+ +
+
ALUT_ERROR_NO_ERROR
+
No ALUT error found.
+ +
ALUT_ERROR_OUT_OF_MEMORY
+
ALUT ran out of memory.
+ +
ALUT_ERROR_INVALID_ENUM
+
ALUT was given an invalid enumeration token.
+ +
ALUT_ERROR_INVALID_VALUE
+
ALUT was given an invalid value.
+ +
ALUT_ERROR_INVALID_OPERATION
+
The operation is invalid in the current ALUT state.
+ +
ALUT_ERROR_NO_CURRENT_CONTEXT
+
There is no current AL context.
+ +
ALUT_ERROR_AL_ERROR_ON_ENTRY
+
There was already an AL error on entry to an ALUT function.
+ +
ALUT_ERROR_ALC_ERROR_ON_ENTRY
+
There was already an ALC error on entry to an ALUT function.
+ +
ALUT_ERROR_OPEN_DEVICE
+
There was an error opening the ALC device.
+ +
ALUT_ERROR_CLOSE_DEVICE
+
There was an error closing the ALC device.
+ +
ALUT_ERROR_CREATE_CONTEXT
+
There was an error creating an ALC context.
+ +
ALUT_ERROR_MAKE_CONTEXT_CURRENT
+
Could not change the current ALC context.
+ +
ALUT_ERROR_DESTROY_CONTEXT
+
There was an error destroying the ALC context.
+ +
ALUT_ERROR_GEN_BUFFERS
+
There was an error generating an AL buffer.
+ +
ALUT_ERROR_BUFFER_DATA
+
There was an error passing buffer data to AL.
+ +
ALUT_ERROR_IO_ERROR
+
I/O error, consult errno for more details.
+ +
ALUT_ERROR_UNSUPPORTED_FILE_TYPE
+
Unsupported file type.
+ +
ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE
+
Unsupported mode within an otherwise usable file type.
+ +
ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA
+
The sound data was corrupt or truncated.
+
+ +

Errors

+ +

alutGetError can be called in any ALUT state and will never + fail.

+ +

alutGetErrorString

+ +

Name

+ +

alutGetErrorString - return an error message string + given an error code

+ +

Synopsis

+ +
+const char *alutGetErrorString (ALenum error);
+
+ +

Description

+ +

alutGetErrorString can be used to convert an error code into a + human-readable description. The precise text of these descriptions may vary + from implementation to implementation and should not be relied upon by the + application.

+ +

Return Value

+ +

alutGetErrorString returns a pointer to an immutable + zero-terminated string corresponding to the given error code.

+ +

Errors

+ +

alutGetErrorString can be called in any ALUT state and + will never fail. An unknown error code is not considered an error + and a generic description will be returned in that case.

+ +
+

Example: Context Handling and Error Reporting

+ +

A typical ALUT program might look like this:

+ +
+static void
+reportError (void)
+{
+  fprintf (stderr, "ALUT error: %s\n",
+           alutGetErrorString (alutGetError ()));
+  exit (EXIT_FAILURE);
+}
+
+int
+main (int argc, char **argv)
+{
+  if (!alutInit (&argc, argv))
+    {
+      reportError ();
+    }
+
+  /* ...play audio for a while... */
+
+  if (!alutExit ())
+    {
+      reportError ();
+    }
+
+  return EXIT_SUCCESS;
+}
+
+
+ +

Initialization / Exit

+ +

ALUT starts in an uninitialized state. alutInit and + alutInitWithoutContext put ALUT into the initialized + state. Those functions must only be called when the state is + uninitialized. alutExit puts ALUT back from an + initialized state to an uninitialized one.

+ +

The following functions must only be called in an initialized + state and with a current context: alutExit, + alutCreateBufferFromFile, alutCreateBufferFromFileImage, + alutLoadMemoryFromFile, alutLoadMemoryFromFileImage, + alutGetMIMETypes, alutCreateBufferHelloWorld, + alutCreateBufferWaveform. All these functions check for AL/ALC + errors on entry and immediately return ALUT_ERROR_AL_ERROR_ON_ENTRY + or ALUT_ERROR_ALC_ERROR_ON_ENTRY if there was one. Note that as a + consequence of these checks the AL/ALC error states for the current + context/device are cleared after calling any of these functions.

+ +

alutSleep can be called in every state.

+ +

The following functions never fail and can be called in any state: + alutGetError, alutGetErrorString, + alutGetMajorVersion, alutGetMinorVersion.

+ +

alutInit

+ +

Name

+ +

alutInit - initialize the ALUT library and create a default + current context

+ +

Synopsis

+ +
+ALboolean alutInit (int *argcp, char **argv);
+
+ +

Description

+ +

alutInit initializes the ALUT internals and creates an OpenAL + context on the default device and makes it the current OpenAL context. If + you want something more complex than that (e.g. running on a non-default + device or opening multiple contexts on multiple devices), you can use alutInitWithoutContext + instead. alutInit examines the commandline arguments passed to it + and remove those it recognizes. It is acceptable to pass two NULL + pointers in settings where no useful information can be obtained from argc + and argv.

+ +

Return Value

+ +

alutInit returns AL_TRUE on success or + AL_FALSE on failure.

+ +

Errors

+ +
+
ALUT_ERROR_INVALID_VALUE
+
One of the arguments was NULL, but not the other one.
+ +
ALUT_ERROR_INVALID_OPERATION
+
ALUT has already been initialized.
+ +
ALUT_ERROR_OPEN_DEVICE
+
There was an error opening the default ALC device.
+ +
ALUT_ERROR_CREATE_CONTEXT
+
There was an error creating an ALC context.
+ +
ALUT_ERROR_MAKE_CONTEXT_CURRENT
+
Could not change the current ALC context.
+
+ +
+

Example: Handling command-line options

+ +

If you pass alutInit the argc and argv from your main program, + it will examine your command-line options and use (and remove) those + options that it recognises:

+ +
+int
+main (int argc, char **argv)
+{
+  alutInit (&argc, argv);
+  ...
+}
+
+ +

Precisely which (if any) command-line options are accepted and what + they control is implementation and operating system dependent. Note that + some implementations will use argv[0] in debug and error messages - but + this is not guaranteed by the API because it is operating-system + dependent. On some OS's, alutInit may use initial settings from + other sources such as 'registry' data, '.alutrc' files or shell + variables. Please consult the README.xxx file for your OS if you need + further details.

+
+ +

alutInitWithoutContext

+ +

Name

+ +

alutInitWithoutContext - initialize the ALUT library

+ +

Synopsis

+ +
+ALboolean alutInitWithoutContext (int *argcp, char **argv);
+
+ +

Description

+ +

alutInitWithoutContext initializes the ALUT internals. It does + not create any OpenAL context or device, so this has to be done via the + usual ALC calls. alutInitWithoutContext examines the commandline + arguments passed to it and remove those it recognizes. It is acceptable to + pass two NULL pointers in settings where no useful information can + be obtained from argc and argv.

+ +

Return Value

+ +

alutInitWithoutContext returns AL_TRUE on success or + AL_FALSE on failure.

+ +

Errors

+ +
+
ALUT_ERROR_INVALID_VALUE
+
One of the arguments was NULL, but not the other one.
+ +
ALUT_ERROR_INVALID_OPERATION
+
ALUT has already been initialized.
+
+ +

alutExit

+ +

Name

+ +

alutExit - shutdown the ALUT library

+ +

Synopsis

+ +
+ALboolean alutExit (void);
+
+ +

Description

+ +

When the application has finished playing audio, it should shut down ALUT + using aluExit. This closes any OpenAL device/context that ALUT may + have created in alutInit (but not any that the application created + using ALC). After calling alutExit, you may subsequently call + alutInit or alutInitWithoutContext again. Note that under + well-behaved operating systems, it should be acceptable to simply exit from + your program without bothering to call alutExit, relying on the OS + to clean up after you. However, it is dangerous to rely on this behavior if + portable operation is expected.

+ +

Return Value

+ +

alutExit returns AL_TRUE on success or + AL_FALSE on failure.

+ +

Errors

+ +
+
ALUT_ERROR_INVALID_OPERATION
+
ALUT has not been initialised.
+ +
ALUT_ERROR_NO_CURRENT_CONTEXT
+
There is no current AL context.
+ +
ALUT_ERROR_AL_ERROR_ON_ENTRY
+
There was already an AL error on entry to alutExit.
+ +
ALUT_ERROR_ALC_ERROR_ON_ENTRY
+
There was already an ALC error on entry to alutExit.
+ +
ALUT_ERROR_CLOSE_DEVICE
+
There was an error closing the ALC device created by + alutInit.
+ +
ALUT_ERROR_MAKE_CONTEXT_CURRENT
+
Could not release the current ALC context.
+ +
ALUT_ERROR_DESTROY_CONTEXT
+
There was an error destroying the ALC context created by + alutInit.
+
+ +

Sound Sample File Loading

+ +

ALUT attempts to simplify the business of getting a simple application + running by providing loaders for a range of file formats. Rather than + enumerate a list of formats that will likely grow with time, the loaders are + generic and try to do their best either by using OpenAL extensions if + possible or by converting the sound data into standard OpenAL formats.

+ +

In order to simplify initial startup and to keep test program + distributions clean, ALUT provides built-in sounds, too, that do not require + disk I/O because they are built into the ALUT library. These functions may + be used to write compact ALUT test/example applications with no external + file dependancies whatsoever. When sending short application programs to + either the ALUT or OpenAL developers as a part of bug reporting, one should + endeavor to use these functions instead of loading ones own sound files.

+ +

There are eight (= 4 * 2) different loaders, corresponding to the sources + and destinations of the sound data. The possible sources are:

+ +
    +
  • The loaders with a FromFile suffix get their sound data from + a named file.
  • + +
  • The loaders with a FromFileImage suffix get their data from a + continuous memory region. This region can be re-used or destroyed + afterwards.
  • + +
  • The loaders with a HelloWorld suffix get their fixed data + internally.
  • + +
  • The loaders with a Waveform suffix get their data via + internal waveform calculation.
  • +
+ +

The possible destinations are:

+ +
    +
  • The loaders with a alutCreateBuffer prefix create a new + OpenAL buffer and put the sound data into it. If possible, OpenAL + extensions are used to avoid conversions at the ALUT level and enable the + use of possible hardware/driveer features for some sound + formats. Therefore, these are the preferred loaders.
  • + +
  • The loaders with a alutLoadMemory prefix allocate a new + memory region with malloc and put the sound data into it, + optionally passing back more information about the sound. The sound data + is guaranteed to be in one of the four standard OpenAL formats (8/16bit + monon/stereo) aftwerwards. Because no OpenAL extensions can be used here, + these loaders might handle fewer sound formats than the + alutCreateBuffer ones.
  • +
+ +

alutCreateBufferFromFile

+ +

Name

+ +

alutCreateBufferFromFile - load a sound file into an OpenAL + buffer

+ +

Synopsis

+ +
+ALuint alutCreateBufferFromFile (const char *filename);
+
+ +

alutCreateBufferFromFile tries to guess the sound data format by + looking at the filename and/or the file contents and loads the sound data + into an OpenAL buffer.

+ +

Return Value

+ +

On success, alutCreateBufferFromFile returns a handle to an + OpenAL buffer containing the loaded sound. It returns AL_NONE on + failure.

+ +

Errors

+ +
+
ALUT_ERROR_OUT_OF_MEMORY
+
ALUT ran out of memory.
+ +
ALUT_ERROR_INVALID_OPERATION
+
ALUT has not been initialised.
+ +
ALUT_ERROR_NO_CURRENT_CONTEXT
+
There is no current AL context.
+ +
ALUT_ERROR_AL_ERROR_ON_ENTRY
+
There was already an AL error on entry to + alutCreateBufferFromFile.
+ +
ALUT_ERROR_ALC_ERROR_ON_ENTRY
+
There was already an ALC error on entry to + alutCreateBufferFromFile.
+ +
ALUT_ERROR_GEN_BUFFERS
+
There was an error generating an AL buffer.
+ +
ALUT_ERROR_BUFFER_DATA
+
There was an error passing buffer data to AL.
+ +
ALUT_ERROR_IO_ERROR
+
I/O error, consult errno for more details.
+ +
ALUT_ERROR_UNSUPPORTED_FILE_TYPE
+
Unsupported file type.
+ +
ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE
+
Unsupported mode within an otherwise usable file type.
+ +
ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA
+
The sound data was corrupt or truncated.
+
+ +

alutCreateBufferFromFileImage

+ +

Name

+ +

alutCreateBufferFromFileImage - load in-memory sound data into + an OpenAL buffer

+ +

Synopsis

+ +
+ALuint alutCreateBufferFromFileImage (const ALvoid *data, ALsizei length);
+
+ +

alutCreateBufferFromFileImage tries to guess the sound data + format by looking at the contents of the memory region given as parameters + and loads the sound data into an OpenAL buffer.

+ +

Return Value

+ +

On success, alutCreateBufferFromFileImage returns a handle to an + OpenAL buffer containing the loaded sound. It returns AL_NONE on + failure.

+ +

Errors

+ +
+
ALUT_ERROR_OUT_OF_MEMORY
+
ALUT ran out of memory.
+ +
ALUT_ERROR_INVALID_OPERATION
+
ALUT has not been initialised.
+ +
ALUT_ERROR_NO_CURRENT_CONTEXT
+
There is no current AL context.
+ +
ALUT_ERROR_AL_ERROR_ON_ENTRY
+
There was already an AL error on entry to + alutCreateBufferFromFileImage.
+ +
ALUT_ERROR_ALC_ERROR_ON_ENTRY
+
There was already an ALC error on entry to + alutCreateBufferFromFileImage.
+ +
ALUT_ERROR_GEN_BUFFERS
+
There was an error generating an AL buffer.
+ +
ALUT_ERROR_BUFFER_DATA
+
There was an error passing buffer data to AL.
+ +
ALUT_ERROR_UNSUPPORTED_FILE_TYPE
+
Unsupported file type.
+ +
ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE
+
Unsupported mode within an otherwise usable file type.
+ +
ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA
+
The sound data was corrupt or truncated.
+
+ +

alutCreateBufferHelloWorld

+ +

Name

+ +

alutCreateBufferHelloWorld - create a buffer with a 'Hello, world!' sound

+ +

Synopsis

+ +
+ALuint alutCreateBufferHelloWorld (void);
+
+ +

Description

+ +

alutCreateBufferHelloWorld returns a handle to an OpenAL buffer + containing the sound of someone saying 'Hello, world!'.

+ +

Return Value

+ +

On success, alutCreateBufferHelloWorld returns a handle to an + OpenAL buffer containing a 'Hello, world!' sound. It returns + AL_NONE on failure.

+ +

Errors

+ +
+
ALUT_ERROR_OUT_OF_MEMORY
+
ALUT ran out of memory.
+ +
ALUT_ERROR_INVALID_OPERATION
+
ALUT has not been initialised.
+ +
ALUT_ERROR_NO_CURRENT_CONTEXT
+
There is no current AL context.
+ +
ALUT_ERROR_AL_ERROR_ON_ENTRY
+
There was already an AL error on entry to + alutCreateBufferHelloWorld.
+ +
ALUT_ERROR_ALC_ERROR_ON_ENTRY
+
There was already an ALC error on entry to + alutCreateBufferHelloWorld.
+ +
ALUT_ERROR_GEN_BUFFERS
+
There was an error generating an AL buffer.
+ +
ALUT_ERROR_BUFFER_DATA
+
There was an error passing buffer data to AL.
+
+ +

alutCreateBufferWaveform

+ +

Name

+ +

alutCreateBufferWaveform - create a buffer with a synthesized waveform sound

+ +

Synopsis

+ +
+ALuint alutCreateBufferWaveform (ALenum waveshape,
+                                 ALfloat frequency,
+                                 ALfloat phase,
+                                 ALfloat duration);
+
+ +

Description

+ +

alutCreateBufferWaveform returns a handle to an OpenAL buffer + containing a snippet of audio with the specified waveshape at the specified + frequency (in Hertz), phase (in degrees: -180 to +180) and duration (in + seconds). Allowed waveforms are:

+ +
    +
  • ALUT_WAVEFORM_SINE
  • +
  • ALUT_WAVEFORM_SQUARE
  • +
  • ALUT_WAVEFORM_SAWTOOTH
  • +
  • ALUT_WAVEFORM_WHITENOISE
  • +
  • ALUT_WAVEFORM_IMPULSE
  • +
+ +

The duration will always be rounded up to an exact number of cycles of + the sound to avoid a click if you loop the sample. The frequency and phase + arguments are ignored for ALUT_WHITENOISE.

+ +

Return Value

+ +

On success, alutCreateBufferWaveform returns a handle to an + OpenAL buffer containing the synthesized waveform. It returns + AL_NONE on failure.

+ +

Errors

+ +
+
ALUT_ERROR_OUT_OF_MEMORY
+
ALUT ran out of memory.
+ +
ALUT_ERROR_INVALID_ENUM
+
An invalid waveform token was given to + alutCreateBufferWaveform.
+ +
ALUT_ERROR_INVALID_VALUE
+
The frequency was not positive or the duration was negative.
+ +
ALUT_ERROR_INVALID_OPERATION
+
ALUT has not been initialised.
+ +
ALUT_ERROR_NO_CURRENT_CONTEXT
+
There is no current AL context.
+ +
ALUT_ERROR_AL_ERROR_ON_ENTRY
+
There was already an AL error on entry to + alutCreateBufferWaveform.
+ +
ALUT_ERROR_ALC_ERROR_ON_ENTRY
+
There was already an ALC error on entry to + alutCreateBufferWaveform.
+ +
ALUT_ERROR_GEN_BUFFERS
+
There was an error generating an AL buffer.
+ +
ALUT_ERROR_BUFFER_DATA
+
There was an error passing buffer data to AL.
+
+ +

alutLoadMemoryFromFile

+ +

Name

+ +

alutLoadMemoryFromFile - load a sound file into OpenAL-like + data

+ +

Synopsis

+ +
+ALvoid *alutLoadMemoryFromFile (const char *filename,
+                                ALenum *format,
+                                ALsizei *size,
+                                ALfloat *frequency);
+
+ +

alutLoadMemoryFromFile tries to guess the sound data format by + looking at the filename and/or the file contents and loads the sound data + into a newly malloced buffer, possibly converting it in the + process. The format is guaranteed to be a standard OpenAL format + afterwards.

+ +

Return Value

+ +

On success, alutLoadMemoryFromFile returns a pointer to a newly + allocated memory area containing the sound data, which can be freed + if not needed anymore. It returns NULL on failure. If any of the + format, size or frequency parameters are non-NULL, the respective + information about the sound will be passed back.

+ +

Errors

+ +
+
ALUT_ERROR_OUT_OF_MEMORY
+
ALUT ran out of memory.
+ +
ALUT_ERROR_INVALID_OPERATION
+
ALUT has not been initialised.
+ +
ALUT_ERROR_NO_CURRENT_CONTEXT
+
There is no current AL context.
+ +
ALUT_ERROR_AL_ERROR_ON_ENTRY
+
There was already an AL error on entry to + alutLoadMemoryFromFile.
+ +
ALUT_ERROR_ALC_ERROR_ON_ENTRY
+
There was already an ALC error on entry to + alutLoadMemoryFromFile.
+ +
ALUT_ERROR_IO_ERROR
+
I/O error, consult errno for more details.
+ +
ALUT_ERROR_UNSUPPORTED_FILE_TYPE
+
Unsupported file type.
+ +
ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE
+
Unsupported mode within an otherwise usable file type.
+ +
ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA
+
The sound data was corrupt or truncated.
+
+ +

alutLoadMemoryFromFileImage

+ +

Name

+ +

alutLoadMemoryFromFileImage - convert in-memory sound data into + OpenAL-like data

+ +

Synopsis

+ +
+ALvoid *alutLoadMemoryFromFileImage (const ALvoid *data,
+                                     ALsizei length,
+                                     ALenum *format,
+                                     ALsizei *size,
+                                     ALfloat *frequency);
+
+ +

alutLoadMemoryFromFileImage tries to guess the sound data format + by looking at the contents of the memory region given as the first two + arguments and loads the sound data into a newly malloced buffer, + possibly converting it in the process. The format is guaranteed to be a + standard OpenAL format afterwards.

+ +

Return Value

+ +

On success, alutLoadMemoryFromFileImage returns a pointer to a + newly allocated memory area containing the sound data, which can be + freed if not needed anymore. It returns NULL on + failure. If any of the format, size or frequency parameters are + non-NULL, the respective information about the sound will be passed + back.

+ +

Errors

+ +
+
ALUT_ERROR_OUT_OF_MEMORY
+
ALUT ran out of memory.
+ +
ALUT_ERROR_INVALID_OPERATION
+
ALUT has not been initialised.
+ +
ALUT_ERROR_NO_CURRENT_CONTEXT
+
There is no current AL context.
+ +
ALUT_ERROR_AL_ERROR_ON_ENTRY
+
There was already an AL error on entry to + alutLoadMemoryFromFileImage.
+ +
ALUT_ERROR_ALC_ERROR_ON_ENTRY
+
There was already an ALC error on entry to + alutLoadMemoryFromFileImage.
+ +
ALUT_ERROR_UNSUPPORTED_FILE_TYPE
+
Unsupported file type.
+ +
ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE
+
Unsupported mode within an otherwise usable file type.
+ +
ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA
+
The sound data was corrupt or truncated.
+
+ +

alutLoadMemoryHelloWorld

+ +

Name

+ +

alutLoadMemoryHelloWorld - load a 'Hello, world!' sound into + OpenAL-like data

+ +

Synopsis

+ +
+ALvoid *alutLoadMemoryHelloWorld (ALenum *format,
+                                  ALsizei *size,
+                                  ALfloat *frequency);
+
+
+ +

Description

+ +

alutLoadMemoryHelloWorld loads the sound of someone saying + 'Hello, world!' into a newly malloced buffer. The sound data is + guaranteed to be in a standard OpenAL format, with a sample frequency chosen + by the ALUT implementation.

+ +

Return Value

+ +

On success, alutLoadMemoryHelloWorld returns a pointer to a + newly allocated memory area containing the sound data, which can be + freed if not needed anymore. It returns NULL on + failure. If any of the format, size or frequency parameters are + non-NULL, the respective information about the sound will be passed + back.

+ +

Errors

+ +
+
ALUT_ERROR_OUT_OF_MEMORY
+
ALUT ran out of memory.
+ +
ALUT_ERROR_INVALID_OPERATION
+
ALUT has not been initialised.
+ +
ALUT_ERROR_NO_CURRENT_CONTEXT
+
There is no current AL context.
+ +
ALUT_ERROR_AL_ERROR_ON_ENTRY
+
There was already an AL error on entry to + alutLoadMemoryHelloWorld.
+ +
ALUT_ERROR_ALC_ERROR_ON_ENTRY
+
There was already an ALC error on entry to + alutLoadMemoryHelloWorld.
+
+ +

alutLoadMemoryWaveform

+ +

Name

+ +

alutLoadMemoryWaveform - load a synthesized waveform sound into + OpenAL-like data

+ +

Synopsis

+ +
+ALvoid *alutLoadMemoryWaveform (ALenum waveshape,
+                                ALfloat frequency,
+                                ALfloat phase,
+                                ALfloat duration,
+                                ALenum *format,
+                                ALsizei *size,
+                                ALfloat *sampleFrequency);
+
+ +

Description

+ +

alutLoadMemoryWaveform loads a snippet of audio with the + specified waveshape at the specified frequency (in Hertz), phase (in + degrees: -180 to +180) and duration (in seconds) into a newly + malloced buffer. The sound data is guaranteed to be in a standard + OpenAL format, with a sample frequency chosen by the ALUT + implementation. Allowed waveforms are:

+ +
    +
  • ALUT_WAVEFORM_SINE
  • +
  • ALUT_WAVEFORM_SQUARE
  • +
  • ALUT_WAVEFORM_SAWTOOTH
  • +
  • ALUT_WAVEFORM_WHITENOISE
  • +
  • ALUT_WAVEFORM_IMPULSE
  • +
+ +

The duration will always be rounded up to an exact number of cycles of + the sound to avoid a click if you loop the sample. The frequency and phase + arguments are ignored for ALUT_WHITENOISE.

+ +

Return Value

+ +

On success, alutLoadMemoryWaveform returns a pointer to a newly + allocated memory area containing the sound data, which can be freed + if not needed anymore. It returns NULL on failure. If any of the + format, size or sample frequency parameters are non-NULL, the + respective information about the sound will be passed back.

+ +

Errors

+ +
+
ALUT_ERROR_OUT_OF_MEMORY
+
ALUT ran out of memory.
+ +
ALUT_ERROR_INVALID_ENUM
+
An invalid waveform token was given to + alutLoadMemoryWaveform.
+ +
ALUT_ERROR_INVALID_VALUE
+
The frequency was not positive or the duration was negative.
+ +
ALUT_ERROR_INVALID_OPERATION
+
ALUT has not been initialised.
+ +
ALUT_ERROR_NO_CURRENT_CONTEXT
+
There is no current AL context.
+ +
ALUT_ERROR_AL_ERROR_ON_ENTRY
+
There was already an AL error on entry to + alutLoadMemoryWaveform.
+ +
ALUT_ERROR_ALC_ERROR_ON_ENTRY
+
There was already an ALC error on entry to + alutLoadMemoryWaveform.
+
+ +

alutGetMIMETypes

+ +

Name

+ +

alutGetMIMETypes - get list support supported audio MIME types

+ +

Synopsis

+ +
+const char *alutGetMIMETypes (ALenum loader);
+
+ +

Description

+ +

alutGetMIMETypes returns a comma-separated list of + supported MIME types for the given loader type, e.g. something like + "audio/basic,audio/mpeg,audio/x-wav". Allowed loader + types are:

+ +
+
ALUT_LOADER_BUFFER
+ +
For the loaders returning sound data in an OpenAL buffer, + e.g. alutCreateBufferFromFile and + alutCreateBufferFromFileImage
+ +
ALUT_LOADER_MEMORY
+ +
For the loaders returning sound data in a newly allocated memory + region, e.g. alutLoadMemoryFromFile and + alutLoadMemoryFromFileImage
+
+ +

It is possible that ALUT_LOADER_MEMORY loaders will be unable to + support some file types that ALUT_LOADER_BUFFER loaders can support + (although the reverse is never the case). Furthermore, it is possible that + for some file types (notably audio/x-wav) the support may be only for a few + sub-formats. For example, an implementation may advertise that audio/x-wav + is supported when in fact it only supports uncompressed (i.e. PCM) WAV files + and not any of the compressed subformats. In this event, the various ALUT + loaders may return an error and set + ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE rather than + ALUT_ERROR_UNSUPPORTED_FILE_TYPE which would indicate that no files + of this type are allowed.

+ +

Return Value

+ +

On success, alutGetMIMETypes returns a zero-terminated string + which contains a comma-separated list of supported MIME types. It returns + NULL on failure.

+ +

Errors

+ +
+
ALUT_ERROR_INVALID_ENUM
+
alutGetMIMETypes was given an invalid loader token.
+ +
ALUT_ERROR_INVALID_OPERATION
+
ALUT has not been initialised.
+ +
ALUT_ERROR_NO_CURRENT_CONTEXT
+
There is no current AL context.
+ +
ALUT_ERROR_AL_ERROR_ON_ENTRY
+
There was already an AL error on entry to + alutGetMIMETypes.
+ +
ALUT_ERROR_ALC_ERROR_ON_ENTRY
+
There was already an ALC error on entry to + alutGetMIMETypes.
+
+ +

Deprecated WAV loaders

+ +

For backwards-compatibility with ALUT 0.x.x, ALUT still offers the three + deprecated functions below. Note that on MacOS 0.x.x version, the + 'loop' parameter is omitted from both loader functions.

+ +
+void alutLoadWAVFile (ALbyte *filename,
+                      ALenum *format,
+                      void **data,
+                      ALsizei *size,
+                      ALsizei *frequency,
+                      ALboolean *loop);
+
+void alutLoadWAVMemory (ALbyte *buffer,
+                        ALenum *format,
+                        void **data,
+                        ALsizei *size,
+                        ALsizei *frequency,
+                        ALboolean *loop);
+
+void alutUnloadWAV (ALenum format ALvoid *data, ALsizei size, ALsizei frequency);
+
+ +

Version Checking

+ +

ALUT version numbers consist of a major version number, a minor version + number, and a patchlevel. The former two numbers will match the major/minor + version number of the corresponding ALUT specification document and can be + accessed at compile time as well as runtime. The patchlevel is not + programmatically available and it is incremented only when fixing bugs + without any API changes.

+ +

alutGetMajorVersion

+ +

Name

+ +

alutGetMajorVersion - return the major ALUT version number

+ +

Synopsis

+ +
+ALint alutGetMajorVersion (void);
+
+ +

Description

+ +

alutGetMajorVersion returns the major version number of the ALUT + in use, which will match the major version number of the corresponding ALUT + specification document.

+ +

Return Value

+ +

alutGetMajorVersion returns the major version number of the ALUT + in use.

+ +

Errors

+ +

alutGetMajorVersion can be called in any ALUT state and will + never fail.

+ +

alutGetMinorVersion

+ +

Name

+ +

alutGetMinorVersion - return the minor ALUT version number

+ +

Synopsis

+ +
+ALint alutGetMinorVersion (void);
+
+ +

Description

+ +

alutGetMinorVersion returns the minor version number of the ALUT + in use, which will match the minor version number of the corresponding ALUT + specification document.

+ +

Return Value

+ +

alutGetMinorVersion returns the minor version number of the ALUT + in use.

+ +

Errors

+ +

alutGetMinorVersion can be called in any ALUT state and will + never fail.

+ +

Compile Time Version Checking

+ +
+#define ALUT_API_MAJOR_VERSION 1
+
+#define ALUT_API_MINOR_VERSION 1
+
+ +

Version 1.0.0 introduced the above preprocessor symbols, whose values + will be incremented appropriately in future revisions of ALUT. In version + 1.1.0, alutLoadMemoryHelloWorld and alutLoadMemoryWaveform + have been added to the ALUT API.

+ +
+

Example: Version consistency check

+ +

Applications can verify at runtime that they have been compiled and + linked with the matching header file and library file as follows:

+ +
+#ifdef ALUT_API_MAJOR_VERSION
+if (alutGetMajorVersion () != ALUT_API_MAJOR_VERSION ||
+    alutGetMinorVersion () != ALUT_API_MINOR_VERSION)
+  /* Oh-oh!  The ALUT header and the ALUT library are different revisions... */
+#else
+  /* Oh-oh!  We're linking against an ALUT 0.x.x header file... */
+#endif
+
+
+ +

Sleeping

+ +

Having a general utility function like the following in an audio-related + toolkit might seem strange at first, but sleeping is a common task in a lot + of audio demos and it can't be done portably without cluttering the source + code with #ifdefs.

+ +

alutSleep

+ +

Name

+ +

alutSleep - sleep for a given number of seconds

+ +

Synopsis

+ +
+ALboolean alutSleep (ALfloat duration);
+
+ +

Description

+ +

alutSleep will delay the execution of the current thread for at + least the given amount of seconds. It will only return earlier if a signal + has been delivered to the thread, but this does not count as an error. Note + that sleeping for zero seconds will give other runnable threads a chance to + run.

+ +

Return Value

+ +

alutSleep returns AL_TRUE on success or + AL_FALSE on failure. Note that current implementations will always + succeed if the duration is non-negative, but this might change in the + future.

+ +

Errors

+ +
+
ALUT_ERROR_INVALID_VALUE
+
alutSleep was given a negative duration.
+
+ + + + diff --git a/tests/freealut/examples/Makefile.am b/tests/freealut/examples/Makefile.am new file mode 100644 index 0000000000000..4c99c50be327b --- /dev/null +++ b/tests/freealut/examples/Makefile.am @@ -0,0 +1,8 @@ +# Build, but do not install the following test programs: +noinst_PROGRAMS = hello_world playfile + +# We need to link against our *own* libalut. +LDADD = ../src/libalut.la + +# Specifying the following path is needed to find . +AM_CPPFLAGS = -I$(top_srcdir)/include diff --git a/tests/freealut/examples/Makefile.in b/tests/freealut/examples/Makefile.in new file mode 100644 index 0000000000000..e7bf9a8aa5c24 --- /dev/null +++ b/tests/freealut/examples/Makefile.in @@ -0,0 +1,451 @@ +# Makefile.in generated by automake 1.9.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = hello_world.c playfile.c + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = hello_world$(EXEEXT) playfile$(EXEEXT) +subdir = examples +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = \ + $(top_srcdir)/admin/autotools/m4/alut_c__attribute.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_cflags_wall.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_flag.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_func.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_eval_stderr.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) +hello_world_SOURCES = hello_world.c +hello_world_OBJECTS = hello_world.$(OBJEXT) +hello_world_LDADD = $(LDADD) +hello_world_DEPENDENCIES = ../src/libalut.la +playfile_SOURCES = playfile.c +playfile_OBJECTS = playfile.$(OBJEXT) +playfile_LDADD = $(LDADD) +playfile_DEPENDENCIES = ../src/libalut.la +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/autotools/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = hello_world.c playfile.c +DIST_SOURCES = hello_world.c playfile.c +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBM = @LIBM@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VERSIONINFO = @VERSIONINFO@ +WNO_DEPRECATED_DECLARATIONS_FALSE = @WNO_DEPRECATED_DECLARATIONS_FALSE@ +WNO_DEPRECATED_DECLARATIONS_TRUE = @WNO_DEPRECATED_DECLARATIONS_TRUE@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_AS = @ac_ct_AS@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ + +# We need to link against our *own* libalut. +LDADD = ../src/libalut.la + +# Specifying the following path is needed to find . +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu examples/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu examples/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +hello_world$(EXEEXT): $(hello_world_OBJECTS) $(hello_world_DEPENDENCIES) + @rm -f hello_world$(EXEEXT) + $(LINK) $(hello_world_LDFLAGS) $(hello_world_OBJECTS) $(hello_world_LDADD) $(LIBS) +playfile$(EXEEXT): $(playfile_OBJECTS) $(playfile_DEPENDENCIES) + @rm -f playfile$(EXEEXT) + $(LINK) $(playfile_LDFLAGS) $(playfile_OBJECTS) $(playfile_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hello_world.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/playfile.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tests/freealut/examples/hello_world.c b/tests/freealut/examples/hello_world.c new file mode 100644 index 0000000000000..ca5b4490716f5 --- /dev/null +++ b/tests/freealut/examples/hello_world.c @@ -0,0 +1,23 @@ +#include +#include + +/* + This is the 'Hello World' program from the ALUT + reference manual. + + Link using '-lalut -lopenal -lpthread'. +*/ + +int main(int argc, char **argv) +{ + ALuint helloBuffer, helloSource; + + alutInit(&argc, argv); + helloBuffer = alutCreateBufferHelloWorld(); + alGenSources(1, &helloSource); + alSourcei(helloSource, AL_BUFFER, helloBuffer); + alSourcePlay(helloSource); + alutSleep(1); + alutExit(); + return EXIT_SUCCESS; +} diff --git a/tests/freealut/examples/playfile.c b/tests/freealut/examples/playfile.c new file mode 100644 index 0000000000000..530222502d6fb --- /dev/null +++ b/tests/freealut/examples/playfile.c @@ -0,0 +1,81 @@ +#include +#include +#include + +#include + +/* + * This program loads and plays a variety of files. + */ + +static void playFile(const char *fileName) +{ + ALuint buffer; + ALuint source; + ALenum error; + ALint status; + + /* Create an AL buffer from the given sound file. */ + buffer = alutCreateBufferFromFile(fileName); + if (buffer == AL_NONE) + { + error = alutGetError(); + fprintf(stderr, "Error loading file: '%s'\n", alutGetErrorString(error)); + alutExit(); + exit(EXIT_FAILURE); + } + + /* Generate a single source, attach the buffer to it and start playing. */ + alGenSources(1, &source); + alSourcei(source, AL_BUFFER, buffer); + alSourcePlay(source); + + /* Normally nothing should go wrong above, but one never knows... */ + error = alGetError(); + if (error != ALUT_ERROR_NO_ERROR) + { + fprintf(stderr, "%s\n", alGetString(error)); + alutExit(); + exit(EXIT_FAILURE); + } + + /* Check every 0.1 seconds if the sound is still playing. */ + do + { + alutSleep(0.1f); + alGetSourcei(source, AL_SOURCE_STATE, &status); + } + while (status == AL_PLAYING); +} + +int main(int argc, char **argv) +{ + /* Initialise ALUT and eat any ALUT-specific commandline flags. */ + if (!alutInit(&argc, argv)) + { + ALenum error = alutGetError(); + + fprintf(stderr, "%s\n", alutGetErrorString(error)); + exit(EXIT_FAILURE); + } + + /* Check for correct usage. */ + if (argc != 2) + { + fprintf(stderr, "usage: playfile \n"); + alutExit(); + exit(EXIT_FAILURE); + } + + /* If everything is OK, play the sound file and exit when finished. */ + playFile(argv[1]); + + if (!alutExit()) + { + ALenum error = alutGetError(); + + fprintf(stderr, "%s\n", alutGetErrorString(error)); + exit(EXIT_FAILURE); + } + return EXIT_SUCCESS; +} diff --git a/tests/freealut/include/AL/alut.h b/tests/freealut/include/AL/alut.h new file mode 100644 index 0000000000000..0f64c8744a0cb --- /dev/null +++ b/tests/freealut/include/AL/alut.h @@ -0,0 +1,133 @@ +#if !defined(AL_ALUT_H) +#define AL_ALUT_H + +#if defined(_MSC_VER) +#include +#include +#elif defined(__APPLE__) +#include +#include +#else +#include +#include +#endif + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#if defined(_WIN32) && !defined(_XBOX) +#if defined (ALUT_BUILD_LIBRARY) +#define ALUT_API __declspec(dllexport) +#else +#define ALUT_API __declspec(dllimport) +#endif +#else +#if defined(ALUT_BUILD_LIBRARY) && defined(HAVE_GCC_VISIBILITY) +#define ALUT_API __attribute__((visibility("default"))) +#else +#define ALUT_API extern +#endif +#endif + +#if defined(_WIN32) +#define ALUT_APIENTRY __cdecl +#else +#define ALUT_APIENTRY +#endif + +#if defined(__MWERKS_) +#pragma export on +#endif + +/* Flag deprecated functions if possible (VisualC++ .NET and GCC >= 3.1.1). */ +#if defined(_MSC_VER) && _MSC_VER >= 1300 && !defined(MIDL_PASS) +#define ALUT_ATTRIBUTE_DEPRECATED __declspec(deprecated) +#elif defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ > 1 || (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ >= 1)))) +#define ALUT_ATTRIBUTE_DEPRECATED __attribute__((deprecated)) +#else +#define ALUT_ATTRIBUTE_DEPRECATED +#endif + +#define ALUT_API_MAJOR_VERSION 1 +#define ALUT_API_MINOR_VERSION 1 + +#define ALUT_ERROR_NO_ERROR 0 +#define ALUT_ERROR_OUT_OF_MEMORY 0x200 +#define ALUT_ERROR_INVALID_ENUM 0x201 +#define ALUT_ERROR_INVALID_VALUE 0x202 +#define ALUT_ERROR_INVALID_OPERATION 0x203 +#define ALUT_ERROR_NO_CURRENT_CONTEXT 0x204 +#define ALUT_ERROR_AL_ERROR_ON_ENTRY 0x205 +#define ALUT_ERROR_ALC_ERROR_ON_ENTRY 0x206 +#define ALUT_ERROR_OPEN_DEVICE 0x207 +#define ALUT_ERROR_CLOSE_DEVICE 0x208 +#define ALUT_ERROR_CREATE_CONTEXT 0x209 +#define ALUT_ERROR_MAKE_CONTEXT_CURRENT 0x20A +#define ALUT_ERROR_DESTROY_CONTEXT 0x20B +#define ALUT_ERROR_GEN_BUFFERS 0x20C +#define ALUT_ERROR_BUFFER_DATA 0x20D +#define ALUT_ERROR_IO_ERROR 0x20E +#define ALUT_ERROR_UNSUPPORTED_FILE_TYPE 0x20F +#define ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE 0x210 +#define ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA 0x211 + +#define ALUT_WAVEFORM_SINE 0x100 +#define ALUT_WAVEFORM_SQUARE 0x101 +#define ALUT_WAVEFORM_SAWTOOTH 0x102 +#define ALUT_WAVEFORM_WHITENOISE 0x103 +#define ALUT_WAVEFORM_IMPULSE 0x104 + +#define ALUT_LOADER_BUFFER 0x300 +#define ALUT_LOADER_MEMORY 0x301 + + ALUT_API ALboolean ALUT_APIENTRY alutInit(int *argcp, char **argv); + ALUT_API ALboolean ALUT_APIENTRY alutInitWithoutContext(int *argcp, char **argv); + ALUT_API ALboolean ALUT_APIENTRY alutExit(void); + + ALUT_API ALenum ALUT_APIENTRY alutGetError(void); + ALUT_API const char *ALUT_APIENTRY alutGetErrorString(ALenum error); + + ALUT_API ALuint ALUT_APIENTRY alutCreateBufferFromFile(const char *fileName); + ALUT_API ALuint ALUT_APIENTRY alutCreateBufferFromFileImage(const ALvoid * data, ALsizei length); + ALUT_API ALuint ALUT_APIENTRY alutCreateBufferHelloWorld(void); + ALUT_API ALuint ALUT_APIENTRY alutCreateBufferWaveform(ALenum waveshape, ALfloat frequency, ALfloat phase, ALfloat duration); + + ALUT_API ALvoid *ALUT_APIENTRY alutLoadMemoryFromFile(const char *fileName, ALenum * format, ALsizei * size, ALfloat * frequency); + ALUT_API ALvoid *ALUT_APIENTRY alutLoadMemoryFromFileImage(const ALvoid * data, ALsizei length, ALenum * format, ALsizei * size, + ALfloat * frequency); + ALUT_API ALvoid *ALUT_APIENTRY alutLoadMemoryHelloWorld(ALenum * format, ALsizei * size, ALfloat * frequency); + ALUT_API ALvoid *ALUT_APIENTRY alutLoadMemoryWaveform(ALenum waveshape, ALfloat frequency, ALfloat phase, ALfloat duration, ALenum * format, + ALsizei * size, ALfloat * freq); + + ALUT_API const char *ALUT_APIENTRY alutGetMIMETypes(ALenum loader); + + ALUT_API ALint ALUT_APIENTRY alutGetMajorVersion(void); + ALUT_API ALint ALUT_APIENTRY alutGetMinorVersion(void); + + ALUT_API ALboolean ALUT_APIENTRY alutSleep(ALfloat duration); + +/* Nasty Compatibility stuff, WARNING: THESE FUNCTIONS ARE STRONGLY DEPRECATED */ +#if defined(__APPLE__) + ALUT_API ALUT_ATTRIBUTE_DEPRECATED void ALUT_APIENTRY alutLoadWAVFile(ALbyte * fileName, ALenum * format, void **data, ALsizei * size, + ALsizei * frequency); + ALUT_API ALUT_ATTRIBUTE_DEPRECATED void ALUT_APIENTRY alutLoadWAVMemory(ALbyte * buffer, ALenum * format, void **data, ALsizei * size, + ALsizei * frequency); +#else + ALUT_API ALUT_ATTRIBUTE_DEPRECATED void ALUT_APIENTRY alutLoadWAVFile(ALbyte * fileName, ALenum * format, void **data, ALsizei * size, + ALsizei * frequency, ALboolean * loop); + ALUT_API ALUT_ATTRIBUTE_DEPRECATED void ALUT_APIENTRY alutLoadWAVMemory(ALbyte * buffer, ALenum * format, void **data, ALsizei * size, + ALsizei * frequency, ALboolean * loop); +#endif + ALUT_API ALUT_ATTRIBUTE_DEPRECATED void ALUT_APIENTRY alutUnloadWAV(ALenum format, ALvoid * data, ALsizei size, ALsizei frequency); + +#if defined(__MWERKS_) +#pragma export off +#endif + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/tests/freealut/include/Makefile.am b/tests/freealut/include/Makefile.am new file mode 100644 index 0000000000000..9423e7b28b78d --- /dev/null +++ b/tests/freealut/include/Makefile.am @@ -0,0 +1 @@ +nobase_include_HEADERS = AL/alut.h diff --git a/tests/freealut/include/Makefile.in b/tests/freealut/include/Makefile.in new file mode 100644 index 0000000000000..3ea4534fc8ee6 --- /dev/null +++ b/tests/freealut/include/Makefile.in @@ -0,0 +1,408 @@ +# Makefile.in generated by automake 1.9.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = include +DIST_COMMON = $(nobase_include_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = \ + $(top_srcdir)/admin/autotools/m4/alut_c__attribute.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_cflags_wall.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_flag.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_func.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_eval_stderr.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(includedir)" +nobase_includeHEADERS_INSTALL = $(install_sh_DATA) +HEADERS = $(nobase_include_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBM = @LIBM@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VERSIONINFO = @VERSIONINFO@ +WNO_DEPRECATED_DECLARATIONS_FALSE = @WNO_DEPRECATED_DECLARATIONS_FALSE@ +WNO_DEPRECATED_DECLARATIONS_TRUE = @WNO_DEPRECATED_DECLARATIONS_TRUE@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_AS = @ac_ct_AS@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +nobase_include_HEADERS = AL/alut.h +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu include/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +install-nobase_includeHEADERS: $(nobase_include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includedir)" || $(mkdir_p) "$(DESTDIR)$(includedir)" + @$(am__vpath_adj_setup) \ + list='$(nobase_include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + $(am__vpath_adj) \ + echo " $(nobase_includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \ + $(nobase_includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \ + done + +uninstall-nobase_includeHEADERS: + @$(NORMAL_UNINSTALL) + @$(am__vpath_adj_setup) \ + list='$(nobase_include_HEADERS)'; for p in $$list; do \ + $(am__vpath_adj) \ + echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \ + rm -f "$(DESTDIR)$(includedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(mkdir_p) $(distdir)/AL + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-nobase_includeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-nobase_includeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-nobase_includeHEADERS \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ + uninstall-nobase_includeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tests/freealut/src/Makefile.am b/tests/freealut/src/Makefile.am new file mode 100644 index 0000000000000..8bd9a2782e6e1 --- /dev/null +++ b/tests/freealut/src/Makefile.am @@ -0,0 +1,32 @@ +# The following files should be in our source distribution in addition to the +# standard ones included by automake itself: +EXTRA_DIST = helloworld.wav README + +# We want to build a libalut library with libtool. +lib_LTLIBRARIES = libalut.la + +# libalut consists of the followin sources and internal headers: +libalut_la_SOURCES = \ + alutBufferData.c \ + alutCodec.c \ + alutError.c \ + alutInit.c \ + alutInputStream.c \ + alutInternal.h \ + alutLoader.c \ + alutOutputStream.c \ + alutUtil.c \ + alutVersion.c \ + alutWaveform.c + +# We use sin and floor, so we might need -lm, autoconf takes care of this. +libalut_la_LIBADD = $(LIBM) + +# The following libtool flag is neccessary for building DLLs on Windows. +libalut_la_LDFLAGS = -no-undefined + +# Append -version-info for correct library versioning with libtool. +libalut_la_LDFLAGS += -version-info @VERSIONINFO@ + +# Specifying the following path is needed to find . +libalut_la_CPPFLAGS = -I$(top_srcdir)/include diff --git a/tests/freealut/src/Makefile.in b/tests/freealut/src/Makefile.in new file mode 100644 index 0000000000000..dc2177fdf4235 --- /dev/null +++ b/tests/freealut/src/Makefile.in @@ -0,0 +1,584 @@ +# Makefile.in generated by automake 1.9.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(libalut_la_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = \ + $(top_srcdir)/admin/autotools/m4/alut_c__attribute.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_cflags_wall.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_flag.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_func.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_eval_stderr.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libalut_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_libalut_la_OBJECTS = libalut_la-alutBufferData.lo \ + libalut_la-alutCodec.lo libalut_la-alutError.lo \ + libalut_la-alutInit.lo libalut_la-alutInputStream.lo \ + libalut_la-alutLoader.lo libalut_la-alutOutputStream.lo \ + libalut_la-alutUtil.lo libalut_la-alutVersion.lo \ + libalut_la-alutWaveform.lo +libalut_la_OBJECTS = $(am_libalut_la_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/autotools/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libalut_la_SOURCES) +DIST_SOURCES = $(libalut_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBM = @LIBM@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VERSIONINFO = @VERSIONINFO@ +WNO_DEPRECATED_DECLARATIONS_FALSE = @WNO_DEPRECATED_DECLARATIONS_FALSE@ +WNO_DEPRECATED_DECLARATIONS_TRUE = @WNO_DEPRECATED_DECLARATIONS_TRUE@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_AS = @ac_ct_AS@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ + +# The following files should be in our source distribution in addition to the +# standard ones included by automake itself: +EXTRA_DIST = helloworld.wav README + +# We want to build a libalut library with libtool. +lib_LTLIBRARIES = libalut.la + +# libalut consists of the followin sources and internal headers: +libalut_la_SOURCES = \ + alutBufferData.c \ + alutCodec.c \ + alutError.c \ + alutInit.c \ + alutInputStream.c \ + alutInternal.h \ + alutLoader.c \ + alutOutputStream.c \ + alutUtil.c \ + alutVersion.c \ + alutWaveform.c + + +# We use sin and floor, so we might need -lm, autoconf takes care of this. +libalut_la_LIBADD = $(LIBM) + +# The following libtool flag is neccessary for building DLLs on Windows. + +# Append -version-info for correct library versioning with libtool. +libalut_la_LDFLAGS = -no-undefined -version-info @VERSIONINFO@ + +# Specifying the following path is needed to find . +libalut_la_CPPFLAGS = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libalut.la: $(libalut_la_OBJECTS) $(libalut_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libalut_la_LDFLAGS) $(libalut_la_OBJECTS) $(libalut_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalut_la-alutBufferData.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalut_la-alutCodec.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalut_la-alutError.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalut_la-alutInit.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalut_la-alutInputStream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalut_la-alutLoader.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalut_la-alutOutputStream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalut_la-alutUtil.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalut_la-alutVersion.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalut_la-alutWaveform.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libalut_la-alutBufferData.lo: alutBufferData.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libalut_la-alutBufferData.lo -MD -MP -MF "$(DEPDIR)/libalut_la-alutBufferData.Tpo" -c -o libalut_la-alutBufferData.lo `test -f 'alutBufferData.c' || echo '$(srcdir)/'`alutBufferData.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libalut_la-alutBufferData.Tpo" "$(DEPDIR)/libalut_la-alutBufferData.Plo"; else rm -f "$(DEPDIR)/libalut_la-alutBufferData.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alutBufferData.c' object='libalut_la-alutBufferData.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libalut_la-alutBufferData.lo `test -f 'alutBufferData.c' || echo '$(srcdir)/'`alutBufferData.c + +libalut_la-alutCodec.lo: alutCodec.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libalut_la-alutCodec.lo -MD -MP -MF "$(DEPDIR)/libalut_la-alutCodec.Tpo" -c -o libalut_la-alutCodec.lo `test -f 'alutCodec.c' || echo '$(srcdir)/'`alutCodec.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libalut_la-alutCodec.Tpo" "$(DEPDIR)/libalut_la-alutCodec.Plo"; else rm -f "$(DEPDIR)/libalut_la-alutCodec.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alutCodec.c' object='libalut_la-alutCodec.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libalut_la-alutCodec.lo `test -f 'alutCodec.c' || echo '$(srcdir)/'`alutCodec.c + +libalut_la-alutError.lo: alutError.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libalut_la-alutError.lo -MD -MP -MF "$(DEPDIR)/libalut_la-alutError.Tpo" -c -o libalut_la-alutError.lo `test -f 'alutError.c' || echo '$(srcdir)/'`alutError.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libalut_la-alutError.Tpo" "$(DEPDIR)/libalut_la-alutError.Plo"; else rm -f "$(DEPDIR)/libalut_la-alutError.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alutError.c' object='libalut_la-alutError.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libalut_la-alutError.lo `test -f 'alutError.c' || echo '$(srcdir)/'`alutError.c + +libalut_la-alutInit.lo: alutInit.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libalut_la-alutInit.lo -MD -MP -MF "$(DEPDIR)/libalut_la-alutInit.Tpo" -c -o libalut_la-alutInit.lo `test -f 'alutInit.c' || echo '$(srcdir)/'`alutInit.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libalut_la-alutInit.Tpo" "$(DEPDIR)/libalut_la-alutInit.Plo"; else rm -f "$(DEPDIR)/libalut_la-alutInit.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alutInit.c' object='libalut_la-alutInit.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libalut_la-alutInit.lo `test -f 'alutInit.c' || echo '$(srcdir)/'`alutInit.c + +libalut_la-alutInputStream.lo: alutInputStream.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libalut_la-alutInputStream.lo -MD -MP -MF "$(DEPDIR)/libalut_la-alutInputStream.Tpo" -c -o libalut_la-alutInputStream.lo `test -f 'alutInputStream.c' || echo '$(srcdir)/'`alutInputStream.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libalut_la-alutInputStream.Tpo" "$(DEPDIR)/libalut_la-alutInputStream.Plo"; else rm -f "$(DEPDIR)/libalut_la-alutInputStream.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alutInputStream.c' object='libalut_la-alutInputStream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libalut_la-alutInputStream.lo `test -f 'alutInputStream.c' || echo '$(srcdir)/'`alutInputStream.c + +libalut_la-alutLoader.lo: alutLoader.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libalut_la-alutLoader.lo -MD -MP -MF "$(DEPDIR)/libalut_la-alutLoader.Tpo" -c -o libalut_la-alutLoader.lo `test -f 'alutLoader.c' || echo '$(srcdir)/'`alutLoader.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libalut_la-alutLoader.Tpo" "$(DEPDIR)/libalut_la-alutLoader.Plo"; else rm -f "$(DEPDIR)/libalut_la-alutLoader.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alutLoader.c' object='libalut_la-alutLoader.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libalut_la-alutLoader.lo `test -f 'alutLoader.c' || echo '$(srcdir)/'`alutLoader.c + +libalut_la-alutOutputStream.lo: alutOutputStream.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libalut_la-alutOutputStream.lo -MD -MP -MF "$(DEPDIR)/libalut_la-alutOutputStream.Tpo" -c -o libalut_la-alutOutputStream.lo `test -f 'alutOutputStream.c' || echo '$(srcdir)/'`alutOutputStream.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libalut_la-alutOutputStream.Tpo" "$(DEPDIR)/libalut_la-alutOutputStream.Plo"; else rm -f "$(DEPDIR)/libalut_la-alutOutputStream.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alutOutputStream.c' object='libalut_la-alutOutputStream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libalut_la-alutOutputStream.lo `test -f 'alutOutputStream.c' || echo '$(srcdir)/'`alutOutputStream.c + +libalut_la-alutUtil.lo: alutUtil.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libalut_la-alutUtil.lo -MD -MP -MF "$(DEPDIR)/libalut_la-alutUtil.Tpo" -c -o libalut_la-alutUtil.lo `test -f 'alutUtil.c' || echo '$(srcdir)/'`alutUtil.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libalut_la-alutUtil.Tpo" "$(DEPDIR)/libalut_la-alutUtil.Plo"; else rm -f "$(DEPDIR)/libalut_la-alutUtil.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alutUtil.c' object='libalut_la-alutUtil.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libalut_la-alutUtil.lo `test -f 'alutUtil.c' || echo '$(srcdir)/'`alutUtil.c + +libalut_la-alutVersion.lo: alutVersion.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libalut_la-alutVersion.lo -MD -MP -MF "$(DEPDIR)/libalut_la-alutVersion.Tpo" -c -o libalut_la-alutVersion.lo `test -f 'alutVersion.c' || echo '$(srcdir)/'`alutVersion.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libalut_la-alutVersion.Tpo" "$(DEPDIR)/libalut_la-alutVersion.Plo"; else rm -f "$(DEPDIR)/libalut_la-alutVersion.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alutVersion.c' object='libalut_la-alutVersion.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libalut_la-alutVersion.lo `test -f 'alutVersion.c' || echo '$(srcdir)/'`alutVersion.c + +libalut_la-alutWaveform.lo: alutWaveform.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libalut_la-alutWaveform.lo -MD -MP -MF "$(DEPDIR)/libalut_la-alutWaveform.Tpo" -c -o libalut_la-alutWaveform.lo `test -f 'alutWaveform.c' || echo '$(srcdir)/'`alutWaveform.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libalut_la-alutWaveform.Tpo" "$(DEPDIR)/libalut_la-alutWaveform.Plo"; else rm -f "$(DEPDIR)/libalut_la-alutWaveform.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alutWaveform.c' object='libalut_la-alutWaveform.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalut_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libalut_la-alutWaveform.lo `test -f 'alutWaveform.c' || echo '$(srcdir)/'`alutWaveform.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-libLTLIBRARIES + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ + uninstall-libLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tests/freealut/src/README b/tests/freealut/src/README new file mode 100644 index 0000000000000..4aae3ac10ec4e --- /dev/null +++ b/tests/freealut/src/README @@ -0,0 +1,13 @@ +The files in this directory contain the code of the ALUT library. They typically +compile to make 'libalut.so' on *nix platforms or to 'alut.dll' for Windows +platforms. + +There is also a header file 'alut.h' in ../include/AL which gets installed into +$(includedir)/AL/alut.h on *nix platforms and someplace else entirely on +Windows platforms. + +The file 'helloworld.wav' is the original voice recording of Steve Baker saying +this immortal phrase. It is converted into a large hexadecimal data block inside +alutWaveform.c - but this file is retained in version control just in case +anyone ever feels like re-doing it. The format is 16bit PCM, 1 channel, 44.1kHz +sample rate. diff --git a/tests/freealut/src/alutBufferData.c b/tests/freealut/src/alutBufferData.c new file mode 100644 index 0000000000000..c7ad94793ee18 --- /dev/null +++ b/tests/freealut/src/alutBufferData.c @@ -0,0 +1,136 @@ +#include "alutInternal.h" + +struct BufferData_struct +{ + ALvoid *data; + size_t length; + ALint numChannels; + ALint bitsPerSample; + ALfloat sampleFrequency; +}; + +BufferData *_alutBufferDataConstruct(ALvoid * data, size_t length, ALint numChannels, ALint bitsPerSample, ALfloat sampleFrequency) +{ + BufferData *bufferData = (BufferData *) _alutMalloc(sizeof(BufferData)); + + if (bufferData == NULL) + { + return NULL; + } + + bufferData->data = data; + bufferData->length = length; + bufferData->numChannels = numChannels; + bufferData->bitsPerSample = bitsPerSample; + bufferData->sampleFrequency = sampleFrequency; + + return bufferData; +} + +ALboolean _alutBufferDataDestroy(BufferData * bufferData) +{ + if (bufferData->data != NULL) + { + free(bufferData->data); + } + free(bufferData); + return AL_TRUE; +} + +ALvoid *_alutBufferDataGetData(const BufferData * bufferData) +{ + return bufferData->data; +} + +void _alutBufferDataDetachData(BufferData * bufferData) +{ + bufferData->data = NULL; +} + +size_t _alutBufferDataGetLength(const BufferData * bufferData) +{ + return bufferData->length; +} + +static ALint getNumChannels(const BufferData * bufferData) +{ + return bufferData->numChannels; +} + +static ALint getBitsPerSample(const BufferData * bufferData) +{ + return bufferData->bitsPerSample; +} + +ALfloat _alutBufferDataGetSampleFrequency(const BufferData * bufferData) +{ + return bufferData->sampleFrequency; +} + +/**************************************************************************** + * The utility functions below do not know the internal BufferData + * representation. + ****************************************************************************/ + +ALboolean _alutGetFormat(const BufferData * bufferData, ALenum * format) +{ + if (!_alutFormatConstruct(getNumChannels(bufferData), getBitsPerSample(bufferData), format)) + { + _alutSetError(ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE); + return AL_FALSE; + } + return AL_TRUE; +} + +static ALuint generateBuffer(void) +{ + ALuint buffer; + + alGenBuffers(1, &buffer); + if (alGetError() != AL_NO_ERROR) + { + _alutSetError(ALUT_ERROR_GEN_BUFFERS); + return AL_NONE; + } + return buffer; +} + +static ALboolean passBufferData(BufferData * bufferData, ALuint bid) +{ + ALenum format; + size_t size; + ALfloat frequency; + + if (!_alutGetFormat(bufferData, &format)) + { + return AL_FALSE; + } + /* GCC is a bit picky about casting function calls, so we do it in two + * steps... */ + size = _alutBufferDataGetLength(bufferData); + frequency = _alutBufferDataGetSampleFrequency(bufferData); + alBufferData(bid, format, _alutBufferDataGetData(bufferData), (ALsizei) size, (ALsizei) frequency); + if (alGetError() != AL_NO_ERROR) + { + _alutSetError(ALUT_ERROR_BUFFER_DATA); + return AL_FALSE; + } + return AL_TRUE; +} + +ALuint _alutPassBufferData(BufferData * bufferData) +{ + ALuint buffer = generateBuffer(); + + if (buffer == AL_NONE) + { + return AL_NONE; + } + + if (!passBufferData(bufferData, buffer)) + { + return AL_NONE; + } + + return buffer; +} diff --git a/tests/freealut/src/alutCodec.c b/tests/freealut/src/alutCodec.c new file mode 100644 index 0000000000000..908c7e32595cf --- /dev/null +++ b/tests/freealut/src/alutCodec.c @@ -0,0 +1,119 @@ +#include "alutInternal.h" + +ALvoid *_alutCodecLinear(ALvoid * data, size_t length, ALint numChannels, ALint bitsPerSample, ALfloat sampleFrequency) +{ + return _alutBufferDataConstruct(data, length, numChannels, bitsPerSample, sampleFrequency); +} + +ALvoid *_alutCodecPCM8s(ALvoid * data, size_t length, ALint numChannels, ALint bitsPerSample, ALfloat sampleFrequency) +{ + int8_t *d = (int8_t *) data; + size_t i; + + for (i = 0; i < length; i++) + { + d[i] += (int8_t) 128; + } + return _alutBufferDataConstruct(data, length, numChannels, bitsPerSample, sampleFrequency); +} + +ALvoid *_alutCodecPCM16(ALvoid * data, size_t length, ALint numChannels, ALint bitsPerSample, ALfloat sampleFrequency) +{ + int16_t *d = (int16_t *) data; + size_t i, l = length / 2; + + for (i = 0; i < l; i++) + { + int16_t x = d[i]; + + d[i] = ((x << 8) & 0xFF00) | ((x >> 8) & 0x00FF); + } + return _alutBufferDataConstruct(data, length, numChannels, bitsPerSample, sampleFrequency); +} + +/* + * From: http://www.multimedia.cx/simpleaudio.html#tth_sEc6.1 + */ +static int16_t mulaw2linear(uint8_t mulawbyte) +{ + static const int16_t exp_lut[8] = { + 0, 132, 396, 924, 1980, 4092, 8316, 16764 + }; + int16_t sign, exponent, mantissa, sample; + + mulawbyte = ~mulawbyte; + sign = (mulawbyte & 0x80); + exponent = (mulawbyte >> 4) & 0x07; + mantissa = mulawbyte & 0x0F; + sample = exp_lut[exponent] + (mantissa << (exponent + 3)); + if (sign != 0) + { + sample = -sample; + } + return sample; +} + +ALvoid *_alutCodecULaw(ALvoid * data, size_t length, ALint numChannels, ALint bitsPerSample, ALfloat sampleFrequency) +{ + uint8_t *d = (uint8_t *) data; + int16_t *buf = (int16_t *) _alutMalloc(length * 2); + size_t i; + + if (buf == NULL) + { + return NULL; + } + for (i = 0; i < length; i++) + { + buf[i] = mulaw2linear(d[i]); + } + free(data); + return _alutBufferDataConstruct(buf, length * 2, numChannels, bitsPerSample, sampleFrequency); +} + +/* + * From: http://www.multimedia.cx/simpleaudio.html#tth_sEc6.1 + */ +#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ +#define QUANT_MASK (0xf) /* Quantization field mask. */ +#define SEG_SHIFT (4) /* Left shift for segment number. */ +#define SEG_MASK (0x70) /* Segment field mask. */ +static int16_t alaw2linear(uint8_t a_val) +{ + int16_t t, seg; + + a_val ^= 0x55; + t = (a_val & QUANT_MASK) << 4; + seg = ((int16_t) a_val & SEG_MASK) >> SEG_SHIFT; + switch (seg) + { + case 0: + t += 8; + break; + case 1: + t += 0x108; + break; + default: + t += 0x108; + t <<= seg - 1; + } + return (a_val & SIGN_BIT) ? t : -t; +} + +ALvoid *_alutCodecALaw(ALvoid * data, size_t length, ALint numChannels, ALint bitsPerSample, ALfloat sampleFrequency) +{ + uint8_t *d = (uint8_t *) data; + int16_t *buf = (int16_t *) _alutMalloc(length * 2); + size_t i; + + if (buf == NULL) + { + return NULL; + } + for (i = 0; i < length; i++) + { + buf[i] = alaw2linear(d[i]); + } + free(data); + return _alutBufferDataConstruct(buf, length * 2, numChannels, bitsPerSample, sampleFrequency); +} diff --git a/tests/freealut/src/alutError.c b/tests/freealut/src/alutError.c new file mode 100644 index 0000000000000..57e2957520006 --- /dev/null +++ b/tests/freealut/src/alutError.c @@ -0,0 +1,92 @@ +#include "alutInternal.h" +#include + +static ALenum lastError = ALUT_ERROR_NO_ERROR; + +void _alutSetError(ALenum err) +{ + /* print a message to stderr if ALUT_DEBUG environment variable is defined */ + if (getenv("ALUT_DEBUG")) + { + fprintf(stderr, "ALUT error: %s\n", alutGetErrorString(err)); + } + + if (lastError == ALUT_ERROR_NO_ERROR) + { + lastError = err; + } +} + +ALenum alutGetError(void) +{ + ALint ret = lastError; + + lastError = ALUT_ERROR_NO_ERROR; + return ret; +} + +const char *alutGetErrorString(ALenum error) +{ + switch (error) + { + case ALUT_ERROR_NO_ERROR: + return "No ALUT error found"; + + case ALUT_ERROR_OUT_OF_MEMORY: + return "ALUT ran out of memory"; + + case ALUT_ERROR_INVALID_ENUM: + return "ALUT was given an invalid enumeration token"; + + case ALUT_ERROR_INVALID_VALUE: + return "ALUT was given an invalid value"; + + case ALUT_ERROR_INVALID_OPERATION: + return "The operation was invalid in the current ALUT state"; + + case ALUT_ERROR_NO_CURRENT_CONTEXT: + return "There is no current AL context"; + + case ALUT_ERROR_AL_ERROR_ON_ENTRY: + return "There was already an AL error on entry to an ALUT function"; + + case ALUT_ERROR_ALC_ERROR_ON_ENTRY: + return "There was already an ALC error on entry to an ALUT function"; + + case ALUT_ERROR_OPEN_DEVICE: + return "There was an error opening the ALC device"; + + case ALUT_ERROR_CLOSE_DEVICE: + return "There was an error closing the ALC device"; + + case ALUT_ERROR_CREATE_CONTEXT: + return "There was an error creating an ALC context"; + + case ALUT_ERROR_MAKE_CONTEXT_CURRENT: + return "Could not change the current ALC context"; + + case ALUT_ERROR_DESTROY_CONTEXT: + return "There was an error destroying the ALC context"; + + case ALUT_ERROR_GEN_BUFFERS: + return "There was an error generating an AL buffer"; + + case ALUT_ERROR_BUFFER_DATA: + return "There was an error passing buffer data to AL"; + + case ALUT_ERROR_IO_ERROR: + return "I/O error"; + + case ALUT_ERROR_UNSUPPORTED_FILE_TYPE: + return "Unsupported file type"; + + case ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE: + return "Unsupported mode within an otherwise usable file type"; + + case ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA: + return "The sound data was corrupt or truncated"; + + default: + return "An impossible ALUT error condition was reported?!?"; + } +} diff --git a/tests/freealut/src/alutInit.c b/tests/freealut/src/alutInit.c new file mode 100644 index 0000000000000..32080c8b93f3f --- /dev/null +++ b/tests/freealut/src/alutInit.c @@ -0,0 +1,154 @@ +#include "alutInternal.h" + +static enum +{ + Unintialized, /* ALUT has not been initialized yet or has been de-initialised */ + ALUTDeviceAndContext, /* alutInit has been called successfully */ + ExternalDeviceAndContext /* alutInitWithoutContext has been called */ +} initialisationState = Unintialized; + +/* + * Note: alutContext contains something valid only when initialisationState + * contains ALUTDeviceAndContext. + */ +static ALCcontext *alutContext; + +ALboolean _alutSanityCheck(void) +{ + ALCcontext *context; + + if (initialisationState == Unintialized) + { + _alutSetError(ALUT_ERROR_INVALID_OPERATION); + return AL_FALSE; + } + + context = alcGetCurrentContext(); + if (context == NULL) + { + _alutSetError(ALUT_ERROR_NO_CURRENT_CONTEXT); + return AL_FALSE; + } + + if (alGetError() != AL_NO_ERROR) + { + _alutSetError(ALUT_ERROR_AL_ERROR_ON_ENTRY); + return AL_FALSE; + } + + if (alcGetError(alcGetContextsDevice(context)) != ALC_NO_ERROR) + { + _alutSetError(ALUT_ERROR_ALC_ERROR_ON_ENTRY); + return AL_FALSE; + } + + return AL_TRUE; +} + +ALboolean alutInit(int *argcp, char **argv) +{ + ALCdevice *device; + ALCcontext *context; + + if (initialisationState != Unintialized) + { + _alutSetError(ALUT_ERROR_INVALID_OPERATION); + return AL_FALSE; + } + + if ((argcp == NULL) != (argv == NULL)) + { + _alutSetError(ALUT_ERROR_INVALID_VALUE); + return AL_FALSE; + } + + device = alcOpenDevice(NULL); + if (device == NULL) + { + _alutSetError(ALUT_ERROR_OPEN_DEVICE); + return AL_FALSE; + } + + context = alcCreateContext(device, NULL); + if (context == NULL) + { + alcCloseDevice(device); + _alutSetError(ALUT_ERROR_CREATE_CONTEXT); + return AL_FALSE; + } + + if (!alcMakeContextCurrent(context)) + { + alcDestroyContext(context); + alcCloseDevice(device); + _alutSetError(ALUT_ERROR_MAKE_CONTEXT_CURRENT); + return AL_FALSE; + } + + initialisationState = ALUTDeviceAndContext; + alutContext = context; + return AL_TRUE; +} + +ALboolean alutInitWithoutContext(int *argcp, char **argv) +{ + if (initialisationState != Unintialized) + { + _alutSetError(ALUT_ERROR_INVALID_OPERATION); + return AL_FALSE; + } + + if ((argcp == NULL) != (argv == NULL)) + { + _alutSetError(ALUT_ERROR_INVALID_VALUE); + return AL_FALSE; + } + + initialisationState = ExternalDeviceAndContext; + return AL_TRUE; +} + +ALboolean alutExit(void) +{ + ALCdevice *device; + + if (initialisationState == Unintialized) + { + _alutSetError(ALUT_ERROR_INVALID_OPERATION); + return AL_FALSE; + } + + if (initialisationState == ExternalDeviceAndContext) + { + initialisationState = Unintialized; + return AL_TRUE; + } + + if (!_alutSanityCheck()) + { + return AL_FALSE; + } + + if (!alcMakeContextCurrent(NULL)) + { + _alutSetError(ALUT_ERROR_MAKE_CONTEXT_CURRENT); + return AL_FALSE; + } + + device = alcGetContextsDevice(alutContext); + alcDestroyContext(alutContext); + if (alcGetError(device) != ALC_NO_ERROR) + { + _alutSetError(ALUT_ERROR_DESTROY_CONTEXT); + return AL_FALSE; + } + + if (!alcCloseDevice(device)) + { + _alutSetError(ALUT_ERROR_CLOSE_DEVICE); + return AL_FALSE; + } + + initialisationState = Unintialized; + return AL_TRUE; +} diff --git a/tests/freealut/src/alutInputStream.c b/tests/freealut/src/alutInputStream.c new file mode 100644 index 0000000000000..9ddcb0590b102 --- /dev/null +++ b/tests/freealut/src/alutInputStream.c @@ -0,0 +1,236 @@ +#include "alutInternal.h" +#include +#include +#include +#include + +#if HAVE_STAT +#if HAVE_UNISTD_H +#include +#endif +#define structStat struct stat +#elif HAVE__STAT +#define stat(p,b) _stat((p),(b)) +#define structStat struct _stat +#else +#error No stat-like function on this platform +#endif + +struct InputStream_struct +{ + ALboolean isFileStream; + char *fileName; + size_t remainingLength; + union + { + FILE *fileDescriptor; /* for file streams */ + const ALvoid *data; /* for memory streams */ + } u; +}; + +/**************************************************************************** + * The functions below know the internal InputStream representation. + ****************************************************************************/ + +InputStream *_alutInputStreamConstructFromFile(const char *fileName) +{ + InputStream *stream; + structStat statBuf; + FILE *fileDescriptor; + char *fileNameBuffer; + + stream = (InputStream *) _alutMalloc(sizeof(InputStream)); + if (stream == NULL) + { + return NULL; + } + + if (stat(fileName, &statBuf)) + { + _alutSetError(ALUT_ERROR_IO_ERROR); + free(stream); + return NULL; + } + + fileDescriptor = fopen(fileName, "rb"); + if (fileDescriptor == NULL) + { + _alutSetError(ALUT_ERROR_IO_ERROR); + free(stream); + return NULL; + } + + fileNameBuffer = (char *)_alutMalloc(strlen(fileName) + 1); + if (fileNameBuffer == NULL) + { + free(stream); + return NULL; + } + + stream->isFileStream = AL_TRUE; + stream->fileName = strcpy(fileNameBuffer, fileName); + stream->remainingLength = statBuf.st_size; + stream->u.fileDescriptor = fileDescriptor; + return stream; +} + +InputStream *_alutInputStreamConstructFromMemory(const ALvoid * data, size_t length) +{ + InputStream *stream = (InputStream *) _alutMalloc(sizeof(InputStream)); + + if (stream == NULL) + { + return NULL; + } + + stream->isFileStream = AL_FALSE; + stream->fileName = NULL; + stream->remainingLength = length; + stream->u.data = data; + return stream; +} + +ALboolean _alutInputStreamDestroy(InputStream * stream) +{ + ALboolean status = (stream->isFileStream && fclose(stream->u.fileDescriptor)) ? AL_FALSE : AL_TRUE; + + if (stream->fileName) + { + free(stream->fileName); + } + free(stream); + return status; +} + +const char *_alutInputStreamGetFileName(const InputStream * stream) +{ + return stream->fileName; +} + +size_t _alutInputStreamGetRemainingLength(const InputStream * stream) +{ + return stream->remainingLength; +} + +ALboolean _alutInputStreamEOF(InputStream * stream) +{ + if (stream->isFileStream) + { + int c = fgetc(stream->u.fileDescriptor); + + if (c != EOF) + { + ungetc(c, stream->u.fileDescriptor); + } + return (c == EOF) ? AL_TRUE : AL_FALSE; + } + else + { + return (stream->remainingLength == 0) ? AL_TRUE : AL_FALSE; + } +} + +static ALboolean streamRead(InputStream * stream, void *ptr, size_t numBytesToRead) +{ + if (stream->isFileStream) + { + size_t numBytesRead = fread(ptr, 1, numBytesToRead, stream->u.fileDescriptor); + + if (numBytesToRead != numBytesRead) + { + _alutSetError(ferror(stream->u.fileDescriptor) ? ALUT_ERROR_IO_ERROR : ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA); + return AL_FALSE; + } + return AL_TRUE; + } + else + { + if (stream->remainingLength < numBytesToRead) + { + _alutSetError(ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA); + return AL_FALSE; + } + memcpy(ptr, stream->u.data, numBytesToRead); + stream->u.data = ((const char *)(stream->u.data) + numBytesToRead); + return AL_TRUE; + } +} + +/**************************************************************************** + * The utility functions below do not know the internal InputStream + * representation. + ****************************************************************************/ + +ALvoid *_alutInputStreamRead(InputStream * stream, size_t length) +{ + ALvoid *data = _alutMalloc(length); + + if (data == NULL) + { + return NULL; + } + + if (!streamRead(stream, data, length)) + { + free(data); + return NULL; + } + + return data; +} + +ALboolean _alutInputStreamSkip(InputStream * stream, size_t numBytesToSkip) +{ + ALboolean status; + char *buf; + + if (numBytesToSkip == 0) + { + return AL_TRUE; + } + buf = (char *)_alutMalloc(numBytesToSkip); + if (buf == NULL) + { + return AL_FALSE; + } + status = streamRead(stream, buf, numBytesToSkip); + free(buf); + return status; +} + +ALboolean _alutInputStreamReadUInt16LE(InputStream * stream, UInt16LittleEndian * value) +{ + unsigned char buf[2]; + + if (!streamRead(stream, buf, sizeof(buf))) + { + return AL_FALSE; + } + *value = ((UInt16LittleEndian) buf[1] << 8) | ((UInt16LittleEndian) buf[0]); + return AL_TRUE; +} + +ALboolean _alutInputStreamReadInt32BE(InputStream * stream, Int32BigEndian * value) +{ + unsigned char buf[4]; + + if (!streamRead(stream, buf, sizeof(buf))) + { + return AL_FALSE; + } + *value = ((Int32BigEndian) buf[0] << 24) | ((Int32BigEndian) buf[1] << 16) | ((Int32BigEndian) buf[2] << 8) | ((Int32BigEndian) buf[3]); + return AL_TRUE; +} + +ALboolean _alutInputStreamReadUInt32LE(InputStream * stream, UInt32LittleEndian * value) +{ + unsigned char buf[4]; + + if (!streamRead(stream, buf, sizeof(buf))) + { + return AL_FALSE; + } + *value = + ((UInt32LittleEndian) buf[3] << 24) | ((UInt32LittleEndian) buf[2] << 16) | ((UInt32LittleEndian) buf[1] << 8) | ((UInt32LittleEndian) buf[0]); + return AL_TRUE; +} diff --git a/tests/freealut/src/alutInternal.h b/tests/freealut/src/alutInternal.h new file mode 100644 index 0000000000000..ae7bba7bde4d4 --- /dev/null +++ b/tests/freealut/src/alutInternal.h @@ -0,0 +1,121 @@ +/* + * This file should be #included as the first header in all *.c files. + */ + +#if !defined(ALUT_INTERNAL_H) +#define ALUT_INTERNAL_H + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#if HAVE_STDINT_H +#include +#elif _MSC_VER < 1300 +typedef char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +#elif HAVE_BASETSD_H +#include +typedef INT8 int8_t; +typedef UINT8 uint8_t; +typedef INT16 int16_t; +typedef UINT16 uint16_t; +typedef INT32 int32_t; +typedef UINT32 uint32_t; +#else +#error Do not know sized types on this platform +#endif + +typedef int16_t Int16BigEndian; +typedef uint16_t UInt16LittleEndian; +typedef int32_t Int32BigEndian; +typedef uint32_t UInt32LittleEndian; + +#if HAVE___ATTRIBUTE__ +#define UNUSED(x) x __attribute__((unused)) +#else +#define UNUSED(x) x +#endif + +#include + +#define AU_HEADER_SIZE 24 + +/* see: http://en.wikipedia.org/wiki/Au_file_format, G.72x are missing */ +enum AUEncoding +{ + AU_ULAW_8 = 1, /* 8-bit ISDN u-law */ + AU_PCM_8 = 2, /* 8-bit linear PCM (signed) */ + AU_PCM_16 = 3, /* 16-bit linear PCM (signed, big-endian) */ + AU_PCM_24 = 4, /* 24-bit linear PCM */ + AU_PCM_32 = 5, /* 32-bit linear PCM */ + AU_FLOAT_32 = 6, /* 32-bit IEEE floating point */ + AU_FLOAT_64 = 7, /* 64-bit IEEE floating point */ + AU_ALAW_8 = 27 /* 8-bit ISDN a-law */ +}; + +/* in alutCodec.c */ +typedef ALvoid *Codec(ALvoid * data, size_t length, ALint numChannels, ALint bitsPerSample, ALfloat sampleFrequency); +extern Codec _alutCodecLinear; +extern Codec _alutCodecPCM8s; +extern Codec _alutCodecPCM16; +extern Codec _alutCodecULaw; +extern Codec _alutCodecALaw; + +/* in alutError.c */ +extern void _alutSetError(ALenum err); + +/* in alutInit.c */ +extern ALboolean _alutSanityCheck(void); + +/* in alutInputStream.c */ +typedef struct InputStream_struct InputStream; +extern InputStream *_alutInputStreamConstructFromFile(const char *fileName); +extern InputStream *_alutInputStreamConstructFromMemory(const ALvoid * data, size_t length); +extern const char *_alutInputStreamGetFileName(const InputStream * stream); +extern size_t _alutInputStreamGetRemainingLength(const InputStream * stream); +extern ALboolean _alutInputStreamDestroy(InputStream * stream); +extern ALboolean _alutInputStreamEOF(InputStream * stream); +extern ALvoid *_alutInputStreamRead(InputStream * stream, size_t length); +extern ALboolean _alutInputStreamSkip(InputStream * stream, size_t numBytesToSkip); +extern ALboolean _alutInputStreamReadUInt16LE(InputStream * stream, UInt16LittleEndian * value); +extern ALboolean _alutInputStreamReadInt32BE(InputStream * stream, Int32BigEndian * value); +extern ALboolean _alutInputStreamReadUInt32LE(InputStream * stream, UInt32LittleEndian * value); + +/* in alutLoader.c */ +extern ALuint _alutCreateBufferFromInputStream(InputStream * stream); +extern void *_alutLoadMemoryFromInputStream(InputStream * stream, ALenum * format, ALsizei * size, ALfloat * frequency); + +/* in alutOutputStream.c */ +typedef struct OutputStream_struct OutputStream; +extern OutputStream *_alutOutputStreamConstruct(size_t maximumLength); +extern ALboolean _alutOutputStreamDestroy(OutputStream * stream); +extern void *_alutOutputStreamGetData(OutputStream * stream); +extern size_t _alutOutputStreamGetLength(OutputStream * stream); +extern ALboolean _alutOutputStreamWriteInt16BE(OutputStream * stream, Int16BigEndian value); +extern ALboolean _alutOutputStreamWriteInt32BE(OutputStream * stream, Int32BigEndian value); + +/* in alutUtil.c */ +extern ALvoid *_alutMalloc(size_t size); +extern ALboolean _alutFormatConstruct(ALint numChannels, ALint bitsPerSample, ALenum * format); +extern ALboolean _alutFormatGetNumChannels(ALenum format, ALint * numChannels); +extern ALboolean _alutFormatGetBitsPerSample(ALenum format, ALint * bitsPerSample); + +/* in alutWaveform.c */ +typedef struct BufferData_struct BufferData; +extern BufferData *_alutBufferDataConstruct(ALvoid * data, size_t length, ALint numChannels, ALint bitsPerSample, ALfloat sampleFrequency); +extern ALboolean _alutBufferDataDestroy(BufferData * bufferData); +extern void _alutBufferDataDetachData(BufferData * bufferData); +extern ALvoid *_alutBufferDataGetData(const BufferData * bufferData); +extern size_t _alutBufferDataGetLength(const BufferData * bufferData); +extern ALfloat _alutBufferDataGetSampleFrequency(const BufferData * bufferData); +extern ALboolean _alutGetFormat(const BufferData * bufferData, ALenum * format); +extern ALuint _alutPassBufferData(BufferData * bufferData); + +#endif /* not ALUT_INTERNAL_H */ diff --git a/tests/freealut/src/alutLoader.c b/tests/freealut/src/alutLoader.c new file mode 100644 index 0000000000000..c21ed4838b9f7 --- /dev/null +++ b/tests/freealut/src/alutLoader.c @@ -0,0 +1,493 @@ +#include "alutInternal.h" +#include + +/****************************************************************************/ + +typedef enum +{ + LittleEndian, + BigEndian, + UnknwonEndian /* has anybody still a PDP11? :-) */ +} Endianess; + +/* test from Harbison & Steele, "C - A Reference Manual", section 6.1.2 */ +static Endianess endianess(void) +{ + union + { + long l; + char c[sizeof(long)]; + } u; + + u.l = 1; + return (u.c[0] == 1) ? LittleEndian : ((u.c[sizeof(long) - 1] == 1) ? BigEndian : UnknwonEndian); +} + +/****************************************************************************/ + +static int safeToLower(int c) +{ + return isupper(c) ? tolower(c) : c; +} + +static int hasSuffixIgnoringCase(const char *string, const char *suffix) +{ + const char *stringPointer = string; + const char *suffixPointer = suffix; + + if (suffix[0] == '\0') + { + return 1; + } + + while (*stringPointer != '\0') + { + stringPointer++; + } + + while (*suffixPointer != '\0') + { + suffixPointer++; + } + + if (stringPointer - string < suffixPointer - suffix) + { + return 0; + } + + while (safeToLower(*--suffixPointer) == safeToLower(*--stringPointer)) + { + if (suffixPointer == suffix) + { + return 1; + } + } + + return 0; +} + +static BufferData *loadWavFile(InputStream * stream) +{ + ALboolean found_header = AL_FALSE; + UInt32LittleEndian chunkLength; + Int32BigEndian magic; + UInt16LittleEndian audioFormat; + UInt16LittleEndian numChannels; + UInt32LittleEndian sampleFrequency; + UInt32LittleEndian byteRate; + UInt16LittleEndian blockAlign; + UInt16LittleEndian bitsPerSample; + Codec *codec = _alutCodecLinear; + + if (!_alutInputStreamReadUInt32LE(stream, &chunkLength) || !_alutInputStreamReadInt32BE(stream, &magic)) + { + return NULL; + } + + if (magic != 0x57415645) /* "WAVE" */ + { + _alutSetError(ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE); + return NULL; + } + + while (1) + { + if (!_alutInputStreamReadInt32BE(stream, &magic) || !_alutInputStreamReadUInt32LE(stream, &chunkLength)) + { + return NULL; + } + + if (magic == 0x666d7420) /* "fmt " */ + { + found_header = AL_TRUE; + + if (chunkLength < 16) + { + _alutSetError(ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA); + return NULL; + } + + if (!_alutInputStreamReadUInt16LE(stream, &audioFormat) || + !_alutInputStreamReadUInt16LE(stream, &numChannels) || + !_alutInputStreamReadUInt32LE(stream, &sampleFrequency) || + !_alutInputStreamReadUInt32LE(stream, &byteRate) || + !_alutInputStreamReadUInt16LE(stream, &blockAlign) || !_alutInputStreamReadUInt16LE(stream, &bitsPerSample)) + { + return NULL; + } + + if (!_alutInputStreamSkip(stream, chunkLength - 16)) + { + return NULL; + } + + switch (audioFormat) + { + case 1: /* PCM */ + codec = (bitsPerSample == 8 || endianess() == LittleEndian) ? _alutCodecLinear : _alutCodecPCM16; + break; + case 7: /* uLaw */ + bitsPerSample *= 2; /* ToDo: ??? */ + codec = _alutCodecULaw; + break; + default: + _alutSetError(ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE); + return NULL; + } + } + else if (magic == 0x64617461) /* "data" */ + { + ALvoid *data; + + if (!found_header) + { + /* ToDo: A bit wrong to check here, fmt chunk could come later... */ + _alutSetError(ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA); + return NULL; + } + data = _alutInputStreamRead(stream, chunkLength); + if (data == NULL) + { + return NULL; + } + return codec(data, chunkLength, numChannels, bitsPerSample, (ALfloat) sampleFrequency); + } + else + { + if (!_alutInputStreamSkip(stream, chunkLength)) + { + return NULL; + } + } + + if ((chunkLength & 1) && !_alutInputStreamEOF(stream) && !_alutInputStreamSkip(stream, 1)) + { + return NULL; + } + } +} + +static BufferData *loadAUFile(InputStream * stream) +{ + Int32BigEndian dataOffset; /* byte offset to data part, minimum 24 */ + Int32BigEndian len; /* number of bytes in the data part, -1 = not known */ + Int32BigEndian encoding; /* encoding of the data part, see AUEncoding */ + Int32BigEndian sampleFrequency; /* number of samples per second */ + Int32BigEndian numChannels; /* number of interleaved channels */ + size_t length; + Codec *codec; + char *data; + ALint bitsPerSample; + + if (!_alutInputStreamReadInt32BE(stream, &dataOffset) || + !_alutInputStreamReadInt32BE(stream, &len) || + !_alutInputStreamReadInt32BE(stream, &encoding) || + !_alutInputStreamReadInt32BE(stream, &sampleFrequency) || !_alutInputStreamReadInt32BE(stream, &numChannels)) + { + return AL_FALSE; + } + + length = (len == -1) ? (_alutInputStreamGetRemainingLength(stream) - AU_HEADER_SIZE - dataOffset) : (size_t) len; + + if (!(dataOffset >= AU_HEADER_SIZE && length > 0 && sampleFrequency >= 1 && numChannels >= 1)) + { + _alutSetError(ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA); + return AL_FALSE; + } + + if (!_alutInputStreamSkip(stream, dataOffset - AU_HEADER_SIZE)) + { + return AL_FALSE; + } + + switch (encoding) + { + case AU_ULAW_8: + bitsPerSample = 16; + codec = _alutCodecULaw; + break; + case AU_PCM_8: + bitsPerSample = 8; + codec = _alutCodecPCM8s; + break; + case AU_PCM_16: + bitsPerSample = 16; + codec = (endianess() == BigEndian) ? _alutCodecLinear : _alutCodecPCM16; + break; + case AU_ALAW_8: + bitsPerSample = 16; + codec = _alutCodecALaw; + break; + default: + _alutSetError(ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE); + return AL_FALSE; + } + + data = _alutInputStreamRead(stream, length); + if (data == NULL) + { + return NULL; + } + return codec(data, length, numChannels, bitsPerSample, (ALfloat) sampleFrequency); +} + +static BufferData *loadRawFile(InputStream * stream) +{ + size_t length = _alutInputStreamGetRemainingLength(stream); + ALvoid *data = _alutInputStreamRead(stream, length); + + if (data == NULL) + { + return NULL; + } + /* Guesses */ + return _alutCodecLinear(data, length, 1, 8, 8000); +} + +static BufferData *loadFile(InputStream * stream) +{ + const char *fileName; + Int32BigEndian magic; + + /* Raw files have no magic number - so use the fileName extension */ + + fileName = _alutInputStreamGetFileName(stream); + if (fileName != NULL && hasSuffixIgnoringCase(fileName, ".raw")) + { + return loadRawFile(stream); + } + + /* For other file formats, read the quasi-standard four byte magic number */ + if (!_alutInputStreamReadInt32BE(stream, &magic)) + { + return AL_FALSE; + } + + /* Magic number 'RIFF' == Microsoft '.wav' format */ + if (magic == 0x52494646) + { + return loadWavFile(stream); + } + + /* Magic number '.snd' == Sun & Next's '.au' format */ + if (magic == 0x2E736E64) + { + return loadAUFile(stream); + } + + _alutSetError(ALUT_ERROR_UNSUPPORTED_FILE_TYPE); + return AL_FALSE; +} + +ALuint _alutCreateBufferFromInputStream(InputStream * stream) +{ + BufferData *bufferData; + ALuint buffer; + + if (stream == NULL) + { + return AL_NONE; + } + + bufferData = loadFile(stream); + _alutInputStreamDestroy(stream); + if (bufferData == NULL) + { + return AL_NONE; + } + + buffer = _alutPassBufferData(bufferData); + _alutBufferDataDestroy(bufferData); + + return buffer; +} + +ALuint alutCreateBufferFromFile(const char *fileName) +{ + InputStream *stream; + + if (!_alutSanityCheck()) + { + return AL_NONE; + } + stream = _alutInputStreamConstructFromFile(fileName); + return _alutCreateBufferFromInputStream(stream); +} + +ALuint alutCreateBufferFromFileImage(const ALvoid * data, ALsizei length) +{ + InputStream *stream; + + if (!_alutSanityCheck()) + { + return AL_NONE; + } + stream = _alutInputStreamConstructFromMemory(data, length); + return _alutCreateBufferFromInputStream(stream); +} + +void *_alutLoadMemoryFromInputStream(InputStream * stream, ALenum * format, ALsizei * size, ALfloat * frequency) +{ + BufferData *bufferData; + ALenum fmt; + void *data; + + if (stream == NULL) + { + return NULL; + } + + bufferData = loadFile(stream); + if (bufferData == NULL) + { + _alutInputStreamDestroy(stream); + return NULL; + } + _alutInputStreamDestroy(stream); + + if (!_alutGetFormat(bufferData, &fmt)) + { + _alutBufferDataDestroy(bufferData); + return NULL; + } + + if (size != NULL) + { + *size = (ALsizei) _alutBufferDataGetLength(bufferData); + } + + if (format != NULL) + { + *format = fmt; + } + + if (frequency != NULL) + { + *frequency = _alutBufferDataGetSampleFrequency(bufferData); + } + + data = _alutBufferDataGetData(bufferData); + _alutBufferDataDetachData(bufferData); + _alutBufferDataDestroy(bufferData); + return data; +} + +ALvoid *alutLoadMemoryFromFile(const char *fileName, ALenum * format, ALsizei * size, ALfloat * frequency) +{ + InputStream *stream; + + if (!_alutSanityCheck()) + { + return NULL; + } + stream = _alutInputStreamConstructFromFile(fileName); + return _alutLoadMemoryFromInputStream(stream, format, size, frequency); +} + +ALvoid *alutLoadMemoryFromFileImage(const ALvoid * data, ALsizei length, ALenum * format, ALsizei * size, ALfloat * frequency) +{ + InputStream *stream; + + if (!_alutSanityCheck()) + { + return NULL; + } + stream = _alutInputStreamConstructFromMemory(data, length); + return _alutLoadMemoryFromInputStream(stream, format, size, frequency); +} + +/* + Yukky backwards compatibility crap. +*/ + +void alutLoadWAVFile(ALbyte * fileName, ALenum * format, void **data, ALsizei * size, ALsizei * frequency +#if !defined(__APPLE__) + , ALboolean * loop +#endif + ) +{ + InputStream *stream; + ALfloat freq; + + /* Don't do an _alutSanityCheck () because it's not required in ALUT 0.x.x */ + + stream = _alutInputStreamConstructFromFile(fileName); + *data = _alutLoadMemoryFromInputStream(stream, format, size, &freq); + if (*data == NULL) + { + return; + } + + if (frequency) + { + *frequency = (ALsizei) freq; + } + +#if !defined(__APPLE__) + if (loop) + { + *loop = AL_FALSE; + } +#endif +} + +void alutLoadWAVMemory(ALbyte * buffer, ALenum * format, void **data, ALsizei * size, ALsizei * frequency +#if !defined(__APPLE__) + , ALboolean * loop +#endif + ) +{ + InputStream *stream; + ALfloat freq; + + /* Don't do an _alutSanityCheck () because it's not required in ALUT 0.x.x */ + + /* ToDo: Can we do something less insane than passing 0x7FFFFFFF? */ + stream = _alutInputStreamConstructFromMemory(buffer, 0x7FFFFFFF); + _alutLoadMemoryFromInputStream(stream, format, size, &freq); + if (*data == NULL) + { + return; + } + + if (frequency) + { + *frequency = (ALsizei) freq; + } + +#if !defined(__APPLE__) + if (loop) + { + *loop = AL_FALSE; + } +#endif +} + +void alutUnloadWAV(ALenum UNUSED(format), ALvoid * data, ALsizei UNUSED(size), ALsizei UNUSED(frequency)) +{ + /* Don't do an _alutSanityCheck () because it's not required in ALUT 0.x.x */ + + free(data); +} + +const char *alutGetMIMETypes(ALenum loader) +{ + if (!_alutSanityCheck()) + { + return NULL; + } + + /* We do not distinguish the loaders yet... */ + switch (loader) + { + case ALUT_LOADER_BUFFER: + return "audio/basic,audio/x-raw,audio/x-wav"; + + case ALUT_LOADER_MEMORY: + return "audio/basic,audio/x-raw,audio/x-wav"; + + default: + _alutSetError(ALUT_ERROR_INVALID_ENUM); + return NULL; + } +} diff --git a/tests/freealut/src/alutOutputStream.c b/tests/freealut/src/alutOutputStream.c new file mode 100644 index 0000000000000..fc8eca030aae3 --- /dev/null +++ b/tests/freealut/src/alutOutputStream.c @@ -0,0 +1,89 @@ +#include "alutInternal.h" +#include + +struct OutputStream_struct +{ + char *data; + char *current; + size_t maximumLength; +}; + +/**************************************************************************** + * The functions below know the internal OutputStream representation. + ****************************************************************************/ + +OutputStream *_alutOutputStreamConstruct(size_t maximumLength) +{ + OutputStream *stream = (OutputStream *) _alutMalloc(sizeof(OutputStream)); + + if (stream == NULL) + { + return NULL; + } + stream->data = _alutMalloc(maximumLength); + if (stream->data == NULL) + { + free(stream); + return NULL; + } + stream->current = stream->data; + stream->maximumLength = maximumLength; + return stream; +} + +ALboolean _alutOutputStreamDestroy(OutputStream * stream) +{ + free(stream->data); + free(stream); + return AL_TRUE; +} + +void *_alutOutputStreamGetData(OutputStream * stream) +{ + return stream->data; +} + +size_t _alutOutputStreamGetLength(OutputStream * stream) +{ + return stream->current - stream->data; +} + +static ALboolean streamWrite(OutputStream * stream, const void *ptr, size_t numBytesToWrite) +{ + size_t remainingLength = stream->maximumLength - _alutOutputStreamGetLength(stream); + + if (remainingLength < numBytesToWrite) + { + /* this should never happen within our library */ + _alutSetError(ALUT_ERROR_IO_ERROR); + return AL_FALSE; + } + memcpy(stream->current, ptr, numBytesToWrite); + stream->current += numBytesToWrite; + return AL_TRUE; +} + +/**************************************************************************** + * The utility functions below do not know the internal OutputStream + * representation. + ****************************************************************************/ + +ALboolean _alutOutputStreamWriteInt16BE(OutputStream * stream, Int16BigEndian value) +{ + unsigned char buf[2]; + + buf[0] = (unsigned char)(value >> 8); + buf[1] = (unsigned char)value; + return streamWrite(stream, buf, 2); +} + +ALboolean _alutOutputStreamWriteInt32BE(OutputStream * stream, Int32BigEndian value) +{ + unsigned char buf[4]; + + buf[0] = (unsigned char)(value >> 24); + buf[1] = (unsigned char)(value >> 16); + buf[2] = (unsigned char)(value >> 8); + buf[3] = (unsigned char)value; + return streamWrite(stream, buf, 4); +} diff --git a/tests/freealut/src/alutUtil.c b/tests/freealut/src/alutUtil.c new file mode 100644 index 0000000000000..09be66e52700e --- /dev/null +++ b/tests/freealut/src/alutUtil.c @@ -0,0 +1,141 @@ +#include "alutInternal.h" + +#if HAVE_NANOSLEEP && HAVE_TIME_H +#include +#include +#elif HAVE_USLEEP && HAVE_UNISTD_H +#include +#elif HAVE_SLEEP && HAVE_WINDOWS_H +#include +#else +#error No way to sleep on this platform +#endif + +ALboolean alutSleep(ALfloat duration) +{ + if (duration < 0) + { + _alutSetError(ALUT_ERROR_INVALID_VALUE); + return AL_FALSE; + } + + { + ALuint seconds = (ALuint) duration; + ALfloat rest = duration - (ALfloat) seconds; + +#if HAVE_NANOSLEEP && HAVE_TIME_H + + ALuint microSecs = (ALuint) (rest * 1000000); + struct timespec t, remainingTime; + + t.tv_sec = (time_t) seconds; + t.tv_nsec = ((long)microSecs) * 1000; + + /* At least the interaction of nanosleep and signals is specified! */ + while (nanosleep(&t, &remainingTime) < 0) + { + if (errno != EINTR) + { + return AL_FALSE; + } + /* If we received a signal, let's try again with the remaining time. */ + t.tv_sec = remainingTime.tv_sec; + t.tv_nsec = remainingTime.tv_nsec; + } + +#elif HAVE_USLEEP && HAVE_UNISTD_H + + while (seconds > 0) + { + usleep(1000000); + seconds--; + } + usleep((unsigned int)(rest * 1000000)); + +#elif HAVE_SLEEP && HAVE_WINDOWS_H + + while (seconds > 0) + { + Sleep(1000); + seconds--; + } + Sleep((DWORD) (rest * 1000)); + +#endif + + } + return AL_TRUE; +} + +ALvoid *_alutMalloc(size_t size) +{ + ALvoid *ptr = malloc(size == 0 ? 1 : size); + + if (ptr == NULL) + { + _alutSetError(ALUT_ERROR_OUT_OF_MEMORY); + } + return ptr; +} + +ALboolean _alutFormatConstruct(ALint numChannels, ALint bitsPerSample, ALenum * format) +{ + switch (numChannels) + { + case 1: + switch (bitsPerSample) + { + case 8: + *format = AL_FORMAT_MONO8; + return AL_TRUE; + case 16: + *format = AL_FORMAT_MONO16; + return AL_TRUE; + } + break; + case 2: + switch (bitsPerSample) + { + case 8: + *format = AL_FORMAT_STEREO8; + return AL_TRUE; + case 16: + *format = AL_FORMAT_STEREO16; + return AL_TRUE; + } + break; + } + return AL_FALSE; +} + +ALboolean _alutFormatGetNumChannels(ALenum format, ALint * numChannels) +{ + switch (format) + { + case AL_FORMAT_MONO8: + case AL_FORMAT_MONO16: + *numChannels = 1; + return AL_TRUE; + case AL_FORMAT_STEREO8: + case AL_FORMAT_STEREO16: + *numChannels = 2; + return AL_TRUE; + } + return AL_FALSE; +} + +ALboolean _alutFormatGetBitsPerSample(ALenum format, ALint * bitsPerSample) +{ + switch (format) + { + case AL_FORMAT_MONO8: + case AL_FORMAT_STEREO8: + *bitsPerSample = 8; + return AL_TRUE; + case AL_FORMAT_MONO16: + case AL_FORMAT_STEREO16: + *bitsPerSample = 16; + return AL_TRUE; + } + return AL_FALSE; +} diff --git a/tests/freealut/src/alutVersion.c b/tests/freealut/src/alutVersion.c new file mode 100644 index 0000000000000..3837415ca6c00 --- /dev/null +++ b/tests/freealut/src/alutVersion.c @@ -0,0 +1,11 @@ +#include "alutInternal.h" + +ALint alutGetMajorVersion(void) +{ + return ALUT_API_MAJOR_VERSION; +} + +ALint alutGetMinorVersion(void) +{ + return ALUT_API_MINOR_VERSION; +} diff --git a/tests/freealut/src/alutWaveform.c b/tests/freealut/src/alutWaveform.c new file mode 100644 index 0000000000000..5eb769d77ed5d --- /dev/null +++ b/tests/freealut/src/alutWaveform.c @@ -0,0 +1,912 @@ +#include "alutInternal.h" +#include +#include + +#if defined(_WIN32) +#define random() rand() +#endif + +static const double sampleFrequency = 44100; + +/* + * The following waveformFoo functions expect the phase of the previous call and + * the current phase, both in the range [0..+1). They return an amplitude in the + * range [-1..+1]. + */ + +typedef double (*waveformFunction) (double lastPhase, double phase); + +static double waveformSine(double UNUSED(lastPhase), double phase) +{ + static const double pi = 3.14159265358979323846; + + return sin(phase * pi); +} + +static double waveformSquare(double UNUSED(lastPhase), double phase) +{ + return (phase >= 0.5) ? -1 : 1; +} + +static double waveformSawtooth(double UNUSED(lastPhase), double phase) +{ + return 2 * phase - 1; +} + +static double waveformWhitenoise(double UNUSED(lastPhase), double UNUSED(phase)) +{ + static const long prime = 67867967L; + + return 2 * (double)(random() % prime) / prime - 1; +} + +static double waveformImpulse(double lastPhase, double phase) +{ + return (lastPhase > phase) ? 1 : 0; +} + +static waveformFunction getWaveformFunction(ALenum waveshape) +{ + switch (waveshape) + { + case ALUT_WAVEFORM_SINE: + return &waveformSine; + case ALUT_WAVEFORM_SQUARE: + return &waveformSquare; + case ALUT_WAVEFORM_SAWTOOTH: + return &waveformSawtooth; + case ALUT_WAVEFORM_WHITENOISE: + return &waveformWhitenoise; + case ALUT_WAVEFORM_IMPULSE: + return &waveformImpulse; + } + _alutSetError(ALUT_ERROR_INVALID_ENUM); + return NULL; +} + +static OutputStream *generateWaveform(ALenum waveshape, ALfloat frequency, ALfloat phase, ALfloat duration) +{ + waveformFunction func; + double sampleDuration, lastPhase, numSamplesD; + size_t numBytes, numSamples, i; + OutputStream *stream; + + func = getWaveformFunction(waveshape); + if (func == NULL) + { + return NULL; + } + + /* ToDo: Shall we test phase for [-180 .. +180]? */ + if (frequency <= 0 || duration < 0) + { + _alutSetError(ALUT_ERROR_INVALID_VALUE); + return NULL; + } + + /* allocate stream to hold AU header and sample data */ + sampleDuration = floor((frequency * duration) + 0.5) / frequency; + /* GCC is a bit picky about casting function calls, so we do it in two + * steps... */ + numSamplesD = floor(sampleDuration * sampleFrequency); + numSamples = (size_t) numSamplesD; + numBytes = numSamples * sizeof(int16_t); + stream = _alutOutputStreamConstruct(AU_HEADER_SIZE + numBytes); + if (stream == NULL) + { + return NULL; + } + + /* write AU header for our 16bit mono data */ + if (!_alutOutputStreamWriteInt32BE(stream, 0x2e736e64) || /* ".snd" */ + !_alutOutputStreamWriteInt32BE(stream, AU_HEADER_SIZE) || + !_alutOutputStreamWriteInt32BE(stream, (Int32BigEndian) numBytes) || + !_alutOutputStreamWriteInt32BE(stream, AU_PCM_16) || + !_alutOutputStreamWriteInt32BE(stream, (Int32BigEndian) sampleFrequency) || !_alutOutputStreamWriteInt32BE(stream, 1)) + { + _alutOutputStreamDestroy(stream); + return NULL; + } + + /* normalize phase from degrees */ + phase /= 180; + + /* the value corresponding to i = -1 below */ + lastPhase = phase - frequency / sampleFrequency; + lastPhase -= floor(lastPhase); + + /* calculate samples */ + for (i = 0; i < numSamples; i++) + { + double p = phase + frequency * (double)i / sampleFrequency; + double currentPhase = p - floor(p); + double amplitude = func(lastPhase, currentPhase); + + if (!_alutOutputStreamWriteInt16BE(stream, (Int16BigEndian) (amplitude * 32767))) + { + _alutOutputStreamDestroy(stream); + return NULL; + } + lastPhase = currentPhase; + } + + return stream; +} + +ALvoid *alutLoadMemoryWaveform(ALenum waveshape, ALfloat frequency, ALfloat phase, ALfloat duration, ALenum * format, ALsizei * size, ALfloat * freq) +{ + OutputStream *outputStream; + InputStream *inputStream; + ALvoid *data; + + if (!_alutSanityCheck()) + { + return NULL; + } + + outputStream = generateWaveform(waveshape, frequency, phase, duration); + if (outputStream == NULL) + { + return NULL; + } + + /* We could do something more efficient here if the internal stream + * structures were known, but this would break the abstraction. */ + inputStream = _alutInputStreamConstructFromMemory(_alutOutputStreamGetData(outputStream), _alutOutputStreamGetLength(outputStream)); + if (inputStream == NULL) + { + _alutOutputStreamDestroy(outputStream); + return NULL; + } + + data = _alutLoadMemoryFromInputStream(inputStream, format, size, freq); + _alutOutputStreamDestroy(outputStream); + return data; +} + +ALuint alutCreateBufferWaveform(ALenum waveshape, ALfloat frequency, ALfloat phase, ALfloat duration) +{ + OutputStream *outputStream; + InputStream *inputStream; + ALuint buffer; + + if (!_alutSanityCheck()) + { + return AL_NONE; + } + + outputStream = generateWaveform(waveshape, frequency, phase, duration); + if (outputStream == NULL) + { + return AL_NONE; + } + + /* We could do something more efficient here if the internal stream + * structures were known, but this would break the abstraction. */ + inputStream = _alutInputStreamConstructFromMemory(_alutOutputStreamGetData(outputStream), _alutOutputStreamGetLength(outputStream)); + if (inputStream == NULL) + { + _alutOutputStreamDestroy(outputStream); + return AL_NONE; + } + + buffer = _alutCreateBufferFromInputStream(inputStream); + _alutOutputStreamDestroy(outputStream); + return buffer; +} + +/* converted from helloworld.wav */ +static uint8_t helloWorldSample[] = { + 0x2e, 0x73, 0x6e, 0x64, /* ".snd" */ + 0x00, 0x00, 0x00, 0x18, /* byte offset to data part (24) */ + 0x00, 0x00, 0x1f, 0xf2, /* number of bytes in the data part (8178) */ + 0x00, 0x00, 0x00, 0x01, /* encoding of the data part (8-bit ISDN u-law) */ + 0x00, 0x00, 0x2b, 0x11, /* number of samples per second (11025) */ + 0x00, 0x00, 0x00, 0x01, /* number of interleaved channels (1) */ + + 0x7e, 0x7c, 0x7d, 0x7a, 0x79, 0xfc, 0xf8, 0x7e, 0x73, 0x6f, 0x7c, 0x7d, + 0x6f, 0x71, 0x78, 0x78, 0x77, 0x6f, 0x6b, 0x6e, 0x71, 0x6c, 0x6b, 0x75, + 0xff, 0x7b, 0x70, 0x6d, 0x6d, 0x6a, 0x6c, 0x74, 0x70, 0x73, 0x71, 0x63, + 0x68, 0xfb, 0xf4, 0x78, 0x6f, 0xfd, 0xef, 0x74, 0x62, 0x70, 0xf6, 0x6a, + 0x60, 0x6b, 0xf9, 0x7e, 0x6a, 0x7b, 0xea, 0x78, 0x62, 0x75, 0xe3, 0xe7, + 0x71, 0x66, 0x78, 0xf9, 0x6d, 0x6d, 0x77, 0x74, 0x6f, 0x68, 0x6a, 0xfe, + 0xf8, 0x7e, 0x6f, 0x6b, 0x72, 0xfe, 0xea, 0xe7, 0x72, 0x60, 0x6a, 0xed, + 0xe8, 0x6f, 0x62, 0x62, 0x6a, 0xf3, 0xef, 0x7e, 0xfd, 0x70, 0x64, 0x6e, + 0xed, 0xe6, 0xec, 0x6b, 0x5e, 0x7b, 0xe0, 0xe7, 0x7e, 0x62, 0x5c, 0x72, + 0xee, 0xf5, 0x74, 0x65, 0x69, 0x6d, 0xfd, 0xe6, 0xef, 0x6c, 0x6a, 0x7e, + 0xf6, 0x7a, 0x67, 0x64, 0x7b, 0x7c, 0x6b, 0xf0, 0xde, 0xfe, 0x5c, 0x5f, + 0x7c, 0xe5, 0xe4, 0xf6, 0x6e, 0x69, 0x7e, 0xe2, 0xe0, 0x77, 0x5d, 0x6a, + 0xf3, 0x6e, 0x6a, 0x79, 0xfa, 0xed, 0xeb, 0xeb, 0xec, 0x7e, 0x6f, 0x78, + 0x69, 0x64, 0x7d, 0xff, 0x74, 0x67, 0x6c, 0xe5, 0xee, 0x77, 0xf2, 0xeb, + 0xf2, 0x68, 0x67, 0x73, 0x6f, 0x74, 0xf2, 0xeb, 0x78, 0x66, 0x66, 0x71, + 0xe7, 0xe2, 0x6d, 0x65, 0xf1, 0x7a, 0x5f, 0x64, 0x73, 0x79, 0x75, 0xeb, + 0xe8, 0x6c, 0x6e, 0xee, 0xe5, 0xee, 0x66, 0x6c, 0xf5, 0x6b, 0x6f, 0xe5, + 0xec, 0x7b, 0x7d, 0x79, 0x76, 0x68, 0x67, 0xf6, 0xef, 0x6e, 0x73, 0xfd, + 0x7c, 0xf6, 0x75, 0x68, 0x72, 0x6a, 0x5e, 0x68, 0x77, 0x77, 0x68, 0x5e, + 0x6e, 0xea, 0xfb, 0x6a, 0xf5, 0xf1, 0x70, 0x6a, 0x6b, 0xde, 0xdf, 0x66, + 0x6e, 0x7d, 0x64, 0x5f, 0xf5, 0xe6, 0x7a, 0x7a, 0xee, 0xeb, 0x74, 0x60, + 0x76, 0xde, 0xf2, 0x58, 0x66, 0xdb, 0xdd, 0x6d, 0x5b, 0xfa, 0xe3, 0x68, + 0x6e, 0xe1, 0xe1, 0x73, 0x55, 0x5a, 0xe5, 0xda, 0xee, 0x7e, 0xef, 0x7c, + 0x6b, 0x7a, 0xe9, 0xe7, 0x72, 0x5e, 0x79, 0xe5, 0xfa, 0xff, 0x78, 0x64, + 0x6b, 0x7a, 0xf6, 0xf7, 0x78, 0xef, 0xe8, 0xf8, 0x7a, 0xef, 0xde, 0xe7, + 0x58, 0x58, 0xde, 0xdf, 0x6c, 0x74, 0xfa, 0xef, 0xed, 0xfd, 0xf8, 0xf4, + 0x66, 0x5f, 0xe7, 0xe0, 0x6e, 0x7c, 0xee, 0x71, 0x67, 0x69, 0xfb, 0xe7, + 0xed, 0x72, 0x6c, 0x6f, 0x67, 0x6b, 0xe8, 0xe2, 0x70, 0x6b, 0xf0, 0x64, + 0x58, 0xee, 0xe3, 0x66, 0x74, 0xe7, 0xed, 0x6d, 0x58, 0x56, 0x62, 0x6e, + 0x6d, 0xe8, 0xd8, 0xe2, 0x6f, 0x5e, 0x63, 0xfd, 0xfa, 0x6f, 0x64, 0x59, + 0x5b, 0x6e, 0x71, 0x69, 0x6c, 0x6c, 0x74, 0xe3, 0xdd, 0xf5, 0x69, 0x71, + 0x7e, 0x62, 0x65, 0xe6, 0xda, 0xee, 0x64, 0xed, 0xcd, 0xcd, 0xd8, 0xd6, + 0xcd, 0xd2, 0xea, 0xe0, 0xcd, 0xcf, 0xe9, 0x74, 0xdd, 0xd0, 0xd4, 0xdc, + 0xef, 0xe2, 0xdd, 0x69, 0x66, 0x76, 0x6c, 0x6d, 0x5c, 0x5a, 0x67, 0x6b, + 0x5c, 0x4c, 0x48, 0x4d, 0x5d, 0x5a, 0x4c, 0x51, 0x4f, 0x4f, 0x58, 0x4d, + 0x4e, 0x4d, 0x40, 0x40, 0x49, 0x4d, 0x4f, 0x4d, 0x3e, 0x38, 0x4c, 0xbe, + 0xb1, 0xb9, 0xc9, 0xcb, 0xcd, 0xf2, 0xe8, 0xd1, 0xd4, 0xeb, 0x4d, 0x54, + 0xca, 0xc2, 0xbf, 0xb7, 0xb2, 0xb7, 0xc6, 0xc4, 0xb8, 0xbe, 0xde, 0x77, + 0xd0, 0xcd, 0xe1, 0xdf, 0xcf, 0xc7, 0xda, 0x54, 0x59, 0x5d, 0x4f, 0x49, + 0x49, 0x51, 0x4d, 0x45, 0x46, 0x4a, 0x46, 0x3b, 0x38, 0x38, 0x38, 0x35, + 0x32, 0x33, 0x38, 0xe7, 0xb0, 0xb0, 0xbc, 0xce, 0xd8, 0x74, 0x47, 0x44, + 0x4b, 0x50, 0x43, 0x3e, 0x57, 0xca, 0xbb, 0xbc, 0xc0, 0xc1, 0xca, 0xde, + 0xee, 0xe0, 0xd3, 0x6c, 0x4d, 0xcf, 0xb7, 0xb9, 0xc7, 0xd1, 0xc5, 0xc7, + 0xe2, 0xf7, 0xd1, 0xcc, 0xfe, 0x5d, 0xe7, 0xce, 0xcd, 0xe1, 0x74, 0x67, + 0x4d, 0x3e, 0x3b, 0x3d, 0x3b, 0x39, 0x34, 0x33, 0x3c, 0x4b, 0x52, 0x4f, + 0xce, 0xaf, 0xae, 0xc3, 0x5c, 0x51, 0x51, 0x3d, 0x36, 0x3c, 0x4b, 0x4d, + 0x47, 0x5c, 0xc7, 0xb9, 0xbb, 0xbe, 0xbe, 0xc6, 0xe7, 0x57, 0x5a, 0x6b, + 0x60, 0x51, 0x54, 0xd0, 0xb7, 0xb4, 0xbc, 0xc0, 0xc5, 0xdc, 0x6b, 0xee, + 0xde, 0xe5, 0x63, 0x5c, 0x7d, 0xe1, 0xd1, 0xcf, 0xe8, 0x51, 0x3d, 0x32, + 0x2d, 0x2c, 0x30, 0x3e, 0x4d, 0x52, 0x62, 0xbe, 0xac, 0xad, 0xbc, 0xdc, + 0x58, 0x43, 0x38, 0x36, 0x3e, 0x48, 0x47, 0x46, 0x6a, 0xbf, 0xb4, 0xb4, + 0xb9, 0xc0, 0xcf, 0x71, 0x57, 0x5b, 0x5d, 0x50, 0x47, 0x4b, 0x63, 0xdd, + 0xc4, 0xb3, 0xad, 0xb2, 0xc9, 0xfc, 0xf9, 0xf5, 0x58, 0x4d, 0x53, 0x5a, + 0x56, 0x53, 0xf1, 0xcd, 0xda, 0x52, 0x3d, 0x38, 0x2f, 0x27, 0x2b, 0x43, + 0xd5, 0xbd, 0xb0, 0xae, 0xb6, 0xc4, 0xe9, 0x6f, 0x71, 0x4a, 0x38, 0x34, + 0x36, 0x3a, 0x4a, 0xde, 0xbe, 0xb6, 0xb9, 0xbf, 0xc3, 0xc9, 0xcf, 0xe3, + 0x5d, 0x4e, 0x44, 0x3f, 0x45, 0x52, 0xf6, 0xd2, 0xc3, 0xb6, 0xb2, 0xb5, + 0xb8, 0xbd, 0xd2, 0x4e, 0x41, 0x43, 0x47, 0x4a, 0x4a, 0x53, 0x5e, 0x51, + 0x48, 0x41, 0x3e, 0x2e, 0x28, 0x37, 0xc1, 0xac, 0xac, 0xb4, 0xbf, 0xd5, + 0x51, 0x46, 0x6e, 0xde, 0x4d, 0x38, 0x2f, 0x33, 0x4a, 0xce, 0xba, 0xb1, + 0xb3, 0xc0, 0xde, 0x71, 0xdc, 0xce, 0xde, 0x59, 0x47, 0x3e, 0x3e, 0x49, + 0x7a, 0xc8, 0xc0, 0xc3, 0xbc, 0xb7, 0xb8, 0xbb, 0xbf, 0xd3, 0x52, 0x3f, + 0x3d, 0x44, 0x4e, 0x4f, 0x4f, 0x4b, 0x45, 0x3f, 0x3c, 0x38, 0x2e, 0x2f, + 0xe1, 0xab, 0xaa, 0xb6, 0xc1, 0xca, 0xf7, 0x47, 0x44, 0xfa, 0xdd, 0x3e, + 0x2d, 0x2f, 0x41, 0xec, 0xc6, 0xb8, 0xaf, 0xb4, 0xcd, 0x66, 0xe8, 0xcb, + 0xcc, 0x6e, 0x4a, 0x44, 0x3e, 0x3c, 0x47, 0xdc, 0xc0, 0xc2, 0xc9, 0xc0, + 0xb7, 0xb4, 0xbd, 0xc9, 0xca, 0xde, 0x48, 0x3b, 0x3f, 0x4e, 0x51, 0x49, + 0x42, 0x42, 0x43, 0x39, 0x32, 0x2f, 0x31, 0xde, 0xaa, 0xaa, 0xb6, 0xbb, + 0xc4, 0x6c, 0x4b, 0x49, 0x6c, 0xd5, 0x43, 0x2e, 0x31, 0x3c, 0x51, 0xce, + 0xbc, 0xb1, 0xb1, 0xc2, 0xee, 0xd8, 0xc8, 0xc7, 0xd6, 0x5e, 0x55, 0x42, + 0x37, 0x3c, 0x50, 0xd9, 0xcb, 0xc4, 0xb9, 0xb5, 0xb6, 0xbd, 0xc5, 0xbe, + 0xc6, 0x5e, 0x42, 0x3e, 0x3f, 0x3d, 0x3a, 0x3a, 0x3d, 0x3b, 0x33, 0x2d, + 0x2a, 0x36, 0xb7, 0xa5, 0xab, 0xb1, 0xb4, 0xc9, 0x52, 0x44, 0x4b, 0xcf, + 0xd7, 0x37, 0x2d, 0x2f, 0x34, 0x3f, 0xeb, 0xbb, 0xad, 0xaf, 0xc5, 0xd4, + 0xc7, 0xc2, 0xc1, 0xc5, 0xd2, 0xfb, 0x43, 0x31, 0x33, 0x3f, 0x53, 0xcf, + 0xba, 0xb6, 0xb5, 0xba, 0xbe, 0xbb, 0xba, 0xc4, 0xdc, 0x5c, 0x43, 0x3a, + 0x35, 0x35, 0x37, 0x35, 0x30, 0x2c, 0x27, 0x2c, 0xcf, 0xaa, 0xab, 0xac, + 0xab, 0xb3, 0xc9, 0x5c, 0x58, 0xc6, 0xc3, 0x47, 0x33, 0x2f, 0x2d, 0x2f, + 0x38, 0x58, 0xb9, 0xb2, 0xbf, 0xc6, 0xbf, 0xbe, 0xbb, 0xba, 0xba, 0xb9, + 0xcc, 0x40, 0x35, 0x38, 0x43, 0x5e, 0xde, 0xc5, 0xb9, 0xbd, 0xd9, 0xeb, + 0xc9, 0xbe, 0xc6, 0xe4, 0x5b, 0x48, 0x39, 0x2f, 0x2c, 0x2b, 0x29, 0x28, + 0x32, 0xd3, 0xb7, 0xbc, 0xba, 0xb2, 0xb3, 0xba, 0xc4, 0xbf, 0xb5, 0xbe, + 0x4c, 0x38, 0x37, 0x35, 0x32, 0x35, 0x46, 0xd6, 0xd2, 0x66, 0xe6, 0xc0, + 0xb9, 0xb8, 0xb6, 0xb2, 0xb2, 0xbf, 0x65, 0x64, 0xdc, 0xea, 0x7c, 0xe2, + 0xdc, 0xfc, 0x4f, 0x49, 0x5a, 0xe5, 0xf0, 0x5e, 0x55, 0x48, 0x3a, 0x2e, + 0x2a, 0x27, 0x2b, 0x51, 0xb8, 0xb9, 0xbe, 0xba, 0xbd, 0xcf, 0xda, 0xcc, + 0xb8, 0xb0, 0xc3, 0x4e, 0x40, 0x39, 0x33, 0x37, 0x45, 0xd9, 0xc1, 0xd9, + 0x58, 0xf9, 0xd8, 0xcf, 0xbf, 0xb6, 0xb0, 0xb3, 0xc9, 0x57, 0x69, 0xd7, + 0xd4, 0xcb, 0xc2, 0xc7, 0xf5, 0x48, 0x42, 0x4d, 0x6c, 0x6f, 0x69, 0x62, + 0x4b, 0x3a, 0x2f, 0x2a, 0x28, 0x29, 0x30, 0xed, 0xb5, 0xb7, 0xbd, 0xbb, + 0xbe, 0xcb, 0xd0, 0xc8, 0xb8, 0xb4, 0xc8, 0x4a, 0x3d, 0x39, 0x35, 0x38, + 0x46, 0xd9, 0xc3, 0xd6, 0x5f, 0xf2, 0xcf, 0xc9, 0xbf, 0xb7, 0xb1, 0xb4, + 0xc4, 0xe1, 0xd0, 0xca, 0xcf, 0xd0, 0xcd, 0xd0, 0xfd, 0x49, 0x41, 0x4a, + 0x55, 0x59, 0x56, 0x53, 0x4a, 0x3a, 0x2e, 0x28, 0x26, 0x2a, 0x38, 0xda, + 0xb6, 0xb5, 0xb9, 0xb8, 0xc1, 0xde, 0xd2, 0xc0, 0xba, 0xb8, 0xc7, 0x50, + 0x41, 0x3b, 0x35, 0x3a, 0x4f, 0xe0, 0xca, 0xcd, 0xec, 0xdd, 0xd1, 0xd5, + 0xc3, 0xb7, 0xb5, 0xb8, 0xbf, 0xc8, 0xc9, 0xcb, 0xd9, 0xd9, 0xce, 0xd5, + 0x69, 0x4e, 0x4c, 0x4c, 0x4f, 0x51, 0x4e, 0x4f, 0x4a, 0x3c, 0x30, 0x2a, + 0x27, 0x2a, 0x2d, 0x38, 0xc6, 0xaf, 0xba, 0xbf, 0xbb, 0xc4, 0xd0, 0xcd, + 0xc9, 0xb9, 0xb3, 0xce, 0x48, 0x45, 0x3e, 0x3a, 0x3e, 0x4b, 0xde, 0xc2, + 0xd4, 0x6e, 0xd6, 0xcc, 0xce, 0xc4, 0xbb, 0xb6, 0xb5, 0xbc, 0xc7, 0xc3, + 0xc4, 0xd3, 0xdc, 0xd5, 0xdd, 0x64, 0x4e, 0x4a, 0x4f, 0x61, 0x5d, 0x55, + 0x5a, 0x4f, 0x3c, 0x31, 0x2b, 0x28, 0x2b, 0x2c, 0x2c, 0x44, 0xb7, 0xb5, + 0xc6, 0xbb, 0xb6, 0xc3, 0xcd, 0xd2, 0xc9, 0xb5, 0xb9, 0x73, 0x58, 0x64, + 0x40, 0x39, 0x3e, 0x4b, 0xda, 0xc7, 0xe2, 0xdd, 0xc3, 0xcc, 0xd6, 0xc5, + 0xbf, 0xba, 0xb6, 0xbe, 0xc2, 0xbd, 0xc5, 0xde, 0xdf, 0xdd, 0xf5, 0x61, + 0x55, 0x51, 0x64, 0xf7, 0x63, 0x66, 0xfd, 0x57, 0x43, 0x38, 0x2e, 0x2b, + 0x2b, 0x2a, 0x29, 0x2b, 0x3f, 0xbf, 0xba, 0xc6, 0xba, 0xb1, 0xbc, 0xce, + 0xd0, 0xc5, 0xb8, 0xba, 0xd8, 0xee, 0xea, 0x46, 0x39, 0x3b, 0x42, 0x66, + 0xd3, 0xe7, 0xda, 0xc3, 0xca, 0xd7, 0xc8, 0xc0, 0xbd, 0xb9, 0xbc, 0xbd, + 0xb9, 0xc1, 0xdd, 0xdf, 0xdf, 0x65, 0x5b, 0x61, 0x64, 0x77, 0xf4, 0x6f, + 0xf1, 0xd9, 0xe7, 0x5b, 0x49, 0x3b, 0x30, 0x2c, 0x2a, 0x29, 0x2a, 0x2a, + 0x2c, 0x4c, 0xbd, 0xc2, 0xc9, 0xb4, 0xb0, 0xbb, 0xc3, 0xc6, 0xbe, 0xb5, + 0xbe, 0xfe, 0xe5, 0xe8, 0x43, 0x3a, 0x3b, 0x3f, 0x56, 0xfc, 0x5d, 0xd3, + 0xbb, 0xc3, 0xcc, 0xc0, 0xc0, 0xc0, 0xbc, 0xc4, 0xc2, 0xb8, 0xbf, 0xd8, + 0xd5, 0xe1, 0x5f, 0x6d, 0x6d, 0x66, 0xda, 0xd2, 0xe8, 0xdc, 0xd1, 0xdc, + 0xe8, 0x6a, 0x47, 0x3c, 0x37, 0x2e, 0x2a, 0x2a, 0x29, 0x29, 0x29, 0x2d, + 0x4d, 0xbf, 0xc5, 0xbf, 0xae, 0xae, 0xbb, 0xc2, 0xc6, 0xc4, 0xbd, 0xcd, + 0x63, 0xdf, 0xf4, 0x3f, 0x3b, 0x3e, 0x40, 0x5a, 0xf1, 0x78, 0xc6, 0xb9, + 0xc4, 0xc7, 0xbe, 0xc4, 0xc3, 0xbe, 0xc9, 0xc8, 0xbb, 0xc2, 0xd3, 0xc8, + 0xcf, 0x7d, 0xe5, 0x7a, 0x5f, 0xd6, 0xd1, 0xf0, 0xd2, 0xc9, 0xd8, 0xda, + 0xd9, 0x68, 0x4f, 0x42, 0x37, 0x33, 0x30, 0x2c, 0x29, 0x2a, 0x29, 0x26, + 0x2b, 0x47, 0xc8, 0xcb, 0xbf, 0xae, 0xae, 0xba, 0xbf, 0xcc, 0xc7, 0xbb, + 0xce, 0x5e, 0xce, 0xd5, 0x46, 0x40, 0x41, 0x3f, 0x5f, 0xf8, 0x5a, 0xc6, + 0xb6, 0xc3, 0xc4, 0xbb, 0xc7, 0xc5, 0xbe, 0xd6, 0xcf, 0xbb, 0xc7, 0xd4, + 0xc1, 0xcd, 0xf7, 0xd5, 0xed, 0x5e, 0xd5, 0xd2, 0xec, 0xcd, 0xca, 0xdc, + 0xd0, 0xce, 0xe9, 0xe3, 0xe0, 0x54, 0x41, 0x3a, 0x32, 0x2e, 0x2b, 0x27, + 0x26, 0x28, 0x26, 0x23, 0x2a, 0xff, 0xb2, 0xbe, 0xb9, 0xa5, 0xa8, 0xbb, + 0xc6, 0xe0, 0xeb, 0xc7, 0x55, 0x3b, 0xea, 0xd5, 0x3e, 0x3c, 0x47, 0x48, + 0xdc, 0xc7, 0xce, 0xb1, 0xa8, 0xb1, 0xb8, 0xb2, 0xbd, 0xc9, 0xcf, 0x53, + 0x63, 0xd8, 0x48, 0x41, 0xec, 0xde, 0xd8, 0xc2, 0xca, 0xc2, 0xb4, 0xc0, + 0xd8, 0xbf, 0xc6, 0xea, 0xdd, 0x70, 0x60, 0xda, 0x6a, 0x4e, 0xfb, 0x75, + 0x47, 0x3e, 0x37, 0x30, 0x2f, 0x2c, 0x29, 0x2a, 0x2b, 0x28, 0x27, 0x27, + 0x25, 0x3c, 0xac, 0xa8, 0xb0, 0xa0, 0x9d, 0xb3, 0xe2, 0x57, 0x35, 0x40, + 0x54, 0x2f, 0x3a, 0xc2, 0x52, 0x36, 0x76, 0xd3, 0xcb, 0xae, 0xae, 0xad, + 0xa0, 0xa7, 0xc1, 0xbd, 0xc7, 0x42, 0x43, 0x3e, 0x35, 0x4d, 0x4e, 0x34, + 0x40, 0xf9, 0x5a, 0xcd, 0xb7, 0xb1, 0xa8, 0xa9, 0xbc, 0xbd, 0xbe, 0x4d, + 0x44, 0x4d, 0x44, 0x68, 0xe4, 0x4f, 0xe7, 0xca, 0xec, 0xf0, 0xe6, 0x64, + 0x5b, 0x45, 0x38, 0x3a, 0x3a, 0x31, 0x30, 0x32, 0x2e, 0x2d, 0x2a, 0x23, + 0x25, 0x24, 0x1f, 0x3e, 0xa1, 0xa3, 0xab, 0x9b, 0x9c, 0xba, 0xe5, 0x3b, + 0x2b, 0x4e, 0x50, 0x2a, 0x4a, 0xb8, 0x4c, 0x43, 0xcf, 0xe3, 0xb8, 0xa7, + 0xb0, 0xab, 0x9e, 0xad, 0xd5, 0xcd, 0x47, 0x35, 0x3d, 0x31, 0x32, 0x66, + 0x4f, 0x3b, 0x5e, 0xdc, 0xe8, 0xc1, 0xbc, 0xba, 0xad, 0xad, 0xbd, 0xc1, + 0xc7, 0x58, 0x4b, 0x4c, 0x49, 0xf9, 0xcf, 0xdd, 0xcf, 0xc7, 0xce, 0xdc, + 0xe7, 0xdd, 0xe2, 0x6e, 0x6a, 0x5a, 0x50, 0x52, 0x42, 0x3d, 0x47, 0x3e, + 0x37, 0x3a, 0x34, 0x2d, 0x2c, 0x28, 0x26, 0x27, 0x25, 0x26, 0x2b, 0x27, + 0x2e, 0xaa, 0x9c, 0xa8, 0x9f, 0x99, 0xa8, 0xca, 0x45, 0x29, 0x35, 0x54, + 0x2b, 0x32, 0xbc, 0xc6, 0xfb, 0xbf, 0xc1, 0xaf, 0xa3, 0xac, 0xaf, 0xa1, + 0xaa, 0xd6, 0x66, 0x3d, 0x33, 0x3b, 0x30, 0x2f, 0x62, 0xe1, 0x49, 0xef, + 0xcb, 0xcc, 0xbc, 0xbf, 0xcb, 0xb8, 0xb8, 0xe0, 0x6c, 0x6f, 0x4f, 0x51, + 0x4e, 0x4f, 0xd0, 0xbf, 0xc7, 0xc4, 0xc0, 0xc5, 0xcf, 0x6a, 0x59, 0x6f, + 0x60, 0x55, 0x5c, 0x7e, 0xdc, 0xe7, 0x65, 0xee, 0xe0, 0x60, 0x4f, 0x4b, + 0x43, 0x3e, 0x38, 0x35, 0x39, 0x3a, 0x39, 0x3b, 0x3d, 0x39, 0x37, 0x34, + 0x2e, 0x2c, 0x2c, 0x28, 0x29, 0x28, 0x29, 0xca, 0x9e, 0xa2, 0xa4, 0x99, + 0xa0, 0xc0, 0x68, 0x2d, 0x2b, 0x58, 0x39, 0x2e, 0xc7, 0xbc, 0x77, 0xc0, + 0xbf, 0xbd, 0xa7, 0xaa, 0xb5, 0xa6, 0xaa, 0xcc, 0xe8, 0x42, 0x33, 0x41, + 0x3a, 0x34, 0xf0, 0xcc, 0x69, 0xce, 0xcb, 0xce, 0xbb, 0xbf, 0xcd, 0xbb, + 0xbd, 0xec, 0x5e, 0x4a, 0x40, 0x48, 0x45, 0x46, 0xe5, 0xc8, 0xc6, 0xc2, + 0xc4, 0xc2, 0xc4, 0xdf, 0x77, 0xe0, 0x7a, 0x5c, 0x5a, 0x5d, 0x7d, 0x75, + 0x5e, 0xfa, 0xda, 0xde, 0xf7, 0x6f, 0x6a, 0x56, 0x46, 0x3f, 0x40, 0x41, + 0x41, 0x43, 0x49, 0x53, 0x52, 0x4b, 0x49, 0x48, 0x43, 0x3c, 0x37, 0x38, + 0x39, 0x36, 0x35, 0x32, 0x30, 0x31, 0x2f, 0x2d, 0x2e, 0x30, 0x33, 0xc3, + 0x9e, 0x9f, 0xa4, 0x9c, 0xa2, 0xc8, 0x4d, 0x30, 0x2b, 0x49, 0x46, 0x37, + 0xc7, 0xb7, 0xd1, 0xbe, 0xbe, 0xc0, 0xab, 0xac, 0xb6, 0xaa, 0xad, 0xd4, + 0xea, 0x41, 0x32, 0x41, 0x3d, 0x38, 0xe2, 0xcc, 0xee, 0xc9, 0xcb, 0xd1, + 0xbe, 0xc6, 0xcf, 0xbe, 0xc5, 0xee, 0x5f, 0x48, 0x41, 0x43, 0x3f, 0x46, + 0x66, 0xdb, 0xcc, 0xcd, 0xd0, 0xcb, 0xd3, 0x7c, 0xec, 0xd7, 0xd5, 0xdc, + 0xee, 0x73, 0x65, 0x59, 0x51, 0x53, 0x68, 0xe1, 0xdd, 0xdc, 0xd9, 0xec, + 0x60, 0x59, 0x51, 0x4f, 0x53, 0x54, 0x5c, 0x61, 0x58, 0x57, 0x59, 0x51, + 0x4d, 0x49, 0x44, 0x44, 0x42, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3c, 0x3b, + 0x3b, 0x37, 0x34, 0x32, 0x2f, 0x2d, 0x2f, 0x33, 0x36, 0xbf, 0x9f, 0xa1, + 0xa7, 0x9f, 0xa6, 0xcb, 0x55, 0x34, 0x30, 0x62, 0x4c, 0x3d, 0xc6, 0xbd, + 0xd6, 0xc1, 0xcb, 0xc0, 0xaa, 0xaf, 0xb7, 0xaa, 0xb3, 0xd7, 0xf5, 0x3b, + 0x36, 0x49, 0x3a, 0x3b, 0xde, 0xdb, 0xe5, 0xcc, 0xd5, 0xca, 0xbd, 0xc9, + 0xcb, 0xc3, 0xd0, 0x6f, 0x4e, 0x42, 0x43, 0x44, 0x45, 0x4e, 0x6f, 0xd7, + 0xd0, 0xdb, 0xdf, 0xdd, 0xe3, 0xfb, 0x6c, 0xf8, 0xeb, 0x65, 0x53, 0x4f, + 0x55, 0x5a, 0x57, 0xf2, 0xcb, 0xcc, 0xd3, 0xd6, 0xea, 0x6f, 0x5e, 0x4d, + 0x51, 0x60, 0x59, 0x63, 0xf1, 0xf4, 0xe3, 0xdf, 0xed, 0xe5, 0xee, 0x61, + 0x5e, 0x58, 0x4f, 0x4f, 0x4a, 0x45, 0x45, 0x45, 0x46, 0x47, 0x48, 0x4a, + 0x45, 0x3f, 0x3d, 0x3a, 0x37, 0x35, 0x31, 0x31, 0x33, 0x31, 0x33, 0x44, + 0xb5, 0xa2, 0xa6, 0xa9, 0xa2, 0xad, 0xeb, 0x41, 0x34, 0x3a, 0x59, 0x44, + 0x45, 0xc7, 0xc7, 0xe3, 0xce, 0xc7, 0xb6, 0xac, 0xb1, 0xb0, 0xad, 0xbb, + 0xe4, 0x4b, 0x3a, 0x3e, 0x43, 0x3b, 0x49, 0xe5, 0xee, 0x7b, 0xea, 0xd9, + 0xc4, 0xbe, 0xc1, 0xbe, 0xbd, 0xcb, 0x62, 0x49, 0x43, 0x40, 0x40, 0x46, + 0x50, 0x76, 0xe0, 0xea, 0xf1, 0xdf, 0xd9, 0xdc, 0xde, 0xd9, 0xda, 0xfe, + 0x54, 0x49, 0x47, 0x48, 0x47, 0x46, 0x55, 0xf8, 0xeb, 0xe7, 0xd7, 0xca, + 0xcb, 0xde, 0xed, 0xdf, 0xe1, 0x74, 0x5c, 0x60, 0x7a, 0x6f, 0x61, 0x7c, + 0xda, 0xd2, 0xd6, 0xd9, 0xd5, 0xd9, 0xf2, 0x61, 0x5a, 0x5d, 0x61, 0x59, + 0x58, 0x60, 0x5c, 0x4f, 0x4b, 0x47, 0x42, 0x3e, 0x3c, 0x3b, 0x3b, 0x3a, + 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x37, 0x36, 0x3a, 0x6f, 0xae, 0xa8, 0xae, + 0xaa, 0xaa, 0xc9, 0x4a, 0x3f, 0x38, 0x4e, 0xf5, 0x48, 0x77, 0xc6, 0xfd, + 0x63, 0xd5, 0xc4, 0xb3, 0xae, 0xb2, 0xaf, 0xb3, 0xcb, 0x56, 0x45, 0x44, + 0x48, 0x49, 0x4d, 0x60, 0x73, 0x5d, 0x52, 0x69, 0xd0, 0xc5, 0xbe, 0xbc, + 0xbd, 0xc3, 0xea, 0x4c, 0x45, 0x43, 0x44, 0x4a, 0x52, 0x68, 0x7d, 0x65, + 0x5f, 0x67, 0xfb, 0xde, 0xda, 0xd6, 0xd1, 0xe2, 0x5b, 0x4c, 0x47, 0x46, + 0x49, 0x49, 0x51, 0x6d, 0x72, 0x60, 0x7e, 0xde, 0xe0, 0xd6, 0xc9, 0xc7, + 0xca, 0xd6, 0x78, 0x60, 0x5a, 0x4f, 0x54, 0x76, 0xde, 0xd5, 0xd4, 0xdb, + 0xd7, 0xd3, 0xdc, 0xdd, 0xd7, 0xdc, 0xed, 0x6d, 0x59, 0x51, 0x51, 0x50, + 0x54, 0x5f, 0x61, 0x59, 0x52, 0x4c, 0x49, 0x47, 0x42, 0x3f, 0x42, 0x40, + 0x3c, 0x3b, 0x3e, 0x40, 0x3c, 0x38, 0x38, 0x38, 0x3a, 0x48, 0xbf, 0xaa, + 0xab, 0xaf, 0xab, 0xb5, 0xf2, 0x55, 0x46, 0x4c, 0xd9, 0x5f, 0x47, 0x74, + 0x5f, 0x45, 0x54, 0xd7, 0xbb, 0xaf, 0xb0, 0xb3, 0xb3, 0xbe, 0xea, 0x4f, + 0x54, 0x65, 0x5d, 0x55, 0x4f, 0x4d, 0x4a, 0x41, 0x44, 0xfe, 0xca, 0xc1, + 0xbd, 0xbd, 0xc1, 0xd0, 0x5a, 0x50, 0x59, 0x56, 0x51, 0x51, 0x4e, 0x4a, + 0x46, 0x43, 0x49, 0x68, 0xd5, 0xce, 0xc9, 0xc6, 0xce, 0xe9, 0x5f, 0x57, + 0x5c, 0x5d, 0x53, 0x51, 0x52, 0x4d, 0x47, 0x48, 0x54, 0x78, 0xd9, 0xcc, + 0xc7, 0xc3, 0xc2, 0xc8, 0xd6, 0xe2, 0xed, 0x69, 0x5a, 0x5c, 0x5f, 0x5d, + 0x5b, 0x5c, 0x67, 0xeb, 0xdf, 0xda, 0xcf, 0xcb, 0xcc, 0xd9, 0xef, 0x72, + 0x60, 0x55, 0x4f, 0x50, 0x53, 0x4f, 0x4c, 0x4b, 0x4d, 0x4f, 0x4f, 0x51, + 0x59, 0x5a, 0x54, 0x51, 0x4d, 0x4a, 0x47, 0x44, 0x42, 0x41, 0x41, 0x40, + 0x3e, 0x3c, 0x3a, 0x39, 0x4d, 0xb9, 0xad, 0xb3, 0xae, 0xab, 0xbc, 0xde, + 0x72, 0x55, 0xe0, 0xd5, 0x4e, 0x4e, 0x63, 0x45, 0x3d, 0x4c, 0xdc, 0xbe, + 0xb8, 0xb8, 0xb8, 0xb8, 0xc3, 0xee, 0xef, 0xd4, 0xde, 0x7d, 0x5d, 0x4c, + 0x46, 0x3c, 0x39, 0x46, 0x7a, 0xd3, 0xc8, 0xc3, 0xc2, 0xc7, 0xdc, 0xf5, + 0xdc, 0xd3, 0xda, 0xf7, 0x67, 0x55, 0x46, 0x3f, 0x40, 0x4c, 0x67, 0xef, + 0xdf, 0xd5, 0xd5, 0xe3, 0xfd, 0xeb, 0xd9, 0xd6, 0xdf, 0x7c, 0x5f, 0x53, + 0x47, 0x41, 0x47, 0x55, 0x61, 0x6b, 0xf6, 0xdd, 0xd4, 0xd0, 0xce, 0xcc, + 0xca, 0xcd, 0xda, 0xf3, 0x6b, 0x61, 0x5a, 0x56, 0x5e, 0x6c, 0x70, 0x77, + 0xf0, 0xe3, 0xdc, 0xd8, 0xd8, 0xda, 0xde, 0xf2, 0x67, 0x5a, 0x52, 0x4d, + 0x4b, 0x4b, 0x4c, 0x4d, 0x4e, 0x4e, 0x4f, 0x52, 0x54, 0x54, 0x56, 0x58, + 0x54, 0x4e, 0x4c, 0x4a, 0x45, 0x42, 0x45, 0x44, 0x42, 0x42, 0x40, 0x40, + 0x3f, 0x41, 0xcd, 0xb0, 0xb9, 0xba, 0xaf, 0xba, 0xcd, 0xd3, 0xfe, 0xd0, + 0xc2, 0xed, 0x54, 0x5f, 0x4d, 0x3f, 0x41, 0x61, 0xc9, 0xbf, 0xbe, 0xbf, + 0xbe, 0xbe, 0xcf, 0xd6, 0xc3, 0xc1, 0xcb, 0xe0, 0x5b, 0x4e, 0x43, 0x3c, + 0x3f, 0x53, 0xeb, 0xe1, 0xe2, 0xd7, 0xd6, 0xdd, 0xdd, 0xd3, 0xc6, 0xc4, + 0xcf, 0xe9, 0x61, 0x4e, 0x44, 0x42, 0x47, 0x4f, 0x58, 0x56, 0x4f, 0x55, + 0x5c, 0x5d, 0x7b, 0xd5, 0xcb, 0xcb, 0xd4, 0xed, 0x6b, 0x5f, 0x5a, 0x5e, + 0xe5, 0xd3, 0xdc, 0x7c, 0x66, 0x60, 0x5e, 0x62, 0xef, 0xd4, 0xd0, 0xdb, + 0xf1, 0x72, 0x71, 0x77, 0xf1, 0xdc, 0xd1, 0xd5, 0xed, 0x66, 0x5b, 0x5b, + 0x5c, 0x5a, 0x63, 0x6a, 0x57, 0x4d, 0x4c, 0x4c, 0x4d, 0x4f, 0x52, 0x58, + 0x58, 0x50, 0x4a, 0x4a, 0x4e, 0x4d, 0x4a, 0x4c, 0x4d, 0x4b, 0x44, 0x40, + 0x43, 0x46, 0x46, 0x46, 0x4a, 0x48, 0x47, 0xcf, 0xb6, 0xbb, 0xbb, 0xb0, + 0xb8, 0xc5, 0xc7, 0xd8, 0xcd, 0xc1, 0xd9, 0x5d, 0x6a, 0x5b, 0x46, 0x44, + 0x59, 0xe1, 0xce, 0xc8, 0xcc, 0xc8, 0xc0, 0xca, 0xce, 0xc0, 0xbe, 0xc4, + 0xce, 0xea, 0x5c, 0x4e, 0x47, 0x42, 0x4b, 0x61, 0x5a, 0x52, 0x5d, 0x61, + 0x65, 0xf1, 0xdd, 0xcd, 0xc5, 0xc9, 0xd8, 0xe7, 0xf6, 0x5e, 0x56, 0x58, + 0x58, 0x57, 0x51, 0x47, 0x45, 0x4a, 0x4c, 0x4e, 0x62, 0xea, 0xdd, 0xdf, + 0xef, 0xe2, 0xd4, 0xd8, 0xd9, 0xce, 0xcd, 0xd0, 0xd8, 0xed, 0x76, 0xfc, + 0x72, 0x63, 0x70, 0xf3, 0x6b, 0x61, 0x66, 0x64, 0x7b, 0xe1, 0xe0, 0xdc, + 0xd4, 0xdc, 0x7c, 0x68, 0x60, 0x5d, 0x5c, 0x59, 0x54, 0x51, 0x4d, 0x47, + 0x45, 0x48, 0x4a, 0x4e, 0x53, 0x55, 0x54, 0x53, 0x4f, 0x4d, 0x4e, 0x51, + 0x53, 0x53, 0x51, 0x4f, 0x4f, 0x4d, 0x4b, 0x4d, 0x50, 0x4f, 0x4d, 0x48, + 0x45, 0xe3, 0xbc, 0xc6, 0xc5, 0xb5, 0xba, 0xc4, 0xc4, 0xcc, 0xc6, 0xbc, + 0xc6, 0xe0, 0xdd, 0xd9, 0x58, 0x46, 0x58, 0xfc, 0xeb, 0xd7, 0xe5, 0xe6, + 0xcc, 0xd2, 0xe8, 0xd0, 0xc0, 0xc0, 0xca, 0xcc, 0xd4, 0xf3, 0x6c, 0x53, + 0x4d, 0x68, 0x6c, 0x4f, 0x4d, 0x50, 0x4f, 0x4e, 0x54, 0x66, 0xe6, 0xd4, + 0xda, 0xf8, 0xeb, 0xe6, 0x79, 0x6b, 0xf8, 0xe2, 0xee, 0x63, 0x55, 0x4e, + 0x4f, 0x4e, 0x4c, 0x5e, 0xec, 0xfb, 0xf8, 0xdf, 0xd6, 0xd4, 0xd3, 0xcf, + 0xcc, 0xcb, 0xcf, 0xe1, 0xe9, 0xeb, 0x6a, 0x5f, 0x6b, 0x70, 0x6b, 0x66, + 0x5e, 0x5b, 0x5f, 0x61, 0x5b, 0x65, 0xfb, 0x6e, 0x5f, 0x5d, 0x58, 0x55, + 0x54, 0x51, 0x50, 0x54, 0x54, 0x4d, 0x49, 0x4a, 0x49, 0x49, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4b, 0x4b, 0x4e, 0x53, 0x5c, 0x62, 0x6d, 0xf9, 0xfa, 0x69, + 0x5f, 0x66, 0x6e, 0x6c, 0x72, 0xea, 0xcf, 0xc7, 0xcb, 0xcc, 0xc4, 0xc4, + 0xc9, 0xc9, 0xc9, 0xc7, 0xc5, 0xca, 0xd3, 0xd8, 0xd5, 0xe2, 0x78, 0xee, + 0xe6, 0xea, 0xeb, 0xf6, 0xfe, 0xee, 0xe7, 0xee, 0xed, 0xda, 0xd5, 0xdb, + 0xdf, 0xe0, 0xe4, 0xe8, 0xf8, 0x6f, 0x79, 0xf8, 0x6f, 0x5e, 0x5d, 0x5e, + 0x5a, 0x56, 0x57, 0x5b, 0x5f, 0x63, 0x61, 0x64, 0x75, 0x7d, 0x7c, 0xea, + 0xe4, 0xdf, 0xd5, 0xd2, 0xd5, 0xd4, 0xd4, 0xdc, 0xe1, 0xdf, 0xec, 0xf9, + 0xf5, 0x7a, 0x6c, 0x68, 0x63, 0x62, 0x68, 0x71, 0x7e, 0x7c, 0x77, 0x72, + 0x65, 0x5f, 0x61, 0x5e, 0x5c, 0x5e, 0x5e, 0x58, 0x55, 0x51, 0x4d, 0x4c, + 0x4c, 0x4b, 0x4a, 0x4b, 0x4c, 0x4a, 0x4a, 0x4b, 0x4b, 0x4a, 0x4b, 0x4e, + 0x51, 0x55, 0x5b, 0x61, 0x6d, 0xff, 0xf5, 0xf2, 0xec, 0xe2, 0xdf, 0xe5, + 0xe8, 0xe4, 0xe0, 0xe5, 0xe2, 0xd8, 0xd1, 0xcd, 0xcb, 0xca, 0xca, 0xc9, + 0xcb, 0xce, 0xcd, 0xcc, 0xce, 0xcf, 0xd1, 0xd5, 0xd9, 0xdd, 0xe9, 0xf6, + 0xf2, 0xf6, 0x7c, 0xfa, 0xf6, 0xf5, 0xef, 0xf3, 0xfa, 0xf5, 0xee, 0xee, + 0xf1, 0xee, 0xea, 0xea, 0xed, 0xef, 0xf6, 0xfe, 0x77, 0x73, 0x71, 0x6f, + 0x6e, 0x6c, 0x6d, 0x6f, 0x6b, 0x6e, 0xf7, 0xed, 0xe7, 0xdd, 0xd9, 0xd9, + 0xd8, 0xd6, 0xda, 0xde, 0xdf, 0xe6, 0xea, 0xed, 0xfd, 0x6f, 0x6d, 0x68, + 0x5f, 0x5d, 0x5b, 0x59, 0x58, 0x57, 0x56, 0x53, 0x51, 0x4f, 0x4d, 0x4d, + 0x4d, 0x4d, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x4d, 0x4d, 0x4d, + 0x4d, 0x4f, 0x52, 0x51, 0x54, 0x5b, 0x5e, 0x5e, 0x62, 0x6d, 0xfc, 0xee, + 0xe8, 0xdf, 0xdd, 0xdb, 0xdb, 0xdd, 0xdc, 0xda, 0xdc, 0xdc, 0xd7, 0xd1, + 0xcf, 0xce, 0xcc, 0xcb, 0xcc, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd7, 0xd8, + 0xd8, 0xd6, 0xd9, 0xdc, 0xdd, 0xe2, 0xe8, 0xe7, 0xea, 0xeb, 0xe6, 0xe4, + 0xe8, 0xec, 0xf0, 0xf7, 0xf9, 0x7a, 0x6f, 0x71, 0x78, 0x77, 0x79, 0xfc, + 0xfc, 0xf9, 0xf3, 0xf2, 0xeb, 0xe0, 0xdd, 0xdd, 0xda, 0xd8, 0xdb, 0xde, + 0xdf, 0xe5, 0xef, 0xf7, 0xf9, 0x7c, 0x79, 0x7a, 0x6e, 0x6b, 0x68, 0x61, + 0x5d, 0x5a, 0x58, 0x57, 0x55, 0x54, 0x53, 0x52, 0x4f, 0x4e, 0x4e, 0x4d, + 0x4c, 0x4c, 0x4d, 0x4e, 0x50, 0x51, 0x50, 0x51, 0x53, 0x53, 0x53, 0x52, + 0x53, 0x54, 0x56, 0x59, 0x5c, 0x60, 0x66, 0x69, 0x6e, 0x75, 0x7c, 0xfc, + 0xf6, 0xee, 0xe9, 0xe2, 0xde, 0xdd, 0xdc, 0xdb, 0xda, 0xdb, 0xd9, 0xd7, + 0xd5, 0xd3, 0xcf, 0xce, 0xcd, 0xcd, 0xcd, 0xcc, 0xce, 0xd1, 0xd3, 0xd4, + 0xd7, 0xda, 0xdb, 0xdb, 0xdb, 0xdc, 0xdd, 0xe1, 0xe4, 0xeb, 0xf5, 0xff, + 0x76, 0x71, 0x6f, 0x6e, 0x72, 0x74, 0x6f, 0x72, 0x72, 0x6d, 0x6d, 0x6e, + 0x72, 0x7c, 0xf9, 0xea, 0xdf, 0xdb, 0xd8, 0xd6, 0xd5, 0xd6, 0xdb, 0xe0, + 0xe6, 0xee, 0xf3, 0xfc, 0x70, 0x6b, 0x6a, 0x68, 0x65, 0x60, 0x5e, 0x5b, + 0x58, 0x58, 0x57, 0x55, 0x54, 0x54, 0x56, 0x56, 0x57, 0x5a, 0x5a, 0x5b, + 0x5b, 0x59, 0x57, 0x56, 0x55, 0x55, 0x56, 0x56, 0x59, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5c, 0x5b, 0x5c, 0x5e, 0x5e, 0x5f, 0x62, 0x64, 0x6a, 0x71, + 0x77, 0xfa, 0xee, 0xeb, 0xe8, 0xe7, 0xe4, 0xe3, 0xe3, 0xe1, 0xdf, 0xde, + 0xdc, 0xda, 0xd8, 0xd7, 0xd7, 0xd4, 0xd2, 0xd2, 0xd2, 0xd0, 0xd1, 0xd3, + 0xd2, 0xd4, 0xd7, 0xd7, 0xd6, 0xd9, 0xdb, 0xda, 0xdc, 0xdf, 0xe1, 0xe6, + 0xe9, 0xed, 0xfb, 0x75, 0x6e, 0x6a, 0x69, 0x67, 0x66, 0x6b, 0x71, 0x7d, + 0xf4, 0xed, 0xe5, 0xe2, 0xe1, 0xde, 0xde, 0xe1, 0xe8, 0xef, 0xf9, 0x79, + 0x70, 0x6d, 0x6c, 0x6d, 0x6f, 0x6e, 0x68, 0x67, 0x68, 0x60, 0x5d, 0x5d, + 0x5c, 0x5a, 0x59, 0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5e, 0x5e, 0x5d, 0x5e, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5e, 0x5f, 0x5f, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, + 0x60, 0x62, 0x64, 0x67, 0x69, 0x6b, 0x6d, 0x6d, 0x6e, 0x74, 0x7b, 0x7c, + 0xfe, 0xf8, 0xf3, 0xed, 0xe9, 0xe6, 0xe3, 0xe3, 0xe1, 0xdf, 0xe1, 0xe1, + 0xdf, 0xe0, 0xe4, 0xe5, 0xe5, 0xe7, 0xe4, 0xe2, 0xe3, 0xe0, 0xdd, 0xdb, + 0xda, 0xd8, 0xd7, 0xd7, 0xd6, 0xd6, 0xd7, 0xd8, 0xda, 0xde, 0xdf, 0xdf, + 0xe3, 0xe7, 0xe5, 0xe2, 0xe0, 0xe3, 0xe7, 0xe7, 0xe9, 0xed, 0xf6, 0x7e, + 0x79, 0x73, 0x6e, 0x6e, 0x6d, 0x6c, 0x6b, 0x67, 0x67, 0x6a, 0x68, 0x67, + 0x67, 0x65, 0x64, 0x64, 0x64, 0x63, 0x64, 0x66, 0x66, 0x68, 0x69, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x65, 0x66, 0x68, 0x69, 0x69, 0x6d, 0x6d, 0x6b, + 0x6d, 0x6d, 0x6c, 0x6b, 0x69, 0x6d, 0x6e, 0x6c, 0x6a, 0x6a, 0x6b, 0x68, + 0x68, 0x6b, 0x6a, 0x6a, 0x6f, 0x73, 0x6f, 0x72, 0x77, 0x75, 0x75, 0x78, + 0x7b, 0x7a, 0xfe, 0xfb, 0xf9, 0xf5, 0xf4, 0xed, 0xe9, 0xea, 0xe9, 0xe6, + 0xe3, 0xe3, 0xe4, 0xe0, 0xdf, 0xe2, 0xe4, 0xe3, 0xe3, 0xe7, 0xe6, 0xe2, + 0xe2, 0xe4, 0xe2, 0xe0, 0xdf, 0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xdf, 0xe3, + 0xe2, 0xe1, 0xe8, 0xed, 0xee, 0xee, 0xf0, 0xf5, 0xf6, 0xf6, 0xf8, 0xfd, + 0xfd, 0xfc, 0xff, 0x78, 0x73, 0x74, 0x74, 0x71, 0x71, 0x72, 0x75, 0x79, + 0x7b, 0x7e, 0xfb, 0xf5, 0xf5, 0xfa, 0xfd, 0x7e, 0x75, 0x70, 0x70, 0x70, + 0x70, 0x70, 0x6f, 0x70, 0x75, 0x71, 0x6f, 0x70, 0x6f, 0x6c, 0x6b, 0x6b, + 0x6b, 0x6a, 0x68, 0x68, 0x67, 0x67, 0x67, 0x66, 0x68, 0x69, 0x67, 0x69, + 0x68, 0x67, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6e, 0x6c, 0x6a, 0x6a, 0x6c, + 0x6b, 0x6a, 0x6d, 0x6f, 0x6f, 0x6f, 0x70, 0x72, 0x72, 0x76, 0x7c, 0xfd, + 0xf5, 0xf0, 0xf2, 0xf4, 0xf2, 0xf0, 0xf1, 0xf9, 0xfb, 0xf1, 0xf1, 0xf2, + 0xec, 0xe8, 0xe7, 0xe4, 0xdf, 0xde, 0xdc, 0xd9, 0xd8, 0xd8, 0xd8, 0xd7, + 0xd8, 0xda, 0xdb, 0xde, 0xe2, 0xe3, 0xe4, 0xe4, 0xe6, 0xe8, 0xe7, 0xe7, + 0xe9, 0xec, 0xef, 0xf2, 0xf3, 0xfb, 0x79, 0x76, 0x77, 0x76, 0x70, 0x6f, + 0x6f, 0x6c, 0x6d, 0x6e, 0x6f, 0x71, 0x70, 0x75, 0x7e, 0x7c, 0x77, 0xfe, + 0xf5, 0xf8, 0xf9, 0xf8, 0xfa, 0xfb, 0xfe, 0xfb, 0xfa, 0x7d, 0xfd, 0xfa, + 0xf9, 0xfd, 0x7b, 0x7c, 0x77, 0x72, 0x72, 0x70, 0x6d, 0x6b, 0x69, 0x66, + 0x67, 0x65, 0x63, 0x62, 0x60, 0x62, 0x63, 0x62, 0x62, 0x61, 0x62, 0x61, + 0x60, 0x61, 0x60, 0x61, 0x61, 0x61, 0x63, 0x66, 0x67, 0x68, 0x6b, 0x6d, + 0x6e, 0x74, 0x7b, 0xfd, 0xfa, 0xf7, 0xf2, 0xef, 0xee, 0xee, 0xed, 0xec, + 0xea, 0xe9, 0xe8, 0xe6, 0xe6, 0xe7, 0xe9, 0xeb, 0xea, 0xe9, 0xe6, 0xe4, + 0xe3, 0xe0, 0xdf, 0xde, 0xdd, 0xde, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xe0, + 0xe2, 0xe4, 0xe9, 0xe8, 0xe6, 0xe9, 0xeb, 0xeb, 0xeb, 0xef, 0xf2, 0xf0, + 0xf4, 0xfa, 0xfe, 0x77, 0x74, 0x74, 0x71, 0x6f, 0x6f, 0x71, 0x6f, 0x6e, + 0x71, 0x73, 0x76, 0x7c, 0xff, 0xfe, 0xfa, 0xfb, 0xfb, 0xf5, 0xf5, 0xfa, + 0xfb, 0xfc, 0xfe, 0x7e, 0xff, 0x79, 0x74, 0x76, 0x79, 0x75, 0x74, 0x7a, + 0x78, 0x75, 0x75, 0x72, 0x6f, 0x6d, 0x6d, 0x6d, 0x69, 0x65, 0x63, 0x63, + 0x61, 0x5e, 0x5f, 0x60, 0x60, 0x60, 0x61, 0x5f, 0x5e, 0x5f, 0x5f, 0x60, + 0x63, 0x65, 0x68, 0x69, 0x6a, 0x6c, 0x6c, 0x6e, 0x70, 0x76, 0x7b, 0xfe, + 0xf5, 0xef, 0xef, 0xef, 0xec, 0xea, 0xeb, 0xe9, 0xe8, 0xec, 0xf0, 0xf4, + 0xef, 0xeb, 0xe9, 0xea, 0xe6, 0xe0, 0xde, 0xdd, 0xdc, 0xda, 0xd9, 0xd9, + 0xdb, 0xdd, 0xdd, 0xde, 0xe2, 0xe2, 0xe1, 0xe3, 0xe6, 0xe5, 0xe4, 0xe6, + 0xe7, 0xe7, 0xe9, 0xed, 0xef, 0xf6, 0xfe, 0xff, 0x7b, 0x72, 0x72, 0x73, + 0x6f, 0x6e, 0x6f, 0x73, 0x6f, 0x6d, 0x6c, 0x6b, 0x6a, 0x6a, 0x6e, 0x73, + 0x75, 0x7a, 0x7e, 0xfa, 0xf7, 0xf2, 0xef, 0xee, 0xee, 0xf0, 0xf2, 0xf4, + 0xf9, 0xf9, 0xfc, 0xfe, 0x7d, 0x79, 0x77, 0x72, 0x73, 0x71, 0x6d, 0x6d, + 0x6d, 0x68, 0x65, 0x67, 0x66, 0x60, 0x5f, 0x5e, 0x5f, 0x5e, 0x5d, 0x5d, + 0x5e, 0x5e, 0x5e, 0x5e, 0x60, 0x61, 0x62, 0x66, 0x66, 0x64, 0x67, 0x69, + 0x66, 0x67, 0x6a, 0x6b, 0x6a, 0x6c, 0x71, 0x72, 0x74, 0x76, 0x75, 0x7a, + 0x79, 0x7a, 0xf8, 0xef, 0xeb, 0xe7, 0xdf, 0xdc, 0xda, 0xd7, 0xd4, 0xd2, + 0xd0, 0xd0, 0xd1, 0xd3, 0xd3, 0xd6, 0xda, 0xdd, 0xde, 0xdf, 0xe5, 0xe5, + 0xe5, 0xe9, 0xeb, 0xeb, 0xef, 0xf2, 0xf5, 0x7d, 0x72, 0x6f, 0x6e, 0x6d, + 0x6c, 0x6e, 0x73, 0x72, 0x72, 0x73, 0x75, 0x78, 0x77, 0x74, 0x74, 0x72, + 0x72, 0x73, 0x6f, 0x6f, 0x72, 0x74, 0x7d, 0xf3, 0xef, 0xec, 0xe7, 0xe5, + 0xe6, 0xe6, 0xe7, 0xe9, 0xea, 0xee, 0xfa, 0xfd, 0xfd, 0x7a, 0x79, 0xfe, + 0xfd, 0x78, 0x74, 0x71, 0x6b, 0x66, 0x65, 0x65, 0x5f, 0x5e, 0x5f, 0x5e, + 0x5d, 0x5d, 0x5e, 0x5e, 0x5d, 0x5e, 0x5e, 0x5f, 0x5f, 0x5e, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5e, 0x5e, 0x5e, 0x60, 0x5f, + 0x62, 0x67, 0x68, 0x6d, 0xfd, 0xee, 0xe7, 0xdd, 0xd6, 0xd2, 0xcf, 0xcd, + 0xcb, 0xcb, 0xcb, 0xca, 0xcb, 0xcd, 0xcf, 0xd0, 0xd4, 0xd8, 0xdb, 0xdf, + 0xe9, 0xea, 0xed, 0xfc, 0x7b, 0x7a, 0x71, 0x6b, 0x68, 0x65, 0x60, 0x5f, + 0x5f, 0x5f, 0x5f, 0x63, 0x67, 0x6b, 0x77, 0xf8, 0xef, 0xec, 0xe8, 0xe5, + 0xe6, 0xe9, 0xed, 0xf4, 0xfe, 0x76, 0x6f, 0x6f, 0x72, 0x79, 0xfb, 0xee, + 0xe7, 0xe2, 0xdf, 0xde, 0xde, 0xe0, 0xe7, 0xef, 0xfd, 0x74, 0x6e, 0x71, + 0x72, 0x75, 0x7c, 0xfc, 0xfa, 0x7e, 0x77, 0x6f, 0x67, 0x60, 0x5d, 0x5a, + 0x58, 0x58, 0x57, 0x57, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x59, 0x59, + 0x59, 0x57, 0x56, 0x55, 0x55, 0x55, 0x56, 0x56, 0x57, 0x5a, 0x5b, 0x5d, + 0x61, 0x64, 0x64, 0x68, 0x6f, 0x7c, 0xee, 0xe4, 0xdc, 0xd3, 0xce, 0xcc, + 0xc9, 0xc6, 0xc5, 0xc5, 0xc5, 0xc6, 0xc9, 0xcb, 0xce, 0xd4, 0xd8, 0xdc, + 0xe5, 0xed, 0xf4, 0xfd, 0x73, 0x6a, 0x66, 0x64, 0x5f, 0x5d, 0x5c, 0x5b, + 0x5c, 0x5c, 0x5d, 0x64, 0x6f, 0x7b, 0xf7, 0xe6, 0xdf, 0xdf, 0xdc, 0xdb, + 0xdc, 0xdf, 0xe5, 0xe9, 0xf2, 0xfe, 0x74, 0x6b, 0x6a, 0x68, 0x63, 0x61, + 0x65, 0x67, 0x63, 0x63, 0x67, 0x6c, 0x73, 0x7c, 0xef, 0xe3, 0xdf, 0xdc, + 0xd8, 0xd4, 0xd4, 0xd6, 0xd8, 0xdb, 0xe0, 0xe8, 0xf7, 0x6e, 0x66, 0x5e, + 0x5a, 0x59, 0x58, 0x59, 0x57, 0x57, 0x59, 0x58, 0x56, 0x55, 0x54, 0x53, + 0x50, 0x50, 0x51, 0x53, 0x54, 0x55, 0x57, 0x58, 0x57, 0x55, 0x54, 0x53, + 0x51, 0x4f, 0x50, 0x50, 0x50, 0x52, 0x52, 0x57, 0x69, 0x7c, 0xfa, 0xd8, + 0xca, 0xc9, 0xc7, 0xbf, 0xbf, 0xc0, 0xbf, 0xc1, 0xc4, 0xc5, 0xca, 0xce, + 0xcf, 0xd2, 0xd7, 0xe1, 0xe6, 0xe6, 0x74, 0x60, 0x63, 0x5c, 0x53, 0x52, + 0x52, 0x53, 0x58, 0x5c, 0x5f, 0x74, 0xe6, 0xde, 0xdd, 0xd7, 0xd1, 0xd5, + 0xd9, 0xd7, 0xda, 0xe2, 0xe2, 0xe6, 0xee, 0xf6, 0x77, 0x6a, 0x65, 0x5f, + 0x58, 0x51, 0x50, 0x4f, 0x4d, 0x4c, 0x4f, 0x53, 0x56, 0x60, 0x7a, 0xec, + 0xdf, 0xd6, 0xd0, 0xcd, 0xcc, 0xcc, 0xcb, 0xcb, 0xcd, 0xcf, 0xd3, 0xd6, + 0xdd, 0xe9, 0xf1, 0x76, 0x63, 0x5d, 0x58, 0x53, 0x52, 0x50, 0x4e, 0x4f, + 0x51, 0x51, 0x4f, 0x52, 0x57, 0x56, 0x53, 0x55, 0x57, 0x55, 0x54, 0x54, + 0x53, 0x51, 0x4f, 0x4d, 0x4e, 0x4d, 0x4b, 0x4a, 0x4c, 0x4c, 0x4b, 0x4c, + 0x4d, 0x4d, 0x56, 0x7a, 0xf8, 0xde, 0xc6, 0xc0, 0xc1, 0xbb, 0xb8, 0xbb, + 0xbc, 0xbd, 0xc1, 0xc5, 0xca, 0xce, 0xd5, 0xd8, 0xd8, 0xee, 0x75, 0xf0, + 0x62, 0x51, 0x55, 0x52, 0x4d, 0x4f, 0x55, 0x5c, 0x6e, 0xe7, 0xd8, 0xd2, + 0xcb, 0xc9, 0xce, 0xcd, 0xcc, 0xd6, 0xde, 0xdc, 0xe1, 0xf0, 0xfd, 0x75, + 0x69, 0x5d, 0x56, 0x4e, 0x4b, 0x4a, 0x47, 0x44, 0x49, 0x4e, 0x4f, 0x58, + 0x6e, 0xef, 0xe4, 0xdb, 0xd5, 0xd2, 0xcf, 0xce, 0xd0, 0xcd, 0xc8, 0xcc, + 0xcd, 0xc9, 0xcd, 0xd9, 0xdf, 0xf4, 0x61, 0x58, 0x56, 0x51, 0x51, 0x57, + 0x58, 0x59, 0x66, 0x67, 0x5d, 0x5e, 0x61, 0x59, 0x54, 0x56, 0x54, 0x52, + 0x51, 0x51, 0x4f, 0x4f, 0x4d, 0x48, 0x46, 0x45, 0x3f, 0x3e, 0x3f, 0x40, + 0x41, 0x44, 0x49, 0x4c, 0x4e, 0x4f, 0x53, 0xfe, 0xd3, 0xd5, 0xc7, 0xb7, + 0xb7, 0xb9, 0xb4, 0xb5, 0xb9, 0xbd, 0xc7, 0xce, 0xd7, 0xef, 0x66, 0x5f, + 0x7d, 0x64, 0x4e, 0x5c, 0x5e, 0x4c, 0x4e, 0x53, 0x58, 0x6f, 0xed, 0xd7, + 0xc9, 0xc1, 0xbf, 0xc4, 0xbf, 0xc0, 0xcf, 0xd7, 0xd5, 0xe8, 0x76, 0x67, + 0x62, 0x61, 0x58, 0x4f, 0x4b, 0x4a, 0x49, 0x42, 0x44, 0x4d, 0x4f, 0x58, + 0xf7, 0xdb, 0xd3, 0xd1, 0xd2, 0xd3, 0xd4, 0xd6, 0xe0, 0xdd, 0xcf, 0xd3, + 0xdb, 0xcf, 0xcf, 0xdd, 0xed, 0xfb, 0x6d, 0x5f, 0x5a, 0x5c, 0x68, 0xf9, + 0xff, 0xfc, 0xde, 0xe2, 0x6e, 0x69, 0x69, 0x5d, 0x56, 0x54, 0x56, 0x55, + 0x52, 0x4d, 0x49, 0x49, 0x43, 0x3e, 0x3e, 0x3f, 0x3d, 0x3c, 0x3e, 0x41, + 0x41, 0x41, 0x43, 0x48, 0x4a, 0x49, 0x4b, 0x51, 0x72, 0xcd, 0xc6, 0xbf, + 0xb3, 0xb1, 0xb7, 0xb6, 0xb8, 0xc0, 0xcb, 0xd7, 0xe6, 0xea, 0xf8, 0x6e, + 0x66, 0xfc, 0x6a, 0x4b, 0x4f, 0x59, 0x4c, 0x53, 0xfd, 0xdb, 0xca, 0xc3, + 0xbf, 0xbd, 0xbd, 0xc1, 0xcd, 0xce, 0xcf, 0xfb, 0xf9, 0xe5, 0xfe, 0x77, + 0x63, 0x59, 0x53, 0x4c, 0x47, 0x44, 0x4b, 0x55, 0x55, 0x78, 0xd4, 0xd1, + 0xcf, 0xd1, 0xd6, 0xda, 0xea, 0x72, 0x7b, 0xe8, 0xe8, 0xec, 0xdc, 0xdc, + 0xf9, 0x70, 0x6b, 0x60, 0x61, 0x6d, 0xef, 0xdf, 0xd4, 0xd1, 0xd4, 0xd3, + 0xdb, 0x7d, 0x6d, 0x65, 0x59, 0x57, 0x5d, 0x5f, 0x5b, 0x58, 0x50, 0x4a, + 0x46, 0x40, 0x3c, 0x3d, 0x3d, 0x3c, 0x3e, 0x40, 0x3f, 0x3e, 0x3e, 0x3d, + 0x3d, 0x3e, 0x41, 0x45, 0x4b, 0x57, 0x5e, 0xdc, 0xbf, 0xbf, 0xbf, 0xb3, + 0xb2, 0xbb, 0xb9, 0xbc, 0xc5, 0xca, 0xd9, 0xf0, 0xe9, 0xee, 0x5c, 0x52, + 0x6c, 0x5b, 0x4a, 0x5a, 0x6f, 0x6b, 0xdc, 0xce, 0xc8, 0xbf, 0xbe, 0xc2, + 0xc2, 0xc0, 0xca, 0xdb, 0xd2, 0xd9, 0x76, 0x7e, 0x6c, 0x5e, 0x5b, 0x4f, + 0x4b, 0x4e, 0x53, 0x4f, 0x56, 0xeb, 0xdf, 0xe0, 0xd1, 0xcf, 0xd3, 0xd7, + 0xe2, 0xe9, 0xe2, 0xe6, 0x7d, 0xf3, 0xe1, 0xf9, 0x67, 0x6a, 0x64, 0x61, + 0x66, 0x6a, 0xf0, 0xdb, 0xdc, 0xdf, 0xd8, 0xda, 0xf7, 0x70, 0x76, 0x68, + 0x61, 0x61, 0x5d, 0x5e, 0x5c, 0x4f, 0x4b, 0x4b, 0x46, 0x3f, 0x3f, 0x40, + 0x3e, 0x3d, 0x3e, 0x3d, 0x3c, 0x3c, 0x3a, 0x3b, 0x3e, 0x3f, 0x41, 0x49, + 0x4e, 0x4f, 0x51, 0xf0, 0xc2, 0xbe, 0xbd, 0xb1, 0xaf, 0xb6, 0xb9, 0xbd, + 0xc9, 0xcf, 0xec, 0x6c, 0xea, 0xe5, 0x6b, 0x59, 0x6e, 0x62, 0x4a, 0x51, + 0x65, 0x7b, 0xd2, 0xcb, 0xc2, 0xbb, 0xbc, 0xc2, 0xc6, 0xc8, 0xd4, 0xff, + 0xec, 0xeb, 0x72, 0x6e, 0x5d, 0x5a, 0x57, 0x4a, 0x47, 0x4d, 0x57, 0x5c, + 0x79, 0xd3, 0xcc, 0xcc, 0xcd, 0xd4, 0xd5, 0xdb, 0xef, 0xdf, 0xd4, 0xd7, + 0xde, 0xdd, 0xe4, 0x6c, 0x60, 0x5d, 0x5e, 0x73, 0xfe, 0xf1, 0xdc, 0xd9, + 0xeb, 0xfc, 0xf3, 0x6b, 0x5c, 0x5e, 0x5f, 0x5e, 0x5c, 0x54, 0x4e, 0x4a, + 0x43, 0x3e, 0x3d, 0x3e, 0x3c, 0x3c, 0x3d, 0x3c, 0x3a, 0x38, 0x36, 0x37, + 0x3a, 0x3c, 0x3e, 0x49, 0x53, 0x50, 0x5e, 0xcc, 0xbc, 0xbc, 0xb8, 0xae, + 0xaf, 0xb8, 0xba, 0xc1, 0xca, 0xd2, 0x68, 0x68, 0xe5, 0x77, 0x57, 0x59, + 0x72, 0x59, 0x4e, 0x6d, 0xe4, 0xd1, 0xc6, 0xc4, 0xbc, 0xba, 0xc0, 0xc9, + 0xcb, 0xce, 0xef, 0x63, 0x6f, 0x64, 0x5b, 0x52, 0x4b, 0x4f, 0x4d, 0x46, + 0x4c, 0x61, 0xfd, 0xe7, 0xd1, 0xc8, 0xc8, 0xca, 0xcf, 0xd4, 0xd0, 0xd7, + 0xde, 0xd5, 0xd1, 0xdc, 0xe9, 0xf6, 0x71, 0x69, 0x61, 0x65, 0xeb, 0xde, + 0xe6, 0xe2, 0xdb, 0xe4, 0x76, 0x6e, 0x6c, 0x65, 0x61, 0x5a, 0x57, 0x54, + 0x4a, 0x42, 0x3e, 0x3c, 0x39, 0x37, 0x37, 0x37, 0x36, 0x36, 0x34, 0x34, + 0x36, 0x36, 0x39, 0x3d, 0x43, 0x4a, 0x78, 0xbc, 0xb6, 0xb8, 0xae, 0xac, + 0xb5, 0xb9, 0xbe, 0xc9, 0xca, 0xdb, 0x76, 0xe9, 0xec, 0x55, 0x46, 0x4f, + 0x50, 0x48, 0x5e, 0xdb, 0xcb, 0xbd, 0xbd, 0xbd, 0xb8, 0xbd, 0xc8, 0xcb, + 0xca, 0xd3, 0xf4, 0xf1, 0x6b, 0x53, 0x4c, 0x40, 0x3f, 0x45, 0x42, 0x46, + 0x5b, 0xef, 0xde, 0xd4, 0xcd, 0xcb, 0xcb, 0xce, 0xcf, 0xc7, 0xc4, 0xcb, + 0xcb, 0xca, 0xd5, 0xf0, 0x6d, 0x65, 0x6a, 0x6d, 0x69, 0xf1, 0xda, 0xe6, + 0x78, 0xef, 0xf2, 0x68, 0x66, 0x6b, 0x69, 0x65, 0x57, 0x4c, 0x48, 0x3f, + 0x3a, 0x37, 0x36, 0x34, 0x33, 0x33, 0x33, 0x32, 0x30, 0x2f, 0x33, 0x36, + 0x37, 0x41, 0xce, 0xb7, 0xb7, 0xaf, 0xaa, 0xae, 0xb8, 0xbd, 0xc8, 0xc8, + 0xcc, 0xf0, 0xde, 0xd2, 0x64, 0x46, 0x45, 0x49, 0x43, 0x4a, 0xfa, 0xce, + 0xbc, 0xb9, 0xbc, 0xb7, 0xb9, 0xc5, 0xcb, 0xc7, 0xc9, 0xd4, 0xdd, 0xeb, + 0x5f, 0x4e, 0x3f, 0x3c, 0x41, 0x43, 0x43, 0x58, 0xe2, 0xda, 0xd5, 0xcf, + 0xce, 0xcc, 0xcc, 0xcb, 0xc4, 0xbf, 0xc2, 0xca, 0xcb, 0xd6, 0x69, 0x59, + 0x58, 0x58, 0x5f, 0x67, 0xfc, 0xde, 0xe5, 0x73, 0x71, 0xf9, 0x6e, 0x63, + 0x79, 0x7c, 0x62, 0x52, 0x45, 0x3e, 0x3a, 0x34, 0x32, 0x32, 0x32, 0x31, + 0x32, 0x32, 0x31, 0x31, 0x33, 0x35, 0x3f, 0xd7, 0xba, 0xb7, 0xaf, 0xaa, + 0xaf, 0xb9, 0xbf, 0xce, 0xd0, 0xd3, 0xee, 0xdb, 0xd8, 0x5f, 0x48, 0x44, + 0x45, 0x42, 0x4d, 0xe7, 0xc9, 0xbb, 0xb8, 0xba, 0xb8, 0xbb, 0xc8, 0xcb, + 0xca, 0xcd, 0xd6, 0xdd, 0xf8, 0x59, 0x49, 0x3d, 0x3c, 0x40, 0x43, 0x49, + 0x6b, 0xda, 0xd3, 0xce, 0xce, 0xcc, 0xc4, 0xc5, 0xc6, 0xbd, 0xbb, 0xc1, + 0xc8, 0xcf, 0xe7, 0x62, 0x53, 0x4f, 0x5b, 0x6d, 0x62, 0x72, 0xe3, 0x6e, + 0x59, 0x5c, 0x5b, 0x57, 0x54, 0x50, 0x4c, 0x46, 0x3d, 0x37, 0x34, 0x31, + 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x31, 0x34, 0x37, 0x45, 0xcc, 0xbc, 0xb8, + 0xad, 0xac, 0xb1, 0xb6, 0xbf, 0xca, 0xc9, 0xd8, 0xeb, 0xd6, 0xde, 0x56, + 0x49, 0x4a, 0x48, 0x47, 0x5b, 0xdf, 0xc6, 0xba, 0xbc, 0xbb, 0xb8, 0xbe, + 0xca, 0xcb, 0xcd, 0xd3, 0xdf, 0xfc, 0x5e, 0x50, 0x46, 0x3d, 0x3e, 0x43, + 0x45, 0x4e, 0x7e, 0xd8, 0xce, 0xcc, 0xc7, 0xbf, 0xbf, 0xc1, 0xbe, 0xbb, + 0xbd, 0xc6, 0xcd, 0xd2, 0xef, 0x59, 0x51, 0x53, 0x5c, 0x5b, 0x5a, 0x75, + 0x7b, 0x5e, 0x58, 0x59, 0x57, 0x4d, 0x48, 0x44, 0x3f, 0x3a, 0x34, 0x30, + 0x2f, 0x2d, 0x2c, 0x2d, 0x2e, 0x30, 0x31, 0x3a, 0xdd, 0xbf, 0xbf, 0xb3, + 0xad, 0xb2, 0xb8, 0xbd, 0xc7, 0xc4, 0xcb, 0xee, 0xd9, 0xd7, 0x56, 0x46, + 0x4a, 0x4b, 0x4a, 0x5b, 0xdd, 0xc9, 0xbb, 0xbc, 0xbe, 0xb7, 0xbc, 0xc8, + 0xc6, 0xc6, 0xcd, 0xd9, 0xfa, 0x5d, 0x52, 0x46, 0x3d, 0x3f, 0x47, 0x46, + 0x4b, 0x6d, 0xe1, 0xd8, 0xce, 0xca, 0xc2, 0xbd, 0xc0, 0xbf, 0xbb, 0xbe, + 0xc9, 0xcf, 0xda, 0xfb, 0x5c, 0x53, 0x55, 0x5f, 0x5e, 0x59, 0x6e, 0xff, + 0x5c, 0x56, 0x57, 0x50, 0x4a, 0x42, 0x3d, 0x3b, 0x37, 0x30, 0x2e, 0x2f, + 0x2d, 0x2c, 0x2f, 0x30, 0x33, 0x4e, 0xc8, 0xc5, 0xb9, 0xae, 0xb3, 0xb9, + 0xba, 0xca, 0xcc, 0xc8, 0xef, 0xf1, 0xd4, 0x62, 0x49, 0x4c, 0x4c, 0x46, + 0x56, 0xe6, 0xd2, 0xbe, 0xbb, 0xbe, 0xb9, 0xba, 0xc6, 0xc7, 0xc6, 0xcf, + 0xda, 0xeb, 0x5b, 0x4f, 0x49, 0x3d, 0x3d, 0x43, 0x43, 0x49, 0x65, 0xe2, + 0xd1, 0xc8, 0xc6, 0xbf, 0xbb, 0xbd, 0xbe, 0xba, 0xbc, 0xc5, 0xcb, 0xd6, + 0xf8, 0x64, 0x58, 0x55, 0x61, 0x66, 0x5b, 0x6c, 0xf6, 0x5c, 0x54, 0x53, + 0x4a, 0x44, 0x3d, 0x38, 0x35, 0x31, 0x2e, 0x2d, 0x2d, 0x2d, 0x2e, 0x30, + 0x3b, 0xdf, 0xca, 0xc7, 0xb2, 0xb0, 0xbc, 0xbd, 0xc5, 0xcf, 0xca, 0xdc, + 0xfd, 0xd3, 0xe0, 0x4f, 0x4c, 0x54, 0x4c, 0x4d, 0xef, 0xcf, 0xc2, 0xba, + 0xbc, 0xba, 0xb7, 0xc1, 0xcb, 0xc5, 0xcc, 0xdb, 0xe8, 0x6b, 0x56, 0x4b, + 0x3f, 0x3c, 0x41, 0x44, 0x44, 0x54, 0xe2, 0xd5, 0xcd, 0xc8, 0xc3, 0xbf, + 0xbf, 0xc1, 0xbe, 0xbd, 0xc5, 0xce, 0xd3, 0xe9, 0x5c, 0x54, 0x54, 0x5a, + 0x64, 0x63, 0x7c, 0xe5, 0x70, 0x57, 0x51, 0x4c, 0x40, 0x39, 0x35, 0x34, + 0x31, 0x2d, 0x2d, 0x2f, 0x2f, 0x2f, 0x3f, 0xd9, 0xcd, 0xc3, 0xb3, 0xb4, + 0xbb, 0xbe, 0xcf, 0xd4, 0xcc, 0x75, 0x6c, 0xd5, 0x71, 0x4c, 0x4e, 0x4f, + 0x4b, 0x51, 0x78, 0xd4, 0xbf, 0xbb, 0xbd, 0xb8, 0xb7, 0xc3, 0xca, 0xc9, + 0xd3, 0xdf, 0xfa, 0x5d, 0x5a, 0x4e, 0x3f, 0x3f, 0x46, 0x44, 0x46, 0x5b, + 0xe0, 0xcd, 0xc7, 0xc5, 0xbf, 0xbd, 0xc2, 0xc5, 0xbf, 0xc2, 0xca, 0xce, + 0xd5, 0xec, 0x60, 0x54, 0x51, 0x59, 0x5b, 0x58, 0x69, 0xf9, 0x5c, 0x4e, + 0x49, 0x41, 0x3a, 0x33, 0x2f, 0x30, 0x2e, 0x2c, 0x2f, 0x34, 0x39, 0x5a, + 0xd1, 0xce, 0xba, 0xb5, 0xbe, 0xbd, 0xbf, 0xd5, 0xd0, 0xd6, 0x7a, 0xe8, + 0xf6, 0x52, 0x4e, 0x54, 0x4d, 0x4e, 0xf3, 0xd3, 0xc8, 0xbc, 0xba, 0xb9, + 0xb8, 0xbe, 0xc5, 0xc5, 0xd0, 0xee, 0xf9, 0x5f, 0x4f, 0x4b, 0x43, 0x3f, + 0x41, 0x41, 0x43, 0x4e, 0x73, 0xdc, 0xcc, 0xc1, 0xbe, 0xbd, 0xbd, 0xc1, + 0xc1, 0xc3, 0xce, 0xd5, 0xd9, 0x7b, 0x5d, 0x58, 0x51, 0x50, 0x53, 0x56, + 0x5f, 0x6d, 0x5c, 0x50, 0x4d, 0x43, 0x3a, 0x34, 0x2f, 0x2e, 0x2e, 0x2e, + 0x32, 0x3b, 0x5f, 0xd0, 0xcf, 0xbc, 0xb7, 0xc4, 0xc5, 0xc6, 0xd8, 0xcf, + 0xd5, 0xf8, 0xda, 0xf5, 0x4d, 0x4d, 0x4e, 0x48, 0x4b, 0x78, 0xd1, 0xc6, + 0xbc, 0xba, 0xb9, 0xb8, 0xbf, 0xc7, 0xc5, 0xcf, 0xef, 0xee, 0x6c, 0x55, + 0x4c, 0x42, 0x3f, 0x42, 0x3f, 0x43, 0x57, 0xeb, 0xd6, 0xc7, 0xbe, 0xbc, + 0xbb, 0xbe, 0xbf, 0xbe, 0xc6, 0xd1, 0xcf, 0xdb, 0x67, 0x57, 0x50, 0x4e, + 0x4d, 0x4c, 0x4f, 0x57, 0x55, 0x4d, 0x4b, 0x45, 0x3a, 0x32, 0x2f, 0x2e, + 0x2d, 0x2f, 0x34, 0x42, 0xdd, 0xca, 0xc9, 0xb9, 0xba, 0xcb, 0xcb, 0xce, + 0xdf, 0xd4, 0xdf, 0xe7, 0xda, 0x62, 0x4b, 0x4c, 0x4b, 0x48, 0x52, 0xdd, + 0xc7, 0xbe, 0xb9, 0xb7, 0xb6, 0xb9, 0xc3, 0xc8, 0xc8, 0xd8, 0xf0, 0xef, + 0x69, 0x55, 0x4a, 0x41, 0x42, 0x42, 0x40, 0x4b, 0x74, 0xd5, 0xc9, 0xbf, + 0xb9, 0xb9, 0xbd, 0xbe, 0xc0, 0xc9, 0xd2, 0xda, 0xde, 0x7c, 0x55, 0x4e, + 0x4d, 0x47, 0x44, 0x47, 0x4a, 0x4a, 0x47, 0x43, 0x3f, 0x37, 0x2f, 0x2e, + 0x2e, 0x2e, 0x31, 0x3d, 0x78, 0xc5, 0xc5, 0xbb, 0xb5, 0xc0, 0xce, 0xcd, + 0xde, 0xdf, 0xdf, 0xed, 0xd3, 0xde, 0x53, 0x4e, 0x4e, 0x48, 0x49, 0x62, + 0xcf, 0xc1, 0xbb, 0xb7, 0xb5, 0xb7, 0xbf, 0xca, 0xc9, 0xd6, 0x6d, 0xfb, + 0xfb, 0x5e, 0x53, 0x48, 0x43, 0x42, 0x3e, 0x43, 0x5c, 0xe2, 0xcd, 0xbd, + 0xb7, 0xb9, 0xbb, 0xbc, 0xc4, 0xcb, 0xd3, 0xdf, 0xdc, 0xe8, 0x67, 0x68, + 0x5c, 0x4c, 0x4a, 0x48, 0x45, 0x43, 0x42, 0x3e, 0x37, 0x31, 0x2e, 0x2c, + 0x2c, 0x2f, 0x36, 0x4e, 0xc8, 0xc1, 0xba, 0xb0, 0xba, 0xc6, 0xc9, 0xe7, + 0x72, 0xf5, 0x66, 0xeb, 0xdf, 0x5d, 0x52, 0x50, 0x47, 0x44, 0x4f, 0xea, + 0xcb, 0xbe, 0xb7, 0xb3, 0xb3, 0xb8, 0xc1, 0xc8, 0xd8, 0x63, 0x5f, 0x63, + 0x59, 0x53, 0x4d, 0x49, 0x45, 0x40, 0x46, 0x56, 0x73, 0xcb, 0xbb, 0xb8, + 0xb6, 0xb5, 0xbb, 0xc2, 0xcb, 0xdd, 0xf5, 0x7e, 0x6b, 0x69, 0x6b, 0x5c, + 0x51, 0x4c, 0x44, 0x3e, 0x3d, 0x39, 0x31, 0x30, 0x30, 0x2d, 0x2e, 0x33, + 0x35, 0x48, 0xcc, 0xc8, 0xbd, 0xb0, 0xb9, 0xc1, 0xbf, 0xdc, 0x71, 0xf6, + 0x53, 0x5d, 0xf3, 0x55, 0x53, 0x5c, 0x4c, 0x4b, 0x5b, 0xee, 0xce, 0xbf, + 0xb8, 0xb3, 0xb0, 0xb4, 0xba, 0xbd, 0xcc, 0x71, 0x60, 0x55, 0x4b, 0x4c, + 0x49, 0x46, 0x49, 0x4b, 0x4b, 0x59, 0xde, 0xcb, 0xc2, 0xb9, 0xb6, 0xb8, + 0xbb, 0xbf, 0xcc, 0xdb, 0x6c, 0x5c, 0x5f, 0x57, 0x50, 0x53, 0x4e, 0x45, + 0x3e, 0x39, 0x32, 0x2e, 0x2c, 0x2c, 0x2c, 0x2e, 0x35, 0x3c, 0x6e, 0xc0, + 0xc0, 0xb8, 0xaf, 0xb9, 0xbf, 0xc1, 0xdd, 0xef, 0x7b, 0x4e, 0x5c, 0x5e, + 0x47, 0x4c, 0x51, 0x49, 0x4d, 0x69, 0xd9, 0xc7, 0xbc, 0xb6, 0xb2, 0xb1, + 0xb5, 0xbb, 0xbe, 0xcc, 0x7a, 0x66, 0x57, 0x4a, 0x4a, 0x47, 0x47, 0x51, + 0x4e, 0x51, 0xe1, 0xce, 0xcb, 0xbd, 0xb8, 0xb9, 0xb9, 0xbb, 0xc3, 0xcb, + 0xdc, 0x64, 0x69, 0x5e, 0x4d, 0x4f, 0x50, 0x43, 0x3e, 0x37, 0x2e, 0x2c, + 0x2a, 0x29, 0x2a, 0x2e, 0x32, 0x3c, 0xe0, 0xbe, 0xbe, 0xb4, 0xae, 0xb9, + 0xbd, 0xc2, 0xe8, 0xeb, 0x69, 0x4b, 0x60, 0x58, 0x43, 0x4d, 0x4d, 0x45, + 0x4d, 0x64, 0xd9, 0xc4, 0xbc, 0xb5, 0xaf, 0xaf, 0xb5, 0xb9, 0xbd, 0xce, + 0xfd, 0x6a, 0x52, 0x4b, 0x4b, 0x48, 0x52, 0x59, 0x4e, 0x7c, 0xd3, 0xda, + 0xc6, 0xbb, 0xbc, 0xbb, 0xbb, 0xbf, 0xc5, 0xd0, 0xfe, 0x6a, 0x5f, 0x4e, + 0x4c, 0x4f, 0x46, 0x3d, 0x37, 0x2e, 0x2c, 0x2a, 0x27, 0x29, 0x2e, 0x2f, + 0x3c, 0xcf, 0xbd, 0xbc, 0xb0, 0xae, 0xb7, 0xbb, 0xc4, 0xdd, 0xdf, 0x5c, + 0x4c, 0x6b, 0x52, 0x42, 0x4d, 0x4b, 0x42, 0x4b, 0x5d, 0xdd, 0xc4, 0xbc, + 0xb5, 0xae, 0xaf, 0xb6, 0xb7, 0xbc, 0xd3, 0xfe, 0x62, 0x4e, 0x4a, 0x4b, + 0x4d, 0x57, 0x5b, 0x5e, 0xe9, 0xd9, 0xd4, 0xc8, 0xbf, 0xbd, 0xbd, 0xbe, + 0xbf, 0xc8, 0xd8, 0xfe, 0x5d, 0x4f, 0x49, 0x45, 0x42, 0x3d, 0x34, 0x2e, + 0x2d, 0x2a, 0x27, 0x29, 0x2d, 0x2f, 0x3c, 0xce, 0xbd, 0xb9, 0xad, 0xad, + 0xb5, 0xb8, 0xc6, 0xe6, 0xe0, 0x54, 0x4d, 0xfb, 0x52, 0x48, 0x58, 0x4c, + 0x44, 0x4b, 0x54, 0xef, 0xc8, 0xbd, 0xb4, 0xae, 0xae, 0xb3, 0xb5, 0xbc, + 0xd7, 0x6b, 0x57, 0x48, 0x4c, 0x55, 0x4f, 0x6a, 0xe4, 0x6d, 0xe3, 0xd1, + 0xdb, 0xcd, 0xc3, 0xc4, 0xbf, 0xbd, 0xc3, 0xc9, 0xd5, 0x65, 0x51, 0x4a, + 0x3f, 0x3c, 0x39, 0x30, 0x2d, 0x2d, 0x29, 0x28, 0x2b, 0x2c, 0x2f, 0x49, + 0xcc, 0xc0, 0xb2, 0xaa, 0xad, 0xb2, 0xb7, 0xca, 0xde, 0x67, 0x49, 0x57, + 0x5d, 0x49, 0x55, 0x5b, 0x48, 0x4a, 0x4d, 0x52, 0xe6, 0xcd, 0xbf, 0xb3, + 0xaf, 0xb0, 0xb0, 0xb4, 0xbf, 0xd3, 0x72, 0x4e, 0x4b, 0x4f, 0x4e, 0x61, + 0xdb, 0xec, 0xe1, 0xd1, 0xe9, 0xe7, 0xd0, 0xd0, 0xc8, 0xc2, 0xc4, 0xc2, + 0xc8, 0xdf, 0x6d, 0x52, 0x41, 0x3b, 0x34, 0x2e, 0x2d, 0x2b, 0x29, 0x2a, + 0x2c, 0x2c, 0x33, 0x57, 0xd6, 0xc5, 0xaf, 0xac, 0xaf, 0xaf, 0xb7, 0xc6, + 0xcd, 0x5a, 0x48, 0x5b, 0x49, 0x44, 0x5b, 0x4f, 0x4a, 0x53, 0x4f, 0x5e, + 0xe4, 0xd8, 0xc1, 0xb6, 0xb4, 0xb3, 0xaf, 0xb5, 0xbf, 0xcc, 0xf6, 0x5b, + 0x56, 0x4c, 0x59, 0xdb, 0xdf, 0xdc, 0xc9, 0xce, 0xda, 0xd3, 0xd5, 0xcf, + 0xcc, 0xce, 0xc6, 0xc6, 0xdb, 0xf8, 0x61, 0x44, 0x38, 0x2f, 0x2d, 0x2b, + 0x29, 0x28, 0x2c, 0x2e, 0x2e, 0x3d, 0xdc, 0xdb, 0xc2, 0xaf, 0xb1, 0xb4, + 0xb3, 0xbf, 0xc3, 0xce, 0x4e, 0x5e, 0x64, 0x3f, 0x49, 0x58, 0x48, 0x4d, + 0x54, 0x5a, 0xdf, 0xd6, 0xcd, 0xba, 0xb5, 0xb7, 0xb3, 0xb2, 0xba, 0xc4, + 0xce, 0xdf, 0x76, 0x56, 0x54, 0xec, 0xe2, 0xfc, 0xd2, 0xcb, 0xd6, 0xd6, + 0xcf, 0xce, 0xcf, 0xd5, 0xce, 0xca, 0xda, 0x76, 0x68, 0x4c, 0x39, 0x30, + 0x2d, 0x2b, 0x28, 0x27, 0x2b, 0x2d, 0x2f, 0x3f, 0xe3, 0xd2, 0xbe, 0xb1, + 0xb2, 0xb4, 0xb6, 0xbf, 0xc2, 0xce, 0x5f, 0xf8, 0x70, 0x49, 0x50, 0x54, + 0x49, 0x4d, 0x4d, 0x55, 0xeb, 0xde, 0xce, 0xbb, 0xb7, 0xb7, 0xb4, 0xb4, + 0xba, 0xc3, 0xcd, 0xd2, 0xeb, 0x59, 0x68, 0xe2, 0xef, 0xf0, 0xd9, 0xd3, + 0xdb, 0xe2, 0xd9, 0xd2, 0xda, 0xda, 0xce, 0xcf, 0xe3, 0x70, 0x5a, 0x42, + 0x34, 0x2e, 0x2c, 0x29, 0x28, 0x29, 0x2c, 0x2e, 0x3b, 0x6a, 0xd6, 0xc1, + 0xb2, 0xb3, 0xb4, 0xb5, 0xbf, 0xc5, 0xcb, 0x65, 0x76, 0xf4, 0x4d, 0x58, + 0x5e, 0x4c, 0x51, 0x52, 0x4f, 0x6e, 0xe4, 0xd6, 0xc0, 0xba, 0xb9, 0xb5, + 0xb5, 0xba, 0xbf, 0xca, 0xd1, 0xe1, 0x64, 0x6b, 0xe1, 0xe2, 0xde, 0xcf, + 0xce, 0xd7, 0xda, 0xd9, 0xda, 0xdd, 0xdf, 0xd9, 0xd6, 0xe8, 0x66, 0x58, + 0x41, 0x34, 0x2f, 0x2d, 0x29, 0x29, 0x2b, 0x2c, 0x2f, 0x40, 0x6e, 0xdb, + 0xbd, 0xb2, 0xb6, 0xb5, 0xb6, 0xc2, 0xc3, 0xcf, 0x69, 0xe1, 0x6f, 0x4d, + 0x64, 0x59, 0x4a, 0x52, 0x4f, 0x52, 0x7a, 0xec, 0xcf, 0xbe, 0xbc, 0xb9, + 0xb5, 0xb7, 0xbc, 0xc2, 0xc9, 0xd1, 0xf2, 0x6b, 0xeb, 0xe2, 0xea, 0xdc, + 0xd1, 0xd5, 0xdd, 0xdb, 0xd9, 0xdf, 0xe1, 0xdb, 0xd7, 0xde, 0x74, 0x5f, + 0x4a, 0x38, 0x31, 0x2e, 0x2a, 0x29, 0x2a, 0x2b, 0x2e, 0x3a, 0x5d, 0xe0, + 0xc2, 0xb2, 0xb4, 0xb6, 0xb4, 0xbf, 0xc7, 0xc9, 0xfe, 0xed, 0xe3, 0x54, + 0x65, 0x6e, 0x4a, 0x4d, 0x4f, 0x4a, 0x56, 0x69, 0xdf, 0xc6, 0xbe, 0xba, + 0xb6, 0xb5, 0xb9, 0xbf, 0xc5, 0xcb, 0xde, 0xf7, 0xde, 0xd5, 0xd7, 0xd2, + 0xcb, 0xce, 0xd9, 0xdc, 0xdf, 0xeb, 0xf4, 0xef, 0xdf, 0xe2, 0x72, 0x5f, + 0x4b, 0x3a, 0x33, 0x2e, 0x2b, 0x29, 0x2a, 0x2b, 0x2e, 0x3d, 0x5e, 0xe7, + 0xc0, 0xb4, 0xb8, 0xb7, 0xb6, 0xc3, 0xc7, 0xcb, 0x7e, 0xdb, 0xe2, 0x56, + 0xf7, 0x6b, 0x49, 0x4f, 0x4d, 0x48, 0x52, 0x5b, 0xee, 0xca, 0xc2, 0xbc, + 0xb7, 0xb8, 0xbc, 0xbf, 0xc3, 0xcb, 0xda, 0xde, 0xd2, 0xd0, 0xd2, 0xcb, + 0xc9, 0xcf, 0xd9, 0xda, 0xdf, 0xef, 0x7e, 0xef, 0xe3, 0xfa, 0x5e, 0x54, + 0x42, 0x35, 0x2f, 0x2d, 0x2a, 0x29, 0x2b, 0x2c, 0x35, 0x4e, 0x69, 0xcd, + 0xb5, 0xb7, 0xba, 0xb5, 0xbe, 0xca, 0xc8, 0xe5, 0xe7, 0xd6, 0x5e, 0x73, + 0xde, 0x51, 0x4e, 0x57, 0x4a, 0x4b, 0x54, 0x63, 0xd7, 0xc7, 0xc1, 0xba, + 0xb7, 0xbb, 0xbe, 0xbf, 0xc6, 0xd3, 0xd8, 0xcf, 0xce, 0xd0, 0xcb, 0xc6, + 0xcb, 0xd7, 0xdb, 0xe0, 0x72, 0x5f, 0x67, 0x73, 0x64, 0x55, 0x4e, 0x43, + 0x37, 0x30, 0x2e, 0x2b, 0x2a, 0x2b, 0x2c, 0x35, 0x4d, 0x60, 0xcf, 0xb6, + 0xb8, 0xbb, 0xb5, 0xbe, 0xcc, 0xc9, 0xe5, 0xe2, 0xd3, 0x68, 0xee, 0xd6, + 0x5b, 0x54, 0x5b, 0x4c, 0x4c, 0x50, 0x5b, 0xdd, 0xcc, 0xc6, 0xbb, 0xb8, + 0xbb, 0xbe, 0xbe, 0xc3, 0xd0, 0xd6, 0xcc, 0xcc, 0xcf, 0xc8, 0xc4, 0xcb, + 0xd2, 0xd8, 0xe2, 0x7e, 0x5e, 0x5f, 0x6d, 0x5e, 0x50, 0x4b, 0x3f, 0x36, + 0x2f, 0x2d, 0x2b, 0x2a, 0x2a, 0x2d, 0x3b, 0x51, 0x65, 0xc3, 0xb4, 0xba, + 0xb9, 0xb6, 0xc2, 0xc7, 0xcb, 0xec, 0xd4, 0xd7, 0x67, 0xd9, 0xdb, 0x58, + 0x5c, 0x57, 0x4b, 0x4e, 0x4e, 0x5a, 0xdc, 0xd0, 0xca, 0xbd, 0xbb, 0xbe, + 0xc0, 0xbe, 0xc3, 0xd3, 0xce, 0xc4, 0xcc, 0xcd, 0xc2, 0xc5, 0xcd, 0xd1, + 0xdd, 0xe5, 0x6d, 0x57, 0x62, 0x62, 0x50, 0x4c, 0x45, 0x3b, 0x34, 0x2f, + 0x2d, 0x2b, 0x2a, 0x2b, 0x2f, 0x3f, 0x4e, 0x68, 0xbd, 0xb6, 0xbd, 0xb6, + 0xb7, 0xc4, 0xc1, 0xcd, 0xda, 0xc7, 0xdc, 0xe7, 0xc8, 0xe0, 0x62, 0x79, + 0x53, 0x4b, 0x4b, 0x48, 0x56, 0xfb, 0xea, 0xce, 0xbf, 0xbe, 0xc1, 0xbe, + 0xbc, 0xc4, 0xcd, 0xc2, 0xc1, 0xcb, 0xc4, 0xbf, 0xc5, 0xcb, 0xd3, 0xdd, + 0xeb, 0x57, 0x50, 0x5c, 0x51, 0x48, 0x44, 0x3f, 0x39, 0x32, 0x2f, 0x2d, + 0x2c, 0x2b, 0x2d, 0x35, 0x48, 0x4e, 0xe7, 0xb8, 0xba, 0xbd, 0xb3, 0xbb, + 0xc3, 0xbe, 0xd3, 0xcd, 0xc4, 0xe5, 0xd1, 0xc5, 0xed, 0x7a, 0xf5, 0x52, + 0x4d, 0x49, 0x48, 0x54, 0x60, 0x6c, 0xd7, 0xc7, 0xc6, 0xc9, 0xbf, 0xbe, + 0xca, 0xc7, 0xbe, 0xc3, 0xc3, 0xbe, 0xc2, 0xc3, 0xc8, 0xdc, 0xda, 0xee, + 0x52, 0x55, 0x56, 0x4a, 0x43, 0x3d, 0x39, 0x35, 0x2f, 0x2d, 0x2d, 0x2d, + 0x2c, 0x2f, 0x3f, 0x4e, 0x58, 0xc4, 0xb8, 0xbe, 0xb8, 0xb6, 0xc1, 0xbe, + 0xc5, 0xd7, 0xc3, 0xcd, 0xea, 0xc7, 0xce, 0x75, 0xea, 0x68, 0x4f, 0x4e, + 0x49, 0x4a, 0x59, 0x64, 0x70, 0xd7, 0xca, 0xcc, 0xc7, 0xbf, 0xc5, 0xc7, + 0xbf, 0xc0, 0xc3, 0xbd, 0xbf, 0xc3, 0xbf, 0xcb, 0xda, 0xd6, 0x7b, 0x59, + 0x59, 0x4e, 0x47, 0x40, 0x3b, 0x37, 0x32, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, + 0x34, 0x46, 0x4d, 0x79, 0xbd, 0xbc, 0xbe, 0xb5, 0xba, 0xc1, 0xbd, 0xc9, + 0xce, 0xc3, 0xd0, 0xd6, 0xc8, 0xd8, 0xfd, 0xf3, 0x59, 0x4b, 0x49, 0x48, + 0x48, 0x4f, 0x5f, 0x73, 0xdc, 0xcb, 0xca, 0xc6, 0xc0, 0xc5, 0xc2, 0xbe, + 0xc2, 0xbf, 0xbb, 0xc1, 0xc4, 0xc1, 0xcd, 0xdc, 0xe2, 0x72, 0x5a, 0x52, + 0x4b, 0x41, 0x3c, 0x39, 0x34, 0x30, 0x2f, 0x2e, 0x2e, 0x2f, 0x30, 0x3a, + 0x4c, 0x51, 0xde, 0xbc, 0xbf, 0xbf, 0xb6, 0xbc, 0xc3, 0xbe, 0xc6, 0xca, + 0xc5, 0xcc, 0xce, 0xcc, 0xd6, 0xea, 0x79, 0x5e, 0x4d, 0x49, 0x4c, 0x4b, + 0x4c, 0x63, 0xf8, 0xed, 0xcf, 0xc7, 0xc9, 0xc6, 0xbf, 0xbf, 0xc0, 0xbe, + 0xbb, 0xbd, 0xbf, 0xc0, 0xc6, 0xcd, 0xd7, 0xee, 0x6d, 0x5a, 0x4d, 0x47, + 0x3f, 0x3c, 0x38, 0x34, 0x31, 0x2f, 0x2f, 0x2e, 0x2f, 0x33, 0x3d, 0x4a, + 0x4f, 0xd8, 0xbe, 0xc4, 0xc0, 0xb9, 0xbe, 0xc6, 0xc1, 0xc3, 0xcb, 0xca, + 0xc8, 0xc9, 0xcd, 0xd2, 0xdd, 0x7e, 0x5e, 0x50, 0x4a, 0x4d, 0x4f, 0x4d, + 0x5b, 0xef, 0xee, 0xdb, 0xca, 0xc9, 0xcb, 0xc2, 0xbe, 0xc2, 0xbf, 0xbb, + 0xbd, 0xc1, 0xbf, 0xc3, 0xcf, 0xd8, 0xde, 0x69, 0x54, 0x52, 0x47, 0x3d, + 0x3c, 0x39, 0x35, 0x33, 0x33, 0x31, 0x2f, 0x32, 0x34, 0x3a, 0x47, 0x4f, + 0x7a, 0xca, 0xc4, 0xc6, 0xc0, 0xbd, 0xc4, 0xcc, 0xc4, 0xc3, 0xce, 0xcc, + 0xc4, 0xc7, 0xd2, 0xd4, 0xd3, 0xfb, 0x5c, 0x5a, 0x57, 0x57, 0x56, 0x5f, + 0xfd, 0xee, 0xdb, 0xd1, 0xd3, 0xcd, 0xc7, 0xc7, 0xc8, 0xc3, 0xbe, 0xc0, + 0xc4, 0xc1, 0xc3, 0xcd, 0xd6, 0xda, 0xf5, 0x5b, 0x53, 0x4e, 0x44, 0x3e, + 0x3d, 0x3b, 0x36, 0x34, 0x34, 0x33, 0x32, 0x34, 0x35, 0x3b, 0x46, 0x4d, + 0x5f, 0xd6, 0xca, 0xcb, 0xca, 0xc4, 0xc5, 0xcc, 0xcc, 0xc5, 0xc5, 0xc8, + 0xc6, 0xc2, 0xc6, 0xce, 0xd5, 0xdd, 0x7a, 0x63, 0x5d, 0x5a, 0x60, 0x65, + 0x6e, 0xf1, 0xdc, 0xd0, 0xd4, 0xd6, 0xcc, 0xc8, 0xcb, 0xca, 0xc2, 0xbf, + 0xc3, 0xc7, 0xc5, 0xc7, 0xd3, 0xe2, 0xf2, 0x6a, 0x5c, 0x4c, 0x47, 0x47, + 0x40, 0x3f, 0x3c, 0x39, 0x3c, 0x38, 0x36, 0x36, 0x37, 0x39, 0x3c, 0x47, + 0x4f, 0x62, 0xdd, 0xd3, 0xcf, 0xd0, 0xcc, 0xca, 0xd2, 0xd0, 0xca, 0xc6, + 0xc4, 0xc5, 0xc4, 0xc3, 0xc8, 0xd0, 0xd9, 0xe8, 0x73, 0x6e, 0x68, 0x66, + 0x77, 0xf2, 0xea, 0xe3, 0xde, 0xdc, 0xdc, 0xdb, 0xd6, 0xcf, 0xcd, 0xcb, + 0xc7, 0xc7, 0xc9, 0xcb, 0xd0, 0xd9, 0xe5, 0xf6, 0x6d, 0x63, 0x58, 0x4f, + 0x4d, 0x4b, 0x48, 0x42, 0x3f, 0x3f, 0x3c, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, + 0x3e, 0x47, 0x4d, 0x54, 0x67, 0xe5, 0xd9, 0xd8, 0xd9, 0xd5, 0xd1, 0xd2, + 0xcf, 0xcd, 0xca, 0xc7, 0xc4, 0xc4, 0xc9, 0xcb, 0xce, 0xd4, 0xdc, 0xeb, + 0xec, 0xe3, 0xe6, 0xe5, 0xe6, 0xe3, 0xde, 0xdd, 0xdc, 0xde, 0xdc, 0xd5, + 0xd4, 0xd2, 0xcf, 0xcf, 0xce, 0xd2, 0xda, 0xdd, 0xe6, 0xf7, 0x7d, 0x6f, + 0x69, 0x68, 0x5d, 0x59, 0x56, 0x4d, 0x4c, 0x4c, 0x4c, 0x4a, 0x44, 0x46, + 0x45, 0x43, 0x47, 0x42, 0x42, 0x45, 0x48, 0x52, 0x55, 0x5c, 0x6a, 0x72, + 0xef, 0xf5, 0xea, 0xe2, 0xe3, 0xdb, 0xd6, 0xcf, 0xcc, 0xcb, 0xca, 0xcc, + 0xcd, 0xd0, 0xd4, 0xd7, 0xda, 0xda, 0xd8, 0xd6, 0xd6, 0xd6, 0xd5, 0xd9, + 0xdd, 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdd, 0xdd, 0xde, 0xdf, 0xe6, 0xe9, + 0xf2, 0xfe, 0xf3, 0xfc, 0x70, 0x79, 0x7b, 0x6e, 0x67, 0x67, 0x65, 0x5c, + 0x58, 0x56, 0x57, 0x56, 0x54, 0x57, 0x52, 0x4f, 0x4e, 0x4b, 0x4a, 0x49, + 0x47, 0x48, 0x4c, 0x4f, 0x53, 0x5a, 0x5d, 0x60, 0x67, 0x65, 0x69, 0x6b, + 0x70, 0xf9, 0xeb, 0xdf, 0xda, 0xd5, 0xcf, 0xd0, 0xcf, 0xcf, 0xd3, 0xd2, + 0xd2, 0xd1, 0xcf, 0xd0, 0xd0, 0xd1, 0xd4, 0xd7, 0xdc, 0xde, 0xdf, 0xe2, + 0xe0, 0xdf, 0xdf, 0xe6, 0xe9, 0xe7, 0xec, 0xfc, 0x7b, 0x7c, 0x72, 0x6c, + 0x72, 0x7c, 0x75, 0x77, 0xfa, 0x73, 0x6f, 0x6c, 0x64, 0x68, 0x61, 0x62, + 0x64, 0x5c, 0x5f, 0x5e, 0x5b, 0x5d, 0x58, 0x57, 0x59, 0x54, 0x56, 0x56, + 0x53, 0x53, 0x53, 0x54, 0x57, 0x56, 0x59, 0x5f, 0x61, 0x63, 0x68, 0x6d, + 0x71, 0x7e, 0xfc, 0xf5, 0xe7, 0xe4, 0xe2, 0xda, 0xd9, 0xdb, 0xdb, 0xd9, + 0xd9, 0xda, 0xd9, 0xd8, 0xd7, 0xd7, 0xda, 0xda, 0xdc, 0xdf, 0xe3, 0xe9, + 0xea, 0xef, 0xf6, 0xef, 0xf5, 0x78, 0x79, 0xff, 0x73, 0x70, 0x73, 0x6f, + 0x70, 0x6f, 0x74, 0xfc, 0xff, 0xfb, 0xfd, 0x76, 0x79, 0x7b, 0x7a, 0x77, + 0x7c, 0x78, 0x6d, 0xf0, 0xf5, 0x64, 0x74, 0x76, 0x65, 0x6e, 0x6b, 0x6a, + 0x69, 0x5f, 0x69, 0x67, 0x5f, 0x65, 0x61, 0x61, 0x63, 0x5e, 0x5f, 0x60, + 0x5c, 0x5d, 0x5f, 0x61, 0x62, 0x61, 0x68, 0x77, 0x75, 0x6e, 0x7e, 0xfe, + 0x77, 0xf8, 0xf7, 0xf4, 0xeb, 0xec, 0xe8, 0xe3, 0xe6, 0xe1, 0xde, 0xe0, + 0xde, 0xdd, 0xdf, 0xdd, 0xdf, 0xe0, 0xde, 0xe7, 0xe5, 0xe5, 0xf6, 0xf3, + 0xf5, 0xfd, 0x7d, 0x7b, 0xfa, 0x7d, 0x7a, 0x76, 0x76, 0x78, 0x6d, 0xe2, + 0xe8, 0x55, 0x6a, 0xea, 0x61, 0x79, 0xf6, 0x6a, 0xfb, 0xfa, 0x79, 0xf5, + 0x7e, 0xfe, 0xf6, 0x75, 0x79, 0x7d, 0x79, 0xfe, 0x79, 0x71, 0x75, 0x79, + 0x6d, 0x6e, 0x75, 0x6e, 0x6f, 0x69, 0x6d, 0x79, 0x6b, 0x6b, 0x74, 0x70, + 0x6f, 0x6f, 0x6c, 0x70, 0x71, 0x71, 0x73, 0x6d, 0x6d, 0x64, 0xfa, 0xee, + 0x5a, 0x65, 0x6c, 0x64, 0x7d, 0x6f +}; + +static InputStream *generateHelloWorld(void) +{ + return _alutInputStreamConstructFromMemory(helloWorldSample, sizeof(helloWorldSample)); +} + +ALvoid *alutLoadMemoryHelloWorld(ALenum * format, ALsizei * size, ALfloat * frequency) +{ + if (!_alutSanityCheck()) + { + return NULL; + } + return _alutLoadMemoryFromInputStream(generateHelloWorld(), format, size, frequency); +} + +ALuint alutCreateBufferHelloWorld(void) +{ + if (!_alutSanityCheck()) + { + return AL_NONE; + } + return _alutCreateBufferFromInputStream(generateHelloWorld()); +} diff --git a/tests/freealut/src/helloworld.wav b/tests/freealut/src/helloworld.wav new file mode 100644 index 0000000000000000000000000000000000000000..cca9f4c7a6787666574acc50a5816927664938da GIT binary patch literal 65462 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
    ~hF2Nd{bx8iV|3`5> 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 N>0|yu9DPF7e*r7Ocy9mz literal 0 HcmV?d00001 diff --git a/tests/freealut/test_suite/Makefile.am b/tests/freealut/test_suite/Makefile.am new file mode 100644 index 0000000000000..898e192549746 --- /dev/null +++ b/tests/freealut/test_suite/Makefile.am @@ -0,0 +1,27 @@ +# The following files should be in our source distribution in addition to the +# standard ones included by automake itself: +EXTRA_DIST = \ + file1.wav \ + file2.au \ + file3.raw + +# Build, but do not install the following test programs: +noinst_PROGRAMS = \ + test_errorstuff \ + test_fileloader \ + test_memoryloader \ + test_retrostuff \ + test_version \ + test_waveforms + +# We need to link against our *own* libalut. +LDADD = ../src/libalut.la + +# Specifying the following path is needed to find . +AM_CPPFLAGS = -I$(top_srcdir)/include + +# test_retrostuff tests deprecated functions, but we don't want to get compiler +# warnings because of that. +if WNO_DEPRECATED_DECLARATIONS +test_retrostuff_CFLAGS = -Wno-deprecated-declarations +endif diff --git a/tests/freealut/test_suite/Makefile.in b/tests/freealut/test_suite/Makefile.in new file mode 100644 index 0000000000000..ed7c67ca9d272 --- /dev/null +++ b/tests/freealut/test_suite/Makefile.in @@ -0,0 +1,513 @@ +# Makefile.in generated by automake 1.9.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = test_errorstuff.c test_fileloader.c test_memoryloader.c test_retrostuff.c test_version.c test_waveforms.c + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = test_errorstuff$(EXEEXT) test_fileloader$(EXEEXT) \ + test_memoryloader$(EXEEXT) test_retrostuff$(EXEEXT) \ + test_version$(EXEEXT) test_waveforms$(EXEEXT) +subdir = test_suite +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = \ + $(top_srcdir)/admin/autotools/m4/alut_c__attribute.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_cflags_wall.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_flag.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_check_func.m4 \ + $(top_srcdir)/admin/autotools/m4/alut_eval_stderr.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) +test_errorstuff_SOURCES = test_errorstuff.c +test_errorstuff_OBJECTS = test_errorstuff.$(OBJEXT) +test_errorstuff_LDADD = $(LDADD) +test_errorstuff_DEPENDENCIES = ../src/libalut.la +test_fileloader_SOURCES = test_fileloader.c +test_fileloader_OBJECTS = test_fileloader.$(OBJEXT) +test_fileloader_LDADD = $(LDADD) +test_fileloader_DEPENDENCIES = ../src/libalut.la +test_memoryloader_SOURCES = test_memoryloader.c +test_memoryloader_OBJECTS = test_memoryloader.$(OBJEXT) +test_memoryloader_LDADD = $(LDADD) +test_memoryloader_DEPENDENCIES = ../src/libalut.la +test_retrostuff_SOURCES = test_retrostuff.c +test_retrostuff_OBJECTS = test_retrostuff-test_retrostuff.$(OBJEXT) +test_retrostuff_LDADD = $(LDADD) +test_retrostuff_DEPENDENCIES = ../src/libalut.la +test_version_SOURCES = test_version.c +test_version_OBJECTS = test_version.$(OBJEXT) +test_version_LDADD = $(LDADD) +test_version_DEPENDENCIES = ../src/libalut.la +test_waveforms_SOURCES = test_waveforms.c +test_waveforms_OBJECTS = test_waveforms.$(OBJEXT) +test_waveforms_LDADD = $(LDADD) +test_waveforms_DEPENDENCIES = ../src/libalut.la +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/autotools/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = test_errorstuff.c test_fileloader.c test_memoryloader.c \ + test_retrostuff.c test_version.c test_waveforms.c +DIST_SOURCES = test_errorstuff.c test_fileloader.c test_memoryloader.c \ + test_retrostuff.c test_version.c test_waveforms.c +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBM = @LIBM@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VERSIONINFO = @VERSIONINFO@ +WNO_DEPRECATED_DECLARATIONS_FALSE = @WNO_DEPRECATED_DECLARATIONS_FALSE@ +WNO_DEPRECATED_DECLARATIONS_TRUE = @WNO_DEPRECATED_DECLARATIONS_TRUE@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_AS = @ac_ct_AS@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ + +# The following files should be in our source distribution in addition to the +# standard ones included by automake itself: +EXTRA_DIST = \ + file1.wav \ + file2.au \ + file3.raw + + +# We need to link against our *own* libalut. +LDADD = ../src/libalut.la + +# Specifying the following path is needed to find . +AM_CPPFLAGS = -I$(top_srcdir)/include + +# test_retrostuff tests deprecated functions, but we don't want to get compiler +# warnings because of that. +@WNO_DEPRECATED_DECLARATIONS_TRUE@test_retrostuff_CFLAGS = -Wno-deprecated-declarations +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test_suite/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu test_suite/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +test_errorstuff$(EXEEXT): $(test_errorstuff_OBJECTS) $(test_errorstuff_DEPENDENCIES) + @rm -f test_errorstuff$(EXEEXT) + $(LINK) $(test_errorstuff_LDFLAGS) $(test_errorstuff_OBJECTS) $(test_errorstuff_LDADD) $(LIBS) +test_fileloader$(EXEEXT): $(test_fileloader_OBJECTS) $(test_fileloader_DEPENDENCIES) + @rm -f test_fileloader$(EXEEXT) + $(LINK) $(test_fileloader_LDFLAGS) $(test_fileloader_OBJECTS) $(test_fileloader_LDADD) $(LIBS) +test_memoryloader$(EXEEXT): $(test_memoryloader_OBJECTS) $(test_memoryloader_DEPENDENCIES) + @rm -f test_memoryloader$(EXEEXT) + $(LINK) $(test_memoryloader_LDFLAGS) $(test_memoryloader_OBJECTS) $(test_memoryloader_LDADD) $(LIBS) +test_retrostuff$(EXEEXT): $(test_retrostuff_OBJECTS) $(test_retrostuff_DEPENDENCIES) + @rm -f test_retrostuff$(EXEEXT) + $(LINK) $(test_retrostuff_LDFLAGS) $(test_retrostuff_OBJECTS) $(test_retrostuff_LDADD) $(LIBS) +test_version$(EXEEXT): $(test_version_OBJECTS) $(test_version_DEPENDENCIES) + @rm -f test_version$(EXEEXT) + $(LINK) $(test_version_LDFLAGS) $(test_version_OBJECTS) $(test_version_LDADD) $(LIBS) +test_waveforms$(EXEEXT): $(test_waveforms_OBJECTS) $(test_waveforms_DEPENDENCIES) + @rm -f test_waveforms$(EXEEXT) + $(LINK) $(test_waveforms_LDFLAGS) $(test_waveforms_OBJECTS) $(test_waveforms_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_errorstuff.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fileloader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_memoryloader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_retrostuff-test_retrostuff.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_version.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_waveforms.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +test_retrostuff-test_retrostuff.o: test_retrostuff.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_retrostuff_CFLAGS) $(CFLAGS) -MT test_retrostuff-test_retrostuff.o -MD -MP -MF "$(DEPDIR)/test_retrostuff-test_retrostuff.Tpo" -c -o test_retrostuff-test_retrostuff.o `test -f 'test_retrostuff.c' || echo '$(srcdir)/'`test_retrostuff.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/test_retrostuff-test_retrostuff.Tpo" "$(DEPDIR)/test_retrostuff-test_retrostuff.Po"; else rm -f "$(DEPDIR)/test_retrostuff-test_retrostuff.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test_retrostuff.c' object='test_retrostuff-test_retrostuff.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_retrostuff_CFLAGS) $(CFLAGS) -c -o test_retrostuff-test_retrostuff.o `test -f 'test_retrostuff.c' || echo '$(srcdir)/'`test_retrostuff.c + +test_retrostuff-test_retrostuff.obj: test_retrostuff.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_retrostuff_CFLAGS) $(CFLAGS) -MT test_retrostuff-test_retrostuff.obj -MD -MP -MF "$(DEPDIR)/test_retrostuff-test_retrostuff.Tpo" -c -o test_retrostuff-test_retrostuff.obj `if test -f 'test_retrostuff.c'; then $(CYGPATH_W) 'test_retrostuff.c'; else $(CYGPATH_W) '$(srcdir)/test_retrostuff.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/test_retrostuff-test_retrostuff.Tpo" "$(DEPDIR)/test_retrostuff-test_retrostuff.Po"; else rm -f "$(DEPDIR)/test_retrostuff-test_retrostuff.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test_retrostuff.c' object='test_retrostuff-test_retrostuff.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_retrostuff_CFLAGS) $(CFLAGS) -c -o test_retrostuff-test_retrostuff.obj `if test -f 'test_retrostuff.c'; then $(CYGPATH_W) 'test_retrostuff.c'; else $(CYGPATH_W) '$(srcdir)/test_retrostuff.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tests/freealut/test_suite/README b/tests/freealut/test_suite/README new file mode 100644 index 0000000000000..905fbd9f8d298 --- /dev/null +++ b/tests/freealut/test_suite/README @@ -0,0 +1,33 @@ + +ALUT Test Suite +~~~~~~~~~~~~~~~ + +These programs are not intended to be particularly excellent +programming style (some of them are downright terrible!) - but +they do provide a reasonable way to test out that ALUT is working +correctly. + +test_version : Tests that the ALUT header file version agrees with + the ALUT library version. + +test_waveforms : Plays a second of 440Hz audio using a variety of waveforms + in order to exercise the ALUT sound synthesis routines. + +test_errorstuff : Tries to load a non-existant file in order to test ALUT's + error handler. + +test_fileloader : Loads three files (in different formats) using ALUT's + 'standard' file loader. + +test_memoryloader: Loads a WAV file into memory - then uses ALUT's + 'File Image' loader. + +test_retrostuff : Loads a WAV file using the two old-fashioned methods from + ALUT 0.x.x + +If compiling these programs produces lots of errors, then you've probably +got an old ALUT header file lying around somewhere. If that's the case +then the 'test_version' program should at least have compiled. You +can run it to verify the version numbers of both header and ALUT library +binary. + diff --git a/tests/freealut/test_suite/file1.wav b/tests/freealut/test_suite/file1.wav new file mode 100644 index 0000000000000000000000000000000000000000..101029c5bf0abad9fc68bbaea63b55abbb97d982 GIT binary patch literal 6246 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 +#include +#include + +/* + * This is a minimal test for error handling. + */ + +int main(int argc, char **argv) +{ + ALuint buffer; + + alutInit(&argc, argv); + buffer = alutCreateBufferFromFile("no_such_file_in_existance.wav"); + alutExit(); + + if (buffer != AL_NONE) + { + fprintf(stderr, "expected an I/O error\n"); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/tests/freealut/test_suite/test_fileloader.c b/tests/freealut/test_suite/test_fileloader.c new file mode 100644 index 0000000000000..ce447daff94aa --- /dev/null +++ b/tests/freealut/test_suite/test_fileloader.c @@ -0,0 +1,74 @@ +#include +#include +#include + +/* + * This program loads and plays a variety of files, basically an automated + * version of examples/playfile.c. + */ + +static void playFile(const char *fileName) +{ + ALuint buffer; + ALuint source; + ALenum error; + ALint status; + + /* Create an AL buffer from the given sound file. */ + buffer = alutCreateBufferFromFile(fileName); + if (buffer == AL_NONE) + { + error = alutGetError(); + fprintf(stderr, "Error loading file: '%s'\n", alutGetErrorString(error)); + alutExit(); + exit(EXIT_FAILURE); + } + + /* Generate a single source, attach the buffer to it and start playing. */ + alGenSources(1, &source); + alSourcei(source, AL_BUFFER, buffer); + alSourcePlay(source); + + /* Normally nothing should go wrong above, but one never knows... */ + error = alGetError(); + if (error != ALUT_ERROR_NO_ERROR) + { + fprintf(stderr, "%s\n", alGetString(error)); + alutExit(); + exit(EXIT_FAILURE); + } + + /* Check every 0.1 seconds if the sound is still playing. */ + do + { + alutSleep(0.1f); + alGetSourcei(source, AL_SOURCE_STATE, &status); + } + while (status == AL_PLAYING); +} + +int main(int argc, char **argv) +{ + /* Initialise ALUT and eat any ALUT-specific commandline flags. */ + if (!alutInit(&argc, argv)) + { + ALenum error = alutGetError(); + + fprintf(stderr, "%s\n", alutGetErrorString(error)); + exit(EXIT_FAILURE); + } + + /* If everything is OK, play the sound files and exit when finished. */ + playFile("file1.wav"); + playFile("file2.au"); + playFile("file3.raw"); + + if (!alutExit()) + { + ALenum error = alutGetError(); + + fprintf(stderr, "%s\n", alutGetErrorString(error)); + exit(EXIT_FAILURE); + } + return EXIT_SUCCESS; +} diff --git a/tests/freealut/test_suite/test_memoryloader.c b/tests/freealut/test_suite/test_memoryloader.c new file mode 100644 index 0000000000000..a51e1744c0205 --- /dev/null +++ b/tests/freealut/test_suite/test_memoryloader.c @@ -0,0 +1,98 @@ +#include +#include +#include + +/* + * This program loads and plays a variety of files from memory, + * basically a modified version of test_suite/test_fileloader.c. + */ + +static ALbyte fileBuffer[100000]; + +static void playFile(const char *fileName) +{ + FILE *fileDescriptor; + size_t fileLength; + ALuint buffer; + ALuint source; + ALenum error; + ALint status; + + /* Load the sound file into memory. */ + fileDescriptor = fopen(fileName, "rb"); + if (fileDescriptor == NULL) + { + fprintf(stderr, "Error opening file %s\n", fileName); + alutExit(); + exit(EXIT_FAILURE); + } + + fileLength = fread(fileBuffer, 1, sizeof(fileBuffer), fileDescriptor); + if (ferror(fileDescriptor)) + { + fprintf(stderr, "Error reading file %s\n", fileName); + alutExit(); + exit(EXIT_FAILURE); + } + + fclose(fileDescriptor); + + /* Create an AL buffer from the given sound file. */ + buffer = alutCreateBufferFromFileImage(fileBuffer, fileLength); + if (buffer == AL_NONE) + { + error = alutGetError(); + fprintf(stderr, "Error creating buffer from file image: '%s'\n", alutGetErrorString(error)); + alutExit(); + exit(EXIT_FAILURE); + } + + /* Generate a single source, attach the buffer to it and start playing. */ + alGenSources(1, &source); + alSourcei(source, AL_BUFFER, buffer); + alSourcePlay(source); + + /* Normally nothing should go wrong above, but one never knows... */ + error = alGetError(); + if (error != ALUT_ERROR_NO_ERROR) + { + fprintf(stderr, "%s\n", alGetString(error)); + alutExit(); + exit(EXIT_FAILURE); + } + + /* Check every 0.1 seconds if the sound is still playing. */ + do + { + alutSleep(0.1f); + alGetSourcei(source, AL_SOURCE_STATE, &status); + } + while (status == AL_PLAYING); +} + +int main(int argc, char **argv) +{ + /* Initialise ALUT and eat any ALUT-specific commandline flags. */ + if (!alutInit(&argc, argv)) + { + ALenum error = alutGetError(); + + fprintf(stderr, "%s\n", alutGetErrorString(error)); + exit(EXIT_FAILURE); + } + + /* If everything is OK, play the sound files and exit when finished. */ + playFile("file1.wav"); + playFile("file2.au"); + /* Note that we can not play raw sound files from memory because the + * format can't be guessed without a file name. */ + + if (!alutExit()) + { + ALenum error = alutGetError(); + + fprintf(stderr, "%s\n", alutGetErrorString(error)); + exit(EXIT_FAILURE); + } + return EXIT_SUCCESS; +} diff --git a/tests/freealut/test_suite/test_retrostuff.c b/tests/freealut/test_suite/test_retrostuff.c new file mode 100644 index 0000000000000..97e3e9490691b --- /dev/null +++ b/tests/freealut/test_suite/test_retrostuff.c @@ -0,0 +1,79 @@ +#include +#include +#include + +/* + * This program loads and plays a file the deprecated ALUT 0.x.x way. + */ + +static void playFile(const char *fileName) +{ + ALenum format; + void *data; + ALsizei size; + ALsizei frequency; + +#if !defined(__APPLE__) + ALboolean loop; +#endif + ALuint buffer; + ALuint source; + ALenum error; + ALint status; + + /* Create an AL buffer from the given sound file. */ + alutLoadWAVFile((ALbyte *) "file1.wav", &format, &data, &size, &frequency +#if !defined(__APPLE__) + , &loop +#endif + ); + alGenBuffers(1, &buffer); + alBufferData(buffer, format, data, size, frequency); + free(data); + + /* Generate a single source, attach the buffer to it and start playing. */ + alGenSources(1, &source); + alSourcei(source, AL_BUFFER, buffer); + alSourcePlay(source); + + /* Normally nothing should go wrong above, but one never knows... */ + error = alGetError(); + if (error != ALUT_ERROR_NO_ERROR) + { + fprintf(stderr, "%s\n", alGetString(error)); + alutExit(); + exit(EXIT_FAILURE); + } + + /* Check every 0.1 seconds if the sound is still playing. */ + do + { + alutSleep(0.1f); + alGetSourcei(source, AL_SOURCE_STATE, &status); + } + while (status == AL_PLAYING); +} + +int main(int argc, char **argv) +{ + /* Initialise ALUT and eat any ALUT-specific commandline flags. */ + if (!alutInit(&argc, argv)) + { + ALenum error = alutGetError(); + + fprintf(stderr, "%s\n", alutGetErrorString(error)); + exit(EXIT_FAILURE); + } + + /* If everything is OK, play the sound files and exit when finished. */ + playFile("file1.wav"); + + if (!alutExit()) + { + ALenum error = alutGetError(); + + fprintf(stderr, "%s\n", alutGetErrorString(error)); + exit(EXIT_FAILURE); + } + return EXIT_SUCCESS; +} diff --git a/tests/freealut/test_suite/test_version.c b/tests/freealut/test_suite/test_version.c new file mode 100644 index 0000000000000..472522456bbf2 --- /dev/null +++ b/tests/freealut/test_suite/test_version.c @@ -0,0 +1,36 @@ +#include +#include +#include + +/* + This program checks that the version of OpenAL in the + library agrees with the header file we're compiled against. +*/ + +int main(int argc, char **argv) +{ + ALboolean ok = AL_FALSE; + + alutInit(&argc, argv); + +#ifdef ALUT_API_MAJOR_VERSION + if (alutGetMajorVersion() != ALUT_API_MAJOR_VERSION || alutGetMinorVersion() != ALUT_API_MINOR_VERSION) + { + fprintf(stderr, + "WARNING: The ALUT library is version %d.%d.x but says it's %d.%d.x!\n", + alutGetMajorVersion(), alutGetMinorVersion(), ALUT_API_MAJOR_VERSION, ALUT_API_MINOR_VERSION); + } + else + { + fprintf(stderr, "The ALUT library is at version %d.%d.x.\n", alutGetMajorVersion(), alutGetMinorVersion()); + ok = AL_TRUE; + } +#else + fprintf(stderr, "WARNING: Your copy of is pre-1.0.0,\n"); + fprintf(stderr, "but you are running the ALUT test suite from ALUT\n"); + fprintf(stderr, "version 1.0.0 or later.\n"); +#endif + + alutExit(); + return ok ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/tests/freealut/test_suite/test_waveforms.c b/tests/freealut/test_suite/test_waveforms.c new file mode 100644 index 0000000000000..fba854feb37e7 --- /dev/null +++ b/tests/freealut/test_suite/test_waveforms.c @@ -0,0 +1,31 @@ +#include +#include + +/* + * This program plays a 440Hz tone using a variety of waveforms. + */ + +static void playTone(ALenum waveshape) +{ + ALuint buffer, source; + + buffer = alutCreateBufferWaveform(waveshape, 440, 0, 1); + alGenSources(1, &source); + alSourcei(source, AL_BUFFER, buffer); + alSourcePlay(source); + alutSleep(1); +} + +int main(int argc, char **argv) +{ + alutInit(&argc, argv); + + playTone(ALUT_WAVEFORM_SINE); + playTone(ALUT_WAVEFORM_SQUARE); + playTone(ALUT_WAVEFORM_SAWTOOTH); + playTone(ALUT_WAVEFORM_WHITENOISE); + playTone(ALUT_WAVEFORM_IMPULSE); + + alutExit(); + return EXIT_SUCCESS; +} diff --git a/tests/runner.py b/tests/runner.py index 23935656275cd..62a8508531c26 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -11246,6 +11246,12 @@ def test_glfw(self): Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'glfw.c'), '-o', 'page.html']).communicate() self.run_browser('page.html', '', '/report_result?1') + def test_freealut(self): + programs = self.get_library('freealut', os.path.join('examples', 'hello_world.bc'), make_args=['EXEEXT=.bc']) + for program in programs: + Popen([PYTHON, EMCC, '-O2', program, '-o', 'page.html']).communicate() + self.run_browser('page.html', 'You should hear "Hello World!"') + def test_worker(self): # Test running in a web worker output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_worker.cpp'), '-o', 'worker.js'], stdout=PIPE, stderr=PIPE).communicate() From 6512c70b5487a9328e19a64f8118529eb4f77b55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Fri, 5 Apr 2013 00:07:11 +0200 Subject: [PATCH 057/544] * Fixed OpenAL currentContext. --- AUTHORS | 2 - src/library_openal.js | 200 ++++++++++++++++++++++-------------------- 2 files changed, 103 insertions(+), 99 deletions(-) diff --git a/AUTHORS b/AUTHORS index 438a13ff9d5ba..b67702650fe91 100644 --- a/AUTHORS +++ b/AUTHORS @@ -58,5 +58,3 @@ a license to everyone to use it as detailed in LICENSE.) * Felix H. Dahlke * Éloi Rivard * Alexander Gladysh - - diff --git a/src/library_openal.js b/src/library_openal.js index 3141974eaeeed..6a97fce734455 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -4,15 +4,20 @@ var LibraryOpenAL = { $AL__deps: ['$Browser'], $AL: { contexts: [], - currentContext: 0, + currentContext: null, }, alcProcessContext: function(context) {}, alcSuspendContext: function(context) {}, alcMakeContextCurrent: function(context) { - AL.currentContext = context; - return (context > 0); + if (context == 0) { + AL.currentContext = null; + return 0; + } else { + AL.currentContext = AL.contexts[context - 1]; + return 1; + } }, alcGetContextsDevice: function(context) { @@ -24,7 +29,12 @@ var LibraryOpenAL = { }, alcGetCurrentContext: function() { - return AL.currentContext; + for (var i = 0; i < AL.contexts.length; ++i) { + if (AL.contexts[i] == AL.currentContext) { + return i + 1; + } + } + return 0; }, alcDestroyContext: function(context) { @@ -74,10 +84,10 @@ var LibraryOpenAL = { }, alGetError: function() { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { return 0xA004 /* AL_INVALID_OPERATION */; } else { - return AL.contexts[AL.currentContext -1].err; + return AL.currentContext.err; } }, @@ -89,7 +99,7 @@ var LibraryOpenAL = { alDeleteSources: function(count, sources) { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alDeleteSources called without a valid context"); #endif @@ -97,26 +107,26 @@ var LibraryOpenAL = { } for (var i = 0; i < count; ++i) { var sourceIdx = {{{ makeGetValue('sources', 'i*4', 'i32') }}} - 1; - delete AL.contexts[AL.currentContext -1].src[sourceIdx]; + delete AL.currentContext.src[sourceIdx]; } }, alGenSources: function(count, sources) { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alGenSources called without a valid context"); #endif return; } for (var i = 0; i < count; ++i) { - var gain = AL.contexts[AL.currentContext -1].ctx.createGain(); - var panner = AL.contexts[AL.currentContext -1].ctx.createPanner(); + var gain = AL.currentContext.ctx.createGain(); + var panner = AL.currentContext.ctx.createPanner(); panner.panningModel = "equalpower"; panner.distanceModel = "linear"; panner.rolloffFactor = 0.3; gain.connect(panner); - panner.connect(AL.contexts[AL.currentContext -1].ctx.destination); - AL.contexts[AL.currentContext -1].src.push({ + panner.connect(AL.currentContext.ctx.destination); + AL.currentContext.src.push({ loop: false, buffer: null, gain: gain, @@ -125,18 +135,18 @@ var LibraryOpenAL = { playTime: -1, pausedTime: 0 }); - {{{ makeSetValue('sources', 'i*4', 'AL.contexts[AL.currentContext -1].src.length', 'i32') }}}; + {{{ makeSetValue('sources', 'i*4', 'AL.currentContext.src.length', 'i32') }}}; } }, alSourcei: function(source, param, value) { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alSourcei called without a valid context"); #endif return; } - if (source > AL.contexts[AL.currentContext -1].src.length) { + if (source > AL.currentContext.src.length) { #if OPENAL_DEBUG console.error("alSourcei called with an invalid source"); #endif @@ -144,13 +154,13 @@ var LibraryOpenAL = { } switch (param) { case 0x1007 /* AL_LOOPING */: - AL.contexts[AL.currentContext -1].src[source - 1].loop = (value != 0 /* AL_FALSE */); + AL.currentContext.src[source - 1].loop = (value != 0 /* AL_FALSE */); break; case 0x1009 /* AL_BUFFER */: if (value == 0) { - AL.contexts[AL.currentContext -1].src[source - 1].buffer = null; + AL.currentContext.src[source - 1].buffer = null; } else { - AL.contexts[AL.currentContext -1].src[source - 1].buffer = AL.contexts[AL.currentContext -1].buf[value - 1].buf; + AL.currentContext.src[source - 1].buffer = AL.currentContext.buf[value - 1].buf; } break; default: @@ -162,13 +172,13 @@ var LibraryOpenAL = { }, alSourcef: function(source, param, value) { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alSourcef called without a valid context"); #endif return; } - if (source > AL.contexts[AL.currentContext -1].src.length) { + if (source > AL.currentContext.src.length) { #if OPENAL_DEBUG console.error("alSourcef called with an invalid source"); #endif @@ -176,8 +186,8 @@ var LibraryOpenAL = { } switch (param) { case 0x100A /* AL_GAIN */: - if (AL.contexts[AL.currentContext -1].src[source - 1]) { - AL.contexts[AL.currentContext -1].src[source - 1].gain.gain.value = value; + if (AL.currentContext.src[source - 1]) { + AL.currentContext.src[source - 1].gain.gain.value = value; } break; case 0x1003 /* AL_PITCH */: @@ -194,13 +204,13 @@ var LibraryOpenAL = { }, alSourcefv: function(source, param, value) { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alSourcefv called without a valid context"); #endif return; } - if (source > AL.contexts[AL.currentContext -1].src.length) { + if (source > AL.currentContext.src.length) { #if OPENAL_DEBUG console.error("alSourcefv called with an invalid source"); #endif @@ -208,14 +218,14 @@ var LibraryOpenAL = { } switch (param) { case 0x1004 /* AL_POSITION */: - AL.contexts[AL.currentContext -1].src[source - 1].panner.setPosition( + AL.currentContext.src[source - 1].panner.setPosition( {{{ makeGetValue('value', '0', 'float') }}}, {{{ makeGetValue('value', '4', 'float') }}}, {{{ makeGetValue('value', '8', 'float') }}} ); break; case 0x1006 /* AL_VELOCITY */: - AL.contexts[AL.currentContext -1].src[source - 1].panner.setVelocity( + AL.currentContext.src[source - 1].panner.setVelocity( {{{ makeGetValue('value', '0', 'float') }}}, {{{ makeGetValue('value', '4', 'float') }}}, {{{ makeGetValue('value', '8', 'float') }}} @@ -230,13 +240,13 @@ var LibraryOpenAL = { }, alSourceQueueBuffers: function(source, count, buffers) { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alSourceQueueBuffers called without a valid context"); #endif return; } - if (source > AL.contexts[AL.currentContext -1].src.length) { + if (source > AL.currentContext.src.length) { #if OPENAL_DEBUG console.error("alSourceQueueBuffers called with an invalid source"); #endif @@ -250,25 +260,25 @@ var LibraryOpenAL = { } for (var i = 0; i < count; ++i) { var buffer = {{{ makeGetValue('buffers', 'i*4', 'i32') }}}; - if (buffer > AL.contexts[AL.currentContext -1].buf.length) { + if (buffer > AL.currentContext.buf.length) { #if OPENAL_DEBUG console.error("alSourceQueueBuffers called with an invalid buffer"); #endif return; } - AL.contexts[AL.currentContext -1].src[source - 1].buffer = AL.contexts[AL.currentContext -1].buf[buffer - 1].buf; + AL.currentContext.src[source - 1].buffer = AL.currentContext.buf[buffer - 1].buf; } }, alSourceUnqueueBuffers: function(source, count, buffers) { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alSourceUnqueueBuffers called without a valid context"); #endif return; } - if (source > AL.contexts[AL.currentContext -1].src.length) { + if (source > AL.currentContext.src.length) { #if OPENAL_DEBUG console.error("alSourceUnqueueBuffers called with an invalid source"); #endif @@ -281,11 +291,11 @@ var LibraryOpenAL = { return; } for (var i = 0; i < count; ++i) { - var buffer = AL.contexts[AL.currentContext -1].src[source - 1].buffer; - for (var j = 0; j < AL.contexts[AL.currentContext -1].buf.length; ++j) { - if (buffer == AL.contexts[AL.currentContext -1].buf[j].buf) { + var buffer = AL.currentContext.src[source - 1].buffer; + for (var j = 0; j < AL.currentContext.buf.length; ++j) { + if (buffer == AL.currentContext.buf[j].buf) { {{{ makeSetValue('buffers', 'i*4', 'j+1', 'i32') }}}; - AL.contexts[AL.currentContext -1].src[source - 1].buffer = null; + AL.currentContext.src[source - 1].buffer = null; break; } } @@ -294,7 +304,7 @@ var LibraryOpenAL = { alDeleteBuffers: function(count, buffers) { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alDeleteBuffers called without a valid context"); #endif @@ -302,40 +312,40 @@ var LibraryOpenAL = { } for (var i = 0; i < count; ++i) { var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}} - 1; - if (bufferIdx < AL.contexts[AL.currentContext -1].buf.length && AL.contexts[AL.currentContext -1].buf[bufferIdx]) { - var buffer = AL.contexts[AL.currentContext -1].buf[bufferIdx].buf; - for (var j = 0; j < AL.contexts[AL.currentContext -1].src.length; ++j) { - if (buffer == AL.contexts[AL.currentContext -1].src[j].buffer) { - AL.contexts[AL.currentContext -1].err = 0xA004 /* AL_INVALID_OPERATION */; + if (bufferIdx < AL.currentContext.buf.length && AL.currentContext.buf[bufferIdx]) { + var buffer = AL.currentContext.buf[bufferIdx].buf; + for (var j = 0; j < AL.currentContext.src.length; ++j) { + if (buffer == AL.currentContext.src[j].buffer) { + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } } - delete AL.contexts[AL.currentContext -1].buf[bufferIdx]; + delete AL.currentContext.buf[bufferIdx]; } } }, alGenBuffers: function(count, buffers) { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alGenBuffers called without a valid context"); #endif return; } for (var i = 0; i < count; ++i) { - AL.contexts[AL.currentContext -1].buf.push({buf: null}); - {{{ makeSetValue('buffers', 'i*4', 'AL.contexts[AL.currentContext -1].buf.length', 'i32') }}}; + AL.currentContext.buf.push({buf: null}); + {{{ makeSetValue('buffers', 'i*4', 'AL.currentContext.buf.length', 'i32') }}}; } }, alBufferData: function(buffer, format, data, size, freq) { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alBufferData called without a valid context"); #endif return; } - if (buffer > AL.contexts[AL.currentContext -1].buf.length) { + if (buffer > AL.currentContext.buf.length) { #if OPENAL_DEBUG console.error("alBufferData called with an invalid buffer"); #endif @@ -365,10 +375,10 @@ var LibraryOpenAL = { #endif return; } - AL.contexts[AL.currentContext -1].buf[buffer - 1].buf = AL.contexts[AL.currentContext -1].ctx.createBuffer(channels, size / (bytes * channels), freq); + AL.currentContext.buf[buffer - 1].buf = AL.currentContext.ctx.createBuffer(channels, size / (bytes * channels), freq); var buf = new Array(channels); for (var i = 0; i < channels; ++i) { - buf[i] = AL.contexts[AL.currentContext -1].buf[buffer - 1].buf.getChannelData(i); + buf[i] = AL.currentContext.buf[buffer - 1].buf.getChannelData(i); } for (var i = 0; i < size / (bytes * channels); ++i) { for (var j = 0; j < channels; ++j) { @@ -388,91 +398,91 @@ var LibraryOpenAL = { alSourcePlay__deps: ["alSourceStop"], alSourcePlay: function(source) { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alSourcePlay called without a valid context"); #endif return; } - if (source > AL.contexts[AL.currentContext -1].src.length) { + if (source > AL.currentContext.src.length) { #if OPENAL_DEBUG console.error("alSourcePlay called with an invalid source"); #endif return; } var offset = 0; - if ("src" in AL.contexts[AL.currentContext -1].src[source - 1] && - AL.contexts[AL.currentContext -1].src[source - 1]["src"].buffer == - AL.contexts[AL.currentContext -1].src[source - 1].buffer) { - if (AL.contexts[AL.currentContext -1].src[source - 1].paused) { + if ("src" in AL.currentContext.src[source - 1] && + AL.currentContext.src[source - 1]["src"].buffer == + AL.currentContext.src[source - 1].buffer) { + if (AL.currentContext.src[source - 1].paused) { // So now we have to resume playback, remember the offset here. - offset = AL.contexts[AL.currentContext -1].src[source - 1].pausedTime - - AL.contexts[AL.currentContext -1].src[source - 1].playTime; + offset = AL.currentContext.src[source - 1].pausedTime - + AL.currentContext.src[source - 1].playTime; } else { // If the source is already playing, we need to resume from beginning. // We do that by stopping the current source and replaying it. _alSourceStop(source); } } - var src = AL.contexts[AL.currentContext -1].ctx.createBufferSource(); - src.loop = AL.contexts[AL.currentContext -1].src[source - 1].loop; - src.buffer = AL.contexts[AL.currentContext -1].src[source - 1].buffer; - src.connect(AL.contexts[AL.currentContext -1].src[source - 1].gain); + var src = AL.currentContext.ctx.createBufferSource(); + src.loop = AL.currentContext.src[source - 1].loop; + src.buffer = AL.currentContext.src[source - 1].buffer; + src.connect(AL.currentContext.src[source - 1].gain); src.start(0, offset); - AL.contexts[AL.currentContext -1].src[source - 1].playTime = AL.contexts[AL.currentContext -1].ctx.currentTime; - AL.contexts[AL.currentContext -1].src[source - 1].paused = false; - AL.contexts[AL.currentContext -1].src[source - 1]['src'] = src; + AL.currentContext.src[source - 1].playTime = AL.currentContext.ctx.currentTime; + AL.currentContext.src[source - 1].paused = false; + AL.currentContext.src[source - 1]['src'] = src; }, alSourceStop: function(source) { - if (AL.currentContext == 0|| !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alSourceStop called without a valid context"); #endif return; } - if (source > AL.contexts[AL.currentContext -1].src.length) { + if (source > AL.currentContext.src.length) { #if OPENAL_DEBUG console.error("alSourceStop called with an invalid source"); #endif return; } - if (AL.contexts[AL.currentContext -1].src[source - 1] && "src" in AL.contexts[AL.currentContext -1].src[source - 1]) { - AL.contexts[AL.currentContext -1].src[source - 1]["src"].stop(0); - delete AL.contexts[AL.currentContext -1].src[source - 1]["src"]; + if (AL.currentContext.src[source - 1] && "src" in AL.currentContext.src[source - 1]) { + AL.currentContext.src[source - 1]["src"].stop(0); + delete AL.currentContext.src[source - 1]["src"]; } }, alSourcePause: function(source) { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alSourcePause called without a valid context"); #endif return; } - if (source > AL.contexts[AL.currentContext -1].src.length) { + if (source > AL.currentContext.src.length) { #if OPENAL_DEBUG console.error("alSourcePause called with an invalid source"); #endif return; } - if ("src" in AL.contexts[AL.currentContext -1].src[source - 1] && - !AL.contexts[AL.currentContext -1].src[source - 1].paused) { - AL.contexts[AL.currentContext -1].src[source - 1].paused = true; - AL.contexts[AL.currentContext -1].src[source - 1].pausedTime = AL.contexts[AL.currentContext -1].ctx.currentTime; - AL.contexts[AL.currentContext -1].src[source - 1]["src"].stop(0); - delete AL.contexts[AL.currentContext -1].src[source - 1].src; + if ("src" in AL.currentContext.src[source - 1] && + !AL.currentContext.src[source - 1].paused) { + AL.currentContext.src[source - 1].paused = true; + AL.currentContext.src[source - 1].pausedTime = AL.currentContext.ctx.currentTime; + AL.currentContext.src[source - 1]["src"].stop(0); + delete AL.currentContext.src[source - 1].src; } }, alGetSourcei: function(source, param, value) { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alGetSourcei called without a valid context"); #endif return; } - if (source > AL.contexts[AL.currentContext -1].src.length) { + if (source > AL.currentContext.src.length) { #if OPENAL_DEBUG console.error("alGetSourcei called with an invalid source"); #endif @@ -484,12 +494,12 @@ var LibraryOpenAL = { {{{ makeSetValue('value', '0', '1', 'i32') }}}; break; case 0x1009 /* AL_BUFFER */: - if (AL.contexts[AL.currentContext -1].src[source - 1].buffer == null) { + if (AL.currentContext.src[source - 1].buffer == null) { {{{ makeSetValue('value', '0', '0', 'i32') }}}; } else { - var buf = AL.contexts[AL.currentContext -1].src[source - 1].buffer; - for (var i = 0; i < AL.contexts[AL.currentContext -1].buf.length; ++i) { - if (buf == AL.contexts[AL.currentContext -1].buf[i].buf) { + var buf = AL.currentContext.src[source - 1].buffer; + for (var i = 0; i < AL.currentContext.buf.length; ++i) { + if (buf == AL.currentContext.buf[i].buf) { {{{ makeSetValue('value', '0', 'i+1', 'i32') }}}; return; } @@ -498,18 +508,18 @@ var LibraryOpenAL = { } break; case 0x1010 /* AL_SOURCE_STATE */: - if ("src" in AL.contexts[AL.currentContext -1].src[source - 1]) { + if ("src" in AL.currentContext.src[source - 1]) { {{{ makeSetValue('value', '0', '0x1012', 'i32') }}} /* AL_PLAYING */; - } else if (AL.contexts[AL.currentContext -1].src[source - 1].paused) { + } else if (AL.currentContext.src[source - 1].paused) { {{{ makeSetValue('value', '0', '0x1013', 'i32') }}} /* AL_PAUSED */; - } else if (AL.contexts[AL.currentContext -1].src[source - 1].playTime == -1) { + } else if (AL.currentContext.src[source - 1].playTime == -1) { {{{ makeSetValue('value', '0', '0x1011', 'i32') }}} /* AL_INITIAL */; } else { {{{ makeSetValue('value', '0', '0x1014', 'i32') }}} /* AL_STOPPED */; } break; case 0x1015 /* AL_BUFFERS_QUEUED */: - if (AL.contexts[AL.currentContext -1].src[source - 1].buffer) { + if (AL.currentContext.src[source - 1].buffer) { {{{ makeSetValue('value', '0', '1', 'i32') }}} } else { {{{ makeSetValue('value', '0', '0', 'i32') }}} @@ -531,7 +541,7 @@ var LibraryOpenAL = { }, alListenerfv: function(param, values) { - if (AL.currentContext == 0 || !AL.contexts[AL.currentContext -1]) { + if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alListenerfv called without a valid context"); #endif @@ -539,21 +549,21 @@ var LibraryOpenAL = { } switch (param) { case 0x1004 /* AL_POSITION */: - AL.contexts[AL.currentContext -1].ctx.listener.setPosition( + AL.currentContext.ctx.listener.setPosition( {{{ makeGetValue('values', '0', 'float') }}}, {{{ makeGetValue('values', '4', 'float') }}}, {{{ makeGetValue('values', '8', 'float') }}} ); break; case 0x1006 /* AL_VELOCITY */: - AL.contexts[AL.currentContext -1].ctx.listener.setVelocity( + AL.currentContext.ctx.listener.setVelocity( {{{ makeGetValue('values', '0', 'float') }}}, {{{ makeGetValue('values', '4', 'float') }}}, {{{ makeGetValue('values', '8', 'float') }}} ); break; case 0x100F /* AL_ORIENTATION */: - AL.contexts[AL.currentContext -1].ctx.listener.setOrientation( + AL.currentContext.ctx.listener.setOrientation( {{{ makeGetValue('values', '0', 'float') }}}, {{{ makeGetValue('values', '4', 'float') }}}, {{{ makeGetValue('values', '8', 'float') }}}, @@ -585,10 +595,6 @@ var LibraryOpenAL = { alcGetProcAddress: function(device, fname) { return 0; }, - - alSourceRewind: function(source) { - - } }; autoAddDeps(LibraryOpenAL, '$AL'); From 4ee2c4b7eeb65135bb74e746abaffea6a308083f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Fri, 5 Apr 2013 17:39:49 +0200 Subject: [PATCH 058/544] * Fixed GLFW mouse position bug. --- src/library_glfw.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index 71552cd8eafc6..8bf3616f7f439 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -32,7 +32,6 @@ var LibraryGLFW = { resizeFunc: null, closeFunc: null, refreshFunc: null, - mouseFunc: null, params: null, initTime: null, wheelPos: 0, @@ -470,7 +469,7 @@ var LibraryGLFW = { }, glfwSetMousePosCallback: function(cbfun) { - GLFW.mouseFunc = cbfun; + GLFW.mousePosFunc = cbfun; }, glfwSetMouseWheelCallback: function(cbfun) { From 758d18bdbdf3ea21b07f802208aa3d79be3bd660 Mon Sep 17 00:00:00 2001 From: Arlo Breault Date: Fri, 5 Apr 2013 08:50:34 -0700 Subject: [PATCH 059/544] Error codes. --- system/include/netdb.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/system/include/netdb.h b/system/include/netdb.h index 6e06944881bf9..27eae65b8d3ba 100644 --- a/system/include/netdb.h +++ b/system/include/netdb.h @@ -11,6 +11,22 @@ extern "C" { #define NO_DATA 4 #define NO_ADDRESS 5 +#define EAI_ADDRFAMILY 1 +#define EAI_AGAIN 2 +#define EAI_BADFLAGS 3 +#define EAI_FAIL 4 +#define EAI_FAMILY 5 +#define EAI_MEMORY 6 +#define EAI_NODATA 7 +#define EAI_NONAME 8 +#define EAI_SERVICE 9 +#define EAI_SOCKTYPE 10 +#define EAI_SYSTEM 11 +#define EAI_BADHINTS 12 +#define EAI_PROTOCOL 13 +#define EAI_OVERFLOW 14 +#define EAI_MAX 15 + #define IP_TOS 1 #define IP_TTL 2 #define IP_HDRINCL 3 From 166cba0f6be768f86faa727b010f61b9d104a926 Mon Sep 17 00:00:00 2001 From: Arlo Breault Date: Fri, 5 Apr 2013 09:05:17 -0700 Subject: [PATCH 060/544] pf_inet6 --- system/include/sys/socket.h | 1 + 1 file changed, 1 insertion(+) diff --git a/system/include/sys/socket.h b/system/include/sys/socket.h index e9b6c7706bf87..87d4de1ab1427 100644 --- a/system/include/sys/socket.h +++ b/system/include/sys/socket.h @@ -40,6 +40,7 @@ extern "C" { typedef unsigned int sa_family_t; #define AF_INET 1 #define AF_INET6 6 +#define PF_INET6 AF_INET6 struct sockaddr { sa_family_t sa_family; From e4d888ce84ea774e95e4b1122e908fb2a6a2f64c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 10:37:32 -0700 Subject: [PATCH 061/544] initialize runtime from run() (asynchronously, if run is asynchronous) --- src/postamble.js | 7 +++++-- src/preamble.js | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/postamble.js b/src/postamble.js index dd4f4f375eaf1..388d012784076 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -51,6 +51,11 @@ Module.callMain = function callMain(args) { function run(args) { args = args || Module['arguments']; + if (!calledInit) { + initRuntime(); + calledInit = true; + } + if (runDependencies > 0) { Module.printErr('run() called, but dependencies remain, so not running'); return 0; @@ -112,8 +117,6 @@ if (Module['preInit']) { } } -initRuntime(); - #if INVOKE_RUN var shouldRunNow = true; #else diff --git a/src/preamble.js b/src/preamble.js index 2cff440cefd78..e7778b302c555 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -805,7 +805,7 @@ Math.imul = function(a, b) { // the dependencies are met. var runDependencies = 0; var runDependencyTracking = {}; -var calledRun = false; +var calledInit = false, calledRun = false; var runDependencyWatcher = null; function addRunDependency(id) { runDependencies++; From 1c504965bdb643dc338774a4eb5027a0030ae837 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 10:47:19 -0700 Subject: [PATCH 062/544] allow calling callMain even if run() was not called --- src/postamble.js | 7 +++++++ tests/runner.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/postamble.js b/src/postamble.js index 388d012784076..971568cd48ee5 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -2,6 +2,13 @@ // === Auto-generated postamble setup entry stuff === Module.callMain = function callMain(args) { + args = args || []; + + if (!calledInit) { + initRuntime(); + calledInit = true; + } + var argc = args.length+1; function pad() { for (var i = 0; i < {{{ QUANTUM_SIZE }}}-1; i++) { diff --git a/tests/runner.py b/tests/runner.py index 23935656275cd..0a8e0209029cf 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -9975,7 +9975,7 @@ def test_prepost(self): if no_initial_run: # Calling main later should still work, filesystem etc. must be set up. - src = open(os.path.join(self.get_dir(), 'a.out.js')).read() + '\n_main();\n'; + src = open(os.path.join(self.get_dir(), 'a.out.js')).read() + '\nModule.callMain();\n'; open(os.path.join(self.get_dir(), 'a.out.js'), 'w').write(src) assert 'hello from main' in run_js(os.path.join(self.get_dir(), 'a.out.js')), 'main should print when called manually' From 8098fe7e06ff47d6944afd47158aac22d9354d32 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 10:53:09 -0700 Subject: [PATCH 063/544] refactor runtime initialization --- src/postamble.js | 10 ++-------- src/preamble.js | 6 +++++- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/postamble.js b/src/postamble.js index 971568cd48ee5..576366fefc15a 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -4,10 +4,7 @@ Module.callMain = function callMain(args) { args = args || []; - if (!calledInit) { - initRuntime(); - calledInit = true; - } + ensureInitRuntime(); var argc = args.length+1; function pad() { @@ -58,10 +55,7 @@ Module.callMain = function callMain(args) { function run(args) { args = args || Module['arguments']; - if (!calledInit) { - initRuntime(); - calledInit = true; - } + ensureInitRuntime(); if (runDependencies > 0) { Module.printErr('run() called, but dependencies remain, so not running'); diff --git a/src/preamble.js b/src/preamble.js index e7778b302c555..f85cf4f370ae5 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -718,7 +718,11 @@ var __ATINIT__ = []; // functions called during startup var __ATMAIN__ = []; // functions called when main() is to be run var __ATEXIT__ = []; // functions called during shutdown -function initRuntime() { +var runtimeInitialized = false; + +function ensureInitRuntime() { + if (runtimeInitialized) return; + runtimeInitialized = true; callRuntimeCallbacks(__ATINIT__); } function preMain() { From 33e9673c68ad017217b13dbf095d5fcb96663ed4 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 13:02:41 -0700 Subject: [PATCH 064/544] improve test_chunking, permanently fix # of cores --- tests/runner.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 0a8e0209029cf..7be9c33fc7a8e 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -10094,12 +10094,14 @@ def test_m_mm(self): def test_chunking(self): if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode') + if os.environ.get('EMCC_CORES'): return self.skip('cannot run if cores are altered') if multiprocessing.cpu_count() < 2: return self.skip('need multiple cores') try: os.environ['EMCC_DEBUG'] = '1' + os.environ['EMCC_CORES'] = '2' for asm, linkable, chunks, js_chunks in [ - (0, 0, 3, 2), (0, 1, 4, 4), - (1, 0, 3, 2), (1, 1, 4, 4) + (0, 0, 3, 2), (0, 1, 3, 4), + (1, 0, 3, 2), (1, 1, 3, 4) ]: print asm, linkable, chunks, js_chunks output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_libcxx.cpp'), '-O1', '-s', 'LINKABLE=%d' % linkable, '-s', 'ASM_JS=%d' % asm, '-s', 'UNRESOLVED_AS_DEAD=1'] + (['-O2'] if asm else []), stdout=PIPE, stderr=PIPE).communicate() @@ -10113,6 +10115,7 @@ def test_chunking(self): assert ok, err finally: del os.environ['EMCC_DEBUG'] + del os.environ['EMCC_CORES'] def test_debuginfo(self): if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode') From 34adb13ead3a0858ad3d38b7755b12f0e9610d55 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 13:33:11 -0700 Subject: [PATCH 065/544] fix xhrs for file URLs --- src/library_browser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_browser.js b/src/library_browser.js index 099516a864553..c1add7406b81a 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -379,7 +379,7 @@ mergeInto(LibraryManager.library, { xhr.open('GET', url, true); xhr.responseType = 'arraybuffer'; xhr.onload = function() { - if (xhr.status == 200) { + if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0 onload(xhr.response); } else { onerror(); From f8c930551e1684cdc8c186e0a58e9e00cb602b8a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 13:34:00 -0700 Subject: [PATCH 066/544] support reading binary data in the shell/node --- src/shell.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/shell.js b/src/shell.js index 8c37bf5bb02d1..c8f3644abe5ea 100644 --- a/src/shell.js +++ b/src/shell.js @@ -24,17 +24,20 @@ if (ENVIRONMENT_IS_NODE) { var nodeFS = require('fs'); var nodePath = require('path'); - Module['read'] = function(filename) { + Module['read'] = function(filename, binary) { filename = nodePath['normalize'](filename); - var ret = nodeFS['readFileSync'](filename).toString(); + var ret = nodeFS['readFileSync'](filename); // The path is absolute if the normalized version is the same as the resolved. if (!ret && filename != nodePath['resolve'](filename)) { filename = path.join(__dirname, '..', 'src', filename); - ret = nodeFS['readFileSync'](filename).toString(); + ret = nodeFS['readFileSync'](filename); } + if (ret && !binary) ret = ret.toString(); return ret; }; + Module['readBinary'] = function(filename) { return Module['read'](filename, true) }; + Module['load'] = function(f) { globalEval(read(f)); }; @@ -48,12 +51,10 @@ if (ENVIRONMENT_IS_SHELL) { Module['print'] = print; if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm - // Polyfill over SpiderMonkey/V8 differences - if (typeof read != 'undefined') { - Module['read'] = read; - } else { - Module['read'] = function(f) { snarf(f) }; - } + Module['read'] = read; + Module['readBinary'] = function(f) { + return read(f, 'binary'); + }; if (!Module['arguments']) { if (typeof scriptArgs != 'undefined') { From 3245705765916fc8cf5b61581bc4720e56166ddd Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 13:39:12 -0700 Subject: [PATCH 067/544] use a separate memory initialization file --- emcc | 26 ++++++++++++++++++++++++++ src/preamble.js | 18 ++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/emcc b/emcc index bc76b01dbc7b9..a3b788156b945 100755 --- a/emcc +++ b/emcc @@ -470,6 +470,11 @@ Options that are modified or new in %s include: libraries, and after any link-time optimizations (if any). + --memory-init-file If on, we generate a separate memory initialization + file. This is more efficient than storing the + memory initialization data embedded inside + JavaScript as text. (default is on) + The target file, if specified (-o ), defines what will be generated: @@ -716,6 +721,7 @@ try: bind = False jcache = False save_bc = False + memory_init_file = True if use_cxx: default_cxx_std = '-std=c++03' # Enforce a consistent C++ standard when compiling .cpp files, if user does not specify one on the cmdline. @@ -849,6 +855,11 @@ try: save_bc = newargs[i+1] newargs[i] = '' newargs[i+1] = '' + elif newargs[i] == '--memory-init-file': + check_bad_eq(newargs[i]) + memory_init_file = int(newargs[i+1]) + newargs[i] = '' + newargs[i+1] = '' elif newargs[i].startswith(('-I/', '-L/')): if not absolute_warning_shown: print >> sys.stderr, 'emcc: warning: -I or -L of an absolute path encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript)' # Of course an absolute path to a non-system-specific library or header is fine, and you can ignore this warning. The danger are system headers that are e.g. x86 specific and nonportable. The emscripten bundled headers are modified to be portable, local system ones are generally not @@ -1429,6 +1440,21 @@ try: src = re.sub(r'\n+[ \n]*\n+', '\n', src) open(final, 'w').write(src) + if memory_init_file: + memfile = target + '.mem' + def repl(m): + open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), m.groups(0)[0].split(',')))) + if DEBUG: + # Copy into temp dir as well, so can be run there too + shutil.copyfile(memfile, os.path.join(shared.EMSCRIPTEN_TEMP_DIR, os.path.basename(memfile))) + return 'Module["preRun"].push(function() { loadMemoryInitializer("%s") })' % os.path.basename(memfile) + src = re.sub('/\* memory initializer \*/ allocate\(\[([\d,]+)\], "i8", ALLOC_NONE, TOTAL_STACK\)', repl, src, count=1) + open(final + '.mem.js', 'w').write(src) + final += '.mem.js' + if DEBUG: + save_intermediate('meminit') + print >> sys.stderr, 'emcc: wrote memory initialization to %s' % memfile + # If we were asked to also generate HTML, do that if final_suffix == 'html': if DEBUG: print >> sys.stderr, 'emcc: generating HTML' diff --git a/src/preamble.js b/src/preamble.js index f85cf4f370ae5..392de7dc726a9 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -882,5 +882,23 @@ if (!Module.preRun) Module.preRun = []; Module.preRun.push(function() { addRunDependency('pgo') }); #endif +function loadMemoryInitializer(filename) { + function applyData(data) { + HEAPU8.set(data, TOTAL_STACK); + } + + if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) { + // synchronous + applyData(Module['readBinary'](filename)); + } else { + // asynchronous + Browser.asyncLoad(filename, function(data) { + applyData(data); + }, function(data) { + throw 'could not load memory initializer ' + filename; + }); + } +} + // === Body === From 0c6c866d47b12a14f2dc8ffee2560cd633dce93f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 16:39:54 -0700 Subject: [PATCH 068/544] ensure runtime initialized when dependencies have arrived, including the memory initializer --- src/postamble.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/postamble.js b/src/postamble.js index 576366fefc15a..833590f25b01c 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -55,8 +55,6 @@ Module.callMain = function callMain(args) { function run(args) { args = args || Module['arguments']; - ensureInitRuntime(); - if (runDependencies > 0) { Module.printErr('run() called, but dependencies remain, so not running'); return 0; @@ -76,6 +74,8 @@ function run(args) { } function doRun() { + ensureInitRuntime(); + var ret = 0; calledRun = true; if (Module['_main']) { From dc2a01d7f459dab9bf431fee51a10a5aa297bedc Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 16:48:38 -0700 Subject: [PATCH 069/544] refactor preRun additions --- emcc | 2 +- src/preamble.js | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/emcc b/emcc index a3b788156b945..07aa15b3e3ce8 100755 --- a/emcc +++ b/emcc @@ -1447,7 +1447,7 @@ try: if DEBUG: # Copy into temp dir as well, so can be run there too shutil.copyfile(memfile, os.path.join(shared.EMSCRIPTEN_TEMP_DIR, os.path.basename(memfile))) - return 'Module["preRun"].push(function() { loadMemoryInitializer("%s") })' % os.path.basename(memfile) + return 'addPreRun(function() { loadMemoryInitializer("%s") });' % os.path.basename(memfile) src = re.sub('/\* memory initializer \*/ allocate\(\[([\d,]+)\], "i8", ALLOC_NONE, TOTAL_STACK\)', repl, src, count=1) open(final + '.mem.js', 'w').write(src) final += '.mem.js' diff --git a/src/preamble.js b/src/preamble.js index 392de7dc726a9..fafc485cd78ef 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -865,6 +865,12 @@ Module['removeRunDependency'] = removeRunDependency; Module["preloadedImages"] = {}; // maps url to image data Module["preloadedAudios"] = {}; // maps url to audio data +function addPreRun(func) { + if (!Module['preRun']) Module['preRun'] = []; + else if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']]; + Module['preRun'].push(func); +} + #if PGO var PGOMonitor = { called: {}, @@ -878,8 +884,7 @@ var PGOMonitor = { } }; __ATEXIT__.push({ func: function() { PGOMonitor.dump() } }); -if (!Module.preRun) Module.preRun = []; -Module.preRun.push(function() { addRunDependency('pgo') }); +addPreRun(function() { addRunDependency('pgo') }); #endif function loadMemoryInitializer(filename) { From 74577f85173e2820658c3fa400da4c70c8138589 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 16:59:27 -0700 Subject: [PATCH 070/544] load memory initializer immediately --- emcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emcc b/emcc index 07aa15b3e3ce8..e43199f37bcaf 100755 --- a/emcc +++ b/emcc @@ -1447,7 +1447,7 @@ try: if DEBUG: # Copy into temp dir as well, so can be run there too shutil.copyfile(memfile, os.path.join(shared.EMSCRIPTEN_TEMP_DIR, os.path.basename(memfile))) - return 'addPreRun(function() { loadMemoryInitializer("%s") });' % os.path.basename(memfile) + return 'loadMemoryInitializer("%s");' % os.path.basename(memfile) src = re.sub('/\* memory initializer \*/ allocate\(\[([\d,]+)\], "i8", ALLOC_NONE, TOTAL_STACK\)', repl, src, count=1) open(final + '.mem.js', 'w').write(src) final += '.mem.js' From 7435dffd517feaae18af17533aeb4e83218e0bc1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 16:59:42 -0700 Subject: [PATCH 071/544] assert on callMain happening when no dependencies left --- src/postamble.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/postamble.js b/src/postamble.js index 833590f25b01c..4b3e831d3d3f8 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -2,6 +2,8 @@ // === Auto-generated postamble setup entry stuff === Module.callMain = function callMain(args) { + assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)'); + args = args || []; ensureInitRuntime(); From 7d495a7fb70ea87c259cc1faed9b5af3fe92aa3c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 16:59:52 -0700 Subject: [PATCH 072/544] debug printout --- tests/runner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/runner.py b/tests/runner.py index 7be9c33fc7a8e..988af12a6d306 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -9975,6 +9975,7 @@ def test_prepost(self): if no_initial_run: # Calling main later should still work, filesystem etc. must be set up. + print 'call main later' src = open(os.path.join(self.get_dir(), 'a.out.js')).read() + '\nModule.callMain();\n'; open(os.path.join(self.get_dir(), 'a.out.js'), 'w').write(src) assert 'hello from main' in run_js(os.path.join(self.get_dir(), 'a.out.js')), 'main should print when called manually' From a65ea6dc5853d4becee51cd8cb8a704e7eae1e95 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 17:09:04 -0700 Subject: [PATCH 073/544] do not copy mem file when already in all places --- emcc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/emcc b/emcc index e43199f37bcaf..48d507c3f6f28 100755 --- a/emcc +++ b/emcc @@ -1446,7 +1446,9 @@ try: open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), m.groups(0)[0].split(',')))) if DEBUG: # Copy into temp dir as well, so can be run there too - shutil.copyfile(memfile, os.path.join(shared.EMSCRIPTEN_TEMP_DIR, os.path.basename(memfile))) + temp_memfile = os.path.join(shared.EMSCRIPTEN_TEMP_DIR, os.path.basename(memfile)) + if os.path.abspath(memfile) != os.path.abspath(memfile): + shutil.copyfile(memfile, temp_memfile) return 'loadMemoryInitializer("%s");' % os.path.basename(memfile) src = re.sub('/\* memory initializer \*/ allocate\(\[([\d,]+)\], "i8", ALLOC_NONE, TOTAL_STACK\)', repl, src, count=1) open(final + '.mem.js', 'w').write(src) From b600e299400097ca72a30a2826e53284dd7ddceb Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 17:09:15 -0700 Subject: [PATCH 074/544] fix test_optimize_normally --- tests/runner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 988af12a6d306..6d47b59b060fa 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -10335,11 +10335,11 @@ def test_optimize_normally(self): assert (' with -O3 since EMCC_OPTIMIZE_NORMALLY defined' in err) == optimize_normally for last in ['both.o', 'both2.o']: - out, err = Popen([PYTHON, EMCC, self.in_dir('both.o'), '-O2', '-o', last + '.js'], stdout=PIPE, stderr=PIPE).communicate() + out, err = Popen([PYTHON, EMCC, self.in_dir('both.o'), '-O2', '-o', last + '.js', '--memory-init-file', '0'], stdout=PIPE, stderr=PIPE).communicate() assert ("emcc: LLVM opts: ['-O3']" not in err) == optimize_normally assert ' with -O3 since EMCC_OPTIMIZE_NORMALLY defined' not in err output = run_js(last + '.js') - assert 'yello' in output, 'code works' + assert 'yello' in output, 'code works ' + err assert open('both.o.js').read() == open('both2.o.js').read() finally: From 156bd51377b4e5805a5519ffc1dae94f5b8e8325 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 17:12:48 -0700 Subject: [PATCH 075/544] add test coverage for not using a memory initialization file --- tests/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runner.py b/tests/runner.py index 6d47b59b060fa..47e93baf19bf7 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -8915,7 +8915,7 @@ def setUp(self): # asm.js exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1"])') - exec('asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1", "-g", "-s", "ASSERTIONS=1"])') + exec('asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "0"])') # Make custom runs with various options for compiler, quantum, embetter, typed_arrays, llvm_opts in [ From 864d7c07e014675f438a14bd71508aea3b9da98d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 17:24:22 -0700 Subject: [PATCH 076/544] fix test_emcc --- tests/runner.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 47e93baf19bf7..1a483a462eb5c 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -9018,20 +9018,23 @@ def test_emcc(self): # emcc [..] -o [path] ==> should work with absolute paths try: - os.mkdir('a_dir') - os.chdir('a_dir') - os.mkdir('b_dir') for path in [os.path.abspath(os.path.join('..', 'file1.js')), os.path.join('b_dir', 'file2.js')]: + print path self.clear(in_curr=True) + os.chdir(self.get_dir()) + if not os.path.exists('a_dir'): os.mkdir('a_dir') + os.chdir('a_dir') + if not os.path.exists('b_dir'): os.mkdir('b_dir') output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world.ll'), '-o', path], stdout=PIPE, stderr=PIPE).communicate() + print output assert os.path.exists(path), path + ' does not exist; ' + '\n'.join(output) - self.assertContained('hello, world!', run_js(path)) + last = os.getcwd() + os.chdir(os.path.dirname(path)) + self.assertContained('hello, world!', run_js(os.path.basename(path))) + os.chdir(last) finally: os.chdir(self.get_dir()) - try: - shutil.rmtree('a_dir') - except: - pass + self.clear() # dlmalloc. dlmalloc is special in that it is the only part of libc that is (1) hard to write well, and # very speed-sensitive. So we do not implement it in JS in library.js, instead we compile it from source From 42a757e16ba255ffb671959352d7fc2c46a7d974 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 17:29:13 -0700 Subject: [PATCH 077/544] wait for Browser to show up to fetch memory initializer --- src/preamble.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/preamble.js b/src/preamble.js index fafc485cd78ef..7de82dbc1928a 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -897,10 +897,12 @@ function loadMemoryInitializer(filename) { applyData(Module['readBinary'](filename)); } else { // asynchronous - Browser.asyncLoad(filename, function(data) { - applyData(data); - }, function(data) { - throw 'could not load memory initializer ' + filename; + addPreRun(function() { + Browser.asyncLoad(filename, function(data) { + applyData(data); + }, function(data) { + throw 'could not load memory initializer ' + filename; + }); }); } } From e24c088f2dfd3f08be4ea808a188b2f653d8617b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 17:43:45 -0700 Subject: [PATCH 078/544] make test_glgears_animation more robust --- tests/hello_world_gles_shell.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/hello_world_gles_shell.html b/tests/hello_world_gles_shell.html index 343ddb64f6932..4abee90cddc0f 100644 --- a/tests/hello_world_gles_shell.html +++ b/tests/hello_world_gles_shell.html @@ -46,7 +46,7 @@ reportResult(firstImage != secondImage); }, 0); } - addEventListener("load", doTest, false); + Module.postRun = doTest; // The compiled code {{{ SCRIPT_CODE }}} From cc324bc9fa6cd9924a84732cceaf79066d1be9c6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 17:58:53 -0700 Subject: [PATCH 079/544] check for memory initialization in source code --- tests/runner.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/runner.py b/tests/runner.py index 1a483a462eb5c..561d85233b9b8 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -266,6 +266,13 @@ def build(self, src, dirname, filename, output_processor=None, main_file=None, a if output_processor is not None: output_processor(open(filename + '.o.js').read()) + if self.emcc_args is not None: + if '--memory-init-file' in self.emcc_args: + memory_init_file = int(self.emcc_args[self.emcc_args.index('--memory-init-file')+1]) + else: + memory_init_file = 1 + assert ('/* memory initializer */' in open(filename + '.o.js').read()) == (not memory_init_file) + def run_generated_code(self, engine, filename, args=[], check_timeout=True, output_nicerizer=None): stdout = os.path.join(self.get_dir(), 'stdout') # use files, as PIPE can get too full and hang us stderr = os.path.join(self.get_dir(), 'stderr') From 0dd006cfc72c023de7557d1c9ee23e779cea5e50 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 18:04:10 -0700 Subject: [PATCH 080/544] fix test_atexit --- src/jsifier.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/jsifier.js b/src/jsifier.js index ce0893347fb8b..500302682aa3a 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1524,6 +1524,8 @@ function JSify(data, functionsOnly, givenFunctions) { }); // write out the singleton big memory initialization value print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'TOTAL_STACK', true)); // we assert on TOTAL_STACK == GLOBAL_BASE + } else { + print('/* memory initializer */'); // test purposes } } From a89426a58dfca0b1b9af2fa97da996bddc976a0f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 18:30:25 -0700 Subject: [PATCH 081/544] test various chunk sizes for memory allocation --- src/parseTools.js | 2 +- src/settings.js | 2 ++ tests/runner.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/parseTools.js b/src/parseTools.js index 200490942030c..7dafbebedadb8 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1560,7 +1560,7 @@ function makePointer(slab, pos, allocator, type, ptr, finalMemoryInitialization) } // JS engines sometimes say array initializers are too large. Work around that by chunking and calling concat to combine at runtime - var chunkSize = 10240; + var chunkSize = JS_CHUNK_SIZE; function chunkify(array) { // break very large slabs into parts var ret = ''; diff --git a/src/settings.js b/src/settings.js index 6b05444316f9b..f9b4722835987 100644 --- a/src/settings.js +++ b/src/settings.js @@ -357,6 +357,8 @@ var NECESSARY_BLOCKADDRS = []; // List of (function, block) for all block addres var EMIT_GENERATED_FUNCTIONS = 0; // whether to emit the list of generated functions, needed for external JS optimization passes +var JS_CHUNK_SIZE = 10240; // Used as a maximum size before breaking up expressions and lines into smaller pieces + // Compiler debugging options var DEBUG_TAGS_SHOWING = []; // Some useful items: diff --git a/tests/runner.py b/tests/runner.py index 561d85233b9b8..3606ff1d8a3d3 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -8918,7 +8918,7 @@ def setUp(self): exec('o1 = make_run("o1", compiler=CLANG, emcc_args=["-O1", "-s", "SAFE_HEAP=1"])') # Make one run with -O2, but without closure (we enable closure in specific tests, otherwise on everything it is too slow) - exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2"])') + exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "-s", "JS_CHUNK_SIZE=10"])') # asm.js exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1"])') From 98665d3a9ac77f0acfd57c5a09136451305f01db Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 18:30:45 -0700 Subject: [PATCH 082/544] work towards detecting chunked memory init --- emcc | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/emcc b/emcc index 48d507c3f6f28..df6e649fee2e4 100755 --- a/emcc +++ b/emcc @@ -1442,20 +1442,29 @@ try: if memory_init_file: memfile = target + '.mem' + seen_memory_init = False def repl(m): - open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), m.groups(0)[0].split(',')))) + seen_memory_init = True + # handle chunking of the memory initializer + s = re.sub('[\[\]\n\(\)\. ]', '', m.groups(0)[0]) + s = s.replace('concat', ',') + if s[-1] == ',': s = s[:-1] + open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), s.split(',')))) if DEBUG: # Copy into temp dir as well, so can be run there too temp_memfile = os.path.join(shared.EMSCRIPTEN_TEMP_DIR, os.path.basename(memfile)) if os.path.abspath(memfile) != os.path.abspath(memfile): shutil.copyfile(memfile, temp_memfile) return 'loadMemoryInitializer("%s");' % os.path.basename(memfile) - src = re.sub('/\* memory initializer \*/ allocate\(\[([\d,]+)\], "i8", ALLOC_NONE, TOTAL_STACK\)', repl, src, count=1) + src = re.sub('/\* memory initializer \*/ allocate\(([\d,\.concat\(\)\[\]\\n ]+)"i8", ALLOC_NONE, TOTAL_STACK\)', repl, src, count=1) open(final + '.mem.js', 'w').write(src) final += '.mem.js' if DEBUG: - save_intermediate('meminit') - print >> sys.stderr, 'emcc: wrote memory initialization to %s' % memfile + if seen_memory_init: + save_intermediate('meminit') + print >> sys.stderr, 'emcc: wrote memory initialization to %s' % memfile + else: + print >> sys.stderr, 'emcc: did not see memory initialization' # If we were asked to also generate HTML, do that if final_suffix == 'html': From dad74e0d397ffc103e1aa53b99c1399f32b07fc2 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 18:31:18 -0700 Subject: [PATCH 083/544] disable memory init for now --- emcc | 2 +- tests/runner.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/emcc b/emcc index df6e649fee2e4..1d285cbb86600 100755 --- a/emcc +++ b/emcc @@ -721,7 +721,7 @@ try: bind = False jcache = False save_bc = False - memory_init_file = True + memory_init_file = False # XXX TODO True if use_cxx: default_cxx_std = '-std=c++03' # Enforce a consistent C++ standard when compiling .cpp files, if user does not specify one on the cmdline. diff --git a/tests/runner.py b/tests/runner.py index 3606ff1d8a3d3..428a7483b9eec 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -266,7 +266,7 @@ def build(self, src, dirname, filename, output_processor=None, main_file=None, a if output_processor is not None: output_processor(open(filename + '.o.js').read()) - if self.emcc_args is not None: + if 0:# XXX TODO self.emcc_args is not None: if '--memory-init-file' in self.emcc_args: memory_init_file = int(self.emcc_args[self.emcc_args.index('--memory-init-file')+1]) else: From bc0983bfa196e924590a244207a86331b293a341 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 18:42:20 -0700 Subject: [PATCH 084/544] allow non-ta2 memory initializer loading --- src/preamble.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/preamble.js b/src/preamble.js index 7de82dbc1928a..68510e3a5035f 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -889,7 +889,11 @@ addPreRun(function() { addRunDependency('pgo') }); function loadMemoryInitializer(filename) { function applyData(data) { +#if USE_TYPED_ARRAYS == 2 HEAPU8.set(data, TOTAL_STACK); +#else + allocate(data, 'i8', ALLOC_NONE, TOTAL_STACK); +#endif } if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) { From e82c91607bc09b86b4959c8b1d6d12a7fdbe8852 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 18:44:36 -0700 Subject: [PATCH 085/544] remove test_glgears_bad --- tests/runner.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 428a7483b9eec..e0484cd3fe2b0 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -11417,14 +11417,6 @@ def test_glgears_animation(self): self.run_browser('something.html', 'You should see animating gears.', '/report_gl_result?true') assert ('var GLEmulation' in open(self.in_dir('something.html')).read()) == emulation, "emulation code should be added when asked for" - def test_glgears_bad(self): - # Make sure that OpenGL ES is not available if typed arrays are not used - Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles.c'), '-o', 'something.html', - '-DHAVE_BUILTIN_SINCOS', '-s', 'GL_TESTING=1', - '-s', 'USE_TYPED_ARRAYS=0', - '--shell-file', path_from_root('tests', 'hello_world_gles_shell.html')]).communicate() - self.run_browser('something.html', 'You should not see animating gears.', '/report_gl_result?false') - def test_glgears_deriv(self): self.reftest(path_from_root('tests', 'gears.png')) Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles_deriv.c'), '-o', 'something.html', '-s', 'GL_TESTING=1', From 75c7e03bc5e282ee3969924c225a0e4545d5258b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Apr 2013 19:00:45 -0700 Subject: [PATCH 086/544] use a more reasonable js chunk size when testing -O2 --- tests/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runner.py b/tests/runner.py index e0484cd3fe2b0..cf46af2ce540b 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -8918,7 +8918,7 @@ def setUp(self): exec('o1 = make_run("o1", compiler=CLANG, emcc_args=["-O1", "-s", "SAFE_HEAP=1"])') # Make one run with -O2, but without closure (we enable closure in specific tests, otherwise on everything it is too slow) - exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "-s", "JS_CHUNK_SIZE=10"])') + exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "-s", "JS_CHUNK_SIZE=1024"])') # asm.js exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1"])') From 66883355e44a2e671c997a7df2193b585be893d7 Mon Sep 17 00:00:00 2001 From: Jacob Lee Date: Sat, 6 Apr 2013 15:07:58 -0400 Subject: [PATCH 087/544] scanf: support '*', which matches without assigning to an argument. For example, sscanf("1 2 3", "%*d %d", &foo) stores 2 into foo. --- AUTHORS | 2 +- src/library.js | 7 +++++++ tests/runner.py | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 0fa41dd21554e..dade5356952c2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -55,4 +55,4 @@ a license to everyone to use it as detailed in LICENSE.) * Tobias Doerffel * Martin von Gagern * Ting-Yuan Huang - +* Jacob Lee (copyright owned by Google, Inc.) diff --git a/src/library.js b/src/library.js index b63ac955f7b26..f6b2a31ee8bbe 100644 --- a/src/library.js +++ b/src/library.js @@ -2513,6 +2513,11 @@ LibraryManager.library = { if (format[formatIndex] === '%') { formatIndex++; + var suppressAssignment = false; + if (format[formatIndex] == '*') { + suppressAssignment = true; + formatIndex++; + } var maxSpecifierStart = formatIndex; while (format[formatIndex].charCodeAt(0) >= {{{ charCode('0') }}} && format[formatIndex].charCodeAt(0) <= {{{ charCode('9') }}}) { @@ -2578,6 +2583,8 @@ LibraryManager.library = { unget(); } if (buffer.length === 0) return 0; // Failure. + if (suppressAssignment) continue; + var text = buffer.join(''); var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}}; argIndex += Runtime.getNativeFieldSize('void*'); diff --git a/tests/runner.py b/tests/runner.py index ef014a1879bb0..17b359a38fe97 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -5743,6 +5743,24 @@ def test_sscanf_5(self): ''' self.do_run(src, '2, , black\n2, ., #001100\n2, X, #111100'); + def test_sscanf_skip(self): + src = r''' + #include + + int main(){ + int val1; + printf("%d\n", sscanf("10 20 30 40", "%*lld %*d %d", &val1)); + printf("%d\n", val1); + + int64_t large, val2; + printf("%d\n", sscanf("1000000 -1125899906842620 -123 -1073741823", "%lld %*lld %ld %*d", &large, &val2)); + printf("%lld,%d\n", large, val2); + + return 0; + } + ''' + self.do_run(src, '1\n30\n2\n1000000,-123\n') + def test_langinfo(self): src = open(path_from_root('tests', 'langinfo', 'test.c'), 'r').read() expected = open(path_from_root('tests', 'langinfo', 'output.txt'), 'r').read() From 01ec39a815750a9bc0900eb0b6629ac77e6bb91f Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 3 Apr 2013 08:07:40 -0700 Subject: [PATCH 088/544] Added "emcc" command for Windows --- emcc.bat | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 emcc.bat diff --git a/emcc.bat b/emcc.bat new file mode 100644 index 0000000000000..2cb3a3e12fb9c --- /dev/null +++ b/emcc.bat @@ -0,0 +1,2 @@ +@echo off +python %~dp0\emcc %* \ No newline at end of file From 5a642b1a7ea78ab5e5a60f83a37dca46623559e0 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 4 Apr 2013 15:41:16 -0700 Subject: [PATCH 089/544] Added name to AUTHORS --- AUTHORS | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index b67702650fe91..17878e1188b12 100644 --- a/AUTHORS +++ b/AUTHORS @@ -24,7 +24,7 @@ a license to everyone to use it as detailed in LICENSE.) * Pierre Renaux * Brian Anderson * Jon Bardin -* Jukka Jylänki +* Jukka Jylänki * Aleksander Guryanov * Chad Austin (copyright owned by IMVU) * nandhp @@ -46,7 +46,7 @@ a license to everyone to use it as detailed in LICENSE.) * Anthony Liot * Michael Riss * Jasper St. Pierre -* Manuel Schölling +* Manuel Schölling * Bruce Mitchener, Jr. * Michael Bishop * Roger Braun @@ -55,6 +55,7 @@ a license to everyone to use it as detailed in LICENSE.) * Tobias Doerffel * Martin von Gagern * Ting-Yuan Huang +* Joshua Granick * Felix H. Dahlke -* Éloi Rivard +* Éloi Rivard * Alexander Gladysh From 1c4c4816b7030b1071ede7bf6d794f0cd65b391b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 6 Apr 2013 23:26:15 +0300 Subject: [PATCH 090/544] Use .bat files to route 'python emxxx' to 'emxxx' on Windows. Remove reference to juj/vs-tool emxxx.exe in favor of the new .bat files. --- cmake/Platform/Emscripten.cmake | 8 ++++---- em++.bat | 2 ++ em-config.bat | 2 ++ emar.bat | 2 ++ emconfigure.bat | 2 ++ emlibtool.bat | 2 ++ emmake.bat | 2 ++ emranlib.bat | 2 ++ 8 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 em++.bat create mode 100644 em-config.bat create mode 100644 emar.bat create mode 100644 emconfigure.bat create mode 100644 emlibtool.bat create mode 100644 emmake.bat create mode 100644 emranlib.bat diff --git a/cmake/Platform/Emscripten.cmake b/cmake/Platform/Emscripten.cmake index 4b9c657279460..aafd38a83bbf3 100644 --- a/cmake/Platform/Emscripten.cmake +++ b/cmake/Platform/Emscripten.cmake @@ -24,10 +24,10 @@ endif() # Specify the compilers to use for C and C++ if ("${CMAKE_C_COMPILER}" STREQUAL "") - set(CMAKE_C_COMPILER "emcc.exe") - set(CMAKE_CXX_COMPILER "em++.exe") - set(CMAKE_AR "emar.exe") - set(CMAKE_RANLIB "emranlib.exe") + set(CMAKE_C_COMPILER "emcc.bat") + set(CMAKE_CXX_COMPILER "em++.bat") + set(CMAKE_AR "emar.bat") + set(CMAKE_RANLIB "emranlib.bat") endif() set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) diff --git a/em++.bat b/em++.bat new file mode 100644 index 0000000000000..b639ff2989396 --- /dev/null +++ b/em++.bat @@ -0,0 +1,2 @@ +@echo off +python %~dp0\em++ %* \ No newline at end of file diff --git a/em-config.bat b/em-config.bat new file mode 100644 index 0000000000000..63b15ea48db34 --- /dev/null +++ b/em-config.bat @@ -0,0 +1,2 @@ +@echo off +python %~dp0\em-config %* \ No newline at end of file diff --git a/emar.bat b/emar.bat new file mode 100644 index 0000000000000..2cfb08502fa8e --- /dev/null +++ b/emar.bat @@ -0,0 +1,2 @@ +@echo off +python %~dp0\emar %* \ No newline at end of file diff --git a/emconfigure.bat b/emconfigure.bat new file mode 100644 index 0000000000000..f900f40761803 --- /dev/null +++ b/emconfigure.bat @@ -0,0 +1,2 @@ +@echo off +python %~dp0\emconfigure %* \ No newline at end of file diff --git a/emlibtool.bat b/emlibtool.bat new file mode 100644 index 0000000000000..76ce48c3b952f --- /dev/null +++ b/emlibtool.bat @@ -0,0 +1,2 @@ +@echo off +python %~dp0\emlibtool %* \ No newline at end of file diff --git a/emmake.bat b/emmake.bat new file mode 100644 index 0000000000000..2db09d07e0484 --- /dev/null +++ b/emmake.bat @@ -0,0 +1,2 @@ +@echo off +python %~dp0\emmake %* \ No newline at end of file diff --git a/emranlib.bat b/emranlib.bat new file mode 100644 index 0000000000000..69bf8aa4f7312 --- /dev/null +++ b/emranlib.bat @@ -0,0 +1,2 @@ +@echo off +python %~dp0\emranlib %* \ No newline at end of file From 69ac92ea4fd158657e0406fe9fdb36026f77e5b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 8 Apr 2013 22:38:51 +0300 Subject: [PATCH 091/544] Remove '.' print in tools/js_optimizer.py on Windows. Fixes other.test_chunking on Windows. On Windows, prints to stdout/stderr do not appear coherently synchronized per-line if multiple threads print data simultaneously to console. This caused other.test_chunking tests to fail when they receive output like emcc: step took 5.09 seconds emcc: running pre-closure post-opts emcc: running post-closure post-opts emcc: applying js optimization passes: ['eliminate', 'simplifyExpressionsPre', 'simplifyExpressionsPost', 'last'] splitting up js o. ptimization into 2 chunks of size 1048576, using 2 cores (total: 1.42 MB) emcc: step took 2.37 seconds emcc: total time: 11.75 seconds where the test looks for the string 'splitting up js optimization into' from the output. Note that the chunk processor thread has printed a single '.' in between the critical line, creating a race condition that randomly makes the test pass or fail, depending on where in the output the '.' lands in. --- tools/js_optimizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index 4d37408c48a7d..b11d04497fee4 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -100,7 +100,7 @@ def run_on_chunk(command): f = open(filename, 'w') f.write(output) f.close() - if DEBUG: print >> sys.stderr, '.' + if DEBUG and not shared.WINDOWS: print >> sys.stderr, '.' # Skip debug progress indicator on Windows, since it doesn't buffer well with multiple threads printing to console. return filename def run_on_js(filename, passes, js_engine, jcache): From ecaaf7a4992ec0d949d3e226e2bd6427009dd6a6 Mon Sep 17 00:00:00 2001 From: Arlo Breault Date: Wed, 3 Apr 2013 19:25:52 -0700 Subject: [PATCH 092/544] combine netdb.h --- AUTHORS | 2 ++ system/include/net/netdb.h | 40 ------------------------------------- system/include/netdb.h | 26 ++++++++++++++++++++---- system/include/sys/socket.h | 2 +- 4 files changed, 25 insertions(+), 45 deletions(-) delete mode 100644 system/include/net/netdb.h diff --git a/AUTHORS b/AUTHORS index b67702650fe91..d7b146e17fe74 100644 --- a/AUTHORS +++ b/AUTHORS @@ -58,3 +58,5 @@ a license to everyone to use it as detailed in LICENSE.) * Felix H. Dahlke * Éloi Rivard * Alexander Gladysh +* Arlo Breault + diff --git a/system/include/net/netdb.h b/system/include/net/netdb.h deleted file mode 100644 index 4151ccb54bb6e..0000000000000 --- a/system/include/net/netdb.h +++ /dev/null @@ -1,40 +0,0 @@ - -#ifndef _NET_NETDB_H -#define _NET_NETDB_H - -#ifdef __cplusplus -extern "C" { -#endif - -struct addrinfo -{ - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - socklen_t ai_addrlen; - struct sockaddr *ai_addr; - char *ai_canonname; - struct addrinfo *ai_next; -}; - -extern int getaddrinfo(const char *name, const char *service, const struct addrinfo *req, struct addrinfo **pai); -extern void freeaddrinfo(struct addrinfo *ai); -extern int getnameinfo (struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, unsigned int flags); -const char *gai_strerror(int ecode); - -struct hostent -{ - char *h_name; - char **h_aliases; - int h_addrtype; - int h_length; - char **h_addr_list; -}; - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/system/include/netdb.h b/system/include/netdb.h index 6e06944881bf9..ac51bcb7030b1 100644 --- a/system/include/netdb.h +++ b/system/include/netdb.h @@ -33,12 +33,30 @@ extern "C" { typedef int socklen_t; -struct hostent { - char* h_name; - char** h_aliases; +struct addrinfo +{ + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + socklen_t ai_addrlen; + struct sockaddr *ai_addr; + char *ai_canonname; + struct addrinfo *ai_next; +}; + +extern int getaddrinfo(const char *name, const char *service, const struct addrinfo *req, struct addrinfo **pai); +extern void freeaddrinfo(struct addrinfo *ai); +extern int getnameinfo (struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, unsigned int flags); +const char *gai_strerror(int ecode); + +struct hostent +{ + char *h_name; + char **h_aliases; int h_addrtype; int h_length; - char** h_addr_list; + char **h_addr_list; }; #define h_addr h_addr_list[0] diff --git a/system/include/sys/socket.h b/system/include/sys/socket.h index e9b6c7706bf87..d0b3ebf432bf7 100644 --- a/system/include/sys/socket.h +++ b/system/include/sys/socket.h @@ -17,7 +17,7 @@ extern "C" { #define SO_BROADCAST 6 #define AF_UNIX PF_UNIX -#define AF_UNSPEC 100 +#define AF_UNSPEC 0 #define SOCK_STREAM 200 #define SOL_SOCKET 50 #define SO_ERROR 10 From 8e9e1f279baf89f97f84b8acdf7b4806990917d1 Mon Sep 17 00:00:00 2001 From: Arlo Breault Date: Thu, 4 Apr 2013 09:45:29 -0700 Subject: [PATCH 093/544] include arpa/inet.h in netinet/in.h --- system/include/net/netinet/in.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/system/include/net/netinet/in.h b/system/include/net/netinet/in.h index e32bf3ee711f9..569a56b0dd423 100644 --- a/system/include/net/netinet/in.h +++ b/system/include/net/netinet/in.h @@ -6,6 +6,8 @@ extern "C" { #endif +#include + enum { IPPROTO_IP = 0, #define IPPROTO_IP IPPROTO_IP From 229cb256da5547127f7512bd01a6e2bc180e71f1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 8 Apr 2013 17:33:49 -0700 Subject: [PATCH 094/544] fix test_799 --- tests/runner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 4afdaa9969b00..ba9403104f8dc 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -6652,8 +6652,8 @@ def test_gethostbyname(self): def test_799(self): src = open(path_from_root('tests', '799.cpp'), 'r').read() - self.do_run(src, '''Set PORT family: 100, port: 3979 -Get PORT family: 100 + self.do_run(src, '''Set PORT family: 0, port: 3979 +Get PORT family: 0 PORT: 3979 ''') From 6388ba8a57be8543ab208deee9aa573d47907e8d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 8 Apr 2013 21:09:12 -0700 Subject: [PATCH 095/544] add new setjmp label into labelsDict, so it can be found by phis; fixes #1046 --- src/analyzer.js | 1 + tests/cases/longjmp_tiny_phi_noasm.ll | 72 ++++++++++++++++++++++++++ tests/cases/longjmp_tiny_phi_noasm.txt | 3 ++ 3 files changed, 76 insertions(+) create mode 100644 tests/cases/longjmp_tiny_phi_noasm.ll create mode 100644 tests/cases/longjmp_tiny_phi_noasm.txt diff --git a/src/analyzer.js b/src/analyzer.js index 6ed554140a3f1..c10f18cc4b09d 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -1394,6 +1394,7 @@ function analyzer(data, sidePass) { lineNum: label.lineNum + 0.5, lines: label.lines.slice(j+1) }); + func.labelsDict[newIdent] = func.labels[i+1]; label.lines = label.lines.slice(0, j+1); label.lines.push({ intertype: 'branch', diff --git a/tests/cases/longjmp_tiny_phi_noasm.ll b/tests/cases/longjmp_tiny_phi_noasm.ll new file mode 100644 index 0000000000000..cced7cab90eb6 --- /dev/null +++ b/tests/cases/longjmp_tiny_phi_noasm.ll @@ -0,0 +1,72 @@ +; ModuleID = '/tmp/emscripten_temp/src.cpp.o' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128" +target triple = "i386-pc-linux-gnu" + +@_ZL3buf = internal global [20 x i16] zeroinitializer, align 2 +@.str = private unnamed_addr constant [13 x i8] c"hello world\0A\00", align 1 +@.str1 = private unnamed_addr constant [6 x i8] c"more\0A\00", align 1 +@.str2 = private unnamed_addr constant [6 x i8] c"*%d*\0A\00", align 1 + +define i32 @main() { +entry: + br label %two + +two: + %retval = alloca i32, align 4 + store i32 0, i32* %retval + %call = call i32 @setjmp(i16* getelementptr inbounds ([20 x i16]* @_ZL3buf, i32 0, i32 0)) returns_twice, !dbg !20 + %tobool = icmp ne i32 %call, 0, !dbg !20 + br i1 %tobool, label %if.else, label %if.then, !dbg !20 + +if.then: ; preds = %entry + %call1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([13 x i8]* @.str, i32 0, i32 0)), !dbg !22 + call void @longjmp(i16* getelementptr inbounds ([20 x i16]* @_ZL3buf, i32 0, i32 0), i32 10), !dbg !24 + br label %if.end, !dbg !25 + +if.else: ; preds = %entry + %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str1, i32 0, i32 0)), !dbg !26 + br label %if.end + +if.end: ; preds = %if.else, %if.then + %aaa = phi i32 [ -1, %if.then ], [ 0, %if.else ], [ 1, %two ], [ 2, %entry ] + %call3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0), i32 %aaa), !dbg !26 + ret i32 %aaa, !dbg !28 +} + +declare i32 @setjmp(i16*) returns_twice + +declare i32 @printf(i8*, ...) + +declare void @longjmp(i16*, i32) + +!llvm.dbg.cu = !{!0} + +!0 = metadata !{i32 786449, i32 0, i32 4, metadata !"/tmp/emscripten_temp/src.cpp", metadata !"/home/alon/Dev/emscripten", metadata !"clang version 3.1 (trunk 150936)", i1 true, i1 false, metadata !"", i32 0, metadata !1, metadata !1, metadata !3, metadata !12} ; [ DW_TAG_compile_unit ] +!1 = metadata !{metadata !2} +!2 = metadata !{i32 0} +!3 = metadata !{metadata !4} +!4 = metadata !{metadata !5} +!5 = metadata !{i32 786478, i32 0, metadata !6, metadata !"main", metadata !"main", metadata !"", metadata !6, i32 7, metadata !7, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 ()* @main, null, null, metadata !10} ; [ DW_TAG_subprogram ] +!6 = metadata !{i32 786473, metadata !"/tmp/emscripten_temp/src.cpp", metadata !"/home/alon/Dev/emscripten", null} ; [ DW_TAG_file_type ] +!7 = metadata !{i32 786453, i32 0, metadata !"", i32 0, i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !8, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] +!8 = metadata !{metadata !9} +!9 = metadata !{i32 786468, null, metadata !"int", null, i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] +!10 = metadata !{metadata !11} +!11 = metadata !{i32 786468} ; [ DW_TAG_base_type ] +!12 = metadata !{metadata !13} +!13 = metadata !{metadata !14} +!14 = metadata !{i32 786484, i32 0, null, metadata !"buf", metadata !"buf", metadata !"_ZL3buf", metadata !6, i32 5, metadata !15, i32 1, i32 1, [20 x i16]* @_ZL3buf} ; [ DW_TAG_variable ] +!15 = metadata !{i32 786454, null, metadata !"jmp_buf", metadata !6, i32 279, i64 0, i64 0, i64 0, i32 0, metadata !16} ; [ DW_TAG_typedef ] +!16 = metadata !{i32 786433, null, metadata !"", null, i32 0, i64 320, i64 16, i32 0, i32 0, metadata !17, metadata !18, i32 0, i32 0} ; [ DW_TAG_array_type ] +!17 = metadata !{i32 786468, null, metadata !"unsigned short", null, i32 0, i64 16, i64 16, i64 0, i32 0, i32 7} ; [ DW_TAG_base_type ] +!18 = metadata !{metadata !19} +!19 = metadata !{i32 786465, i64 0, i64 19} ; [ DW_TAG_subrange_type ] +!20 = metadata !{i32 8, i32 18, metadata !21, null} +!21 = metadata !{i32 786443, metadata !5, i32 7, i32 22, metadata !6, i32 0} ; [ DW_TAG_lexical_block ] +!22 = metadata !{i32 9, i32 15, metadata !23, null} +!23 = metadata !{i32 786443, metadata !21, i32 8, i32 31, metadata !6, i32 1} ; [ DW_TAG_lexical_block ] +!24 = metadata !{i32 10, i32 15, metadata !23, null} +!25 = metadata !{i32 11, i32 13, metadata !23, null} +!26 = metadata !{i32 12, i32 15, metadata !27, null} +!27 = metadata !{i32 786443, metadata !21, i32 11, i32 20, metadata !6, i32 2} ; [ DW_TAG_lexical_block ] +!28 = metadata !{i32 14, i32 13, metadata !21, null} diff --git a/tests/cases/longjmp_tiny_phi_noasm.txt b/tests/cases/longjmp_tiny_phi_noasm.txt new file mode 100644 index 0000000000000..16f5a93e5fec8 --- /dev/null +++ b/tests/cases/longjmp_tiny_phi_noasm.txt @@ -0,0 +1,3 @@ +hello world +more +*0* From 62c67168ae0bcbca6f17cd9af5e6057117697b6e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 9 Apr 2013 08:57:26 -0700 Subject: [PATCH 096/544] add another setjmp/phi testcase --- tests/cases/longjmp_tiny_phi2_noasm.ll | 68 +++++++++++++++++++++++++ tests/cases/longjmp_tiny_phi2_noasm.txt | 2 + 2 files changed, 70 insertions(+) create mode 100644 tests/cases/longjmp_tiny_phi2_noasm.ll create mode 100644 tests/cases/longjmp_tiny_phi2_noasm.txt diff --git a/tests/cases/longjmp_tiny_phi2_noasm.ll b/tests/cases/longjmp_tiny_phi2_noasm.ll new file mode 100644 index 0000000000000..1d7761c3b02f8 --- /dev/null +++ b/tests/cases/longjmp_tiny_phi2_noasm.ll @@ -0,0 +1,68 @@ +; ModuleID = '/tmp/emscripten_temp/src.cpp.o' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128" +target triple = "i386-pc-linux-gnu" + +@_ZL3buf = internal global [20 x i16] zeroinitializer, align 2 +@.str = private unnamed_addr constant [13 x i8] c"hello world\0A\00", align 1 +@.str1 = private unnamed_addr constant [6 x i8] c"more\0A\00", align 1 +@.str2 = private unnamed_addr constant [6 x i8] c"*%d*\0A\00", align 1 + +define i32 @main() { +entry: + br label %two + +two: + %retval = alloca i32, align 4 + store i32 0, i32* %retval + %call = call i32 @setjmp(i16* getelementptr inbounds ([20 x i16]* @_ZL3buf, i32 0, i32 0)) returns_twice, !dbg !20 + %tobool = icmp ne i32 %call, 0, !dbg !20 + br i1 %tobool, label %if.end, label %if.then, !dbg !20 + +if.then: ; preds = %entry + %call1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([13 x i8]* @.str, i32 0, i32 0)), !dbg !22 + call void @longjmp(i16* getelementptr inbounds ([20 x i16]* @_ZL3buf, i32 0, i32 0), i32 10), !dbg !24 + br label %if.end, !dbg !25 + +if.end: ; preds = %if.else, %if.then + %aaa = phi i32 [ -1, %if.then ], [ 1, %two ], [ 2, %entry ] + %call3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0), i32 %aaa), !dbg !26 + ret i32 %aaa, !dbg !28 +} + +declare i32 @setjmp(i16*) returns_twice + +declare i32 @printf(i8*, ...) + +declare void @longjmp(i16*, i32) + +!llvm.dbg.cu = !{!0} + +!0 = metadata !{i32 786449, i32 0, i32 4, metadata !"/tmp/emscripten_temp/src.cpp", metadata !"/home/alon/Dev/emscripten", metadata !"clang version 3.1 (trunk 150936)", i1 true, i1 false, metadata !"", i32 0, metadata !1, metadata !1, metadata !3, metadata !12} ; [ DW_TAG_compile_unit ] +!1 = metadata !{metadata !2} +!2 = metadata !{i32 0} +!3 = metadata !{metadata !4} +!4 = metadata !{metadata !5} +!5 = metadata !{i32 786478, i32 0, metadata !6, metadata !"main", metadata !"main", metadata !"", metadata !6, i32 7, metadata !7, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 ()* @main, null, null, metadata !10} ; [ DW_TAG_subprogram ] +!6 = metadata !{i32 786473, metadata !"/tmp/emscripten_temp/src.cpp", metadata !"/home/alon/Dev/emscripten", null} ; [ DW_TAG_file_type ] +!7 = metadata !{i32 786453, i32 0, metadata !"", i32 0, i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !8, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] +!8 = metadata !{metadata !9} +!9 = metadata !{i32 786468, null, metadata !"int", null, i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] +!10 = metadata !{metadata !11} +!11 = metadata !{i32 786468} ; [ DW_TAG_base_type ] +!12 = metadata !{metadata !13} +!13 = metadata !{metadata !14} +!14 = metadata !{i32 786484, i32 0, null, metadata !"buf", metadata !"buf", metadata !"_ZL3buf", metadata !6, i32 5, metadata !15, i32 1, i32 1, [20 x i16]* @_ZL3buf} ; [ DW_TAG_variable ] +!15 = metadata !{i32 786454, null, metadata !"jmp_buf", metadata !6, i32 279, i64 0, i64 0, i64 0, i32 0, metadata !16} ; [ DW_TAG_typedef ] +!16 = metadata !{i32 786433, null, metadata !"", null, i32 0, i64 320, i64 16, i32 0, i32 0, metadata !17, metadata !18, i32 0, i32 0} ; [ DW_TAG_array_type ] +!17 = metadata !{i32 786468, null, metadata !"unsigned short", null, i32 0, i64 16, i64 16, i64 0, i32 0, i32 7} ; [ DW_TAG_base_type ] +!18 = metadata !{metadata !19} +!19 = metadata !{i32 786465, i64 0, i64 19} ; [ DW_TAG_subrange_type ] +!20 = metadata !{i32 8, i32 18, metadata !21, null} +!21 = metadata !{i32 786443, metadata !5, i32 7, i32 22, metadata !6, i32 0} ; [ DW_TAG_lexical_block ] +!22 = metadata !{i32 9, i32 15, metadata !23, null} +!23 = metadata !{i32 786443, metadata !21, i32 8, i32 31, metadata !6, i32 1} ; [ DW_TAG_lexical_block ] +!24 = metadata !{i32 10, i32 15, metadata !23, null} +!25 = metadata !{i32 11, i32 13, metadata !23, null} +!26 = metadata !{i32 12, i32 15, metadata !27, null} +!27 = metadata !{i32 786443, metadata !21, i32 11, i32 20, metadata !6, i32 2} ; [ DW_TAG_lexical_block ] +!28 = metadata !{i32 14, i32 13, metadata !21, null} diff --git a/tests/cases/longjmp_tiny_phi2_noasm.txt b/tests/cases/longjmp_tiny_phi2_noasm.txt new file mode 100644 index 0000000000000..37e85737a2bf2 --- /dev/null +++ b/tests/cases/longjmp_tiny_phi2_noasm.txt @@ -0,0 +1,2 @@ +hello world +*1* From c5425d7d8c38ca1f9617b9823b1cc231bdc73314 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 9 Apr 2013 11:31:53 -0700 Subject: [PATCH 097/544] fix handling of blockaddresses > 255 in the new unified memory initializer world; fixes #1048 --- emscripten.py | 10 ++++++---- tests/runner.py | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/emscripten.py b/emscripten.py index 8f68ee77e87bf..efa6894aa05d0 100755 --- a/emscripten.py +++ b/emscripten.py @@ -306,18 +306,20 @@ def load_from_cache(chunk): i += 2 forwarded_json['Functions']['nextIndex'] = i + def split_32(x): + x = int(x) + return '%d,%d,%d,%d' % (x&255, (x >> 8)&255, (x >> 16)&255, (x >> 24)&255) + indexing = forwarded_json['Functions']['indexedFunctions'] def indexize(js): # In the global initial allocation, we need to split up into Uint8 format - def split_32(x): - x = int(x) - return '%d,%d,%d,%d' % (x&255, (x >> 8)&255, (x >> 16)&255, (x >> 24)&255) ret = re.sub(r"\"?'?{{ FI_([\w\d_$]+) }}'?\"?,0,0,0", lambda m: split_32(indexing.get(m.groups(0)[0]) or 0), js) return re.sub(r"'{{ FI_([\w\d_$]+) }}'", lambda m: str(indexing.get(m.groups(0)[0]) or 0), ret) blockaddrs = forwarded_json['Functions']['blockAddresses'] def blockaddrsize(js): - return re.sub(r'{{{ BA_([\w\d_$]+)\|([\w\d_$]+) }}}', lambda m: str(blockaddrs[m.groups(0)[0]][m.groups(0)[1]]), js) + ret = re.sub(r'"?{{{ BA_([\w\d_$]+)\|([\w\d_$]+) }}}"?,0,0,0', lambda m: split_32(blockaddrs[m.groups(0)[0]][m.groups(0)[1]]), js) + return re.sub(r'"?{{{ BA_([\w\d_$]+)\|([\w\d_$]+) }}}"?', lambda m: str(blockaddrs[m.groups(0)[0]][m.groups(0)[1]]), ret) #if DEBUG: outfile.write('// pre\n') outfile.write(blockaddrsize(indexize(pre))) diff --git a/tests/runner.py b/tests/runner.py index e6d5b33098ca6..1965cad91c38f 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -3728,6 +3728,25 @@ def test_indirectbr(self): ''' self.do_run(src, 'good\nbad') + def test_indirectbr_many(self): + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('blockaddr > 255 requires ta2') + + blocks = range(1500) + init = ', '.join(['&&B%d' % b for b in blocks]) + defs = '\n'.join(['B%d: printf("%d\\n"); return 0;' % (b,b) for b in blocks]) + src = ''' + #include + int main(int argc, char **argv) { + printf("\\n"); + const void *addrs[] = { %s }; + goto *addrs[argc*argc + 1000]; + +%s + return 0; + } + ''' % (init, defs) + self.do_run(src, '\n1001\n') + def test_pack(self): src = ''' #include From 8bd0457ad49d025489d6c46c0f266daec562dcb5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 9 Apr 2013 17:26:39 -0700 Subject: [PATCH 098/544] try to make WindowsPopen errors a little more explicit --- tools/shared.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index a13c20a6a403d..539144c691c40 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -39,7 +39,8 @@ def __init__(self, args, bufsize=0, executable=None, stdin=None, stdout=None, st try: self.process = subprocess.Popen(args, bufsize, executable, self.stdin_, self.stdout_, self.stderr_, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags) except Exception, e: - print >> sys.stderr, 'subprocess.Popen(args=%s) failed! Exception %s' % (' '.join(args), str(e)) + print >> sys.stderr, '\nsubprocess.Popen(args=%s) failed! Exception %s\n' % (' '.join(args), str(e)) + raise e def communicate(self, input=None): output = self.process.communicate(input) From c44aaae800adb84de2ae892e1eae77720118d8cf Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 9 Apr 2013 14:13:09 -0700 Subject: [PATCH 099/544] restore memory initialization and testing --- emcc | 2 +- src/jsifier.js | 2 +- tests/runner.py | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/emcc b/emcc index 1d285cbb86600..df6e649fee2e4 100755 --- a/emcc +++ b/emcc @@ -721,7 +721,7 @@ try: bind = False jcache = False save_bc = False - memory_init_file = False # XXX TODO True + memory_init_file = True if use_cxx: default_cxx_std = '-std=c++03' # Enforce a consistent C++ standard when compiling .cpp files, if user does not specify one on the cmdline. diff --git a/src/jsifier.js b/src/jsifier.js index 500302682aa3a..2a9c5ba885802 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1525,7 +1525,7 @@ function JSify(data, functionsOnly, givenFunctions) { // write out the singleton big memory initialization value print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'TOTAL_STACK', true)); // we assert on TOTAL_STACK == GLOBAL_BASE } else { - print('/* memory initializer */'); // test purposes + print('/* no memory initializer */'); // test purposes } } diff --git a/tests/runner.py b/tests/runner.py index 1965cad91c38f..2ce08ddd5997c 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -266,12 +266,15 @@ def build(self, src, dirname, filename, output_processor=None, main_file=None, a if output_processor is not None: output_processor(open(filename + '.o.js').read()) - if 0:# XXX TODO self.emcc_args is not None: + if self.emcc_args is not None: if '--memory-init-file' in self.emcc_args: memory_init_file = int(self.emcc_args[self.emcc_args.index('--memory-init-file')+1]) else: memory_init_file = 1 - assert ('/* memory initializer */' in open(filename + '.o.js').read()) == (not memory_init_file) + if memory_init_file: + assert '/* memory initializer */' not in open(filename + '.o.js').read() + else: + assert 'memory initializer */' in open(filename + '.o.js').read() def run_generated_code(self, engine, filename, args=[], check_timeout=True, output_nicerizer=None): stdout = os.path.join(self.get_dir(), 'stdout') # use files, as PIPE can get too full and hang us From f643819fc1cffbd522d62512a0f23db0228fdcf7 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 9 Apr 2013 14:21:19 -0700 Subject: [PATCH 100/544] always load memory initializer asynchronously, to keep shell and web as similar as possible --- src/preamble.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/preamble.js b/src/preamble.js index 68510e3a5035f..56f01751463f7 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -896,19 +896,18 @@ function loadMemoryInitializer(filename) { #endif } - if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) { - // synchronous - applyData(Module['readBinary'](filename)); - } else { - // asynchronous - addPreRun(function() { + // always do this asynchronously, to keep shell and web as similar as possible + addPreRun(function() { + if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) { + applyData(Module['readBinary'](filename)); + } else { Browser.asyncLoad(filename, function(data) { applyData(data); }, function(data) { throw 'could not load memory initializer ' + filename; }); - }); - } + } + }); } // === Body === From 0d08f9d8a20962097346dee80d634a6afe533850 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 9 Apr 2013 14:56:23 -0700 Subject: [PATCH 101/544] do not use memory init file in relooper itself --- tools/shared.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/shared.py b/tools/shared.py index 539144c691c40..72f4868e7c910 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -1150,6 +1150,7 @@ def make(opt_level): raw = relooper + '.raw.js' Building.emcc(os.path.join('relooper', 'Relooper.cpp'), ['-I' + os.path.join('relooper'), '--post-js', os.path.join('relooper', 'emscripten', 'glue.js'), + '--memory-init-file', '0', '-s', 'TOTAL_MEMORY=52428800', '-s', 'EXPORTED_FUNCTIONS=["_rl_set_output_buffer","_rl_make_output_buffer","_rl_new_block","_rl_delete_block","_rl_block_add_branch_to","_rl_new_relooper","_rl_delete_relooper","_rl_relooper_add_block","_rl_relooper_calculate","_rl_relooper_render", "_rl_set_asm_js_mode"]', '-s', 'DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=["memcpy", "memset", "malloc", "free", "puts"]', From bba3cd9cf5d797a2aef02bf966d595d3ec3cbcad Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 9 Apr 2013 16:12:42 -0700 Subject: [PATCH 102/544] split out dynamic cast tests --- tests/runner.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/runner.py b/tests/runner.py index 2ce08ddd5997c..982b6899de322 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -2961,6 +2961,9 @@ def test_dynamic_cast(self): ''' self.do_run(src, 'f()\n') + def test_dynamic_cast_b(self): + if self.emcc_args is None: return self.skip('need libcxxabi') + src = ''' #include From 7b2d1583a184edef4b920982426706224b937414 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 9 Apr 2013 16:25:56 -0700 Subject: [PATCH 103/544] run postsets right before main, and after the memory initializer has been set up --- src/jsifier.js | 3 +++ src/postamble.js | 3 ++- src/preamble.js | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/jsifier.js b/src/jsifier.js index 2a9c5ba885802..6ef9781c06a9c 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1529,7 +1529,10 @@ function JSify(data, functionsOnly, givenFunctions) { } } + // Run postsets right before main, and after the memory initializer has been set up + print('__ATMAIN__.push(function() {\n'); print(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n')); + print('});\n'); return; } diff --git a/src/postamble.js b/src/postamble.js index 4b3e831d3d3f8..ea520eae8a51b 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -78,10 +78,11 @@ function run(args) { function doRun() { ensureInitRuntime(); + preMain(); + var ret = 0; calledRun = true; if (Module['_main']) { - preMain(); ret = Module.callMain(args); if (!Module['noExitRuntime']) { exitRuntime(); diff --git a/src/preamble.js b/src/preamble.js index 56f01751463f7..6961a0e9cc57c 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -701,6 +701,10 @@ var nullString = allocate(intArrayFromString('(null)'), 'i8', ALLOC_STACK); function callRuntimeCallbacks(callbacks) { while(callbacks.length > 0) { var callback = callbacks.shift(); + if (typeof callback == 'function') { + callback(); + continue; + } var func = callback.func; if (typeof func === 'number') { if (callback.arg === undefined) { From 6d67e17176321f4c9c9bcf9aa9cd9d4db5c33aa5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 9 Apr 2013 16:32:22 -0700 Subject: [PATCH 104/544] only emit postsets in pre and when they actually exist --- src/jsifier.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 6ef9781c06a9c..eab4a88d23ce8 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1527,12 +1527,15 @@ function JSify(data, functionsOnly, givenFunctions) { } else { print('/* no memory initializer */'); // test purposes } + + // Run postsets right before main, and after the memory initializer has been set up + if (itemsDict.GlobalVariablePostSet.length > 0) { + print('__ATMAIN__.push(function() {\n'); + print(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n')); + print('});\n'); + } } - // Run postsets right before main, and after the memory initializer has been set up - print('__ATMAIN__.push(function() {\n'); - print(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n')); - print('});\n'); return; } From 294bdda3b3cb7a4554074968f4fcd8beb60c1fc5 Mon Sep 17 00:00:00 2001 From: Arlo Breault Date: Tue, 9 Apr 2013 17:53:10 -0700 Subject: [PATCH 105/544] implement setgroups --- src/library.js | 15 ++++++++++++++- system/include/libc/sys/unistd.h | 2 +- system/include/sys/un.h | 1 + tests/unistd/misc.c | 9 +++++++-- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/library.js b/src/library.js index f6b2a31ee8bbe..01c0a3f347e7f 100644 --- a/src/library.js +++ b/src/library.js @@ -2118,7 +2118,20 @@ LibraryManager.library = { return 1; } }, - // TODO: Implement initgroups, setgroups (grp.h). + // TODO: Implement initgroups (grp.h). + setgroups__deps: ['__setErrNo', '$ERRNO_CODES', 'sysconf'], + setgroups: function (ngroups, gidset) { + // int setgroups(int ngroups, const gid_t *gidset); + // https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man2/setgroups.2.html + if (ngroups < 1 || ngroups > _sysconf({{{ cDefine('_SC_NGROUPS_MAX') }}})) { + ___setErrNo(ERRNO_CODES.EINVAL); + return -1; + } else { + // We have just one process/user/group, so it makes no sense to set groups. + ___setErrNo(ERRNO_CODES.EPERM); + return -1; + } + }, gethostid: function() { // long gethostid(void); // http://pubs.opengroup.org/onlinepubs/000095399/functions/gethostid.html diff --git a/system/include/libc/sys/unistd.h b/system/include/libc/sys/unistd.h index b0c6d5057e15f..24d1346b5d762 100644 --- a/system/include/libc/sys/unistd.h +++ b/system/include/libc/sys/unistd.h @@ -153,7 +153,7 @@ int _EXFUN(seteuid, (uid_t __uid )); #endif int _EXFUN(setgid, (gid_t __gid )); #endif -#if defined(__CYGWIN__) +#if defined(EMSCRIPTEN) || defined(__CYGWIN__) int _EXFUN(setgroups, (int ngroups, const gid_t *grouplist )); #endif int _EXFUN(setpgid, (pid_t __pid, pid_t __pgid )); diff --git a/system/include/sys/un.h b/system/include/sys/un.h index b70425fbe7cf1..ca002158b63de 100644 --- a/system/include/sys/un.h +++ b/system/include/sys/un.h @@ -35,6 +35,7 @@ #include #include +#include /* * Definitions for UNIX IPC domain. diff --git a/tests/unistd/misc.c b/tests/unistd/misc.c index 4e7ac21623467..5b0d63d2304ea 100644 --- a/tests/unistd/misc.c +++ b/tests/unistd/misc.c @@ -106,7 +106,7 @@ int main() { printf("alarm: %d", alarm(42)); printf(", errno: %d\n", errno); errno = 0; - printf("ualarm: %d", ualarm(123, 456)); + printf("ualarm: %ld", ualarm(123, 456)); printf(", errno: %d\n", errno); errno = 0; @@ -117,7 +117,7 @@ int main() { printf(", errno: %d\n", errno); errno = 0; - printf("crypt: %d", crypt("foo", "bar")); + printf("crypt: %s", crypt("foo", "bar")); printf(", errno: %d\n", errno); errno = 0; char encrypt_block[64] = {0}; @@ -192,5 +192,10 @@ int main() { printf(", errno: %d\n", errno); errno = 0; + gid_t groups2[1] = {0}; + printf("setgroups: %d", setgroups(1, groups2)); + printf(", errno: %d\n", errno); + errno = 0; + return 0; } From b2a132cd667a004dc64d58c0f029978cc46eb564 Mon Sep 17 00:00:00 2001 From: Arlo Breault Date: Tue, 9 Apr 2013 17:58:40 -0700 Subject: [PATCH 106/544] consistent --- system/include/libc/sys/unistd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/include/libc/sys/unistd.h b/system/include/libc/sys/unistd.h index 24d1346b5d762..1a414b3c21cd0 100644 --- a/system/include/libc/sys/unistd.h +++ b/system/include/libc/sys/unistd.h @@ -154,7 +154,7 @@ int _EXFUN(seteuid, (uid_t __uid )); int _EXFUN(setgid, (gid_t __gid )); #endif #if defined(EMSCRIPTEN) || defined(__CYGWIN__) -int _EXFUN(setgroups, (int ngroups, const gid_t *grouplist )); +int _EXFUN(setgroups, (int ngroups, const gid_t *gidset)); #endif int _EXFUN(setpgid, (pid_t __pid, pid_t __pgid )); int _EXFUN(setpgrp, (void )); From 064206f86c62c546b1860cb14e4f303b6056b5bc Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 9 Apr 2013 20:17:50 -0700 Subject: [PATCH 107/544] remove ATMAIN hack, use a designated runPostSets function for postSets --- src/jsifier.js | 9 ++++----- src/preamble.js | 5 +++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index eab4a88d23ce8..23fbb4c5cfc77 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1529,11 +1529,10 @@ function JSify(data, functionsOnly, givenFunctions) { } // Run postsets right before main, and after the memory initializer has been set up - if (itemsDict.GlobalVariablePostSet.length > 0) { - print('__ATMAIN__.push(function() {\n'); - print(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n')); - print('});\n'); - } + print('function runPostSets() {\n'); + print(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n')); + print('}\n'); + print('if (!awaitingMemoryInitializer) runPostSets();\n'); // if we load the memory initializer, this is done later } return; diff --git a/src/preamble.js b/src/preamble.js index 6961a0e9cc57c..592363f91966c 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -891,6 +891,8 @@ __ATEXIT__.push({ func: function() { PGOMonitor.dump() } }); addPreRun(function() { addRunDependency('pgo') }); #endif +var awaitingMemoryInitializer = false; + function loadMemoryInitializer(filename) { function applyData(data) { #if USE_TYPED_ARRAYS == 2 @@ -898,6 +900,7 @@ function loadMemoryInitializer(filename) { #else allocate(data, 'i8', ALLOC_NONE, TOTAL_STACK); #endif + runPostSets(); } // always do this asynchronously, to keep shell and web as similar as possible @@ -912,6 +915,8 @@ function loadMemoryInitializer(filename) { }); } }); + + awaitingMemoryInitializer = false; } // === Body === From f58e77da332cb0f8123c0c062c275c63783736a7 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 9 Apr 2013 20:34:37 -0700 Subject: [PATCH 108/544] make noInitialRun and INVOKE_RUN refer to main(), not run(). run() need not call main(), and is necessary to set things up even if you call main() manually --- src/postamble.js | 8 ++++---- src/settings.js | 4 ++-- tests/runner.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/postamble.js b/src/postamble.js index ea520eae8a51b..8dd0158905b40 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -3,6 +3,7 @@ Module.callMain = function callMain(args) { assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)'); + assert(!Module['preRun'] || Module['preRun'].length == 0, 'cannot call main when preRun functions remain to be called'); args = args || []; @@ -82,7 +83,7 @@ function run(args) { var ret = 0; calledRun = true; - if (Module['_main']) { + if (Module['_main'] && shouldRunNow) { ret = Module.callMain(args); if (!Module['noExitRuntime']) { exitRuntime(); @@ -121,6 +122,7 @@ if (Module['preInit']) { } } +// shouldRunNow refers to calling main(), not run(). #if INVOKE_RUN var shouldRunNow = true; #else @@ -130,9 +132,7 @@ if (Module['noInitialRun']) { shouldRunNow = false; } -if (shouldRunNow) { - run(); -} +run(); // {{POST_RUN_ADDITIONS}} diff --git a/src/settings.js b/src/settings.js index f9b4722835987..78a2161626fc4 100644 --- a/src/settings.js +++ b/src/settings.js @@ -35,8 +35,8 @@ var ASSERTIONS = 1; // Whether we should add runtime assertions, for example to // if code flow runs into a fault var VERBOSE = 0; // When set to 1, will generate more verbose output during compilation. -var INVOKE_RUN = 1; // Whether we will call run(). Disable if you embed the generated - // code in your own, and will call run() yourself at the right time +var INVOKE_RUN = 1; // Whether we will run the main() function. Disable if you embed the generated + // code in your own, and will call main() yourself at the right time. var INIT_HEAP = 0; // Whether to initialize memory anywhere other than the stack to 0. var TOTAL_STACK = 5*1024*1024; // The total stack size. There is no way to enlarge the stack, so this // value must be large enough for the program's requirements. If diff --git a/tests/runner.py b/tests/runner.py index 982b6899de322..325ecdb563ed1 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -10016,7 +10016,7 @@ def test_prepost(self): self.assertNotContained('pre-run\nhello from main\npost-run\n', run_js(os.path.join(self.get_dir(), 'a.out.js'))) # noInitialRun prevents run - for no_initial_run, run_dep in [(0, 0), (1, 0), (0, 1), (1, 1)]: + for no_initial_run, run_dep in [(0, 0), (1, 0), (0, 1)]: print no_initial_run, run_dep Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')]).communicate() src = 'var Module = { noInitialRun: %d };\n' % no_initial_run + open(os.path.join(self.get_dir(), 'a.out.js')).read() From 884dada6736b940f336aefa9f7bc094cb8dfe781 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 10 Apr 2013 12:48:49 -0700 Subject: [PATCH 109/544] fix test_poppler --- tests/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runner.py b/tests/runner.py index 325ecdb563ed1..609c38c331177 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -7540,7 +7540,7 @@ def process(filename): src.write( \'\'\' FS.createDataFile('/', 'paper.pdf', eval(Module.read('paper.pdf.js')), true, false); - run(); + Module.callMain(Module.arguments); Module.print("Data: " + JSON.stringify(FS.root.contents['filename-1.ppm'].contents.map(function(x) { return unSign(x, 8) }))); \'\'\' ) From 3f96c03f4dc777f53a8b4d5a6cbda36f942aa44a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 10 Apr 2013 14:29:07 -0700 Subject: [PATCH 110/544] emcc note about .mem files --- emcc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/emcc b/emcc index df6e649fee2e4..15c38cd418de4 100755 --- a/emcc +++ b/emcc @@ -483,6 +483,9 @@ be generated: .bc LLVM bitcode (default) .o LLVM bitcode (same as .bc) +Note that if --memory-init-file is used, then in addition to a +.js or .html file that is generated, a .mem file will also appear. + The -c option (which tells gcc not to run the linker) will cause LLVM bitcode to be generated, as %s only generates JavaScript in the final linking stage of building. From 89cb346773e0b4137d95c6cd8b794c28b750f96c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 10 Apr 2013 14:31:35 -0700 Subject: [PATCH 111/544] fix test_sscanf_skip --- tests/runner.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/runner.py b/tests/runner.py index 609c38c331177..74fbbdba0c93e 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -5775,6 +5775,8 @@ def test_sscanf_5(self): self.do_run(src, '2, , black\n2, ., #001100\n2, X, #111100'); def test_sscanf_skip(self): + if Settings.USE_TYPED_ARRAYS != 2: return self.skip("need ta2 for full i64") + src = r''' #include From 37ea1bd02c7769a41797de25428c59913455ea2a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 10 Apr 2013 15:28:01 -0700 Subject: [PATCH 112/544] fix sanity.test_emcc --- tests/runner.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/runner.py b/tests/runner.py index 74fbbdba0c93e..03299dd0c61ae 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -12688,7 +12688,12 @@ def test_emcc(self): ''') Popen([PYTHON, EMCC, os.path.join(dirname, 'main.cpp'), '-o', os.path.join(dirname, 'a.out.js')]).communicate() del os.environ['EM_CONFIG'] - self.assertContained('hello from emcc with no config file', run_js(os.path.join(dirname, 'a.out.js'))) + old_dir = os.getcwd() + try: + os.chdir(dirname) + self.assertContained('hello from emcc with no config file', run_js('a.out.js')) + finally: + os.chdir(old_dir) shutil.rmtree(dirname) try_delete(CANONICAL_TEMP_DIR) From 0c1958f51ddd3a6cac3769abf7059dbbb0140428 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 10 Apr 2013 15:29:31 -0700 Subject: [PATCH 113/544] box2d v2.2.1 (from box2d.js) --- tests/Box2D_v2.2.1/Box2D/Box2D.h | 67 + tests/Box2D_v2.2.1/Box2D/Box2DConfig.cmake | 3 + tests/Box2D_v2.2.1/Box2D/CMakeLists.txt | 205 ++ .../Box2D/Collision/Shapes/b2ChainShape.cpp | 171 + .../Box2D/Collision/Shapes/b2ChainShape.h | 102 + .../Box2D/Collision/Shapes/b2CircleShape.cpp | 100 + .../Box2D/Collision/Shapes/b2CircleShape.h | 91 + .../Box2D/Collision/Shapes/b2EdgeShape.cpp | 139 + .../Box2D/Collision/Shapes/b2EdgeShape.h | 74 + .../Box2D/Collision/Shapes/b2PolygonShape.cpp | 361 +++ .../Box2D/Collision/Shapes/b2PolygonShape.h | 95 + .../Box2D/Collision/Shapes/b2Shape.h | 101 + .../Box2D/Collision/b2BroadPhase.cpp | 122 + .../Box2D/Collision/b2BroadPhase.h | 250 ++ .../Box2D/Collision/b2CollideCircle.cpp | 154 + .../Box2D/Collision/b2CollideEdge.cpp | 698 ++++ .../Box2D/Collision/b2CollidePolygon.cpp | 317 ++ .../Box2D/Collision/b2Collision.cpp | 249 ++ .../Box2D/Collision/b2Collision.h | 281 ++ .../Box2D/Collision/b2Distance.cpp | 603 ++++ .../Box2D_v2.2.1/Box2D/Collision/b2Distance.h | 141 + .../Box2D/Collision/b2DynamicTree.cpp | 771 +++++ .../Box2D/Collision/b2DynamicTree.h | 284 ++ .../Box2D/Collision/b2TimeOfImpact.cpp | 483 +++ .../Box2D/Collision/b2TimeOfImpact.h | 58 + .../Box2D/Common/b2BlockAllocator.cpp | 217 ++ .../Box2D/Common/b2BlockAllocator.h | 62 + tests/Box2D_v2.2.1/Box2D/Common/b2Draw.cpp | 44 + tests/Box2D_v2.2.1/Box2D/Common/b2Draw.h | 85 + .../Box2D/Common/b2GrowableStack.h | 87 + tests/Box2D_v2.2.1/Box2D/Common/b2Math.cpp | 94 + tests/Box2D_v2.2.1/Box2D/Common/b2Math.h | 739 +++++ .../Box2D_v2.2.1/Box2D/Common/b2Settings.cpp | 44 + tests/Box2D_v2.2.1/Box2D/Common/b2Settings.h | 155 + .../Box2D/Common/b2StackAllocator.cpp | 83 + .../Box2D/Common/b2StackAllocator.h | 60 + tests/Box2D_v2.2.1/Box2D/Common/b2Timer.cpp | 100 + tests/Box2D_v2.2.1/Box2D/Common/b2Timer.h | 45 + .../Contacts/b2ChainAndCircleContact.cpp | 54 + .../Contacts/b2ChainAndCircleContact.h | 39 + .../Contacts/b2ChainAndPolygonContact.cpp | 54 + .../Contacts/b2ChainAndPolygonContact.h | 39 + .../Dynamics/Contacts/b2CircleContact.cpp | 53 + .../Box2D/Dynamics/Contacts/b2CircleContact.h | 39 + .../Box2D/Dynamics/Contacts/b2Contact.cpp | 240 ++ .../Box2D/Dynamics/Contacts/b2Contact.h | 334 ++ .../Dynamics/Contacts/b2ContactSolver.cpp | 832 +++++ .../Box2D/Dynamics/Contacts/b2ContactSolver.h | 94 + .../Contacts/b2EdgeAndCircleContact.cpp | 50 + .../Contacts/b2EdgeAndCircleContact.h | 39 + .../Contacts/b2EdgeAndPolygonContact.cpp | 50 + .../Contacts/b2EdgeAndPolygonContact.h | 39 + .../Contacts/b2PolygonAndCircleContact.cpp | 50 + .../Contacts/b2PolygonAndCircleContact.h | 38 + .../Dynamics/Contacts/b2PolygonContact.cpp | 53 + .../Dynamics/Contacts/b2PolygonContact.h | 39 + .../Box2D/Dynamics/Joints/b2DistanceJoint.cpp | 260 ++ .../Box2D/Dynamics/Joints/b2DistanceJoint.h | 180 ++ .../Box2D/Dynamics/Joints/b2FrictionJoint.cpp | 251 ++ .../Box2D/Dynamics/Joints/b2FrictionJoint.h | 129 + .../Box2D/Dynamics/Joints/b2GearJoint.cpp | 423 +++ .../Box2D/Dynamics/Joints/b2GearJoint.h | 136 + .../Box2D/Dynamics/Joints/b2Joint.cpp | 199 ++ .../Box2D/Dynamics/Joints/b2Joint.h | 222 ++ .../Box2D/Dynamics/Joints/b2MouseJoint.cpp | 217 ++ .../Box2D/Dynamics/Joints/b2MouseJoint.h | 136 + .../Dynamics/Joints/b2PrismaticJoint.cpp | 637 ++++ .../Box2D/Dynamics/Joints/b2PrismaticJoint.h | 207 ++ .../Box2D/Dynamics/Joints/b2PulleyJoint.cpp | 332 ++ .../Box2D/Dynamics/Joints/b2PulleyJoint.h | 154 + .../Box2D/Dynamics/Joints/b2RevoluteJoint.cpp | 504 +++ .../Box2D/Dynamics/Joints/b2RevoluteJoint.h | 214 ++ .../Box2D/Dynamics/Joints/b2RopeJoint.cpp | 241 ++ .../Box2D/Dynamics/Joints/b2RopeJoint.h | 125 + .../Box2D/Dynamics/Joints/b2WeldJoint.cpp | 330 ++ .../Box2D/Dynamics/Joints/b2WeldJoint.h | 136 + .../Box2D/Dynamics/Joints/b2WheelJoint.cpp | 419 +++ .../Box2D/Dynamics/Joints/b2WheelJoint.h | 224 ++ tests/Box2D_v2.2.1/Box2D/Dynamics/b2Body.cpp | 514 +++ tests/Box2D_v2.2.1/Box2D/Dynamics/b2Body.h | 848 +++++ .../Box2D/Dynamics/b2ContactManager.cpp | 293 ++ .../Box2D/Dynamics/b2ContactManager.h | 52 + .../Box2D_v2.2.1/Box2D/Dynamics/b2Fixture.cpp | 303 ++ tests/Box2D_v2.2.1/Box2D/Dynamics/b2Fixture.h | 348 ++ .../Box2D_v2.2.1/Box2D/Dynamics/b2Island.cpp | 539 ++++ tests/Box2D_v2.2.1/Box2D/Dynamics/b2Island.h | 93 + .../Box2D_v2.2.1/Box2D/Dynamics/b2TimeStep.h | 70 + tests/Box2D_v2.2.1/Box2D/Dynamics/b2World.cpp | 1316 ++++++++ tests/Box2D_v2.2.1/Box2D/Dynamics/b2World.h | 349 ++ .../Box2D/Dynamics/b2WorldCallbacks.cpp | 36 + .../Box2D/Dynamics/b2WorldCallbacks.h | 163 + tests/Box2D_v2.2.1/Box2D/Rope/b2Rope.cpp | 259 ++ tests/Box2D_v2.2.1/Box2D/Rope/b2Rope.h | 115 + tests/Box2D_v2.2.1/Build/Readme.txt | 1 + tests/Box2D_v2.2.1/Build/vs2010/Box2D.sln | 74 + tests/Box2D_v2.2.1/Build/vs2010/Box2D.vcxproj | 340 ++ .../Build/vs2010/Box2D.vcxproj.filters | 301 ++ .../Build/vs2010/FreeGLUT.vcxproj | 250 ++ .../Build/vs2010/FreeGLUT.vcxproj.filters | 102 + tests/Box2D_v2.2.1/Build/vs2010/GLUI.vcxproj | 275 ++ .../Build/vs2010/GLUI.vcxproj.filters | 129 + .../Build/vs2010/HelloWorld.vcxproj | 209 ++ .../Build/vs2010/HelloWorld.vcxproj.filters | 6 + .../Box2D_v2.2.1/Build/vs2010/Testbed.vcxproj | 265 ++ .../Build/vs2010/Testbed.vcxproj.filters | 171 + .../xcode4/Box2D.xcodeproj/project.pbxproj | 1210 +++++++ .../contents.xcworkspacedata | 7 + tests/Box2D_v2.2.1/Building.txt | 37 + tests/Box2D_v2.2.1/CMakeLists.txt | 35 + tests/Box2D_v2.2.1/HelloWorld/CMakeLists.txt | 4 + tests/Box2D_v2.2.1/HelloWorld/HelloWorld.cpp | 106 + tests/Box2D_v2.2.1/License.txt | 18 + tests/Box2D_v2.2.1/Readme.txt | 19 + tests/Box2D_v2.2.1/Testbed/CMakeLists.txt | 92 + tests/Box2D_v2.2.1/Testbed/Framework/Main.cpp | 447 +++ .../Box2D_v2.2.1/Testbed/Framework/Render.cpp | 197 ++ tests/Box2D_v2.2.1/Testbed/Framework/Render.h | 51 + tests/Box2D_v2.2.1/Testbed/Framework/Test.cpp | 447 +++ tests/Box2D_v2.2.1/Testbed/Framework/Test.h | 189 ++ tests/Box2D_v2.2.1/Testbed/Tests/AddPair.h | 51 + tests/Box2D_v2.2.1/Testbed/Tests/ApplyForce.h | 180 ++ tests/Box2D_v2.2.1/Testbed/Tests/BodyTypes.h | 159 + tests/Box2D_v2.2.1/Testbed/Tests/Breakable.h | 155 + tests/Box2D_v2.2.1/Testbed/Tests/Bridge.h | 125 + tests/Box2D_v2.2.1/Testbed/Tests/BulletTest.h | 136 + tests/Box2D_v2.2.1/Testbed/Tests/Cantilever.h | 211 ++ tests/Box2D_v2.2.1/Testbed/Tests/Car.h | 286 ++ tests/Box2D_v2.2.1/Testbed/Tests/Chain.h | 74 + .../Testbed/Tests/CharacterCollision.h | 253 ++ .../Testbed/Tests/CollisionFiltering.h | 176 + .../Testbed/Tests/CollisionProcessing.h | 188 ++ .../Testbed/Tests/CompoundShapes.h | 143 + tests/Box2D_v2.2.1/Testbed/Tests/Confined.h | 167 + .../Testbed/Tests/ContinuousTest.h | 137 + .../Box2D_v2.2.1/Testbed/Tests/DistanceTest.h | 135 + tests/Box2D_v2.2.1/Testbed/Tests/Dominos.h | 215 ++ tests/Box2D_v2.2.1/Testbed/Tests/DumpShell.h | 267 ++ .../Testbed/Tests/DynamicTreeTest.h | 357 +++ tests/Box2D_v2.2.1/Testbed/Tests/EdgeShapes.h | 249 ++ tests/Box2D_v2.2.1/Testbed/Tests/EdgeTest.h | 109 + tests/Box2D_v2.2.1/Testbed/Tests/Gears.h | 187 ++ .../Testbed/Tests/OneSidedPlatform.h | 120 + tests/Box2D_v2.2.1/Testbed/Tests/Pinball.h | 169 + .../Testbed/Tests/PolyCollision.h | 122 + tests/Box2D_v2.2.1/Testbed/Tests/PolyShapes.h | 295 ++ tests/Box2D_v2.2.1/Testbed/Tests/Prismatic.h | 107 + tests/Box2D_v2.2.1/Testbed/Tests/Pulleys.h | 106 + tests/Box2D_v2.2.1/Testbed/Tests/Pyramid.h | 89 + tests/Box2D_v2.2.1/Testbed/Tests/RayCast.h | 440 +++ tests/Box2D_v2.2.1/Testbed/Tests/Revolute.h | 166 + tests/Box2D_v2.2.1/Testbed/Tests/Rope.h | 101 + tests/Box2D_v2.2.1/Testbed/Tests/RopeJoint.h | 145 + tests/Box2D_v2.2.1/Testbed/Tests/SensorTest.h | 181 ++ .../Box2D_v2.2.1/Testbed/Tests/ShapeEditing.h | 105 + .../Box2D_v2.2.1/Testbed/Tests/SliderCrank.h | 156 + .../Box2D_v2.2.1/Testbed/Tests/SphereStack.h | 86 + .../Testbed/Tests/TestEntries.cpp | 125 + tests/Box2D_v2.2.1/Testbed/Tests/TheoJansen.h | 256 ++ tests/Box2D_v2.2.1/Testbed/Tests/Tiles.h | 156 + .../Box2D_v2.2.1/Testbed/Tests/TimeOfImpact.h | 131 + tests/Box2D_v2.2.1/Testbed/Tests/Tumbler.h | 99 + .../Testbed/Tests/VaryingFriction.h | 124 + .../Testbed/Tests/VaryingRestitution.h | 69 + .../Testbed/Tests/VerticalStack.h | 165 + tests/Box2D_v2.2.1/Testbed/Tests/Web.h | 209 ++ tests/Box2D_v2.2.1/freeglut/CMakeLists.txt | 51 + tests/Box2D_v2.2.1/freeglut/COPYING | 27 + tests/Box2D_v2.2.1/freeglut/freeglut.h | 22 + .../freeglut/freeglut_callbacks.c | 367 +++ tests/Box2D_v2.2.1/freeglut/freeglut_cursor.c | 280 ++ .../Box2D_v2.2.1/freeglut/freeglut_display.c | 98 + tests/Box2D_v2.2.1/freeglut/freeglut_ext.c | 226 ++ tests/Box2D_v2.2.1/freeglut/freeglut_ext.h | 212 ++ tests/Box2D_v2.2.1/freeglut/freeglut_font.c | 384 +++ .../freeglut/freeglut_font_data.c | 2020 ++++++++++++ .../Box2D_v2.2.1/freeglut/freeglut_gamemode.c | 594 ++++ .../Box2D_v2.2.1/freeglut/freeglut_geometry.c | 1215 +++++++ .../freeglut/freeglut_glutfont_definitions.c | 108 + tests/Box2D_v2.2.1/freeglut/freeglut_init.c | 1166 +++++++ .../freeglut/freeglut_input_devices.c | 395 +++ .../Box2D_v2.2.1/freeglut/freeglut_internal.h | 960 ++++++ .../Box2D_v2.2.1/freeglut/freeglut_joystick.c | 1801 +++++++++++ tests/Box2D_v2.2.1/freeglut/freeglut_main.c | 2296 +++++++++++++ tests/Box2D_v2.2.1/freeglut/freeglut_menu.c | 1002 ++++++ tests/Box2D_v2.2.1/freeglut/freeglut_misc.c | 214 ++ .../Box2D_v2.2.1/freeglut/freeglut_overlay.c | 45 + .../freeglut/freeglut_spaceball.c | 454 +++ tests/Box2D_v2.2.1/freeglut/freeglut_state.c | 895 ++++++ tests/Box2D_v2.2.1/freeglut/freeglut_std.h | 583 ++++ .../freeglut/freeglut_stroke_mono_roman.c | 2849 +++++++++++++++++ .../freeglut/freeglut_stroke_roman.c | 2849 +++++++++++++++++ .../freeglut/freeglut_structure.c | 596 ++++ tests/Box2D_v2.2.1/freeglut/freeglut_teapot.c | 200 ++ .../freeglut/freeglut_teapot_data.h | 2429 ++++++++++++++ .../freeglut/freeglut_videoresize.c | 50 + tests/Box2D_v2.2.1/freeglut/freeglut_window.c | 1743 ++++++++++ tests/Box2D_v2.2.1/glui/CMakeLists.txt | 49 + tests/Box2D_v2.2.1/glui/algebra3.cpp | 1609 ++++++++++ tests/Box2D_v2.2.1/glui/algebra3.h | 475 +++ tests/Box2D_v2.2.1/glui/arcball.cpp | 237 ++ tests/Box2D_v2.2.1/glui/arcball.h | 97 + tests/Box2D_v2.2.1/glui/glui.cpp | 2105 ++++++++++++ tests/Box2D_v2.2.1/glui/glui.h | 2568 +++++++++++++++ tests/Box2D_v2.2.1/glui/glui_add_controls.cpp | 319 ++ .../glui/glui_bitmap_img_data.cpp | 138 + tests/Box2D_v2.2.1/glui/glui_bitmaps.cpp | 176 + tests/Box2D_v2.2.1/glui/glui_button.cpp | 186 ++ tests/Box2D_v2.2.1/glui/glui_checkbox.cpp | 188 ++ tests/Box2D_v2.2.1/glui/glui_column.cpp | 89 + tests/Box2D_v2.2.1/glui/glui_commandline.cpp | 197 ++ tests/Box2D_v2.2.1/glui/glui_control.cpp | 1203 +++++++ tests/Box2D_v2.2.1/glui/glui_edittext.cpp | 1198 +++++++ tests/Box2D_v2.2.1/glui/glui_filebrowser.cpp | 165 + tests/Box2D_v2.2.1/glui/glui_internal.h | 105 + .../Box2D_v2.2.1/glui/glui_internal_control.h | 45 + tests/Box2D_v2.2.1/glui/glui_list.cpp | 540 ++++ tests/Box2D_v2.2.1/glui/glui_listbox.cpp | 448 +++ .../Box2D_v2.2.1/glui/glui_mouse_iaction.cpp | 210 ++ tests/Box2D_v2.2.1/glui/glui_node.cpp | 212 ++ tests/Box2D_v2.2.1/glui/glui_panel.cpp | 186 ++ tests/Box2D_v2.2.1/glui/glui_radio.cpp | 362 +++ tests/Box2D_v2.2.1/glui/glui_rollout.cpp | 275 ++ tests/Box2D_v2.2.1/glui/glui_rotation.cpp | 473 +++ tests/Box2D_v2.2.1/glui/glui_scrollbar.cpp | 832 +++++ tests/Box2D_v2.2.1/glui/glui_separator.cpp | 75 + tests/Box2D_v2.2.1/glui/glui_spinner.cpp | 647 ++++ tests/Box2D_v2.2.1/glui/glui_statictext.cpp | 105 + tests/Box2D_v2.2.1/glui/glui_string.cpp | 62 + tests/Box2D_v2.2.1/glui/glui_textbox.cpp | 1108 +++++++ tests/Box2D_v2.2.1/glui/glui_translation.cpp | 559 ++++ tests/Box2D_v2.2.1/glui/glui_tree.cpp | 278 ++ tests/Box2D_v2.2.1/glui/glui_treepanel.cpp | 387 +++ tests/Box2D_v2.2.1/glui/glui_window.cpp | 44 + tests/Box2D_v2.2.1/glui/quaternion.cpp | 243 ++ tests/Box2D_v2.2.1/glui/quaternion.h | 114 + tests/Box2D_v2.2.1/glui/readme.txt | 228 ++ tests/Box2D_v2.2.1/premake4.lua | 67 + 237 files changed, 78244 insertions(+) create mode 100755 tests/Box2D_v2.2.1/Box2D/Box2D.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Box2DConfig.cmake create mode 100755 tests/Box2D_v2.2.1/Box2D/CMakeLists.txt create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2ChainShape.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2ChainShape.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2CircleShape.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2CircleShape.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2EdgeShape.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2EdgeShape.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2PolygonShape.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2PolygonShape.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2Shape.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/b2BroadPhase.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/b2BroadPhase.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/b2CollideCircle.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/b2CollideEdge.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/b2CollidePolygon.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/b2Collision.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/b2Collision.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/b2Distance.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/b2Distance.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/b2DynamicTree.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/b2DynamicTree.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/b2TimeOfImpact.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Collision/b2TimeOfImpact.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Common/b2BlockAllocator.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Common/b2BlockAllocator.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Common/b2Draw.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Common/b2Draw.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Common/b2GrowableStack.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Common/b2Math.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Common/b2Math.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Common/b2Settings.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Common/b2Settings.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Common/b2StackAllocator.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Common/b2StackAllocator.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Common/b2Timer.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Common/b2Timer.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2CircleContact.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2CircleContact.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2Contact.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2Contact.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ContactSolver.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ContactSolver.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonContact.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonContact.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2DistanceJoint.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2DistanceJoint.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2FrictionJoint.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2FrictionJoint.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2GearJoint.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2GearJoint.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2Joint.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2Joint.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2MouseJoint.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2MouseJoint.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PrismaticJoint.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PulleyJoint.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PulleyJoint.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RevoluteJoint.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RopeJoint.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RopeJoint.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WeldJoint.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WeldJoint.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WheelJoint.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WheelJoint.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/b2Body.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/b2Body.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/b2ContactManager.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/b2ContactManager.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/b2Fixture.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/b2Fixture.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/b2Island.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/b2Island.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/b2TimeStep.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/b2World.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/b2World.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/b2WorldCallbacks.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Dynamics/b2WorldCallbacks.h create mode 100755 tests/Box2D_v2.2.1/Box2D/Rope/b2Rope.cpp create mode 100755 tests/Box2D_v2.2.1/Box2D/Rope/b2Rope.h create mode 100755 tests/Box2D_v2.2.1/Build/Readme.txt create mode 100755 tests/Box2D_v2.2.1/Build/vs2010/Box2D.sln create mode 100755 tests/Box2D_v2.2.1/Build/vs2010/Box2D.vcxproj create mode 100755 tests/Box2D_v2.2.1/Build/vs2010/Box2D.vcxproj.filters create mode 100755 tests/Box2D_v2.2.1/Build/vs2010/FreeGLUT.vcxproj create mode 100755 tests/Box2D_v2.2.1/Build/vs2010/FreeGLUT.vcxproj.filters create mode 100755 tests/Box2D_v2.2.1/Build/vs2010/GLUI.vcxproj create mode 100755 tests/Box2D_v2.2.1/Build/vs2010/GLUI.vcxproj.filters create mode 100755 tests/Box2D_v2.2.1/Build/vs2010/HelloWorld.vcxproj create mode 100755 tests/Box2D_v2.2.1/Build/vs2010/HelloWorld.vcxproj.filters create mode 100755 tests/Box2D_v2.2.1/Build/vs2010/Testbed.vcxproj create mode 100755 tests/Box2D_v2.2.1/Build/vs2010/Testbed.vcxproj.filters create mode 100755 tests/Box2D_v2.2.1/Build/xcode4/Box2D.xcodeproj/project.pbxproj create mode 100755 tests/Box2D_v2.2.1/Build/xcode4/Box2D.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100755 tests/Box2D_v2.2.1/Building.txt create mode 100755 tests/Box2D_v2.2.1/CMakeLists.txt create mode 100755 tests/Box2D_v2.2.1/HelloWorld/CMakeLists.txt create mode 100755 tests/Box2D_v2.2.1/HelloWorld/HelloWorld.cpp create mode 100755 tests/Box2D_v2.2.1/License.txt create mode 100755 tests/Box2D_v2.2.1/Readme.txt create mode 100755 tests/Box2D_v2.2.1/Testbed/CMakeLists.txt create mode 100755 tests/Box2D_v2.2.1/Testbed/Framework/Main.cpp create mode 100755 tests/Box2D_v2.2.1/Testbed/Framework/Render.cpp create mode 100755 tests/Box2D_v2.2.1/Testbed/Framework/Render.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Framework/Test.cpp create mode 100755 tests/Box2D_v2.2.1/Testbed/Framework/Test.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/AddPair.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/ApplyForce.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/BodyTypes.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Breakable.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Bridge.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/BulletTest.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Cantilever.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Car.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Chain.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/CharacterCollision.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/CollisionFiltering.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/CollisionProcessing.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/CompoundShapes.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Confined.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/ContinuousTest.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/DistanceTest.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Dominos.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/DumpShell.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/DynamicTreeTest.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/EdgeShapes.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/EdgeTest.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Gears.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/OneSidedPlatform.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Pinball.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/PolyCollision.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/PolyShapes.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Prismatic.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Pulleys.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Pyramid.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/RayCast.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Revolute.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Rope.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/RopeJoint.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/SensorTest.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/ShapeEditing.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/SliderCrank.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/SphereStack.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/TestEntries.cpp create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/TheoJansen.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Tiles.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/TimeOfImpact.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Tumbler.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/VaryingFriction.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/VaryingRestitution.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/VerticalStack.h create mode 100755 tests/Box2D_v2.2.1/Testbed/Tests/Web.h create mode 100755 tests/Box2D_v2.2.1/freeglut/CMakeLists.txt create mode 100755 tests/Box2D_v2.2.1/freeglut/COPYING create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut.h create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_callbacks.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_cursor.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_display.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_ext.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_ext.h create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_font.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_font_data.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_gamemode.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_geometry.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_glutfont_definitions.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_init.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_input_devices.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_internal.h create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_joystick.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_main.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_menu.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_misc.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_overlay.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_spaceball.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_state.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_std.h create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_stroke_mono_roman.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_stroke_roman.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_structure.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_teapot.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_teapot_data.h create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_videoresize.c create mode 100755 tests/Box2D_v2.2.1/freeglut/freeglut_window.c create mode 100755 tests/Box2D_v2.2.1/glui/CMakeLists.txt create mode 100755 tests/Box2D_v2.2.1/glui/algebra3.cpp create mode 100755 tests/Box2D_v2.2.1/glui/algebra3.h create mode 100755 tests/Box2D_v2.2.1/glui/arcball.cpp create mode 100755 tests/Box2D_v2.2.1/glui/arcball.h create mode 100755 tests/Box2D_v2.2.1/glui/glui.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui.h create mode 100755 tests/Box2D_v2.2.1/glui/glui_add_controls.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_bitmap_img_data.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_bitmaps.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_button.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_checkbox.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_column.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_commandline.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_control.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_edittext.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_filebrowser.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_internal.h create mode 100755 tests/Box2D_v2.2.1/glui/glui_internal_control.h create mode 100755 tests/Box2D_v2.2.1/glui/glui_list.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_listbox.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_mouse_iaction.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_node.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_panel.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_radio.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_rollout.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_rotation.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_scrollbar.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_separator.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_spinner.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_statictext.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_string.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_textbox.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_translation.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_tree.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_treepanel.cpp create mode 100755 tests/Box2D_v2.2.1/glui/glui_window.cpp create mode 100755 tests/Box2D_v2.2.1/glui/quaternion.cpp create mode 100755 tests/Box2D_v2.2.1/glui/quaternion.h create mode 100755 tests/Box2D_v2.2.1/glui/readme.txt create mode 100755 tests/Box2D_v2.2.1/premake4.lua diff --git a/tests/Box2D_v2.2.1/Box2D/Box2D.h b/tests/Box2D_v2.2.1/Box2D/Box2D.h new file mode 100755 index 0000000000000..66d2217429135 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Box2D.h @@ -0,0 +1,67 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef BOX2D_H +#define BOX2D_H + +/** +\mainpage Box2D API Documentation + +\section intro_sec Getting Started + +For documentation please see http://box2d.org/documentation.html + +For discussion please visit http://box2d.org/forum +*/ + +// These include files constitute the main Box2D API + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Box2DConfig.cmake b/tests/Box2D_v2.2.1/Box2D/Box2DConfig.cmake new file mode 100755 index 0000000000000..b567c17d14df9 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Box2DConfig.cmake @@ -0,0 +1,3 @@ +get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +include(${SELF_DIR}/Box2D-targets.cmake) +get_filename_component(Box2D_INCLUDE_DIRS "${SELF_DIR}/../../include" ABSOLUTE) diff --git a/tests/Box2D_v2.2.1/Box2D/CMakeLists.txt b/tests/Box2D_v2.2.1/Box2D/CMakeLists.txt new file mode 100755 index 0000000000000..445c248acfa18 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/CMakeLists.txt @@ -0,0 +1,205 @@ +set(BOX2D_Collision_SRCS + Collision/b2BroadPhase.cpp + Collision/b2CollideCircle.cpp + Collision/b2CollideEdge.cpp + Collision/b2CollidePolygon.cpp + Collision/b2Collision.cpp + Collision/b2Distance.cpp + Collision/b2DynamicTree.cpp + Collision/b2TimeOfImpact.cpp +) +set(BOX2D_Collision_HDRS + Collision/b2BroadPhase.h + Collision/b2Collision.h + Collision/b2Distance.h + Collision/b2DynamicTree.h + Collision/b2TimeOfImpact.h +) +set(BOX2D_Shapes_SRCS + Collision/Shapes/b2CircleShape.cpp + Collision/Shapes/b2EdgeShape.cpp + Collision/Shapes/b2ChainShape.cpp + Collision/Shapes/b2PolygonShape.cpp +) +set(BOX2D_Shapes_HDRS + Collision/Shapes/b2CircleShape.h + Collision/Shapes/b2EdgeShape.h + Collision/Shapes/b2ChainShape.h + Collision/Shapes/b2PolygonShape.h + Collision/Shapes/b2Shape.h +) +set(BOX2D_Common_SRCS + Common/b2BlockAllocator.cpp + Common/b2Draw.cpp + Common/b2Math.cpp + Common/b2Settings.cpp + Common/b2StackAllocator.cpp + Common/b2Timer.cpp +) +set(BOX2D_Common_HDRS + Common/b2BlockAllocator.h + Common/b2Draw.h + Common/b2GrowableStack.h + Common/b2Math.h + Common/b2Settings.h + Common/b2StackAllocator.h + Common/b2Timer.h +) +set(BOX2D_Dynamics_SRCS + Dynamics/b2Body.cpp + Dynamics/b2ContactManager.cpp + Dynamics/b2Fixture.cpp + Dynamics/b2Island.cpp + Dynamics/b2World.cpp + Dynamics/b2WorldCallbacks.cpp +) +set(BOX2D_Dynamics_HDRS + Dynamics/b2Body.h + Dynamics/b2ContactManager.h + Dynamics/b2Fixture.h + Dynamics/b2Island.h + Dynamics/b2TimeStep.h + Dynamics/b2World.h + Dynamics/b2WorldCallbacks.h +) +set(BOX2D_Contacts_SRCS + Dynamics/Contacts/b2CircleContact.cpp + Dynamics/Contacts/b2Contact.cpp + Dynamics/Contacts/b2ContactSolver.cpp + Dynamics/Contacts/b2PolygonAndCircleContact.cpp + Dynamics/Contacts/b2EdgeAndCircleContact.cpp + Dynamics/Contacts/b2EdgeAndPolygonContact.cpp + Dynamics/Contacts/b2ChainAndCircleContact.cpp + Dynamics/Contacts/b2ChainAndPolygonContact.cpp + Dynamics/Contacts/b2PolygonContact.cpp +) +set(BOX2D_Contacts_HDRS + Dynamics/Contacts/b2CircleContact.h + Dynamics/Contacts/b2Contact.h + Dynamics/Contacts/b2ContactSolver.h + Dynamics/Contacts/b2PolygonAndCircleContact.h + Dynamics/Contacts/b2EdgeAndCircleContact.h + Dynamics/Contacts/b2EdgeAndPolygonContact.h + Dynamics/Contacts/b2ChainAndCircleContact.h + Dynamics/Contacts/b2ChainAndPolygonContact.h + Dynamics/Contacts/b2PolygonContact.h +) +set(BOX2D_Joints_SRCS + Dynamics/Joints/b2DistanceJoint.cpp + Dynamics/Joints/b2FrictionJoint.cpp + Dynamics/Joints/b2GearJoint.cpp + Dynamics/Joints/b2Joint.cpp + Dynamics/Joints/b2MouseJoint.cpp + Dynamics/Joints/b2PrismaticJoint.cpp + Dynamics/Joints/b2PulleyJoint.cpp + Dynamics/Joints/b2RevoluteJoint.cpp + Dynamics/Joints/b2RopeJoint.cpp + Dynamics/Joints/b2WeldJoint.cpp + Dynamics/Joints/b2WheelJoint.cpp +) +set(BOX2D_Joints_HDRS + Dynamics/Joints/b2DistanceJoint.h + Dynamics/Joints/b2FrictionJoint.h + Dynamics/Joints/b2GearJoint.h + Dynamics/Joints/b2Joint.h + Dynamics/Joints/b2MouseJoint.h + Dynamics/Joints/b2PrismaticJoint.h + Dynamics/Joints/b2PulleyJoint.h + Dynamics/Joints/b2RevoluteJoint.h + Dynamics/Joints/b2RopeJoint.h + Dynamics/Joints/b2WeldJoint.h + Dynamics/Joints/b2WheelJoint.h +) +set(BOX2D_Rope_SRCS + Rope/b2Rope.cpp +) +set(BOX2D_Rope_HDRS + Rope/b2Rope.h +) +set(BOX2D_General_HDRS + Box2D.h +) +include_directories( ../ ) + +if(BOX2D_BUILD_SHARED) + add_library(Box2D_shared SHARED + ${BOX2D_General_HDRS} + ${BOX2D_Joints_SRCS} + ${BOX2D_Joints_HDRS} + ${BOX2D_Contacts_SRCS} + ${BOX2D_Contacts_HDRS} + ${BOX2D_Dynamics_SRCS} + ${BOX2D_Dynamics_HDRS} + ${BOX2D_Common_SRCS} + ${BOX2D_Common_HDRS} + ${BOX2D_Shapes_SRCS} + ${BOX2D_Shapes_HDRS} + ${BOX2D_Collision_SRCS} + ${BOX2D_Collision_HDRS} + ${BOX2D_Rope_SRCS} + ${BOX2D_Rope_HDRS} + ) + set_target_properties(Box2D_shared PROPERTIES + OUTPUT_NAME "Box2D" + CLEAN_DIRECT_OUTPUT 1 + VERSION ${BOX2D_VERSION} + ) +endif() + +if(BOX2D_BUILD_STATIC) + add_library(Box2D STATIC + ${BOX2D_General_HDRS} + ${BOX2D_Joints_SRCS} + ${BOX2D_Joints_HDRS} + ${BOX2D_Contacts_SRCS} + ${BOX2D_Contacts_HDRS} + ${BOX2D_Dynamics_SRCS} + ${BOX2D_Dynamics_HDRS} + ${BOX2D_Common_SRCS} + ${BOX2D_Common_HDRS} + ${BOX2D_Shapes_SRCS} + ${BOX2D_Shapes_HDRS} + ${BOX2D_Collision_SRCS} + ${BOX2D_Collision_HDRS} + ${BOX2D_Rope_SRCS} + ${BOX2D_Rope_HDRS} + ) + set_target_properties(Box2D PROPERTIES + CLEAN_DIRECT_OUTPUT 1 + VERSION ${BOX2D_VERSION} + ) +endif() + +# These are used to create visual studio folders. +source_group(Collision FILES ${BOX2D_Collision_SRCS} ${BOX2D_Collision_HDRS}) +source_group(Collision\\Shapes FILES ${BOX2D_Shapes_SRCS} ${BOX2D_Shapes_HDRS}) +source_group(Common FILES ${BOX2D_Common_SRCS} ${BOX2D_Common_HDRS}) +source_group(Dynamics FILES ${BOX2D_Dynamics_SRCS} ${BOX2D_Dynamics_HDRS}) +source_group(Dynamics\\Contacts FILES ${BOX2D_Contacts_SRCS} ${BOX2D_Contacts_HDRS}) +source_group(Dynamics\\Joints FILES ${BOX2D_Joints_SRCS} ${BOX2D_Joints_HDRS}) +source_group(Include FILES ${BOX2D_General_HDRS}) +source_group(Rope FILES ${BOX2D_Rope_SRCS} ${BOX2D_Rope_HDRS}) + +if(BOX2D_INSTALL) + # install headers + install(FILES ${BOX2D_General_HDRS} DESTINATION include/Box2D) + install(FILES ${BOX2D_Collision_HDRS} DESTINATION include/Box2D/Collision) + install(FILES ${BOX2D_Shapes_HDRS} DESTINATION include/Box2D/Collision/Shapes) + install(FILES ${BOX2D_Common_HDRS} DESTINATION include/Box2D/Common) + install(FILES ${BOX2D_Dynamics_HDRS} DESTINATION include/Box2D/Dynamics) + install(FILES ${BOX2D_Contacts_HDRS} DESTINATION include/Box2D/Dynamics/Contacts) + install(FILES ${BOX2D_Joints_HDRS} DESTINATION include/Box2D/Dynamics/Joints) + install(FILES ${BOX2D_Rope_HDRS} DESTINATION include/Box2D/Rope) + + # install libraries + if(BOX2D_BUILD_SHARED) + install(TARGETS Box2D_shared EXPORT Box2D-targets DESTINATION lib) + endif() + if(BOX2D_BUILD_STATIC) + install(TARGETS Box2D EXPORT Box2D-targets DESTINATION lib) + endif() + + # install build system hooks for third-party apps + install(EXPORT Box2D-targets DESTINATION lib/Box2D) + install(FILES Box2DConfig.cmake DESTINATION lib/Box2D) +endif(BOX2D_INSTALL) \ No newline at end of file diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2ChainShape.cpp b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2ChainShape.cpp new file mode 100755 index 0000000000000..f7bbe06b68d59 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2ChainShape.cpp @@ -0,0 +1,171 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +using namespace std; + +b2ChainShape::~b2ChainShape() +{ + b2Free(m_vertices); + m_vertices = NULL; + m_count = 0; +} + +void b2ChainShape::CreateLoop(const b2Vec2* vertices, int32 count) +{ + b2Assert(m_vertices == NULL && m_count == 0); + b2Assert(count >= 3); + m_count = count + 1; + m_vertices = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); + memcpy(m_vertices, vertices, count * sizeof(b2Vec2)); + m_vertices[count] = m_vertices[0]; + m_prevVertex = m_vertices[m_count - 2]; + m_nextVertex = m_vertices[1]; + m_hasPrevVertex = true; + m_hasNextVertex = true; +} + +void b2ChainShape::CreateChain(const b2Vec2* vertices, int32 count) +{ + b2Assert(m_vertices == NULL && m_count == 0); + b2Assert(count >= 2); + m_count = count; + m_vertices = (b2Vec2*)b2Alloc(count * sizeof(b2Vec2)); + memcpy(m_vertices, vertices, m_count * sizeof(b2Vec2)); + m_hasPrevVertex = false; + m_hasNextVertex = false; +} + +void b2ChainShape::SetPrevVertex(const b2Vec2& prevVertex) +{ + m_prevVertex = prevVertex; + m_hasPrevVertex = true; +} + +void b2ChainShape::SetNextVertex(const b2Vec2& nextVertex) +{ + m_nextVertex = nextVertex; + m_hasNextVertex = true; +} + +b2Shape* b2ChainShape::Clone(b2BlockAllocator* allocator) const +{ + void* mem = allocator->Allocate(sizeof(b2ChainShape)); + b2ChainShape* clone = new (mem) b2ChainShape; + clone->CreateChain(m_vertices, m_count); + clone->m_prevVertex = m_prevVertex; + clone->m_nextVertex = m_nextVertex; + clone->m_hasPrevVertex = m_hasPrevVertex; + clone->m_hasNextVertex = m_hasNextVertex; + return clone; +} + +int32 b2ChainShape::GetChildCount() const +{ + // edge count = vertex count - 1 + return m_count - 1; +} + +void b2ChainShape::GetChildEdge(b2EdgeShape* edge, int32 index) const +{ + b2Assert(0 <= index && index < m_count - 1); + edge->m_type = b2Shape::e_edge; + edge->m_radius = m_radius; + + edge->m_vertex1 = m_vertices[index + 0]; + edge->m_vertex2 = m_vertices[index + 1]; + + if (index > 0) + { + edge->m_vertex0 = m_vertices[index - 1]; + edge->m_hasVertex0 = true; + } + else + { + edge->m_vertex0 = m_prevVertex; + edge->m_hasVertex0 = m_hasPrevVertex; + } + + if (index < m_count - 2) + { + edge->m_vertex3 = m_vertices[index + 2]; + edge->m_hasVertex3 = true; + } + else + { + edge->m_vertex3 = m_nextVertex; + edge->m_hasVertex3 = m_hasNextVertex; + } +} + +bool b2ChainShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const +{ + B2_NOT_USED(xf); + B2_NOT_USED(p); + return false; +} + +bool b2ChainShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& xf, int32 childIndex) const +{ + b2Assert(childIndex < m_count); + + b2EdgeShape edgeShape; + + int32 i1 = childIndex; + int32 i2 = childIndex + 1; + if (i2 == m_count) + { + i2 = 0; + } + + edgeShape.m_vertex1 = m_vertices[i1]; + edgeShape.m_vertex2 = m_vertices[i2]; + + return edgeShape.RayCast(output, input, xf, 0); +} + +void b2ChainShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const +{ + b2Assert(childIndex < m_count); + + int32 i1 = childIndex; + int32 i2 = childIndex + 1; + if (i2 == m_count) + { + i2 = 0; + } + + b2Vec2 v1 = b2Mul(xf, m_vertices[i1]); + b2Vec2 v2 = b2Mul(xf, m_vertices[i2]); + + aabb->lowerBound = b2Min(v1, v2); + aabb->upperBound = b2Max(v1, v2); +} + +void b2ChainShape::ComputeMass(b2MassData* massData, float32 density) const +{ + B2_NOT_USED(density); + + massData->mass = 0.0f; + massData->center.SetZero(); + massData->I = 0.0f; +} diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2ChainShape.h b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2ChainShape.h new file mode 100755 index 0000000000000..6aa41ea417d6e --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2ChainShape.h @@ -0,0 +1,102 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_CHAIN_SHAPE_H +#define B2_CHAIN_SHAPE_H + +#include + +class b2EdgeShape; + +/// A chain shape is a free form sequence of line segments. +/// The chain has two-sided collision, so you can use inside and outside collision. +/// Therefore, you may use any winding order. +/// Since there may be many vertices, they are allocated using b2Alloc. +/// Connectivity information is used to create smooth collisions. +/// WARNING: The chain will not collide properly if there are self-intersections. +class b2ChainShape : public b2Shape +{ +public: + b2ChainShape(); + + /// The destructor frees the vertices using b2Free. + ~b2ChainShape(); + + /// Create a loop. This automatically adjusts connectivity. + /// @param vertices an array of vertices, these are copied + /// @param count the vertex count + void CreateLoop(const b2Vec2* vertices, int32 count); + + /// Create a chain with isolated end vertices. + /// @param vertices an array of vertices, these are copied + /// @param count the vertex count + void CreateChain(const b2Vec2* vertices, int32 count); + + /// Establish connectivity to a vertex that precedes the first vertex. + /// Don't call this for loops. + void SetPrevVertex(const b2Vec2& prevVertex); + + /// Establish connectivity to a vertex that follows the last vertex. + /// Don't call this for loops. + void SetNextVertex(const b2Vec2& nextVertex); + + /// Implement b2Shape. Vertices are cloned using b2Alloc. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// Get a child edge. + void GetChildEdge(b2EdgeShape* edge, int32 index) const; + + /// This always return false. + /// @see b2Shape::TestPoint + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// Chains have zero mass. + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// The vertices. Owned by this class. + b2Vec2* m_vertices; + + /// The vertex count. + int32 m_count; + + b2Vec2 m_prevVertex, m_nextVertex; + bool m_hasPrevVertex, m_hasNextVertex; +}; + +inline b2ChainShape::b2ChainShape() +{ + m_type = e_chain; + m_radius = b2_polygonRadius; + m_vertices = NULL; + m_count = 0; + m_hasPrevVertex = NULL; + m_hasNextVertex = NULL; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2CircleShape.cpp b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2CircleShape.cpp new file mode 100755 index 0000000000000..c03d662df7f05 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2CircleShape.cpp @@ -0,0 +1,100 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +using namespace std; + +b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const +{ + void* mem = allocator->Allocate(sizeof(b2CircleShape)); + b2CircleShape* clone = new (mem) b2CircleShape; + *clone = *this; + return clone; +} + +int32 b2CircleShape::GetChildCount() const +{ + return 1; +} + +bool b2CircleShape::TestPoint(const b2Transform& transform, const b2Vec2& p) const +{ + b2Vec2 center = transform.p + b2Mul(transform.q, m_p); + b2Vec2 d = p - center; + return b2Dot(d, d) <= m_radius * m_radius; +} + +// Collision Detection in Interactive 3D Environments by Gino van den Bergen +// From Section 3.1.2 +// x = s + a * r +// norm(x) = radius +bool b2CircleShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + b2Vec2 position = transform.p + b2Mul(transform.q, m_p); + b2Vec2 s = input.p1 - position; + float32 b = b2Dot(s, s) - m_radius * m_radius; + + // Solve quadratic equation. + b2Vec2 r = input.p2 - input.p1; + float32 c = b2Dot(s, r); + float32 rr = b2Dot(r, r); + float32 sigma = c * c - rr * b; + + // Check for negative discriminant and short segment. + if (sigma < 0.0f || rr < b2_epsilon) + { + return false; + } + + // Find the point of intersection of the line with the circle. + float32 a = -(c + b2Sqrt(sigma)); + + // Is the intersection point on the segment? + if (0.0f <= a && a <= input.maxFraction * rr) + { + a /= rr; + output->fraction = a; + output->normal = s + a * r; + output->normal.Normalize(); + return true; + } + + return false; +} + +void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + b2Vec2 p = transform.p + b2Mul(transform.q, m_p); + aabb->lowerBound.Set(p.x - m_radius, p.y - m_radius); + aabb->upperBound.Set(p.x + m_radius, p.y + m_radius); +} + +void b2CircleShape::ComputeMass(b2MassData* massData, float32 density) const +{ + massData->mass = density * b2_pi * m_radius * m_radius; + massData->center = m_p; + + // inertia about the local origin + massData->I = massData->mass * (0.5f * m_radius * m_radius + b2Dot(m_p, m_p)); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2CircleShape.h b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2CircleShape.h new file mode 100755 index 0000000000000..6c1fd543a3a40 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2CircleShape.h @@ -0,0 +1,91 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_CIRCLE_SHAPE_H +#define B2_CIRCLE_SHAPE_H + +#include + +/// A circle shape. +class b2CircleShape : public b2Shape +{ +public: + b2CircleShape(); + + /// Implement b2Shape. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// Implement b2Shape. + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// Get the supporting vertex index in the given direction. + int32 GetSupport(const b2Vec2& d) const; + + /// Get the supporting vertex in the given direction. + const b2Vec2& GetSupportVertex(const b2Vec2& d) const; + + /// Get the vertex count. + int32 GetVertexCount() const { return 1; } + + /// Get a vertex by index. Used by b2Distance. + const b2Vec2& GetVertex(int32 index) const; + + /// Position + b2Vec2 m_p; +}; + +inline b2CircleShape::b2CircleShape() +{ + m_type = e_circle; + m_radius = 0.0f; + m_p.SetZero(); +} + +inline int32 b2CircleShape::GetSupport(const b2Vec2 &d) const +{ + B2_NOT_USED(d); + return 0; +} + +inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const +{ + B2_NOT_USED(d); + return m_p; +} + +inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const +{ + B2_NOT_USED(index); + b2Assert(index == 0); + return m_p; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2EdgeShape.cpp b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2EdgeShape.cpp new file mode 100755 index 0000000000000..e204160b0e23e --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2EdgeShape.cpp @@ -0,0 +1,139 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +using namespace std; + +void b2EdgeShape::Set(const b2Vec2& v1, const b2Vec2& v2) +{ + m_vertex1 = v1; + m_vertex2 = v2; + m_hasVertex0 = false; + m_hasVertex3 = false; +} + +b2Shape* b2EdgeShape::Clone(b2BlockAllocator* allocator) const +{ + void* mem = allocator->Allocate(sizeof(b2EdgeShape)); + b2EdgeShape* clone = new (mem) b2EdgeShape; + *clone = *this; + return clone; +} + +int32 b2EdgeShape::GetChildCount() const +{ + return 1; +} + +bool b2EdgeShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const +{ + B2_NOT_USED(xf); + B2_NOT_USED(p); + return false; +} + +// p = p1 + t * d +// v = v1 + s * e +// p1 + t * d = v1 + s * e +// s * e - t * d = p1 - v1 +bool b2EdgeShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& xf, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + // Put the ray into the edge's frame of reference. + b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p); + b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p); + b2Vec2 d = p2 - p1; + + b2Vec2 v1 = m_vertex1; + b2Vec2 v2 = m_vertex2; + b2Vec2 e = v2 - v1; + b2Vec2 normal(e.y, -e.x); + normal.Normalize(); + + // q = p1 + t * d + // dot(normal, q - v1) = 0 + // dot(normal, p1 - v1) + t * dot(normal, d) = 0 + float32 numerator = b2Dot(normal, v1 - p1); + float32 denominator = b2Dot(normal, d); + + if (denominator == 0.0f) + { + return false; + } + + float32 t = numerator / denominator; + if (t < 0.0f || input.maxFraction < t) + { + return false; + } + + b2Vec2 q = p1 + t * d; + + // q = v1 + s * r + // s = dot(q - v1, r) / dot(r, r) + b2Vec2 r = v2 - v1; + float32 rr = b2Dot(r, r); + if (rr == 0.0f) + { + return false; + } + + float32 s = b2Dot(q - v1, r) / rr; + if (s < 0.0f || 1.0f < s) + { + return false; + } + + output->fraction = t; + if (numerator > 0.0f) + { + output->normal = -normal; + } + else + { + output->normal = normal; + } + return true; +} + +void b2EdgeShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + b2Vec2 v1 = b2Mul(xf, m_vertex1); + b2Vec2 v2 = b2Mul(xf, m_vertex2); + + b2Vec2 lower = b2Min(v1, v2); + b2Vec2 upper = b2Max(v1, v2); + + b2Vec2 r(m_radius, m_radius); + aabb->lowerBound = lower - r; + aabb->upperBound = upper + r; +} + +void b2EdgeShape::ComputeMass(b2MassData* massData, float32 density) const +{ + B2_NOT_USED(density); + + massData->mass = 0.0f; + massData->center = 0.5f * (m_vertex1 + m_vertex2); + massData->I = 0.0f; +} diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2EdgeShape.h b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2EdgeShape.h new file mode 100755 index 0000000000000..99f822bec6176 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2EdgeShape.h @@ -0,0 +1,74 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_EDGE_SHAPE_H +#define B2_EDGE_SHAPE_H + +#include + +/// A line segment (edge) shape. These can be connected in chains or loops +/// to other edge shapes. The connectivity information is used to ensure +/// correct contact normals. +class b2EdgeShape : public b2Shape +{ +public: + b2EdgeShape(); + + /// Set this as an isolated edge. + void Set(const b2Vec2& v1, const b2Vec2& v2); + + /// Implement b2Shape. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// @see b2Shape::TestPoint + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// These are the edge vertices + b2Vec2 m_vertex1, m_vertex2; + + /// Optional adjacent vertices. These are used for smooth collision. + b2Vec2 m_vertex0, m_vertex3; + bool m_hasVertex0, m_hasVertex3; +}; + +inline b2EdgeShape::b2EdgeShape() +{ + m_type = e_edge; + m_radius = b2_polygonRadius; + m_vertex0.x = 0.0f; + m_vertex0.y = 0.0f; + m_vertex3.x = 0.0f; + m_vertex3.y = 0.0f; + m_hasVertex0 = false; + m_hasVertex3 = false; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2PolygonShape.cpp b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2PolygonShape.cpp new file mode 100755 index 0000000000000..8be813338a4fb --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2PolygonShape.cpp @@ -0,0 +1,361 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include + +b2Shape* b2PolygonShape::Clone(b2BlockAllocator* allocator) const +{ + void* mem = allocator->Allocate(sizeof(b2PolygonShape)); + b2PolygonShape* clone = new (mem) b2PolygonShape; + *clone = *this; + return clone; +} + +void b2PolygonShape::SetAsBox(float32 hx, float32 hy) +{ + m_vertexCount = 4; + m_vertices[0].Set(-hx, -hy); + m_vertices[1].Set( hx, -hy); + m_vertices[2].Set( hx, hy); + m_vertices[3].Set(-hx, hy); + m_normals[0].Set(0.0f, -1.0f); + m_normals[1].Set(1.0f, 0.0f); + m_normals[2].Set(0.0f, 1.0f); + m_normals[3].Set(-1.0f, 0.0f); + m_centroid.SetZero(); +} + +void b2PolygonShape::SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle) +{ + m_vertexCount = 4; + m_vertices[0].Set(-hx, -hy); + m_vertices[1].Set( hx, -hy); + m_vertices[2].Set( hx, hy); + m_vertices[3].Set(-hx, hy); + m_normals[0].Set(0.0f, -1.0f); + m_normals[1].Set(1.0f, 0.0f); + m_normals[2].Set(0.0f, 1.0f); + m_normals[3].Set(-1.0f, 0.0f); + m_centroid = center; + + b2Transform xf; + xf.p = center; + xf.q.Set(angle); + + // Transform vertices and normals. + for (int32 i = 0; i < m_vertexCount; ++i) + { + m_vertices[i] = b2Mul(xf, m_vertices[i]); + m_normals[i] = b2Mul(xf.q, m_normals[i]); + } +} + +int32 b2PolygonShape::GetChildCount() const +{ + return 1; +} + +static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count) +{ + b2Assert(count >= 3); + + b2Vec2 c; c.Set(0.0f, 0.0f); + float32 area = 0.0f; + + // pRef is the reference point for forming triangles. + // It's location doesn't change the result (except for rounding error). + b2Vec2 pRef(0.0f, 0.0f); +#if 0 + // This code would put the reference point inside the polygon. + for (int32 i = 0; i < count; ++i) + { + pRef += vs[i]; + } + pRef *= 1.0f / count; +#endif + + const float32 inv3 = 1.0f / 3.0f; + + for (int32 i = 0; i < count; ++i) + { + // Triangle vertices. + b2Vec2 p1 = pRef; + b2Vec2 p2 = vs[i]; + b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0]; + + b2Vec2 e1 = p2 - p1; + b2Vec2 e2 = p3 - p1; + + float32 D = b2Cross(e1, e2); + + float32 triangleArea = 0.5f * D; + area += triangleArea; + + // Area weighted centroid + c += triangleArea * inv3 * (p1 + p2 + p3); + } + + // Centroid + b2Assert(area > b2_epsilon); + c *= 1.0f / area; + return c; +} + +void b2PolygonShape::Set(const b2Vec2* vertices, int32 count) +{ + b2Assert(3 <= count && count <= b2_maxPolygonVertices); + m_vertexCount = count; + + // Copy vertices. + for (int32 i = 0; i < m_vertexCount; ++i) + { + m_vertices[i] = vertices[i]; + } + + // Compute normals. Ensure the edges have non-zero length. + for (int32 i = 0; i < m_vertexCount; ++i) + { + int32 i1 = i; + int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0; + b2Vec2 edge = m_vertices[i2] - m_vertices[i1]; + b2Assert(edge.LengthSquared() > b2_epsilon * b2_epsilon); + m_normals[i] = b2Cross(edge, 1.0f); + m_normals[i].Normalize(); + } + +#ifdef _DEBUG + // Ensure the polygon is convex and the interior + // is to the left of each edge. + for (int32 i = 0; i < m_vertexCount; ++i) + { + int32 i1 = i; + int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0; + b2Vec2 edge = m_vertices[i2] - m_vertices[i1]; + + for (int32 j = 0; j < m_vertexCount; ++j) + { + // Don't check vertices on the current edge. + if (j == i1 || j == i2) + { + continue; + } + + b2Vec2 r = m_vertices[j] - m_vertices[i1]; + + // If this crashes, your polygon is non-convex, has colinear edges, + // or the winding order is wrong. + float32 s = b2Cross(edge, r); + b2Assert(s > 0.0f && "ERROR: Please ensure your polygon is convex and has a CCW winding order"); + } + } +#endif + + // Compute the polygon centroid. + m_centroid = ComputeCentroid(m_vertices, m_vertexCount); +} + +bool b2PolygonShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const +{ + b2Vec2 pLocal = b2MulT(xf.q, p - xf.p); + + for (int32 i = 0; i < m_vertexCount; ++i) + { + float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]); + if (dot > 0.0f) + { + return false; + } + } + + return true; +} + +bool b2PolygonShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& xf, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + // Put the ray into the polygon's frame of reference. + b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p); + b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p); + b2Vec2 d = p2 - p1; + + float32 lower = 0.0f, upper = input.maxFraction; + + int32 index = -1; + + for (int32 i = 0; i < m_vertexCount; ++i) + { + // p = p1 + a * d + // dot(normal, p - v) = 0 + // dot(normal, p1 - v) + a * dot(normal, d) = 0 + float32 numerator = b2Dot(m_normals[i], m_vertices[i] - p1); + float32 denominator = b2Dot(m_normals[i], d); + + if (denominator == 0.0f) + { + if (numerator < 0.0f) + { + return false; + } + } + else + { + // Note: we want this predicate without division: + // lower < numerator / denominator, where denominator < 0 + // Since denominator < 0, we have to flip the inequality: + // lower < numerator / denominator <==> denominator * lower > numerator. + if (denominator < 0.0f && numerator < lower * denominator) + { + // Increase lower. + // The segment enters this half-space. + lower = numerator / denominator; + index = i; + } + else if (denominator > 0.0f && numerator < upper * denominator) + { + // Decrease upper. + // The segment exits this half-space. + upper = numerator / denominator; + } + } + + // The use of epsilon here causes the assert on lower to trip + // in some cases. Apparently the use of epsilon was to make edge + // shapes work, but now those are handled separately. + //if (upper < lower - b2_epsilon) + if (upper < lower) + { + return false; + } + } + + b2Assert(0.0f <= lower && lower <= input.maxFraction); + + if (index >= 0) + { + output->fraction = lower; + output->normal = b2Mul(xf.q, m_normals[index]); + return true; + } + + return false; +} + +void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + b2Vec2 lower = b2Mul(xf, m_vertices[0]); + b2Vec2 upper = lower; + + for (int32 i = 1; i < m_vertexCount; ++i) + { + b2Vec2 v = b2Mul(xf, m_vertices[i]); + lower = b2Min(lower, v); + upper = b2Max(upper, v); + } + + b2Vec2 r(m_radius, m_radius); + aabb->lowerBound = lower - r; + aabb->upperBound = upper + r; +} + +void b2PolygonShape::ComputeMass(b2MassData* massData, float32 density) const +{ + // Polygon mass, centroid, and inertia. + // Let rho be the polygon density in mass per unit area. + // Then: + // mass = rho * int(dA) + // centroid.x = (1/mass) * rho * int(x * dA) + // centroid.y = (1/mass) * rho * int(y * dA) + // I = rho * int((x*x + y*y) * dA) + // + // We can compute these integrals by summing all the integrals + // for each triangle of the polygon. To evaluate the integral + // for a single triangle, we make a change of variables to + // the (u,v) coordinates of the triangle: + // x = x0 + e1x * u + e2x * v + // y = y0 + e1y * u + e2y * v + // where 0 <= u && 0 <= v && u + v <= 1. + // + // We integrate u from [0,1-v] and then v from [0,1]. + // We also need to use the Jacobian of the transformation: + // D = cross(e1, e2) + // + // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3) + // + // The rest of the derivation is handled by computer algebra. + + b2Assert(m_vertexCount >= 3); + + b2Vec2 center; center.Set(0.0f, 0.0f); + float32 area = 0.0f; + float32 I = 0.0f; + + // s is the reference point for forming triangles. + // It's location doesn't change the result (except for rounding error). + b2Vec2 s(0.0f, 0.0f); + + // This code would put the reference point inside the polygon. + for (int32 i = 0; i < m_vertexCount; ++i) + { + s += m_vertices[i]; + } + s *= 1.0f / m_vertexCount; + + const float32 k_inv3 = 1.0f / 3.0f; + + for (int32 i = 0; i < m_vertexCount; ++i) + { + // Triangle vertices. + b2Vec2 e1 = m_vertices[i] - s; + b2Vec2 e2 = i + 1 < m_vertexCount ? m_vertices[i+1] - s : m_vertices[0] - s; + + float32 D = b2Cross(e1, e2); + + float32 triangleArea = 0.5f * D; + area += triangleArea; + + // Area weighted centroid + center += triangleArea * k_inv3 * (e1 + e2); + + float32 ex1 = e1.x, ey1 = e1.y; + float32 ex2 = e2.x, ey2 = e2.y; + + float32 intx2 = ex1*ex1 + ex2*ex1 + ex2*ex2; + float32 inty2 = ey1*ey1 + ey2*ey1 + ey2*ey2; + + I += (0.25f * k_inv3 * D) * (intx2 + inty2); + } + + // Total mass + massData->mass = density * area; + + // Center of mass + b2Assert(area > b2_epsilon); + center *= 1.0f / area; + massData->center = center + s; + + // Inertia tensor relative to the local origin (point s). + massData->I = density * I; + + // Shift to center of mass then to original body origin. + massData->I += massData->mass * (b2Dot(massData->center, massData->center) - b2Dot(center, center)); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2PolygonShape.h b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2PolygonShape.h new file mode 100755 index 0000000000000..fd11bd16286c6 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2PolygonShape.h @@ -0,0 +1,95 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_POLYGON_SHAPE_H +#define B2_POLYGON_SHAPE_H + +#include + +/// A convex polygon. It is assumed that the interior of the polygon is to +/// the left of each edge. +/// Polygons have a maximum number of vertices equal to b2_maxPolygonVertices. +/// In most cases you should not need many vertices for a convex polygon. +class b2PolygonShape : public b2Shape +{ +public: + b2PolygonShape(); + + /// Implement b2Shape. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// Copy vertices. This assumes the vertices define a convex polygon. + /// It is assumed that the exterior is the the right of each edge. + /// The count must be in the range [3, b2_maxPolygonVertices]. + void Set(const b2Vec2* vertices, int32 vertexCount); + + /// Build vertices to represent an axis-aligned box. + /// @param hx the half-width. + /// @param hy the half-height. + void SetAsBox(float32 hx, float32 hy); + + /// Build vertices to represent an oriented box. + /// @param hx the half-width. + /// @param hy the half-height. + /// @param center the center of the box in local coordinates. + /// @param angle the rotation of the box in local coordinates. + void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle); + + /// @see b2Shape::TestPoint + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// Get the vertex count. + int32 GetVertexCount() const { return m_vertexCount; } + + /// Get a vertex by index. + const b2Vec2& GetVertex(int32 index) const; + + b2Vec2 m_centroid; + b2Vec2 m_vertices[b2_maxPolygonVertices]; + b2Vec2 m_normals[b2_maxPolygonVertices]; + int32 m_vertexCount; +}; + +inline b2PolygonShape::b2PolygonShape() +{ + m_type = e_polygon; + m_radius = b2_polygonRadius; + m_vertexCount = 0; + m_centroid.SetZero(); +} + +inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const +{ + b2Assert(0 <= index && index < m_vertexCount); + return m_vertices[index]; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2Shape.h b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2Shape.h new file mode 100755 index 0000000000000..fd7de2626e17e --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2Shape.h @@ -0,0 +1,101 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_SHAPE_H +#define B2_SHAPE_H + +#include +#include +#include + +/// This holds the mass data computed for a shape. +struct b2MassData +{ + /// The mass of the shape, usually in kilograms. + float32 mass; + + /// The position of the shape's centroid relative to the shape's origin. + b2Vec2 center; + + /// The rotational inertia of the shape about the local origin. + float32 I; +}; + +/// A shape is used for collision detection. You can create a shape however you like. +/// Shapes used for simulation in b2World are created automatically when a b2Fixture +/// is created. Shapes may encapsulate a one or more child shapes. +class b2Shape +{ +public: + + enum Type + { + e_circle = 0, + e_edge = 1, + e_polygon = 2, + e_chain = 3, + e_typeCount = 4 + }; + + virtual ~b2Shape() {} + + /// Clone the concrete shape using the provided allocator. + virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0; + + /// Get the type of this shape. You can use this to down cast to the concrete shape. + /// @return the shape type. + Type GetType() const; + + /// Get the number of child primitives. + virtual int32 GetChildCount() const = 0; + + /// Test a point for containment in this shape. This only works for convex shapes. + /// @param xf the shape world transform. + /// @param p a point in world coordinates. + virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0; + + /// Cast a ray against a child shape. + /// @param output the ray-cast results. + /// @param input the ray-cast input parameters. + /// @param transform the transform to be applied to the shape. + /// @param childIndex the child shape index + virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const = 0; + + /// Given a transform, compute the associated axis aligned bounding box for a child shape. + /// @param aabb returns the axis aligned box. + /// @param xf the world transform of the shape. + /// @param childIndex the child shape + virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const = 0; + + /// Compute the mass properties of this shape using its dimensions and density. + /// The inertia tensor is computed about the local origin. + /// @param massData returns the mass data for this shape. + /// @param density the density in kilograms per meter squared. + virtual void ComputeMass(b2MassData* massData, float32 density) const = 0; + + Type m_type; + float32 m_radius; +}; + +inline b2Shape::Type b2Shape::GetType() const +{ + return m_type; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2BroadPhase.cpp b/tests/Box2D_v2.2.1/Box2D/Collision/b2BroadPhase.cpp new file mode 100755 index 0000000000000..2aa62f9482e4b --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/b2BroadPhase.cpp @@ -0,0 +1,122 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +using namespace std; + +b2BroadPhase::b2BroadPhase() +{ + m_proxyCount = 0; + + m_pairCapacity = 16; + m_pairCount = 0; + m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); + + m_moveCapacity = 16; + m_moveCount = 0; + m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32)); +} + +b2BroadPhase::~b2BroadPhase() +{ + b2Free(m_moveBuffer); + b2Free(m_pairBuffer); +} + +int32 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData) +{ + int32 proxyId = m_tree.CreateProxy(aabb, userData); + ++m_proxyCount; + BufferMove(proxyId); + return proxyId; +} + +void b2BroadPhase::DestroyProxy(int32 proxyId) +{ + UnBufferMove(proxyId); + --m_proxyCount; + m_tree.DestroyProxy(proxyId); +} + +void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement) +{ + bool buffer = m_tree.MoveProxy(proxyId, aabb, displacement); + if (buffer) + { + BufferMove(proxyId); + } +} + +void b2BroadPhase::TouchProxy(int32 proxyId) +{ + BufferMove(proxyId); +} + +void b2BroadPhase::BufferMove(int32 proxyId) +{ + if (m_moveCount == m_moveCapacity) + { + int32* oldBuffer = m_moveBuffer; + m_moveCapacity *= 2; + m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32)); + memcpy(m_moveBuffer, oldBuffer, m_moveCount * sizeof(int32)); + b2Free(oldBuffer); + } + + m_moveBuffer[m_moveCount] = proxyId; + ++m_moveCount; +} + +void b2BroadPhase::UnBufferMove(int32 proxyId) +{ + for (int32 i = 0; i < m_moveCount; ++i) + { + if (m_moveBuffer[i] == proxyId) + { + m_moveBuffer[i] = e_nullProxy; + return; + } + } +} + +// This is called from b2DynamicTree::Query when we are gathering pairs. +bool b2BroadPhase::QueryCallback(int32 proxyId) +{ + // A proxy cannot form a pair with itself. + if (proxyId == m_queryProxyId) + { + return true; + } + + // Grow the pair buffer as needed. + if (m_pairCount == m_pairCapacity) + { + b2Pair* oldBuffer = m_pairBuffer; + m_pairCapacity *= 2; + m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); + memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair)); + b2Free(oldBuffer); + } + + m_pairBuffer[m_pairCount].proxyIdA = b2Min(proxyId, m_queryProxyId); + m_pairBuffer[m_pairCount].proxyIdB = b2Max(proxyId, m_queryProxyId); + ++m_pairCount; + + return true; +} diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2BroadPhase.h b/tests/Box2D_v2.2.1/Box2D/Collision/b2BroadPhase.h new file mode 100755 index 0000000000000..e31ff3d26fe07 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/b2BroadPhase.h @@ -0,0 +1,250 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_BROAD_PHASE_H +#define B2_BROAD_PHASE_H + +#include +#include +#include +#ifndef EM_NO_LIBCPP +#include +#endif + +struct b2Pair +{ + int32 proxyIdA; + int32 proxyIdB; + int32 next; +}; + +/// The broad-phase is used for computing pairs and performing volume queries and ray casts. +/// This broad-phase does not persist pairs. Instead, this reports potentially new pairs. +/// It is up to the client to consume the new pairs and to track subsequent overlap. +class b2BroadPhase +{ +public: + + enum + { + e_nullProxy = -1 + }; + + b2BroadPhase(); + ~b2BroadPhase(); + + /// Create a proxy with an initial AABB. Pairs are not reported until + /// UpdatePairs is called. + int32 CreateProxy(const b2AABB& aabb, void* userData); + + /// Destroy a proxy. It is up to the client to remove any pairs. + void DestroyProxy(int32 proxyId); + + /// Call MoveProxy as many times as you like, then when you are done + /// call UpdatePairs to finalized the proxy pairs (for your time step). + void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement); + + /// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs. + void TouchProxy(int32 proxyId); + + /// Get the fat AABB for a proxy. + const b2AABB& GetFatAABB(int32 proxyId) const; + + /// Get user data from a proxy. Returns NULL if the id is invalid. + void* GetUserData(int32 proxyId) const; + + /// Test overlap of fat AABBs. + bool TestOverlap(int32 proxyIdA, int32 proxyIdB) const; + + /// Get the number of proxies. + int32 GetProxyCount() const; + + /// Update the pairs. This results in pair callbacks. This can only add pairs. + template + void UpdatePairs(T* callback); + + /// Query an AABB for overlapping proxies. The callback class + /// is called for each proxy that overlaps the supplied AABB. + template + void Query(T* callback, const b2AABB& aabb) const; + + /// Ray-cast against the proxies in the tree. This relies on the callback + /// to perform a exact ray-cast in the case were the proxy contains a shape. + /// The callback also performs the any collision filtering. This has performance + /// roughly equal to k * log(n), where k is the number of collisions and n is the + /// number of proxies in the tree. + /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). + /// @param callback a callback class that is called for each proxy that is hit by the ray. + template + void RayCast(T* callback, const b2RayCastInput& input) const; + + /// Get the height of the embedded tree. + int32 GetTreeHeight() const; + + /// Get the balance of the embedded tree. + int32 GetTreeBalance() const; + + /// Get the quality metric of the embedded tree. + float32 GetTreeQuality() const; + +private: + + friend class b2DynamicTree; + + void BufferMove(int32 proxyId); + void UnBufferMove(int32 proxyId); + + bool QueryCallback(int32 proxyId); + + b2DynamicTree m_tree; + + int32 m_proxyCount; + + int32* m_moveBuffer; + int32 m_moveCapacity; + int32 m_moveCount; + + b2Pair* m_pairBuffer; + int32 m_pairCapacity; + int32 m_pairCount; + + int32 m_queryProxyId; +}; + +/// This is used to sort pairs. +inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2) +{ + if (pair1.proxyIdA < pair2.proxyIdA) + { + return true; + } + + if (pair1.proxyIdA == pair2.proxyIdA) + { + return pair1.proxyIdB < pair2.proxyIdB; + } + + return false; +} + +inline void* b2BroadPhase::GetUserData(int32 proxyId) const +{ + return m_tree.GetUserData(proxyId); +} + +inline bool b2BroadPhase::TestOverlap(int32 proxyIdA, int32 proxyIdB) const +{ + const b2AABB& aabbA = m_tree.GetFatAABB(proxyIdA); + const b2AABB& aabbB = m_tree.GetFatAABB(proxyIdB); + return b2TestOverlap(aabbA, aabbB); +} + +inline const b2AABB& b2BroadPhase::GetFatAABB(int32 proxyId) const +{ + return m_tree.GetFatAABB(proxyId); +} + +inline int32 b2BroadPhase::GetProxyCount() const +{ + return m_proxyCount; +} + +inline int32 b2BroadPhase::GetTreeHeight() const +{ + return m_tree.GetHeight(); +} + +inline int32 b2BroadPhase::GetTreeBalance() const +{ + return m_tree.GetMaxBalance(); +} + +inline float32 b2BroadPhase::GetTreeQuality() const +{ + return m_tree.GetAreaRatio(); +} + +template +void b2BroadPhase::UpdatePairs(T* callback) +{ + // Reset pair buffer + m_pairCount = 0; + + // Perform tree queries for all moving proxies. + for (int32 i = 0; i < m_moveCount; ++i) + { + m_queryProxyId = m_moveBuffer[i]; + if (m_queryProxyId == e_nullProxy) + { + continue; + } + + // We have to query the tree with the fat AABB so that + // we don't fail to create a pair that may touch later. + const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId); + + // Query tree, create pairs and add them pair buffer. + m_tree.Query(this, fatAABB); + } + + // Reset move buffer + m_moveCount = 0; + + // Sort the pair buffer to expose duplicates. + std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan); + + // Send the pairs back to the client. + int32 i = 0; + while (i < m_pairCount) + { + b2Pair* primaryPair = m_pairBuffer + i; + void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA); + void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB); + + callback->AddPair(userDataA, userDataB); + ++i; + + // Skip any duplicate pairs. + while (i < m_pairCount) + { + b2Pair* pair = m_pairBuffer + i; + if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB) + { + break; + } + ++i; + } + } + + // Try to keep the tree balanced. + //m_tree.Rebalance(4); +} + +template +inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const +{ + m_tree.Query(callback, aabb); +} + +template +inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const +{ + m_tree.RayCast(callback, input); +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2CollideCircle.cpp b/tests/Box2D_v2.2.1/Box2D/Collision/b2CollideCircle.cpp new file mode 100755 index 0000000000000..0ad58f00063a1 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/b2CollideCircle.cpp @@ -0,0 +1,154 @@ +/* +* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include + +void b2CollideCircles( + b2Manifold* manifold, + const b2CircleShape* circleA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB) +{ + manifold->pointCount = 0; + + b2Vec2 pA = b2Mul(xfA, circleA->m_p); + b2Vec2 pB = b2Mul(xfB, circleB->m_p); + + b2Vec2 d = pB - pA; + float32 distSqr = b2Dot(d, d); + float32 rA = circleA->m_radius, rB = circleB->m_radius; + float32 radius = rA + rB; + if (distSqr > radius * radius) + { + return; + } + + manifold->type = b2Manifold::e_circles; + manifold->localPoint = circleA->m_p; + manifold->localNormal.SetZero(); + manifold->pointCount = 1; + + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; +} + +void b2CollidePolygonAndCircle( + b2Manifold* manifold, + const b2PolygonShape* polygonA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB) +{ + manifold->pointCount = 0; + + // Compute circle position in the frame of the polygon. + b2Vec2 c = b2Mul(xfB, circleB->m_p); + b2Vec2 cLocal = b2MulT(xfA, c); + + // Find the min separating edge. + int32 normalIndex = 0; + float32 separation = -b2_maxFloat; + float32 radius = polygonA->m_radius + circleB->m_radius; + int32 vertexCount = polygonA->m_vertexCount; + const b2Vec2* vertices = polygonA->m_vertices; + const b2Vec2* normals = polygonA->m_normals; + + for (int32 i = 0; i < vertexCount; ++i) + { + float32 s = b2Dot(normals[i], cLocal - vertices[i]); + + if (s > radius) + { + // Early out. + return; + } + + if (s > separation) + { + separation = s; + normalIndex = i; + } + } + + // Vertices that subtend the incident face. + int32 vertIndex1 = normalIndex; + int32 vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0; + b2Vec2 v1 = vertices[vertIndex1]; + b2Vec2 v2 = vertices[vertIndex2]; + + // If the center is inside the polygon ... + if (separation < b2_epsilon) + { + manifold->pointCount = 1; + manifold->type = b2Manifold::e_faceA; + manifold->localNormal = normals[normalIndex]; + manifold->localPoint = 0.5f * (v1 + v2); + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; + return; + } + + // Compute barycentric coordinates + float32 u1 = b2Dot(cLocal - v1, v2 - v1); + float32 u2 = b2Dot(cLocal - v2, v1 - v2); + if (u1 <= 0.0f) + { + if (b2DistanceSquared(cLocal, v1) > radius * radius) + { + return; + } + + manifold->pointCount = 1; + manifold->type = b2Manifold::e_faceA; + manifold->localNormal = cLocal - v1; + manifold->localNormal.Normalize(); + manifold->localPoint = v1; + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; + } + else if (u2 <= 0.0f) + { + if (b2DistanceSquared(cLocal, v2) > radius * radius) + { + return; + } + + manifold->pointCount = 1; + manifold->type = b2Manifold::e_faceA; + manifold->localNormal = cLocal - v2; + manifold->localNormal.Normalize(); + manifold->localPoint = v2; + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; + } + else + { + b2Vec2 faceCenter = 0.5f * (v1 + v2); + float32 separation = b2Dot(cLocal - faceCenter, normals[vertIndex1]); + if (separation > radius) + { + return; + } + + manifold->pointCount = 1; + manifold->type = b2Manifold::e_faceA; + manifold->localNormal = normals[vertIndex1]; + manifold->localPoint = faceCenter; + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; + } +} diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2CollideEdge.cpp b/tests/Box2D_v2.2.1/Box2D/Collision/b2CollideEdge.cpp new file mode 100755 index 0000000000000..281967183dccd --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/b2CollideEdge.cpp @@ -0,0 +1,698 @@ +/* + * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org + * + * 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. + */ + +#include +#include +#include +#include + + +// Compute contact points for edge versus circle. +// This accounts for edge connectivity. +void b2CollideEdgeAndCircle(b2Manifold* manifold, + const b2EdgeShape* edgeA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB) +{ + manifold->pointCount = 0; + + // Compute circle in frame of edge + b2Vec2 Q = b2MulT(xfA, b2Mul(xfB, circleB->m_p)); + + b2Vec2 A = edgeA->m_vertex1, B = edgeA->m_vertex2; + b2Vec2 e = B - A; + + // Barycentric coordinates + float32 u = b2Dot(e, B - Q); + float32 v = b2Dot(e, Q - A); + + float32 radius = edgeA->m_radius + circleB->m_radius; + + b2ContactFeature cf; + cf.indexB = 0; + cf.typeB = b2ContactFeature::e_vertex; + + // Region A + if (v <= 0.0f) + { + b2Vec2 P = A; + b2Vec2 d = Q - P; + float32 dd = b2Dot(d, d); + if (dd > radius * radius) + { + return; + } + + // Is there an edge connected to A? + if (edgeA->m_hasVertex0) + { + b2Vec2 A1 = edgeA->m_vertex0; + b2Vec2 B1 = A; + b2Vec2 e1 = B1 - A1; + float32 u1 = b2Dot(e1, B1 - Q); + + // Is the circle in Region AB of the previous edge? + if (u1 > 0.0f) + { + return; + } + } + + cf.indexA = 0; + cf.typeA = b2ContactFeature::e_vertex; + manifold->pointCount = 1; + manifold->type = b2Manifold::e_circles; + manifold->localNormal.SetZero(); + manifold->localPoint = P; + manifold->points[0].id.key = 0; + manifold->points[0].id.cf = cf; + manifold->points[0].localPoint = circleB->m_p; + return; + } + + // Region B + if (u <= 0.0f) + { + b2Vec2 P = B; + b2Vec2 d = Q - P; + float32 dd = b2Dot(d, d); + if (dd > radius * radius) + { + return; + } + + // Is there an edge connected to B? + if (edgeA->m_hasVertex3) + { + b2Vec2 B2 = edgeA->m_vertex3; + b2Vec2 A2 = B; + b2Vec2 e2 = B2 - A2; + float32 v2 = b2Dot(e2, Q - A2); + + // Is the circle in Region AB of the next edge? + if (v2 > 0.0f) + { + return; + } + } + + cf.indexA = 1; + cf.typeA = b2ContactFeature::e_vertex; + manifold->pointCount = 1; + manifold->type = b2Manifold::e_circles; + manifold->localNormal.SetZero(); + manifold->localPoint = P; + manifold->points[0].id.key = 0; + manifold->points[0].id.cf = cf; + manifold->points[0].localPoint = circleB->m_p; + return; + } + + // Region AB + float32 den = b2Dot(e, e); + b2Assert(den > 0.0f); + b2Vec2 P = (1.0f / den) * (u * A + v * B); + b2Vec2 d = Q - P; + float32 dd = b2Dot(d, d); + if (dd > radius * radius) + { + return; + } + + b2Vec2 n(-e.y, e.x); + if (b2Dot(n, Q - A) < 0.0f) + { + n.Set(-n.x, -n.y); + } + n.Normalize(); + + cf.indexA = 0; + cf.typeA = b2ContactFeature::e_face; + manifold->pointCount = 1; + manifold->type = b2Manifold::e_faceA; + manifold->localNormal = n; + manifold->localPoint = A; + manifold->points[0].id.key = 0; + manifold->points[0].id.cf = cf; + manifold->points[0].localPoint = circleB->m_p; +} + +// This structure is used to keep track of the best separating axis. +struct b2EPAxis +{ + enum Type + { + e_unknown, + e_edgeA, + e_edgeB + }; + + Type type; + int32 index; + float32 separation; +}; + +// This holds polygon B expressed in frame A. +struct b2TempPolygon +{ + b2Vec2 vertices[b2_maxPolygonVertices]; + b2Vec2 normals[b2_maxPolygonVertices]; + int32 count; +}; + +// Reference face used for clipping +struct b2ReferenceFace +{ + int32 i1, i2; + + b2Vec2 v1, v2; + + b2Vec2 normal; + + b2Vec2 sideNormal1; + float32 sideOffset1; + + b2Vec2 sideNormal2; + float32 sideOffset2; +}; + +// This class collides and edge and a polygon, taking into account edge adjacency. +struct b2EPCollider +{ + void Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA, + const b2PolygonShape* polygonB, const b2Transform& xfB); + b2EPAxis ComputeEdgeSeparation(); + b2EPAxis ComputePolygonSeparation(); + + enum VertexType + { + e_isolated, + e_concave, + e_convex + }; + + b2TempPolygon m_polygonB; + + b2Transform m_xf; + b2Vec2 m_centroidB; + b2Vec2 m_v0, m_v1, m_v2, m_v3; + b2Vec2 m_normal0, m_normal1, m_normal2; + b2Vec2 m_normal; + VertexType m_type1, m_type2; + b2Vec2 m_lowerLimit, m_upperLimit; + float32 m_radius; + bool m_front; +}; + +// Algorithm: +// 1. Classify v1 and v2 +// 2. Classify polygon centroid as front or back +// 3. Flip normal if necessary +// 4. Initialize normal range to [-pi, pi] about face normal +// 5. Adjust normal range according to adjacent edges +// 6. Visit each separating axes, only accept axes within the range +// 7. Return if _any_ axis indicates separation +// 8. Clip +void b2EPCollider::Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA, + const b2PolygonShape* polygonB, const b2Transform& xfB) +{ + m_xf = b2MulT(xfA, xfB); + + m_centroidB = b2Mul(m_xf, polygonB->m_centroid); + + m_v0 = edgeA->m_vertex0; + m_v1 = edgeA->m_vertex1; + m_v2 = edgeA->m_vertex2; + m_v3 = edgeA->m_vertex3; + + bool hasVertex0 = edgeA->m_hasVertex0; + bool hasVertex3 = edgeA->m_hasVertex3; + + b2Vec2 edge1 = m_v2 - m_v1; + edge1.Normalize(); + m_normal1.Set(edge1.y, -edge1.x); + float32 offset1 = b2Dot(m_normal1, m_centroidB - m_v1); + float32 offset0 = 0.0f, offset2 = 0.0f; + bool convex1 = false, convex2 = false; + + // Is there a preceding edge? + if (hasVertex0) + { + b2Vec2 edge0 = m_v1 - m_v0; + edge0.Normalize(); + m_normal0.Set(edge0.y, -edge0.x); + convex1 = b2Cross(edge0, edge1) >= 0.0f; + offset0 = b2Dot(m_normal0, m_centroidB - m_v0); + } + + // Is there a following edge? + if (hasVertex3) + { + b2Vec2 edge2 = m_v3 - m_v2; + edge2.Normalize(); + m_normal2.Set(edge2.y, -edge2.x); + convex2 = b2Cross(edge1, edge2) > 0.0f; + offset2 = b2Dot(m_normal2, m_centroidB - m_v2); + } + + // Determine front or back collision. Determine collision normal limits. + if (hasVertex0 && hasVertex3) + { + if (convex1 && convex2) + { + m_front = offset0 >= 0.0f || offset1 >= 0.0f || offset2 >= 0.0f; + if (m_front) + { + m_normal = m_normal1; + m_lowerLimit = m_normal0; + m_upperLimit = m_normal2; + } + else + { + m_normal = -m_normal1; + m_lowerLimit = -m_normal1; + m_upperLimit = -m_normal1; + } + } + else if (convex1) + { + m_front = offset0 >= 0.0f || (offset1 >= 0.0f && offset2 >= 0.0f); + if (m_front) + { + m_normal = m_normal1; + m_lowerLimit = m_normal0; + m_upperLimit = m_normal1; + } + else + { + m_normal = -m_normal1; + m_lowerLimit = -m_normal2; + m_upperLimit = -m_normal1; + } + } + else if (convex2) + { + m_front = offset2 >= 0.0f || (offset0 >= 0.0f && offset1 >= 0.0f); + if (m_front) + { + m_normal = m_normal1; + m_lowerLimit = m_normal1; + m_upperLimit = m_normal2; + } + else + { + m_normal = -m_normal1; + m_lowerLimit = -m_normal1; + m_upperLimit = -m_normal0; + } + } + else + { + m_front = offset0 >= 0.0f && offset1 >= 0.0f && offset2 >= 0.0f; + if (m_front) + { + m_normal = m_normal1; + m_lowerLimit = m_normal1; + m_upperLimit = m_normal1; + } + else + { + m_normal = -m_normal1; + m_lowerLimit = -m_normal2; + m_upperLimit = -m_normal0; + } + } + } + else if (hasVertex0) + { + if (convex1) + { + m_front = offset0 >= 0.0f || offset1 >= 0.0f; + if (m_front) + { + m_normal = m_normal1; + m_lowerLimit = m_normal0; + m_upperLimit = -m_normal1; + } + else + { + m_normal = -m_normal1; + m_lowerLimit = m_normal1; + m_upperLimit = -m_normal1; + } + } + else + { + m_front = offset0 >= 0.0f && offset1 >= 0.0f; + if (m_front) + { + m_normal = m_normal1; + m_lowerLimit = m_normal1; + m_upperLimit = -m_normal1; + } + else + { + m_normal = -m_normal1; + m_lowerLimit = m_normal1; + m_upperLimit = -m_normal0; + } + } + } + else if (hasVertex3) + { + if (convex2) + { + m_front = offset1 >= 0.0f || offset2 >= 0.0f; + if (m_front) + { + m_normal = m_normal1; + m_lowerLimit = -m_normal1; + m_upperLimit = m_normal2; + } + else + { + m_normal = -m_normal1; + m_lowerLimit = -m_normal1; + m_upperLimit = m_normal1; + } + } + else + { + m_front = offset1 >= 0.0f && offset2 >= 0.0f; + if (m_front) + { + m_normal = m_normal1; + m_lowerLimit = -m_normal1; + m_upperLimit = m_normal1; + } + else + { + m_normal = -m_normal1; + m_lowerLimit = -m_normal2; + m_upperLimit = m_normal1; + } + } + } + else + { + m_front = offset1 >= 0.0f; + if (m_front) + { + m_normal = m_normal1; + m_lowerLimit = -m_normal1; + m_upperLimit = -m_normal1; + } + else + { + m_normal = -m_normal1; + m_lowerLimit = m_normal1; + m_upperLimit = m_normal1; + } + } + + // Get polygonB in frameA + m_polygonB.count = polygonB->m_vertexCount; + for (int32 i = 0; i < polygonB->m_vertexCount; ++i) + { + m_polygonB.vertices[i] = b2Mul(m_xf, polygonB->m_vertices[i]); + m_polygonB.normals[i] = b2Mul(m_xf.q, polygonB->m_normals[i]); + } + + m_radius = 2.0f * b2_polygonRadius; + + manifold->pointCount = 0; + + b2EPAxis edgeAxis = ComputeEdgeSeparation(); + + // If no valid normal can be found than this edge should not collide. + if (edgeAxis.type == b2EPAxis::e_unknown) + { + return; + } + + if (edgeAxis.separation > m_radius) + { + return; + } + + b2EPAxis polygonAxis = ComputePolygonSeparation(); + if (polygonAxis.type != b2EPAxis::e_unknown && polygonAxis.separation > m_radius) + { + return; + } + + // Use hysteresis for jitter reduction. + const float32 k_relativeTol = 0.98f; + const float32 k_absoluteTol = 0.001f; + + b2EPAxis primaryAxis; + if (polygonAxis.type == b2EPAxis::e_unknown) + { + primaryAxis = edgeAxis; + } + else if (polygonAxis.separation > k_relativeTol * edgeAxis.separation + k_absoluteTol) + { + primaryAxis = polygonAxis; + } + else + { + primaryAxis = edgeAxis; + } + + b2ClipVertex ie[2]; + b2ReferenceFace rf; + if (primaryAxis.type == b2EPAxis::e_edgeA) + { + manifold->type = b2Manifold::e_faceA; + + // Search for the polygon normal that is most anti-parallel to the edge normal. + int32 bestIndex = 0; + float32 bestValue = b2Dot(m_normal, m_polygonB.normals[0]); + for (int32 i = 1; i < m_polygonB.count; ++i) + { + float32 value = b2Dot(m_normal, m_polygonB.normals[i]); + if (value < bestValue) + { + bestValue = value; + bestIndex = i; + } + } + + int32 i1 = bestIndex; + int32 i2 = i1 + 1 < m_polygonB.count ? i1 + 1 : 0; + + ie[0].v = m_polygonB.vertices[i1]; + ie[0].id.cf.indexA = 0; + ie[0].id.cf.indexB = i1; + ie[0].id.cf.typeA = b2ContactFeature::e_face; + ie[0].id.cf.typeB = b2ContactFeature::e_vertex; + + ie[1].v = m_polygonB.vertices[i2]; + ie[1].id.cf.indexA = 0; + ie[1].id.cf.indexB = i2; + ie[1].id.cf.typeA = b2ContactFeature::e_face; + ie[1].id.cf.typeB = b2ContactFeature::e_vertex; + + if (m_front) + { + rf.i1 = 0; + rf.i2 = 1; + rf.v1 = m_v1; + rf.v2 = m_v2; + rf.normal = m_normal1; + } + else + { + rf.i1 = 1; + rf.i2 = 0; + rf.v1 = m_v2; + rf.v2 = m_v1; + rf.normal = -m_normal1; + } + } + else + { + manifold->type = b2Manifold::e_faceB; + + ie[0].v = m_v1; + ie[0].id.cf.indexA = 0; + ie[0].id.cf.indexB = primaryAxis.index; + ie[0].id.cf.typeA = b2ContactFeature::e_vertex; + ie[0].id.cf.typeB = b2ContactFeature::e_face; + + ie[1].v = m_v2; + ie[1].id.cf.indexA = 0; + ie[1].id.cf.indexB = primaryAxis.index; + ie[1].id.cf.typeA = b2ContactFeature::e_vertex; + ie[1].id.cf.typeB = b2ContactFeature::e_face; + + rf.i1 = primaryAxis.index; + rf.i2 = rf.i1 + 1 < m_polygonB.count ? rf.i1 + 1 : 0; + rf.v1 = m_polygonB.vertices[rf.i1]; + rf.v2 = m_polygonB.vertices[rf.i2]; + rf.normal = m_polygonB.normals[rf.i1]; + } + + rf.sideNormal1.Set(rf.normal.y, -rf.normal.x); + rf.sideNormal2 = -rf.sideNormal1; + rf.sideOffset1 = b2Dot(rf.sideNormal1, rf.v1); + rf.sideOffset2 = b2Dot(rf.sideNormal2, rf.v2); + + // Clip incident edge against extruded edge1 side edges. + b2ClipVertex clipPoints1[2]; + b2ClipVertex clipPoints2[2]; + int32 np; + + // Clip to box side 1 + np = b2ClipSegmentToLine(clipPoints1, ie, rf.sideNormal1, rf.sideOffset1, rf.i1); + + if (np < b2_maxManifoldPoints) + { + return; + } + + // Clip to negative box side 1 + np = b2ClipSegmentToLine(clipPoints2, clipPoints1, rf.sideNormal2, rf.sideOffset2, rf.i2); + + if (np < b2_maxManifoldPoints) + { + return; + } + + // Now clipPoints2 contains the clipped points. + if (primaryAxis.type == b2EPAxis::e_edgeA) + { + manifold->localNormal = rf.normal; + manifold->localPoint = rf.v1; + } + else + { + manifold->localNormal = polygonB->m_normals[rf.i1]; + manifold->localPoint = polygonB->m_vertices[rf.i1]; + } + + int32 pointCount = 0; + for (int32 i = 0; i < b2_maxManifoldPoints; ++i) + { + float32 separation; + + separation = b2Dot(rf.normal, clipPoints2[i].v - rf.v1); + + if (separation <= m_radius) + { + b2ManifoldPoint* cp = manifold->points + pointCount; + + if (primaryAxis.type == b2EPAxis::e_edgeA) + { + cp->localPoint = b2MulT(m_xf, clipPoints2[i].v); + cp->id = clipPoints2[i].id; + } + else + { + cp->localPoint = clipPoints2[i].v; + cp->id.cf.typeA = clipPoints2[i].id.cf.typeB; + cp->id.cf.typeB = clipPoints2[i].id.cf.typeA; + cp->id.cf.indexA = clipPoints2[i].id.cf.indexB; + cp->id.cf.indexB = clipPoints2[i].id.cf.indexA; + } + + ++pointCount; + } + } + + manifold->pointCount = pointCount; +} + +b2EPAxis b2EPCollider::ComputeEdgeSeparation() +{ + b2EPAxis axis; + axis.type = b2EPAxis::e_edgeA; + axis.index = m_front ? 0 : 1; + axis.separation = FLT_MAX; + + for (int32 i = 0; i < m_polygonB.count; ++i) + { + float32 s = b2Dot(m_normal, m_polygonB.vertices[i] - m_v1); + if (s < axis.separation) + { + axis.separation = s; + } + } + + return axis; +} + +b2EPAxis b2EPCollider::ComputePolygonSeparation() +{ + b2EPAxis axis; + axis.type = b2EPAxis::e_unknown; + axis.index = -1; + axis.separation = -FLT_MAX; + + b2Vec2 perp(-m_normal.y, m_normal.x); + + for (int32 i = 0; i < m_polygonB.count; ++i) + { + b2Vec2 n = -m_polygonB.normals[i]; + + float32 s1 = b2Dot(n, m_polygonB.vertices[i] - m_v1); + float32 s2 = b2Dot(n, m_polygonB.vertices[i] - m_v2); + float32 s = b2Min(s1, s2); + + if (s > m_radius) + { + // No collision + axis.type = b2EPAxis::e_edgeB; + axis.index = i; + axis.separation = s; + return axis; + } + + // Adjacency + if (b2Dot(n, perp) >= 0.0f) + { + if (b2Dot(n - m_upperLimit, m_normal) < -b2_angularSlop) + { + continue; + } + } + else + { + if (b2Dot(n - m_lowerLimit, m_normal) < -b2_angularSlop) + { + continue; + } + } + + if (s > axis.separation) + { + axis.type = b2EPAxis::e_edgeB; + axis.index = i; + axis.separation = s; + } + } + + return axis; +} + +void b2CollideEdgeAndPolygon( b2Manifold* manifold, + const b2EdgeShape* edgeA, const b2Transform& xfA, + const b2PolygonShape* polygonB, const b2Transform& xfB) +{ + b2EPCollider collider; + collider.Collide(manifold, edgeA, xfA, polygonB, xfB); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2CollidePolygon.cpp b/tests/Box2D_v2.2.1/Box2D/Collision/b2CollidePolygon.cpp new file mode 100755 index 0000000000000..2f0946b9235a9 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/b2CollidePolygon.cpp @@ -0,0 +1,317 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include + +// Find the separation between poly1 and poly2 for a give edge normal on poly1. +static float32 b2EdgeSeparation(const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1, + const b2PolygonShape* poly2, const b2Transform& xf2) +{ + const b2Vec2* vertices1 = poly1->m_vertices; + const b2Vec2* normals1 = poly1->m_normals; + + int32 count2 = poly2->m_vertexCount; + const b2Vec2* vertices2 = poly2->m_vertices; + + b2Assert(0 <= edge1 && edge1 < poly1->m_vertexCount); + + // Convert normal from poly1's frame into poly2's frame. + b2Vec2 normal1World = b2Mul(xf1.q, normals1[edge1]); + b2Vec2 normal1 = b2MulT(xf2.q, normal1World); + + // Find support vertex on poly2 for -normal. + int32 index = 0; + float32 minDot = b2_maxFloat; + + for (int32 i = 0; i < count2; ++i) + { + float32 dot = b2Dot(vertices2[i], normal1); + if (dot < minDot) + { + minDot = dot; + index = i; + } + } + + b2Vec2 v1 = b2Mul(xf1, vertices1[edge1]); + b2Vec2 v2 = b2Mul(xf2, vertices2[index]); + float32 separation = b2Dot(v2 - v1, normal1World); + return separation; +} + +// Find the max separation between poly1 and poly2 using edge normals from poly1. +static float32 b2FindMaxSeparation(int32* edgeIndex, + const b2PolygonShape* poly1, const b2Transform& xf1, + const b2PolygonShape* poly2, const b2Transform& xf2) +{ + int32 count1 = poly1->m_vertexCount; + const b2Vec2* normals1 = poly1->m_normals; + + // Vector pointing from the centroid of poly1 to the centroid of poly2. + b2Vec2 d = b2Mul(xf2, poly2->m_centroid) - b2Mul(xf1, poly1->m_centroid); + b2Vec2 dLocal1 = b2MulT(xf1.q, d); + + // Find edge normal on poly1 that has the largest projection onto d. + int32 edge = 0; + float32 maxDot = -b2_maxFloat; + for (int32 i = 0; i < count1; ++i) + { + float32 dot = b2Dot(normals1[i], dLocal1); + if (dot > maxDot) + { + maxDot = dot; + edge = i; + } + } + + // Get the separation for the edge normal. + float32 s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2); + + // Check the separation for the previous edge normal. + int32 prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1; + float32 sPrev = b2EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); + + // Check the separation for the next edge normal. + int32 nextEdge = edge + 1 < count1 ? edge + 1 : 0; + float32 sNext = b2EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); + + // Find the best edge and the search direction. + int32 bestEdge; + float32 bestSeparation; + int32 increment; + if (sPrev > s && sPrev > sNext) + { + increment = -1; + bestEdge = prevEdge; + bestSeparation = sPrev; + } + else if (sNext > s) + { + increment = 1; + bestEdge = nextEdge; + bestSeparation = sNext; + } + else + { + *edgeIndex = edge; + return s; + } + + // Perform a local search for the best edge normal. + for ( ; ; ) + { + if (increment == -1) + edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1; + else + edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0; + + s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2); + + if (s > bestSeparation) + { + bestEdge = edge; + bestSeparation = s; + } + else + { + break; + } + } + + *edgeIndex = bestEdge; + return bestSeparation; +} + +static void b2FindIncidentEdge(b2ClipVertex c[2], + const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1, + const b2PolygonShape* poly2, const b2Transform& xf2) +{ + const b2Vec2* normals1 = poly1->m_normals; + + int32 count2 = poly2->m_vertexCount; + const b2Vec2* vertices2 = poly2->m_vertices; + const b2Vec2* normals2 = poly2->m_normals; + + b2Assert(0 <= edge1 && edge1 < poly1->m_vertexCount); + + // Get the normal of the reference edge in poly2's frame. + b2Vec2 normal1 = b2MulT(xf2.q, b2Mul(xf1.q, normals1[edge1])); + + // Find the incident edge on poly2. + int32 index = 0; + float32 minDot = b2_maxFloat; + for (int32 i = 0; i < count2; ++i) + { + float32 dot = b2Dot(normal1, normals2[i]); + if (dot < minDot) + { + minDot = dot; + index = i; + } + } + + // Build the clip vertices for the incident edge. + int32 i1 = index; + int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0; + + c[0].v = b2Mul(xf2, vertices2[i1]); + c[0].id.cf.indexA = (uint8)edge1; + c[0].id.cf.indexB = (uint8)i1; + c[0].id.cf.typeA = b2ContactFeature::e_face; + c[0].id.cf.typeB = b2ContactFeature::e_vertex; + + c[1].v = b2Mul(xf2, vertices2[i2]); + c[1].id.cf.indexA = (uint8)edge1; + c[1].id.cf.indexB = (uint8)i2; + c[1].id.cf.typeA = b2ContactFeature::e_face; + c[1].id.cf.typeB = b2ContactFeature::e_vertex; +} + +// Find edge normal of max separation on A - return if separating axis is found +// Find edge normal of max separation on B - return if separation axis is found +// Choose reference edge as min(minA, minB) +// Find incident edge +// Clip + +// The normal points from 1 to 2 +void b2CollidePolygons(b2Manifold* manifold, + const b2PolygonShape* polyA, const b2Transform& xfA, + const b2PolygonShape* polyB, const b2Transform& xfB) +{ + manifold->pointCount = 0; + float32 totalRadius = polyA->m_radius + polyB->m_radius; + + int32 edgeA = 0; + float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB); + if (separationA > totalRadius) + return; + + int32 edgeB = 0; + float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA); + if (separationB > totalRadius) + return; + + const b2PolygonShape* poly1; // reference polygon + const b2PolygonShape* poly2; // incident polygon + b2Transform xf1, xf2; + int32 edge1; // reference edge + uint8 flip; + const float32 k_relativeTol = 0.98f; + const float32 k_absoluteTol = 0.001f; + + if (separationB > k_relativeTol * separationA + k_absoluteTol) + { + poly1 = polyB; + poly2 = polyA; + xf1 = xfB; + xf2 = xfA; + edge1 = edgeB; + manifold->type = b2Manifold::e_faceB; + flip = 1; + } + else + { + poly1 = polyA; + poly2 = polyB; + xf1 = xfA; + xf2 = xfB; + edge1 = edgeA; + manifold->type = b2Manifold::e_faceA; + flip = 0; + } + + b2ClipVertex incidentEdge[2]; + b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); + + int32 count1 = poly1->m_vertexCount; + const b2Vec2* vertices1 = poly1->m_vertices; + + int32 iv1 = edge1; + int32 iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0; + + b2Vec2 v11 = vertices1[iv1]; + b2Vec2 v12 = vertices1[iv2]; + + b2Vec2 localTangent = v12 - v11; + localTangent.Normalize(); + + b2Vec2 localNormal = b2Cross(localTangent, 1.0f); + b2Vec2 planePoint = 0.5f * (v11 + v12); + + b2Vec2 tangent = b2Mul(xf1.q, localTangent); + b2Vec2 normal = b2Cross(tangent, 1.0f); + + v11 = b2Mul(xf1, v11); + v12 = b2Mul(xf1, v12); + + // Face offset. + float32 frontOffset = b2Dot(normal, v11); + + // Side offsets, extended by polytope skin thickness. + float32 sideOffset1 = -b2Dot(tangent, v11) + totalRadius; + float32 sideOffset2 = b2Dot(tangent, v12) + totalRadius; + + // Clip incident edge against extruded edge1 side edges. + b2ClipVertex clipPoints1[2]; + b2ClipVertex clipPoints2[2]; + int np; + + // Clip to box side 1 + np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1, iv1); + + if (np < 2) + return; + + // Clip to negative box side 1 + np = b2ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2, iv2); + + if (np < 2) + { + return; + } + + // Now clipPoints2 contains the clipped points. + manifold->localNormal = localNormal; + manifold->localPoint = planePoint; + + int32 pointCount = 0; + for (int32 i = 0; i < b2_maxManifoldPoints; ++i) + { + float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset; + + if (separation <= totalRadius) + { + b2ManifoldPoint* cp = manifold->points + pointCount; + cp->localPoint = b2MulT(xf2, clipPoints2[i].v); + cp->id = clipPoints2[i].id; + if (flip) + { + // Swap features + b2ContactFeature cf = cp->id.cf; + cp->id.cf.indexA = cf.indexB; + cp->id.cf.indexB = cf.indexA; + cp->id.cf.typeA = cf.typeB; + cp->id.cf.typeB = cf.typeA; + } + ++pointCount; + } + } + + manifold->pointCount = pointCount; +} diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2Collision.cpp b/tests/Box2D_v2.2.1/Box2D/Collision/b2Collision.cpp new file mode 100755 index 0000000000000..4b092f0cbe9e3 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/b2Collision.cpp @@ -0,0 +1,249 @@ +/* +* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include + +void b2WorldManifold::Initialize(const b2Manifold* manifold, + const b2Transform& xfA, float32 radiusA, + const b2Transform& xfB, float32 radiusB) +{ + if (manifold->pointCount == 0) + { + return; + } + + switch (manifold->type) + { + case b2Manifold::e_circles: + { + normal.Set(1.0f, 0.0f); + b2Vec2 pointA = b2Mul(xfA, manifold->localPoint); + b2Vec2 pointB = b2Mul(xfB, manifold->points[0].localPoint); + if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon) + { + normal = pointB - pointA; + normal.Normalize(); + } + + b2Vec2 cA = pointA + radiusA * normal; + b2Vec2 cB = pointB - radiusB * normal; + points[0] = 0.5f * (cA + cB); + } + break; + + case b2Manifold::e_faceA: + { + normal = b2Mul(xfA.q, manifold->localNormal); + b2Vec2 planePoint = b2Mul(xfA, manifold->localPoint); + + for (int32 i = 0; i < manifold->pointCount; ++i) + { + b2Vec2 clipPoint = b2Mul(xfB, manifold->points[i].localPoint); + b2Vec2 cA = clipPoint + (radiusA - b2Dot(clipPoint - planePoint, normal)) * normal; + b2Vec2 cB = clipPoint - radiusB * normal; + points[i] = 0.5f * (cA + cB); + } + } + break; + + case b2Manifold::e_faceB: + { + normal = b2Mul(xfB.q, manifold->localNormal); + b2Vec2 planePoint = b2Mul(xfB, manifold->localPoint); + + for (int32 i = 0; i < manifold->pointCount; ++i) + { + b2Vec2 clipPoint = b2Mul(xfA, manifold->points[i].localPoint); + b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal; + b2Vec2 cA = clipPoint - radiusA * normal; + points[i] = 0.5f * (cA + cB); + } + + // Ensure normal points from A to B. + normal = -normal; + } + break; + } +} + +void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints], + const b2Manifold* manifold1, const b2Manifold* manifold2) +{ + for (int32 i = 0; i < b2_maxManifoldPoints; ++i) + { + state1[i] = b2_nullState; + state2[i] = b2_nullState; + } + + // Detect persists and removes. + for (int32 i = 0; i < manifold1->pointCount; ++i) + { + b2ContactID id = manifold1->points[i].id; + + state1[i] = b2_removeState; + + for (int32 j = 0; j < manifold2->pointCount; ++j) + { + if (manifold2->points[j].id.key == id.key) + { + state1[i] = b2_persistState; + break; + } + } + } + + // Detect persists and adds. + for (int32 i = 0; i < manifold2->pointCount; ++i) + { + b2ContactID id = manifold2->points[i].id; + + state2[i] = b2_addState; + + for (int32 j = 0; j < manifold1->pointCount; ++j) + { + if (manifold1->points[j].id.key == id.key) + { + state2[i] = b2_persistState; + break; + } + } + } +} + +// From Real-time Collision Detection, p179. +bool b2AABB::RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const +{ + float32 tmin = -b2_maxFloat; + float32 tmax = b2_maxFloat; + + b2Vec2 p = input.p1; + b2Vec2 d = input.p2 - input.p1; + b2Vec2 absD = b2Abs(d); + + b2Vec2 normal; + + for (int32 i = 0; i < 2; ++i) + { + if (absD(i) < b2_epsilon) + { + // Parallel. + if (p(i) < lowerBound(i) || upperBound(i) < p(i)) + { + return false; + } + } + else + { + float32 inv_d = 1.0f / d(i); + float32 t1 = (lowerBound(i) - p(i)) * inv_d; + float32 t2 = (upperBound(i) - p(i)) * inv_d; + + // Sign of the normal vector. + float32 s = -1.0f; + + if (t1 > t2) + { + b2Swap(t1, t2); + s = 1.0f; + } + + // Push the min up + if (t1 > tmin) + { + normal.SetZero(); + normal(i) = s; + tmin = t1; + } + + // Pull the max down + tmax = b2Min(tmax, t2); + + if (tmin > tmax) + { + return false; + } + } + } + + // Does the ray start inside the box? + // Does the ray intersect beyond the max fraction? + if (tmin < 0.0f || input.maxFraction < tmin) + { + return false; + } + + // Intersection. + output->fraction = tmin; + output->normal = normal; + return true; +} + +// Sutherland-Hodgman clipping. +int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2], + const b2Vec2& normal, float32 offset, int32 vertexIndexA) +{ + // Start with no output points + int32 numOut = 0; + + // Calculate the distance of end points to the line + float32 distance0 = b2Dot(normal, vIn[0].v) - offset; + float32 distance1 = b2Dot(normal, vIn[1].v) - offset; + + // If the points are behind the plane + if (distance0 <= 0.0f) vOut[numOut++] = vIn[0]; + if (distance1 <= 0.0f) vOut[numOut++] = vIn[1]; + + // If the points are on different sides of the plane + if (distance0 * distance1 < 0.0f) + { + // Find intersection point of edge and plane + float32 interp = distance0 / (distance0 - distance1); + vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v); + + // VertexA is hitting edgeB. + vOut[numOut].id.cf.indexA = vertexIndexA; + vOut[numOut].id.cf.indexB = vIn[0].id.cf.indexB; + vOut[numOut].id.cf.typeA = b2ContactFeature::e_vertex; + vOut[numOut].id.cf.typeB = b2ContactFeature::e_face; + ++numOut; + } + + return numOut; +} + +bool b2TestOverlap( const b2Shape* shapeA, int32 indexA, + const b2Shape* shapeB, int32 indexB, + const b2Transform& xfA, const b2Transform& xfB) +{ + b2DistanceInput input; + input.proxyA.Set(shapeA, indexA); + input.proxyB.Set(shapeB, indexB); + input.transformA = xfA; + input.transformB = xfB; + input.useRadii = true; + + b2SimplexCache cache; + cache.count = 0; + + b2DistanceOutput output; + + b2Distance(&output, &cache, &input); + + return output.distance < 10.0f * b2_epsilon; +} diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2Collision.h b/tests/Box2D_v2.2.1/Box2D/Collision/b2Collision.h new file mode 100755 index 0000000000000..71bf15b6de4b9 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/b2Collision.h @@ -0,0 +1,281 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_COLLISION_H +#define B2_COLLISION_H + +#include +#ifndef EM_NO_LIBCPP +#include +#endif + +/// @file +/// Structures and functions used for computing contact points, distance +/// queries, and TOI queries. + +class b2Shape; +class b2CircleShape; +class b2EdgeShape; +class b2PolygonShape; + +const uint8 b2_nullFeature = UCHAR_MAX; + +/// The features that intersect to form the contact point +/// This must be 4 bytes or less. +struct b2ContactFeature +{ + enum Type + { + e_vertex = 0, + e_face = 1 + }; + + uint8 indexA; ///< Feature index on shapeA + uint8 indexB; ///< Feature index on shapeB + uint8 typeA; ///< The feature type on shapeA + uint8 typeB; ///< The feature type on shapeB +}; + +/// Contact ids to facilitate warm starting. +union b2ContactID +{ + b2ContactFeature cf; + uint32 key; ///< Used to quickly compare contact ids. +}; + +/// A manifold point is a contact point belonging to a contact +/// manifold. It holds details related to the geometry and dynamics +/// of the contact points. +/// The local point usage depends on the manifold type: +/// -e_circles: the local center of circleB +/// -e_faceA: the local center of cirlceB or the clip point of polygonB +/// -e_faceB: the clip point of polygonA +/// This structure is stored across time steps, so we keep it small. +/// Note: the impulses are used for internal caching and may not +/// provide reliable contact forces, especially for high speed collisions. +struct b2ManifoldPoint +{ + b2Vec2 localPoint; ///< usage depends on manifold type + float32 normalImpulse; ///< the non-penetration impulse + float32 tangentImpulse; ///< the friction impulse + b2ContactID id; ///< uniquely identifies a contact point between two shapes +}; + +/// A manifold for two touching convex shapes. +/// Box2D supports multiple types of contact: +/// - clip point versus plane with radius +/// - point versus point with radius (circles) +/// The local point usage depends on the manifold type: +/// -e_circles: the local center of circleA +/// -e_faceA: the center of faceA +/// -e_faceB: the center of faceB +/// Similarly the local normal usage: +/// -e_circles: not used +/// -e_faceA: the normal on polygonA +/// -e_faceB: the normal on polygonB +/// We store contacts in this way so that position correction can +/// account for movement, which is critical for continuous physics. +/// All contact scenarios must be expressed in one of these types. +/// This structure is stored across time steps, so we keep it small. +struct b2Manifold +{ + enum Type + { + e_circles, + e_faceA, + e_faceB + }; + + b2ManifoldPoint points[b2_maxManifoldPoints]; ///< the points of contact + b2Vec2 localNormal; ///< not use for Type::e_points + b2Vec2 localPoint; ///< usage depends on manifold type + Type type; + int32 pointCount; ///< the number of manifold points +}; + +/// This is used to compute the current state of a contact manifold. +struct b2WorldManifold +{ + /// Evaluate the manifold with supplied transforms. This assumes + /// modest motion from the original state. This does not change the + /// point count, impulses, etc. The radii must come from the shapes + /// that generated the manifold. + void Initialize(const b2Manifold* manifold, + const b2Transform& xfA, float32 radiusA, + const b2Transform& xfB, float32 radiusB); + + b2Vec2 normal; ///< world vector pointing from A to B + b2Vec2 points[b2_maxManifoldPoints]; ///< world contact point (point of intersection) +}; + +/// This is used for determining the state of contact points. +enum b2PointState +{ + b2_nullState, ///< point does not exist + b2_addState, ///< point was added in the update + b2_persistState, ///< point persisted across the update + b2_removeState ///< point was removed in the update +}; + +/// Compute the point states given two manifolds. The states pertain to the transition from manifold1 +/// to manifold2. So state1 is either persist or remove while state2 is either add or persist. +void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints], + const b2Manifold* manifold1, const b2Manifold* manifold2); + +/// Used for computing contact manifolds. +struct b2ClipVertex +{ + b2Vec2 v; + b2ContactID id; +}; + +/// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). +struct b2RayCastInput +{ + b2Vec2 p1, p2; + float32 maxFraction; +}; + +/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2 +/// come from b2RayCastInput. +struct b2RayCastOutput +{ + b2Vec2 normal; + float32 fraction; +}; + +/// An axis aligned bounding box. +// emscripten - b2AABB: add constructor +struct b2AABB +{ + b2AABB() {} + + /// Verify that the bounds are sorted. + bool IsValid() const; + + /// Get the center of the AABB. + b2Vec2 GetCenter() const + { + return 0.5f * (lowerBound + upperBound); + } + + /// Get the extents of the AABB (half-widths). + b2Vec2 GetExtents() const + { + return 0.5f * (upperBound - lowerBound); + } + + /// Get the perimeter length + float32 GetPerimeter() const + { + float32 wx = upperBound.x - lowerBound.x; + float32 wy = upperBound.y - lowerBound.y; + return 2.0f * (wx + wy); + } + + /// Combine an AABB into this one. + void Combine(const b2AABB& aabb) + { + lowerBound = b2Min(lowerBound, aabb.lowerBound); + upperBound = b2Max(upperBound, aabb.upperBound); + } + + /// Combine two AABBs into this one. + void Combine(const b2AABB& aabb1, const b2AABB& aabb2) + { + lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound); + upperBound = b2Max(aabb1.upperBound, aabb2.upperBound); + } + + /// Does this aabb contain the provided AABB. + bool Contains(const b2AABB& aabb) const + { + bool result = true; + result = result && lowerBound.x <= aabb.lowerBound.x; + result = result && lowerBound.y <= aabb.lowerBound.y; + result = result && aabb.upperBound.x <= upperBound.x; + result = result && aabb.upperBound.y <= upperBound.y; + return result; + } + + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const; + + b2Vec2 lowerBound; ///< the lower vertex + b2Vec2 upperBound; ///< the upper vertex +}; + +/// Compute the collision manifold between two circles. +void b2CollideCircles(b2Manifold* manifold, + const b2CircleShape* circleA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB); + +/// Compute the collision manifold between a polygon and a circle. +void b2CollidePolygonAndCircle(b2Manifold* manifold, + const b2PolygonShape* polygonA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB); + +/// Compute the collision manifold between two polygons. +void b2CollidePolygons(b2Manifold* manifold, + const b2PolygonShape* polygonA, const b2Transform& xfA, + const b2PolygonShape* polygonB, const b2Transform& xfB); + +/// Compute the collision manifold between an edge and a circle. +void b2CollideEdgeAndCircle(b2Manifold* manifold, + const b2EdgeShape* polygonA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB); + +/// Compute the collision manifold between an edge and a circle. +void b2CollideEdgeAndPolygon(b2Manifold* manifold, + const b2EdgeShape* edgeA, const b2Transform& xfA, + const b2PolygonShape* circleB, const b2Transform& xfB); + +/// Clipping for contact manifolds. +int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2], + const b2Vec2& normal, float32 offset, int32 vertexIndexA); + +/// Determine if two generic shapes overlap. +bool b2TestOverlap( const b2Shape* shapeA, int32 indexA, + const b2Shape* shapeB, int32 indexB, + const b2Transform& xfA, const b2Transform& xfB); + +// ---------------- Inline Functions ------------------------------------------ + +inline bool b2AABB::IsValid() const +{ + b2Vec2 d = upperBound - lowerBound; + bool valid = d.x >= 0.0f && d.y >= 0.0f; + valid = valid && lowerBound.IsValid() && upperBound.IsValid(); + return valid; +} + +inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b) +{ + b2Vec2 d1, d2; + d1 = b.lowerBound - a.upperBound; + d2 = a.lowerBound - b.upperBound; + + if (d1.x > 0.0f || d1.y > 0.0f) + return false; + + if (d2.x > 0.0f || d2.y > 0.0f) + return false; + + return true; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2Distance.cpp b/tests/Box2D_v2.2.1/Box2D/Collision/b2Distance.cpp new file mode 100755 index 0000000000000..1010c8c0e8e9b --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/b2Distance.cpp @@ -0,0 +1,603 @@ +/* +* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include + +// GJK using Voronoi regions (Christer Ericson) and Barycentric coordinates. +int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters; + +void b2DistanceProxy::Set(const b2Shape* shape, int32 index) +{ + switch (shape->GetType()) + { + case b2Shape::e_circle: + { + const b2CircleShape* circle = (b2CircleShape*)shape; + m_vertices = &circle->m_p; + m_count = 1; + m_radius = circle->m_radius; + } + break; + + case b2Shape::e_polygon: + { + const b2PolygonShape* polygon = (b2PolygonShape*)shape; + m_vertices = polygon->m_vertices; + m_count = polygon->m_vertexCount; + m_radius = polygon->m_radius; + } + break; + + case b2Shape::e_chain: + { + const b2ChainShape* chain = (b2ChainShape*)shape; + b2Assert(0 <= index && index < chain->m_count); + + m_buffer[0] = chain->m_vertices[index]; + if (index + 1 < chain->m_count) + { + m_buffer[1] = chain->m_vertices[index + 1]; + } + else + { + m_buffer[1] = chain->m_vertices[0]; + } + + m_vertices = m_buffer; + m_count = 2; + m_radius = chain->m_radius; + } + break; + + case b2Shape::e_edge: + { + const b2EdgeShape* edge = (b2EdgeShape*)shape; + m_vertices = &edge->m_vertex1; + m_count = 2; + m_radius = edge->m_radius; + } + break; + + default: + b2Assert(false); + } +} + + +struct b2SimplexVertex +{ + b2Vec2 wA; // support point in proxyA + b2Vec2 wB; // support point in proxyB + b2Vec2 w; // wB - wA + float32 a; // barycentric coordinate for closest point + int32 indexA; // wA index + int32 indexB; // wB index +}; + +struct b2Simplex +{ + void ReadCache( const b2SimplexCache* cache, + const b2DistanceProxy* proxyA, const b2Transform& transformA, + const b2DistanceProxy* proxyB, const b2Transform& transformB) + { + b2Assert(cache->count <= 3); + + // Copy data from cache. + m_count = cache->count; + b2SimplexVertex* vertices = &m_v1; + for (int32 i = 0; i < m_count; ++i) + { + b2SimplexVertex* v = vertices + i; + v->indexA = cache->indexA[i]; + v->indexB = cache->indexB[i]; + b2Vec2 wALocal = proxyA->GetVertex(v->indexA); + b2Vec2 wBLocal = proxyB->GetVertex(v->indexB); + v->wA = b2Mul(transformA, wALocal); + v->wB = b2Mul(transformB, wBLocal); + v->w = v->wB - v->wA; + v->a = 0.0f; + } + + // Compute the new simplex metric, if it is substantially different than + // old metric then flush the simplex. + if (m_count > 1) + { + float32 metric1 = cache->metric; + float32 metric2 = GetMetric(); + if (metric2 < 0.5f * metric1 || 2.0f * metric1 < metric2 || metric2 < b2_epsilon) + { + // Reset the simplex. + m_count = 0; + } + } + + // If the cache is empty or invalid ... + if (m_count == 0) + { + b2SimplexVertex* v = vertices + 0; + v->indexA = 0; + v->indexB = 0; + b2Vec2 wALocal = proxyA->GetVertex(0); + b2Vec2 wBLocal = proxyB->GetVertex(0); + v->wA = b2Mul(transformA, wALocal); + v->wB = b2Mul(transformB, wBLocal); + v->w = v->wB - v->wA; + m_count = 1; + } + } + + void WriteCache(b2SimplexCache* cache) const + { + cache->metric = GetMetric(); + cache->count = uint16(m_count); + const b2SimplexVertex* vertices = &m_v1; + for (int32 i = 0; i < m_count; ++i) + { + cache->indexA[i] = uint8(vertices[i].indexA); + cache->indexB[i] = uint8(vertices[i].indexB); + } + } + + b2Vec2 GetSearchDirection() const + { + switch (m_count) + { + case 1: + return -m_v1.w; + + case 2: + { + b2Vec2 e12 = m_v2.w - m_v1.w; + float32 sgn = b2Cross(e12, -m_v1.w); + if (sgn > 0.0f) + { + // Origin is left of e12. + return b2Cross(1.0f, e12); + } + else + { + // Origin is right of e12. + return b2Cross(e12, 1.0f); + } + } + + default: + b2Assert(false); + return b2Vec2_zero; + } + } + + b2Vec2 GetClosestPoint() const + { + switch (m_count) + { + case 0: + b2Assert(false); + return b2Vec2_zero; + + case 1: + return m_v1.w; + + case 2: + return m_v1.a * m_v1.w + m_v2.a * m_v2.w; + + case 3: + return b2Vec2_zero; + + default: + b2Assert(false); + return b2Vec2_zero; + } + } + + void GetWitnessPoints(b2Vec2* pA, b2Vec2* pB) const + { + switch (m_count) + { + case 0: + b2Assert(false); + break; + + case 1: + *pA = m_v1.wA; + *pB = m_v1.wB; + break; + + case 2: + *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA; + *pB = m_v1.a * m_v1.wB + m_v2.a * m_v2.wB; + break; + + case 3: + *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA + m_v3.a * m_v3.wA; + *pB = *pA; + break; + + default: + b2Assert(false); + break; + } + } + + float32 GetMetric() const + { + switch (m_count) + { + case 0: + b2Assert(false); + return 0.0; + + case 1: + return 0.0f; + + case 2: + return b2Distance(m_v1.w, m_v2.w); + + case 3: + return b2Cross(m_v2.w - m_v1.w, m_v3.w - m_v1.w); + + default: + b2Assert(false); + return 0.0f; + } + } + + void Solve2(); + void Solve3(); + + b2SimplexVertex m_v1, m_v2, m_v3; + int32 m_count; +}; + + +// Solve a line segment using barycentric coordinates. +// +// p = a1 * w1 + a2 * w2 +// a1 + a2 = 1 +// +// The vector from the origin to the closest point on the line is +// perpendicular to the line. +// e12 = w2 - w1 +// dot(p, e) = 0 +// a1 * dot(w1, e) + a2 * dot(w2, e) = 0 +// +// 2-by-2 linear system +// [1 1 ][a1] = [1] +// [w1.e12 w2.e12][a2] = [0] +// +// Define +// d12_1 = dot(w2, e12) +// d12_2 = -dot(w1, e12) +// d12 = d12_1 + d12_2 +// +// Solution +// a1 = d12_1 / d12 +// a2 = d12_2 / d12 +void b2Simplex::Solve2() +{ + b2Vec2 w1 = m_v1.w; + b2Vec2 w2 = m_v2.w; + b2Vec2 e12 = w2 - w1; + + // w1 region + float32 d12_2 = -b2Dot(w1, e12); + if (d12_2 <= 0.0f) + { + // a2 <= 0, so we clamp it to 0 + m_v1.a = 1.0f; + m_count = 1; + return; + } + + // w2 region + float32 d12_1 = b2Dot(w2, e12); + if (d12_1 <= 0.0f) + { + // a1 <= 0, so we clamp it to 0 + m_v2.a = 1.0f; + m_count = 1; + m_v1 = m_v2; + return; + } + + // Must be in e12 region. + float32 inv_d12 = 1.0f / (d12_1 + d12_2); + m_v1.a = d12_1 * inv_d12; + m_v2.a = d12_2 * inv_d12; + m_count = 2; +} + +// Possible regions: +// - points[2] +// - edge points[0]-points[2] +// - edge points[1]-points[2] +// - inside the triangle +void b2Simplex::Solve3() +{ + b2Vec2 w1 = m_v1.w; + b2Vec2 w2 = m_v2.w; + b2Vec2 w3 = m_v3.w; + + // Edge12 + // [1 1 ][a1] = [1] + // [w1.e12 w2.e12][a2] = [0] + // a3 = 0 + b2Vec2 e12 = w2 - w1; + float32 w1e12 = b2Dot(w1, e12); + float32 w2e12 = b2Dot(w2, e12); + float32 d12_1 = w2e12; + float32 d12_2 = -w1e12; + + // Edge13 + // [1 1 ][a1] = [1] + // [w1.e13 w3.e13][a3] = [0] + // a2 = 0 + b2Vec2 e13 = w3 - w1; + float32 w1e13 = b2Dot(w1, e13); + float32 w3e13 = b2Dot(w3, e13); + float32 d13_1 = w3e13; + float32 d13_2 = -w1e13; + + // Edge23 + // [1 1 ][a2] = [1] + // [w2.e23 w3.e23][a3] = [0] + // a1 = 0 + b2Vec2 e23 = w3 - w2; + float32 w2e23 = b2Dot(w2, e23); + float32 w3e23 = b2Dot(w3, e23); + float32 d23_1 = w3e23; + float32 d23_2 = -w2e23; + + // Triangle123 + float32 n123 = b2Cross(e12, e13); + + float32 d123_1 = n123 * b2Cross(w2, w3); + float32 d123_2 = n123 * b2Cross(w3, w1); + float32 d123_3 = n123 * b2Cross(w1, w2); + + // w1 region + if (d12_2 <= 0.0f && d13_2 <= 0.0f) + { + m_v1.a = 1.0f; + m_count = 1; + return; + } + + // e12 + if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f) + { + float32 inv_d12 = 1.0f / (d12_1 + d12_2); + m_v1.a = d12_1 * inv_d12; + m_v2.a = d12_2 * inv_d12; + m_count = 2; + return; + } + + // e13 + if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f) + { + float32 inv_d13 = 1.0f / (d13_1 + d13_2); + m_v1.a = d13_1 * inv_d13; + m_v3.a = d13_2 * inv_d13; + m_count = 2; + m_v2 = m_v3; + return; + } + + // w2 region + if (d12_1 <= 0.0f && d23_2 <= 0.0f) + { + m_v2.a = 1.0f; + m_count = 1; + m_v1 = m_v2; + return; + } + + // w3 region + if (d13_1 <= 0.0f && d23_1 <= 0.0f) + { + m_v3.a = 1.0f; + m_count = 1; + m_v1 = m_v3; + return; + } + + // e23 + if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f) + { + float32 inv_d23 = 1.0f / (d23_1 + d23_2); + m_v2.a = d23_1 * inv_d23; + m_v3.a = d23_2 * inv_d23; + m_count = 2; + m_v1 = m_v3; + return; + } + + // Must be in triangle123 + float32 inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3); + m_v1.a = d123_1 * inv_d123; + m_v2.a = d123_2 * inv_d123; + m_v3.a = d123_3 * inv_d123; + m_count = 3; +} + +void b2Distance(b2DistanceOutput* output, + b2SimplexCache* cache, + const b2DistanceInput* input) +{ + ++b2_gjkCalls; + + const b2DistanceProxy* proxyA = &input->proxyA; + const b2DistanceProxy* proxyB = &input->proxyB; + + b2Transform transformA = input->transformA; + b2Transform transformB = input->transformB; + + // Initialize the simplex. + b2Simplex simplex; + simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB); + + // Get simplex vertices as an array. + b2SimplexVertex* vertices = &simplex.m_v1; + const int32 k_maxIters = 20; + + // These store the vertices of the last simplex so that we + // can check for duplicates and prevent cycling. + int32 saveA[3], saveB[3]; + int32 saveCount = 0; + + b2Vec2 closestPoint = simplex.GetClosestPoint(); + float32 distanceSqr1 = closestPoint.LengthSquared(); + float32 distanceSqr2 = distanceSqr1; + + // Main iteration loop. + int32 iter = 0; + while (iter < k_maxIters) + { + // Copy simplex so we can identify duplicates. + saveCount = simplex.m_count; + for (int32 i = 0; i < saveCount; ++i) + { + saveA[i] = vertices[i].indexA; + saveB[i] = vertices[i].indexB; + } + + switch (simplex.m_count) + { + case 1: + break; + + case 2: + simplex.Solve2(); + break; + + case 3: + simplex.Solve3(); + break; + + default: + b2Assert(false); + } + + // If we have 3 points, then the origin is in the corresponding triangle. + if (simplex.m_count == 3) + { + break; + } + + // Compute closest point. + b2Vec2 p = simplex.GetClosestPoint(); + distanceSqr2 = p.LengthSquared(); + + // Ensure progress + if (distanceSqr2 >= distanceSqr1) + { + //break; + } + distanceSqr1 = distanceSqr2; + + // Get search direction. + b2Vec2 d = simplex.GetSearchDirection(); + + // Ensure the search direction is numerically fit. + if (d.LengthSquared() < b2_epsilon * b2_epsilon) + { + // The origin is probably contained by a line segment + // or triangle. Thus the shapes are overlapped. + + // We can't return zero here even though there may be overlap. + // In case the simplex is a point, segment, or triangle it is difficult + // to determine if the origin is contained in the CSO or very close to it. + break; + } + + // Compute a tentative new simplex vertex using support points. + b2SimplexVertex* vertex = vertices + simplex.m_count; + vertex->indexA = proxyA->GetSupport(b2MulT(transformA.q, -d)); + vertex->wA = b2Mul(transformA, proxyA->GetVertex(vertex->indexA)); + b2Vec2 wBLocal; + vertex->indexB = proxyB->GetSupport(b2MulT(transformB.q, d)); + vertex->wB = b2Mul(transformB, proxyB->GetVertex(vertex->indexB)); + vertex->w = vertex->wB - vertex->wA; + + // Iteration count is equated to the number of support point calls. + ++iter; + ++b2_gjkIters; + + // Check for duplicate support points. This is the main termination criteria. + bool duplicate = false; + for (int32 i = 0; i < saveCount; ++i) + { + if (vertex->indexA == saveA[i] && vertex->indexB == saveB[i]) + { + duplicate = true; + break; + } + } + + // If we found a duplicate support point we must exit to avoid cycling. + if (duplicate) + { + break; + } + + // New vertex is ok and needed. + ++simplex.m_count; + } + + b2_gjkMaxIters = b2Max(b2_gjkMaxIters, iter); + + // Prepare output. + simplex.GetWitnessPoints(&output->pointA, &output->pointB); + output->distance = b2Distance(output->pointA, output->pointB); + output->iterations = iter; + + // Cache the simplex. + simplex.WriteCache(cache); + + // Apply radii if requested. + if (input->useRadii) + { + float32 rA = proxyA->m_radius; + float32 rB = proxyB->m_radius; + + if (output->distance > rA + rB && output->distance > b2_epsilon) + { + // Shapes are still no overlapped. + // Move the witness points to the outer surface. + output->distance -= rA + rB; + b2Vec2 normal = output->pointB - output->pointA; + normal.Normalize(); + output->pointA += rA * normal; + output->pointB -= rB * normal; + } + else + { + // Shapes are overlapped when radii are considered. + // Move the witness points to the middle. + b2Vec2 p = 0.5f * (output->pointA + output->pointB); + output->pointA = p; + output->pointB = p; + output->distance = 0.0f; + } + } +} diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2Distance.h b/tests/Box2D_v2.2.1/Box2D/Collision/b2Distance.h new file mode 100755 index 0000000000000..54ed1e136c327 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/b2Distance.h @@ -0,0 +1,141 @@ + +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_DISTANCE_H +#define B2_DISTANCE_H + +#include + +class b2Shape; + +/// A distance proxy is used by the GJK algorithm. +/// It encapsulates any shape. +struct b2DistanceProxy +{ + b2DistanceProxy() : m_vertices(NULL), m_count(0), m_radius(0.0f) {} + + /// Initialize the proxy using the given shape. The shape + /// must remain in scope while the proxy is in use. + void Set(const b2Shape* shape, int32 index); + + /// Get the supporting vertex index in the given direction. + int32 GetSupport(const b2Vec2& d) const; + + /// Get the supporting vertex in the given direction. + const b2Vec2& GetSupportVertex(const b2Vec2& d) const; + + /// Get the vertex count. + int32 GetVertexCount() const; + + /// Get a vertex by index. Used by b2Distance. + const b2Vec2& GetVertex(int32 index) const; + + b2Vec2 m_buffer[2]; + const b2Vec2* m_vertices; + int32 m_count; + float32 m_radius; +}; + +/// Used to warm start b2Distance. +/// Set count to zero on first call. +struct b2SimplexCache +{ + float32 metric; ///< length or area + uint16 count; + uint8 indexA[3]; ///< vertices on shape A + uint8 indexB[3]; ///< vertices on shape B +}; + +/// Input for b2Distance. +/// You have to option to use the shape radii +/// in the computation. Even +struct b2DistanceInput +{ + b2DistanceProxy proxyA; + b2DistanceProxy proxyB; + b2Transform transformA; + b2Transform transformB; + bool useRadii; +}; + +/// Output for b2Distance. +struct b2DistanceOutput +{ + b2Vec2 pointA; ///< closest point on shapeA + b2Vec2 pointB; ///< closest point on shapeB + float32 distance; + int32 iterations; ///< number of GJK iterations used +}; + +/// Compute the closest points between two shapes. Supports any combination of: +/// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output. +/// On the first call set b2SimplexCache.count to zero. +void b2Distance(b2DistanceOutput* output, + b2SimplexCache* cache, + const b2DistanceInput* input); + + +////////////////////////////////////////////////////////////////////////// + +inline int32 b2DistanceProxy::GetVertexCount() const +{ + return m_count; +} + +inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const +{ + b2Assert(0 <= index && index < m_count); + return m_vertices[index]; +} + +inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const +{ + int32 bestIndex = 0; + float32 bestValue = b2Dot(m_vertices[0], d); + for (int32 i = 1; i < m_count; ++i) + { + float32 value = b2Dot(m_vertices[i], d); + if (value > bestValue) + { + bestIndex = i; + bestValue = value; + } + } + + return bestIndex; +} + +inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const +{ + int32 bestIndex = 0; + float32 bestValue = b2Dot(m_vertices[0], d); + for (int32 i = 1; i < m_count; ++i) + { + float32 value = b2Dot(m_vertices[i], d); + if (value > bestValue) + { + bestIndex = i; + bestValue = value; + } + } + + return m_vertices[bestIndex]; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2DynamicTree.cpp b/tests/Box2D_v2.2.1/Box2D/Collision/b2DynamicTree.cpp new file mode 100755 index 0000000000000..1a42c3a5fcec7 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/b2DynamicTree.cpp @@ -0,0 +1,771 @@ +/* +* Copyright (c) 2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +using namespace std; + + +b2DynamicTree::b2DynamicTree() +{ + m_root = b2_nullNode; + + m_nodeCapacity = 16; + m_nodeCount = 0; + m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode)); + memset(m_nodes, 0, m_nodeCapacity * sizeof(b2TreeNode)); + + // Build a linked list for the free list. + for (int32 i = 0; i < m_nodeCapacity - 1; ++i) + { + m_nodes[i].next = i + 1; + m_nodes[i].height = -1; + } + m_nodes[m_nodeCapacity-1].next = b2_nullNode; + m_nodes[m_nodeCapacity-1].height = -1; + m_freeList = 0; + + m_path = 0; + + m_insertionCount = 0; +} + +b2DynamicTree::~b2DynamicTree() +{ + // This frees the entire tree in one shot. + b2Free(m_nodes); +} + +// Allocate a node from the pool. Grow the pool if necessary. +int32 b2DynamicTree::AllocateNode() +{ + // Expand the node pool as needed. + if (m_freeList == b2_nullNode) + { + b2Assert(m_nodeCount == m_nodeCapacity); + + // The free list is empty. Rebuild a bigger pool. + b2TreeNode* oldNodes = m_nodes; + m_nodeCapacity *= 2; + m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode)); + memcpy(m_nodes, oldNodes, m_nodeCount * sizeof(b2TreeNode)); + b2Free(oldNodes); + + // Build a linked list for the free list. The parent + // pointer becomes the "next" pointer. + for (int32 i = m_nodeCount; i < m_nodeCapacity - 1; ++i) + { + m_nodes[i].next = i + 1; + m_nodes[i].height = -1; + } + m_nodes[m_nodeCapacity-1].next = b2_nullNode; + m_nodes[m_nodeCapacity-1].height = -1; + m_freeList = m_nodeCount; + } + + // Peel a node off the free list. + int32 nodeId = m_freeList; + m_freeList = m_nodes[nodeId].next; + m_nodes[nodeId].parent = b2_nullNode; + m_nodes[nodeId].child1 = b2_nullNode; + m_nodes[nodeId].child2 = b2_nullNode; + m_nodes[nodeId].height = 0; + m_nodes[nodeId].userData = NULL; + ++m_nodeCount; + return nodeId; +} + +// Return a node to the pool. +void b2DynamicTree::FreeNode(int32 nodeId) +{ + b2Assert(0 <= nodeId && nodeId < m_nodeCapacity); + b2Assert(0 < m_nodeCount); + m_nodes[nodeId].next = m_freeList; + m_nodes[nodeId].height = -1; + m_freeList = nodeId; + --m_nodeCount; +} + +// Create a proxy in the tree as a leaf node. We return the index +// of the node instead of a pointer so that we can grow +// the node pool. +int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData) +{ + int32 proxyId = AllocateNode(); + + // Fatten the aabb. + b2Vec2 r(b2_aabbExtension, b2_aabbExtension); + m_nodes[proxyId].aabb.lowerBound = aabb.lowerBound - r; + m_nodes[proxyId].aabb.upperBound = aabb.upperBound + r; + m_nodes[proxyId].userData = userData; + m_nodes[proxyId].height = 0; + + InsertLeaf(proxyId); + + return proxyId; +} + +void b2DynamicTree::DestroyProxy(int32 proxyId) +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + b2Assert(m_nodes[proxyId].IsLeaf()); + + RemoveLeaf(proxyId); + FreeNode(proxyId); +} + +bool b2DynamicTree::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement) +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + + b2Assert(m_nodes[proxyId].IsLeaf()); + + if (m_nodes[proxyId].aabb.Contains(aabb)) + { + return false; + } + + RemoveLeaf(proxyId); + + // Extend AABB. + b2AABB b = aabb; + b2Vec2 r(b2_aabbExtension, b2_aabbExtension); + b.lowerBound = b.lowerBound - r; + b.upperBound = b.upperBound + r; + + // Predict AABB displacement. + b2Vec2 d = b2_aabbMultiplier * displacement; + + if (d.x < 0.0f) + { + b.lowerBound.x += d.x; + } + else + { + b.upperBound.x += d.x; + } + + if (d.y < 0.0f) + { + b.lowerBound.y += d.y; + } + else + { + b.upperBound.y += d.y; + } + + m_nodes[proxyId].aabb = b; + + InsertLeaf(proxyId); + return true; +} + +void b2DynamicTree::InsertLeaf(int32 leaf) +{ + ++m_insertionCount; + + if (m_root == b2_nullNode) + { + m_root = leaf; + m_nodes[m_root].parent = b2_nullNode; + return; + } + + // Find the best sibling for this node + b2AABB leafAABB = m_nodes[leaf].aabb; + int32 index = m_root; + while (m_nodes[index].IsLeaf() == false) + { + int32 child1 = m_nodes[index].child1; + int32 child2 = m_nodes[index].child2; + + float32 area = m_nodes[index].aabb.GetPerimeter(); + + b2AABB combinedAABB; + combinedAABB.Combine(m_nodes[index].aabb, leafAABB); + float32 combinedArea = combinedAABB.GetPerimeter(); + + // Cost of creating a new parent for this node and the new leaf + float32 cost = 2.0f * combinedArea; + + // Minimum cost of pushing the leaf further down the tree + float32 inheritanceCost = 2.0f * (combinedArea - area); + + // Cost of descending into child1 + float32 cost1; + if (m_nodes[child1].IsLeaf()) + { + b2AABB aabb; + aabb.Combine(leafAABB, m_nodes[child1].aabb); + cost1 = aabb.GetPerimeter() + inheritanceCost; + } + else + { + b2AABB aabb; + aabb.Combine(leafAABB, m_nodes[child1].aabb); + float32 oldArea = m_nodes[child1].aabb.GetPerimeter(); + float32 newArea = aabb.GetPerimeter(); + cost1 = (newArea - oldArea) + inheritanceCost; + } + + // Cost of descending into child2 + float32 cost2; + if (m_nodes[child2].IsLeaf()) + { + b2AABB aabb; + aabb.Combine(leafAABB, m_nodes[child2].aabb); + cost2 = aabb.GetPerimeter() + inheritanceCost; + } + else + { + b2AABB aabb; + aabb.Combine(leafAABB, m_nodes[child2].aabb); + float32 oldArea = m_nodes[child2].aabb.GetPerimeter(); + float32 newArea = aabb.GetPerimeter(); + cost2 = newArea - oldArea + inheritanceCost; + } + + // Descend according to the minimum cost. + if (cost < cost1 && cost < cost2) + { + break; + } + + // Descend + if (cost1 < cost2) + { + index = child1; + } + else + { + index = child2; + } + } + + int32 sibling = index; + + // Create a new parent. + int32 oldParent = m_nodes[sibling].parent; + int32 newParent = AllocateNode(); + m_nodes[newParent].parent = oldParent; + m_nodes[newParent].userData = NULL; + m_nodes[newParent].aabb.Combine(leafAABB, m_nodes[sibling].aabb); + m_nodes[newParent].height = m_nodes[sibling].height + 1; + + if (oldParent != b2_nullNode) + { + // The sibling was not the root. + if (m_nodes[oldParent].child1 == sibling) + { + m_nodes[oldParent].child1 = newParent; + } + else + { + m_nodes[oldParent].child2 = newParent; + } + + m_nodes[newParent].child1 = sibling; + m_nodes[newParent].child2 = leaf; + m_nodes[sibling].parent = newParent; + m_nodes[leaf].parent = newParent; + } + else + { + // The sibling was the root. + m_nodes[newParent].child1 = sibling; + m_nodes[newParent].child2 = leaf; + m_nodes[sibling].parent = newParent; + m_nodes[leaf].parent = newParent; + m_root = newParent; + } + + // Walk back up the tree fixing heights and AABBs + index = m_nodes[leaf].parent; + while (index != b2_nullNode) + { + index = Balance(index); + + int32 child1 = m_nodes[index].child1; + int32 child2 = m_nodes[index].child2; + + b2Assert(child1 != b2_nullNode); + b2Assert(child2 != b2_nullNode); + + m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height); + m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); + + index = m_nodes[index].parent; + } + + //Validate(); +} + +void b2DynamicTree::RemoveLeaf(int32 leaf) +{ + if (leaf == m_root) + { + m_root = b2_nullNode; + return; + } + + int32 parent = m_nodes[leaf].parent; + int32 grandParent = m_nodes[parent].parent; + int32 sibling; + if (m_nodes[parent].child1 == leaf) + { + sibling = m_nodes[parent].child2; + } + else + { + sibling = m_nodes[parent].child1; + } + + if (grandParent != b2_nullNode) + { + // Destroy parent and connect sibling to grandParent. + if (m_nodes[grandParent].child1 == parent) + { + m_nodes[grandParent].child1 = sibling; + } + else + { + m_nodes[grandParent].child2 = sibling; + } + m_nodes[sibling].parent = grandParent; + FreeNode(parent); + + // Adjust ancestor bounds. + int32 index = grandParent; + while (index != b2_nullNode) + { + index = Balance(index); + + int32 child1 = m_nodes[index].child1; + int32 child2 = m_nodes[index].child2; + + m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); + m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height); + + index = m_nodes[index].parent; + } + } + else + { + m_root = sibling; + m_nodes[sibling].parent = b2_nullNode; + FreeNode(parent); + } + + //Validate(); +} + +// Perform a left or right rotation if node A is imbalanced. +// Returns the new root index. +int32 b2DynamicTree::Balance(int32 iA) +{ + b2Assert(iA != b2_nullNode); + + b2TreeNode* A = m_nodes + iA; + if (A->IsLeaf() || A->height < 2) + { + return iA; + } + + int32 iB = A->child1; + int32 iC = A->child2; + b2Assert(0 <= iB && iB < m_nodeCapacity); + b2Assert(0 <= iC && iC < m_nodeCapacity); + + b2TreeNode* B = m_nodes + iB; + b2TreeNode* C = m_nodes + iC; + + int32 balance = C->height - B->height; + + // Rotate C up + if (balance > 1) + { + int32 iF = C->child1; + int32 iG = C->child2; + b2TreeNode* F = m_nodes + iF; + b2TreeNode* G = m_nodes + iG; + b2Assert(0 <= iF && iF < m_nodeCapacity); + b2Assert(0 <= iG && iG < m_nodeCapacity); + + // Swap A and C + C->child1 = iA; + C->parent = A->parent; + A->parent = iC; + + // A's old parent should point to C + if (C->parent != b2_nullNode) + { + if (m_nodes[C->parent].child1 == iA) + { + m_nodes[C->parent].child1 = iC; + } + else + { + b2Assert(m_nodes[C->parent].child2 == iA); + m_nodes[C->parent].child2 = iC; + } + } + else + { + m_root = iC; + } + + // Rotate + if (F->height > G->height) + { + C->child2 = iF; + A->child2 = iG; + G->parent = iA; + A->aabb.Combine(B->aabb, G->aabb); + C->aabb.Combine(A->aabb, F->aabb); + + A->height = 1 + b2Max(B->height, G->height); + C->height = 1 + b2Max(A->height, F->height); + } + else + { + C->child2 = iG; + A->child2 = iF; + F->parent = iA; + A->aabb.Combine(B->aabb, F->aabb); + C->aabb.Combine(A->aabb, G->aabb); + + A->height = 1 + b2Max(B->height, F->height); + C->height = 1 + b2Max(A->height, G->height); + } + + return iC; + } + + // Rotate B up + if (balance < -1) + { + int32 iD = B->child1; + int32 iE = B->child2; + b2TreeNode* D = m_nodes + iD; + b2TreeNode* E = m_nodes + iE; + b2Assert(0 <= iD && iD < m_nodeCapacity); + b2Assert(0 <= iE && iE < m_nodeCapacity); + + // Swap A and B + B->child1 = iA; + B->parent = A->parent; + A->parent = iB; + + // A's old parent should point to B + if (B->parent != b2_nullNode) + { + if (m_nodes[B->parent].child1 == iA) + { + m_nodes[B->parent].child1 = iB; + } + else + { + b2Assert(m_nodes[B->parent].child2 == iA); + m_nodes[B->parent].child2 = iB; + } + } + else + { + m_root = iB; + } + + // Rotate + if (D->height > E->height) + { + B->child2 = iD; + A->child1 = iE; + E->parent = iA; + A->aabb.Combine(C->aabb, E->aabb); + B->aabb.Combine(A->aabb, D->aabb); + + A->height = 1 + b2Max(C->height, E->height); + B->height = 1 + b2Max(A->height, D->height); + } + else + { + B->child2 = iE; + A->child1 = iD; + D->parent = iA; + A->aabb.Combine(C->aabb, D->aabb); + B->aabb.Combine(A->aabb, E->aabb); + + A->height = 1 + b2Max(C->height, D->height); + B->height = 1 + b2Max(A->height, E->height); + } + + return iB; + } + + return iA; +} + +int32 b2DynamicTree::GetHeight() const +{ + if (m_root == b2_nullNode) + { + return 0; + } + + return m_nodes[m_root].height; +} + +// +float32 b2DynamicTree::GetAreaRatio() const +{ + if (m_root == b2_nullNode) + { + return 0.0f; + } + + const b2TreeNode* root = m_nodes + m_root; + float32 rootArea = root->aabb.GetPerimeter(); + + float32 totalArea = 0.0f; + for (int32 i = 0; i < m_nodeCapacity; ++i) + { + const b2TreeNode* node = m_nodes + i; + if (node->height < 0) + { + // Free node in pool + continue; + } + + totalArea += node->aabb.GetPerimeter(); + } + + return totalArea / rootArea; +} + +// Compute the height of a sub-tree. +int32 b2DynamicTree::ComputeHeight(int32 nodeId) const +{ + b2Assert(0 <= nodeId && nodeId < m_nodeCapacity); + b2TreeNode* node = m_nodes + nodeId; + + if (node->IsLeaf()) + { + return 0; + } + + int32 height1 = ComputeHeight(node->child1); + int32 height2 = ComputeHeight(node->child2); + return 1 + b2Max(height1, height2); +} + +int32 b2DynamicTree::ComputeHeight() const +{ + int32 height = ComputeHeight(m_root); + return height; +} + +void b2DynamicTree::ValidateStructure(int32 index) const +{ + if (index == b2_nullNode) + { + return; + } + + if (index == m_root) + { + b2Assert(m_nodes[index].parent == b2_nullNode); + } + + const b2TreeNode* node = m_nodes + index; + + int32 child1 = node->child1; + int32 child2 = node->child2; + + if (node->IsLeaf()) + { + b2Assert(child1 == b2_nullNode); + b2Assert(child2 == b2_nullNode); + b2Assert(node->height == 0); + return; + } + + b2Assert(0 <= child1 && child1 < m_nodeCapacity); + b2Assert(0 <= child2 && child2 < m_nodeCapacity); + + b2Assert(m_nodes[child1].parent == index); + b2Assert(m_nodes[child2].parent == index); + + ValidateStructure(child1); + ValidateStructure(child2); +} + +void b2DynamicTree::ValidateMetrics(int32 index) const +{ + if (index == b2_nullNode) + { + return; + } + + const b2TreeNode* node = m_nodes + index; + + int32 child1 = node->child1; + int32 child2 = node->child2; + + if (node->IsLeaf()) + { + b2Assert(child1 == b2_nullNode); + b2Assert(child2 == b2_nullNode); + b2Assert(node->height == 0); + return; + } + + b2Assert(0 <= child1 && child1 < m_nodeCapacity); + b2Assert(0 <= child2 && child2 < m_nodeCapacity); + + int32 height1 = m_nodes[child1].height; + int32 height2 = m_nodes[child2].height; + int32 height; + height = 1 + b2Max(height1, height2); + b2Assert(node->height == height); + + b2AABB aabb; + aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); + + b2Assert(aabb.lowerBound == node->aabb.lowerBound); + b2Assert(aabb.upperBound == node->aabb.upperBound); + + ValidateMetrics(child1); + ValidateMetrics(child2); +} + +void b2DynamicTree::Validate() const +{ + ValidateStructure(m_root); + ValidateMetrics(m_root); + + int32 freeCount = 0; + int32 freeIndex = m_freeList; + while (freeIndex != b2_nullNode) + { + b2Assert(0 <= freeIndex && freeIndex < m_nodeCapacity); + freeIndex = m_nodes[freeIndex].next; + ++freeCount; + } + + b2Assert(GetHeight() == ComputeHeight()); + + b2Assert(m_nodeCount + freeCount == m_nodeCapacity); +} + +int32 b2DynamicTree::GetMaxBalance() const +{ + int32 maxBalance = 0; + for (int32 i = 0; i < m_nodeCapacity; ++i) + { + const b2TreeNode* node = m_nodes + i; + if (node->height <= 1) + { + continue; + } + + b2Assert(node->IsLeaf() == false); + + int32 child1 = node->child1; + int32 child2 = node->child2; + int32 balance = b2Abs(m_nodes[child2].height - m_nodes[child1].height); + maxBalance = b2Max(maxBalance, balance); + } + + return maxBalance; +} + +void b2DynamicTree::RebuildBottomUp() +{ + int32* nodes = (int32*)b2Alloc(m_nodeCount * sizeof(int32)); + int32 count = 0; + + // Build array of leaves. Free the rest. + for (int32 i = 0; i < m_nodeCapacity; ++i) + { + if (m_nodes[i].height < 0) + { + // free node in pool + continue; + } + + if (m_nodes[i].IsLeaf()) + { + m_nodes[i].parent = b2_nullNode; + nodes[count] = i; + ++count; + } + else + { + FreeNode(i); + } + } + + while (count > 1) + { + float32 minCost = b2_maxFloat; + int32 iMin = -1, jMin = -1; + for (int32 i = 0; i < count; ++i) + { + b2AABB aabbi = m_nodes[nodes[i]].aabb; + + for (int32 j = i + 1; j < count; ++j) + { + b2AABB aabbj = m_nodes[nodes[j]].aabb; + b2AABB b; + b.Combine(aabbi, aabbj); + float32 cost = b.GetPerimeter(); + if (cost < minCost) + { + iMin = i; + jMin = j; + minCost = cost; + } + } + } + + int32 index1 = nodes[iMin]; + int32 index2 = nodes[jMin]; + b2TreeNode* child1 = m_nodes + index1; + b2TreeNode* child2 = m_nodes + index2; + + int32 parentIndex = AllocateNode(); + b2TreeNode* parent = m_nodes + parentIndex; + parent->child1 = index1; + parent->child2 = index2; + parent->height = 1 + b2Max(child1->height, child2->height); + parent->aabb.Combine(child1->aabb, child2->aabb); + parent->parent = b2_nullNode; + + child1->parent = parentIndex; + child2->parent = parentIndex; + + nodes[jMin] = nodes[count-1]; + nodes[iMin] = parentIndex; + --count; + } + + m_root = nodes[0]; + b2Free(nodes); + + Validate(); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2DynamicTree.h b/tests/Box2D_v2.2.1/Box2D/Collision/b2DynamicTree.h new file mode 100755 index 0000000000000..a9bfbf379a009 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/b2DynamicTree.h @@ -0,0 +1,284 @@ +/* +* Copyright (c) 2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_DYNAMIC_TREE_H +#define B2_DYNAMIC_TREE_H + +#include +#include + +#define b2_nullNode (-1) + +/// A node in the dynamic tree. The client does not interact with this directly. +struct b2TreeNode +{ + bool IsLeaf() const + { + return child1 == b2_nullNode; + } + + /// Enlarged AABB + b2AABB aabb; + + void* userData; + + union + { + int32 parent; + int32 next; + }; + + int32 child1; + int32 child2; + + // leaf = 0, free node = -1 + int32 height; +}; + +/// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt. +/// A dynamic tree arranges data in a binary tree to accelerate +/// queries such as volume queries and ray casts. Leafs are proxies +/// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor +/// so that the proxy AABB is bigger than the client object. This allows the client +/// object to move by small amounts without triggering a tree update. +/// +/// Nodes are pooled and relocatable, so we use node indices rather than pointers. +class b2DynamicTree +{ +public: + /// Constructing the tree initializes the node pool. + b2DynamicTree(); + + /// Destroy the tree, freeing the node pool. + ~b2DynamicTree(); + + /// Create a proxy. Provide a tight fitting AABB and a userData pointer. + int32 CreateProxy(const b2AABB& aabb, void* userData); + + /// Destroy a proxy. This asserts if the id is invalid. + void DestroyProxy(int32 proxyId); + + /// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB, + /// then the proxy is removed from the tree and re-inserted. Otherwise + /// the function returns immediately. + /// @return true if the proxy was re-inserted. + bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement); + + /// Get proxy user data. + /// @return the proxy user data or 0 if the id is invalid. + void* GetUserData(int32 proxyId) const; + + /// Get the fat AABB for a proxy. + const b2AABB& GetFatAABB(int32 proxyId) const; + + /// Query an AABB for overlapping proxies. The callback class + /// is called for each proxy that overlaps the supplied AABB. + template + void Query(T* callback, const b2AABB& aabb) const; + + /// Ray-cast against the proxies in the tree. This relies on the callback + /// to perform a exact ray-cast in the case were the proxy contains a shape. + /// The callback also performs the any collision filtering. This has performance + /// roughly equal to k * log(n), where k is the number of collisions and n is the + /// number of proxies in the tree. + /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). + /// @param callback a callback class that is called for each proxy that is hit by the ray. + template + void RayCast(T* callback, const b2RayCastInput& input) const; + + /// Validate this tree. For testing. + void Validate() const; + + /// Compute the height of the binary tree in O(N) time. Should not be + /// called often. + int32 GetHeight() const; + + /// Get the maximum balance of an node in the tree. The balance is the difference + /// in height of the two children of a node. + int32 GetMaxBalance() const; + + /// Get the ratio of the sum of the node areas to the root area. + float32 GetAreaRatio() const; + + /// Build an optimal tree. Very expensive. For testing. + void RebuildBottomUp(); + +private: + + int32 AllocateNode(); + void FreeNode(int32 node); + + void InsertLeaf(int32 node); + void RemoveLeaf(int32 node); + + int32 Balance(int32 index); + + int32 ComputeHeight() const; + int32 ComputeHeight(int32 nodeId) const; + + void ValidateStructure(int32 index) const; + void ValidateMetrics(int32 index) const; + + int32 m_root; + + b2TreeNode* m_nodes; + int32 m_nodeCount; + int32 m_nodeCapacity; + + int32 m_freeList; + + /// This is used to incrementally traverse the tree for re-balancing. + uint32 m_path; + + int32 m_insertionCount; +}; + +inline void* b2DynamicTree::GetUserData(int32 proxyId) const +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + return m_nodes[proxyId].userData; +} + +inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + return m_nodes[proxyId].aabb; +} + +template +inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const +{ + b2GrowableStack stack; + stack.Push(m_root); + + while (stack.GetCount() > 0) + { + int32 nodeId = stack.Pop(); + if (nodeId == b2_nullNode) + { + continue; + } + + const b2TreeNode* node = m_nodes + nodeId; + + if (b2TestOverlap(node->aabb, aabb)) + { + if (node->IsLeaf()) + { + bool proceed = callback->QueryCallback(nodeId); + if (proceed == false) + { + return; + } + } + else + { + stack.Push(node->child1); + stack.Push(node->child2); + } + } + } +} + +template +inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const +{ + b2Vec2 p1 = input.p1; + b2Vec2 p2 = input.p2; + b2Vec2 r = p2 - p1; + b2Assert(r.LengthSquared() > 0.0f); + r.Normalize(); + + // v is perpendicular to the segment. + b2Vec2 v = b2Cross(1.0f, r); + b2Vec2 abs_v = b2Abs(v); + + // Separating axis for segment (Gino, p80). + // |dot(v, p1 - c)| > dot(|v|, h) + + float32 maxFraction = input.maxFraction; + + // Build a bounding box for the segment. + b2AABB segmentAABB; + { + b2Vec2 t = p1 + maxFraction * (p2 - p1); + segmentAABB.lowerBound = b2Min(p1, t); + segmentAABB.upperBound = b2Max(p1, t); + } + + b2GrowableStack stack; + stack.Push(m_root); + + while (stack.GetCount() > 0) + { + int32 nodeId = stack.Pop(); + if (nodeId == b2_nullNode) + { + continue; + } + + const b2TreeNode* node = m_nodes + nodeId; + + if (b2TestOverlap(node->aabb, segmentAABB) == false) + { + continue; + } + + // Separating axis for segment (Gino, p80). + // |dot(v, p1 - c)| > dot(|v|, h) + b2Vec2 c = node->aabb.GetCenter(); + b2Vec2 h = node->aabb.GetExtents(); + float32 separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h); + if (separation > 0.0f) + { + continue; + } + + if (node->IsLeaf()) + { + b2RayCastInput subInput; + subInput.p1 = input.p1; + subInput.p2 = input.p2; + subInput.maxFraction = maxFraction; + + float32 value = callback->RayCastCallback(subInput, nodeId); + + if (value == 0.0f) + { + // The client has terminated the ray cast. + return; + } + + if (value > 0.0f) + { + // Update segment bounding box. + maxFraction = value; + b2Vec2 t = p1 + maxFraction * (p2 - p1); + segmentAABB.lowerBound = b2Min(p1, t); + segmentAABB.upperBound = b2Max(p1, t); + } + } + else + { + stack.Push(node->child1); + stack.Push(node->child2); + } + } +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2TimeOfImpact.cpp b/tests/Box2D_v2.2.1/Box2D/Collision/b2TimeOfImpact.cpp new file mode 100755 index 0000000000000..5c33e828c2503 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/b2TimeOfImpact.cpp @@ -0,0 +1,483 @@ +/* +* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include + +#include +using namespace std; + +int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters; +int32 b2_toiRootIters, b2_toiMaxRootIters; + +struct b2SeparationFunction +{ + enum Type + { + e_points, + e_faceA, + e_faceB + }; + + // TODO_ERIN might not need to return the separation + + float32 Initialize(const b2SimplexCache* cache, + const b2DistanceProxy* proxyA, const b2Sweep& sweepA, + const b2DistanceProxy* proxyB, const b2Sweep& sweepB, + float32 t1) + { + m_proxyA = proxyA; + m_proxyB = proxyB; + int32 count = cache->count; + b2Assert(0 < count && count < 3); + + m_sweepA = sweepA; + m_sweepB = sweepB; + + b2Transform xfA, xfB; + m_sweepA.GetTransform(&xfA, t1); + m_sweepB.GetTransform(&xfB, t1); + + if (count == 1) + { + m_type = e_points; + b2Vec2 localPointA = m_proxyA->GetVertex(cache->indexA[0]); + b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]); + b2Vec2 pointA = b2Mul(xfA, localPointA); + b2Vec2 pointB = b2Mul(xfB, localPointB); + m_axis = pointB - pointA; + float32 s = m_axis.Normalize(); + return s; + } + else if (cache->indexA[0] == cache->indexA[1]) + { + // Two points on B and one on A. + m_type = e_faceB; + b2Vec2 localPointB1 = proxyB->GetVertex(cache->indexB[0]); + b2Vec2 localPointB2 = proxyB->GetVertex(cache->indexB[1]); + + m_axis = b2Cross(localPointB2 - localPointB1, 1.0f); + m_axis.Normalize(); + b2Vec2 normal = b2Mul(xfB.q, m_axis); + + m_localPoint = 0.5f * (localPointB1 + localPointB2); + b2Vec2 pointB = b2Mul(xfB, m_localPoint); + + b2Vec2 localPointA = proxyA->GetVertex(cache->indexA[0]); + b2Vec2 pointA = b2Mul(xfA, localPointA); + + float32 s = b2Dot(pointA - pointB, normal); + if (s < 0.0f) + { + m_axis = -m_axis; + s = -s; + } + return s; + } + else + { + // Two points on A and one or two points on B. + m_type = e_faceA; + b2Vec2 localPointA1 = m_proxyA->GetVertex(cache->indexA[0]); + b2Vec2 localPointA2 = m_proxyA->GetVertex(cache->indexA[1]); + + m_axis = b2Cross(localPointA2 - localPointA1, 1.0f); + m_axis.Normalize(); + b2Vec2 normal = b2Mul(xfA.q, m_axis); + + m_localPoint = 0.5f * (localPointA1 + localPointA2); + b2Vec2 pointA = b2Mul(xfA, m_localPoint); + + b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]); + b2Vec2 pointB = b2Mul(xfB, localPointB); + + float32 s = b2Dot(pointB - pointA, normal); + if (s < 0.0f) + { + m_axis = -m_axis; + s = -s; + } + return s; + } + } + + float32 FindMinSeparation(int32* indexA, int32* indexB, float32 t) const + { + b2Transform xfA, xfB; + m_sweepA.GetTransform(&xfA, t); + m_sweepB.GetTransform(&xfB, t); + + switch (m_type) + { + case e_points: + { + b2Vec2 axisA = b2MulT(xfA.q, m_axis); + b2Vec2 axisB = b2MulT(xfB.q, -m_axis); + + *indexA = m_proxyA->GetSupport(axisA); + *indexB = m_proxyB->GetSupport(axisB); + + b2Vec2 localPointA = m_proxyA->GetVertex(*indexA); + b2Vec2 localPointB = m_proxyB->GetVertex(*indexB); + + b2Vec2 pointA = b2Mul(xfA, localPointA); + b2Vec2 pointB = b2Mul(xfB, localPointB); + + float32 separation = b2Dot(pointB - pointA, m_axis); + return separation; + } + + case e_faceA: + { + b2Vec2 normal = b2Mul(xfA.q, m_axis); + b2Vec2 pointA = b2Mul(xfA, m_localPoint); + + b2Vec2 axisB = b2MulT(xfB.q, -normal); + + *indexA = -1; + *indexB = m_proxyB->GetSupport(axisB); + + b2Vec2 localPointB = m_proxyB->GetVertex(*indexB); + b2Vec2 pointB = b2Mul(xfB, localPointB); + + float32 separation = b2Dot(pointB - pointA, normal); + return separation; + } + + case e_faceB: + { + b2Vec2 normal = b2Mul(xfB.q, m_axis); + b2Vec2 pointB = b2Mul(xfB, m_localPoint); + + b2Vec2 axisA = b2MulT(xfA.q, -normal); + + *indexB = -1; + *indexA = m_proxyA->GetSupport(axisA); + + b2Vec2 localPointA = m_proxyA->GetVertex(*indexA); + b2Vec2 pointA = b2Mul(xfA, localPointA); + + float32 separation = b2Dot(pointA - pointB, normal); + return separation; + } + + default: + b2Assert(false); + *indexA = -1; + *indexB = -1; + return 0.0f; + } + } + + float32 Evaluate(int32 indexA, int32 indexB, float32 t) const + { + b2Transform xfA, xfB; + m_sweepA.GetTransform(&xfA, t); + m_sweepB.GetTransform(&xfB, t); + + switch (m_type) + { + case e_points: + { + b2Vec2 axisA = b2MulT(xfA.q, m_axis); + b2Vec2 axisB = b2MulT(xfB.q, -m_axis); + + b2Vec2 localPointA = m_proxyA->GetVertex(indexA); + b2Vec2 localPointB = m_proxyB->GetVertex(indexB); + + b2Vec2 pointA = b2Mul(xfA, localPointA); + b2Vec2 pointB = b2Mul(xfB, localPointB); + float32 separation = b2Dot(pointB - pointA, m_axis); + + return separation; + } + + case e_faceA: + { + b2Vec2 normal = b2Mul(xfA.q, m_axis); + b2Vec2 pointA = b2Mul(xfA, m_localPoint); + + b2Vec2 axisB = b2MulT(xfB.q, -normal); + + b2Vec2 localPointB = m_proxyB->GetVertex(indexB); + b2Vec2 pointB = b2Mul(xfB, localPointB); + + float32 separation = b2Dot(pointB - pointA, normal); + return separation; + } + + case e_faceB: + { + b2Vec2 normal = b2Mul(xfB.q, m_axis); + b2Vec2 pointB = b2Mul(xfB, m_localPoint); + + b2Vec2 axisA = b2MulT(xfA.q, -normal); + + b2Vec2 localPointA = m_proxyA->GetVertex(indexA); + b2Vec2 pointA = b2Mul(xfA, localPointA); + + float32 separation = b2Dot(pointA - pointB, normal); + return separation; + } + + default: + b2Assert(false); + return 0.0f; + } + } + + const b2DistanceProxy* m_proxyA; + const b2DistanceProxy* m_proxyB; + b2Sweep m_sweepA, m_sweepB; + Type m_type; + b2Vec2 m_localPoint; + b2Vec2 m_axis; +}; + +// CCD via the local separating axis method. This seeks progression +// by computing the largest time at which separation is maintained. +void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input) +{ + ++b2_toiCalls; + + output->state = b2TOIOutput::e_unknown; + output->t = input->tMax; + + const b2DistanceProxy* proxyA = &input->proxyA; + const b2DistanceProxy* proxyB = &input->proxyB; + + b2Sweep sweepA = input->sweepA; + b2Sweep sweepB = input->sweepB; + + // Large rotations can make the root finder fail, so we normalize the + // sweep angles. + sweepA.Normalize(); + sweepB.Normalize(); + + float32 tMax = input->tMax; + + float32 totalRadius = proxyA->m_radius + proxyB->m_radius; + float32 target = b2Max(b2_linearSlop, totalRadius - 3.0f * b2_linearSlop); + float32 tolerance = 0.25f * b2_linearSlop; + b2Assert(target > tolerance); + + float32 t1 = 0.0f; + const int32 k_maxIterations = 20; // TODO_ERIN b2Settings + int32 iter = 0; + + // Prepare input for distance query. + b2SimplexCache cache; + cache.count = 0; + b2DistanceInput distanceInput; + distanceInput.proxyA = input->proxyA; + distanceInput.proxyB = input->proxyB; + distanceInput.useRadii = false; + + // The outer loop progressively attempts to compute new separating axes. + // This loop terminates when an axis is repeated (no progress is made). + for(;;) + { + b2Transform xfA, xfB; + sweepA.GetTransform(&xfA, t1); + sweepB.GetTransform(&xfB, t1); + + // Get the distance between shapes. We can also use the results + // to get a separating axis. + distanceInput.transformA = xfA; + distanceInput.transformB = xfB; + b2DistanceOutput distanceOutput; + b2Distance(&distanceOutput, &cache, &distanceInput); + + // If the shapes are overlapped, we give up on continuous collision. + if (distanceOutput.distance <= 0.0f) + { + // Failure! + output->state = b2TOIOutput::e_overlapped; + output->t = 0.0f; + break; + } + + if (distanceOutput.distance < target + tolerance) + { + // Victory! + output->state = b2TOIOutput::e_touching; + output->t = t1; + break; + } + + // Initialize the separating axis. + b2SeparationFunction fcn; + fcn.Initialize(&cache, proxyA, sweepA, proxyB, sweepB, t1); +#if 0 + // Dump the curve seen by the root finder + { + const int32 N = 100; + float32 dx = 1.0f / N; + float32 xs[N+1]; + float32 fs[N+1]; + + float32 x = 0.0f; + + for (int32 i = 0; i <= N; ++i) + { + sweepA.GetTransform(&xfA, x); + sweepB.GetTransform(&xfB, x); + float32 f = fcn.Evaluate(xfA, xfB) - target; + + printf("%g %g\n", x, f); + + xs[i] = x; + fs[i] = f; + + x += dx; + } + } +#endif + + // Compute the TOI on the separating axis. We do this by successively + // resolving the deepest point. This loop is bounded by the number of vertices. + bool done = false; + float32 t2 = tMax; + int32 pushBackIter = 0; + for (;;) + { + // Find the deepest point at t2. Store the witness point indices. + int32 indexA, indexB; + float32 s2 = fcn.FindMinSeparation(&indexA, &indexB, t2); + + // Is the final configuration separated? + if (s2 > target + tolerance) + { + // Victory! + output->state = b2TOIOutput::e_separated; + output->t = tMax; + done = true; + break; + } + + // Has the separation reached tolerance? + if (s2 > target - tolerance) + { + // Advance the sweeps + t1 = t2; + break; + } + + // Compute the initial separation of the witness points. + float32 s1 = fcn.Evaluate(indexA, indexB, t1); + + // Check for initial overlap. This might happen if the root finder + // runs out of iterations. + if (s1 < target - tolerance) + { + output->state = b2TOIOutput::e_failed; + output->t = t1; + done = true; + break; + } + + // Check for touching + if (s1 <= target + tolerance) + { + // Victory! t1 should hold the TOI (could be 0.0). + output->state = b2TOIOutput::e_touching; + output->t = t1; + done = true; + break; + } + + // Compute 1D root of: f(x) - target = 0 + int32 rootIterCount = 0; + float32 a1 = t1, a2 = t2; + for (;;) + { + // Use a mix of the secant rule and bisection. + float32 t; + if (rootIterCount & 1) + { + // Secant rule to improve convergence. + t = a1 + (target - s1) * (a2 - a1) / (s2 - s1); + } + else + { + // Bisection to guarantee progress. + t = 0.5f * (a1 + a2); + } + + float32 s = fcn.Evaluate(indexA, indexB, t); + + if (b2Abs(s - target) < tolerance) + { + // t2 holds a tentative value for t1 + t2 = t; + break; + } + + // Ensure we continue to bracket the root. + if (s > target) + { + a1 = t; + s1 = s; + } + else + { + a2 = t; + s2 = s; + } + + ++rootIterCount; + ++b2_toiRootIters; + + if (rootIterCount == 50) + { + break; + } + } + + b2_toiMaxRootIters = b2Max(b2_toiMaxRootIters, rootIterCount); + + ++pushBackIter; + + if (pushBackIter == b2_maxPolygonVertices) + { + break; + } + } + + ++iter; + ++b2_toiIters; + + if (done) + { + break; + } + + if (iter == k_maxIterations) + { + // Root finder got stuck. Semi-victory. + output->state = b2TOIOutput::e_failed; + output->t = t1; + break; + } + } + + b2_toiMaxIters = b2Max(b2_toiMaxIters, iter); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2TimeOfImpact.h b/tests/Box2D_v2.2.1/Box2D/Collision/b2TimeOfImpact.h new file mode 100755 index 0000000000000..179a1700ec121 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Collision/b2TimeOfImpact.h @@ -0,0 +1,58 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_TIME_OF_IMPACT_H +#define B2_TIME_OF_IMPACT_H + +#include +#include + +/// Input parameters for b2TimeOfImpact +struct b2TOIInput +{ + b2DistanceProxy proxyA; + b2DistanceProxy proxyB; + b2Sweep sweepA; + b2Sweep sweepB; + float32 tMax; // defines sweep interval [0, tMax] +}; + +// Output parameters for b2TimeOfImpact. +struct b2TOIOutput +{ + enum State + { + e_unknown, + e_failed, + e_overlapped, + e_touching, + e_separated + }; + + State state; + float32 t; +}; + +/// Compute the upper bound on time before two shapes penetrate. Time is represented as +/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, +/// non-tunneling collision. If you change the time interval, you should call this function +/// again. +/// Note: use b2Distance to compute the contact point and normal at the time of impact. +void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input); + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2BlockAllocator.cpp b/tests/Box2D_v2.2.1/Box2D/Common/b2BlockAllocator.cpp new file mode 100755 index 0000000000000..f5060daa2a80f --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Common/b2BlockAllocator.cpp @@ -0,0 +1,217 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include +using namespace std; + +int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] = +{ + 16, // 0 + 32, // 1 + 64, // 2 + 96, // 3 + 128, // 4 + 160, // 5 + 192, // 6 + 224, // 7 + 256, // 8 + 320, // 9 + 384, // 10 + 448, // 11 + 512, // 12 + 640, // 13 +}; +uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1]; +bool b2BlockAllocator::s_blockSizeLookupInitialized; + +struct b2Chunk +{ + int32 blockSize; + b2Block* blocks; +}; + +struct b2Block +{ + b2Block* next; +}; + +b2BlockAllocator::b2BlockAllocator() +{ + b2Assert(b2_blockSizes < UCHAR_MAX); + + m_chunkSpace = b2_chunkArrayIncrement; + m_chunkCount = 0; + m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); + + memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); + memset(m_freeLists, 0, sizeof(m_freeLists)); + + if (s_blockSizeLookupInitialized == false) + { + int32 j = 0; + for (int32 i = 1; i <= b2_maxBlockSize; ++i) + { + b2Assert(j < b2_blockSizes); + if (i <= s_blockSizes[j]) + { + s_blockSizeLookup[i] = (uint8)j; + } + else + { + ++j; + s_blockSizeLookup[i] = (uint8)j; + } + } + + s_blockSizeLookupInitialized = true; + } +} + +b2BlockAllocator::~b2BlockAllocator() +{ + for (int32 i = 0; i < m_chunkCount; ++i) + { + b2Free(m_chunks[i].blocks); + } + + b2Free(m_chunks); +} + +void* b2BlockAllocator::Allocate(int32 size) +{ + if (size == 0) + return NULL; + + b2Assert(0 < size); + + if (size > b2_maxBlockSize) + { + return b2Alloc(size); + } + + int32 index = s_blockSizeLookup[size]; + b2Assert(0 <= index && index < b2_blockSizes); + + if (m_freeLists[index]) + { + b2Block* block = m_freeLists[index]; + m_freeLists[index] = block->next; + return block; + } + else + { + if (m_chunkCount == m_chunkSpace) + { + b2Chunk* oldChunks = m_chunks; + m_chunkSpace += b2_chunkArrayIncrement; + m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); + memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk)); + memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk)); + b2Free(oldChunks); + } + + b2Chunk* chunk = m_chunks + m_chunkCount; + chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize); +#if defined(_DEBUG) + memset(chunk->blocks, 0xcd, b2_chunkSize); +#endif + int32 blockSize = s_blockSizes[index]; + chunk->blockSize = blockSize; + int32 blockCount = b2_chunkSize / blockSize; + b2Assert(blockCount * blockSize <= b2_chunkSize); + for (int32 i = 0; i < blockCount - 1; ++i) + { + b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i); + b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1)); + block->next = next; + } + b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1)); + last->next = NULL; + + m_freeLists[index] = chunk->blocks->next; + ++m_chunkCount; + + return chunk->blocks; + } +} + +void b2BlockAllocator::Free(void* p, int32 size) +{ + if (size == 0) + { + return; + } + + b2Assert(0 < size); + + if (size > b2_maxBlockSize) + { + b2Free(p); + return; + } + + int32 index = s_blockSizeLookup[size]; + b2Assert(0 <= index && index < b2_blockSizes); + +#ifdef _DEBUG + // Verify the memory address and size is valid. + int32 blockSize = s_blockSizes[index]; + bool found = false; + for (int32 i = 0; i < m_chunkCount; ++i) + { + b2Chunk* chunk = m_chunks + i; + if (chunk->blockSize != blockSize) + { + b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks || + (int8*)chunk->blocks + b2_chunkSize <= (int8*)p); + } + else + { + if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize) + { + found = true; + } + } + } + + b2Assert(found); + + memset(p, 0xfd, blockSize); +#endif + + b2Block* block = (b2Block*)p; + block->next = m_freeLists[index]; + m_freeLists[index] = block; +} + +void b2BlockAllocator::Clear() +{ + for (int32 i = 0; i < m_chunkCount; ++i) + { + b2Free(m_chunks[i].blocks); + } + + m_chunkCount = 0; + memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); + + memset(m_freeLists, 0, sizeof(m_freeLists)); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2BlockAllocator.h b/tests/Box2D_v2.2.1/Box2D/Common/b2BlockAllocator.h new file mode 100755 index 0000000000000..8ba29a5e93acf --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Common/b2BlockAllocator.h @@ -0,0 +1,62 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_BLOCK_ALLOCATOR_H +#define B2_BLOCK_ALLOCATOR_H + +#include + +const int32 b2_chunkSize = 16 * 1024; +const int32 b2_maxBlockSize = 640; +const int32 b2_blockSizes = 14; +const int32 b2_chunkArrayIncrement = 128; + +struct b2Block; +struct b2Chunk; + +/// This is a small object allocator used for allocating small +/// objects that persist for more than one time step. +/// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp +class b2BlockAllocator +{ +public: + b2BlockAllocator(); + ~b2BlockAllocator(); + + /// Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize. + void* Allocate(int32 size); + + /// Free memory. This will use b2Free if the size is larger than b2_maxBlockSize. + void Free(void* p, int32 size); + + void Clear(); + +private: + + b2Chunk* m_chunks; + int32 m_chunkCount; + int32 m_chunkSpace; + + b2Block* m_freeLists[b2_blockSizes]; + + static int32 s_blockSizes[b2_blockSizes]; + static uint8 s_blockSizeLookup[b2_maxBlockSize + 1]; + static bool s_blockSizeLookupInitialized; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Draw.cpp b/tests/Box2D_v2.2.1/Box2D/Common/b2Draw.cpp new file mode 100755 index 0000000000000..327b580793de0 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Common/b2Draw.cpp @@ -0,0 +1,44 @@ +/* +* Copyright (c) 2011 Erin Catto http://box2d.org +* +* 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. +*/ + +#include + +b2Draw::b2Draw() +{ + m_drawFlags = 0; +} + +void b2Draw::SetFlags(uint32 flags) +{ + m_drawFlags = flags; +} + +uint32 b2Draw::GetFlags() const +{ + return m_drawFlags; +} + +void b2Draw::AppendFlags(uint32 flags) +{ + m_drawFlags |= flags; +} + +void b2Draw::ClearFlags(uint32 flags) +{ + m_drawFlags &= ~flags; +} diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Draw.h b/tests/Box2D_v2.2.1/Box2D/Common/b2Draw.h new file mode 100755 index 0000000000000..a27f335a8a471 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Common/b2Draw.h @@ -0,0 +1,85 @@ +/* +* Copyright (c) 2011 Erin Catto http://box2d.org +* +* 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. +*/ + +#include + +/// Color for debug drawing. Each value has the range [0,1]. +// emscripten - b2Color: rearrange member variables to be on separate lines +struct b2Color +{ + b2Color() {} + b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {} + void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; } + float32 r; + float32 g; + float32 b; +}; + +/// Implement and register this class with a b2World to provide debug drawing of physics +/// entities in your game. +// emscripten - b2Draw: make virtual functions non-pure +class b2Draw +{ +public: + b2Draw(); + + virtual ~b2Draw() {} + + enum + { + e_shapeBit = 0x0001, ///< draw shapes + e_jointBit = 0x0002, ///< draw joint connections + e_aabbBit = 0x0004, ///< draw axis aligned bounding boxes + e_pairBit = 0x0008, ///< draw broad-phase pairs + e_centerOfMassBit = 0x0010 ///< draw center of mass frame + }; + + /// Set the drawing flags. + void SetFlags(uint32 flags); + + /// Get the drawing flags. + uint32 GetFlags() const; + + /// Append flags to the current flags. + void AppendFlags(uint32 flags); + + /// Clear flags from the current flags. + void ClearFlags(uint32 flags); + + /// Draw a closed polygon provided in CCW order. + virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) {} + + /// Draw a solid closed polygon provided in CCW order. + virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) {} + + /// Draw a circle. + virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) {} + + /// Draw a solid circle. + virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) {} + + /// Draw a line segment. + virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) {} + + /// Draw a transform. Choose your own length scale. + /// @param xf a transform. + virtual void DrawTransform(const b2Transform& xf) {} + +protected: + uint32 m_drawFlags; +}; diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2GrowableStack.h b/tests/Box2D_v2.2.1/Box2D/Common/b2GrowableStack.h new file mode 100755 index 0000000000000..a36d3bbb71e70 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Common/b2GrowableStack.h @@ -0,0 +1,87 @@ +/* +* Copyright (c) 2010 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_GROWABLE_STACK_H +#define B2_GROWABLE_STACK_H +#include +#ifndef EM_NO_LIBCPP +#include +#endif + +/// This is a growable LIFO stack with an initial capacity of N. +/// If the stack size exceeds the initial capacity, the heap is used +/// to increase the size of the stack. +template +class b2GrowableStack +{ +public: + b2GrowableStack() + { + m_stack = m_array; + m_count = 0; + m_capacity = N; + } + + ~b2GrowableStack() + { + if (m_stack != m_array) + { + b2Free(m_stack); + m_stack = NULL; + } + } + + void Push(const T& element) + { + if (m_count == m_capacity) + { + T* old = m_stack; + m_capacity *= 2; + m_stack = (T*)b2Alloc(m_capacity * sizeof(T)); + std::memcpy(m_stack, old, m_count * sizeof(T)); + if (old != m_array) + { + b2Free(old); + } + } + + m_stack[m_count] = element; + ++m_count; + } + + T Pop() + { + b2Assert(m_count > 0); + --m_count; + return m_stack[m_count]; + } + + int32 GetCount() + { + return m_count; + } + +private: + T* m_stack; + T m_array[N]; + int32 m_count; + int32 m_capacity; +}; + + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Math.cpp b/tests/Box2D_v2.2.1/Box2D/Common/b2Math.cpp new file mode 100755 index 0000000000000..4974fe1871afc --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Common/b2Math.cpp @@ -0,0 +1,94 @@ +/* +* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include + +const b2Vec2 b2Vec2_zero(0.0f, 0.0f); + +/// Solve A * x = b, where b is a column vector. This is more efficient +/// than computing the inverse in one-shot cases. +b2Vec3 b2Mat33::Solve33(const b2Vec3& b) const +{ + float32 det = b2Dot(ex, b2Cross(ey, ez)); + if (det != 0.0f) + { + det = 1.0f / det; + } + b2Vec3 x; + x.x = det * b2Dot(b, b2Cross(ey, ez)); + x.y = det * b2Dot(ex, b2Cross(b, ez)); + x.z = det * b2Dot(ex, b2Cross(ey, b)); + return x; +} + +/// Solve A * x = b, where b is a column vector. This is more efficient +/// than computing the inverse in one-shot cases. +b2Vec2 b2Mat33::Solve22(const b2Vec2& b) const +{ + float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y; + float32 det = a11 * a22 - a12 * a21; + if (det != 0.0f) + { + det = 1.0f / det; + } + b2Vec2 x; + x.x = det * (a22 * b.x - a12 * b.y); + x.y = det * (a11 * b.y - a21 * b.x); + return x; +} + +/// +void b2Mat33::GetInverse22(b2Mat33* M) const +{ + float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y; + float32 det = a * d - b * c; + if (det != 0.0f) + { + det = 1.0f / det; + } + + M->ex.x = det * d; M->ey.x = -det * b; M->ex.z = 0.0f; + M->ex.y = -det * c; M->ey.y = det * a; M->ey.z = 0.0f; + M->ez.x = 0.0f; M->ez.y = 0.0f; M->ez.z = 0.0f; +} + +/// Returns the zero matrix if singular. +void b2Mat33::GetSymInverse33(b2Mat33* M) const +{ + float32 det = b2Dot(ex, b2Cross(ey, ez)); + if (det != 0.0f) + { + det = 1.0f / det; + } + + float32 a11 = ex.x, a12 = ey.x, a13 = ez.x; + float32 a22 = ey.y, a23 = ez.y; + float32 a33 = ez.z; + + M->ex.x = det * (a22 * a33 - a23 * a23); + M->ex.y = det * (a13 * a23 - a12 * a33); + M->ex.z = det * (a12 * a23 - a13 * a22); + + M->ey.x = M->ex.y; + M->ey.y = det * (a11 * a33 - a13 * a13); + M->ey.z = det * (a13 * a12 - a11 * a23); + + M->ez.x = M->ex.z; + M->ez.y = M->ey.z; + M->ez.z = det * (a11 * a22 - a12 * a12); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Math.h b/tests/Box2D_v2.2.1/Box2D/Common/b2Math.h new file mode 100755 index 0000000000000..84382a6f73504 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Common/b2Math.h @@ -0,0 +1,739 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_MATH_H +#define B2_MATH_H + +#include + +#ifdef EM_NO_LIBCPP +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif + +/// This function is used to ensure that a floating point number is +/// not a NaN or infinity. +inline bool b2IsValid(float32 x) +{ + if (x != x) + { + // NaN. + return false; + } + + float32 infinity = std::numeric_limits::infinity(); + return -infinity < x && x < infinity; +} + +/// This is a approximate yet fast inverse square-root. +inline float32 b2InvSqrt(float32 x) +{ + union + { + float32 x; + int32 i; + } convert; + + convert.x = x; + float32 xhalf = 0.5f * x; + convert.i = 0x5f3759df - (convert.i >> 1); + x = convert.x; + x = x * (1.5f - xhalf * x * x); + return x; +} + +#define b2Sqrt(x) std::sqrt(x) +#define b2Atan2(y, x) std::atan2(y, x) + +/// A 2D column vector. +struct b2Vec2 +{ + /// Default constructor does nothing (for performance). + b2Vec2() {} + + /// Construct using coordinates. + b2Vec2(float32 x, float32 y) : x(x), y(y) {} + + /// Set this vector to all zeros. + void SetZero() { x = 0.0f; y = 0.0f; } + + /// Set this vector to some specified coordinates. + void Set(float32 x_, float32 y_) { x = x_; y = y_; } + + /// Negate this vector. + b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; } + + /// Read from and indexed element. + float32 operator () (int32 i) const + { + return (&x)[i]; + } + + /// Write to an indexed element. + float32& operator () (int32 i) + { + return (&x)[i]; + } + + /// Add a vector to this vector. + void operator += (const b2Vec2& v) + { + x += v.x; y += v.y; + } + + /// Subtract a vector from this vector. + void operator -= (const b2Vec2& v) + { + x -= v.x; y -= v.y; + } + + /// Multiply this vector by a scalar. + void operator *= (float32 a) + { + x *= a; y *= a; + } + + /// Get the length of this vector (the norm). + float32 Length() const + { + return b2Sqrt(x * x + y * y); + } + + /// Get the length squared. For performance, use this instead of + /// b2Vec2::Length (if possible). + float32 LengthSquared() const + { + return x * x + y * y; + } + + /// Convert this vector into a unit vector. Returns the length. + float32 Normalize() + { + float32 length = Length(); + if (length < b2_epsilon) + { + return 0.0f; + } + float32 invLength = 1.0f / length; + x *= invLength; + y *= invLength; + + return length; + } + + /// Does this vector contain finite coordinates? + bool IsValid() const + { + return b2IsValid(x) && b2IsValid(y); + } + + /// Get the skew vector such that dot(skew_vec, other) == cross(vec, other) + b2Vec2 Skew() const + { + return b2Vec2(-y, x); + } + + float32 x; + float32 y; +}; + +/// A 2D column vector with 3 elements. +struct b2Vec3 +{ + /// Default constructor does nothing (for performance). + b2Vec3() {} + + /// Construct using coordinates. + b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {} + + /// Set this vector to all zeros. + void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; } + + /// Set this vector to some specified coordinates. + void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; } + + /// Negate this vector. + b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; } + + /// Add a vector to this vector. + void operator += (const b2Vec3& v) + { + x += v.x; y += v.y; z += v.z; + } + + /// Subtract a vector from this vector. + void operator -= (const b2Vec3& v) + { + x -= v.x; y -= v.y; z -= v.z; + } + + /// Multiply this vector by a scalar. + void operator *= (float32 s) + { + x *= s; y *= s; z *= s; + } + + float32 x, y, z; +}; + +/// A 2-by-2 matrix. Stored in column-major order. +struct b2Mat22 +{ + /// The default constructor does nothing (for performance). + b2Mat22() {} + + /// Construct this matrix using columns. + b2Mat22(const b2Vec2& c1, const b2Vec2& c2) + { + ex = c1; + ey = c2; + } + + /// Construct this matrix using scalars. + b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22) + { + ex.x = a11; ex.y = a21; + ey.x = a12; ey.y = a22; + } + + /// Initialize this matrix using columns. + void Set(const b2Vec2& c1, const b2Vec2& c2) + { + ex = c1; + ey = c2; + } + + /// Set this to the identity matrix. + void SetIdentity() + { + ex.x = 1.0f; ey.x = 0.0f; + ex.y = 0.0f; ey.y = 1.0f; + } + + /// Set this matrix to all zeros. + void SetZero() + { + ex.x = 0.0f; ey.x = 0.0f; + ex.y = 0.0f; ey.y = 0.0f; + } + + b2Mat22 GetInverse() const + { + float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y; + b2Mat22 B; + float32 det = a * d - b * c; + if (det != 0.0f) + { + det = 1.0f / det; + } + B.ex.x = det * d; B.ey.x = -det * b; + B.ex.y = -det * c; B.ey.y = det * a; + return B; + } + + /// Solve A * x = b, where b is a column vector. This is more efficient + /// than computing the inverse in one-shot cases. + b2Vec2 Solve(const b2Vec2& b) const + { + float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y; + float32 det = a11 * a22 - a12 * a21; + if (det != 0.0f) + { + det = 1.0f / det; + } + b2Vec2 x; + x.x = det * (a22 * b.x - a12 * b.y); + x.y = det * (a11 * b.y - a21 * b.x); + return x; + } + + b2Vec2 ex, ey; +}; + +/// A 3-by-3 matrix. Stored in column-major order. +struct b2Mat33 +{ + /// The default constructor does nothing (for performance). + b2Mat33() {} + + /// Construct this matrix using columns. + b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3) + { + ex = c1; + ey = c2; + ez = c3; + } + + /// Set this matrix to all zeros. + void SetZero() + { + ex.SetZero(); + ey.SetZero(); + ez.SetZero(); + } + + /// Solve A * x = b, where b is a column vector. This is more efficient + /// than computing the inverse in one-shot cases. + b2Vec3 Solve33(const b2Vec3& b) const; + + /// Solve A * x = b, where b is a column vector. This is more efficient + /// than computing the inverse in one-shot cases. Solve only the upper + /// 2-by-2 matrix equation. + b2Vec2 Solve22(const b2Vec2& b) const; + + /// Get the inverse of this matrix as a 2-by-2. + /// Returns the zero matrix if singular. + void GetInverse22(b2Mat33* M) const; + + /// Get the symmetric inverse of this matrix as a 3-by-3. + /// Returns the zero matrix if singular. + void GetSymInverse33(b2Mat33* M) const; + + b2Vec3 ex, ey, ez; +}; + +/// Rotation +struct b2Rot +{ + b2Rot() {} + + /// Initialize from an angle in radians + explicit b2Rot(float32 angle) + { + /// TODO_ERIN optimize + s = sinf(angle); + c = cosf(angle); + } + + /// Set using an angle in radians. + void Set(float32 angle) + { + /// TODO_ERIN optimize + s = sinf(angle); + c = cosf(angle); + } + + /// Set to the identity rotation + void SetIdentity() + { + s = 0.0f; + c = 1.0f; + } + + /// Get the angle in radians + float32 GetAngle() const + { + return b2Atan2(s, c); + } + + /// Get the x-axis + b2Vec2 GetXAxis() const + { + return b2Vec2(c, s); + } + + /// Get the u-axis + b2Vec2 GetYAxis() const + { + return b2Vec2(-s, c); + } + + /// Sine and cosine + float32 s, c; +}; + +/// A transform contains translation and rotation. It is used to represent +/// the position and orientation of rigid frames. +struct b2Transform +{ + /// The default constructor does nothing. + b2Transform() {} + + /// Initialize using a position vector and a rotation. + b2Transform(const b2Vec2& position, const b2Rot& rotation) : p(position), q(rotation) {} + + /// Set this to the identity transform. + void SetIdentity() + { + p.SetZero(); + q.SetIdentity(); + } + + /// Set this based on the position and angle. + void Set(const b2Vec2& position, float32 angle) + { + p = position; + q.Set(angle); + } + + b2Vec2 p; + b2Rot q; +}; + +/// This describes the motion of a body/shape for TOI computation. +/// Shapes are defined with respect to the body origin, which may +/// no coincide with the center of mass. However, to support dynamics +/// we must interpolate the center of mass position. +struct b2Sweep +{ + /// Get the interpolated transform at a specific time. + /// @param beta is a factor in [0,1], where 0 indicates alpha0. + void GetTransform(b2Transform* xfb, float32 beta) const; + + /// Advance the sweep forward, yielding a new initial state. + /// @param alpha the new initial time. + void Advance(float32 alpha); + + /// Normalize the angles. + void Normalize(); + + b2Vec2 localCenter; ///< local center of mass position + b2Vec2 c0, c; ///< center world positions + float32 a0, a; ///< world angles + + /// Fraction of the current time step in the range [0,1] + /// c0 and a0 are the positions at alpha0. + float32 alpha0; +}; + +/// Useful constant +extern const b2Vec2 b2Vec2_zero; + +/// Perform the dot product on two vectors. +inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b) +{ + return a.x * b.x + a.y * b.y; +} + +/// Perform the cross product on two vectors. In 2D this produces a scalar. +inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b) +{ + return a.x * b.y - a.y * b.x; +} + +/// Perform the cross product on a vector and a scalar. In 2D this produces +/// a vector. +inline b2Vec2 b2Cross(const b2Vec2& a, float32 s) +{ + return b2Vec2(s * a.y, -s * a.x); +} + +/// Perform the cross product on a scalar and a vector. In 2D this produces +/// a vector. +inline b2Vec2 b2Cross(float32 s, const b2Vec2& a) +{ + return b2Vec2(-s * a.y, s * a.x); +} + +/// Multiply a matrix times a vector. If a rotation matrix is provided, +/// then this transforms the vector from one frame to another. +inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v) +{ + return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y); +} + +/// Multiply a matrix transpose times a vector. If a rotation matrix is provided, +/// then this transforms the vector from one frame to another (inverse transform). +inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v) +{ + return b2Vec2(b2Dot(v, A.ex), b2Dot(v, A.ey)); +} + +/// Add two vectors component-wise. +inline b2Vec2 operator + (const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(a.x + b.x, a.y + b.y); +} + +/// Subtract two vectors component-wise. +inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(a.x - b.x, a.y - b.y); +} + +inline b2Vec2 operator * (float32 s, const b2Vec2& a) +{ + return b2Vec2(s * a.x, s * a.y); +} + +inline bool operator == (const b2Vec2& a, const b2Vec2& b) +{ + return a.x == b.x && a.y == b.y; +} + +inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b) +{ + b2Vec2 c = a - b; + return c.Length(); +} + +inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b) +{ + b2Vec2 c = a - b; + return b2Dot(c, c); +} + +inline b2Vec3 operator * (float32 s, const b2Vec3& a) +{ + return b2Vec3(s * a.x, s * a.y, s * a.z); +} + +/// Add two vectors component-wise. +inline b2Vec3 operator + (const b2Vec3& a, const b2Vec3& b) +{ + return b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z); +} + +/// Subtract two vectors component-wise. +inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b) +{ + return b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z); +} + +/// Perform the dot product on two vectors. +inline float32 b2Dot(const b2Vec3& a, const b2Vec3& b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} + +/// Perform the cross product on two vectors. +inline b2Vec3 b2Cross(const b2Vec3& a, const b2Vec3& b) +{ + return b2Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); +} + +inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B) +{ + return b2Mat22(A.ex + B.ex, A.ey + B.ey); +} + +// A * B +inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B) +{ + return b2Mat22(b2Mul(A, B.ex), b2Mul(A, B.ey)); +} + +// A^T * B +inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B) +{ + b2Vec2 c1(b2Dot(A.ex, B.ex), b2Dot(A.ey, B.ex)); + b2Vec2 c2(b2Dot(A.ex, B.ey), b2Dot(A.ey, B.ey)); + return b2Mat22(c1, c2); +} + +/// Multiply a matrix times a vector. +inline b2Vec3 b2Mul(const b2Mat33& A, const b2Vec3& v) +{ + return v.x * A.ex + v.y * A.ey + v.z * A.ez; +} + +/// Multiply a matrix times a vector. +inline b2Vec2 b2Mul22(const b2Mat33& A, const b2Vec2& v) +{ + return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y); +} + +/// Multiply two rotations: q * r +inline b2Rot b2Mul(const b2Rot& q, const b2Rot& r) +{ + // [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc] + // [qs qc] [rs rc] [qs*rc+qc*rs -qs*rs+qc*rc] + // s = qs * rc + qc * rs + // c = qc * rc - qs * rs + b2Rot qr; + qr.s = q.s * r.c + q.c * r.s; + qr.c = q.c * r.c - q.s * r.s; + return qr; +} + +/// Transpose multiply two rotations: qT * r +inline b2Rot b2MulT(const b2Rot& q, const b2Rot& r) +{ + // [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc] + // [-qs qc] [rs rc] [-qs*rc+qc*rs qs*rs+qc*rc] + // s = qc * rs - qs * rc + // c = qc * rc + qs * rs + b2Rot qr; + qr.s = q.c * r.s - q.s * r.c; + qr.c = q.c * r.c + q.s * r.s; + return qr; +} + +/// Rotate a vector +inline b2Vec2 b2Mul(const b2Rot& q, const b2Vec2& v) +{ + return b2Vec2(q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y); +} + +/// Inverse rotate a vector +inline b2Vec2 b2MulT(const b2Rot& q, const b2Vec2& v) +{ + return b2Vec2(q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y); +} + +inline b2Vec2 b2Mul(const b2Transform& T, const b2Vec2& v) +{ + float32 x = (T.q.c * v.x - T.q.s * v.y) + T.p.x; + float32 y = (T.q.s * v.x + T.q.c * v.y) + T.p.y; + + return b2Vec2(x, y); +} + +inline b2Vec2 b2MulT(const b2Transform& T, const b2Vec2& v) +{ + float32 px = v.x - T.p.x; + float32 py = v.y - T.p.y; + float32 x = (T.q.c * px + T.q.s * py); + float32 y = (-T.q.s * px + T.q.c * py); + + return b2Vec2(x, y); +} + +// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p +// = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p +inline b2Transform b2Mul(const b2Transform& A, const b2Transform& B) +{ + b2Transform C; + C.q = b2Mul(A.q, B.q); + C.p = b2Mul(A.q, B.p) + A.p; + return C; +} + +// v2 = A.q' * (B.q * v1 + B.p - A.p) +// = A.q' * B.q * v1 + A.q' * (B.p - A.p) +inline b2Transform b2MulT(const b2Transform& A, const b2Transform& B) +{ + b2Transform C; + C.q = b2MulT(A.q, B.q); + C.p = b2MulT(A.q, B.p - A.p); + return C; +} + +template +inline T b2Abs(T a) +{ + return a > T(0) ? a : -a; +} + +inline b2Vec2 b2Abs(const b2Vec2& a) +{ + return b2Vec2(b2Abs(a.x), b2Abs(a.y)); +} + +inline b2Mat22 b2Abs(const b2Mat22& A) +{ + return b2Mat22(b2Abs(A.ex), b2Abs(A.ey)); +} + +template +inline T b2Min(T a, T b) +{ + return a < b ? a : b; +} + +inline b2Vec2 b2Min(const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(b2Min(a.x, b.x), b2Min(a.y, b.y)); +} + +template +inline T b2Max(T a, T b) +{ + return a > b ? a : b; +} + +inline b2Vec2 b2Max(const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(b2Max(a.x, b.x), b2Max(a.y, b.y)); +} + +template +inline T b2Clamp(T a, T low, T high) +{ + return b2Max(low, b2Min(a, high)); +} + +inline b2Vec2 b2Clamp(const b2Vec2& a, const b2Vec2& low, const b2Vec2& high) +{ + return b2Max(low, b2Min(a, high)); +} + +template inline void b2Swap(T& a, T& b) +{ + T tmp = a; + a = b; + b = tmp; +} + +/// "Next Largest Power of 2 +/// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm +/// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with +/// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next +/// largest power of 2. For a 32-bit value:" +inline uint32 b2NextPowerOfTwo(uint32 x) +{ + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return x + 1; +} + +inline bool b2IsPowerOfTwo(uint32 x) +{ + bool result = x > 0 && (x & (x - 1)) == 0; + return result; +} + +inline void b2Sweep::GetTransform(b2Transform* xf, float32 beta) const +{ + xf->p = (1.0f - beta) * c0 + beta * c; + float32 angle = (1.0f - beta) * a0 + beta * a; + xf->q.Set(angle); + + // Shift to origin + xf->p -= b2Mul(xf->q, localCenter); +} + +inline void b2Sweep::Advance(float32 alpha) +{ + b2Assert(alpha0 < 1.0f); + float32 beta = (alpha - alpha0) / (1.0f - alpha0); + c0 = (1.0f - beta) * c0 + beta * c; + a0 = (1.0f - beta) * a0 + beta * a; + alpha0 = alpha; +} + +/// Normalize an angle in radians to be between -pi and pi +inline void b2Sweep::Normalize() +{ + float32 twoPi = 2.0f * b2_pi; + float32 d = twoPi * floorf(a0 / twoPi); + a0 -= d; + a -= d; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Settings.cpp b/tests/Box2D_v2.2.1/Box2D/Common/b2Settings.cpp new file mode 100755 index 0000000000000..05a322305746e --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Common/b2Settings.cpp @@ -0,0 +1,44 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include + +b2Version b2_version = {2, 2, 1}; + +// Memory allocators. Modify these to use your own allocator. +void* b2Alloc(int32 size) +{ + return malloc(size); +} + +void b2Free(void* mem) +{ + free(mem); +} + +// You can modify this to use your logging facility. +void b2Log(const char* string, ...) +{ + va_list args; + va_start(args, string); + vprintf(string, args); + va_end(args); +} \ No newline at end of file diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Settings.h b/tests/Box2D_v2.2.1/Box2D/Common/b2Settings.h new file mode 100755 index 0000000000000..391b6f843cbea --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Common/b2Settings.h @@ -0,0 +1,155 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_SETTINGS_H +#define B2_SETTINGS_H + +#ifdef EM_NO_LIBCPP +#include +#include +#else +#include +#include +#endif + +#define B2_NOT_USED(x) ((void)(x)) +#define b2Assert(A) assert(A) + +typedef signed char int8; +typedef signed short int16; +typedef signed int int32; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef float float32; +typedef double float64; + +#define b2_maxFloat FLT_MAX +#define b2_epsilon FLT_EPSILON +#define b2_pi 3.14159265359f + +/// @file +/// Global tuning constants based on meters-kilograms-seconds (MKS) units. +/// + +// Collision + +/// The maximum number of contact points between two convex shapes. Do +/// not change this value. +#define b2_maxManifoldPoints 2 + +/// The maximum number of vertices on a convex polygon. You cannot increase +/// this too much because b2BlockAllocator has a maximum object size. +#define b2_maxPolygonVertices 8 + +/// This is used to fatten AABBs in the dynamic tree. This allows proxies +/// to move by a small amount without triggering a tree adjustment. +/// This is in meters. +#define b2_aabbExtension 0.1f + +/// This is used to fatten AABBs in the dynamic tree. This is used to predict +/// the future position based on the current displacement. +/// This is a dimensionless multiplier. +#define b2_aabbMultiplier 2.0f + +/// A small length used as a collision and constraint tolerance. Usually it is +/// chosen to be numerically significant, but visually insignificant. +#define b2_linearSlop 0.005f + +/// A small angle used as a collision and constraint tolerance. Usually it is +/// chosen to be numerically significant, but visually insignificant. +#define b2_angularSlop (2.0f / 180.0f * b2_pi) + +/// The radius of the polygon/edge shape skin. This should not be modified. Making +/// this smaller means polygons will have an insufficient buffer for continuous collision. +/// Making it larger may create artifacts for vertex collision. +#define b2_polygonRadius (2.0f * b2_linearSlop) + +/// Maximum number of sub-steps per contact in continuous physics simulation. +#define b2_maxSubSteps 8 + + +// Dynamics + +/// Maximum number of contacts to be handled to solve a TOI impact. +#define b2_maxTOIContacts 32 + +/// A velocity threshold for elastic collisions. Any collision with a relative linear +/// velocity below this threshold will be treated as inelastic. +#define b2_velocityThreshold 1.0f + +/// The maximum linear position correction used when solving constraints. This helps to +/// prevent overshoot. +#define b2_maxLinearCorrection 0.2f + +/// The maximum angular position correction used when solving constraints. This helps to +/// prevent overshoot. +#define b2_maxAngularCorrection (8.0f / 180.0f * b2_pi) + +/// The maximum linear velocity of a body. This limit is very large and is used +/// to prevent numerical problems. You shouldn't need to adjust this. +#define b2_maxTranslation 2.0f +#define b2_maxTranslationSquared (b2_maxTranslation * b2_maxTranslation) + +/// The maximum angular velocity of a body. This limit is very large and is used +/// to prevent numerical problems. You shouldn't need to adjust this. +#define b2_maxRotation (0.5f * b2_pi) +#define b2_maxRotationSquared (b2_maxRotation * b2_maxRotation) + +/// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so +/// that overlap is removed in one time step. However using values close to 1 often lead +/// to overshoot. +#define b2_baumgarte 0.2f +#define b2_toiBaugarte 0.75f + + +// Sleep + +/// The time that a body must be still before it will go to sleep. +#define b2_timeToSleep 0.5f + +/// A body cannot sleep if its linear velocity is above this tolerance. +#define b2_linearSleepTolerance 0.01f + +/// A body cannot sleep if its angular velocity is above this tolerance. +#define b2_angularSleepTolerance (2.0f / 180.0f * b2_pi) + +// Memory Allocation + +/// Implement this function to use your own memory allocator. +void* b2Alloc(int32 size); + +/// If you implement b2Alloc, you should also implement this function. +void b2Free(void* mem); + +/// Logging function. +void b2Log(const char* string, ...); + +/// Version numbering scheme. +/// See http://en.wikipedia.org/wiki/Software_versioning +struct b2Version +{ + int32 major; ///< significant changes + int32 minor; ///< incremental changes + int32 revision; ///< bug fixes +}; + +/// Current version. +extern b2Version b2_version; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2StackAllocator.cpp b/tests/Box2D_v2.2.1/Box2D/Common/b2StackAllocator.cpp new file mode 100755 index 0000000000000..4a862835ba131 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Common/b2StackAllocator.cpp @@ -0,0 +1,83 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include + +b2StackAllocator::b2StackAllocator() +{ + m_index = 0; + m_allocation = 0; + m_maxAllocation = 0; + m_entryCount = 0; +} + +b2StackAllocator::~b2StackAllocator() +{ + b2Assert(m_index == 0); + b2Assert(m_entryCount == 0); +} + +void* b2StackAllocator::Allocate(int32 size) +{ + b2Assert(m_entryCount < b2_maxStackEntries); + + b2StackEntry* entry = m_entries + m_entryCount; + entry->size = size; + if (m_index + size > b2_stackSize) + { + entry->data = (char*)b2Alloc(size); + entry->usedMalloc = true; + } + else + { + entry->data = m_data + m_index; + entry->usedMalloc = false; + m_index += size; + } + + m_allocation += size; + m_maxAllocation = b2Max(m_maxAllocation, m_allocation); + ++m_entryCount; + + return entry->data; +} + +void b2StackAllocator::Free(void* p) +{ + b2Assert(m_entryCount > 0); + b2StackEntry* entry = m_entries + m_entryCount - 1; + b2Assert(p == entry->data); + if (entry->usedMalloc) + { + b2Free(p); + } + else + { + m_index -= entry->size; + } + m_allocation -= entry->size; + --m_entryCount; + + p = NULL; +} + +int32 b2StackAllocator::GetMaxAllocation() const +{ + return m_maxAllocation; +} diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2StackAllocator.h b/tests/Box2D_v2.2.1/Box2D/Common/b2StackAllocator.h new file mode 100755 index 0000000000000..796c51dfd589f --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Common/b2StackAllocator.h @@ -0,0 +1,60 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_STACK_ALLOCATOR_H +#define B2_STACK_ALLOCATOR_H + +#include + +const int32 b2_stackSize = 100 * 1024; // 100k +const int32 b2_maxStackEntries = 32; + +struct b2StackEntry +{ + char* data; + int32 size; + bool usedMalloc; +}; + +// This is a stack allocator used for fast per step allocations. +// You must nest allocate/free pairs. The code will assert +// if you try to interleave multiple allocate/free pairs. +class b2StackAllocator +{ +public: + b2StackAllocator(); + ~b2StackAllocator(); + + void* Allocate(int32 size); + void Free(void* p); + + int32 GetMaxAllocation() const; + +private: + + char m_data[b2_stackSize]; + int32 m_index; + + int32 m_allocation; + int32 m_maxAllocation; + + b2StackEntry m_entries[b2_maxStackEntries]; + int32 m_entryCount; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Timer.cpp b/tests/Box2D_v2.2.1/Box2D/Common/b2Timer.cpp new file mode 100755 index 0000000000000..ea3479f119793 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Common/b2Timer.cpp @@ -0,0 +1,100 @@ +/* +* Copyright (c) 2011 Erin Catto http://box2d.org +* +* 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. +*/ + +#include + +#if defined(_WIN32) + +float64 b2Timer::s_invFrequency = 0.0f; + +#include + +b2Timer::b2Timer() +{ + LARGE_INTEGER largeInteger; + + if (s_invFrequency == 0.0f) + { + QueryPerformanceFrequency(&largeInteger); + s_invFrequency = float64(largeInteger.QuadPart); + if (s_invFrequency > 0.0f) + { + s_invFrequency = 1000.0f / s_invFrequency; + } + } + + QueryPerformanceCounter(&largeInteger); + m_start = float64(largeInteger.QuadPart); +} + +void b2Timer::Reset() +{ + LARGE_INTEGER largeInteger; + QueryPerformanceCounter(&largeInteger); + m_start = float64(largeInteger.QuadPart); +} + +float32 b2Timer::GetMilliseconds() const +{ + LARGE_INTEGER largeInteger; + QueryPerformanceCounter(&largeInteger); + float64 count = float64(largeInteger.QuadPart); + float32 ms = float32(s_invFrequency * (count - m_start)); + return ms; +} + +#elif defined(__linux__) || defined (__APPLE__) + +#include + +b2Timer::b2Timer() +{ + Reset(); +} + +void b2Timer::Reset() +{ + timeval t; + gettimeofday(&t, 0); + m_start_sec = t.tv_sec; + m_start_msec = t.tv_usec * 0.001f; +} + +float32 b2Timer::GetMilliseconds() const +{ + timeval t; + gettimeofday(&t, 0); + return (t.tv_sec - m_start_sec) * 1000 + t.tv_usec * 0.001f - m_start_msec; +} + +#else + +b2Timer::b2Timer() +{ +} + +void b2Timer::Reset() +{ +} + +float32 b2Timer::GetMilliseconds() const +{ + return 0.0f; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Timer.h b/tests/Box2D_v2.2.1/Box2D/Common/b2Timer.h new file mode 100755 index 0000000000000..19bde287f8cce --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Common/b2Timer.h @@ -0,0 +1,45 @@ +/* +* Copyright (c) 2011 Erin Catto http://box2d.org +* +* 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. +*/ + +#include + +/// Timer for profiling. This has platform specific code and may +/// not work on every platform. +class b2Timer +{ +public: + + /// Constructor + b2Timer(); + + /// Reset the timer. + void Reset(); + + /// Get the time since construction or the last reset. + float32 GetMilliseconds() const; + +private: + +#if defined(_WIN32) + float64 m_start; + static float64 s_invFrequency; +#elif defined(__linux__) || defined (__APPLE__) + unsigned long m_start_sec; + unsigned long m_start_msec; +#endif +}; diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp new file mode 100755 index 0000000000000..3886dfd70bc3b --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2ChainAndCircleContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2ChainAndCircleContact)); + return new (mem) b2ChainAndCircleContact(fixtureA, indexA, fixtureB, indexB); +} + +void b2ChainAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2ChainAndCircleContact*)contact)->~b2ChainAndCircleContact(); + allocator->Free(contact, sizeof(b2ChainAndCircleContact)); +} + +b2ChainAndCircleContact::b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB) +: b2Contact(fixtureA, indexA, fixtureB, indexB) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_chain); + b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); +} + +void b2ChainAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape(); + b2EdgeShape edge; + chain->GetChildEdge(&edge, m_indexA); + b2CollideEdgeAndCircle( manifold, &edge, xfA, + (b2CircleShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h new file mode 100755 index 0000000000000..2dad0b64f36ce --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_CHAIN_AND_CIRCLE_CONTACT_H +#define B2_CHAIN_AND_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2ChainAndCircleContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); + ~b2ChainAndCircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp new file mode 100755 index 0000000000000..02bcaaf6ab988 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2ChainAndPolygonContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2ChainAndPolygonContact)); + return new (mem) b2ChainAndPolygonContact(fixtureA, indexA, fixtureB, indexB); +} + +void b2ChainAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2ChainAndPolygonContact*)contact)->~b2ChainAndPolygonContact(); + allocator->Free(contact, sizeof(b2ChainAndPolygonContact)); +} + +b2ChainAndPolygonContact::b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB) +: b2Contact(fixtureA, indexA, fixtureB, indexB) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_chain); + b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); +} + +void b2ChainAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape(); + b2EdgeShape edge; + chain->GetChildEdge(&edge, m_indexA); + b2CollideEdgeAndPolygon( manifold, &edge, xfA, + (b2PolygonShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h new file mode 100755 index 0000000000000..8f30ee86706fb --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_CHAIN_AND_POLYGON_CONTACT_H +#define B2_CHAIN_AND_POLYGON_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2ChainAndPolygonContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); + ~b2ChainAndPolygonContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2CircleContact.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2CircleContact.cpp new file mode 100755 index 0000000000000..584ef2f1f610b --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2CircleContact.cpp @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2CircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2CircleContact)); + return new (mem) b2CircleContact(fixtureA, fixtureB); +} + +void b2CircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2CircleContact*)contact)->~b2CircleContact(); + allocator->Free(contact, sizeof(b2CircleContact)); +} + +b2CircleContact::b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) + : b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_circle); + b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); +} + +void b2CircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollideCircles(manifold, + (b2CircleShape*)m_fixtureA->GetShape(), xfA, + (b2CircleShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2CircleContact.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2CircleContact.h new file mode 100755 index 0000000000000..aac1f0bd6b6ab --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2CircleContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_CIRCLE_CONTACT_H +#define B2_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2CircleContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2CircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2Contact.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2Contact.cpp new file mode 100755 index 0000000000000..557af7f08e473 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2Contact.cpp @@ -0,0 +1,240 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +b2ContactRegister b2Contact::s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount]; +bool b2Contact::s_initialized = false; + +void b2Contact::InitializeRegisters() +{ + AddType(b2CircleContact::Create, b2CircleContact::Destroy, b2Shape::e_circle, b2Shape::e_circle); + AddType(b2PolygonAndCircleContact::Create, b2PolygonAndCircleContact::Destroy, b2Shape::e_polygon, b2Shape::e_circle); + AddType(b2PolygonContact::Create, b2PolygonContact::Destroy, b2Shape::e_polygon, b2Shape::e_polygon); + AddType(b2EdgeAndCircleContact::Create, b2EdgeAndCircleContact::Destroy, b2Shape::e_edge, b2Shape::e_circle); + AddType(b2EdgeAndPolygonContact::Create, b2EdgeAndPolygonContact::Destroy, b2Shape::e_edge, b2Shape::e_polygon); + AddType(b2ChainAndCircleContact::Create, b2ChainAndCircleContact::Destroy, b2Shape::e_chain, b2Shape::e_circle); + AddType(b2ChainAndPolygonContact::Create, b2ChainAndPolygonContact::Destroy, b2Shape::e_chain, b2Shape::e_polygon); +} + +void b2Contact::AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destoryFcn, + b2Shape::Type type1, b2Shape::Type type2) +{ + b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount); + b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount); + + s_registers[type1][type2].createFcn = createFcn; + s_registers[type1][type2].destroyFcn = destoryFcn; + s_registers[type1][type2].primary = true; + + if (type1 != type2) + { + s_registers[type2][type1].createFcn = createFcn; + s_registers[type2][type1].destroyFcn = destoryFcn; + s_registers[type2][type1].primary = false; + } +} + +b2Contact* b2Contact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) +{ + if (s_initialized == false) + { + InitializeRegisters(); + s_initialized = true; + } + + b2Shape::Type type1 = fixtureA->GetType(); + b2Shape::Type type2 = fixtureB->GetType(); + + b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount); + b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount); + + b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn; + if (createFcn) + { + if (s_registers[type1][type2].primary) + { + return createFcn(fixtureA, indexA, fixtureB, indexB, allocator); + } + else + { + return createFcn(fixtureB, indexB, fixtureA, indexA, allocator); + } + } + else + { + return NULL; + } +} + +void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + b2Assert(s_initialized == true); + + if (contact->m_manifold.pointCount > 0) + { + contact->GetFixtureA()->GetBody()->SetAwake(true); + contact->GetFixtureB()->GetBody()->SetAwake(true); + } + + b2Shape::Type typeA = contact->GetFixtureA()->GetType(); + b2Shape::Type typeB = contact->GetFixtureB()->GetType(); + + b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount); + b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount); + + b2ContactDestroyFcn* destroyFcn = s_registers[typeA][typeB].destroyFcn; + destroyFcn(contact, allocator); +} + +b2Contact::b2Contact(b2Fixture* fA, int32 indexA, b2Fixture* fB, int32 indexB) +{ + m_flags = e_enabledFlag; + + m_fixtureA = fA; + m_fixtureB = fB; + + m_indexA = indexA; + m_indexB = indexB; + + m_manifold.pointCount = 0; + + m_prev = NULL; + m_next = NULL; + + m_nodeA.contact = NULL; + m_nodeA.prev = NULL; + m_nodeA.next = NULL; + m_nodeA.other = NULL; + + m_nodeB.contact = NULL; + m_nodeB.prev = NULL; + m_nodeB.next = NULL; + m_nodeB.other = NULL; + + m_toiCount = 0; + + m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction); + m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution); +} + +// Update the contact manifold and touching status. +// Note: do not assume the fixture AABBs are overlapping or are valid. +void b2Contact::Update(b2ContactListener* listener) +{ + b2Manifold oldManifold = m_manifold; + + // Re-enable this contact. + m_flags |= e_enabledFlag; + + bool touching = false; + bool wasTouching = (m_flags & e_touchingFlag) == e_touchingFlag; + + bool sensorA = m_fixtureA->IsSensor(); + bool sensorB = m_fixtureB->IsSensor(); + bool sensor = sensorA || sensorB; + + b2Body* bodyA = m_fixtureA->GetBody(); + b2Body* bodyB = m_fixtureB->GetBody(); + const b2Transform& xfA = bodyA->GetTransform(); + const b2Transform& xfB = bodyB->GetTransform(); + + // Is this contact a sensor? + if (sensor) + { + const b2Shape* shapeA = m_fixtureA->GetShape(); + const b2Shape* shapeB = m_fixtureB->GetShape(); + touching = b2TestOverlap(shapeA, m_indexA, shapeB, m_indexB, xfA, xfB); + + // Sensors don't generate manifolds. + m_manifold.pointCount = 0; + } + else + { + Evaluate(&m_manifold, xfA, xfB); + touching = m_manifold.pointCount > 0; + + // Match old contact ids to new contact ids and copy the + // stored impulses to warm start the solver. + for (int32 i = 0; i < m_manifold.pointCount; ++i) + { + b2ManifoldPoint* mp2 = m_manifold.points + i; + mp2->normalImpulse = 0.0f; + mp2->tangentImpulse = 0.0f; + b2ContactID id2 = mp2->id; + + for (int32 j = 0; j < oldManifold.pointCount; ++j) + { + b2ManifoldPoint* mp1 = oldManifold.points + j; + + if (mp1->id.key == id2.key) + { + mp2->normalImpulse = mp1->normalImpulse; + mp2->tangentImpulse = mp1->tangentImpulse; + break; + } + } + } + + if (touching != wasTouching) + { + bodyA->SetAwake(true); + bodyB->SetAwake(true); + } + } + + if (touching) + { + m_flags |= e_touchingFlag; + } + else + { + m_flags &= ~e_touchingFlag; + } + + if (wasTouching == false && touching == true && listener) + { + listener->BeginContact(this); + } + + if (wasTouching == true && touching == false && listener) + { + listener->EndContact(this); + } + + if (sensor == false && touching && listener) + { + listener->PreSolve(this, &oldManifold); + } +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2Contact.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2Contact.h new file mode 100755 index 0000000000000..7c132f923a67b --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2Contact.h @@ -0,0 +1,334 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_CONTACT_H +#define B2_CONTACT_H + +#include +#include +#include +#include + +class b2Body; +class b2Contact; +class b2Fixture; +class b2World; +class b2BlockAllocator; +class b2StackAllocator; +class b2ContactListener; + +/// Friction mixing law. The idea is to allow either fixture to drive the restitution to zero. +/// For example, anything slides on ice. +inline float32 b2MixFriction(float32 friction1, float32 friction2) +{ + return std::sqrt(friction1 * friction2); +} + +/// Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface. +/// For example, a superball bounces on anything. +inline float32 b2MixRestitution(float32 restitution1, float32 restitution2) +{ + return restitution1 > restitution2 ? restitution1 : restitution2; +} + +typedef b2Contact* b2ContactCreateFcn( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, + b2BlockAllocator* allocator); +typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator); + +struct b2ContactRegister +{ + b2ContactCreateFcn* createFcn; + b2ContactDestroyFcn* destroyFcn; + bool primary; +}; + +/// A contact edge is used to connect bodies and contacts together +/// in a contact graph where each body is a node and each contact +/// is an edge. A contact edge belongs to a doubly linked list +/// maintained in each attached body. Each contact has two contact +/// nodes, one for each attached body. +// emscripten - b2ContactEdge: add constructor +struct b2ContactEdge +{ + b2Body* other; ///< provides quick access to the other body attached. + b2Contact* contact; ///< the contact + b2ContactEdge* prev; ///< the previous contact edge in the body's contact list + b2ContactEdge* next; ///< the next contact edge in the body's contact list + + b2ContactEdge() {} +}; + +/// The class manages contact between two shapes. A contact exists for each overlapping +/// AABB in the broad-phase (except if filtered). Therefore a contact object may exist +/// that has no contact points. +class b2Contact +{ +public: + + /// Get the contact manifold. Do not modify the manifold unless you understand the + /// internals of Box2D. + b2Manifold* GetManifold(); + const b2Manifold* GetManifold() const; + + /// Get the world manifold. + void GetWorldManifold(b2WorldManifold* worldManifold) const; + + /// Is this contact touching? + bool IsTouching() const; + + /// Enable/disable this contact. This can be used inside the pre-solve + /// contact listener. The contact is only disabled for the current + /// time step (or sub-step in continuous collisions). + void SetEnabled(bool flag); + + /// Has this contact been disabled? + bool IsEnabled() const; + + /// Get the next contact in the world's contact list. + b2Contact* GetNext(); + const b2Contact* GetNext() const; + + /// Get fixture A in this contact. + b2Fixture* GetFixtureA(); + const b2Fixture* GetFixtureA() const; + + /// Get the child primitive index for fixture A. + int32 GetChildIndexA() const; + + /// Get fixture B in this contact. + b2Fixture* GetFixtureB(); + const b2Fixture* GetFixtureB() const; + + /// Get the child primitive index for fixture B. + int32 GetChildIndexB() const; + + /// Override the default friction mixture. You can call this in b2ContactListener::PreSolve. + /// This value persists until set or reset. + void SetFriction(float32 friction); + + /// Get the friction. + float32 GetFriction() const; + + /// Reset the friction mixture to the default value. + void ResetFriction(); + + /// Override the default restitution mixture. You can call this in b2ContactListener::PreSolve. + /// The value persists until you set or reset. + void SetRestitution(float32 restitution); + + /// Get the restitution. + float32 GetRestitution() const; + + /// Reset the restitution to the default value. + void ResetRestitution(); + + /// Evaluate this contact with your own manifold and transforms. + virtual void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) = 0; + +protected: + friend class b2ContactManager; + friend class b2World; + friend class b2ContactSolver; + friend class b2Body; + friend class b2Fixture; + + // Flags stored in m_flags + enum + { + // Used when crawling contact graph when forming islands. + e_islandFlag = 0x0001, + + // Set when the shapes are touching. + e_touchingFlag = 0x0002, + + // This contact can be disabled (by user) + e_enabledFlag = 0x0004, + + // This contact needs filtering because a fixture filter was changed. + e_filterFlag = 0x0008, + + // This bullet contact had a TOI event + e_bulletHitFlag = 0x0010, + + // This contact has a valid TOI in m_toi + e_toiFlag = 0x0020 + }; + + /// Flag this contact for filtering. Filtering will occur the next time step. + void FlagForFiltering(); + + static void AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destroyFcn, + b2Shape::Type typeA, b2Shape::Type typeB); + static void InitializeRegisters(); + static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2Shape::Type typeA, b2Shape::Type typeB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2Contact() : m_fixtureA(NULL), m_fixtureB(NULL) {} + b2Contact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); + virtual ~b2Contact() {} + + void Update(b2ContactListener* listener); + + static b2ContactRegister s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount]; + static bool s_initialized; + + uint32 m_flags; + + // World pool and list pointers. + b2Contact* m_prev; + b2Contact* m_next; + + // Nodes for connecting bodies. + b2ContactEdge m_nodeA; + b2ContactEdge m_nodeB; + + b2Fixture* m_fixtureA; + b2Fixture* m_fixtureB; + + int32 m_indexA; + int32 m_indexB; + + b2Manifold m_manifold; + + int32 m_toiCount; + float32 m_toi; + + float32 m_friction; + float32 m_restitution; +}; + +inline b2Manifold* b2Contact::GetManifold() +{ + return &m_manifold; +} + +inline const b2Manifold* b2Contact::GetManifold() const +{ + return &m_manifold; +} + +inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const +{ + const b2Body* bodyA = m_fixtureA->GetBody(); + const b2Body* bodyB = m_fixtureB->GetBody(); + const b2Shape* shapeA = m_fixtureA->GetShape(); + const b2Shape* shapeB = m_fixtureB->GetShape(); + + worldManifold->Initialize(&m_manifold, bodyA->GetTransform(), shapeA->m_radius, bodyB->GetTransform(), shapeB->m_radius); +} + +inline void b2Contact::SetEnabled(bool flag) +{ + if (flag) + { + m_flags |= e_enabledFlag; + } + else + { + m_flags &= ~e_enabledFlag; + } +} + +inline bool b2Contact::IsEnabled() const +{ + return (m_flags & e_enabledFlag) == e_enabledFlag; +} + +inline bool b2Contact::IsTouching() const +{ + return (m_flags & e_touchingFlag) == e_touchingFlag; +} + +inline b2Contact* b2Contact::GetNext() +{ + return m_next; +} + +inline const b2Contact* b2Contact::GetNext() const +{ + return m_next; +} + +inline b2Fixture* b2Contact::GetFixtureA() +{ + return m_fixtureA; +} + +inline const b2Fixture* b2Contact::GetFixtureA() const +{ + return m_fixtureA; +} + +inline b2Fixture* b2Contact::GetFixtureB() +{ + return m_fixtureB; +} + +inline int32 b2Contact::GetChildIndexA() const +{ + return m_indexA; +} + +inline const b2Fixture* b2Contact::GetFixtureB() const +{ + return m_fixtureB; +} + +inline int32 b2Contact::GetChildIndexB() const +{ + return m_indexB; +} + +inline void b2Contact::FlagForFiltering() +{ + m_flags |= e_filterFlag; +} + +inline void b2Contact::SetFriction(float32 friction) +{ + m_friction = friction; +} + +inline float32 b2Contact::GetFriction() const +{ + return m_friction; +} + +inline void b2Contact::ResetFriction() +{ + m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction); +} + +inline void b2Contact::SetRestitution(float32 restitution) +{ + m_restitution = restitution; +} + +inline float32 b2Contact::GetRestitution() const +{ + return m_restitution; +} + +inline void b2Contact::ResetRestitution() +{ + m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution); +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ContactSolver.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ContactSolver.cpp new file mode 100755 index 0000000000000..c990d7fb8ded0 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ContactSolver.cpp @@ -0,0 +1,832 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include + +#include +#include +#include +#include +#include + +#define B2_DEBUG_SOLVER 0 + +struct b2ContactPositionConstraint +{ + b2Vec2 localPoints[b2_maxManifoldPoints]; + b2Vec2 localNormal; + b2Vec2 localPoint; + int32 indexA; + int32 indexB; + float32 invMassA, invMassB; + b2Vec2 localCenterA, localCenterB; + float32 invIA, invIB; + b2Manifold::Type type; + float32 radiusA, radiusB; + int32 pointCount; +}; + +b2ContactSolver::b2ContactSolver(b2ContactSolverDef* def) +{ + m_step = def->step; + m_allocator = def->allocator; + m_count = def->count; + m_positionConstraints = (b2ContactPositionConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactPositionConstraint)); + m_velocityConstraints = (b2ContactVelocityConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactVelocityConstraint)); + m_positions = def->positions; + m_velocities = def->velocities; + m_contacts = def->contacts; + + // Initialize position independent portions of the constraints. + for (int32 i = 0; i < m_count; ++i) + { + b2Contact* contact = m_contacts[i]; + + b2Fixture* fixtureA = contact->m_fixtureA; + b2Fixture* fixtureB = contact->m_fixtureB; + b2Shape* shapeA = fixtureA->GetShape(); + b2Shape* shapeB = fixtureB->GetShape(); + float32 radiusA = shapeA->m_radius; + float32 radiusB = shapeB->m_radius; + b2Body* bodyA = fixtureA->GetBody(); + b2Body* bodyB = fixtureB->GetBody(); + b2Manifold* manifold = contact->GetManifold(); + + int32 pointCount = manifold->pointCount; + b2Assert(pointCount > 0); + + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + vc->friction = contact->m_friction; + vc->restitution = contact->m_restitution; + vc->indexA = bodyA->m_islandIndex; + vc->indexB = bodyB->m_islandIndex; + vc->invMassA = bodyA->m_invMass; + vc->invMassB = bodyB->m_invMass; + vc->invIA = bodyA->m_invI; + vc->invIB = bodyB->m_invI; + vc->contactIndex = i; + vc->pointCount = pointCount; + vc->K.SetZero(); + vc->normalMass.SetZero(); + + b2ContactPositionConstraint* pc = m_positionConstraints + i; + pc->indexA = bodyA->m_islandIndex; + pc->indexB = bodyB->m_islandIndex; + pc->invMassA = bodyA->m_invMass; + pc->invMassB = bodyB->m_invMass; + pc->localCenterA = bodyA->m_sweep.localCenter; + pc->localCenterB = bodyB->m_sweep.localCenter; + pc->invIA = bodyA->m_invI; + pc->invIB = bodyB->m_invI; + pc->localNormal = manifold->localNormal; + pc->localPoint = manifold->localPoint; + pc->pointCount = pointCount; + pc->radiusA = radiusA; + pc->radiusB = radiusB; + pc->type = manifold->type; + + for (int32 j = 0; j < pointCount; ++j) + { + b2ManifoldPoint* cp = manifold->points + j; + b2VelocityConstraintPoint* vcp = vc->points + j; + + if (m_step.warmStarting) + { + vcp->normalImpulse = m_step.dtRatio * cp->normalImpulse; + vcp->tangentImpulse = m_step.dtRatio * cp->tangentImpulse; + } + else + { + vcp->normalImpulse = 0.0f; + vcp->tangentImpulse = 0.0f; + } + + vcp->rA.SetZero(); + vcp->rB.SetZero(); + vcp->normalMass = 0.0f; + vcp->tangentMass = 0.0f; + vcp->velocityBias = 0.0f; + + pc->localPoints[j] = cp->localPoint; + } + } +} + +b2ContactSolver::~b2ContactSolver() +{ + m_allocator->Free(m_velocityConstraints); + m_allocator->Free(m_positionConstraints); +} + +// Initialize position dependent portions of the velocity constraints. +void b2ContactSolver::InitializeVelocityConstraints() +{ + for (int32 i = 0; i < m_count; ++i) + { + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + b2ContactPositionConstraint* pc = m_positionConstraints + i; + + float32 radiusA = pc->radiusA; + float32 radiusB = pc->radiusB; + b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold(); + + int32 indexA = vc->indexA; + int32 indexB = vc->indexB; + + float32 mA = vc->invMassA; + float32 mB = vc->invMassB; + float32 iA = vc->invIA; + float32 iB = vc->invIB; + b2Vec2 localCenterA = pc->localCenterA; + b2Vec2 localCenterB = pc->localCenterB; + + b2Vec2 cA = m_positions[indexA].c; + float32 aA = m_positions[indexA].a; + b2Vec2 vA = m_velocities[indexA].v; + float32 wA = m_velocities[indexA].w; + + b2Vec2 cB = m_positions[indexB].c; + float32 aB = m_positions[indexB].a; + b2Vec2 vB = m_velocities[indexB].v; + float32 wB = m_velocities[indexB].w; + + b2Assert(manifold->pointCount > 0); + + b2Transform xfA, xfB; + xfA.q.Set(aA); + xfB.q.Set(aB); + xfA.p = cA - b2Mul(xfA.q, localCenterA); + xfB.p = cB - b2Mul(xfB.q, localCenterB); + + b2WorldManifold worldManifold; + worldManifold.Initialize(manifold, xfA, radiusA, xfB, radiusB); + + vc->normal = worldManifold.normal; + + int32 pointCount = vc->pointCount; + for (int32 j = 0; j < pointCount; ++j) + { + b2VelocityConstraintPoint* vcp = vc->points + j; + + vcp->rA = worldManifold.points[j] - cA; + vcp->rB = worldManifold.points[j] - cB; + + float32 rnA = b2Cross(vcp->rA, vc->normal); + float32 rnB = b2Cross(vcp->rB, vc->normal); + + float32 kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB; + + vcp->normalMass = kNormal > 0.0f ? 1.0f / kNormal : 0.0f; + + b2Vec2 tangent = b2Cross(vc->normal, 1.0f); + + float32 rtA = b2Cross(vcp->rA, tangent); + float32 rtB = b2Cross(vcp->rB, tangent); + + float32 kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB; + + vcp->tangentMass = kTangent > 0.0f ? 1.0f / kTangent : 0.0f; + + // Setup a velocity bias for restitution. + vcp->velocityBias = 0.0f; + float32 vRel = b2Dot(vc->normal, vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA)); + if (vRel < -b2_velocityThreshold) + { + vcp->velocityBias = -vc->restitution * vRel; + } + } + + // If we have two points, then prepare the block solver. + if (vc->pointCount == 2) + { + b2VelocityConstraintPoint* vcp1 = vc->points + 0; + b2VelocityConstraintPoint* vcp2 = vc->points + 1; + + float32 rn1A = b2Cross(vcp1->rA, vc->normal); + float32 rn1B = b2Cross(vcp1->rB, vc->normal); + float32 rn2A = b2Cross(vcp2->rA, vc->normal); + float32 rn2B = b2Cross(vcp2->rB, vc->normal); + + float32 k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B; + float32 k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B; + float32 k12 = mA + mB + iA * rn1A * rn2A + iB * rn1B * rn2B; + + // Ensure a reasonable condition number. + const float32 k_maxConditionNumber = 1000.0f; + if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12)) + { + // K is safe to invert. + vc->K.ex.Set(k11, k12); + vc->K.ey.Set(k12, k22); + vc->normalMass = vc->K.GetInverse(); + } + else + { + // The constraints are redundant, just use one. + // TODO_ERIN use deepest? + vc->pointCount = 1; + } + } + } +} + +void b2ContactSolver::WarmStart() +{ + // Warm start. + for (int32 i = 0; i < m_count; ++i) + { + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + + int32 indexA = vc->indexA; + int32 indexB = vc->indexB; + float32 mA = vc->invMassA; + float32 iA = vc->invIA; + float32 mB = vc->invMassB; + float32 iB = vc->invIB; + int32 pointCount = vc->pointCount; + + b2Vec2 vA = m_velocities[indexA].v; + float32 wA = m_velocities[indexA].w; + b2Vec2 vB = m_velocities[indexB].v; + float32 wB = m_velocities[indexB].w; + + b2Vec2 normal = vc->normal; + b2Vec2 tangent = b2Cross(normal, 1.0f); + + for (int32 j = 0; j < pointCount; ++j) + { + b2VelocityConstraintPoint* vcp = vc->points + j; + b2Vec2 P = vcp->normalImpulse * normal + vcp->tangentImpulse * tangent; + wA -= iA * b2Cross(vcp->rA, P); + vA -= mA * P; + wB += iB * b2Cross(vcp->rB, P); + vB += mB * P; + } + + m_velocities[indexA].v = vA; + m_velocities[indexA].w = wA; + m_velocities[indexB].v = vB; + m_velocities[indexB].w = wB; + } +} + +void b2ContactSolver::SolveVelocityConstraints() +{ + for (int32 i = 0; i < m_count; ++i) + { + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + + int32 indexA = vc->indexA; + int32 indexB = vc->indexB; + float32 mA = vc->invMassA; + float32 iA = vc->invIA; + float32 mB = vc->invMassB; + float32 iB = vc->invIB; + int32 pointCount = vc->pointCount; + + b2Vec2 vA = m_velocities[indexA].v; + float32 wA = m_velocities[indexA].w; + b2Vec2 vB = m_velocities[indexB].v; + float32 wB = m_velocities[indexB].w; + + b2Vec2 normal = vc->normal; + b2Vec2 tangent = b2Cross(normal, 1.0f); + float32 friction = vc->friction; + + b2Assert(pointCount == 1 || pointCount == 2); + + // Solve tangent constraints first because non-penetration is more important + // than friction. + for (int32 j = 0; j < pointCount; ++j) + { + b2VelocityConstraintPoint* vcp = vc->points + j; + + // Relative velocity at contact + b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA); + + // Compute tangent force + float32 vt = b2Dot(dv, tangent); + float32 lambda = vcp->tangentMass * (-vt); + + // b2Clamp the accumulated force + float32 maxFriction = friction * vcp->normalImpulse; + float32 newImpulse = b2Clamp(vcp->tangentImpulse + lambda, -maxFriction, maxFriction); + lambda = newImpulse - vcp->tangentImpulse; + vcp->tangentImpulse = newImpulse; + + // Apply contact impulse + b2Vec2 P = lambda * tangent; + + vA -= mA * P; + wA -= iA * b2Cross(vcp->rA, P); + + vB += mB * P; + wB += iB * b2Cross(vcp->rB, P); + } + + // Solve normal constraints + if (vc->pointCount == 1) + { + b2VelocityConstraintPoint* vcp = vc->points + 0; + + // Relative velocity at contact + b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA); + + // Compute normal impulse + float32 vn = b2Dot(dv, normal); + float32 lambda = -vcp->normalMass * (vn - vcp->velocityBias); + + // b2Clamp the accumulated impulse + float32 newImpulse = b2Max(vcp->normalImpulse + lambda, 0.0f); + lambda = newImpulse - vcp->normalImpulse; + vcp->normalImpulse = newImpulse; + + // Apply contact impulse + b2Vec2 P = lambda * normal; + vA -= mA * P; + wA -= iA * b2Cross(vcp->rA, P); + + vB += mB * P; + wB += iB * b2Cross(vcp->rB, P); + } + else + { + // Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite). + // Build the mini LCP for this contact patch + // + // vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2 + // + // A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n ) + // b = vn0 - velocityBias + // + // The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i + // implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases + // vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid + // solution that satisfies the problem is chosen. + // + // In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires + // that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i). + // + // Substitute: + // + // x = a + d + // + // a := old total impulse + // x := new total impulse + // d := incremental impulse + // + // For the current iteration we extend the formula for the incremental impulse + // to compute the new total impulse: + // + // vn = A * d + b + // = A * (x - a) + b + // = A * x + b - A * a + // = A * x + b' + // b' = b - A * a; + + b2VelocityConstraintPoint* cp1 = vc->points + 0; + b2VelocityConstraintPoint* cp2 = vc->points + 1; + + b2Vec2 a(cp1->normalImpulse, cp2->normalImpulse); + b2Assert(a.x >= 0.0f && a.y >= 0.0f); + + // Relative velocity at contact + b2Vec2 dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); + b2Vec2 dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); + + // Compute normal velocity + float32 vn1 = b2Dot(dv1, normal); + float32 vn2 = b2Dot(dv2, normal); + + b2Vec2 b; + b.x = vn1 - cp1->velocityBias; + b.y = vn2 - cp2->velocityBias; + + // Compute b' + b -= b2Mul(vc->K, a); + + const float32 k_errorTol = 1e-3f; + B2_NOT_USED(k_errorTol); + + for (;;) + { + // + // Case 1: vn = 0 + // + // 0 = A * x + b' + // + // Solve for x: + // + // x = - inv(A) * b' + // + b2Vec2 x = - b2Mul(vc->normalMass, b); + + if (x.x >= 0.0f && x.y >= 0.0f) + { + // Get the incremental impulse + b2Vec2 d = x - a; + + // Apply incremental impulse + b2Vec2 P1 = d.x * normal; + b2Vec2 P2 = d.y * normal; + vA -= mA * (P1 + P2); + wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); + + vB += mB * (P1 + P2); + wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); + + // Accumulate + cp1->normalImpulse = x.x; + cp2->normalImpulse = x.y; + +#if B2_DEBUG_SOLVER == 1 + // Postconditions + dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); + dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); + + // Compute normal velocity + vn1 = b2Dot(dv1, normal); + vn2 = b2Dot(dv2, normal); + + b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol); + b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol); +#endif + break; + } + + // + // Case 2: vn1 = 0 and x2 = 0 + // + // 0 = a11 * x1 + a12 * 0 + b1' + // vn2 = a21 * x1 + a22 * 0 + b2' + // + x.x = - cp1->normalMass * b.x; + x.y = 0.0f; + vn1 = 0.0f; + vn2 = vc->K.ex.y * x.x + b.y; + + if (x.x >= 0.0f && vn2 >= 0.0f) + { + // Get the incremental impulse + b2Vec2 d = x - a; + + // Apply incremental impulse + b2Vec2 P1 = d.x * normal; + b2Vec2 P2 = d.y * normal; + vA -= mA * (P1 + P2); + wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); + + vB += mB * (P1 + P2); + wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); + + // Accumulate + cp1->normalImpulse = x.x; + cp2->normalImpulse = x.y; + +#if B2_DEBUG_SOLVER == 1 + // Postconditions + dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); + + // Compute normal velocity + vn1 = b2Dot(dv1, normal); + + b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol); +#endif + break; + } + + + // + // Case 3: vn2 = 0 and x1 = 0 + // + // vn1 = a11 * 0 + a12 * x2 + b1' + // 0 = a21 * 0 + a22 * x2 + b2' + // + x.x = 0.0f; + x.y = - cp2->normalMass * b.y; + vn1 = vc->K.ey.x * x.y + b.x; + vn2 = 0.0f; + + if (x.y >= 0.0f && vn1 >= 0.0f) + { + // Resubstitute for the incremental impulse + b2Vec2 d = x - a; + + // Apply incremental impulse + b2Vec2 P1 = d.x * normal; + b2Vec2 P2 = d.y * normal; + vA -= mA * (P1 + P2); + wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); + + vB += mB * (P1 + P2); + wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); + + // Accumulate + cp1->normalImpulse = x.x; + cp2->normalImpulse = x.y; + +#if B2_DEBUG_SOLVER == 1 + // Postconditions + dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); + + // Compute normal velocity + vn2 = b2Dot(dv2, normal); + + b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol); +#endif + break; + } + + // + // Case 4: x1 = 0 and x2 = 0 + // + // vn1 = b1 + // vn2 = b2; + x.x = 0.0f; + x.y = 0.0f; + vn1 = b.x; + vn2 = b.y; + + if (vn1 >= 0.0f && vn2 >= 0.0f ) + { + // Resubstitute for the incremental impulse + b2Vec2 d = x - a; + + // Apply incremental impulse + b2Vec2 P1 = d.x * normal; + b2Vec2 P2 = d.y * normal; + vA -= mA * (P1 + P2); + wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); + + vB += mB * (P1 + P2); + wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); + + // Accumulate + cp1->normalImpulse = x.x; + cp2->normalImpulse = x.y; + + break; + } + + // No solution, give up. This is hit sometimes, but it doesn't seem to matter. + break; + } + } + + m_velocities[indexA].v = vA; + m_velocities[indexA].w = wA; + m_velocities[indexB].v = vB; + m_velocities[indexB].w = wB; + } +} + +void b2ContactSolver::StoreImpulses() +{ + for (int32 i = 0; i < m_count; ++i) + { + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold(); + + for (int32 j = 0; j < vc->pointCount; ++j) + { + manifold->points[j].normalImpulse = vc->points[j].normalImpulse; + manifold->points[j].tangentImpulse = vc->points[j].tangentImpulse; + } + } +} + +struct b2PositionSolverManifold +{ + void Initialize(b2ContactPositionConstraint* pc, const b2Transform& xfA, const b2Transform& xfB, int32 index) + { + b2Assert(pc->pointCount > 0); + + switch (pc->type) + { + case b2Manifold::e_circles: + { + b2Vec2 pointA = b2Mul(xfA, pc->localPoint); + b2Vec2 pointB = b2Mul(xfB, pc->localPoints[0]); + normal = pointB - pointA; + normal.Normalize(); + point = 0.5f * (pointA + pointB); + separation = b2Dot(pointB - pointA, normal) - pc->radiusA - pc->radiusB; + } + break; + + case b2Manifold::e_faceA: + { + normal = b2Mul(xfA.q, pc->localNormal); + b2Vec2 planePoint = b2Mul(xfA, pc->localPoint); + + b2Vec2 clipPoint = b2Mul(xfB, pc->localPoints[index]); + separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB; + point = clipPoint; + } + break; + + case b2Manifold::e_faceB: + { + normal = b2Mul(xfB.q, pc->localNormal); + b2Vec2 planePoint = b2Mul(xfB, pc->localPoint); + + b2Vec2 clipPoint = b2Mul(xfA, pc->localPoints[index]); + separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB; + point = clipPoint; + + // Ensure normal points from A to B + normal = -normal; + } + break; + } + } + + b2Vec2 normal; + b2Vec2 point; + float32 separation; +}; + +// Sequential solver. +bool b2ContactSolver::SolvePositionConstraints() +{ + float32 minSeparation = 0.0f; + + for (int32 i = 0; i < m_count; ++i) + { + b2ContactPositionConstraint* pc = m_positionConstraints + i; + + int32 indexA = pc->indexA; + int32 indexB = pc->indexB; + b2Vec2 localCenterA = pc->localCenterA; + float32 mA = pc->invMassA; + float32 iA = pc->invIA; + b2Vec2 localCenterB = pc->localCenterB; + float32 mB = pc->invMassB; + float32 iB = pc->invIB; + int32 pointCount = pc->pointCount; + + b2Vec2 cA = m_positions[indexA].c; + float32 aA = m_positions[indexA].a; + + b2Vec2 cB = m_positions[indexB].c; + float32 aB = m_positions[indexB].a; + + // Solve normal constraints + for (int32 j = 0; j < pointCount; ++j) + { + b2Transform xfA, xfB; + xfA.q.Set(aA); + xfB.q.Set(aB); + xfA.p = cA - b2Mul(xfA.q, localCenterA); + xfB.p = cB - b2Mul(xfB.q, localCenterB); + + b2PositionSolverManifold psm; + psm.Initialize(pc, xfA, xfB, j); + b2Vec2 normal = psm.normal; + + b2Vec2 point = psm.point; + float32 separation = psm.separation; + + b2Vec2 rA = point - cA; + b2Vec2 rB = point - cB; + + // Track max constraint error. + minSeparation = b2Min(minSeparation, separation); + + // Prevent large corrections and allow slop. + float32 C = b2Clamp(b2_baumgarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f); + + // Compute the effective mass. + float32 rnA = b2Cross(rA, normal); + float32 rnB = b2Cross(rB, normal); + float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB; + + // Compute normal impulse + float32 impulse = K > 0.0f ? - C / K : 0.0f; + + b2Vec2 P = impulse * normal; + + cA -= mA * P; + aA -= iA * b2Cross(rA, P); + + cB += mB * P; + aB += iB * b2Cross(rB, P); + } + + m_positions[indexA].c = cA; + m_positions[indexA].a = aA; + + m_positions[indexB].c = cB; + m_positions[indexB].a = aB; + } + + // We can't expect minSpeparation >= -b2_linearSlop because we don't + // push the separation above -b2_linearSlop. + return minSeparation >= -3.0f * b2_linearSlop; +} + +// Sequential position solver for position constraints. +bool b2ContactSolver::SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB) +{ + float32 minSeparation = 0.0f; + + for (int32 i = 0; i < m_count; ++i) + { + b2ContactPositionConstraint* pc = m_positionConstraints + i; + + int32 indexA = pc->indexA; + int32 indexB = pc->indexB; + b2Vec2 localCenterA = pc->localCenterA; + b2Vec2 localCenterB = pc->localCenterB; + int32 pointCount = pc->pointCount; + + float32 mA = 0.0f; + float32 iA = 0.0f; + if (indexA == toiIndexA || indexA == toiIndexB) + { + mA = pc->invMassA; + iA = pc->invIA; + } + + float32 mB = pc->invMassB; + float32 iB = pc->invIB; + if (indexB == toiIndexA || indexB == toiIndexB) + { + mB = pc->invMassB; + iB = pc->invIB; + } + + b2Vec2 cA = m_positions[indexA].c; + float32 aA = m_positions[indexA].a; + + b2Vec2 cB = m_positions[indexB].c; + float32 aB = m_positions[indexB].a; + + // Solve normal constraints + for (int32 j = 0; j < pointCount; ++j) + { + b2Transform xfA, xfB; + xfA.q.Set(aA); + xfB.q.Set(aB); + xfA.p = cA - b2Mul(xfA.q, localCenterA); + xfB.p = cB - b2Mul(xfB.q, localCenterB); + + b2PositionSolverManifold psm; + psm.Initialize(pc, xfA, xfB, j); + b2Vec2 normal = psm.normal; + + b2Vec2 point = psm.point; + float32 separation = psm.separation; + + b2Vec2 rA = point - cA; + b2Vec2 rB = point - cB; + + // Track max constraint error. + minSeparation = b2Min(minSeparation, separation); + + // Prevent large corrections and allow slop. + float32 C = b2Clamp(b2_toiBaugarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f); + + // Compute the effective mass. + float32 rnA = b2Cross(rA, normal); + float32 rnB = b2Cross(rB, normal); + float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB; + + // Compute normal impulse + float32 impulse = K > 0.0f ? - C / K : 0.0f; + + b2Vec2 P = impulse * normal; + + cA -= mA * P; + aA -= iA * b2Cross(rA, P); + + cB += mB * P; + aB += iB * b2Cross(rB, P); + } + + m_positions[indexA].c = cA; + m_positions[indexA].a = aA; + + m_positions[indexB].c = cB; + m_positions[indexB].a = aB; + } + + // We can't expect minSpeparation >= -b2_linearSlop because we don't + // push the separation above -b2_linearSlop. + return minSeparation >= -1.5f * b2_linearSlop; +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ContactSolver.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ContactSolver.h new file mode 100755 index 0000000000000..ca9de04db9f43 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ContactSolver.h @@ -0,0 +1,94 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_CONTACT_SOLVER_H +#define B2_CONTACT_SOLVER_H + +#include +#include +#include + +class b2Contact; +class b2Body; +class b2StackAllocator; +struct b2ContactPositionConstraint; + +struct b2VelocityConstraintPoint +{ + b2Vec2 rA; + b2Vec2 rB; + float32 normalImpulse; + float32 tangentImpulse; + float32 normalMass; + float32 tangentMass; + float32 velocityBias; +}; + +struct b2ContactVelocityConstraint +{ + b2VelocityConstraintPoint points[b2_maxManifoldPoints]; + b2Vec2 normal; + b2Mat22 normalMass; + b2Mat22 K; + int32 indexA; + int32 indexB; + float32 invMassA, invMassB; + float32 invIA, invIB; + float32 friction; + float32 restitution; + int32 pointCount; + int32 contactIndex; +}; + +struct b2ContactSolverDef +{ + b2TimeStep step; + b2Contact** contacts; + int32 count; + b2Position* positions; + b2Velocity* velocities; + b2StackAllocator* allocator; +}; + +class b2ContactSolver +{ +public: + b2ContactSolver(b2ContactSolverDef* def); + ~b2ContactSolver(); + + void InitializeVelocityConstraints(); + + void WarmStart(); + void SolveVelocityConstraints(); + void StoreImpulses(); + + bool SolvePositionConstraints(); + bool SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB); + + b2TimeStep m_step; + b2Position* m_positions; + b2Velocity* m_velocities; + b2StackAllocator* m_allocator; + b2ContactPositionConstraint* m_positionConstraints; + b2ContactVelocityConstraint* m_velocityConstraints; + b2Contact** m_contacts; + int m_count; +}; + +#endif + diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp new file mode 100755 index 0000000000000..04336507074ea --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2EdgeAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2EdgeAndCircleContact)); + return new (mem) b2EdgeAndCircleContact(fixtureA, fixtureB); +} + +void b2EdgeAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2EdgeAndCircleContact*)contact)->~b2EdgeAndCircleContact(); + allocator->Free(contact, sizeof(b2EdgeAndCircleContact)); +} + +b2EdgeAndCircleContact::b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) +: b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_edge); + b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); +} + +void b2EdgeAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollideEdgeAndCircle( manifold, + (b2EdgeShape*)m_fixtureA->GetShape(), xfA, + (b2CircleShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h new file mode 100755 index 0000000000000..11b61b880773f --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_EDGE_AND_CIRCLE_CONTACT_H +#define B2_EDGE_AND_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2EdgeAndCircleContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2EdgeAndCircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp new file mode 100755 index 0000000000000..8bac536a0e988 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2EdgeAndPolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2EdgeAndPolygonContact)); + return new (mem) b2EdgeAndPolygonContact(fixtureA, fixtureB); +} + +void b2EdgeAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2EdgeAndPolygonContact*)contact)->~b2EdgeAndPolygonContact(); + allocator->Free(contact, sizeof(b2EdgeAndPolygonContact)); +} + +b2EdgeAndPolygonContact::b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB) +: b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_edge); + b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); +} + +void b2EdgeAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollideEdgeAndPolygon( manifold, + (b2EdgeShape*)m_fixtureA->GetShape(), xfA, + (b2PolygonShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h new file mode 100755 index 0000000000000..74b27ee01c740 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_EDGE_AND_POLYGON_CONTACT_H +#define B2_EDGE_AND_POLYGON_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2EdgeAndPolygonContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2EdgeAndPolygonContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp new file mode 100755 index 0000000000000..880f83e228ff3 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2PolygonAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2PolygonAndCircleContact)); + return new (mem) b2PolygonAndCircleContact(fixtureA, fixtureB); +} + +void b2PolygonAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2PolygonAndCircleContact*)contact)->~b2PolygonAndCircleContact(); + allocator->Free(contact, sizeof(b2PolygonAndCircleContact)); +} + +b2PolygonAndCircleContact::b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) +: b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon); + b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); +} + +void b2PolygonAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollidePolygonAndCircle( manifold, + (b2PolygonShape*)m_fixtureA->GetShape(), xfA, + (b2CircleShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h new file mode 100755 index 0000000000000..6beca16a2e75f --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h @@ -0,0 +1,38 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_POLYGON_AND_CIRCLE_CONTACT_H +#define B2_POLYGON_AND_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2PolygonAndCircleContact : public b2Contact +{ +public: + static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2PolygonAndCircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonContact.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonContact.cpp new file mode 100755 index 0000000000000..52e1be87467a4 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonContact.cpp @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2PolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2PolygonContact)); + return new (mem) b2PolygonContact(fixtureA, fixtureB); +} + +void b2PolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2PolygonContact*)contact)->~b2PolygonContact(); + allocator->Free(contact, sizeof(b2PolygonContact)); +} + +b2PolygonContact::b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB) + : b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon); + b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); +} + +void b2PolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollidePolygons( manifold, + (b2PolygonShape*)m_fixtureA->GetShape(), xfA, + (b2PolygonShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonContact.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonContact.h new file mode 100755 index 0000000000000..45932148c8984 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_POLYGON_CONTACT_H +#define B2_POLYGON_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2PolygonContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2PolygonContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2DistanceJoint.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2DistanceJoint.cpp new file mode 100755 index 0000000000000..1ced7d9de4413 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2DistanceJoint.cpp @@ -0,0 +1,260 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include + +// 1-D constrained system +// m (v2 - v1) = lambda +// v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass. +// x2 = x1 + h * v2 + +// 1-D mass-damper-spring system +// m (v2 - v1) + h * d * v2 + h * k * + +// C = norm(p2 - p1) - L +// u = (p2 - p1) / norm(p2 - p1) +// Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1)) +// J = [-u -cross(r1, u) u cross(r2, u)] +// K = J * invM * JT +// = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2 + +void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2, + const b2Vec2& anchor1, const b2Vec2& anchor2) +{ + bodyA = b1; + bodyB = b2; + localAnchorA = bodyA->GetLocalPoint(anchor1); + localAnchorB = bodyB->GetLocalPoint(anchor2); + b2Vec2 d = anchor2 - anchor1; + length = d.Length(); +} + +b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_length = def->length; + m_frequencyHz = def->frequencyHz; + m_dampingRatio = def->dampingRatio; + m_impulse = 0.0f; + m_gamma = 0.0f; + m_bias = 0.0f; +} + +void b2DistanceJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + m_u = cB + m_rB - cA - m_rA; + + // Handle singularity. + float32 length = m_u.Length(); + if (length > b2_linearSlop) + { + m_u *= 1.0f / length; + } + else + { + m_u.Set(0.0f, 0.0f); + } + + float32 crAu = b2Cross(m_rA, m_u); + float32 crBu = b2Cross(m_rB, m_u); + float32 invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu; + + // Compute the effective mass matrix. + m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; + + if (m_frequencyHz > 0.0f) + { + float32 C = length - m_length; + + // Frequency + float32 omega = 2.0f * b2_pi * m_frequencyHz; + + // Damping coefficient + float32 d = 2.0f * m_mass * m_dampingRatio * omega; + + // Spring stiffness + float32 k = m_mass * omega * omega; + + // magic formulas + float32 h = data.step.dt; + m_gamma = h * (d + h * k); + m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f; + m_bias = C * h * k * m_gamma; + + invMass += m_gamma; + m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; + } + else + { + m_gamma = 0.0f; + m_bias = 0.0f; + } + + if (data.step.warmStarting) + { + // Scale the impulse to support a variable time step. + m_impulse *= data.step.dtRatio; + + b2Vec2 P = m_impulse * m_u; + vA -= m_invMassA * P; + wA -= m_invIA * b2Cross(m_rA, P); + vB += m_invMassB * P; + wB += m_invIB * b2Cross(m_rB, P); + } + else + { + m_impulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2DistanceJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + // Cdot = dot(u, v + cross(w, r)) + b2Vec2 vpA = vA + b2Cross(wA, m_rA); + b2Vec2 vpB = vB + b2Cross(wB, m_rB); + float32 Cdot = b2Dot(m_u, vpB - vpA); + + float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse); + m_impulse += impulse; + + b2Vec2 P = impulse * m_u; + vA -= m_invMassA * P; + wA -= m_invIA * b2Cross(m_rA, P); + vB += m_invMassB * P; + wB += m_invIB * b2Cross(m_rB, P); + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2DistanceJoint::SolvePositionConstraints(const b2SolverData& data) +{ + if (m_frequencyHz > 0.0f) + { + // There is no position correction for soft distance constraints. + return true; + } + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 u = cB + rB - cA - rA; + + float32 length = u.Normalize(); + float32 C = length - m_length; + C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection); + + float32 impulse = -m_mass * C; + b2Vec2 P = impulse * u; + + cA -= m_invMassA * P; + aA -= m_invIA * b2Cross(rA, P); + cB += m_invMassB * P; + aB += m_invIB * b2Cross(rB, P); + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return b2Abs(C) < b2_linearSlop; +} + +b2Vec2 b2DistanceJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2DistanceJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2DistanceJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 F = (inv_dt * m_impulse) * m_u; + return F; +} + +float32 b2DistanceJoint::GetReactionTorque(float32 inv_dt) const +{ + B2_NOT_USED(inv_dt); + return 0.0f; +} + +void b2DistanceJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2DistanceJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.length = %.15lef;\n", m_length); + b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); + b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2DistanceJoint.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2DistanceJoint.h new file mode 100755 index 0000000000000..63eadd93a34e1 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2DistanceJoint.h @@ -0,0 +1,180 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_DISTANCE_JOINT_H +#define B2_DISTANCE_JOINT_H + +#include + +/// Distance joint definition. This requires defining an +/// anchor point on both bodies and the non-zero length of the +/// distance joint. The definition uses local anchor points +/// so that the initial configuration can violate the constraint +/// slightly. This helps when saving and loading a game. +/// @warning Do not use a zero or short length. +// emscripten - b2DistanceJointDef: add functions to set/get base class members +struct b2DistanceJointDef : public b2JointDef +{ + b2DistanceJointDef() + { + type = e_distanceJoint; + localAnchorA.Set(0.0f, 0.0f); + localAnchorB.Set(0.0f, 0.0f); + length = 1.0f; + frequencyHz = 0.0f; + dampingRatio = 0.0f; + } + + /// Initialize the bodies, anchors, and length using the world + /// anchors. + void Initialize(b2Body* bodyA, b2Body* bodyB, + const b2Vec2& anchorA, const b2Vec2& anchorB); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The natural length between the anchor points. + float32 length; + + /// The mass-spring-damper frequency in Hertz. A value of 0 + /// disables softness. + float32 frequencyHz; + + /// The damping ratio. 0 = no damping, 1 = critical damping. + float32 dampingRatio; + + // to generate javascript bindings + void set_bodyA(b2Body* b) { bodyA = b; } + void set_bodyB(b2Body* b) { bodyB = b; } + void set_collideConnected(bool b) { collideConnected = b; } + b2Body* get_bodyA(b2Body* b) { return bodyA; } + b2Body* get_bodyB(b2Body* b) { return bodyB; } + bool get_collideConnected(bool b) { return collideConnected; } +}; + +/// A distance joint constrains two points on two bodies +/// to remain at a fixed distance from each other. You can view +/// this as a massless, rigid rod. +// emscripten - b2DistanceJoint: make constructor public +class b2DistanceJoint : public b2Joint +{ +public: + + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + /// Get the reaction force given the inverse time step. + /// Unit is N. + b2Vec2 GetReactionForce(float32 inv_dt) const; + + /// Get the reaction torque given the inverse time step. + /// Unit is N*m. This is always zero for a distance joint. + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Set/get the natural length. + /// Manipulating the length can lead to non-physical behavior when the frequency is zero. + void SetLength(float32 length); + float32 GetLength() const; + + /// Set/get frequency in Hz. + void SetFrequency(float32 hz); + float32 GetFrequency() const; + + /// Set/get damping ratio. + void SetDampingRatio(float32 ratio); + float32 GetDampingRatio() const; + + /// Dump joint to dmLog + void Dump(); + + b2DistanceJoint(const b2DistanceJointDef* data); + +protected: + + friend class b2Joint; + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + float32 m_frequencyHz; + float32 m_dampingRatio; + float32 m_bias; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_gamma; + float32 m_impulse; + float32 m_length; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_u; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + float32 m_mass; +}; + +inline void b2DistanceJoint::SetLength(float32 length) +{ + m_length = length; +} + +inline float32 b2DistanceJoint::GetLength() const +{ + return m_length; +} + +inline void b2DistanceJoint::SetFrequency(float32 hz) +{ + m_frequencyHz = hz; +} + +inline float32 b2DistanceJoint::GetFrequency() const +{ + return m_frequencyHz; +} + +inline void b2DistanceJoint::SetDampingRatio(float32 ratio) +{ + m_dampingRatio = ratio; +} + +inline float32 b2DistanceJoint::GetDampingRatio() const +{ + return m_dampingRatio; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2FrictionJoint.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2FrictionJoint.cpp new file mode 100755 index 0000000000000..075e72bb4da5a --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2FrictionJoint.cpp @@ -0,0 +1,251 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include + +// Point-to-point constraint +// Cdot = v2 - v1 +// = v2 + cross(w2, r2) - v1 - cross(w1, r1) +// J = [-I -r1_skew I r2_skew ] +// Identity used: +// w k % (rx i + ry j) = w * (-ry i + rx j) + +// Angle constraint +// Cdot = w2 - w1 +// J = [0 0 -1 0 0 1] +// K = invI1 + invI2 + +void b2FrictionJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); +} + +b2FrictionJoint::b2FrictionJoint(const b2FrictionJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + + m_linearImpulse.SetZero(); + m_angularImpulse = 0.0f; + + m_maxForce = def->maxForce; + m_maxTorque = def->maxTorque; +} + +void b2FrictionJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + // Compute the effective mass matrix. + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // J = [-I -r1_skew I r2_skew] + // [ 0 -1 0 1] + // r_skew = [-ry; rx] + + // Matlab + // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] + // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] + // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Mat22 K; + K.ex.x = mA + mB + iA * m_rA.y * m_rA.y + iB * m_rB.y * m_rB.y; + K.ex.y = -iA * m_rA.x * m_rA.y - iB * m_rB.x * m_rB.y; + K.ey.x = K.ex.y; + K.ey.y = mA + mB + iA * m_rA.x * m_rA.x + iB * m_rB.x * m_rB.x; + + m_linearMass = K.GetInverse(); + + m_angularMass = iA + iB; + if (m_angularMass > 0.0f) + { + m_angularMass = 1.0f / m_angularMass; + } + + if (data.step.warmStarting) + { + // Scale impulses to support a variable time step. + m_linearImpulse *= data.step.dtRatio; + m_angularImpulse *= data.step.dtRatio; + + b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y); + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + m_angularImpulse); + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + m_angularImpulse); + } + else + { + m_linearImpulse.SetZero(); + m_angularImpulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2FrictionJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + float32 h = data.step.dt; + + // Solve angular friction + { + float32 Cdot = wB - wA; + float32 impulse = -m_angularMass * Cdot; + + float32 oldImpulse = m_angularImpulse; + float32 maxImpulse = h * m_maxTorque; + m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse); + impulse = m_angularImpulse - oldImpulse; + + wA -= iA * impulse; + wB += iB * impulse; + } + + // Solve linear friction + { + b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + + b2Vec2 impulse = -b2Mul(m_linearMass, Cdot); + b2Vec2 oldImpulse = m_linearImpulse; + m_linearImpulse += impulse; + + float32 maxImpulse = h * m_maxForce; + + if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse) + { + m_linearImpulse.Normalize(); + m_linearImpulse *= maxImpulse; + } + + impulse = m_linearImpulse - oldImpulse; + + vA -= mA * impulse; + wA -= iA * b2Cross(m_rA, impulse); + + vB += mB * impulse; + wB += iB * b2Cross(m_rB, impulse); + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2FrictionJoint::SolvePositionConstraints(const b2SolverData& data) +{ + B2_NOT_USED(data); + + return true; +} + +b2Vec2 b2FrictionJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2FrictionJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2FrictionJoint::GetReactionForce(float32 inv_dt) const +{ + return inv_dt * m_linearImpulse; +} + +float32 b2FrictionJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_angularImpulse; +} + +void b2FrictionJoint::SetMaxForce(float32 force) +{ + b2Assert(b2IsValid(force) && force >= 0.0f); + m_maxForce = force; +} + +float32 b2FrictionJoint::GetMaxForce() const +{ + return m_maxForce; +} + +void b2FrictionJoint::SetMaxTorque(float32 torque) +{ + b2Assert(b2IsValid(torque) && torque >= 0.0f); + m_maxTorque = torque; +} + +float32 b2FrictionJoint::GetMaxTorque() const +{ + return m_maxTorque; +} + +void b2FrictionJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2FrictionJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.maxForce = %.15lef;\n", m_maxForce); + b2Log(" jd.maxTorque = %.15lef;\n", m_maxTorque); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2FrictionJoint.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2FrictionJoint.h new file mode 100755 index 0000000000000..7e261fc99534c --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2FrictionJoint.h @@ -0,0 +1,129 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_FRICTION_JOINT_H +#define B2_FRICTION_JOINT_H + +#include + +/// Friction joint definition. +// emscripten - b2FrictionJointDef: add functions to set/get base class members +struct b2FrictionJointDef : public b2JointDef +{ + b2FrictionJointDef() + { + type = e_frictionJoint; + localAnchorA.SetZero(); + localAnchorB.SetZero(); + maxForce = 0.0f; + maxTorque = 0.0f; + } + + /// Initialize the bodies, anchors, axis, and reference angle using the world + /// anchor and world axis. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The maximum friction force in N. + float32 maxForce; + + /// The maximum friction torque in N-m. + float32 maxTorque; + + // to generate javascript bindings + void set_bodyA(b2Body* b) { bodyA = b; } + void set_bodyB(b2Body* b) { bodyB = b; } + void set_collideConnected(bool b) { collideConnected = b; } + b2Body* get_bodyA(b2Body* b) { return bodyA; } + b2Body* get_bodyB(b2Body* b) { return bodyB; } + bool get_collideConnected(bool b) { return collideConnected; } +}; + +/// Friction joint. This is used for top-down friction. +/// It provides 2D translational friction and angular friction. +// emscripten - b2FrictionJoint: make constructor public +class b2FrictionJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Set the maximum friction force in N. + void SetMaxForce(float32 force); + + /// Get the maximum friction force in N. + float32 GetMaxForce() const; + + /// Set the maximum friction torque in N*m. + void SetMaxTorque(float32 torque); + + /// Get the maximum friction torque in N*m. + float32 GetMaxTorque() const; + + /// Dump joint to dmLog + void Dump(); + + b2FrictionJoint(const b2FrictionJointDef* def); + +protected: + + friend class b2Joint; + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + + // Solver shared + b2Vec2 m_linearImpulse; + float32 m_angularImpulse; + float32 m_maxForce; + float32 m_maxTorque; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Mat22 m_linearMass; + float32 m_angularMass; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2GearJoint.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2GearJoint.cpp new file mode 100755 index 0000000000000..201f01233c65f --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2GearJoint.cpp @@ -0,0 +1,423 @@ +/* +* Copyright (c) 2007-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include + +// Gear Joint: +// C0 = (coordinate1 + ratio * coordinate2)_initial +// C = (coordinate1 + ratio * coordinate2) - C0 = 0 +// J = [J1 ratio * J2] +// K = J * invM * JT +// = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T +// +// Revolute: +// coordinate = rotation +// Cdot = angularVelocity +// J = [0 0 1] +// K = J * invM * JT = invI +// +// Prismatic: +// coordinate = dot(p - pg, ug) +// Cdot = dot(v + cross(w, r), ug) +// J = [ug cross(r, ug)] +// K = J * invM * JT = invMass + invI * cross(r, ug)^2 + +b2GearJoint::b2GearJoint(const b2GearJointDef* def) +: b2Joint(def) +{ + m_joint1 = def->joint1; + m_joint2 = def->joint2; + + m_typeA = m_joint1->GetType(); + m_typeB = m_joint2->GetType(); + + b2Assert(m_typeA == e_revoluteJoint || m_typeA == e_prismaticJoint); + b2Assert(m_typeB == e_revoluteJoint || m_typeB == e_prismaticJoint); + + float32 coordinateA, coordinateB; + + // TODO_ERIN there might be some problem with the joint edges in b2Joint. + + m_bodyC = m_joint1->GetBodyA(); + m_bodyA = m_joint1->GetBodyB(); + + // Get geometry of joint1 + b2Transform xfA = m_bodyA->m_xf; + float32 aA = m_bodyA->m_sweep.a; + b2Transform xfC = m_bodyC->m_xf; + float32 aC = m_bodyC->m_sweep.a; + + if (m_typeA == e_revoluteJoint) + { + b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint1; + m_localAnchorC = revolute->m_localAnchorA; + m_localAnchorA = revolute->m_localAnchorB; + m_referenceAngleA = revolute->m_referenceAngle; + m_localAxisC.SetZero(); + + coordinateA = aA - aC - m_referenceAngleA; + } + else + { + b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint1; + m_localAnchorC = prismatic->m_localAnchorA; + m_localAnchorA = prismatic->m_localAnchorB; + m_referenceAngleA = prismatic->m_referenceAngle; + m_localAxisC = prismatic->m_localXAxisA; + + b2Vec2 pC = m_localAnchorC; + b2Vec2 pA = b2MulT(xfC.q, b2Mul(xfA.q, m_localAnchorA) + (xfA.p - xfC.p)); + coordinateA = b2Dot(pA - pC, m_localAxisC); + } + + m_bodyD = m_joint2->GetBodyA(); + m_bodyB = m_joint2->GetBodyB(); + + // Get geometry of joint2 + b2Transform xfB = m_bodyB->m_xf; + float32 aB = m_bodyB->m_sweep.a; + b2Transform xfD = m_bodyD->m_xf; + float32 aD = m_bodyD->m_sweep.a; + + if (m_typeB == e_revoluteJoint) + { + b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint2; + m_localAnchorD = revolute->m_localAnchorA; + m_localAnchorB = revolute->m_localAnchorB; + m_referenceAngleB = revolute->m_referenceAngle; + m_localAxisD.SetZero(); + + coordinateB = aB - aD - m_referenceAngleB; + } + else + { + b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint2; + m_localAnchorD = prismatic->m_localAnchorA; + m_localAnchorB = prismatic->m_localAnchorB; + m_referenceAngleB = prismatic->m_referenceAngle; + m_localAxisD = prismatic->m_localXAxisA; + + b2Vec2 pD = m_localAnchorD; + b2Vec2 pB = b2MulT(xfD.q, b2Mul(xfB.q, m_localAnchorB) + (xfB.p - xfD.p)); + coordinateB = b2Dot(pB - pD, m_localAxisD); + } + + m_ratio = def->ratio; + + m_constant = coordinateA + m_ratio * coordinateB; + + m_impulse = 0.0f; +} + +void b2GearJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_indexC = m_bodyC->m_islandIndex; + m_indexD = m_bodyD->m_islandIndex; + m_lcA = m_bodyA->m_sweep.localCenter; + m_lcB = m_bodyB->m_sweep.localCenter; + m_lcC = m_bodyC->m_sweep.localCenter; + m_lcD = m_bodyD->m_sweep.localCenter; + m_mA = m_bodyA->m_invMass; + m_mB = m_bodyB->m_invMass; + m_mC = m_bodyC->m_invMass; + m_mD = m_bodyD->m_invMass; + m_iA = m_bodyA->m_invI; + m_iB = m_bodyB->m_invI; + m_iC = m_bodyC->m_invI; + m_iD = m_bodyD->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Vec2 cC = data.positions[m_indexC].c; + float32 aC = data.positions[m_indexC].a; + b2Vec2 vC = data.velocities[m_indexC].v; + float32 wC = data.velocities[m_indexC].w; + + b2Vec2 cD = data.positions[m_indexD].c; + float32 aD = data.positions[m_indexD].a; + b2Vec2 vD = data.velocities[m_indexD].v; + float32 wD = data.velocities[m_indexD].w; + + b2Rot qA(aA), qB(aB), qC(aC), qD(aD); + + m_mass = 0.0f; + + if (m_typeA == e_revoluteJoint) + { + m_JvAC.SetZero(); + m_JwA = 1.0f; + m_JwC = 1.0f; + m_mass += m_iA + m_iC; + } + else + { + b2Vec2 u = b2Mul(qC, m_localAxisC); + b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC); + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA); + m_JvAC = u; + m_JwC = b2Cross(rC, u); + m_JwA = b2Cross(rA, u); + m_mass += m_mC + m_mA + m_iC * m_JwC * m_JwC + m_iA * m_JwA * m_JwA; + } + + if (m_typeB == e_revoluteJoint) + { + m_JvBD.SetZero(); + m_JwB = m_ratio; + m_JwD = m_ratio; + m_mass += m_ratio * m_ratio * (m_iB + m_iD); + } + else + { + b2Vec2 u = b2Mul(qD, m_localAxisD); + b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB); + m_JvBD = m_ratio * u; + m_JwD = m_ratio * b2Cross(rD, u); + m_JwB = m_ratio * b2Cross(rB, u); + m_mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * m_JwD * m_JwD + m_iB * m_JwB * m_JwB; + } + + // Compute effective mass. + m_mass = m_mass > 0.0f ? 1.0f / m_mass : 0.0f; + + if (data.step.warmStarting) + { + vA += (m_mA * m_impulse) * m_JvAC; + wA += m_iA * m_impulse * m_JwA; + vB += (m_mB * m_impulse) * m_JvBD; + wB += m_iB * m_impulse * m_JwB; + vC -= (m_mC * m_impulse) * m_JvAC; + wC -= m_iC * m_impulse * m_JwC; + vD -= (m_mD * m_impulse) * m_JvBD; + wD -= m_iD * m_impulse * m_JwD; + } + else + { + m_impulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; + data.velocities[m_indexC].v = vC; + data.velocities[m_indexC].w = wC; + data.velocities[m_indexD].v = vD; + data.velocities[m_indexD].w = wD; +} + +void b2GearJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + b2Vec2 vC = data.velocities[m_indexC].v; + float32 wC = data.velocities[m_indexC].w; + b2Vec2 vD = data.velocities[m_indexD].v; + float32 wD = data.velocities[m_indexD].w; + + float32 Cdot = b2Dot(m_JvAC, vA - vC) + b2Dot(m_JvBD, vB - vD); + Cdot += (m_JwA * wA - m_JwC * wC) + (m_JwB * wB - m_JwD * wD); + + float32 impulse = -m_mass * Cdot; + m_impulse += impulse; + + vA += (m_mA * impulse) * m_JvAC; + wA += m_iA * impulse * m_JwA; + vB += (m_mB * impulse) * m_JvBD; + wB += m_iB * impulse * m_JwB; + vC -= (m_mC * impulse) * m_JvAC; + wC -= m_iC * impulse * m_JwC; + vD -= (m_mD * impulse) * m_JvBD; + wD -= m_iD * impulse * m_JwD; + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; + data.velocities[m_indexC].v = vC; + data.velocities[m_indexC].w = wC; + data.velocities[m_indexD].v = vD; + data.velocities[m_indexD].w = wD; +} + +bool b2GearJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 cC = data.positions[m_indexC].c; + float32 aC = data.positions[m_indexC].a; + b2Vec2 cD = data.positions[m_indexD].c; + float32 aD = data.positions[m_indexD].a; + + b2Rot qA(aA), qB(aB), qC(aC), qD(aD); + + float32 linearError = 0.0f; + + float32 coordinateA, coordinateB; + + b2Vec2 JvAC, JvBD; + float32 JwA, JwB, JwC, JwD; + float32 mass = 0.0f; + + if (m_typeA == e_revoluteJoint) + { + JvAC.SetZero(); + JwA = 1.0f; + JwC = 1.0f; + mass += m_iA + m_iC; + + coordinateA = aA - aC - m_referenceAngleA; + } + else + { + b2Vec2 u = b2Mul(qC, m_localAxisC); + b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC); + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA); + JvAC = u; + JwC = b2Cross(rC, u); + JwA = b2Cross(rA, u); + mass += m_mC + m_mA + m_iC * JwC * JwC + m_iA * JwA * JwA; + + b2Vec2 pC = m_localAnchorC - m_lcC; + b2Vec2 pA = b2MulT(qC, rA + (cA - cC)); + coordinateA = b2Dot(pA - pC, m_localAxisC); + } + + if (m_typeB == e_revoluteJoint) + { + JvBD.SetZero(); + JwB = m_ratio; + JwD = m_ratio; + mass += m_ratio * m_ratio * (m_iB + m_iD); + + coordinateB = aB - aD - m_referenceAngleB; + } + else + { + b2Vec2 u = b2Mul(qD, m_localAxisD); + b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB); + JvBD = m_ratio * u; + JwD = m_ratio * b2Cross(rD, u); + JwB = m_ratio * b2Cross(rB, u); + mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * JwD * JwD + m_iB * JwB * JwB; + + b2Vec2 pD = m_localAnchorD - m_lcD; + b2Vec2 pB = b2MulT(qD, rB + (cB - cD)); + coordinateB = b2Dot(pB - pD, m_localAxisD); + } + + float32 C = (coordinateA + m_ratio * coordinateB) - m_constant; + + float32 impulse = 0.0f; + if (mass > 0.0f) + { + impulse = -C / mass; + } + + cA += m_mA * impulse * JvAC; + aA += m_iA * impulse * JwA; + cB += m_mB * impulse * JvBD; + aB += m_iB * impulse * JwB; + cC -= m_mC * impulse * JvAC; + aC -= m_iC * impulse * JwC; + cD -= m_mD * impulse * JvBD; + aD -= m_iD * impulse * JwD; + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + data.positions[m_indexC].c = cC; + data.positions[m_indexC].a = aC; + data.positions[m_indexD].c = cD; + data.positions[m_indexD].a = aD; + + // TODO_ERIN not implemented + return linearError < b2_linearSlop; +} + +b2Vec2 b2GearJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2GearJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2GearJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 P = m_impulse * m_JvAC; + return inv_dt * P; +} + +float32 b2GearJoint::GetReactionTorque(float32 inv_dt) const +{ + float32 L = m_impulse * m_JwA; + return inv_dt * L; +} + +void b2GearJoint::SetRatio(float32 ratio) +{ + b2Assert(b2IsValid(ratio)); + m_ratio = ratio; +} + +float32 b2GearJoint::GetRatio() const +{ + return m_ratio; +} + +void b2GearJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + int32 index1 = m_joint1->m_index; + int32 index2 = m_joint2->m_index; + + b2Log(" b2GearJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.joint1 = joints[%d];\n", index1); + b2Log(" jd.joint2 = joints[%d];\n", index2); + b2Log(" jd.ratio = %.15lef;\n", m_ratio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2GearJoint.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2GearJoint.h new file mode 100755 index 0000000000000..97283e13f72b6 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2GearJoint.h @@ -0,0 +1,136 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_GEAR_JOINT_H +#define B2_GEAR_JOINT_H + +#include + +/// Gear joint definition. This definition requires two existing +/// revolute or prismatic joints (any combination will work). +// emscripten - b2GearJointDef: add functions to set/get base class members +struct b2GearJointDef : public b2JointDef +{ + b2GearJointDef() + { + type = e_gearJoint; + joint1 = NULL; + joint2 = NULL; + ratio = 1.0f; + } + + /// The first revolute/prismatic joint attached to the gear joint. + b2Joint* joint1; + + /// The second revolute/prismatic joint attached to the gear joint. + b2Joint* joint2; + + /// The gear ratio. + /// @see b2GearJoint for explanation. + float32 ratio; + + // to generate javascript bindings + void set_bodyA(b2Body* b) { bodyA = b; } + void set_bodyB(b2Body* b) { bodyB = b; } + void set_collideConnected(bool b) { collideConnected = b; } + b2Body* get_bodyA(b2Body* b) { return bodyA; } + b2Body* get_bodyB(b2Body* b) { return bodyB; } + bool get_collideConnected(bool b) { return collideConnected; } +}; + +/// A gear joint is used to connect two joints together. Either joint +/// can be a revolute or prismatic joint. You specify a gear ratio +/// to bind the motions together: +/// coordinate1 + ratio * coordinate2 = constant +/// The ratio can be negative or positive. If one joint is a revolute joint +/// and the other joint is a prismatic joint, then the ratio will have units +/// of length or units of 1/length. +/// @warning You have to manually destroy the gear joint if joint1 or joint2 +/// is destroyed. +// emscripten - b2GearJoint: make constructor public +class b2GearJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// Get the first joint. + b2Joint* GetJoint1() { return m_joint1; } + + /// Get the second joint. + b2Joint* GetJoint2() { return m_joint2; } + + /// Set/Get the gear ratio. + void SetRatio(float32 ratio); + float32 GetRatio() const; + + /// Dump joint to dmLog + void Dump(); + + b2GearJoint(const b2GearJointDef* data); + +protected: + + friend class b2Joint; + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Joint* m_joint1; + b2Joint* m_joint2; + + b2JointType m_typeA; + b2JointType m_typeB; + + // Body A is connected to body C + // Body B is connected to body D + b2Body* m_bodyC; + b2Body* m_bodyD; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec2 m_localAnchorC; + b2Vec2 m_localAnchorD; + + b2Vec2 m_localAxisC; + b2Vec2 m_localAxisD; + + float32 m_referenceAngleA; + float32 m_referenceAngleB; + + float32 m_constant; + float32 m_ratio; + + float32 m_impulse; + + // Solver temp + int32 m_indexA, m_indexB, m_indexC, m_indexD; + b2Vec2 m_lcA, m_lcB, m_lcC, m_lcD; + float32 m_mA, m_mB, m_mC, m_mD; + float32 m_iA, m_iB, m_iC, m_iD; + b2Vec2 m_JvAC, m_JvBD; + float32 m_JwA, m_JwB, m_JwC, m_JwD; + float32 m_mass; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2Joint.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2Joint.cpp new file mode 100755 index 0000000000000..85322f77cc3fe --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2Joint.cpp @@ -0,0 +1,199 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +b2Joint* b2Joint::Create(const b2JointDef* def, b2BlockAllocator* allocator) +{ + b2Joint* joint = NULL; + + switch (def->type) + { + case e_distanceJoint: + { + void* mem = allocator->Allocate(sizeof(b2DistanceJoint)); + joint = new (mem) b2DistanceJoint((b2DistanceJointDef*)def); + } + break; + + case e_mouseJoint: + { + void* mem = allocator->Allocate(sizeof(b2MouseJoint)); + joint = new (mem) b2MouseJoint((b2MouseJointDef*)def); + } + break; + + case e_prismaticJoint: + { + void* mem = allocator->Allocate(sizeof(b2PrismaticJoint)); + joint = new (mem) b2PrismaticJoint((b2PrismaticJointDef*)def); + } + break; + + case e_revoluteJoint: + { + void* mem = allocator->Allocate(sizeof(b2RevoluteJoint)); + joint = new (mem) b2RevoluteJoint((b2RevoluteJointDef*)def); + } + break; + + case e_pulleyJoint: + { + void* mem = allocator->Allocate(sizeof(b2PulleyJoint)); + joint = new (mem) b2PulleyJoint((b2PulleyJointDef*)def); + } + break; + + case e_gearJoint: + { + void* mem = allocator->Allocate(sizeof(b2GearJoint)); + joint = new (mem) b2GearJoint((b2GearJointDef*)def); + } + break; + + case e_wheelJoint: + { + void* mem = allocator->Allocate(sizeof(b2WheelJoint)); + joint = new (mem) b2WheelJoint((b2WheelJointDef*)def); + } + break; + + case e_weldJoint: + { + void* mem = allocator->Allocate(sizeof(b2WeldJoint)); + joint = new (mem) b2WeldJoint((b2WeldJointDef*)def); + } + break; + + case e_frictionJoint: + { + void* mem = allocator->Allocate(sizeof(b2FrictionJoint)); + joint = new (mem) b2FrictionJoint((b2FrictionJointDef*)def); + } + break; + + case e_ropeJoint: + { + void* mem = allocator->Allocate(sizeof(b2RopeJoint)); + joint = new (mem) b2RopeJoint((b2RopeJointDef*)def); + } + break; + + default: + b2Assert(false); + break; + } + + return joint; +} + +void b2Joint::Destroy(b2Joint* joint, b2BlockAllocator* allocator) +{ + joint->~b2Joint(); + switch (joint->m_type) + { + case e_distanceJoint: + allocator->Free(joint, sizeof(b2DistanceJoint)); + break; + + case e_mouseJoint: + allocator->Free(joint, sizeof(b2MouseJoint)); + break; + + case e_prismaticJoint: + allocator->Free(joint, sizeof(b2PrismaticJoint)); + break; + + case e_revoluteJoint: + allocator->Free(joint, sizeof(b2RevoluteJoint)); + break; + + case e_pulleyJoint: + allocator->Free(joint, sizeof(b2PulleyJoint)); + break; + + case e_gearJoint: + allocator->Free(joint, sizeof(b2GearJoint)); + break; + + case e_wheelJoint: + allocator->Free(joint, sizeof(b2WheelJoint)); + break; + + case e_weldJoint: + allocator->Free(joint, sizeof(b2WeldJoint)); + break; + + case e_frictionJoint: + allocator->Free(joint, sizeof(b2FrictionJoint)); + break; + + case e_ropeJoint: + allocator->Free(joint, sizeof(b2RopeJoint)); + break; + + default: + b2Assert(false); + break; + } +} + +b2Joint::b2Joint(const b2JointDef* def) +{ + b2Assert(def->bodyA != def->bodyB); + + m_type = def->type; + m_prev = NULL; + m_next = NULL; + m_bodyA = def->bodyA; + m_bodyB = def->bodyB; + m_index = 0; + m_collideConnected = def->collideConnected; + m_islandFlag = false; + m_userData = def->userData; + + m_edgeA.joint = NULL; + m_edgeA.other = NULL; + m_edgeA.prev = NULL; + m_edgeA.next = NULL; + + m_edgeB.joint = NULL; + m_edgeB.other = NULL; + m_edgeB.prev = NULL; + m_edgeB.next = NULL; +} + +bool b2Joint::IsActive() const +{ + return m_bodyA->IsActive() && m_bodyB->IsActive(); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2Joint.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2Joint.h new file mode 100755 index 0000000000000..90154ccb88d2a --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2Joint.h @@ -0,0 +1,222 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_JOINT_H +#define B2_JOINT_H + +#include + +class b2Body; +class b2Joint; +struct b2SolverData; +class b2BlockAllocator; + +enum b2JointType +{ + e_unknownJoint, + e_revoluteJoint, + e_prismaticJoint, + e_distanceJoint, + e_pulleyJoint, + e_mouseJoint, + e_gearJoint, + e_wheelJoint, + e_weldJoint, + e_frictionJoint, + e_ropeJoint +}; + +enum b2LimitState +{ + e_inactiveLimit, + e_atLowerLimit, + e_atUpperLimit, + e_equalLimits +}; + +struct b2Jacobian +{ + b2Vec2 linear; + float32 angularA; + float32 angularB; +}; + +/// A joint edge is used to connect bodies and joints together +/// in a joint graph where each body is a node and each joint +/// is an edge. A joint edge belongs to a doubly linked list +/// maintained in each attached body. Each joint has two joint +/// nodes, one for each attached body. +struct b2JointEdge +{ + b2Body* other; ///< provides quick access to the other body attached. + b2Joint* joint; ///< the joint + b2JointEdge* prev; ///< the previous joint edge in the body's joint list + b2JointEdge* next; ///< the next joint edge in the body's joint list +}; + +/// Joint definitions are used to construct joints. +struct b2JointDef +{ + b2JointDef() + { + type = e_unknownJoint; + userData = NULL; + bodyA = NULL; + bodyB = NULL; + collideConnected = false; + } + + /// The joint type is set automatically for concrete joint types. + b2JointType type; + + /// Use this to attach application specific data to your joints. + void* userData; + + /// The first attached body. + b2Body* bodyA; + + /// The second attached body. + b2Body* bodyB; + + /// Set this flag to true if the attached bodies should collide. + bool collideConnected; +}; + +/// The base joint class. Joints are used to constraint two bodies together in +/// various fashions. Some joints also feature limits and motors. +class b2Joint +{ +public: + + /// Get the type of the concrete joint. + b2JointType GetType() const; + + /// Get the first body attached to this joint. + b2Body* GetBodyA(); + + /// Get the second body attached to this joint. + b2Body* GetBodyB(); + + /// Get the anchor point on bodyA in world coordinates. + virtual b2Vec2 GetAnchorA() const = 0; + + /// Get the anchor point on bodyB in world coordinates. + virtual b2Vec2 GetAnchorB() const = 0; + + /// Get the reaction force on bodyB at the joint anchor in Newtons. + virtual b2Vec2 GetReactionForce(float32 inv_dt) const = 0; + + /// Get the reaction torque on bodyB in N*m. + virtual float32 GetReactionTorque(float32 inv_dt) const = 0; + + /// Get the next joint the world joint list. + b2Joint* GetNext(); + const b2Joint* GetNext() const; + + /// Get the user data pointer. + void* GetUserData() const; + + /// Set the user data pointer. + void SetUserData(void* data); + + /// Short-cut function to determine if either body is inactive. + bool IsActive() const; + + /// Get collide connected. + /// Note: modifying the collide connect flag won't work correctly because + /// the flag is only checked when fixture AABBs begin to overlap. + bool GetCollideConnected() const; + + /// Dump this joint to the log file. + virtual void Dump() { b2Log("// Dump is not supported for this joint type.\n"); } + +protected: + friend class b2World; + friend class b2Body; + friend class b2Island; + friend class b2GearJoint; + + static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator); + static void Destroy(b2Joint* joint, b2BlockAllocator* allocator); + + b2Joint(const b2JointDef* def); + virtual ~b2Joint() {} + + virtual void InitVelocityConstraints(const b2SolverData& data) = 0; + virtual void SolveVelocityConstraints(const b2SolverData& data) = 0; + + // This returns true if the position errors are within tolerance. + virtual bool SolvePositionConstraints(const b2SolverData& data) = 0; + + b2JointType m_type; + b2Joint* m_prev; + b2Joint* m_next; + b2JointEdge m_edgeA; + b2JointEdge m_edgeB; + b2Body* m_bodyA; + b2Body* m_bodyB; + + int32 m_index; + + bool m_islandFlag; + bool m_collideConnected; + + void* m_userData; +}; + +inline b2JointType b2Joint::GetType() const +{ + return m_type; +} + +inline b2Body* b2Joint::GetBodyA() +{ + return m_bodyA; +} + +inline b2Body* b2Joint::GetBodyB() +{ + return m_bodyB; +} + +inline b2Joint* b2Joint::GetNext() +{ + return m_next; +} + +inline const b2Joint* b2Joint::GetNext() const +{ + return m_next; +} + +inline void* b2Joint::GetUserData() const +{ + return m_userData; +} + +inline void b2Joint::SetUserData(void* data) +{ + m_userData = data; +} + +inline bool b2Joint::GetCollideConnected() const +{ + return m_collideConnected; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2MouseJoint.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2MouseJoint.cpp new file mode 100755 index 0000000000000..be7c38348306b --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2MouseJoint.cpp @@ -0,0 +1,217 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include + +// p = attached point, m = mouse point +// C = p - m +// Cdot = v +// = v + cross(w, r) +// J = [I r_skew] +// Identity used: +// w k % (rx i + ry j) = w * (-ry i + rx j) + +b2MouseJoint::b2MouseJoint(const b2MouseJointDef* def) +: b2Joint(def) +{ + b2Assert(def->target.IsValid()); + b2Assert(b2IsValid(def->maxForce) && def->maxForce >= 0.0f); + b2Assert(b2IsValid(def->frequencyHz) && def->frequencyHz >= 0.0f); + b2Assert(b2IsValid(def->dampingRatio) && def->dampingRatio >= 0.0f); + + m_targetA = def->target; + m_localAnchorB = b2MulT(m_bodyB->GetTransform(), m_targetA); + + m_maxForce = def->maxForce; + m_impulse.SetZero(); + + m_frequencyHz = def->frequencyHz; + m_dampingRatio = def->dampingRatio; + + m_beta = 0.0f; + m_gamma = 0.0f; +} + +void b2MouseJoint::SetTarget(const b2Vec2& target) +{ + if (m_bodyB->IsAwake() == false) + { + m_bodyB->SetAwake(true); + } + m_targetA = target; +} + +const b2Vec2& b2MouseJoint::GetTarget() const +{ + return m_targetA; +} + +void b2MouseJoint::SetMaxForce(float32 force) +{ + m_maxForce = force; +} + +float32 b2MouseJoint::GetMaxForce() const +{ + return m_maxForce; +} + +void b2MouseJoint::SetFrequency(float32 hz) +{ + m_frequencyHz = hz; +} + +float32 b2MouseJoint::GetFrequency() const +{ + return m_frequencyHz; +} + +void b2MouseJoint::SetDampingRatio(float32 ratio) +{ + m_dampingRatio = ratio; +} + +float32 b2MouseJoint::GetDampingRatio() const +{ + return m_dampingRatio; +} + +void b2MouseJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexB = m_bodyB->m_islandIndex; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassB = m_bodyB->m_invMass; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qB(aB); + + float32 mass = m_bodyB->GetMass(); + + // Frequency + float32 omega = 2.0f * b2_pi * m_frequencyHz; + + // Damping coefficient + float32 d = 2.0f * mass * m_dampingRatio * omega; + + // Spring stiffness + float32 k = mass * (omega * omega); + + // magic formulas + // gamma has units of inverse mass. + // beta has units of inverse time. + float32 h = data.step.dt; + b2Assert(d + h * k > b2_epsilon); + m_gamma = h * (d + h * k); + if (m_gamma != 0.0f) + { + m_gamma = 1.0f / m_gamma; + } + m_beta = h * k * m_gamma; + + // Compute the effective mass matrix. + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)] + // = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y] + // [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x] + b2Mat22 K; + K.ex.x = m_invMassB + m_invIB * m_rB.y * m_rB.y + m_gamma; + K.ex.y = -m_invIB * m_rB.x * m_rB.y; + K.ey.x = K.ex.y; + K.ey.y = m_invMassB + m_invIB * m_rB.x * m_rB.x + m_gamma; + + m_mass = K.GetInverse(); + + m_C = cB + m_rB - m_targetA; + m_C *= m_beta; + + // Cheat with some damping + wB *= 0.98f; + + if (data.step.warmStarting) + { + m_impulse *= data.step.dtRatio; + vB += m_invMassB * m_impulse; + wB += m_invIB * b2Cross(m_rB, m_impulse); + } + else + { + m_impulse.SetZero(); + } + + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2MouseJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + // Cdot = v + cross(w, r) + b2Vec2 Cdot = vB + b2Cross(wB, m_rB); + b2Vec2 impulse = b2Mul(m_mass, -(Cdot + m_C + m_gamma * m_impulse)); + + b2Vec2 oldImpulse = m_impulse; + m_impulse += impulse; + float32 maxImpulse = data.step.dt * m_maxForce; + if (m_impulse.LengthSquared() > maxImpulse * maxImpulse) + { + m_impulse *= maxImpulse / m_impulse.Length(); + } + impulse = m_impulse - oldImpulse; + + vB += m_invMassB * impulse; + wB += m_invIB * b2Cross(m_rB, impulse); + + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2MouseJoint::SolvePositionConstraints(const b2SolverData& data) +{ + B2_NOT_USED(data); + return true; +} + +b2Vec2 b2MouseJoint::GetAnchorA() const +{ + return m_targetA; +} + +b2Vec2 b2MouseJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2MouseJoint::GetReactionForce(float32 inv_dt) const +{ + return inv_dt * m_impulse; +} + +float32 b2MouseJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * 0.0f; +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2MouseJoint.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2MouseJoint.h new file mode 100755 index 0000000000000..f6df2b31ecc5f --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2MouseJoint.h @@ -0,0 +1,136 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_MOUSE_JOINT_H +#define B2_MOUSE_JOINT_H + +#include + +/// Mouse joint definition. This requires a world target point, +/// tuning parameters, and the time step. +// emscripten - b2MouseJointDef: add functions to set/get base class members +struct b2MouseJointDef : public b2JointDef +{ + b2MouseJointDef() + { + type = e_mouseJoint; + target.Set(0.0f, 0.0f); + maxForce = 0.0f; + frequencyHz = 5.0f; + dampingRatio = 0.7f; + } + + /// The initial world target point. This is assumed + /// to coincide with the body anchor initially. + b2Vec2 target; + + /// The maximum constraint force that can be exerted + /// to move the candidate body. Usually you will express + /// as some multiple of the weight (multiplier * mass * gravity). + float32 maxForce; + + /// The response speed. + float32 frequencyHz; + + /// The damping ratio. 0 = no damping, 1 = critical damping. + float32 dampingRatio; + + // to generate javascript bindings + void set_bodyA(b2Body* b) { bodyA = b; } + void set_bodyB(b2Body* b) { bodyB = b; } + void set_collideConnected(bool b) { collideConnected = b; } + b2Body* get_bodyA(b2Body* b) { return bodyA; } + b2Body* get_bodyB(b2Body* b) { return bodyB; } + bool get_collideConnected(bool b) { return collideConnected; } +}; + +/// A mouse joint is used to make a point on a body track a +/// specified world point. This a soft constraint with a maximum +/// force. This allows the constraint to stretch and without +/// applying huge forces. +/// NOTE: this joint is not documented in the manual because it was +/// developed to be used in the testbed. If you want to learn how to +/// use the mouse joint, look at the testbed. +// emscripten - b2MouseJoint: make constructor public +class b2MouseJoint : public b2Joint +{ +public: + + /// Implements b2Joint. + b2Vec2 GetAnchorA() const; + + /// Implements b2Joint. + b2Vec2 GetAnchorB() const; + + /// Implements b2Joint. + b2Vec2 GetReactionForce(float32 inv_dt) const; + + /// Implements b2Joint. + float32 GetReactionTorque(float32 inv_dt) const; + + /// Use this to update the target point. + void SetTarget(const b2Vec2& target); + const b2Vec2& GetTarget() const; + + /// Set/get the maximum force in Newtons. + void SetMaxForce(float32 force); + float32 GetMaxForce() const; + + /// Set/get the frequency in Hertz. + void SetFrequency(float32 hz); + float32 GetFrequency() const; + + /// Set/get the damping ratio (dimensionless). + void SetDampingRatio(float32 ratio); + float32 GetDampingRatio() const; + + /// The mouse joint does not support dumping. + void Dump() { b2Log("Mouse joint dumping is not supported.\n"); } + + b2MouseJoint(const b2MouseJointDef* def); + +protected: + friend class b2Joint; + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Vec2 m_localAnchorB; + b2Vec2 m_targetA; + float32 m_frequencyHz; + float32 m_dampingRatio; + float32 m_beta; + + // Solver shared + b2Vec2 m_impulse; + float32 m_maxForce; + float32 m_gamma; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rB; + b2Vec2 m_localCenterB; + float32 m_invMassB; + float32 m_invIB; + b2Mat22 m_mass; + b2Vec2 m_C; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp new file mode 100755 index 0000000000000..88a38807258c6 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp @@ -0,0 +1,637 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include + +// Linear constraint (point-to-line) +// d = p2 - p1 = x2 + r2 - x1 - r1 +// C = dot(perp, d) +// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1)) +// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2) +// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)] +// +// Angular constraint +// C = a2 - a1 + a_initial +// Cdot = w2 - w1 +// J = [0 0 -1 0 0 1] +// +// K = J * invM * JT +// +// J = [-a -s1 a s2] +// [0 -1 0 1] +// a = perp +// s1 = cross(d + r1, a) = cross(p2 - x1, a) +// s2 = cross(r2, a) = cross(p2 - x2, a) + + +// Motor/Limit linear constraint +// C = dot(ax1, d) +// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2) +// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)] + +// Block Solver +// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even +// when the mass has poor distribution (leading to large torques about the joint anchor points). +// +// The Jacobian has 3 rows: +// J = [-uT -s1 uT s2] // linear +// [0 -1 0 1] // angular +// [-vT -a1 vT a2] // limit +// +// u = perp +// v = axis +// s1 = cross(d + r1, u), s2 = cross(r2, u) +// a1 = cross(d + r1, v), a2 = cross(r2, v) + +// M * (v2 - v1) = JT * df +// J * v2 = bias +// +// v2 = v1 + invM * JT * df +// J * (v1 + invM * JT * df) = bias +// K * df = bias - J * v1 = -Cdot +// K = J * invM * JT +// Cdot = J * v1 - bias +// +// Now solve for f2. +// df = f2 - f1 +// K * (f2 - f1) = -Cdot +// f2 = invK * (-Cdot) + f1 +// +// Clamp accumulated limit impulse. +// lower: f2(3) = max(f2(3), 0) +// upper: f2(3) = min(f2(3), 0) +// +// Solve for correct f2(1:2) +// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1 +// = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3) +// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2) +// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) +// +// Now compute impulse to be applied: +// df = f2 - f1 + +void b2PrismaticJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); + localAxisA = bodyA->GetLocalVector(axis); + referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); +} + +b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_localXAxisA = def->localAxisA; + m_localXAxisA.Normalize(); + m_localYAxisA = b2Cross(1.0f, m_localXAxisA); + m_referenceAngle = def->referenceAngle; + + m_impulse.SetZero(); + m_motorMass = 0.0; + m_motorImpulse = 0.0f; + + m_lowerTranslation = def->lowerTranslation; + m_upperTranslation = def->upperTranslation; + m_maxMotorForce = def->maxMotorForce; + m_motorSpeed = def->motorSpeed; + m_enableLimit = def->enableLimit; + m_enableMotor = def->enableMotor; + m_limitState = e_inactiveLimit; + + m_axis.SetZero(); + m_perp.SetZero(); +} + +void b2PrismaticJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + // Compute the effective masses. + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 d = (cB - cA) + rB - rA; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + // Compute motor Jacobian and effective mass. + { + m_axis = b2Mul(qA, m_localXAxisA); + m_a1 = b2Cross(d + rA, m_axis); + m_a2 = b2Cross(rB, m_axis); + + m_motorMass = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; + if (m_motorMass > 0.0f) + { + m_motorMass = 1.0f / m_motorMass; + } + } + + // Prismatic constraint. + { + m_perp = b2Mul(qA, m_localYAxisA); + + m_s1 = b2Cross(d + rA, m_perp); + m_s2 = b2Cross(rB, m_perp); + + float32 k11 = mA + mB + iA * m_s1 * m_s1 + iB * m_s2 * m_s2; + float32 k12 = iA * m_s1 + iB * m_s2; + float32 k13 = iA * m_s1 * m_a1 + iB * m_s2 * m_a2; + float32 k22 = iA + iB; + if (k22 == 0.0f) + { + // For bodies with fixed rotation. + k22 = 1.0f; + } + float32 k23 = iA * m_a1 + iB * m_a2; + float32 k33 = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; + + m_K.ex.Set(k11, k12, k13); + m_K.ey.Set(k12, k22, k23); + m_K.ez.Set(k13, k23, k33); + } + + // Compute motor and limit terms. + if (m_enableLimit) + { + float32 jointTranslation = b2Dot(m_axis, d); + if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) + { + m_limitState = e_equalLimits; + } + else if (jointTranslation <= m_lowerTranslation) + { + if (m_limitState != e_atLowerLimit) + { + m_limitState = e_atLowerLimit; + m_impulse.z = 0.0f; + } + } + else if (jointTranslation >= m_upperTranslation) + { + if (m_limitState != e_atUpperLimit) + { + m_limitState = e_atUpperLimit; + m_impulse.z = 0.0f; + } + } + else + { + m_limitState = e_inactiveLimit; + m_impulse.z = 0.0f; + } + } + else + { + m_limitState = e_inactiveLimit; + m_impulse.z = 0.0f; + } + + if (m_enableMotor == false) + { + m_motorImpulse = 0.0f; + } + + if (data.step.warmStarting) + { + // Account for variable time step. + m_impulse *= data.step.dtRatio; + m_motorImpulse *= data.step.dtRatio; + + b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis; + float32 LA = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1; + float32 LB = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + else + { + m_impulse.SetZero(); + m_motorImpulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2PrismaticJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + // Solve linear motor constraint. + if (m_enableMotor && m_limitState != e_equalLimits) + { + float32 Cdot = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA; + float32 impulse = m_motorMass * (m_motorSpeed - Cdot); + float32 oldImpulse = m_motorImpulse; + float32 maxImpulse = data.step.dt * m_maxMotorForce; + m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); + impulse = m_motorImpulse - oldImpulse; + + b2Vec2 P = impulse * m_axis; + float32 LA = impulse * m_a1; + float32 LB = impulse * m_a2; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + + b2Vec2 Cdot1; + Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA; + Cdot1.y = wB - wA; + + if (m_enableLimit && m_limitState != e_inactiveLimit) + { + // Solve prismatic and limit constraint in block form. + float32 Cdot2; + Cdot2 = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA; + b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); + + b2Vec3 f1 = m_impulse; + b2Vec3 df = m_K.Solve33(-Cdot); + m_impulse += df; + + if (m_limitState == e_atLowerLimit) + { + m_impulse.z = b2Max(m_impulse.z, 0.0f); + } + else if (m_limitState == e_atUpperLimit) + { + m_impulse.z = b2Min(m_impulse.z, 0.0f); + } + + // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) + b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.ez.x, m_K.ez.y); + b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y); + m_impulse.x = f2r.x; + m_impulse.y = f2r.y; + + df = m_impulse - f1; + + b2Vec2 P = df.x * m_perp + df.z * m_axis; + float32 LA = df.x * m_s1 + df.y + df.z * m_a1; + float32 LB = df.x * m_s2 + df.y + df.z * m_a2; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + else + { + // Limit is inactive, just solve the prismatic constraint in block form. + b2Vec2 df = m_K.Solve22(-Cdot1); + m_impulse.x += df.x; + m_impulse.y += df.y; + + b2Vec2 P = df.x * m_perp; + float32 LA = df.x * m_s1 + df.y; + float32 LB = df.x * m_s2 + df.y; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + + b2Vec2 Cdot10 = Cdot1; + + Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA; + Cdot1.y = wB - wA; + + if (b2Abs(Cdot1.x) > 0.01f || b2Abs(Cdot1.y) > 0.01f) + { + b2Vec2 test = b2Mul22(m_K, df); + Cdot1.x += 0.0f; + } + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2PrismaticJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + // Compute fresh Jacobians + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 d = cB + rB - cA - rA; + + b2Vec2 axis = b2Mul(qA, m_localXAxisA); + float32 a1 = b2Cross(d + rA, axis); + float32 a2 = b2Cross(rB, axis); + b2Vec2 perp = b2Mul(qA, m_localYAxisA); + + float32 s1 = b2Cross(d + rA, perp); + float32 s2 = b2Cross(rB, perp); + + b2Vec3 impulse; + b2Vec2 C1; + C1.x = b2Dot(perp, d); + C1.y = aB - aA - m_referenceAngle; + + float32 linearError = b2Abs(C1.x); + float32 angularError = b2Abs(C1.y); + + bool active = false; + float32 C2 = 0.0f; + if (m_enableLimit) + { + float32 translation = b2Dot(axis, d); + if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) + { + // Prevent large angular corrections + C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection); + linearError = b2Max(linearError, b2Abs(translation)); + active = true; + } + else if (translation <= m_lowerTranslation) + { + // Prevent large linear corrections and allow some slop. + C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); + linearError = b2Max(linearError, m_lowerTranslation - translation); + active = true; + } + else if (translation >= m_upperTranslation) + { + // Prevent large linear corrections and allow some slop. + C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection); + linearError = b2Max(linearError, translation - m_upperTranslation); + active = true; + } + } + + if (active) + { + float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2; + float32 k12 = iA * s1 + iB * s2; + float32 k13 = iA * s1 * a1 + iB * s2 * a2; + float32 k22 = iA + iB; + if (k22 == 0.0f) + { + // For fixed rotation + k22 = 1.0f; + } + float32 k23 = iA * a1 + iB * a2; + float32 k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2; + + b2Mat33 K; + K.ex.Set(k11, k12, k13); + K.ey.Set(k12, k22, k23); + K.ez.Set(k13, k23, k33); + + b2Vec3 C; + C.x = C1.x; + C.y = C1.y; + C.z = C2; + + impulse = K.Solve33(-C); + } + else + { + float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2; + float32 k12 = iA * s1 + iB * s2; + float32 k22 = iA + iB; + if (k22 == 0.0f) + { + k22 = 1.0f; + } + + b2Mat22 K; + K.ex.Set(k11, k12); + K.ey.Set(k12, k22); + + b2Vec2 impulse1 = K.Solve(-C1); + impulse.x = impulse1.x; + impulse.y = impulse1.y; + impulse.z = 0.0f; + } + + b2Vec2 P = impulse.x * perp + impulse.z * axis; + float32 LA = impulse.x * s1 + impulse.y + impulse.z * a1; + float32 LB = impulse.x * s2 + impulse.y + impulse.z * a2; + + cA -= mA * P; + aA -= iA * LA; + cB += mB * P; + aB += iB * LB; + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return linearError <= b2_linearSlop && angularError <= b2_angularSlop; +} + +b2Vec2 b2PrismaticJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2PrismaticJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const +{ + return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis); +} + +float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_impulse.y; +} + +float32 b2PrismaticJoint::GetJointTranslation() const +{ + b2Vec2 pA = m_bodyA->GetWorldPoint(m_localAnchorA); + b2Vec2 pB = m_bodyB->GetWorldPoint(m_localAnchorB); + b2Vec2 d = pB - pA; + b2Vec2 axis = m_bodyA->GetWorldVector(m_localXAxisA); + + float32 translation = b2Dot(d, axis); + return translation; +} + +float32 b2PrismaticJoint::GetJointSpeed() const +{ + b2Body* bA = m_bodyA; + b2Body* bB = m_bodyB; + + b2Vec2 rA = b2Mul(bA->m_xf.q, m_localAnchorA - bA->m_sweep.localCenter); + b2Vec2 rB = b2Mul(bB->m_xf.q, m_localAnchorB - bB->m_sweep.localCenter); + b2Vec2 p1 = bA->m_sweep.c + rA; + b2Vec2 p2 = bB->m_sweep.c + rB; + b2Vec2 d = p2 - p1; + b2Vec2 axis = b2Mul(bA->m_xf.q, m_localXAxisA); + + b2Vec2 vA = bA->m_linearVelocity; + b2Vec2 vB = bB->m_linearVelocity; + float32 wA = bA->m_angularVelocity; + float32 wB = bB->m_angularVelocity; + + float32 speed = b2Dot(d, b2Cross(wA, axis)) + b2Dot(axis, vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA)); + return speed; +} + +bool b2PrismaticJoint::IsLimitEnabled() const +{ + return m_enableLimit; +} + +void b2PrismaticJoint::EnableLimit(bool flag) +{ + if (flag != m_enableLimit) + { + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableLimit = flag; + m_impulse.z = 0.0f; + } +} + +float32 b2PrismaticJoint::GetLowerLimit() const +{ + return m_lowerTranslation; +} + +float32 b2PrismaticJoint::GetUpperLimit() const +{ + return m_upperTranslation; +} + +void b2PrismaticJoint::SetLimits(float32 lower, float32 upper) +{ + b2Assert(lower <= upper); + if (lower != m_lowerTranslation || upper != m_upperTranslation) + { + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_lowerTranslation = lower; + m_upperTranslation = upper; + m_impulse.z = 0.0f; + } +} + +bool b2PrismaticJoint::IsMotorEnabled() const +{ + return m_enableMotor; +} + +void b2PrismaticJoint::EnableMotor(bool flag) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableMotor = flag; +} + +void b2PrismaticJoint::SetMotorSpeed(float32 speed) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_motorSpeed = speed; +} + +void b2PrismaticJoint::SetMaxMotorForce(float32 force) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_maxMotorForce = force; +} + +float32 b2PrismaticJoint::GetMotorForce(float32 inv_dt) const +{ + return inv_dt * m_motorImpulse; +} + +void b2PrismaticJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2PrismaticJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y); + b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); + b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit); + b2Log(" jd.lowerTranslation = %.15lef;\n", m_lowerTranslation); + b2Log(" jd.upperTranslation = %.15lef;\n", m_upperTranslation); + b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); + b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); + b2Log(" jd.maxMotorForce = %.15lef;\n", m_maxMotorForce); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PrismaticJoint.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PrismaticJoint.h new file mode 100755 index 0000000000000..b1b50a88cf4b8 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PrismaticJoint.h @@ -0,0 +1,207 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_PRISMATIC_JOINT_H +#define B2_PRISMATIC_JOINT_H + +#include + +/// Prismatic joint definition. This requires defining a line of +/// motion using an axis and an anchor point. The definition uses local +/// anchor points and a local axis so that the initial configuration +/// can violate the constraint slightly. The joint translation is zero +/// when the local anchor points coincide in world space. Using local +/// anchors and a local axis helps when saving and loading a game. +// emscripten - b2PrismaticJointDef: add functions to set/get base class members +struct b2PrismaticJointDef : public b2JointDef +{ + b2PrismaticJointDef() + { + type = e_prismaticJoint; + localAnchorA.SetZero(); + localAnchorB.SetZero(); + localAxisA.Set(1.0f, 0.0f); + referenceAngle = 0.0f; + enableLimit = false; + lowerTranslation = 0.0f; + upperTranslation = 0.0f; + enableMotor = false; + maxMotorForce = 0.0f; + motorSpeed = 0.0f; + } + + /// Initialize the bodies, anchors, axis, and reference angle using the world + /// anchor and unit world axis. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The local translation unit axis in bodyA. + b2Vec2 localAxisA; + + /// The constrained angle between the bodies: bodyB_angle - bodyA_angle. + float32 referenceAngle; + + /// Enable/disable the joint limit. + bool enableLimit; + + /// The lower translation limit, usually in meters. + float32 lowerTranslation; + + /// The upper translation limit, usually in meters. + float32 upperTranslation; + + /// Enable/disable the joint motor. + bool enableMotor; + + /// The maximum motor torque, usually in N-m. + float32 maxMotorForce; + + /// The desired motor speed in radians per second. + float32 motorSpeed; + + // to generate javascript bindings + void set_bodyA(b2Body* b) { bodyA = b; } + void set_bodyB(b2Body* b) { bodyB = b; } + void set_collideConnected(bool b) { collideConnected = b; } + b2Body* get_bodyA(b2Body* b) { return bodyA; } + b2Body* get_bodyB(b2Body* b) { return bodyB; } + bool get_collideConnected(bool b) { return collideConnected; } +}; + +/// A prismatic joint. This joint provides one degree of freedom: translation +/// along an axis fixed in bodyA. Relative rotation is prevented. You can +/// use a joint limit to restrict the range of motion and a joint motor to +/// drive the motion or to model joint friction. +// emscripten - b2PrismaticJoint: make constructor public +class b2PrismaticJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// The local joint axis relative to bodyA. + const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; } + + /// Get the reference angle. + float32 GetReferenceAngle() const { return m_referenceAngle; } + + /// Get the current joint translation, usually in meters. + float32 GetJointTranslation() const; + + /// Get the current joint translation speed, usually in meters per second. + float32 GetJointSpeed() const; + + /// Is the joint limit enabled? + bool IsLimitEnabled() const; + + /// Enable/disable the joint limit. + void EnableLimit(bool flag); + + /// Get the lower joint limit, usually in meters. + float32 GetLowerLimit() const; + + /// Get the upper joint limit, usually in meters. + float32 GetUpperLimit() const; + + /// Set the joint limits, usually in meters. + void SetLimits(float32 lower, float32 upper); + + /// Is the joint motor enabled? + bool IsMotorEnabled() const; + + /// Enable/disable the joint motor. + void EnableMotor(bool flag); + + /// Set the motor speed, usually in meters per second. + void SetMotorSpeed(float32 speed); + + /// Get the motor speed, usually in meters per second. + float32 GetMotorSpeed() const; + + /// Set the maximum motor force, usually in N. + void SetMaxMotorForce(float32 force); + float32 GetMaxMotorForce() const { return m_maxMotorForce; } + + /// Get the current motor force given the inverse time step, usually in N. + float32 GetMotorForce(float32 inv_dt) const; + + /// Dump to b2Log + void Dump(); + + b2PrismaticJoint(const b2PrismaticJointDef* def); + +protected: + friend class b2Joint; + friend class b2GearJoint; + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec2 m_localXAxisA; + b2Vec2 m_localYAxisA; + float32 m_referenceAngle; + b2Vec3 m_impulse; + float32 m_motorImpulse; + float32 m_lowerTranslation; + float32 m_upperTranslation; + float32 m_maxMotorForce; + float32 m_motorSpeed; + bool m_enableLimit; + bool m_enableMotor; + b2LimitState m_limitState; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Vec2 m_axis, m_perp; + float32 m_s1, m_s2; + float32 m_a1, m_a2; + b2Mat33 m_K; + float32 m_motorMass; +}; + +inline float32 b2PrismaticJoint::GetMotorSpeed() const +{ + return m_motorSpeed; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PulleyJoint.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PulleyJoint.cpp new file mode 100755 index 0000000000000..e0bb7da5130e5 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PulleyJoint.cpp @@ -0,0 +1,332 @@ +/* +* Copyright (c) 2007 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include + +// Pulley: +// length1 = norm(p1 - s1) +// length2 = norm(p2 - s2) +// C0 = (length1 + ratio * length2)_initial +// C = C0 - (length1 + ratio * length2) +// u1 = (p1 - s1) / norm(p1 - s1) +// u2 = (p2 - s2) / norm(p2 - s2) +// Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2)) +// J = -[u1 cross(r1, u1) ratio * u2 ratio * cross(r2, u2)] +// K = J * invM * JT +// = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2) + +void b2PulleyJointDef::Initialize(b2Body* bA, b2Body* bB, + const b2Vec2& groundA, const b2Vec2& groundB, + const b2Vec2& anchorA, const b2Vec2& anchorB, + float32 r) +{ + bodyA = bA; + bodyB = bB; + groundAnchorA = groundA; + groundAnchorB = groundB; + localAnchorA = bodyA->GetLocalPoint(anchorA); + localAnchorB = bodyB->GetLocalPoint(anchorB); + b2Vec2 dA = anchorA - groundA; + lengthA = dA.Length(); + b2Vec2 dB = anchorB - groundB; + lengthB = dB.Length(); + ratio = r; + b2Assert(ratio > b2_epsilon); +} + +b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def) +: b2Joint(def) +{ + m_groundAnchorA = def->groundAnchorA; + m_groundAnchorB = def->groundAnchorB; + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + + m_lengthA = def->lengthA; + m_lengthB = def->lengthB; + + b2Assert(def->ratio != 0.0f); + m_ratio = def->ratio; + + m_constant = def->lengthA + m_ratio * def->lengthB; + + m_impulse = 0.0f; +} + +void b2PulleyJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // Get the pulley axes. + m_uA = cA + m_rA - m_groundAnchorA; + m_uB = cB + m_rB - m_groundAnchorB; + + float32 lengthA = m_uA.Length(); + float32 lengthB = m_uB.Length(); + + if (lengthA > 10.0f * b2_linearSlop) + { + m_uA *= 1.0f / lengthA; + } + else + { + m_uA.SetZero(); + } + + if (lengthB > 10.0f * b2_linearSlop) + { + m_uB *= 1.0f / lengthB; + } + else + { + m_uB.SetZero(); + } + + // Compute effective mass. + float32 ruA = b2Cross(m_rA, m_uA); + float32 ruB = b2Cross(m_rB, m_uB); + + float32 mA = m_invMassA + m_invIA * ruA * ruA; + float32 mB = m_invMassB + m_invIB * ruB * ruB; + + m_mass = mA + m_ratio * m_ratio * mB; + + if (m_mass > 0.0f) + { + m_mass = 1.0f / m_mass; + } + + if (data.step.warmStarting) + { + // Scale impulses to support variable time steps. + m_impulse *= data.step.dtRatio; + + // Warm starting. + b2Vec2 PA = -(m_impulse) * m_uA; + b2Vec2 PB = (-m_ratio * m_impulse) * m_uB; + + vA += m_invMassA * PA; + wA += m_invIA * b2Cross(m_rA, PA); + vB += m_invMassB * PB; + wB += m_invIB * b2Cross(m_rB, PB); + } + else + { + m_impulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2PulleyJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Vec2 vpA = vA + b2Cross(wA, m_rA); + b2Vec2 vpB = vB + b2Cross(wB, m_rB); + + float32 Cdot = -b2Dot(m_uA, vpA) - m_ratio * b2Dot(m_uB, vpB); + float32 impulse = -m_mass * Cdot; + m_impulse += impulse; + + b2Vec2 PA = -impulse * m_uA; + b2Vec2 PB = -m_ratio * impulse * m_uB; + vA += m_invMassA * PA; + wA += m_invIA * b2Cross(m_rA, PA); + vB += m_invMassB * PB; + wB += m_invIB * b2Cross(m_rB, PB); + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2PulleyJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // Get the pulley axes. + b2Vec2 uA = cA + rA - m_groundAnchorA; + b2Vec2 uB = cB + rB - m_groundAnchorB; + + float32 lengthA = uA.Length(); + float32 lengthB = uB.Length(); + + if (lengthA > 10.0f * b2_linearSlop) + { + uA *= 1.0f / lengthA; + } + else + { + uA.SetZero(); + } + + if (lengthB > 10.0f * b2_linearSlop) + { + uB *= 1.0f / lengthB; + } + else + { + uB.SetZero(); + } + + // Compute effective mass. + float32 ruA = b2Cross(rA, uA); + float32 ruB = b2Cross(rB, uB); + + float32 mA = m_invMassA + m_invIA * ruA * ruA; + float32 mB = m_invMassB + m_invIB * ruB * ruB; + + float32 mass = mA + m_ratio * m_ratio * mB; + + if (mass > 0.0f) + { + mass = 1.0f / mass; + } + + float32 C = m_constant - lengthA - m_ratio * lengthB; + float32 linearError = b2Abs(C); + + float32 impulse = -mass * C; + + b2Vec2 PA = -impulse * uA; + b2Vec2 PB = -m_ratio * impulse * uB; + + cA += m_invMassA * PA; + aA += m_invIA * b2Cross(rA, PA); + cB += m_invMassB * PB; + aB += m_invIB * b2Cross(rB, PB); + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return linearError < b2_linearSlop; +} + +b2Vec2 b2PulleyJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2PulleyJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2PulleyJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 P = m_impulse * m_uB; + return inv_dt * P; +} + +float32 b2PulleyJoint::GetReactionTorque(float32 inv_dt) const +{ + B2_NOT_USED(inv_dt); + return 0.0f; +} + +b2Vec2 b2PulleyJoint::GetGroundAnchorA() const +{ + return m_groundAnchorA; +} + +b2Vec2 b2PulleyJoint::GetGroundAnchorB() const +{ + return m_groundAnchorB; +} + +float32 b2PulleyJoint::GetLengthA() const +{ + b2Vec2 p = m_bodyA->GetWorldPoint(m_localAnchorA); + b2Vec2 s = m_groundAnchorA; + b2Vec2 d = p - s; + return d.Length(); +} + +float32 b2PulleyJoint::GetLengthB() const +{ + b2Vec2 p = m_bodyB->GetWorldPoint(m_localAnchorB); + b2Vec2 s = m_groundAnchorB; + b2Vec2 d = p - s; + return d.Length(); +} + +float32 b2PulleyJoint::GetRatio() const +{ + return m_ratio; +} + +void b2PulleyJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2PulleyJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.groundAnchorA.Set(%.15lef, %.15lef);\n", m_groundAnchorA.x, m_groundAnchorA.y); + b2Log(" jd.groundAnchorB.Set(%.15lef, %.15lef);\n", m_groundAnchorB.x, m_groundAnchorB.y); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.lengthA = %.15lef;\n", m_lengthA); + b2Log(" jd.lengthB = %.15lef;\n", m_lengthB); + b2Log(" jd.ratio = %.15lef;\n", m_ratio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PulleyJoint.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PulleyJoint.h new file mode 100755 index 0000000000000..d27583c9c9ef8 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PulleyJoint.h @@ -0,0 +1,154 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_PULLEY_JOINT_H +#define B2_PULLEY_JOINT_H + +#include + +const float32 b2_minPulleyLength = 2.0f; + +/// Pulley joint definition. This requires two ground anchors, +/// two dynamic body anchor points, and a pulley ratio. +// emscripten - b2PulleyJointDef: add functions to set/get base class members +struct b2PulleyJointDef : public b2JointDef +{ + b2PulleyJointDef() + { + type = e_pulleyJoint; + groundAnchorA.Set(-1.0f, 1.0f); + groundAnchorB.Set(1.0f, 1.0f); + localAnchorA.Set(-1.0f, 0.0f); + localAnchorB.Set(1.0f, 0.0f); + lengthA = 0.0f; + lengthB = 0.0f; + ratio = 1.0f; + collideConnected = true; + } + + /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors. + void Initialize(b2Body* bodyA, b2Body* bodyB, + const b2Vec2& groundAnchorA, const b2Vec2& groundAnchorB, + const b2Vec2& anchorA, const b2Vec2& anchorB, + float32 ratio); + + /// The first ground anchor in world coordinates. This point never moves. + b2Vec2 groundAnchorA; + + /// The second ground anchor in world coordinates. This point never moves. + b2Vec2 groundAnchorB; + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The a reference length for the segment attached to bodyA. + float32 lengthA; + + /// The a reference length for the segment attached to bodyB. + float32 lengthB; + + /// The pulley ratio, used to simulate a block-and-tackle. + float32 ratio; + + // to generate javascript bindings + void set_bodyA(b2Body* b) { bodyA = b; } + void set_bodyB(b2Body* b) { bodyB = b; } + void set_collideConnected(bool b) { collideConnected = b; } + b2Body* get_bodyA(b2Body* b) { return bodyA; } + b2Body* get_bodyB(b2Body* b) { return bodyB; } + bool get_collideConnected(bool b) { return collideConnected; } +}; + +/// The pulley joint is connected to two bodies and two fixed ground points. +/// The pulley supports a ratio such that: +/// length1 + ratio * length2 <= constant +/// Yes, the force transmitted is scaled by the ratio. +/// Warning: the pulley joint can get a bit squirrelly by itself. They often +/// work better when combined with prismatic joints. You should also cover the +/// the anchor points with static shapes to prevent one side from going to +/// zero length. +// emscripten - b2PulleyJoint: make constructor public +class b2PulleyJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// Get the first ground anchor. + b2Vec2 GetGroundAnchorA() const; + + /// Get the second ground anchor. + b2Vec2 GetGroundAnchorB() const; + + /// Get the current length of the segment attached to bodyA. + float32 GetLengthA() const; + + /// Get the current length of the segment attached to bodyB. + float32 GetLengthB() const; + + /// Get the pulley ratio. + float32 GetRatio() const; + + /// Dump joint to dmLog + void Dump(); + + b2PulleyJoint(const b2PulleyJointDef* data); + +protected: + + friend class b2Joint; + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Vec2 m_groundAnchorA; + b2Vec2 m_groundAnchorB; + float32 m_lengthA; + float32 m_lengthB; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_constant; + float32 m_ratio; + float32 m_impulse; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_uA; + b2Vec2 m_uB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + float32 m_mass; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp new file mode 100755 index 0000000000000..ffb17252c7a68 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp @@ -0,0 +1,504 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include + +// Point-to-point constraint +// C = p2 - p1 +// Cdot = v2 - v1 +// = v2 + cross(w2, r2) - v1 - cross(w1, r1) +// J = [-I -r1_skew I r2_skew ] +// Identity used: +// w k % (rx i + ry j) = w * (-ry i + rx j) + +// Motor constraint +// Cdot = w2 - w1 +// J = [0 0 -1 0 0 1] +// K = invI1 + invI2 + +void b2RevoluteJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); + referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); +} + +b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_referenceAngle = def->referenceAngle; + + m_impulse.SetZero(); + m_motorImpulse = 0.0f; + + m_lowerAngle = def->lowerAngle; + m_upperAngle = def->upperAngle; + m_maxMotorTorque = def->maxMotorTorque; + m_motorSpeed = def->motorSpeed; + m_enableLimit = def->enableLimit; + m_enableMotor = def->enableMotor; + m_limitState = e_inactiveLimit; +} + +void b2RevoluteJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // J = [-I -r1_skew I r2_skew] + // [ 0 -1 0 1] + // r_skew = [-ry; rx] + + // Matlab + // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] + // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] + // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + bool fixedRotation = (iA + iB == 0.0f); + + m_mass.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB; + m_mass.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB; + m_mass.ez.x = -m_rA.y * iA - m_rB.y * iB; + m_mass.ex.y = m_mass.ey.x; + m_mass.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB; + m_mass.ez.y = m_rA.x * iA + m_rB.x * iB; + m_mass.ex.z = m_mass.ez.x; + m_mass.ey.z = m_mass.ez.y; + m_mass.ez.z = iA + iB; + + m_motorMass = iA + iB; + if (m_motorMass > 0.0f) + { + m_motorMass = 1.0f / m_motorMass; + } + + if (m_enableMotor == false || fixedRotation) + { + m_motorImpulse = 0.0f; + } + + if (m_enableLimit && fixedRotation == false) + { + float32 jointAngle = aB - aA - m_referenceAngle; + if (b2Abs(m_upperAngle - m_lowerAngle) < 2.0f * b2_angularSlop) + { + m_limitState = e_equalLimits; + } + else if (jointAngle <= m_lowerAngle) + { + if (m_limitState != e_atLowerLimit) + { + m_impulse.z = 0.0f; + } + m_limitState = e_atLowerLimit; + } + else if (jointAngle >= m_upperAngle) + { + if (m_limitState != e_atUpperLimit) + { + m_impulse.z = 0.0f; + } + m_limitState = e_atUpperLimit; + } + else + { + m_limitState = e_inactiveLimit; + m_impulse.z = 0.0f; + } + } + else + { + m_limitState = e_inactiveLimit; + } + + if (data.step.warmStarting) + { + // Scale impulses to support a variable time step. + m_impulse *= data.step.dtRatio; + m_motorImpulse *= data.step.dtRatio; + + b2Vec2 P(m_impulse.x, m_impulse.y); + + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + m_motorImpulse + m_impulse.z); + + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + m_motorImpulse + m_impulse.z); + } + else + { + m_impulse.SetZero(); + m_motorImpulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2RevoluteJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + bool fixedRotation = (iA + iB == 0.0f); + + // Solve motor constraint. + if (m_enableMotor && m_limitState != e_equalLimits && fixedRotation == false) + { + float32 Cdot = wB - wA - m_motorSpeed; + float32 impulse = -m_motorMass * Cdot; + float32 oldImpulse = m_motorImpulse; + float32 maxImpulse = data.step.dt * m_maxMotorTorque; + m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); + impulse = m_motorImpulse - oldImpulse; + + wA -= iA * impulse; + wB += iB * impulse; + } + + // Solve limit constraint. + if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false) + { + b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + float32 Cdot2 = wB - wA; + b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); + + b2Vec3 impulse = -m_mass.Solve33(Cdot); + + if (m_limitState == e_equalLimits) + { + m_impulse += impulse; + } + else if (m_limitState == e_atLowerLimit) + { + float32 newImpulse = m_impulse.z + impulse.z; + if (newImpulse < 0.0f) + { + b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y); + b2Vec2 reduced = m_mass.Solve22(rhs); + impulse.x = reduced.x; + impulse.y = reduced.y; + impulse.z = -m_impulse.z; + m_impulse.x += reduced.x; + m_impulse.y += reduced.y; + m_impulse.z = 0.0f; + } + else + { + m_impulse += impulse; + } + } + else if (m_limitState == e_atUpperLimit) + { + float32 newImpulse = m_impulse.z + impulse.z; + if (newImpulse > 0.0f) + { + b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y); + b2Vec2 reduced = m_mass.Solve22(rhs); + impulse.x = reduced.x; + impulse.y = reduced.y; + impulse.z = -m_impulse.z; + m_impulse.x += reduced.x; + m_impulse.y += reduced.y; + m_impulse.z = 0.0f; + } + else + { + m_impulse += impulse; + } + } + + b2Vec2 P(impulse.x, impulse.y); + + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + impulse.z); + + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + impulse.z); + } + else + { + // Solve point-to-point constraint + b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + b2Vec2 impulse = m_mass.Solve22(-Cdot); + + m_impulse.x += impulse.x; + m_impulse.y += impulse.y; + + vA -= mA * impulse; + wA -= iA * b2Cross(m_rA, impulse); + + vB += mB * impulse; + wB += iB * b2Cross(m_rB, impulse); + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2RevoluteJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + float32 angularError = 0.0f; + float32 positionError = 0.0f; + + bool fixedRotation = (m_invIA + m_invIB == 0.0f); + + // Solve angular limit constraint. + if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false) + { + float32 angle = aB - aA - m_referenceAngle; + float32 limitImpulse = 0.0f; + + if (m_limitState == e_equalLimits) + { + // Prevent large angular corrections + float32 C = b2Clamp(angle - m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection); + limitImpulse = -m_motorMass * C; + angularError = b2Abs(C); + } + else if (m_limitState == e_atLowerLimit) + { + float32 C = angle - m_lowerAngle; + angularError = -C; + + // Prevent large angular corrections and allow some slop. + C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0.0f); + limitImpulse = -m_motorMass * C; + } + else if (m_limitState == e_atUpperLimit) + { + float32 C = angle - m_upperAngle; + angularError = C; + + // Prevent large angular corrections and allow some slop. + C = b2Clamp(C - b2_angularSlop, 0.0f, b2_maxAngularCorrection); + limitImpulse = -m_motorMass * C; + } + + aA -= m_invIA * limitImpulse; + aB += m_invIB * limitImpulse; + } + + // Solve point-to-point constraint. + { + qA.Set(aA); + qB.Set(aB); + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + b2Vec2 C = cB + rB - cA - rA; + positionError = C.Length(); + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Mat22 K; + K.ex.x = mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y; + K.ex.y = -iA * rA.x * rA.y - iB * rB.x * rB.y; + K.ey.x = K.ex.y; + K.ey.y = mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x; + + b2Vec2 impulse = -K.Solve(C); + + cA -= mA * impulse; + aA -= iA * b2Cross(rA, impulse); + + cB += mB * impulse; + aB += iB * b2Cross(rB, impulse); + } + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return positionError <= b2_linearSlop && angularError <= b2_angularSlop; +} + +b2Vec2 b2RevoluteJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2RevoluteJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2RevoluteJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 P(m_impulse.x, m_impulse.y); + return inv_dt * P; +} + +float32 b2RevoluteJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_impulse.z; +} + +float32 b2RevoluteJoint::GetJointAngle() const +{ + b2Body* bA = m_bodyA; + b2Body* bB = m_bodyB; + return bB->m_sweep.a - bA->m_sweep.a - m_referenceAngle; +} + +float32 b2RevoluteJoint::GetJointSpeed() const +{ + b2Body* bA = m_bodyA; + b2Body* bB = m_bodyB; + return bB->m_angularVelocity - bA->m_angularVelocity; +} + +bool b2RevoluteJoint::IsMotorEnabled() const +{ + return m_enableMotor; +} + +void b2RevoluteJoint::EnableMotor(bool flag) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableMotor = flag; +} + +float32 b2RevoluteJoint::GetMotorTorque(float32 inv_dt) const +{ + return inv_dt * m_motorImpulse; +} + +void b2RevoluteJoint::SetMotorSpeed(float32 speed) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_motorSpeed = speed; +} + +void b2RevoluteJoint::SetMaxMotorTorque(float32 torque) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_maxMotorTorque = torque; +} + +bool b2RevoluteJoint::IsLimitEnabled() const +{ + return m_enableLimit; +} + +void b2RevoluteJoint::EnableLimit(bool flag) +{ + if (flag != m_enableLimit) + { + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableLimit = flag; + m_impulse.z = 0.0f; + } +} + +float32 b2RevoluteJoint::GetLowerLimit() const +{ + return m_lowerAngle; +} + +float32 b2RevoluteJoint::GetUpperLimit() const +{ + return m_upperAngle; +} + +void b2RevoluteJoint::SetLimits(float32 lower, float32 upper) +{ + b2Assert(lower <= upper); + + if (lower != m_lowerAngle || upper != m_upperAngle) + { + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_impulse.z = 0.0f; + m_lowerAngle = lower; + m_upperAngle = upper; + } +} + +void b2RevoluteJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2RevoluteJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); + b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit); + b2Log(" jd.lowerAngle = %.15lef;\n", m_lowerAngle); + b2Log(" jd.upperAngle = %.15lef;\n", m_upperAngle); + b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); + b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); + b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RevoluteJoint.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RevoluteJoint.h new file mode 100755 index 0000000000000..672ef1699ec89 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RevoluteJoint.h @@ -0,0 +1,214 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_REVOLUTE_JOINT_H +#define B2_REVOLUTE_JOINT_H + +#include + +/// Revolute joint definition. This requires defining an +/// anchor point where the bodies are joined. The definition +/// uses local anchor points so that the initial configuration +/// can violate the constraint slightly. You also need to +/// specify the initial relative angle for joint limits. This +/// helps when saving and loading a game. +/// The local anchor points are measured from the body's origin +/// rather than the center of mass because: +/// 1. you might not know where the center of mass will be. +/// 2. if you add/remove shapes from a body and recompute the mass, +/// the joints will be broken. +// emscripten - b2RevoluteJointDef: add functions to set/get base class members +struct b2RevoluteJointDef : public b2JointDef +{ + b2RevoluteJointDef() + { + type = e_revoluteJoint; + localAnchorA.Set(0.0f, 0.0f); + localAnchorB.Set(0.0f, 0.0f); + referenceAngle = 0.0f; + lowerAngle = 0.0f; + upperAngle = 0.0f; + maxMotorTorque = 0.0f; + motorSpeed = 0.0f; + enableLimit = false; + enableMotor = false; + } + + /// Initialize the bodies, anchors, and reference angle using a world + /// anchor point. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The bodyB angle minus bodyA angle in the reference state (radians). + float32 referenceAngle; + + /// A flag to enable joint limits. + bool enableLimit; + + /// The lower angle for the joint limit (radians). + float32 lowerAngle; + + /// The upper angle for the joint limit (radians). + float32 upperAngle; + + /// A flag to enable the joint motor. + bool enableMotor; + + /// The desired motor speed. Usually in radians per second. + float32 motorSpeed; + + /// The maximum motor torque used to achieve the desired motor speed. + /// Usually in N-m. + float32 maxMotorTorque; + + // to generate javascript bindings + void set_bodyA(b2Body* b) { bodyA = b; } + void set_bodyB(b2Body* b) { bodyB = b; } + void set_collideConnected(bool b) { collideConnected = b; } + b2Body* get_bodyA(b2Body* b) { return bodyA; } + b2Body* get_bodyB(b2Body* b) { return bodyB; } + bool get_collideConnected(bool b) { return collideConnected; } +}; + +/// A revolute joint constrains two bodies to share a common point while they +/// are free to rotate about the point. The relative rotation about the shared +/// point is the joint angle. You can limit the relative rotation with +/// a joint limit that specifies a lower and upper angle. You can use a motor +/// to drive the relative rotation about the shared point. A maximum motor torque +/// is provided so that infinite forces are not generated. +// emscripten - b2RevoluteJoint: make constructor public +class b2RevoluteJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Get the reference angle. + float32 GetReferenceAngle() const { return m_referenceAngle; } + + /// Get the current joint angle in radians. + float32 GetJointAngle() const; + + /// Get the current joint angle speed in radians per second. + float32 GetJointSpeed() const; + + /// Is the joint limit enabled? + bool IsLimitEnabled() const; + + /// Enable/disable the joint limit. + void EnableLimit(bool flag); + + /// Get the lower joint limit in radians. + float32 GetLowerLimit() const; + + /// Get the upper joint limit in radians. + float32 GetUpperLimit() const; + + /// Set the joint limits in radians. + void SetLimits(float32 lower, float32 upper); + + /// Is the joint motor enabled? + bool IsMotorEnabled() const; + + /// Enable/disable the joint motor. + void EnableMotor(bool flag); + + /// Set the motor speed in radians per second. + void SetMotorSpeed(float32 speed); + + /// Get the motor speed in radians per second. + float32 GetMotorSpeed() const; + + /// Set the maximum motor torque, usually in N-m. + void SetMaxMotorTorque(float32 torque); + float32 GetMaxMotorTorque() const { return m_maxMotorTorque; } + + /// Get the reaction force given the inverse time step. + /// Unit is N. + b2Vec2 GetReactionForce(float32 inv_dt) const; + + /// Get the reaction torque due to the joint limit given the inverse time step. + /// Unit is N*m. + float32 GetReactionTorque(float32 inv_dt) const; + + /// Get the current motor torque given the inverse time step. + /// Unit is N*m. + float32 GetMotorTorque(float32 inv_dt) const; + + /// Dump to b2Log. + void Dump(); + + b2RevoluteJoint(const b2RevoluteJointDef* def); + +protected: + + friend class b2Joint; + friend class b2GearJoint; + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec3 m_impulse; + float32 m_motorImpulse; + + bool m_enableMotor; + float32 m_maxMotorTorque; + float32 m_motorSpeed; + + bool m_enableLimit; + float32 m_referenceAngle; + float32 m_lowerAngle; + float32 m_upperAngle; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Mat33 m_mass; // effective mass for point-to-point constraint. + float32 m_motorMass; // effective mass for motor/limit angular constraint. + b2LimitState m_limitState; +}; + +inline float32 b2RevoluteJoint::GetMotorSpeed() const +{ + return m_motorSpeed; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RopeJoint.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RopeJoint.cpp new file mode 100755 index 0000000000000..107ce1fa5e41c --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RopeJoint.cpp @@ -0,0 +1,241 @@ +/* +* Copyright (c) 2007-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include + + +// Limit: +// C = norm(pB - pA) - L +// u = (pB - pA) / norm(pB - pA) +// Cdot = dot(u, vB + cross(wB, rB) - vA - cross(wA, rA)) +// J = [-u -cross(rA, u) u cross(rB, u)] +// K = J * invM * JT +// = invMassA + invIA * cross(rA, u)^2 + invMassB + invIB * cross(rB, u)^2 + +b2RopeJoint::b2RopeJoint(const b2RopeJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + + m_maxLength = def->maxLength; + + m_mass = 0.0f; + m_impulse = 0.0f; + m_state = e_inactiveLimit; + m_length = 0.0f; +} + +void b2RopeJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + m_u = cB + m_rB - cA - m_rA; + + m_length = m_u.Length(); + + float32 C = m_length - m_maxLength; + if (C > 0.0f) + { + m_state = e_atUpperLimit; + } + else + { + m_state = e_inactiveLimit; + } + + if (m_length > b2_linearSlop) + { + m_u *= 1.0f / m_length; + } + else + { + m_u.SetZero(); + m_mass = 0.0f; + m_impulse = 0.0f; + return; + } + + // Compute effective mass. + float32 crA = b2Cross(m_rA, m_u); + float32 crB = b2Cross(m_rB, m_u); + float32 invMass = m_invMassA + m_invIA * crA * crA + m_invMassB + m_invIB * crB * crB; + + m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; + + if (data.step.warmStarting) + { + // Scale the impulse to support a variable time step. + m_impulse *= data.step.dtRatio; + + b2Vec2 P = m_impulse * m_u; + vA -= m_invMassA * P; + wA -= m_invIA * b2Cross(m_rA, P); + vB += m_invMassB * P; + wB += m_invIB * b2Cross(m_rB, P); + } + else + { + m_impulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2RopeJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + // Cdot = dot(u, v + cross(w, r)) + b2Vec2 vpA = vA + b2Cross(wA, m_rA); + b2Vec2 vpB = vB + b2Cross(wB, m_rB); + float32 C = m_length - m_maxLength; + float32 Cdot = b2Dot(m_u, vpB - vpA); + + // Predictive constraint. + if (C < 0.0f) + { + Cdot += data.step.inv_dt * C; + } + + float32 impulse = -m_mass * Cdot; + float32 oldImpulse = m_impulse; + m_impulse = b2Min(0.0f, m_impulse + impulse); + impulse = m_impulse - oldImpulse; + + b2Vec2 P = impulse * m_u; + vA -= m_invMassA * P; + wA -= m_invIA * b2Cross(m_rA, P); + vB += m_invMassB * P; + wB += m_invIB * b2Cross(m_rB, P); + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2RopeJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 u = cB + rB - cA - rA; + + float32 length = u.Normalize(); + float32 C = length - m_maxLength; + + C = b2Clamp(C, 0.0f, b2_maxLinearCorrection); + + float32 impulse = -m_mass * C; + b2Vec2 P = impulse * u; + + cA -= m_invMassA * P; + aA -= m_invIA * b2Cross(rA, P); + cB += m_invMassB * P; + aB += m_invIB * b2Cross(rB, P); + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return length - m_maxLength < b2_linearSlop; +} + +b2Vec2 b2RopeJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2RopeJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2RopeJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 F = (inv_dt * m_impulse) * m_u; + return F; +} + +float32 b2RopeJoint::GetReactionTorque(float32 inv_dt) const +{ + B2_NOT_USED(inv_dt); + return 0.0f; +} + +float32 b2RopeJoint::GetMaxLength() const +{ + return m_maxLength; +} + +b2LimitState b2RopeJoint::GetLimitState() const +{ + return m_state; +} + +void b2RopeJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2RopeJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.maxLength = %.15lef;\n", m_maxLength); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RopeJoint.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RopeJoint.h new file mode 100755 index 0000000000000..eb67a9985be7a --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RopeJoint.h @@ -0,0 +1,125 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_ROPE_JOINT_H +#define B2_ROPE_JOINT_H + +#include + +/// Rope joint definition. This requires two body anchor points and +/// a maximum lengths. +/// Note: by default the connected objects will not collide. +/// see collideConnected in b2JointDef. +// emscripten - b2RopeJointDef: add functions to set/get base class members +struct b2RopeJointDef : public b2JointDef +{ + b2RopeJointDef() + { + type = e_ropeJoint; + localAnchorA.Set(-1.0f, 0.0f); + localAnchorB.Set(1.0f, 0.0f); + maxLength = 0.0f; + } + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The maximum length of the rope. + /// Warning: this must be larger than b2_linearSlop or + /// the joint will have no effect. + float32 maxLength; + + // to generate javascript bindings + void set_bodyA(b2Body* b) { bodyA = b; } + void set_bodyB(b2Body* b) { bodyB = b; } + void set_collideConnected(bool b) { collideConnected = b; } + b2Body* get_bodyA(b2Body* b) { return bodyA; } + b2Body* get_bodyB(b2Body* b) { return bodyB; } + bool get_collideConnected(bool b) { return collideConnected; } +}; + +/// A rope joint enforces a maximum distance between two points +/// on two bodies. It has no other effect. +/// Warning: if you attempt to change the maximum length during +/// the simulation you will get some non-physical behavior. +/// A model that would allow you to dynamically modify the length +/// would have some sponginess, so I chose not to implement it +/// that way. See b2DistanceJoint if you want to dynamically +/// control length. +// emscripten - b2RopeJoint: make constructor public +class b2RopeJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Set/Get the maximum length of the rope. + void SetMaxLength(float32 length) { m_maxLength = length; } + float32 GetMaxLength() const; + + b2LimitState GetLimitState() const; + + /// Dump joint to dmLog + void Dump(); + + b2RopeJoint(const b2RopeJointDef* data); + +protected: + + friend class b2Joint; + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_maxLength; + float32 m_length; + float32 m_impulse; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_u; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + float32 m_mass; + b2LimitState m_state; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WeldJoint.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WeldJoint.cpp new file mode 100755 index 0000000000000..9a86686e2d404 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WeldJoint.cpp @@ -0,0 +1,330 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include + +// Point-to-point constraint +// C = p2 - p1 +// Cdot = v2 - v1 +// = v2 + cross(w2, r2) - v1 - cross(w1, r1) +// J = [-I -r1_skew I r2_skew ] +// Identity used: +// w k % (rx i + ry j) = w * (-ry i + rx j) + +// Angle constraint +// C = angle2 - angle1 - referenceAngle +// Cdot = w2 - w1 +// J = [0 0 -1 0 0 1] +// K = invI1 + invI2 + +void b2WeldJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); + referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); +} + +b2WeldJoint::b2WeldJoint(const b2WeldJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_referenceAngle = def->referenceAngle; + m_frequencyHz = def->frequencyHz; + m_dampingRatio = def->dampingRatio; + + m_impulse.SetZero(); +} + +void b2WeldJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // J = [-I -r1_skew I r2_skew] + // [ 0 -1 0 1] + // r_skew = [-ry; rx] + + // Matlab + // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] + // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] + // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Mat33 K; + K.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB; + K.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB; + K.ez.x = -m_rA.y * iA - m_rB.y * iB; + K.ex.y = K.ey.x; + K.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB; + K.ez.y = m_rA.x * iA + m_rB.x * iB; + K.ex.z = K.ez.x; + K.ey.z = K.ez.y; + K.ez.z = iA + iB; + + if (m_frequencyHz > 0.0f) + { + K.GetInverse22(&m_mass); + + float32 invM = iA + iB; + float32 m = invM > 0.0f ? 1.0f / invM : 0.0f; + + float32 C = aB - aA - m_referenceAngle; + + // Frequency + float32 omega = 2.0f * b2_pi * m_frequencyHz; + + // Damping coefficient + float32 d = 2.0f * m * m_dampingRatio * omega; + + // Spring stiffness + float32 k = m * omega * omega; + + // magic formulas + float32 h = data.step.dt; + m_gamma = h * (d + h * k); + m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f; + m_bias = C * h * k * m_gamma; + + invM += m_gamma; + m_mass.ez.z = invM != 0.0f ? 1.0f / invM : 0.0f; + } + else + { + K.GetSymInverse33(&m_mass); + m_gamma = 0.0f; + m_bias = 0.0f; + } + + if (data.step.warmStarting) + { + // Scale impulses to support a variable time step. + m_impulse *= data.step.dtRatio; + + b2Vec2 P(m_impulse.x, m_impulse.y); + + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + m_impulse.z); + + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + m_impulse.z); + } + else + { + m_impulse.SetZero(); + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2WeldJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + if (m_frequencyHz > 0.0f) + { + float32 Cdot2 = wB - wA; + + float32 impulse2 = -m_mass.ez.z * (Cdot2 + m_bias + m_gamma * m_impulse.z); + m_impulse.z += impulse2; + + wA -= iA * impulse2; + wB += iB * impulse2; + + b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + + b2Vec2 impulse1 = -b2Mul22(m_mass, Cdot1); + m_impulse.x += impulse1.x; + m_impulse.y += impulse1.y; + + b2Vec2 P = impulse1; + + vA -= mA * P; + wA -= iA * b2Cross(m_rA, P); + + vB += mB * P; + wB += iB * b2Cross(m_rB, P); + } + else + { + b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + float32 Cdot2 = wB - wA; + b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); + + b2Vec3 impulse = -b2Mul(m_mass, Cdot); + m_impulse += impulse; + + b2Vec2 P(impulse.x, impulse.y); + + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + impulse.z); + + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + impulse.z); + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2WeldJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + float32 positionError, angularError; + + b2Mat33 K; + K.ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB; + K.ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB; + K.ez.x = -rA.y * iA - rB.y * iB; + K.ex.y = K.ey.x; + K.ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB; + K.ez.y = rA.x * iA + rB.x * iB; + K.ex.z = K.ez.x; + K.ey.z = K.ez.y; + K.ez.z = iA + iB; + + if (m_frequencyHz > 0.0f) + { + b2Vec2 C1 = cB + rB - cA - rA; + + positionError = C1.Length(); + angularError = 0.0f; + + b2Vec2 P = -K.Solve22(C1); + + cA -= mA * P; + aA -= iA * b2Cross(rA, P); + + cB += mB * P; + aB += iB * b2Cross(rB, P); + } + else + { + b2Vec2 C1 = cB + rB - cA - rA; + float32 C2 = aB - aA - m_referenceAngle; + + positionError = C1.Length(); + angularError = b2Abs(C2); + + b2Vec3 C(C1.x, C1.y, C2); + + b2Vec3 impulse = -K.Solve33(C); + b2Vec2 P(impulse.x, impulse.y); + + cA -= mA * P; + aA -= iA * (b2Cross(rA, P) + impulse.z); + + cB += mB * P; + aB += iB * (b2Cross(rB, P) + impulse.z); + } + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return positionError <= b2_linearSlop && angularError <= b2_angularSlop; +} + +b2Vec2 b2WeldJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2WeldJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2WeldJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 P(m_impulse.x, m_impulse.y); + return inv_dt * P; +} + +float32 b2WeldJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_impulse.z; +} + +void b2WeldJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2WeldJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); + b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); + b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WeldJoint.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WeldJoint.h new file mode 100755 index 0000000000000..02f33d4f559fc --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WeldJoint.h @@ -0,0 +1,136 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_WELD_JOINT_H +#define B2_WELD_JOINT_H + +#include + +/// Weld joint definition. You need to specify local anchor points +/// where they are attached and the relative body angle. The position +/// of the anchor points is important for computing the reaction torque. +// emscripten - b2WeldJointDef: add functions to set/get base class members +struct b2WeldJointDef : public b2JointDef +{ + b2WeldJointDef() + { + type = e_weldJoint; + localAnchorA.Set(0.0f, 0.0f); + localAnchorB.Set(0.0f, 0.0f); + referenceAngle = 0.0f; + frequencyHz = 0.0f; + dampingRatio = 0.0f; + } + + /// Initialize the bodies, anchors, and reference angle using a world + /// anchor point. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The bodyB angle minus bodyA angle in the reference state (radians). + float32 referenceAngle; + + /// The mass-spring-damper frequency in Hertz. Rotation only. + /// Disable softness with a value of 0. + float32 frequencyHz; + + /// The damping ratio. 0 = no damping, 1 = critical damping. + float32 dampingRatio; + + // to generate javascript bindings + void set_bodyA(b2Body* b) { bodyA = b; } + void set_bodyB(b2Body* b) { bodyB = b; } + void set_collideConnected(bool b) { collideConnected = b; } + b2Body* get_bodyA(b2Body* b) { return bodyA; } + b2Body* get_bodyB(b2Body* b) { return bodyB; } + bool get_collideConnected(bool b) { return collideConnected; } +}; + +/// A weld joint essentially glues two bodies together. A weld joint may +/// distort somewhat because the island constraint solver is approximate. +// emscripten - b2WeldJoint: make constructor public +class b2WeldJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Get the reference angle. + float32 GetReferenceAngle() const { return m_referenceAngle; } + + /// Set/get frequency in Hz. + void SetFrequency(float32 hz) { m_frequencyHz = hz; } + float32 GetFrequency() const { return m_frequencyHz; } + + /// Set/get damping ratio. + void SetDampingRatio(float32 ratio) { m_dampingRatio = ratio; } + float32 GetDampingRatio() const { return m_dampingRatio; } + + /// Dump to b2Log + void Dump(); + + b2WeldJoint(const b2WeldJointDef* def); + +protected: + + friend class b2Joint; + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + float32 m_frequencyHz; + float32 m_dampingRatio; + float32 m_bias; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_referenceAngle; + float32 m_gamma; + b2Vec3 m_impulse; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Mat33 m_mass; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WheelJoint.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WheelJoint.cpp new file mode 100755 index 0000000000000..998c627dbfbb8 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WheelJoint.cpp @@ -0,0 +1,419 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include + +// Linear constraint (point-to-line) +// d = pB - pA = xB + rB - xA - rA +// C = dot(ay, d) +// Cdot = dot(d, cross(wA, ay)) + dot(ay, vB + cross(wB, rB) - vA - cross(wA, rA)) +// = -dot(ay, vA) - dot(cross(d + rA, ay), wA) + dot(ay, vB) + dot(cross(rB, ay), vB) +// J = [-ay, -cross(d + rA, ay), ay, cross(rB, ay)] + +// Spring linear constraint +// C = dot(ax, d) +// Cdot = = -dot(ax, vA) - dot(cross(d + rA, ax), wA) + dot(ax, vB) + dot(cross(rB, ax), vB) +// J = [-ax -cross(d+rA, ax) ax cross(rB, ax)] + +// Motor rotational constraint +// Cdot = wB - wA +// J = [0 0 -1 0 0 1] + +void b2WheelJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); + localAxisA = bodyA->GetLocalVector(axis); +} + +b2WheelJoint::b2WheelJoint(const b2WheelJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_localXAxisA = def->localAxisA; + m_localYAxisA = b2Cross(1.0f, m_localXAxisA); + + m_mass = 0.0f; + m_impulse = 0.0f; + m_motorMass = 0.0; + m_motorImpulse = 0.0f; + m_springMass = 0.0f; + m_springImpulse = 0.0f; + + m_maxMotorTorque = def->maxMotorTorque; + m_motorSpeed = def->motorSpeed; + m_enableMotor = def->enableMotor; + + m_frequencyHz = def->frequencyHz; + m_dampingRatio = def->dampingRatio; + + m_bias = 0.0f; + m_gamma = 0.0f; + + m_ax.SetZero(); + m_ay.SetZero(); +} + +void b2WheelJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + // Compute the effective masses. + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 d = cB + rB - cA - rA; + + // Point to line constraint + { + m_ay = b2Mul(qA, m_localYAxisA); + m_sAy = b2Cross(d + rA, m_ay); + m_sBy = b2Cross(rB, m_ay); + + m_mass = mA + mB + iA * m_sAy * m_sAy + iB * m_sBy * m_sBy; + + if (m_mass > 0.0f) + { + m_mass = 1.0f / m_mass; + } + } + + // Spring constraint + m_springMass = 0.0f; + m_bias = 0.0f; + m_gamma = 0.0f; + if (m_frequencyHz > 0.0f) + { + m_ax = b2Mul(qA, m_localXAxisA); + m_sAx = b2Cross(d + rA, m_ax); + m_sBx = b2Cross(rB, m_ax); + + float32 invMass = mA + mB + iA * m_sAx * m_sAx + iB * m_sBx * m_sBx; + + if (invMass > 0.0f) + { + m_springMass = 1.0f / invMass; + + float32 C = b2Dot(d, m_ax); + + // Frequency + float32 omega = 2.0f * b2_pi * m_frequencyHz; + + // Damping coefficient + float32 d = 2.0f * m_springMass * m_dampingRatio * omega; + + // Spring stiffness + float32 k = m_springMass * omega * omega; + + // magic formulas + float32 h = data.step.dt; + m_gamma = h * (d + h * k); + if (m_gamma > 0.0f) + { + m_gamma = 1.0f / m_gamma; + } + + m_bias = C * h * k * m_gamma; + + m_springMass = invMass + m_gamma; + if (m_springMass > 0.0f) + { + m_springMass = 1.0f / m_springMass; + } + } + } + else + { + m_springImpulse = 0.0f; + } + + // Rotational motor + if (m_enableMotor) + { + m_motorMass = iA + iB; + if (m_motorMass > 0.0f) + { + m_motorMass = 1.0f / m_motorMass; + } + } + else + { + m_motorMass = 0.0f; + m_motorImpulse = 0.0f; + } + + if (data.step.warmStarting) + { + // Account for variable time step. + m_impulse *= data.step.dtRatio; + m_springImpulse *= data.step.dtRatio; + m_motorImpulse *= data.step.dtRatio; + + b2Vec2 P = m_impulse * m_ay + m_springImpulse * m_ax; + float32 LA = m_impulse * m_sAy + m_springImpulse * m_sAx + m_motorImpulse; + float32 LB = m_impulse * m_sBy + m_springImpulse * m_sBx + m_motorImpulse; + + vA -= m_invMassA * P; + wA -= m_invIA * LA; + + vB += m_invMassB * P; + wB += m_invIB * LB; + } + else + { + m_impulse = 0.0f; + m_springImpulse = 0.0f; + m_motorImpulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2WheelJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + // Solve spring constraint + { + float32 Cdot = b2Dot(m_ax, vB - vA) + m_sBx * wB - m_sAx * wA; + float32 impulse = -m_springMass * (Cdot + m_bias + m_gamma * m_springImpulse); + m_springImpulse += impulse; + + b2Vec2 P = impulse * m_ax; + float32 LA = impulse * m_sAx; + float32 LB = impulse * m_sBx; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + + // Solve rotational motor constraint + { + float32 Cdot = wB - wA - m_motorSpeed; + float32 impulse = -m_motorMass * Cdot; + + float32 oldImpulse = m_motorImpulse; + float32 maxImpulse = data.step.dt * m_maxMotorTorque; + m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); + impulse = m_motorImpulse - oldImpulse; + + wA -= iA * impulse; + wB += iB * impulse; + } + + // Solve point to line constraint + { + float32 Cdot = b2Dot(m_ay, vB - vA) + m_sBy * wB - m_sAy * wA; + float32 impulse = -m_mass * Cdot; + m_impulse += impulse; + + b2Vec2 P = impulse * m_ay; + float32 LA = impulse * m_sAy; + float32 LB = impulse * m_sBy; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2WheelJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 d = (cB - cA) + rB - rA; + + b2Vec2 ay = b2Mul(qA, m_localYAxisA); + + float32 sAy = b2Cross(d + rA, ay); + float32 sBy = b2Cross(rB, ay); + + float32 C = b2Dot(d, ay); + + float32 k = m_invMassA + m_invMassB + m_invIA * m_sAy * m_sAy + m_invIB * m_sBy * m_sBy; + + float32 impulse; + if (k != 0.0f) + { + impulse = - C / k; + } + else + { + impulse = 0.0f; + } + + b2Vec2 P = impulse * ay; + float32 LA = impulse * sAy; + float32 LB = impulse * sBy; + + cA -= m_invMassA * P; + aA -= m_invIA * LA; + cB += m_invMassB * P; + aB += m_invIB * LB; + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return b2Abs(C) <= b2_linearSlop; +} + +b2Vec2 b2WheelJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2WheelJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2WheelJoint::GetReactionForce(float32 inv_dt) const +{ + return inv_dt * (m_impulse * m_ay + m_springImpulse * m_ax); +} + +float32 b2WheelJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_motorImpulse; +} + +float32 b2WheelJoint::GetJointTranslation() const +{ + b2Body* bA = m_bodyA; + b2Body* bB = m_bodyB; + + b2Vec2 pA = bA->GetWorldPoint(m_localAnchorA); + b2Vec2 pB = bB->GetWorldPoint(m_localAnchorB); + b2Vec2 d = pB - pA; + b2Vec2 axis = bA->GetWorldVector(m_localXAxisA); + + float32 translation = b2Dot(d, axis); + return translation; +} + +float32 b2WheelJoint::GetJointSpeed() const +{ + float32 wA = m_bodyA->m_angularVelocity; + float32 wB = m_bodyB->m_angularVelocity; + return wB - wA; +} + +bool b2WheelJoint::IsMotorEnabled() const +{ + return m_enableMotor; +} + +void b2WheelJoint::EnableMotor(bool flag) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableMotor = flag; +} + +void b2WheelJoint::SetMotorSpeed(float32 speed) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_motorSpeed = speed; +} + +void b2WheelJoint::SetMaxMotorTorque(float32 torque) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_maxMotorTorque = torque; +} + +float32 b2WheelJoint::GetMotorTorque(float32 inv_dt) const +{ + return inv_dt * m_motorImpulse; +} + +void b2WheelJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2WheelJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y); + b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); + b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); + b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque); + b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); + b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WheelJoint.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WheelJoint.h new file mode 100755 index 0000000000000..00afa6ac05796 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WheelJoint.h @@ -0,0 +1,224 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_WHEEL_JOINT_H +#define B2_WHEEL_JOINT_H + +#include + +/// Wheel joint definition. This requires defining a line of +/// motion using an axis and an anchor point. The definition uses local +/// anchor points and a local axis so that the initial configuration +/// can violate the constraint slightly. The joint translation is zero +/// when the local anchor points coincide in world space. Using local +/// anchors and a local axis helps when saving and loading a game. +// emscripten - b2WheelJointDef: add functions to set/get base class members +struct b2WheelJointDef : public b2JointDef +{ + b2WheelJointDef() + { + type = e_wheelJoint; + localAnchorA.SetZero(); + localAnchorB.SetZero(); + localAxisA.Set(1.0f, 0.0f); + enableMotor = false; + maxMotorTorque = 0.0f; + motorSpeed = 0.0f; + frequencyHz = 2.0f; + dampingRatio = 0.7f; + } + + /// Initialize the bodies, anchors, axis, and reference angle using the world + /// anchor and world axis. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The local translation axis in bodyA. + b2Vec2 localAxisA; + + /// Enable/disable the joint motor. + bool enableMotor; + + /// The maximum motor torque, usually in N-m. + float32 maxMotorTorque; + + /// The desired motor speed in radians per second. + float32 motorSpeed; + + /// Suspension frequency, zero indicates no suspension + float32 frequencyHz; + + /// Suspension damping ratio, one indicates critical damping + float32 dampingRatio; + + // to generate javascript bindings + void set_bodyA(b2Body* b) { bodyA = b; } + void set_bodyB(b2Body* b) { bodyB = b; } + void set_collideConnected(bool b) { collideConnected = b; } + b2Body* get_bodyA(b2Body* b) { return bodyA; } + b2Body* get_bodyB(b2Body* b) { return bodyB; } + bool get_collideConnected(bool b) { return collideConnected; } +}; + +/// A wheel joint. This joint provides two degrees of freedom: translation +/// along an axis fixed in bodyA and rotation in the plane. You can use a +/// joint limit to restrict the range of motion and a joint motor to drive +/// the rotation or to model rotational friction. +/// This joint is designed for vehicle suspensions. +// emscripten - b2WheelJoint: make constructor public +class b2WheelJoint : public b2Joint +{ +public: + void GetDefinition(b2WheelJointDef* def) const; + + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// The local joint axis relative to bodyA. + const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; } + + /// Get the current joint translation, usually in meters. + float32 GetJointTranslation() const; + + /// Get the current joint translation speed, usually in meters per second. + float32 GetJointSpeed() const; + + /// Is the joint motor enabled? + bool IsMotorEnabled() const; + + /// Enable/disable the joint motor. + void EnableMotor(bool flag); + + /// Set the motor speed, usually in radians per second. + void SetMotorSpeed(float32 speed); + + /// Get the motor speed, usually in radians per second. + float32 GetMotorSpeed() const; + + /// Set/Get the maximum motor force, usually in N-m. + void SetMaxMotorTorque(float32 torque); + float32 GetMaxMotorTorque() const; + + /// Get the current motor torque given the inverse time step, usually in N-m. + float32 GetMotorTorque(float32 inv_dt) const; + + /// Set/Get the spring frequency in hertz. Setting the frequency to zero disables the spring. + void SetSpringFrequencyHz(float32 hz); + float32 GetSpringFrequencyHz() const; + + /// Set/Get the spring damping ratio + void SetSpringDampingRatio(float32 ratio); + float32 GetSpringDampingRatio() const; + + /// Dump to b2Log + void Dump(); + + b2WheelJoint(const b2WheelJointDef* def); + +protected: + + friend class b2Joint; + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + float32 m_frequencyHz; + float32 m_dampingRatio; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec2 m_localXAxisA; + b2Vec2 m_localYAxisA; + + float32 m_impulse; + float32 m_motorImpulse; + float32 m_springImpulse; + + float32 m_maxMotorTorque; + float32 m_motorSpeed; + bool m_enableMotor; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + + b2Vec2 m_ax, m_ay; + float32 m_sAx, m_sBx; + float32 m_sAy, m_sBy; + + float32 m_mass; + float32 m_motorMass; + float32 m_springMass; + + float32 m_bias; + float32 m_gamma; +}; + +inline float32 b2WheelJoint::GetMotorSpeed() const +{ + return m_motorSpeed; +} + +inline float32 b2WheelJoint::GetMaxMotorTorque() const +{ + return m_maxMotorTorque; +} + +inline void b2WheelJoint::SetSpringFrequencyHz(float32 hz) +{ + m_frequencyHz = hz; +} + +inline float32 b2WheelJoint::GetSpringFrequencyHz() const +{ + return m_frequencyHz; +} + +inline void b2WheelJoint::SetSpringDampingRatio(float32 ratio) +{ + m_dampingRatio = ratio; +} + +inline float32 b2WheelJoint::GetSpringDampingRatio() const +{ + return m_dampingRatio; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Body.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Body.cpp new file mode 100755 index 0000000000000..b50bf45adb015 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Body.cpp @@ -0,0 +1,514 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include + +b2Body::b2Body(const b2BodyDef* bd, b2World* world) +{ + b2Assert(bd->position.IsValid()); + b2Assert(bd->linearVelocity.IsValid()); + b2Assert(b2IsValid(bd->angle)); + b2Assert(b2IsValid(bd->angularVelocity)); + b2Assert(b2IsValid(bd->angularDamping) && bd->angularDamping >= 0.0f); + b2Assert(b2IsValid(bd->linearDamping) && bd->linearDamping >= 0.0f); + + m_flags = 0; + + if (bd->bullet) + { + m_flags |= e_bulletFlag; + } + if (bd->fixedRotation) + { + m_flags |= e_fixedRotationFlag; + } + if (bd->allowSleep) + { + m_flags |= e_autoSleepFlag; + } + if (bd->awake) + { + m_flags |= e_awakeFlag; + } + if (bd->active) + { + m_flags |= e_activeFlag; + } + + m_world = world; + + m_xf.p = bd->position; + m_xf.q.Set(bd->angle); + + m_sweep.localCenter.SetZero(); + m_sweep.c0 = m_xf.p; + m_sweep.c = m_xf.p; + m_sweep.a0 = bd->angle; + m_sweep.a = bd->angle; + m_sweep.alpha0 = 0.0f; + + m_jointList = NULL; + m_contactList = NULL; + m_prev = NULL; + m_next = NULL; + + m_linearVelocity = bd->linearVelocity; + m_angularVelocity = bd->angularVelocity; + + m_linearDamping = bd->linearDamping; + m_angularDamping = bd->angularDamping; + m_gravityScale = bd->gravityScale; + + m_force.SetZero(); + m_torque = 0.0f; + + m_sleepTime = 0.0f; + + m_type = bd->type; + + if (m_type == b2_dynamicBody) + { + m_mass = 1.0f; + m_invMass = 1.0f; + } + else + { + m_mass = 0.0f; + m_invMass = 0.0f; + } + + m_I = 0.0f; + m_invI = 0.0f; + + m_userData = bd->userData; + + m_fixtureList = NULL; + m_fixtureCount = 0; +} + +b2Body::~b2Body() +{ + // shapes and joints are destroyed in b2World::Destroy +} + +void b2Body::SetType(b2BodyType type) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return; + } + + if (m_type == type) + { + return; + } + + m_type = type; + + ResetMassData(); + + if (m_type == b2_staticBody) + { + m_linearVelocity.SetZero(); + m_angularVelocity = 0.0f; + m_sweep.a0 = m_sweep.a; + m_sweep.c0 = m_sweep.c; + SynchronizeFixtures(); + } + + SetAwake(true); + + m_force.SetZero(); + m_torque = 0.0f; + + // Since the body type changed, we need to flag contacts for filtering. + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->Refilter(); + } +} + +b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return NULL; + } + + b2BlockAllocator* allocator = &m_world->m_blockAllocator; + + void* memory = allocator->Allocate(sizeof(b2Fixture)); + b2Fixture* fixture = new (memory) b2Fixture; + fixture->Create(allocator, this, def); + + if (m_flags & e_activeFlag) + { + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + fixture->CreateProxies(broadPhase, m_xf); + } + + fixture->m_next = m_fixtureList; + m_fixtureList = fixture; + ++m_fixtureCount; + + fixture->m_body = this; + + // Adjust mass properties if needed. + if (fixture->m_density > 0.0f) + { + ResetMassData(); + } + + // Let the world know we have a new fixture. This will cause new contacts + // to be created at the beginning of the next time step. + m_world->m_flags |= b2World::e_newFixture; + + return fixture; +} + +b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density) +{ + b2FixtureDef def; + def.shape = shape; + def.density = density; + + return CreateFixture(&def); +} + +void b2Body::DestroyFixture(b2Fixture* fixture) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return; + } + + b2Assert(fixture->m_body == this); + + // Remove the fixture from this body's singly linked list. + b2Assert(m_fixtureCount > 0); + b2Fixture** node = &m_fixtureList; + bool found = false; + while (*node != NULL) + { + if (*node == fixture) + { + *node = fixture->m_next; + found = true; + break; + } + + node = &(*node)->m_next; + } + + // You tried to remove a shape that is not attached to this body. + b2Assert(found); + + // Destroy any contacts associated with the fixture. + b2ContactEdge* edge = m_contactList; + while (edge) + { + b2Contact* c = edge->contact; + edge = edge->next; + + b2Fixture* fixtureA = c->GetFixtureA(); + b2Fixture* fixtureB = c->GetFixtureB(); + + if (fixture == fixtureA || fixture == fixtureB) + { + // This destroys the contact and removes it from + // this body's contact list. + m_world->m_contactManager.Destroy(c); + } + } + + b2BlockAllocator* allocator = &m_world->m_blockAllocator; + + if (m_flags & e_activeFlag) + { + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + fixture->DestroyProxies(broadPhase); + } + + fixture->Destroy(allocator); + fixture->m_body = NULL; + fixture->m_next = NULL; + fixture->~b2Fixture(); + allocator->Free(fixture, sizeof(b2Fixture)); + + --m_fixtureCount; + + // Reset the mass data. + ResetMassData(); +} + +void b2Body::ResetMassData() +{ + // Compute mass data from shapes. Each shape has its own density. + m_mass = 0.0f; + m_invMass = 0.0f; + m_I = 0.0f; + m_invI = 0.0f; + m_sweep.localCenter.SetZero(); + + // Static and kinematic bodies have zero mass. + if (m_type == b2_staticBody || m_type == b2_kinematicBody) + { + m_sweep.c0 = m_xf.p; + m_sweep.c = m_xf.p; + m_sweep.a0 = m_sweep.a; + return; + } + + b2Assert(m_type == b2_dynamicBody); + + // Accumulate mass over all fixtures. + b2Vec2 localCenter = b2Vec2_zero; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + if (f->m_density == 0.0f) + { + continue; + } + + b2MassData massData; + f->GetMassData(&massData); + m_mass += massData.mass; + localCenter += massData.mass * massData.center; + m_I += massData.I; + } + + // Compute center of mass. + if (m_mass > 0.0f) + { + m_invMass = 1.0f / m_mass; + localCenter *= m_invMass; + } + else + { + // Force all dynamic bodies to have a positive mass. + m_mass = 1.0f; + m_invMass = 1.0f; + } + + if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0) + { + // Center the inertia about the center of mass. + m_I -= m_mass * b2Dot(localCenter, localCenter); + b2Assert(m_I > 0.0f); + m_invI = 1.0f / m_I; + + } + else + { + m_I = 0.0f; + m_invI = 0.0f; + } + + // Move center of mass. + b2Vec2 oldCenter = m_sweep.c; + m_sweep.localCenter = localCenter; + m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); + + // Update center of mass velocity. + m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter); +} + +void b2Body::SetMassData(const b2MassData* massData) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return; + } + + if (m_type != b2_dynamicBody) + { + return; + } + + m_invMass = 0.0f; + m_I = 0.0f; + m_invI = 0.0f; + + m_mass = massData->mass; + if (m_mass <= 0.0f) + { + m_mass = 1.0f; + } + + m_invMass = 1.0f / m_mass; + + if (massData->I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0) + { + m_I = massData->I - m_mass * b2Dot(massData->center, massData->center); + b2Assert(m_I > 0.0f); + m_invI = 1.0f / m_I; + } + + // Move center of mass. + b2Vec2 oldCenter = m_sweep.c; + m_sweep.localCenter = massData->center; + m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); + + // Update center of mass velocity. + m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter); +} + +bool b2Body::ShouldCollide(const b2Body* other) const +{ + // At least one body should be dynamic. + if (m_type != b2_dynamicBody && other->m_type != b2_dynamicBody) + { + return false; + } + + // Does a joint prevent collision? + for (b2JointEdge* jn = m_jointList; jn; jn = jn->next) + { + if (jn->other == other) + { + if (jn->joint->m_collideConnected == false) + { + return false; + } + } + } + + return true; +} + +void b2Body::SetTransform(const b2Vec2& position, float32 angle) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return; + } + + m_xf.q.Set(angle); + m_xf.p = position; + + m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); + m_sweep.a = angle; + + m_sweep.c0 = m_sweep.c; + m_sweep.a0 = angle; + + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->Synchronize(broadPhase, m_xf, m_xf); + } + + m_world->m_contactManager.FindNewContacts(); +} + +void b2Body::SynchronizeFixtures() +{ + b2Transform xf1; + xf1.q.Set(m_sweep.a0); + xf1.p = m_sweep.c0 - b2Mul(xf1.q, m_sweep.localCenter); + + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->Synchronize(broadPhase, xf1, m_xf); + } +} + +void b2Body::SetActive(bool flag) +{ + b2Assert(m_world->IsLocked() == false); + + if (flag == IsActive()) + { + return; + } + + if (flag) + { + m_flags |= e_activeFlag; + + // Create all proxies. + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->CreateProxies(broadPhase, m_xf); + } + + // Contacts are created the next time step. + } + else + { + m_flags &= ~e_activeFlag; + + // Destroy all proxies. + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->DestroyProxies(broadPhase); + } + + // Destroy the attached contacts. + b2ContactEdge* ce = m_contactList; + while (ce) + { + b2ContactEdge* ce0 = ce; + ce = ce->next; + m_world->m_contactManager.Destroy(ce0->contact); + } + m_contactList = NULL; + } +} + +void b2Body::Dump() +{ + int32 bodyIndex = m_islandIndex; + + b2Log("{\n"); + b2Log(" b2BodyDef bd;\n"); + b2Log(" bd.type = b2BodyType(%d);\n", m_type); + b2Log(" bd.position.Set(%.15lef, %.15lef);\n", m_xf.p.x, m_xf.p.y); + b2Log(" bd.angle = %.15lef;\n", m_sweep.a); + b2Log(" bd.linearVelocity.Set(%.15lef, %.15lef);\n", m_linearVelocity.x, m_linearVelocity.y); + b2Log(" bd.angularVelocity = %.15lef;\n", m_angularVelocity); + b2Log(" bd.linearDamping = %.15lef;\n", m_linearDamping); + b2Log(" bd.angularDamping = %.15lef;\n", m_angularDamping); + b2Log(" bd.allowSleep = bool(%d);\n", m_flags & e_autoSleepFlag); + b2Log(" bd.awake = bool(%d);\n", m_flags & e_awakeFlag); + b2Log(" bd.fixedRotation = bool(%d);\n", m_flags & e_fixedRotationFlag); + b2Log(" bd.bullet = bool(%d);\n", m_flags & e_bulletFlag); + b2Log(" bd.active = bool(%d);\n", m_flags & e_activeFlag); + b2Log(" bd.gravityScale = %.15lef;\n", m_gravityScale); + b2Log(" bodies[%d] = m_world->CreateBody(&bd);\n", m_islandIndex); + b2Log("\n"); + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + b2Log(" {\n"); + f->Dump(bodyIndex); + b2Log(" }\n"); + } + b2Log("}\n"); +} \ No newline at end of file diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Body.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Body.h new file mode 100755 index 0000000000000..3b1be1c3baa0f --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Body.h @@ -0,0 +1,848 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_BODY_H +#define B2_BODY_H + +#include +#include +#ifndef EM_NO_LIBCPP +#include +#endif + +class b2Fixture; +class b2Joint; +class b2Contact; +class b2Controller; +class b2World; +struct b2FixtureDef; +struct b2JointEdge; +struct b2ContactEdge; + +/// The body type. +/// static: zero mass, zero velocity, may be manually moved +/// kinematic: zero mass, non-zero velocity set by user, moved by solver +/// dynamic: positive mass, non-zero velocity determined by forces, moved by solver +enum b2BodyType +{ + b2_staticBody = 0, + b2_kinematicBody, + b2_dynamicBody + + // TODO_ERIN + //b2_bulletBody, +}; + +/// A body definition holds all the data needed to construct a rigid body. +/// You can safely re-use body definitions. Shapes are added to a body after construction. +struct b2BodyDef +{ + /// This constructor sets the body definition default values. + b2BodyDef() + { + userData = NULL; + position.Set(0.0f, 0.0f); + angle = 0.0f; + linearVelocity.Set(0.0f, 0.0f); + angularVelocity = 0.0f; + linearDamping = 0.0f; + angularDamping = 0.0f; + allowSleep = true; + awake = true; + fixedRotation = false; + bullet = false; + type = b2_staticBody; + active = true; + gravityScale = 1.0f; + } + + /// The body type: static, kinematic, or dynamic. + /// Note: if a dynamic body would have zero mass, the mass is set to one. + b2BodyType type; + + /// The world position of the body. Avoid creating bodies at the origin + /// since this can lead to many overlapping shapes. + b2Vec2 position; + + /// The world angle of the body in radians. + float32 angle; + + /// The linear velocity of the body's origin in world co-ordinates. + b2Vec2 linearVelocity; + + /// The angular velocity of the body. + float32 angularVelocity; + + /// Linear damping is use to reduce the linear velocity. The damping parameter + /// can be larger than 1.0f but the damping effect becomes sensitive to the + /// time step when the damping parameter is large. + float32 linearDamping; + + /// Angular damping is use to reduce the angular velocity. The damping parameter + /// can be larger than 1.0f but the damping effect becomes sensitive to the + /// time step when the damping parameter is large. + float32 angularDamping; + + /// Set this flag to false if this body should never fall asleep. Note that + /// this increases CPU usage. + bool allowSleep; + + /// Is this body initially awake or sleeping? + bool awake; + + /// Should this body be prevented from rotating? Useful for characters. + bool fixedRotation; + + /// Is this a fast moving body that should be prevented from tunneling through + /// other moving bodies? Note that all bodies are prevented from tunneling through + /// kinematic and static bodies. This setting is only considered on dynamic bodies. + /// @warning You should use this flag sparingly since it increases processing time. + bool bullet; + + /// Does this body start out active? + bool active; + + /// Use this to store application specific body data. + void* userData; + + /// Scale the gravity applied to this body. + float32 gravityScale; +}; + +/// A rigid body. These are created via b2World::CreateBody. +class b2Body +{ +public: + /// Creates a fixture and attach it to this body. Use this function if you need + /// to set some fixture parameters, like friction. Otherwise you can create the + /// fixture directly from a shape. + /// If the density is non-zero, this function automatically updates the mass of the body. + /// Contacts are not created until the next time step. + /// @param def the fixture definition. + /// @warning This function is locked during callbacks. + b2Fixture* CreateFixture(const b2FixtureDef* def); + + /// Creates a fixture from a shape and attach it to this body. + /// This is a convenience function. Use b2FixtureDef if you need to set parameters + /// like friction, restitution, user data, or filtering. + /// If the density is non-zero, this function automatically updates the mass of the body. + /// @param shape the shape to be cloned. + /// @param density the shape density (set to zero for static bodies). + /// @warning This function is locked during callbacks. + b2Fixture* CreateFixture(const b2Shape* shape, float32 density); + + /// Destroy a fixture. This removes the fixture from the broad-phase and + /// destroys all contacts associated with this fixture. This will + /// automatically adjust the mass of the body if the body is dynamic and the + /// fixture has positive density. + /// All fixtures attached to a body are implicitly destroyed when the body is destroyed. + /// @param fixture the fixture to be removed. + /// @warning This function is locked during callbacks. + void DestroyFixture(b2Fixture* fixture); + + /// Set the position of the body's origin and rotation. + /// This breaks any contacts and wakes the other bodies. + /// Manipulating a body's transform may cause non-physical behavior. + /// @param position the world position of the body's local origin. + /// @param angle the world rotation in radians. + void SetTransform(const b2Vec2& position, float32 angle); + + /// Get the body transform for the body's origin. + /// @return the world transform of the body's origin. + const b2Transform& GetTransform() const; + + /// Get the world body origin position. + /// @return the world position of the body's origin. + const b2Vec2& GetPosition() const; + + /// Get the angle in radians. + /// @return the current world rotation angle in radians. + float32 GetAngle() const; + + /// Get the world position of the center of mass. + const b2Vec2& GetWorldCenter() const; + + /// Get the local position of the center of mass. + const b2Vec2& GetLocalCenter() const; + + /// Set the linear velocity of the center of mass. + /// @param v the new linear velocity of the center of mass. + void SetLinearVelocity(const b2Vec2& v); + + /// Get the linear velocity of the center of mass. + /// @return the linear velocity of the center of mass. + b2Vec2 GetLinearVelocity() const; + + /// Set the angular velocity. + /// @param omega the new angular velocity in radians/second. + void SetAngularVelocity(float32 omega); + + /// Get the angular velocity. + /// @return the angular velocity in radians/second. + float32 GetAngularVelocity() const; + + /// Apply a force at a world point. If the force is not + /// applied at the center of mass, it will generate a torque and + /// affect the angular velocity. This wakes up the body. + /// @param force the world force vector, usually in Newtons (N). + /// @param point the world position of the point of application. + void ApplyForce(const b2Vec2& force, const b2Vec2& point); + + /// Apply a force to the center of mass. This wakes up the body. + /// @param force the world force vector, usually in Newtons (N). + void ApplyForceToCenter(const b2Vec2& force); + + /// Apply a torque. This affects the angular velocity + /// without affecting the linear velocity of the center of mass. + /// This wakes up the body. + /// @param torque about the z-axis (out of the screen), usually in N-m. + void ApplyTorque(float32 torque); + + /// Apply an impulse at a point. This immediately modifies the velocity. + /// It also modifies the angular velocity if the point of application + /// is not at the center of mass. This wakes up the body. + /// @param impulse the world impulse vector, usually in N-seconds or kg-m/s. + /// @param point the world position of the point of application. + void ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point); + + /// Apply an angular impulse. + /// @param impulse the angular impulse in units of kg*m*m/s + void ApplyAngularImpulse(float32 impulse); + + /// Get the total mass of the body. + /// @return the mass, usually in kilograms (kg). + float32 GetMass() const; + + /// Get the rotational inertia of the body about the local origin. + /// @return the rotational inertia, usually in kg-m^2. + float32 GetInertia() const; + + /// Get the mass data of the body. + /// @return a struct containing the mass, inertia and center of the body. + void GetMassData(b2MassData* data) const; + + /// Set the mass properties to override the mass properties of the fixtures. + /// Note that this changes the center of mass position. + /// Note that creating or destroying fixtures can also alter the mass. + /// This function has no effect if the body isn't dynamic. + /// @param massData the mass properties. + void SetMassData(const b2MassData* data); + + /// This resets the mass properties to the sum of the mass properties of the fixtures. + /// This normally does not need to be called unless you called SetMassData to override + /// the mass and you later want to reset the mass. + void ResetMassData(); + + /// Get the world coordinates of a point given the local coordinates. + /// @param localPoint a point on the body measured relative the the body's origin. + /// @return the same point expressed in world coordinates. + b2Vec2 GetWorldPoint(const b2Vec2& localPoint) const; + + /// Get the world coordinates of a vector given the local coordinates. + /// @param localVector a vector fixed in the body. + /// @return the same vector expressed in world coordinates. + b2Vec2 GetWorldVector(const b2Vec2& localVector) const; + + /// Gets a local point relative to the body's origin given a world point. + /// @param a point in world coordinates. + /// @return the corresponding local point relative to the body's origin. + b2Vec2 GetLocalPoint(const b2Vec2& worldPoint) const; + + /// Gets a local vector given a world vector. + /// @param a vector in world coordinates. + /// @return the corresponding local vector. + b2Vec2 GetLocalVector(const b2Vec2& worldVector) const; + + /// Get the world linear velocity of a world point attached to this body. + /// @param a point in world coordinates. + /// @return the world velocity of a point. + b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const; + + /// Get the world velocity of a local point. + /// @param a point in local coordinates. + /// @return the world velocity of a point. + b2Vec2 GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const; + + /// Get the linear damping of the body. + float32 GetLinearDamping() const; + + /// Set the linear damping of the body. + void SetLinearDamping(float32 linearDamping); + + /// Get the angular damping of the body. + float32 GetAngularDamping() const; + + /// Set the angular damping of the body. + void SetAngularDamping(float32 angularDamping); + + /// Get the gravity scale of the body. + float32 GetGravityScale() const; + + /// Set the gravity scale of the body. + void SetGravityScale(float32 scale); + + /// Set the type of this body. This may alter the mass and velocity. + void SetType(b2BodyType type); + + /// Get the type of this body. + b2BodyType GetType() const; + + /// Should this body be treated like a bullet for continuous collision detection? + void SetBullet(bool flag); + + /// Is this body treated like a bullet for continuous collision detection? + bool IsBullet() const; + + /// You can disable sleeping on this body. If you disable sleeping, the + /// body will be woken. + void SetSleepingAllowed(bool flag); + + /// Is this body allowed to sleep + bool IsSleepingAllowed() const; + + /// Set the sleep state of the body. A sleeping body has very + /// low CPU cost. + /// @param flag set to true to put body to sleep, false to wake it. + void SetAwake(bool flag); + + /// Get the sleeping state of this body. + /// @return true if the body is sleeping. + bool IsAwake() const; + + /// Set the active state of the body. An inactive body is not + /// simulated and cannot be collided with or woken up. + /// If you pass a flag of true, all fixtures will be added to the + /// broad-phase. + /// If you pass a flag of false, all fixtures will be removed from + /// the broad-phase and all contacts will be destroyed. + /// Fixtures and joints are otherwise unaffected. You may continue + /// to create/destroy fixtures and joints on inactive bodies. + /// Fixtures on an inactive body are implicitly inactive and will + /// not participate in collisions, ray-casts, or queries. + /// Joints connected to an inactive body are implicitly inactive. + /// An inactive body is still owned by a b2World object and remains + /// in the body list. + void SetActive(bool flag); + + /// Get the active state of the body. + bool IsActive() const; + + /// Set this body to have fixed rotation. This causes the mass + /// to be reset. + void SetFixedRotation(bool flag); + + /// Does this body have fixed rotation? + bool IsFixedRotation() const; + + /// Get the list of all fixtures attached to this body. + b2Fixture* GetFixtureList(); + const b2Fixture* GetFixtureList() const; + + /// Get the list of all joints attached to this body. + b2JointEdge* GetJointList(); + const b2JointEdge* GetJointList() const; + + /// Get the list of all contacts attached to this body. + /// @warning this list changes during the time step and you may + /// miss some collisions if you don't use b2ContactListener. + b2ContactEdge* GetContactList(); + const b2ContactEdge* GetContactList() const; + + /// Get the next body in the world's body list. + b2Body* GetNext(); + const b2Body* GetNext() const; + + /// Get the user data pointer that was provided in the body definition. + void* GetUserData() const; + + /// Set the user data. Use this to store your application specific data. + void SetUserData(void* data); + + /// Get the parent world of this body. + b2World* GetWorld(); + const b2World* GetWorld() const; + + /// Dump this body to a log file + void Dump(); + +private: + + friend class b2World; + friend class b2Island; + friend class b2ContactManager; + friend class b2ContactSolver; + friend class b2Contact; + + friend class b2DistanceJoint; + friend class b2GearJoint; + friend class b2WheelJoint; + friend class b2MouseJoint; + friend class b2PrismaticJoint; + friend class b2PulleyJoint; + friend class b2RevoluteJoint; + friend class b2WeldJoint; + friend class b2FrictionJoint; + friend class b2RopeJoint; + + // m_flags + enum + { + e_islandFlag = 0x0001, + e_awakeFlag = 0x0002, + e_autoSleepFlag = 0x0004, + e_bulletFlag = 0x0008, + e_fixedRotationFlag = 0x0010, + e_activeFlag = 0x0020, + e_toiFlag = 0x0040 + }; + + b2Body(const b2BodyDef* bd, b2World* world); + ~b2Body(); + + void SynchronizeFixtures(); + void SynchronizeTransform(); + + // This is used to prevent connected bodies from colliding. + // It may lie, depending on the collideConnected flag. + bool ShouldCollide(const b2Body* other) const; + + void Advance(float32 t); + + b2BodyType m_type; + + uint16 m_flags; + + int32 m_islandIndex; + + b2Transform m_xf; // the body origin transform + b2Sweep m_sweep; // the swept motion for CCD + + b2Vec2 m_linearVelocity; + float32 m_angularVelocity; + + b2Vec2 m_force; + float32 m_torque; + + b2World* m_world; + b2Body* m_prev; + b2Body* m_next; + + b2Fixture* m_fixtureList; + int32 m_fixtureCount; + + b2JointEdge* m_jointList; + b2ContactEdge* m_contactList; + + float32 m_mass, m_invMass; + + // Rotational inertia about the center of mass. + float32 m_I, m_invI; + + float32 m_linearDamping; + float32 m_angularDamping; + float32 m_gravityScale; + + float32 m_sleepTime; + + void* m_userData; +}; + +inline b2BodyType b2Body::GetType() const +{ + return m_type; +} + +inline const b2Transform& b2Body::GetTransform() const +{ + return m_xf; +} + +inline const b2Vec2& b2Body::GetPosition() const +{ + return m_xf.p; +} + +inline float32 b2Body::GetAngle() const +{ + return m_sweep.a; +} + +inline const b2Vec2& b2Body::GetWorldCenter() const +{ + return m_sweep.c; +} + +inline const b2Vec2& b2Body::GetLocalCenter() const +{ + return m_sweep.localCenter; +} + +inline void b2Body::SetLinearVelocity(const b2Vec2& v) +{ + if (m_type == b2_staticBody) + { + return; + } + + if (b2Dot(v,v) > 0.0f) + { + SetAwake(true); + } + + m_linearVelocity = v; +} + +inline b2Vec2 b2Body::GetLinearVelocity() const +{ + return m_linearVelocity; +} + +inline void b2Body::SetAngularVelocity(float32 w) +{ + if (m_type == b2_staticBody) + { + return; + } + + if (w * w > 0.0f) + { + SetAwake(true); + } + + m_angularVelocity = w; +} + +inline float32 b2Body::GetAngularVelocity() const +{ + return m_angularVelocity; +} + +inline float32 b2Body::GetMass() const +{ + return m_mass; +} + +inline float32 b2Body::GetInertia() const +{ + return m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter); +} + +inline void b2Body::GetMassData(b2MassData* data) const +{ + data->mass = m_mass; + data->I = m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter); + data->center = m_sweep.localCenter; +} + +inline b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint) const +{ + return b2Mul(m_xf, localPoint); +} + +inline b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector) const +{ + return b2Mul(m_xf.q, localVector); +} + +inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const +{ + return b2MulT(m_xf, worldPoint); +} + +inline b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector) const +{ + return b2MulT(m_xf.q, worldVector); +} + +inline b2Vec2 b2Body::GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const +{ + return m_linearVelocity + b2Cross(m_angularVelocity, worldPoint - m_sweep.c); +} + +inline b2Vec2 b2Body::GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const +{ + return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint)); +} + +inline float32 b2Body::GetLinearDamping() const +{ + return m_linearDamping; +} + +inline void b2Body::SetLinearDamping(float32 linearDamping) +{ + m_linearDamping = linearDamping; +} + +inline float32 b2Body::GetAngularDamping() const +{ + return m_angularDamping; +} + +inline void b2Body::SetAngularDamping(float32 angularDamping) +{ + m_angularDamping = angularDamping; +} + +inline float32 b2Body::GetGravityScale() const +{ + return m_gravityScale; +} + +inline void b2Body::SetGravityScale(float32 scale) +{ + m_gravityScale = scale; +} + +inline void b2Body::SetBullet(bool flag) +{ + if (flag) + { + m_flags |= e_bulletFlag; + } + else + { + m_flags &= ~e_bulletFlag; + } +} + +inline bool b2Body::IsBullet() const +{ + return (m_flags & e_bulletFlag) == e_bulletFlag; +} + +inline void b2Body::SetAwake(bool flag) +{ + if (flag) + { + if ((m_flags & e_awakeFlag) == 0) + { + m_flags |= e_awakeFlag; + m_sleepTime = 0.0f; + } + } + else + { + m_flags &= ~e_awakeFlag; + m_sleepTime = 0.0f; + m_linearVelocity.SetZero(); + m_angularVelocity = 0.0f; + m_force.SetZero(); + m_torque = 0.0f; + } +} + +inline bool b2Body::IsAwake() const +{ + return (m_flags & e_awakeFlag) == e_awakeFlag; +} + +inline bool b2Body::IsActive() const +{ + return (m_flags & e_activeFlag) == e_activeFlag; +} + +inline void b2Body::SetFixedRotation(bool flag) +{ + if (flag) + { + m_flags |= e_fixedRotationFlag; + } + else + { + m_flags &= ~e_fixedRotationFlag; + } + + ResetMassData(); +} + +inline bool b2Body::IsFixedRotation() const +{ + return (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag; +} + +inline void b2Body::SetSleepingAllowed(bool flag) +{ + if (flag) + { + m_flags |= e_autoSleepFlag; + } + else + { + m_flags &= ~e_autoSleepFlag; + SetAwake(true); + } +} + +inline bool b2Body::IsSleepingAllowed() const +{ + return (m_flags & e_autoSleepFlag) == e_autoSleepFlag; +} + +inline b2Fixture* b2Body::GetFixtureList() +{ + return m_fixtureList; +} + +inline const b2Fixture* b2Body::GetFixtureList() const +{ + return m_fixtureList; +} + +inline b2JointEdge* b2Body::GetJointList() +{ + return m_jointList; +} + +inline const b2JointEdge* b2Body::GetJointList() const +{ + return m_jointList; +} + +inline b2ContactEdge* b2Body::GetContactList() +{ + return m_contactList; +} + +inline const b2ContactEdge* b2Body::GetContactList() const +{ + return m_contactList; +} + +inline b2Body* b2Body::GetNext() +{ + return m_next; +} + +inline const b2Body* b2Body::GetNext() const +{ + return m_next; +} + +inline void b2Body::SetUserData(void* data) +{ + m_userData = data; +} + +inline void* b2Body::GetUserData() const +{ + return m_userData; +} + +inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + + m_force += force; + m_torque += b2Cross(point - m_sweep.c, force); +} + +inline void b2Body::ApplyForceToCenter(const b2Vec2& force) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + + m_force += force; +} + +inline void b2Body::ApplyTorque(float32 torque) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + + m_torque += torque; +} + +inline void b2Body::ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + m_linearVelocity += m_invMass * impulse; + m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse); +} + +inline void b2Body::ApplyAngularImpulse(float32 impulse) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + m_angularVelocity += m_invI * impulse; +} + +inline void b2Body::SynchronizeTransform() +{ + m_xf.q.Set(m_sweep.a); + m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter); +} + +inline void b2Body::Advance(float32 alpha) +{ + // Advance to the new safe time. This doesn't sync the broad-phase. + m_sweep.Advance(alpha); + m_sweep.c = m_sweep.c0; + m_sweep.a = m_sweep.a0; + m_xf.q.Set(m_sweep.a); + m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter); +} + +inline b2World* b2Body::GetWorld() +{ + return m_world; +} + +inline const b2World* b2Body::GetWorld() const +{ + return m_world; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2ContactManager.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2ContactManager.cpp new file mode 100755 index 0000000000000..5ac12b35075ee --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2ContactManager.cpp @@ -0,0 +1,293 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include + +b2ContactFilter b2_defaultFilter; +b2ContactListener b2_defaultListener; + +b2ContactManager::b2ContactManager() +{ + m_contactList = NULL; + m_contactCount = 0; + m_contactFilter = &b2_defaultFilter; + m_contactListener = &b2_defaultListener; + m_allocator = NULL; +} + +void b2ContactManager::Destroy(b2Contact* c) +{ + b2Fixture* fixtureA = c->GetFixtureA(); + b2Fixture* fixtureB = c->GetFixtureB(); + b2Body* bodyA = fixtureA->GetBody(); + b2Body* bodyB = fixtureB->GetBody(); + + if (m_contactListener && c->IsTouching()) + { + m_contactListener->EndContact(c); + } + + // Remove from the world. + if (c->m_prev) + { + c->m_prev->m_next = c->m_next; + } + + if (c->m_next) + { + c->m_next->m_prev = c->m_prev; + } + + if (c == m_contactList) + { + m_contactList = c->m_next; + } + + // Remove from body 1 + if (c->m_nodeA.prev) + { + c->m_nodeA.prev->next = c->m_nodeA.next; + } + + if (c->m_nodeA.next) + { + c->m_nodeA.next->prev = c->m_nodeA.prev; + } + + if (&c->m_nodeA == bodyA->m_contactList) + { + bodyA->m_contactList = c->m_nodeA.next; + } + + // Remove from body 2 + if (c->m_nodeB.prev) + { + c->m_nodeB.prev->next = c->m_nodeB.next; + } + + if (c->m_nodeB.next) + { + c->m_nodeB.next->prev = c->m_nodeB.prev; + } + + if (&c->m_nodeB == bodyB->m_contactList) + { + bodyB->m_contactList = c->m_nodeB.next; + } + + // Call the factory. + b2Contact::Destroy(c, m_allocator); + --m_contactCount; +} + +// This is the top level collision call for the time step. Here +// all the narrow phase collision is processed for the world +// contact list. +void b2ContactManager::Collide() +{ + // Update awake contacts. + b2Contact* c = m_contactList; + while (c) + { + b2Fixture* fixtureA = c->GetFixtureA(); + b2Fixture* fixtureB = c->GetFixtureB(); + int32 indexA = c->GetChildIndexA(); + int32 indexB = c->GetChildIndexB(); + b2Body* bodyA = fixtureA->GetBody(); + b2Body* bodyB = fixtureB->GetBody(); + + // Is this contact flagged for filtering? + if (c->m_flags & b2Contact::e_filterFlag) + { + // Should these bodies collide? + if (bodyB->ShouldCollide(bodyA) == false) + { + b2Contact* cNuke = c; + c = cNuke->GetNext(); + Destroy(cNuke); + continue; + } + + // Check user filtering. + if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) + { + b2Contact* cNuke = c; + c = cNuke->GetNext(); + Destroy(cNuke); + continue; + } + + // Clear the filtering flag. + c->m_flags &= ~b2Contact::e_filterFlag; + } + + bool activeA = bodyA->IsAwake() && bodyA->m_type != b2_staticBody; + bool activeB = bodyB->IsAwake() && bodyB->m_type != b2_staticBody; + + // At least one body must be awake and it must be dynamic or kinematic. + if (activeA == false && activeB == false) + { + c = c->GetNext(); + continue; + } + + int32 proxyIdA = fixtureA->m_proxies[indexA].proxyId; + int32 proxyIdB = fixtureB->m_proxies[indexB].proxyId; + bool overlap = m_broadPhase.TestOverlap(proxyIdA, proxyIdB); + + // Here we destroy contacts that cease to overlap in the broad-phase. + if (overlap == false) + { + b2Contact* cNuke = c; + c = cNuke->GetNext(); + Destroy(cNuke); + continue; + } + + // The contact persists. + c->Update(m_contactListener); + c = c->GetNext(); + } +} + +void b2ContactManager::FindNewContacts() +{ + m_broadPhase.UpdatePairs(this); +} + +void b2ContactManager::AddPair(void* proxyUserDataA, void* proxyUserDataB) +{ + b2FixtureProxy* proxyA = (b2FixtureProxy*)proxyUserDataA; + b2FixtureProxy* proxyB = (b2FixtureProxy*)proxyUserDataB; + + b2Fixture* fixtureA = proxyA->fixture; + b2Fixture* fixtureB = proxyB->fixture; + + int32 indexA = proxyA->childIndex; + int32 indexB = proxyB->childIndex; + + b2Body* bodyA = fixtureA->GetBody(); + b2Body* bodyB = fixtureB->GetBody(); + + // Are the fixtures on the same body? + if (bodyA == bodyB) + { + return; + } + + // TODO_ERIN use a hash table to remove a potential bottleneck when both + // bodies have a lot of contacts. + // Does a contact already exist? + b2ContactEdge* edge = bodyB->GetContactList(); + while (edge) + { + if (edge->other == bodyA) + { + b2Fixture* fA = edge->contact->GetFixtureA(); + b2Fixture* fB = edge->contact->GetFixtureB(); + int32 iA = edge->contact->GetChildIndexA(); + int32 iB = edge->contact->GetChildIndexB(); + + if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB) + { + // A contact already exists. + return; + } + + if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA) + { + // A contact already exists. + return; + } + } + + edge = edge->next; + } + + // Does a joint override collision? Is at least one body dynamic? + if (bodyB->ShouldCollide(bodyA) == false) + { + return; + } + + // Check user filtering. + if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) + { + return; + } + + // Call the factory. + b2Contact* c = b2Contact::Create(fixtureA, indexA, fixtureB, indexB, m_allocator); + if (c == NULL) + { + return; + } + + // Contact creation may swap fixtures. + fixtureA = c->GetFixtureA(); + fixtureB = c->GetFixtureB(); + indexA = c->GetChildIndexA(); + indexB = c->GetChildIndexB(); + bodyA = fixtureA->GetBody(); + bodyB = fixtureB->GetBody(); + + // Insert into the world. + c->m_prev = NULL; + c->m_next = m_contactList; + if (m_contactList != NULL) + { + m_contactList->m_prev = c; + } + m_contactList = c; + + // Connect to island graph. + + // Connect to body A + c->m_nodeA.contact = c; + c->m_nodeA.other = bodyB; + + c->m_nodeA.prev = NULL; + c->m_nodeA.next = bodyA->m_contactList; + if (bodyA->m_contactList != NULL) + { + bodyA->m_contactList->prev = &c->m_nodeA; + } + bodyA->m_contactList = &c->m_nodeA; + + // Connect to body B + c->m_nodeB.contact = c; + c->m_nodeB.other = bodyA; + + c->m_nodeB.prev = NULL; + c->m_nodeB.next = bodyB->m_contactList; + if (bodyB->m_contactList != NULL) + { + bodyB->m_contactList->prev = &c->m_nodeB; + } + bodyB->m_contactList = &c->m_nodeB; + + // Wake up the bodies + bodyA->SetAwake(true); + bodyB->SetAwake(true); + + ++m_contactCount; +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2ContactManager.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2ContactManager.h new file mode 100755 index 0000000000000..dc1f77fe57c84 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2ContactManager.h @@ -0,0 +1,52 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_CONTACT_MANAGER_H +#define B2_CONTACT_MANAGER_H + +#include + +class b2Contact; +class b2ContactFilter; +class b2ContactListener; +class b2BlockAllocator; + +// Delegate of b2World. +class b2ContactManager +{ +public: + b2ContactManager(); + + // Broad-phase callback. + void AddPair(void* proxyUserDataA, void* proxyUserDataB); + + void FindNewContacts(); + + void Destroy(b2Contact* c); + + void Collide(); + + b2BroadPhase m_broadPhase; + b2Contact* m_contactList; + int32 m_contactCount; + b2ContactFilter* m_contactFilter; + b2ContactListener* m_contactListener; + b2BlockAllocator* m_allocator; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Fixture.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Fixture.cpp new file mode 100755 index 0000000000000..77537b2769d5d --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Fixture.cpp @@ -0,0 +1,303 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +b2Fixture::b2Fixture() +{ + m_userData = NULL; + m_body = NULL; + m_next = NULL; + m_proxies = NULL; + m_proxyCount = 0; + m_shape = NULL; + m_density = 0.0f; +} + +void b2Fixture::Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def) +{ + m_userData = def->userData; + m_friction = def->friction; + m_restitution = def->restitution; + + m_body = body; + m_next = NULL; + + m_filter = def->filter; + + m_isSensor = def->isSensor; + + m_shape = def->shape->Clone(allocator); + + // Reserve proxy space + int32 childCount = m_shape->GetChildCount(); + m_proxies = (b2FixtureProxy*)allocator->Allocate(childCount * sizeof(b2FixtureProxy)); + for (int32 i = 0; i < childCount; ++i) + { + m_proxies[i].fixture = NULL; + m_proxies[i].proxyId = b2BroadPhase::e_nullProxy; + } + m_proxyCount = 0; + + m_density = def->density; +} + +void b2Fixture::Destroy(b2BlockAllocator* allocator) +{ + // The proxies must be destroyed before calling this. + b2Assert(m_proxyCount == 0); + + // Free the proxy array. + int32 childCount = m_shape->GetChildCount(); + allocator->Free(m_proxies, childCount * sizeof(b2FixtureProxy)); + m_proxies = NULL; + + // Free the child shape. + switch (m_shape->m_type) + { + case b2Shape::e_circle: + { + b2CircleShape* s = (b2CircleShape*)m_shape; + s->~b2CircleShape(); + allocator->Free(s, sizeof(b2CircleShape)); + } + break; + + case b2Shape::e_edge: + { + b2EdgeShape* s = (b2EdgeShape*)m_shape; + s->~b2EdgeShape(); + allocator->Free(s, sizeof(b2EdgeShape)); + } + break; + + case b2Shape::e_polygon: + { + b2PolygonShape* s = (b2PolygonShape*)m_shape; + s->~b2PolygonShape(); + allocator->Free(s, sizeof(b2PolygonShape)); + } + break; + + case b2Shape::e_chain: + { + b2ChainShape* s = (b2ChainShape*)m_shape; + s->~b2ChainShape(); + allocator->Free(s, sizeof(b2ChainShape)); + } + break; + + default: + b2Assert(false); + break; + } + + m_shape = NULL; +} + +void b2Fixture::CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf) +{ + b2Assert(m_proxyCount == 0); + + // Create proxies in the broad-phase. + m_proxyCount = m_shape->GetChildCount(); + + for (int32 i = 0; i < m_proxyCount; ++i) + { + b2FixtureProxy* proxy = m_proxies + i; + m_shape->ComputeAABB(&proxy->aabb, xf, i); + proxy->proxyId = broadPhase->CreateProxy(proxy->aabb, proxy); + proxy->fixture = this; + proxy->childIndex = i; + } +} + +void b2Fixture::DestroyProxies(b2BroadPhase* broadPhase) +{ + // Destroy proxies in the broad-phase. + for (int32 i = 0; i < m_proxyCount; ++i) + { + b2FixtureProxy* proxy = m_proxies + i; + broadPhase->DestroyProxy(proxy->proxyId); + proxy->proxyId = b2BroadPhase::e_nullProxy; + } + + m_proxyCount = 0; +} + +void b2Fixture::Synchronize(b2BroadPhase* broadPhase, const b2Transform& transform1, const b2Transform& transform2) +{ + if (m_proxyCount == 0) + { + return; + } + + for (int32 i = 0; i < m_proxyCount; ++i) + { + b2FixtureProxy* proxy = m_proxies + i; + + // Compute an AABB that covers the swept shape (may miss some rotation effect). + b2AABB aabb1, aabb2; + m_shape->ComputeAABB(&aabb1, transform1, proxy->childIndex); + m_shape->ComputeAABB(&aabb2, transform2, proxy->childIndex); + + proxy->aabb.Combine(aabb1, aabb2); + + b2Vec2 displacement = transform2.p - transform1.p; + + broadPhase->MoveProxy(proxy->proxyId, proxy->aabb, displacement); + } +} + +void b2Fixture::SetFilterData(const b2Filter& filter) +{ + m_filter = filter; + + Refilter(); +} + +void b2Fixture::Refilter() +{ + if (m_body == NULL) + { + return; + } + + // Flag associated contacts for filtering. + b2ContactEdge* edge = m_body->GetContactList(); + while (edge) + { + b2Contact* contact = edge->contact; + b2Fixture* fixtureA = contact->GetFixtureA(); + b2Fixture* fixtureB = contact->GetFixtureB(); + if (fixtureA == this || fixtureB == this) + { + contact->FlagForFiltering(); + } + + edge = edge->next; + } + + b2World* world = m_body->GetWorld(); + + if (world == NULL) + { + return; + } + + // Touch each proxy so that new pairs may be created + b2BroadPhase* broadPhase = &world->m_contactManager.m_broadPhase; + for (int32 i = 0; i < m_proxyCount; ++i) + { + broadPhase->TouchProxy(m_proxies[i].proxyId); + } +} + +void b2Fixture::SetSensor(bool sensor) +{ + if (sensor != m_isSensor) + { + m_body->SetAwake(true); + m_isSensor = sensor; + } +} + +void b2Fixture::Dump(int32 bodyIndex) +{ + b2Log(" b2FixtureDef fd;\n"); + b2Log(" fd.friction = %.15lef;\n", m_friction); + b2Log(" fd.restitution = %.15lef;\n", m_restitution); + b2Log(" fd.density = %.15lef;\n", m_density); + b2Log(" fd.isSensor = bool(%d);\n", m_isSensor); + b2Log(" fd.filter.categoryBits = uint16(%d);\n", m_filter.categoryBits); + b2Log(" fd.filter.maskBits = uint16(%d);\n", m_filter.maskBits); + b2Log(" fd.filter.groupIndex = int16(%d);\n", m_filter.groupIndex); + + switch (m_shape->m_type) + { + case b2Shape::e_circle: + { + b2CircleShape* s = (b2CircleShape*)m_shape; + b2Log(" b2CircleShape shape;\n"); + b2Log(" shape.m_radius = %.15lef;\n", s->m_radius); + b2Log(" shape.m_p.Set(%.15lef, %.15lef);\n", s->m_p.x, s->m_p.y); + } + break; + + case b2Shape::e_edge: + { + b2EdgeShape* s = (b2EdgeShape*)m_shape; + b2Log(" b2EdgeShape shape;\n"); + b2Log(" shape.m_radius = %.15lef;\n", s->m_radius); + b2Log(" shape.m_vertex0.Set(%.15lef, %.15lef);\n", s->m_vertex0.x, s->m_vertex0.y); + b2Log(" shape.m_vertex1.Set(%.15lef, %.15lef);\n", s->m_vertex1.x, s->m_vertex1.y); + b2Log(" shape.m_vertex2.Set(%.15lef, %.15lef);\n", s->m_vertex2.x, s->m_vertex2.y); + b2Log(" shape.m_vertex3.Set(%.15lef, %.15lef);\n", s->m_vertex3.x, s->m_vertex3.y); + b2Log(" shape.m_hasVertex0 = bool(%d);\n", s->m_hasVertex0); + b2Log(" shape.m_hasVertex3 = bool(%d);\n", s->m_hasVertex3); + } + break; + + case b2Shape::e_polygon: + { + b2PolygonShape* s = (b2PolygonShape*)m_shape; + b2Log(" b2PolygonShape shape;\n"); + b2Log(" b2Vec2 vs[%d];\n", b2_maxPolygonVertices); + for (int32 i = 0; i < s->m_vertexCount; ++i) + { + b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y); + } + b2Log(" shape.Set(vs, %d);\n", s->m_vertexCount); + } + break; + + case b2Shape::e_chain: + { + b2ChainShape* s = (b2ChainShape*)m_shape; + b2Log(" b2ChainShape shape;\n"); + b2Log(" b2Vec2 vs[%d];\n", s->m_count); + for (int32 i = 0; i < s->m_count; ++i) + { + b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y); + } + b2Log(" shape.CreateChain(vs, %d);\n", s->m_count); + b2Log(" shape.m_prevVertex.Set(%.15lef, %.15lef);\n", s->m_prevVertex.x, s->m_prevVertex.y); + b2Log(" shape.m_nextVertex.Set(%.15lef, %.15lef);\n", s->m_nextVertex.x, s->m_nextVertex.y); + b2Log(" shape.m_hasPrevVertex = bool(%d);\n", s->m_hasPrevVertex); + b2Log(" shape.m_hasNextVertex = bool(%d);\n", s->m_hasNextVertex); + } + break; + + default: + return; + } + + b2Log("\n"); + b2Log(" fd.shape = &shape;\n"); + b2Log("\n"); + b2Log(" bodies[%d]->CreateFixture(&fd);\n", bodyIndex); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Fixture.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Fixture.h new file mode 100755 index 0000000000000..d92751fd68cda --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Fixture.h @@ -0,0 +1,348 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_FIXTURE_H +#define B2_FIXTURE_H + +#include +#include +#include + +class b2BlockAllocator; +class b2Body; +class b2BroadPhase; +class b2Fixture; + +/// This holds contact filtering data. +struct b2Filter +{ + b2Filter() + { + categoryBits = 0x0001; + maskBits = 0xFFFF; + groupIndex = 0; + } + + /// The collision category bits. Normally you would just set one bit. + uint16 categoryBits; + + /// The collision mask bits. This states the categories that this + /// shape would accept for collision. + uint16 maskBits; + + /// Collision groups allow a certain group of objects to never collide (negative) + /// or always collide (positive). Zero means no collision group. Non-zero group + /// filtering always wins against the mask bits. + int16 groupIndex; +}; + +/// A fixture definition is used to create a fixture. This class defines an +/// abstract fixture definition. You can reuse fixture definitions safely. +struct b2FixtureDef +{ + /// The constructor sets the default fixture definition values. + b2FixtureDef() + { + shape = NULL; + userData = NULL; + friction = 0.2f; + restitution = 0.0f; + density = 0.0f; + isSensor = false; + } + + /// The shape, this must be set. The shape will be cloned, so you + /// can create the shape on the stack. + const b2Shape* shape; + + /// Use this to store application specific fixture data. + void* userData; + + /// The friction coefficient, usually in the range [0,1]. + float32 friction; + + /// The restitution (elasticity) usually in the range [0,1]. + float32 restitution; + + /// The density, usually in kg/m^2. + float32 density; + + /// A sensor shape collects contact information but never generates a collision + /// response. + bool isSensor; + + /// Contact filtering data. + b2Filter filter; +}; + +/// This proxy is used internally to connect fixtures to the broad-phase. +struct b2FixtureProxy +{ + b2AABB aabb; + b2Fixture* fixture; + int32 childIndex; + int32 proxyId; +}; + +/// A fixture is used to attach a shape to a body for collision detection. A fixture +/// inherits its transform from its parent. Fixtures hold additional non-geometric data +/// such as friction, collision filters, etc. +/// Fixtures are created via b2Body::CreateFixture. +/// @warning you cannot reuse fixtures. +// emscripten - b2Fixture: make constructor public +class b2Fixture +{ +public: + /// Get the type of the child shape. You can use this to down cast to the concrete shape. + /// @return the shape type. + b2Shape::Type GetType() const; + + /// Get the child shape. You can modify the child shape, however you should not change the + /// number of vertices because this will crash some collision caching mechanisms. + /// Manipulating the shape may lead to non-physical behavior. + b2Shape* GetShape(); + const b2Shape* GetShape() const; + + /// Set if this fixture is a sensor. + void SetSensor(bool sensor); + + /// Is this fixture a sensor (non-solid)? + /// @return the true if the shape is a sensor. + bool IsSensor() const; + + /// Set the contact filtering data. This will not update contacts until the next time + /// step when either parent body is active and awake. + /// This automatically calls Refilter. + void SetFilterData(const b2Filter& filter); + + /// Get the contact filtering data. + const b2Filter& GetFilterData() const; + + /// Call this if you want to establish collision that was previously disabled by b2ContactFilter::ShouldCollide. + void Refilter(); + + /// Get the parent body of this fixture. This is NULL if the fixture is not attached. + /// @return the parent body. + b2Body* GetBody(); + const b2Body* GetBody() const; + + /// Get the next fixture in the parent body's fixture list. + /// @return the next shape. + b2Fixture* GetNext(); + const b2Fixture* GetNext() const; + + /// Get the user data that was assigned in the fixture definition. Use this to + /// store your application specific data. + void* GetUserData() const; + + /// Set the user data. Use this to store your application specific data. + void SetUserData(void* data); + + /// Test a point for containment in this fixture. + /// @param p a point in world coordinates. + bool TestPoint(const b2Vec2& p) const; + + /// Cast a ray against this shape. + /// @param output the ray-cast results. + /// @param input the ray-cast input parameters. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const; + + /// Get the mass data for this fixture. The mass data is based on the density and + /// the shape. The rotational inertia is about the shape's origin. This operation + /// may be expensive. + void GetMassData(b2MassData* massData) const; + + /// Set the density of this fixture. This will _not_ automatically adjust the mass + /// of the body. You must call b2Body::ResetMassData to update the body's mass. + void SetDensity(float32 density); + + /// Get the density of this fixture. + float32 GetDensity() const; + + /// Get the coefficient of friction. + float32 GetFriction() const; + + /// Set the coefficient of friction. This will _not_ change the friction of + /// existing contacts. + void SetFriction(float32 friction); + + /// Get the coefficient of restitution. + float32 GetRestitution() const; + + /// Set the coefficient of restitution. This will _not_ change the restitution of + /// existing contacts. + void SetRestitution(float32 restitution); + + /// Get the fixture's AABB. This AABB may be enlarge and/or stale. + /// If you need a more accurate AABB, compute it using the shape and + /// the body transform. + const b2AABB& GetAABB(int32 childIndex) const; + + /// Dump this fixture to the log file. + void Dump(int32 bodyIndex); + +protected: + + friend class b2Body; + friend class b2World; + friend class b2Contact; + friend class b2ContactManager; + +public: + b2Fixture(); + +protected: + // We need separation create/destroy functions from the constructor/destructor because + // the destructor cannot access the allocator (no destructor arguments allowed by C++). + void Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def); + void Destroy(b2BlockAllocator* allocator); + + // These support body activation/deactivation. + void CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf); + void DestroyProxies(b2BroadPhase* broadPhase); + + void Synchronize(b2BroadPhase* broadPhase, const b2Transform& xf1, const b2Transform& xf2); + + float32 m_density; + + b2Fixture* m_next; + b2Body* m_body; + + b2Shape* m_shape; + + float32 m_friction; + float32 m_restitution; + + b2FixtureProxy* m_proxies; + int32 m_proxyCount; + + b2Filter m_filter; + + bool m_isSensor; + + void* m_userData; +}; + +inline b2Shape::Type b2Fixture::GetType() const +{ + return m_shape->GetType(); +} + +inline b2Shape* b2Fixture::GetShape() +{ + return m_shape; +} + +inline const b2Shape* b2Fixture::GetShape() const +{ + return m_shape; +} + +inline bool b2Fixture::IsSensor() const +{ + return m_isSensor; +} + +inline const b2Filter& b2Fixture::GetFilterData() const +{ + return m_filter; +} + +inline void* b2Fixture::GetUserData() const +{ + return m_userData; +} + +inline void b2Fixture::SetUserData(void* data) +{ + m_userData = data; +} + +inline b2Body* b2Fixture::GetBody() +{ + return m_body; +} + +inline const b2Body* b2Fixture::GetBody() const +{ + return m_body; +} + +inline b2Fixture* b2Fixture::GetNext() +{ + return m_next; +} + +inline const b2Fixture* b2Fixture::GetNext() const +{ + return m_next; +} + +inline void b2Fixture::SetDensity(float32 density) +{ + b2Assert(b2IsValid(density) && density >= 0.0f); + m_density = density; +} + +inline float32 b2Fixture::GetDensity() const +{ + return m_density; +} + +inline float32 b2Fixture::GetFriction() const +{ + return m_friction; +} + +inline void b2Fixture::SetFriction(float32 friction) +{ + m_friction = friction; +} + +inline float32 b2Fixture::GetRestitution() const +{ + return m_restitution; +} + +inline void b2Fixture::SetRestitution(float32 restitution) +{ + m_restitution = restitution; +} + +inline bool b2Fixture::TestPoint(const b2Vec2& p) const +{ + return m_shape->TestPoint(m_body->GetTransform(), p); +} + +inline bool b2Fixture::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const +{ + return m_shape->RayCast(output, input, m_body->GetTransform(), childIndex); +} + +inline void b2Fixture::GetMassData(b2MassData* massData) const +{ + m_shape->ComputeMass(massData, m_density); +} + +inline const b2AABB& b2Fixture::GetAABB(int32 childIndex) const +{ + b2Assert(0 <= childIndex && childIndex < m_proxyCount); + return m_proxies[childIndex].aabb; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Island.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Island.cpp new file mode 100755 index 0000000000000..0e2129cf8d180 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Island.cpp @@ -0,0 +1,539 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +Position Correction Notes +========================= +I tried the several algorithms for position correction of the 2D revolute joint. +I looked at these systems: +- simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s. +- suspension bridge with 30 1m long planks of length 1m. +- multi-link chain with 30 1m long links. + +Here are the algorithms: + +Baumgarte - A fraction of the position error is added to the velocity error. There is no +separate position solver. + +Pseudo Velocities - After the velocity solver and position integration, +the position error, Jacobian, and effective mass are recomputed. Then +the velocity constraints are solved with pseudo velocities and a fraction +of the position error is added to the pseudo velocity error. The pseudo +velocities are initialized to zero and there is no warm-starting. After +the position solver, the pseudo velocities are added to the positions. +This is also called the First Order World method or the Position LCP method. + +Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the +position error is re-computed for each constraint and the positions are updated +after the constraint is solved. The radius vectors (aka Jacobians) are +re-computed too (otherwise the algorithm has horrible instability). The pseudo +velocity states are not needed because they are effectively zero at the beginning +of each iteration. Since we have the current position error, we allow the +iterations to terminate early if the error becomes smaller than b2_linearSlop. + +Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed +each time a constraint is solved. + +Here are the results: +Baumgarte - this is the cheapest algorithm but it has some stability problems, +especially with the bridge. The chain links separate easily close to the root +and they jitter as they struggle to pull together. This is one of the most common +methods in the field. The big drawback is that the position correction artificially +affects the momentum, thus leading to instabilities and false bounce. I used a +bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller +factor makes joints and contacts more spongy. + +Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is +stable. However, joints still separate with large angular velocities. Drag the +simple pendulum in a circle quickly and the joint will separate. The chain separates +easily and does not recover. I used a bias factor of 0.2. A larger value lead to +the bridge collapsing when a heavy cube drops on it. + +Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo +Velocities, but in other ways it is worse. The bridge and chain are much more +stable, but the simple pendulum goes unstable at high angular velocities. + +Full NGS - stable in all tests. The joints display good stiffness. The bridge +still sags, but this is better than infinite forces. + +Recommendations +Pseudo Velocities are not really worthwhile because the bridge and chain cannot +recover from joint separation. In other cases the benefit over Baumgarte is small. + +Modified NGS is not a robust method for the revolute joint due to the violent +instability seen in the simple pendulum. Perhaps it is viable with other constraint +types, especially scalar constraints where the effective mass is a scalar. + +This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities +and is very fast. I don't think we can escape Baumgarte, especially in highly +demanding cases where high constraint fidelity is not needed. + +Full NGS is robust and easy on the eyes. I recommend this as an option for +higher fidelity simulation and certainly for suspension bridges and long chains. +Full NGS might be a good choice for ragdolls, especially motorized ragdolls where +joint separation can be problematic. The number of NGS iterations can be reduced +for better performance without harming robustness much. + +Each joint in a can be handled differently in the position solver. So I recommend +a system where the user can select the algorithm on a per joint basis. I would +probably default to the slower Full NGS and let the user select the faster +Baumgarte method in performance critical scenarios. +*/ + +/* +Cache Performance + +The Box2D solvers are dominated by cache misses. Data structures are designed +to increase the number of cache hits. Much of misses are due to random access +to body data. The constraint structures are iterated over linearly, which leads +to few cache misses. + +The bodies are not accessed during iteration. Instead read only data, such as +the mass values are stored with the constraints. The mutable data are the constraint +impulses and the bodies velocities/positions. The impulses are held inside the +constraint structures. The body velocities/positions are held in compact, temporary +arrays to increase the number of cache hits. Linear and angular velocity are +stored in a single array since multiple arrays lead to multiple misses. +*/ + +/* +2D Rotation + +R = [cos(theta) -sin(theta)] + [sin(theta) cos(theta) ] + +thetaDot = omega + +Let q1 = cos(theta), q2 = sin(theta). +R = [q1 -q2] + [q2 q1] + +q1Dot = -thetaDot * q2 +q2Dot = thetaDot * q1 + +q1_new = q1_old - dt * w * q2 +q2_new = q2_old + dt * w * q1 +then normalize. + +This might be faster than computing sin+cos. +However, we can compute sin+cos of the same angle fast. +*/ + +b2Island::b2Island( + int32 bodyCapacity, + int32 contactCapacity, + int32 jointCapacity, + b2StackAllocator* allocator, + b2ContactListener* listener) +{ + m_bodyCapacity = bodyCapacity; + m_contactCapacity = contactCapacity; + m_jointCapacity = jointCapacity; + m_bodyCount = 0; + m_contactCount = 0; + m_jointCount = 0; + + m_allocator = allocator; + m_listener = listener; + + m_bodies = (b2Body**)m_allocator->Allocate(bodyCapacity * sizeof(b2Body*)); + m_contacts = (b2Contact**)m_allocator->Allocate(contactCapacity * sizeof(b2Contact*)); + m_joints = (b2Joint**)m_allocator->Allocate(jointCapacity * sizeof(b2Joint*)); + + m_velocities = (b2Velocity*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Velocity)); + m_positions = (b2Position*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Position)); +} + +b2Island::~b2Island() +{ + // Warning: the order should reverse the constructor order. + m_allocator->Free(m_positions); + m_allocator->Free(m_velocities); + m_allocator->Free(m_joints); + m_allocator->Free(m_contacts); + m_allocator->Free(m_bodies); +} + +void b2Island::Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep) +{ + b2Timer timer; + + float32 h = step.dt; + + // Integrate velocities and apply damping. Initialize the body state. + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* b = m_bodies[i]; + + b2Vec2 c = b->m_sweep.c; + float32 a = b->m_sweep.a; + b2Vec2 v = b->m_linearVelocity; + float32 w = b->m_angularVelocity; + + // Store positions for continuous collision. + b->m_sweep.c0 = b->m_sweep.c; + b->m_sweep.a0 = b->m_sweep.a; + + if (b->m_type == b2_dynamicBody) + { + // Integrate velocities. + v += h * (b->m_gravityScale * gravity + b->m_invMass * b->m_force); + w += h * b->m_invI * b->m_torque; + + // Apply damping. + // ODE: dv/dt + c * v = 0 + // Solution: v(t) = v0 * exp(-c * t) + // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt) + // v2 = exp(-c * dt) * v1 + // Taylor expansion: + // v2 = (1.0f - c * dt) * v1 + v *= b2Clamp(1.0f - h * b->m_linearDamping, 0.0f, 1.0f); + w *= b2Clamp(1.0f - h * b->m_angularDamping, 0.0f, 1.0f); + } + + m_positions[i].c = c; + m_positions[i].a = a; + m_velocities[i].v = v; + m_velocities[i].w = w; + } + + timer.Reset(); + + // Solver data + b2SolverData solverData; + solverData.step = step; + solverData.positions = m_positions; + solverData.velocities = m_velocities; + + // Initialize velocity constraints. + b2ContactSolverDef contactSolverDef; + contactSolverDef.step = step; + contactSolverDef.contacts = m_contacts; + contactSolverDef.count = m_contactCount; + contactSolverDef.positions = m_positions; + contactSolverDef.velocities = m_velocities; + contactSolverDef.allocator = m_allocator; + + b2ContactSolver contactSolver(&contactSolverDef); + contactSolver.InitializeVelocityConstraints(); + + if (step.warmStarting) + { + contactSolver.WarmStart(); + } + + for (int32 i = 0; i < m_jointCount; ++i) + { + m_joints[i]->InitVelocityConstraints(solverData); + } + + profile->solveInit = timer.GetMilliseconds(); + + // Solve velocity constraints + timer.Reset(); + for (int32 i = 0; i < step.velocityIterations; ++i) + { + for (int32 j = 0; j < m_jointCount; ++j) + { + m_joints[j]->SolveVelocityConstraints(solverData); + } + + contactSolver.SolveVelocityConstraints(); + } + + // Store impulses for warm starting + contactSolver.StoreImpulses(); + profile->solveVelocity = timer.GetMilliseconds(); + + // Integrate positions + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Vec2 c = m_positions[i].c; + float32 a = m_positions[i].a; + b2Vec2 v = m_velocities[i].v; + float32 w = m_velocities[i].w; + + // Check for large velocities + b2Vec2 translation = h * v; + if (b2Dot(translation, translation) > b2_maxTranslationSquared) + { + float32 ratio = b2_maxTranslation / translation.Length(); + v *= ratio; + } + + float32 rotation = h * w; + if (rotation * rotation > b2_maxRotationSquared) + { + float32 ratio = b2_maxRotation / b2Abs(rotation); + w *= ratio; + } + + // Integrate + c += h * v; + a += h * w; + + m_positions[i].c = c; + m_positions[i].a = a; + m_velocities[i].v = v; + m_velocities[i].w = w; + } + + // Solve position constraints + timer.Reset(); + bool positionSolved = false; + for (int32 i = 0; i < step.positionIterations; ++i) + { + bool contactsOkay = contactSolver.SolvePositionConstraints(); + + bool jointsOkay = true; + for (int32 i = 0; i < m_jointCount; ++i) + { + bool jointOkay = m_joints[i]->SolvePositionConstraints(solverData); + jointsOkay = jointsOkay && jointOkay; + } + + if (contactsOkay && jointsOkay) + { + // Exit early if the position errors are small. + positionSolved = true; + break; + } + } + + // Copy state buffers back to the bodies + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* body = m_bodies[i]; + body->m_sweep.c = m_positions[i].c; + body->m_sweep.a = m_positions[i].a; + body->m_linearVelocity = m_velocities[i].v; + body->m_angularVelocity = m_velocities[i].w; + body->SynchronizeTransform(); + } + + profile->solvePosition = timer.GetMilliseconds(); + + Report(contactSolver.m_velocityConstraints); + + if (allowSleep) + { + float32 minSleepTime = b2_maxFloat; + + const float32 linTolSqr = b2_linearSleepTolerance * b2_linearSleepTolerance; + const float32 angTolSqr = b2_angularSleepTolerance * b2_angularSleepTolerance; + + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* b = m_bodies[i]; + if (b->GetType() == b2_staticBody) + { + continue; + } + + if ((b->m_flags & b2Body::e_autoSleepFlag) == 0 || + b->m_angularVelocity * b->m_angularVelocity > angTolSqr || + b2Dot(b->m_linearVelocity, b->m_linearVelocity) > linTolSqr) + { + b->m_sleepTime = 0.0f; + minSleepTime = 0.0f; + } + else + { + b->m_sleepTime += h; + minSleepTime = b2Min(minSleepTime, b->m_sleepTime); + } + } + + if (minSleepTime >= b2_timeToSleep && positionSolved) + { + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* b = m_bodies[i]; + b->SetAwake(false); + } + } + } +} + +void b2Island::SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB) +{ + b2Assert(toiIndexA < m_bodyCount); + b2Assert(toiIndexB < m_bodyCount); + + // Initialize the body state. + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* b = m_bodies[i]; + m_positions[i].c = b->m_sweep.c; + m_positions[i].a = b->m_sweep.a; + m_velocities[i].v = b->m_linearVelocity; + m_velocities[i].w = b->m_angularVelocity; + } + + b2ContactSolverDef contactSolverDef; + contactSolverDef.contacts = m_contacts; + contactSolverDef.count = m_contactCount; + contactSolverDef.allocator = m_allocator; + contactSolverDef.step = subStep; + contactSolverDef.positions = m_positions; + contactSolverDef.velocities = m_velocities; + b2ContactSolver contactSolver(&contactSolverDef); + + // Solve position constraints. + for (int32 i = 0; i < subStep.positionIterations; ++i) + { + bool contactsOkay = contactSolver.SolveTOIPositionConstraints(toiIndexA, toiIndexB); + if (contactsOkay) + { + break; + } + } + +#if 0 + // Is the new position really safe? + for (int32 i = 0; i < m_contactCount; ++i) + { + b2Contact* c = m_contacts[i]; + b2Fixture* fA = c->GetFixtureA(); + b2Fixture* fB = c->GetFixtureB(); + + b2Body* bA = fA->GetBody(); + b2Body* bB = fB->GetBody(); + + int32 indexA = c->GetChildIndexA(); + int32 indexB = c->GetChildIndexB(); + + b2DistanceInput input; + input.proxyA.Set(fA->GetShape(), indexA); + input.proxyB.Set(fB->GetShape(), indexB); + input.transformA = bA->GetTransform(); + input.transformB = bB->GetTransform(); + input.useRadii = false; + + b2DistanceOutput output; + b2SimplexCache cache; + cache.count = 0; + b2Distance(&output, &cache, &input); + + if (output.distance == 0 || cache.count == 3) + { + cache.count += 0; + } + } +#endif + + // Leap of faith to new safe state. + m_bodies[toiIndexA]->m_sweep.c0 = m_positions[toiIndexA].c; + m_bodies[toiIndexA]->m_sweep.a0 = m_positions[toiIndexA].a; + m_bodies[toiIndexB]->m_sweep.c0 = m_positions[toiIndexB].c; + m_bodies[toiIndexB]->m_sweep.a0 = m_positions[toiIndexB].a; + + // No warm starting is needed for TOI events because warm + // starting impulses were applied in the discrete solver. + contactSolver.InitializeVelocityConstraints(); + + // Solve velocity constraints. + for (int32 i = 0; i < subStep.velocityIterations; ++i) + { + contactSolver.SolveVelocityConstraints(); + } + + // Don't store the TOI contact forces for warm starting + // because they can be quite large. + + float32 h = subStep.dt; + + // Integrate positions + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Vec2 c = m_positions[i].c; + float32 a = m_positions[i].a; + b2Vec2 v = m_velocities[i].v; + float32 w = m_velocities[i].w; + + // Check for large velocities + b2Vec2 translation = h * v; + if (b2Dot(translation, translation) > b2_maxTranslationSquared) + { + float32 ratio = b2_maxTranslation / translation.Length(); + v *= ratio; + } + + float32 rotation = h * w; + if (rotation * rotation > b2_maxRotationSquared) + { + float32 ratio = b2_maxRotation / b2Abs(rotation); + w *= ratio; + } + + // Integrate + c += h * v; + a += h * w; + + m_positions[i].c = c; + m_positions[i].a = a; + m_velocities[i].v = v; + m_velocities[i].w = w; + + // Sync bodies + b2Body* body = m_bodies[i]; + body->m_sweep.c = c; + body->m_sweep.a = a; + body->m_linearVelocity = v; + body->m_angularVelocity = w; + body->SynchronizeTransform(); + } + + Report(contactSolver.m_velocityConstraints); +} + +void b2Island::Report(const b2ContactVelocityConstraint* constraints) +{ + if (m_listener == NULL) + { + return; + } + + for (int32 i = 0; i < m_contactCount; ++i) + { + b2Contact* c = m_contacts[i]; + + const b2ContactVelocityConstraint* vc = constraints + i; + + b2ContactImpulse impulse; + impulse.count = vc->pointCount; + for (int32 j = 0; j < vc->pointCount; ++j) + { + impulse.normalImpulses[j] = vc->points[j].normalImpulse; + impulse.tangentImpulses[j] = vc->points[j].tangentImpulse; + } + + m_listener->PostSolve(c, &impulse); + } +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Island.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Island.h new file mode 100755 index 0000000000000..ef3d9b1df24ed --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Island.h @@ -0,0 +1,93 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_ISLAND_H +#define B2_ISLAND_H + +#include +#include +#include + +class b2Contact; +class b2Joint; +class b2StackAllocator; +class b2ContactListener; +struct b2ContactVelocityConstraint; +struct b2Profile; + +/// This is an internal class. +class b2Island +{ +public: + b2Island(int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity, + b2StackAllocator* allocator, b2ContactListener* listener); + ~b2Island(); + + void Clear() + { + m_bodyCount = 0; + m_contactCount = 0; + m_jointCount = 0; + } + + void Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep); + + void SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB); + + void Add(b2Body* body) + { + b2Assert(m_bodyCount < m_bodyCapacity); + body->m_islandIndex = m_bodyCount; + m_bodies[m_bodyCount] = body; + ++m_bodyCount; + } + + void Add(b2Contact* contact) + { + b2Assert(m_contactCount < m_contactCapacity); + m_contacts[m_contactCount++] = contact; + } + + void Add(b2Joint* joint) + { + b2Assert(m_jointCount < m_jointCapacity); + m_joints[m_jointCount++] = joint; + } + + void Report(const b2ContactVelocityConstraint* constraints); + + b2StackAllocator* m_allocator; + b2ContactListener* m_listener; + + b2Body** m_bodies; + b2Contact** m_contacts; + b2Joint** m_joints; + + b2Position* m_positions; + b2Velocity* m_velocities; + + int32 m_bodyCount; + int32 m_jointCount; + int32 m_contactCount; + + int32 m_bodyCapacity; + int32 m_contactCapacity; + int32 m_jointCapacity; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2TimeStep.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2TimeStep.h new file mode 100755 index 0000000000000..abe6fb6e0f4f9 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2TimeStep.h @@ -0,0 +1,70 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_TIME_STEP_H +#define B2_TIME_STEP_H + +#include + +/// Profiling data. Times are in milliseconds. +struct b2Profile +{ + float32 step; + float32 collide; + float32 solve; + float32 solveInit; + float32 solveVelocity; + float32 solvePosition; + float32 broadphase; + float32 solveTOI; +}; + +/// This is an internal structure. +struct b2TimeStep +{ + float32 dt; // time step + float32 inv_dt; // inverse time step (0 if dt == 0). + float32 dtRatio; // dt * inv_dt0 + int32 velocityIterations; + int32 positionIterations; + bool warmStarting; +}; + +/// This is an internal structure. +struct b2Position +{ + b2Vec2 c; + float32 a; +}; + +/// This is an internal structure. +struct b2Velocity +{ + b2Vec2 v; + float32 w; +}; + +/// Solver Data +struct b2SolverData +{ + b2TimeStep step; + b2Position* positions; + b2Velocity* velocities; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2World.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2World.cpp new file mode 100755 index 0000000000000..baacded4f023d --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2World.cpp @@ -0,0 +1,1316 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +b2World::b2World(const b2Vec2& gravity) +{ + m_destructionListener = NULL; + m_debugDraw = NULL; + + m_bodyList = NULL; + m_jointList = NULL; + + m_bodyCount = 0; + m_jointCount = 0; + + m_warmStarting = true; + m_continuousPhysics = true; + m_subStepping = false; + + m_stepComplete = true; + + m_allowSleep = true; + m_gravity = gravity; + + m_flags = e_clearForces; + + m_inv_dt0 = 0.0f; + + m_contactManager.m_allocator = &m_blockAllocator; + + memset(&m_profile, 0, sizeof(b2Profile)); +} + +b2World::~b2World() +{ + // Some shapes allocate using b2Alloc. + b2Body* b = m_bodyList; + while (b) + { + b2Body* bNext = b->m_next; + + b2Fixture* f = b->m_fixtureList; + while (f) + { + b2Fixture* fNext = f->m_next; + f->m_proxyCount = 0; + f->Destroy(&m_blockAllocator); + f = fNext; + } + + b = bNext; + } +} + +void b2World::SetDestructionListener(b2DestructionListener* listener) +{ + m_destructionListener = listener; +} + +void b2World::SetContactFilter(b2ContactFilter* filter) +{ + m_contactManager.m_contactFilter = filter; +} + +void b2World::SetContactListener(b2ContactListener* listener) +{ + m_contactManager.m_contactListener = listener; +} + +void b2World::SetDebugDraw(b2Draw* debugDraw) +{ + m_debugDraw = debugDraw; +} + +b2Body* b2World::CreateBody(const b2BodyDef* def) +{ + b2Assert(IsLocked() == false); + if (IsLocked()) + { + return NULL; + } + + void* mem = m_blockAllocator.Allocate(sizeof(b2Body)); + b2Body* b = new (mem) b2Body(def, this); + + // Add to world doubly linked list. + b->m_prev = NULL; + b->m_next = m_bodyList; + if (m_bodyList) + { + m_bodyList->m_prev = b; + } + m_bodyList = b; + ++m_bodyCount; + + return b; +} + +void b2World::DestroyBody(b2Body* b) +{ + b2Assert(m_bodyCount > 0); + b2Assert(IsLocked() == false); + if (IsLocked()) + { + return; + } + + // Delete the attached joints. + b2JointEdge* je = b->m_jointList; + while (je) + { + b2JointEdge* je0 = je; + je = je->next; + + if (m_destructionListener) + { + m_destructionListener->SayGoodbye(je0->joint); + } + + DestroyJoint(je0->joint); + + b->m_jointList = je; + } + b->m_jointList = NULL; + + // Delete the attached contacts. + b2ContactEdge* ce = b->m_contactList; + while (ce) + { + b2ContactEdge* ce0 = ce; + ce = ce->next; + m_contactManager.Destroy(ce0->contact); + } + b->m_contactList = NULL; + + // Delete the attached fixtures. This destroys broad-phase proxies. + b2Fixture* f = b->m_fixtureList; + while (f) + { + b2Fixture* f0 = f; + f = f->m_next; + + if (m_destructionListener) + { + m_destructionListener->SayGoodbye(f0); + } + + f0->DestroyProxies(&m_contactManager.m_broadPhase); + f0->Destroy(&m_blockAllocator); + f0->~b2Fixture(); + m_blockAllocator.Free(f0, sizeof(b2Fixture)); + + b->m_fixtureList = f; + b->m_fixtureCount -= 1; + } + b->m_fixtureList = NULL; + b->m_fixtureCount = 0; + + // Remove world body list. + if (b->m_prev) + { + b->m_prev->m_next = b->m_next; + } + + if (b->m_next) + { + b->m_next->m_prev = b->m_prev; + } + + if (b == m_bodyList) + { + m_bodyList = b->m_next; + } + + --m_bodyCount; + b->~b2Body(); + m_blockAllocator.Free(b, sizeof(b2Body)); +} + +b2Joint* b2World::CreateJoint(const b2JointDef* def) +{ + b2Assert(IsLocked() == false); + if (IsLocked()) + { + return NULL; + } + + b2Joint* j = b2Joint::Create(def, &m_blockAllocator); + + // Connect to the world list. + j->m_prev = NULL; + j->m_next = m_jointList; + if (m_jointList) + { + m_jointList->m_prev = j; + } + m_jointList = j; + ++m_jointCount; + + // Connect to the bodies' doubly linked lists. + j->m_edgeA.joint = j; + j->m_edgeA.other = j->m_bodyB; + j->m_edgeA.prev = NULL; + j->m_edgeA.next = j->m_bodyA->m_jointList; + if (j->m_bodyA->m_jointList) j->m_bodyA->m_jointList->prev = &j->m_edgeA; + j->m_bodyA->m_jointList = &j->m_edgeA; + + j->m_edgeB.joint = j; + j->m_edgeB.other = j->m_bodyA; + j->m_edgeB.prev = NULL; + j->m_edgeB.next = j->m_bodyB->m_jointList; + if (j->m_bodyB->m_jointList) j->m_bodyB->m_jointList->prev = &j->m_edgeB; + j->m_bodyB->m_jointList = &j->m_edgeB; + + b2Body* bodyA = def->bodyA; + b2Body* bodyB = def->bodyB; + + // If the joint prevents collisions, then flag any contacts for filtering. + if (def->collideConnected == false) + { + b2ContactEdge* edge = bodyB->GetContactList(); + while (edge) + { + if (edge->other == bodyA) + { + // Flag the contact for filtering at the next time step (where either + // body is awake). + edge->contact->FlagForFiltering(); + } + + edge = edge->next; + } + } + + // Note: creating a joint doesn't wake the bodies. + + return j; +} + +void b2World::DestroyJoint(b2Joint* j) +{ + b2Assert(IsLocked() == false); + if (IsLocked()) + { + return; + } + + bool collideConnected = j->m_collideConnected; + + // Remove from the doubly linked list. + if (j->m_prev) + { + j->m_prev->m_next = j->m_next; + } + + if (j->m_next) + { + j->m_next->m_prev = j->m_prev; + } + + if (j == m_jointList) + { + m_jointList = j->m_next; + } + + // Disconnect from island graph. + b2Body* bodyA = j->m_bodyA; + b2Body* bodyB = j->m_bodyB; + + // Wake up connected bodies. + bodyA->SetAwake(true); + bodyB->SetAwake(true); + + // Remove from body 1. + if (j->m_edgeA.prev) + { + j->m_edgeA.prev->next = j->m_edgeA.next; + } + + if (j->m_edgeA.next) + { + j->m_edgeA.next->prev = j->m_edgeA.prev; + } + + if (&j->m_edgeA == bodyA->m_jointList) + { + bodyA->m_jointList = j->m_edgeA.next; + } + + j->m_edgeA.prev = NULL; + j->m_edgeA.next = NULL; + + // Remove from body 2 + if (j->m_edgeB.prev) + { + j->m_edgeB.prev->next = j->m_edgeB.next; + } + + if (j->m_edgeB.next) + { + j->m_edgeB.next->prev = j->m_edgeB.prev; + } + + if (&j->m_edgeB == bodyB->m_jointList) + { + bodyB->m_jointList = j->m_edgeB.next; + } + + j->m_edgeB.prev = NULL; + j->m_edgeB.next = NULL; + + b2Joint::Destroy(j, &m_blockAllocator); + + b2Assert(m_jointCount > 0); + --m_jointCount; + + // If the joint prevents collisions, then flag any contacts for filtering. + if (collideConnected == false) + { + b2ContactEdge* edge = bodyB->GetContactList(); + while (edge) + { + if (edge->other == bodyA) + { + // Flag the contact for filtering at the next time step (where either + // body is awake). + edge->contact->FlagForFiltering(); + } + + edge = edge->next; + } + } +} + +// +void b2World::SetAllowSleeping(bool flag) +{ + if (flag == m_allowSleep) + { + return; + } + + m_allowSleep = flag; + if (m_allowSleep == false) + { + for (b2Body* b = m_bodyList; b; b = b->m_next) + { + b->SetAwake(true); + } + } +} + +// Find islands, integrate and solve constraints, solve position constraints +void b2World::Solve(const b2TimeStep& step) +{ + m_profile.solveInit = 0.0f; + m_profile.solveVelocity = 0.0f; + m_profile.solvePosition = 0.0f; + + // Size the island for the worst case. + b2Island island(m_bodyCount, + m_contactManager.m_contactCount, + m_jointCount, + &m_stackAllocator, + m_contactManager.m_contactListener); + + // Clear all the island flags. + for (b2Body* b = m_bodyList; b; b = b->m_next) + { + b->m_flags &= ~b2Body::e_islandFlag; + } + for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) + { + c->m_flags &= ~b2Contact::e_islandFlag; + } + for (b2Joint* j = m_jointList; j; j = j->m_next) + { + j->m_islandFlag = false; + } + + // Build and simulate all awake islands. + int32 stackSize = m_bodyCount; + b2Body** stack = (b2Body**)m_stackAllocator.Allocate(stackSize * sizeof(b2Body*)); + for (b2Body* seed = m_bodyList; seed; seed = seed->m_next) + { + if (seed->m_flags & b2Body::e_islandFlag) + { + continue; + } + + if (seed->IsAwake() == false || seed->IsActive() == false) + { + continue; + } + + // The seed can be dynamic or kinematic. + if (seed->GetType() == b2_staticBody) + { + continue; + } + + // Reset island and stack. + island.Clear(); + int32 stackCount = 0; + stack[stackCount++] = seed; + seed->m_flags |= b2Body::e_islandFlag; + + // Perform a depth first search (DFS) on the constraint graph. + while (stackCount > 0) + { + // Grab the next body off the stack and add it to the island. + b2Body* b = stack[--stackCount]; + b2Assert(b->IsActive() == true); + island.Add(b); + + // Make sure the body is awake. + b->SetAwake(true); + + // To keep islands as small as possible, we don't + // propagate islands across static bodies. + if (b->GetType() == b2_staticBody) + { + continue; + } + + // Search all contacts connected to this body. + for (b2ContactEdge* ce = b->m_contactList; ce; ce = ce->next) + { + b2Contact* contact = ce->contact; + + // Has this contact already been added to an island? + if (contact->m_flags & b2Contact::e_islandFlag) + { + continue; + } + + // Is this contact solid and touching? + if (contact->IsEnabled() == false || + contact->IsTouching() == false) + { + continue; + } + + // Skip sensors. + bool sensorA = contact->m_fixtureA->m_isSensor; + bool sensorB = contact->m_fixtureB->m_isSensor; + if (sensorA || sensorB) + { + continue; + } + + island.Add(contact); + contact->m_flags |= b2Contact::e_islandFlag; + + b2Body* other = ce->other; + + // Was the other body already added to this island? + if (other->m_flags & b2Body::e_islandFlag) + { + continue; + } + + b2Assert(stackCount < stackSize); + stack[stackCount++] = other; + other->m_flags |= b2Body::e_islandFlag; + } + + // Search all joints connect to this body. + for (b2JointEdge* je = b->m_jointList; je; je = je->next) + { + if (je->joint->m_islandFlag == true) + { + continue; + } + + b2Body* other = je->other; + + // Don't simulate joints connected to inactive bodies. + if (other->IsActive() == false) + { + continue; + } + + island.Add(je->joint); + je->joint->m_islandFlag = true; + + if (other->m_flags & b2Body::e_islandFlag) + { + continue; + } + + b2Assert(stackCount < stackSize); + stack[stackCount++] = other; + other->m_flags |= b2Body::e_islandFlag; + } + } + + b2Profile profile; + island.Solve(&profile, step, m_gravity, m_allowSleep); + m_profile.solveInit += profile.solveInit; + m_profile.solveVelocity += profile.solveVelocity; + m_profile.solvePosition += profile.solvePosition; + + // Post solve cleanup. + for (int32 i = 0; i < island.m_bodyCount; ++i) + { + // Allow static bodies to participate in other islands. + b2Body* b = island.m_bodies[i]; + if (b->GetType() == b2_staticBody) + { + b->m_flags &= ~b2Body::e_islandFlag; + } + } + } + + m_stackAllocator.Free(stack); + + { + b2Timer timer; + // Synchronize fixtures, check for out of range bodies. + for (b2Body* b = m_bodyList; b; b = b->GetNext()) + { + // If a body was not in an island then it did not move. + if ((b->m_flags & b2Body::e_islandFlag) == 0) + { + continue; + } + + if (b->GetType() == b2_staticBody) + { + continue; + } + + // Update fixtures (for broad-phase). + b->SynchronizeFixtures(); + } + + // Look for new contacts. + m_contactManager.FindNewContacts(); + m_profile.broadphase = timer.GetMilliseconds(); + } +} + +// Find TOI contacts and solve them. +void b2World::SolveTOI(const b2TimeStep& step) +{ + b2Island island(2 * b2_maxTOIContacts, b2_maxTOIContacts, 0, &m_stackAllocator, m_contactManager.m_contactListener); + + if (m_stepComplete) + { + for (b2Body* b = m_bodyList; b; b = b->m_next) + { + b->m_flags &= ~b2Body::e_islandFlag; + b->m_sweep.alpha0 = 0.0f; + } + + for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) + { + // Invalidate TOI + c->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); + c->m_toiCount = 0; + c->m_toi = 1.0f; + } + } + + // Find TOI events and solve them. + for (;;) + { + // Find the first TOI. + b2Contact* minContact = NULL; + float32 minAlpha = 1.0f; + + for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) + { + // Is this contact disabled? + if (c->IsEnabled() == false) + { + continue; + } + + // Prevent excessive sub-stepping. + if (c->m_toiCount > b2_maxSubSteps) + { + continue; + } + + float32 alpha = 1.0f; + if (c->m_flags & b2Contact::e_toiFlag) + { + // This contact has a valid cached TOI. + alpha = c->m_toi; + } + else + { + b2Fixture* fA = c->GetFixtureA(); + b2Fixture* fB = c->GetFixtureB(); + + // Is there a sensor? + if (fA->IsSensor() || fB->IsSensor()) + { + continue; + } + + b2Body* bA = fA->GetBody(); + b2Body* bB = fB->GetBody(); + + b2BodyType typeA = bA->m_type; + b2BodyType typeB = bB->m_type; + b2Assert(typeA == b2_dynamicBody || typeB == b2_dynamicBody); + + bool activeA = bA->IsAwake() && typeA != b2_staticBody; + bool activeB = bB->IsAwake() && typeB != b2_staticBody; + + // Is at least one body active (awake and dynamic or kinematic)? + if (activeA == false && activeB == false) + { + continue; + } + + bool collideA = bA->IsBullet() || typeA != b2_dynamicBody; + bool collideB = bB->IsBullet() || typeB != b2_dynamicBody; + + // Are these two non-bullet dynamic bodies? + if (collideA == false && collideB == false) + { + continue; + } + + // Compute the TOI for this contact. + // Put the sweeps onto the same time interval. + float32 alpha0 = bA->m_sweep.alpha0; + + if (bA->m_sweep.alpha0 < bB->m_sweep.alpha0) + { + alpha0 = bB->m_sweep.alpha0; + bA->m_sweep.Advance(alpha0); + } + else if (bB->m_sweep.alpha0 < bA->m_sweep.alpha0) + { + alpha0 = bA->m_sweep.alpha0; + bB->m_sweep.Advance(alpha0); + } + + b2Assert(alpha0 < 1.0f); + + int32 indexA = c->GetChildIndexA(); + int32 indexB = c->GetChildIndexB(); + + // Compute the time of impact in interval [0, minTOI] + b2TOIInput input; + input.proxyA.Set(fA->GetShape(), indexA); + input.proxyB.Set(fB->GetShape(), indexB); + input.sweepA = bA->m_sweep; + input.sweepB = bB->m_sweep; + input.tMax = 1.0f; + + b2TOIOutput output; + b2TimeOfImpact(&output, &input); + + // Beta is the fraction of the remaining portion of the . + float32 beta = output.t; + if (output.state == b2TOIOutput::e_touching) + { + alpha = b2Min(alpha0 + (1.0f - alpha0) * beta, 1.0f); + } + else + { + alpha = 1.0f; + } + + c->m_toi = alpha; + c->m_flags |= b2Contact::e_toiFlag; + } + + if (alpha < minAlpha) + { + // This is the minimum TOI found so far. + minContact = c; + minAlpha = alpha; + } + } + + if (minContact == NULL || 1.0f - 10.0f * b2_epsilon < minAlpha) + { + // No more TOI events. Done! + m_stepComplete = true; + break; + } + + // Advance the bodies to the TOI. + b2Fixture* fA = minContact->GetFixtureA(); + b2Fixture* fB = minContact->GetFixtureB(); + b2Body* bA = fA->GetBody(); + b2Body* bB = fB->GetBody(); + + b2Sweep backup1 = bA->m_sweep; + b2Sweep backup2 = bB->m_sweep; + + bA->Advance(minAlpha); + bB->Advance(minAlpha); + + // The TOI contact likely has some new contact points. + minContact->Update(m_contactManager.m_contactListener); + minContact->m_flags &= ~b2Contact::e_toiFlag; + ++minContact->m_toiCount; + + // Is the contact solid? + if (minContact->IsEnabled() == false || minContact->IsTouching() == false) + { + // Restore the sweeps. + minContact->SetEnabled(false); + bA->m_sweep = backup1; + bB->m_sweep = backup2; + bA->SynchronizeTransform(); + bB->SynchronizeTransform(); + continue; + } + + bA->SetAwake(true); + bB->SetAwake(true); + + // Build the island + island.Clear(); + island.Add(bA); + island.Add(bB); + island.Add(minContact); + + bA->m_flags |= b2Body::e_islandFlag; + bB->m_flags |= b2Body::e_islandFlag; + minContact->m_flags |= b2Contact::e_islandFlag; + + // Get contacts on bodyA and bodyB. + b2Body* bodies[2] = {bA, bB}; + for (int32 i = 0; i < 2; ++i) + { + b2Body* body = bodies[i]; + if (body->m_type == b2_dynamicBody) + { + for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next) + { + if (island.m_bodyCount == island.m_bodyCapacity) + { + break; + } + + if (island.m_contactCount == island.m_contactCapacity) + { + break; + } + + b2Contact* contact = ce->contact; + + // Has this contact already been added to the island? + if (contact->m_flags & b2Contact::e_islandFlag) + { + continue; + } + + // Only add static, kinematic, or bullet bodies. + b2Body* other = ce->other; + if (other->m_type == b2_dynamicBody && + body->IsBullet() == false && other->IsBullet() == false) + { + continue; + } + + // Skip sensors. + bool sensorA = contact->m_fixtureA->m_isSensor; + bool sensorB = contact->m_fixtureB->m_isSensor; + if (sensorA || sensorB) + { + continue; + } + + // Tentatively advance the body to the TOI. + b2Sweep backup = other->m_sweep; + if ((other->m_flags & b2Body::e_islandFlag) == 0) + { + other->Advance(minAlpha); + } + + // Update the contact points + contact->Update(m_contactManager.m_contactListener); + + // Was the contact disabled by the user? + if (contact->IsEnabled() == false) + { + other->m_sweep = backup; + other->SynchronizeTransform(); + continue; + } + + // Are there contact points? + if (contact->IsTouching() == false) + { + other->m_sweep = backup; + other->SynchronizeTransform(); + continue; + } + + // Add the contact to the island + contact->m_flags |= b2Contact::e_islandFlag; + island.Add(contact); + + // Has the other body already been added to the island? + if (other->m_flags & b2Body::e_islandFlag) + { + continue; + } + + // Add the other body to the island. + other->m_flags |= b2Body::e_islandFlag; + + if (other->m_type != b2_staticBody) + { + other->SetAwake(true); + } + + island.Add(other); + } + } + } + + b2TimeStep subStep; + subStep.dt = (1.0f - minAlpha) * step.dt; + subStep.inv_dt = 1.0f / subStep.dt; + subStep.dtRatio = 1.0f; + subStep.positionIterations = 20; + subStep.velocityIterations = step.velocityIterations; + subStep.warmStarting = false; + island.SolveTOI(subStep, bA->m_islandIndex, bB->m_islandIndex); + + // Reset island flags and synchronize broad-phase proxies. + for (int32 i = 0; i < island.m_bodyCount; ++i) + { + b2Body* body = island.m_bodies[i]; + body->m_flags &= ~b2Body::e_islandFlag; + + if (body->m_type != b2_dynamicBody) + { + continue; + } + + body->SynchronizeFixtures(); + + // Invalidate all contact TOIs on this displaced body. + for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next) + { + ce->contact->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); + } + } + + // Commit fixture proxy movements to the broad-phase so that new contacts are created. + // Also, some contacts can be destroyed. + m_contactManager.FindNewContacts(); + + if (m_subStepping) + { + m_stepComplete = false; + break; + } + } +} + +void b2World::Step(float32 dt, int32 velocityIterations, int32 positionIterations) +{ + b2Timer stepTimer; + + // If new fixtures were added, we need to find the new contacts. + if (m_flags & e_newFixture) + { + m_contactManager.FindNewContacts(); + m_flags &= ~e_newFixture; + } + + m_flags |= e_locked; + + b2TimeStep step; + step.dt = dt; + step.velocityIterations = velocityIterations; + step.positionIterations = positionIterations; + if (dt > 0.0f) + { + step.inv_dt = 1.0f / dt; + } + else + { + step.inv_dt = 0.0f; + } + + step.dtRatio = m_inv_dt0 * dt; + + step.warmStarting = m_warmStarting; + + // Update contacts. This is where some contacts are destroyed. + { + b2Timer timer; + m_contactManager.Collide(); + m_profile.collide = timer.GetMilliseconds(); + } + + // Integrate velocities, solve velocity constraints, and integrate positions. + if (m_stepComplete && step.dt > 0.0f) + { + b2Timer timer; + Solve(step); + m_profile.solve = timer.GetMilliseconds(); + } + + // Handle TOI events. + if (m_continuousPhysics && step.dt > 0.0f) + { + b2Timer timer; + SolveTOI(step); + m_profile.solveTOI = timer.GetMilliseconds(); + } + + if (step.dt > 0.0f) + { + m_inv_dt0 = step.inv_dt; + } + + if (m_flags & e_clearForces) + { + ClearForces(); + } + + m_flags &= ~e_locked; + + m_profile.step = stepTimer.GetMilliseconds(); +} + +void b2World::ClearForces() +{ + for (b2Body* body = m_bodyList; body; body = body->GetNext()) + { + body->m_force.SetZero(); + body->m_torque = 0.0f; + } +} + +struct b2WorldQueryWrapper +{ + bool QueryCallback(int32 proxyId) + { + b2FixtureProxy* proxy = (b2FixtureProxy*)broadPhase->GetUserData(proxyId); + return callback->ReportFixture(proxy->fixture); + } + + const b2BroadPhase* broadPhase; + b2QueryCallback* callback; +}; + +void b2World::QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const +{ + b2WorldQueryWrapper wrapper; + wrapper.broadPhase = &m_contactManager.m_broadPhase; + wrapper.callback = callback; + m_contactManager.m_broadPhase.Query(&wrapper, aabb); +} + +struct b2WorldRayCastWrapper +{ + float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId) + { + void* userData = broadPhase->GetUserData(proxyId); + b2FixtureProxy* proxy = (b2FixtureProxy*)userData; + b2Fixture* fixture = proxy->fixture; + int32 index = proxy->childIndex; + b2RayCastOutput output; + bool hit = fixture->RayCast(&output, input, index); + + if (hit) + { + float32 fraction = output.fraction; + b2Vec2 point = (1.0f - fraction) * input.p1 + fraction * input.p2; + return callback->ReportFixture(fixture, point, output.normal, fraction); + } + + return input.maxFraction; + } + + const b2BroadPhase* broadPhase; + b2RayCastCallback* callback; +}; + +void b2World::RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const +{ + b2WorldRayCastWrapper wrapper; + wrapper.broadPhase = &m_contactManager.m_broadPhase; + wrapper.callback = callback; + b2RayCastInput input; + input.maxFraction = 1.0f; + input.p1 = point1; + input.p2 = point2; + m_contactManager.m_broadPhase.RayCast(&wrapper, input); +} + +void b2World::DrawShape(b2Fixture* fixture, const b2Transform& xf, const b2Color& color) +{ + switch (fixture->GetType()) + { + case b2Shape::e_circle: + { + b2CircleShape* circle = (b2CircleShape*)fixture->GetShape(); + + b2Vec2 center = b2Mul(xf, circle->m_p); + float32 radius = circle->m_radius; + b2Vec2 axis = b2Mul(xf.q, b2Vec2(1.0f, 0.0f)); + + m_debugDraw->DrawSolidCircle(center, radius, axis, color); + } + break; + + case b2Shape::e_edge: + { + b2EdgeShape* edge = (b2EdgeShape*)fixture->GetShape(); + b2Vec2 v1 = b2Mul(xf, edge->m_vertex1); + b2Vec2 v2 = b2Mul(xf, edge->m_vertex2); + m_debugDraw->DrawSegment(v1, v2, color); + } + break; + + case b2Shape::e_chain: + { + b2ChainShape* chain = (b2ChainShape*)fixture->GetShape(); + int32 count = chain->m_count; + const b2Vec2* vertices = chain->m_vertices; + + b2Vec2 v1 = b2Mul(xf, vertices[0]); + for (int32 i = 1; i < count; ++i) + { + b2Vec2 v2 = b2Mul(xf, vertices[i]); + m_debugDraw->DrawSegment(v1, v2, color); + m_debugDraw->DrawCircle(v1, 0.05f, color); + v1 = v2; + } + } + break; + + case b2Shape::e_polygon: + { + b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape(); + int32 vertexCount = poly->m_vertexCount; + b2Assert(vertexCount <= b2_maxPolygonVertices); + b2Vec2 vertices[b2_maxPolygonVertices]; + + for (int32 i = 0; i < vertexCount; ++i) + { + vertices[i] = b2Mul(xf, poly->m_vertices[i]); + } + + m_debugDraw->DrawSolidPolygon(vertices, vertexCount, color); + } + break; + + default: + break; + } +} + +void b2World::DrawJoint(b2Joint* joint) +{ + b2Body* bodyA = joint->GetBodyA(); + b2Body* bodyB = joint->GetBodyB(); + const b2Transform& xf1 = bodyA->GetTransform(); + const b2Transform& xf2 = bodyB->GetTransform(); + b2Vec2 x1 = xf1.p; + b2Vec2 x2 = xf2.p; + b2Vec2 p1 = joint->GetAnchorA(); + b2Vec2 p2 = joint->GetAnchorB(); + + b2Color color(0.5f, 0.8f, 0.8f); + + switch (joint->GetType()) + { + case e_distanceJoint: + m_debugDraw->DrawSegment(p1, p2, color); + break; + + case e_pulleyJoint: + { + b2PulleyJoint* pulley = (b2PulleyJoint*)joint; + b2Vec2 s1 = pulley->GetGroundAnchorA(); + b2Vec2 s2 = pulley->GetGroundAnchorB(); + m_debugDraw->DrawSegment(s1, p1, color); + m_debugDraw->DrawSegment(s2, p2, color); + m_debugDraw->DrawSegment(s1, s2, color); + } + break; + + case e_mouseJoint: + // don't draw this + break; + + default: + m_debugDraw->DrawSegment(x1, p1, color); + m_debugDraw->DrawSegment(p1, p2, color); + m_debugDraw->DrawSegment(x2, p2, color); + } +} + +void b2World::DrawDebugData() +{ + if (m_debugDraw == NULL) + { + return; + } + + uint32 flags = m_debugDraw->GetFlags(); + + if (flags & b2Draw::e_shapeBit) + { + for (b2Body* b = m_bodyList; b; b = b->GetNext()) + { + const b2Transform& xf = b->GetTransform(); + for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) + { + if (b->IsActive() == false) + { + DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.3f)); + } + else if (b->GetType() == b2_staticBody) + { + DrawShape(f, xf, b2Color(0.5f, 0.9f, 0.5f)); + } + else if (b->GetType() == b2_kinematicBody) + { + DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.9f)); + } + else if (b->IsAwake() == false) + { + DrawShape(f, xf, b2Color(0.6f, 0.6f, 0.6f)); + } + else + { + DrawShape(f, xf, b2Color(0.9f, 0.7f, 0.7f)); + } + } + } + } + + if (flags & b2Draw::e_jointBit) + { + for (b2Joint* j = m_jointList; j; j = j->GetNext()) + { + DrawJoint(j); + } + } + + if (flags & b2Draw::e_pairBit) + { + b2Color color(0.3f, 0.9f, 0.9f); + for (b2Contact* c = m_contactManager.m_contactList; c; c = c->GetNext()) + { + //b2Fixture* fixtureA = c->GetFixtureA(); + //b2Fixture* fixtureB = c->GetFixtureB(); + + //b2Vec2 cA = fixtureA->GetAABB().GetCenter(); + //b2Vec2 cB = fixtureB->GetAABB().GetCenter(); + + //m_debugDraw->DrawSegment(cA, cB, color); + } + } + + if (flags & b2Draw::e_aabbBit) + { + b2Color color(0.9f, 0.3f, 0.9f); + b2BroadPhase* bp = &m_contactManager.m_broadPhase; + + for (b2Body* b = m_bodyList; b; b = b->GetNext()) + { + if (b->IsActive() == false) + { + continue; + } + + for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) + { + for (int32 i = 0; i < f->m_proxyCount; ++i) + { + b2FixtureProxy* proxy = f->m_proxies + i; + b2AABB aabb = bp->GetFatAABB(proxy->proxyId); + b2Vec2 vs[4]; + vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y); + vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y); + vs[2].Set(aabb.upperBound.x, aabb.upperBound.y); + vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y); + + m_debugDraw->DrawPolygon(vs, 4, color); + } + } + } + } + + if (flags & b2Draw::e_centerOfMassBit) + { + for (b2Body* b = m_bodyList; b; b = b->GetNext()) + { + b2Transform xf = b->GetTransform(); + xf.p = b->GetWorldCenter(); + m_debugDraw->DrawTransform(xf); + } + } +} + +int32 b2World::GetProxyCount() const +{ + return m_contactManager.m_broadPhase.GetProxyCount(); +} + +int32 b2World::GetTreeHeight() const +{ + return m_contactManager.m_broadPhase.GetTreeHeight(); +} + +int32 b2World::GetTreeBalance() const +{ + return m_contactManager.m_broadPhase.GetTreeBalance(); +} + +float32 b2World::GetTreeQuality() const +{ + return m_contactManager.m_broadPhase.GetTreeQuality(); +} + +void b2World::Dump() +{ + if ((m_flags & e_locked) == e_locked) + { + return; + } + + b2Log("b2Vec2 g(%.15lef, %.15lef);\n", m_gravity.x, m_gravity.y); + b2Log("m_world->SetGravity(g);\n"); + + b2Log("b2Body** bodies = (b2Body**)b2Alloc(%d * sizeof(b2Body*));\n", m_bodyCount); + b2Log("b2Joint** joints = (b2Joint**)b2Alloc(%d * sizeof(b2Joint*));\n", m_jointCount); + int32 i = 0; + for (b2Body* b = m_bodyList; b; b = b->m_next) + { + b->m_islandIndex = i; + b->Dump(); + ++i; + } + + i = 0; + for (b2Joint* j = m_jointList; j; j = j->m_next) + { + j->m_index = i; + ++i; + } + + // First pass on joints, skip gear joints. + for (b2Joint* j = m_jointList; j; j = j->m_next) + { + if (j->m_type == e_gearJoint) + { + continue; + } + + b2Log("{\n"); + j->Dump(); + b2Log("}\n"); + } + + // Second pass on joints, only gear joints. + for (b2Joint* j = m_jointList; j; j = j->m_next) + { + if (j->m_type != e_gearJoint) + { + continue; + } + + b2Log("{\n"); + j->Dump(); + b2Log("}\n"); + } + + b2Log("b2Free(joints);\n"); + b2Log("b2Free(bodies);\n"); + b2Log("joints = NULL;\n"); + b2Log("bodies = NULL;\n"); +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2World.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2World.h new file mode 100755 index 0000000000000..eba7572762024 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2World.h @@ -0,0 +1,349 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_WORLD_H +#define B2_WORLD_H + +#include +#include +#include +#include +#include +#include + +struct b2AABB; +struct b2BodyDef; +struct b2Color; +struct b2JointDef; +class b2Body; +class b2Draw; +class b2Fixture; +class b2Joint; + +/// The world class manages all physics entities, dynamic simulation, +/// and asynchronous queries. The world also contains efficient memory +/// management facilities. +class b2World +{ +public: + /// Construct a world object. + /// @param gravity the world gravity vector. + b2World(const b2Vec2& gravity); + + /// Destruct the world. All physics entities are destroyed and all heap memory is released. + ~b2World(); + + /// Register a destruction listener. The listener is owned by you and must + /// remain in scope. + void SetDestructionListener(b2DestructionListener* listener); + + /// Register a contact filter to provide specific control over collision. + /// Otherwise the default filter is used (b2_defaultFilter). The listener is + /// owned by you and must remain in scope. + void SetContactFilter(b2ContactFilter* filter); + + /// Register a contact event listener. The listener is owned by you and must + /// remain in scope. + void SetContactListener(b2ContactListener* listener); + + /// Register a routine for debug drawing. The debug draw functions are called + /// inside with b2World::DrawDebugData method. The debug draw object is owned + /// by you and must remain in scope. + void SetDebugDraw(b2Draw* debugDraw); + + /// Create a rigid body given a definition. No reference to the definition + /// is retained. + /// @warning This function is locked during callbacks. + b2Body* CreateBody(const b2BodyDef* def); + + /// Destroy a rigid body given a definition. No reference to the definition + /// is retained. This function is locked during callbacks. + /// @warning This automatically deletes all associated shapes and joints. + /// @warning This function is locked during callbacks. + void DestroyBody(b2Body* body); + + /// Create a joint to constrain bodies together. No reference to the definition + /// is retained. This may cause the connected bodies to cease colliding. + /// @warning This function is locked during callbacks. + b2Joint* CreateJoint(const b2JointDef* def); + + /// Destroy a joint. This may cause the connected bodies to begin colliding. + /// @warning This function is locked during callbacks. + void DestroyJoint(b2Joint* joint); + + /// Take a time step. This performs collision detection, integration, + /// and constraint solution. + /// @param timeStep the amount of time to simulate, this should not vary. + /// @param velocityIterations for the velocity constraint solver. + /// @param positionIterations for the position constraint solver. + void Step( float32 timeStep, + int32 velocityIterations, + int32 positionIterations); + + /// Manually clear the force buffer on all bodies. By default, forces are cleared automatically + /// after each call to Step. The default behavior is modified by calling SetAutoClearForces. + /// The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain + /// a fixed sized time step under a variable frame-rate. + /// When you perform sub-stepping you will disable auto clearing of forces and instead call + /// ClearForces after all sub-steps are complete in one pass of your game loop. + /// @see SetAutoClearForces + void ClearForces(); + + /// Call this to draw shapes and other debug draw data. + void DrawDebugData(); + + /// Query the world for all fixtures that potentially overlap the + /// provided AABB. + /// @param callback a user implemented callback class. + /// @param aabb the query box. + void QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const; + + /// Ray-cast the world for all fixtures in the path of the ray. Your callback + /// controls whether you get the closest point, any point, or n-points. + /// The ray-cast ignores shapes that contain the starting point. + /// @param callback a user implemented callback class. + /// @param point1 the ray starting point + /// @param point2 the ray ending point + void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const; + + /// Get the world body list. With the returned body, use b2Body::GetNext to get + /// the next body in the world list. A NULL body indicates the end of the list. + /// @return the head of the world body list. + b2Body* GetBodyList(); + const b2Body* GetBodyList() const; + + /// Get the world joint list. With the returned joint, use b2Joint::GetNext to get + /// the next joint in the world list. A NULL joint indicates the end of the list. + /// @return the head of the world joint list. + b2Joint* GetJointList(); + const b2Joint* GetJointList() const; + + /// Get the world contact list. With the returned contact, use b2Contact::GetNext to get + /// the next contact in the world list. A NULL contact indicates the end of the list. + /// @return the head of the world contact list. + /// @warning contacts are created and destroyed in the middle of a time step. + /// Use b2ContactListener to avoid missing contacts. + b2Contact* GetContactList(); + const b2Contact* GetContactList() const; + + /// Enable/disable sleep. + void SetAllowSleeping(bool flag); + bool GetAllowSleeping() const { return m_allowSleep; } + + /// Enable/disable warm starting. For testing. + void SetWarmStarting(bool flag) { m_warmStarting = flag; } + bool GetWarmStarting() const { return m_warmStarting; } + + /// Enable/disable continuous physics. For testing. + void SetContinuousPhysics(bool flag) { m_continuousPhysics = flag; } + bool GetContinuousPhysics() const { return m_continuousPhysics; } + + /// Enable/disable single stepped continuous physics. For testing. + void SetSubStepping(bool flag) { m_subStepping = flag; } + bool GetSubStepping() const { return m_subStepping; } + + /// Get the number of broad-phase proxies. + int32 GetProxyCount() const; + + /// Get the number of bodies. + int32 GetBodyCount() const; + + /// Get the number of joints. + int32 GetJointCount() const; + + /// Get the number of contacts (each may have 0 or more contact points). + int32 GetContactCount() const; + + /// Get the height of the dynamic tree. + int32 GetTreeHeight() const; + + /// Get the balance of the dynamic tree. + int32 GetTreeBalance() const; + + /// Get the quality metric of the dynamic tree. The smaller the better. + /// The minimum is 1. + float32 GetTreeQuality() const; + + /// Change the global gravity vector. + void SetGravity(const b2Vec2& gravity); + + /// Get the global gravity vector. + b2Vec2 GetGravity() const; + + /// Is the world locked (in the middle of a time step). + bool IsLocked() const; + + /// Set flag to control automatic clearing of forces after each time step. + void SetAutoClearForces(bool flag); + + /// Get the flag that controls automatic clearing of forces after each time step. + bool GetAutoClearForces() const; + + /// Get the contact manager for testing. + const b2ContactManager& GetContactManager() const; + + /// Get the current profile. + const b2Profile& GetProfile() const; + + /// Dump the world into the log file. + /// @warning this should be called outside of a time step. + void Dump(); + +private: + + // m_flags + enum + { + e_newFixture = 0x0001, + e_locked = 0x0002, + e_clearForces = 0x0004 + }; + + friend class b2Body; + friend class b2Fixture; + friend class b2ContactManager; + friend class b2Controller; + + void Solve(const b2TimeStep& step); + void SolveTOI(const b2TimeStep& step); + + void DrawJoint(b2Joint* joint); + void DrawShape(b2Fixture* shape, const b2Transform& xf, const b2Color& color); + + b2BlockAllocator m_blockAllocator; + b2StackAllocator m_stackAllocator; + + int32 m_flags; + + b2ContactManager m_contactManager; + + b2Body* m_bodyList; + b2Joint* m_jointList; + + int32 m_bodyCount; + int32 m_jointCount; + + b2Vec2 m_gravity; + bool m_allowSleep; + + b2DestructionListener* m_destructionListener; + b2Draw* m_debugDraw; + + // This is used to compute the time step ratio to + // support a variable time step. + float32 m_inv_dt0; + + // These are for debugging the solver. + bool m_warmStarting; + bool m_continuousPhysics; + bool m_subStepping; + + bool m_stepComplete; + + b2Profile m_profile; +}; + +inline b2Body* b2World::GetBodyList() +{ + return m_bodyList; +} + +inline const b2Body* b2World::GetBodyList() const +{ + return m_bodyList; +} + +inline b2Joint* b2World::GetJointList() +{ + return m_jointList; +} + +inline const b2Joint* b2World::GetJointList() const +{ + return m_jointList; +} + +inline b2Contact* b2World::GetContactList() +{ + return m_contactManager.m_contactList; +} + +inline const b2Contact* b2World::GetContactList() const +{ + return m_contactManager.m_contactList; +} + +inline int32 b2World::GetBodyCount() const +{ + return m_bodyCount; +} + +inline int32 b2World::GetJointCount() const +{ + return m_jointCount; +} + +inline int32 b2World::GetContactCount() const +{ + return m_contactManager.m_contactCount; +} + +inline void b2World::SetGravity(const b2Vec2& gravity) +{ + m_gravity = gravity; +} + +inline b2Vec2 b2World::GetGravity() const +{ + return m_gravity; +} + +inline bool b2World::IsLocked() const +{ + return (m_flags & e_locked) == e_locked; +} + +inline void b2World::SetAutoClearForces(bool flag) +{ + if (flag) + { + m_flags |= e_clearForces; + } + else + { + m_flags &= ~e_clearForces; + } +} + +/// Get the flag that controls automatic clearing of forces after each time step. +inline bool b2World::GetAutoClearForces() const +{ + return (m_flags & e_clearForces) == e_clearForces; +} + +inline const b2ContactManager& b2World::GetContactManager() const +{ + return m_contactManager; +} + +inline const b2Profile& b2World::GetProfile() const +{ + return m_profile; +} + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2WorldCallbacks.cpp b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2WorldCallbacks.cpp new file mode 100755 index 0000000000000..82b28cc0526d5 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2WorldCallbacks.cpp @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include +#include + +// Return true if contact calculations should be performed between these two shapes. +// If you implement your own collision filter you may want to build from this implementation. +bool b2ContactFilter::ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB) +{ + const b2Filter& filterA = fixtureA->GetFilterData(); + const b2Filter& filterB = fixtureB->GetFilterData(); + + if (filterA.groupIndex == filterB.groupIndex && filterA.groupIndex != 0) + { + return filterA.groupIndex > 0; + } + + bool collide = (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0; + return collide; +} diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2WorldCallbacks.h b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2WorldCallbacks.h new file mode 100755 index 0000000000000..a64c1abe8f491 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Dynamics/b2WorldCallbacks.h @@ -0,0 +1,163 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_WORLD_CALLBACKS_H +#define B2_WORLD_CALLBACKS_H + +#include + +struct b2Vec2; +struct b2Transform; +class b2Fixture; +class b2Body; +class b2Joint; +class b2Contact; +struct b2ContactResult; +struct b2Manifold; + +/// Joints and fixtures are destroyed when their associated +/// body is destroyed. Implement this listener so that you +/// may nullify references to these joints and shapes. +// emscripten - b2DestructionListener: add constructor and make virtual functions non-pure +class b2DestructionListener +{ +public: + b2DestructionListener() {} + virtual ~b2DestructionListener() {} + + /// Called when any joint is about to be destroyed due + /// to the destruction of one of its attached bodies. + virtual void SayGoodbye(b2Joint* joint) {} + + /// Called when any fixture is about to be destroyed due + /// to the destruction of its parent body. + virtual void SayGoodbye(b2Fixture* fixture) {} +}; + +/// Implement this class to provide collision filtering. In other words, you can implement +/// this class if you want finer control over contact creation. +class b2ContactFilter +{ +public: + virtual ~b2ContactFilter() {} + + /// Return true if contact calculations should be performed between these two shapes. + /// @warning for performance reasons this is only called when the AABBs begin to overlap. + virtual bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB); +}; + +/// Contact impulses for reporting. Impulses are used instead of forces because +/// sub-step forces may approach infinity for rigid body collisions. These +/// match up one-to-one with the contact points in b2Manifold. +struct b2ContactImpulse +{ + float32 normalImpulses[b2_maxManifoldPoints]; + float32 tangentImpulses[b2_maxManifoldPoints]; + int32 count; +}; + +/// Implement this class to get contact information. You can use these results for +/// things like sounds and game logic. You can also get contact results by +/// traversing the contact lists after the time step. However, you might miss +/// some contacts because continuous physics leads to sub-stepping. +/// Additionally you may receive multiple callbacks for the same contact in a +/// single time step. +/// You should strive to make your callbacks efficient because there may be +/// many callbacks per time step. +/// @warning You cannot create/destroy Box2D entities inside these callbacks. +// emscripten - b2ContactListener: add constructor and make virtual functions non-pure +class b2ContactListener +{ +public: + b2ContactListener() {} + virtual ~b2ContactListener() {} + + /// Called when two fixtures begin to touch. + virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); } + + /// Called when two fixtures cease to touch. + virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); } + + /// This is called after a contact is updated. This allows you to inspect a + /// contact before it goes to the solver. If you are careful, you can modify the + /// contact manifold (e.g. disable contact). + /// A copy of the old manifold is provided so that you can detect changes. + /// Note: this is called only for awake bodies. + /// Note: this is called even when the number of contact points is zero. + /// Note: this is not called for sensors. + /// Note: if you set the number of contact points to zero, you will not + /// get an EndContact callback. However, you may get a BeginContact callback + /// the next step. + virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) + { + B2_NOT_USED(contact); + B2_NOT_USED(oldManifold); + } + + /// This lets you inspect a contact after the solver is finished. This is useful + /// for inspecting impulses. + /// Note: the contact manifold does not include time of impact impulses, which can be + /// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly + /// in a separate data structure. + /// Note: this is only called for contacts that are touching, solid, and awake. + virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) + { + B2_NOT_USED(contact); + B2_NOT_USED(impulse); + } +}; + +/// Callback class for AABB queries. +/// See b2World::Query +// emscripten - b2QueryCallback: add constructor and make virtual functions non-pure +class b2QueryCallback +{ +public: + b2QueryCallback() {} + virtual ~b2QueryCallback() {} + + /// Called for each fixture found in the query AABB. + /// @return false to terminate the query. + virtual bool ReportFixture(b2Fixture* fixture) { return false; } +}; + +/// Callback class for ray casts. +/// See b2World::RayCast +// emscripten - b2RayCastCallback: add constructor and make virtual functions non-pure +class b2RayCastCallback +{ +public: + b2RayCastCallback() {} + virtual ~b2RayCastCallback() {} + + /// Called for each fixture found in the query. You control how the ray cast + /// proceeds by returning a float: + /// return -1: ignore this fixture and continue + /// return 0: terminate the ray cast + /// return fraction: clip the ray to this point + /// return 1: don't clip the ray and continue + /// @param fixture the fixture hit by the ray + /// @param point the point of initial intersection + /// @param normal the normal vector at the point of intersection + /// @return -1 to filter, 0 to terminate, fraction to clip the ray for + /// closest hit, 1 to continue + virtual float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point, + const b2Vec2& normal, float32 fraction) { return 0; } +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Box2D/Rope/b2Rope.cpp b/tests/Box2D_v2.2.1/Box2D/Rope/b2Rope.cpp new file mode 100755 index 0000000000000..97578b2662f28 --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Rope/b2Rope.cpp @@ -0,0 +1,259 @@ +/* +* Copyright (c) 2011 Erin Catto http://box2d.org +* +* 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. +*/ + +#include +#include + +b2Rope::b2Rope() +{ + m_count = 0; + m_ps = NULL; + m_p0s = NULL; + m_vs = NULL; + m_ims = NULL; + m_Ls = NULL; + m_as = NULL; + m_gravity.SetZero(); + m_k2 = 1.0f; + m_k3 = 0.1f; +} + +b2Rope::~b2Rope() +{ + b2Free(m_ps); + b2Free(m_p0s); + b2Free(m_vs); + b2Free(m_ims); + b2Free(m_Ls); + b2Free(m_as); +} + +void b2Rope::Initialize(const b2RopeDef* def) +{ + b2Assert(def->count >= 3); + m_count = def->count; + m_ps = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); + m_p0s = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); + m_vs = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); + m_ims = (float32*)b2Alloc(m_count * sizeof(float32)); + + for (int32 i = 0; i < m_count; ++i) + { + m_ps[i] = def->vertices[i]; + m_p0s[i] = def->vertices[i]; + m_vs[i].SetZero(); + + float32 m = def->masses[i]; + if (m > 0.0f) + { + m_ims[i] = 1.0f / m; + } + else + { + m_ims[i] = 0.0f; + } + } + + int32 count2 = m_count - 1; + int32 count3 = m_count - 2; + m_Ls = (float32*)b2Alloc(count2 * sizeof(float32)); + m_as = (float32*)b2Alloc(count3 * sizeof(float32)); + + for (int32 i = 0; i < count2; ++i) + { + b2Vec2 p1 = m_ps[i]; + b2Vec2 p2 = m_ps[i+1]; + m_Ls[i] = b2Distance(p1, p2); + } + + for (int32 i = 0; i < count3; ++i) + { + b2Vec2 p1 = m_ps[i]; + b2Vec2 p2 = m_ps[i + 1]; + b2Vec2 p3 = m_ps[i + 2]; + + b2Vec2 d1 = p2 - p1; + b2Vec2 d2 = p3 - p2; + + float32 a = b2Cross(d1, d2); + float32 b = b2Dot(d1, d2); + + m_as[i] = b2Atan2(a, b); + } + + m_gravity = def->gravity; + m_damping = def->damping; + m_k2 = def->k2; + m_k3 = def->k3; +} + +void b2Rope::Step(float32 h, int32 iterations) +{ + if (h == 0.0) + { + return; + } + + float32 d = expf(- h * m_damping); + + for (int32 i = 0; i < m_count; ++i) + { + m_p0s[i] = m_ps[i]; + if (m_ims[i] > 0.0f) + { + m_vs[i] += h * m_gravity; + } + m_vs[i] *= d; + m_ps[i] += h * m_vs[i]; + + } + + for (int32 i = 0; i < iterations; ++i) + { + SolveC2(); + SolveC3(); + SolveC2(); + } + + float32 inv_h = 1.0f / h; + for (int32 i = 0; i < m_count; ++i) + { + m_vs[i] = inv_h * (m_ps[i] - m_p0s[i]); + } +} + +void b2Rope::SolveC2() +{ + int32 count2 = m_count - 1; + + for (int32 i = 0; i < count2; ++i) + { + b2Vec2 p1 = m_ps[i]; + b2Vec2 p2 = m_ps[i + 1]; + + b2Vec2 d = p2 - p1; + float32 L = d.Normalize(); + + float32 im1 = m_ims[i]; + float32 im2 = m_ims[i + 1]; + + if (im1 + im2 == 0.0f) + { + continue; + } + + float32 s1 = im1 / (im1 + im2); + float32 s2 = im2 / (im1 + im2); + + p1 -= m_k2 * s1 * (m_Ls[i] - L) * d; + p2 += m_k2 * s2 * (m_Ls[i] - L) * d; + + m_ps[i] = p1; + m_ps[i + 1] = p2; + } +} + +void b2Rope::SetAngle(float32 angle) +{ + int32 count3 = m_count - 2; + for (int32 i = 0; i < count3; ++i) + { + m_as[i] = angle; + } +} + +void b2Rope::SolveC3() +{ + int32 count3 = m_count - 2; + + for (int32 i = 0; i < count3; ++i) + { + b2Vec2 p1 = m_ps[i]; + b2Vec2 p2 = m_ps[i + 1]; + b2Vec2 p3 = m_ps[i + 2]; + + float32 m1 = m_ims[i]; + float32 m2 = m_ims[i + 1]; + float32 m3 = m_ims[i + 2]; + + b2Vec2 d1 = p2 - p1; + b2Vec2 d2 = p3 - p2; + + float32 L1sqr = d1.LengthSquared(); + float32 L2sqr = d2.LengthSquared(); + + if (L1sqr * L2sqr == 0.0f) + { + continue; + } + + float32 a = b2Cross(d1, d2); + float32 b = b2Dot(d1, d2); + + float32 angle = b2Atan2(a, b); + + b2Vec2 Jd1 = (-1.0f / L1sqr) * d1.Skew(); + b2Vec2 Jd2 = (1.0f / L2sqr) * d2.Skew(); + + b2Vec2 J1 = -Jd1; + b2Vec2 J2 = Jd1 - Jd2; + b2Vec2 J3 = Jd2; + + float32 mass = m1 * b2Dot(J1, J1) + m2 * b2Dot(J2, J2) + m3 * b2Dot(J3, J3); + if (mass == 0.0f) + { + continue; + } + + mass = 1.0f / mass; + + float32 C = angle - m_as[i]; + + while (C > b2_pi) + { + angle -= 2 * b2_pi; + C = angle - m_as[i]; + } + + while (C < -b2_pi) + { + angle += 2.0f * b2_pi; + C = angle - m_as[i]; + } + + float32 impulse = - m_k3 * mass * C; + + p1 += (m1 * impulse) * J1; + p2 += (m2 * impulse) * J2; + p3 += (m3 * impulse) * J3; + + m_ps[i] = p1; + m_ps[i + 1] = p2; + m_ps[i + 2] = p3; + } +} + +void b2Rope::Draw(b2Draw* draw) const +{ + b2Color c(0.4f, 0.5f, 0.7f); + + for (int32 i = 0; i < m_count - 1; ++i) + { + draw->DrawSegment(m_ps[i], m_ps[i+1], c); + } +} diff --git a/tests/Box2D_v2.2.1/Box2D/Rope/b2Rope.h b/tests/Box2D_v2.2.1/Box2D/Rope/b2Rope.h new file mode 100755 index 0000000000000..bc5375ddb491f --- /dev/null +++ b/tests/Box2D_v2.2.1/Box2D/Rope/b2Rope.h @@ -0,0 +1,115 @@ +/* +* Copyright (c) 2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef B2_ROPE_H +#define B2_ROPE_H + +#include + +class b2Draw; + +/// +struct b2RopeDef +{ + b2RopeDef() + { + vertices = NULL; + count = 0; + masses = NULL; + gravity.SetZero(); + damping = 0.1f; + k2 = 0.9f; + k3 = 0.1f; + } + + /// + b2Vec2* vertices; + + /// + int32 count; + + /// + float32* masses; + + /// + b2Vec2 gravity; + + /// + float32 damping; + + /// Stretching stiffness + float32 k2; + + /// Bending stiffness. Values above 0.5 can make the simulation blow up. + float32 k3; +}; + +/// +class b2Rope +{ +public: + b2Rope(); + ~b2Rope(); + + /// + void Initialize(const b2RopeDef* def); + + /// + void Step(float32 timeStep, int32 iterations); + + /// + int32 GetVertexCount() const + { + return m_count; + } + + /// + const b2Vec2* GetVertices() const + { + return m_ps; + } + + /// + void Draw(b2Draw* draw) const; + + /// + void SetAngle(float32 angle); + +private: + + void SolveC2(); + void SolveC3(); + + int32 m_count; + b2Vec2* m_ps; + b2Vec2* m_p0s; + b2Vec2* m_vs; + + float32* m_ims; + + float32* m_Ls; + float32* m_as; + + b2Vec2 m_gravity; + float32 m_damping; + + float32 m_k2; + float32 m_k3; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Build/Readme.txt b/tests/Box2D_v2.2.1/Build/Readme.txt new file mode 100755 index 0000000000000..f28e90b3bfa19 --- /dev/null +++ b/tests/Box2D_v2.2.1/Build/Readme.txt @@ -0,0 +1 @@ +You should use CMake to target this directory for build files. \ No newline at end of file diff --git a/tests/Box2D_v2.2.1/Build/vs2010/Box2D.sln b/tests/Box2D_v2.2.1/Build/vs2010/Box2D.sln new file mode 100755 index 0000000000000..e6fd1a02ac57f --- /dev/null +++ b/tests/Box2D_v2.2.1/Build/vs2010/Box2D.sln @@ -0,0 +1,74 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Box2D", "Box2D.vcxproj", "{98400D17-43A5-1A40-95BE-C53AC78E7694}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeGLUT", "FreeGLUT.vcxproj", "{BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GLUI", "GLUI.vcxproj", "{6F01DB00-32F0-A842-9B60-3ABA75A2D458}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloWorld", "HelloWorld.vcxproj", "{259F29FB-40F1-F04D-940B-BCEA3ED16B75}" + ProjectSection(ProjectDependencies) = postProject + {98400D17-43A5-1A40-95BE-C53AC78E7694} = {98400D17-43A5-1A40-95BE-C53AC78E7694} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Testbed", "Testbed.vcxproj", "{3FC8974C-9179-4D4E-A5E0-79E3C836548F}" + ProjectSection(ProjectDependencies) = postProject + {98400D17-43A5-1A40-95BE-C53AC78E7694} = {98400D17-43A5-1A40-95BE-C53AC78E7694} + {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8} = {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8} + {6F01DB00-32F0-A842-9B60-3ABA75A2D458} = {6F01DB00-32F0-A842-9B60-3ABA75A2D458} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {98400D17-43A5-1A40-95BE-C53AC78E7694}.Debug|Win32.ActiveCfg = Debug|Win32 + {98400D17-43A5-1A40-95BE-C53AC78E7694}.Debug|Win32.Build.0 = Debug|Win32 + {98400D17-43A5-1A40-95BE-C53AC78E7694}.Debug|x64.ActiveCfg = Debug|x64 + {98400D17-43A5-1A40-95BE-C53AC78E7694}.Debug|x64.Build.0 = Debug|x64 + {98400D17-43A5-1A40-95BE-C53AC78E7694}.Release|Win32.ActiveCfg = Release|Win32 + {98400D17-43A5-1A40-95BE-C53AC78E7694}.Release|Win32.Build.0 = Release|Win32 + {98400D17-43A5-1A40-95BE-C53AC78E7694}.Release|x64.ActiveCfg = Release|x64 + {98400D17-43A5-1A40-95BE-C53AC78E7694}.Release|x64.Build.0 = Release|x64 + {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Debug|Win32.ActiveCfg = Debug|Win32 + {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Debug|Win32.Build.0 = Debug|Win32 + {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Debug|x64.ActiveCfg = Debug|x64 + {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Debug|x64.Build.0 = Debug|x64 + {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Release|Win32.ActiveCfg = Release|Win32 + {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Release|Win32.Build.0 = Release|Win32 + {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Release|x64.ActiveCfg = Release|x64 + {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Release|x64.Build.0 = Release|x64 + {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Debug|Win32.ActiveCfg = Debug|Win32 + {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Debug|Win32.Build.0 = Debug|Win32 + {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Debug|x64.ActiveCfg = Debug|x64 + {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Debug|x64.Build.0 = Debug|x64 + {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Release|Win32.ActiveCfg = Release|Win32 + {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Release|Win32.Build.0 = Release|Win32 + {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Release|x64.ActiveCfg = Release|x64 + {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Release|x64.Build.0 = Release|x64 + {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Debug|Win32.ActiveCfg = Debug|Win32 + {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Debug|Win32.Build.0 = Debug|Win32 + {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Debug|x64.ActiveCfg = Debug|x64 + {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Debug|x64.Build.0 = Debug|x64 + {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Release|Win32.ActiveCfg = Release|Win32 + {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Release|Win32.Build.0 = Release|Win32 + {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Release|x64.ActiveCfg = Release|x64 + {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Release|x64.Build.0 = Release|x64 + {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Debug|Win32.ActiveCfg = Debug|Win32 + {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Debug|Win32.Build.0 = Debug|Win32 + {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Debug|x64.ActiveCfg = Debug|x64 + {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Debug|x64.Build.0 = Debug|x64 + {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Release|Win32.ActiveCfg = Release|Win32 + {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Release|Win32.Build.0 = Release|Win32 + {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Release|x64.ActiveCfg = Release|x64 + {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/Box2D_v2.2.1/Build/vs2010/Box2D.vcxproj b/tests/Box2D_v2.2.1/Build/vs2010/Box2D.vcxproj new file mode 100755 index 0000000000000..9e0460e2e30c0 --- /dev/null +++ b/tests/Box2D_v2.2.1/Build/vs2010/Box2D.vcxproj @@ -0,0 +1,340 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {98400D17-43A5-1A40-95BE-C53AC78E7694} + Box2D + Win32Proj + + + + StaticLibrary + MultiByte + true + + + StaticLibrary + MultiByte + true + + + StaticLibrary + MultiByte + false + + + StaticLibrary + MultiByte + false + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + bin\Debug\ + obj\x32\Debug\Box2D\ + Box2D + bin\Debug\ + obj\x64\Debug\Box2D\ + Box2D + bin\Release\ + obj\x32\Release\Box2D\ + Box2D + bin\Release\ + obj\x64\Release\Box2D\ + Box2D + + + + Disabled + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level3 + EditAndContinue + $(OutDir)Box2D.pdb + + + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + $(OutDir)Box2D.lib + MachineX86 + + + Windows + true + + + + + Disabled + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level3 + ProgramDatabase + $(OutDir)Box2D.pdb + + + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + $(OutDir)Box2D.lib + MachineX64 + + + Windows + true + + + + + Full + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + false + true + MultiThreadedDLL + true + + + Level3 + + + + + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + $(OutDir)Box2D.lib + MachineX86 + + + Windows + false + true + true + + + + + Full + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + false + true + MultiThreadedDLL + true + + + Level3 + + + false + Fast + false + + + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + $(OutDir)Box2D.lib + MachineX64 + + + Windows + false + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Box2D_v2.2.1/Build/vs2010/Box2D.vcxproj.filters b/tests/Box2D_v2.2.1/Build/vs2010/Box2D.vcxproj.filters new file mode 100755 index 0000000000000..6576c6ba6c762 --- /dev/null +++ b/tests/Box2D_v2.2.1/Build/vs2010/Box2D.vcxproj.filters @@ -0,0 +1,301 @@ + + + + + {EE06093C-52B3-9A42-A586-8CCC65597D57} + + + {4A368771-7ADC-A143-B42F-58CB8448EA17} + + + {17132958-D902-9D46-A032-A2DD9E3FAED5} + + + {C815CFE9-147A-D443-8BB0-31FC775E62F4} + + + {BE9A720A-8AF8-9C4C-A4FE-3F2BACAF8A59} + + + {CFBD1F37-CEEA-CA41-9715-5C0ACDD84298} + + + {064F8909-BE63-9844-86F5-4B9354A16847} + + + + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Common + + + Common + + + Common + + + Common + + + Common + + + Common + + + Common + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Rope + + + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Common + + + Common + + + Common + + + Common + + + Common + + + Common + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Rope + + + diff --git a/tests/Box2D_v2.2.1/Build/vs2010/FreeGLUT.vcxproj b/tests/Box2D_v2.2.1/Build/vs2010/FreeGLUT.vcxproj new file mode 100755 index 0000000000000..68214339b1f15 --- /dev/null +++ b/tests/Box2D_v2.2.1/Build/vs2010/FreeGLUT.vcxproj @@ -0,0 +1,250 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8} + FreeGLUT + Win32Proj + + + + StaticLibrary + MultiByte + true + + + StaticLibrary + MultiByte + true + + + StaticLibrary + MultiByte + false + + + StaticLibrary + MultiByte + false + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + bin\Debug\ + obj\x32\Debug\FreeGLUT\ + FreeGLUT + bin\Debug\ + obj\x64\Debug\FreeGLUT\ + FreeGLUT + bin\Release\ + obj\x32\Release\FreeGLUT\ + FreeGLUT + bin\Release\ + obj\x64\Release\FreeGLUT\ + FreeGLUT + + + + Disabled + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level3 + EditAndContinue + $(OutDir)FreeGLUT.pdb + CompileAsC + + + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + + + $(OutDir)FreeGLUT.lib + MachineX86 + + + Windows + true + + + + + Disabled + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level3 + ProgramDatabase + $(OutDir)FreeGLUT.pdb + CompileAsC + + + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + + + $(OutDir)FreeGLUT.lib + MachineX64 + + + Windows + true + + + + + Full + _CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + false + true + MultiThreadedDLL + true + + + Level3 + + + CompileAsC + + + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + + + $(OutDir)FreeGLUT.lib + MachineX86 + + + Windows + false + true + true + + + + + Full + _CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + false + true + MultiThreadedDLL + true + + + Level3 + + + CompileAsC + + + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + + + $(OutDir)FreeGLUT.lib + MachineX64 + + + Windows + false + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Box2D_v2.2.1/Build/vs2010/FreeGLUT.vcxproj.filters b/tests/Box2D_v2.2.1/Build/vs2010/FreeGLUT.vcxproj.filters new file mode 100755 index 0000000000000..d4cd78c4fd84b --- /dev/null +++ b/tests/Box2D_v2.2.1/Build/vs2010/FreeGLUT.vcxproj.filters @@ -0,0 +1,102 @@ + + + + + {CF400ACD-5E78-A54C-B6AC-3BF8A203852D} + + + {28BB812D-7BF4-C741-8D3C-0C93BDD09371} + + + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + diff --git a/tests/Box2D_v2.2.1/Build/vs2010/GLUI.vcxproj b/tests/Box2D_v2.2.1/Build/vs2010/GLUI.vcxproj new file mode 100755 index 0000000000000..a526d3a1d8db0 --- /dev/null +++ b/tests/Box2D_v2.2.1/Build/vs2010/GLUI.vcxproj @@ -0,0 +1,275 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {6F01DB00-32F0-A842-9B60-3ABA75A2D458} + GLUI + Win32Proj + + + + StaticLibrary + MultiByte + true + + + StaticLibrary + MultiByte + true + + + StaticLibrary + MultiByte + false + + + StaticLibrary + MultiByte + false + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + bin\Debug\ + obj\x32\Debug\GLUI\ + GLUI + bin\Debug\ + obj\x64\Debug\GLUI\ + GLUI + bin\Release\ + obj\x32\Release\GLUI\ + GLUI + bin\Release\ + obj\x64\Release\GLUI\ + GLUI + + + + /W1 %(AdditionalOptions) + Disabled + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level3 + EditAndContinue + $(OutDir)GLUI.pdb + + + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + $(OutDir)GLUI.lib + MachineX86 + + + Windows + true + + + + + /W1 %(AdditionalOptions) + Disabled + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level3 + ProgramDatabase + $(OutDir)GLUI.pdb + + + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + $(OutDir)GLUI.lib + MachineX64 + + + Windows + true + + + + + /W1 %(AdditionalOptions) + Full + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + false + true + MultiThreadedDLL + true + + + Level3 + + + + + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + $(OutDir)GLUI.lib + MachineX86 + + + Windows + false + true + true + + + + + /W1 %(AdditionalOptions) + Full + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + false + true + MultiThreadedDLL + true + + + Level3 + + + + + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + $(OutDir)GLUI.lib + MachineX64 + + + Windows + false + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Box2D_v2.2.1/Build/vs2010/GLUI.vcxproj.filters b/tests/Box2D_v2.2.1/Build/vs2010/GLUI.vcxproj.filters new file mode 100755 index 0000000000000..587ea8675e7b0 --- /dev/null +++ b/tests/Box2D_v2.2.1/Build/vs2010/GLUI.vcxproj.filters @@ -0,0 +1,129 @@ + + + + + {7EE70127-33D6-EE45-A170-6D9CD2ECBA05} + + + {392FBE2C-081A-8743-83E6-1344CBD265D1} + + + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + diff --git a/tests/Box2D_v2.2.1/Build/vs2010/HelloWorld.vcxproj b/tests/Box2D_v2.2.1/Build/vs2010/HelloWorld.vcxproj new file mode 100755 index 0000000000000..8ebf4c6218ddd --- /dev/null +++ b/tests/Box2D_v2.2.1/Build/vs2010/HelloWorld.vcxproj @@ -0,0 +1,209 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {259F29FB-40F1-F04D-940B-BCEA3ED16B75} + HelloWorld + Win32Proj + + + + Application + MultiByte + true + + + Application + MultiByte + true + + + Application + MultiByte + false + + + Application + MultiByte + false + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + bin\Debug\ + obj\x32\Debug\HelloWorld\ + HelloWorld + true + bin\Debug\ + obj\x64\Debug\HelloWorld\ + HelloWorld + true + bin\Release\ + obj\x32\Release\HelloWorld\ + HelloWorld + false + bin\Release\ + obj\x64\Release\HelloWorld\ + HelloWorld + false + + + + Disabled + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level3 + EditAndContinue + $(OutDir)HelloWorld.pdb + + + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + bin\Debug\Box2D.lib;%(AdditionalDependencies) + $(OutDir)HelloWorld.exe + %(AdditionalLibraryDirectories) + Console + true + mainCRTStartup + MachineX86 + + + + + Disabled + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level3 + ProgramDatabase + $(OutDir)HelloWorld.pdb + + + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + bin\Debug\Box2D.lib;%(AdditionalDependencies) + $(OutDir)HelloWorld.exe + %(AdditionalLibraryDirectories) + Console + true + mainCRTStartup + MachineX64 + + + + + Full + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + false + true + MultiThreadedDLL + true + + + Level3 + + + + + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + bin\Release\Box2D.lib;%(AdditionalDependencies) + $(OutDir)HelloWorld.exe + %(AdditionalLibraryDirectories) + Console + false + true + true + mainCRTStartup + MachineX86 + + + + + Full + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + false + true + MultiThreadedDLL + true + + + Level3 + + + + + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + bin\Release\Box2D.lib;%(AdditionalDependencies) + $(OutDir)HelloWorld.exe + %(AdditionalLibraryDirectories) + Console + false + true + true + mainCRTStartup + MachineX64 + + + + + + + + + + \ No newline at end of file diff --git a/tests/Box2D_v2.2.1/Build/vs2010/HelloWorld.vcxproj.filters b/tests/Box2D_v2.2.1/Build/vs2010/HelloWorld.vcxproj.filters new file mode 100755 index 0000000000000..1cbc00cbce426 --- /dev/null +++ b/tests/Box2D_v2.2.1/Build/vs2010/HelloWorld.vcxproj.filters @@ -0,0 +1,6 @@ + + + + + + diff --git a/tests/Box2D_v2.2.1/Build/vs2010/Testbed.vcxproj b/tests/Box2D_v2.2.1/Build/vs2010/Testbed.vcxproj new file mode 100755 index 0000000000000..1723c9abbf887 --- /dev/null +++ b/tests/Box2D_v2.2.1/Build/vs2010/Testbed.vcxproj @@ -0,0 +1,265 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {3FC8974C-9179-4D4E-A5E0-79E3C836548F} + Testbed + Win32Proj + + + + Application + MultiByte + true + + + Application + MultiByte + true + + + Application + MultiByte + false + + + Application + MultiByte + false + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + bin\Debug\ + obj\x32\Debug\Testbed\ + Testbed + true + bin\Debug\ + obj\x64\Debug\Testbed\ + Testbed + true + bin\Release\ + obj\x32\Release\Testbed\ + Testbed + false + bin\Release\ + obj\x64\Release\Testbed\ + Testbed + false + + + + Disabled + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level3 + EditAndContinue + $(OutDir)Testbed.pdb + + + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + bin\Debug\Box2D.lib;bin\Debug\FreeGLUT.lib;bin\Debug\GLUI.lib;glu32.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + $(OutDir)Testbed.exe + %(AdditionalLibraryDirectories) + Console + true + mainCRTStartup + MachineX86 + + + + + Disabled + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level3 + ProgramDatabase + $(OutDir)Testbed.pdb + + + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + bin\Debug\Box2D.lib;bin\Debug\FreeGLUT.lib;bin\Debug\GLUI.lib;glu32.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + $(OutDir)Testbed.exe + %(AdditionalLibraryDirectories) + Console + true + mainCRTStartup + MachineX64 + + + + + Full + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + false + true + MultiThreadedDLL + true + + + Level3 + + + + + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + bin\Release\Box2D.lib;bin\Release\FreeGLUT.lib;bin\Release\GLUI.lib;glu32.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + $(OutDir)Testbed.exe + %(AdditionalLibraryDirectories) + Console + false + true + true + mainCRTStartup + MachineX86 + + + + + Full + ..\..;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + false + true + MultiThreadedDLL + true + + + Level3 + + + + + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + ..\..;%(AdditionalIncludeDirectories) + + + bin\Release\Box2D.lib;bin\Release\FreeGLUT.lib;bin\Release\GLUI.lib;glu32.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + $(OutDir)Testbed.exe + %(AdditionalLibraryDirectories) + Console + false + true + true + mainCRTStartup + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Box2D_v2.2.1/Build/vs2010/Testbed.vcxproj.filters b/tests/Box2D_v2.2.1/Build/vs2010/Testbed.vcxproj.filters new file mode 100755 index 0000000000000..529617318b36b --- /dev/null +++ b/tests/Box2D_v2.2.1/Build/vs2010/Testbed.vcxproj.filters @@ -0,0 +1,171 @@ + + + + + {F5D5D9E8-9CBD-914E-B539-B995BEA73920} + + + {CF6BC554-9DC6-4547-9F18-A1BA2F3345BF} + + + + + Framework + + + Framework + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + + + + + Framework + + + Framework + + + Framework + + + Tests + + + \ No newline at end of file diff --git a/tests/Box2D_v2.2.1/Build/xcode4/Box2D.xcodeproj/project.pbxproj b/tests/Box2D_v2.2.1/Build/xcode4/Box2D.xcodeproj/project.pbxproj new file mode 100755 index 0000000000000..a8bd249012fcb --- /dev/null +++ b/tests/Box2D_v2.2.1/Build/xcode4/Box2D.xcodeproj/project.pbxproj @@ -0,0 +1,1210 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 80BB8987141C3E5900F1753A /* Box2D.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8923141C3E5900F1753A /* Box2D.h */; }; + 80BB8988141C3E5900F1753A /* b2BroadPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8927141C3E5900F1753A /* b2BroadPhase.cpp */; }; + 80BB8989141C3E5900F1753A /* b2BroadPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8928141C3E5900F1753A /* b2BroadPhase.h */; }; + 80BB898A141C3E5900F1753A /* b2CollideCircle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8929141C3E5900F1753A /* b2CollideCircle.cpp */; }; + 80BB898B141C3E5900F1753A /* b2CollideEdge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB892A141C3E5900F1753A /* b2CollideEdge.cpp */; }; + 80BB898C141C3E5900F1753A /* b2CollidePolygon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB892B141C3E5900F1753A /* b2CollidePolygon.cpp */; }; + 80BB898D141C3E5900F1753A /* b2Collision.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB892C141C3E5900F1753A /* b2Collision.cpp */; }; + 80BB898E141C3E5900F1753A /* b2Collision.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB892D141C3E5900F1753A /* b2Collision.h */; }; + 80BB898F141C3E5900F1753A /* b2Distance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB892E141C3E5900F1753A /* b2Distance.cpp */; }; + 80BB8990141C3E5900F1753A /* b2Distance.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB892F141C3E5900F1753A /* b2Distance.h */; }; + 80BB8991141C3E5900F1753A /* b2DynamicTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8930141C3E5900F1753A /* b2DynamicTree.cpp */; }; + 80BB8992141C3E5900F1753A /* b2DynamicTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8931141C3E5900F1753A /* b2DynamicTree.h */; }; + 80BB8993141C3E5900F1753A /* b2TimeOfImpact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8932141C3E5900F1753A /* b2TimeOfImpact.cpp */; }; + 80BB8994141C3E5900F1753A /* b2TimeOfImpact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8933141C3E5900F1753A /* b2TimeOfImpact.h */; }; + 80BB8995141C3E5900F1753A /* b2ChainShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8935141C3E5900F1753A /* b2ChainShape.cpp */; }; + 80BB8996141C3E5900F1753A /* b2ChainShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8936141C3E5900F1753A /* b2ChainShape.h */; }; + 80BB8997141C3E5900F1753A /* b2CircleShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8937141C3E5900F1753A /* b2CircleShape.cpp */; }; + 80BB8998141C3E5900F1753A /* b2CircleShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8938141C3E5900F1753A /* b2CircleShape.h */; }; + 80BB8999141C3E5900F1753A /* b2EdgeShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8939141C3E5900F1753A /* b2EdgeShape.cpp */; }; + 80BB899A141C3E5900F1753A /* b2EdgeShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB893A141C3E5900F1753A /* b2EdgeShape.h */; }; + 80BB899B141C3E5900F1753A /* b2PolygonShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB893B141C3E5900F1753A /* b2PolygonShape.cpp */; }; + 80BB899C141C3E5900F1753A /* b2PolygonShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB893C141C3E5900F1753A /* b2PolygonShape.h */; }; + 80BB899D141C3E5900F1753A /* b2Shape.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB893D141C3E5900F1753A /* b2Shape.h */; }; + 80BB899E141C3E5900F1753A /* b2BlockAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB893F141C3E5900F1753A /* b2BlockAllocator.cpp */; }; + 80BB899F141C3E5900F1753A /* b2BlockAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8940141C3E5900F1753A /* b2BlockAllocator.h */; }; + 80BB89A0141C3E5900F1753A /* b2Draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8941141C3E5900F1753A /* b2Draw.cpp */; }; + 80BB89A1141C3E5900F1753A /* b2Draw.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8942141C3E5900F1753A /* b2Draw.h */; }; + 80BB89A2141C3E5900F1753A /* b2GrowableStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8943141C3E5900F1753A /* b2GrowableStack.h */; }; + 80BB89A3141C3E5900F1753A /* b2Math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8944141C3E5900F1753A /* b2Math.cpp */; }; + 80BB89A4141C3E5900F1753A /* b2Math.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8945141C3E5900F1753A /* b2Math.h */; }; + 80BB89A5141C3E5900F1753A /* b2Settings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8946141C3E5900F1753A /* b2Settings.cpp */; }; + 80BB89A6141C3E5900F1753A /* b2Settings.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8947141C3E5900F1753A /* b2Settings.h */; }; + 80BB89A7141C3E5900F1753A /* b2StackAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8948141C3E5900F1753A /* b2StackAllocator.cpp */; }; + 80BB89A8141C3E5900F1753A /* b2StackAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8949141C3E5900F1753A /* b2StackAllocator.h */; }; + 80BB89A9141C3E5900F1753A /* b2Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB894A141C3E5900F1753A /* b2Timer.cpp */; }; + 80BB89AA141C3E5900F1753A /* b2Timer.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB894B141C3E5900F1753A /* b2Timer.h */; }; + 80BB89AB141C3E5900F1753A /* b2Body.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB894D141C3E5900F1753A /* b2Body.cpp */; }; + 80BB89AC141C3E5900F1753A /* b2Body.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB894E141C3E5900F1753A /* b2Body.h */; }; + 80BB89AD141C3E5900F1753A /* b2ContactManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB894F141C3E5900F1753A /* b2ContactManager.cpp */; }; + 80BB89AE141C3E5900F1753A /* b2ContactManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8950141C3E5900F1753A /* b2ContactManager.h */; }; + 80BB89AF141C3E5900F1753A /* b2Fixture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8951141C3E5900F1753A /* b2Fixture.cpp */; }; + 80BB89B0141C3E5900F1753A /* b2Fixture.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8952141C3E5900F1753A /* b2Fixture.h */; }; + 80BB89B1141C3E5900F1753A /* b2Island.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8953141C3E5900F1753A /* b2Island.cpp */; }; + 80BB89B2141C3E5900F1753A /* b2Island.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8954141C3E5900F1753A /* b2Island.h */; }; + 80BB89B3141C3E5900F1753A /* b2TimeStep.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8955141C3E5900F1753A /* b2TimeStep.h */; }; + 80BB89B4141C3E5900F1753A /* b2World.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8956141C3E5900F1753A /* b2World.cpp */; }; + 80BB89B5141C3E5900F1753A /* b2World.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8957141C3E5900F1753A /* b2World.h */; }; + 80BB89B6141C3E5900F1753A /* b2WorldCallbacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8958141C3E5900F1753A /* b2WorldCallbacks.cpp */; }; + 80BB89B7141C3E5900F1753A /* b2WorldCallbacks.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8959141C3E5900F1753A /* b2WorldCallbacks.h */; }; + 80BB89B8141C3E5900F1753A /* b2ChainAndCircleContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB895B141C3E5900F1753A /* b2ChainAndCircleContact.cpp */; }; + 80BB89B9141C3E5900F1753A /* b2ChainAndCircleContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB895C141C3E5900F1753A /* b2ChainAndCircleContact.h */; }; + 80BB89BA141C3E5900F1753A /* b2ChainAndPolygonContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB895D141C3E5900F1753A /* b2ChainAndPolygonContact.cpp */; }; + 80BB89BB141C3E5900F1753A /* b2ChainAndPolygonContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB895E141C3E5900F1753A /* b2ChainAndPolygonContact.h */; }; + 80BB89BC141C3E5900F1753A /* b2CircleContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB895F141C3E5900F1753A /* b2CircleContact.cpp */; }; + 80BB89BD141C3E5900F1753A /* b2CircleContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8960141C3E5900F1753A /* b2CircleContact.h */; }; + 80BB89BE141C3E5900F1753A /* b2Contact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8961141C3E5900F1753A /* b2Contact.cpp */; }; + 80BB89BF141C3E5900F1753A /* b2Contact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8962141C3E5900F1753A /* b2Contact.h */; }; + 80BB89C0141C3E5900F1753A /* b2ContactSolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8963141C3E5900F1753A /* b2ContactSolver.cpp */; }; + 80BB89C1141C3E5900F1753A /* b2ContactSolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8964141C3E5900F1753A /* b2ContactSolver.h */; }; + 80BB89C2141C3E5900F1753A /* b2EdgeAndCircleContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8965141C3E5900F1753A /* b2EdgeAndCircleContact.cpp */; }; + 80BB89C3141C3E5900F1753A /* b2EdgeAndCircleContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8966141C3E5900F1753A /* b2EdgeAndCircleContact.h */; }; + 80BB89C4141C3E5900F1753A /* b2EdgeAndPolygonContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8967141C3E5900F1753A /* b2EdgeAndPolygonContact.cpp */; }; + 80BB89C5141C3E5900F1753A /* b2EdgeAndPolygonContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8968141C3E5900F1753A /* b2EdgeAndPolygonContact.h */; }; + 80BB89C6141C3E5900F1753A /* b2PolygonAndCircleContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8969141C3E5900F1753A /* b2PolygonAndCircleContact.cpp */; }; + 80BB89C7141C3E5900F1753A /* b2PolygonAndCircleContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB896A141C3E5900F1753A /* b2PolygonAndCircleContact.h */; }; + 80BB89C8141C3E5900F1753A /* b2PolygonContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB896B141C3E5900F1753A /* b2PolygonContact.cpp */; }; + 80BB89C9141C3E5900F1753A /* b2PolygonContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB896C141C3E5900F1753A /* b2PolygonContact.h */; }; + 80BB89CA141C3E5900F1753A /* b2DistanceJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB896E141C3E5900F1753A /* b2DistanceJoint.cpp */; }; + 80BB89CB141C3E5900F1753A /* b2DistanceJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB896F141C3E5900F1753A /* b2DistanceJoint.h */; }; + 80BB89CC141C3E5900F1753A /* b2FrictionJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8970141C3E5900F1753A /* b2FrictionJoint.cpp */; }; + 80BB89CD141C3E5900F1753A /* b2FrictionJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8971141C3E5900F1753A /* b2FrictionJoint.h */; }; + 80BB89CE141C3E5900F1753A /* b2GearJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8972141C3E5900F1753A /* b2GearJoint.cpp */; }; + 80BB89CF141C3E5900F1753A /* b2GearJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8973141C3E5900F1753A /* b2GearJoint.h */; }; + 80BB89D0141C3E5900F1753A /* b2Joint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8974141C3E5900F1753A /* b2Joint.cpp */; }; + 80BB89D1141C3E5900F1753A /* b2Joint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8975141C3E5900F1753A /* b2Joint.h */; }; + 80BB89D2141C3E5900F1753A /* b2MouseJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8976141C3E5900F1753A /* b2MouseJoint.cpp */; }; + 80BB89D3141C3E5900F1753A /* b2MouseJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8977141C3E5900F1753A /* b2MouseJoint.h */; }; + 80BB89D4141C3E5900F1753A /* b2PrismaticJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8978141C3E5900F1753A /* b2PrismaticJoint.cpp */; }; + 80BB89D5141C3E5900F1753A /* b2PrismaticJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8979141C3E5900F1753A /* b2PrismaticJoint.h */; }; + 80BB89D6141C3E5900F1753A /* b2PulleyJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB897A141C3E5900F1753A /* b2PulleyJoint.cpp */; }; + 80BB89D7141C3E5900F1753A /* b2PulleyJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB897B141C3E5900F1753A /* b2PulleyJoint.h */; }; + 80BB89D8141C3E5900F1753A /* b2RevoluteJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB897C141C3E5900F1753A /* b2RevoluteJoint.cpp */; }; + 80BB89D9141C3E5900F1753A /* b2RevoluteJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB897D141C3E5900F1753A /* b2RevoluteJoint.h */; }; + 80BB89DA141C3E5900F1753A /* b2RopeJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB897E141C3E5900F1753A /* b2RopeJoint.cpp */; }; + 80BB89DB141C3E5900F1753A /* b2RopeJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB897F141C3E5900F1753A /* b2RopeJoint.h */; }; + 80BB89DC141C3E5900F1753A /* b2WeldJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8980141C3E5900F1753A /* b2WeldJoint.cpp */; }; + 80BB89DD141C3E5900F1753A /* b2WeldJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8981141C3E5900F1753A /* b2WeldJoint.h */; }; + 80BB89DE141C3E5900F1753A /* b2WheelJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8982141C3E5900F1753A /* b2WheelJoint.cpp */; }; + 80BB89DF141C3E5900F1753A /* b2WheelJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8983141C3E5900F1753A /* b2WheelJoint.h */; }; + 80BB89E0141C3E5900F1753A /* b2Rope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8985141C3E5900F1753A /* b2Rope.cpp */; }; + 80BB89E1141C3E5900F1753A /* b2Rope.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8986141C3E5900F1753A /* b2Rope.h */; }; + 80BB8A0B141C3E6900F1753A /* algebra3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89E3141C3E6900F1753A /* algebra3.cpp */; }; + 80BB8A0C141C3E6900F1753A /* algebra3.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB89E4141C3E6900F1753A /* algebra3.h */; }; + 80BB8A0D141C3E6900F1753A /* arcball.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89E5141C3E6900F1753A /* arcball.cpp */; }; + 80BB8A0E141C3E6900F1753A /* arcball.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB89E6141C3E6900F1753A /* arcball.h */; }; + 80BB8A0F141C3E6900F1753A /* glui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89E8141C3E6900F1753A /* glui.cpp */; }; + 80BB8A10141C3E6900F1753A /* glui.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB89E9141C3E6900F1753A /* glui.h */; }; + 80BB8A11141C3E6900F1753A /* glui_add_controls.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89EA141C3E6900F1753A /* glui_add_controls.cpp */; }; + 80BB8A12141C3E6900F1753A /* glui_bitmap_img_data.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89EB141C3E6900F1753A /* glui_bitmap_img_data.cpp */; }; + 80BB8A13141C3E6900F1753A /* glui_bitmaps.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89EC141C3E6900F1753A /* glui_bitmaps.cpp */; }; + 80BB8A14141C3E6900F1753A /* glui_button.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89ED141C3E6900F1753A /* glui_button.cpp */; }; + 80BB8A15141C3E6900F1753A /* glui_checkbox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89EE141C3E6900F1753A /* glui_checkbox.cpp */; }; + 80BB8A16141C3E6900F1753A /* glui_column.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89EF141C3E6900F1753A /* glui_column.cpp */; }; + 80BB8A17141C3E6900F1753A /* glui_commandline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F0141C3E6900F1753A /* glui_commandline.cpp */; }; + 80BB8A18141C3E6900F1753A /* glui_control.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F1141C3E6900F1753A /* glui_control.cpp */; }; + 80BB8A19141C3E6900F1753A /* glui_edittext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F2141C3E6900F1753A /* glui_edittext.cpp */; }; + 80BB8A1A141C3E6900F1753A /* glui_filebrowser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F3141C3E6900F1753A /* glui_filebrowser.cpp */; }; + 80BB8A1B141C3E6900F1753A /* glui_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB89F4141C3E6900F1753A /* glui_internal.h */; }; + 80BB8A1C141C3E6900F1753A /* glui_internal_control.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB89F5141C3E6900F1753A /* glui_internal_control.h */; }; + 80BB8A1D141C3E6900F1753A /* glui_list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F6141C3E6900F1753A /* glui_list.cpp */; }; + 80BB8A1E141C3E6900F1753A /* glui_listbox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F7141C3E6900F1753A /* glui_listbox.cpp */; }; + 80BB8A1F141C3E6900F1753A /* glui_mouse_iaction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F8141C3E6900F1753A /* glui_mouse_iaction.cpp */; }; + 80BB8A20141C3E6900F1753A /* glui_node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F9141C3E6900F1753A /* glui_node.cpp */; }; + 80BB8A21141C3E6900F1753A /* glui_panel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89FA141C3E6900F1753A /* glui_panel.cpp */; }; + 80BB8A22141C3E6900F1753A /* glui_radio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89FB141C3E6900F1753A /* glui_radio.cpp */; }; + 80BB8A23141C3E6900F1753A /* glui_rollout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89FC141C3E6900F1753A /* glui_rollout.cpp */; }; + 80BB8A24141C3E6900F1753A /* glui_rotation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89FD141C3E6900F1753A /* glui_rotation.cpp */; }; + 80BB8A25141C3E6900F1753A /* glui_scrollbar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89FE141C3E6900F1753A /* glui_scrollbar.cpp */; }; + 80BB8A26141C3E6900F1753A /* glui_separator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89FF141C3E6900F1753A /* glui_separator.cpp */; }; + 80BB8A27141C3E6900F1753A /* glui_spinner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A00141C3E6900F1753A /* glui_spinner.cpp */; }; + 80BB8A28141C3E6900F1753A /* glui_statictext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A01141C3E6900F1753A /* glui_statictext.cpp */; }; + 80BB8A29141C3E6900F1753A /* glui_string.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A02141C3E6900F1753A /* glui_string.cpp */; }; + 80BB8A2A141C3E6900F1753A /* glui_textbox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A03141C3E6900F1753A /* glui_textbox.cpp */; }; + 80BB8A2B141C3E6900F1753A /* glui_translation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A04141C3E6900F1753A /* glui_translation.cpp */; }; + 80BB8A2C141C3E6900F1753A /* glui_tree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A05141C3E6900F1753A /* glui_tree.cpp */; }; + 80BB8A2D141C3E6900F1753A /* glui_treepanel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A06141C3E6900F1753A /* glui_treepanel.cpp */; }; + 80BB8A2E141C3E6900F1753A /* glui_window.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A07141C3E6900F1753A /* glui_window.cpp */; }; + 80BB8A2F141C3E6900F1753A /* quaternion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A08141C3E6900F1753A /* quaternion.cpp */; }; + 80BB8A30141C3E6900F1753A /* quaternion.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8A09141C3E6900F1753A /* quaternion.h */; }; + 80BB8A34141C3E7B00F1753A /* HelloWorld.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A33141C3E7B00F1753A /* HelloWorld.cpp */; }; + 80BB8A6B141C3E8600F1753A /* Main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A38141C3E8500F1753A /* Main.cpp */; }; + 80BB8A6C141C3E8600F1753A /* Render.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A39141C3E8500F1753A /* Render.cpp */; }; + 80BB8A6D141C3E8600F1753A /* Test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A3B141C3E8500F1753A /* Test.cpp */; }; + 80BB8A6E141C3E8600F1753A /* TestEntries.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A63141C3E8600F1753A /* TestEntries.cpp */; }; + 80BB8A75141C3F4C00F1753A /* libBox2D.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 80FF01D2141C3D980059E59D /* libBox2D.a */; }; + 80BB8A76141C3F7600F1753A /* libBox2D.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 80FF01D2141C3D980059E59D /* libBox2D.a */; }; + 80BB8A77141C3F7600F1753A /* libGLUI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 80BB8901141C3E1800F1753A /* libGLUI.a */; }; + 80BB8A79141C3F9C00F1753A /* GLUT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80BB8A78141C3F9C00F1753A /* GLUT.framework */; }; + 80BB8A7B141C3FA700F1753A /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80BB8A7A141C3FA700F1753A /* OpenGL.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 80BB8A6F141C3EA100F1753A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 80FF01C9141C3D980059E59D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 80FF01D1141C3D980059E59D; + remoteInfo = Box2D; + }; + 80BB8A71141C3EA800F1753A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 80FF01C9141C3D980059E59D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 80FF01D1141C3D980059E59D; + remoteInfo = Box2D; + }; + 80BB8A73141C3EA800F1753A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 80FF01C9141C3D980059E59D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 80BB8900141C3E1800F1753A; + remoteInfo = GLUI; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 80BB8908141C3E2600F1753A /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 80BB8916141C3E3600F1753A /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 80154ACD141DED6B00C8251F /* Tumbler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tumbler.h; sourceTree = ""; }; + 80BB8901141C3E1800F1753A /* libGLUI.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libGLUI.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 80BB890A141C3E2700F1753A /* HelloWorld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = HelloWorld; sourceTree = BUILT_PRODUCTS_DIR; }; + 80BB8918141C3E3600F1753A /* Testbed */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Testbed; sourceTree = BUILT_PRODUCTS_DIR; }; + 80BB8923141C3E5900F1753A /* Box2D.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Box2D.h; sourceTree = ""; }; + 80BB8924141C3E5900F1753A /* Box2DConfig.cmake */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Box2DConfig.cmake; sourceTree = ""; }; + 80BB8925141C3E5900F1753A /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 80BB8927141C3E5900F1753A /* b2BroadPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2BroadPhase.cpp; sourceTree = ""; }; + 80BB8928141C3E5900F1753A /* b2BroadPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2BroadPhase.h; sourceTree = ""; }; + 80BB8929141C3E5900F1753A /* b2CollideCircle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CollideCircle.cpp; sourceTree = ""; }; + 80BB892A141C3E5900F1753A /* b2CollideEdge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CollideEdge.cpp; sourceTree = ""; }; + 80BB892B141C3E5900F1753A /* b2CollidePolygon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CollidePolygon.cpp; sourceTree = ""; }; + 80BB892C141C3E5900F1753A /* b2Collision.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Collision.cpp; sourceTree = ""; }; + 80BB892D141C3E5900F1753A /* b2Collision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Collision.h; sourceTree = ""; }; + 80BB892E141C3E5900F1753A /* b2Distance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Distance.cpp; sourceTree = ""; }; + 80BB892F141C3E5900F1753A /* b2Distance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Distance.h; sourceTree = ""; }; + 80BB8930141C3E5900F1753A /* b2DynamicTree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2DynamicTree.cpp; sourceTree = ""; }; + 80BB8931141C3E5900F1753A /* b2DynamicTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2DynamicTree.h; sourceTree = ""; }; + 80BB8932141C3E5900F1753A /* b2TimeOfImpact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2TimeOfImpact.cpp; sourceTree = ""; }; + 80BB8933141C3E5900F1753A /* b2TimeOfImpact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2TimeOfImpact.h; sourceTree = ""; }; + 80BB8935141C3E5900F1753A /* b2ChainShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2ChainShape.cpp; sourceTree = ""; }; + 80BB8936141C3E5900F1753A /* b2ChainShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2ChainShape.h; sourceTree = ""; }; + 80BB8937141C3E5900F1753A /* b2CircleShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CircleShape.cpp; sourceTree = ""; }; + 80BB8938141C3E5900F1753A /* b2CircleShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2CircleShape.h; sourceTree = ""; }; + 80BB8939141C3E5900F1753A /* b2EdgeShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2EdgeShape.cpp; sourceTree = ""; }; + 80BB893A141C3E5900F1753A /* b2EdgeShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2EdgeShape.h; sourceTree = ""; }; + 80BB893B141C3E5900F1753A /* b2PolygonShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PolygonShape.cpp; sourceTree = ""; }; + 80BB893C141C3E5900F1753A /* b2PolygonShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PolygonShape.h; sourceTree = ""; }; + 80BB893D141C3E5900F1753A /* b2Shape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Shape.h; sourceTree = ""; }; + 80BB893F141C3E5900F1753A /* b2BlockAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2BlockAllocator.cpp; sourceTree = ""; }; + 80BB8940141C3E5900F1753A /* b2BlockAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2BlockAllocator.h; sourceTree = ""; }; + 80BB8941141C3E5900F1753A /* b2Draw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Draw.cpp; sourceTree = ""; }; + 80BB8942141C3E5900F1753A /* b2Draw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Draw.h; sourceTree = ""; }; + 80BB8943141C3E5900F1753A /* b2GrowableStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2GrowableStack.h; sourceTree = ""; }; + 80BB8944141C3E5900F1753A /* b2Math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Math.cpp; sourceTree = ""; }; + 80BB8945141C3E5900F1753A /* b2Math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Math.h; sourceTree = ""; }; + 80BB8946141C3E5900F1753A /* b2Settings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Settings.cpp; sourceTree = ""; }; + 80BB8947141C3E5900F1753A /* b2Settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Settings.h; sourceTree = ""; }; + 80BB8948141C3E5900F1753A /* b2StackAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2StackAllocator.cpp; sourceTree = ""; }; + 80BB8949141C3E5900F1753A /* b2StackAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2StackAllocator.h; sourceTree = ""; }; + 80BB894A141C3E5900F1753A /* b2Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Timer.cpp; sourceTree = ""; }; + 80BB894B141C3E5900F1753A /* b2Timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Timer.h; sourceTree = ""; }; + 80BB894D141C3E5900F1753A /* b2Body.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Body.cpp; sourceTree = ""; }; + 80BB894E141C3E5900F1753A /* b2Body.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Body.h; sourceTree = ""; }; + 80BB894F141C3E5900F1753A /* b2ContactManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2ContactManager.cpp; sourceTree = ""; }; + 80BB8950141C3E5900F1753A /* b2ContactManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2ContactManager.h; sourceTree = ""; }; + 80BB8951141C3E5900F1753A /* b2Fixture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Fixture.cpp; sourceTree = ""; }; + 80BB8952141C3E5900F1753A /* b2Fixture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Fixture.h; sourceTree = ""; }; + 80BB8953141C3E5900F1753A /* b2Island.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Island.cpp; sourceTree = ""; }; + 80BB8954141C3E5900F1753A /* b2Island.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Island.h; sourceTree = ""; }; + 80BB8955141C3E5900F1753A /* b2TimeStep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2TimeStep.h; sourceTree = ""; }; + 80BB8956141C3E5900F1753A /* b2World.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2World.cpp; sourceTree = ""; }; + 80BB8957141C3E5900F1753A /* b2World.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2World.h; sourceTree = ""; }; + 80BB8958141C3E5900F1753A /* b2WorldCallbacks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2WorldCallbacks.cpp; sourceTree = ""; }; + 80BB8959141C3E5900F1753A /* b2WorldCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2WorldCallbacks.h; sourceTree = ""; }; + 80BB895B141C3E5900F1753A /* b2ChainAndCircleContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2ChainAndCircleContact.cpp; sourceTree = ""; }; + 80BB895C141C3E5900F1753A /* b2ChainAndCircleContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2ChainAndCircleContact.h; sourceTree = ""; }; + 80BB895D141C3E5900F1753A /* b2ChainAndPolygonContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2ChainAndPolygonContact.cpp; sourceTree = ""; }; + 80BB895E141C3E5900F1753A /* b2ChainAndPolygonContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2ChainAndPolygonContact.h; sourceTree = ""; }; + 80BB895F141C3E5900F1753A /* b2CircleContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CircleContact.cpp; sourceTree = ""; }; + 80BB8960141C3E5900F1753A /* b2CircleContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2CircleContact.h; sourceTree = ""; }; + 80BB8961141C3E5900F1753A /* b2Contact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Contact.cpp; sourceTree = ""; }; + 80BB8962141C3E5900F1753A /* b2Contact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Contact.h; sourceTree = ""; }; + 80BB8963141C3E5900F1753A /* b2ContactSolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2ContactSolver.cpp; sourceTree = ""; }; + 80BB8964141C3E5900F1753A /* b2ContactSolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2ContactSolver.h; sourceTree = ""; }; + 80BB8965141C3E5900F1753A /* b2EdgeAndCircleContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2EdgeAndCircleContact.cpp; sourceTree = ""; }; + 80BB8966141C3E5900F1753A /* b2EdgeAndCircleContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2EdgeAndCircleContact.h; sourceTree = ""; }; + 80BB8967141C3E5900F1753A /* b2EdgeAndPolygonContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2EdgeAndPolygonContact.cpp; sourceTree = ""; }; + 80BB8968141C3E5900F1753A /* b2EdgeAndPolygonContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2EdgeAndPolygonContact.h; sourceTree = ""; }; + 80BB8969141C3E5900F1753A /* b2PolygonAndCircleContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PolygonAndCircleContact.cpp; sourceTree = ""; }; + 80BB896A141C3E5900F1753A /* b2PolygonAndCircleContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PolygonAndCircleContact.h; sourceTree = ""; }; + 80BB896B141C3E5900F1753A /* b2PolygonContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PolygonContact.cpp; sourceTree = ""; }; + 80BB896C141C3E5900F1753A /* b2PolygonContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PolygonContact.h; sourceTree = ""; }; + 80BB896E141C3E5900F1753A /* b2DistanceJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2DistanceJoint.cpp; sourceTree = ""; }; + 80BB896F141C3E5900F1753A /* b2DistanceJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2DistanceJoint.h; sourceTree = ""; }; + 80BB8970141C3E5900F1753A /* b2FrictionJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2FrictionJoint.cpp; sourceTree = ""; }; + 80BB8971141C3E5900F1753A /* b2FrictionJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2FrictionJoint.h; sourceTree = ""; }; + 80BB8972141C3E5900F1753A /* b2GearJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2GearJoint.cpp; sourceTree = ""; }; + 80BB8973141C3E5900F1753A /* b2GearJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2GearJoint.h; sourceTree = ""; }; + 80BB8974141C3E5900F1753A /* b2Joint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Joint.cpp; sourceTree = ""; }; + 80BB8975141C3E5900F1753A /* b2Joint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Joint.h; sourceTree = ""; }; + 80BB8976141C3E5900F1753A /* b2MouseJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2MouseJoint.cpp; sourceTree = ""; }; + 80BB8977141C3E5900F1753A /* b2MouseJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2MouseJoint.h; sourceTree = ""; }; + 80BB8978141C3E5900F1753A /* b2PrismaticJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PrismaticJoint.cpp; sourceTree = ""; }; + 80BB8979141C3E5900F1753A /* b2PrismaticJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PrismaticJoint.h; sourceTree = ""; }; + 80BB897A141C3E5900F1753A /* b2PulleyJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PulleyJoint.cpp; sourceTree = ""; }; + 80BB897B141C3E5900F1753A /* b2PulleyJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PulleyJoint.h; sourceTree = ""; }; + 80BB897C141C3E5900F1753A /* b2RevoluteJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2RevoluteJoint.cpp; sourceTree = ""; }; + 80BB897D141C3E5900F1753A /* b2RevoluteJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2RevoluteJoint.h; sourceTree = ""; }; + 80BB897E141C3E5900F1753A /* b2RopeJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2RopeJoint.cpp; sourceTree = ""; }; + 80BB897F141C3E5900F1753A /* b2RopeJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2RopeJoint.h; sourceTree = ""; }; + 80BB8980141C3E5900F1753A /* b2WeldJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2WeldJoint.cpp; sourceTree = ""; }; + 80BB8981141C3E5900F1753A /* b2WeldJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2WeldJoint.h; sourceTree = ""; }; + 80BB8982141C3E5900F1753A /* b2WheelJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2WheelJoint.cpp; sourceTree = ""; }; + 80BB8983141C3E5900F1753A /* b2WheelJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2WheelJoint.h; sourceTree = ""; }; + 80BB8985141C3E5900F1753A /* b2Rope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Rope.cpp; sourceTree = ""; }; + 80BB8986141C3E5900F1753A /* b2Rope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Rope.h; sourceTree = ""; }; + 80BB89E3141C3E6900F1753A /* algebra3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = algebra3.cpp; sourceTree = ""; }; + 80BB89E4141C3E6900F1753A /* algebra3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = algebra3.h; sourceTree = ""; }; + 80BB89E5141C3E6900F1753A /* arcball.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = arcball.cpp; sourceTree = ""; }; + 80BB89E6141C3E6900F1753A /* arcball.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arcball.h; sourceTree = ""; }; + 80BB89E7141C3E6900F1753A /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 80BB89E8141C3E6900F1753A /* glui.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui.cpp; sourceTree = ""; }; + 80BB89E9141C3E6900F1753A /* glui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glui.h; sourceTree = ""; }; + 80BB89EA141C3E6900F1753A /* glui_add_controls.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_add_controls.cpp; sourceTree = ""; }; + 80BB89EB141C3E6900F1753A /* glui_bitmap_img_data.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_bitmap_img_data.cpp; sourceTree = ""; }; + 80BB89EC141C3E6900F1753A /* glui_bitmaps.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_bitmaps.cpp; sourceTree = ""; }; + 80BB89ED141C3E6900F1753A /* glui_button.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_button.cpp; sourceTree = ""; }; + 80BB89EE141C3E6900F1753A /* glui_checkbox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_checkbox.cpp; sourceTree = ""; }; + 80BB89EF141C3E6900F1753A /* glui_column.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_column.cpp; sourceTree = ""; }; + 80BB89F0141C3E6900F1753A /* glui_commandline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_commandline.cpp; sourceTree = ""; }; + 80BB89F1141C3E6900F1753A /* glui_control.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_control.cpp; sourceTree = ""; }; + 80BB89F2141C3E6900F1753A /* glui_edittext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_edittext.cpp; sourceTree = ""; }; + 80BB89F3141C3E6900F1753A /* glui_filebrowser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_filebrowser.cpp; sourceTree = ""; }; + 80BB89F4141C3E6900F1753A /* glui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glui_internal.h; sourceTree = ""; }; + 80BB89F5141C3E6900F1753A /* glui_internal_control.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glui_internal_control.h; sourceTree = ""; }; + 80BB89F6141C3E6900F1753A /* glui_list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_list.cpp; sourceTree = ""; }; + 80BB89F7141C3E6900F1753A /* glui_listbox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_listbox.cpp; sourceTree = ""; }; + 80BB89F8141C3E6900F1753A /* glui_mouse_iaction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_mouse_iaction.cpp; sourceTree = ""; }; + 80BB89F9141C3E6900F1753A /* glui_node.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_node.cpp; sourceTree = ""; }; + 80BB89FA141C3E6900F1753A /* glui_panel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_panel.cpp; sourceTree = ""; }; + 80BB89FB141C3E6900F1753A /* glui_radio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_radio.cpp; sourceTree = ""; }; + 80BB89FC141C3E6900F1753A /* glui_rollout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_rollout.cpp; sourceTree = ""; }; + 80BB89FD141C3E6900F1753A /* glui_rotation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_rotation.cpp; sourceTree = ""; }; + 80BB89FE141C3E6900F1753A /* glui_scrollbar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_scrollbar.cpp; sourceTree = ""; }; + 80BB89FF141C3E6900F1753A /* glui_separator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_separator.cpp; sourceTree = ""; }; + 80BB8A00141C3E6900F1753A /* glui_spinner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_spinner.cpp; sourceTree = ""; }; + 80BB8A01141C3E6900F1753A /* glui_statictext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_statictext.cpp; sourceTree = ""; }; + 80BB8A02141C3E6900F1753A /* glui_string.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_string.cpp; sourceTree = ""; }; + 80BB8A03141C3E6900F1753A /* glui_textbox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_textbox.cpp; sourceTree = ""; }; + 80BB8A04141C3E6900F1753A /* glui_translation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_translation.cpp; sourceTree = ""; }; + 80BB8A05141C3E6900F1753A /* glui_tree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_tree.cpp; sourceTree = ""; }; + 80BB8A06141C3E6900F1753A /* glui_treepanel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_treepanel.cpp; sourceTree = ""; }; + 80BB8A07141C3E6900F1753A /* glui_window.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_window.cpp; sourceTree = ""; }; + 80BB8A08141C3E6900F1753A /* quaternion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = quaternion.cpp; sourceTree = ""; }; + 80BB8A09141C3E6900F1753A /* quaternion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = quaternion.h; sourceTree = ""; }; + 80BB8A0A141C3E6900F1753A /* readme.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = readme.txt; sourceTree = ""; }; + 80BB8A32141C3E7B00F1753A /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 80BB8A33141C3E7B00F1753A /* HelloWorld.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HelloWorld.cpp; sourceTree = ""; }; + 80BB8A36141C3E8500F1753A /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 80BB8A38141C3E8500F1753A /* Main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Main.cpp; sourceTree = ""; }; + 80BB8A39141C3E8500F1753A /* Render.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Render.cpp; sourceTree = ""; }; + 80BB8A3A141C3E8500F1753A /* Render.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Render.h; sourceTree = ""; }; + 80BB8A3B141C3E8500F1753A /* Test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Test.cpp; sourceTree = ""; }; + 80BB8A3C141C3E8500F1753A /* Test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Test.h; sourceTree = ""; }; + 80BB8A3E141C3E8500F1753A /* AddPair.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddPair.h; sourceTree = ""; }; + 80BB8A3F141C3E8500F1753A /* ApplyForce.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplyForce.h; sourceTree = ""; }; + 80BB8A40141C3E8500F1753A /* BodyTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BodyTypes.h; sourceTree = ""; }; + 80BB8A41141C3E8500F1753A /* Breakable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Breakable.h; sourceTree = ""; }; + 80BB8A42141C3E8500F1753A /* Bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Bridge.h; sourceTree = ""; }; + 80BB8A43141C3E8500F1753A /* BulletTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BulletTest.h; sourceTree = ""; }; + 80BB8A44141C3E8500F1753A /* Cantilever.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Cantilever.h; sourceTree = ""; }; + 80BB8A45141C3E8500F1753A /* Car.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Car.h; sourceTree = ""; }; + 80BB8A46141C3E8500F1753A /* Chain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Chain.h; sourceTree = ""; }; + 80BB8A47141C3E8500F1753A /* CharacterCollision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CharacterCollision.h; sourceTree = ""; }; + 80BB8A48141C3E8500F1753A /* CollisionFiltering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollisionFiltering.h; sourceTree = ""; }; + 80BB8A49141C3E8500F1753A /* CollisionProcessing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollisionProcessing.h; sourceTree = ""; }; + 80BB8A4A141C3E8500F1753A /* CompoundShapes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompoundShapes.h; sourceTree = ""; }; + 80BB8A4B141C3E8600F1753A /* Confined.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Confined.h; sourceTree = ""; }; + 80BB8A4C141C3E8600F1753A /* ContinuousTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContinuousTest.h; sourceTree = ""; }; + 80BB8A4D141C3E8600F1753A /* DistanceTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DistanceTest.h; sourceTree = ""; }; + 80BB8A4E141C3E8600F1753A /* Dominos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Dominos.h; sourceTree = ""; }; + 80BB8A4F141C3E8600F1753A /* DumpShell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumpShell.h; sourceTree = ""; }; + 80BB8A50141C3E8600F1753A /* DynamicTreeTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicTreeTest.h; sourceTree = ""; }; + 80BB8A51141C3E8600F1753A /* EdgeShapes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EdgeShapes.h; sourceTree = ""; }; + 80BB8A52141C3E8600F1753A /* EdgeTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EdgeTest.h; sourceTree = ""; }; + 80BB8A53141C3E8600F1753A /* Gears.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Gears.h; sourceTree = ""; }; + 80BB8A54141C3E8600F1753A /* OneSidedPlatform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OneSidedPlatform.h; sourceTree = ""; }; + 80BB8A55141C3E8600F1753A /* Pinball.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pinball.h; sourceTree = ""; }; + 80BB8A56141C3E8600F1753A /* PolyCollision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolyCollision.h; sourceTree = ""; }; + 80BB8A57141C3E8600F1753A /* PolyShapes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolyShapes.h; sourceTree = ""; }; + 80BB8A58141C3E8600F1753A /* Prismatic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Prismatic.h; sourceTree = ""; }; + 80BB8A59141C3E8600F1753A /* Pulleys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pulleys.h; sourceTree = ""; }; + 80BB8A5A141C3E8600F1753A /* Pyramid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pyramid.h; sourceTree = ""; }; + 80BB8A5B141C3E8600F1753A /* RayCast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RayCast.h; sourceTree = ""; }; + 80BB8A5C141C3E8600F1753A /* Revolute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Revolute.h; sourceTree = ""; }; + 80BB8A5D141C3E8600F1753A /* Rope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Rope.h; sourceTree = ""; }; + 80BB8A5E141C3E8600F1753A /* RopeJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RopeJoint.h; sourceTree = ""; }; + 80BB8A5F141C3E8600F1753A /* SensorTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SensorTest.h; sourceTree = ""; }; + 80BB8A60141C3E8600F1753A /* ShapeEditing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShapeEditing.h; sourceTree = ""; }; + 80BB8A61141C3E8600F1753A /* SliderCrank.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SliderCrank.h; sourceTree = ""; }; + 80BB8A62141C3E8600F1753A /* SphereStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SphereStack.h; sourceTree = ""; }; + 80BB8A63141C3E8600F1753A /* TestEntries.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestEntries.cpp; sourceTree = ""; }; + 80BB8A64141C3E8600F1753A /* TheoJansen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TheoJansen.h; sourceTree = ""; }; + 80BB8A65141C3E8600F1753A /* Tiles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tiles.h; sourceTree = ""; }; + 80BB8A66141C3E8600F1753A /* TimeOfImpact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TimeOfImpact.h; sourceTree = ""; }; + 80BB8A67141C3E8600F1753A /* VaryingFriction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VaryingFriction.h; sourceTree = ""; }; + 80BB8A68141C3E8600F1753A /* VaryingRestitution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VaryingRestitution.h; sourceTree = ""; }; + 80BB8A69141C3E8600F1753A /* VerticalStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VerticalStack.h; sourceTree = ""; }; + 80BB8A6A141C3E8600F1753A /* Web.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Web.h; sourceTree = ""; }; + 80BB8A78141C3F9C00F1753A /* GLUT.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLUT.framework; path = System/Library/Frameworks/GLUT.framework; sourceTree = SDKROOT; }; + 80BB8A7A141C3FA700F1753A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 80FF01D2141C3D980059E59D /* libBox2D.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBox2D.a; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 80BB88FE141C3E1800F1753A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80BB8907141C3E2600F1753A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8A75141C3F4C00F1753A /* libBox2D.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80BB8915141C3E3600F1753A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8A7B141C3FA700F1753A /* OpenGL.framework in Frameworks */, + 80BB8A79141C3F9C00F1753A /* GLUT.framework in Frameworks */, + 80BB8A76141C3F7600F1753A /* libBox2D.a in Frameworks */, + 80BB8A77141C3F7600F1753A /* libGLUI.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80FF01CF141C3D980059E59D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 80BB8922141C3E5900F1753A /* Box2D */ = { + isa = PBXGroup; + children = ( + 80BB8923141C3E5900F1753A /* Box2D.h */, + 80BB8924141C3E5900F1753A /* Box2DConfig.cmake */, + 80BB8925141C3E5900F1753A /* CMakeLists.txt */, + 80BB8926141C3E5900F1753A /* Collision */, + 80BB893E141C3E5900F1753A /* Common */, + 80BB894C141C3E5900F1753A /* Dynamics */, + 80BB8984141C3E5900F1753A /* Rope */, + ); + name = Box2D; + path = ../../Box2D; + sourceTree = ""; + }; + 80BB8926141C3E5900F1753A /* Collision */ = { + isa = PBXGroup; + children = ( + 80BB8927141C3E5900F1753A /* b2BroadPhase.cpp */, + 80BB8928141C3E5900F1753A /* b2BroadPhase.h */, + 80BB8929141C3E5900F1753A /* b2CollideCircle.cpp */, + 80BB892A141C3E5900F1753A /* b2CollideEdge.cpp */, + 80BB892B141C3E5900F1753A /* b2CollidePolygon.cpp */, + 80BB892C141C3E5900F1753A /* b2Collision.cpp */, + 80BB892D141C3E5900F1753A /* b2Collision.h */, + 80BB892E141C3E5900F1753A /* b2Distance.cpp */, + 80BB892F141C3E5900F1753A /* b2Distance.h */, + 80BB8930141C3E5900F1753A /* b2DynamicTree.cpp */, + 80BB8931141C3E5900F1753A /* b2DynamicTree.h */, + 80BB8932141C3E5900F1753A /* b2TimeOfImpact.cpp */, + 80BB8933141C3E5900F1753A /* b2TimeOfImpact.h */, + 80BB8934141C3E5900F1753A /* Shapes */, + ); + path = Collision; + sourceTree = ""; + }; + 80BB8934141C3E5900F1753A /* Shapes */ = { + isa = PBXGroup; + children = ( + 80BB8935141C3E5900F1753A /* b2ChainShape.cpp */, + 80BB8936141C3E5900F1753A /* b2ChainShape.h */, + 80BB8937141C3E5900F1753A /* b2CircleShape.cpp */, + 80BB8938141C3E5900F1753A /* b2CircleShape.h */, + 80BB8939141C3E5900F1753A /* b2EdgeShape.cpp */, + 80BB893A141C3E5900F1753A /* b2EdgeShape.h */, + 80BB893B141C3E5900F1753A /* b2PolygonShape.cpp */, + 80BB893C141C3E5900F1753A /* b2PolygonShape.h */, + 80BB893D141C3E5900F1753A /* b2Shape.h */, + ); + path = Shapes; + sourceTree = ""; + }; + 80BB893E141C3E5900F1753A /* Common */ = { + isa = PBXGroup; + children = ( + 80BB893F141C3E5900F1753A /* b2BlockAllocator.cpp */, + 80BB8940141C3E5900F1753A /* b2BlockAllocator.h */, + 80BB8941141C3E5900F1753A /* b2Draw.cpp */, + 80BB8942141C3E5900F1753A /* b2Draw.h */, + 80BB8943141C3E5900F1753A /* b2GrowableStack.h */, + 80BB8944141C3E5900F1753A /* b2Math.cpp */, + 80BB8945141C3E5900F1753A /* b2Math.h */, + 80BB8946141C3E5900F1753A /* b2Settings.cpp */, + 80BB8947141C3E5900F1753A /* b2Settings.h */, + 80BB8948141C3E5900F1753A /* b2StackAllocator.cpp */, + 80BB8949141C3E5900F1753A /* b2StackAllocator.h */, + 80BB894A141C3E5900F1753A /* b2Timer.cpp */, + 80BB894B141C3E5900F1753A /* b2Timer.h */, + ); + path = Common; + sourceTree = ""; + }; + 80BB894C141C3E5900F1753A /* Dynamics */ = { + isa = PBXGroup; + children = ( + 80BB894D141C3E5900F1753A /* b2Body.cpp */, + 80BB894E141C3E5900F1753A /* b2Body.h */, + 80BB894F141C3E5900F1753A /* b2ContactManager.cpp */, + 80BB8950141C3E5900F1753A /* b2ContactManager.h */, + 80BB8951141C3E5900F1753A /* b2Fixture.cpp */, + 80BB8952141C3E5900F1753A /* b2Fixture.h */, + 80BB8953141C3E5900F1753A /* b2Island.cpp */, + 80BB8954141C3E5900F1753A /* b2Island.h */, + 80BB8955141C3E5900F1753A /* b2TimeStep.h */, + 80BB8956141C3E5900F1753A /* b2World.cpp */, + 80BB8957141C3E5900F1753A /* b2World.h */, + 80BB8958141C3E5900F1753A /* b2WorldCallbacks.cpp */, + 80BB8959141C3E5900F1753A /* b2WorldCallbacks.h */, + 80BB895A141C3E5900F1753A /* Contacts */, + 80BB896D141C3E5900F1753A /* Joints */, + ); + path = Dynamics; + sourceTree = ""; + }; + 80BB895A141C3E5900F1753A /* Contacts */ = { + isa = PBXGroup; + children = ( + 80BB895B141C3E5900F1753A /* b2ChainAndCircleContact.cpp */, + 80BB895C141C3E5900F1753A /* b2ChainAndCircleContact.h */, + 80BB895D141C3E5900F1753A /* b2ChainAndPolygonContact.cpp */, + 80BB895E141C3E5900F1753A /* b2ChainAndPolygonContact.h */, + 80BB895F141C3E5900F1753A /* b2CircleContact.cpp */, + 80BB8960141C3E5900F1753A /* b2CircleContact.h */, + 80BB8961141C3E5900F1753A /* b2Contact.cpp */, + 80BB8962141C3E5900F1753A /* b2Contact.h */, + 80BB8963141C3E5900F1753A /* b2ContactSolver.cpp */, + 80BB8964141C3E5900F1753A /* b2ContactSolver.h */, + 80BB8965141C3E5900F1753A /* b2EdgeAndCircleContact.cpp */, + 80BB8966141C3E5900F1753A /* b2EdgeAndCircleContact.h */, + 80BB8967141C3E5900F1753A /* b2EdgeAndPolygonContact.cpp */, + 80BB8968141C3E5900F1753A /* b2EdgeAndPolygonContact.h */, + 80BB8969141C3E5900F1753A /* b2PolygonAndCircleContact.cpp */, + 80BB896A141C3E5900F1753A /* b2PolygonAndCircleContact.h */, + 80BB896B141C3E5900F1753A /* b2PolygonContact.cpp */, + 80BB896C141C3E5900F1753A /* b2PolygonContact.h */, + ); + path = Contacts; + sourceTree = ""; + }; + 80BB896D141C3E5900F1753A /* Joints */ = { + isa = PBXGroup; + children = ( + 80BB896E141C3E5900F1753A /* b2DistanceJoint.cpp */, + 80BB896F141C3E5900F1753A /* b2DistanceJoint.h */, + 80BB8970141C3E5900F1753A /* b2FrictionJoint.cpp */, + 80BB8971141C3E5900F1753A /* b2FrictionJoint.h */, + 80BB8972141C3E5900F1753A /* b2GearJoint.cpp */, + 80BB8973141C3E5900F1753A /* b2GearJoint.h */, + 80BB8974141C3E5900F1753A /* b2Joint.cpp */, + 80BB8975141C3E5900F1753A /* b2Joint.h */, + 80BB8976141C3E5900F1753A /* b2MouseJoint.cpp */, + 80BB8977141C3E5900F1753A /* b2MouseJoint.h */, + 80BB8978141C3E5900F1753A /* b2PrismaticJoint.cpp */, + 80BB8979141C3E5900F1753A /* b2PrismaticJoint.h */, + 80BB897A141C3E5900F1753A /* b2PulleyJoint.cpp */, + 80BB897B141C3E5900F1753A /* b2PulleyJoint.h */, + 80BB897C141C3E5900F1753A /* b2RevoluteJoint.cpp */, + 80BB897D141C3E5900F1753A /* b2RevoluteJoint.h */, + 80BB897E141C3E5900F1753A /* b2RopeJoint.cpp */, + 80BB897F141C3E5900F1753A /* b2RopeJoint.h */, + 80BB8980141C3E5900F1753A /* b2WeldJoint.cpp */, + 80BB8981141C3E5900F1753A /* b2WeldJoint.h */, + 80BB8982141C3E5900F1753A /* b2WheelJoint.cpp */, + 80BB8983141C3E5900F1753A /* b2WheelJoint.h */, + ); + path = Joints; + sourceTree = ""; + }; + 80BB8984141C3E5900F1753A /* Rope */ = { + isa = PBXGroup; + children = ( + 80BB8985141C3E5900F1753A /* b2Rope.cpp */, + 80BB8986141C3E5900F1753A /* b2Rope.h */, + ); + path = Rope; + sourceTree = ""; + }; + 80BB89E2141C3E6900F1753A /* glui */ = { + isa = PBXGroup; + children = ( + 80BB89E3141C3E6900F1753A /* algebra3.cpp */, + 80BB89E4141C3E6900F1753A /* algebra3.h */, + 80BB89E5141C3E6900F1753A /* arcball.cpp */, + 80BB89E6141C3E6900F1753A /* arcball.h */, + 80BB89E7141C3E6900F1753A /* CMakeLists.txt */, + 80BB89E8141C3E6900F1753A /* glui.cpp */, + 80BB89E9141C3E6900F1753A /* glui.h */, + 80BB89EA141C3E6900F1753A /* glui_add_controls.cpp */, + 80BB89EB141C3E6900F1753A /* glui_bitmap_img_data.cpp */, + 80BB89EC141C3E6900F1753A /* glui_bitmaps.cpp */, + 80BB89ED141C3E6900F1753A /* glui_button.cpp */, + 80BB89EE141C3E6900F1753A /* glui_checkbox.cpp */, + 80BB89EF141C3E6900F1753A /* glui_column.cpp */, + 80BB89F0141C3E6900F1753A /* glui_commandline.cpp */, + 80BB89F1141C3E6900F1753A /* glui_control.cpp */, + 80BB89F2141C3E6900F1753A /* glui_edittext.cpp */, + 80BB89F3141C3E6900F1753A /* glui_filebrowser.cpp */, + 80BB89F4141C3E6900F1753A /* glui_internal.h */, + 80BB89F5141C3E6900F1753A /* glui_internal_control.h */, + 80BB89F6141C3E6900F1753A /* glui_list.cpp */, + 80BB89F7141C3E6900F1753A /* glui_listbox.cpp */, + 80BB89F8141C3E6900F1753A /* glui_mouse_iaction.cpp */, + 80BB89F9141C3E6900F1753A /* glui_node.cpp */, + 80BB89FA141C3E6900F1753A /* glui_panel.cpp */, + 80BB89FB141C3E6900F1753A /* glui_radio.cpp */, + 80BB89FC141C3E6900F1753A /* glui_rollout.cpp */, + 80BB89FD141C3E6900F1753A /* glui_rotation.cpp */, + 80BB89FE141C3E6900F1753A /* glui_scrollbar.cpp */, + 80BB89FF141C3E6900F1753A /* glui_separator.cpp */, + 80BB8A00141C3E6900F1753A /* glui_spinner.cpp */, + 80BB8A01141C3E6900F1753A /* glui_statictext.cpp */, + 80BB8A02141C3E6900F1753A /* glui_string.cpp */, + 80BB8A03141C3E6900F1753A /* glui_textbox.cpp */, + 80BB8A04141C3E6900F1753A /* glui_translation.cpp */, + 80BB8A05141C3E6900F1753A /* glui_tree.cpp */, + 80BB8A06141C3E6900F1753A /* glui_treepanel.cpp */, + 80BB8A07141C3E6900F1753A /* glui_window.cpp */, + 80BB8A08141C3E6900F1753A /* quaternion.cpp */, + 80BB8A09141C3E6900F1753A /* quaternion.h */, + 80BB8A0A141C3E6900F1753A /* readme.txt */, + ); + name = glui; + path = ../../glui; + sourceTree = ""; + }; + 80BB8A31141C3E7B00F1753A /* HelloWorld */ = { + isa = PBXGroup; + children = ( + 80BB8A32141C3E7B00F1753A /* CMakeLists.txt */, + 80BB8A33141C3E7B00F1753A /* HelloWorld.cpp */, + ); + name = HelloWorld; + path = ../../HelloWorld; + sourceTree = ""; + }; + 80BB8A35141C3E8500F1753A /* Testbed */ = { + isa = PBXGroup; + children = ( + 80BB8A36141C3E8500F1753A /* CMakeLists.txt */, + 80BB8A37141C3E8500F1753A /* Framework */, + 80BB8A3D141C3E8500F1753A /* Tests */, + ); + name = Testbed; + path = ../../Testbed; + sourceTree = ""; + }; + 80BB8A37141C3E8500F1753A /* Framework */ = { + isa = PBXGroup; + children = ( + 80BB8A38141C3E8500F1753A /* Main.cpp */, + 80BB8A39141C3E8500F1753A /* Render.cpp */, + 80BB8A3A141C3E8500F1753A /* Render.h */, + 80BB8A3B141C3E8500F1753A /* Test.cpp */, + 80BB8A3C141C3E8500F1753A /* Test.h */, + ); + path = Framework; + sourceTree = ""; + }; + 80BB8A3D141C3E8500F1753A /* Tests */ = { + isa = PBXGroup; + children = ( + 80BB8A3E141C3E8500F1753A /* AddPair.h */, + 80BB8A3F141C3E8500F1753A /* ApplyForce.h */, + 80BB8A40141C3E8500F1753A /* BodyTypes.h */, + 80BB8A41141C3E8500F1753A /* Breakable.h */, + 80BB8A42141C3E8500F1753A /* Bridge.h */, + 80BB8A43141C3E8500F1753A /* BulletTest.h */, + 80BB8A44141C3E8500F1753A /* Cantilever.h */, + 80BB8A45141C3E8500F1753A /* Car.h */, + 80BB8A46141C3E8500F1753A /* Chain.h */, + 80BB8A47141C3E8500F1753A /* CharacterCollision.h */, + 80BB8A48141C3E8500F1753A /* CollisionFiltering.h */, + 80BB8A49141C3E8500F1753A /* CollisionProcessing.h */, + 80BB8A4A141C3E8500F1753A /* CompoundShapes.h */, + 80BB8A4B141C3E8600F1753A /* Confined.h */, + 80BB8A4C141C3E8600F1753A /* ContinuousTest.h */, + 80BB8A4D141C3E8600F1753A /* DistanceTest.h */, + 80BB8A4E141C3E8600F1753A /* Dominos.h */, + 80BB8A4F141C3E8600F1753A /* DumpShell.h */, + 80BB8A50141C3E8600F1753A /* DynamicTreeTest.h */, + 80BB8A51141C3E8600F1753A /* EdgeShapes.h */, + 80BB8A52141C3E8600F1753A /* EdgeTest.h */, + 80BB8A53141C3E8600F1753A /* Gears.h */, + 80BB8A54141C3E8600F1753A /* OneSidedPlatform.h */, + 80BB8A55141C3E8600F1753A /* Pinball.h */, + 80BB8A56141C3E8600F1753A /* PolyCollision.h */, + 80BB8A57141C3E8600F1753A /* PolyShapes.h */, + 80BB8A58141C3E8600F1753A /* Prismatic.h */, + 80BB8A59141C3E8600F1753A /* Pulleys.h */, + 80BB8A5A141C3E8600F1753A /* Pyramid.h */, + 80BB8A5B141C3E8600F1753A /* RayCast.h */, + 80BB8A5C141C3E8600F1753A /* Revolute.h */, + 80BB8A5D141C3E8600F1753A /* Rope.h */, + 80BB8A5E141C3E8600F1753A /* RopeJoint.h */, + 80BB8A5F141C3E8600F1753A /* SensorTest.h */, + 80BB8A60141C3E8600F1753A /* ShapeEditing.h */, + 80BB8A61141C3E8600F1753A /* SliderCrank.h */, + 80BB8A62141C3E8600F1753A /* SphereStack.h */, + 80BB8A63141C3E8600F1753A /* TestEntries.cpp */, + 80BB8A64141C3E8600F1753A /* TheoJansen.h */, + 80BB8A65141C3E8600F1753A /* Tiles.h */, + 80BB8A66141C3E8600F1753A /* TimeOfImpact.h */, + 80154ACD141DED6B00C8251F /* Tumbler.h */, + 80BB8A67141C3E8600F1753A /* VaryingFriction.h */, + 80BB8A68141C3E8600F1753A /* VaryingRestitution.h */, + 80BB8A69141C3E8600F1753A /* VerticalStack.h */, + 80BB8A6A141C3E8600F1753A /* Web.h */, + ); + path = Tests; + sourceTree = ""; + }; + 80FF01C7141C3D980059E59D = { + isa = PBXGroup; + children = ( + 80BB8A7A141C3FA700F1753A /* OpenGL.framework */, + 80BB8A78141C3F9C00F1753A /* GLUT.framework */, + 80BB8A35141C3E8500F1753A /* Testbed */, + 80BB8A31141C3E7B00F1753A /* HelloWorld */, + 80BB89E2141C3E6900F1753A /* glui */, + 80BB8922141C3E5900F1753A /* Box2D */, + 80FF01D3141C3D980059E59D /* Products */, + ); + sourceTree = ""; + }; + 80FF01D3141C3D980059E59D /* Products */ = { + isa = PBXGroup; + children = ( + 80FF01D2141C3D980059E59D /* libBox2D.a */, + 80BB8901141C3E1800F1753A /* libGLUI.a */, + 80BB890A141C3E2700F1753A /* HelloWorld */, + 80BB8918141C3E3600F1753A /* Testbed */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 80BB88FF141C3E1800F1753A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8A0C141C3E6900F1753A /* algebra3.h in Headers */, + 80BB8A0E141C3E6900F1753A /* arcball.h in Headers */, + 80BB8A10141C3E6900F1753A /* glui.h in Headers */, + 80BB8A1B141C3E6900F1753A /* glui_internal.h in Headers */, + 80BB8A1C141C3E6900F1753A /* glui_internal_control.h in Headers */, + 80BB8A30141C3E6900F1753A /* quaternion.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80FF01D0141C3D980059E59D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8987141C3E5900F1753A /* Box2D.h in Headers */, + 80BB8989141C3E5900F1753A /* b2BroadPhase.h in Headers */, + 80BB898E141C3E5900F1753A /* b2Collision.h in Headers */, + 80BB8990141C3E5900F1753A /* b2Distance.h in Headers */, + 80BB8992141C3E5900F1753A /* b2DynamicTree.h in Headers */, + 80BB8994141C3E5900F1753A /* b2TimeOfImpact.h in Headers */, + 80BB8996141C3E5900F1753A /* b2ChainShape.h in Headers */, + 80BB8998141C3E5900F1753A /* b2CircleShape.h in Headers */, + 80BB899A141C3E5900F1753A /* b2EdgeShape.h in Headers */, + 80BB899C141C3E5900F1753A /* b2PolygonShape.h in Headers */, + 80BB899D141C3E5900F1753A /* b2Shape.h in Headers */, + 80BB899F141C3E5900F1753A /* b2BlockAllocator.h in Headers */, + 80BB89A1141C3E5900F1753A /* b2Draw.h in Headers */, + 80BB89A2141C3E5900F1753A /* b2GrowableStack.h in Headers */, + 80BB89A4141C3E5900F1753A /* b2Math.h in Headers */, + 80BB89A6141C3E5900F1753A /* b2Settings.h in Headers */, + 80BB89A8141C3E5900F1753A /* b2StackAllocator.h in Headers */, + 80BB89AA141C3E5900F1753A /* b2Timer.h in Headers */, + 80BB89AC141C3E5900F1753A /* b2Body.h in Headers */, + 80BB89AE141C3E5900F1753A /* b2ContactManager.h in Headers */, + 80BB89B0141C3E5900F1753A /* b2Fixture.h in Headers */, + 80BB89B2141C3E5900F1753A /* b2Island.h in Headers */, + 80BB89B3141C3E5900F1753A /* b2TimeStep.h in Headers */, + 80BB89B5141C3E5900F1753A /* b2World.h in Headers */, + 80BB89B7141C3E5900F1753A /* b2WorldCallbacks.h in Headers */, + 80BB89B9141C3E5900F1753A /* b2ChainAndCircleContact.h in Headers */, + 80BB89BB141C3E5900F1753A /* b2ChainAndPolygonContact.h in Headers */, + 80BB89BD141C3E5900F1753A /* b2CircleContact.h in Headers */, + 80BB89BF141C3E5900F1753A /* b2Contact.h in Headers */, + 80BB89C1141C3E5900F1753A /* b2ContactSolver.h in Headers */, + 80BB89C3141C3E5900F1753A /* b2EdgeAndCircleContact.h in Headers */, + 80BB89C5141C3E5900F1753A /* b2EdgeAndPolygonContact.h in Headers */, + 80BB89C7141C3E5900F1753A /* b2PolygonAndCircleContact.h in Headers */, + 80BB89C9141C3E5900F1753A /* b2PolygonContact.h in Headers */, + 80BB89CB141C3E5900F1753A /* b2DistanceJoint.h in Headers */, + 80BB89CD141C3E5900F1753A /* b2FrictionJoint.h in Headers */, + 80BB89CF141C3E5900F1753A /* b2GearJoint.h in Headers */, + 80BB89D1141C3E5900F1753A /* b2Joint.h in Headers */, + 80BB89D3141C3E5900F1753A /* b2MouseJoint.h in Headers */, + 80BB89D5141C3E5900F1753A /* b2PrismaticJoint.h in Headers */, + 80BB89D7141C3E5900F1753A /* b2PulleyJoint.h in Headers */, + 80BB89D9141C3E5900F1753A /* b2RevoluteJoint.h in Headers */, + 80BB89DB141C3E5900F1753A /* b2RopeJoint.h in Headers */, + 80BB89DD141C3E5900F1753A /* b2WeldJoint.h in Headers */, + 80BB89DF141C3E5900F1753A /* b2WheelJoint.h in Headers */, + 80BB89E1141C3E5900F1753A /* b2Rope.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 80BB8900141C3E1800F1753A /* GLUI */ = { + isa = PBXNativeTarget; + buildConfigurationList = 80BB8904141C3E1800F1753A /* Build configuration list for PBXNativeTarget "GLUI" */; + buildPhases = ( + 80BB88FD141C3E1800F1753A /* Sources */, + 80BB88FE141C3E1800F1753A /* Frameworks */, + 80BB88FF141C3E1800F1753A /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GLUI; + productName = GLUI; + productReference = 80BB8901141C3E1800F1753A /* libGLUI.a */; + productType = "com.apple.product-type.library.static"; + }; + 80BB8909141C3E2600F1753A /* HelloWorld */ = { + isa = PBXNativeTarget; + buildConfigurationList = 80BB8911141C3E2700F1753A /* Build configuration list for PBXNativeTarget "HelloWorld" */; + buildPhases = ( + 80BB8906141C3E2600F1753A /* Sources */, + 80BB8907141C3E2600F1753A /* Frameworks */, + 80BB8908141C3E2600F1753A /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 80BB8A70141C3EA100F1753A /* PBXTargetDependency */, + ); + name = HelloWorld; + productName = HelloWorld; + productReference = 80BB890A141C3E2700F1753A /* HelloWorld */; + productType = "com.apple.product-type.tool"; + }; + 80BB8917141C3E3600F1753A /* Testbed */ = { + isa = PBXNativeTarget; + buildConfigurationList = 80BB891F141C3E3600F1753A /* Build configuration list for PBXNativeTarget "Testbed" */; + buildPhases = ( + 80BB8914141C3E3600F1753A /* Sources */, + 80BB8915141C3E3600F1753A /* Frameworks */, + 80BB8916141C3E3600F1753A /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 80BB8A72141C3EA800F1753A /* PBXTargetDependency */, + 80BB8A74141C3EA800F1753A /* PBXTargetDependency */, + ); + name = Testbed; + productName = Testbed; + productReference = 80BB8918141C3E3600F1753A /* Testbed */; + productType = "com.apple.product-type.tool"; + }; + 80FF01D1141C3D980059E59D /* Box2D */ = { + isa = PBXNativeTarget; + buildConfigurationList = 80FF01D6141C3D980059E59D /* Build configuration list for PBXNativeTarget "Box2D" */; + buildPhases = ( + 80FF01CE141C3D980059E59D /* Sources */, + 80FF01CF141C3D980059E59D /* Frameworks */, + 80FF01D0141C3D980059E59D /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Box2D; + productName = Box2D; + productReference = 80FF01D2141C3D980059E59D /* libBox2D.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 80FF01C9141C3D980059E59D /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 80FF01CC141C3D980059E59D /* Build configuration list for PBXProject "Box2D" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 80FF01C7141C3D980059E59D; + productRefGroup = 80FF01D3141C3D980059E59D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 80FF01D1141C3D980059E59D /* Box2D */, + 80BB8900141C3E1800F1753A /* GLUI */, + 80BB8909141C3E2600F1753A /* HelloWorld */, + 80BB8917141C3E3600F1753A /* Testbed */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 80BB88FD141C3E1800F1753A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8A0B141C3E6900F1753A /* algebra3.cpp in Sources */, + 80BB8A0D141C3E6900F1753A /* arcball.cpp in Sources */, + 80BB8A0F141C3E6900F1753A /* glui.cpp in Sources */, + 80BB8A11141C3E6900F1753A /* glui_add_controls.cpp in Sources */, + 80BB8A12141C3E6900F1753A /* glui_bitmap_img_data.cpp in Sources */, + 80BB8A13141C3E6900F1753A /* glui_bitmaps.cpp in Sources */, + 80BB8A14141C3E6900F1753A /* glui_button.cpp in Sources */, + 80BB8A15141C3E6900F1753A /* glui_checkbox.cpp in Sources */, + 80BB8A16141C3E6900F1753A /* glui_column.cpp in Sources */, + 80BB8A17141C3E6900F1753A /* glui_commandline.cpp in Sources */, + 80BB8A18141C3E6900F1753A /* glui_control.cpp in Sources */, + 80BB8A19141C3E6900F1753A /* glui_edittext.cpp in Sources */, + 80BB8A1A141C3E6900F1753A /* glui_filebrowser.cpp in Sources */, + 80BB8A1D141C3E6900F1753A /* glui_list.cpp in Sources */, + 80BB8A1E141C3E6900F1753A /* glui_listbox.cpp in Sources */, + 80BB8A1F141C3E6900F1753A /* glui_mouse_iaction.cpp in Sources */, + 80BB8A20141C3E6900F1753A /* glui_node.cpp in Sources */, + 80BB8A21141C3E6900F1753A /* glui_panel.cpp in Sources */, + 80BB8A22141C3E6900F1753A /* glui_radio.cpp in Sources */, + 80BB8A23141C3E6900F1753A /* glui_rollout.cpp in Sources */, + 80BB8A24141C3E6900F1753A /* glui_rotation.cpp in Sources */, + 80BB8A25141C3E6900F1753A /* glui_scrollbar.cpp in Sources */, + 80BB8A26141C3E6900F1753A /* glui_separator.cpp in Sources */, + 80BB8A27141C3E6900F1753A /* glui_spinner.cpp in Sources */, + 80BB8A28141C3E6900F1753A /* glui_statictext.cpp in Sources */, + 80BB8A29141C3E6900F1753A /* glui_string.cpp in Sources */, + 80BB8A2A141C3E6900F1753A /* glui_textbox.cpp in Sources */, + 80BB8A2B141C3E6900F1753A /* glui_translation.cpp in Sources */, + 80BB8A2C141C3E6900F1753A /* glui_tree.cpp in Sources */, + 80BB8A2D141C3E6900F1753A /* glui_treepanel.cpp in Sources */, + 80BB8A2E141C3E6900F1753A /* glui_window.cpp in Sources */, + 80BB8A2F141C3E6900F1753A /* quaternion.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80BB8906141C3E2600F1753A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8A34141C3E7B00F1753A /* HelloWorld.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80BB8914141C3E3600F1753A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8A6B141C3E8600F1753A /* Main.cpp in Sources */, + 80BB8A6C141C3E8600F1753A /* Render.cpp in Sources */, + 80BB8A6D141C3E8600F1753A /* Test.cpp in Sources */, + 80BB8A6E141C3E8600F1753A /* TestEntries.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80FF01CE141C3D980059E59D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8988141C3E5900F1753A /* b2BroadPhase.cpp in Sources */, + 80BB898A141C3E5900F1753A /* b2CollideCircle.cpp in Sources */, + 80BB898B141C3E5900F1753A /* b2CollideEdge.cpp in Sources */, + 80BB898C141C3E5900F1753A /* b2CollidePolygon.cpp in Sources */, + 80BB898D141C3E5900F1753A /* b2Collision.cpp in Sources */, + 80BB898F141C3E5900F1753A /* b2Distance.cpp in Sources */, + 80BB8991141C3E5900F1753A /* b2DynamicTree.cpp in Sources */, + 80BB8993141C3E5900F1753A /* b2TimeOfImpact.cpp in Sources */, + 80BB8995141C3E5900F1753A /* b2ChainShape.cpp in Sources */, + 80BB8997141C3E5900F1753A /* b2CircleShape.cpp in Sources */, + 80BB8999141C3E5900F1753A /* b2EdgeShape.cpp in Sources */, + 80BB899B141C3E5900F1753A /* b2PolygonShape.cpp in Sources */, + 80BB899E141C3E5900F1753A /* b2BlockAllocator.cpp in Sources */, + 80BB89A0141C3E5900F1753A /* b2Draw.cpp in Sources */, + 80BB89A3141C3E5900F1753A /* b2Math.cpp in Sources */, + 80BB89A5141C3E5900F1753A /* b2Settings.cpp in Sources */, + 80BB89A7141C3E5900F1753A /* b2StackAllocator.cpp in Sources */, + 80BB89A9141C3E5900F1753A /* b2Timer.cpp in Sources */, + 80BB89AB141C3E5900F1753A /* b2Body.cpp in Sources */, + 80BB89AD141C3E5900F1753A /* b2ContactManager.cpp in Sources */, + 80BB89AF141C3E5900F1753A /* b2Fixture.cpp in Sources */, + 80BB89B1141C3E5900F1753A /* b2Island.cpp in Sources */, + 80BB89B4141C3E5900F1753A /* b2World.cpp in Sources */, + 80BB89B6141C3E5900F1753A /* b2WorldCallbacks.cpp in Sources */, + 80BB89B8141C3E5900F1753A /* b2ChainAndCircleContact.cpp in Sources */, + 80BB89BA141C3E5900F1753A /* b2ChainAndPolygonContact.cpp in Sources */, + 80BB89BC141C3E5900F1753A /* b2CircleContact.cpp in Sources */, + 80BB89BE141C3E5900F1753A /* b2Contact.cpp in Sources */, + 80BB89C0141C3E5900F1753A /* b2ContactSolver.cpp in Sources */, + 80BB89C2141C3E5900F1753A /* b2EdgeAndCircleContact.cpp in Sources */, + 80BB89C4141C3E5900F1753A /* b2EdgeAndPolygonContact.cpp in Sources */, + 80BB89C6141C3E5900F1753A /* b2PolygonAndCircleContact.cpp in Sources */, + 80BB89C8141C3E5900F1753A /* b2PolygonContact.cpp in Sources */, + 80BB89CA141C3E5900F1753A /* b2DistanceJoint.cpp in Sources */, + 80BB89CC141C3E5900F1753A /* b2FrictionJoint.cpp in Sources */, + 80BB89CE141C3E5900F1753A /* b2GearJoint.cpp in Sources */, + 80BB89D0141C3E5900F1753A /* b2Joint.cpp in Sources */, + 80BB89D2141C3E5900F1753A /* b2MouseJoint.cpp in Sources */, + 80BB89D4141C3E5900F1753A /* b2PrismaticJoint.cpp in Sources */, + 80BB89D6141C3E5900F1753A /* b2PulleyJoint.cpp in Sources */, + 80BB89D8141C3E5900F1753A /* b2RevoluteJoint.cpp in Sources */, + 80BB89DA141C3E5900F1753A /* b2RopeJoint.cpp in Sources */, + 80BB89DC141C3E5900F1753A /* b2WeldJoint.cpp in Sources */, + 80BB89DE141C3E5900F1753A /* b2WheelJoint.cpp in Sources */, + 80BB89E0141C3E5900F1753A /* b2Rope.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 80BB8A70141C3EA100F1753A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 80FF01D1141C3D980059E59D /* Box2D */; + targetProxy = 80BB8A6F141C3EA100F1753A /* PBXContainerItemProxy */; + }; + 80BB8A72141C3EA800F1753A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 80FF01D1141C3D980059E59D /* Box2D */; + targetProxy = 80BB8A71141C3EA800F1753A /* PBXContainerItemProxy */; + }; + 80BB8A74141C3EA800F1753A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 80BB8900141C3E1800F1753A /* GLUI */; + targetProxy = 80BB8A73141C3EA800F1753A /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 80BB8902141C3E1800F1753A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXECUTABLE_PREFIX = lib; + GCC_WARN_INHIBIT_ALL_WARNINGS = YES; + GCC_WARN_UNUSED_VALUE = NO; + GCC_WARN_UNUSED_VARIABLE = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 80BB8903141C3E1800F1753A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXECUTABLE_PREFIX = lib; + GCC_WARN_INHIBIT_ALL_WARNINGS = YES; + GCC_WARN_UNUSED_VALUE = NO; + GCC_WARN_UNUSED_VARIABLE = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 80BB8912141C3E2700F1753A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 80BB8913141C3E2700F1753A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 80BB8920141C3E3600F1753A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_UNUSED_VALUE = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 80BB8921141C3E3600F1753A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_UNUSED_VALUE = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 80FF01D4141C3D980059E59D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ../..; + MACOSX_DEPLOYMENT_TARGET = 10.7; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 80FF01D5141C3D980059E59D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ../..; + MACOSX_DEPLOYMENT_TARGET = 10.7; + SDKROOT = macosx; + }; + name = Release; + }; + 80FF01D7141C3D980059E59D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 80FF01D8141C3D980059E59D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 80BB8904141C3E1800F1753A /* Build configuration list for PBXNativeTarget "GLUI" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 80BB8902141C3E1800F1753A /* Debug */, + 80BB8903141C3E1800F1753A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 80BB8911141C3E2700F1753A /* Build configuration list for PBXNativeTarget "HelloWorld" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 80BB8912141C3E2700F1753A /* Debug */, + 80BB8913141C3E2700F1753A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 80BB891F141C3E3600F1753A /* Build configuration list for PBXNativeTarget "Testbed" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 80BB8920141C3E3600F1753A /* Debug */, + 80BB8921141C3E3600F1753A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 80FF01CC141C3D980059E59D /* Build configuration list for PBXProject "Box2D" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 80FF01D4141C3D980059E59D /* Debug */, + 80FF01D5141C3D980059E59D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 80FF01D6141C3D980059E59D /* Build configuration list for PBXNativeTarget "Box2D" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 80FF01D7141C3D980059E59D /* Debug */, + 80FF01D8141C3D980059E59D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 80FF01C9141C3D980059E59D /* Project object */; +} diff --git a/tests/Box2D_v2.2.1/Build/xcode4/Box2D.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/tests/Box2D_v2.2.1/Build/xcode4/Box2D.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 0000000000000..9641d88974171 --- /dev/null +++ b/tests/Box2D_v2.2.1/Build/xcode4/Box2D.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/tests/Box2D_v2.2.1/Building.txt b/tests/Box2D_v2.2.1/Building.txt new file mode 100755 index 0000000000000..fa3741f1f8734 --- /dev/null +++ b/tests/Box2D_v2.2.1/Building.txt @@ -0,0 +1,37 @@ +The Build folder contains custom made project files for Visual Studio 2010 and XCode4. + +For other platforms you need to run premake in this directory. You can get premake here: +http://industriousone.com/premake + +For example, on Linux, you would type: +premake4 gmake + +This will create a gmake folder in the Build directory. From there you can run: +make config="debug" + +If you have build problems, you can post a question here: +http://box2d.org/forum/viewforum.php?f=7 + +=============== OLD METHOD ==================== + +Box2D uses CMake to describe the build in a platform independent manner. + +First download and install cmake from cmake.org + +For Microsoft Visual Studio: +- Run the cmake-gui +- Set the source directory to the path of Box2D on your PC (the folder that contains this file). +- Set the build directory to be the path of Box2D/Build on your PC. +- Press the Configure button and select your version of Visual Studio. +- You may have to press the Configure button again. +- Press the Generate button. +- Open Box2D/Build/Box2D.sln. +- Set the Testbed or HelloWorld as your startup project. +- Press F5 or Ctrl-F5 to run. + +For Unix platforms, say the following on a terminal: (Replace $BOX2DPATH with the directory where this file is located.) + cd $BOX2DPATH/Build + cmake -DBOX2D_INSTALL=ON -DBOX2D_BUILD_SHARED=ON .. + make + make install +You might want to add -DCMAKE_INSTALL_PREFIX=/opt/Box2D or similar to the cmake call to change the installation location. make install might need sudo. diff --git a/tests/Box2D_v2.2.1/CMakeLists.txt b/tests/Box2D_v2.2.1/CMakeLists.txt new file mode 100755 index 0000000000000..a9dc06cbfbea4 --- /dev/null +++ b/tests/Box2D_v2.2.1/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 2.6) + +project(Box2D) + +if(UNIX) + set(BOX2D_INSTALL_BY_DEFAULT ON) +else(UNIX) + set(BOX2D_INSTALL_BY_DEFAULT OFF) +endif(UNIX) + +option(BOX2D_INSTALL "Install Box2D libs, includes, and CMake scripts" ${BOX2D_INSTALL_BY_DEFAULT}) +option(BOX2D_INSTALL_DOC "Install Box2D documentation" OFF) +option(BOX2D_BUILD_SHARED "Build Box2D shared libraries" OFF) +option(BOX2D_BUILD_STATIC "Build Box2D static libraries" ON) +option(BOX2D_BUILD_EXAMPLES "Build Box2D examples" ON) + +set(BOX2D_VERSION 2.1.0) + +# The Box2D library. +add_subdirectory(Box2D) + +if(BOX2D_BUILD_EXAMPLES) + # HelloWorld console example. + add_subdirectory(HelloWorld) + + # Testbed and dependencies. + find_package(OpenGL REQUIRED) + add_subdirectory(freeglut) + add_subdirectory(glui) + add_subdirectory(Testbed) +endif(BOX2D_BUILD_EXAMPLES) + +if(BOX2D_INSTALL_DOC) + install(DIRECTORY Documentation DESTINATION share/doc/Box2D PATTERN ".svn" EXCLUDE) +endif(BOX2D_INSTALL_DOC) \ No newline at end of file diff --git a/tests/Box2D_v2.2.1/HelloWorld/CMakeLists.txt b/tests/Box2D_v2.2.1/HelloWorld/CMakeLists.txt new file mode 100755 index 0000000000000..c6ae2b2fd45ef --- /dev/null +++ b/tests/Box2D_v2.2.1/HelloWorld/CMakeLists.txt @@ -0,0 +1,4 @@ +# Hello World examples +include_directories (${Box2D_SOURCE_DIR}) +add_executable(HelloWorld HelloWorld.cpp) +target_link_libraries (HelloWorld Box2D) diff --git a/tests/Box2D_v2.2.1/HelloWorld/HelloWorld.cpp b/tests/Box2D_v2.2.1/HelloWorld/HelloWorld.cpp new file mode 100755 index 0000000000000..b8e04384289a9 --- /dev/null +++ b/tests/Box2D_v2.2.1/HelloWorld/HelloWorld.cpp @@ -0,0 +1,106 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include + +#include +using namespace std; + +// This is a simple example of building and running a simulation +// using Box2D. Here we create a large ground box and a small dynamic +// box. +// There are no graphics for this example. Box2D is meant to be used +// with your rendering engine in your game engine. +int main(int argc, char** argv) +{ + B2_NOT_USED(argc); + B2_NOT_USED(argv); + + // Define the gravity vector. + b2Vec2 gravity(0.0f, -10.0f); + + // Construct a world object, which will hold and simulate the rigid bodies. + b2World world(gravity); + + // Define the ground body. + b2BodyDef groundBodyDef; + groundBodyDef.position.Set(0.0f, -10.0f); + + // Call the body factory which allocates memory for the ground body + // from a pool and creates the ground box shape (also from a pool). + // The body is also added to the world. + b2Body* groundBody = world.CreateBody(&groundBodyDef); + + // Define the ground box shape. + b2PolygonShape groundBox; + + // The extents are the half-widths of the box. + groundBox.SetAsBox(50.0f, 10.0f); + + // Add the ground fixture to the ground body. + groundBody->CreateFixture(&groundBox, 0.0f); + + // Define the dynamic body. We set its position and call the body factory. + b2BodyDef bodyDef; + bodyDef.type = b2_dynamicBody; + bodyDef.position.Set(0.0f, 4.0f); + b2Body* body = world.CreateBody(&bodyDef); + + // Define another box shape for our dynamic body. + b2PolygonShape dynamicBox; + dynamicBox.SetAsBox(1.0f, 1.0f); + + // Define the dynamic body fixture. + b2FixtureDef fixtureDef; + fixtureDef.shape = &dynamicBox; + + // Set the box density to be non-zero, so it will be dynamic. + fixtureDef.density = 1.0f; + + // Override the default friction. + fixtureDef.friction = 0.3f; + + // Add the shape to the body. + body->CreateFixture(&fixtureDef); + + // Prepare for simulation. Typically we use a time step of 1/60 of a + // second (60Hz) and 10 iterations. This provides a high quality simulation + // in most game scenarios. + float32 timeStep = 1.0f / 60.0f; + int32 velocityIterations = 6; + int32 positionIterations = 2; + + // This is our little game loop. + for (int32 i = 0; i < 60; ++i) + { + // Instruct the world to perform a single step of simulation. + // It is generally best to keep the time step and iterations fixed. + world.Step(timeStep, velocityIterations, positionIterations); + + // Now print the position and angle of the body. + b2Vec2 position = body->GetPosition(); + float32 angle = body->GetAngle(); + + printf("%4.2f %4.2f %4.2f\n", position.x, position.y, angle); + } + + // When the world destructor is called, all bodies and joints are freed. This can + // create orphaned pointers, so be careful about your world management. + + return 0; +} diff --git a/tests/Box2D_v2.2.1/License.txt b/tests/Box2D_v2.2.1/License.txt new file mode 100755 index 0000000000000..622772e5950ec --- /dev/null +++ b/tests/Box2D_v2.2.1/License.txt @@ -0,0 +1,18 @@ +Copyright (c) 2006-2010 Erin Catto http://www.gphysics.com + +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. + diff --git a/tests/Box2D_v2.2.1/Readme.txt b/tests/Box2D_v2.2.1/Readme.txt new file mode 100755 index 0000000000000..d97240a2bcc01 --- /dev/null +++ b/tests/Box2D_v2.2.1/Readme.txt @@ -0,0 +1,19 @@ +Box2D Version 2.1 + +Welcome to Box2D! + +Box2D is a 2D physics engine for games. + +For help with Box2D, please visit http://www.box2d.org. There is a forum there where you may post your questions. + +Please see Building.txt to learn how to build Box2D and run the testbed. + +To run the demos, set "Testbed" as your startup project and press F5. Some test bed commands are: +- 'r' to reset the current test +- SPACE to launch a bomb +- arrow keys to pan +- 'x' and 'z' to zoom in/out +- use the mouse to click and drag objects + +Erin Catto +http://www.box2d.org diff --git a/tests/Box2D_v2.2.1/Testbed/CMakeLists.txt b/tests/Box2D_v2.2.1/Testbed/CMakeLists.txt new file mode 100755 index 0000000000000..b030a4840ea1f --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/CMakeLists.txt @@ -0,0 +1,92 @@ +# Some flags for Freeglut and GLUI. +add_definitions( -DFREEGLUT_EXPORTS -DFREEGLUT_STATIC -D_CRT_SECURE_NO_WARNINGS ) + +# Define the framework files. +set(Testbed_Framework_SRCS + Framework/Main.cpp + Framework/Render.cpp + Framework/Render.h + Framework/Test.cpp + Framework/Test.h +) + +#define the test files. +set(Testbed_Tests_SRCS + Tests/TestEntries.cpp + Tests/AddPair.h + Tests/ApplyForce.h + Tests/BodyTypes.h + Tests/Breakable.h + Tests/Bridge.h + Tests/BulletTest.h + Tests/Cantilever.h + Tests/Car.h + Tests/Chain.h + Tests/CharacterCollision.h + Tests/CollisionFiltering.h + Tests/CollisionProcessing.h + Tests/CompoundShapes.h + Tests/Confined.h + Tests/ContinuousTest.h + Tests/DistanceTest.h + Tests/Dominos.h + Tests/DumpShell.h + Tests/DynamicTreeTest.h + Tests/EdgeShapes.h + Tests/EdgeTest.h + Tests/Gears.h + Tests/OneSidedPlatform.h + Tests/Pinball.h + Tests/PolyCollision.h + Tests/PolyShapes.h + Tests/Prismatic.h + Tests/Pulleys.h + Tests/Pyramid.h + Tests/RayCast.h + Tests/Revolute.h + Tests/Rope.h + Tests/RopeJoint.h + Tests/SensorTest.h + Tests/ShapeEditing.h + Tests/SliderCrank.h + Tests/SphereStack.h + Tests/TheoJansen.h + Tests/Tiles.h + Tests/TimeOfImpact.h + Tests/VaryingFriction.h + Tests/VaryingRestitution.h + Tests/VerticalStack.h + Tests/Web.h +) + +# These are used to create visual studio folders. +source_group(Framework FILES ${Testbed_Framework_SRCS}) +source_group(Tests FILES ${Testbed_Tests_SRCS}) + +include_directories ( + ${OPENGL_INCLUDE_DIR} + ${Box2D_SOURCE_DIR} +) + +if(APPLE) + # We are not using the Apple's framework version, but X11's + include_directories( /usr/X11/include ) + link_directories( /usr/X11/lib ) + set (OPENGL_LIBRARIES GL GLU GLUT X11) +elseif(WIN32) + set (ADDITIONAL_LIBRARIES winmm) +endif(APPLE) + +add_executable(Testbed + ${Testbed_Framework_SRCS} + ${Testbed_Tests_SRCS} +) + +target_link_libraries ( + Testbed + Box2D + freeglut_static + glui + ${ADDITIONAL_LIBRARIES} + ${OPENGL_LIBRARIES} +) diff --git a/tests/Box2D_v2.2.1/Testbed/Framework/Main.cpp b/tests/Box2D_v2.2.1/Testbed/Framework/Main.cpp new file mode 100755 index 0000000000000..048ed88690643 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Framework/Main.cpp @@ -0,0 +1,447 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include "Render.h" +#include "Test.h" +#include "glui/glui.h" + +#include +using namespace std; + +namespace +{ + int32 testIndex = 0; + int32 testSelection = 0; + int32 testCount = 0; + TestEntry* entry; + Test* test; + Settings settings; + int32 width = 640; + int32 height = 480; + int32 framePeriod = 16; + int32 mainWindow; + float settingsHz = 60.0; + GLUI *glui; + float32 viewZoom = 1.0f; + int tx, ty, tw, th; + bool rMouseDown; + b2Vec2 lastp; +} + +static void Resize(int32 w, int32 h) +{ + width = w; + height = h; + + GLUI_Master.get_viewport_area(&tx, &ty, &tw, &th); + glViewport(tx, ty, tw, th); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + float32 ratio = float32(tw) / float32(th); + + b2Vec2 extents(ratio * 25.0f, 25.0f); + extents *= viewZoom; + + b2Vec2 lower = settings.viewCenter - extents; + b2Vec2 upper = settings.viewCenter + extents; + + // L/R/B/T + gluOrtho2D(lower.x, upper.x, lower.y, upper.y); +} + +static b2Vec2 ConvertScreenToWorld(int32 x, int32 y) +{ + float32 u = x / float32(tw); + float32 v = (th - y) / float32(th); + + float32 ratio = float32(tw) / float32(th); + b2Vec2 extents(ratio * 25.0f, 25.0f); + extents *= viewZoom; + + b2Vec2 lower = settings.viewCenter - extents; + b2Vec2 upper = settings.viewCenter + extents; + + b2Vec2 p; + p.x = (1.0f - u) * lower.x + u * upper.x; + p.y = (1.0f - v) * lower.y + v * upper.y; + return p; +} + +// This is used to control the frame rate (60Hz). +static void Timer(int) +{ + glutSetWindow(mainWindow); + glutPostRedisplay(); + glutTimerFunc(framePeriod, Timer, 0); +} + +static void SimulationLoop() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + test->SetTextLine(30); + b2Vec2 oldCenter = settings.viewCenter; + settings.hz = settingsHz; + test->Step(&settings); + if (oldCenter.x != settings.viewCenter.x || oldCenter.y != settings.viewCenter.y) + { + Resize(width, height); + } + + test->DrawTitle(5, 15, entry->name); + + glutSwapBuffers(); + + if (testSelection != testIndex) + { + testIndex = testSelection; + delete test; + entry = g_testEntries + testIndex; + test = entry->createFcn(); + viewZoom = 1.0f; + settings.viewCenter.Set(0.0f, 20.0f); + Resize(width, height); + } +} + +static void Keyboard(unsigned char key, int x, int y) +{ + B2_NOT_USED(x); + B2_NOT_USED(y); + + switch (key) + { + case 27: +#ifndef __APPLE__ + // freeglut specific function + glutLeaveMainLoop(); +#endif + exit(0); + break; + + // Press 'z' to zoom out. + case 'z': + viewZoom = b2Min(1.1f * viewZoom, 20.0f); + Resize(width, height); + break; + + // Press 'x' to zoom in. + case 'x': + viewZoom = b2Max(0.9f * viewZoom, 0.02f); + Resize(width, height); + break; + + // Press 'r' to reset. + case 'r': + delete test; + test = entry->createFcn(); + break; + + // Press space to launch a bomb. + case ' ': + if (test) + { + test->LaunchBomb(); + } + break; + + case 'p': + settings.pause = !settings.pause; + break; + + // Press [ to prev test. + case '[': + --testSelection; + if (testSelection < 0) + { + testSelection = testCount - 1; + } + glui->sync_live(); + break; + + // Press ] to next test. + case ']': + ++testSelection; + if (testSelection == testCount) + { + testSelection = 0; + } + glui->sync_live(); + break; + + default: + if (test) + { + test->Keyboard(key); + } + } +} + +static void KeyboardSpecial(int key, int x, int y) +{ + B2_NOT_USED(x); + B2_NOT_USED(y); + + switch (key) + { + case GLUT_ACTIVE_SHIFT: + // Press left to pan left. + case GLUT_KEY_LEFT: + settings.viewCenter.x -= 0.5f; + Resize(width, height); + break; + + // Press right to pan right. + case GLUT_KEY_RIGHT: + settings.viewCenter.x += 0.5f; + Resize(width, height); + break; + + // Press down to pan down. + case GLUT_KEY_DOWN: + settings.viewCenter.y -= 0.5f; + Resize(width, height); + break; + + // Press up to pan up. + case GLUT_KEY_UP: + settings.viewCenter.y += 0.5f; + Resize(width, height); + break; + + // Press home to reset the view. + case GLUT_KEY_HOME: + viewZoom = 1.0f; + settings.viewCenter.Set(0.0f, 20.0f); + Resize(width, height); + break; + } +} + +static void KeyboardUp(unsigned char key, int x, int y) +{ + B2_NOT_USED(x); + B2_NOT_USED(y); + + if (test) + { + test->KeyboardUp(key); + } +} + +static void Mouse(int32 button, int32 state, int32 x, int32 y) +{ + // Use the mouse to move things around. + if (button == GLUT_LEFT_BUTTON) + { + int mod = glutGetModifiers(); + b2Vec2 p = ConvertScreenToWorld(x, y); + if (state == GLUT_DOWN) + { + b2Vec2 p = ConvertScreenToWorld(x, y); + if (mod == GLUT_ACTIVE_SHIFT) + { + test->ShiftMouseDown(p); + } + else + { + test->MouseDown(p); + } + } + + if (state == GLUT_UP) + { + test->MouseUp(p); + } + } + else if (button == GLUT_RIGHT_BUTTON) + { + if (state == GLUT_DOWN) + { + lastp = ConvertScreenToWorld(x, y); + rMouseDown = true; + } + + if (state == GLUT_UP) + { + rMouseDown = false; + } + } +} + +static void MouseMotion(int32 x, int32 y) +{ + b2Vec2 p = ConvertScreenToWorld(x, y); + test->MouseMove(p); + + if (rMouseDown) + { + b2Vec2 diff = p - lastp; + settings.viewCenter.x -= diff.x; + settings.viewCenter.y -= diff.y; + Resize(width, height); + lastp = ConvertScreenToWorld(x, y); + } +} + +static void MouseWheel(int wheel, int direction, int x, int y) +{ + B2_NOT_USED(wheel); + B2_NOT_USED(x); + B2_NOT_USED(y); + if (direction > 0) + { + viewZoom /= 1.1f; + } + else + { + viewZoom *= 1.1f; + } + Resize(width, height); +} + +static void Restart(int) +{ + delete test; + entry = g_testEntries + testIndex; + test = entry->createFcn(); + Resize(width, height); +} + +static void Pause(int) +{ + settings.pause = !settings.pause; +} + +static void Exit(int code) +{ + // TODO: freeglut is not building on OSX +#ifdef FREEGLUT + glutLeaveMainLoop(); +#endif + exit(code); +} + +static void SingleStep(int) +{ + settings.pause = 1; + settings.singleStep = 1; +} + +int main(int argc, char** argv) +{ + testCount = 0; + while (g_testEntries[testCount].createFcn != NULL) + { + ++testCount; + } + + testIndex = b2Clamp(testIndex, 0, testCount-1); + testSelection = testIndex; + + entry = g_testEntries + testIndex; + test = entry->createFcn(); + + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); + glutInitWindowSize(width, height); + char title[32]; + sprintf(title, "Box2D Version %d.%d.%d", b2_version.major, b2_version.minor, b2_version.revision); + mainWindow = glutCreateWindow(title); + //glutSetOption (GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS); + + glutDisplayFunc(SimulationLoop); + GLUI_Master.set_glutReshapeFunc(Resize); + GLUI_Master.set_glutKeyboardFunc(Keyboard); + GLUI_Master.set_glutSpecialFunc(KeyboardSpecial); + GLUI_Master.set_glutMouseFunc(Mouse); +#ifdef FREEGLUT + glutMouseWheelFunc(MouseWheel); +#endif + glutMotionFunc(MouseMotion); + + glutKeyboardUpFunc(KeyboardUp); + + glui = GLUI_Master.create_glui_subwindow( mainWindow, + GLUI_SUBWINDOW_RIGHT ); + + glui->add_statictext("Tests"); + GLUI_Listbox* testList = + glui->add_listbox("", &testSelection); + + glui->add_separator(); + + GLUI_Spinner* velocityIterationSpinner = + glui->add_spinner("Vel Iters", GLUI_SPINNER_INT, &settings.velocityIterations); + velocityIterationSpinner->set_int_limits(1, 500); + + GLUI_Spinner* positionIterationSpinner = + glui->add_spinner("Pos Iters", GLUI_SPINNER_INT, &settings.positionIterations); + positionIterationSpinner->set_int_limits(0, 100); + + GLUI_Spinner* hertzSpinner = + glui->add_spinner("Hertz", GLUI_SPINNER_FLOAT, &settingsHz); + + hertzSpinner->set_float_limits(5.0f, 200.0f); + + glui->add_checkbox("Warm Starting", &settings.enableWarmStarting); + glui->add_checkbox("Time of Impact", &settings.enableContinuous); + glui->add_checkbox("Sub-Stepping", &settings.enableSubStepping); + + //glui->add_separator(); + + GLUI_Panel* drawPanel = glui->add_panel("Draw"); + glui->add_checkbox_to_panel(drawPanel, "Shapes", &settings.drawShapes); + glui->add_checkbox_to_panel(drawPanel, "Joints", &settings.drawJoints); + glui->add_checkbox_to_panel(drawPanel, "AABBs", &settings.drawAABBs); + glui->add_checkbox_to_panel(drawPanel, "Pairs", &settings.drawPairs); + glui->add_checkbox_to_panel(drawPanel, "Contact Points", &settings.drawContactPoints); + glui->add_checkbox_to_panel(drawPanel, "Contact Normals", &settings.drawContactNormals); + glui->add_checkbox_to_panel(drawPanel, "Contact Forces", &settings.drawContactForces); + glui->add_checkbox_to_panel(drawPanel, "Friction Forces", &settings.drawFrictionForces); + glui->add_checkbox_to_panel(drawPanel, "Center of Masses", &settings.drawCOMs); + glui->add_checkbox_to_panel(drawPanel, "Statistics", &settings.drawStats); + glui->add_checkbox_to_panel(drawPanel, "Profile", &settings.drawProfile); + + int32 testCount = 0; + TestEntry* e = g_testEntries; + while (e->createFcn) + { + testList->add_item(testCount, e->name); + ++testCount; + ++e; + } + + glui->add_button("Pause", 0, Pause); + glui->add_button("Single Step", 0, SingleStep); + glui->add_button("Restart", 0, Restart); + + glui->add_button("Quit", 0,(GLUI_Update_CB)Exit); + glui->set_main_gfx_window( mainWindow ); + + // Use a timer to control the frame rate. + glutTimerFunc(framePeriod, Timer, 0); + + glutMainLoop(); + + return 0; +} diff --git a/tests/Box2D_v2.2.1/Testbed/Framework/Render.cpp b/tests/Box2D_v2.2.1/Testbed/Framework/Render.cpp new file mode 100755 index 0000000000000..0533479c357d5 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Framework/Render.cpp @@ -0,0 +1,197 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include "Render.h" + +#ifdef __APPLE__ + #include +#else + #include "freeglut/freeglut.h" +#endif + +#include +#include +#include +using namespace std; + +void DebugDraw::DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) +{ + glColor3f(color.r, color.g, color.b); + glBegin(GL_LINE_LOOP); + for (int32 i = 0; i < vertexCount; ++i) + { + glVertex2f(vertices[i].x, vertices[i].y); + } + glEnd(); +} + +void DebugDraw::DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) +{ + glEnable(GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glColor4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f); + glBegin(GL_TRIANGLE_FAN); + for (int32 i = 0; i < vertexCount; ++i) + { + glVertex2f(vertices[i].x, vertices[i].y); + } + glEnd(); + glDisable(GL_BLEND); + + glColor4f(color.r, color.g, color.b, 1.0f); + glBegin(GL_LINE_LOOP); + for (int32 i = 0; i < vertexCount; ++i) + { + glVertex2f(vertices[i].x, vertices[i].y); + } + glEnd(); +} + +void DebugDraw::DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) +{ + const float32 k_segments = 16.0f; + const float32 k_increment = 2.0f * b2_pi / k_segments; + float32 theta = 0.0f; + glColor3f(color.r, color.g, color.b); + glBegin(GL_LINE_LOOP); + for (int32 i = 0; i < k_segments; ++i) + { + b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta)); + glVertex2f(v.x, v.y); + theta += k_increment; + } + glEnd(); +} + +void DebugDraw::DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) +{ + const float32 k_segments = 16.0f; + const float32 k_increment = 2.0f * b2_pi / k_segments; + float32 theta = 0.0f; + glEnable(GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glColor4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f); + glBegin(GL_TRIANGLE_FAN); + for (int32 i = 0; i < k_segments; ++i) + { + b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta)); + glVertex2f(v.x, v.y); + theta += k_increment; + } + glEnd(); + glDisable(GL_BLEND); + + theta = 0.0f; + glColor4f(color.r, color.g, color.b, 1.0f); + glBegin(GL_LINE_LOOP); + for (int32 i = 0; i < k_segments; ++i) + { + b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta)); + glVertex2f(v.x, v.y); + theta += k_increment; + } + glEnd(); + + b2Vec2 p = center + radius * axis; + glBegin(GL_LINES); + glVertex2f(center.x, center.y); + glVertex2f(p.x, p.y); + glEnd(); +} + +void DebugDraw::DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) +{ + glColor3f(color.r, color.g, color.b); + glBegin(GL_LINES); + glVertex2f(p1.x, p1.y); + glVertex2f(p2.x, p2.y); + glEnd(); +} + +void DebugDraw::DrawTransform(const b2Transform& xf) +{ + b2Vec2 p1 = xf.p, p2; + const float32 k_axisScale = 0.4f; + glBegin(GL_LINES); + + glColor3f(1.0f, 0.0f, 0.0f); + glVertex2f(p1.x, p1.y); + p2 = p1 + k_axisScale * xf.q.GetXAxis(); + glVertex2f(p2.x, p2.y); + + glColor3f(0.0f, 1.0f, 0.0f); + glVertex2f(p1.x, p1.y); + p2 = p1 + k_axisScale * xf.q.GetYAxis(); + glVertex2f(p2.x, p2.y); + + glEnd(); +} + +void DebugDraw::DrawPoint(const b2Vec2& p, float32 size, const b2Color& color) +{ + glPointSize(size); + glBegin(GL_POINTS); + glColor3f(color.r, color.g, color.b); + glVertex2f(p.x, p.y); + glEnd(); + glPointSize(1.0f); +} + +void DebugDraw::DrawString(int x, int y, const char *string, ...) +{ + char buffer[128]; + + va_list arg; + va_start(arg, string); + vsprintf(buffer, string, arg); + va_end(arg); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + int w = glutGet(GLUT_WINDOW_WIDTH); + int h = glutGet(GLUT_WINDOW_HEIGHT); + gluOrtho2D(0, w, h, 0); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glColor3f(0.9f, 0.6f, 0.6f); + glRasterPos2i(x, y); + int32 length = (int32)strlen(buffer); + for (int32 i = 0; i < length; ++i) + { + glutBitmapCharacter(GLUT_BITMAP_8_BY_13, buffer[i]); + } + + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); +} + +void DebugDraw::DrawAABB(b2AABB* aabb, const b2Color& c) +{ + glColor3f(c.r, c.g, c.b); + glBegin(GL_LINE_LOOP); + glVertex2f(aabb->lowerBound.x, aabb->lowerBound.y); + glVertex2f(aabb->upperBound.x, aabb->lowerBound.y); + glVertex2f(aabb->upperBound.x, aabb->upperBound.y); + glVertex2f(aabb->lowerBound.x, aabb->upperBound.y); + glEnd(); +} diff --git a/tests/Box2D_v2.2.1/Testbed/Framework/Render.h b/tests/Box2D_v2.2.1/Testbed/Framework/Render.h new file mode 100755 index 0000000000000..a1d0e88104aee --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Framework/Render.h @@ -0,0 +1,51 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef RENDER_H +#define RENDER_H + +#include + +struct b2AABB; + +// This class implements debug drawing callbacks that are invoked +// inside b2World::Step. +class DebugDraw : public b2Draw +{ +public: + void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color); + + void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color); + + void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color); + + void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color); + + void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color); + + void DrawTransform(const b2Transform& xf); + + void DrawPoint(const b2Vec2& p, float32 size, const b2Color& color); + + void DrawString(int x, int y, const char* string, ...); + + void DrawAABB(b2AABB* aabb, const b2Color& color); +}; + + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Framework/Test.cpp b/tests/Box2D_v2.2.1/Testbed/Framework/Test.cpp new file mode 100755 index 0000000000000..3c5b4ad889195 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Framework/Test.cpp @@ -0,0 +1,447 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include "Test.h" +#include +using namespace std; + +void DestructionListener::SayGoodbye(b2Joint* joint) +{ + if (test->m_mouseJoint == joint) + { + test->m_mouseJoint = NULL; + } + else + { + test->JointDestroyed(joint); + } +} + +Test::Test() +{ + b2Vec2 gravity; + gravity.Set(0.0f, -10.0f); + m_world = new b2World(gravity); + m_bomb = NULL; + m_textLine = 30; + m_mouseJoint = NULL; + m_pointCount = 0; + + m_destructionListener.test = this; + m_world->SetDestructionListener(&m_destructionListener); + m_world->SetContactListener(this); + m_world->SetDebugDraw(&m_debugDraw); + + m_bombSpawning = false; + + m_stepCount = 0; + + b2BodyDef bodyDef; + m_groundBody = m_world->CreateBody(&bodyDef); + + memset(&m_maxProfile, 0, sizeof(b2Profile)); + memset(&m_totalProfile, 0, sizeof(b2Profile)); +} + +Test::~Test() +{ + // By deleting the world, we delete the bomb, mouse joint, etc. + delete m_world; + m_world = NULL; +} + +void Test::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) +{ + const b2Manifold* manifold = contact->GetManifold(); + + if (manifold->pointCount == 0) + { + return; + } + + b2Fixture* fixtureA = contact->GetFixtureA(); + b2Fixture* fixtureB = contact->GetFixtureB(); + + b2PointState state1[b2_maxManifoldPoints], state2[b2_maxManifoldPoints]; + b2GetPointStates(state1, state2, oldManifold, manifold); + + b2WorldManifold worldManifold; + contact->GetWorldManifold(&worldManifold); + + for (int32 i = 0; i < manifold->pointCount && m_pointCount < k_maxContactPoints; ++i) + { + ContactPoint* cp = m_points + m_pointCount; + cp->fixtureA = fixtureA; + cp->fixtureB = fixtureB; + cp->position = worldManifold.points[i]; + cp->normal = worldManifold.normal; + cp->state = state2[i]; + ++m_pointCount; + } +} + +void Test::DrawTitle(int x, int y, const char *string) +{ + m_debugDraw.DrawString(x, y, string); +} + +class QueryCallback : public b2QueryCallback +{ +public: + QueryCallback(const b2Vec2& point) + { + m_point = point; + m_fixture = NULL; + } + + bool ReportFixture(b2Fixture* fixture) + { + b2Body* body = fixture->GetBody(); + if (body->GetType() == b2_dynamicBody) + { + bool inside = fixture->TestPoint(m_point); + if (inside) + { + m_fixture = fixture; + + // We are done, terminate the query. + return false; + } + } + + // Continue the query. + return true; + } + + b2Vec2 m_point; + b2Fixture* m_fixture; +}; + +void Test::MouseDown(const b2Vec2& p) +{ + m_mouseWorld = p; + + if (m_mouseJoint != NULL) + { + return; + } + + // Make a small box. + b2AABB aabb; + b2Vec2 d; + d.Set(0.001f, 0.001f); + aabb.lowerBound = p - d; + aabb.upperBound = p + d; + + // Query the world for overlapping shapes. + QueryCallback callback(p); + m_world->QueryAABB(&callback, aabb); + + if (callback.m_fixture) + { + b2Body* body = callback.m_fixture->GetBody(); + b2MouseJointDef md; + md.bodyA = m_groundBody; + md.bodyB = body; + md.target = p; + md.maxForce = 1000.0f * body->GetMass(); + m_mouseJoint = (b2MouseJoint*)m_world->CreateJoint(&md); + body->SetAwake(true); + } +} + +void Test::SpawnBomb(const b2Vec2& worldPt) +{ + m_bombSpawnPoint = worldPt; + m_bombSpawning = true; +} + +void Test::CompleteBombSpawn(const b2Vec2& p) +{ + if (m_bombSpawning == false) + { + return; + } + + const float multiplier = 30.0f; + b2Vec2 vel = m_bombSpawnPoint - p; + vel *= multiplier; + LaunchBomb(m_bombSpawnPoint,vel); + m_bombSpawning = false; +} + +void Test::ShiftMouseDown(const b2Vec2& p) +{ + m_mouseWorld = p; + + if (m_mouseJoint != NULL) + { + return; + } + + SpawnBomb(p); +} + +void Test::MouseUp(const b2Vec2& p) +{ + if (m_mouseJoint) + { + m_world->DestroyJoint(m_mouseJoint); + m_mouseJoint = NULL; + } + + if (m_bombSpawning) + { + CompleteBombSpawn(p); + } +} + +void Test::MouseMove(const b2Vec2& p) +{ + m_mouseWorld = p; + + if (m_mouseJoint) + { + m_mouseJoint->SetTarget(p); + } +} + +void Test::LaunchBomb() +{ + b2Vec2 p(RandomFloat(-15.0f, 15.0f), 30.0f); + b2Vec2 v = -5.0f * p; + LaunchBomb(p, v); +} + +void Test::LaunchBomb(const b2Vec2& position, const b2Vec2& velocity) +{ + if (m_bomb) + { + m_world->DestroyBody(m_bomb); + m_bomb = NULL; + } + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position = position; + bd.bullet = true; + m_bomb = m_world->CreateBody(&bd); + m_bomb->SetLinearVelocity(velocity); + + b2CircleShape circle; + circle.m_radius = 0.3f; + + b2FixtureDef fd; + fd.shape = &circle; + fd.density = 20.0f; + fd.restitution = 0.0f; + + b2Vec2 minV = position - b2Vec2(0.3f,0.3f); + b2Vec2 maxV = position + b2Vec2(0.3f,0.3f); + + b2AABB aabb; + aabb.lowerBound = minV; + aabb.upperBound = maxV; + + m_bomb->CreateFixture(&fd); +} + +void Test::Step(Settings* settings) +{ + float32 timeStep = settings->hz > 0.0f ? 1.0f / settings->hz : float32(0.0f); + + if (settings->pause) + { + if (settings->singleStep) + { + settings->singleStep = 0; + } + else + { + timeStep = 0.0f; + } + + m_debugDraw.DrawString(5, m_textLine, "****PAUSED****"); + m_textLine += 15; + } + + uint32 flags = 0; + flags += settings->drawShapes * b2Draw::e_shapeBit; + flags += settings->drawJoints * b2Draw::e_jointBit; + flags += settings->drawAABBs * b2Draw::e_aabbBit; + flags += settings->drawPairs * b2Draw::e_pairBit; + flags += settings->drawCOMs * b2Draw::e_centerOfMassBit; + m_debugDraw.SetFlags(flags); + + m_world->SetWarmStarting(settings->enableWarmStarting > 0); + m_world->SetContinuousPhysics(settings->enableContinuous > 0); + m_world->SetSubStepping(settings->enableSubStepping > 0); + + m_pointCount = 0; + + m_world->Step(timeStep, settings->velocityIterations, settings->positionIterations); + + m_world->DrawDebugData(); + + if (timeStep > 0.0f) + { + ++m_stepCount; + } + + if (settings->drawStats) + { + int32 bodyCount = m_world->GetBodyCount(); + int32 contactCount = m_world->GetContactCount(); + int32 jointCount = m_world->GetJointCount(); + m_debugDraw.DrawString(5, m_textLine, "bodies/contacts/joints = %d/%d/%d", bodyCount, contactCount, jointCount); + m_textLine += 15; + + int32 proxyCount = m_world->GetProxyCount(); + int32 height = m_world->GetTreeHeight(); + int32 balance = m_world->GetTreeBalance(); + float32 quality = m_world->GetTreeQuality(); + m_debugDraw.DrawString(5, m_textLine, "proxies/height/balance/quality = %d/%d/%d/%g", proxyCount, height, balance, quality); + m_textLine += 15; + } + + // Track maximum profile times + { + const b2Profile& p = m_world->GetProfile(); + m_maxProfile.step = b2Max(m_maxProfile.step, p.step); + m_maxProfile.collide = b2Max(m_maxProfile.collide, p.collide); + m_maxProfile.solve = b2Max(m_maxProfile.solve, p.solve); + m_maxProfile.solveInit = b2Max(m_maxProfile.solveInit, p.solveInit); + m_maxProfile.solveVelocity = b2Max(m_maxProfile.solveVelocity, p.solveVelocity); + m_maxProfile.solvePosition = b2Max(m_maxProfile.solvePosition, p.solvePosition); + m_maxProfile.solveTOI = b2Max(m_maxProfile.solveTOI, p.solveTOI); + m_maxProfile.broadphase = b2Max(m_maxProfile.broadphase, p.broadphase); + + m_totalProfile.step += p.step; + m_totalProfile.collide += p.collide; + m_totalProfile.solve += p.solve; + m_totalProfile.solveInit += p.solveInit; + m_totalProfile.solveVelocity += p.solveVelocity; + m_totalProfile.solvePosition += p.solvePosition; + m_totalProfile.solveTOI += p.solveTOI; + m_totalProfile.broadphase += p.broadphase; + } + + if (settings->drawProfile) + { + const b2Profile& p = m_world->GetProfile(); + + b2Profile aveProfile; + memset(&aveProfile, 0, sizeof(b2Profile)); + if (m_stepCount > 0) + { + float32 scale = 1.0f / m_stepCount; + aveProfile.step = scale * m_totalProfile.step; + aveProfile.collide = scale * m_totalProfile.collide; + aveProfile.solve = scale * m_totalProfile.solve; + aveProfile.solveInit = scale * m_totalProfile.solveInit; + aveProfile.solveVelocity = scale * m_totalProfile.solveVelocity; + aveProfile.solvePosition = scale * m_totalProfile.solvePosition; + aveProfile.solveTOI = scale * m_totalProfile.solveTOI; + aveProfile.broadphase = scale * m_totalProfile.broadphase; + } + + m_debugDraw.DrawString(5, m_textLine, "step [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.step, aveProfile.step, m_maxProfile.step); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "collide [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.collide, aveProfile.collide, m_maxProfile.collide); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "solve [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solve, aveProfile.solve, m_maxProfile.solve); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "solve init [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solveInit, aveProfile.solveInit, m_maxProfile.solveInit); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "solve velocity [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solveVelocity, aveProfile.solveVelocity, m_maxProfile.solveVelocity); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "solve position [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solvePosition, aveProfile.solvePosition, m_maxProfile.solvePosition); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "solveTOI [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solveTOI, aveProfile.solveTOI, m_maxProfile.solveTOI); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "broad-phase [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.broadphase, aveProfile.broadphase, m_maxProfile.broadphase); + m_textLine += 15; + } + + if (m_mouseJoint) + { + b2Vec2 p1 = m_mouseJoint->GetAnchorB(); + b2Vec2 p2 = m_mouseJoint->GetTarget(); + + b2Color c; + c.Set(0.0f, 1.0f, 0.0f); + m_debugDraw.DrawPoint(p1, 4.0f, c); + m_debugDraw.DrawPoint(p2, 4.0f, c); + + c.Set(0.8f, 0.8f, 0.8f); + m_debugDraw.DrawSegment(p1, p2, c); + } + + if (m_bombSpawning) + { + b2Color c; + c.Set(0.0f, 0.0f, 1.0f); + m_debugDraw.DrawPoint(m_bombSpawnPoint, 4.0f, c); + + c.Set(0.8f, 0.8f, 0.8f); + m_debugDraw.DrawSegment(m_mouseWorld, m_bombSpawnPoint, c); + } + + if (settings->drawContactPoints) + { + //const float32 k_impulseScale = 0.1f; + const float32 k_axisScale = 0.3f; + + for (int32 i = 0; i < m_pointCount; ++i) + { + ContactPoint* point = m_points + i; + + if (point->state == b2_addState) + { + // Add + m_debugDraw.DrawPoint(point->position, 10.0f, b2Color(0.3f, 0.95f, 0.3f)); + } + else if (point->state == b2_persistState) + { + // Persist + m_debugDraw.DrawPoint(point->position, 5.0f, b2Color(0.3f, 0.3f, 0.95f)); + } + + if (settings->drawContactNormals == 1) + { + b2Vec2 p1 = point->position; + b2Vec2 p2 = p1 + k_axisScale * point->normal; + m_debugDraw.DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.9f)); + } + else if (settings->drawContactForces == 1) + { + //b2Vec2 p1 = point->position; + //b2Vec2 p2 = p1 + k_forceScale * point->normalForce * point->normal; + //DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.3f)); + } + + if (settings->drawFrictionForces == 1) + { + //b2Vec2 tangent = b2Cross(point->normal, 1.0f); + //b2Vec2 p1 = point->position; + //b2Vec2 p2 = p1 + k_forceScale * point->tangentForce * tangent; + //DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.3f)); + } + } + } +} diff --git a/tests/Box2D_v2.2.1/Testbed/Framework/Test.h b/tests/Box2D_v2.2.1/Testbed/Framework/Test.h new file mode 100755 index 0000000000000..71e3b46ea709a --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Framework/Test.h @@ -0,0 +1,189 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef TEST_H +#define TEST_H + +#include +#include "Render.h" + +#include + +class Test; +struct Settings; + +typedef Test* TestCreateFcn(); + +#define RAND_LIMIT 32767 + +/// Random number in range [-1,1] +inline float32 RandomFloat() +{ + float32 r = (float32)(std::rand() & (RAND_LIMIT)); + r /= RAND_LIMIT; + r = 2.0f * r - 1.0f; + return r; +} + +/// Random floating point number in range [lo, hi] +inline float32 RandomFloat(float32 lo, float32 hi) +{ + float32 r = (float32)(std::rand() & (RAND_LIMIT)); + r /= RAND_LIMIT; + r = (hi - lo) * r + lo; + return r; +} + +/// Test settings. Some can be controlled in the GUI. +struct Settings +{ + Settings() : + viewCenter(0.0f, 20.0f), + hz(60.0f), + velocityIterations(8), + positionIterations(3), + drawShapes(1), + drawJoints(1), + drawAABBs(0), + drawPairs(0), + drawContactPoints(0), + drawContactNormals(0), + drawContactForces(0), + drawFrictionForces(0), + drawCOMs(0), + drawStats(0), + drawProfile(0), + enableWarmStarting(1), + enableContinuous(1), + enableSubStepping(0), + pause(0), + singleStep(0) + {} + + b2Vec2 viewCenter; + float32 hz; + int32 velocityIterations; + int32 positionIterations; + int32 drawShapes; + int32 drawJoints; + int32 drawAABBs; + int32 drawPairs; + int32 drawContactPoints; + int32 drawContactNormals; + int32 drawContactForces; + int32 drawFrictionForces; + int32 drawCOMs; + int32 drawStats; + int32 drawProfile; + int32 enableWarmStarting; + int32 enableContinuous; + int32 enableSubStepping; + int32 pause; + int32 singleStep; +}; + +struct TestEntry +{ + const char *name; + TestCreateFcn *createFcn; +}; + +extern TestEntry g_testEntries[]; +// This is called when a joint in the world is implicitly destroyed +// because an attached body is destroyed. This gives us a chance to +// nullify the mouse joint. +class DestructionListener : public b2DestructionListener +{ +public: + void SayGoodbye(b2Fixture* fixture) { B2_NOT_USED(fixture); } + void SayGoodbye(b2Joint* joint); + + Test* test; +}; + +const int32 k_maxContactPoints = 2048; + +struct ContactPoint +{ + b2Fixture* fixtureA; + b2Fixture* fixtureB; + b2Vec2 normal; + b2Vec2 position; + b2PointState state; +}; + +class Test : public b2ContactListener +{ +public: + + Test(); + virtual ~Test(); + + void SetTextLine(int32 line) { m_textLine = line; } + void DrawTitle(int x, int y, const char *string); + virtual void Step(Settings* settings); + virtual void Keyboard(unsigned char key) { B2_NOT_USED(key); } + virtual void KeyboardUp(unsigned char key) { B2_NOT_USED(key); } + void ShiftMouseDown(const b2Vec2& p); + virtual void MouseDown(const b2Vec2& p); + virtual void MouseUp(const b2Vec2& p); + void MouseMove(const b2Vec2& p); + void LaunchBomb(); + void LaunchBomb(const b2Vec2& position, const b2Vec2& velocity); + + void SpawnBomb(const b2Vec2& worldPt); + void CompleteBombSpawn(const b2Vec2& p); + + // Let derived tests know that a joint was destroyed. + virtual void JointDestroyed(b2Joint* joint) { B2_NOT_USED(joint); } + + // Callbacks for derived classes. + virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); } + virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); } + virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold); + virtual void PostSolve(const b2Contact* contact, const b2ContactImpulse* impulse) + { + B2_NOT_USED(contact); + B2_NOT_USED(impulse); + } + +protected: + friend class DestructionListener; + friend class BoundaryListener; + friend class ContactListener; + + b2Body* m_groundBody; + b2AABB m_worldAABB; + ContactPoint m_points[k_maxContactPoints]; + int32 m_pointCount; + DestructionListener m_destructionListener; + DebugDraw m_debugDraw; + int32 m_textLine; + b2World* m_world; + b2Body* m_bomb; + b2MouseJoint* m_mouseJoint; + b2Vec2 m_bombSpawnPoint; + bool m_bombSpawning; + b2Vec2 m_mouseWorld; + int32 m_stepCount; + + b2Profile m_maxProfile; + b2Profile m_totalProfile; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/AddPair.h b/tests/Box2D_v2.2.1/Testbed/Tests/AddPair.h new file mode 100755 index 0000000000000..8f0893ac64309 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/AddPair.h @@ -0,0 +1,51 @@ + +#ifndef AddPair_H +#define AddPair_H + +class AddPair : public Test +{ +public: + + AddPair() + { + m_world->SetGravity(b2Vec2(0.0f,0.0f)); + { + b2CircleShape shape; + shape.m_p.SetZero(); + shape.m_radius = 0.1f; + + float minX = -6.0f; + float maxX = 0.0f; + float minY = 4.0f; + float maxY = 6.0f; + + for (int32 i = 0; i < 400; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position = b2Vec2(RandomFloat(minX,maxX),RandomFloat(minY,maxY)); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&shape, 0.01f); + } + } + + { + b2PolygonShape shape; + shape.SetAsBox(1.5f, 1.5f); + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-40.0f,5.0f); + bd.bullet = true; + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&shape, 1.0f); + body->SetLinearVelocity(b2Vec2(150.0f, 0.0f)); + } + } + + static Test* Create() + { + return new AddPair; + } +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/ApplyForce.h b/tests/Box2D_v2.2.1/Testbed/Tests/ApplyForce.h new file mode 100755 index 0000000000000..c04f8642a56e5 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/ApplyForce.h @@ -0,0 +1,180 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef APPLY_FORCE_H +#define APPLY_FORCE_H + +class ApplyForce : public Test +{ +public: + ApplyForce() + { + m_world->SetGravity(b2Vec2(0.0f, 0.0f)); + + const float32 k_restitution = 0.4f; + + b2Body* ground; + { + b2BodyDef bd; + bd.position.Set(0.0f, 20.0f); + ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + + b2FixtureDef sd; + sd.shape = &shape; + sd.density = 0.0f; + sd.restitution = k_restitution; + + // Left vertical + shape.Set(b2Vec2(-20.0f, -20.0f), b2Vec2(-20.0f, 20.0f)); + ground->CreateFixture(&sd); + + // Right vertical + shape.Set(b2Vec2(20.0f, -20.0f), b2Vec2(20.0f, 20.0f)); + ground->CreateFixture(&sd); + + // Top horizontal + shape.Set(b2Vec2(-20.0f, 20.0f), b2Vec2(20.0f, 20.0f)); + ground->CreateFixture(&sd); + + // Bottom horizontal + shape.Set(b2Vec2(-20.0f, -20.0f), b2Vec2(20.0f, -20.0f)); + ground->CreateFixture(&sd); + } + + { + b2Transform xf1; + xf1.q.Set(0.3524f * b2_pi); + xf1.p = xf1.q.GetXAxis(); + + b2Vec2 vertices[3]; + vertices[0] = b2Mul(xf1, b2Vec2(-1.0f, 0.0f)); + vertices[1] = b2Mul(xf1, b2Vec2(1.0f, 0.0f)); + vertices[2] = b2Mul(xf1, b2Vec2(0.0f, 0.5f)); + + b2PolygonShape poly1; + poly1.Set(vertices, 3); + + b2FixtureDef sd1; + sd1.shape = &poly1; + sd1.density = 4.0f; + + b2Transform xf2; + xf2.q.Set(-0.3524f * b2_pi); + xf2.p = -xf2.q.GetXAxis(); + + vertices[0] = b2Mul(xf2, b2Vec2(-1.0f, 0.0f)); + vertices[1] = b2Mul(xf2, b2Vec2(1.0f, 0.0f)); + vertices[2] = b2Mul(xf2, b2Vec2(0.0f, 0.5f)); + + b2PolygonShape poly2; + poly2.Set(vertices, 3); + + b2FixtureDef sd2; + sd2.shape = &poly2; + sd2.density = 2.0f; + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.angularDamping = 5.0f; + bd.linearDamping = 0.1f; + + bd.position.Set(0.0f, 2.0); + bd.angle = b2_pi; + bd.allowSleep = false; + m_body = m_world->CreateBody(&bd); + m_body->CreateFixture(&sd1); + m_body->CreateFixture(&sd2); + } + + { + b2PolygonShape shape; + shape.SetAsBox(0.5f, 0.5f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 1.0f; + fd.friction = 0.3f; + + for (int i = 0; i < 10; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + + bd.position.Set(0.0f, 5.0f + 1.54f * i); + b2Body* body = m_world->CreateBody(&bd); + + body->CreateFixture(&fd); + + float32 gravity = 10.0f; + float32 I = body->GetInertia(); + float32 mass = body->GetMass(); + + // For a circle: I = 0.5 * m * r * r ==> r = sqrt(2 * I / m) + float32 radius = b2Sqrt(2.0f * I / mass); + + b2FrictionJointDef jd; + jd.localAnchorA.SetZero(); + jd.localAnchorB.SetZero(); + jd.bodyA = ground; + jd.bodyB = body; + jd.collideConnected = true; + jd.maxForce = mass * gravity; + jd.maxTorque = mass * radius * gravity; + + m_world->CreateJoint(&jd); + } + } + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'w': + { + b2Vec2 f = m_body->GetWorldVector(b2Vec2(0.0f, -200.0f)); + b2Vec2 p = m_body->GetWorldPoint(b2Vec2(0.0f, 2.0f)); + m_body->ApplyForce(f, p); + } + break; + + case 'a': + { + m_body->ApplyTorque(50.0f); + } + break; + + case 'd': + { + m_body->ApplyTorque(-50.0f); + } + break; + } + } + + static Test* Create() + { + return new ApplyForce; + } + + b2Body* m_body; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/BodyTypes.h b/tests/Box2D_v2.2.1/Testbed/Tests/BodyTypes.h new file mode 100755 index 0000000000000..1e04b27f7b459 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/BodyTypes.h @@ -0,0 +1,159 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef BODY_TYPES_H +#define BODY_TYPES_H + +class BodyTypes : public Test +{ +public: + BodyTypes() + { + b2Body* ground = NULL; + { + b2BodyDef bd; + ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f)); + + b2FixtureDef fd; + fd.shape = &shape; + + ground->CreateFixture(&fd); + } + + // Define attachment + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.0f, 3.0f); + m_attachment = m_world->CreateBody(&bd); + + b2PolygonShape shape; + shape.SetAsBox(0.5f, 2.0f); + m_attachment->CreateFixture(&shape, 2.0f); + } + + // Define platform + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-4.0f, 5.0f); + m_platform = m_world->CreateBody(&bd); + + b2PolygonShape shape; + shape.SetAsBox(0.5f, 4.0f, b2Vec2(4.0f, 0.0f), 0.5f * b2_pi); + + b2FixtureDef fd; + fd.shape = &shape; + fd.friction = 0.6f; + fd.density = 2.0f; + m_platform->CreateFixture(&fd); + + b2RevoluteJointDef rjd; + rjd.Initialize(m_attachment, m_platform, b2Vec2(0.0f, 5.0f)); + rjd.maxMotorTorque = 50.0f; + rjd.enableMotor = true; + m_world->CreateJoint(&rjd); + + b2PrismaticJointDef pjd; + pjd.Initialize(ground, m_platform, b2Vec2(0.0f, 5.0f), b2Vec2(1.0f, 0.0f)); + + pjd.maxMotorForce = 1000.0f; + pjd.enableMotor = true; + pjd.lowerTranslation = -10.0f; + pjd.upperTranslation = 10.0f; + pjd.enableLimit = true; + + m_world->CreateJoint(&pjd); + + m_speed = 3.0f; + } + + // Create a payload + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.0f, 8.0f); + b2Body* body = m_world->CreateBody(&bd); + + b2PolygonShape shape; + shape.SetAsBox(0.75f, 0.75f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.friction = 0.6f; + fd.density = 2.0f; + + body->CreateFixture(&fd); + } + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'd': + m_platform->SetType(b2_dynamicBody); + break; + + case 's': + m_platform->SetType(b2_staticBody); + break; + + case 'k': + m_platform->SetType(b2_kinematicBody); + m_platform->SetLinearVelocity(b2Vec2(-m_speed, 0.0f)); + m_platform->SetAngularVelocity(0.0f); + break; + } + } + + void Step(Settings* settings) + { + // Drive the kinematic body. + if (m_platform->GetType() == b2_kinematicBody) + { + b2Vec2 p = m_platform->GetTransform().p; + b2Vec2 v = m_platform->GetLinearVelocity(); + + if ((p.x < -10.0f && v.x < 0.0f) || + (p.x > 10.0f && v.x > 0.0f)) + { + v.x = -v.x; + m_platform->SetLinearVelocity(v); + } + } + + Test::Step(settings); + m_debugDraw.DrawString(5, m_textLine, "Keys: (d) dynamic, (s) static, (k) kinematic"); + m_textLine += 15; + } + + static Test* Create() + { + return new BodyTypes; + } + + b2Body* m_attachment; + b2Body* m_platform; + float32 m_speed; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Breakable.h b/tests/Box2D_v2.2.1/Testbed/Tests/Breakable.h new file mode 100755 index 0000000000000..3fbdd476fab16 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Breakable.h @@ -0,0 +1,155 @@ +/* +* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef BREAKABLE_TEST_H +#define BREAKABLE_TEST_H + +// This is used to test sensor shapes. +class Breakable : public Test +{ +public: + + enum + { + e_count = 7 + }; + + Breakable() + { + // Ground body + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + // Breakable dynamic body + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.0f, 40.0f); + bd.angle = 0.25f * b2_pi; + m_body1 = m_world->CreateBody(&bd); + + m_shape1.SetAsBox(0.5f, 0.5f, b2Vec2(-0.5f, 0.0f), 0.0f); + m_piece1 = m_body1->CreateFixture(&m_shape1, 1.0f); + + m_shape2.SetAsBox(0.5f, 0.5f, b2Vec2(0.5f, 0.0f), 0.0f); + m_piece2 = m_body1->CreateFixture(&m_shape2, 1.0f); + } + + m_break = false; + m_broke = false; + } + + void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) + { + if (m_broke) + { + // The body already broke. + return; + } + + // Should the body break? + int32 count = contact->GetManifold()->pointCount; + + float32 maxImpulse = 0.0f; + for (int32 i = 0; i < count; ++i) + { + maxImpulse = b2Max(maxImpulse, impulse->normalImpulses[i]); + } + + if (maxImpulse > 40.0f) + { + // Flag the body for breaking. + m_break = true; + } + } + + void Break() + { + // Create two bodies from one. + b2Body* body1 = m_piece1->GetBody(); + b2Vec2 center = body1->GetWorldCenter(); + + body1->DestroyFixture(m_piece2); + m_piece2 = NULL; + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position = body1->GetPosition(); + bd.angle = body1->GetAngle(); + + b2Body* body2 = m_world->CreateBody(&bd); + m_piece2 = body2->CreateFixture(&m_shape2, 1.0f); + + // Compute consistent velocities for new bodies based on + // cached velocity. + b2Vec2 center1 = body1->GetWorldCenter(); + b2Vec2 center2 = body2->GetWorldCenter(); + + b2Vec2 velocity1 = m_velocity + b2Cross(m_angularVelocity, center1 - center); + b2Vec2 velocity2 = m_velocity + b2Cross(m_angularVelocity, center2 - center); + + body1->SetAngularVelocity(m_angularVelocity); + body1->SetLinearVelocity(velocity1); + + body2->SetAngularVelocity(m_angularVelocity); + body2->SetLinearVelocity(velocity2); + } + + void Step(Settings* settings) + { + if (m_break) + { + Break(); + m_broke = true; + m_break = false; + } + + // Cache velocities to improve movement on breakage. + if (m_broke == false) + { + m_velocity = m_body1->GetLinearVelocity(); + m_angularVelocity = m_body1->GetAngularVelocity(); + } + + Test::Step(settings); + } + + static Test* Create() + { + return new Breakable; + } + + b2Body* m_body1; + b2Vec2 m_velocity; + float32 m_angularVelocity; + b2PolygonShape m_shape1; + b2PolygonShape m_shape2; + b2Fixture* m_piece1; + b2Fixture* m_piece2; + + bool m_broke; + bool m_break; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Bridge.h b/tests/Box2D_v2.2.1/Testbed/Tests/Bridge.h new file mode 100755 index 0000000000000..ef836499710eb --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Bridge.h @@ -0,0 +1,125 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef BRIDGE_H +#define BRIDGE_H + +class Bridge : public Test +{ +public: + + enum + { + e_count = 30 + }; + + Bridge() + { + b2Body* ground = NULL; + { + b2BodyDef bd; + ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2PolygonShape shape; + shape.SetAsBox(0.5f, 0.125f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + fd.friction = 0.2f; + + b2RevoluteJointDef jd; + + b2Body* prevBody = ground; + for (int32 i = 0; i < e_count; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-14.5f + 1.0f * i, 5.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + + b2Vec2 anchor(-15.0f + 1.0f * i, 5.0f); + jd.Initialize(prevBody, body, anchor); + m_world->CreateJoint(&jd); + + if (i == (e_count >> 1)) + { + m_middle = body; + } + prevBody = body; + } + + b2Vec2 anchor(-15.0f + 1.0f * e_count, 5.0f); + jd.Initialize(prevBody, ground, anchor); + m_world->CreateJoint(&jd); + } + + for (int32 i = 0; i < 2; ++i) + { + b2Vec2 vertices[3]; + vertices[0].Set(-0.5f, 0.0f); + vertices[1].Set(0.5f, 0.0f); + vertices[2].Set(0.0f, 1.5f); + + b2PolygonShape shape; + shape.Set(vertices, 3); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 1.0f; + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-8.0f + 8.0f * i, 12.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + } + + for (int32 i = 0; i < 3; ++i) + { + b2CircleShape shape; + shape.m_radius = 0.5f; + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 1.0f; + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-6.0f + 6.0f * i, 10.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + } + } + + static Test* Create() + { + return new Bridge; + } + + b2Body* m_middle; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/BulletTest.h b/tests/Box2D_v2.2.1/Testbed/Tests/BulletTest.h new file mode 100755 index 0000000000000..10f1f000d011a --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/BulletTest.h @@ -0,0 +1,136 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef BULLET_TEST_H +#define BULLET_TEST_H + +class BulletTest : public Test +{ +public: + + BulletTest() + { + { + b2BodyDef bd; + bd.position.Set(0.0f, 0.0f); + b2Body* body = m_world->CreateBody(&bd); + + b2EdgeShape edge; + + edge.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f)); + body->CreateFixture(&edge, 0.0f); + + b2PolygonShape shape; + shape.SetAsBox(0.2f, 1.0f, b2Vec2(0.5f, 1.0f), 0.0f); + body->CreateFixture(&shape, 0.0f); + } + + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.0f, 4.0f); + + b2PolygonShape box; + box.SetAsBox(2.0f, 0.1f); + + m_body = m_world->CreateBody(&bd); + m_body->CreateFixture(&box, 1.0f); + + box.SetAsBox(0.25f, 0.25f); + + //m_x = RandomFloat(-1.0f, 1.0f); + m_x = 0.20352793f; + bd.position.Set(m_x, 10.0f); + bd.bullet = true; + + m_bullet = m_world->CreateBody(&bd); + m_bullet->CreateFixture(&box, 100.0f); + + m_bullet->SetLinearVelocity(b2Vec2(0.0f, -50.0f)); + } + } + + void Launch() + { + m_body->SetTransform(b2Vec2(0.0f, 4.0f), 0.0f); + m_body->SetLinearVelocity(b2Vec2_zero); + m_body->SetAngularVelocity(0.0f); + + m_x = RandomFloat(-1.0f, 1.0f); + m_bullet->SetTransform(b2Vec2(m_x, 10.0f), 0.0f); + m_bullet->SetLinearVelocity(b2Vec2(0.0f, -50.0f)); + m_bullet->SetAngularVelocity(0.0f); + + extern int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters; + extern int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters; + extern int32 b2_toiRootIters, b2_toiMaxRootIters; + + b2_gjkCalls = 0; + b2_gjkIters = 0; + b2_gjkMaxIters = 0; + + b2_toiCalls = 0; + b2_toiIters = 0; + b2_toiMaxIters = 0; + b2_toiRootIters = 0; + b2_toiMaxRootIters = 0; + } + + void Step(Settings* settings) + { + Test::Step(settings); + + extern int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters; + extern int32 b2_toiCalls, b2_toiIters; + extern int32 b2_toiRootIters, b2_toiMaxRootIters; + + if (b2_gjkCalls > 0) + { + m_debugDraw.DrawString(5, m_textLine, "gjk calls = %d, ave gjk iters = %3.1f, max gjk iters = %d", + b2_gjkCalls, b2_gjkIters / float32(b2_gjkCalls), b2_gjkMaxIters); + m_textLine += 15; + } + + if (b2_toiCalls > 0) + { + m_debugDraw.DrawString(5, m_textLine, "toi calls = %d, ave toi iters = %3.1f, max toi iters = %d", + b2_toiCalls, b2_toiIters / float32(b2_toiCalls), b2_toiMaxRootIters); + m_textLine += 15; + + m_debugDraw.DrawString(5, m_textLine, "ave toi root iters = %3.1f, max toi root iters = %d", + b2_toiRootIters / float32(b2_toiCalls), b2_toiMaxRootIters); + m_textLine += 15; + } + + if (m_stepCount % 60 == 0) + { + Launch(); + } + } + + static Test* Create() + { + return new BulletTest; + } + + b2Body* m_body; + b2Body* m_bullet; + float32 m_x; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Cantilever.h b/tests/Box2D_v2.2.1/Testbed/Tests/Cantilever.h new file mode 100755 index 0000000000000..26994d6f14454 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Cantilever.h @@ -0,0 +1,211 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef CANTILEVER_H +#define CANTILEVER_H + +// It is difficult to make a cantilever made of links completely rigid with weld joints. +// You will have to use a high number of iterations to make them stiff. +// So why not go ahead and use soft weld joints? They behave like a revolute +// joint with a rotational spring. +class Cantilever : public Test +{ +public: + + enum + { + e_count = 8 + }; + + Cantilever() + { + b2Body* ground = NULL; + { + b2BodyDef bd; + ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2PolygonShape shape; + shape.SetAsBox(0.5f, 0.125f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + + b2WeldJointDef jd; + + b2Body* prevBody = ground; + for (int32 i = 0; i < e_count; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-14.5f + 1.0f * i, 5.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + + b2Vec2 anchor(-15.0f + 1.0f * i, 5.0f); + jd.Initialize(prevBody, body, anchor); + m_world->CreateJoint(&jd); + + prevBody = body; + } + } + + { + b2PolygonShape shape; + shape.SetAsBox(1.0f, 0.125f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + + b2WeldJointDef jd; + jd.frequencyHz = 5.0f; + jd.dampingRatio = 0.7f; + + b2Body* prevBody = ground; + for (int32 i = 0; i < 3; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-14.0f + 2.0f * i, 15.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + + b2Vec2 anchor(-15.0f + 2.0f * i, 15.0f); + jd.Initialize(prevBody, body, anchor); + m_world->CreateJoint(&jd); + + prevBody = body; + } + } + + { + b2PolygonShape shape; + shape.SetAsBox(0.5f, 0.125f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + + b2WeldJointDef jd; + + b2Body* prevBody = ground; + for (int32 i = 0; i < e_count; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-4.5f + 1.0f * i, 5.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + + if (i > 0) + { + b2Vec2 anchor(-5.0f + 1.0f * i, 5.0f); + jd.Initialize(prevBody, body, anchor); + m_world->CreateJoint(&jd); + } + + prevBody = body; + } + } + + { + b2PolygonShape shape; + shape.SetAsBox(0.5f, 0.125f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + + b2WeldJointDef jd; + jd.frequencyHz = 8.0f; + jd.dampingRatio = 0.7f; + + b2Body* prevBody = ground; + for (int32 i = 0; i < e_count; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(5.5f + 1.0f * i, 10.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + + if (i > 0) + { + b2Vec2 anchor(5.0f + 1.0f * i, 10.0f); + jd.Initialize(prevBody, body, anchor); + m_world->CreateJoint(&jd); + } + + prevBody = body; + } + } + + for (int32 i = 0; i < 2; ++i) + { + b2Vec2 vertices[3]; + vertices[0].Set(-0.5f, 0.0f); + vertices[1].Set(0.5f, 0.0f); + vertices[2].Set(0.0f, 1.5f); + + b2PolygonShape shape; + shape.Set(vertices, 3); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 1.0f; + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-8.0f + 8.0f * i, 12.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + } + + for (int32 i = 0; i < 2; ++i) + { + b2CircleShape shape; + shape.m_radius = 0.5f; + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 1.0f; + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-6.0f + 6.0f * i, 10.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + } + } + + static Test* Create() + { + return new Cantilever; + } + + b2Body* m_middle; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Car.h b/tests/Box2D_v2.2.1/Testbed/Tests/Car.h new file mode 100755 index 0000000000000..d86201e7bd342 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Car.h @@ -0,0 +1,286 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef CAR_H +#define CAR_H + +// This is a fun demo that shows off the wheel joint +class Car : public Test +{ +public: + Car() + { + m_hz = 4.0f; + m_zeta = 0.7f; + m_speed = 50.0f; + + b2Body* ground = NULL; + { + b2BodyDef bd; + ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 0.0f; + fd.friction = 0.6f; + + shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f)); + ground->CreateFixture(&fd); + + float32 hs[10] = {0.25f, 1.0f, 4.0f, 0.0f, 0.0f, -1.0f, -2.0f, -2.0f, -1.25f, 0.0f}; + + float32 x = 20.0f, y1 = 0.0f, dx = 5.0f; + + for (int32 i = 0; i < 10; ++i) + { + float32 y2 = hs[i]; + shape.Set(b2Vec2(x, y1), b2Vec2(x + dx, y2)); + ground->CreateFixture(&fd); + y1 = y2; + x += dx; + } + + for (int32 i = 0; i < 10; ++i) + { + float32 y2 = hs[i]; + shape.Set(b2Vec2(x, y1), b2Vec2(x + dx, y2)); + ground->CreateFixture(&fd); + y1 = y2; + x += dx; + } + + shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f)); + ground->CreateFixture(&fd); + + x += 80.0f; + shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f)); + ground->CreateFixture(&fd); + + x += 40.0f; + shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 10.0f, 5.0f)); + ground->CreateFixture(&fd); + + x += 20.0f; + shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f)); + ground->CreateFixture(&fd); + + x += 40.0f; + shape.Set(b2Vec2(x, 0.0f), b2Vec2(x, 20.0f)); + ground->CreateFixture(&fd); + } + + // Teeter + { + b2BodyDef bd; + bd.position.Set(140.0f, 1.0f); + bd.type = b2_dynamicBody; + b2Body* body = m_world->CreateBody(&bd); + + b2PolygonShape box; + box.SetAsBox(10.0f, 0.25f); + body->CreateFixture(&box, 1.0f); + + b2RevoluteJointDef jd; + jd.Initialize(ground, body, body->GetPosition()); + jd.lowerAngle = -8.0f * b2_pi / 180.0f; + jd.upperAngle = 8.0f * b2_pi / 180.0f; + jd.enableLimit = true; + m_world->CreateJoint(&jd); + + body->ApplyAngularImpulse(100.0f); + } + + // Bridge + { + int32 N = 20; + b2PolygonShape shape; + shape.SetAsBox(1.0f, 0.125f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 1.0f; + fd.friction = 0.6f; + + b2RevoluteJointDef jd; + + b2Body* prevBody = ground; + for (int32 i = 0; i < N; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(161.0f + 2.0f * i, -0.125f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + + b2Vec2 anchor(160.0f + 2.0f * i, -0.125f); + jd.Initialize(prevBody, body, anchor); + m_world->CreateJoint(&jd); + + prevBody = body; + } + + b2Vec2 anchor(160.0f + 2.0f * N, -0.125f); + jd.Initialize(prevBody, ground, anchor); + m_world->CreateJoint(&jd); + } + + // Boxes + { + b2PolygonShape box; + box.SetAsBox(0.5f, 0.5f); + + b2Body* body = NULL; + b2BodyDef bd; + bd.type = b2_dynamicBody; + + bd.position.Set(230.0f, 0.5f); + body = m_world->CreateBody(&bd); + body->CreateFixture(&box, 0.5f); + + bd.position.Set(230.0f, 1.5f); + body = m_world->CreateBody(&bd); + body->CreateFixture(&box, 0.5f); + + bd.position.Set(230.0f, 2.5f); + body = m_world->CreateBody(&bd); + body->CreateFixture(&box, 0.5f); + + bd.position.Set(230.0f, 3.5f); + body = m_world->CreateBody(&bd); + body->CreateFixture(&box, 0.5f); + + bd.position.Set(230.0f, 4.5f); + body = m_world->CreateBody(&bd); + body->CreateFixture(&box, 0.5f); + } + + // Car + { + b2PolygonShape chassis; + b2Vec2 vertices[8]; + vertices[0].Set(-1.5f, -0.5f); + vertices[1].Set(1.5f, -0.5f); + vertices[2].Set(1.5f, 0.0f); + vertices[3].Set(0.0f, 0.9f); + vertices[4].Set(-1.15f, 0.9f); + vertices[5].Set(-1.5f, 0.2f); + chassis.Set(vertices, 6); + + b2CircleShape circle; + circle.m_radius = 0.4f; + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.0f, 1.0f); + m_car = m_world->CreateBody(&bd); + m_car->CreateFixture(&chassis, 1.0f); + + b2FixtureDef fd; + fd.shape = &circle; + fd.density = 1.0f; + fd.friction = 0.9f; + + bd.position.Set(-1.0f, 0.35f); + m_wheel1 = m_world->CreateBody(&bd); + m_wheel1->CreateFixture(&fd); + + bd.position.Set(1.0f, 0.4f); + m_wheel2 = m_world->CreateBody(&bd); + m_wheel2->CreateFixture(&fd); + + b2WheelJointDef jd; + b2Vec2 axis(0.0f, 1.0f); + + jd.Initialize(m_car, m_wheel1, m_wheel1->GetPosition(), axis); + jd.motorSpeed = 0.0f; + jd.maxMotorTorque = 20.0f; + jd.enableMotor = true; + jd.frequencyHz = m_hz; + jd.dampingRatio = m_zeta; + m_spring1 = (b2WheelJoint*)m_world->CreateJoint(&jd); + + jd.Initialize(m_car, m_wheel2, m_wheel2->GetPosition(), axis); + jd.motorSpeed = 0.0f; + jd.maxMotorTorque = 10.0f; + jd.enableMotor = false; + jd.frequencyHz = m_hz; + jd.dampingRatio = m_zeta; + m_spring2 = (b2WheelJoint*)m_world->CreateJoint(&jd); + } + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'a': + m_spring1->SetMotorSpeed(m_speed); + break; + + case 's': + m_spring1->SetMotorSpeed(0.0f); + break; + + case 'd': + m_spring1->SetMotorSpeed(-m_speed); + break; + + case 'q': + m_hz = b2Max(0.0f, m_hz - 1.0f); + m_spring1->SetSpringFrequencyHz(m_hz); + m_spring2->SetSpringFrequencyHz(m_hz); + break; + + case 'e': + m_hz += 1.0f; + m_spring1->SetSpringFrequencyHz(m_hz); + m_spring2->SetSpringFrequencyHz(m_hz); + break; + } + } + + void Step(Settings* settings) + { + m_debugDraw.DrawString(5, m_textLine, "Keys: left = a, brake = s, right = d, hz down = q, hz up = e"); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "frequency = %g hz, damping ratio = %g", m_hz, m_zeta); + m_textLine += 15; + + settings->viewCenter.x = m_car->GetPosition().x; + Test::Step(settings); + } + + static Test* Create() + { + return new Car; + } + + b2Body* m_car; + b2Body* m_wheel1; + b2Body* m_wheel2; + + float32 m_hz; + float32 m_zeta; + float32 m_speed; + b2WheelJoint* m_spring1; + b2WheelJoint* m_spring2; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Chain.h b/tests/Box2D_v2.2.1/Testbed/Tests/Chain.h new file mode 100755 index 0000000000000..33b8de9b0eec8 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Chain.h @@ -0,0 +1,74 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef CHAIN_H +#define CHAIN_H + +class Chain : public Test +{ +public: + Chain() + { + b2Body* ground = NULL; + { + b2BodyDef bd; + ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2PolygonShape shape; + shape.SetAsBox(0.6f, 0.125f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + fd.friction = 0.2f; + + b2RevoluteJointDef jd; + jd.collideConnected = false; + + const float32 y = 25.0f; + b2Body* prevBody = ground; + for (int32 i = 0; i < 30; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.5f + i, y); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + + b2Vec2 anchor(float32(i), y); + jd.Initialize(prevBody, body, anchor); + m_world->CreateJoint(&jd); + + prevBody = body; + } + } + } + + static Test* Create() + { + return new Chain; + } +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/CharacterCollision.h b/tests/Box2D_v2.2.1/Testbed/Tests/CharacterCollision.h new file mode 100755 index 0000000000000..b000a828039c0 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/CharacterCollision.h @@ -0,0 +1,253 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef CHARACTER_COLLISION_H +#define CHARACTER_COLLISION_H + +/// This is a test of typical character collision scenarios. This does not +/// show how you should implement a character in your application. +/// Instead this is used to test smooth collision on edge chains. +class CharacterCollision : public Test +{ +public: + CharacterCollision() + { + // Ground body + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + // Collinear edges with no adjacency information. + // This shows the problematic case where a box shape can hit + // an internal vertex. + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-8.0f, 1.0f), b2Vec2(-6.0f, 1.0f)); + ground->CreateFixture(&shape, 0.0f); + shape.Set(b2Vec2(-6.0f, 1.0f), b2Vec2(-4.0f, 1.0f)); + ground->CreateFixture(&shape, 0.0f); + shape.Set(b2Vec2(-4.0f, 1.0f), b2Vec2(-2.0f, 1.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + // Chain shape + { + b2BodyDef bd; + bd.angle = 0.25f * b2_pi; + b2Body* ground = m_world->CreateBody(&bd); + + b2Vec2 vs[4]; + vs[0].Set(5.0f, 7.0f); + vs[1].Set(6.0f, 8.0f); + vs[2].Set(7.0f, 8.0f); + vs[3].Set(8.0f, 7.0f); + b2ChainShape shape; + shape.CreateChain(vs, 4); + ground->CreateFixture(&shape, 0.0f); + } + + // Square tiles. This shows that adjacency shapes may + // have non-smooth collision. There is no solution + // to this problem. + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2PolygonShape shape; + shape.SetAsBox(1.0f, 1.0f, b2Vec2(4.0f, 3.0f), 0.0f); + ground->CreateFixture(&shape, 0.0f); + shape.SetAsBox(1.0f, 1.0f, b2Vec2(6.0f, 3.0f), 0.0f); + ground->CreateFixture(&shape, 0.0f); + shape.SetAsBox(1.0f, 1.0f, b2Vec2(8.0f, 3.0f), 0.0f); + ground->CreateFixture(&shape, 0.0f); + } + + // Square made from an edge loop. Collision should be smooth. + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2Vec2 vs[4]; + vs[0].Set(-1.0f, 3.0f); + vs[1].Set(1.0f, 3.0f); + vs[2].Set(1.0f, 5.0f); + vs[3].Set(-1.0f, 5.0f); + b2ChainShape shape; + shape.CreateLoop(vs, 4); + ground->CreateFixture(&shape, 0.0f); + } + + // Edge loop. Collision should be smooth. + { + b2BodyDef bd; + bd.position.Set(-10.0f, 4.0f); + b2Body* ground = m_world->CreateBody(&bd); + + b2Vec2 vs[10]; + vs[0].Set(0.0f, 0.0f); + vs[1].Set(6.0f, 0.0f); + vs[2].Set(6.0f, 2.0f); + vs[3].Set(4.0f, 1.0f); + vs[4].Set(2.0f, 2.0f); + vs[5].Set(0.0f, 2.0f); + vs[6].Set(-2.0f, 2.0f); + vs[7].Set(-4.0f, 3.0f); + vs[8].Set(-6.0f, 2.0f); + vs[9].Set(-6.0f, 0.0f); + b2ChainShape shape; + shape.CreateLoop(vs, 10); + ground->CreateFixture(&shape, 0.0f); + } + + // Square character 1 + { + b2BodyDef bd; + bd.position.Set(-3.0f, 8.0f); + bd.type = b2_dynamicBody; + bd.fixedRotation = true; + bd.allowSleep = false; + + b2Body* body = m_world->CreateBody(&bd); + + b2PolygonShape shape; + shape.SetAsBox(0.5f, 0.5f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + body->CreateFixture(&fd); + } + + // Square character 2 + { + b2BodyDef bd; + bd.position.Set(-5.0f, 5.0f); + bd.type = b2_dynamicBody; + bd.fixedRotation = true; + bd.allowSleep = false; + + b2Body* body = m_world->CreateBody(&bd); + + b2PolygonShape shape; + shape.SetAsBox(0.25f, 0.25f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + body->CreateFixture(&fd); + } + + // Hexagon character + { + b2BodyDef bd; + bd.position.Set(-5.0f, 8.0f); + bd.type = b2_dynamicBody; + bd.fixedRotation = true; + bd.allowSleep = false; + + b2Body* body = m_world->CreateBody(&bd); + + float32 angle = 0.0f; + float32 delta = b2_pi / 3.0f; + b2Vec2 vertices[6]; + for (int32 i = 0; i < 6; ++i) + { + vertices[i].Set(0.5f * cosf(angle), 0.5f * sinf(angle)); + angle += delta; + } + + b2PolygonShape shape; + shape.Set(vertices, 6); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + body->CreateFixture(&fd); + } + + // Circle character + { + b2BodyDef bd; + bd.position.Set(3.0f, 5.0f); + bd.type = b2_dynamicBody; + bd.fixedRotation = true; + bd.allowSleep = false; + + b2Body* body = m_world->CreateBody(&bd); + + b2CircleShape shape; + shape.m_radius = 0.5f; + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + body->CreateFixture(&fd); + } + + // Circle character + { + b2BodyDef bd; + bd.position.Set(-7.0f, 6.0f); + bd.type = b2_dynamicBody; + bd.allowSleep = false; + + m_character = m_world->CreateBody(&bd); + + b2CircleShape shape; + shape.m_radius = 0.25f; + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + fd.friction = 1.0f; + m_character->CreateFixture(&fd); + } + } + + void Step(Settings* settings) + { + b2Vec2 v = m_character->GetLinearVelocity(); + v.x = -5.0f; + m_character->SetLinearVelocity(v); + + Test::Step(settings); + m_debugDraw.DrawString(5, m_textLine, "This tests various character collision shapes."); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "Limitation: square and hexagon can snag on aligned boxes."); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "Feature: edge chains have smooth collision inside and out."); + m_textLine += 15; + } + + static Test* Create() + { + return new CharacterCollision; + } + + b2Body* m_character; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/CollisionFiltering.h b/tests/Box2D_v2.2.1/Testbed/Tests/CollisionFiltering.h new file mode 100755 index 0000000000000..828717593bbc9 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/CollisionFiltering.h @@ -0,0 +1,176 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef COLLISION_FILTERING_H +#define COLLISION_FILTERING_H + +// This is a test of collision filtering. +// There is a triangle, a box, and a circle. +// There are 6 shapes. 3 large and 3 small. +// The 3 small ones always collide. +// The 3 large ones never collide. +// The boxes don't collide with triangles (except if both are small). +const int16 k_smallGroup = 1; +const int16 k_largeGroup = -1; + +const uint16 k_defaultCategory = 0x0001; +const uint16 k_triangleCategory = 0x0002; +const uint16 k_boxCategory = 0x0004; +const uint16 k_circleCategory = 0x0008; + +const uint16 k_triangleMask = 0xFFFF; +const uint16 k_boxMask = 0xFFFF ^ k_triangleCategory; +const uint16 k_circleMask = 0xFFFF; + +class CollisionFiltering : public Test +{ +public: + CollisionFiltering() + { + // Ground body + { + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + + b2FixtureDef sd; + sd.shape = &shape; + sd.friction = 0.3f; + + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + ground->CreateFixture(&sd); + } + + // Small triangle + b2Vec2 vertices[3]; + vertices[0].Set(-1.0f, 0.0f); + vertices[1].Set(1.0f, 0.0f); + vertices[2].Set(0.0f, 2.0f); + b2PolygonShape polygon; + polygon.Set(vertices, 3); + + b2FixtureDef triangleShapeDef; + triangleShapeDef.shape = &polygon; + triangleShapeDef.density = 1.0f; + + triangleShapeDef.filter.groupIndex = k_smallGroup; + triangleShapeDef.filter.categoryBits = k_triangleCategory; + triangleShapeDef.filter.maskBits = k_triangleMask; + + b2BodyDef triangleBodyDef; + triangleBodyDef.type = b2_dynamicBody; + triangleBodyDef.position.Set(-5.0f, 2.0f); + + b2Body* body1 = m_world->CreateBody(&triangleBodyDef); + body1->CreateFixture(&triangleShapeDef); + + // Large triangle (recycle definitions) + vertices[0] *= 2.0f; + vertices[1] *= 2.0f; + vertices[2] *= 2.0f; + polygon.Set(vertices, 3); + triangleShapeDef.filter.groupIndex = k_largeGroup; + triangleBodyDef.position.Set(-5.0f, 6.0f); + triangleBodyDef.fixedRotation = true; // look at me! + + b2Body* body2 = m_world->CreateBody(&triangleBodyDef); + body2->CreateFixture(&triangleShapeDef); + + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-5.0f, 10.0f); + b2Body* body = m_world->CreateBody(&bd); + + b2PolygonShape p; + p.SetAsBox(0.5f, 1.0f); + body->CreateFixture(&p, 1.0f); + + b2PrismaticJointDef jd; + jd.bodyA = body2; + jd.bodyB = body; + jd.enableLimit = true; + jd.localAnchorA.Set(0.0f, 4.0f); + jd.localAnchorB.SetZero(); + jd.localAxisA.Set(0.0f, 1.0f); + jd.lowerTranslation = -1.0f; + jd.upperTranslation = 1.0f; + + m_world->CreateJoint(&jd); + } + + // Small box + polygon.SetAsBox(1.0f, 0.5f); + b2FixtureDef boxShapeDef; + boxShapeDef.shape = &polygon; + boxShapeDef.density = 1.0f; + boxShapeDef.restitution = 0.1f; + + boxShapeDef.filter.groupIndex = k_smallGroup; + boxShapeDef.filter.categoryBits = k_boxCategory; + boxShapeDef.filter.maskBits = k_boxMask; + + b2BodyDef boxBodyDef; + boxBodyDef.type = b2_dynamicBody; + boxBodyDef.position.Set(0.0f, 2.0f); + + b2Body* body3 = m_world->CreateBody(&boxBodyDef); + body3->CreateFixture(&boxShapeDef); + + // Large box (recycle definitions) + polygon.SetAsBox(2.0f, 1.0f); + boxShapeDef.filter.groupIndex = k_largeGroup; + boxBodyDef.position.Set(0.0f, 6.0f); + + b2Body* body4 = m_world->CreateBody(&boxBodyDef); + body4->CreateFixture(&boxShapeDef); + + // Small circle + b2CircleShape circle; + circle.m_radius = 1.0f; + + b2FixtureDef circleShapeDef; + circleShapeDef.shape = &circle; + circleShapeDef.density = 1.0f; + + circleShapeDef.filter.groupIndex = k_smallGroup; + circleShapeDef.filter.categoryBits = k_circleCategory; + circleShapeDef.filter.maskBits = k_circleMask; + + b2BodyDef circleBodyDef; + circleBodyDef.type = b2_dynamicBody; + circleBodyDef.position.Set(5.0f, 2.0f); + + b2Body* body5 = m_world->CreateBody(&circleBodyDef); + body5->CreateFixture(&circleShapeDef); + + // Large circle + circle.m_radius *= 2.0f; + circleShapeDef.filter.groupIndex = k_largeGroup; + circleBodyDef.position.Set(5.0f, 6.0f); + + b2Body* body6 = m_world->CreateBody(&circleBodyDef); + body6->CreateFixture(&circleShapeDef); + } + static Test* Create() + { + return new CollisionFiltering; + } +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/CollisionProcessing.h b/tests/Box2D_v2.2.1/Testbed/Tests/CollisionProcessing.h new file mode 100755 index 0000000000000..c8cc3283f8f52 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/CollisionProcessing.h @@ -0,0 +1,188 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef COLLISION_PROCESSING_H +#define COLLISION_PROCESSING_H + +#include + +// This test shows collision processing and tests +// deferred body destruction. +class CollisionProcessing : public Test +{ +public: + CollisionProcessing() + { + // Ground body + { + b2EdgeShape shape; + shape.Set(b2Vec2(-50.0f, 0.0f), b2Vec2(50.0f, 0.0f)); + + b2FixtureDef sd; + sd.shape = &shape;; + + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + ground->CreateFixture(&sd); + } + + float32 xLo = -5.0f, xHi = 5.0f; + float32 yLo = 2.0f, yHi = 35.0f; + + // Small triangle + b2Vec2 vertices[3]; + vertices[0].Set(-1.0f, 0.0f); + vertices[1].Set(1.0f, 0.0f); + vertices[2].Set(0.0f, 2.0f); + + b2PolygonShape polygon; + polygon.Set(vertices, 3); + + b2FixtureDef triangleShapeDef; + triangleShapeDef.shape = &polygon; + triangleShapeDef.density = 1.0f; + + b2BodyDef triangleBodyDef; + triangleBodyDef.type = b2_dynamicBody; + triangleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi)); + + b2Body* body1 = m_world->CreateBody(&triangleBodyDef); + body1->CreateFixture(&triangleShapeDef); + + // Large triangle (recycle definitions) + vertices[0] *= 2.0f; + vertices[1] *= 2.0f; + vertices[2] *= 2.0f; + polygon.Set(vertices, 3); + + triangleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi)); + + b2Body* body2 = m_world->CreateBody(&triangleBodyDef); + body2->CreateFixture(&triangleShapeDef); + + // Small box + polygon.SetAsBox(1.0f, 0.5f); + + b2FixtureDef boxShapeDef; + boxShapeDef.shape = &polygon; + boxShapeDef.density = 1.0f; + + b2BodyDef boxBodyDef; + boxBodyDef.type = b2_dynamicBody; + boxBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi)); + + b2Body* body3 = m_world->CreateBody(&boxBodyDef); + body3->CreateFixture(&boxShapeDef); + + // Large box (recycle definitions) + polygon.SetAsBox(2.0f, 1.0f); + boxBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi)); + + b2Body* body4 = m_world->CreateBody(&boxBodyDef); + body4->CreateFixture(&boxShapeDef); + + // Small circle + b2CircleShape circle; + circle.m_radius = 1.0f; + + b2FixtureDef circleShapeDef; + circleShapeDef.shape = &circle; + circleShapeDef.density = 1.0f; + + b2BodyDef circleBodyDef; + circleBodyDef.type = b2_dynamicBody; + circleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi)); + + b2Body* body5 = m_world->CreateBody(&circleBodyDef); + body5->CreateFixture(&circleShapeDef); + + // Large circle + circle.m_radius *= 2.0f; + circleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi)); + + b2Body* body6 = m_world->CreateBody(&circleBodyDef); + body6->CreateFixture(&circleShapeDef); + } + + void Step(Settings* settings) + { + Test::Step(settings); + + // We are going to destroy some bodies according to contact + // points. We must buffer the bodies that should be destroyed + // because they may belong to multiple contact points. + const int32 k_maxNuke = 6; + b2Body* nuke[k_maxNuke]; + int32 nukeCount = 0; + + // Traverse the contact results. Destroy bodies that + // are touching heavier bodies. + for (int32 i = 0; i < m_pointCount; ++i) + { + ContactPoint* point = m_points + i; + + b2Body* body1 = point->fixtureA->GetBody(); + b2Body* body2 = point->fixtureB->GetBody(); + float32 mass1 = body1->GetMass(); + float32 mass2 = body2->GetMass(); + + if (mass1 > 0.0f && mass2 > 0.0f) + { + if (mass2 > mass1) + { + nuke[nukeCount++] = body1; + } + else + { + nuke[nukeCount++] = body2; + } + + if (nukeCount == k_maxNuke) + { + break; + } + } + } + + // Sort the nuke array to group duplicates. + std::sort(nuke, nuke + nukeCount); + + // Destroy the bodies, skipping duplicates. + int32 i = 0; + while (i < nukeCount) + { + b2Body* b = nuke[i++]; + while (i < nukeCount && nuke[i] == b) + { + ++i; + } + + if (b != m_bomb) + { + m_world->DestroyBody(b); + } + } + } + + static Test* Create() + { + return new CollisionProcessing; + } +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/CompoundShapes.h b/tests/Box2D_v2.2.1/Testbed/Tests/CompoundShapes.h new file mode 100755 index 0000000000000..bc14e882aee56 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/CompoundShapes.h @@ -0,0 +1,143 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef COMPOUND_SHAPES_H +#define COMPOUND_SHAPES_H + +// TODO_ERIN test joints on compounds. +class CompoundShapes : public Test +{ +public: + CompoundShapes() + { + { + b2BodyDef bd; + bd.position.Set(0.0f, 0.0f); + b2Body* body = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(50.0f, 0.0f), b2Vec2(-50.0f, 0.0f)); + + body->CreateFixture(&shape, 0.0f); + } + + { + b2CircleShape circle1; + circle1.m_radius = 0.5f; + circle1.m_p.Set(-0.5f, 0.5f); + + b2CircleShape circle2; + circle2.m_radius = 0.5f; + circle2.m_p.Set(0.5f, 0.5f); + + for (int i = 0; i < 10; ++i) + { + float32 x = RandomFloat(-0.1f, 0.1f); + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(x + 5.0f, 1.05f + 2.5f * i); + bd.angle = RandomFloat(-b2_pi, b2_pi); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&circle1, 2.0f); + body->CreateFixture(&circle2, 0.0f); + } + } + + { + b2PolygonShape polygon1; + polygon1.SetAsBox(0.25f, 0.5f); + + b2PolygonShape polygon2; + polygon2.SetAsBox(0.25f, 0.5f, b2Vec2(0.0f, -0.5f), 0.5f * b2_pi); + + for (int i = 0; i < 10; ++i) + { + float32 x = RandomFloat(-0.1f, 0.1f); + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(x - 5.0f, 1.05f + 2.5f * i); + bd.angle = RandomFloat(-b2_pi, b2_pi); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&polygon1, 2.0f); + body->CreateFixture(&polygon2, 2.0f); + } + } + + { + b2Transform xf1; + xf1.q.Set(0.3524f * b2_pi); + xf1.p = xf1.q.GetXAxis(); + + b2Vec2 vertices[3]; + + b2PolygonShape triangle1; + vertices[0] = b2Mul(xf1, b2Vec2(-1.0f, 0.0f)); + vertices[1] = b2Mul(xf1, b2Vec2(1.0f, 0.0f)); + vertices[2] = b2Mul(xf1, b2Vec2(0.0f, 0.5f)); + triangle1.Set(vertices, 3); + + b2Transform xf2; + xf2.q.Set(-0.3524f * b2_pi); + xf2.p = -xf2.q.GetXAxis(); + + b2PolygonShape triangle2; + vertices[0] = b2Mul(xf2, b2Vec2(-1.0f, 0.0f)); + vertices[1] = b2Mul(xf2, b2Vec2(1.0f, 0.0f)); + vertices[2] = b2Mul(xf2, b2Vec2(0.0f, 0.5f)); + triangle2.Set(vertices, 3); + + for (int32 i = 0; i < 10; ++i) + { + float32 x = RandomFloat(-0.1f, 0.1f); + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(x, 2.05f + 2.5f * i); + bd.angle = 0.0f; + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&triangle1, 2.0f); + body->CreateFixture(&triangle2, 2.0f); + } + } + + { + b2PolygonShape bottom; + bottom.SetAsBox( 1.5f, 0.15f ); + + b2PolygonShape left; + left.SetAsBox(0.15f, 2.7f, b2Vec2(-1.45f, 2.35f), 0.2f); + + b2PolygonShape right; + right.SetAsBox(0.15f, 2.7f, b2Vec2(1.45f, 2.35f), -0.2f); + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set( 0.0f, 2.0f ); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&bottom, 4.0f); + body->CreateFixture(&left, 4.0f); + body->CreateFixture(&right, 4.0f); + } + } + + static Test* Create() + { + return new CompoundShapes; + } +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Confined.h b/tests/Box2D_v2.2.1/Testbed/Tests/Confined.h new file mode 100755 index 0000000000000..f2d205eba680f --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Confined.h @@ -0,0 +1,167 @@ +/* +* Copyright (c) 2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef CONFINED_H +#define CONFINED_H + +class Confined : public Test +{ +public: + + enum + { + e_columnCount = 0, + e_rowCount = 0 + }; + + Confined() + { + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + + // Floor + shape.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + + // Left wall + shape.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(-10.0f, 20.0f)); + ground->CreateFixture(&shape, 0.0f); + + // Right wall + shape.Set(b2Vec2(10.0f, 0.0f), b2Vec2(10.0f, 20.0f)); + ground->CreateFixture(&shape, 0.0f); + + // Roof + shape.Set(b2Vec2(-10.0f, 20.0f), b2Vec2(10.0f, 20.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + float32 radius = 0.5f; + b2CircleShape shape; + shape.m_p.SetZero(); + shape.m_radius = radius; + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 1.0f; + fd.friction = 0.1f; + + for (int32 j = 0; j < e_columnCount; ++j) + { + for (int i = 0; i < e_rowCount; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-10.0f + (2.1f * j + 1.0f + 0.01f * i) * radius, (2.0f * i + 1.0f) * radius); + b2Body* body = m_world->CreateBody(&bd); + + body->CreateFixture(&fd); + } + } + + m_world->SetGravity(b2Vec2(0.0f, 0.0f)); + } + + void CreateCircle() + { + float32 radius = 2.0f; + b2CircleShape shape; + shape.m_p.SetZero(); + shape.m_radius = radius; + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 1.0f; + fd.friction = 0.0f; + + b2Vec2 p(RandomFloat(), 3.0f + RandomFloat()); + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position = p; + //bd.allowSleep = false; + b2Body* body = m_world->CreateBody(&bd); + + body->CreateFixture(&fd); + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'c': + CreateCircle(); + break; + } + } + + void Step(Settings* settings) + { + bool sleeping = true; + for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext()) + { + if (b->GetType() != b2_dynamicBody) + { + continue; + } + + if (b->IsAwake()) + { + sleeping = false; + } + } + + if (m_stepCount == 180) + { + m_stepCount += 0; + } + + //if (sleeping) + //{ + // CreateCircle(); + //} + + Test::Step(settings); + + for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext()) + { + if (b->GetType() != b2_dynamicBody) + { + continue; + } + + b2Vec2 p = b->GetPosition(); + if (p.x <= -10.0f || 10.0f <= p.x || p.y <= 0.0f || 20.0f <= p.y) + { + p.x += 0.0; + } + } + + m_debugDraw.DrawString(5, m_textLine, "Press 'c' to create a circle."); + m_textLine += 15; + } + + static Test* Create() + { + return new Confined; + } +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/ContinuousTest.h b/tests/Box2D_v2.2.1/Testbed/Tests/ContinuousTest.h new file mode 100755 index 0000000000000..817103a5e9311 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/ContinuousTest.h @@ -0,0 +1,137 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef CONTINUOUS_TEST_H +#define CONTINUOUS_TEST_H + +class ContinuousTest : public Test +{ +public: + + ContinuousTest() + { + { + b2BodyDef bd; + bd.position.Set(0.0f, 0.0f); + b2Body* body = m_world->CreateBody(&bd); + + b2EdgeShape edge; + + edge.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f)); + body->CreateFixture(&edge, 0.0f); + + b2PolygonShape shape; + shape.SetAsBox(0.2f, 1.0f, b2Vec2(0.5f, 1.0f), 0.0f); + body->CreateFixture(&shape, 0.0f); + } + +#if 1 + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.0f, 20.0f); + //bd.angle = 0.1f; + + b2PolygonShape shape; + shape.SetAsBox(2.0f, 0.1f); + + m_body = m_world->CreateBody(&bd); + m_body->CreateFixture(&shape, 1.0f); + + m_angularVelocity = RandomFloat(-50.0f, 50.0f); + //m_angularVelocity = 46.661274f; + m_body->SetLinearVelocity(b2Vec2(0.0f, -100.0f)); + m_body->SetAngularVelocity(m_angularVelocity); + } +#else + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.0f, 2.0f); + b2Body* body = m_world->CreateBody(&bd); + + b2CircleShape shape; + shape.m_p.SetZero(); + shape.m_radius = 0.5f; + body->CreateFixture(&shape, 1.0f); + + bd.bullet = true; + bd.position.Set(0.0f, 10.0f); + body = m_world->CreateBody(&bd); + body->CreateFixture(&shape, 1.0f); + body->SetLinearVelocity(b2Vec2(0.0f, -100.0f)); + } +#endif + } + + void Launch() + { + m_body->SetTransform(b2Vec2(0.0f, 20.0f), 0.0f); + m_angularVelocity = RandomFloat(-50.0f, 50.0f); + m_body->SetLinearVelocity(b2Vec2(0.0f, -100.0f)); + m_body->SetAngularVelocity(m_angularVelocity); + } + + void Step(Settings* settings) + { + if (m_stepCount == 12) + { + m_stepCount += 0; + } + + Test::Step(settings); + + extern int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters; + + if (b2_gjkCalls > 0) + { + m_debugDraw.DrawString(5, m_textLine, "gjk calls = %d, ave gjk iters = %3.1f, max gjk iters = %d", + b2_gjkCalls, b2_gjkIters / float32(b2_gjkCalls), b2_gjkMaxIters); + m_textLine += 15; + } + + extern int32 b2_toiCalls, b2_toiIters; + extern int32 b2_toiRootIters, b2_toiMaxRootIters; + + if (b2_toiCalls > 0) + { + m_debugDraw.DrawString(5, m_textLine, "toi calls = %d, ave toi iters = %3.1f, max toi iters = %d", + b2_toiCalls, b2_toiIters / float32(b2_toiCalls), b2_toiMaxRootIters); + m_textLine += 15; + + m_debugDraw.DrawString(5, m_textLine, "ave toi root iters = %3.1f, max toi root iters = %d", + b2_toiRootIters / float32(b2_toiCalls), b2_toiMaxRootIters); + m_textLine += 15; + } + + if (m_stepCount % 60 == 0) + { + //Launch(); + } + } + + static Test* Create() + { + return new ContinuousTest; + } + + b2Body* m_body; + float32 m_angularVelocity; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/DistanceTest.h b/tests/Box2D_v2.2.1/Testbed/Tests/DistanceTest.h new file mode 100755 index 0000000000000..81e96de3bc75f --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/DistanceTest.h @@ -0,0 +1,135 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef DISTANCE_TEST_H +#define DISTANCE_TEST_H + +class DistanceTest : public Test +{ +public: + DistanceTest() + { + { + m_transformA.SetIdentity(); + m_transformA.p.Set(0.0f, -0.2f); + m_polygonA.SetAsBox(10.0f, 0.2f); + } + + { + m_positionB.Set(12.017401f, 0.13678508f); + m_angleB = -0.0109265f; + m_transformB.Set(m_positionB, m_angleB); + + m_polygonB.SetAsBox(2.0f, 0.1f); + } + } + + static Test* Create() + { + return new DistanceTest; + } + + void Step(Settings* settings) + { + Test::Step(settings); + + b2DistanceInput input; + input.proxyA.Set(&m_polygonA, 0); + input.proxyB.Set(&m_polygonB, 0); + input.transformA = m_transformA; + input.transformB = m_transformB; + input.useRadii = true; + b2SimplexCache cache; + cache.count = 0; + b2DistanceOutput output; + b2Distance(&output, &cache, &input); + + m_debugDraw.DrawString(5, m_textLine, "distance = %g", output.distance); + m_textLine += 15; + + m_debugDraw.DrawString(5, m_textLine, "iterations = %d", output.iterations); + m_textLine += 15; + + { + b2Color color(0.9f, 0.9f, 0.9f); + b2Vec2 v[b2_maxPolygonVertices]; + for (int32 i = 0; i < m_polygonA.m_vertexCount; ++i) + { + v[i] = b2Mul(m_transformA, m_polygonA.m_vertices[i]); + } + m_debugDraw.DrawPolygon(v, m_polygonA.m_vertexCount, color); + + for (int32 i = 0; i < m_polygonB.m_vertexCount; ++i) + { + v[i] = b2Mul(m_transformB, m_polygonB.m_vertices[i]); + } + m_debugDraw.DrawPolygon(v, m_polygonB.m_vertexCount, color); + } + + b2Vec2 x1 = output.pointA; + b2Vec2 x2 = output.pointB; + + b2Color c1(1.0f, 0.0f, 0.0f); + m_debugDraw.DrawPoint(x1, 4.0f, c1); + + b2Color c2(1.0f, 1.0f, 0.0f); + m_debugDraw.DrawPoint(x2, 4.0f, c2); + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'a': + m_positionB.x -= 0.1f; + break; + + case 'd': + m_positionB.x += 0.1f; + break; + + case 's': + m_positionB.y -= 0.1f; + break; + + case 'w': + m_positionB.y += 0.1f; + break; + + case 'q': + m_angleB += 0.1f * b2_pi; + break; + + case 'e': + m_angleB -= 0.1f * b2_pi; + break; + } + + m_transformB.Set(m_positionB, m_angleB); + } + + b2Vec2 m_positionB; + float32 m_angleB; + + b2Transform m_transformA; + b2Transform m_transformB; + b2PolygonShape m_polygonA; + b2PolygonShape m_polygonB; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Dominos.h b/tests/Box2D_v2.2.1/Testbed/Tests/Dominos.h new file mode 100755 index 0000000000000..01e8bbdb5e855 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Dominos.h @@ -0,0 +1,215 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef DOMINOS_H +#define DOMINOS_H + +class Dominos : public Test +{ +public: + + Dominos() + { + b2Body* b1; + { + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + + b2BodyDef bd; + b1 = m_world->CreateBody(&bd); + b1->CreateFixture(&shape, 0.0f); + } + + { + b2PolygonShape shape; + shape.SetAsBox(6.0f, 0.25f); + + b2BodyDef bd; + bd.position.Set(-1.5f, 10.0f); + b2Body* ground = m_world->CreateBody(&bd); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2PolygonShape shape; + shape.SetAsBox(0.1f, 1.0f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + fd.friction = 0.1f; + + for (int i = 0; i < 10; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-6.0f + 1.0f * i, 11.25f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + } + } + + { + b2PolygonShape shape; + shape.SetAsBox(7.0f, 0.25f, b2Vec2_zero, 0.3f); + + b2BodyDef bd; + bd.position.Set(1.0f, 6.0f); + b2Body* ground = m_world->CreateBody(&bd); + ground->CreateFixture(&shape, 0.0f); + } + + b2Body* b2; + { + b2PolygonShape shape; + shape.SetAsBox(0.25f, 1.5f); + + b2BodyDef bd; + bd.position.Set(-7.0f, 4.0f); + b2 = m_world->CreateBody(&bd); + b2->CreateFixture(&shape, 0.0f); + } + + b2Body* b3; + { + b2PolygonShape shape; + shape.SetAsBox(6.0f, 0.125f); + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-0.9f, 1.0f); + bd.angle = -0.15f; + + b3 = m_world->CreateBody(&bd); + b3->CreateFixture(&shape, 10.0f); + } + + b2RevoluteJointDef jd; + b2Vec2 anchor; + + anchor.Set(-2.0f, 1.0f); + jd.Initialize(b1, b3, anchor); + jd.collideConnected = true; + m_world->CreateJoint(&jd); + + b2Body* b4; + { + b2PolygonShape shape; + shape.SetAsBox(0.25f, 0.25f); + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-10.0f, 15.0f); + b4 = m_world->CreateBody(&bd); + b4->CreateFixture(&shape, 10.0f); + } + + anchor.Set(-7.0f, 15.0f); + jd.Initialize(b2, b4, anchor); + m_world->CreateJoint(&jd); + + b2Body* b5; + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(6.5f, 3.0f); + b5 = m_world->CreateBody(&bd); + + b2PolygonShape shape; + b2FixtureDef fd; + + fd.shape = &shape; + fd.density = 10.0f; + fd.friction = 0.1f; + + shape.SetAsBox(1.0f, 0.1f, b2Vec2(0.0f, -0.9f), 0.0f); + b5->CreateFixture(&fd); + + shape.SetAsBox(0.1f, 1.0f, b2Vec2(-0.9f, 0.0f), 0.0f); + b5->CreateFixture(&fd); + + shape.SetAsBox(0.1f, 1.0f, b2Vec2(0.9f, 0.0f), 0.0f); + b5->CreateFixture(&fd); + } + + anchor.Set(6.0f, 2.0f); + jd.Initialize(b1, b5, anchor); + m_world->CreateJoint(&jd); + + b2Body* b6; + { + b2PolygonShape shape; + shape.SetAsBox(1.0f, 0.1f); + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(6.5f, 4.1f); + b6 = m_world->CreateBody(&bd); + b6->CreateFixture(&shape, 30.0f); + } + + anchor.Set(7.5f, 4.0f); + jd.Initialize(b5, b6, anchor); + m_world->CreateJoint(&jd); + + b2Body* b7; + { + b2PolygonShape shape; + shape.SetAsBox(0.1f, 1.0f); + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(7.4f, 1.0f); + + b7 = m_world->CreateBody(&bd); + b7->CreateFixture(&shape, 10.0f); + } + + b2DistanceJointDef djd; + djd.bodyA = b3; + djd.bodyB = b7; + djd.localAnchorA.Set(6.0f, 0.0f); + djd.localAnchorB.Set(0.0f, -1.0f); + b2Vec2 d = djd.bodyB->GetWorldPoint(djd.localAnchorB) - djd.bodyA->GetWorldPoint(djd.localAnchorA); + djd.length = d.Length(); + m_world->CreateJoint(&djd); + + { + float32 radius = 0.2f; + + b2CircleShape shape; + shape.m_radius = radius; + + for (int32 i = 0; i < 4; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(5.9f + 2.0f * radius * i, 2.4f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&shape, 10.0f); + } + } + } + + static Test* Create() + { + return new Dominos; + } +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/DumpShell.h b/tests/Box2D_v2.2.1/Testbed/Tests/DumpShell.h new file mode 100755 index 0000000000000..8437687d50d20 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/DumpShell.h @@ -0,0 +1,267 @@ +/* +* Copyright (c) 2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef DUMP_SHELL_H +#define DUMP_SHELL_H + +// This test holds worlds dumped using b2World::Dump. +class DumpShell : public Test +{ +public: + + DumpShell() + { + +b2Vec2 g(0.000000000000000e+00f, 0.000000000000000e+00f); +m_world->SetGravity(g); +b2Body** bodies = (b2Body**)b2Alloc(3 * sizeof(b2Body*)); +b2Joint** joints = (b2Joint**)b2Alloc(2 * sizeof(b2Joint*)); +{ + b2BodyDef bd; + bd.type = b2BodyType(2); + bd.position.Set(1.304347801208496e+01f, 2.500000000000000e+00f); + bd.angle = 0.000000000000000e+00f; + bd.linearVelocity.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + bd.angularVelocity = 0.000000000000000e+00f; + bd.linearDamping = 5.000000000000000e-01f; + bd.angularDamping = 5.000000000000000e-01f; + bd.allowSleep = bool(4); + bd.awake = bool(2); + bd.fixedRotation = bool(0); + bd.bullet = bool(0); + bd.active = bool(32); + bd.gravityScale = 1.000000000000000e+00f; + bodies[0] = m_world->CreateBody(&bd); + + { + b2FixtureDef fd; + fd.friction = 1.000000000000000e+00f; + fd.restitution = 5.000000000000000e-01f; + fd.density = 1.000000000000000e+01f; + fd.isSensor = bool(0); + fd.filter.categoryBits = uint16(1); + fd.filter.maskBits = uint16(65535); + fd.filter.groupIndex = int16(0); + b2PolygonShape shape; + b2Vec2 vs[8]; + vs[0].Set(-6.900000095367432e+00f, -3.000000119209290e-01f); + vs[1].Set(2.000000029802322e-01f, -3.000000119209290e-01f); + vs[2].Set(2.000000029802322e-01f, 2.000000029802322e-01f); + vs[3].Set(-6.900000095367432e+00f, 2.000000029802322e-01f); + shape.Set(vs, 4); + + fd.shape = &shape; + + bodies[0]->CreateFixture(&fd); + } +} +{ + b2BodyDef bd; + bd.type = b2BodyType(2); + bd.position.Set(8.478260636329651e-01f, 2.500000000000000e+00f); + bd.angle = 0.000000000000000e+00f; + bd.linearVelocity.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + bd.angularVelocity = 0.000000000000000e+00f; + bd.linearDamping = 5.000000000000000e-01f; + bd.angularDamping = 5.000000000000000e-01f; + bd.allowSleep = bool(4); + bd.awake = bool(2); + bd.fixedRotation = bool(0); + bd.bullet = bool(0); + bd.active = bool(32); + bd.gravityScale = 1.000000000000000e+00f; + bodies[1] = m_world->CreateBody(&bd); + + { + b2FixtureDef fd; + fd.friction = 1.000000000000000e+00f; + fd.restitution = 5.000000000000000e-01f; + fd.density = 1.000000000000000e+01f; + fd.isSensor = bool(0); + fd.filter.categoryBits = uint16(1); + fd.filter.maskBits = uint16(65535); + fd.filter.groupIndex = int16(0); + b2PolygonShape shape; + b2Vec2 vs[8]; + vs[0].Set(-3.228000104427338e-01f, -2.957000136375427e-01f); + vs[1].Set(6.885900020599365e+00f, -3.641000092029572e-01f); + vs[2].Set(6.907599925994873e+00f, 3.271999955177307e-01f); + vs[3].Set(-3.228000104427338e-01f, 2.825999855995178e-01f); + shape.Set(vs, 4); + + fd.shape = &shape; + + bodies[1]->CreateFixture(&fd); + } +} + +{ + b2BodyDef bd; + bd.type = b2BodyType(0); + bd.position.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + bd.angle = 0.000000000000000e+00f; + bd.linearVelocity.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + bd.angularVelocity = 0.000000000000000e+00f; + bd.linearDamping = 0.000000000000000e+00f; + bd.angularDamping = 0.000000000000000e+00f; + bd.allowSleep = bool(4); + bd.awake = bool(2); + bd.fixedRotation = bool(0); + bd.bullet = bool(0); + bd.active = bool(32); + bd.gravityScale = 1.000000000000000e+00f; + bodies[2] = m_world->CreateBody(&bd); + + { + b2FixtureDef fd; + fd.friction = 1.000000000000000e+01f; + fd.restitution = 0.000000000000000e+00f; + fd.density = 0.000000000000000e+00f; + fd.isSensor = bool(0); + fd.filter.categoryBits = uint16(1); + fd.filter.maskBits = uint16(65535); + fd.filter.groupIndex = int16(0); + b2EdgeShape shape; + shape.m_radius = 9.999999776482582e-03f; + shape.m_vertex0.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + shape.m_vertex1.Set(4.452173995971680e+01f, 1.669565200805664e+01f); + shape.m_vertex2.Set(4.452173995971680e+01f, 0.000000000000000e+00f); + shape.m_vertex3.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + shape.m_hasVertex0 = bool(0); + shape.m_hasVertex3 = bool(0); + + fd.shape = &shape; + + bodies[2]->CreateFixture(&fd); + } + { + b2FixtureDef fd; + fd.friction = 1.000000000000000e+01f; + fd.restitution = 0.000000000000000e+00f; + fd.density = 0.000000000000000e+00f; + fd.isSensor = bool(0); + fd.filter.categoryBits = uint16(1); + fd.filter.maskBits = uint16(65535); + fd.filter.groupIndex = int16(0); + b2EdgeShape shape; + shape.m_radius = 9.999999776482582e-03f; + shape.m_vertex0.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + shape.m_vertex1.Set(0.000000000000000e+00f, 1.669565200805664e+01f); + shape.m_vertex2.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + shape.m_vertex3.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + shape.m_hasVertex0 = bool(0); + shape.m_hasVertex3 = bool(0); + + fd.shape = &shape; + + bodies[2]->CreateFixture(&fd); + } + { + b2FixtureDef fd; + fd.friction = 1.000000000000000e+01f; + fd.restitution = 0.000000000000000e+00f; + fd.density = 0.000000000000000e+00f; + fd.isSensor = bool(0); + fd.filter.categoryBits = uint16(1); + fd.filter.maskBits = uint16(65535); + fd.filter.groupIndex = int16(0); + b2EdgeShape shape; + shape.m_radius = 9.999999776482582e-03f; + shape.m_vertex0.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + shape.m_vertex1.Set(0.000000000000000e+00f, 1.669565200805664e+01f); + shape.m_vertex2.Set(4.452173995971680e+01f, 1.669565200805664e+01f); + shape.m_vertex3.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + shape.m_hasVertex0 = bool(0); + shape.m_hasVertex3 = bool(0); + + fd.shape = &shape; + + bodies[2]->CreateFixture(&fd); + } + { + b2FixtureDef fd; + fd.friction = 1.000000000000000e+01f; + fd.restitution = 0.000000000000000e+00f; + fd.density = 0.000000000000000e+00f; + fd.isSensor = bool(0); + fd.filter.categoryBits = uint16(1); + fd.filter.maskBits = uint16(65535); + fd.filter.groupIndex = int16(0); + b2EdgeShape shape; + shape.m_radius = 9.999999776482582e-03f; + shape.m_vertex0.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + shape.m_vertex1.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + shape.m_vertex2.Set(4.452173995971680e+01f, 0.000000000000000e+00f); + shape.m_vertex3.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + shape.m_hasVertex0 = bool(0); + shape.m_hasVertex3 = bool(0); + + fd.shape = &shape; + + bodies[2]->CreateFixture(&fd); + } +} + +{ + b2PrismaticJointDef jd; + jd.bodyA = bodies[1]; + jd.bodyB = bodies[0]; + jd.collideConnected = bool(0); + jd.localAnchorA.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + jd.localAnchorB.Set(-1.219565200805664e+01f, 0.000000000000000e+00f); + jd.localAxisA.Set(-1.219565200805664e+01f, 0.000000000000000e+00f); + jd.referenceAngle = 0.000000000000000e+00f; + jd.enableLimit = bool(1); + jd.lowerTranslation = -2.000000000000000e+01f; + jd.upperTranslation = 0.000000000000000e+00f; + jd.enableMotor = bool(1); + jd.motorSpeed = 0.000000000000000e+00f; + jd.maxMotorForce = 1.000000000000000e+01f; + joints[0] = m_world->CreateJoint(&jd); +} +{ + b2RevoluteJointDef jd; + jd.bodyA = bodies[1]; + jd.bodyB = bodies[2]; + jd.collideConnected = bool(0); + jd.localAnchorA.Set(0.000000000000000e+00f, 0.000000000000000e+00f); + jd.localAnchorB.Set(8.478260636329651e-01f, 2.500000000000000e+00f); + jd.referenceAngle = 0.000000000000000e+00f; + jd.enableLimit = bool(0); + jd.lowerAngle = 0.000000000000000e+00f; + jd.upperAngle = 0.000000000000000e+00f; + jd.enableMotor = bool(0); + jd.motorSpeed = 0.000000000000000e+00f; + jd.maxMotorTorque = 0.000000000000000e+00f; + joints[1] = m_world->CreateJoint(&jd); +} +b2Free(joints); +b2Free(bodies); +joints = NULL; +bodies = NULL; + + + } + + static Test* Create() + { + return new DumpShell; + } +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/DynamicTreeTest.h b/tests/Box2D_v2.2.1/Testbed/Tests/DynamicTreeTest.h new file mode 100755 index 0000000000000..4456a39618e45 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/DynamicTreeTest.h @@ -0,0 +1,357 @@ +/* +* Copyright (c) 2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef DYNAMIC_TREE_TEST_H +#define DYNAMIC_TREE_TEST_H + +class DynamicTreeTest : public Test +{ +public: + + enum + { + e_actorCount = 128 + }; + + DynamicTreeTest() + { + m_worldExtent = 15.0f; + m_proxyExtent = 0.5f; + + srand(888); + + for (int32 i = 0; i < e_actorCount; ++i) + { + Actor* actor = m_actors + i; + GetRandomAABB(&actor->aabb); + actor->proxyId = m_tree.CreateProxy(actor->aabb, actor); + } + + m_stepCount = 0; + + float32 h = m_worldExtent; + m_queryAABB.lowerBound.Set(-3.0f, -4.0f + h); + m_queryAABB.upperBound.Set(5.0f, 6.0f + h); + + m_rayCastInput.p1.Set(-5.0, 5.0f + h); + m_rayCastInput.p2.Set(7.0f, -4.0f + h); + //m_rayCastInput.p1.Set(0.0f, 2.0f + h); + //m_rayCastInput.p2.Set(0.0f, -2.0f + h); + m_rayCastInput.maxFraction = 1.0f; + + m_automated = false; + } + + static Test* Create() + { + return new DynamicTreeTest; + } + + void Step(Settings* settings) + { + B2_NOT_USED(settings); + + m_rayActor = NULL; + for (int32 i = 0; i < e_actorCount; ++i) + { + m_actors[i].fraction = 1.0f; + m_actors[i].overlap = false; + } + + if (m_automated == true) + { + int32 actionCount = b2Max(1, e_actorCount >> 2); + + for (int32 i = 0; i < actionCount; ++i) + { + Action(); + } + } + + Query(); + RayCast(); + + for (int32 i = 0; i < e_actorCount; ++i) + { + Actor* actor = m_actors + i; + if (actor->proxyId == b2_nullNode) + continue; + + b2Color c(0.9f, 0.9f, 0.9f); + if (actor == m_rayActor && actor->overlap) + { + c.Set(0.9f, 0.6f, 0.6f); + } + else if (actor == m_rayActor) + { + c.Set(0.6f, 0.9f, 0.6f); + } + else if (actor->overlap) + { + c.Set(0.6f, 0.6f, 0.9f); + } + + m_debugDraw.DrawAABB(&actor->aabb, c); + } + + b2Color c(0.7f, 0.7f, 0.7f); + m_debugDraw.DrawAABB(&m_queryAABB, c); + + m_debugDraw.DrawSegment(m_rayCastInput.p1, m_rayCastInput.p2, c); + + b2Color c1(0.2f, 0.9f, 0.2f); + b2Color c2(0.9f, 0.2f, 0.2f); + m_debugDraw.DrawPoint(m_rayCastInput.p1, 6.0f, c1); + m_debugDraw.DrawPoint(m_rayCastInput.p2, 6.0f, c2); + + if (m_rayActor) + { + b2Color cr(0.2f, 0.2f, 0.9f); + b2Vec2 p = m_rayCastInput.p1 + m_rayActor->fraction * (m_rayCastInput.p2 - m_rayCastInput.p1); + m_debugDraw.DrawPoint(p, 6.0f, cr); + } + + { + int32 height = m_tree.GetHeight(); + m_debugDraw.DrawString(5, m_textLine, "dynamic tree height = %d", height); + m_textLine += 15; + } + + ++m_stepCount; + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'a': + m_automated = !m_automated; + break; + + case 'c': + CreateProxy(); + break; + + case 'd': + DestroyProxy(); + break; + + case 'm': + MoveProxy(); + break; + } + } + + bool QueryCallback(int32 proxyId) + { + Actor* actor = (Actor*)m_tree.GetUserData(proxyId); + actor->overlap = b2TestOverlap(m_queryAABB, actor->aabb); + return true; + } + + float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId) + { + Actor* actor = (Actor*)m_tree.GetUserData(proxyId); + + b2RayCastOutput output; + bool hit = actor->aabb.RayCast(&output, input); + + if (hit) + { + m_rayCastOutput = output; + m_rayActor = actor; + m_rayActor->fraction = output.fraction; + return output.fraction; + } + + return input.maxFraction; + } + +private: + + struct Actor + { + b2AABB aabb; + float32 fraction; + bool overlap; + int32 proxyId; + }; + + void GetRandomAABB(b2AABB* aabb) + { + b2Vec2 w; w.Set(2.0f * m_proxyExtent, 2.0f * m_proxyExtent); + //aabb->lowerBound.x = -m_proxyExtent; + //aabb->lowerBound.y = -m_proxyExtent + m_worldExtent; + aabb->lowerBound.x = RandomFloat(-m_worldExtent, m_worldExtent); + aabb->lowerBound.y = RandomFloat(0.0f, 2.0f * m_worldExtent); + aabb->upperBound = aabb->lowerBound + w; + } + + void MoveAABB(b2AABB* aabb) + { + b2Vec2 d; + d.x = RandomFloat(-0.5f, 0.5f); + d.y = RandomFloat(-0.5f, 0.5f); + //d.x = 2.0f; + //d.y = 0.0f; + aabb->lowerBound += d; + aabb->upperBound += d; + + b2Vec2 c0 = 0.5f * (aabb->lowerBound + aabb->upperBound); + b2Vec2 min; min.Set(-m_worldExtent, 0.0f); + b2Vec2 max; max.Set(m_worldExtent, 2.0f * m_worldExtent); + b2Vec2 c = b2Clamp(c0, min, max); + + aabb->lowerBound += c - c0; + aabb->upperBound += c - c0; + } + + void CreateProxy() + { + for (int32 i = 0; i < e_actorCount; ++i) + { + int32 j = rand() % e_actorCount; + Actor* actor = m_actors + j; + if (actor->proxyId == b2_nullNode) + { + GetRandomAABB(&actor->aabb); + actor->proxyId = m_tree.CreateProxy(actor->aabb, actor); + return; + } + } + } + + void DestroyProxy() + { + for (int32 i = 0; i < e_actorCount; ++i) + { + int32 j = rand() % e_actorCount; + Actor* actor = m_actors + j; + if (actor->proxyId != b2_nullNode) + { + m_tree.DestroyProxy(actor->proxyId); + actor->proxyId = b2_nullNode; + return; + } + } + } + + void MoveProxy() + { + for (int32 i = 0; i < e_actorCount; ++i) + { + int32 j = rand() % e_actorCount; + Actor* actor = m_actors + j; + if (actor->proxyId == b2_nullNode) + { + continue; + } + + b2AABB aabb0 = actor->aabb; + MoveAABB(&actor->aabb); + b2Vec2 displacement = actor->aabb.GetCenter() - aabb0.GetCenter(); + m_tree.MoveProxy(actor->proxyId, actor->aabb, displacement); + return; + } + } + + void Action() + { + int32 choice = rand() % 20; + + switch (choice) + { + case 0: + CreateProxy(); + break; + + case 1: + DestroyProxy(); + break; + + default: + MoveProxy(); + } + } + + void Query() + { + m_tree.Query(this, m_queryAABB); + + for (int32 i = 0; i < e_actorCount; ++i) + { + if (m_actors[i].proxyId == b2_nullNode) + { + continue; + } + + bool overlap = b2TestOverlap(m_queryAABB, m_actors[i].aabb); + B2_NOT_USED(overlap); + b2Assert(overlap == m_actors[i].overlap); + } + } + + void RayCast() + { + m_rayActor = NULL; + + b2RayCastInput input = m_rayCastInput; + + // Ray cast against the dynamic tree. + m_tree.RayCast(this, input); + + // Brute force ray cast. + Actor* bruteActor = NULL; + b2RayCastOutput bruteOutput; + for (int32 i = 0; i < e_actorCount; ++i) + { + if (m_actors[i].proxyId == b2_nullNode) + { + continue; + } + + b2RayCastOutput output; + bool hit = m_actors[i].aabb.RayCast(&output, input); + if (hit) + { + bruteActor = m_actors + i; + bruteOutput = output; + input.maxFraction = output.fraction; + } + } + + if (bruteActor != NULL) + { + b2Assert(bruteOutput.fraction == m_rayCastOutput.fraction); + } + } + + float32 m_worldExtent; + float32 m_proxyExtent; + + b2DynamicTree m_tree; + b2AABB m_queryAABB; + b2RayCastInput m_rayCastInput; + b2RayCastOutput m_rayCastOutput; + Actor* m_rayActor; + Actor m_actors[e_actorCount]; + int32 m_stepCount; + bool m_automated; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/EdgeShapes.h b/tests/Box2D_v2.2.1/Testbed/Tests/EdgeShapes.h new file mode 100755 index 0000000000000..56a6d6277073c --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/EdgeShapes.h @@ -0,0 +1,249 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef EDGE_SHAPES_H +#define EDGE_SHAPES_H + +class EdgeShapesCallback : public b2RayCastCallback +{ +public: + EdgeShapesCallback() + { + m_fixture = NULL; + } + + float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point, + const b2Vec2& normal, float32 fraction) + { + m_fixture = fixture; + m_point = point; + m_normal = normal; + + return fraction; + } + + b2Fixture* m_fixture; + b2Vec2 m_point; + b2Vec2 m_normal; +}; + +class EdgeShapes : public Test +{ +public: + + enum + { + e_maxBodies = 256 + }; + + EdgeShapes() + { + // Ground body + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + float32 x1 = -20.0f; + float32 y1 = 2.0f * cosf(x1 / 10.0f * b2_pi); + for (int32 i = 0; i < 80; ++i) + { + float32 x2 = x1 + 0.5f; + float32 y2 = 2.0f * cosf(x2 / 10.0f * b2_pi); + + b2EdgeShape shape; + shape.Set(b2Vec2(x1, y1), b2Vec2(x2, y2)); + ground->CreateFixture(&shape, 0.0f); + + x1 = x2; + y1 = y2; + } + } + + { + b2Vec2 vertices[3]; + vertices[0].Set(-0.5f, 0.0f); + vertices[1].Set(0.5f, 0.0f); + vertices[2].Set(0.0f, 1.5f); + m_polygons[0].Set(vertices, 3); + } + + { + b2Vec2 vertices[3]; + vertices[0].Set(-0.1f, 0.0f); + vertices[1].Set(0.1f, 0.0f); + vertices[2].Set(0.0f, 1.5f); + m_polygons[1].Set(vertices, 3); + } + + { + float32 w = 1.0f; + float32 b = w / (2.0f + b2Sqrt(2.0f)); + float32 s = b2Sqrt(2.0f) * b; + + b2Vec2 vertices[8]; + vertices[0].Set(0.5f * s, 0.0f); + vertices[1].Set(0.5f * w, b); + vertices[2].Set(0.5f * w, b + s); + vertices[3].Set(0.5f * s, w); + vertices[4].Set(-0.5f * s, w); + vertices[5].Set(-0.5f * w, b + s); + vertices[6].Set(-0.5f * w, b); + vertices[7].Set(-0.5f * s, 0.0f); + + m_polygons[2].Set(vertices, 8); + } + + { + m_polygons[3].SetAsBox(0.5f, 0.5f); + } + + { + m_circle.m_radius = 0.5f; + } + + m_bodyIndex = 0; + memset(m_bodies, 0, sizeof(m_bodies)); + + m_angle = 0.0f; + } + + void Create(int32 index) + { + if (m_bodies[m_bodyIndex] != NULL) + { + m_world->DestroyBody(m_bodies[m_bodyIndex]); + m_bodies[m_bodyIndex] = NULL; + } + + b2BodyDef bd; + + float32 x = RandomFloat(-10.0f, 10.0f); + float32 y = RandomFloat(10.0f, 20.0f); + bd.position.Set(x, y); + bd.angle = RandomFloat(-b2_pi, b2_pi); + bd.type = b2_dynamicBody; + + if (index == 4) + { + bd.angularDamping = 0.02f; + } + + m_bodies[m_bodyIndex] = m_world->CreateBody(&bd); + + if (index < 4) + { + b2FixtureDef fd; + fd.shape = m_polygons + index; + fd.friction = 0.3f; + fd.density = 20.0f; + m_bodies[m_bodyIndex]->CreateFixture(&fd); + } + else + { + b2FixtureDef fd; + fd.shape = &m_circle; + fd.friction = 0.3f; + fd.density = 20.0f; + m_bodies[m_bodyIndex]->CreateFixture(&fd); + } + + m_bodyIndex = (m_bodyIndex + 1) % e_maxBodies; + } + + void DestroyBody() + { + for (int32 i = 0; i < e_maxBodies; ++i) + { + if (m_bodies[i] != NULL) + { + m_world->DestroyBody(m_bodies[i]); + m_bodies[i] = NULL; + return; + } + } + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case '1': + case '2': + case '3': + case '4': + case '5': + Create(key - '1'); + break; + + case 'd': + DestroyBody(); + break; + } + } + + void Step(Settings* settings) + { + bool advanceRay = settings->pause == 0 || settings->singleStep; + + Test::Step(settings); + m_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff"); + m_textLine += 15; + + float32 L = 25.0f; + b2Vec2 point1(0.0f, 10.0f); + b2Vec2 d(L * cosf(m_angle), -L * b2Abs(sinf(m_angle))); + b2Vec2 point2 = point1 + d; + + EdgeShapesCallback callback; + + m_world->RayCast(&callback, point1, point2); + + if (callback.m_fixture) + { + m_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f)); + + m_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f)); + + b2Vec2 head = callback.m_point + 0.5f * callback.m_normal; + m_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f)); + } + else + { + m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f)); + } + + if (advanceRay) + { + m_angle += 0.25f * b2_pi / 180.0f; + } + } + + static Test* Create() + { + return new EdgeShapes; + } + + int32 m_bodyIndex; + b2Body* m_bodies[e_maxBodies]; + b2PolygonShape m_polygons[4]; + b2CircleShape m_circle; + + float32 m_angle; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/EdgeTest.h b/tests/Box2D_v2.2.1/Testbed/Tests/EdgeTest.h new file mode 100755 index 0000000000000..2cabf2e302193 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/EdgeTest.h @@ -0,0 +1,109 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef EDGE_TEST_H +#define EDGE_TEST_H + +class EdgeTest : public Test +{ +public: + + EdgeTest() + { + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2Vec2 v1(-10.0f, 0.0f), v2(-7.0f, -2.0f), v3(-4.0f, 0.0f); + b2Vec2 v4(0.0f, 0.0f), v5(4.0f, 0.0f), v6(7.0f, 2.0f), v7(10.0f, 0.0f); + + b2EdgeShape shape; + + shape.Set(v1, v2); + shape.m_hasVertex3 = true; + shape.m_vertex3 = v3; + ground->CreateFixture(&shape, 0.0f); + + shape.Set(v2, v3); + shape.m_hasVertex0 = true; + shape.m_hasVertex3 = true; + shape.m_vertex0 = v1; + shape.m_vertex3 = v4; + ground->CreateFixture(&shape, 0.0f); + + shape.Set(v3, v4); + shape.m_hasVertex0 = true; + shape.m_hasVertex3 = true; + shape.m_vertex0 = v2; + shape.m_vertex3 = v5; + ground->CreateFixture(&shape, 0.0f); + + shape.Set(v4, v5); + shape.m_hasVertex0 = true; + shape.m_hasVertex3 = true; + shape.m_vertex0 = v3; + shape.m_vertex3 = v6; + ground->CreateFixture(&shape, 0.0f); + + shape.Set(v5, v6); + shape.m_hasVertex0 = true; + shape.m_hasVertex3 = true; + shape.m_vertex0 = v4; + shape.m_vertex3 = v7; + ground->CreateFixture(&shape, 0.0f); + + shape.Set(v6, v7); + shape.m_hasVertex0 = true; + shape.m_vertex0 = v5; + ground->CreateFixture(&shape, 0.0f); + } + + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-0.5f, 0.6f); + bd.allowSleep = false; + b2Body* body = m_world->CreateBody(&bd); + + b2CircleShape shape; + shape.m_radius = 0.5f; + + body->CreateFixture(&shape, 1.0f); + } + + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(1.0f, 0.6f); + bd.allowSleep = false; + b2Body* body = m_world->CreateBody(&bd); + + b2PolygonShape shape; + shape.SetAsBox(0.5f, 0.5f); + + body->CreateFixture(&shape, 1.0f); + } + } + + static Test* Create() + { + return new EdgeTest; + } +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Gears.h b/tests/Box2D_v2.2.1/Testbed/Tests/Gears.h new file mode 100755 index 0000000000000..c1bc795589d34 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Gears.h @@ -0,0 +1,187 @@ +/* +* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef GEARS_H +#define GEARS_H + +class Gears : public Test +{ +public: + Gears() + { + b2Body* ground = NULL; + { + b2BodyDef bd; + ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(50.0f, 0.0f), b2Vec2(-50.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + // Gears co + { + b2CircleShape circle1; + circle1.m_radius = 1.0f; + + b2PolygonShape box; + box.SetAsBox(0.5f, 5.0f); + + b2CircleShape circle2; + circle2.m_radius = 2.0f; + + b2BodyDef bd1; + bd1.type = b2_staticBody; + bd1.position.Set(10.0f, 9.0f); + b2Body* body1 = m_world->CreateBody(&bd1); + body1->CreateFixture(&circle1, 0.0f); + + b2BodyDef bd2; + bd2.type = b2_dynamicBody; + bd2.position.Set(10.0f, 8.0f); + b2Body* body2 = m_world->CreateBody(&bd2); + body2->CreateFixture(&box, 5.0f); + + b2BodyDef bd3; + bd3.type = b2_dynamicBody; + bd3.position.Set(10.0f, 6.0f); + b2Body* body3 = m_world->CreateBody(&bd3); + body3->CreateFixture(&circle2, 5.0f); + + b2RevoluteJointDef jd1; + jd1.Initialize(body2, body1, bd1.position); + b2Joint* joint1 = m_world->CreateJoint(&jd1); + + b2RevoluteJointDef jd2; + jd2.Initialize(body2, body3, bd3.position); + b2Joint* joint2 = m_world->CreateJoint(&jd2); + + b2GearJointDef jd4; + jd4.bodyA = body1; + jd4.bodyB = body3; + jd4.joint1 = joint1; + jd4.joint2 = joint2; + jd4.ratio = circle2.m_radius / circle1.m_radius; + m_world->CreateJoint(&jd4); + } + + { + b2CircleShape circle1; + circle1.m_radius = 1.0f; + + b2CircleShape circle2; + circle2.m_radius = 2.0f; + + b2PolygonShape box; + box.SetAsBox(0.5f, 5.0f); + + b2BodyDef bd1; + bd1.type = b2_dynamicBody; + bd1.position.Set(-3.0f, 12.0f); + b2Body* body1 = m_world->CreateBody(&bd1); + body1->CreateFixture(&circle1, 5.0f); + + b2RevoluteJointDef jd1; + jd1.bodyA = ground; + jd1.bodyB = body1; + jd1.localAnchorA = ground->GetLocalPoint(bd1.position); + jd1.localAnchorB = body1->GetLocalPoint(bd1.position); + jd1.referenceAngle = body1->GetAngle() - ground->GetAngle(); + m_joint1 = (b2RevoluteJoint*)m_world->CreateJoint(&jd1); + + b2BodyDef bd2; + bd2.type = b2_dynamicBody; + bd2.position.Set(0.0f, 12.0f); + b2Body* body2 = m_world->CreateBody(&bd2); + body2->CreateFixture(&circle2, 5.0f); + + b2RevoluteJointDef jd2; + jd2.Initialize(ground, body2, bd2.position); + m_joint2 = (b2RevoluteJoint*)m_world->CreateJoint(&jd2); + + b2BodyDef bd3; + bd3.type = b2_dynamicBody; + bd3.position.Set(2.5f, 12.0f); + b2Body* body3 = m_world->CreateBody(&bd3); + body3->CreateFixture(&box, 5.0f); + + b2PrismaticJointDef jd3; + jd3.Initialize(ground, body3, bd3.position, b2Vec2(0.0f, 1.0f)); + jd3.lowerTranslation = -5.0f; + jd3.upperTranslation = 5.0f; + jd3.enableLimit = true; + + m_joint3 = (b2PrismaticJoint*)m_world->CreateJoint(&jd3); + + b2GearJointDef jd4; + jd4.bodyA = body1; + jd4.bodyB = body2; + jd4.joint1 = m_joint1; + jd4.joint2 = m_joint2; + jd4.ratio = circle2.m_radius / circle1.m_radius; + m_joint4 = (b2GearJoint*)m_world->CreateJoint(&jd4); + + b2GearJointDef jd5; + jd5.bodyA = body2; + jd5.bodyB = body3; + jd5.joint1 = m_joint2; + jd5.joint2 = m_joint3; + jd5.ratio = -1.0f / circle2.m_radius; + m_joint5 = (b2GearJoint*)m_world->CreateJoint(&jd5); + } + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 0: + break; + } + } + + void Step(Settings* settings) + { + Test::Step(settings); + + float32 ratio, value; + + ratio = m_joint4->GetRatio(); + value = m_joint1->GetJointAngle() + ratio * m_joint2->GetJointAngle(); + m_debugDraw.DrawString(5, m_textLine, "theta1 + %4.2f * theta2 = %4.2f", (float) ratio, (float) value); + m_textLine += 15; + + ratio = m_joint5->GetRatio(); + value = m_joint2->GetJointAngle() + ratio * m_joint3->GetJointTranslation(); + m_debugDraw.DrawString(5, m_textLine, "theta2 + %4.2f * delta = %4.2f", (float) ratio, (float) value); + m_textLine += 15; + } + + static Test* Create() + { + return new Gears; + } + + b2RevoluteJoint* m_joint1; + b2RevoluteJoint* m_joint2; + b2PrismaticJoint* m_joint3; + b2GearJoint* m_joint4; + b2GearJoint* m_joint5; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/OneSidedPlatform.h b/tests/Box2D_v2.2.1/Testbed/Tests/OneSidedPlatform.h new file mode 100755 index 0000000000000..9d3c84e3746a6 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/OneSidedPlatform.h @@ -0,0 +1,120 @@ +/* +* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef ONE_SIDED_PLATFORM_H +#define ONE_SIDED_PLATFORM_H + +class OneSidedPlatform : public Test +{ +public: + + enum State + { + e_unknown, + e_above, + e_below + }; + + OneSidedPlatform() + { + // Ground + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + // Platform + { + b2BodyDef bd; + bd.position.Set(0.0f, 10.0f); + b2Body* body = m_world->CreateBody(&bd); + + b2PolygonShape shape; + shape.SetAsBox(3.0f, 0.5f); + m_platform = body->CreateFixture(&shape, 0.0f); + + m_bottom = 10.0f - 0.5f; + m_top = 10.0f + 0.5f; + } + + // Actor + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.0f, 12.0f); + b2Body* body = m_world->CreateBody(&bd); + + m_radius = 0.5f; + b2CircleShape shape; + shape.m_radius = m_radius; + m_character = body->CreateFixture(&shape, 20.0f); + + body->SetLinearVelocity(b2Vec2(0.0f, -50.0f)); + + m_state = e_unknown; + } + } + + void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) + { + Test::PreSolve(contact, oldManifold); + + b2Fixture* fixtureA = contact->GetFixtureA(); + b2Fixture* fixtureB = contact->GetFixtureB(); + + if (fixtureA != m_platform && fixtureA != m_character) + { + return; + } + + if (fixtureB != m_platform && fixtureB != m_character) + { + return; + } + + b2Vec2 position = m_character->GetBody()->GetPosition(); + + if (position.y < m_top + m_radius - 3.0f * b2_linearSlop) + { + contact->SetEnabled(false); + } + } + + void Step(Settings* settings) + { + Test::Step(settings); + m_debugDraw.DrawString(5, m_textLine, "Press: (c) create a shape, (d) destroy a shape."); + m_textLine += 15; + } + + static Test* Create() + { + return new OneSidedPlatform; + } + + float32 m_radius, m_top, m_bottom; + State m_state; + b2Fixture* m_platform; + b2Fixture* m_character; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Pinball.h b/tests/Box2D_v2.2.1/Testbed/Tests/Pinball.h new file mode 100755 index 0000000000000..640edf47a2a04 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Pinball.h @@ -0,0 +1,169 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef PINBALL_H +#define PINBALL_H + +/// This tests bullet collision and provides an example of a gameplay scenario. +/// This also uses a loop shape. +class Pinball : public Test +{ +public: + Pinball() + { + // Ground body + b2Body* ground = NULL; + { + b2BodyDef bd; + ground = m_world->CreateBody(&bd); + + b2Vec2 vs[5]; + vs[0].Set(0.0f, -2.0f); + vs[1].Set(8.0f, 6.0f); + vs[2].Set(8.0f, 20.0f); + vs[3].Set(-8.0f, 20.0f); + vs[4].Set(-8.0f, 6.0f); + + b2ChainShape loop; + loop.CreateLoop(vs, 5); + b2FixtureDef fd; + fd.shape = &loop; + fd.density = 0.0f; + ground->CreateFixture(&fd); + } + + // Flippers + { + b2Vec2 p1(-2.0f, 0.0f), p2(2.0f, 0.0f); + + b2BodyDef bd; + bd.type = b2_dynamicBody; + + bd.position = p1; + b2Body* leftFlipper = m_world->CreateBody(&bd); + + bd.position = p2; + b2Body* rightFlipper = m_world->CreateBody(&bd); + + b2PolygonShape box; + box.SetAsBox(1.75f, 0.1f); + + b2FixtureDef fd; + fd.shape = &box; + fd.density = 1.0f; + + leftFlipper->CreateFixture(&fd); + rightFlipper->CreateFixture(&fd); + + b2RevoluteJointDef jd; + jd.bodyA = ground; + jd.localAnchorB.SetZero(); + jd.enableMotor = true; + jd.maxMotorTorque = 1000.0f; + jd.enableLimit = true; + + jd.motorSpeed = 0.0f; + jd.localAnchorA = p1; + jd.bodyB = leftFlipper; + jd.lowerAngle = -30.0f * b2_pi / 180.0f; + jd.upperAngle = 5.0f * b2_pi / 180.0f; + m_leftJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd); + + jd.motorSpeed = 0.0f; + jd.localAnchorA = p2; + jd.bodyB = rightFlipper; + jd.lowerAngle = -5.0f * b2_pi / 180.0f; + jd.upperAngle = 30.0f * b2_pi / 180.0f; + m_rightJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd); + } + + // Circle character + { + b2BodyDef bd; + bd.position.Set(1.0f, 15.0f); + bd.type = b2_dynamicBody; + bd.bullet = true; + + m_ball = m_world->CreateBody(&bd); + + b2CircleShape shape; + shape.m_radius = 0.2f; + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 1.0f; + m_ball->CreateFixture(&fd); + } + + m_button = false; + } + + void Step(Settings* settings) + { + if (m_button) + { + m_leftJoint->SetMotorSpeed(20.0f); + m_rightJoint->SetMotorSpeed(-20.0f); + } + else + { + m_leftJoint->SetMotorSpeed(-10.0f); + m_rightJoint->SetMotorSpeed(10.0f); + } + + Test::Step(settings); + + m_debugDraw.DrawString(5, m_textLine, "Press 'a' to control the flippers"); + m_textLine += 15; + + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'a': + case 'A': + m_button = true; + break; + } + } + + void KeyboardUp(unsigned char key) + { + switch (key) + { + case 'a': + case 'A': + m_button = false; + break; + } + } + + static Test* Create() + { + return new Pinball; + } + + b2RevoluteJoint* m_leftJoint; + b2RevoluteJoint* m_rightJoint; + b2Body* m_ball; + bool m_button; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/PolyCollision.h b/tests/Box2D_v2.2.1/Testbed/Tests/PolyCollision.h new file mode 100755 index 0000000000000..43ede334334b0 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/PolyCollision.h @@ -0,0 +1,122 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef POLYCOLLISION_H +#define POLYCOLLISION_H + +class PolyCollision : public Test +{ +public: + PolyCollision() + { + { + m_polygonA.SetAsBox(0.2f, 0.4f); + m_transformA.Set(b2Vec2(0.0f, 0.0f), 0.0f); + } + + { + m_polygonB.SetAsBox(0.5f, 0.5f); + m_positionB.Set(19.345284f, 1.5632932f); + m_angleB = 1.9160721f; + m_transformB.Set(m_positionB, m_angleB); + } + } + + static Test* Create() + { + return new PolyCollision; + } + + void Step(Settings* settings) + { + B2_NOT_USED(settings); + + b2Manifold manifold; + b2CollidePolygons(&manifold, &m_polygonA, m_transformA, &m_polygonB, m_transformB); + + b2WorldManifold worldManifold; + worldManifold.Initialize(&manifold, m_transformA, m_polygonA.m_radius, m_transformB, m_polygonB.m_radius); + + m_debugDraw.DrawString(5, m_textLine, "point count = %d", manifold.pointCount); + m_textLine += 15; + + { + b2Color color(0.9f, 0.9f, 0.9f); + b2Vec2 v[b2_maxPolygonVertices]; + for (int32 i = 0; i < m_polygonA.m_vertexCount; ++i) + { + v[i] = b2Mul(m_transformA, m_polygonA.m_vertices[i]); + } + m_debugDraw.DrawPolygon(v, m_polygonA.m_vertexCount, color); + + for (int32 i = 0; i < m_polygonB.m_vertexCount; ++i) + { + v[i] = b2Mul(m_transformB, m_polygonB.m_vertices[i]); + } + m_debugDraw.DrawPolygon(v, m_polygonB.m_vertexCount, color); + } + + for (int32 i = 0; i < manifold.pointCount; ++i) + { + m_debugDraw.DrawPoint(worldManifold.points[i], 4.0f, b2Color(0.9f, 0.3f, 0.3f)); + } + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'a': + m_positionB.x -= 0.1f; + break; + + case 'd': + m_positionB.x += 0.1f; + break; + + case 's': + m_positionB.y -= 0.1f; + break; + + case 'w': + m_positionB.y += 0.1f; + break; + + case 'q': + m_angleB += 0.1f * b2_pi; + break; + + case 'e': + m_angleB -= 0.1f * b2_pi; + break; + } + + m_transformB.Set(m_positionB, m_angleB); + } + + b2PolygonShape m_polygonA; + b2PolygonShape m_polygonB; + + b2Transform m_transformA; + b2Transform m_transformB; + + b2Vec2 m_positionB; + float32 m_angleB; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/PolyShapes.h b/tests/Box2D_v2.2.1/Testbed/Tests/PolyShapes.h new file mode 100755 index 0000000000000..60bb7340b8c9c --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/PolyShapes.h @@ -0,0 +1,295 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef POLY_SHAPES_H +#define POLY_SHAPES_H + +/// This tests stacking. It also shows how to use b2World::Query +/// and b2TestOverlap. + +const int32 k_maxBodies = 256; + +/// This callback is called by b2World::QueryAABB. We find all the fixtures +/// that overlap an AABB. Of those, we use b2TestOverlap to determine which fixtures +/// overlap a circle. Up to 4 overlapped fixtures will be highlighted with a yellow border. +class PolyShapesCallback : public b2QueryCallback +{ +public: + + enum + { + e_maxCount = 4 + }; + + PolyShapesCallback() + { + m_count = 0; + } + + void DrawFixture(b2Fixture* fixture) + { + b2Color color(0.95f, 0.95f, 0.6f); + const b2Transform& xf = fixture->GetBody()->GetTransform(); + + switch (fixture->GetType()) + { + case b2Shape::e_circle: + { + b2CircleShape* circle = (b2CircleShape*)fixture->GetShape(); + + b2Vec2 center = b2Mul(xf, circle->m_p); + float32 radius = circle->m_radius; + + m_debugDraw->DrawCircle(center, radius, color); + } + break; + + case b2Shape::e_polygon: + { + b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape(); + int32 vertexCount = poly->m_vertexCount; + b2Assert(vertexCount <= b2_maxPolygonVertices); + b2Vec2 vertices[b2_maxPolygonVertices]; + + for (int32 i = 0; i < vertexCount; ++i) + { + vertices[i] = b2Mul(xf, poly->m_vertices[i]); + } + + m_debugDraw->DrawPolygon(vertices, vertexCount, color); + } + break; + + default: + break; + } + } + + /// Called for each fixture found in the query AABB. + /// @return false to terminate the query. + bool ReportFixture(b2Fixture* fixture) + { + if (m_count == e_maxCount) + { + return false; + } + + b2Body* body = fixture->GetBody(); + b2Shape* shape = fixture->GetShape(); + + bool overlap = b2TestOverlap(shape, 0, &m_circle, 0, body->GetTransform(), m_transform); + + if (overlap) + { + DrawFixture(fixture); + ++m_count; + } + + return true; + } + + b2CircleShape m_circle; + b2Transform m_transform; + b2Draw* m_debugDraw; + int32 m_count; +}; + +class PolyShapes : public Test +{ +public: + PolyShapes() + { + // Ground body + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2Vec2 vertices[3]; + vertices[0].Set(-0.5f, 0.0f); + vertices[1].Set(0.5f, 0.0f); + vertices[2].Set(0.0f, 1.5f); + m_polygons[0].Set(vertices, 3); + } + + { + b2Vec2 vertices[3]; + vertices[0].Set(-0.1f, 0.0f); + vertices[1].Set(0.1f, 0.0f); + vertices[2].Set(0.0f, 1.5f); + m_polygons[1].Set(vertices, 3); + } + + { + float32 w = 1.0f; + float32 b = w / (2.0f + b2Sqrt(2.0f)); + float32 s = b2Sqrt(2.0f) * b; + + b2Vec2 vertices[8]; + vertices[0].Set(0.5f * s, 0.0f); + vertices[1].Set(0.5f * w, b); + vertices[2].Set(0.5f * w, b + s); + vertices[3].Set(0.5f * s, w); + vertices[4].Set(-0.5f * s, w); + vertices[5].Set(-0.5f * w, b + s); + vertices[6].Set(-0.5f * w, b); + vertices[7].Set(-0.5f * s, 0.0f); + + m_polygons[2].Set(vertices, 8); + } + + { + m_polygons[3].SetAsBox(0.5f, 0.5f); + } + + { + m_circle.m_radius = 0.5f; + } + + m_bodyIndex = 0; + memset(m_bodies, 0, sizeof(m_bodies)); + } + + void Create(int32 index) + { + if (m_bodies[m_bodyIndex] != NULL) + { + m_world->DestroyBody(m_bodies[m_bodyIndex]); + m_bodies[m_bodyIndex] = NULL; + } + + b2BodyDef bd; + bd.type = b2_dynamicBody; + + float32 x = RandomFloat(-2.0f, 2.0f); + bd.position.Set(x, 10.0f); + bd.angle = RandomFloat(-b2_pi, b2_pi); + + if (index == 4) + { + bd.angularDamping = 0.02f; + } + + m_bodies[m_bodyIndex] = m_world->CreateBody(&bd); + + if (index < 4) + { + b2FixtureDef fd; + fd.shape = m_polygons + index; + fd.density = 1.0f; + fd.friction = 0.3f; + m_bodies[m_bodyIndex]->CreateFixture(&fd); + } + else + { + b2FixtureDef fd; + fd.shape = &m_circle; + fd.density = 1.0f; + fd.friction = 0.3f; + + m_bodies[m_bodyIndex]->CreateFixture(&fd); + } + + m_bodyIndex = (m_bodyIndex + 1) % k_maxBodies; + } + + void DestroyBody() + { + for (int32 i = 0; i < k_maxBodies; ++i) + { + if (m_bodies[i] != NULL) + { + m_world->DestroyBody(m_bodies[i]); + m_bodies[i] = NULL; + return; + } + } + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case '1': + case '2': + case '3': + case '4': + case '5': + Create(key - '1'); + break; + + case 'a': + for (int32 i = 0; i < k_maxBodies; i += 2) + { + if (m_bodies[i]) + { + bool active = m_bodies[i]->IsActive(); + m_bodies[i]->SetActive(!active); + } + } + break; + + case 'd': + DestroyBody(); + break; + } + } + + void Step(Settings* settings) + { + Test::Step(settings); + + PolyShapesCallback callback; + callback.m_circle.m_radius = 2.0f; + callback.m_circle.m_p.Set(0.0f, 1.1f); + callback.m_transform.SetIdentity(); + callback.m_debugDraw = &m_debugDraw; + + b2AABB aabb; + callback.m_circle.ComputeAABB(&aabb, callback.m_transform, 0); + + m_world->QueryAABB(&callback, aabb); + + b2Color color(0.4f, 0.7f, 0.8f); + m_debugDraw.DrawCircle(callback.m_circle.m_p, callback.m_circle.m_radius, color); + + m_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff"); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "Press 'a' to (de)activate some bodies"); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "Press 'd' to destroy a body"); + m_textLine += 15; + } + + static Test* Create() + { + return new PolyShapes; + } + + int32 m_bodyIndex; + b2Body* m_bodies[k_maxBodies]; + b2PolygonShape m_polygons[4]; + b2CircleShape m_circle; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Prismatic.h b/tests/Box2D_v2.2.1/Testbed/Tests/Prismatic.h new file mode 100755 index 0000000000000..fb58cba572b5d --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Prismatic.h @@ -0,0 +1,107 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef PRISMATIC_H +#define PRISMATIC_H + +// The motor in this test gets smoother with higher velocity iterations. +class Prismatic : public Test +{ +public: + Prismatic() + { + b2Body* ground = NULL; + { + b2BodyDef bd; + ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2PolygonShape shape; + shape.SetAsBox(2.0f, 0.5f); + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-10.0f, 10.0f); + bd.angle = 0.5f * b2_pi; + bd.allowSleep = false; + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&shape, 5.0f); + + b2PrismaticJointDef pjd; + + // Bouncy limit + b2Vec2 axis(2.0f, 1.0f); + axis.Normalize(); + pjd.Initialize(ground, body, b2Vec2(0.0f, 0.0f), axis); + + // Non-bouncy limit + //pjd.Initialize(ground, body, b2Vec2(-10.0f, 10.0f), b2Vec2(1.0f, 0.0f)); + + pjd.motorSpeed = 10.0f; + pjd.maxMotorForce = 10000.0f; + pjd.enableMotor = true; + pjd.lowerTranslation = 0.0f; + pjd.upperTranslation = 20.0f; + pjd.enableLimit = true; + + m_joint = (b2PrismaticJoint*)m_world->CreateJoint(&pjd); + } + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'l': + m_joint->EnableLimit(!m_joint->IsLimitEnabled()); + break; + + case 'm': + m_joint->EnableMotor(!m_joint->IsMotorEnabled()); + break; + + case 's': + m_joint->SetMotorSpeed(-m_joint->GetMotorSpeed()); + break; + } + } + + void Step(Settings* settings) + { + Test::Step(settings); + m_debugDraw.DrawString(5, m_textLine, "Keys: (l) limits, (m) motors, (s) speed"); + m_textLine += 15; + float32 force = m_joint->GetMotorForce(settings->hz); + m_debugDraw.DrawString(5, m_textLine, "Motor Force = %4.0f", (float) force); + m_textLine += 15; + } + + static Test* Create() + { + return new Prismatic; + } + + b2PrismaticJoint* m_joint; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Pulleys.h b/tests/Box2D_v2.2.1/Testbed/Tests/Pulleys.h new file mode 100755 index 0000000000000..9c71626748dab --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Pulleys.h @@ -0,0 +1,106 @@ +/* +* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef PULLEYS_H +#define PULLEYS_H + +class Pulleys : public Test +{ +public: + Pulleys() + { + float32 y = 16.0f; + float32 L = 12.0f; + float32 a = 1.0f; + float32 b = 2.0f; + + b2Body* ground = NULL; + { + b2BodyDef bd; + ground = m_world->CreateBody(&bd); + + b2EdgeShape edge; + edge.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + //ground->CreateFixture(&shape, 0.0f); + + b2CircleShape circle; + circle.m_radius = 2.0f; + + circle.m_p.Set(-10.0f, y + b + L); + ground->CreateFixture(&circle, 0.0f); + + circle.m_p.Set(10.0f, y + b + L); + ground->CreateFixture(&circle, 0.0f); + } + + { + + b2PolygonShape shape; + shape.SetAsBox(a, b); + + b2BodyDef bd; + bd.type = b2_dynamicBody; + + //bd.fixedRotation = true; + bd.position.Set(-10.0f, y); + b2Body* body1 = m_world->CreateBody(&bd); + body1->CreateFixture(&shape, 5.0f); + + bd.position.Set(10.0f, y); + b2Body* body2 = m_world->CreateBody(&bd); + body2->CreateFixture(&shape, 5.0f); + + b2PulleyJointDef pulleyDef; + b2Vec2 anchor1(-10.0f, y + b); + b2Vec2 anchor2(10.0f, y + b); + b2Vec2 groundAnchor1(-10.0f, y + b + L); + b2Vec2 groundAnchor2(10.0f, y + b + L); + pulleyDef.Initialize(body1, body2, groundAnchor1, groundAnchor2, anchor1, anchor2, 1.5f); + + m_joint1 = (b2PulleyJoint*)m_world->CreateJoint(&pulleyDef); + } + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 0: + break; + } + } + + void Step(Settings* settings) + { + Test::Step(settings); + + float32 ratio = m_joint1->GetRatio(); + float32 L = m_joint1->GetLengthA() + ratio * m_joint1->GetLengthB(); + m_debugDraw.DrawString(5, m_textLine, "L1 + %4.2f * L2 = %4.2f", (float) ratio, (float) L); + m_textLine += 15; + } + + static Test* Create() + { + return new Pulleys; + } + + b2PulleyJoint* m_joint1; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Pyramid.h b/tests/Box2D_v2.2.1/Testbed/Tests/Pyramid.h new file mode 100755 index 0000000000000..ac3cd46525467 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Pyramid.h @@ -0,0 +1,89 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef PYRAMID_H +#define PYRAMID_H + +class Pyramid : public Test +{ +public: + enum + { + e_count = 20 + }; + + Pyramid() + { + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + { + float32 a = 0.5f; + b2PolygonShape shape; + shape.SetAsBox(a, a); + + b2Vec2 x(-7.0f, 0.75f); + b2Vec2 y; + b2Vec2 deltaX(0.5625f, 1.25f); + b2Vec2 deltaY(1.125f, 0.0f); + + for (int32 i = 0; i < e_count; ++i) + { + y = x; + + for (int32 j = i; j < e_count; ++j) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position = y; + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&shape, 5.0f); + + y += deltaY; + } + + x += deltaX; + } + } + } + + void Step(Settings* settings) + { + Test::Step(settings); + + //b2DynamicTree* tree = &m_world->m_contactManager.m_broadPhase.m_tree; + + //if (m_stepCount == 400) + //{ + // tree->RebuildBottomUp(); + //} + } + + static Test* Create() + { + return new Pyramid; + } +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/RayCast.h b/tests/Box2D_v2.2.1/Testbed/Tests/RayCast.h new file mode 100755 index 0000000000000..5eefd9b055eca --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/RayCast.h @@ -0,0 +1,440 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef RAY_CAST_H +#define RAY_CAST_H + +// This test demonstrates how to use the world ray-cast feature. +// NOTE: we are intentionally filtering one of the polygons, therefore +// the ray will always miss one type of polygon. + +// This callback finds the closest hit. Polygon 0 is filtered. +class RayCastClosestCallback : public b2RayCastCallback +{ +public: + RayCastClosestCallback() + { + m_hit = false; + } + + float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point, + const b2Vec2& normal, float32 fraction) + { + b2Body* body = fixture->GetBody(); + void* userData = body->GetUserData(); + if (userData) + { + int32 index = *(int32*)userData; + if (index == 0) + { + // filter + return -1.0f; + } + } + + m_hit = true; + m_point = point; + m_normal = normal; + return fraction; + } + + bool m_hit; + b2Vec2 m_point; + b2Vec2 m_normal; +}; + +// This callback finds any hit. Polygon 0 is filtered. +class RayCastAnyCallback : public b2RayCastCallback +{ +public: + RayCastAnyCallback() + { + m_hit = false; + } + + float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point, + const b2Vec2& normal, float32 fraction) + { + b2Body* body = fixture->GetBody(); + void* userData = body->GetUserData(); + if (userData) + { + int32 index = *(int32*)userData; + if (index == 0) + { + // filter + return -1.0f; + } + } + + m_hit = true; + m_point = point; + m_normal = normal; + return 0.0f; + } + + bool m_hit; + b2Vec2 m_point; + b2Vec2 m_normal; +}; + +// This ray cast collects multiple hits along the ray. Polygon 0 is filtered. +class RayCastMultipleCallback : public b2RayCastCallback +{ +public: + enum + { + e_maxCount = 3 + }; + + RayCastMultipleCallback() + { + m_count = 0; + } + + float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point, + const b2Vec2& normal, float32 fraction) + { + b2Body* body = fixture->GetBody(); + void* userData = body->GetUserData(); + if (userData) + { + int32 index = *(int32*)userData; + if (index == 0) + { + // filter + return -1.0f; + } + } + + b2Assert(m_count < e_maxCount); + + m_points[m_count] = point; + m_normals[m_count] = normal; + ++m_count; + + if (m_count == e_maxCount) + { + return 0.0f; + } + + return 1.0f; + } + + b2Vec2 m_points[e_maxCount]; + b2Vec2 m_normals[e_maxCount]; + int32 m_count; +}; + + +class RayCast : public Test +{ +public: + + enum + { + e_maxBodies = 256 + }; + + enum Mode + { + e_closest, + e_any, + e_multiple + }; + + RayCast() + { + // Ground body + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2Vec2 vertices[3]; + vertices[0].Set(-0.5f, 0.0f); + vertices[1].Set(0.5f, 0.0f); + vertices[2].Set(0.0f, 1.5f); + m_polygons[0].Set(vertices, 3); + } + + { + b2Vec2 vertices[3]; + vertices[0].Set(-0.1f, 0.0f); + vertices[1].Set(0.1f, 0.0f); + vertices[2].Set(0.0f, 1.5f); + m_polygons[1].Set(vertices, 3); + } + + { + float32 w = 1.0f; + float32 b = w / (2.0f + b2Sqrt(2.0f)); + float32 s = b2Sqrt(2.0f) * b; + + b2Vec2 vertices[8]; + vertices[0].Set(0.5f * s, 0.0f); + vertices[1].Set(0.5f * w, b); + vertices[2].Set(0.5f * w, b + s); + vertices[3].Set(0.5f * s, w); + vertices[4].Set(-0.5f * s, w); + vertices[5].Set(-0.5f * w, b + s); + vertices[6].Set(-0.5f * w, b); + vertices[7].Set(-0.5f * s, 0.0f); + + m_polygons[2].Set(vertices, 8); + } + + { + m_polygons[3].SetAsBox(0.5f, 0.5f); + } + + { + m_circle.m_radius = 0.5f; + } + + m_bodyIndex = 0; + memset(m_bodies, 0, sizeof(m_bodies)); + + m_angle = 0.0f; + + m_mode = e_closest; + } + + void Create(int32 index) + { + if (m_bodies[m_bodyIndex] != NULL) + { + m_world->DestroyBody(m_bodies[m_bodyIndex]); + m_bodies[m_bodyIndex] = NULL; + } + + b2BodyDef bd; + + float32 x = RandomFloat(-10.0f, 10.0f); + float32 y = RandomFloat(0.0f, 20.0f); + bd.position.Set(x, y); + bd.angle = RandomFloat(-b2_pi, b2_pi); + + m_userData[m_bodyIndex] = index; + bd.userData = m_userData + m_bodyIndex; + + if (index == 4) + { + bd.angularDamping = 0.02f; + } + + m_bodies[m_bodyIndex] = m_world->CreateBody(&bd); + + if (index < 4) + { + b2FixtureDef fd; + fd.shape = m_polygons + index; + fd.friction = 0.3f; + m_bodies[m_bodyIndex]->CreateFixture(&fd); + } + else + { + b2FixtureDef fd; + fd.shape = &m_circle; + fd.friction = 0.3f; + + m_bodies[m_bodyIndex]->CreateFixture(&fd); + } + + m_bodyIndex = (m_bodyIndex + 1) % e_maxBodies; + } + + void DestroyBody() + { + for (int32 i = 0; i < e_maxBodies; ++i) + { + if (m_bodies[i] != NULL) + { + m_world->DestroyBody(m_bodies[i]); + m_bodies[i] = NULL; + return; + } + } + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case '1': + case '2': + case '3': + case '4': + case '5': + Create(key - '1'); + break; + + case 'd': + DestroyBody(); + break; + + case 'm': + if (m_mode == e_closest) + { + m_mode = e_any; + } + else if (m_mode == e_any) + { + m_mode = e_multiple; + } + else if (m_mode == e_multiple) + { + m_mode = e_closest; + } + } + } + + void Step(Settings* settings) + { + bool advanceRay = settings->pause == 0 || settings->singleStep; + + Test::Step(settings); + m_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff, m to change the mode"); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "Mode = %d", m_mode); + m_textLine += 15; + + float32 L = 11.0f; + b2Vec2 point1(0.0f, 10.0f); + b2Vec2 d(L * cosf(m_angle), L * sinf(m_angle)); + b2Vec2 point2 = point1 + d; + + if (m_mode == e_closest) + { + RayCastClosestCallback callback; + m_world->RayCast(&callback, point1, point2); + + if (callback.m_hit) + { + m_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f)); + m_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f)); + b2Vec2 head = callback.m_point + 0.5f * callback.m_normal; + m_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f)); + } + else + { + m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f)); + } + } + else if (m_mode == e_any) + { + RayCastAnyCallback callback; + m_world->RayCast(&callback, point1, point2); + + if (callback.m_hit) + { + m_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f)); + m_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f)); + b2Vec2 head = callback.m_point + 0.5f * callback.m_normal; + m_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f)); + } + else + { + m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f)); + } + } + else if (m_mode == e_multiple) + { + RayCastMultipleCallback callback; + m_world->RayCast(&callback, point1, point2); + m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f)); + + for (int32 i = 0; i < callback.m_count; ++i) + { + b2Vec2 p = callback.m_points[i]; + b2Vec2 n = callback.m_normals[i]; + m_debugDraw.DrawPoint(p, 5.0f, b2Color(0.4f, 0.9f, 0.4f)); + m_debugDraw.DrawSegment(point1, p, b2Color(0.8f, 0.8f, 0.8f)); + b2Vec2 head = p + 0.5f * n; + m_debugDraw.DrawSegment(p, head, b2Color(0.9f, 0.9f, 0.4f)); + } + } + + if (advanceRay) + { + m_angle += 0.25f * b2_pi / 180.0f; + } + +#if 0 + // This case was failing. + { + b2Vec2 vertices[4]; + //vertices[0].Set(-22.875f, -3.0f); + //vertices[1].Set(22.875f, -3.0f); + //vertices[2].Set(22.875f, 3.0f); + //vertices[3].Set(-22.875f, 3.0f); + + b2PolygonShape shape; + //shape.Set(vertices, 4); + shape.SetAsBox(22.875f, 3.0f); + + b2RayCastInput input; + input.p1.Set(10.2725f,1.71372f); + input.p2.Set(10.2353f,2.21807f); + //input.maxFraction = 0.567623f; + input.maxFraction = 0.56762173f; + + b2Transform xf; + xf.SetIdentity(); + xf.position.Set(23.0f, 5.0f); + + b2RayCastOutput output; + bool hit; + hit = shape.RayCast(&output, input, xf); + hit = false; + + b2Color color(1.0f, 1.0f, 1.0f); + b2Vec2 vs[4]; + for (int32 i = 0; i < 4; ++i) + { + vs[i] = b2Mul(xf, shape.m_vertices[i]); + } + + m_debugDraw.DrawPolygon(vs, 4, color); + m_debugDraw.DrawSegment(input.p1, input.p2, color); + } +#endif + } + + static Test* Create() + { + return new RayCast; + } + + int32 m_bodyIndex; + b2Body* m_bodies[e_maxBodies]; + int32 m_userData[e_maxBodies]; + b2PolygonShape m_polygons[4]; + b2CircleShape m_circle; + + float32 m_angle; + + Mode m_mode; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Revolute.h b/tests/Box2D_v2.2.1/Testbed/Tests/Revolute.h new file mode 100755 index 0000000000000..86ac28a5c9779 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Revolute.h @@ -0,0 +1,166 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef REVOLUTE_H +#define REVOLUTE_H + +class Revolute : public Test +{ +public: + Revolute() + { + b2Body* ground = NULL; + { + b2BodyDef bd; + ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + + b2FixtureDef fd; + fd.shape = &shape; + //fd.filter.categoryBits = 2; + + ground->CreateFixture(&fd); + } + + { + b2CircleShape shape; + shape.m_radius = 0.5f; + + b2BodyDef bd; + bd.type = b2_dynamicBody; + + b2RevoluteJointDef rjd; + + bd.position.Set(-10.0f, 20.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&shape, 5.0f); + + float32 w = 100.0f; + body->SetAngularVelocity(w); + body->SetLinearVelocity(b2Vec2(-8.0f * w, 0.0f)); + + rjd.Initialize(ground, body, b2Vec2(-10.0f, 12.0f)); + rjd.motorSpeed = 1.0f * b2_pi; + rjd.maxMotorTorque = 10000.0f; + rjd.enableMotor = false; + rjd.lowerAngle = -0.25f * b2_pi; + rjd.upperAngle = 0.5f * b2_pi; + rjd.enableLimit = true; + rjd.collideConnected = true; + + m_joint = (b2RevoluteJoint*)m_world->CreateJoint(&rjd); + } + + { + b2CircleShape circle_shape; + circle_shape.m_radius = 3.0f; + + b2BodyDef circle_bd; + circle_bd.type = b2_dynamicBody; + circle_bd.position.Set(5.0f, 30.0f); + + b2FixtureDef fd; + fd.density = 5.0f; + fd.filter.maskBits = 1; + fd.shape = &circle_shape; + + m_ball = m_world->CreateBody(&circle_bd); + m_ball->CreateFixture(&fd); + + b2PolygonShape polygon_shape; + polygon_shape.SetAsBox(10.0f, 0.2f, b2Vec2 (-10.0f, 0.0f), 0.0f); + + b2BodyDef polygon_bd; + polygon_bd.position.Set(20.0f, 10.0f); + polygon_bd.type = b2_dynamicBody; + polygon_bd.bullet = true; + b2Body* polygon_body = m_world->CreateBody(&polygon_bd); + polygon_body->CreateFixture(&polygon_shape, 2.0f); + + b2RevoluteJointDef rjd; + rjd.Initialize(ground, polygon_body, b2Vec2(20.0f, 10.0f)); + rjd.lowerAngle = -0.25f * b2_pi; + rjd.upperAngle = 0.0f * b2_pi; + rjd.enableLimit = true; + m_world->CreateJoint(&rjd); + } + + // Tests mass computation of a small object far from the origin + { + b2BodyDef bodyDef; + bodyDef.type = b2_dynamicBody; + b2Body* body = m_world->CreateBody(&bodyDef); + + b2PolygonShape polyShape; + b2Vec2 verts[3]; + verts[0].Set( 17.63f, 36.31f ); + verts[1].Set( 17.52f, 36.69f ); + verts[2].Set( 17.19f, 36.36f ); + polyShape.Set(verts, 3); + + b2FixtureDef polyFixtureDef; + polyFixtureDef.shape = &polyShape; + polyFixtureDef.density = 1; + + body->CreateFixture(&polyFixtureDef); //assertion hits inside here + } + + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'l': + m_joint->EnableLimit(!m_joint->IsLimitEnabled()); + break; + + case 'm': + m_joint->EnableMotor(!m_joint->IsMotorEnabled()); + break; + } + } + + void Step(Settings* settings) + { + Test::Step(settings); + m_debugDraw.DrawString(5, m_textLine, "Keys: (l) limits, (m) motor"); + m_textLine += 15; + + //if (m_stepCount == 360) + //{ + // m_ball->SetTransform(b2Vec2(0.0f, 0.5f), 0.0f); + //} + + //float32 torque1 = m_joint1->GetMotorTorque(); + //m_debugDraw.DrawString(5, m_textLine, "Motor Torque = %4.0f, %4.0f : Motor Force = %4.0f", (float) torque1, (float) torque2, (float) force3); + //m_textLine += 15; + } + + static Test* Create() + { + return new Revolute; + } + + b2Body* m_ball; + b2RevoluteJoint* m_joint; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Rope.h b/tests/Box2D_v2.2.1/Testbed/Tests/Rope.h new file mode 100755 index 0000000000000..38ff81d429be1 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Rope.h @@ -0,0 +1,101 @@ +/* +* Copyright (c) 2011 Erin Catto http://box2d.org +* +* 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. +*/ + +#ifndef ROPE_H +#define ROPE_H + +/// +class Rope : public Test +{ +public: + Rope() + { + const int32 N = 40; + b2Vec2 vertices[N]; + float32 masses[N]; + + for (int32 i = 0; i < N; ++i) + { + vertices[i].Set(0.0f, 20.0f - 0.25f * i); + masses[i] = 1.0f; + } + masses[0] = 0.0f; + masses[1] = 0.0f; + + b2RopeDef def; + def.vertices = vertices; + def.count = N; + def.gravity.Set(0.0f, -10.0f); + def.masses = masses; + def.damping = 0.1f; + def.k2 = 1.0f; + def.k3 = 0.5f; + + m_rope.Initialize(&def); + + m_angle = 0.0f; + m_rope.SetAngle(m_angle); + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'q': + m_angle = b2Max(-b2_pi, m_angle - 0.05f * b2_pi); + m_rope.SetAngle(m_angle); + break; + + case 'e': + m_angle = b2Min(b2_pi, m_angle + 0.05f * b2_pi); + m_rope.SetAngle(m_angle); + break; + } + } + + void Step(Settings* settings) + { + float32 dt = settings->hz > 0.0f ? 1.0f / settings->hz : 0.0f; + + if (settings->pause == 1 && settings->singleStep == 0) + { + dt = 0.0f; + } + + m_rope.Step(dt, 1); + + Test::Step(settings); + + m_rope.Draw(&m_debugDraw); + + m_debugDraw.DrawString(5, m_textLine, "Press (q,e) to adjust target angle"); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "Target angle = %g degrees", m_angle * 180.0f / b2_pi); + m_textLine += 15; + } + + static Test* Create() + { + return new Rope; + } + + b2Rope m_rope; + float32 m_angle; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/RopeJoint.h b/tests/Box2D_v2.2.1/Testbed/Tests/RopeJoint.h new file mode 100755 index 0000000000000..038dede0482dd --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/RopeJoint.h @@ -0,0 +1,145 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef ROPE_JOINT_H +#define ROPE_JOINT_H + +/// This test shows how a rope joint can be used to stabilize a chain of +/// bodies with a heavy payload. Notice that the rope joint just prevents +/// excessive stretching and has no other effect. +/// By disabling the rope joint you can see that the Box2D solver has trouble +/// supporting heavy bodies with light bodies. Try playing around with the +/// densities, time step, and iterations to see how they affect stability. +/// This test also shows how to use contact filtering. Filtering is configured +/// so that the payload does not collide with the chain. +class RopeJoint : public Test +{ +public: + RopeJoint() + { + b2Body* ground = NULL; + { + b2BodyDef bd; + ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2PolygonShape shape; + shape.SetAsBox(0.5f, 0.125f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + fd.friction = 0.2f; + fd.filter.categoryBits = 0x0001; + fd.filter.maskBits = 0xFFFF & ~0x0002; + + b2RevoluteJointDef jd; + jd.collideConnected = false; + + const int32 N = 10; + const float32 y = 15.0f; + m_ropeDef.localAnchorA.Set(0.0f, y); + + b2Body* prevBody = ground; + for (int32 i = 0; i < N; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.5f + 1.0f * i, y); + if (i == N - 1) + { + shape.SetAsBox(1.5f, 1.5f); + fd.density = 100.0f; + fd.filter.categoryBits = 0x0002; + bd.position.Set(1.0f * i, y); + bd.angularDamping = 0.4f; + } + + b2Body* body = m_world->CreateBody(&bd); + + body->CreateFixture(&fd); + + b2Vec2 anchor(float32(i), y); + jd.Initialize(prevBody, body, anchor); + m_world->CreateJoint(&jd); + + prevBody = body; + } + + m_ropeDef.localAnchorB.SetZero(); + + float32 extraLength = 0.01f; + m_ropeDef.maxLength = N - 1.0f + extraLength; + m_ropeDef.bodyB = prevBody; + } + + { + m_ropeDef.bodyA = ground; + m_rope = m_world->CreateJoint(&m_ropeDef); + } + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'j': + if (m_rope) + { + m_world->DestroyJoint(m_rope); + m_rope = NULL; + } + else + { + m_rope = m_world->CreateJoint(&m_ropeDef); + } + break; + } + } + + void Step(Settings* settings) + { + Test::Step(settings); + m_debugDraw.DrawString(5, m_textLine, "Press (j) to toggle the rope joint."); + m_textLine += 15; + if (m_rope) + { + m_debugDraw.DrawString(5, m_textLine, "Rope ON"); + } + else + { + m_debugDraw.DrawString(5, m_textLine, "Rope OFF"); + } + m_textLine += 15; + } + + static Test* Create() + { + return new RopeJoint; + } + + b2RopeJointDef m_ropeDef; + b2Joint* m_rope; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/SensorTest.h b/tests/Box2D_v2.2.1/Testbed/Tests/SensorTest.h new file mode 100755 index 0000000000000..a268041515d42 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/SensorTest.h @@ -0,0 +1,181 @@ +/* +* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef SENSOR_TEST_H +#define SENSOR_TEST_H + +// This is used to test sensor shapes. +class SensorTest : public Test +{ +public: + + enum + { + e_count = 7 + }; + + SensorTest() + { + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + { + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + +#if 0 + { + b2FixtureDef sd; + sd.SetAsBox(10.0f, 2.0f, b2Vec2(0.0f, 20.0f), 0.0f); + sd.isSensor = true; + m_sensor = ground->CreateFixture(&sd); + } +#else + { + b2CircleShape shape; + shape.m_radius = 5.0f; + shape.m_p.Set(0.0f, 10.0f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.isSensor = true; + m_sensor = ground->CreateFixture(&fd); + } +#endif + } + + { + b2CircleShape shape; + shape.m_radius = 1.0f; + + for (int32 i = 0; i < e_count; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-10.0f + 3.0f * i, 20.0f); + bd.userData = m_touching + i; + + m_touching[i] = false; + m_bodies[i] = m_world->CreateBody(&bd); + + m_bodies[i]->CreateFixture(&shape, 1.0f); + } + } + } + + // Implement contact listener. + void BeginContact(b2Contact* contact) + { + b2Fixture* fixtureA = contact->GetFixtureA(); + b2Fixture* fixtureB = contact->GetFixtureB(); + + if (fixtureA == m_sensor) + { + void* userData = fixtureB->GetBody()->GetUserData(); + if (userData) + { + bool* touching = (bool*)userData; + *touching = true; + } + } + + if (fixtureB == m_sensor) + { + void* userData = fixtureA->GetBody()->GetUserData(); + if (userData) + { + bool* touching = (bool*)userData; + *touching = true; + } + } + } + + // Implement contact listener. + void EndContact(b2Contact* contact) + { + b2Fixture* fixtureA = contact->GetFixtureA(); + b2Fixture* fixtureB = contact->GetFixtureB(); + + if (fixtureA == m_sensor) + { + void* userData = fixtureB->GetBody()->GetUserData(); + if (userData) + { + bool* touching = (bool*)userData; + *touching = false; + } + } + + if (fixtureB == m_sensor) + { + void* userData = fixtureA->GetBody()->GetUserData(); + if (userData) + { + bool* touching = (bool*)userData; + *touching = false; + } + } + } + + void Step(Settings* settings) + { + Test::Step(settings); + + // Traverse the contact results. Apply a force on shapes + // that overlap the sensor. + for (int32 i = 0; i < e_count; ++i) + { + if (m_touching[i] == false) + { + continue; + } + + b2Body* body = m_bodies[i]; + b2Body* ground = m_sensor->GetBody(); + + b2CircleShape* circle = (b2CircleShape*)m_sensor->GetShape(); + b2Vec2 center = ground->GetWorldPoint(circle->m_p); + + b2Vec2 position = body->GetPosition(); + + b2Vec2 d = center - position; + if (d.LengthSquared() < FLT_EPSILON * FLT_EPSILON) + { + continue; + } + + d.Normalize(); + b2Vec2 F = 100.0f * d; + body->ApplyForce(F, position); + } + } + + static Test* Create() + { + return new SensorTest; + } + + b2Fixture* m_sensor; + b2Body* m_bodies[e_count]; + bool m_touching[e_count]; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/ShapeEditing.h b/tests/Box2D_v2.2.1/Testbed/Tests/ShapeEditing.h new file mode 100755 index 0000000000000..c900bbcbe78fa --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/ShapeEditing.h @@ -0,0 +1,105 @@ +/* +* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef SHAPE_EDITING_H +#define SHAPE_EDITING_H + +class ShapeEditing : public Test +{ +public: + + ShapeEditing() + { + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.0f, 10.0f); + m_body = m_world->CreateBody(&bd); + + b2PolygonShape shape; + shape.SetAsBox(4.0f, 4.0f, b2Vec2(0.0f, 0.0f), 0.0f); + m_fixture1 = m_body->CreateFixture(&shape, 10.0f); + + m_fixture2 = NULL; + + m_sensor = false; + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'c': + if (m_fixture2 == NULL) + { + b2CircleShape shape; + shape.m_radius = 3.0f; + shape.m_p.Set(0.5f, -4.0f); + m_fixture2 = m_body->CreateFixture(&shape, 10.0f); + m_body->SetAwake(true); + } + break; + + case 'd': + if (m_fixture2 != NULL) + { + m_body->DestroyFixture(m_fixture2); + m_fixture2 = NULL; + m_body->SetAwake(true); + } + break; + + case 's': + if (m_fixture2 != NULL) + { + m_sensor = !m_sensor; + m_fixture2->SetSensor(m_sensor); + } + break; + } + } + + void Step(Settings* settings) + { + Test::Step(settings); + m_debugDraw.DrawString(5, m_textLine, "Press: (c) create a shape, (d) destroy a shape."); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "sensor = %d", m_sensor); + m_textLine += 15; + } + + static Test* Create() + { + return new ShapeEditing; + } + + b2Body* m_body; + b2Fixture* m_fixture1; + b2Fixture* m_fixture2; + bool m_sensor; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/SliderCrank.h b/tests/Box2D_v2.2.1/Testbed/Tests/SliderCrank.h new file mode 100755 index 0000000000000..52e6e9cf0cc68 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/SliderCrank.h @@ -0,0 +1,156 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef SLIDER_CRANK_H +#define SLIDER_CRANK_H + +// A motor driven slider crank with joint friction. + +class SliderCrank : public Test +{ +public: + SliderCrank() + { + b2Body* ground = NULL; + { + b2BodyDef bd; + ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2Body* prevBody = ground; + + // Define crank. + { + b2PolygonShape shape; + shape.SetAsBox(0.5f, 2.0f); + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.0f, 7.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&shape, 2.0f); + + b2RevoluteJointDef rjd; + rjd.Initialize(prevBody, body, b2Vec2(0.0f, 5.0f)); + rjd.motorSpeed = 1.0f * b2_pi; + rjd.maxMotorTorque = 10000.0f; + rjd.enableMotor = true; + m_joint1 = (b2RevoluteJoint*)m_world->CreateJoint(&rjd); + + prevBody = body; + } + + // Define follower. + { + b2PolygonShape shape; + shape.SetAsBox(0.5f, 4.0f); + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.0f, 13.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&shape, 2.0f); + + b2RevoluteJointDef rjd; + rjd.Initialize(prevBody, body, b2Vec2(0.0f, 9.0f)); + rjd.enableMotor = false; + m_world->CreateJoint(&rjd); + + prevBody = body; + } + + // Define piston + { + b2PolygonShape shape; + shape.SetAsBox(1.5f, 1.5f); + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.fixedRotation = true; + bd.position.Set(0.0f, 17.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&shape, 2.0f); + + b2RevoluteJointDef rjd; + rjd.Initialize(prevBody, body, b2Vec2(0.0f, 17.0f)); + m_world->CreateJoint(&rjd); + + b2PrismaticJointDef pjd; + pjd.Initialize(ground, body, b2Vec2(0.0f, 17.0f), b2Vec2(0.0f, 1.0f)); + + pjd.maxMotorForce = 1000.0f; + pjd.enableMotor = true; + + m_joint2 = (b2PrismaticJoint*)m_world->CreateJoint(&pjd); + } + + // Create a payload + { + b2PolygonShape shape; + shape.SetAsBox(1.5f, 1.5f); + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.0f, 23.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&shape, 2.0f); + } + } + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'f': + m_joint2->EnableMotor(!m_joint2->IsMotorEnabled()); + m_joint2->GetBodyB()->SetAwake(true); + break; + + case 'm': + m_joint1->EnableMotor(!m_joint1->IsMotorEnabled()); + m_joint1->GetBodyB()->SetAwake(true); + break; + } + } + + void Step(Settings* settings) + { + Test::Step(settings); + m_debugDraw.DrawString(5, m_textLine, "Keys: (f) toggle friction, (m) toggle motor"); + m_textLine += 15; + float32 torque = m_joint1->GetMotorTorque(settings->hz); + m_debugDraw.DrawString(5, m_textLine, "Motor Torque = %5.0f", (float) torque); + m_textLine += 15; + } + + static Test* Create() + { + return new SliderCrank; + } + + b2RevoluteJoint* m_joint1; + b2PrismaticJoint* m_joint2; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/SphereStack.h b/tests/Box2D_v2.2.1/Testbed/Tests/SphereStack.h new file mode 100755 index 0000000000000..22485c6d050a3 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/SphereStack.h @@ -0,0 +1,86 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef SPHERE_STACK_H +#define SPHERE_STACK_H + +class SphereStack : public Test +{ +public: + + enum + { + e_count = 10 + }; + + SphereStack() + { + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2CircleShape shape; + shape.m_radius = 1.0f; + + for (int32 i = 0; i < e_count; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.0, 4.0f + 3.0f * i); + + m_bodies[i] = m_world->CreateBody(&bd); + + m_bodies[i]->CreateFixture(&shape, 1.0f); + + m_bodies[i]->SetLinearVelocity(b2Vec2(0.0f, -50.0f)); + } + } + } + + void Step(Settings* settings) + { + Test::Step(settings); + + //for (int32 i = 0; i < e_count; ++i) + //{ + // printf("%g ", m_bodies[i]->GetWorldCenter().y); + //} + + //for (int32 i = 0; i < e_count; ++i) + //{ + // printf("%g ", m_bodies[i]->GetLinearVelocity().y); + //} + + //printf("\n"); + } + + static Test* Create() + { + return new SphereStack; + } + + b2Body* m_bodies[e_count]; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/TestEntries.cpp b/tests/Box2D_v2.2.1/Testbed/Tests/TestEntries.cpp new file mode 100755 index 0000000000000..85db6615dc22a --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/TestEntries.cpp @@ -0,0 +1,125 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#include "../Framework/Test.h" +#include "../Framework/Render.h" + +#ifdef __APPLE__ + #include +#else + #include "freeglut/freeglut.h" +#endif + +#include +using namespace std; + +#include "AddPair.h" +#include "ApplyForce.h" +#include "BodyTypes.h" +#include "Breakable.h" +#include "Bridge.h" +#include "BulletTest.h" +#include "Cantilever.h" +#include "Car.h" +#include "ContinuousTest.h" +#include "Chain.h" +#include "CharacterCollision.h" +#include "CollisionFiltering.h" +#include "CollisionProcessing.h" +#include "CompoundShapes.h" +#include "Confined.h" +#include "DistanceTest.h" +#include "Dominos.h" +#include "DumpShell.h" +#include "DynamicTreeTest.h" +#include "EdgeShapes.h" +#include "EdgeTest.h" +#include "Gears.h" +#include "OneSidedPlatform.h" +#include "Pinball.h" +#include "PolyCollision.h" +#include "PolyShapes.h" +#include "Prismatic.h" +#include "Pulleys.h" +#include "Pyramid.h" +#include "RayCast.h" +#include "Revolute.h" +//#include "Rope.h" +#include "RopeJoint.h" +#include "SensorTest.h" +#include "ShapeEditing.h" +#include "SliderCrank.h" +#include "SphereStack.h" +#include "TheoJansen.h" +#include "Tiles.h" +#include "TimeOfImpact.h" +#include "Tumbler.h" +#include "VaryingFriction.h" +#include "VaryingRestitution.h" +#include "VerticalStack.h" +#include "Web.h" + +TestEntry g_testEntries[] = +{ + {"Tumbler", Tumbler::Create}, + {"Tiles", Tiles::Create}, + {"Dump Shell", DumpShell::Create}, + {"Gears", Gears::Create}, + {"Cantilever", Cantilever::Create}, + {"Varying Restitution", VaryingRestitution::Create}, + {"Character Collision", CharacterCollision::Create}, + {"Edge Test", EdgeTest::Create}, + {"Body Types", BodyTypes::Create}, + {"Shape Editing", ShapeEditing::Create}, + {"Car", Car::Create}, + {"Apply Force", ApplyForce::Create}, + {"Prismatic", Prismatic::Create}, + {"Vertical Stack", VerticalStack::Create}, + {"SphereStack", SphereStack::Create}, + {"Revolute", Revolute::Create}, + {"Pulleys", Pulleys::Create}, + {"Polygon Shapes", PolyShapes::Create}, + //{"Rope", Rope::Create}, + {"Web", Web::Create}, + {"RopeJoint", RopeJoint::Create}, + {"One-Sided Platform", OneSidedPlatform::Create}, + {"Pinball", Pinball::Create}, + {"Bullet Test", BulletTest::Create}, + {"Continuous Test", ContinuousTest::Create}, + {"Time of Impact", TimeOfImpact::Create}, + {"Ray-Cast", RayCast::Create}, + {"Confined", Confined::Create}, + {"Pyramid", Pyramid::Create}, + {"Theo Jansen's Walker", TheoJansen::Create}, + {"Edge Shapes", EdgeShapes::Create}, + {"PolyCollision", PolyCollision::Create}, + {"Bridge", Bridge::Create}, + {"Breakable", Breakable::Create}, + {"Chain", Chain::Create}, + {"Collision Filtering", CollisionFiltering::Create}, + {"Collision Processing", CollisionProcessing::Create}, + {"Compound Shapes", CompoundShapes::Create}, + {"Distance Test", DistanceTest::Create}, + {"Dominos", Dominos::Create}, + {"Dynamic Tree", DynamicTreeTest::Create}, + {"Sensor Test", SensorTest::Create}, + {"Slider Crank", SliderCrank::Create}, + {"Varying Friction", VaryingFriction::Create}, + {"Add Pair Stress Test", AddPair::Create}, + {NULL, NULL} +}; diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/TheoJansen.h b/tests/Box2D_v2.2.1/Testbed/Tests/TheoJansen.h new file mode 100755 index 0000000000000..6fb808b911df5 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/TheoJansen.h @@ -0,0 +1,256 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +// Inspired by a contribution by roman_m +// Dimensions scooped from APE (http://www.cove.org/ape/index.htm) + +#ifndef THEO_JANSEN_H +#define THEO_JANSEN_H + +class TheoJansen : public Test +{ +public: + + void CreateLeg(float32 s, const b2Vec2& wheelAnchor) + { + b2Vec2 p1(5.4f * s, -6.1f); + b2Vec2 p2(7.2f * s, -1.2f); + b2Vec2 p3(4.3f * s, -1.9f); + b2Vec2 p4(3.1f * s, 0.8f); + b2Vec2 p5(6.0f * s, 1.5f); + b2Vec2 p6(2.5f * s, 3.7f); + + b2FixtureDef fd1, fd2; + fd1.filter.groupIndex = -1; + fd2.filter.groupIndex = -1; + fd1.density = 1.0f; + fd2.density = 1.0f; + + b2PolygonShape poly1, poly2; + + if (s > 0.0f) + { + b2Vec2 vertices[3]; + + vertices[0] = p1; + vertices[1] = p2; + vertices[2] = p3; + poly1.Set(vertices, 3); + + vertices[0] = b2Vec2_zero; + vertices[1] = p5 - p4; + vertices[2] = p6 - p4; + poly2.Set(vertices, 3); + } + else + { + b2Vec2 vertices[3]; + + vertices[0] = p1; + vertices[1] = p3; + vertices[2] = p2; + poly1.Set(vertices, 3); + + vertices[0] = b2Vec2_zero; + vertices[1] = p6 - p4; + vertices[2] = p5 - p4; + poly2.Set(vertices, 3); + } + + fd1.shape = &poly1; + fd2.shape = &poly2; + + b2BodyDef bd1, bd2; + bd1.type = b2_dynamicBody; + bd2.type = b2_dynamicBody; + bd1.position = m_offset; + bd2.position = p4 + m_offset; + + bd1.angularDamping = 10.0f; + bd2.angularDamping = 10.0f; + + b2Body* body1 = m_world->CreateBody(&bd1); + b2Body* body2 = m_world->CreateBody(&bd2); + + body1->CreateFixture(&fd1); + body2->CreateFixture(&fd2); + + b2DistanceJointDef djd; + + // Using a soft distance constraint can reduce some jitter. + // It also makes the structure seem a bit more fluid by + // acting like a suspension system. + djd.dampingRatio = 0.5f; + djd.frequencyHz = 10.0f; + + djd.Initialize(body1, body2, p2 + m_offset, p5 + m_offset); + m_world->CreateJoint(&djd); + + djd.Initialize(body1, body2, p3 + m_offset, p4 + m_offset); + m_world->CreateJoint(&djd); + + djd.Initialize(body1, m_wheel, p3 + m_offset, wheelAnchor + m_offset); + m_world->CreateJoint(&djd); + + djd.Initialize(body2, m_wheel, p6 + m_offset, wheelAnchor + m_offset); + m_world->CreateJoint(&djd); + + b2RevoluteJointDef rjd; + + rjd.Initialize(body2, m_chassis, p4 + m_offset); + m_world->CreateJoint(&rjd); + } + + TheoJansen() + { + m_offset.Set(0.0f, 8.0f); + m_motorSpeed = 2.0f; + m_motorOn = true; + b2Vec2 pivot(0.0f, 0.8f); + + // Ground + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-50.0f, 0.0f), b2Vec2(50.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + + shape.Set(b2Vec2(-50.0f, 0.0f), b2Vec2(-50.0f, 10.0f)); + ground->CreateFixture(&shape, 0.0f); + + shape.Set(b2Vec2(50.0f, 0.0f), b2Vec2(50.0f, 10.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + // Balls + for (int32 i = 0; i < 40; ++i) + { + b2CircleShape shape; + shape.m_radius = 0.25f; + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-40.0f + 2.0f * i, 0.5f); + + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&shape, 1.0f); + } + + // Chassis + { + b2PolygonShape shape; + shape.SetAsBox(2.5f, 1.0f); + + b2FixtureDef sd; + sd.density = 1.0f; + sd.shape = &shape; + sd.filter.groupIndex = -1; + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position = pivot + m_offset; + m_chassis = m_world->CreateBody(&bd); + m_chassis->CreateFixture(&sd); + } + + { + b2CircleShape shape; + shape.m_radius = 1.6f; + + b2FixtureDef sd; + sd.density = 1.0f; + sd.shape = &shape; + sd.filter.groupIndex = -1; + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position = pivot + m_offset; + m_wheel = m_world->CreateBody(&bd); + m_wheel->CreateFixture(&sd); + } + + { + b2RevoluteJointDef jd; + jd.Initialize(m_wheel, m_chassis, pivot + m_offset); + jd.collideConnected = false; + jd.motorSpeed = m_motorSpeed; + jd.maxMotorTorque = 400.0f; + jd.enableMotor = m_motorOn; + m_motorJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd); + } + + b2Vec2 wheelAnchor; + + wheelAnchor = pivot + b2Vec2(0.0f, -0.8f); + + CreateLeg(-1.0f, wheelAnchor); + CreateLeg(1.0f, wheelAnchor); + + m_wheel->SetTransform(m_wheel->GetPosition(), 120.0f * b2_pi / 180.0f); + CreateLeg(-1.0f, wheelAnchor); + CreateLeg(1.0f, wheelAnchor); + + m_wheel->SetTransform(m_wheel->GetPosition(), -120.0f * b2_pi / 180.0f); + CreateLeg(-1.0f, wheelAnchor); + CreateLeg(1.0f, wheelAnchor); + } + + void Step(Settings* settings) + { + m_debugDraw.DrawString(5, m_textLine, "Keys: left = a, brake = s, right = d, toggle motor = m"); + m_textLine += 15; + + Test::Step(settings); + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'a': + m_motorJoint->SetMotorSpeed(-m_motorSpeed); + break; + + case 's': + m_motorJoint->SetMotorSpeed(0.0f); + break; + + case 'd': + m_motorJoint->SetMotorSpeed(m_motorSpeed); + break; + + case 'm': + m_motorJoint->EnableMotor(!m_motorJoint->IsMotorEnabled()); + break; + } + } + + static Test* Create() + { + return new TheoJansen; + } + + b2Vec2 m_offset; + b2Body* m_chassis; + b2Body* m_wheel; + b2RevoluteJoint* m_motorJoint; + bool m_motorOn; + float32 m_motorSpeed; +}; + +#endif // THEO_JANSEN_H diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Tiles.h b/tests/Box2D_v2.2.1/Testbed/Tests/Tiles.h new file mode 100755 index 0000000000000..a437961ccd60a --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Tiles.h @@ -0,0 +1,156 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef TILES_H +#define TILES_H + +/// This stress tests the dynamic tree broad-phase. This also shows that tile +/// based collision is _not_ smooth due to Box2D not knowing about adjacency. +class Tiles : public Test +{ +public: + enum + { + e_count = 20 + }; + + Tiles() + { + m_fixtureCount = 0; + b2Timer timer; + + { + float32 a = 0.5f; + b2BodyDef bd; + bd.position.y = -a; + b2Body* ground = m_world->CreateBody(&bd); + +#if 1 + int32 N = 200; + int32 M = 10; + b2Vec2 position; + position.y = 0.0f; + for (int32 j = 0; j < M; ++j) + { + position.x = -N * a; + for (int32 i = 0; i < N; ++i) + { + b2PolygonShape shape; + shape.SetAsBox(a, a, position, 0.0f); + ground->CreateFixture(&shape, 0.0f); + ++m_fixtureCount; + position.x += 2.0f * a; + } + position.y -= 2.0f * a; + } +#else + int32 N = 200; + int32 M = 10; + b2Vec2 position; + position.x = -N * a; + for (int32 i = 0; i < N; ++i) + { + position.y = 0.0f; + for (int32 j = 0; j < M; ++j) + { + b2PolygonShape shape; + shape.SetAsBox(a, a, position, 0.0f); + ground->CreateFixture(&shape, 0.0f); + position.y -= 2.0f * a; + } + position.x += 2.0f * a; + } +#endif + } + + { + float32 a = 0.5f; + b2PolygonShape shape; + shape.SetAsBox(a, a); + + b2Vec2 x(-7.0f, 0.75f); + b2Vec2 y; + b2Vec2 deltaX(0.5625f, 1.25f); + b2Vec2 deltaY(1.125f, 0.0f); + + for (int32 i = 0; i < e_count; ++i) + { + y = x; + + for (int32 j = i; j < e_count; ++j) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position = y; + + //if (i == 0 && j == 0) + //{ + // bd.allowSleep = false; + //} + //else + //{ + // bd.allowSleep = true; + //} + + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&shape, 5.0f); + ++m_fixtureCount; + y += deltaY; + } + + x += deltaX; + } + } + + m_createTime = timer.GetMilliseconds(); + } + + void Step(Settings* settings) + { + const b2ContactManager& cm = m_world->GetContactManager(); + int32 height = cm.m_broadPhase.GetTreeHeight(); + int32 leafCount = cm.m_broadPhase.GetProxyCount(); + int32 minimumNodeCount = 2 * leafCount - 1; + float32 minimumHeight = ceilf(logf(float32(minimumNodeCount)) / logf(2.0f)); + m_debugDraw.DrawString(5, m_textLine, "dynamic tree height = %d, min = %d", height, int32(minimumHeight)); + m_textLine += 15; + + Test::Step(settings); + + m_debugDraw.DrawString(5, m_textLine, "create time = %6.2f ms, fixture count = %d", + m_createTime, m_fixtureCount); + m_textLine += 15; + + //b2DynamicTree* tree = &m_world->m_contactManager.m_broadPhase.m_tree; + + //if (m_stepCount == 400) + //{ + // tree->RebuildBottomUp(); + //} + } + + static Test* Create() + { + return new Tiles; + } + + int32 m_fixtureCount; + float32 m_createTime; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/TimeOfImpact.h b/tests/Box2D_v2.2.1/Testbed/Tests/TimeOfImpact.h new file mode 100755 index 0000000000000..f836e0e09034b --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/TimeOfImpact.h @@ -0,0 +1,131 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef TIME_OF_IMPACT_H +#define TIME_OF_IMPACT_H + +class TimeOfImpact : public Test +{ +public: + TimeOfImpact() + { + m_shapeA.SetAsBox(25.0f, 5.0f); + m_shapeB.SetAsBox(2.5f, 2.5f); + } + + static Test* Create() + { + return new TimeOfImpact; + } + + void Step(Settings* settings) + { + Test::Step(settings); + + b2Sweep sweepA; + sweepA.c0.Set(24.0f, -60.0f); + sweepA.a0 = 2.95f; + sweepA.c = sweepA.c0; + sweepA.a = sweepA.a0; + sweepA.localCenter.SetZero(); + + b2Sweep sweepB; + sweepB.c0.Set(53.474274f, -50.252514f); + sweepB.a0 = 513.36676f; // - 162.0f * b2_pi; + sweepB.c.Set(54.595478f, -51.083473f); + sweepB.a = 513.62781f; // - 162.0f * b2_pi; + sweepB.localCenter.SetZero(); + + //sweepB.a0 -= 300.0f * b2_pi; + //sweepB.a -= 300.0f * b2_pi; + + b2TOIInput input; + input.proxyA.Set(&m_shapeA, 0); + input.proxyB.Set(&m_shapeB, 0); + input.sweepA = sweepA; + input.sweepB = sweepB; + input.tMax = 1.0f; + + b2TOIOutput output; + + b2TimeOfImpact(&output, &input); + + m_debugDraw.DrawString(5, m_textLine, "toi = %g", output.t); + m_textLine += 15; + + extern int32 b2_toiMaxIters, b2_toiMaxRootIters; + m_debugDraw.DrawString(5, m_textLine, "max toi iters = %d, max root iters = %d", b2_toiMaxIters, b2_toiMaxRootIters); + m_textLine += 15; + + b2Vec2 vertices[b2_maxPolygonVertices]; + + b2Transform transformA; + sweepA.GetTransform(&transformA, 0.0f); + for (int32 i = 0; i < m_shapeA.m_vertexCount; ++i) + { + vertices[i] = b2Mul(transformA, m_shapeA.m_vertices[i]); + } + m_debugDraw.DrawPolygon(vertices, m_shapeA.m_vertexCount, b2Color(0.9f, 0.9f, 0.9f)); + + b2Transform transformB; + sweepB.GetTransform(&transformB, 0.0f); + + b2Vec2 localPoint(2.0f, -0.1f); + b2Vec2 rB = b2Mul(transformB, localPoint) - sweepB.c0; + float32 wB = sweepB.a - sweepB.a0; + b2Vec2 vB = sweepB.c - sweepB.c0; + b2Vec2 v = vB + b2Cross(wB, rB); + + for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i) + { + vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]); + } + m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.5f, 0.9f, 0.5f)); + + sweepB.GetTransform(&transformB, output.t); + for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i) + { + vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]); + } + m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.5f, 0.7f, 0.9f)); + + sweepB.GetTransform(&transformB, 1.0f); + for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i) + { + vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]); + } + m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.9f, 0.5f, 0.5f)); + +#if 0 + for (float32 t = 0.0f; t < 1.0f; t += 0.1f) + { + sweepB.GetTransform(&transformB, t); + for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i) + { + vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]); + } + m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.9f, 0.5f, 0.5f)); + } +#endif + } + + b2PolygonShape m_shapeA; + b2PolygonShape m_shapeB; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Tumbler.h b/tests/Box2D_v2.2.1/Testbed/Tests/Tumbler.h new file mode 100755 index 0000000000000..b654915ccfdaf --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Tumbler.h @@ -0,0 +1,99 @@ +/* +* Copyright (c) 2011 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef TUMBLER_H +#define TUMBLER_H + +class Tumbler : public Test +{ +public: + + enum + { + e_count = 800 + }; + + Tumbler() + { + b2Body* ground = NULL; + { + b2BodyDef bd; + ground = m_world->CreateBody(&bd); + } + + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.allowSleep = false; + bd.position.Set(0.0f, 10.0f); + b2Body* body = m_world->CreateBody(&bd); + + b2PolygonShape shape; + shape.SetAsBox(0.5f, 10.0f, b2Vec2( 10.0f, 0.0f), 0.0); + body->CreateFixture(&shape, 5.0f); + shape.SetAsBox(0.5f, 10.0f, b2Vec2(-10.0f, 0.0f), 0.0); + body->CreateFixture(&shape, 5.0f); + shape.SetAsBox(10.0f, 0.5f, b2Vec2(0.0f, 10.0f), 0.0); + body->CreateFixture(&shape, 5.0f); + shape.SetAsBox(10.0f, 0.5f, b2Vec2(0.0f, -10.0f), 0.0); + body->CreateFixture(&shape, 5.0f); + + b2RevoluteJointDef jd; + jd.bodyA = ground; + jd.bodyB = body; + jd.localAnchorA.Set(0.0f, 10.0f); + jd.localAnchorB.Set(0.0f, 0.0f); + jd.referenceAngle = 0.0f; + jd.motorSpeed = 0.05f * b2_pi; + jd.maxMotorTorque = 1e8f; + jd.enableMotor = true; + m_joint = (b2RevoluteJoint*)m_world->CreateJoint(&jd); + } + + m_count = 0; + } + + void Step(Settings* settings) + { + Test::Step(settings); + + if (m_count < e_count) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(0.0f, 10.0f); + b2Body* body = m_world->CreateBody(&bd); + + b2PolygonShape shape; + shape.SetAsBox(0.125f, 0.125f); + body->CreateFixture(&shape, 1.0f); + + ++m_count; + } + } + + static Test* Create() + { + return new Tumbler; + } + + b2RevoluteJoint* m_joint; + int32 m_count; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/VaryingFriction.h b/tests/Box2D_v2.2.1/Testbed/Tests/VaryingFriction.h new file mode 100755 index 0000000000000..a28354a990d00 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/VaryingFriction.h @@ -0,0 +1,124 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef VARYING_FRICTION_H +#define VARYING_FRICTION_H + +class VaryingFriction : public Test +{ +public: + + VaryingFriction() + { + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2PolygonShape shape; + shape.SetAsBox(13.0f, 0.25f); + + b2BodyDef bd; + bd.position.Set(-4.0f, 22.0f); + bd.angle = -0.25f; + + b2Body* ground = m_world->CreateBody(&bd); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2PolygonShape shape; + shape.SetAsBox(0.25f, 1.0f); + + b2BodyDef bd; + bd.position.Set(10.5f, 19.0f); + + b2Body* ground = m_world->CreateBody(&bd); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2PolygonShape shape; + shape.SetAsBox(13.0f, 0.25f); + + b2BodyDef bd; + bd.position.Set(4.0f, 14.0f); + bd.angle = 0.25f; + + b2Body* ground = m_world->CreateBody(&bd); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2PolygonShape shape; + shape.SetAsBox(0.25f, 1.0f); + + b2BodyDef bd; + bd.position.Set(-10.5f, 11.0f); + + b2Body* ground = m_world->CreateBody(&bd); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2PolygonShape shape; + shape.SetAsBox(13.0f, 0.25f); + + b2BodyDef bd; + bd.position.Set(-4.0f, 6.0f); + bd.angle = -0.25f; + + b2Body* ground = m_world->CreateBody(&bd); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2PolygonShape shape; + shape.SetAsBox(0.5f, 0.5f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 25.0f; + + float friction[5] = {0.75f, 0.5f, 0.35f, 0.1f, 0.0f}; + + for (int i = 0; i < 5; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-15.0f + 4.0f * i, 28.0f); + b2Body* body = m_world->CreateBody(&bd); + + fd.friction = friction[i]; + body->CreateFixture(&fd); + } + } + } + + static Test* Create() + { + return new VaryingFriction; + } +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/VaryingRestitution.h b/tests/Box2D_v2.2.1/Testbed/Tests/VaryingRestitution.h new file mode 100755 index 0000000000000..8a1bed6980b7d --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/VaryingRestitution.h @@ -0,0 +1,69 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef VARYING_RESTITUTION_H +#define VARYING_RESTITUTION_H + +// Note: even with a restitution of 1.0, there is some energy change +// due to position correction. +class VaryingRestitution : public Test +{ +public: + + VaryingRestitution() + { + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2CircleShape shape; + shape.m_radius = 1.0f; + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 1.0f; + + float32 restitution[7] = {0.0f, 0.1f, 0.3f, 0.5f, 0.75f, 0.9f, 1.0f}; + + for (int32 i = 0; i < 7; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-10.0f + 3.0f * i, 20.0f); + + b2Body* body = m_world->CreateBody(&bd); + + fd.restitution = restitution[i]; + body->CreateFixture(&fd); + } + } + } + + static Test* Create() + { + return new VaryingRestitution; + } +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/VerticalStack.h b/tests/Box2D_v2.2.1/Testbed/Tests/VerticalStack.h new file mode 100755 index 0000000000000..7d545e2350bb4 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/VerticalStack.h @@ -0,0 +1,165 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef VERTICAL_STACK_H +#define VERTICAL_STACK_H + +class VerticalStack : public Test +{ +public: + + enum + { + e_columnCount = 5, + e_rowCount = 16 + //e_columnCount = 1, + //e_rowCount = 1 + }; + + VerticalStack() + { + { + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + + shape.Set(b2Vec2(20.0f, 0.0f), b2Vec2(20.0f, 20.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + float32 xs[5] = {0.0f, -10.0f, -5.0f, 5.0f, 10.0f}; + + for (int32 j = 0; j < e_columnCount; ++j) + { + b2PolygonShape shape; + shape.SetAsBox(0.5f, 0.5f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 1.0f; + fd.friction = 0.3f; + + for (int i = 0; i < e_rowCount; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + + int32 n = j * e_rowCount + i; + b2Assert(n < e_rowCount * e_columnCount); + m_indices[n] = n; + bd.userData = m_indices + n; + + float32 x = 0.0f; + //float32 x = RandomFloat(-0.02f, 0.02f); + //float32 x = i % 2 == 0 ? -0.025f : 0.025f; + bd.position.Set(xs[j] + x, 0.752f + 1.54f * i); + b2Body* body = m_world->CreateBody(&bd); + + m_bodies[n] = body; + + body->CreateFixture(&fd); + } + } + + m_bullet = NULL; + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case ',': + if (m_bullet != NULL) + { + m_world->DestroyBody(m_bullet); + m_bullet = NULL; + } + + { + b2CircleShape shape; + shape.m_radius = 0.25f; + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + fd.restitution = 0.05f; + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.bullet = true; + bd.position.Set(-31.0f, 5.0f); + + m_bullet = m_world->CreateBody(&bd); + m_bullet->CreateFixture(&fd); + + m_bullet->SetLinearVelocity(b2Vec2(400.0f, 0.0f)); + } + break; + } + } + + void Step(Settings* settings) + { + Test::Step(settings); + m_debugDraw.DrawString(5, m_textLine, "Press: (,) to launch a bullet."); + m_textLine += 15; + + //if (m_stepCount == 300) + //{ + // if (m_bullet != NULL) + // { + // m_world->DestroyBody(m_bullet); + // m_bullet = NULL; + // } + + // { + // b2CircleShape shape; + // shape.m_radius = 0.25f; + + // b2FixtureDef fd; + // fd.shape = &shape; + // fd.density = 20.0f; + // fd.restitution = 0.05f; + + // b2BodyDef bd; + // bd.type = b2_dynamicBody; + // bd.bullet = true; + // bd.position.Set(-31.0f, 5.0f); + + // m_bullet = m_world->CreateBody(&bd); + // m_bullet->CreateFixture(&fd); + + // m_bullet->SetLinearVelocity(b2Vec2(400.0f, 0.0f)); + // } + //} + } + + static Test* Create() + { + return new VerticalStack; + } + + b2Body* m_bullet; + b2Body* m_bodies[e_rowCount * e_columnCount]; + int32 m_indices[e_rowCount * e_columnCount]; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Web.h b/tests/Box2D_v2.2.1/Testbed/Tests/Web.h new file mode 100755 index 0000000000000..9ed279ec84447 --- /dev/null +++ b/tests/Box2D_v2.2.1/Testbed/Tests/Web.h @@ -0,0 +1,209 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* 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. +*/ + +#ifndef WEB_H +#define WEB_H + +// This tests distance joints, body destruction, and joint destruction. +class Web : public Test +{ +public: + Web() + { + b2Body* ground = NULL; + { + b2BodyDef bd; + ground = m_world->CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + { + b2PolygonShape shape; + shape.SetAsBox(0.5f, 0.5f); + + b2BodyDef bd; + bd.type = b2_dynamicBody; + + bd.position.Set(-5.0f, 5.0f); + m_bodies[0] = m_world->CreateBody(&bd); + m_bodies[0]->CreateFixture(&shape, 5.0f); + + bd.position.Set(5.0f, 5.0f); + m_bodies[1] = m_world->CreateBody(&bd); + m_bodies[1]->CreateFixture(&shape, 5.0f); + + bd.position.Set(5.0f, 15.0f); + m_bodies[2] = m_world->CreateBody(&bd); + m_bodies[2]->CreateFixture(&shape, 5.0f); + + bd.position.Set(-5.0f, 15.0f); + m_bodies[3] = m_world->CreateBody(&bd); + m_bodies[3]->CreateFixture(&shape, 5.0f); + + b2DistanceJointDef jd; + b2Vec2 p1, p2, d; + + jd.frequencyHz = 2.0f; + jd.dampingRatio = 0.0f; + + jd.bodyA = ground; + jd.bodyB = m_bodies[0]; + jd.localAnchorA.Set(-10.0f, 0.0f); + jd.localAnchorB.Set(-0.5f, -0.5f); + p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA); + p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB); + d = p2 - p1; + jd.length = d.Length(); + m_joints[0] = m_world->CreateJoint(&jd); + + jd.bodyA = ground; + jd.bodyB = m_bodies[1]; + jd.localAnchorA.Set(10.0f, 0.0f); + jd.localAnchorB.Set(0.5f, -0.5f); + p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA); + p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB); + d = p2 - p1; + jd.length = d.Length(); + m_joints[1] = m_world->CreateJoint(&jd); + + jd.bodyA = ground; + jd.bodyB = m_bodies[2]; + jd.localAnchorA.Set(10.0f, 20.0f); + jd.localAnchorB.Set(0.5f, 0.5f); + p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA); + p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB); + d = p2 - p1; + jd.length = d.Length(); + m_joints[2] = m_world->CreateJoint(&jd); + + jd.bodyA = ground; + jd.bodyB = m_bodies[3]; + jd.localAnchorA.Set(-10.0f, 20.0f); + jd.localAnchorB.Set(-0.5f, 0.5f); + p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA); + p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB); + d = p2 - p1; + jd.length = d.Length(); + m_joints[3] = m_world->CreateJoint(&jd); + + jd.bodyA = m_bodies[0]; + jd.bodyB = m_bodies[1]; + jd.localAnchorA.Set(0.5f, 0.0f); + jd.localAnchorB.Set(-0.5f, 0.0f);; + p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA); + p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB); + d = p2 - p1; + jd.length = d.Length(); + m_joints[4] = m_world->CreateJoint(&jd); + + jd.bodyA = m_bodies[1]; + jd.bodyB = m_bodies[2]; + jd.localAnchorA.Set(0.0f, 0.5f); + jd.localAnchorB.Set(0.0f, -0.5f); + p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA); + p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB); + d = p2 - p1; + jd.length = d.Length(); + m_joints[5] = m_world->CreateJoint(&jd); + + jd.bodyA = m_bodies[2]; + jd.bodyB = m_bodies[3]; + jd.localAnchorA.Set(-0.5f, 0.0f); + jd.localAnchorB.Set(0.5f, 0.0f); + p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA); + p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB); + d = p2 - p1; + jd.length = d.Length(); + m_joints[6] = m_world->CreateJoint(&jd); + + jd.bodyA = m_bodies[3]; + jd.bodyB = m_bodies[0]; + jd.localAnchorA.Set(0.0f, -0.5f); + jd.localAnchorB.Set(0.0f, 0.5f); + p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA); + p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB); + d = p2 - p1; + jd.length = d.Length(); + m_joints[7] = m_world->CreateJoint(&jd); + } + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'b': + for (int32 i = 0; i < 4; ++i) + { + if (m_bodies[i]) + { + m_world->DestroyBody(m_bodies[i]); + m_bodies[i] = NULL; + break; + } + } + break; + + case 'j': + for (int32 i = 0; i < 8; ++i) + { + if (m_joints[i]) + { + m_world->DestroyJoint(m_joints[i]); + m_joints[i] = NULL; + break; + } + } + break; + } + } + + void Step(Settings* settings) + { + Test::Step(settings); + m_debugDraw.DrawString(5, m_textLine, "This demonstrates a soft distance joint."); + m_textLine += 15; + m_debugDraw.DrawString(5, m_textLine, "Press: (b) to delete a body, (j) to delete a joint"); + m_textLine += 15; + } + + void JointDestroyed(b2Joint* joint) + { + for (int32 i = 0; i < 8; ++i) + { + if (m_joints[i] == joint) + { + m_joints[i] = NULL; + break; + } + } + } + + static Test* Create() + { + return new Web; + } + + b2Body* m_bodies[4]; + b2Joint* m_joints[8]; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/freeglut/CMakeLists.txt b/tests/Box2D_v2.2.1/freeglut/CMakeLists.txt new file mode 100755 index 0000000000000..8c97446deb60b --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/CMakeLists.txt @@ -0,0 +1,51 @@ +add_definitions( -DFREEGLUT_EXPORTS -DFREEGLUT_STATIC -D_CRT_SECURE_NO_WARNINGS ) + +if(APPLE) + include_directories( /usr/X11/include ) +endif(APPLE) + +if(UNIX) + add_definitions( -D__unix__ -DHAVE_FCNTL_H -DHAVE_GETTIMEOFDAY ) +endif(UNIX) + +set(freeglut_SRCS + freeglut_callbacks.c + freeglut_callbacks.c + freeglut_cursor.c + freeglut_display.c + freeglut_ext.c + freeglut_font_data.c + freeglut_font.c + freeglut_gamemode.c + freeglut_geometry.c + freeglut_glutfont_definitions.c + freeglut_init.c + freeglut_input_devices.c + freeglut_internal.h + freeglut_joystick.c + freeglut_main.c + freeglut_menu.c + freeglut_misc.c + freeglut_overlay.c + freeglut_spaceball.c + freeglut_state.c + freeglut_stroke_mono_roman.c + freeglut_stroke_roman.c + freeglut_structure.c + freeglut_teapot_data.h + freeglut_teapot.c + freeglut_videoresize.c + freeglut_window.c + freeglut.h + freeglut_ext.h + freeglut_std.h +) + +include_directories ( + ${OPENGL_INCLUDE_DIR} + . +) + +add_library(freeglut_static + ${freeglut_SRCS} +) diff --git a/tests/Box2D_v2.2.1/freeglut/COPYING b/tests/Box2D_v2.2.1/freeglut/COPYING new file mode 100755 index 0000000000000..fc36ad99039de --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/COPYING @@ -0,0 +1,27 @@ + + Freeglut Copyright + ------------------ + + Freeglut code without an explicit copyright is covered by the following + copyright: + + Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + 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 or substantial portions of the Software. + + 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 + PAWEL W. OLSZTA 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. + + Except as contained in this notice, the name of Pawel W. Olszta shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Pawel W. Olszta. diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut.h b/tests/Box2D_v2.2.1/freeglut/freeglut.h new file mode 100755 index 0000000000000..0e6f8c6ad86d3 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut.h @@ -0,0 +1,22 @@ +#ifndef __FREEGLUT_H__ +#define __FREEGLUT_H__ + +/* + * freeglut.h + * + * The freeglut library include file + * + * 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 + * PAWEL W. OLSZTA 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 "freeglut_std.h" +#include "freeglut_ext.h" + +/*** END OF FILE ***/ + +#endif /* __FREEGLUT_H__ */ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_callbacks.c b/tests/Box2D_v2.2.1/freeglut/freeglut_callbacks.c new file mode 100755 index 0000000000000..b6b25b375c056 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_callbacks.c @@ -0,0 +1,367 @@ +/* + * freeglut_callbacks.c + * + * The callbacks setting methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Fri Dec 3 1999 + * + * 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 + * PAWEL W. OLSZTA 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 "freeglut.h" +#include "freeglut_internal.h" + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * All of the callbacks setting methods can be generalized to this: + */ +#define SET_CALLBACK(a) \ +do \ +{ \ + if( fgStructure.CurrentWindow == NULL ) \ + return; \ + SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback ); \ +} while( 0 ) + +/* + * Sets the Display callback for the current window + */ +void FGAPIENTRY glutDisplayFunc( void (* callback)( void ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFunc" ); + if( !callback ) + fgError( "Fatal error in program. NULL display callback not " + "permitted in GLUT 3.0+ or freeglut 2.0.1+" ); + SET_CALLBACK( Display ); +} + +/* + * Sets the Reshape callback for the current window + */ +void FGAPIENTRY glutReshapeFunc( void (* callback)( int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFunc" ); + SET_CALLBACK( Reshape ); +} + +/* + * Sets the Keyboard callback for the current window + */ +void FGAPIENTRY glutKeyboardFunc( void (* callback) + ( unsigned char, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutKeyboardFunc" ); + SET_CALLBACK( Keyboard ); +} + +/* + * Sets the Special callback for the current window + */ +void FGAPIENTRY glutSpecialFunc( void (* callback)( int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpecialFunc" ); + SET_CALLBACK( Special ); +} + +/* + * Sets the global idle callback + */ +void FGAPIENTRY glutIdleFunc( void (* callback)( void ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIdleFunc" ); + fgState.IdleCallback = callback; +} + +/* + * Sets the Timer callback for the current window + */ +void FGAPIENTRY glutTimerFunc( unsigned int timeOut, void (* callback)( int ), + int timerID ) +{ + SFG_Timer *timer, *node; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTimerFunc" ); + + if( (timer = fgState.FreeTimers.Last) ) + { + fgListRemove( &fgState.FreeTimers, &timer->Node ); + } + else + { + if( ! (timer = malloc(sizeof(SFG_Timer))) ) + fgError( "Fatal error: " + "Memory allocation failure in glutTimerFunc()" ); + } + + timer->Callback = callback; + timer->ID = timerID; + timer->TriggerTime = fgElapsedTime() + timeOut; + + for( node = fgState.Timers.First; node; node = node->Node.Next ) + { + if( node->TriggerTime > timer->TriggerTime ) + break; + } + + fgListInsert( &fgState.Timers, &node->Node, &timer->Node ); +} + +/* + * Sets the Visibility callback for the current window. + */ +static void fghVisibility( int status ) +{ + int glut_status = GLUT_VISIBLE; + + FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Visibility Callback" ); + freeglut_return_if_fail( fgStructure.CurrentWindow ); + + if( ( GLUT_HIDDEN == status ) || ( GLUT_FULLY_COVERED == status ) ) + glut_status = GLUT_NOT_VISIBLE; + INVOKE_WCB( *( fgStructure.CurrentWindow ), Visibility, ( glut_status ) ); +} + +void FGAPIENTRY glutVisibilityFunc( void (* callback)( int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFunc" ); + SET_CALLBACK( Visibility ); + + if( callback ) + glutWindowStatusFunc( fghVisibility ); + else + glutWindowStatusFunc( NULL ); +} + +/* + * Sets the keyboard key release callback for the current window + */ +void FGAPIENTRY glutKeyboardUpFunc( void (* callback) + ( unsigned char, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutKeyboardUpFunc" ); + SET_CALLBACK( KeyboardUp ); +} + +/* + * Sets the special key release callback for the current window + */ +void FGAPIENTRY glutSpecialUpFunc( void (* callback)( int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpecialUpFunc" ); + SET_CALLBACK( SpecialUp ); +} + +/* + * Sets the joystick callback and polling rate for the current window + */ +void FGAPIENTRY glutJoystickFunc( void (* callback) + ( unsigned int, int, int, int ), + int pollInterval ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFunc" ); + fgInitialiseJoysticks (); + + SET_CALLBACK( Joystick ); + fgStructure.CurrentWindow->State.JoystickPollRate = pollInterval; + + fgStructure.CurrentWindow->State.JoystickLastPoll = + fgElapsedTime() - fgStructure.CurrentWindow->State.JoystickPollRate; + + if( fgStructure.CurrentWindow->State.JoystickLastPoll < 0 ) + fgStructure.CurrentWindow->State.JoystickLastPoll = 0; +} + +/* + * Sets the mouse callback for the current window + */ +void FGAPIENTRY glutMouseFunc( void (* callback)( int, int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMouseFunc" ); + SET_CALLBACK( Mouse ); +} + +/* + * Sets the mouse wheel callback for the current window + */ +void FGAPIENTRY glutMouseWheelFunc( void (* callback)( int, int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMouseWheelFunc" ); + SET_CALLBACK( MouseWheel ); +} + +/* + * Sets the mouse motion callback for the current window (one or more buttons + * are pressed) + */ +void FGAPIENTRY glutMotionFunc( void (* callback)( int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMotionFunc" ); + SET_CALLBACK( Motion ); +} + +/* + * Sets the passive mouse motion callback for the current window (no mouse + * buttons are pressed) + */ +void FGAPIENTRY glutPassiveMotionFunc( void (* callback)( int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPassiveMotionFunc" ); + SET_CALLBACK( Passive ); +} + +/* + * Window mouse entry/leave callback + */ +void FGAPIENTRY glutEntryFunc( void (* callback)( int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutEntryFunc" ); + SET_CALLBACK( Entry ); +} + +/* + * Window destruction callbacks + */ +void FGAPIENTRY glutCloseFunc( void (* callback)( void ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCloseFunc" ); + SET_CALLBACK( Destroy ); +} + +void FGAPIENTRY glutWMCloseFunc( void (* callback)( void ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWMCloseFunc" ); + glutCloseFunc( callback ); +} + +/* A. Donev: Destruction callback for menus */ +void FGAPIENTRY glutMenuDestroyFunc( void (* callback)( void ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFunc" ); + if( fgStructure.CurrentMenu ) + fgStructure.CurrentMenu->Destroy = callback; +} + +/* + * Deprecated version of glutMenuStatusFunc callback setting method + */ +void FGAPIENTRY glutMenuStateFunc( void (* callback)( int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStateFunc" ); + fgState.MenuStateCallback = callback; +} + +/* + * Sets the global menu status callback for the current window + */ +void FGAPIENTRY glutMenuStatusFunc( void (* callback)( int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStatusFunc" ); + fgState.MenuStatusCallback = callback; +} + +/* + * Sets the overlay display callback for the current window + */ +void FGAPIENTRY glutOverlayDisplayFunc( void (* callback)( void ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutOverlayDisplayFunc" ); + SET_CALLBACK( OverlayDisplay ); +} + +/* + * Sets the window status callback for the current window + */ +void FGAPIENTRY glutWindowStatusFunc( void (* callback)( int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWindowStatusFunc" ); + SET_CALLBACK( WindowStatus ); +} + +/* + * Sets the spaceball motion callback for the current window + */ +void FGAPIENTRY glutSpaceballMotionFunc( void (* callback)( int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFunc" ); + fgInitialiseSpaceball(); + + SET_CALLBACK( SpaceMotion ); +} + +/* + * Sets the spaceball rotate callback for the current window + */ +void FGAPIENTRY glutSpaceballRotateFunc( void (* callback)( int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFunc" ); + fgInitialiseSpaceball(); + + SET_CALLBACK( SpaceRotation ); +} + +/* + * Sets the spaceball button callback for the current window + */ +void FGAPIENTRY glutSpaceballButtonFunc( void (* callback)( int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFunc" ); + fgInitialiseSpaceball(); + + SET_CALLBACK( SpaceButton ); +} + +/* + * Sets the button box callback for the current window + */ +void FGAPIENTRY glutButtonBoxFunc( void (* callback)( int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutButtonBoxFunc" ); + SET_CALLBACK( ButtonBox ); +} + +/* + * Sets the dials box callback for the current window + */ +void FGAPIENTRY glutDialsFunc( void (* callback)( int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDialsFunc" ); + SET_CALLBACK( Dials ); +} + +/* + * Sets the tablet motion callback for the current window + */ +void FGAPIENTRY glutTabletMotionFunc( void (* callback)( int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTabletMotionFunc" ); + SET_CALLBACK( TabletMotion ); +} + +/* + * Sets the tablet buttons callback for the current window + */ +void FGAPIENTRY glutTabletButtonFunc( void (* callback)( int, int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTabletButtonFunc" ); + SET_CALLBACK( TabletButton ); +} + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_cursor.c b/tests/Box2D_v2.2.1/freeglut/freeglut_cursor.c new file mode 100755 index 0000000000000..f0ba136a8d1da --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_cursor.c @@ -0,0 +1,280 @@ +/* + * freeglut_cursor.c + * + * The mouse cursor related stuff. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 16 1999 + * + * 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 + * PAWEL W. OLSZTA 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 "freeglut.h" +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 + #include +#endif + +/* + * TODO BEFORE THE STABLE RELEASE: + * glutSetCursor() -- Win32 mappings are incomplete. + * + * It would be good to use custom mouse cursor shapes, and introduce + * an option to display them using glBitmap() and/or texture mapping, + * apart from the windowing system version. + */ + +/* -- PRIVATE FUNCTIONS --------------------------------------------------- */ + +#if TARGET_HOST_POSIX_X11 +/* + * A factory method for an empty cursor + */ +static Cursor getEmptyCursor( void ) +{ + static Cursor cursorNone = None; + if( cursorNone == None ) { + char cursorNoneBits[ 32 ]; + XColor dontCare; + Pixmap cursorNonePixmap; + memset( cursorNoneBits, 0, sizeof( cursorNoneBits ) ); + memset( &dontCare, 0, sizeof( dontCare ) ); + cursorNonePixmap = XCreateBitmapFromData ( fgDisplay.Display, + fgDisplay.RootWindow, + cursorNoneBits, 16, 16 ); + if( cursorNonePixmap != None ) { + cursorNone = XCreatePixmapCursor( fgDisplay.Display, + cursorNonePixmap, cursorNonePixmap, + &dontCare, &dontCare, 0, 0 ); + XFreePixmap( fgDisplay.Display, cursorNonePixmap ); + } + } + return cursorNone; +} + +typedef struct tag_cursorCacheEntry cursorCacheEntry; +struct tag_cursorCacheEntry { + unsigned int cursorShape; /* an XC_foo value */ + Cursor cachedCursor; /* None if the corresponding cursor has + not been created yet */ +}; + +/* + * Note: The arrangement of the table below depends on the fact that + * the "normal" GLUT_CURSOR_* values start a 0 and are consecutive. + */ +static cursorCacheEntry cursorCache[] = { + { XC_arrow, None }, /* GLUT_CURSOR_RIGHT_ARROW */ + { XC_top_left_arrow, None }, /* GLUT_CURSOR_LEFT_ARROW */ + { XC_hand1, None }, /* GLUT_CURSOR_INFO */ + { XC_pirate, None }, /* GLUT_CURSOR_DESTROY */ + { XC_question_arrow, None }, /* GLUT_CURSOR_HELP */ + { XC_exchange, None }, /* GLUT_CURSOR_CYCLE */ + { XC_spraycan, None }, /* GLUT_CURSOR_SPRAY */ + { XC_watch, None }, /* GLUT_CURSOR_WAIT */ + { XC_xterm, None }, /* GLUT_CURSOR_TEXT */ + { XC_crosshair, None }, /* GLUT_CURSOR_CROSSHAIR */ + { XC_sb_v_double_arrow, None }, /* GLUT_CURSOR_UP_DOWN */ + { XC_sb_h_double_arrow, None }, /* GLUT_CURSOR_LEFT_RIGHT */ + { XC_top_side, None }, /* GLUT_CURSOR_TOP_SIDE */ + { XC_bottom_side, None }, /* GLUT_CURSOR_BOTTOM_SIDE */ + { XC_left_side, None }, /* GLUT_CURSOR_LEFT_SIDE */ + { XC_right_side, None }, /* GLUT_CURSOR_RIGHT_SIDE */ + { XC_top_left_corner, None }, /* GLUT_CURSOR_TOP_LEFT_CORNER */ + { XC_top_right_corner, None }, /* GLUT_CURSOR_TOP_RIGHT_CORNER */ + { XC_bottom_right_corner, None }, /* GLUT_CURSOR_BOTTOM_RIGHT_CORNER */ + { XC_bottom_left_corner, None } /* GLUT_CURSOR_BOTTOM_LEFT_CORNER */ +}; +#endif + +/* -- INTERNAL FUNCTIONS ---------------------------------------------------- */ + +/* + * Set the cursor image to be used for the current window + */ +void fgSetCursor ( SFG_Window *window, int cursorID ) +{ +#if TARGET_HOST_POSIX_X11 + { + Cursor cursor; + /* + * XXX FULL_CROSSHAIR demotes to plain CROSSHAIR. Old GLUT allows + * for this, but if there is a system that easily supports a full- + * window (or full-screen) crosshair, we might consider it. + */ + int cursorIDToUse = + ( cursorID == GLUT_CURSOR_FULL_CROSSHAIR ) ? GLUT_CURSOR_CROSSHAIR : cursorID; + + if( ( cursorIDToUse >= 0 ) && + ( cursorIDToUse < sizeof( cursorCache ) / sizeof( cursorCache[0] ) ) ) { + cursorCacheEntry *entry = &cursorCache[ cursorIDToUse ]; + if( entry->cachedCursor == None ) { + entry->cachedCursor = + XCreateFontCursor( fgDisplay.Display, entry->cursorShape ); + } + cursor = entry->cachedCursor; + } else { + switch( cursorIDToUse ) + { + case GLUT_CURSOR_NONE: + cursor = getEmptyCursor( ); + break; + + case GLUT_CURSOR_INHERIT: + cursor = None; + break; + + default: + fgError( "Unknown cursor type: %d", cursorIDToUse ); + return; + } + } + + if ( cursorIDToUse == GLUT_CURSOR_INHERIT ) { + XUndefineCursor( fgDisplay.Display, window->Window.Handle ); + } else if ( cursor != None ) { + XDefineCursor( fgDisplay.Display, window->Window.Handle, cursor ); + } else if ( cursorIDToUse != GLUT_CURSOR_NONE ) { + fgError( "Failed to create cursor" ); + } + } + +#elif TARGET_HOST_MS_WINDOWS + + /* + * Joe Krahn is re-writing the following code. + */ + /* Set the cursor AND change it for this window class. */ +#if !defined(__MINGW64__) && _MSC_VER <= 1200 +# define MAP_CURSOR(a,b) \ + case a: \ + SetCursor( LoadCursor( NULL, b ) ); \ + SetClassLong( window->Window.Handle, \ + GCL_HCURSOR, \ + ( LONG )LoadCursor( NULL, b ) ); \ + break; + /* Nuke the cursor AND change it for this window class. */ +# define ZAP_CURSOR(a,b) \ + case a: \ + SetCursor( NULL ); \ + SetClassLong( window->Window.Handle, \ + GCL_HCURSOR, ( LONG )NULL ); \ + break; +#else +# define MAP_CURSOR(a,b) \ + case a: \ + SetCursor( LoadCursor( NULL, b ) ); \ + SetClassLongPtr( window->Window.Handle, \ + GCLP_HCURSOR, \ + ( LONG )( LONG_PTR )LoadCursor( NULL, b ) ); \ + break; + /* Nuke the cursor AND change it for this window class. */ +# define ZAP_CURSOR(a,b) \ + case a: \ + SetCursor( NULL ); \ + SetClassLongPtr( window->Window.Handle, \ + GCLP_HCURSOR, ( LONG )( LONG_PTR )NULL ); \ + break; +#endif + + switch( cursorID ) + { + MAP_CURSOR( GLUT_CURSOR_RIGHT_ARROW, IDC_ARROW ); + MAP_CURSOR( GLUT_CURSOR_LEFT_ARROW, IDC_ARROW ); + MAP_CURSOR( GLUT_CURSOR_INFO, IDC_HELP ); + MAP_CURSOR( GLUT_CURSOR_DESTROY, IDC_CROSS ); + MAP_CURSOR( GLUT_CURSOR_HELP, IDC_HELP ); + MAP_CURSOR( GLUT_CURSOR_CYCLE, IDC_SIZEALL ); + MAP_CURSOR( GLUT_CURSOR_SPRAY, IDC_CROSS ); + MAP_CURSOR( GLUT_CURSOR_WAIT, IDC_WAIT ); + MAP_CURSOR( GLUT_CURSOR_TEXT, IDC_IBEAM ); + MAP_CURSOR( GLUT_CURSOR_CROSSHAIR, IDC_CROSS ); + MAP_CURSOR( GLUT_CURSOR_UP_DOWN, IDC_SIZENS ); + MAP_CURSOR( GLUT_CURSOR_LEFT_RIGHT, IDC_SIZEWE ); + MAP_CURSOR( GLUT_CURSOR_TOP_SIDE, IDC_ARROW ); /* XXX ToDo */ + MAP_CURSOR( GLUT_CURSOR_BOTTOM_SIDE, IDC_ARROW ); /* XXX ToDo */ + MAP_CURSOR( GLUT_CURSOR_LEFT_SIDE, IDC_ARROW ); /* XXX ToDo */ + MAP_CURSOR( GLUT_CURSOR_RIGHT_SIDE, IDC_ARROW ); /* XXX ToDo */ + MAP_CURSOR( GLUT_CURSOR_TOP_LEFT_CORNER, IDC_SIZENWSE ); + MAP_CURSOR( GLUT_CURSOR_TOP_RIGHT_CORNER, IDC_SIZENESW ); + MAP_CURSOR( GLUT_CURSOR_BOTTOM_RIGHT_CORNER, IDC_SIZENWSE ); + MAP_CURSOR( GLUT_CURSOR_BOTTOM_LEFT_CORNER, IDC_SIZENESW ); + MAP_CURSOR( GLUT_CURSOR_INHERIT, IDC_ARROW ); /* XXX ToDo */ + ZAP_CURSOR( GLUT_CURSOR_NONE, NULL ); + MAP_CURSOR( GLUT_CURSOR_FULL_CROSSHAIR, IDC_CROSS ); /* XXX ToDo */ + + default: + fgError( "Unknown cursor type: %d", cursorID ); + break; + } +#endif + + window->State.Cursor = cursorID; +} + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Set the cursor image to be used for the current window + */ +void FGAPIENTRY glutSetCursor( int cursorID ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetCursor" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetCursor" ); + + fgSetCursor ( fgStructure.CurrentWindow, cursorID ); +} + +/* + * Moves the mouse pointer to given window coordinates + */ +void FGAPIENTRY glutWarpPointer( int x, int y ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWarpPointer" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutWarpPointer" ); + +#if TARGET_HOST_POSIX_X11 + + XWarpPointer( + fgDisplay.Display, + None, + fgStructure.CurrentWindow->Window.Handle, + 0, 0, 0, 0, + x, y + ); + /* Make the warp visible immediately. */ + XFlush( fgDisplay.Display ); + +#elif TARGET_HOST_MS_WINDOWS + + { + POINT coords; + coords.x = x; + coords.y = y; + + /* ClientToScreen() translates {coords} for us. */ + ClientToScreen( fgStructure.CurrentWindow->Window.Handle, &coords ); + SetCursorPos( coords.x, coords.y ); + } + +#endif +} + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_display.c b/tests/Box2D_v2.2.1/freeglut/freeglut_display.c new file mode 100755 index 0000000000000..2f2c5752d9365 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_display.c @@ -0,0 +1,98 @@ +/* + * freeglut_display.c + * + * Display message posting, context buffer swapping. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Fri Dec 3 1999 + * + * 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 + * PAWEL W. OLSZTA 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 "freeglut.h" +#include "freeglut_internal.h" + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Marks the current window to have the redisplay performed when possible... + */ +void FGAPIENTRY glutPostRedisplay( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPostRedisplay" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPostRedisplay" ); + fgStructure.CurrentWindow->State.Redisplay = GL_TRUE; +} + +/* + * Swaps the buffers for the current window (if any) + */ +void FGAPIENTRY glutSwapBuffers( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSwapBuffers" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSwapBuffers" ); + + /* + * "glXSwapBuffers" already performs an implicit call to "glFlush". What + * about "SwapBuffers"? + */ + glFlush( ); + if( ! fgStructure.CurrentWindow->Window.DoubleBuffered ) + return; + +#if TARGET_HOST_POSIX_X11 + glXSwapBuffers( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); +#elif TARGET_HOST_MS_WINDOWS + SwapBuffers( fgStructure.CurrentWindow->Window.Device ); +#endif + + /* GLUT_FPS env var support */ + if( fgState.FPSInterval ) + { + GLint t = glutGet( GLUT_ELAPSED_TIME ); + fgState.SwapCount++; + if( fgState.SwapTime == 0 ) + fgState.SwapTime = t; + else if( t - fgState.SwapTime > fgState.FPSInterval ) + { + float time = 0.001f * ( t - fgState.SwapTime ); + float fps = ( float )fgState.SwapCount / time; + fprintf( stderr, + "freeglut: %d frames in %.2f seconds = %.2f FPS\n", + fgState.SwapCount, time, fps ); + fgState.SwapTime = t; + fgState.SwapCount = 0; + } + } +} + +/* + * Mark appropriate window to be displayed + */ +void FGAPIENTRY glutPostWindowRedisplay( int windowID ) +{ + SFG_Window* window; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPostWindowRedisplay" ); + window = fgWindowByID( windowID ); + freeglut_return_if_fail( window ); + window->State.Redisplay = GL_TRUE; +} + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_ext.c b/tests/Box2D_v2.2.1/freeglut/freeglut_ext.c new file mode 100755 index 0000000000000..cf854341e2e9d --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_ext.c @@ -0,0 +1,226 @@ +/* + * freeglut_ext.c + * + * Functions related to OpenGL extensions. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 9 1999 + * + * 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 + * PAWEL W. OLSZTA 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. + */ + +#define GLX_GLXEXT_PROTOTYPES +#include "freeglut.h" +#include "freeglut_internal.h" + +static GLUTproc fghGetGLUTProcAddress( const char* procName ) +{ + /* optimization: quick initial check */ + if( strncmp( procName, "glut", 4 ) != 0 ) + return NULL; + +#define CHECK_NAME(x) if( strcmp( procName, #x ) == 0) return (GLUTproc)x; + CHECK_NAME(glutInit); + CHECK_NAME(glutInitDisplayMode); + CHECK_NAME(glutInitDisplayString); + CHECK_NAME(glutInitWindowPosition); + CHECK_NAME(glutInitWindowSize); + CHECK_NAME(glutMainLoop); + CHECK_NAME(glutExit); + CHECK_NAME(glutCreateWindow); + CHECK_NAME(glutCreateSubWindow); + CHECK_NAME(glutDestroyWindow); + CHECK_NAME(glutPostRedisplay); + CHECK_NAME(glutPostWindowRedisplay); + CHECK_NAME(glutSwapBuffers); + CHECK_NAME(glutGetWindow); + CHECK_NAME(glutSetWindow); + CHECK_NAME(glutSetWindowTitle); + CHECK_NAME(glutSetIconTitle); + CHECK_NAME(glutPositionWindow); + CHECK_NAME(glutReshapeWindow); + CHECK_NAME(glutPopWindow); + CHECK_NAME(glutPushWindow); + CHECK_NAME(glutIconifyWindow); + CHECK_NAME(glutShowWindow); + CHECK_NAME(glutHideWindow); + CHECK_NAME(glutFullScreen); + CHECK_NAME(glutSetCursor); + CHECK_NAME(glutWarpPointer); + CHECK_NAME(glutEstablishOverlay); + CHECK_NAME(glutRemoveOverlay); + CHECK_NAME(glutUseLayer); + CHECK_NAME(glutPostOverlayRedisplay); + CHECK_NAME(glutPostWindowOverlayRedisplay); + CHECK_NAME(glutShowOverlay); + CHECK_NAME(glutHideOverlay); + CHECK_NAME(glutCreateMenu); + CHECK_NAME(glutDestroyMenu); + CHECK_NAME(glutGetMenu); + CHECK_NAME(glutSetMenu); + CHECK_NAME(glutAddMenuEntry); + CHECK_NAME(glutAddSubMenu); + CHECK_NAME(glutChangeToMenuEntry); + CHECK_NAME(glutChangeToSubMenu); + CHECK_NAME(glutRemoveMenuItem); + CHECK_NAME(glutAttachMenu); + CHECK_NAME(glutDetachMenu); + CHECK_NAME(glutDisplayFunc); + CHECK_NAME(glutReshapeFunc); + CHECK_NAME(glutKeyboardFunc); + CHECK_NAME(glutMouseFunc); + CHECK_NAME(glutMotionFunc); + CHECK_NAME(glutPassiveMotionFunc); + CHECK_NAME(glutEntryFunc); + CHECK_NAME(glutVisibilityFunc); + CHECK_NAME(glutIdleFunc); + CHECK_NAME(glutTimerFunc); + CHECK_NAME(glutMenuStateFunc); + CHECK_NAME(glutSpecialFunc); + CHECK_NAME(glutSpaceballMotionFunc); + CHECK_NAME(glutSpaceballRotateFunc); + CHECK_NAME(glutSpaceballButtonFunc); + CHECK_NAME(glutButtonBoxFunc); + CHECK_NAME(glutDialsFunc); + CHECK_NAME(glutTabletMotionFunc); + CHECK_NAME(glutTabletButtonFunc); + CHECK_NAME(glutMenuStatusFunc); + CHECK_NAME(glutOverlayDisplayFunc); + CHECK_NAME(glutWindowStatusFunc); + CHECK_NAME(glutKeyboardUpFunc); + CHECK_NAME(glutSpecialUpFunc); +#if !defined(_WIN32_WCE) + CHECK_NAME(glutJoystickFunc); +#endif /* !defined(_WIN32_WCE) */ + CHECK_NAME(glutSetColor); + CHECK_NAME(glutGetColor); + CHECK_NAME(glutCopyColormap); + CHECK_NAME(glutGet); + CHECK_NAME(glutDeviceGet); + CHECK_NAME(glutExtensionSupported); + CHECK_NAME(glutGetModifiers); + CHECK_NAME(glutLayerGet); + CHECK_NAME(glutBitmapCharacter); + CHECK_NAME(glutBitmapWidth); + CHECK_NAME(glutStrokeCharacter); + CHECK_NAME(glutStrokeWidth); + CHECK_NAME(glutBitmapLength); + CHECK_NAME(glutStrokeLength); + CHECK_NAME(glutWireSphere); + CHECK_NAME(glutSolidSphere); + CHECK_NAME(glutWireCone); + CHECK_NAME(glutSolidCone); + CHECK_NAME(glutWireCube); + CHECK_NAME(glutSolidCube); + CHECK_NAME(glutWireTorus); + CHECK_NAME(glutSolidTorus); + CHECK_NAME(glutWireDodecahedron); + CHECK_NAME(glutSolidDodecahedron); + CHECK_NAME(glutWireTeapot); + CHECK_NAME(glutSolidTeapot); + CHECK_NAME(glutWireOctahedron); + CHECK_NAME(glutSolidOctahedron); + CHECK_NAME(glutWireTetrahedron); + CHECK_NAME(glutSolidTetrahedron); + CHECK_NAME(glutWireIcosahedron); + CHECK_NAME(glutSolidIcosahedron); + CHECK_NAME(glutVideoResizeGet); + CHECK_NAME(glutSetupVideoResizing); + CHECK_NAME(glutStopVideoResizing); + CHECK_NAME(glutVideoResize); + CHECK_NAME(glutVideoPan); + CHECK_NAME(glutReportErrors); + CHECK_NAME(glutIgnoreKeyRepeat); + CHECK_NAME(glutSetKeyRepeat); +#if !defined(_WIN32_WCE) + CHECK_NAME(glutForceJoystickFunc); + CHECK_NAME(glutGameModeString); + CHECK_NAME(glutEnterGameMode); + CHECK_NAME(glutLeaveGameMode); + CHECK_NAME(glutGameModeGet); +#endif /* !defined(_WIN32_WCE) */ + /* freeglut extensions */ + CHECK_NAME(glutMainLoopEvent); + CHECK_NAME(glutLeaveMainLoop); + CHECK_NAME(glutCloseFunc); + CHECK_NAME(glutWMCloseFunc); + CHECK_NAME(glutMenuDestroyFunc); + CHECK_NAME(glutFullScreenToggle); + CHECK_NAME(glutSetOption); + CHECK_NAME(glutGetModeValues); + CHECK_NAME(glutSetWindowData); + CHECK_NAME(glutGetWindowData); + CHECK_NAME(glutSetMenuData); + CHECK_NAME(glutGetMenuData); + CHECK_NAME(glutBitmapHeight); + CHECK_NAME(glutStrokeHeight); + CHECK_NAME(glutBitmapString); + CHECK_NAME(glutStrokeString); + CHECK_NAME(glutWireRhombicDodecahedron); + CHECK_NAME(glutSolidRhombicDodecahedron); + CHECK_NAME(glutWireSierpinskiSponge); + CHECK_NAME(glutSolidSierpinskiSponge); + CHECK_NAME(glutWireCylinder); + CHECK_NAME(glutSolidCylinder); + CHECK_NAME(glutGetProcAddress); + CHECK_NAME(glutMouseWheelFunc); + CHECK_NAME(glutJoystickGetNumAxes); + CHECK_NAME(glutJoystickGetNumButtons); + CHECK_NAME(glutJoystickNotWorking); + CHECK_NAME(glutJoystickGetDeadBand); + CHECK_NAME(glutJoystickSetDeadBand); + CHECK_NAME(glutJoystickGetSaturation); + CHECK_NAME(glutJoystickSetSaturation); + CHECK_NAME(glutJoystickSetMinRange); + CHECK_NAME(glutJoystickSetMaxRange); + CHECK_NAME(glutJoystickSetCenter); + CHECK_NAME(glutJoystickGetMinRange); + CHECK_NAME(glutJoystickGetMaxRange); + CHECK_NAME(glutJoystickGetCenter); + CHECK_NAME(glutInitContextVersion); + CHECK_NAME(glutInitContextFlags); + CHECK_NAME(glutInitContextProfile); +#undef CHECK_NAME + + return NULL; +} + + +SFG_Proc fghGetProcAddress( const char *procName ) +{ +#if TARGET_HOST_MS_WINDOWS + return (SFG_Proc)wglGetProcAddress( ( LPCSTR )procName ); +#elif TARGET_HOST_POSIX_X11 && defined( GLX_ARB_get_proc_address ) + return (SFG_Proc)glXGetProcAddressARB( ( const GLubyte * )procName ); +#else + return NULL; +#endif +} + + +GLUTproc FGAPIENTRY +glutGetProcAddress( const char *procName ) +{ + GLUTproc p; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetProcAddress" ); + + /* Try GLUT functions first, then core GL functions */ + p = fghGetGLUTProcAddress( procName ); + return ( p != NULL ) ? p : fghGetProcAddress( procName ); +} diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_ext.h b/tests/Box2D_v2.2.1/freeglut/freeglut_ext.h new file mode 100755 index 0000000000000..aca85e7b62200 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_ext.h @@ -0,0 +1,212 @@ +#ifndef __FREEGLUT_EXT_H__ +#define __FREEGLUT_EXT_H__ + +/* + * freeglut_ext.h + * + * The non-GLUT-compatible extensions to the freeglut library include file + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 2 1999 + * + * 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 + * PAWEL W. OLSZTA 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. + */ + +#ifdef __cplusplus + extern "C" { +#endif + +/* + * Additional GLUT Key definitions for the Special key function + */ +#define GLUT_KEY_NUM_LOCK 0x006D +#define GLUT_KEY_BEGIN 0x006E +#define GLUT_KEY_DELETE 0x006F + +/* + * GLUT API Extension macro definitions -- behaviour when the user clicks on an "x" to close a window + */ +#define GLUT_ACTION_EXIT 0 +#define GLUT_ACTION_GLUTMAINLOOP_RETURNS 1 +#define GLUT_ACTION_CONTINUE_EXECUTION 2 + +/* + * Create a new rendering context when the user opens a new window? + */ +#define GLUT_CREATE_NEW_CONTEXT 0 +#define GLUT_USE_CURRENT_CONTEXT 1 + +/* + * Direct/Indirect rendering context options (has meaning only in Unix/X11) + */ +#define GLUT_FORCE_INDIRECT_CONTEXT 0 +#define GLUT_ALLOW_DIRECT_CONTEXT 1 +#define GLUT_TRY_DIRECT_CONTEXT 2 +#define GLUT_FORCE_DIRECT_CONTEXT 3 + +/* + * GLUT API Extension macro definitions -- the glutGet parameters + */ +#define GLUT_INIT_STATE 0x007C + +#define GLUT_ACTION_ON_WINDOW_CLOSE 0x01F9 + +#define GLUT_WINDOW_BORDER_WIDTH 0x01FA +#define GLUT_WINDOW_HEADER_HEIGHT 0x01FB + +#define GLUT_VERSION 0x01FC + +#define GLUT_RENDERING_CONTEXT 0x01FD +#define GLUT_DIRECT_RENDERING 0x01FE + +#define GLUT_FULL_SCREEN 0x01FF + +/* + * New tokens for glutInitDisplayMode. + * Only one GLUT_AUXn bit may be used at a time. + * Value 0x0400 is defined in OpenGLUT. + */ +#define GLUT_AUX 0x1000 + +#define GLUT_AUX1 0x1000 +#define GLUT_AUX2 0x2000 +#define GLUT_AUX3 0x4000 +#define GLUT_AUX4 0x8000 + +/* + * Context-related flags, see freeglut_state.c + */ +#define GLUT_INIT_MAJOR_VERSION 0x0200 +#define GLUT_INIT_MINOR_VERSION 0x0201 +#define GLUT_INIT_FLAGS 0x0202 +#define GLUT_INIT_PROFILE 0x0203 + +/* + * Flags for glutInitContextFlags, see freeglut_init.c + */ +#define GLUT_DEBUG 0x0001 +#define GLUT_FORWARD_COMPATIBLE 0x0002 + + +/* + * Flags for glutInitContextProfile, see freeglut_init.c + */ +#define GLUT_CORE_PROFILE 0x0001 +#define GLUT_COMPATIBILITY_PROFILE 0x0002 + +/* + * Process loop function, see freeglut_main.c + */ +FGAPI void FGAPIENTRY glutMainLoopEvent( void ); +FGAPI void FGAPIENTRY glutLeaveMainLoop( void ); +FGAPI void FGAPIENTRY glutExit ( void ); + +/* + * Window management functions, see freeglut_window.c + */ +FGAPI void FGAPIENTRY glutFullScreenToggle( void ); + +/* + * Window-specific callback functions, see freeglut_callbacks.c + */ +FGAPI void FGAPIENTRY glutMouseWheelFunc( void (* callback)( int, int, int, int ) ); +FGAPI void FGAPIENTRY glutCloseFunc( void (* callback)( void ) ); +FGAPI void FGAPIENTRY glutWMCloseFunc( void (* callback)( void ) ); +/* A. Donev: Also a destruction callback for menus */ +FGAPI void FGAPIENTRY glutMenuDestroyFunc( void (* callback)( void ) ); + +/* + * State setting and retrieval functions, see freeglut_state.c + */ +FGAPI void FGAPIENTRY glutSetOption ( GLenum option_flag, int value ); +FGAPI int * FGAPIENTRY glutGetModeValues(GLenum mode, int * size); +/* A.Donev: User-data manipulation */ +FGAPI void* FGAPIENTRY glutGetWindowData( void ); +FGAPI void FGAPIENTRY glutSetWindowData(void* data); +FGAPI void* FGAPIENTRY glutGetMenuData( void ); +FGAPI void FGAPIENTRY glutSetMenuData(void* data); + +/* + * Font stuff, see freeglut_font.c + */ +FGAPI int FGAPIENTRY glutBitmapHeight( void* font ); +FGAPI GLfloat FGAPIENTRY glutStrokeHeight( void* font ); +FGAPI void FGAPIENTRY glutBitmapString( void* font, const unsigned char *string ); +FGAPI void FGAPIENTRY glutStrokeString( void* font, const unsigned char *string ); + +/* + * Geometry functions, see freeglut_geometry.c + */ +FGAPI void FGAPIENTRY glutWireRhombicDodecahedron( void ); +FGAPI void FGAPIENTRY glutSolidRhombicDodecahedron( void ); +FGAPI void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale ); +FGAPI void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale ); +FGAPI void FGAPIENTRY glutWireCylinder( GLdouble radius, GLdouble height, GLint slices, GLint stacks); +FGAPI void FGAPIENTRY glutSolidCylinder( GLdouble radius, GLdouble height, GLint slices, GLint stacks); + +/* + * Extension functions, see freeglut_ext.c + */ +typedef void (*GLUTproc)(); +FGAPI GLUTproc FGAPIENTRY glutGetProcAddress( const char *procName ); + +/* + * Joystick functions, see freeglut_joystick.c + */ +/* USE OF THESE FUNCTIONS IS DEPRECATED !!!!! */ +/* If you have a serious need for these functions in your application, please either + * contact the "freeglut" developer community at freeglut-developer@lists.sourceforge.net, + * switch to the OpenGLUT library, or else port your joystick functionality over to PLIB's + * "js" library. + */ +int glutJoystickGetNumAxes( int ident ); +int glutJoystickGetNumButtons( int ident ); +int glutJoystickNotWorking( int ident ); +float glutJoystickGetDeadBand( int ident, int axis ); +void glutJoystickSetDeadBand( int ident, int axis, float db ); +float glutJoystickGetSaturation( int ident, int axis ); +void glutJoystickSetSaturation( int ident, int axis, float st ); +void glutJoystickSetMinRange( int ident, float *axes ); +void glutJoystickSetMaxRange( int ident, float *axes ); +void glutJoystickSetCenter( int ident, float *axes ); +void glutJoystickGetMinRange( int ident, float *axes ); +void glutJoystickGetMaxRange( int ident, float *axes ); +void glutJoystickGetCenter( int ident, float *axes ); + +/* + * Initialization functions, see freeglut_init.c + */ +FGAPI void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion ); +FGAPI void FGAPIENTRY glutInitContextFlags( int flags ); +FGAPI void FGAPIENTRY glutInitContextProfile( int profile ); + +/* + * GLUT API macro definitions -- the display mode definitions + */ +#define GLUT_CAPTIONLESS 0x0400 +#define GLUT_BORDERLESS 0x0800 +#define GLUT_SRGB 0x1000 + +#ifdef __cplusplus + } +#endif + +/*** END OF FILE ***/ + +#endif /* __FREEGLUT_EXT_H__ */ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_font.c b/tests/Box2D_v2.2.1/freeglut/freeglut_font.c new file mode 100755 index 0000000000000..6e37b95d9724a --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_font.c @@ -0,0 +1,384 @@ +/* + * freeglut_font.c + * + * Bitmap and stroke fonts displaying. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 16 1999 + * + * 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 + * PAWEL W. OLSZTA 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 "freeglut.h" +#include "freeglut_internal.h" + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * Test things out ... + */ + +/* -- IMPORT DECLARATIONS -------------------------------------------------- */ + +/* + * These are the font faces defined in freeglut_font_data.c file: + */ +extern SFG_Font fgFontFixed8x13; +extern SFG_Font fgFontFixed9x15; +extern SFG_Font fgFontHelvetica10; +extern SFG_Font fgFontHelvetica12; +extern SFG_Font fgFontHelvetica18; +extern SFG_Font fgFontTimesRoman10; +extern SFG_Font fgFontTimesRoman24; +extern SFG_StrokeFont fgStrokeRoman; +extern SFG_StrokeFont fgStrokeMonoRoman; + + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +/* + * Matches a font ID with a SFG_Font structure pointer. + * This was changed to match the GLUT header style. + */ +static SFG_Font* fghFontByID( void* font ) +{ + if( font == GLUT_BITMAP_8_BY_13 ) + return &fgFontFixed8x13; + if( font == GLUT_BITMAP_9_BY_15 ) + return &fgFontFixed9x15; + if( font == GLUT_BITMAP_HELVETICA_10 ) + return &fgFontHelvetica10; + if( font == GLUT_BITMAP_HELVETICA_12 ) + return &fgFontHelvetica12; + if( font == GLUT_BITMAP_HELVETICA_18 ) + return &fgFontHelvetica18; + if( font == GLUT_BITMAP_TIMES_ROMAN_10 ) + return &fgFontTimesRoman10; + if( font == GLUT_BITMAP_TIMES_ROMAN_24 ) + return &fgFontTimesRoman24; + + fgWarning( "font 0x%08x not found", font ); + return 0; +} + +/* + * Matches a font ID with a SFG_StrokeFont structure pointer. + * This was changed to match the GLUT header style. + */ +static SFG_StrokeFont* fghStrokeByID( void* font ) +{ + if( font == GLUT_STROKE_ROMAN ) + return &fgStrokeRoman; + if( font == GLUT_STROKE_MONO_ROMAN ) + return &fgStrokeMonoRoman; + + fgWarning( "stroke font 0x%08x not found", font ); + return 0; +} + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Draw a bitmap character + */ +void FGAPIENTRY glutBitmapCharacter( void* fontID, int character ) +{ + const GLubyte* face; + SFG_Font* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutBitmapCharacter" ); + font = fghFontByID( fontID ); + freeglut_return_if_fail( ( character >= 1 )&&( character < 256 ) ); + freeglut_return_if_fail( font ); + + /* + * Find the character we want to draw (???) + */ + face = font->Characters[ character ]; + + glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT ); + glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE ); + glPixelStorei( GL_UNPACK_LSB_FIRST, GL_FALSE ); + glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); + glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 ); + glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glBitmap( + face[ 0 ], font->Height, /* The bitmap's width and height */ + font->xorig, font->yorig, /* The origin in the font glyph */ + ( float )( face[ 0 ] ), 0.0, /* The raster advance -- inc. x,y */ + ( face + 1 ) /* The packed bitmap data... */ + ); + glPopClientAttrib( ); +} + +void FGAPIENTRY glutBitmapString( void* fontID, const unsigned char *string ) +{ + unsigned char c; + float x = 0.0f ; + SFG_Font* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutBitmapString" ); + font = fghFontByID( fontID ); + freeglut_return_if_fail( font ); + if ( !string || ! *string ) + return; + + glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT ); + glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE ); + glPixelStorei( GL_UNPACK_LSB_FIRST, GL_FALSE ); + glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); + glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 ); + glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + /* + * Step through the string, drawing each character. + * A newline will simply translate the next character's insertion + * point back to the start of the line and down one line. + */ + while( ( c = *string++) ) + if( c == '\n' ) + { + glBitmap ( 0, 0, 0, 0, -x, (float) -font->Height, NULL ); + x = 0.0f; + } + else /* Not an EOL, draw the bitmap character */ + { + const GLubyte* face = font->Characters[ c ]; + + glBitmap( + face[ 0 ], font->Height, /* Bitmap's width and height */ + font->xorig, font->yorig, /* The origin in the font glyph */ + ( float )( face[ 0 ] ), 0.0, /* The raster advance; inc. x,y */ + ( face + 1 ) /* The packed bitmap data... */ + ); + + x += ( float )( face[ 0 ] ); + } + + glPopClientAttrib( ); +} + +/* + * Returns the width in pixels of a font's character + */ +int FGAPIENTRY glutBitmapWidth( void* fontID, int character ) +{ + SFG_Font* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutBitmapWidth" ); + font = fghFontByID( fontID ); + freeglut_return_val_if_fail( character > 0 && character < 256, 0 ); + freeglut_return_val_if_fail( font, 0 ); + return *( font->Characters[ character ] ); +} + +/* + * Return the width of a string drawn using a bitmap font + */ +int FGAPIENTRY glutBitmapLength( void* fontID, const unsigned char* string ) +{ + unsigned char c; + int length = 0, this_line_length = 0; + SFG_Font* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutBitmapLength" ); + font = fghFontByID( fontID ); + freeglut_return_val_if_fail( font, 0 ); + if ( !string || ! *string ) + return 0; + + while( ( c = *string++) ) + { + if( c != '\n' )/* Not an EOL, increment length of line */ + this_line_length += *( font->Characters[ c ]); + else /* EOL; reset the length of this line */ + { + if( length < this_line_length ) + length = this_line_length; + this_line_length = 0; + } + } + if ( length < this_line_length ) + length = this_line_length; + + return length; +} + +/* + * Returns the height of a bitmap font + */ +int FGAPIENTRY glutBitmapHeight( void* fontID ) +{ + SFG_Font* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutBitmapHeight" ); + font = fghFontByID( fontID ); + freeglut_return_val_if_fail( font, 0 ); + return font->Height; +} + +/* + * Draw a stroke character + */ +void FGAPIENTRY glutStrokeCharacter( void* fontID, int character ) +{ + const SFG_StrokeChar *schar; + const SFG_StrokeStrip *strip; + int i, j; + SFG_StrokeFont* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutStrokeCharacter" ); + font = fghStrokeByID( fontID ); + freeglut_return_if_fail( character >= 0 ); + freeglut_return_if_fail( character < font->Quantity ); + freeglut_return_if_fail( font ); + + schar = font->Characters[ character ]; + freeglut_return_if_fail( schar ); + strip = schar->Strips; + + for( i = 0; i < schar->Number; i++, strip++ ) + { + glBegin( GL_LINE_STRIP ); + for( j = 0; j < strip->Number; j++ ) + glVertex2f( strip->Vertices[ j ].X, strip->Vertices[ j ].Y ); + glEnd( ); + glBegin( GL_POINTS ); + for( j = 0; j < strip->Number; j++ ) + glVertex2f( strip->Vertices[ j ].X, strip->Vertices[ j ].Y ); + glEnd( ); + } + glTranslatef( schar->Right, 0.0, 0.0 ); +} + +void FGAPIENTRY glutStrokeString( void* fontID, const unsigned char *string ) +{ + unsigned char c; + int i, j; + float length = 0.0; + SFG_StrokeFont* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutStrokeString" ); + font = fghStrokeByID( fontID ); + freeglut_return_if_fail( font ); + if ( !string || ! *string ) + return; + + /* + * Step through the string, drawing each character. + * A newline will simply translate the next character's insertion + * point back to the start of the line and down one line. + */ + while( ( c = *string++) ) + if( c < font->Quantity ) + { + if( c == '\n' ) + { + glTranslatef ( -length, -( float )( font->Height ), 0.0 ); + length = 0.0; + } + else /* Not an EOL, draw the bitmap character */ + { + const SFG_StrokeChar *schar = font->Characters[ c ]; + if( schar ) + { + const SFG_StrokeStrip *strip = schar->Strips; + + for( i = 0; i < schar->Number; i++, strip++ ) + { + glBegin( GL_LINE_STRIP ); + for( j = 0; j < strip->Number; j++ ) + glVertex2f( strip->Vertices[ j ].X, + strip->Vertices[ j ].Y); + + glEnd( ); + } + + length += schar->Right; + glTranslatef( schar->Right, 0.0, 0.0 ); + } + } + } +} + +/* + * Return the width in pixels of a stroke character + */ +int FGAPIENTRY glutStrokeWidth( void* fontID, int character ) +{ + const SFG_StrokeChar *schar; + SFG_StrokeFont* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutStrokeWidth" ); + font = fghStrokeByID( fontID ); + freeglut_return_val_if_fail( ( character >= 0 ) && + ( character < font->Quantity ), + 0 + ); + freeglut_return_val_if_fail( font, 0 ); + schar = font->Characters[ character ]; + freeglut_return_val_if_fail( schar, 0 ); + + return ( int )( schar->Right + 0.5 ); +} + +/* + * Return the width of a string drawn using a stroke font + */ +int FGAPIENTRY glutStrokeLength( void* fontID, const unsigned char* string ) +{ + unsigned char c; + float length = 0.0; + float this_line_length = 0.0; + SFG_StrokeFont* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutStrokeLength" ); + font = fghStrokeByID( fontID ); + freeglut_return_val_if_fail( font, 0 ); + if ( !string || ! *string ) + return 0; + + while( ( c = *string++) ) + if( c < font->Quantity ) + { + if( c == '\n' ) /* EOL; reset the length of this line */ + { + if( length < this_line_length ) + length = this_line_length; + this_line_length = 0.0; + } + else /* Not an EOL, increment the length of this line */ + { + const SFG_StrokeChar *schar = font->Characters[ c ]; + if( schar ) + this_line_length += schar->Right; + } + } + if( length < this_line_length ) + length = this_line_length; + return( int )( length + 0.5 ); +} + +/* + * Returns the height of a stroke font + */ +GLfloat FGAPIENTRY glutStrokeHeight( void* fontID ) +{ + SFG_StrokeFont* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutStrokeHeight" ); + font = fghStrokeByID( fontID ); + freeglut_return_val_if_fail( font, 0.0 ); + return font->Height; +} + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_font_data.c b/tests/Box2D_v2.2.1/freeglut/freeglut_font_data.c new file mode 100755 index 0000000000000..5ffef5a0b493d --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_font_data.c @@ -0,0 +1,2020 @@ +/* + \file og_font_data.c + \brief Bitmapped font data for OpenGLUT fonts. +*/ + +/* + * This file has been automatically generated by the + * genfonts utility. + * + * The legal status of this file is a bit vague. The font glyphs + * themselves come from XFree86 v4.3.0 (as of this writing), and as + * part of the X server may be subject to the XFree86 copyrights. + * The original freeglut fonts were extracted by a utility written + * by Pawel W. Olszta (see below) and the generated fonts contained + * his copyright exclusively. Steve Baker asserts that Pawel + * assigned intellectual property rights to Steve Baker. Steve + * Baker also asserts that fonts cannot be copyrighted. He has + * neither stripped the copyright from the freeglut fonts nor + * formally retitled anything in his name. Since that time, the + * OpenGLUT project has branched from freeglut, and has made + * necessary modifications to Pawel's ``genfonts'' utility. + * To that extent, OpenGLUT may have some title to this file. + * What is fairly clear is that the font data is licensed under + * the XFree86 license (which is variously termed ``XFree'' and + * ``MIT'' by the freeglut project). It is believed that all + * title holders wish this file to be as useful as possible, and + * that either the ``XFree'' or ``MIT'' license works. + * + * Portions copyright (c) 2004, the OpenGLUT project contributors. + * OpenGLUT branched from freeglut in February, 2004. + * + * Copyright (c) 1999-2000 by Pawel W. Olszta + * Written by Pawel W. Olszta, + * + * 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 Sotware. + * + * 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 + * PAWEL W. OLSZTA 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 "freeglut.h" +#include "freeglut_internal.h" + +/* + * The following bitmapped fonts are defined in this file: + * + * 1. fgFontFixed8x13 + * -misc-fixed-medium-r-normal--13-120-75-75-C-80-iso8859-1 + * 2. fgFontFixed9x15 + * -misc-fixed-medium-r-normal--15-140-75-75-C-90-iso8859-1 + * 3. fgFontHelvetica10 + * -adobe-helvetica-medium-r-normal--10-100-75-75-p-56-iso8859-1 + * 4. fgFontHelvetica12 + * -adobe-helvetica-medium-r-normal--12-120-75-75-p-67-iso8859-1 + * 5. fgFontHelvetica18 + * -adobe-helvetica-medium-r-normal--18-180-75-75-p-98-iso8859-1 + * 6. fgFontTimesRoman10 + * -adobe-times-medium-r-normal--10-100-75-75-p-54-iso8859-1 + * 7. fgFontTimesRoman24 + * -adobe-times-medium-r-normal--24-240-75-75-p-124-iso8859-1 + */ + +static const GLubyte Fixed8x13_Character_000[] = { 8, 0, 0, 0,170, 0,130, 0,130, 0,130, 0,170, 0, 0}; +static const GLubyte Fixed8x13_Character_001[] = { 8, 0, 0, 0, 0, 16, 56,124,254,124, 56, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_002[] = { 8, 0,170, 85,170, 85,170, 85,170, 85,170, 85,170, 85,170}; +static const GLubyte Fixed8x13_Character_003[] = { 8, 0, 0, 0, 4, 4, 4, 4,174,160,224,160,160, 0, 0}; +static const GLubyte Fixed8x13_Character_004[] = { 8, 0, 0, 0, 8, 8, 12, 8,142,128,192,128,224, 0, 0}; +static const GLubyte Fixed8x13_Character_005[] = { 8, 0, 0, 0, 10, 10, 12, 10,108,128,128,128, 96, 0, 0}; +static const GLubyte Fixed8x13_Character_006[] = { 8, 0, 0, 0, 8, 8, 12, 8,238,128,128,128,128, 0, 0}; +static const GLubyte Fixed8x13_Character_007[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 24, 36, 36, 24, 0, 0}; +static const GLubyte Fixed8x13_Character_008[] = { 8, 0, 0, 0, 0,124, 0, 16, 16,124, 16, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_009[] = { 8, 0, 0, 0, 14, 8, 8, 8,168,160,160,160,192, 0, 0}; +static const GLubyte Fixed8x13_Character_010[] = { 8, 0, 0, 0, 4, 4, 4, 4, 46, 80, 80,136,136, 0, 0}; +static const GLubyte Fixed8x13_Character_011[] = { 8, 0, 0, 0, 0, 0, 0, 0,240, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_012[] = { 8, 0, 16, 16, 16, 16, 16, 16,240, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_013[] = { 8, 0, 16, 16, 16, 16, 16, 16, 31, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_014[] = { 8, 0, 0, 0, 0, 0, 0, 0, 31, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_015[] = { 8, 0, 16, 16, 16, 16, 16, 16,255, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_016[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255}; +static const GLubyte Fixed8x13_Character_017[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_018[] = { 8, 0, 0, 0, 0, 0, 0, 0,255, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_019[] = { 8, 0, 0, 0, 0,255, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_020[] = { 8, 0,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_021[] = { 8, 0, 16, 16, 16, 16, 16, 16, 31, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_022[] = { 8, 0, 16, 16, 16, 16, 16, 16,240, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_023[] = { 8, 0, 0, 0, 0, 0, 0, 0,255, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_024[] = { 8, 0, 16, 16, 16, 16, 16, 16,255, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_025[] = { 8, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_026[] = { 8, 0, 0, 0,254, 0, 14, 48,192, 48, 14, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_027[] = { 8, 0, 0, 0,254, 0,224, 24, 6, 24,224, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_028[] = { 8, 0, 0, 0, 68, 68, 68, 68, 68,254, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_029[] = { 8, 0, 0, 0, 32, 32,126, 16, 8,126, 4, 4, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_030[] = { 8, 0, 0, 0,220, 98, 32, 32, 32,112, 32, 34, 28, 0, 0}; +static const GLubyte Fixed8x13_Character_031[] = { 8, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_032[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_033[] = { 8, 0, 0, 0, 16, 0, 16, 16, 16, 16, 16, 16, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_034[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 36, 36, 0, 0}; +static const GLubyte Fixed8x13_Character_035[] = { 8, 0, 0, 0, 0, 36, 36,126, 36,126, 36, 36, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_036[] = { 8, 0, 0, 0, 16,120, 20, 20, 56, 80, 80, 60, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_037[] = { 8, 0, 0, 0, 68, 42, 36, 16, 8, 8, 36, 82, 34, 0, 0}; +static const GLubyte Fixed8x13_Character_038[] = { 8, 0, 0, 0, 58, 68, 74, 48, 72, 72, 48, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_039[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 48, 56, 0, 0}; +static const GLubyte Fixed8x13_Character_040[] = { 8, 0, 0, 0, 4, 8, 8, 16, 16, 16, 8, 8, 4, 0, 0}; +static const GLubyte Fixed8x13_Character_041[] = { 8, 0, 0, 0, 32, 16, 16, 8, 8, 8, 16, 16, 32, 0, 0}; +static const GLubyte Fixed8x13_Character_042[] = { 8, 0, 0, 0, 0, 0, 36, 24,126, 24, 36, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_043[] = { 8, 0, 0, 0, 0, 0, 16, 16,124, 16, 16, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_044[] = { 8, 0, 0, 64, 48, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_045[] = { 8, 0, 0, 0, 0, 0, 0, 0,126, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_046[] = { 8, 0, 0, 16, 56, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_047[] = { 8, 0, 0, 0,128,128, 64, 32, 16, 8, 4, 2, 2, 0, 0}; +static const GLubyte Fixed8x13_Character_048[] = { 8, 0, 0, 0, 24, 36, 66, 66, 66, 66, 66, 36, 24, 0, 0}; +static const GLubyte Fixed8x13_Character_049[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16, 80, 48, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_050[] = { 8, 0, 0, 0,126, 64, 32, 24, 4, 2, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_051[] = { 8, 0, 0, 0, 60, 66, 2, 2, 28, 8, 4, 2,126, 0, 0}; +static const GLubyte Fixed8x13_Character_052[] = { 8, 0, 0, 0, 4, 4,126, 68, 68, 36, 20, 12, 4, 0, 0}; +static const GLubyte Fixed8x13_Character_053[] = { 8, 0, 0, 0, 60, 66, 2, 2, 98, 92, 64, 64,126, 0, 0}; +static const GLubyte Fixed8x13_Character_054[] = { 8, 0, 0, 0, 60, 66, 66, 98, 92, 64, 64, 32, 28, 0, 0}; +static const GLubyte Fixed8x13_Character_055[] = { 8, 0, 0, 0, 32, 32, 16, 16, 8, 8, 4, 2,126, 0, 0}; +static const GLubyte Fixed8x13_Character_056[] = { 8, 0, 0, 0, 60, 66, 66, 66, 60, 66, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_057[] = { 8, 0, 0, 0, 56, 4, 2, 2, 58, 70, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_058[] = { 8, 0, 0, 16, 56, 16, 0, 0, 16, 56, 16, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_059[] = { 8, 0, 0, 64, 48, 56, 0, 0, 16, 56, 16, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_060[] = { 8, 0, 0, 0, 2, 4, 8, 16, 32, 16, 8, 4, 2, 0, 0}; +static const GLubyte Fixed8x13_Character_061[] = { 8, 0, 0, 0, 0, 0,126, 0, 0,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_062[] = { 8, 0, 0, 0, 64, 32, 16, 8, 4, 8, 16, 32, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_063[] = { 8, 0, 0, 0, 8, 0, 8, 8, 4, 2, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_064[] = { 8, 0, 0, 0, 60, 64, 74, 86, 82, 78, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_065[] = { 8, 0, 0, 0, 66, 66, 66,126, 66, 66, 66, 36, 24, 0, 0}; +static const GLubyte Fixed8x13_Character_066[] = { 8, 0, 0, 0,252, 66, 66, 66,124, 66, 66, 66,252, 0, 0}; +static const GLubyte Fixed8x13_Character_067[] = { 8, 0, 0, 0, 60, 66, 64, 64, 64, 64, 64, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_068[] = { 8, 0, 0, 0,252, 66, 66, 66, 66, 66, 66, 66,252, 0, 0}; +static const GLubyte Fixed8x13_Character_069[] = { 8, 0, 0, 0,126, 64, 64, 64,120, 64, 64, 64,126, 0, 0}; +static const GLubyte Fixed8x13_Character_070[] = { 8, 0, 0, 0, 64, 64, 64, 64,120, 64, 64, 64,126, 0, 0}; +static const GLubyte Fixed8x13_Character_071[] = { 8, 0, 0, 0, 58, 70, 66, 78, 64, 64, 64, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_072[] = { 8, 0, 0, 0, 66, 66, 66, 66,126, 66, 66, 66, 66, 0, 0}; +static const GLubyte Fixed8x13_Character_073[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16, 16, 16,124, 0, 0}; +static const GLubyte Fixed8x13_Character_074[] = { 8, 0, 0, 0, 56, 68, 4, 4, 4, 4, 4, 4, 31, 0, 0}; +static const GLubyte Fixed8x13_Character_075[] = { 8, 0, 0, 0, 66, 68, 72, 80, 96, 80, 72, 68, 66, 0, 0}; +static const GLubyte Fixed8x13_Character_076[] = { 8, 0, 0, 0,126, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_077[] = { 8, 0, 0, 0,130,130,130,146,146,170,198,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_078[] = { 8, 0, 0, 0, 66, 66, 66, 70, 74, 82, 98, 66, 66, 0, 0}; +static const GLubyte Fixed8x13_Character_079[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_080[] = { 8, 0, 0, 0, 64, 64, 64, 64,124, 66, 66, 66,124, 0, 0}; +static const GLubyte Fixed8x13_Character_081[] = { 8, 0, 0, 2, 60, 74, 82, 66, 66, 66, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_082[] = { 8, 0, 0, 0, 66, 68, 72, 80,124, 66, 66, 66,124, 0, 0}; +static const GLubyte Fixed8x13_Character_083[] = { 8, 0, 0, 0, 60, 66, 2, 2, 60, 64, 64, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_084[] = { 8, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16,254, 0, 0}; +static const GLubyte Fixed8x13_Character_085[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 66, 0, 0}; +static const GLubyte Fixed8x13_Character_086[] = { 8, 0, 0, 0, 16, 40, 40, 40, 68, 68, 68,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_087[] = { 8, 0, 0, 0, 68,170,146,146,146,130,130,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_088[] = { 8, 0, 0, 0,130,130, 68, 40, 16, 40, 68,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_089[] = { 8, 0, 0, 0, 16, 16, 16, 16, 16, 40, 68,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_090[] = { 8, 0, 0, 0,126, 64, 64, 32, 16, 8, 4, 2,126, 0, 0}; +static const GLubyte Fixed8x13_Character_091[] = { 8, 0, 0, 0, 60, 32, 32, 32, 32, 32, 32, 32, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_092[] = { 8, 0, 0, 0, 2, 2, 4, 8, 16, 32, 64,128,128, 0, 0}; +static const GLubyte Fixed8x13_Character_093[] = { 8, 0, 0, 0,120, 8, 8, 8, 8, 8, 8, 8,120, 0, 0}; +static const GLubyte Fixed8x13_Character_094[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 40, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_095[] = { 8, 0, 0,254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_096[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 24, 56, 0, 0}; +static const GLubyte Fixed8x13_Character_097[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_098[] = { 8, 0, 0, 0, 92, 98, 66, 66, 98, 92, 64, 64, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_099[] = { 8, 0, 0, 0, 60, 66, 64, 64, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_100[] = { 8, 0, 0, 0, 58, 70, 66, 66, 70, 58, 2, 2, 2, 0, 0}; +static const GLubyte Fixed8x13_Character_101[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_102[] = { 8, 0, 0, 0, 32, 32, 32, 32,124, 32, 32, 34, 28, 0, 0}; +static const GLubyte Fixed8x13_Character_103[] = { 8, 0, 60, 66, 60, 64, 56, 68, 68, 58, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_104[] = { 8, 0, 0, 0, 66, 66, 66, 66, 98, 92, 64, 64, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_105[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_106[] = { 8, 0, 56, 68, 68, 4, 4, 4, 4, 12, 0, 4, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_107[] = { 8, 0, 0, 0, 66, 68, 72,112, 72, 68, 64, 64, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_108[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16, 16, 16, 48, 0, 0}; +static const GLubyte Fixed8x13_Character_109[] = { 8, 0, 0, 0,130,146,146,146,146,236, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_110[] = { 8, 0, 0, 0, 66, 66, 66, 66, 98, 92, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_111[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_112[] = { 8, 0, 64, 64, 64, 92, 98, 66, 98, 92, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_113[] = { 8, 0, 2, 2, 2, 58, 70, 66, 70, 58, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_114[] = { 8, 0, 0, 0, 32, 32, 32, 32, 34, 92, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_115[] = { 8, 0, 0, 0, 60, 66, 12, 48, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_116[] = { 8, 0, 0, 0, 28, 34, 32, 32, 32,124, 32, 32, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_117[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_118[] = { 8, 0, 0, 0, 16, 40, 40, 68, 68, 68, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_119[] = { 8, 0, 0, 0, 68,170,146,146,130,130, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_120[] = { 8, 0, 0, 0, 66, 36, 24, 24, 36, 66, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_121[] = { 8, 0, 60, 66, 2, 58, 70, 66, 66, 66, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_122[] = { 8, 0, 0, 0,126, 32, 16, 8, 4,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_123[] = { 8, 0, 0, 0, 14, 16, 16, 8, 48, 8, 16, 16, 14, 0, 0}; +static const GLubyte Fixed8x13_Character_124[] = { 8, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_125[] = { 8, 0, 0, 0,112, 8, 8, 16, 12, 16, 8, 8,112, 0, 0}; +static const GLubyte Fixed8x13_Character_126[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 84, 36, 0, 0}; +static const GLubyte Fixed8x13_Character_127[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_128[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_129[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_130[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_131[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_132[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_133[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_134[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_135[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_136[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_137[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_138[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_139[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_140[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_141[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_142[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_143[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_144[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_145[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_146[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_147[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_148[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_149[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_150[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_151[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_152[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_153[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_154[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_155[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_156[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_157[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_158[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_159[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_160[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_161[] = { 8, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 0, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_162[] = { 8, 0, 0, 0, 0, 16, 56, 84, 80, 80, 84, 56, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_163[] = { 8, 0, 0, 0,220, 98, 32, 32, 32,112, 32, 34, 28, 0, 0}; +static const GLubyte Fixed8x13_Character_164[] = { 8, 0, 0, 0, 0, 66, 60, 36, 36, 60, 66, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_165[] = { 8, 0, 0, 0, 16, 16,124, 16,124, 40, 68,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_166[] = { 8, 0, 0, 0, 16, 16, 16, 16, 0, 16, 16, 16, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_167[] = { 8, 0, 0, 0, 24, 36, 4, 24, 36, 36, 24, 32, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_168[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,108, 0, 0}; +static const GLubyte Fixed8x13_Character_169[] = { 8, 0, 0, 0, 0, 56, 68,146,170,162,170,146, 68, 56, 0}; +static const GLubyte Fixed8x13_Character_170[] = { 8, 0, 0, 0, 0, 0,124, 0, 60, 68, 60, 4, 56, 0, 0}; +static const GLubyte Fixed8x13_Character_171[] = { 8, 0, 0, 0, 0, 18, 36, 72,144, 72, 36, 18, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_172[] = { 8, 0, 0, 0, 0, 2, 2, 2,126, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_173[] = { 8, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_174[] = { 8, 0, 0, 0, 0, 56, 68,170,178,170,170,146, 68, 56, 0}; +static const GLubyte Fixed8x13_Character_175[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 0}; +static const GLubyte Fixed8x13_Character_176[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 24, 36, 36, 24, 0, 0}; +static const GLubyte Fixed8x13_Character_177[] = { 8, 0, 0, 0, 0,124, 0, 16, 16,124, 16, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_178[] = { 8, 0, 0, 0, 0, 0, 0, 0,120, 64, 48, 8, 72, 48, 0}; +static const GLubyte Fixed8x13_Character_179[] = { 8, 0, 0, 0, 0, 0, 0, 0, 48, 72, 8, 16, 72, 48, 0}; +static const GLubyte Fixed8x13_Character_180[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_181[] = { 8, 0, 0, 64, 90,102, 66, 66, 66, 66, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_182[] = { 8, 0, 0, 0, 20, 20, 20, 20, 52,116,116,116, 62, 0, 0}; +static const GLubyte Fixed8x13_Character_183[] = { 8, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_184[] = { 8, 0, 24, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_185[] = { 8, 0, 0, 0, 0, 0, 0, 0,112, 32, 32, 32, 96, 32, 0}; +static const GLubyte Fixed8x13_Character_186[] = { 8, 0, 0, 0, 0, 0, 0,120, 0, 48, 72, 72, 48, 0, 0}; +static const GLubyte Fixed8x13_Character_187[] = { 8, 0, 0, 0, 0,144, 72, 36, 18, 36, 72,144, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_188[] = { 8, 0, 0, 0, 6, 26, 18, 10,230, 66, 64, 64,192, 64, 0}; +static const GLubyte Fixed8x13_Character_189[] = { 8, 0, 0, 0, 30, 16, 12, 2,242, 76, 64, 64,192, 64, 0}; +static const GLubyte Fixed8x13_Character_190[] = { 8, 0, 0, 0, 6, 26, 18, 10,102,146, 16, 32,144, 96, 0}; +static const GLubyte Fixed8x13_Character_191[] = { 8, 0, 0, 0, 60, 66, 66, 64, 32, 16, 16, 0, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_192[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_193[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_194[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_195[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 76, 50, 0}; +static const GLubyte Fixed8x13_Character_196[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_197[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 24, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_198[] = { 8, 0, 0, 0,158,144,144,240,156,144,144,144,110, 0, 0}; +static const GLubyte Fixed8x13_Character_199[] = { 8, 0, 16, 8, 60, 66, 64, 64, 64, 64, 64, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_200[] = { 8, 0, 0, 0,126, 64, 64,120, 64, 64,126, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_201[] = { 8, 0, 0, 0,126, 64, 64,120, 64, 64,126, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_202[] = { 8, 0, 0, 0,126, 64, 64,120, 64, 64,126, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_203[] = { 8, 0, 0, 0,126, 64, 64,120, 64, 64,126, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_204[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16,124, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_205[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16,124, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_206[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16,124, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_207[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16,124, 0, 40, 40, 0}; +static const GLubyte Fixed8x13_Character_208[] = { 8, 0, 0, 0,120, 68, 66, 66,226, 66, 66, 68,120, 0, 0}; +static const GLubyte Fixed8x13_Character_209[] = { 8, 0, 0, 0,130,134,138,146,162,194,130, 0,152,100, 0}; +static const GLubyte Fixed8x13_Character_210[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_211[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_212[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_213[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0,152,100, 0}; +static const GLubyte Fixed8x13_Character_214[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0, 40, 40, 0}; +static const GLubyte Fixed8x13_Character_215[] = { 8, 0, 0, 0, 0, 66, 36, 24, 24, 36, 66, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_216[] = { 8, 0, 0, 64, 60, 98, 82, 82, 82, 74, 74, 70, 60, 2, 0}; +static const GLubyte Fixed8x13_Character_217[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_218[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_219[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_220[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_221[] = { 8, 0, 0, 0, 16, 16, 16, 16, 40, 68, 68, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_222[] = { 8, 0, 0, 0, 64, 64, 64,124, 66, 66, 66,124, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_223[] = { 8, 0, 0, 0, 92, 66, 66, 76, 80, 72, 68, 68, 56, 0, 0}; +static const GLubyte Fixed8x13_Character_224[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_225[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 8, 4, 0}; +static const GLubyte Fixed8x13_Character_226[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_227[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 76, 50, 0}; +static const GLubyte Fixed8x13_Character_228[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_229[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 24, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_230[] = { 8, 0, 0, 0,108,146,144,124, 18,108, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_231[] = { 8, 0, 16, 8, 60, 66, 64, 64, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_232[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_233[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_234[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_235[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_236[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_237[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 0, 32, 16, 0}; +static const GLubyte Fixed8x13_Character_238[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 0, 72, 48, 0}; +static const GLubyte Fixed8x13_Character_239[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 0, 40, 40, 0}; +static const GLubyte Fixed8x13_Character_240[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 4, 40, 24, 36, 0}; +static const GLubyte Fixed8x13_Character_241[] = { 8, 0, 0, 0, 66, 66, 66, 66, 98, 92, 0, 0, 76, 50, 0}; +static const GLubyte Fixed8x13_Character_242[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_243[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_244[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_245[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 76, 50, 0}; +static const GLubyte Fixed8x13_Character_246[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_247[] = { 8, 0, 0, 0, 0, 16, 16, 0,124, 0, 16, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_248[] = { 8, 0, 0, 64, 60, 98, 82, 74, 70, 60, 2, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_249[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_250[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_251[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_252[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 40, 40, 0}; +static const GLubyte Fixed8x13_Character_253[] = { 8, 0, 60, 66, 2, 58, 70, 66, 66, 66, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_254[] = { 8, 0, 64, 64, 92, 98, 66, 66, 98, 92, 64, 64, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_255[] = { 8, 0, 60, 66, 2, 58, 70, 66, 66, 66, 0, 0, 36, 36, 0}; + +/* The font characters mapping: */ +static const GLubyte* Fixed8x13_Character_Map[] = {Fixed8x13_Character_000,Fixed8x13_Character_001,Fixed8x13_Character_002,Fixed8x13_Character_003,Fixed8x13_Character_004,Fixed8x13_Character_005,Fixed8x13_Character_006,Fixed8x13_Character_007,Fixed8x13_Character_008,Fixed8x13_Character_009,Fixed8x13_Character_010,Fixed8x13_Character_011,Fixed8x13_Character_012,Fixed8x13_Character_013,Fixed8x13_Character_014,Fixed8x13_Character_015, + Fixed8x13_Character_016,Fixed8x13_Character_017,Fixed8x13_Character_018,Fixed8x13_Character_019,Fixed8x13_Character_020,Fixed8x13_Character_021,Fixed8x13_Character_022,Fixed8x13_Character_023,Fixed8x13_Character_024,Fixed8x13_Character_025,Fixed8x13_Character_026,Fixed8x13_Character_027,Fixed8x13_Character_028,Fixed8x13_Character_029,Fixed8x13_Character_030,Fixed8x13_Character_031, + Fixed8x13_Character_032,Fixed8x13_Character_033,Fixed8x13_Character_034,Fixed8x13_Character_035,Fixed8x13_Character_036,Fixed8x13_Character_037,Fixed8x13_Character_038,Fixed8x13_Character_039,Fixed8x13_Character_040,Fixed8x13_Character_041,Fixed8x13_Character_042,Fixed8x13_Character_043,Fixed8x13_Character_044,Fixed8x13_Character_045,Fixed8x13_Character_046,Fixed8x13_Character_047, + Fixed8x13_Character_048,Fixed8x13_Character_049,Fixed8x13_Character_050,Fixed8x13_Character_051,Fixed8x13_Character_052,Fixed8x13_Character_053,Fixed8x13_Character_054,Fixed8x13_Character_055,Fixed8x13_Character_056,Fixed8x13_Character_057,Fixed8x13_Character_058,Fixed8x13_Character_059,Fixed8x13_Character_060,Fixed8x13_Character_061,Fixed8x13_Character_062,Fixed8x13_Character_063, + Fixed8x13_Character_064,Fixed8x13_Character_065,Fixed8x13_Character_066,Fixed8x13_Character_067,Fixed8x13_Character_068,Fixed8x13_Character_069,Fixed8x13_Character_070,Fixed8x13_Character_071,Fixed8x13_Character_072,Fixed8x13_Character_073,Fixed8x13_Character_074,Fixed8x13_Character_075,Fixed8x13_Character_076,Fixed8x13_Character_077,Fixed8x13_Character_078,Fixed8x13_Character_079, + Fixed8x13_Character_080,Fixed8x13_Character_081,Fixed8x13_Character_082,Fixed8x13_Character_083,Fixed8x13_Character_084,Fixed8x13_Character_085,Fixed8x13_Character_086,Fixed8x13_Character_087,Fixed8x13_Character_088,Fixed8x13_Character_089,Fixed8x13_Character_090,Fixed8x13_Character_091,Fixed8x13_Character_092,Fixed8x13_Character_093,Fixed8x13_Character_094,Fixed8x13_Character_095, + Fixed8x13_Character_096,Fixed8x13_Character_097,Fixed8x13_Character_098,Fixed8x13_Character_099,Fixed8x13_Character_100,Fixed8x13_Character_101,Fixed8x13_Character_102,Fixed8x13_Character_103,Fixed8x13_Character_104,Fixed8x13_Character_105,Fixed8x13_Character_106,Fixed8x13_Character_107,Fixed8x13_Character_108,Fixed8x13_Character_109,Fixed8x13_Character_110,Fixed8x13_Character_111, + Fixed8x13_Character_112,Fixed8x13_Character_113,Fixed8x13_Character_114,Fixed8x13_Character_115,Fixed8x13_Character_116,Fixed8x13_Character_117,Fixed8x13_Character_118,Fixed8x13_Character_119,Fixed8x13_Character_120,Fixed8x13_Character_121,Fixed8x13_Character_122,Fixed8x13_Character_123,Fixed8x13_Character_124,Fixed8x13_Character_125,Fixed8x13_Character_126,Fixed8x13_Character_032, + Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032, + Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032, + Fixed8x13_Character_160,Fixed8x13_Character_161,Fixed8x13_Character_162,Fixed8x13_Character_163,Fixed8x13_Character_164,Fixed8x13_Character_165,Fixed8x13_Character_166,Fixed8x13_Character_167,Fixed8x13_Character_168,Fixed8x13_Character_169,Fixed8x13_Character_170,Fixed8x13_Character_171,Fixed8x13_Character_172,Fixed8x13_Character_173,Fixed8x13_Character_174,Fixed8x13_Character_175, + Fixed8x13_Character_176,Fixed8x13_Character_177,Fixed8x13_Character_178,Fixed8x13_Character_179,Fixed8x13_Character_180,Fixed8x13_Character_181,Fixed8x13_Character_182,Fixed8x13_Character_183,Fixed8x13_Character_184,Fixed8x13_Character_185,Fixed8x13_Character_186,Fixed8x13_Character_187,Fixed8x13_Character_188,Fixed8x13_Character_189,Fixed8x13_Character_190,Fixed8x13_Character_191, + Fixed8x13_Character_192,Fixed8x13_Character_193,Fixed8x13_Character_194,Fixed8x13_Character_195,Fixed8x13_Character_196,Fixed8x13_Character_197,Fixed8x13_Character_198,Fixed8x13_Character_199,Fixed8x13_Character_200,Fixed8x13_Character_201,Fixed8x13_Character_202,Fixed8x13_Character_203,Fixed8x13_Character_204,Fixed8x13_Character_205,Fixed8x13_Character_206,Fixed8x13_Character_207, + Fixed8x13_Character_208,Fixed8x13_Character_209,Fixed8x13_Character_210,Fixed8x13_Character_211,Fixed8x13_Character_212,Fixed8x13_Character_213,Fixed8x13_Character_214,Fixed8x13_Character_215,Fixed8x13_Character_216,Fixed8x13_Character_217,Fixed8x13_Character_218,Fixed8x13_Character_219,Fixed8x13_Character_220,Fixed8x13_Character_221,Fixed8x13_Character_222,Fixed8x13_Character_223, + Fixed8x13_Character_224,Fixed8x13_Character_225,Fixed8x13_Character_226,Fixed8x13_Character_227,Fixed8x13_Character_228,Fixed8x13_Character_229,Fixed8x13_Character_230,Fixed8x13_Character_231,Fixed8x13_Character_232,Fixed8x13_Character_233,Fixed8x13_Character_234,Fixed8x13_Character_235,Fixed8x13_Character_236,Fixed8x13_Character_237,Fixed8x13_Character_238,Fixed8x13_Character_239, + Fixed8x13_Character_240,Fixed8x13_Character_241,Fixed8x13_Character_242,Fixed8x13_Character_243,Fixed8x13_Character_244,Fixed8x13_Character_245,Fixed8x13_Character_246,Fixed8x13_Character_247,Fixed8x13_Character_248,Fixed8x13_Character_249,Fixed8x13_Character_250,Fixed8x13_Character_251,Fixed8x13_Character_252,Fixed8x13_Character_253,Fixed8x13_Character_254,Fixed8x13_Character_255,NULL}; + +/* The font structure: */ +const SFG_Font fgFontFixed8x13 = { "-misc-fixed-medium-r-normal--13-120-75-75-C-80-iso8859-1", 256, 14, Fixed8x13_Character_Map, 0, 3 }; + +static const GLubyte Fixed9x15_Character_000[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_001[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 28, 0, 62, 0,127, 0,255,128,127, 0, 62, 0, 28, 0, 8, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_002[] = { 9, 0, 0,170,128, 85, 0,170,128, 85, 0,170,128, 85, 0,170,128, 85, 0,170,128, 85, 0,170,128, 85, 0,170,128, 85, 0,170,128}; +static const GLubyte Fixed9x15_Character_003[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 4, 0, 4, 0, 31, 0, 0, 0, 72, 0, 72, 0,120, 0, 72, 0, 72, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_004[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 14, 0, 72, 0, 79, 0, 64, 0,112, 0, 64, 0,120, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_005[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 9, 0, 14, 0, 9, 0, 14, 0, 0, 0, 56, 0, 64, 0, 64, 0, 64, 0, 56, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_006[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 14, 0, 8, 0, 15, 0, 0, 0,120, 0, 64, 0, 64, 0, 64, 0, 64, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_007[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 18, 0, 18, 0, 12, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_008[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 0, 0, 8, 0, 8, 0, 8, 0,127, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_009[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 68, 0, 76, 0, 84, 0,100, 0, 68, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_010[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 4, 0, 4, 0, 31, 0, 0, 0, 16, 0, 40, 0, 40, 0, 68, 0, 68, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_011[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,248, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_012[] = { 9, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_013[] = { 9, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 15,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_014[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,128, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_015[] = { 9, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0,255,128, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_016[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,128}; +static const GLubyte Fixed9x15_Character_017[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,128, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_018[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_019[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,255,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_020[] = { 9, 0, 0,255,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_021[] = { 9, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 15,128, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_022[] = { 9, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0,248, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_023[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,128, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_024[] = { 9, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0,255,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_025[] = { 9, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_026[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 0, 0, 3, 0, 28, 0, 96, 0, 28, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_027[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 0, 0, 96, 0, 28, 0, 3, 0, 28, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_028[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 34, 0, 34, 0, 34, 0, 34, 0, 34, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_029[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0,127, 0, 8, 0,127, 0, 4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_030[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 81, 0, 48, 0, 16, 0, 16, 0,124, 0, 16, 0, 16, 0, 17, 0, 14, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_031[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_032[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_033[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_034[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_035[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 36, 0,126, 0, 36, 0, 36, 0,126, 0, 36, 0, 36, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_036[] = { 9, 0, 0, 0, 0, 0, 0, 8, 0, 62, 0, 73, 0, 9, 0, 9, 0, 10, 0, 28, 0, 40, 0, 72, 0, 73, 0, 62, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_037[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 37, 0, 37, 0, 18, 0, 8, 0, 8, 0, 36, 0, 82, 0, 82, 0, 33, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_038[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 74, 0, 68, 0, 74, 0, 49, 0, 48, 0, 72, 0, 72, 0, 72, 0, 48, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_039[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 8, 0, 4, 0, 6, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_040[] = { 9, 0, 0, 0, 0, 0, 0, 4, 0, 8, 0, 8, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 8, 0, 8, 0, 4, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_041[] = { 9, 0, 0, 0, 0, 0, 0, 16, 0, 8, 0, 8, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 8, 0, 8, 0, 16, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_042[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 73, 0, 42, 0, 28, 0, 42, 0, 73, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_043[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0,127, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_044[] = { 9, 0, 0, 8, 0, 4, 0, 4, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_045[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_046[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_047[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 32, 0, 32, 0, 16, 0, 8, 0, 8, 0, 4, 0, 2, 0, 2, 0, 1, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_048[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 34, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 34, 0, 28, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_049[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 72, 0, 40, 0, 24, 0, 8, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_050[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 64, 0, 32, 0, 16, 0, 8, 0, 4, 0, 2, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_051[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 1, 0, 1, 0, 1, 0, 14, 0, 4, 0, 2, 0, 1, 0,127, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_052[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2, 0,127, 0, 66, 0, 34, 0, 18, 0, 10, 0, 6, 0, 2, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_053[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 1, 0, 1, 0, 1, 0, 97, 0, 94, 0, 64, 0, 64, 0,127, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_054[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 97, 0, 94, 0, 64, 0, 64, 0, 32, 0, 30, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_055[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 32, 0, 16, 0, 16, 0, 8, 0, 4, 0, 2, 0, 1, 0, 1, 0,127, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_056[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 34, 0, 65, 0, 65, 0, 34, 0, 28, 0, 34, 0, 65, 0, 34, 0, 28, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_057[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 2, 0, 1, 0, 1, 0, 61, 0, 67, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_058[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_059[] = { 9, 0, 0, 8, 0, 4, 0, 4, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_060[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 0, 8, 0, 16, 0, 32, 0, 32, 0, 16, 0, 8, 0, 4, 0, 2, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_061[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 0, 0, 0, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_062[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 16, 0, 8, 0, 4, 0, 2, 0, 2, 0, 4, 0, 8, 0, 16, 0, 32, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_063[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 8, 0, 4, 0, 2, 0, 1, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_064[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 64, 0, 64, 0, 77, 0, 83, 0, 81, 0, 79, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_065[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 65, 0, 34, 0, 20, 0, 8, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_066[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 33, 0, 33, 0, 33, 0, 33, 0,126, 0, 33, 0, 33, 0, 33, 0,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_067[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_068[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 33, 0, 33, 0, 33, 0, 33, 0, 33, 0, 33, 0, 33, 0, 33, 0,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_069[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 32, 0, 32, 0, 32, 0, 32, 0, 60, 0, 32, 0, 32, 0, 32, 0,127, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_070[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 60, 0, 32, 0, 32, 0, 32, 0,127, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_071[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 71, 0, 64, 0, 64, 0, 64, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_072[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_073[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_074[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 66, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 15,128, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_075[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 66, 0, 68, 0, 72, 0, 80, 0,112, 0, 72, 0, 68, 0, 66, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_076[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_077[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 73, 0, 73, 0, 85, 0, 85, 0, 99, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_078[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 67, 0, 69, 0, 73, 0, 81, 0, 97, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_079[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_080[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0,126, 0, 65, 0, 65, 0, 65, 0,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_081[] = { 9, 0, 0, 0, 0, 3, 0, 4, 0, 62, 0, 73, 0, 81, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_082[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 66, 0, 68, 0, 72, 0,126, 0, 65, 0, 65, 0, 65, 0,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_083[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 1, 0, 6, 0, 56, 0, 64, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_084[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0,127, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_085[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_086[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 20, 0, 20, 0, 20, 0, 34, 0, 34, 0, 34, 0, 65, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_087[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 85, 0, 73, 0, 73, 0, 73, 0, 73, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_088[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 34, 0, 20, 0, 8, 0, 8, 0, 20, 0, 34, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_089[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 20, 0, 34, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_090[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 64, 0, 64, 0, 32, 0, 16, 0, 8, 0, 4, 0, 2, 0, 1, 0,127, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_091[] = { 9, 0, 0, 0, 0, 0, 0, 30, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 30, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_092[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 2, 0, 4, 0, 8, 0, 8, 0, 16, 0, 32, 0, 32, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_093[] = { 9, 0, 0, 0, 0, 0, 0, 60, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 60, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_094[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 34, 0, 20, 0, 8, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_095[] = { 9, 0, 0, 0, 0, 0, 0,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_096[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 8, 0, 16, 0, 48, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_097[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 63, 0, 1, 0, 1, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_098[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 94, 0, 97, 0, 65, 0, 65, 0, 65, 0, 97, 0, 94, 0, 64, 0, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_099[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 64, 0, 64, 0, 64, 0, 65, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_100[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 65, 0, 65, 0, 67, 0, 61, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_101[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 64, 0, 64, 0,127, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_102[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 0,124, 0, 16, 0, 16, 0, 17, 0, 17, 0, 14, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_103[] = { 9, 0, 0, 62, 0, 65, 0, 65, 0, 62, 0, 64, 0, 60, 0, 66, 0, 66, 0, 66, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_104[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 97, 0, 94, 0, 64, 0, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_105[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 56, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_106[] = { 9, 0, 0, 60, 0, 66, 0, 66, 0, 66, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 14, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_107[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 70, 0, 88, 0, 96, 0, 88, 0, 70, 0, 65, 0, 64, 0, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_108[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 56, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_109[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 73, 0, 73, 0, 73, 0, 73, 0, 73, 0,118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_110[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 97, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_111[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_112[] = { 9, 0, 0, 64, 0, 64, 0, 64, 0, 94, 0, 97, 0, 65, 0, 65, 0, 65, 0, 97, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_113[] = { 9, 0, 0, 1, 0, 1, 0, 1, 0, 61, 0, 67, 0, 65, 0, 65, 0, 65, 0, 67, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_114[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 32, 0, 32, 0, 32, 0, 33, 0, 49, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_115[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 1, 0, 62, 0, 64, 0, 65, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_116[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 17, 0, 16, 0, 16, 0, 16, 0, 16, 0,126, 0, 16, 0, 16, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_117[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_118[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 20, 0, 20, 0, 34, 0, 34, 0, 65, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_119[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 85, 0, 73, 0, 73, 0, 73, 0, 65, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_120[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 34, 0, 20, 0, 8, 0, 20, 0, 34, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_121[] = { 9, 0, 0, 60, 0, 66, 0, 2, 0, 58, 0, 70, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_122[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 32, 0, 16, 0, 8, 0, 4, 0, 2, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_123[] = { 9, 0, 0, 0, 0, 0, 0, 7, 0, 8, 0, 8, 0, 8, 0, 4, 0, 24, 0, 24, 0, 4, 0, 8, 0, 8, 0, 8, 0, 7, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_124[] = { 9, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_125[] = { 9, 0, 0, 0, 0, 0, 0,112, 0, 8, 0, 8, 0, 8, 0, 16, 0, 12, 0, 12, 0, 16, 0, 8, 0, 8, 0, 8, 0,112, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_126[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0, 73, 0, 49, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_127[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_128[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_129[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_130[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_131[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_132[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_133[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_134[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_135[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_136[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_137[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_138[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_139[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_140[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_141[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_142[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_143[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_144[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_145[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_146[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_147[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_148[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_149[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_150[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_151[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_152[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_153[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_154[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_155[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_156[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_157[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_158[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_159[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_160[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_161[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_162[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 60, 0, 82, 0, 80, 0, 72, 0, 74, 0, 60, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_163[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 81, 0, 48, 0, 16, 0, 16, 0,124, 0, 16, 0, 16, 0, 17, 0, 14, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_164[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 62, 0, 34, 0, 34, 0, 62, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_165[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 62, 0, 8, 0, 62, 0, 20, 0, 34, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_166[] = { 9, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_167[] = { 9, 0, 0, 0, 0, 0, 0, 24, 0, 36, 0, 4, 0, 24, 0, 36, 0, 36, 0, 36, 0, 24, 0, 32, 0, 36, 0, 24, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_168[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 34, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_169[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 66, 0,153, 0,165, 0,161, 0,165, 0,153, 0, 66, 0, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_170[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 0, 0, 60, 0, 72, 0, 56, 0, 72, 0, 48, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_171[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 18, 0, 36, 0, 72, 0, 72, 0, 36, 0, 18, 0, 9, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_172[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2, 0,126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_173[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_174[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 66, 0,165, 0,169, 0,185, 0,165, 0,185, 0, 66, 0, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_175[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_176[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 18, 0, 18, 0, 12, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_177[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 0, 0, 8, 0, 8, 0, 8, 0,127, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_178[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120, 0, 64, 0, 48, 0, 8, 0, 72, 0, 48, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_179[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 72, 0, 8, 0, 16, 0, 72, 0, 48, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_180[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 8, 0, 4, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_181[] = { 9, 0, 0, 0, 0, 64, 0, 64, 0, 93, 0, 99, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_182[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 61, 0, 69, 0, 69, 0, 69, 0, 63, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_183[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_184[] = { 9, 0, 0, 24, 0, 36, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_185[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,112, 0, 32, 0, 32, 0, 32, 0, 96, 0, 32, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_186[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 0, 0, 56, 0, 68, 0, 68, 0, 56, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_187[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, 36, 0, 18, 0, 9, 0, 9, 0, 18, 0, 36, 0, 72, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_188[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 13, 0, 9, 0, 5, 0,115, 0, 33, 0, 32, 0, 32, 0, 96, 0, 32, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_189[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 8, 0, 6, 0, 1, 0,121, 0, 38, 0, 32, 0, 32, 0, 96, 0, 32, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_190[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 13, 0, 9, 0, 5, 0, 51, 0, 73, 0, 8, 0, 16, 0, 72, 0, 48, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_191[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 64, 0, 32, 0, 16, 0, 8, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_192[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 34, 0, 28, 0, 0, 0, 8, 0, 16, 0, 32, 0}; +static const GLubyte Fixed9x15_Character_193[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 34, 0, 28, 0, 0, 0, 8, 0, 4, 0, 2, 0}; +static const GLubyte Fixed9x15_Character_194[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 34, 0, 28, 0, 0, 0, 34, 0, 20, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_195[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 34, 0, 28, 0, 0, 0, 78, 0, 49, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_196[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 34, 0, 28, 0, 0, 0, 34, 0, 34, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_197[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 34, 0, 20, 0, 28, 0, 34, 0, 28, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_198[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 79, 0, 72, 0, 72, 0, 72, 0,126, 0, 72, 0, 72, 0, 72, 0, 72, 0, 55, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_199[] = { 9, 0, 0, 24, 0, 36, 0, 12, 0, 62, 0, 65, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_200[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 32, 0, 32, 0, 32, 0, 60, 0, 32, 0, 32, 0,127, 0, 0, 0, 8, 0, 16, 0, 32, 0}; +static const GLubyte Fixed9x15_Character_201[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 32, 0, 32, 0, 32, 0, 60, 0, 32, 0, 32, 0,127, 0, 0, 0, 8, 0, 4, 0, 2, 0}; +static const GLubyte Fixed9x15_Character_202[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 32, 0, 32, 0, 32, 0, 60, 0, 32, 0, 32, 0,127, 0, 0, 0, 34, 0, 20, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_203[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 32, 0, 32, 0, 32, 0, 60, 0, 32, 0, 32, 0,127, 0, 0, 0, 34, 0, 34, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_204[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 62, 0, 0, 0, 8, 0, 16, 0, 32, 0}; +static const GLubyte Fixed9x15_Character_205[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 62, 0, 0, 0, 8, 0, 4, 0, 2, 0}; +static const GLubyte Fixed9x15_Character_206[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 62, 0, 0, 0, 34, 0, 20, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_207[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 62, 0, 0, 0, 34, 0, 34, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_208[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 33, 0, 33, 0, 33, 0, 33, 0,225, 0, 33, 0, 33, 0, 33, 0,124, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_209[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 67, 0, 69, 0, 73, 0, 73, 0, 81, 0, 97, 0, 65, 0, 0, 0, 78, 0, 49, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_210[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 8, 0, 16, 0, 32, 0}; +static const GLubyte Fixed9x15_Character_211[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 8, 0, 4, 0, 2, 0}; +static const GLubyte Fixed9x15_Character_212[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 34, 0, 20, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_213[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 78, 0, 49, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_214[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 34, 0, 34, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_215[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 34, 0, 20, 0, 8, 0, 20, 0, 34, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_216[] = { 9, 0, 0, 0, 0, 0, 0, 64, 0, 62, 0, 97, 0, 81, 0, 81, 0, 73, 0, 73, 0, 69, 0, 69, 0, 67, 0, 62, 0, 1, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_217[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 8, 0, 16, 0, 32, 0}; +static const GLubyte Fixed9x15_Character_218[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 8, 0, 4, 0, 2, 0}; +static const GLubyte Fixed9x15_Character_219[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 34, 0, 20, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_220[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 34, 0, 34, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_221[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 20, 0, 34, 0, 65, 0, 65, 0, 0, 0, 8, 0, 4, 0, 2, 0}; +static const GLubyte Fixed9x15_Character_222[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 64, 0, 64, 0,126, 0, 65, 0, 65, 0, 65, 0,126, 0, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_223[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 34, 0, 34, 0, 34, 0, 36, 0,104, 0, 36, 0, 34, 0, 34, 0, 28, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_224[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 63, 0, 1, 0, 1, 0, 62, 0, 0, 0, 4, 0, 8, 0, 16, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_225[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 63, 0, 1, 0, 1, 0, 62, 0, 0, 0, 8, 0, 4, 0, 2, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_226[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 63, 0, 1, 0, 1, 0, 62, 0, 0, 0, 34, 0, 20, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_227[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 63, 0, 1, 0, 1, 0, 62, 0, 0, 0, 38, 0, 25, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_228[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 63, 0, 1, 0, 1, 0, 62, 0, 0, 0, 34, 0, 34, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_229[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 63, 0, 1, 0, 1, 0, 62, 0, 0, 0, 12, 0, 18, 0, 12, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_230[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 73, 0, 72, 0, 62, 0, 9, 0, 73, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_231[] = { 9, 0, 0, 24, 0, 36, 0, 12, 0, 62, 0, 65, 0, 64, 0, 64, 0, 64, 0, 65, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_232[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 64, 0, 64, 0,127, 0, 65, 0, 65, 0, 62, 0, 0, 0, 8, 0, 16, 0, 32, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_233[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 64, 0, 64, 0,127, 0, 65, 0, 65, 0, 62, 0, 0, 0, 8, 0, 4, 0, 2, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_234[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 64, 0, 64, 0,127, 0, 65, 0, 65, 0, 62, 0, 0, 0, 34, 0, 20, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_235[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 64, 0, 64, 0,127, 0, 65, 0, 65, 0, 62, 0, 0, 0, 34, 0, 34, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_236[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 56, 0, 0, 0, 8, 0, 16, 0, 32, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_237[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 56, 0, 0, 0, 16, 0, 8, 0, 4, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_238[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 56, 0, 0, 0, 68, 0, 40, 0, 16, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_239[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 56, 0, 0, 0, 36, 0, 36, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_240[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 4, 0, 40, 0, 24, 0, 36, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_241[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 97, 0, 94, 0, 0, 0, 78, 0, 49, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_242[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 8, 0, 16, 0, 32, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_243[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 8, 0, 4, 0, 2, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_244[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 34, 0, 20, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_245[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 78, 0, 49, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_246[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 34, 0, 34, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_247[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 28, 0, 8, 0, 0, 0,127, 0, 0, 0, 8, 0, 28, 0, 8, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_248[] = { 9, 0, 0, 0, 0, 0, 0, 64, 0, 62, 0, 81, 0, 81, 0, 73, 0, 69, 0, 69, 0, 62, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_249[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 8, 0, 16, 0, 32, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_250[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 8, 0, 4, 0, 2, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_251[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 34, 0, 20, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_252[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 36, 0, 36, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_253[] = { 9, 0, 0, 60, 0, 66, 0, 2, 0, 58, 0, 70, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 16, 0, 8, 0, 4, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_254[] = { 9, 0, 0, 64, 0, 64, 0, 64, 0, 94, 0, 97, 0, 65, 0, 65, 0, 97, 0, 94, 0, 64, 0, 64, 0, 64, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_255[] = { 9, 0, 0, 60, 0, 66, 0, 2, 0, 58, 0, 70, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 36, 0, 36, 0, 0, 0, 0, 0}; + +/* The font characters mapping: */ +static const GLubyte* Fixed9x15_Character_Map[] = {Fixed9x15_Character_000,Fixed9x15_Character_001,Fixed9x15_Character_002,Fixed9x15_Character_003,Fixed9x15_Character_004,Fixed9x15_Character_005,Fixed9x15_Character_006,Fixed9x15_Character_007,Fixed9x15_Character_008,Fixed9x15_Character_009,Fixed9x15_Character_010,Fixed9x15_Character_011,Fixed9x15_Character_012,Fixed9x15_Character_013,Fixed9x15_Character_014,Fixed9x15_Character_015, + Fixed9x15_Character_016,Fixed9x15_Character_017,Fixed9x15_Character_018,Fixed9x15_Character_019,Fixed9x15_Character_020,Fixed9x15_Character_021,Fixed9x15_Character_022,Fixed9x15_Character_023,Fixed9x15_Character_024,Fixed9x15_Character_025,Fixed9x15_Character_026,Fixed9x15_Character_027,Fixed9x15_Character_028,Fixed9x15_Character_029,Fixed9x15_Character_030,Fixed9x15_Character_031, + Fixed9x15_Character_032,Fixed9x15_Character_033,Fixed9x15_Character_034,Fixed9x15_Character_035,Fixed9x15_Character_036,Fixed9x15_Character_037,Fixed9x15_Character_038,Fixed9x15_Character_039,Fixed9x15_Character_040,Fixed9x15_Character_041,Fixed9x15_Character_042,Fixed9x15_Character_043,Fixed9x15_Character_044,Fixed9x15_Character_045,Fixed9x15_Character_046,Fixed9x15_Character_047, + Fixed9x15_Character_048,Fixed9x15_Character_049,Fixed9x15_Character_050,Fixed9x15_Character_051,Fixed9x15_Character_052,Fixed9x15_Character_053,Fixed9x15_Character_054,Fixed9x15_Character_055,Fixed9x15_Character_056,Fixed9x15_Character_057,Fixed9x15_Character_058,Fixed9x15_Character_059,Fixed9x15_Character_060,Fixed9x15_Character_061,Fixed9x15_Character_062,Fixed9x15_Character_063, + Fixed9x15_Character_064,Fixed9x15_Character_065,Fixed9x15_Character_066,Fixed9x15_Character_067,Fixed9x15_Character_068,Fixed9x15_Character_069,Fixed9x15_Character_070,Fixed9x15_Character_071,Fixed9x15_Character_072,Fixed9x15_Character_073,Fixed9x15_Character_074,Fixed9x15_Character_075,Fixed9x15_Character_076,Fixed9x15_Character_077,Fixed9x15_Character_078,Fixed9x15_Character_079, + Fixed9x15_Character_080,Fixed9x15_Character_081,Fixed9x15_Character_082,Fixed9x15_Character_083,Fixed9x15_Character_084,Fixed9x15_Character_085,Fixed9x15_Character_086,Fixed9x15_Character_087,Fixed9x15_Character_088,Fixed9x15_Character_089,Fixed9x15_Character_090,Fixed9x15_Character_091,Fixed9x15_Character_092,Fixed9x15_Character_093,Fixed9x15_Character_094,Fixed9x15_Character_095, + Fixed9x15_Character_096,Fixed9x15_Character_097,Fixed9x15_Character_098,Fixed9x15_Character_099,Fixed9x15_Character_100,Fixed9x15_Character_101,Fixed9x15_Character_102,Fixed9x15_Character_103,Fixed9x15_Character_104,Fixed9x15_Character_105,Fixed9x15_Character_106,Fixed9x15_Character_107,Fixed9x15_Character_108,Fixed9x15_Character_109,Fixed9x15_Character_110,Fixed9x15_Character_111, + Fixed9x15_Character_112,Fixed9x15_Character_113,Fixed9x15_Character_114,Fixed9x15_Character_115,Fixed9x15_Character_116,Fixed9x15_Character_117,Fixed9x15_Character_118,Fixed9x15_Character_119,Fixed9x15_Character_120,Fixed9x15_Character_121,Fixed9x15_Character_122,Fixed9x15_Character_123,Fixed9x15_Character_124,Fixed9x15_Character_125,Fixed9x15_Character_126,Fixed9x15_Character_032, + Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032, + Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032, + Fixed9x15_Character_160,Fixed9x15_Character_161,Fixed9x15_Character_162,Fixed9x15_Character_163,Fixed9x15_Character_164,Fixed9x15_Character_165,Fixed9x15_Character_166,Fixed9x15_Character_167,Fixed9x15_Character_168,Fixed9x15_Character_169,Fixed9x15_Character_170,Fixed9x15_Character_171,Fixed9x15_Character_172,Fixed9x15_Character_173,Fixed9x15_Character_174,Fixed9x15_Character_175, + Fixed9x15_Character_176,Fixed9x15_Character_177,Fixed9x15_Character_178,Fixed9x15_Character_179,Fixed9x15_Character_180,Fixed9x15_Character_181,Fixed9x15_Character_182,Fixed9x15_Character_183,Fixed9x15_Character_184,Fixed9x15_Character_185,Fixed9x15_Character_186,Fixed9x15_Character_187,Fixed9x15_Character_188,Fixed9x15_Character_189,Fixed9x15_Character_190,Fixed9x15_Character_191, + Fixed9x15_Character_192,Fixed9x15_Character_193,Fixed9x15_Character_194,Fixed9x15_Character_195,Fixed9x15_Character_196,Fixed9x15_Character_197,Fixed9x15_Character_198,Fixed9x15_Character_199,Fixed9x15_Character_200,Fixed9x15_Character_201,Fixed9x15_Character_202,Fixed9x15_Character_203,Fixed9x15_Character_204,Fixed9x15_Character_205,Fixed9x15_Character_206,Fixed9x15_Character_207, + Fixed9x15_Character_208,Fixed9x15_Character_209,Fixed9x15_Character_210,Fixed9x15_Character_211,Fixed9x15_Character_212,Fixed9x15_Character_213,Fixed9x15_Character_214,Fixed9x15_Character_215,Fixed9x15_Character_216,Fixed9x15_Character_217,Fixed9x15_Character_218,Fixed9x15_Character_219,Fixed9x15_Character_220,Fixed9x15_Character_221,Fixed9x15_Character_222,Fixed9x15_Character_223, + Fixed9x15_Character_224,Fixed9x15_Character_225,Fixed9x15_Character_226,Fixed9x15_Character_227,Fixed9x15_Character_228,Fixed9x15_Character_229,Fixed9x15_Character_230,Fixed9x15_Character_231,Fixed9x15_Character_232,Fixed9x15_Character_233,Fixed9x15_Character_234,Fixed9x15_Character_235,Fixed9x15_Character_236,Fixed9x15_Character_237,Fixed9x15_Character_238,Fixed9x15_Character_239, + Fixed9x15_Character_240,Fixed9x15_Character_241,Fixed9x15_Character_242,Fixed9x15_Character_243,Fixed9x15_Character_244,Fixed9x15_Character_245,Fixed9x15_Character_246,Fixed9x15_Character_247,Fixed9x15_Character_248,Fixed9x15_Character_249,Fixed9x15_Character_250,Fixed9x15_Character_251,Fixed9x15_Character_252,Fixed9x15_Character_253,Fixed9x15_Character_254,Fixed9x15_Character_255,NULL}; + +/* The font structure: */ +const SFG_Font fgFontFixed9x15 = { "-misc-fixed-medium-r-normal--15-140-75-75-C-90-iso8859-1", 256, 16, Fixed9x15_Character_Map, 0, 4 }; + +static const GLubyte Helvetica10_Character_000[] = { 8, 0, 0, 0, 84, 0, 68, 0, 68, 0, 84, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_001[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_002[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_003[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_004[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_005[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_006[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_007[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_008[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_009[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_010[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_011[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_012[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_013[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_014[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_015[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_016[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_017[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_018[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_019[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_020[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_021[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_022[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_023[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_024[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_025[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_026[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_027[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_028[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_029[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_030[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_031[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_032[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_033[] = { 3, 0, 0, 0, 64, 0, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_034[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 0, 0, 0}; +static const GLubyte Helvetica10_Character_035[] = { 6, 0, 0, 0, 80, 80,248, 40,124, 40, 40, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_036[] = { 6, 0, 0, 32,112,168, 40,112,160,168,112, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_037[] = { 9, 0, 0, 0, 0, 0, 0, 38, 0, 41, 0, 22, 0, 16, 0, 8, 0,104, 0,148, 0,100, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_038[] = { 8, 0, 0, 0, 50, 76, 76, 82, 48, 40, 40, 16, 0, 0, 0}; +static const GLubyte Helvetica10_Character_039[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 64, 32, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_040[] = { 4, 0, 32, 64, 64,128,128,128,128, 64, 64, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_041[] = { 4, 0, 64, 32, 32, 16, 16, 16, 16, 32, 32, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_042[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0,160, 64,160, 0, 0, 0}; +static const GLubyte Helvetica10_Character_043[] = { 6, 0, 0, 0, 0, 32, 32,248, 32, 32, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_044[] = { 3, 0,128, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_045[] = { 7, 0, 0, 0, 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_046[] = { 3, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_047[] = { 3, 0, 0, 0,128,128, 64, 64, 64, 64, 32, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_048[] = { 6, 0, 0, 0,112,136,136,136,136,136,136,112, 0, 0, 0}; +static const GLubyte Helvetica10_Character_049[] = { 6, 0, 0, 0, 32, 32, 32, 32, 32, 32, 96, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_050[] = { 6, 0, 0, 0,248,128, 64, 48, 8, 8,136,112, 0, 0, 0}; +static const GLubyte Helvetica10_Character_051[] = { 6, 0, 0, 0,112,136, 8, 8, 48, 8,136,112, 0, 0, 0}; +static const GLubyte Helvetica10_Character_052[] = { 6, 0, 0, 0, 16, 16,248,144, 80, 80, 48, 16, 0, 0, 0}; +static const GLubyte Helvetica10_Character_053[] = { 6, 0, 0, 0,112,136, 8, 8,240,128,128,248, 0, 0, 0}; +static const GLubyte Helvetica10_Character_054[] = { 6, 0, 0, 0,112,136,136,200,176,128,136,112, 0, 0, 0}; +static const GLubyte Helvetica10_Character_055[] = { 6, 0, 0, 0, 64, 64, 32, 32, 16, 16, 8,248, 0, 0, 0}; +static const GLubyte Helvetica10_Character_056[] = { 6, 0, 0, 0,112,136,136,136,112,136,136,112, 0, 0, 0}; +static const GLubyte Helvetica10_Character_057[] = { 6, 0, 0, 0,112,136, 8,104,152,136,136,112, 0, 0, 0}; +static const GLubyte Helvetica10_Character_058[] = { 3, 0, 0, 0, 64, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_059[] = { 3, 0,128, 64, 64, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_060[] = { 6, 0, 0, 0, 0, 16, 32, 64, 32, 16, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_061[] = { 5, 0, 0, 0, 0, 0,240, 0,240, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_062[] = { 6, 0, 0, 0, 0, 64, 32, 16, 32, 64, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_063[] = { 6, 0, 0, 0, 32, 0, 32, 32, 16, 8, 72, 48, 0, 0, 0}; +static const GLubyte Helvetica10_Character_064[] = { 11, 0, 0, 62, 0, 64, 0,155, 0,164,128,164,128,162, 64,146, 64, 77, 64, 32,128, 31, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_065[] = { 7, 0, 0, 0,130,130,124, 68, 40, 40, 16, 16, 0, 0, 0}; +static const GLubyte Helvetica10_Character_066[] = { 7, 0, 0, 0,120, 68, 68, 68,120, 68, 68,120, 0, 0, 0}; +static const GLubyte Helvetica10_Character_067[] = { 8, 0, 0, 0, 60, 66, 64, 64, 64, 64, 66, 60, 0, 0, 0}; +static const GLubyte Helvetica10_Character_068[] = { 8, 0, 0, 0,120, 68, 66, 66, 66, 66, 68,120, 0, 0, 0}; +static const GLubyte Helvetica10_Character_069[] = { 7, 0, 0, 0,124, 64, 64, 64,124, 64, 64,124, 0, 0, 0}; +static const GLubyte Helvetica10_Character_070[] = { 6, 0, 0, 0, 64, 64, 64, 64,120, 64, 64,124, 0, 0, 0}; +static const GLubyte Helvetica10_Character_071[] = { 8, 0, 0, 0, 58, 70, 66, 70, 64, 64, 66, 60, 0, 0, 0}; +static const GLubyte Helvetica10_Character_072[] = { 8, 0, 0, 0, 66, 66, 66, 66,126, 66, 66, 66, 0, 0, 0}; +static const GLubyte Helvetica10_Character_073[] = { 3, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_074[] = { 5, 0, 0, 0, 96,144, 16, 16, 16, 16, 16, 16, 0, 0, 0}; +static const GLubyte Helvetica10_Character_075[] = { 7, 0, 0, 0, 68, 68, 72, 72,112, 80, 72, 68, 0, 0, 0}; +static const GLubyte Helvetica10_Character_076[] = { 6, 0, 0, 0,120, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_077[] = { 9, 0, 0, 0, 0, 0, 0, 73, 0, 73, 0, 73, 0, 85, 0, 85, 0, 99, 0, 99, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_078[] = { 8, 0, 0, 0, 70, 70, 74, 74, 82, 82, 98, 98, 0, 0, 0}; +static const GLubyte Helvetica10_Character_079[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 60, 0, 0, 0}; +static const GLubyte Helvetica10_Character_080[] = { 7, 0, 0, 0, 64, 64, 64, 64,120, 68, 68,120, 0, 0, 0}; +static const GLubyte Helvetica10_Character_081[] = { 8, 0, 0, 1, 62, 70, 74, 66, 66, 66, 66, 60, 0, 0, 0}; +static const GLubyte Helvetica10_Character_082[] = { 7, 0, 0, 0, 68, 68, 68, 68,120, 68, 68,120, 0, 0, 0}; +static const GLubyte Helvetica10_Character_083[] = { 7, 0, 0, 0, 56, 68, 68, 4, 56, 64, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica10_Character_084[] = { 5, 0, 0, 0, 32, 32, 32, 32, 32, 32, 32,248, 0, 0, 0}; +static const GLubyte Helvetica10_Character_085[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 0, 0, 0}; +static const GLubyte Helvetica10_Character_086[] = { 7, 0, 0, 0, 16, 40, 40, 68, 68, 68,130,130, 0, 0, 0}; +static const GLubyte Helvetica10_Character_087[] = { 9, 0, 0, 0, 0, 0, 0, 34, 0, 34, 0, 34, 0, 85, 0, 73, 0, 73, 0,136,128,136,128, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_088[] = { 7, 0, 0, 0, 68, 68, 40, 40, 16, 40, 68, 68, 0, 0, 0}; +static const GLubyte Helvetica10_Character_089[] = { 7, 0, 0, 0, 16, 16, 16, 40, 40, 68, 68,130, 0, 0, 0}; +static const GLubyte Helvetica10_Character_090[] = { 7, 0, 0, 0,124, 64, 32, 16, 16, 8, 4,124, 0, 0, 0}; +static const GLubyte Helvetica10_Character_091[] = { 3, 0, 96, 64, 64, 64, 64, 64, 64, 64, 64, 96, 0, 0, 0}; +static const GLubyte Helvetica10_Character_092[] = { 3, 0, 0, 0, 32, 32, 64, 64, 64, 64,128,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_093[] = { 3, 0,192, 64, 64, 64, 64, 64, 64, 64, 64,192, 0, 0, 0}; +static const GLubyte Helvetica10_Character_094[] = { 6, 0, 0, 0, 0, 0, 0,136, 80, 80, 32, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_095[] = { 6, 0,252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_096[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_097[] = { 5, 0, 0, 0,104,144,144,112, 16,224, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_098[] = { 6, 0, 0, 0,176,200,136,136,200,176,128,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_099[] = { 5, 0, 0, 0, 96,144,128,128,144, 96, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_100[] = { 6, 0, 0, 0,104,152,136,136,152,104, 8, 8, 0, 0, 0}; +static const GLubyte Helvetica10_Character_101[] = { 5, 0, 0, 0, 96,144,128,240,144, 96, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_102[] = { 4, 0, 0, 0, 64, 64, 64, 64, 64,224, 64, 48, 0, 0, 0}; +static const GLubyte Helvetica10_Character_103[] = { 6, 0,112, 8,104,152,136,136,152,104, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_104[] = { 6, 0, 0, 0,136,136,136,136,200,176,128,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_105[] = { 2, 0, 0, 0,128,128,128,128,128,128, 0,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_106[] = { 2, 0, 0,128,128,128,128,128,128,128, 0,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_107[] = { 5, 0, 0, 0,144,144,160,192,160,144,128,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_108[] = { 2, 0, 0, 0,128,128,128,128,128,128,128,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_109[] = { 8, 0, 0, 0,146,146,146,146,146,236, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_110[] = { 6, 0, 0, 0,136,136,136,136,200,176, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_111[] = { 6, 0, 0, 0,112,136,136,136,136,112, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_112[] = { 6, 0,128,128,176,200,136,136,200,176, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_113[] = { 6, 0, 8, 8,104,152,136,136,152,104, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_114[] = { 4, 0, 0, 0,128,128,128,128,192,160, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_115[] = { 5, 0, 0, 0, 96,144, 16, 96,144, 96, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_116[] = { 4, 0, 0, 0, 96, 64, 64, 64, 64,224, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_117[] = { 5, 0, 0, 0,112,144,144,144,144,144, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_118[] = { 6, 0, 0, 0, 32, 32, 80, 80,136,136, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_119[] = { 8, 0, 0, 0, 40, 40, 84, 84,146,146, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_120[] = { 6, 0, 0, 0,136,136, 80, 32, 80,136, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_121[] = { 5, 0,128, 64, 64, 96,160,160,144,144, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_122[] = { 5, 0, 0, 0,240,128, 64, 32, 16,240, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_123[] = { 3, 0, 32, 64, 64, 64, 64,128, 64, 64, 64, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_124[] = { 3, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_125[] = { 3, 0,128, 64, 64, 64, 64, 32, 64, 64, 64,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_126[] = { 7, 0, 0, 0, 0, 0, 0,152,100, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_127[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_128[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_129[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_130[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_131[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_132[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_133[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_134[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_135[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_136[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_137[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_138[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_139[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_140[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_141[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_142[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_143[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_144[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_145[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_146[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_147[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_148[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_149[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_150[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_151[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_152[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_153[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_154[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_155[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_156[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_157[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_158[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_159[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_160[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_161[] = { 3, 0, 64, 64, 64, 64, 64, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_162[] = { 6, 0, 0, 64,112,168,160,160,168,112, 16, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_163[] = { 6, 0, 0, 0,176, 72, 64, 64,224, 64, 72, 48, 0, 0, 0}; +static const GLubyte Helvetica10_Character_164[] = { 5, 0, 0, 0, 0,144, 96,144,144, 96,144, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_165[] = { 6, 0, 0, 0, 32,248, 32,248, 80, 80,136,136, 0, 0, 0}; +static const GLubyte Helvetica10_Character_166[] = { 3, 0, 64, 64, 64, 64, 0, 0, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_167[] = { 6, 0,112,136, 24,112,200,152,112,192,136,112, 0, 0, 0}; +static const GLubyte Helvetica10_Character_168[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,160, 0, 0, 0}; +static const GLubyte Helvetica10_Character_169[] = { 9, 0, 0, 0, 0, 0, 0, 28, 0, 34, 0, 77, 0, 81, 0, 77, 0, 34, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_170[] = { 4, 0, 0, 0, 0, 0, 0,224, 0,160, 32,224, 0, 0, 0}; +static const GLubyte Helvetica10_Character_171[] = { 6, 0, 0, 0, 40, 80,160, 80, 40, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_172[] = { 7, 0, 0, 0, 0, 0, 4, 4,124, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_173[] = { 4, 0, 0, 0, 0, 0, 0,224, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_174[] = { 9, 0, 0, 0, 0, 0, 0, 28, 0, 34, 0, 85, 0, 89, 0, 93, 0, 34, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_175[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,224, 0, 0, 0}; +static const GLubyte Helvetica10_Character_176[] = { 4, 0, 0, 0, 0, 0, 0, 96,144,144, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_177[] = { 6, 0, 0, 0,248, 0, 32, 32,248, 32, 32, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_178[] = { 3, 0, 0, 0, 0, 0, 0,224, 64,160, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_179[] = { 3, 0, 0, 0, 0, 0, 0,192, 32, 64,224, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_180[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_181[] = { 5, 0,128,128,240,144,144,144,144,144, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_182[] = { 6, 0, 40, 40, 40, 40, 40,104,232,232,232,124, 0, 0, 0}; +static const GLubyte Helvetica10_Character_183[] = { 3, 0, 0, 0, 0, 0, 0,192, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_184[] = { 3, 0,192, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_185[] = { 3, 0, 0, 0, 0, 0, 0, 64, 64,192, 64, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_186[] = { 4, 0, 0, 0, 0, 0, 0,224, 0,224,160,224, 0, 0, 0}; +static const GLubyte Helvetica10_Character_187[] = { 6, 0, 0, 0,160, 80, 40, 80,160, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_188[] = { 9, 0, 0, 0, 0, 0, 0, 33, 0, 23,128, 19, 0, 9, 0, 72, 0, 68, 0,196, 0, 66, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_189[] = { 9, 0, 0, 0, 0, 0, 0, 39, 0, 18, 0, 21, 0, 11, 0, 72, 0, 68, 0,196, 0, 66, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_190[] = { 9, 0, 0, 0, 0, 0, 0, 33, 0, 23,128, 19, 0, 9, 0,200, 0, 36, 0, 68, 0,226, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_191[] = { 6, 0, 48, 72, 64, 32, 16, 16, 0, 16, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_192[] = { 7, 0, 0, 0,130,130,124, 68, 40, 40, 16, 16, 0, 16, 32}; +static const GLubyte Helvetica10_Character_193[] = { 7, 0, 0, 0,130,130,124, 68, 40, 40, 16, 16, 0, 16, 8}; +static const GLubyte Helvetica10_Character_194[] = { 7, 0, 0, 0,130,130,124, 68, 40, 40, 16, 16, 0, 40, 16}; +static const GLubyte Helvetica10_Character_195[] = { 7, 0, 0, 0,130,130,124, 68, 40, 40, 16, 16, 0, 40, 20}; +static const GLubyte Helvetica10_Character_196[] = { 7, 0, 0, 0,130,130,124, 68, 40, 40, 16, 16, 0, 40, 0}; +static const GLubyte Helvetica10_Character_197[] = { 7, 0, 0, 0,130,130,124, 68, 40, 40, 16, 16, 16, 40, 16}; +static const GLubyte Helvetica10_Character_198[] = { 10, 0, 0, 0, 0, 0, 0,143,128,136, 0,120, 0, 72, 0, 47,128, 40, 0, 24, 0, 31,128, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_199[] = { 8, 0, 24, 8, 60, 66, 64, 64, 64, 64, 66, 60, 0, 0, 0}; +static const GLubyte Helvetica10_Character_200[] = { 7, 0, 0, 0,124, 64, 64, 64,124, 64, 64,124, 0, 16, 32}; +static const GLubyte Helvetica10_Character_201[] = { 7, 0, 0, 0,124, 64, 64, 64,124, 64, 64,124, 0, 16, 8}; +static const GLubyte Helvetica10_Character_202[] = { 7, 0, 0, 0,124, 64, 64,124, 64, 64, 64,124, 0, 40, 16}; +static const GLubyte Helvetica10_Character_203[] = { 7, 0, 0, 0,124, 64, 64, 64,124, 64, 64,124, 0, 40, 0}; +static const GLubyte Helvetica10_Character_204[] = { 3, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64,128}; +static const GLubyte Helvetica10_Character_205[] = { 3, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 32}; +static const GLubyte Helvetica10_Character_206[] = { 3, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 0,160, 64}; +static const GLubyte Helvetica10_Character_207[] = { 3, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 0,160, 0}; +static const GLubyte Helvetica10_Character_208[] = { 8, 0, 0, 0,120, 68, 66, 66,242, 66, 68,120, 0, 0, 0}; +static const GLubyte Helvetica10_Character_209[] = { 8, 0, 0, 0, 70, 70, 74, 74, 82, 82, 98, 98, 0, 40, 20}; +static const GLubyte Helvetica10_Character_210[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 60, 0, 8, 16}; +static const GLubyte Helvetica10_Character_211[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 60, 0, 8, 4}; +static const GLubyte Helvetica10_Character_212[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 60, 0, 20, 8}; +static const GLubyte Helvetica10_Character_213[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 60, 0, 40, 20}; +static const GLubyte Helvetica10_Character_214[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 60, 0, 36, 0}; +static const GLubyte Helvetica10_Character_215[] = { 6, 0, 0, 0, 0,136, 80, 32, 80,136, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_216[] = { 8, 0, 0, 64, 60, 98, 82, 82, 74, 74, 70, 60, 2, 0, 0}; +static const GLubyte Helvetica10_Character_217[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 0, 8, 16}; +static const GLubyte Helvetica10_Character_218[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 0, 16, 8}; +static const GLubyte Helvetica10_Character_219[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 0, 20, 8}; +static const GLubyte Helvetica10_Character_220[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 0, 36, 0}; +static const GLubyte Helvetica10_Character_221[] = { 7, 0, 0, 0, 16, 16, 16, 40, 40, 68, 68,130, 0, 16, 8}; +static const GLubyte Helvetica10_Character_222[] = { 7, 0, 0, 0, 64, 64,120, 68, 68,120, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_223[] = { 5, 0, 0, 0,160,144,144,144,160,144,144, 96, 0, 0, 0}; +static const GLubyte Helvetica10_Character_224[] = { 5, 0, 0, 0,104,144,144,112, 16,224, 0, 32, 64, 0, 0}; +static const GLubyte Helvetica10_Character_225[] = { 5, 0, 0, 0,104,144,144,112, 16,224, 0, 32, 16, 0, 0}; +static const GLubyte Helvetica10_Character_226[] = { 5, 0, 0, 0,104,144,144,112, 16,224, 0, 80, 32, 0, 0}; +static const GLubyte Helvetica10_Character_227[] = { 5, 0, 0, 0,104,144,144,112, 16,224, 0,160, 80, 0, 0}; +static const GLubyte Helvetica10_Character_228[] = { 5, 0, 0, 0,104,144,144,112, 16,224, 0, 80, 0, 0, 0}; +static const GLubyte Helvetica10_Character_229[] = { 5, 0, 0, 0,104,144,144,112, 16,224, 32, 80, 32, 0, 0}; +static const GLubyte Helvetica10_Character_230[] = { 8, 0, 0, 0,108,146,144,126, 18,236, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_231[] = { 5, 0, 96, 32, 96,144,128,128,144, 96, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_232[] = { 5, 0, 0, 0, 96,144,128,240,144, 96, 0, 32, 64, 0, 0}; +static const GLubyte Helvetica10_Character_233[] = { 5, 0, 0, 0, 96,144,128,240,144, 96, 0, 64, 32, 0, 0}; +static const GLubyte Helvetica10_Character_234[] = { 5, 0, 0, 0, 96,144,128,240,144, 96, 0, 80, 32, 0, 0}; +static const GLubyte Helvetica10_Character_235[] = { 5, 0, 0, 0, 96,144,128,240,144, 96, 0, 80, 0, 0, 0}; +static const GLubyte Helvetica10_Character_236[] = { 2, 0, 0, 0,128,128,128,128,128,128, 0,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_237[] = { 2, 0, 0, 0,128,128,128,128,128,128, 0,128, 64, 0, 0}; +static const GLubyte Helvetica10_Character_238[] = { 2, 0, 0, 0,128,128,128,128,128,128, 0, 64,128, 0, 0}; +static const GLubyte Helvetica10_Character_239[] = { 2, 0, 0, 0, 64, 64, 64, 64, 64, 64, 0,160, 0, 0, 0}; +static const GLubyte Helvetica10_Character_240[] = { 6, 0, 0, 0,112,136,136,136,136,120,144, 96, 80, 0, 0}; +static const GLubyte Helvetica10_Character_241[] = { 5, 0, 0, 0,144,144,144,144,144,224, 0,160, 80, 0, 0}; +static const GLubyte Helvetica10_Character_242[] = { 6, 0, 0, 0,112,136,136,136,136,112, 0, 32, 64, 0, 0}; +static const GLubyte Helvetica10_Character_243[] = { 6, 0, 0, 0,112,136,136,136,136,112, 0, 32, 16, 0, 0}; +static const GLubyte Helvetica10_Character_244[] = { 6, 0, 0, 0,112,136,136,136,136,112, 0, 80, 32, 0, 0}; +static const GLubyte Helvetica10_Character_245[] = { 6, 0, 0, 0,112,136,136,136,136,112, 0, 80, 40, 0, 0}; +static const GLubyte Helvetica10_Character_246[] = { 6, 0, 0, 0,112,136,136,136,136,112, 0, 80, 0, 0, 0}; +static const GLubyte Helvetica10_Character_247[] = { 6, 0, 0, 0, 0, 32, 0,248, 0, 32, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_248[] = { 6, 0, 0, 0,112,136,200,168,152,116, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_249[] = { 5, 0, 0, 0,112,144,144,144,144,144, 0, 32, 64, 0, 0}; +static const GLubyte Helvetica10_Character_250[] = { 5, 0, 0, 0,112,144,144,144,144,144, 0, 64, 32, 0, 0}; +static const GLubyte Helvetica10_Character_251[] = { 5, 0, 0, 0,112,144,144,144,144,144, 0, 80, 32, 0, 0}; +static const GLubyte Helvetica10_Character_252[] = { 5, 0, 0, 0,112,144,144,144,144,144, 0, 80, 0, 0, 0}; +static const GLubyte Helvetica10_Character_253[] = { 5, 0,128, 64, 64, 96,160,160,144,144, 0, 32, 16, 0, 0}; +static const GLubyte Helvetica10_Character_254[] = { 6, 0,128,128,176,200,136,136,200,176,128,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_255[] = { 5, 0,128, 64, 64, 96,160,160,144,144, 0, 80, 0, 0, 0}; + +/* The font characters mapping: */ +static const GLubyte* Helvetica10_Character_Map[] = {Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032, + Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032, + Helvetica10_Character_032,Helvetica10_Character_033,Helvetica10_Character_034,Helvetica10_Character_035,Helvetica10_Character_036,Helvetica10_Character_037,Helvetica10_Character_038,Helvetica10_Character_039,Helvetica10_Character_040,Helvetica10_Character_041,Helvetica10_Character_042,Helvetica10_Character_043,Helvetica10_Character_044,Helvetica10_Character_045,Helvetica10_Character_046,Helvetica10_Character_047, + Helvetica10_Character_048,Helvetica10_Character_049,Helvetica10_Character_050,Helvetica10_Character_051,Helvetica10_Character_052,Helvetica10_Character_053,Helvetica10_Character_054,Helvetica10_Character_055,Helvetica10_Character_056,Helvetica10_Character_057,Helvetica10_Character_058,Helvetica10_Character_059,Helvetica10_Character_060,Helvetica10_Character_061,Helvetica10_Character_062,Helvetica10_Character_063, + Helvetica10_Character_064,Helvetica10_Character_065,Helvetica10_Character_066,Helvetica10_Character_067,Helvetica10_Character_068,Helvetica10_Character_069,Helvetica10_Character_070,Helvetica10_Character_071,Helvetica10_Character_072,Helvetica10_Character_073,Helvetica10_Character_074,Helvetica10_Character_075,Helvetica10_Character_076,Helvetica10_Character_077,Helvetica10_Character_078,Helvetica10_Character_079, + Helvetica10_Character_080,Helvetica10_Character_081,Helvetica10_Character_082,Helvetica10_Character_083,Helvetica10_Character_084,Helvetica10_Character_085,Helvetica10_Character_086,Helvetica10_Character_087,Helvetica10_Character_088,Helvetica10_Character_089,Helvetica10_Character_090,Helvetica10_Character_091,Helvetica10_Character_092,Helvetica10_Character_093,Helvetica10_Character_094,Helvetica10_Character_095, + Helvetica10_Character_096,Helvetica10_Character_097,Helvetica10_Character_098,Helvetica10_Character_099,Helvetica10_Character_100,Helvetica10_Character_101,Helvetica10_Character_102,Helvetica10_Character_103,Helvetica10_Character_104,Helvetica10_Character_105,Helvetica10_Character_106,Helvetica10_Character_107,Helvetica10_Character_108,Helvetica10_Character_109,Helvetica10_Character_110,Helvetica10_Character_111, + Helvetica10_Character_112,Helvetica10_Character_113,Helvetica10_Character_114,Helvetica10_Character_115,Helvetica10_Character_116,Helvetica10_Character_117,Helvetica10_Character_118,Helvetica10_Character_119,Helvetica10_Character_120,Helvetica10_Character_121,Helvetica10_Character_122,Helvetica10_Character_123,Helvetica10_Character_124,Helvetica10_Character_125,Helvetica10_Character_126,Helvetica10_Character_032, + Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032, + Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032, + Helvetica10_Character_160,Helvetica10_Character_161,Helvetica10_Character_162,Helvetica10_Character_163,Helvetica10_Character_164,Helvetica10_Character_165,Helvetica10_Character_166,Helvetica10_Character_167,Helvetica10_Character_168,Helvetica10_Character_169,Helvetica10_Character_170,Helvetica10_Character_171,Helvetica10_Character_172,Helvetica10_Character_173,Helvetica10_Character_174,Helvetica10_Character_175, + Helvetica10_Character_176,Helvetica10_Character_177,Helvetica10_Character_178,Helvetica10_Character_179,Helvetica10_Character_180,Helvetica10_Character_181,Helvetica10_Character_182,Helvetica10_Character_183,Helvetica10_Character_184,Helvetica10_Character_185,Helvetica10_Character_186,Helvetica10_Character_187,Helvetica10_Character_188,Helvetica10_Character_189,Helvetica10_Character_190,Helvetica10_Character_191, + Helvetica10_Character_192,Helvetica10_Character_193,Helvetica10_Character_194,Helvetica10_Character_195,Helvetica10_Character_196,Helvetica10_Character_197,Helvetica10_Character_198,Helvetica10_Character_199,Helvetica10_Character_200,Helvetica10_Character_201,Helvetica10_Character_202,Helvetica10_Character_203,Helvetica10_Character_204,Helvetica10_Character_205,Helvetica10_Character_206,Helvetica10_Character_207, + Helvetica10_Character_208,Helvetica10_Character_209,Helvetica10_Character_210,Helvetica10_Character_211,Helvetica10_Character_212,Helvetica10_Character_213,Helvetica10_Character_214,Helvetica10_Character_215,Helvetica10_Character_216,Helvetica10_Character_217,Helvetica10_Character_218,Helvetica10_Character_219,Helvetica10_Character_220,Helvetica10_Character_221,Helvetica10_Character_222,Helvetica10_Character_223, + Helvetica10_Character_224,Helvetica10_Character_225,Helvetica10_Character_226,Helvetica10_Character_227,Helvetica10_Character_228,Helvetica10_Character_229,Helvetica10_Character_230,Helvetica10_Character_231,Helvetica10_Character_232,Helvetica10_Character_233,Helvetica10_Character_234,Helvetica10_Character_235,Helvetica10_Character_236,Helvetica10_Character_237,Helvetica10_Character_238,Helvetica10_Character_239, + Helvetica10_Character_240,Helvetica10_Character_241,Helvetica10_Character_242,Helvetica10_Character_243,Helvetica10_Character_244,Helvetica10_Character_245,Helvetica10_Character_246,Helvetica10_Character_247,Helvetica10_Character_248,Helvetica10_Character_249,Helvetica10_Character_250,Helvetica10_Character_251,Helvetica10_Character_252,Helvetica10_Character_253,Helvetica10_Character_254,Helvetica10_Character_255,NULL}; + +/* The font structure: */ +const SFG_Font fgFontHelvetica10 = { "-adobe-helvetica-medium-r-normal--10-100-75-75-p-56-iso8859-1", 256, 14, Helvetica10_Character_Map, 0, 3 }; + +static const GLubyte Helvetica12_Character_000[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_001[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_002[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_003[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_004[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_005[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_006[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_007[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_008[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_009[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_010[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_011[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_012[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_013[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_014[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_015[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_016[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_017[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_018[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_019[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_020[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_021[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_022[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_023[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_024[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_025[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_026[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_027[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_028[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_029[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_030[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_031[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_032[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_033[] = { 3, 0, 0, 0, 0, 64, 0, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_034[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 0, 0, 0}; +static const GLubyte Helvetica12_Character_035[] = { 7, 0, 0, 0, 0, 80, 80, 80,252, 40,252, 40, 40, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_036[] = { 7, 0, 0, 0, 16, 56, 84, 84, 20, 56, 80, 84, 56, 16, 0, 0, 0}; +static const GLubyte Helvetica12_Character_037[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 17,128, 10, 64, 10, 64, 9,128, 4, 0, 52, 0, 74, 0, 74, 0, 49, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_038[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 70, 0, 66, 0, 69, 0, 40, 0, 24, 0, 36, 0, 36, 0, 24, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_039[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 32, 96, 0, 0, 0}; +static const GLubyte Helvetica12_Character_040[] = { 4, 0, 16, 32, 32, 64, 64, 64, 64, 64, 64, 32, 32, 16, 0, 0, 0}; +static const GLubyte Helvetica12_Character_041[] = { 4, 0,128, 64, 64, 32, 32, 32, 32, 32, 32, 64, 64,128, 0, 0, 0}; +static const GLubyte Helvetica12_Character_042[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 32, 80, 0, 0, 0}; +static const GLubyte Helvetica12_Character_043[] = { 7, 0, 0, 0, 0, 0, 16, 16,124, 16, 16, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_044[] = { 4, 0, 0, 64, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_045[] = { 8, 0, 0, 0, 0, 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_046[] = { 3, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_047[] = { 4, 0, 0, 0, 0,128,128, 64, 64, 64, 32, 32, 16, 16, 0, 0, 0}; +static const GLubyte Helvetica12_Character_048[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 68, 68, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_049[] = { 7, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16,112, 16, 0, 0, 0}; +static const GLubyte Helvetica12_Character_050[] = { 7, 0, 0, 0, 0,124, 64, 64, 32, 16, 8, 4, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_051[] = { 7, 0, 0, 0, 0, 56, 68, 68, 4, 4, 24, 4, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_052[] = { 7, 0, 0, 0, 0, 8, 8,252,136, 72, 40, 40, 24, 8, 0, 0, 0}; +static const GLubyte Helvetica12_Character_053[] = { 7, 0, 0, 0, 0, 56, 68, 68, 4, 4,120, 64, 64,124, 0, 0, 0}; +static const GLubyte Helvetica12_Character_054[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68,100, 88, 64, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_055[] = { 7, 0, 0, 0, 0, 32, 32, 16, 16, 16, 8, 8, 4,124, 0, 0, 0}; +static const GLubyte Helvetica12_Character_056[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 56, 68, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_057[] = { 7, 0, 0, 0, 0, 56, 68, 4, 4, 60, 68, 68, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_058[] = { 3, 0, 0, 0, 0, 64, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_059[] = { 3, 0, 0,128, 64, 64, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_060[] = { 7, 0, 0, 0, 0, 0, 12, 48,192, 48, 12, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_061[] = { 7, 0, 0, 0, 0, 0, 0,124, 0,124, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_062[] = { 7, 0, 0, 0, 0, 0, 96, 24, 6, 24, 96, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_063[] = { 7, 0, 0, 0, 0, 16, 0, 16, 16, 8, 8, 68, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_064[] = { 12, 0, 0, 0, 0, 0, 0, 31, 0, 32, 0, 77,128, 83, 64, 81, 32, 81, 32, 73, 32, 38,160, 48, 64, 15,128, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_065[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 62, 0, 34, 0, 34, 0, 20, 0, 20, 0, 8, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_066[] = { 8, 0, 0, 0, 0,124, 66, 66, 66,124, 66, 66, 66,124, 0, 0, 0}; +static const GLubyte Helvetica12_Character_067[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 33, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 33, 0, 30, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_068[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 66, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 66, 0,124, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_069[] = { 8, 0, 0, 0, 0,126, 64, 64, 64,126, 64, 64, 64,126, 0, 0, 0}; +static const GLubyte Helvetica12_Character_070[] = { 8, 0, 0, 0, 0, 64, 64, 64, 64,124, 64, 64, 64,126, 0, 0, 0}; +static const GLubyte Helvetica12_Character_071[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 35, 0, 65, 0, 65, 0, 71, 0, 64, 0, 64, 0, 33, 0, 30, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_072[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_073[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_074[] = { 7, 0, 0, 0, 0, 56, 68, 68, 4, 4, 4, 4, 4, 4, 0, 0, 0}; +static const GLubyte Helvetica12_Character_075[] = { 8, 0, 0, 0, 0, 65, 66, 68, 72,112, 80, 72, 68, 66, 0, 0, 0}; +static const GLubyte Helvetica12_Character_076[] = { 7, 0, 0, 0, 0,124, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_077[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 68, 64, 68, 64, 74, 64, 74, 64, 81, 64, 81, 64, 96,192, 96,192, 64, 64, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_078[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 67, 0, 69, 0, 69, 0, 73, 0, 81, 0, 81, 0, 97, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_079[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 33, 0, 64,128, 64,128, 64,128, 64,128, 64,128, 33, 0, 30, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_080[] = { 8, 0, 0, 0, 0, 64, 64, 64, 64,124, 66, 66, 66,124, 0, 0, 0}; +static const GLubyte Helvetica12_Character_081[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 30,128, 33, 0, 66,128, 68,128, 64,128, 64,128, 64,128, 33, 0, 30, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_082[] = { 8, 0, 0, 0, 0, 66, 66, 66, 68,124, 66, 66, 66,124, 0, 0, 0}; +static const GLubyte Helvetica12_Character_083[] = { 8, 0, 0, 0, 0, 60, 66, 66, 2, 12, 48, 64, 66, 60, 0, 0, 0}; +static const GLubyte Helvetica12_Character_084[] = { 7, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16,254, 0, 0, 0}; +static const GLubyte Helvetica12_Character_085[] = { 8, 0, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 66, 0, 0, 0}; +static const GLubyte Helvetica12_Character_086[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 20, 0, 20, 0, 34, 0, 34, 0, 34, 0, 65, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_087[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 42,128, 42,128, 36,128, 68, 64, 68, 64, 68, 64, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_088[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 34, 0, 34, 0, 20, 0, 8, 0, 20, 0, 34, 0, 34, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_089[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 20, 0, 34, 0, 34, 0, 65, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_090[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 64, 0, 32, 0, 16, 0, 8, 0, 4, 0, 2, 0, 1, 0,127, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_091[] = { 3, 0, 96, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96, 0, 0, 0}; +static const GLubyte Helvetica12_Character_092[] = { 4, 0, 0, 0, 0, 16, 16, 32, 32, 32, 64, 64,128,128, 0, 0, 0}; +static const GLubyte Helvetica12_Character_093[] = { 3, 0,192, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,192, 0, 0, 0}; +static const GLubyte Helvetica12_Character_094[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,136, 80, 32, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_095[] = { 7, 0, 0,254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_096[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192,128, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_097[] = { 7, 0, 0, 0, 0, 58, 68, 68, 60, 4, 68, 56, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_098[] = { 7, 0, 0, 0, 0, 88,100, 68, 68, 68,100, 88, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_099[] = { 7, 0, 0, 0, 0, 56, 68, 64, 64, 64, 68, 56, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_100[] = { 7, 0, 0, 0, 0, 52, 76, 68, 68, 68, 76, 52, 4, 4, 0, 0, 0}; +static const GLubyte Helvetica12_Character_101[] = { 7, 0, 0, 0, 0, 56, 68, 64,124, 68, 68, 56, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_102[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64,224, 64, 48, 0, 0, 0}; +static const GLubyte Helvetica12_Character_103[] = { 7, 0, 56, 68, 4, 52, 76, 68, 68, 68, 76, 52, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_104[] = { 7, 0, 0, 0, 0, 68, 68, 68, 68, 68,100, 88, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_105[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 0, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_106[] = { 3, 0,128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_107[] = { 6, 0, 0, 0, 0, 68, 72, 80, 96, 96, 80, 72, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_108[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_109[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 73, 0, 73, 0, 73, 0, 73, 0, 73, 0,109, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_110[] = { 7, 0, 0, 0, 0, 68, 68, 68, 68, 68,100, 88, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_111[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 68, 56, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_112[] = { 7, 0, 64, 64, 64, 88,100, 68, 68, 68,100, 88, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_113[] = { 7, 0, 4, 4, 4, 52, 76, 68, 68, 68, 76, 52, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_114[] = { 4, 0, 0, 0, 0, 64, 64, 64, 64, 64, 96, 80, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_115[] = { 6, 0, 0, 0, 0, 48, 72, 8, 48, 64, 72, 48, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_116[] = { 3, 0, 0, 0, 0, 96, 64, 64, 64, 64, 64,224, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_117[] = { 7, 0, 0, 0, 0, 52, 76, 68, 68, 68, 68, 68, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_118[] = { 7, 0, 0, 0, 0, 16, 16, 40, 40, 68, 68, 68, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_119[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 34, 0, 85, 0, 73, 0, 73, 0,136,128,136,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_120[] = { 6, 0, 0, 0, 0,132,132, 72, 48, 48, 72,132, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_121[] = { 7, 0, 64, 32, 16, 16, 40, 40, 72, 68, 68, 68, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_122[] = { 6, 0, 0, 0, 0,120, 64, 32, 32, 16, 8,120, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_123[] = { 4, 0, 48, 64, 64, 64, 64, 64,128, 64, 64, 64, 64, 48, 0, 0, 0}; +static const GLubyte Helvetica12_Character_124[] = { 3, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_125[] = { 4, 0,192, 32, 32, 32, 32, 32, 16, 32, 32, 32, 32,192, 0, 0, 0}; +static const GLubyte Helvetica12_Character_126[] = { 7, 0, 0, 0, 0, 0, 0, 0,152,100, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_127[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_128[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_129[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_130[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_131[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_132[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_133[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_134[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_135[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_136[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_137[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_138[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_139[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_140[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_141[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_142[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_143[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_144[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_145[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_146[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_147[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_148[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_149[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_150[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_151[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_152[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_153[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_154[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_155[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_156[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_157[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_158[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_159[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_160[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_161[] = { 3, 0, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_162[] = { 7, 0, 0, 0, 32, 56,100, 80, 80, 80, 84, 56, 8, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_163[] = { 7, 0, 0, 0, 0, 88, 36, 16, 16,120, 32, 32, 36, 24, 0, 0, 0}; +static const GLubyte Helvetica12_Character_164[] = { 7, 0, 0, 0, 0, 0,132,120, 72, 72,120,132, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_165[] = { 7, 0, 0, 0, 0, 16, 16,124, 16,124, 16, 40, 68, 68, 0, 0, 0}; +static const GLubyte Helvetica12_Character_166[] = { 3, 0, 0, 64, 64, 64, 64, 0, 0, 0, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_167[] = { 6, 0,112,136, 8, 48, 72,136,136,144, 96,128,136,112, 0, 0, 0}; +static const GLubyte Helvetica12_Character_168[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,160, 0, 0, 0}; +static const GLubyte Helvetica12_Character_169[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 32,128, 78, 64, 81, 64, 80, 64, 81, 64, 78, 64, 32,128, 31, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_170[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0,112, 0, 80, 16,112, 0, 0, 0}; +static const GLubyte Helvetica12_Character_171[] = { 7, 0, 0, 0, 0, 0, 20, 40, 80, 40, 20, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_172[] = { 8, 0, 0, 0, 0, 0, 0, 2, 2, 2,126, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_173[] = { 5, 0, 0, 0, 0, 0, 0, 0,240, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_174[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 32,128, 74, 64, 74, 64, 76, 64, 74, 64, 78, 64, 32,128, 31, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_175[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,240, 0, 0, 0}; +static const GLubyte Helvetica12_Character_176[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 96,144,144, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_177[] = { 7, 0, 0, 0, 0,124, 0, 16, 16,124, 16, 16, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_178[] = { 4, 0, 0, 0, 0, 0, 0, 0,240, 64, 32,144, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_179[] = { 4, 0, 0, 0, 0, 0, 0, 0,192, 32, 64, 32,224, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_180[] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 64, 0, 0}; +static const GLubyte Helvetica12_Character_181[] = { 7, 0, 64, 64, 64,116, 76, 68, 68, 68, 68, 68, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_182[] = { 7, 0, 40, 40, 40, 40, 40, 40,104,232,232,232,104, 60, 0, 0, 0}; +static const GLubyte Helvetica12_Character_183[] = { 3, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_184[] = { 3, 0,192, 32, 32, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_185[] = { 4, 0, 0, 0, 0, 0, 0, 0, 32, 32, 32, 96, 32, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_186[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0,112, 0,112, 80,112, 0, 0, 0}; +static const GLubyte Helvetica12_Character_187[] = { 7, 0, 0, 0, 0, 0, 80, 40, 20, 40, 80, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_188[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 39,128, 21, 0, 19, 0, 73, 0, 68, 0, 68, 0,194, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_189[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 71,128, 34, 0, 17, 0, 20,128, 75, 0, 72, 0, 68, 0,194, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_190[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 23,128, 21, 0, 11, 0,201, 0, 36, 0, 68, 0, 34, 0,225, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_191[] = { 7, 0, 56, 68, 68, 32, 32, 16, 16, 0, 16, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_192[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 62, 0, 34, 0, 34, 0, 20, 0, 8, 0, 8, 0, 0, 0, 8, 0, 16, 0}; +static const GLubyte Helvetica12_Character_193[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 62, 0, 34, 0, 34, 0, 20, 0, 8, 0, 8, 0, 0, 0, 8, 0, 4, 0}; +static const GLubyte Helvetica12_Character_194[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 62, 0, 34, 0, 34, 0, 20, 0, 8, 0, 8, 0, 0, 0, 20, 0, 8, 0}; +static const GLubyte Helvetica12_Character_195[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 62, 0, 34, 0, 34, 0, 20, 0, 8, 0, 8, 0, 0, 0, 20, 0, 10, 0}; +static const GLubyte Helvetica12_Character_196[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 62, 0, 34, 0, 34, 0, 20, 0, 8, 0, 8, 0, 0, 0, 20, 0, 0, 0}; +static const GLubyte Helvetica12_Character_197[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 62, 0, 34, 0, 34, 0, 20, 0, 8, 0, 8, 0, 8, 0, 20, 0, 8, 0}; +static const GLubyte Helvetica12_Character_198[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 71,192, 68, 0, 68, 0, 60, 0, 39,192, 36, 0, 20, 0, 20, 0, 15,192, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_199[] = { 9, 0, 0, 24, 0, 4, 0, 4, 0, 30, 0, 33, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 33, 0, 30, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_200[] = { 8, 0, 0, 0, 0,126, 64, 64, 64,126, 64, 64, 64,126, 0, 8, 16}; +static const GLubyte Helvetica12_Character_201[] = { 8, 0, 0, 0, 0,126, 64, 64, 64,126, 64, 64, 64,126, 0, 8, 4}; +static const GLubyte Helvetica12_Character_202[] = { 8, 0, 0, 0, 0,126, 64, 64, 64,126, 64, 64, 64,126, 0, 20, 8}; +static const GLubyte Helvetica12_Character_203[] = { 8, 0, 0, 0, 0,126, 64, 64, 64,126, 64, 64, 64,126, 0, 20, 0}; +static const GLubyte Helvetica12_Character_204[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64,128}; +static const GLubyte Helvetica12_Character_205[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 32}; +static const GLubyte Helvetica12_Character_206[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0,160, 64}; +static const GLubyte Helvetica12_Character_207[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0,160, 0}; +static const GLubyte Helvetica12_Character_208[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 66, 0, 65, 0, 65, 0,241, 0, 65, 0, 65, 0, 66, 0,124, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_209[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 67, 0, 69, 0, 69, 0, 73, 0, 81, 0, 81, 0, 97, 0, 65, 0, 0, 0, 20, 0, 10, 0}; +static const GLubyte Helvetica12_Character_210[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 33, 0, 64,128, 64,128, 64,128, 64,128, 64,128, 33, 0, 30, 0, 0, 0, 4, 0, 8, 0}; +static const GLubyte Helvetica12_Character_211[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 33, 0, 64,128, 64,128, 64,128, 64,128, 64,128, 33, 0, 30, 0, 0, 0, 4, 0, 2, 0}; +static const GLubyte Helvetica12_Character_212[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 33, 0, 64,128, 64,128, 64,128, 64,128, 64,128, 33, 0, 30, 0, 0, 0, 10, 0, 4, 0}; +static const GLubyte Helvetica12_Character_213[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 33, 0, 64,128, 64,128, 64,128, 64,128, 64,128, 33, 0, 30, 0, 0, 0, 20, 0, 10, 0}; +static const GLubyte Helvetica12_Character_214[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 33, 0, 64,128, 64,128, 64,128, 64,128, 64,128, 33, 0, 30, 0, 0, 0, 18, 0, 0, 0}; +static const GLubyte Helvetica12_Character_215[] = { 7, 0, 0, 0, 0, 0, 68, 40, 16, 40, 68, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_216[] = { 10, 0, 0, 0, 0, 0, 0,128, 0, 94, 0, 33, 0, 80,128, 72,128, 68,128, 68,128, 66,128, 33, 0, 30,128, 0, 64, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_217[] = { 8, 0, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 66, 0, 8, 16}; +static const GLubyte Helvetica12_Character_218[] = { 8, 0, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 66, 0, 8, 4}; +static const GLubyte Helvetica12_Character_219[] = { 8, 0, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 66, 0, 20, 8}; +static const GLubyte Helvetica12_Character_220[] = { 8, 0, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 66, 0, 36, 0}; +static const GLubyte Helvetica12_Character_221[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 20, 0, 34, 0, 34, 0, 65, 0, 65, 0, 0, 0, 8, 0, 4, 0}; +static const GLubyte Helvetica12_Character_222[] = { 8, 0, 0, 0, 0, 64, 64,124, 66, 66, 66,124, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_223[] = { 7, 0, 0, 0, 0, 88, 68, 68, 68, 88, 68, 68, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_224[] = { 7, 0, 0, 0, 0, 58, 68, 68, 60, 4, 68, 56, 0, 8, 16, 0, 0}; +static const GLubyte Helvetica12_Character_225[] = { 7, 0, 0, 0, 0, 58, 68, 68, 60, 4, 68, 56, 0, 16, 8, 0, 0}; +static const GLubyte Helvetica12_Character_226[] = { 7, 0, 0, 0, 0, 58, 68, 68, 60, 4, 68, 56, 0, 40, 16, 0, 0}; +static const GLubyte Helvetica12_Character_227[] = { 7, 0, 0, 0, 0, 58, 68, 68, 60, 4, 68, 56, 0, 40, 20, 0, 0}; +static const GLubyte Helvetica12_Character_228[] = { 7, 0, 0, 0, 0, 58, 68, 68, 60, 4, 68, 56, 0, 40, 0, 0, 0}; +static const GLubyte Helvetica12_Character_229[] = { 7, 0, 0, 0, 0, 58, 68, 68, 60, 4, 68, 56, 24, 36, 24, 0, 0}; +static const GLubyte Helvetica12_Character_230[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 59,128, 68, 64, 68, 0, 63,192, 4, 64, 68, 64, 59,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_231[] = { 7, 0, 48, 8, 16, 56, 68, 64, 64, 64, 68, 56, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_232[] = { 7, 0, 0, 0, 0, 56, 68, 64,124, 68, 68, 56, 0, 16, 32, 0, 0}; +static const GLubyte Helvetica12_Character_233[] = { 7, 0, 0, 0, 0, 56, 68, 64,124, 68, 68, 56, 0, 16, 8, 0, 0}; +static const GLubyte Helvetica12_Character_234[] = { 7, 0, 0, 0, 0, 56, 68, 64,124, 68, 68, 56, 0, 40, 16, 0, 0}; +static const GLubyte Helvetica12_Character_235[] = { 7, 0, 0, 0, 0, 56, 68, 64,124, 68, 68, 56, 0, 40, 0, 0, 0}; +static const GLubyte Helvetica12_Character_236[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 0, 64,128, 0, 0}; +static const GLubyte Helvetica12_Character_237[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 0, 64, 32, 0, 0}; +static const GLubyte Helvetica12_Character_238[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 0,160, 64, 0, 0}; +static const GLubyte Helvetica12_Character_239[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 0,160, 0, 0, 0}; +static const GLubyte Helvetica12_Character_240[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 60, 4, 40, 24, 52, 0, 0}; +static const GLubyte Helvetica12_Character_241[] = { 7, 0, 0, 0, 0, 68, 68, 68, 68, 68,100, 88, 0, 40, 20, 0, 0}; +static const GLubyte Helvetica12_Character_242[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 68, 56, 0, 16, 32, 0, 0}; +static const GLubyte Helvetica12_Character_243[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 68, 56, 0, 16, 8, 0, 0}; +static const GLubyte Helvetica12_Character_244[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 68, 56, 0, 40, 16, 0, 0}; +static const GLubyte Helvetica12_Character_245[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 68, 56, 0, 40, 20, 0, 0}; +static const GLubyte Helvetica12_Character_246[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 68, 56, 0, 40, 0, 0, 0}; +static const GLubyte Helvetica12_Character_247[] = { 7, 0, 0, 0, 0, 0, 16, 0,124, 0, 16, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_248[] = { 7, 0, 0, 0, 0,184, 68,100, 84, 76, 68, 58, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_249[] = { 7, 0, 0, 0, 0, 52, 76, 68, 68, 68, 68, 68, 0, 16, 32, 0, 0}; +static const GLubyte Helvetica12_Character_250[] = { 7, 0, 0, 0, 0, 52, 76, 68, 68, 68, 68, 68, 0, 16, 8, 0, 0}; +static const GLubyte Helvetica12_Character_251[] = { 7, 0, 0, 0, 0, 52, 76, 68, 68, 68, 68, 68, 0, 40, 16, 0, 0}; +static const GLubyte Helvetica12_Character_252[] = { 7, 0, 0, 0, 0, 52, 76, 68, 68, 68, 68, 68, 0, 40, 0, 0, 0}; +static const GLubyte Helvetica12_Character_253[] = { 7, 0, 64, 32, 16, 16, 40, 40, 72, 68, 68, 68, 0, 16, 8, 0, 0}; +static const GLubyte Helvetica12_Character_254[] = { 7, 0, 64, 64, 64, 88,100, 68, 68, 68,100, 88, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_255[] = { 7, 0, 96, 16, 16, 16, 24, 40, 40, 36, 68, 68, 0, 40, 0, 0, 0}; + +/* The font characters mapping: */ +static const GLubyte* Helvetica12_Character_Map[] = {Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032, + Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032, + Helvetica12_Character_032,Helvetica12_Character_033,Helvetica12_Character_034,Helvetica12_Character_035,Helvetica12_Character_036,Helvetica12_Character_037,Helvetica12_Character_038,Helvetica12_Character_039,Helvetica12_Character_040,Helvetica12_Character_041,Helvetica12_Character_042,Helvetica12_Character_043,Helvetica12_Character_044,Helvetica12_Character_045,Helvetica12_Character_046,Helvetica12_Character_047, + Helvetica12_Character_048,Helvetica12_Character_049,Helvetica12_Character_050,Helvetica12_Character_051,Helvetica12_Character_052,Helvetica12_Character_053,Helvetica12_Character_054,Helvetica12_Character_055,Helvetica12_Character_056,Helvetica12_Character_057,Helvetica12_Character_058,Helvetica12_Character_059,Helvetica12_Character_060,Helvetica12_Character_061,Helvetica12_Character_062,Helvetica12_Character_063, + Helvetica12_Character_064,Helvetica12_Character_065,Helvetica12_Character_066,Helvetica12_Character_067,Helvetica12_Character_068,Helvetica12_Character_069,Helvetica12_Character_070,Helvetica12_Character_071,Helvetica12_Character_072,Helvetica12_Character_073,Helvetica12_Character_074,Helvetica12_Character_075,Helvetica12_Character_076,Helvetica12_Character_077,Helvetica12_Character_078,Helvetica12_Character_079, + Helvetica12_Character_080,Helvetica12_Character_081,Helvetica12_Character_082,Helvetica12_Character_083,Helvetica12_Character_084,Helvetica12_Character_085,Helvetica12_Character_086,Helvetica12_Character_087,Helvetica12_Character_088,Helvetica12_Character_089,Helvetica12_Character_090,Helvetica12_Character_091,Helvetica12_Character_092,Helvetica12_Character_093,Helvetica12_Character_094,Helvetica12_Character_095, + Helvetica12_Character_096,Helvetica12_Character_097,Helvetica12_Character_098,Helvetica12_Character_099,Helvetica12_Character_100,Helvetica12_Character_101,Helvetica12_Character_102,Helvetica12_Character_103,Helvetica12_Character_104,Helvetica12_Character_105,Helvetica12_Character_106,Helvetica12_Character_107,Helvetica12_Character_108,Helvetica12_Character_109,Helvetica12_Character_110,Helvetica12_Character_111, + Helvetica12_Character_112,Helvetica12_Character_113,Helvetica12_Character_114,Helvetica12_Character_115,Helvetica12_Character_116,Helvetica12_Character_117,Helvetica12_Character_118,Helvetica12_Character_119,Helvetica12_Character_120,Helvetica12_Character_121,Helvetica12_Character_122,Helvetica12_Character_123,Helvetica12_Character_124,Helvetica12_Character_125,Helvetica12_Character_126,Helvetica12_Character_032, + Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032, + Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032, + Helvetica12_Character_160,Helvetica12_Character_161,Helvetica12_Character_162,Helvetica12_Character_163,Helvetica12_Character_164,Helvetica12_Character_165,Helvetica12_Character_166,Helvetica12_Character_167,Helvetica12_Character_168,Helvetica12_Character_169,Helvetica12_Character_170,Helvetica12_Character_171,Helvetica12_Character_172,Helvetica12_Character_173,Helvetica12_Character_174,Helvetica12_Character_175, + Helvetica12_Character_176,Helvetica12_Character_177,Helvetica12_Character_178,Helvetica12_Character_179,Helvetica12_Character_180,Helvetica12_Character_181,Helvetica12_Character_182,Helvetica12_Character_183,Helvetica12_Character_184,Helvetica12_Character_185,Helvetica12_Character_186,Helvetica12_Character_187,Helvetica12_Character_188,Helvetica12_Character_189,Helvetica12_Character_190,Helvetica12_Character_191, + Helvetica12_Character_192,Helvetica12_Character_193,Helvetica12_Character_194,Helvetica12_Character_195,Helvetica12_Character_196,Helvetica12_Character_197,Helvetica12_Character_198,Helvetica12_Character_199,Helvetica12_Character_200,Helvetica12_Character_201,Helvetica12_Character_202,Helvetica12_Character_203,Helvetica12_Character_204,Helvetica12_Character_205,Helvetica12_Character_206,Helvetica12_Character_207, + Helvetica12_Character_208,Helvetica12_Character_209,Helvetica12_Character_210,Helvetica12_Character_211,Helvetica12_Character_212,Helvetica12_Character_213,Helvetica12_Character_214,Helvetica12_Character_215,Helvetica12_Character_216,Helvetica12_Character_217,Helvetica12_Character_218,Helvetica12_Character_219,Helvetica12_Character_220,Helvetica12_Character_221,Helvetica12_Character_222,Helvetica12_Character_223, + Helvetica12_Character_224,Helvetica12_Character_225,Helvetica12_Character_226,Helvetica12_Character_227,Helvetica12_Character_228,Helvetica12_Character_229,Helvetica12_Character_230,Helvetica12_Character_231,Helvetica12_Character_232,Helvetica12_Character_233,Helvetica12_Character_234,Helvetica12_Character_235,Helvetica12_Character_236,Helvetica12_Character_237,Helvetica12_Character_238,Helvetica12_Character_239, + Helvetica12_Character_240,Helvetica12_Character_241,Helvetica12_Character_242,Helvetica12_Character_243,Helvetica12_Character_244,Helvetica12_Character_245,Helvetica12_Character_246,Helvetica12_Character_247,Helvetica12_Character_248,Helvetica12_Character_249,Helvetica12_Character_250,Helvetica12_Character_251,Helvetica12_Character_252,Helvetica12_Character_253,Helvetica12_Character_254,Helvetica12_Character_255,NULL}; + +/* The font structure: */ +const SFG_Font fgFontHelvetica12 = { "-adobe-helvetica-medium-r-normal--12-120-75-75-p-67-iso8859-1", 256, 16, Helvetica12_Character_Map, 0, 4 }; + +static const GLubyte Helvetica18_Character_000[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 64, 16, 0, 0, 64, 16, 0, 0, 64, 16, 0, 0, 64, 16, 0, 0, 64, 16, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_001[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_002[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_003[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_004[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_005[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_006[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_007[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_008[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_009[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_010[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_011[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_012[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_013[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_014[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_015[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_016[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_017[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_018[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_019[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_020[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_021[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_022[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_023[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_024[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_025[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_026[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_027[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_028[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_029[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_030[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_031[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_032[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_033[] = { 6, 0, 0, 0, 0, 0, 48, 48, 0, 0, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_034[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,144,144,216,216,216, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_035[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 36, 0, 36, 0,255,128,255,128, 18, 0, 18, 0, 18, 0,127,192,127,192, 9, 0, 9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_036[] = { 10, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 31, 0, 63,128,117,192,100,192, 4,192, 7,128, 31, 0, 60, 0,116, 0,100, 0,101,128, 63,128, 31, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_037[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 60, 12,126, 6,102, 6,102, 3,126, 3, 60, 1,128, 61,128,126,192,102,192,102, 96,126, 96, 60, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_038[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 56, 63,112,115,224, 97,192, 97,224, 99, 96,119, 96, 62, 0, 30, 0, 51, 0, 51, 0, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_039[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 32, 32, 96, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_040[] = { 6, 0, 8, 24, 48, 48, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48, 48, 24, 8, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_041[] = { 6, 0, 64, 96, 48, 48, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 48, 48, 96, 64, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_042[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 56, 56,124, 16, 16, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_043[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 12, 0, 12, 0,127,128,127,128, 12, 0, 12, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_044[] = { 5, 0, 0, 64, 32, 32, 96, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_045[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,128,127,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_046[] = { 5, 0, 0, 0, 0, 0, 96, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_047[] = { 5, 0, 0, 0, 0, 0,192,192, 64, 64, 96, 96, 32, 32, 48, 48, 16, 16, 24, 24, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_048[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63, 0, 51, 0, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 51, 0, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_049[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 62, 0, 62, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_050[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,128,127,128, 96, 0,112, 0, 56, 0, 28, 0, 14, 0, 7, 0, 3,128, 1,128, 97,128,127, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_051[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63, 0, 99,128, 97,128, 1,128, 3,128, 15, 0, 14, 0, 3, 0, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_052[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,128, 1,128, 1,128,127,192,127,192, 97,128, 49,128, 25,128, 25,128, 13,128, 7,128, 3,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_053[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0,127, 0, 99,128, 97,128, 1,128, 1,128, 99,128,127, 0,126, 0, 96, 0, 96, 0,127, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_054[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63, 0,113,128, 97,128, 97,128, 97,128,127, 0,110, 0, 96, 0, 96, 0, 49,128, 63,128, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_055[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 48, 0, 24, 0, 24, 0, 24, 0, 12, 0, 12, 0, 6, 0, 6, 0, 3, 0, 1,128,127,128,127,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_056[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63, 0,115,128, 97,128, 97,128, 51, 0, 63, 0, 51, 0, 97,128, 97,128,115,128, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_057[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0,127, 0, 99, 0, 1,128, 1,128, 29,128, 63,128, 97,128, 97,128, 97,128, 99,128, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_058[] = { 5, 0, 0, 0, 0, 0, 96, 96, 0, 0, 0, 0, 0, 0, 96, 96, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_059[] = { 5, 0, 0, 64, 32, 32, 96, 96, 0, 0, 0, 0, 0, 0, 96, 96, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_060[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,128, 7,128, 30, 0, 56, 0, 96, 0, 56, 0, 30, 0, 7,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_061[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 63,128, 0, 0, 0, 0, 63,128, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_062[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0,120, 0, 30, 0, 7, 0, 1,128, 7, 0, 30, 0,120, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_063[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 24, 0, 0, 0, 0, 0, 24, 0, 24, 0, 24, 0, 28, 0, 14, 0, 7, 0, 99, 0, 99, 0,127, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_064[] = { 18, 0, 0, 0, 0, 0, 0, 3,240, 0, 15,248, 0, 28, 0, 0, 56, 0, 0, 51,184, 0,103,252, 0,102,102, 0,102, 51, 0,102, 51, 0,102, 49,128, 99, 25,128, 51,185,128, 49,217,128, 24, 3, 0, 14, 7, 0, 7,254, 0, 1,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_065[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 48,192, 48, 96, 96, 96, 96,127,224, 63,192, 48,192, 48,192, 25,128, 25,128, 15, 0, 15, 0, 6, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_066[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,192,127,224, 96,112, 96, 48, 96, 48, 96,112,127,224,127,192, 96,192, 96, 96, 96, 96, 96,224,127,192,127,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_067[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 31,240, 56, 56, 48, 24,112, 0, 96, 0, 96, 0, 96, 0, 96, 0,112, 0, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_068[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,128,127,192, 96,224, 96, 96, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 96, 96,224,127,192,127,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_069[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,192,127,192, 96, 0, 96, 0, 96, 0, 96, 0,127,128,127,128, 96, 0, 96, 0, 96, 0, 96, 0,127,192,127,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_070[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0,127,128,127,128, 96, 0, 96, 0, 96, 0, 96, 0,127,192,127,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_071[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,216, 31,248, 56, 56, 48, 24,112, 24, 96,248, 96,248, 96, 0, 96, 0,112, 24, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_072[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48,127,240,127,240, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_073[] = { 6, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_074[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63, 0,115,128, 97,128, 97,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_075[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 56, 96,112, 96,224, 97,192, 99,128,103, 0,126, 0,124, 0,110, 0,103, 0, 99,128, 97,192, 96,224, 96,112, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_076[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,128,127,128, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_077[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97,134, 97,134, 99,198, 98, 70,102,102,102,102,108, 54,108, 54,120, 30,120, 30,112, 14,112, 14, 96, 6, 96, 6, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_078[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 48, 96,112, 96,240, 96,240, 97,176, 99, 48, 99, 48,102, 48,102, 48,108, 48,120, 48,120, 48,112, 48, 96, 48, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_079[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 31,240, 56, 56, 48, 24,112, 28, 96, 12, 96, 12, 96, 12, 96, 12,112, 28, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_080[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0,127,128,127,192, 96,224, 96, 96, 96, 96, 96,224,127,192,127,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_081[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 7,216, 31,240, 56,120, 48,216,112,220, 96, 12, 96, 12, 96, 12, 96, 12,112, 28, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_082[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96,192, 96,192,127,128,127,192, 96,224, 96, 96, 96, 96, 96,224,127,192,127,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_083[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31,128, 63,224,112,112, 96, 48, 0, 48, 0,112, 1,224, 15,128, 62, 0,112, 0, 96, 48,112,112, 63,224, 15,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_084[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0,127,224,127,224, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_085[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,128, 63,224, 48, 96, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_086[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 7,128, 7,128, 12,192, 12,192, 12,192, 24, 96, 24, 96, 24, 96, 48, 48, 48, 48, 48, 48, 96, 24, 96, 24, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_087[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 12, 12, 0, 14, 28, 0, 26, 22, 0, 27, 54, 0, 27, 54, 0, 51, 51, 0, 51, 51, 0, 49, 35, 0, 49,227, 0, 97,225,128, 96,193,128, 96,193,128, 96,193,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_088[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 48,112,112, 48, 96, 56,224, 24,192, 13,128, 7, 0, 7, 0, 13,128, 24,192, 56,224, 48, 96,112,112, 96, 48, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_089[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 7,128, 12,192, 24, 96, 24, 96, 48, 48, 48, 48, 96, 24, 96, 24, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_090[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,224,127,224, 96, 0, 48, 0, 24, 0, 12, 0, 14, 0, 6, 0, 3, 0, 1,128, 0,192, 0, 96,127,224,127,224, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_091[] = { 5, 0,120,120, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,120,120, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_092[] = { 5, 0, 0, 0, 0, 0, 24, 24, 16, 16, 48, 48, 32, 32, 96, 96, 64, 64,192,192, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_093[] = { 5, 0,240,240, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,240,240, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_094[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 99, 0, 54, 0, 28, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_095[] = { 10, 0, 0,255,192,255,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_096[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 96, 64, 64, 32, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_097[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0,119, 0, 99, 0, 99, 0,115, 0, 63, 0, 7, 0, 99, 0,119, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_098[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 0,127,128,113,128, 96,192, 96,192, 96,192, 96,192,113,128,127,128,111, 0, 96, 0, 96, 0, 96, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_099[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96, 0, 96, 0, 96, 0, 96, 0, 49,128, 63,128, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_100[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30,192, 63,192, 49,192, 96,192, 96,192, 96,192, 96,192, 49,192, 63,192, 30,192, 0,192, 0,192, 0,192, 0,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_101[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63,128,113,128, 96, 0, 96, 0,127,128, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_102[] = { 6, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48,252,252, 48, 48, 60, 28, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_103[] = { 11, 0, 0, 14, 0, 63,128, 49,128, 0,192, 30,192, 63,192, 49,192, 96,192, 96,192, 96,192, 96,192, 48,192, 63,192, 30,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_104[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128,113,128,111,128,103, 0, 96, 0, 96, 0, 96, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_105[] = { 4, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, 0, 96, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_106[] = { 4, 0,192,224, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, 0, 96, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_107[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99,128, 99, 0,103, 0,102, 0,108, 0,124, 0,120, 0,108, 0,102, 0, 99, 0, 96, 0, 96, 0, 96, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_108[] = { 4, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_109[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 24, 99, 24, 99, 24, 99, 24, 99, 24, 99, 24, 99, 24,115,152,111,120,102, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_110[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128,113,128,111,128,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_111[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96,192, 96,192, 96,192, 96,192, 49,128, 63,128, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_112[] = { 11, 0, 0, 96, 0, 96, 0, 96, 0, 96, 0,111, 0,127,128,113,128, 96,192, 96,192, 96,192, 96,192,113,128,127,128,111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_113[] = { 11, 0, 0, 0,192, 0,192, 0,192, 0,192, 30,192, 63,192, 49,192, 96,192, 96,192, 96,192, 96,192, 49,192, 63,192, 30,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_114[] = { 6, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96,112,108,108, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_115[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0,126, 0, 99, 0, 3, 0, 31, 0,126, 0, 96, 0, 99, 0, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_116[] = { 6, 0, 0, 0, 0, 0, 24, 56, 48, 48, 48, 48, 48, 48,252,252, 48, 48, 48, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_117[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57,128,125,128, 99,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_118[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 30, 0, 18, 0, 51, 0, 51, 0, 51, 0, 97,128, 97,128, 97,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_119[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12,192, 12,192, 28,224, 20,160, 52,176, 51, 48, 51, 48, 99, 24, 99, 24, 99, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_120[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97,128,115,128, 51, 0, 30, 0, 12, 0, 12, 0, 30, 0, 51, 0,115,128, 97,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_121[] = { 10, 0, 0, 56, 0, 56, 0, 12, 0, 12, 0, 12, 0, 12, 0, 30, 0, 18, 0, 51, 0, 51, 0, 51, 0, 97,128, 97,128, 97,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_122[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0,127, 0, 96, 0, 48, 0, 24, 0, 12, 0, 6, 0, 3, 0,127, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_123[] = { 6, 0, 12, 24, 48, 48, 48, 48, 48, 48, 96,192, 96, 48, 48, 48, 48, 48, 24, 12, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_124[] = { 4, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_125[] = { 6, 0,192, 96, 48, 48, 48, 48, 48, 48, 24, 12, 24, 48, 48, 48, 48, 48, 96,192, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_126[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102, 0, 63, 0, 25,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_127[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_128[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_129[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_130[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_131[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_132[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_133[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_134[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_135[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_136[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_137[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_138[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_139[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_140[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_141[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_142[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_143[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_144[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_145[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_146[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_147[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_148[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_149[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_150[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_151[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_152[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_153[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_154[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_155[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_156[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_157[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_158[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_159[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_160[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_161[] = { 6, 0, 48, 48, 48, 48, 48, 48, 48, 48, 16, 16, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_162[] = { 10, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 31, 0, 63,128, 53,128,100, 0,100, 0,100, 0,100, 0, 53,128, 63,128, 31, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_163[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,223, 0,255,128, 96,128, 48, 0, 24, 0, 24, 0,126, 0, 48, 0, 96, 0, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_164[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97,128,127,128, 51, 0, 51, 0, 51, 0,127,128, 97,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_165[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 12, 0, 12, 0,127,128, 12, 0,127,128, 30, 0, 51, 0, 51, 0, 51, 0, 97,128, 97,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_166[] = { 4, 0, 0, 96, 96, 96, 96, 96, 96, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_167[] = { 10, 0, 0, 30, 0, 63, 0, 97,128, 97,128, 3,128, 7, 0, 31, 0, 57,128,113,128, 97,128, 99,128, 55, 0, 62, 0,120, 0, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_168[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,216,216, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_169[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 24, 48, 32, 8, 35,136, 68, 68, 72, 4, 72, 4, 72, 4, 68, 68, 35,136, 32, 8, 24, 48, 7,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_170[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 52,108, 36, 28,100, 56, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_171[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 27, 0, 54, 0,108, 0,108, 0, 54, 0, 27, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_172[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 0,192, 0,192,127,192,127,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_173[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,124,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_174[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 24, 48, 32, 8, 36, 40, 68, 68, 68,132, 71,196, 68, 36, 68, 36, 39,200, 32, 8, 24, 48, 7,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_175[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,248, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_176[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,108, 68,108, 56, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_177[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,128,127,128, 0, 0, 12, 0, 12, 0, 12, 0,127,128,127,128, 12, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_178[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,248,248, 96, 48, 24,152,248,112, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_179[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,112,248,152, 48, 48,152,248,112, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_180[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 96, 48, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_181[] = { 10, 0, 0, 96, 0, 96, 0, 96, 0, 96, 0,109,128,127,128,115,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_182[] = { 10, 0, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 25, 0, 57, 0,121, 0,121, 0,121, 0,121, 0, 57, 0, 31,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_183[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_184[] = { 5, 0,240,216, 24,112, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_185[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48,112,112, 48, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_186[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 56,108, 68, 68,108, 56, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_187[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0,108, 0, 54, 0, 27, 0, 27, 0, 54, 0,108, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_188[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 12,252, 6,216, 6,120, 51, 56, 49, 24, 49,136, 48,192, 48,192,112, 96,112, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_189[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24,124, 24,124, 12, 48, 6, 24, 6, 12, 51, 76, 49,124, 49,184, 48,192, 48,192,112, 96,112, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_190[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 12,252, 6,216, 6,120,115, 56,249, 24,153,136, 48,192, 48,192,152, 96,248, 48,112, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_191[] = { 10, 0, 0, 62, 0,127, 0, 99, 0, 99, 0,112, 0, 56, 0, 28, 0, 12, 0, 12, 0, 12, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_192[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 48,192, 48, 96, 96, 96, 96,127,224, 63,192, 48,192, 48,192, 25,128, 25,128, 15, 0, 15, 0, 6, 0, 6, 0, 0, 0, 6, 0, 12, 0, 24, 0}; +static const GLubyte Helvetica18_Character_193[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 48,192, 48, 96, 96, 96, 96,127,224, 63,192, 48,192, 48,192, 25,128, 25,128, 15, 0, 15, 0, 6, 0, 6, 0, 0, 0, 6, 0, 3, 0, 1,128}; +static const GLubyte Helvetica18_Character_194[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 48,192, 48, 96, 96, 96, 96,127,224, 63,192, 48,192, 48,192, 25,128, 25,128, 15, 0, 15, 0, 6, 0, 6, 0, 0, 0, 25,128, 15, 0, 6, 0}; +static const GLubyte Helvetica18_Character_195[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 48,192, 48, 96, 96, 96, 96,127,224, 63,192, 48,192, 48,192, 25,128, 25,128, 15, 0, 15, 0, 6, 0, 6, 0, 0, 0, 19, 0, 22,128, 12,128}; +static const GLubyte Helvetica18_Character_196[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 48,192, 48, 96, 96, 96, 96,127,224, 63,192, 48,192, 48,192, 25,128, 25,128, 15, 0, 15, 0, 6, 0, 6, 0, 0, 0, 25,128, 25,128, 0, 0}; +static const GLubyte Helvetica18_Character_197[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 48,192, 48, 96, 96, 96, 96,127,224, 63,192, 48,192, 48,192, 25,128, 25,128, 15, 0, 15, 0, 6, 0, 6, 0, 15, 0, 25,128, 25,128, 15, 0}; +static const GLubyte Helvetica18_Character_198[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96,255,128, 96,255,128, 48,192, 0, 48,192, 0, 63,192, 0, 31,192, 0, 24,255, 0, 24,255, 0, 12,192, 0, 12,192, 0, 6,192, 0, 6,192, 0, 3,255,128, 3,255,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_199[] = { 14, 0, 0, 15, 0, 13,128, 1,128, 7, 0, 7,192, 31,240, 56, 56, 48, 24,112, 0, 96, 0, 96, 0, 96, 0, 96, 0,112, 0, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_200[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,192,127,192, 96, 0, 96, 0, 96, 0, 96, 0,127,128,127,128, 96, 0, 96, 0, 96, 0, 96, 0,127,192,127,192, 0, 0, 6, 0, 12, 0, 24, 0}; +static const GLubyte Helvetica18_Character_201[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,192,127,192, 96, 0, 96, 0, 96, 0, 96, 0,127,128,127,128, 96, 0, 96, 0, 96, 0, 96, 0,127,192,127,192, 0, 0, 6, 0, 3, 0, 1,128}; +static const GLubyte Helvetica18_Character_202[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,192,127,192, 96, 0, 96, 0, 96, 0, 96, 0,127,128,127,128, 96, 0, 96, 0, 96, 0, 96, 0,127,192,127,192, 0, 0, 25,128, 15, 0, 6, 0}; +static const GLubyte Helvetica18_Character_203[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,192,127,192, 96, 0, 96, 0, 96, 0, 96, 0,127,128,127,128, 96, 0, 96, 0, 96, 0, 96, 0,127,192,127,192, 0, 0, 25,128, 25,128, 0, 0}; +static const GLubyte Helvetica18_Character_204[] = { 6, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 96,192}; +static const GLubyte Helvetica18_Character_205[] = { 6, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 24, 12}; +static const GLubyte Helvetica18_Character_206[] = { 6, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0,204,120, 48}; +static const GLubyte Helvetica18_Character_207[] = { 6, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0,204,204, 0}; +static const GLubyte Helvetica18_Character_208[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,128,127,192, 96,224, 96, 96, 96, 48, 96, 48,252, 48,252, 48, 96, 48, 96, 48, 96, 96, 96,224,127,192,127,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_209[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 48, 96,112, 96,240, 96,240, 97,176, 99, 48, 99, 48,102, 48,102, 48,108, 48,108, 48,120, 48,112, 48,112, 48, 0, 0, 9,128, 11, 64, 6, 64}; +static const GLubyte Helvetica18_Character_210[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 31,240, 56, 56, 48, 24,112, 28, 96, 12, 96, 12, 96, 12, 96, 12,112, 28, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 1,128, 3, 0, 6, 0}; +static const GLubyte Helvetica18_Character_211[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 31,240, 56, 56, 48, 24,112, 28, 96, 12, 96, 12, 96, 12, 96, 12,112, 28, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 1,128, 0,192, 0, 96}; +static const GLubyte Helvetica18_Character_212[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 31,240, 56, 56, 48, 24,112, 28, 96, 12, 96, 12, 96, 12, 96, 12,112, 28, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 6, 96, 3,192, 1,128}; +static const GLubyte Helvetica18_Character_213[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 31,240, 56, 56, 48, 24,112, 28, 96, 12, 96, 12, 96, 12, 96, 12,112, 28, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 4,192, 5,160, 3, 32}; +static const GLubyte Helvetica18_Character_214[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 31,240, 56, 56, 48, 24,112, 28, 96, 12, 96, 12, 96, 12, 96, 12,112, 28, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 6,192, 6,192, 0, 0}; +static const GLubyte Helvetica18_Character_215[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192,192, 97,128, 51, 0, 30, 0, 12, 0, 30, 0, 51, 0, 97,128,192,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_216[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,199,192,255,240,120, 56, 56, 24,108, 28,110, 12,103, 12, 99,140, 97,204,112,220, 48,120, 56, 56, 31,252, 7,204, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_217[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,128, 63,224, 48, 96, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 0, 0, 3, 0, 6, 0, 12, 0}; +static const GLubyte Helvetica18_Character_218[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,128, 63,224, 48, 96, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 0, 0, 6, 0, 3, 0, 1,128}; +static const GLubyte Helvetica18_Character_219[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,128, 63,224, 48, 96, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 0, 0, 12,192, 7,128, 3, 0}; +static const GLubyte Helvetica18_Character_220[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,128, 63,224, 48, 96, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 0, 0, 12,192, 12,192, 0, 0}; +static const GLubyte Helvetica18_Character_221[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 7,128, 12,192, 24, 96, 24, 96, 48, 48, 48, 48, 96, 24, 96, 24, 0, 0, 3, 0, 1,128, 0,192}; +static const GLubyte Helvetica18_Character_222[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 96, 0, 96, 0,127,128,127,192, 96,224, 96, 96, 96, 96, 96,224,127,192,127,128, 96, 0, 96, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_223[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,110, 0,111, 0, 99, 0, 99, 0, 99, 0, 99, 0,110, 0,110, 0, 99, 0, 99, 0, 99, 0, 99, 0, 62, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_224[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0,119, 0, 99, 0, 99, 0,115, 0, 63, 0, 7, 0, 99, 0,119, 0, 62, 0, 0, 0, 12, 0, 24, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_225[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0,119, 0, 99, 0, 99, 0,115, 0, 63, 0, 7, 0, 99, 0,119, 0, 62, 0, 0, 0, 24, 0, 12, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_226[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0,119, 0, 99, 0, 99, 0,115, 0, 63, 0, 7, 0, 99, 0,119, 0, 62, 0, 0, 0, 51, 0, 30, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_227[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0,119, 0, 99, 0, 99, 0,115, 0, 63, 0, 7, 0, 99, 0,119, 0, 62, 0, 0, 0, 38, 0, 45, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_228[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0,119, 0, 99, 0, 99, 0,115, 0, 63, 0, 7, 0, 99, 0,119, 0, 62, 0, 0, 0, 54, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_229[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0,119, 0, 99, 0, 99, 0,115, 0, 63, 0, 7, 0, 99, 0,119, 0, 62, 0, 28, 0, 54, 0, 54, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_230[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58,240,119,252, 99,140, 99, 0,115, 0, 63,252, 7, 12, 99, 12,119,248, 62,240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_231[] = { 10, 0, 0, 60, 0, 54, 0, 6, 0, 28, 0, 31, 0, 63,128, 49,128, 96, 0, 96, 0, 96, 0, 96, 0, 49,128, 63,128, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_232[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63,128,113,128, 96, 0, 96, 0,127,128, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 12, 0, 24, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_233[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63,128,113,128, 96, 0, 96, 0,127,128, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 12, 0, 6, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_234[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63,128,113,128, 96, 0, 96, 0,127,128, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 51, 0, 30, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_235[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63,128,113,128, 96, 0, 96, 0,127,128, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 27, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_236[] = { 4, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, 48, 96,192, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_237[] = { 4, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0,192, 96, 48, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_238[] = { 4, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0,144,240, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_239[] = { 4, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0,216,216, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_240[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96,192, 96,192, 96,192, 96,192, 49,128, 63,128, 31, 0, 38, 0, 28, 0, 27, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_241[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128,113,128,111,128,103, 0, 0, 0, 38, 0, 45, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_242[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96,192, 96,192, 96,192, 96,192, 49,128, 63,128, 31, 0, 0, 0, 6, 0, 12, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_243[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96,192, 96,192, 96,192, 96,192, 49,128, 63,128, 31, 0, 0, 0, 12, 0, 6, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_244[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96,192, 96,192, 96,192, 96,192, 49,128, 63,128, 31, 0, 0, 0, 25,128, 15, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_245[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96,192, 96,192, 96,192, 96,192, 49,128, 63,128, 31, 0, 0, 0, 19, 0, 22,128, 12,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_246[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96,192, 96,192, 96,192, 96,192, 49,128, 63,128, 31, 0, 0, 0, 27, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_247[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0,127,128,127,128, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_248[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,206, 0,127,128, 49,128,120,192,108,192,102,192, 99,192, 49,128, 63,192, 14, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_249[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57,128,125,128, 99,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 0, 0, 6, 0, 12, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_250[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57,128,125,128, 99,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 0, 0, 12, 0, 6, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_251[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57,128,125,128, 99,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 0, 0, 51, 0, 30, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_252[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57,128,125,128, 99,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 0, 0, 51, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_253[] = { 10, 0, 0, 56, 0, 56, 0, 12, 0, 12, 0, 12, 0, 12, 0, 30, 0, 18, 0, 51, 0, 51, 0, 51, 0, 97,128, 97,128, 97,128, 0, 0, 12, 0, 6, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_254[] = { 11, 0, 0, 96, 0, 96, 0, 96, 0, 96, 0,111, 0,127,128,113,128, 96,192, 96,192, 96,192, 96,192,113,128,127,128,111, 0, 96, 0, 96, 0, 96, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_255[] = { 10, 0, 0, 56, 0, 56, 0, 12, 0, 12, 0, 12, 0, 12, 0, 30, 0, 18, 0, 51, 0, 51, 0, 51, 0, 97,128, 97,128, 97,128, 0, 0, 51, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +/* The font characters mapping: */ +static const GLubyte* Helvetica18_Character_Map[] = {Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032, + Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032, + Helvetica18_Character_032,Helvetica18_Character_033,Helvetica18_Character_034,Helvetica18_Character_035,Helvetica18_Character_036,Helvetica18_Character_037,Helvetica18_Character_038,Helvetica18_Character_039,Helvetica18_Character_040,Helvetica18_Character_041,Helvetica18_Character_042,Helvetica18_Character_043,Helvetica18_Character_044,Helvetica18_Character_045,Helvetica18_Character_046,Helvetica18_Character_047, + Helvetica18_Character_048,Helvetica18_Character_049,Helvetica18_Character_050,Helvetica18_Character_051,Helvetica18_Character_052,Helvetica18_Character_053,Helvetica18_Character_054,Helvetica18_Character_055,Helvetica18_Character_056,Helvetica18_Character_057,Helvetica18_Character_058,Helvetica18_Character_059,Helvetica18_Character_060,Helvetica18_Character_061,Helvetica18_Character_062,Helvetica18_Character_063, + Helvetica18_Character_064,Helvetica18_Character_065,Helvetica18_Character_066,Helvetica18_Character_067,Helvetica18_Character_068,Helvetica18_Character_069,Helvetica18_Character_070,Helvetica18_Character_071,Helvetica18_Character_072,Helvetica18_Character_073,Helvetica18_Character_074,Helvetica18_Character_075,Helvetica18_Character_076,Helvetica18_Character_077,Helvetica18_Character_078,Helvetica18_Character_079, + Helvetica18_Character_080,Helvetica18_Character_081,Helvetica18_Character_082,Helvetica18_Character_083,Helvetica18_Character_084,Helvetica18_Character_085,Helvetica18_Character_086,Helvetica18_Character_087,Helvetica18_Character_088,Helvetica18_Character_089,Helvetica18_Character_090,Helvetica18_Character_091,Helvetica18_Character_092,Helvetica18_Character_093,Helvetica18_Character_094,Helvetica18_Character_095, + Helvetica18_Character_096,Helvetica18_Character_097,Helvetica18_Character_098,Helvetica18_Character_099,Helvetica18_Character_100,Helvetica18_Character_101,Helvetica18_Character_102,Helvetica18_Character_103,Helvetica18_Character_104,Helvetica18_Character_105,Helvetica18_Character_106,Helvetica18_Character_107,Helvetica18_Character_108,Helvetica18_Character_109,Helvetica18_Character_110,Helvetica18_Character_111, + Helvetica18_Character_112,Helvetica18_Character_113,Helvetica18_Character_114,Helvetica18_Character_115,Helvetica18_Character_116,Helvetica18_Character_117,Helvetica18_Character_118,Helvetica18_Character_119,Helvetica18_Character_120,Helvetica18_Character_121,Helvetica18_Character_122,Helvetica18_Character_123,Helvetica18_Character_124,Helvetica18_Character_125,Helvetica18_Character_126,Helvetica18_Character_032, + Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032, + Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032, + Helvetica18_Character_160,Helvetica18_Character_161,Helvetica18_Character_162,Helvetica18_Character_163,Helvetica18_Character_164,Helvetica18_Character_165,Helvetica18_Character_166,Helvetica18_Character_167,Helvetica18_Character_168,Helvetica18_Character_169,Helvetica18_Character_170,Helvetica18_Character_171,Helvetica18_Character_172,Helvetica18_Character_173,Helvetica18_Character_174,Helvetica18_Character_175, + Helvetica18_Character_176,Helvetica18_Character_177,Helvetica18_Character_178,Helvetica18_Character_179,Helvetica18_Character_180,Helvetica18_Character_181,Helvetica18_Character_182,Helvetica18_Character_183,Helvetica18_Character_184,Helvetica18_Character_185,Helvetica18_Character_186,Helvetica18_Character_187,Helvetica18_Character_188,Helvetica18_Character_189,Helvetica18_Character_190,Helvetica18_Character_191, + Helvetica18_Character_192,Helvetica18_Character_193,Helvetica18_Character_194,Helvetica18_Character_195,Helvetica18_Character_196,Helvetica18_Character_197,Helvetica18_Character_198,Helvetica18_Character_199,Helvetica18_Character_200,Helvetica18_Character_201,Helvetica18_Character_202,Helvetica18_Character_203,Helvetica18_Character_204,Helvetica18_Character_205,Helvetica18_Character_206,Helvetica18_Character_207, + Helvetica18_Character_208,Helvetica18_Character_209,Helvetica18_Character_210,Helvetica18_Character_211,Helvetica18_Character_212,Helvetica18_Character_213,Helvetica18_Character_214,Helvetica18_Character_215,Helvetica18_Character_216,Helvetica18_Character_217,Helvetica18_Character_218,Helvetica18_Character_219,Helvetica18_Character_220,Helvetica18_Character_221,Helvetica18_Character_222,Helvetica18_Character_223, + Helvetica18_Character_224,Helvetica18_Character_225,Helvetica18_Character_226,Helvetica18_Character_227,Helvetica18_Character_228,Helvetica18_Character_229,Helvetica18_Character_230,Helvetica18_Character_231,Helvetica18_Character_232,Helvetica18_Character_233,Helvetica18_Character_234,Helvetica18_Character_235,Helvetica18_Character_236,Helvetica18_Character_237,Helvetica18_Character_238,Helvetica18_Character_239, + Helvetica18_Character_240,Helvetica18_Character_241,Helvetica18_Character_242,Helvetica18_Character_243,Helvetica18_Character_244,Helvetica18_Character_245,Helvetica18_Character_246,Helvetica18_Character_247,Helvetica18_Character_248,Helvetica18_Character_249,Helvetica18_Character_250,Helvetica18_Character_251,Helvetica18_Character_252,Helvetica18_Character_253,Helvetica18_Character_254,Helvetica18_Character_255,NULL}; + +/* The font structure: */ +const SFG_Font fgFontHelvetica18 = { "-adobe-helvetica-medium-r-normal--18-180-75-75-p-98-iso8859-1", 256, 23, Helvetica18_Character_Map, 0, 5 }; + +static const GLubyte TimesRoman10_Character_000[] = { 8, 0, 0, 0, 0,170, 0,130, 0,130, 0,170, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_001[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_002[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_003[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_004[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_005[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_006[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_007[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_008[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_009[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_010[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_011[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_012[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_013[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_014[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_015[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_016[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_017[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_018[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_019[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_020[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_021[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_022[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_023[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_024[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_025[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_026[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_027[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_028[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_029[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_030[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_031[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_032[] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_033[] = { 3, 0, 0, 0, 0, 64, 0, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_034[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,160,160, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_035[] = { 5, 0, 0, 0, 0, 80, 80,248, 80,248, 80, 80, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_036[] = { 5, 0, 0, 0, 32,224,144, 16, 96,128,144,112, 32, 0, 0}; +static const GLubyte TimesRoman10_Character_037[] = { 8, 0, 0, 0, 0, 68, 42, 42, 86,168,164,126, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_038[] = { 8, 0, 0, 0, 0,118,141,152,116,110, 80, 48, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_039[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64,192, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_040[] = { 4, 0, 0, 32, 64, 64,128,128,128, 64, 64, 32, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_041[] = { 4, 0, 0,128, 64, 64, 32, 32, 32, 64, 64,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_042[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0,160, 64,160, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_043[] = { 6, 0, 0, 0, 0, 32, 32,248, 32, 32, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_044[] = { 3, 0, 0, 64, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_045[] = { 7, 0, 0, 0, 0, 0, 0,120, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_046[] = { 3, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_047[] = { 3, 0, 0, 0, 0,128,128, 64, 64, 64, 32, 32, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_048[] = { 5, 0, 0, 0, 0, 96,144,144,144,144,144, 96, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_049[] = { 5, 0, 0, 0, 0,112, 32, 32, 32, 32, 96, 32, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_050[] = { 5, 0, 0, 0, 0,240, 64, 32, 32, 16,144, 96, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_051[] = { 5, 0, 0, 0, 0,224, 16, 16, 96, 16,144, 96, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_052[] = { 5, 0, 0, 0, 0, 16, 16,248,144, 80, 48, 16, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_053[] = { 5, 0, 0, 0, 0,224,144, 16, 16,224, 64,112, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_054[] = { 5, 0, 0, 0, 0, 96,144,144,144,224, 64, 48, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_055[] = { 5, 0, 0, 0, 0, 64, 64, 64, 32, 32,144,240, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_056[] = { 5, 0, 0, 0, 0, 96,144,144, 96,144,144, 96, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_057[] = { 5, 0, 0, 0, 0,192, 32,112,144,144,144, 96, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_058[] = { 3, 0, 0, 0, 0, 64, 0, 0, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_059[] = { 3, 0, 0, 64, 64, 64, 0, 0, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_060[] = { 5, 0, 0, 0, 0, 16, 32, 64, 32, 16, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_061[] = { 6, 0, 0, 0, 0, 0,248, 0,248, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_062[] = { 5, 0, 0, 0, 0,128, 64, 32, 64,128, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_063[] = { 4, 0, 0, 0, 0, 64, 0, 64, 64, 32,160,224, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_064[] = { 9, 0, 0, 0, 0, 62, 0, 64, 0,146, 0,173, 0,165, 0,165, 0,157, 0, 66, 0, 60, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_065[] = { 8, 0, 0, 0, 0,238, 68,124, 40, 40, 56, 16, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_066[] = { 6, 0, 0, 0, 0,240, 72, 72,112, 72, 72,240, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_067[] = { 7, 0, 0, 0, 0,120,196,128,128,128,196,124, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_068[] = { 7, 0, 0, 0, 0,248, 76, 68, 68, 68, 76,248, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_069[] = { 6, 0, 0, 0, 0,248, 72, 64,112, 64, 72,248, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_070[] = { 6, 0, 0, 0, 0,224, 64, 64,112, 64, 72,248, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_071[] = { 7, 0, 0, 0, 0,120,196,132,156,128,196,124, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_072[] = { 8, 0, 0, 0, 0,238, 68, 68,124, 68, 68,238, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_073[] = { 4, 0, 0, 0, 0,224, 64, 64, 64, 64, 64,224, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_074[] = { 4, 0, 0, 0, 0,192,160, 32, 32, 32, 32,112, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_075[] = { 7, 0, 0, 0, 0,236, 72, 80, 96, 80, 72,236, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_076[] = { 6, 0, 0, 0, 0,248, 72, 64, 64, 64, 64,224, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_077[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0,235,128, 73, 0, 85, 0, 85, 0, 99, 0, 99, 0,227,128, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_078[] = { 8, 0, 0, 0, 0,228, 76, 76, 84, 84,100,238, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_079[] = { 7, 0, 0, 0, 0,120,204,132,132,132,204,120, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_080[] = { 6, 0, 0, 0, 0,224, 64, 64,112, 72, 72,240, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_081[] = { 7, 0, 0, 12, 24,112,204,132,132,132,204,120, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_082[] = { 7, 0, 0, 0, 0,236, 72, 80,112, 72, 72,240, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_083[] = { 5, 0, 0, 0, 0,224,144, 16, 96,192,144,112, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_084[] = { 6, 0, 0, 0, 0,112, 32, 32, 32, 32,168,248, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_085[] = { 8, 0, 0, 0, 0, 56,108, 68, 68, 68, 68,238, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_086[] = { 8, 0, 0, 0, 0, 16, 16, 40, 40,108, 68,238, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_087[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 34, 0, 85, 0, 85, 0,201,128,136,128,221,192, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_088[] = { 8, 0, 0, 0, 0,238, 68, 40, 16, 40, 68,238, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_089[] = { 8, 0, 0, 0, 0, 56, 16, 16, 40, 40, 68,238, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_090[] = { 6, 0, 0, 0, 0,248,136, 64, 32, 16,136,248, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_091[] = { 3, 0, 0,192,128,128,128,128,128,128,128,192, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_092[] = { 3, 0, 0, 0, 0, 32, 32, 64, 64, 64,128,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_093[] = { 3, 0, 0,192, 64, 64, 64, 64, 64, 64, 64,192, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_094[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 32, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_095[] = { 5, 0,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_096[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192,128, 0, 0}; +static const GLubyte TimesRoman10_Character_097[] = { 4, 0, 0, 0, 0,224,160, 96, 32,192, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_098[] = { 5, 0, 0, 0, 0,224,144,144,144,224,128,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_099[] = { 4, 0, 0, 0, 0, 96,128,128,128, 96, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_100[] = { 5, 0, 0, 0, 0,104,144,144,144,112, 16, 48, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_101[] = { 4, 0, 0, 0, 0, 96,128,192,160, 96, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_102[] = { 4, 0, 0, 0, 0,224, 64, 64, 64,224, 64, 48, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_103[] = { 5, 0, 0,224,144, 96, 64,160,160,112, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_104[] = { 5, 0, 0, 0, 0,216,144,144,144,224,128,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_105[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64,192, 0, 64, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_106[] = { 3, 0, 0,128, 64, 64, 64, 64, 64,192, 0, 64, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_107[] = { 5, 0, 0, 0, 0,152,144,224,160,144,128,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_108[] = { 4, 0, 0, 0, 0,224, 64, 64, 64, 64, 64,192, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_109[] = { 8, 0, 0, 0, 0,219,146,146,146,236, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_110[] = { 5, 0, 0, 0, 0,216,144,144,144,224, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_111[] = { 5, 0, 0, 0, 0, 96,144,144,144, 96, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_112[] = { 5, 0, 0,192,128,224,144,144,144,224, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_113[] = { 5, 0, 0, 56, 16,112,144,144,144,112, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_114[] = { 4, 0, 0, 0, 0,224, 64, 64, 96,160, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_115[] = { 4, 0, 0, 0, 0,224, 32, 96,128,224, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_116[] = { 4, 0, 0, 0, 0, 48, 64, 64, 64,224, 64, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_117[] = { 5, 0, 0, 0, 0,104,144,144,144,144, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_118[] = { 5, 0, 0, 0, 0, 32, 96, 80,144,216, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_119[] = { 8, 0, 0, 0, 0, 40,108, 84,146,219, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_120[] = { 6, 0, 0, 0, 0,216, 80, 32, 80,216, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_121[] = { 5, 0, 0,128,128, 64, 96,160,144,184, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_122[] = { 5, 0, 0, 0, 0,240,144, 64, 32,240, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_123[] = { 4, 0, 0, 32, 64, 64, 64,128, 64, 64, 64, 32, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_124[] = { 2, 0, 0,128,128,128,128,128,128,128,128,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_125[] = { 4, 0, 0,128, 64, 64, 64, 32, 64, 64, 64,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_126[] = { 7, 0, 0, 0, 0, 0, 0,152,100, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_127[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_128[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_129[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_130[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_131[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_132[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_133[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_134[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_135[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_136[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_137[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_138[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_139[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_140[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_141[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_142[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_143[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_144[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_145[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_146[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_147[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_148[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_149[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_150[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_151[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_152[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_153[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_154[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_155[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_156[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_157[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_158[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_159[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_160[] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_161[] = { 3, 0, 0, 64, 64, 64, 64, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_162[] = { 5, 0, 0, 0,128,224,144,128,144,112, 16, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_163[] = { 5, 0, 0, 0, 0,240,200, 64,224, 64, 80, 48, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_164[] = { 5, 0, 0, 0, 0, 0,136,112, 80, 80,112,136, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_165[] = { 5, 0, 0, 0, 0,112, 32,248, 32,216, 80,136, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_166[] = { 2, 0, 0, 0, 0,128,128,128, 0,128,128,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_167[] = { 5, 0, 0, 0,224,144, 32, 80,144,160, 64,144,112, 0, 0}; +static const GLubyte TimesRoman10_Character_168[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_169[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 34, 0, 77, 0, 81, 0, 77, 0, 34, 0, 28, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_170[] = { 4, 0, 0, 0, 0, 0, 0,224, 0,160, 32,192, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_171[] = { 5, 0, 0, 0, 0, 0, 80,160,160, 80, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_172[] = { 7, 0, 0, 0, 0, 0, 4, 4,124, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_173[] = { 4, 0, 0, 0, 0, 0, 0,224, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_174[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 34, 0, 85, 0, 89, 0, 93, 0, 34, 0, 28, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_175[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,224, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_176[] = { 4, 0, 0, 0, 0, 0, 0, 0, 96,144,144, 96, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_177[] = { 6, 0, 0, 0, 0,248, 0, 32, 32,248, 32, 32, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_178[] = { 3, 0, 0, 0, 0, 0, 0, 0,224, 64,160, 96, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_179[] = { 3, 0, 0, 0, 0, 0, 0, 0,192, 32, 64,224, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_180[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 64, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_181[] = { 5, 0, 0,128,128,232,144,144,144,144, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_182[] = { 6, 0, 0, 40, 40, 40, 40,104,232,232,232,124, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_183[] = { 2, 0, 0, 0, 0, 0, 0,128, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_184[] = { 4, 0,192, 32, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_185[] = { 3, 0, 0, 0, 0, 0, 0, 0,224, 64,192, 64, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_186[] = { 4, 0, 0, 0, 0, 0, 0,224, 0, 64,160, 64, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_187[] = { 5, 0, 0, 0, 0, 0,160, 80, 80,160, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_188[] = { 8, 0, 0, 0, 0, 68, 62, 44,244, 72,200, 68, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_189[] = { 8, 0, 0, 0, 0, 78, 36, 42,246, 72,200, 68, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_190[] = { 8, 0, 0, 0, 0, 68, 62, 44,212, 40, 72,228, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_191[] = { 4, 0, 0,224,160,128, 64, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_192[] = { 8, 0, 0, 0, 0,238, 68,124, 40, 40, 56, 16, 0, 16, 32}; +static const GLubyte TimesRoman10_Character_193[] = { 8, 0, 0, 0, 0,238, 68,124, 40, 40, 56, 16, 0, 16, 8}; +static const GLubyte TimesRoman10_Character_194[] = { 8, 0, 0, 0, 0,238, 68,124, 40, 40, 56, 16, 0, 40, 16}; +static const GLubyte TimesRoman10_Character_195[] = { 8, 0, 0, 0, 0,238, 68,124, 40, 40, 56, 16, 0, 40, 20}; +static const GLubyte TimesRoman10_Character_196[] = { 8, 0, 0, 0, 0,238, 68,124, 40, 40, 56, 16, 0, 40, 0}; +static const GLubyte TimesRoman10_Character_197[] = { 8, 0, 0, 0, 0,238, 68,124, 40, 40, 56, 16, 16, 40, 16}; +static const GLubyte TimesRoman10_Character_198[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,239, 0, 73, 0,120, 0, 46, 0, 40, 0, 57, 0, 31, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_199[] = { 7, 0, 96, 16, 32,120,196,128,128,128,196,124, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_200[] = { 6, 0, 0, 0, 0,248, 72, 64,112, 64, 72,248, 0, 32, 64}; +static const GLubyte TimesRoman10_Character_201[] = { 6, 0, 0, 0, 0,248, 72, 64,112, 64, 72,248, 0, 32, 16}; +static const GLubyte TimesRoman10_Character_202[] = { 6, 0, 0, 0, 0,248, 72, 64,112, 64, 72,248, 0, 80, 32}; +static const GLubyte TimesRoman10_Character_203[] = { 6, 0, 0, 0, 0,248, 72, 64,112, 64, 72,248, 0, 80, 0}; +static const GLubyte TimesRoman10_Character_204[] = { 4, 0, 0, 0, 0,224, 64, 64, 64, 64, 64,224, 0, 64,128}; +static const GLubyte TimesRoman10_Character_205[] = { 4, 0, 0, 0, 0,224, 64, 64, 64, 64, 64,224, 0, 64, 32}; +static const GLubyte TimesRoman10_Character_206[] = { 4, 0, 0, 0, 0,224, 64, 64, 64, 64, 64,224, 0,160, 64}; +static const GLubyte TimesRoman10_Character_207[] = { 4, 0, 0, 0, 0,224, 64, 64, 64, 64, 64,224, 0,160, 0}; +static const GLubyte TimesRoman10_Character_208[] = { 7, 0, 0, 0, 0,248, 76, 68,228, 68, 76,248, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_209[] = { 8, 0, 0, 0, 0,228, 76, 76, 84, 84,100,238, 0, 80, 40}; +static const GLubyte TimesRoman10_Character_210[] = { 7, 0, 0, 0, 0,120,204,132,132,132,204,120, 0, 32, 64}; +static const GLubyte TimesRoman10_Character_211[] = { 7, 0, 0, 0, 0,120,204,132,132,132,204,120, 0, 16, 8}; +static const GLubyte TimesRoman10_Character_212[] = { 7, 0, 0, 0, 0,120,204,132,132,132,204,120, 0, 80, 32}; +static const GLubyte TimesRoman10_Character_213[] = { 7, 0, 0, 0, 0,120,204,132,132,132,204,120, 0, 80, 40}; +static const GLubyte TimesRoman10_Character_214[] = { 7, 0, 0, 0, 0,120,204,132,132,132,204,120, 0, 80, 0}; +static const GLubyte TimesRoman10_Character_215[] = { 6, 0, 0, 0, 0,136, 80, 32, 80,136, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_216[] = { 8, 0, 0, 0,128,124,102, 82, 82, 74,102, 62, 1, 0, 0}; +static const GLubyte TimesRoman10_Character_217[] = { 8, 0, 0, 0, 0, 56,108, 68, 68, 68, 68,238, 0, 16, 32}; +static const GLubyte TimesRoman10_Character_218[] = { 8, 0, 0, 0, 0, 56,108, 68, 68, 68, 68,238, 0, 16, 8}; +static const GLubyte TimesRoman10_Character_219[] = { 8, 0, 0, 0, 0, 56,108, 68, 68, 68, 68,238, 0, 40, 16}; +static const GLubyte TimesRoman10_Character_220[] = { 8, 0, 0, 0, 0, 56,108, 68, 68, 68, 68,238, 0, 40, 0}; +static const GLubyte TimesRoman10_Character_221[] = { 8, 0, 0, 0, 0, 56, 16, 16, 40, 40, 68,238, 0, 16, 8}; +static const GLubyte TimesRoman10_Character_222[] = { 6, 0, 0, 0, 0,224, 64,112, 72,112, 64,224, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_223[] = { 5, 0, 0, 0, 0,224, 80, 80, 96, 80, 80, 32, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_224[] = { 4, 0, 0, 0, 0,224,160, 96, 32,192, 0, 64,128, 0, 0}; +static const GLubyte TimesRoman10_Character_225[] = { 4, 0, 0, 0, 0,224,160, 96, 32,192, 0, 64, 32, 0, 0}; +static const GLubyte TimesRoman10_Character_226[] = { 4, 0, 0, 0, 0,224,160, 96, 32,192, 0,160, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_227[] = { 4, 0, 0, 0, 0,224,160, 96, 32,192, 0,160, 80, 0, 0}; +static const GLubyte TimesRoman10_Character_228[] = { 4, 0, 0, 0, 0,224,160, 96, 32,192, 0,160, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_229[] = { 4, 0, 0, 0, 0,224,160, 96, 32,192, 64,160, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_230[] = { 6, 0, 0, 0, 0,216,160,112, 40,216, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_231[] = { 4, 0,192, 32, 64, 96,128,128,128, 96, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_232[] = { 4, 0, 0, 0, 0, 96,128,192,160, 96, 0, 64,128, 0, 0}; +static const GLubyte TimesRoman10_Character_233[] = { 4, 0, 0, 0, 0, 96,128,192,160, 96, 0, 64, 32, 0, 0}; +static const GLubyte TimesRoman10_Character_234[] = { 4, 0, 0, 0, 0, 96,128,192,160, 96, 0,160, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_235[] = { 4, 0, 0, 0, 0, 96,128,192,160, 96, 0,160, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_236[] = { 4, 0, 0, 0, 0,224, 64, 64, 64,192, 0, 64,128, 0, 0}; +static const GLubyte TimesRoman10_Character_237[] = { 4, 0, 0, 0, 0,224, 64, 64, 64,192, 0, 64, 32, 0, 0}; +static const GLubyte TimesRoman10_Character_238[] = { 4, 0, 0, 0, 0,224, 64, 64, 64,192, 0,160, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_239[] = { 4, 0, 0, 0, 0,224, 64, 64, 64,192, 0,160, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_240[] = { 5, 0, 0, 0, 0, 96,144,144,144,112,160,112, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_241[] = { 5, 0, 0, 0, 0,216,144,144,144,224, 0,160, 80, 0, 0}; +static const GLubyte TimesRoman10_Character_242[] = { 5, 0, 0, 0, 0, 96,144,144,144, 96, 0, 32, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_243[] = { 5, 0, 0, 0, 0, 96,144,144,144, 96, 0, 64, 32, 0, 0}; +static const GLubyte TimesRoman10_Character_244[] = { 5, 0, 0, 0, 0, 96,144,144,144, 96, 0,160, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_245[] = { 5, 0, 0, 0, 0, 96,144,144,144, 96, 0,160, 80, 0, 0}; +static const GLubyte TimesRoman10_Character_246[] = { 5, 0, 0, 0, 0, 96,144,144,144, 96, 0,160, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_247[] = { 6, 0, 0, 0, 0, 32, 0,248, 0, 32, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_248[] = { 5, 0, 0, 0, 0,224,144,144,144,112, 8, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_249[] = { 5, 0, 0, 0, 0,104,144,144,144,144, 0, 32, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_250[] = { 5, 0, 0, 0, 0,104,144,144,144,144, 0, 64, 32, 0, 0}; +static const GLubyte TimesRoman10_Character_251[] = { 5, 0, 0, 0, 0,104,144,144,144,144, 0, 80, 32, 0, 0}; +static const GLubyte TimesRoman10_Character_252[] = { 5, 0, 0, 0, 0,104,144,144,144,144, 0, 80, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_253[] = { 5, 0, 0,128,192, 64, 96,160,144,184, 0, 32, 16, 0, 0}; +static const GLubyte TimesRoman10_Character_254[] = { 5, 0, 0,192,128,224,144,144,144,224,128,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_255[] = { 5, 0, 0,128,192, 64, 96,160,144,184, 0,160, 0, 0, 0}; + +/* The font characters mapping: */ +static const GLubyte* TimesRoman10_Character_Map[] = {TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032, + TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032, + TimesRoman10_Character_032,TimesRoman10_Character_033,TimesRoman10_Character_034,TimesRoman10_Character_035,TimesRoman10_Character_036,TimesRoman10_Character_037,TimesRoman10_Character_038,TimesRoman10_Character_039,TimesRoman10_Character_040,TimesRoman10_Character_041,TimesRoman10_Character_042,TimesRoman10_Character_043,TimesRoman10_Character_044,TimesRoman10_Character_045,TimesRoman10_Character_046,TimesRoman10_Character_047, + TimesRoman10_Character_048,TimesRoman10_Character_049,TimesRoman10_Character_050,TimesRoman10_Character_051,TimesRoman10_Character_052,TimesRoman10_Character_053,TimesRoman10_Character_054,TimesRoman10_Character_055,TimesRoman10_Character_056,TimesRoman10_Character_057,TimesRoman10_Character_058,TimesRoman10_Character_059,TimesRoman10_Character_060,TimesRoman10_Character_061,TimesRoman10_Character_062,TimesRoman10_Character_063, + TimesRoman10_Character_064,TimesRoman10_Character_065,TimesRoman10_Character_066,TimesRoman10_Character_067,TimesRoman10_Character_068,TimesRoman10_Character_069,TimesRoman10_Character_070,TimesRoman10_Character_071,TimesRoman10_Character_072,TimesRoman10_Character_073,TimesRoman10_Character_074,TimesRoman10_Character_075,TimesRoman10_Character_076,TimesRoman10_Character_077,TimesRoman10_Character_078,TimesRoman10_Character_079, + TimesRoman10_Character_080,TimesRoman10_Character_081,TimesRoman10_Character_082,TimesRoman10_Character_083,TimesRoman10_Character_084,TimesRoman10_Character_085,TimesRoman10_Character_086,TimesRoman10_Character_087,TimesRoman10_Character_088,TimesRoman10_Character_089,TimesRoman10_Character_090,TimesRoman10_Character_091,TimesRoman10_Character_092,TimesRoman10_Character_093,TimesRoman10_Character_094,TimesRoman10_Character_095, + TimesRoman10_Character_096,TimesRoman10_Character_097,TimesRoman10_Character_098,TimesRoman10_Character_099,TimesRoman10_Character_100,TimesRoman10_Character_101,TimesRoman10_Character_102,TimesRoman10_Character_103,TimesRoman10_Character_104,TimesRoman10_Character_105,TimesRoman10_Character_106,TimesRoman10_Character_107,TimesRoman10_Character_108,TimesRoman10_Character_109,TimesRoman10_Character_110,TimesRoman10_Character_111, + TimesRoman10_Character_112,TimesRoman10_Character_113,TimesRoman10_Character_114,TimesRoman10_Character_115,TimesRoman10_Character_116,TimesRoman10_Character_117,TimesRoman10_Character_118,TimesRoman10_Character_119,TimesRoman10_Character_120,TimesRoman10_Character_121,TimesRoman10_Character_122,TimesRoman10_Character_123,TimesRoman10_Character_124,TimesRoman10_Character_125,TimesRoman10_Character_126,TimesRoman10_Character_032, + TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032, + TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032, + TimesRoman10_Character_160,TimesRoman10_Character_161,TimesRoman10_Character_162,TimesRoman10_Character_163,TimesRoman10_Character_164,TimesRoman10_Character_165,TimesRoman10_Character_166,TimesRoman10_Character_167,TimesRoman10_Character_168,TimesRoman10_Character_169,TimesRoman10_Character_170,TimesRoman10_Character_171,TimesRoman10_Character_172,TimesRoman10_Character_173,TimesRoman10_Character_174,TimesRoman10_Character_175, + TimesRoman10_Character_176,TimesRoman10_Character_177,TimesRoman10_Character_178,TimesRoman10_Character_179,TimesRoman10_Character_180,TimesRoman10_Character_181,TimesRoman10_Character_182,TimesRoman10_Character_183,TimesRoman10_Character_184,TimesRoman10_Character_185,TimesRoman10_Character_186,TimesRoman10_Character_187,TimesRoman10_Character_188,TimesRoman10_Character_189,TimesRoman10_Character_190,TimesRoman10_Character_191, + TimesRoman10_Character_192,TimesRoman10_Character_193,TimesRoman10_Character_194,TimesRoman10_Character_195,TimesRoman10_Character_196,TimesRoman10_Character_197,TimesRoman10_Character_198,TimesRoman10_Character_199,TimesRoman10_Character_200,TimesRoman10_Character_201,TimesRoman10_Character_202,TimesRoman10_Character_203,TimesRoman10_Character_204,TimesRoman10_Character_205,TimesRoman10_Character_206,TimesRoman10_Character_207, + TimesRoman10_Character_208,TimesRoman10_Character_209,TimesRoman10_Character_210,TimesRoman10_Character_211,TimesRoman10_Character_212,TimesRoman10_Character_213,TimesRoman10_Character_214,TimesRoman10_Character_215,TimesRoman10_Character_216,TimesRoman10_Character_217,TimesRoman10_Character_218,TimesRoman10_Character_219,TimesRoman10_Character_220,TimesRoman10_Character_221,TimesRoman10_Character_222,TimesRoman10_Character_223, + TimesRoman10_Character_224,TimesRoman10_Character_225,TimesRoman10_Character_226,TimesRoman10_Character_227,TimesRoman10_Character_228,TimesRoman10_Character_229,TimesRoman10_Character_230,TimesRoman10_Character_231,TimesRoman10_Character_232,TimesRoman10_Character_233,TimesRoman10_Character_234,TimesRoman10_Character_235,TimesRoman10_Character_236,TimesRoman10_Character_237,TimesRoman10_Character_238,TimesRoman10_Character_239, + TimesRoman10_Character_240,TimesRoman10_Character_241,TimesRoman10_Character_242,TimesRoman10_Character_243,TimesRoman10_Character_244,TimesRoman10_Character_245,TimesRoman10_Character_246,TimesRoman10_Character_247,TimesRoman10_Character_248,TimesRoman10_Character_249,TimesRoman10_Character_250,TimesRoman10_Character_251,TimesRoman10_Character_252,TimesRoman10_Character_253,TimesRoman10_Character_254,TimesRoman10_Character_255,NULL}; + +/* The font structure: */ +const SFG_Font fgFontTimesRoman10 = { "-adobe-times-medium-r-normal--10-100-75-75-p-54-iso8859-1", 256, 14, TimesRoman10_Character_Map, 0, 4 }; + +static const GLubyte TimesRoman24_Character_000[] = { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 64, 0, 64, 0, 0, 0, 64, 0, 64, 0, 0, 0, 64, 0, 64, 0, 0, 0, 64, 0, 64, 0, 0, 0, 64, 0, 64, 0, 0, 0, 64, 0, 64, 0, 0, 0, 64, 0, 64, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_001[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_002[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_003[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_004[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_005[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_006[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_007[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_008[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_009[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_010[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_011[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_012[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_013[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_014[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_015[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_016[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_017[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_018[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_019[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_020[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_021[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_022[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_023[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_024[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_025[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_026[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_027[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_028[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_029[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_030[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_031[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_032[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_033[] = { 8, 0, 0, 0, 0, 0, 0, 0, 24, 24, 0, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_034[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0,102, 0,102, 0,102, 0,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_035[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 0, 17, 0,127,224,127,224, 8,128, 8,128, 8,128, 63,240, 63,240, 4, 64, 4, 64, 4, 64, 4, 64, 4, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_036[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 63, 0,229,192,196,192,132, 96,132, 96, 4, 96, 4,224, 7,192, 7,128, 30, 0, 60, 0,116, 0,100, 0,100, 32,100, 96, 52,224, 31,128, 4, 0, 4, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_037[] = { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 30, 0, 12, 57, 0, 6, 48,128, 2, 48, 64, 3, 48, 64, 1,152, 64, 0,140,192, 0,199,128, 60, 96, 0,114, 32, 0, 97, 48, 0, 96,152, 0, 96,136, 0, 48,140, 0, 25,254, 0, 15, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_038[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 0, 63,191, 0,112,240,128, 96, 96, 0, 96,224, 0, 96,208, 0, 49,144, 0, 27,136, 0, 15, 12, 0, 7, 31, 0, 7,128, 0, 14,192, 0, 12, 96, 0, 12, 32, 0, 12, 32, 0, 6, 96, 0, 3,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_039[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 12, 4, 28, 24, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_040[] = { 8, 0, 0, 2, 4, 8, 24, 16, 48, 48, 96, 96, 96, 96, 96, 96, 96, 96, 48, 48, 16, 24, 8, 4, 2, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_041[] = { 8, 0, 0, 64, 32, 16, 24, 8, 12, 12, 6, 6, 6, 6, 6, 6, 6, 6, 12, 12, 8, 24, 16, 32, 64, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_042[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 7, 0, 50, 96, 58,224, 7, 0, 58,224, 50, 96, 7, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_043[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0,127,248,127,248, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_044[] = { 7, 0, 0, 0, 0, 48, 24, 8, 56, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_045[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,248,127,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_046[] = { 6, 0, 0, 0, 0, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_047[] = { 7, 0, 0, 0, 0,192,192,192, 64, 96, 96, 32, 48, 48, 16, 24, 24, 8, 12, 12, 4, 6, 6, 6, 6, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_048[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 25,128, 48,192, 48,192,112,224, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 48,192, 25,128, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_049[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,192, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 30, 0, 6, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_050[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,192,127,224, 48, 32, 24, 0, 12, 0, 6, 0, 2, 0, 3, 0, 1,128, 1,128, 0,192, 0,192, 64,192, 64,192, 33,192, 63,128, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_051[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0,115, 0, 97,128, 0,128, 0,192, 0,192, 0,192, 1,192, 3,128, 15, 0, 6, 0, 3, 0, 65,128, 65,128, 35,128, 63, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_052[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,128, 1,128, 1,128, 1,128,127,224,127,224, 97,128, 33,128, 49,128, 17,128, 25,128, 9,128, 13,128, 5,128, 3,128, 3,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_053[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0,113,192, 96,192, 0, 96, 0, 96, 0, 96, 0, 96, 0,224, 1,192, 7,192, 63, 0, 60, 0, 48, 0, 16, 0, 16, 0, 15,192, 15,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_054[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 61,192, 48,192,112, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,192,121,192,119, 0, 48, 0, 56, 0, 24, 0, 12, 0, 7, 0, 1,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_055[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 6, 0, 6, 0, 6, 0, 2, 0, 3, 0, 3, 0, 1, 0, 1,128, 1,128, 0,128, 0,192, 64,192, 96, 96,127,224, 63,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_056[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192,112,192, 96, 96, 96, 96, 96, 96, 32,224, 48,192, 27,128, 15, 0, 15, 0, 25,128, 48,192, 48,192, 48,192, 25,128, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_057[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120, 0, 14, 0, 3, 0, 1,128, 1,192, 0,192, 14,192, 57,224, 48,224, 96, 96, 96, 96, 96, 96, 96, 96, 96,224, 48,192, 59,192, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_058[] = { 6, 0, 0, 0, 0, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_059[] = { 7, 0, 0, 0, 0, 48, 24, 8, 56, 48, 0, 0, 0, 0, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_060[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0,224, 3,128, 14, 0, 56, 0, 96, 0, 56, 0, 14, 0, 3,128, 0,224, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_061[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,248,127,248, 0, 0, 0, 0,127,248,127,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_062[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 56, 0, 14, 0, 3,128, 0,224, 0, 48, 0,224, 3,128, 14, 0, 56, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_063[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 4, 0, 4, 0, 4, 0, 6, 0, 6, 0, 3, 0, 3,128, 1,192, 48,192, 48,192, 32,192, 49,128, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_064[] = { 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 0, 3,131, 0, 6, 0, 0, 12, 0, 0, 24,119,128, 24,222,192, 49,142, 96, 49,134, 32, 49,134, 48, 49,134, 16, 49,131, 16, 48,195, 16, 48,227, 16, 56,127, 16, 24, 59, 48, 28, 0, 32, 14, 0, 96, 7, 0,192, 3,195,128, 0,254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_065[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 31,128, 48, 6, 0, 16, 6, 0, 16, 12, 0, 24, 12, 0, 8, 12, 0, 15,248, 0, 12, 24, 0, 4, 24, 0, 4, 48, 0, 6, 48, 0, 2, 48, 0, 2, 96, 0, 1, 96, 0, 1,192, 0, 1,192, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_066[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,240, 24, 60, 24, 12, 24, 6, 24, 6, 24, 6, 24, 12, 24, 28, 31,240, 24, 32, 24, 24, 24, 12, 24, 12, 24, 12, 24, 24, 24, 56,127,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_067[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 15, 28, 28, 4, 48, 2, 48, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 48, 2, 48, 2, 28, 6, 14, 30, 3,242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_068[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,224, 0, 24, 56, 0, 24, 28, 0, 24, 6, 0, 24, 6, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 6, 0, 24, 6, 0, 24, 28, 0, 24, 56, 0,127,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_069[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,252, 24, 12, 24, 4, 24, 4, 24, 0, 24, 0, 24, 32, 24, 32, 31,224, 24, 32, 24, 32, 24, 0, 24, 0, 24, 8, 24, 8, 24, 24,127,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_070[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 16, 24, 16, 31,240, 24, 16, 24, 16, 24, 0, 24, 0, 24, 8, 24, 8, 24, 24,127,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_071[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 15, 28, 0, 28, 14, 0, 48, 6, 0, 48, 6, 0, 96, 6, 0, 96, 6, 0, 96, 31,128, 96, 0, 0, 96, 0, 0, 96, 0, 0, 96, 0, 0, 48, 2, 0, 48, 2, 0, 28, 6, 0, 14, 30, 0, 3,242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_072[] = { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 15,192, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 31,255, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0,126, 15,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_073[] = { 8, 0, 0, 0, 0, 0, 0, 0,126, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,126, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_074[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0,102, 0, 99, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 15,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_075[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 15,128, 24, 7, 0, 24, 14, 0, 24, 28, 0, 24, 56, 0, 24,112, 0, 24,224, 0, 25,192, 0, 31,128, 0, 31, 0, 0, 25,128, 0, 24,192, 0, 24, 96, 0, 24, 48, 0, 24, 24, 0, 24, 12, 0,126, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_076[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,252, 24, 12, 24, 4, 24, 4, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0,126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_077[] = { 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 16,252, 16, 48, 48, 16, 48, 48, 16,104, 48, 16,104, 48, 16,196, 48, 16,196, 48, 17,132, 48, 17,130, 48, 19, 2, 48, 19, 1, 48, 22, 1, 48, 22, 1, 48, 28, 0,176, 28, 0,176, 24, 0,112,120, 0,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_078[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 6, 0, 16, 14, 0, 16, 14, 0, 16, 26, 0, 16, 50, 0, 16, 50, 0, 16, 98, 0, 16,194, 0, 16,194, 0, 17,130, 0, 19, 2, 0, 19, 2, 0, 22, 2, 0, 28, 2, 0, 28, 2, 0, 24, 2, 0,120, 15,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_079[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 28, 0, 28, 14, 0, 48, 3, 0, 48, 3, 0, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 48, 3, 0, 48, 3, 0, 28, 14, 0, 14, 28, 0, 3,240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_080[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 31,224, 24, 56, 24, 24, 24, 12, 24, 12, 24, 12, 24, 24, 24, 56,127,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_081[] = { 18, 0, 0, 0, 0, 0, 0, 0, 7,128, 0, 28, 0, 0, 56, 0, 0,112, 0, 0,224, 0, 3,240, 0, 14, 28, 0, 28, 14, 0, 48, 3, 0, 48, 3, 0, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 48, 3, 0, 48, 3, 0, 28, 14, 0, 14, 28, 0, 3,240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_082[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 15, 24, 14, 24, 28, 24, 56, 24, 48, 24, 96, 24,224, 25,192, 31,224, 24, 56, 24, 24, 24, 28, 24, 12, 24, 28, 24, 24, 24, 56,127,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_083[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 0,120,192, 96, 96, 64, 48, 64, 48, 0, 48, 0,112, 1,224, 7,192, 15, 0, 60, 0,112, 0, 96, 32, 96, 32, 96, 96, 49,224, 15, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_084[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,224, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 65,130, 65,130, 97,134,127,254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_085[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 24, 0, 12, 4, 0, 24, 4, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0,126, 15,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_086[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,128, 0, 1,128, 0, 1,128, 0, 3,192, 0, 3, 64, 0, 3, 96, 0, 6, 32, 0, 6, 32, 0, 6, 48, 0, 12, 16, 0, 12, 24, 0, 24, 8, 0, 24, 8, 0, 24, 12, 0, 48, 4, 0, 48, 6, 0,252, 31,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_087[] = { 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,131, 0, 1,131, 0, 1,131,128, 3,135,128, 3, 70,128, 3, 70,192, 6, 70, 64, 6, 76, 64, 6, 76, 96, 12, 44, 96, 12, 44, 32, 24, 44, 32, 24, 24, 48, 24, 24, 16, 48, 24, 16, 48, 24, 24,252,126,126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_088[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 15,192, 48, 3,128, 24, 7, 0, 8, 14, 0, 4, 12, 0, 6, 24, 0, 2, 56, 0, 1,112, 0, 0,224, 0, 0,192, 0, 1,192, 0, 3,160, 0, 3, 16, 0, 6, 8, 0, 14, 12, 0, 28, 6, 0,126, 15,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_089[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,224, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 3,192, 3, 64, 6, 96, 6, 32, 12, 48, 28, 16, 24, 24, 56, 8, 48, 12,252, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_090[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,252,112, 12, 56, 4, 24, 4, 28, 0, 12, 0, 14, 0, 7, 0, 3, 0, 3,128, 1,128, 1,192, 0,224, 64, 96, 64,112, 96, 56,127,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_091[] = { 8, 0, 0, 0, 62, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 62, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_092[] = { 7, 0, 0, 0, 0, 0, 0, 0, 6, 6, 4, 12, 12, 8, 24, 24, 16, 48, 48, 32, 96, 96, 64,192,192, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_093[] = { 8, 0, 0, 0,124, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,124, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_094[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 64, 96,192, 32,128, 49,128, 17, 0, 27, 0, 10, 0, 14, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_095[] = { 13, 0, 0, 0, 0,255,248,255,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_096[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48,112, 64, 96, 48, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_097[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,192,125,128, 99,128, 97,128, 97,128, 49,128, 29,128, 7,128, 1,128, 49,128, 51,128, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_098[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 57,192, 48,192, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48,192, 57,192, 55, 0, 48, 0, 48, 0, 48, 0, 48, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_099[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 63,128, 56, 64,112, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 32,192, 49,192, 15,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_100[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 96, 57,192, 48,192, 96,192, 96,192, 96,192, 96,192, 96,192, 96,192, 48,192, 57,192, 14,192, 0,192, 0,192, 0,192, 0,192, 1,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_101[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 63,128, 56, 64,112, 0, 96, 0, 96, 0, 96, 0,127,192, 96,192, 32,192, 49,128, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_102[] = { 7, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,254, 48, 48, 48, 22, 14, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_103[] = { 12, 0, 0, 0, 0, 31,128,120,224, 96, 48, 96, 16, 48, 48, 31,224, 63,128, 48, 0, 24, 0, 31, 0, 25,128, 48,192, 48,192, 48,192, 48,192, 25,128, 15,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_104[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,240, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 56,224, 55,192, 51,128, 48, 0, 48, 0, 48, 0, 48, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_105[] = { 6, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,112, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_106[] = { 6, 0, 0,192,224, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,112, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_107[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,121,240, 48,224, 49,192, 51,128, 55, 0, 54, 0, 60, 0, 52, 0, 50, 0, 51, 0, 49,128, 51,224, 48, 0, 48, 0, 48, 0, 48, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_108[] = { 6, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,112, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_109[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,241,224, 48, 96,192, 48, 96,192, 48, 96,192, 48, 96,192, 48, 96,192, 48, 96,192, 48, 96,192, 48, 96,192, 56,241,192, 55,207,128,115,135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_110[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,240, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 56,224, 55,192,115,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_111[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192, 48,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 57,192, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_112[] = { 12, 0, 0, 0, 0,120, 0, 48, 0, 48, 0, 48, 0, 48, 0, 55, 0, 57,192, 48,192, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48,192, 57,192,119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_113[] = { 12, 0, 0, 0, 0, 1,224, 0,192, 0,192, 0,192, 0,192, 14,192, 57,192, 48,192, 96,192, 96,192, 96,192, 96,192, 96,192, 96,192, 48,192, 57,192, 14,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_114[] = { 8, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 59, 55,115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_115[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 99, 0, 65,128, 1,128, 3,128, 15, 0, 62, 0, 56, 0,112, 0, 97, 0, 51, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_116[] = { 7, 0, 0, 0, 0, 0, 0, 0, 28, 50, 48, 48, 48, 48, 48, 48, 48, 48, 48,254,112, 48, 16, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_117[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14,112, 31, 96, 56,224, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96,112,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_118[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 14, 0, 14, 0, 26, 0, 25, 0, 25, 0, 49, 0, 48,128, 48,128, 96,128, 96,192,241,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_119[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 16, 0, 14, 56, 0, 14, 56, 0, 26, 40, 0, 26,100, 0, 25,100, 0, 49,100, 0, 48,194, 0, 48,194, 0, 96,194, 0, 96,195, 0,241,231,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_120[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,240, 48, 96, 16,192, 25,192, 13,128, 7, 0, 6, 0, 13, 0, 28,128, 24,192, 48, 96,120,240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_121[] = { 11, 0, 0, 0, 0,224, 0,240, 0, 24, 0, 8, 0, 12, 0, 4, 0, 14, 0, 14, 0, 26, 0, 25, 0, 25, 0, 49, 0, 48,128, 48,128, 96,128, 96,192,241,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_122[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,128, 97,128, 48,128, 56, 0, 24, 0, 28, 0, 12, 0, 14, 0, 7, 0, 67, 0, 97,128,127,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_123[] = { 10, 0, 0, 0, 0, 3,128, 6, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 8, 0, 24, 0, 16, 0, 96, 0, 16, 0, 24, 0, 8, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 6, 0, 3,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_124[] = { 6, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_125[] = { 10, 0, 0, 0, 0,112, 0, 24, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 4, 0, 6, 0, 2, 0, 1,128, 2, 0, 6, 0, 4, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 24, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_126[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65,192, 99,224, 62, 48, 28, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_127[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_128[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_129[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_130[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_131[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_132[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_133[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_134[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_135[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_136[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_137[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_138[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_139[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_140[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_141[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_142[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_143[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_144[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_145[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_146[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_147[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_148[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_149[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_150[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_151[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_152[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_153[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_154[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_155[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_156[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_157[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_158[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_159[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_160[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_161[] = { 8, 0, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_162[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 32, 0, 31, 0, 63,128, 56, 64,104, 0,100, 0,100, 0,100, 0, 98, 0, 98, 0, 33,192, 49,192, 15,128, 0,128, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_163[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,115,192, 95, 96, 60, 32, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0,126, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24,192, 12,192, 7,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_164[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 48,119,112, 63,224, 24,192, 48, 96, 48, 96, 48, 96, 48, 96, 24,192, 63,224,119,112, 96, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_165[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,192, 3, 0, 3, 0, 3, 0, 3, 0, 31,224, 3, 0, 31,224, 3, 0, 7,128, 12,128, 12,192, 24, 64, 24, 96, 48, 32,112, 48,248,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_166[] = { 6, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_167[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 25, 0, 24,128, 1,128, 3,128, 7, 0, 14, 0, 29, 0, 56,128, 48,192, 32,192, 33,192, 19,128, 15, 0, 14, 0, 28, 0, 24, 0, 17,128, 9,128, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_168[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102,102, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_169[] = { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,248, 0, 14, 14, 0, 24, 3, 0, 48,225,128, 35,184,128, 98, 12,192, 70, 0, 64, 68, 0, 64, 68, 0, 64, 68, 0, 64, 70, 0, 64, 98, 12,192, 35,152,128, 48,241,128, 24, 3, 0, 14, 14, 0, 3,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_170[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0,118,204,204,124, 12,204,120, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_171[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 32, 6, 96, 12,192, 25,128, 51, 0, 51, 0, 25,128, 12,192, 6, 96, 2, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_172[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24,127,248,127,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_173[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_174[] = { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,248, 0, 14, 14, 0, 24, 3, 0, 48, 1,128, 35,140,128, 97, 24,192, 65, 16, 64, 65, 32, 64, 65,240, 64, 65, 24, 64, 65, 8, 64, 97, 8,192, 33, 24,128, 51,241,128, 24, 3, 0, 14, 14, 0, 3,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_175[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126,126, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_176[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 34, 0, 65, 0, 65, 0, 65, 0, 34, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_177[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,248,127,248, 0, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0,127,248,127,248, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_178[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 68, 32, 48, 16, 8, 12,140, 76, 56, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_179[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,112,136,140, 12, 8, 48, 8,140, 76, 56, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_180[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 24, 14, 6, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_181[] = { 13, 0, 0, 0, 0, 32, 0,112, 0, 96, 0, 32, 0, 32, 0, 46,112, 63, 96, 56,224, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96,112,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_182[] = { 11, 0, 0, 0, 0, 4,128, 4,128, 4,128, 4,128, 4,128, 4,128, 4,128, 4,128, 4,128, 4,128, 4,128, 12,128, 28,128, 60,128, 60,128,124,128,124,128,124,128, 60,128, 60,128, 28,128, 15,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_183[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_184[] = { 8, 0, 60,102, 6, 30, 24, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_185[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 16, 16, 16, 16, 16, 16, 80, 48, 16, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_186[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 60,102,102,102,102,102, 60, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_187[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 51, 0, 25,128, 12,192, 6, 96, 6, 96, 12,192, 25,128, 51, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_188[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 2, 0, 8, 2, 0, 12,127,128, 4, 34, 0, 6, 50, 0, 3, 18, 0, 1, 10, 0,125,142, 0, 16,134, 0, 16,194, 0, 16, 96, 0, 16, 32, 0, 16, 48, 0, 16, 16, 0, 80, 24, 0, 48, 12, 0, 16, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_189[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 63, 0, 8, 17, 0, 12, 8, 0, 4, 12, 0, 6, 4, 0, 3, 2, 0, 1, 3, 0,125,163, 0, 16,147, 0, 16,206, 0, 16, 96, 0, 16, 32, 0, 16, 48, 0, 16, 16, 0, 80, 24, 0, 48, 12, 0, 16, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_190[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 2, 0, 8, 2, 0, 12,127,128, 4, 34, 0, 6, 50, 0, 3, 18, 0, 1, 10, 0,113,142, 0,136,134, 0,140,194, 0, 12, 96, 0, 8, 32, 0, 48, 48, 0, 8, 16, 0,140, 24, 0, 76, 12, 0, 56, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_191[] = { 11, 0, 0, 0, 0, 31, 0, 49,128, 96,128, 97,128, 97,128,112, 0, 56, 0, 24, 0, 28, 0, 12, 0, 12, 0, 4, 0, 4, 0, 0, 0, 0, 0, 6, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_192[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 31,128, 48, 6, 0, 16, 6, 0, 16, 12, 0, 24, 12, 0, 8, 12, 0, 15,248, 0, 12, 24, 0, 4, 24, 0, 4, 48, 0, 6, 48, 0, 2, 48, 0, 2, 96, 0, 1, 96, 0, 1,192, 0, 1,192, 0, 0,128, 0, 0, 0, 0, 0, 32, 0, 0,192, 0, 3,128, 0, 3, 0, 0}; +static const GLubyte TimesRoman24_Character_193[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 31,128, 48, 6, 0, 16, 6, 0, 16, 12, 0, 24, 12, 0, 8, 12, 0, 15,248, 0, 12, 24, 0, 4, 24, 0, 4, 48, 0, 6, 48, 0, 2, 48, 0, 2, 96, 0, 1, 96, 0, 1,192, 0, 1,192, 0, 0,128, 0, 0, 0, 0, 1, 0, 0, 0,192, 0, 0,112, 0, 0, 48, 0}; +static const GLubyte TimesRoman24_Character_194[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 31,128, 48, 6, 0, 16, 6, 0, 16, 12, 0, 24, 12, 0, 8, 12, 0, 15,248, 0, 12, 24, 0, 4, 24, 0, 4, 48, 0, 6, 48, 0, 2, 48, 0, 2, 96, 0, 1, 96, 0, 1,192, 0, 1,192, 0, 0,128, 0, 0, 0, 0, 8, 16, 0, 6, 96, 0, 3,192, 0, 1,128, 0}; +static const GLubyte TimesRoman24_Character_195[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 31,128, 48, 7, 0, 16, 6, 0, 16, 12, 0, 24, 12, 0, 8, 12, 0, 15,248, 0, 12, 24, 0, 4, 24, 0, 4, 48, 0, 6, 48, 0, 2, 48, 0, 2, 96, 0, 1, 96, 0, 1,192, 0, 1,192, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 4,224, 0, 3,144, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_196[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 31,128, 48, 6, 0, 16, 6, 0, 16, 12, 0, 24, 12, 0, 8, 12, 0, 15,248, 0, 12, 24, 0, 4, 24, 0, 4, 48, 0, 6, 48, 0, 2, 48, 0, 2, 96, 0, 1, 96, 0, 1,192, 0, 1,192, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 6, 48, 0, 6, 48, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_197[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 31,128, 48, 6, 0, 16, 6, 0, 16, 12, 0, 24, 12, 0, 8, 12, 0, 15,248, 0, 12, 24, 0, 4, 24, 0, 4, 48, 0, 6, 48, 0, 2, 48, 0, 2, 96, 0, 1, 96, 0, 1,192, 0, 1,192, 0, 0,128, 0, 1,192, 0, 2, 32, 0, 2, 32, 0, 1,192, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_198[] = { 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,249,255,240, 48, 96, 48, 16, 96, 16, 16, 96, 16, 24, 96, 0, 8, 96, 0, 15,224,128, 12, 96,128, 4,127,128, 4, 96,128, 6, 96,128, 2, 96, 0, 2, 96, 0, 1, 96, 32, 1, 96, 32, 1,224, 96, 3,255,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_199[] = { 16, 0, 0, 3,192, 6, 96, 0, 96, 1,224, 1,128, 0,128, 3,240, 15, 28, 28, 4, 48, 2, 48, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 48, 2, 48, 2, 28, 6, 14, 30, 3,242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_200[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,252, 24, 12, 24, 4, 24, 4, 24, 0, 24, 0, 24, 32, 24, 32, 31,224, 24, 32, 24, 32, 24, 0, 24, 0, 24, 8, 24, 8, 24, 24,127,248, 0, 0, 0,128, 3, 0, 14, 0, 12, 0}; +static const GLubyte TimesRoman24_Character_201[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,252, 24, 12, 24, 4, 24, 4, 24, 0, 24, 0, 24, 32, 24, 32, 31,224, 24, 32, 24, 32, 24, 0, 24, 0, 24, 8, 24, 8, 24, 24,127,248, 0, 0, 2, 0, 1,128, 0,224, 0, 96}; +static const GLubyte TimesRoman24_Character_202[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,252, 24, 12, 24, 4, 24, 4, 24, 0, 24, 0, 24, 32, 24, 32, 31,224, 24, 32, 24, 32, 24, 0, 24, 0, 24, 8, 24, 8, 24, 24,127,248, 0, 0, 8, 16, 6, 96, 3,192, 1,128}; +static const GLubyte TimesRoman24_Character_203[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,252, 24, 12, 24, 4, 24, 4, 24, 0, 24, 0, 24, 32, 24, 32, 31,224, 24, 32, 24, 32, 24, 0, 24, 0, 24, 8, 24, 8, 24, 24,127,248, 0, 0, 0, 0, 12,192, 12,192, 0, 0}; +static const GLubyte TimesRoman24_Character_204[] = { 8, 0, 0, 0, 0, 0, 0, 0,126, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,126, 0, 4, 24,112, 96}; +static const GLubyte TimesRoman24_Character_205[] = { 8, 0, 0, 0, 0, 0, 0, 0,126, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,126, 0, 32, 24, 14, 6}; +static const GLubyte TimesRoman24_Character_206[] = { 8, 0, 0, 0, 0, 0, 0, 0, 63, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 63, 0, 64, 51, 30, 12}; +static const GLubyte TimesRoman24_Character_207[] = { 8, 0, 0, 0, 0, 0, 0, 0,126, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,126, 0, 0,102,102, 0}; +static const GLubyte TimesRoman24_Character_208[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,224, 0, 24, 56, 0, 24, 28, 0, 24, 6, 0, 24, 6, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0,255, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 6, 0, 24, 6, 0, 24, 28, 0, 24, 56, 0,127,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_209[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 6, 0, 16, 14, 0, 16, 14, 0, 16, 26, 0, 16, 50, 0, 16, 50, 0, 16, 98, 0, 16,194, 0, 16,194, 0, 17,130, 0, 19, 2, 0, 19, 2, 0, 22, 2, 0, 28, 2, 0, 28, 2, 0, 24, 2, 0,120, 15,128, 0, 0, 0, 0, 0, 0, 2,112, 0, 1,200, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_210[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 28, 0, 28, 14, 0, 48, 3, 0, 48, 3, 0, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 48, 3, 0, 48, 3, 0, 28, 14, 0, 14, 28, 0, 3,240, 0, 0, 0, 0, 0, 32, 0, 0,192, 0, 3,128, 0, 3, 0, 0}; +static const GLubyte TimesRoman24_Character_211[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 28, 0, 28, 14, 0, 48, 3, 0, 48, 3, 0, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 48, 3, 0, 48, 3, 0, 28, 14, 0, 14, 28, 0, 3,240, 0, 0, 0, 0, 0,128, 0, 0, 96, 0, 0, 56, 0, 0, 24, 0}; +static const GLubyte TimesRoman24_Character_212[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 28, 0, 28, 14, 0, 48, 3, 0, 48, 3, 0, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 48, 3, 0, 48, 3, 0, 28, 14, 0, 14, 28, 0, 3,240, 0, 0, 0, 0, 4, 8, 0, 3, 48, 0, 1,224, 0, 0,192, 0}; +static const GLubyte TimesRoman24_Character_213[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 28, 0, 28, 14, 0, 48, 3, 0, 48, 3, 0, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 48, 3, 0, 48, 3, 0, 28, 14, 0, 14, 28, 0, 3,240, 0, 0, 0, 0, 0, 0, 0, 2,112, 0, 1,200, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_214[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 28, 0, 28, 14, 0, 48, 3, 0, 48, 3, 0, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 48, 3, 0, 48, 3, 0, 28, 14, 0, 14, 28, 0, 3,240, 0, 0, 0, 0, 0, 0, 0, 3, 48, 0, 3, 48, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_215[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 16, 48, 48, 24, 96, 12,192, 7,128, 3, 0, 7,128, 12,192, 24, 96, 48, 48, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_216[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19,240, 0, 14, 28, 0, 28, 14, 0, 52, 3, 0, 50, 3, 0, 97, 1,128, 97, 1,128, 96,129,128, 96,129,128, 96, 65,128, 96, 65,128, 96, 33,128, 48, 35, 0, 48, 19, 0, 28, 14, 0, 14, 28, 0, 3,242, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_217[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 24, 0, 12, 4, 0, 24, 4, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0,126, 15,128, 0, 0, 0, 0, 32, 0, 0,192, 0, 3,128, 0, 3, 0, 0}; +static const GLubyte TimesRoman24_Character_218[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 24, 0, 12, 4, 0, 24, 4, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0,126, 15,128, 0, 0, 0, 0,128, 0, 0, 96, 0, 0, 56, 0, 0, 24, 0}; +static const GLubyte TimesRoman24_Character_219[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 24, 0, 12, 4, 0, 24, 4, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0,126, 15,128, 0, 0, 0, 4, 8, 0, 3, 48, 0, 1,224, 0, 0,192, 0}; +static const GLubyte TimesRoman24_Character_220[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 24, 0, 12, 4, 0, 24, 4, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0,126, 15,128, 0, 0, 0, 0, 0, 0, 3, 24, 0, 3, 24, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_221[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,224, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 3,192, 3, 64, 6, 96, 6, 32, 12, 48, 28, 16, 24, 24, 56, 8, 48, 12,252, 63, 0, 0, 1, 0, 0,192, 0,112, 0, 48}; +static const GLubyte TimesRoman24_Character_222[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 24, 0, 24, 0, 24, 0, 31,224, 24, 56, 24, 24, 24, 12, 24, 12, 24, 12, 24, 24, 24, 56, 31,224, 24, 0, 24, 0, 24, 0,126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_223[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,115,128, 54, 64, 54, 96, 48, 96, 48, 96, 48,224, 48,192, 49,192, 51,128, 54, 0, 49,128, 48,192, 48,192, 48,192, 48,192, 25,128, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_224[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,192,125,128, 99,128, 97,128, 97,128, 49,128, 29,128, 7,128, 1,128, 49,128, 51,128, 31, 0, 0, 0, 2, 0, 12, 0, 56, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_225[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,192,125,128, 99,128, 97,128, 97,128, 49,128, 29,128, 7,128, 1,128, 49,128, 51,128, 31, 0, 0, 0, 8, 0, 6, 0, 3,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_226[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,192,125,128, 99,128, 97,128, 97,128, 49,128, 29,128, 7,128, 1,128, 49,128, 51,128, 31, 0, 0, 0, 33, 0, 18, 0, 30, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_227[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,192,125,128, 99,128, 97,128, 97,128, 49,128, 29,128, 7,128, 1,128, 49,128, 51,128, 31, 0, 0, 0, 0, 0, 46, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_228[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,192,125,128, 99,128, 97,128, 97,128, 49,128, 29,128, 7,128, 1,128, 49,128, 51,128, 31, 0, 0, 0, 0, 0, 51, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_229[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,192,125,128, 99,128, 97,128, 97,128, 49,128, 29,128, 7,128, 1,128, 49,128, 51,128, 31, 0, 0, 0, 14, 0, 17, 0, 17, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_230[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,120,125,252, 99,194, 97,128, 97,128, 49,128, 29,128, 7,254, 1,134, 49,134, 51,204, 30,120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_231[] = { 11, 0, 0, 30, 0, 51, 0, 3, 0, 15, 0, 12, 0, 4, 0, 15, 0, 63,128, 56, 64,112, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 32,192, 49,192, 15,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_232[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 63,128, 56, 64,112, 0, 96, 0, 96, 0, 96, 0,127,192, 96,192, 32,192, 49,128, 15, 0, 0, 0, 2, 0, 12, 0, 56, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_233[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 63,128, 56, 64,112, 0, 96, 0, 96, 0, 96, 0,127,192, 96,192, 32,192, 49,128, 15, 0, 0, 0, 8, 0, 6, 0, 3,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_234[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 63,128, 56, 64,112, 0, 96, 0, 96, 0, 96, 0,127,192, 96,192, 32,192, 49,128, 15, 0, 0, 0, 16,128, 9, 0, 15, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_235[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 63,128, 56, 64,112, 0, 96, 0, 96, 0, 96, 0,127,192, 96,192, 32,192, 49,128, 15, 0, 0, 0, 0, 0, 25,128, 25,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_236[] = { 6, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,112, 0, 8, 48,224,192, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_237[] = { 6, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,112, 0, 64, 48, 28, 12, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_238[] = { 6, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,112, 0,132, 72,120, 48, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_239[] = { 6, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,112, 0, 0,204,204, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_240[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192, 48,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 57,192, 15,128, 99, 0, 30, 0, 15, 0, 56,192, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_241[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,240, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 56,224, 55,192,115,128, 0, 0, 0, 0, 19,128, 14, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_242[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192, 48,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 57,192, 15, 0, 0, 0, 1, 0, 6, 0, 28, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_243[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192, 48,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 57,192, 15, 0, 0, 0, 4, 0, 3, 0, 1,192, 0,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_244[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192, 48,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 57,192, 15, 0, 0, 0, 16,128, 9, 0, 15, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_245[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192, 48,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 57,192, 15, 0, 0, 0, 0, 0, 19,128, 14, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_246[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192, 48,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 57,192, 15, 0, 0, 0, 0, 0, 25,128, 25,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_247[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 0,127,248,127,248, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_248[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0,111, 0, 57,192, 56,192,104, 96,108, 96,100, 96,102, 96, 98, 96, 99, 96, 49,192, 57,192, 15, 96, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_249[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14,112, 31, 96, 56,224, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96,112,224, 0, 0, 1, 0, 6, 0, 28, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_250[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14,112, 31, 96, 56,224, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96,112,224, 0, 0, 4, 0, 3, 0, 1,192, 0,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_251[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14,112, 31, 96, 56,224, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96,112,224, 0, 0, 16,128, 9, 0, 15, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_252[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14,112, 31, 96, 56,224, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96,112,224, 0, 0, 0, 0, 25,128, 25,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_253[] = { 11, 0, 0, 0, 0,224, 0,240, 0, 24, 0, 8, 0, 12, 0, 4, 0, 14, 0, 14, 0, 26, 0, 25, 0, 25, 0, 49, 0, 48,128, 48,128, 96,128, 96,192,241,224, 0, 0, 8, 0, 6, 0, 3,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_254[] = { 12, 0, 0, 0, 0,120, 0, 48, 0, 48, 0, 48, 0, 48, 0, 55, 0, 57,192, 48,192, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48,192, 57,192, 55, 0, 48, 0, 48, 0, 48, 0, 48, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_255[] = { 11, 0, 0, 0, 0,224, 0,240, 0, 24, 0, 8, 0, 12, 0, 4, 0, 14, 0, 14, 0, 26, 0, 25, 0, 25, 0, 49, 0, 48,128, 48,128, 96,128, 96,192,241,224, 0, 0, 0, 0, 51, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +/* The font characters mapping: */ +static const GLubyte* TimesRoman24_Character_Map[] = {TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032, + TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032, + TimesRoman24_Character_032,TimesRoman24_Character_033,TimesRoman24_Character_034,TimesRoman24_Character_035,TimesRoman24_Character_036,TimesRoman24_Character_037,TimesRoman24_Character_038,TimesRoman24_Character_039,TimesRoman24_Character_040,TimesRoman24_Character_041,TimesRoman24_Character_042,TimesRoman24_Character_043,TimesRoman24_Character_044,TimesRoman24_Character_045,TimesRoman24_Character_046,TimesRoman24_Character_047, + TimesRoman24_Character_048,TimesRoman24_Character_049,TimesRoman24_Character_050,TimesRoman24_Character_051,TimesRoman24_Character_052,TimesRoman24_Character_053,TimesRoman24_Character_054,TimesRoman24_Character_055,TimesRoman24_Character_056,TimesRoman24_Character_057,TimesRoman24_Character_058,TimesRoman24_Character_059,TimesRoman24_Character_060,TimesRoman24_Character_061,TimesRoman24_Character_062,TimesRoman24_Character_063, + TimesRoman24_Character_064,TimesRoman24_Character_065,TimesRoman24_Character_066,TimesRoman24_Character_067,TimesRoman24_Character_068,TimesRoman24_Character_069,TimesRoman24_Character_070,TimesRoman24_Character_071,TimesRoman24_Character_072,TimesRoman24_Character_073,TimesRoman24_Character_074,TimesRoman24_Character_075,TimesRoman24_Character_076,TimesRoman24_Character_077,TimesRoman24_Character_078,TimesRoman24_Character_079, + TimesRoman24_Character_080,TimesRoman24_Character_081,TimesRoman24_Character_082,TimesRoman24_Character_083,TimesRoman24_Character_084,TimesRoman24_Character_085,TimesRoman24_Character_086,TimesRoman24_Character_087,TimesRoman24_Character_088,TimesRoman24_Character_089,TimesRoman24_Character_090,TimesRoman24_Character_091,TimesRoman24_Character_092,TimesRoman24_Character_093,TimesRoman24_Character_094,TimesRoman24_Character_095, + TimesRoman24_Character_096,TimesRoman24_Character_097,TimesRoman24_Character_098,TimesRoman24_Character_099,TimesRoman24_Character_100,TimesRoman24_Character_101,TimesRoman24_Character_102,TimesRoman24_Character_103,TimesRoman24_Character_104,TimesRoman24_Character_105,TimesRoman24_Character_106,TimesRoman24_Character_107,TimesRoman24_Character_108,TimesRoman24_Character_109,TimesRoman24_Character_110,TimesRoman24_Character_111, + TimesRoman24_Character_112,TimesRoman24_Character_113,TimesRoman24_Character_114,TimesRoman24_Character_115,TimesRoman24_Character_116,TimesRoman24_Character_117,TimesRoman24_Character_118,TimesRoman24_Character_119,TimesRoman24_Character_120,TimesRoman24_Character_121,TimesRoman24_Character_122,TimesRoman24_Character_123,TimesRoman24_Character_124,TimesRoman24_Character_125,TimesRoman24_Character_126,TimesRoman24_Character_032, + TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032, + TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032, + TimesRoman24_Character_160,TimesRoman24_Character_161,TimesRoman24_Character_162,TimesRoman24_Character_163,TimesRoman24_Character_164,TimesRoman24_Character_165,TimesRoman24_Character_166,TimesRoman24_Character_167,TimesRoman24_Character_168,TimesRoman24_Character_169,TimesRoman24_Character_170,TimesRoman24_Character_171,TimesRoman24_Character_172,TimesRoman24_Character_173,TimesRoman24_Character_174,TimesRoman24_Character_175, + TimesRoman24_Character_176,TimesRoman24_Character_177,TimesRoman24_Character_178,TimesRoman24_Character_179,TimesRoman24_Character_180,TimesRoman24_Character_181,TimesRoman24_Character_182,TimesRoman24_Character_183,TimesRoman24_Character_184,TimesRoman24_Character_185,TimesRoman24_Character_186,TimesRoman24_Character_187,TimesRoman24_Character_188,TimesRoman24_Character_189,TimesRoman24_Character_190,TimesRoman24_Character_191, + TimesRoman24_Character_192,TimesRoman24_Character_193,TimesRoman24_Character_194,TimesRoman24_Character_195,TimesRoman24_Character_196,TimesRoman24_Character_197,TimesRoman24_Character_198,TimesRoman24_Character_199,TimesRoman24_Character_200,TimesRoman24_Character_201,TimesRoman24_Character_202,TimesRoman24_Character_203,TimesRoman24_Character_204,TimesRoman24_Character_205,TimesRoman24_Character_206,TimesRoman24_Character_207, + TimesRoman24_Character_208,TimesRoman24_Character_209,TimesRoman24_Character_210,TimesRoman24_Character_211,TimesRoman24_Character_212,TimesRoman24_Character_213,TimesRoman24_Character_214,TimesRoman24_Character_215,TimesRoman24_Character_216,TimesRoman24_Character_217,TimesRoman24_Character_218,TimesRoman24_Character_219,TimesRoman24_Character_220,TimesRoman24_Character_221,TimesRoman24_Character_222,TimesRoman24_Character_223, + TimesRoman24_Character_224,TimesRoman24_Character_225,TimesRoman24_Character_226,TimesRoman24_Character_227,TimesRoman24_Character_228,TimesRoman24_Character_229,TimesRoman24_Character_230,TimesRoman24_Character_231,TimesRoman24_Character_232,TimesRoman24_Character_233,TimesRoman24_Character_234,TimesRoman24_Character_235,TimesRoman24_Character_236,TimesRoman24_Character_237,TimesRoman24_Character_238,TimesRoman24_Character_239, + TimesRoman24_Character_240,TimesRoman24_Character_241,TimesRoman24_Character_242,TimesRoman24_Character_243,TimesRoman24_Character_244,TimesRoman24_Character_245,TimesRoman24_Character_246,TimesRoman24_Character_247,TimesRoman24_Character_248,TimesRoman24_Character_249,TimesRoman24_Character_250,TimesRoman24_Character_251,TimesRoman24_Character_252,TimesRoman24_Character_253,TimesRoman24_Character_254,TimesRoman24_Character_255,NULL}; + +/* The font structure: */ +const SFG_Font fgFontTimesRoman24 = { "-adobe-times-medium-r-normal--24-240-75-75-p-124-iso8859-1", 256, 29, TimesRoman24_Character_Map, 0, 7 }; + diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_gamemode.c b/tests/Box2D_v2.2.1/freeglut/freeglut_gamemode.c new file mode 100755 index 0000000000000..db776b512ba21 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_gamemode.c @@ -0,0 +1,594 @@ +/* + * freeglut_gamemode.c + * + * The game mode handling code. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 16 1999 + * + * 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 + * PAWEL W. OLSZTA 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 "freeglut.h" +#include "freeglut_internal.h" + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * glutGameModeString() -- missing + * glutEnterGameMode() -- X11 version + * glutLeaveGameMode() -- is that correct? + * glutGameModeGet() -- is that correct? + */ + + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +/* + * Remembers the current visual settings, so that + * we can change them and restore later... + */ +static void fghRememberState( void ) +{ +#if TARGET_HOST_POSIX_X11 + + /* + * This highly depends on the XFree86 extensions, + * not approved as X Consortium standards + */ +# ifdef X_XF86VidModeGetModeLine + + + /* + * Remember the current ViewPort location of the screen to be able to + * restore the ViewPort on LeaveGameMode(): + */ + if( !XF86VidModeGetViewPort( + fgDisplay.Display, + fgDisplay.Screen, + &fgDisplay.DisplayViewPortX, + &fgDisplay.DisplayViewPortY ) ) + fgWarning( "XF86VidModeGetViewPort failed" ); + + /* + * Remember the current pointer location before going fullscreen + * for restoring it later: + */ + { + Window junk_window; + unsigned int mask; + + XQueryPointer( + fgDisplay.Display, fgDisplay.RootWindow, + &junk_window, &junk_window, + &fgDisplay.DisplayPointerX, &fgDisplay.DisplayPointerY, + &fgDisplay.DisplayPointerX, &fgDisplay.DisplayPointerY, &mask + ); + } + + /* Query the current display settings: */ + fgDisplay.DisplayModeValid = + XF86VidModeGetModeLine( + fgDisplay.Display, + fgDisplay.Screen, + &fgDisplay.DisplayModeClock, + &fgDisplay.DisplayMode + ); + + if( !fgDisplay.DisplayModeValid ) + fgWarning( "XF86VidModeGetModeLine failed" ); + +# else + /* + * XXX warning fghRememberState: missing XFree86 video mode extensions, + * XXX game mode will not change screen resolution when activated + */ +# endif + +#elif TARGET_HOST_MS_WINDOWS + +/* DEVMODE devMode; */ + + /* Grab the current desktop settings... */ + +/* hack to get around my stupid cross-gcc headers */ +#define FREEGLUT_ENUM_CURRENT_SETTINGS -1 + + EnumDisplaySettings( NULL, FREEGLUT_ENUM_CURRENT_SETTINGS, + &fgDisplay.DisplayMode ); + + /* Make sure we will be restoring all settings needed */ + fgDisplay.DisplayMode.dmFields |= + DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; + +#endif +} + +/* + * Restores the previously remembered visual settings + */ +static void fghRestoreState( void ) +{ +#if TARGET_HOST_POSIX_X11 + +# ifdef X_XF86VidModeGetAllModeLines + /* Restore the remembered pointer position: */ + XWarpPointer( + fgDisplay.Display, None, fgDisplay.RootWindow, 0, 0, 0, 0, + fgDisplay.DisplayPointerX, fgDisplay.DisplayPointerY + ); + + /* + * This highly depends on the XFree86 extensions, + * not approved as X Consortium standards + */ + + if( fgDisplay.DisplayModeValid ) + { + XF86VidModeModeInfo** displayModes; + int i, displayModesCount; + + if( !XF86VidModeGetAllModeLines( + fgDisplay.Display, + fgDisplay.Screen, + &displayModesCount, + &displayModes ) ) + { + fgWarning( "XF86VidModeGetAllModeLines failed" ); + return; + } + + + /* + * Check every of the modes looking for one that matches our demands. + * If we find one, switch to it and restore the remembered viewport. + */ + for( i = 0; i < displayModesCount; i++ ) + { + if(displayModes[ i ]->hdisplay == fgDisplay.DisplayMode.hdisplay && + displayModes[ i ]->vdisplay == fgDisplay.DisplayMode.vdisplay && + displayModes[ i ]->dotclock == fgDisplay.DisplayModeClock ) + { + if( !XF86VidModeSwitchToMode( + fgDisplay.Display, + fgDisplay.Screen, + displayModes[ i ] ) ) + { + fgWarning( "XF86VidModeSwitchToMode failed" ); + break; + } + + if( !XF86VidModeSetViewPort( + fgDisplay.Display, + fgDisplay.Screen, + fgDisplay.DisplayViewPortX, + fgDisplay.DisplayViewPortY ) ) + fgWarning( "XF86VidModeSetViewPort failed" ); + + + /* + * For the case this would be the last X11 call the application + * calls exit() we've to flush the X11 output queue to have the + * commands sent to the X server before the application exits. + */ + XFlush( fgDisplay.Display ); + + break; + } + } + XFree( displayModes ); + } + +# else + /* + * XXX warning fghRestoreState: missing XFree86 video mode extensions, + * XXX game mode will not change screen resolution when activated + */ +# endif + +#elif TARGET_HOST_MS_WINDOWS + + /* Restore the previously rememebered desktop display settings */ + ChangeDisplaySettings( &fgDisplay.DisplayMode, 0 ); + +#endif +} + +#if TARGET_HOST_POSIX_X11 +#ifdef X_XF86VidModeGetAllModeLines + +/* + * Checks a single display mode settings against user's preferences. + */ +static GLboolean fghCheckDisplayMode( int width, int height, int depth, int refresh ) +{ + /* The desired values should be stored in fgState structure... */ + return ( width == fgState.GameModeSize.X ) && + ( height == fgState.GameModeSize.Y ) && + ( depth == fgState.GameModeDepth ) && + ( refresh == fgState.GameModeRefresh ); +} + +/* + * Checks all display modes settings against user's preferences. + * Returns the mode number found or -1 if none could be found. + */ +static int fghCheckDisplayModes( GLboolean exactMatch, int displayModesCount, XF86VidModeModeInfo** displayModes ) +{ + int i; + for( i = 0; i < displayModesCount; i++ ) + { + /* Compute the displays refresh rate, dotclock comes in kHz. */ + int refresh = ( displayModes[ i ]->dotclock * 1000 ) / + ( displayModes[ i ]->htotal * displayModes[ i ]->vtotal ); + + if( fghCheckDisplayMode( displayModes[ i ]->hdisplay, + displayModes[ i ]->vdisplay, + fgState.GameModeDepth, + ( exactMatch ? refresh : fgState.GameModeRefresh ) ) ) { + return i; + } + } + return -1; +} + +#endif +#endif + +/* + * Changes the current display mode to match user's settings + */ +static GLboolean fghChangeDisplayMode( GLboolean haveToTest ) +{ + GLboolean success = GL_FALSE; +#if TARGET_HOST_POSIX_X11 + + /* + * This highly depends on the XFree86 extensions, + * not approved as X Consortium standards + */ +# ifdef X_XF86VidModeGetAllModeLines + + /* + * This is also used by applcations which check modes by calling + * glutGameModeGet(GLUT_GAME_MODE_POSSIBLE), so allow the check: + */ + if( haveToTest || fgDisplay.DisplayModeValid ) + { + XF86VidModeModeInfo** displayModes; + int i, displayModesCount; + + if( !XF86VidModeGetAllModeLines( + fgDisplay.Display, + fgDisplay.Screen, + &displayModesCount, + &displayModes ) ) + { + fgWarning( "XF86VidModeGetAllModeLines failed" ); + return success; + } + + + /* + * Check every of the modes looking for one that matches our demands, + * ignoring the refresh rate if no exact match could be found. + */ + i = fghCheckDisplayModes( GL_TRUE, displayModesCount, displayModes ); + if( i < 0 ) { + i = fghCheckDisplayModes( GL_FALSE, displayModesCount, displayModes ); + } + success = ( i < 0 ) ? GL_FALSE : GL_TRUE; + + if( !haveToTest && success ) { + if( !XF86VidModeSwitchToMode( + fgDisplay.Display, + fgDisplay.Screen, + displayModes[ i ] ) ) + fgWarning( "XF86VidModeSwitchToMode failed" ); + } + + XFree( displayModes ); + } + +# else + + /* + * XXX warning fghChangeDisplayMode: missing XFree86 video mode extensions, + * XXX game mode will not change screen resolution when activated + */ + success = GL_TRUE; + +# endif + +#elif TARGET_HOST_MS_WINDOWS + + DEVMODE devMode; + char *fggmstr = NULL; + + success = GL_FALSE; + + EnumDisplaySettings( NULL, -1, &devMode ); + devMode.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; + + devMode.dmPelsWidth = fgState.GameModeSize.X; + devMode.dmPelsHeight = fgState.GameModeSize.Y; + devMode.dmBitsPerPel = fgState.GameModeDepth; + devMode.dmDisplayFrequency = fgState.GameModeRefresh; + devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; + + switch ( ChangeDisplaySettingsEx(NULL, &devMode, NULL, haveToTest ? CDS_TEST : CDS_FULLSCREEN , NULL) ) + { + case DISP_CHANGE_SUCCESSFUL: + success = GL_TRUE; + + /* update vars in case if windows switched to proper mode */ + EnumDisplaySettings( NULL, FREEGLUT_ENUM_CURRENT_SETTINGS, &devMode ); + fgState.GameModeSize.X = devMode.dmPelsWidth; + fgState.GameModeSize.Y = devMode.dmPelsHeight; + fgState.GameModeDepth = devMode.dmBitsPerPel; + fgState.GameModeRefresh = devMode.dmDisplayFrequency; + break; + case DISP_CHANGE_RESTART: + fggmstr = "The computer must be restarted for the graphics mode to work."; + break; + case DISP_CHANGE_BADFLAGS: + fggmstr = "An invalid set of flags was passed in."; + break; + case DISP_CHANGE_BADPARAM: + fggmstr = "An invalid parameter was passed in. This can include an invalid flag or combination of flags."; + break; + case DISP_CHANGE_FAILED: + fggmstr = "The display driver failed the specified graphics mode."; + break; + case DISP_CHANGE_BADMODE: + fggmstr = "The graphics mode is not supported."; + break; + default: + fggmstr = "Unknown error in graphics mode???"; /* dunno if it is possible,MSDN does not mention any other error */ + break; + } + + if ( !success ) + fgWarning(fggmstr); /* I'd rather get info whats going on in my program than wonder about */ + /* magic happenings behind my back, its lib for devels at last ;) */ +#endif + + return success; +} + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Sets the game mode display string + */ +void FGAPIENTRY glutGameModeString( const char* string ) +{ + int width = 640, height = 480, depth = 16, refresh = 72; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGameModeString" ); + + /* + * This one seems a bit easier than glutInitDisplayString. The bad thing + * about it that I was unable to find the game mode string definition, so + * that I assumed it is: "[width]x[height]:[depth]@[refresh rate]", which + * appears in all GLUT game mode programs I have seen to date. + */ + if( sscanf( string, "%ix%i:%i@%i", &width, &height, &depth, &refresh ) != + 4 ) + if( sscanf( string, "%ix%i:%i", &width, &height, &depth ) != 3 ) + if( sscanf( string, "%ix%i@%i", &width, &height, &refresh ) != 3 ) + if( sscanf( string, "%ix%i", &width, &height ) != 2 ) + if( sscanf( string, ":%i@%i", &depth, &refresh ) != 2 ) + if( sscanf( string, ":%i", &depth ) != 1 ) + if( sscanf( string, "@%i", &refresh ) != 1 ) + fgWarning( + "unable to parse game mode string `%s'", + string + ); + + /* Hopefully it worked, and if not, we still have the default values */ + fgState.GameModeSize.X = width; + fgState.GameModeSize.Y = height; + fgState.GameModeDepth = depth; + fgState.GameModeRefresh = refresh; +} + +/* + * Enters the game mode + */ +int FGAPIENTRY glutEnterGameMode( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutEnterGameMode" ); + + if( fgStructure.GameModeWindow ) + fgAddToWindowDestroyList( fgStructure.GameModeWindow ); + else + fghRememberState( ); + + if( ! fghChangeDisplayMode( GL_FALSE ) ) + { + fgWarning( "failed to change screen settings" ); + return 0; + } + + fgStructure.GameModeWindow = fgCreateWindow( + NULL, "FREEGLUT", GL_TRUE, 0, 0, + GL_TRUE, fgState.GameModeSize.X, fgState.GameModeSize.Y, + GL_TRUE, GL_FALSE + ); + + fgStructure.GameModeWindow->State.Width = fgState.GameModeSize.X; + fgStructure.GameModeWindow->State.Height = fgState.GameModeSize.Y; + fgStructure.GameModeWindow->State.NeedToResize = GL_TRUE; + +#if TARGET_HOST_POSIX_X11 + + /* + * Sync needed to avoid a real race, the Xserver must have really created + * the window before we can grab the pointer into it: + */ + XSync( fgDisplay.Display, False ); + + /* + * Grab the pointer to confine it into the window after the calls to + * XWrapPointer() which ensure that the pointer really enters the window. + * + * We also need to wait here until XGrabPointer() returns GrabSuccess, + * otherwise the new window is not viewable yet and if the next function + * (XSetInputFocus) is called with a not yet viewable window, it will exit + * the application which we have to aviod, so wait until it's viewable: + */ + while( GrabSuccess != XGrabPointer( + fgDisplay.Display, fgStructure.GameModeWindow->Window.Handle, + TRUE, + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask + | PointerMotionMask, + GrabModeAsync, GrabModeAsync, + fgStructure.GameModeWindow->Window.Handle, None, CurrentTime) ) + usleep( 100 ); + + /* + * Change input focus to the new window. This will exit the application + * if the new window is not viewable yet, see the XGrabPointer loop above. + */ + XSetInputFocus( + fgDisplay.Display, + fgStructure.GameModeWindow->Window.Handle, + RevertToNone, + CurrentTime + ); + + /* Move the Pointer to the middle of the fullscreen window */ + XWarpPointer( + fgDisplay.Display, + None, + fgDisplay.RootWindow, + 0, 0, 0, 0, + fgState.GameModeSize.X/2, fgState.GameModeSize.Y/2 + ); + +# ifdef X_XF86VidModeSetViewPort + + if( fgDisplay.DisplayModeValid ) + { + int x, y; + Window child; + + /* Change to viewport to the window topleft edge: */ + if( !XF86VidModeSetViewPort( fgDisplay.Display, fgDisplay.Screen, 0, 0 ) ) + fgWarning( "XF86VidModeSetViewPort failed" ); + + /* + * Final window repositioning: It could be avoided using an undecorated + * window using override_redirect, but this * would possily require + * more changes and investigation. + */ + + /* Get the current postion of the drawable area on screen */ + XTranslateCoordinates( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + fgDisplay.RootWindow, + 0, 0, &x, &y, + &child + ); + + /* Move the decorataions out of the topleft corner of the display */ + XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, + -x, -y); + } + +#endif + + /* Grab the keyboard, too */ + XGrabKeyboard( + fgDisplay.Display, + fgStructure.GameModeWindow->Window.Handle, + FALSE, + GrabModeAsync, GrabModeAsync, + CurrentTime + ); + +#endif + + return fgStructure.GameModeWindow->ID; +} + +/* + * Leaves the game mode + */ +void FGAPIENTRY glutLeaveGameMode( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLeaveGameMode" ); + + freeglut_return_if_fail( fgStructure.GameModeWindow ); + + fgAddToWindowDestroyList( fgStructure.GameModeWindow ); + fgStructure.GameModeWindow = NULL; + +#if TARGET_HOST_POSIX_X11 + + XUngrabPointer( fgDisplay.Display, CurrentTime ); + XUngrabKeyboard( fgDisplay.Display, CurrentTime ); + +#endif + + fghRestoreState(); +} + +/* + * Returns information concerning the freeglut game mode + */ +int FGAPIENTRY glutGameModeGet( GLenum eWhat ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGameModeGet" ); + + switch( eWhat ) + { + case GLUT_GAME_MODE_ACTIVE: + return !!fgStructure.GameModeWindow; + + case GLUT_GAME_MODE_POSSIBLE: + return fghChangeDisplayMode( GL_TRUE ); + + case GLUT_GAME_MODE_WIDTH: + return fgState.GameModeSize.X; + + case GLUT_GAME_MODE_HEIGHT: + return fgState.GameModeSize.Y; + + case GLUT_GAME_MODE_PIXEL_DEPTH: + return fgState.GameModeDepth; + + case GLUT_GAME_MODE_REFRESH_RATE: + return fgState.GameModeRefresh; + + case GLUT_GAME_MODE_DISPLAY_CHANGED: + /* + * This is true if the game mode has been activated successfully.. + */ + return !!fgStructure.GameModeWindow; + } + + fgWarning( "Unknown gamemode get: %d", eWhat ); + return -1; +} + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_geometry.c b/tests/Box2D_v2.2.1/freeglut/freeglut_geometry.c new file mode 100755 index 0000000000000..1b6cb7d89ad8c --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_geometry.c @@ -0,0 +1,1215 @@ +/* + * freeglut_geometry.c + * + * Freeglut geometry rendering methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Fri Dec 3 1999 + * + * 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 + * PAWEL W. OLSZTA 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 "freeglut.h" +#include "freeglut_internal.h" + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * Following functions have been contributed by Andreas Umbach. + * + * glutWireCube() -- looks OK + * glutSolidCube() -- OK + * + * Those functions have been implemented by John Fay. + * + * glutWireTorus() -- looks OK + * glutSolidTorus() -- looks OK + * glutWireDodecahedron() -- looks OK + * glutSolidDodecahedron() -- looks OK + * glutWireOctahedron() -- looks OK + * glutSolidOctahedron() -- looks OK + * glutWireTetrahedron() -- looks OK + * glutSolidTetrahedron() -- looks OK + * glutWireIcosahedron() -- looks OK + * glutSolidIcosahedron() -- looks OK + * + * The Following functions have been updated by Nigel Stewart, based + * on FreeGLUT 2.0.0 implementations: + * + * glutWireSphere() -- looks OK + * glutSolidSphere() -- looks OK + * glutWireCone() -- looks OK + * glutSolidCone() -- looks OK + */ + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Draws a wireframed cube. Code contributed by Andreas Umbach + */ +void FGAPIENTRY glutWireCube( GLdouble dSize ) +{ + double size = dSize * 0.5; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" ); + +# define V(a,b,c) glVertex3d( a size, b size, c size ); +# define N(a,b,c) glNormal3d( a, b, c ); + + /* PWO: I dared to convert the code to use macros... */ + glBegin( GL_LINE_LOOP ); N( 1.0, 0.0, 0.0); V(+,-,+); V(+,-,-); V(+,+,-); V(+,+,+); glEnd(); + glBegin( GL_LINE_LOOP ); N( 0.0, 1.0, 0.0); V(+,+,+); V(+,+,-); V(-,+,-); V(-,+,+); glEnd(); + glBegin( GL_LINE_LOOP ); N( 0.0, 0.0, 1.0); V(+,+,+); V(-,+,+); V(-,-,+); V(+,-,+); glEnd(); + glBegin( GL_LINE_LOOP ); N(-1.0, 0.0, 0.0); V(-,-,+); V(-,+,+); V(-,+,-); V(-,-,-); glEnd(); + glBegin( GL_LINE_LOOP ); N( 0.0,-1.0, 0.0); V(-,-,+); V(-,-,-); V(+,-,-); V(+,-,+); glEnd(); + glBegin( GL_LINE_LOOP ); N( 0.0, 0.0,-1.0); V(-,-,-); V(-,+,-); V(+,+,-); V(+,-,-); glEnd(); + +# undef V +# undef N +} + +/* + * Draws a solid cube. Code contributed by Andreas Umbach + */ +void FGAPIENTRY glutSolidCube( GLdouble dSize ) +{ + double size = dSize * 0.5; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" ); + +# define V(a,b,c) glVertex3d( a size, b size, c size ); +# define N(a,b,c) glNormal3d( a, b, c ); + + /* PWO: Again, I dared to convert the code to use macros... */ + glBegin( GL_QUADS ); + N( 1.0, 0.0, 0.0); V(+,-,+); V(+,-,-); V(+,+,-); V(+,+,+); + N( 0.0, 1.0, 0.0); V(+,+,+); V(+,+,-); V(-,+,-); V(-,+,+); + N( 0.0, 0.0, 1.0); V(+,+,+); V(-,+,+); V(-,-,+); V(+,-,+); + N(-1.0, 0.0, 0.0); V(-,-,+); V(-,+,+); V(-,+,-); V(-,-,-); + N( 0.0,-1.0, 0.0); V(-,-,+); V(-,-,-); V(+,-,-); V(+,-,+); + N( 0.0, 0.0,-1.0); V(-,-,-); V(-,+,-); V(+,+,-); V(+,-,-); + glEnd(); + +# undef V +# undef N +} + +/* + * Compute lookup table of cos and sin values forming a cirle + * + * Notes: + * It is the responsibility of the caller to free these tables + * The size of the table is (n+1) to form a connected loop + * The last entry is exactly the same as the first + * The sign of n can be flipped to get the reverse loop + */ + +static void fghCircleTable(double **sint,double **cost,const int n) +{ + int i; + + /* Table size, the sign of n flips the circle direction */ + + const int size = abs(n); + + /* Determine the angle between samples */ + + const double angle = 2*M_PI/(double)( ( n == 0 ) ? 1 : n ); + + /* Allocate memory for n samples, plus duplicate of first entry at the end */ + + *sint = (double *) calloc(sizeof(double), size+1); + *cost = (double *) calloc(sizeof(double), size+1); + + /* Bail out if memory allocation fails, fgError never returns */ + + if (!(*sint) || !(*cost)) + { + free(*sint); + free(*cost); + fgError("Failed to allocate memory in fghCircleTable"); + } + + /* Compute cos and sin around the circle */ + + (*sint)[0] = 0.0; + (*cost)[0] = 1.0; + + for (i=1; i0)?1:0]; + r0 = 0.0; + r1 = sint2[(stacks>0)?1:0]; + + glBegin(GL_TRIANGLE_FAN); + + glNormal3d(0,0,1); + glVertex3d(0,0,radius); + + for (j=slices; j>=0; j--) + { + glNormal3d(cost1[j]*r1, sint1[j]*r1, z1 ); + glVertex3d(cost1[j]*r1*radius, sint1[j]*r1*radius, z1*radius); + } + + glEnd(); + + /* Cover each stack with a quad strip, except the top and bottom stacks */ + + for( i=1; i 0 ) ? stacks : 1 ); + const double rStep = base / ( ( stacks > 0 ) ? stacks : 1 ); + + /* Scaling factors for vertex normals */ + + const double cosn = ( height / sqrt ( height * height + base * base )); + const double sinn = ( base / sqrt ( height * height + base * base )); + + /* Pre-computed circle */ + + double *sint,*cost; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" ); + + fghCircleTable(&sint,&cost,-slices); + + /* Cover the circular base with a triangle fan... */ + + z0 = 0.0; + z1 = zStep; + + r0 = base; + r1 = r0 - rStep; + + glBegin(GL_TRIANGLE_FAN); + + glNormal3d(0.0,0.0,-1.0); + glVertex3d(0.0,0.0, z0 ); + + for (j=0; j<=slices; j++) + glVertex3d(cost[j]*r0, sint[j]*r0, z0); + + glEnd(); + + /* Cover each stack with a quad strip, except the top stack */ + + for( i=0; i 0 ) ? stacks : 1 ); + const double rStep = base / ( ( stacks > 0 ) ? stacks : 1 ); + + /* Scaling factors for vertex normals */ + + const double cosn = ( height / sqrt ( height * height + base * base )); + const double sinn = ( base / sqrt ( height * height + base * base )); + + /* Pre-computed circle */ + + double *sint,*cost; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" ); + + fghCircleTable(&sint,&cost,-slices); + + /* Draw the stacks... */ + + for (i=0; i 0 ) ? stacks : 1 ); + + /* Pre-computed circle */ + + double *sint,*cost; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" ); + + fghCircleTable(&sint,&cost,-slices); + + /* Cover the base and top */ + + glBegin(GL_TRIANGLE_FAN); + glNormal3d(0.0, 0.0, -1.0 ); + glVertex3d(0.0, 0.0, 0.0 ); + for (j=0; j<=slices; j++) + glVertex3d(cost[j]*radius, sint[j]*radius, 0.0); + glEnd(); + + glBegin(GL_TRIANGLE_FAN); + glNormal3d(0.0, 0.0, 1.0 ); + glVertex3d(0.0, 0.0, height); + for (j=slices; j>=0; j--) + glVertex3d(cost[j]*radius, sint[j]*radius, height); + glEnd(); + + /* Do the stacks */ + + z0 = 0.0; + z1 = zStep; + + for (i=1; i<=stacks; i++) + { + if (i==stacks) + z1 = height; + + glBegin(GL_QUAD_STRIP); + for (j=0; j<=slices; j++ ) + { + glNormal3d(cost[j], sint[j], 0.0 ); + glVertex3d(cost[j]*radius, sint[j]*radius, z0 ); + glVertex3d(cost[j]*radius, sint[j]*radius, z1 ); + } + glEnd(); + + z0 = z1; z1 += zStep; + } + + /* Release sin and cos tables */ + + free(sint); + free(cost); +} + +/* + * Draws a wire cylinder + */ +void FGAPIENTRY glutWireCylinder(GLdouble radius, GLdouble height, GLint slices, GLint stacks) +{ + int i,j; + + /* Step in z and radius as stacks are drawn. */ + + double z = 0.0; + const double zStep = height / ( ( stacks > 0 ) ? stacks : 1 ); + + /* Pre-computed circle */ + + double *sint,*cost; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" ); + + fghCircleTable(&sint,&cost,-slices); + + /* Draw the stacks... */ + + for (i=0; i<=stacks; i++) + { + if (i==stacks) + z = height; + + glBegin(GL_LINE_LOOP); + + for( j=0; j 0 ) + { + GLdouble local_offset[3] ; /* Use a local variable to avoid buildup of roundoff errors */ + num_levels -- ; + scale /= 2.0 ; + for ( i = 0 ; i < NUM_TETR_FACES ; i++ ) + { + local_offset[0] = offset[0] + scale * tet_r[i][0] ; + local_offset[1] = offset[1] + scale * tet_r[i][1] ; + local_offset[2] = offset[2] + scale * tet_r[i][2] ; + glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ; + } + } +} + +void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale ) +{ + int i, j ; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" ); + + if ( num_levels == 0 ) + { + glBegin ( GL_TRIANGLES ) ; + + for ( i = 0 ; i < NUM_TETR_FACES ; i++ ) + { + glNormal3d ( -tet_r[i][0], -tet_r[i][1], -tet_r[i][2] ) ; + for ( j = 0; j < 3; j++ ) + { + double x = offset[0] + scale * tet_r[tet_i[i][j]][0] ; + double y = offset[1] + scale * tet_r[tet_i[i][j]][1] ; + double z = offset[2] + scale * tet_r[tet_i[i][j]][2] ; + glVertex3d ( x, y, z ) ; + } + } + + glEnd () ; + } + else if ( num_levels > 0 ) + { + GLdouble local_offset[3] ; /* Use a local variable to avoid buildup of roundoff errors */ + num_levels -- ; + scale /= 2.0 ; + for ( i = 0 ; i < NUM_TETR_FACES ; i++ ) + { + local_offset[0] = offset[0] + scale * tet_r[i][0] ; + local_offset[1] = offset[1] + scale * tet_r[i][1] ; + local_offset[2] = offset[2] + scale * tet_r[i][2] ; + glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ; + } + } +} + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_glutfont_definitions.c b/tests/Box2D_v2.2.1/freeglut/freeglut_glutfont_definitions.c new file mode 100755 index 0000000000000..0a24cce7ca994 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_glutfont_definitions.c @@ -0,0 +1,108 @@ +/* + * freeglut_glutfont_definitions.c + * + * Bitmap and stroke fonts displaying. + * + * Copyright (c) 2003 Stephen J. Baker (whether he wants it or not). + * All Rights Reserved. + * Written by John F. Fay , who releases the + * copyright over to the "freeglut" project lead. + * Creation date: Mon July 21 2003 + * + * 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 + * PAWEL W. OLSZTA 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. + */ + +/* + * This file is necessary for the *nix version of "freeglut" because the + * original GLUT defined its font variables in rather an unusual way. + * Publicly, in "glut.h", they were defined as "void *". Privately, + * in one of the source code files, they were defined as pointers to a + * structure. Most compilers and linkers are satisfied with the "void *" + * and don't go any farther, but some of them balked. In particular, + * when compiling with "freeglut" and then trying to run using the GLUT + * ".so" library, some of them would give an error. So we are having to + * create this file to define the variables as pointers to an unusual + * structure to match GLUT. + */ + +/* + * freeglut_internal.h uses some GL types, but including the GL header portably + * is a bit tricky, so we include freeglut_std.h here, which contains the + * necessary machinery. But this poses another problem, caused by the ugly + * original defintion of the font constants in "classic" GLUT: They are defined + * as void* externally, so we move them temporarily out of the way by AN EXTREME + * CPP HACK. + */ + +#define glutStrokeRoman glutStrokeRomanIGNOREME +#define glutStrokeMonoRoman glutStrokeMonoRomanIGNOREME +#define glutBitmap9By15 glutBitmap9By15IGNOREME +#define glutBitmap8By13 glutBitmap8By13IGNOREME +#define glutBitmapTimesRoman10 glutBitmapTimesRoman10IGNOREME +#define glutBitmapTimesRoman24 glutBitmapTimesRoman24IGNOREME +#define glutBitmapHelvetica10 glutBitmapHelvetica10IGNOREME +#define glutBitmapHelvetica12 glutBitmapHelvetica12IGNOREME +#define glutBitmapHelvetica18 glutBitmapHelvetica18IGNOREME + +#include "freeglut_std.h" + +#undef glutStrokeRoman +#undef glutStrokeMonoRoman +#undef glutBitmap9By15 +#undef glutBitmap8By13 +#undef glutBitmapTimesRoman10 +#undef glutBitmapTimesRoman24 +#undef glutBitmapHelvetica10 +#undef glutBitmapHelvetica12 +#undef glutBitmapHelvetica18 + +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 + +struct freeglutStrokeFont +{ + const char *name ; + int num_chars ; + void *ch ; + float top ; + float bottom ; +}; + +struct freeglutBitmapFont +{ + const char *name ; + const int num_chars ; + const int first ; + const void *ch ; +}; + + +struct freeglutStrokeFont glutStrokeRoman ; +struct freeglutStrokeFont glutStrokeMonoRoman ; + +struct freeglutBitmapFont glutBitmap9By15 ; +struct freeglutBitmapFont glutBitmap8By13 ; +struct freeglutBitmapFont glutBitmapTimesRoman10 ; +struct freeglutBitmapFont glutBitmapTimesRoman24 ; +struct freeglutBitmapFont glutBitmapHelvetica10 ; +struct freeglutBitmapFont glutBitmapHelvetica12 ; +struct freeglutBitmapFont glutBitmapHelvetica18 ; + +#endif + diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_init.c b/tests/Box2D_v2.2.1/freeglut/freeglut_init.c new file mode 100755 index 0000000000000..73310eaab11b6 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_init.c @@ -0,0 +1,1166 @@ +/* + * freeglut_init.c + * + * Various freeglut initialization functions. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 2 1999 + * + * 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 + * PAWEL W. OLSZTA 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. + */ + +#define FREEGLUT_BUILDING_LIB +#include "freeglut.h" +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 +#include /* LONG_MAX */ +#endif + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * fgDeinitialize() -- Win32's OK, X11 needs the OS-specific + * deinitialization done + * glutInitDisplayString() -- display mode string parsing + * + * Wouldn't it be cool to use gettext() for error messages? I just love + * bash saying "nie znaleziono pliku" instead of "file not found" :) + * Is gettext easily portable? + */ + +/* -- GLOBAL VARIABLES ----------------------------------------------------- */ + +/* + * A structure pointed by g_pDisplay holds all information + * regarding the display, screen, root window etc. + */ +SFG_Display fgDisplay; + +/* + * The settings for the current freeglut session + */ +SFG_State fgState = { { -1, -1, GL_FALSE }, /* Position */ + { 300, 300, GL_TRUE }, /* Size */ + GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH, /* DisplayMode */ + GL_FALSE, /* Initialised */ + GLUT_TRY_DIRECT_CONTEXT, /* DirectContext */ + GL_FALSE, /* ForceIconic */ + GL_FALSE, /* UseCurrentContext */ + GL_FALSE, /* GLDebugSwitch */ + GL_FALSE, /* XSyncSwitch */ + GLUT_KEY_REPEAT_ON, /* KeyRepeat */ + INVALID_MODIFIERS, /* Modifiers */ + 0, /* FPSInterval */ + 0, /* SwapCount */ + 0, /* SwapTime */ + 0, /* Time */ + { NULL, NULL }, /* Timers */ + { NULL, NULL }, /* FreeTimers */ + NULL, /* IdleCallback */ + 0, /* ActiveMenus */ + NULL, /* MenuStateCallback */ + NULL, /* MenuStatusCallback */ + { 640, 480, GL_TRUE }, /* GameModeSize */ + 16, /* GameModeDepth */ + 72, /* GameModeRefresh */ + GLUT_ACTION_EXIT, /* ActionOnWindowClose */ + GLUT_EXEC_STATE_INIT, /* ExecState */ + NULL, /* ProgramName */ + GL_FALSE, /* JoysticksInitialised */ + GL_FALSE, /* InputDevsInitialised */ + 1, /* AuxiliaryBufferNumber */ + 4, /* SampleNumber */ + 1, /* MajorVersion */ + 0, /* MajorVersion */ + 0, /* ContextFlags */ + 0 /* ContextProfile */ +}; + + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +#if TARGET_HOST_POSIX_X11 + +/* Return the atom associated with "name". */ +static Atom fghGetAtom(const char * name) +{ + return XInternAtom(fgDisplay.Display, name, False); +} + +/* + * Check if "property" is set on "window". The property's values are returned + * through "data". If the property is set and is of type "type", return the + * number of elements in "data". Return zero otherwise. In both cases, use + * "Xfree()" to free "data". + */ +static int fghGetWindowProperty(Window window, + Atom property, + Atom type, + unsigned char ** data) +{ + /* + * Caller always has to use "Xfree()" to free "data", since + * "XGetWindowProperty() always allocates one extra byte in prop_return + * [i.e. "data"] (even if the property is zero length) [..]". + */ + + int status; /* Returned by "XGetWindowProperty". */ + + Atom type_returned; + int temp_format; /* Not used. */ + unsigned long number_of_elements; + unsigned long temp_bytes_after; /* Not used. */ + + + status = XGetWindowProperty(fgDisplay.Display, + window, + property, + 0, + LONG_MAX, + False, + type, + &type_returned, + &temp_format, + &number_of_elements, + &temp_bytes_after, + data); + + FREEGLUT_INTERNAL_ERROR_EXIT(status == Success, + "XGetWindowProperty failled", + "fghGetWindowProperty"); + + if (type_returned != type) + { + number_of_elements = 0; + } + + return number_of_elements; +} + +/* Check if the window manager is NET WM compliant. */ +static int fghNetWMSupported(void) +{ + Atom wm_check; + Window ** window_ptr_1; + + int number_of_windows; + int net_wm_supported; + + + net_wm_supported = 0; + + wm_check = fghGetAtom("_NET_SUPPORTING_WM_CHECK"); + window_ptr_1 = malloc(sizeof(Window *)); + + /* + * Check that the window manager has set this property on the root window. + * The property must be the ID of a child window. + */ + number_of_windows = fghGetWindowProperty(fgDisplay.RootWindow, + wm_check, + XA_WINDOW, + (unsigned char **) window_ptr_1); + if (number_of_windows == 1) + { + Window ** window_ptr_2; + + window_ptr_2 = malloc(sizeof(Window *)); + + /* Check that the window has the same property set to the same value. */ + number_of_windows = fghGetWindowProperty(**window_ptr_1, + wm_check, + XA_WINDOW, + (unsigned char **) window_ptr_2); + if ((number_of_windows == 1) && (**window_ptr_1 == **window_ptr_2)) + { + /* NET WM compliant */ + net_wm_supported = 1; + } + + XFree(*window_ptr_2); + free(window_ptr_2); + } + + XFree(*window_ptr_1); + free(window_ptr_1); + + return net_wm_supported; +} + +/* Check if "hint" is present in "property" for "window". */ +int fgHintPresent(Window window, Atom property, Atom hint) +{ + Atom ** atoms_ptr; + int number_of_atoms; + int supported; + int i; + + supported = 0; + + atoms_ptr = malloc(sizeof(Atom *)); + number_of_atoms = fghGetWindowProperty(window, + property, + XA_ATOM, + (unsigned char **) atoms_ptr); + for (i = 0; i < number_of_atoms; i++) + { + if ((*atoms_ptr)[i] == hint) + { + supported = 1; + break; + } + } + + return supported; +} + +#endif /* TARGET_HOST_POSIX_X11 */ + + +/* + * A call to this function should initialize all the display stuff... + */ +static void fghInitialize( const char* displayName ) +{ +#if TARGET_HOST_POSIX_X11 + fgDisplay.Display = XOpenDisplay( displayName ); + + if( fgDisplay.Display == NULL ) + fgError( "failed to open display '%s'", XDisplayName( displayName ) ); + + if( !glXQueryExtension( fgDisplay.Display, NULL, NULL ) ) + fgError( "OpenGL GLX extension not supported by display '%s'", + XDisplayName( displayName ) ); + + fgDisplay.Screen = DefaultScreen( fgDisplay.Display ); + fgDisplay.RootWindow = RootWindow( + fgDisplay.Display, + fgDisplay.Screen + ); + + fgDisplay.ScreenWidth = DisplayWidth( + fgDisplay.Display, + fgDisplay.Screen + ); + fgDisplay.ScreenHeight = DisplayHeight( + fgDisplay.Display, + fgDisplay.Screen + ); + + fgDisplay.ScreenWidthMM = DisplayWidthMM( + fgDisplay.Display, + fgDisplay.Screen + ); + fgDisplay.ScreenHeightMM = DisplayHeightMM( + fgDisplay.Display, + fgDisplay.Screen + ); + + fgDisplay.Connection = ConnectionNumber( fgDisplay.Display ); + + /* Create the window deletion atom */ + fgDisplay.DeleteWindow = fghGetAtom("WM_DELETE_WINDOW"); + + /* Create the state and full screen atoms */ + fgDisplay.State = None; + fgDisplay.StateFullScreen = None; + + if (fghNetWMSupported()) + { + const Atom supported = fghGetAtom("_NET_SUPPORTED"); + const Atom state = fghGetAtom("_NET_WM_STATE"); + + /* Check if the state hint is supported. */ + if (fgHintPresent(fgDisplay.RootWindow, supported, state)) + { + const Atom full_screen = fghGetAtom("_NET_WM_STATE_FULLSCREEN"); + + fgDisplay.State = state; + + /* Check if the window manager supports full screen. */ + /** Check "_NET_WM_ALLOWED_ACTIONS" on our window instead? **/ + if (fgHintPresent(fgDisplay.RootWindow, supported, full_screen)) + { + fgDisplay.StateFullScreen = full_screen; + } + } + } + +#elif TARGET_HOST_MS_WINDOWS + + WNDCLASS wc; + ATOM atom; + + /* What we need to do is to initialize the fgDisplay global structure here. */ + fgDisplay.Instance = GetModuleHandle( NULL ); + + atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc ); + + if( atom == 0 ) + { + ZeroMemory( &wc, sizeof(WNDCLASS) ); + + /* + * Each of the windows should have its own device context, and we + * want redraw events during Vertical and Horizontal Resizes by + * the user. + * + * XXX Old code had "| CS_DBCLCKS" commented out. Plans for the + * XXX future? Dead-end idea? + */ + wc.lpfnWndProc = fgWindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = fgDisplay.Instance; + wc.hIcon = LoadIcon( fgDisplay.Instance, _T("GLUT_ICON") ); + +#if defined(_WIN32_WCE) + wc.style = CS_HREDRAW | CS_VREDRAW; +#else + wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + if (!wc.hIcon) + wc.hIcon = LoadIcon( NULL, IDI_WINLOGO ); +#endif + + wc.hCursor = LoadCursor( NULL, IDC_ARROW ); + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = _T("FREEGLUT"); + + /* Register the window class */ + atom = RegisterClass( &wc ); + FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Not Registered", "fghInitialize" ); + } + + /* The screen dimensions can be obtained via GetSystemMetrics() calls */ + fgDisplay.ScreenWidth = GetSystemMetrics( SM_CXSCREEN ); + fgDisplay.ScreenHeight = GetSystemMetrics( SM_CYSCREEN ); + + { + HWND desktop = GetDesktopWindow( ); + HDC context = GetDC( desktop ); + + fgDisplay.ScreenWidthMM = GetDeviceCaps( context, HORZSIZE ); + fgDisplay.ScreenHeightMM = GetDeviceCaps( context, VERTSIZE ); + + ReleaseDC( desktop, context ); + } + + /* Set the timer granularity to 1 ms */ + timeBeginPeriod ( 1 ); + +#endif + + fgState.Initialised = GL_TRUE; + + /* InputDevice uses GlutTimerFunc(), so fgState.Initialised must be TRUE */ + fgInitialiseInputDevices(); +} + +/* + * Perform the freeglut deinitialization... + */ +void fgDeinitialize( void ) +{ + SFG_Timer *timer; + + if( !fgState.Initialised ) + { + fgWarning( "fgDeinitialize(): " + "no valid initialization has been performed" ); + return; + } + + /* If there was a menu created, destroy the rendering context */ + if( fgStructure.MenuContext ) + { +#if TARGET_HOST_POSIX_X11 + /* Note that the MVisualInfo is not owned by the MenuContext! */ + glXDestroyContext( fgDisplay.Display, fgStructure.MenuContext->MContext ); +#endif + free( fgStructure.MenuContext ); + fgStructure.MenuContext = NULL; + } + + fgDestroyStructure( ); + + while( ( timer = fgState.Timers.First) ) + { + fgListRemove( &fgState.Timers, &timer->Node ); + free( timer ); + } + + while( ( timer = fgState.FreeTimers.First) ) + { + fgListRemove( &fgState.FreeTimers, &timer->Node ); + free( timer ); + } + +#if !defined(_WIN32_WCE) + if ( fgState.JoysticksInitialised ) + fgJoystickClose( ); + + if ( fgState.InputDevsInitialised ) + fgInputDeviceClose( ); +#endif /* !defined(_WIN32_WCE) */ + fgState.JoysticksInitialised = GL_FALSE; + fgState.InputDevsInitialised = GL_FALSE; + + fgState.MajorVersion = 1; + fgState.MinorVersion = 0; + fgState.ContextFlags = 0; + fgState.ContextProfile = 0; + + fgState.Initialised = GL_FALSE; + + fgState.Position.X = -1; + fgState.Position.Y = -1; + fgState.Position.Use = GL_FALSE; + + fgState.Size.X = 300; + fgState.Size.Y = 300; + fgState.Size.Use = GL_TRUE; + + fgState.DisplayMode = GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH; + + fgState.DirectContext = GLUT_TRY_DIRECT_CONTEXT; + fgState.ForceIconic = GL_FALSE; + fgState.UseCurrentContext = GL_FALSE; + fgState.GLDebugSwitch = GL_FALSE; + fgState.XSyncSwitch = GL_FALSE; + fgState.ActionOnWindowClose = GLUT_ACTION_EXIT; + fgState.ExecState = GLUT_EXEC_STATE_INIT; + + fgState.KeyRepeat = GLUT_KEY_REPEAT_ON; + fgState.Modifiers = INVALID_MODIFIERS; + + fgState.GameModeSize.X = 640; + fgState.GameModeSize.Y = 480; + fgState.GameModeDepth = 16; + fgState.GameModeRefresh = 72; + + fgListInit( &fgState.Timers ); + fgListInit( &fgState.FreeTimers ); + + fgState.IdleCallback = NULL; + fgState.MenuStateCallback = ( FGCBMenuState )NULL; + fgState.MenuStatusCallback = ( FGCBMenuStatus )NULL; + + fgState.SwapCount = 0; + fgState.SwapTime = 0; + fgState.FPSInterval = 0; + + if( fgState.ProgramName ) + { + free( fgState.ProgramName ); + fgState.ProgramName = NULL; + } + +#if TARGET_HOST_POSIX_X11 + + /* + * Make sure all X-client data we have created will be destroyed on + * display closing + */ + XSetCloseDownMode( fgDisplay.Display, DestroyAll ); + + /* + * Close the display connection, destroying all windows we have + * created so far + */ + XCloseDisplay( fgDisplay.Display ); + +#elif TARGET_HOST_MS_WINDOWS + + /* Reset the timer granularity */ + timeEndPeriod ( 1 ); + +#endif + + fgState.Initialised = GL_FALSE; +} + +/* + * Everything inside the following #ifndef is copied from the X sources. + */ + +#if TARGET_HOST_MS_WINDOWS + +/* + +Copyright 1985, 1986, 1987,1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +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 OPEN GROUP 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. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +#define NoValue 0x0000 +#define XValue 0x0001 +#define YValue 0x0002 +#define WidthValue 0x0004 +#define HeightValue 0x0008 +#define AllValues 0x000F +#define XNegative 0x0010 +#define YNegative 0x0020 + +/* + * XParseGeometry parses strings of the form + * "=x{+-}{+-}", where + * width, height, xoffset, and yoffset are unsigned integers. + * Example: "=80x24+300-49" + * The equal sign is optional. + * It returns a bitmask that indicates which of the four values + * were actually found in the string. For each value found, + * the corresponding argument is updated; for each value + * not found, the corresponding argument is left unchanged. + */ + +static int +ReadInteger(char *string, char **NextString) +{ + register int Result = 0; + int Sign = 1; + + if (*string == '+') + string++; + else if (*string == '-') + { + string++; + Sign = -1; + } + for (; (*string >= '0') && (*string <= '9'); string++) + { + Result = (Result * 10) + (*string - '0'); + } + *NextString = string; + if (Sign >= 0) + return Result; + else + return -Result; +} + +static int XParseGeometry ( + const char *string, + int *x, + int *y, + unsigned int *width, /* RETURN */ + unsigned int *height) /* RETURN */ +{ + int mask = NoValue; + register char *strind; + unsigned int tempWidth = 0, tempHeight = 0; + int tempX = 0, tempY = 0; + char *nextCharacter; + + if ( (string == NULL) || (*string == '\0')) + return mask; + if (*string == '=') + string++; /* ignore possible '=' at beg of geometry spec */ + + strind = (char *)string; + if (*strind != '+' && *strind != '-' && *strind != 'x') { + tempWidth = ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return 0; + strind = nextCharacter; + mask |= WidthValue; + } + + if (*strind == 'x' || *strind == 'X') { + strind++; + tempHeight = ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return 0; + strind = nextCharacter; + mask |= HeightValue; + } + + if ((*strind == '+') || (*strind == '-')) { + if (*strind == '-') { + strind++; + tempX = -ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return 0; + strind = nextCharacter; + mask |= XNegative; + } + else + { + strind++; + tempX = ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return 0; + strind = nextCharacter; + } + mask |= XValue; + if ((*strind == '+') || (*strind == '-')) { + if (*strind == '-') { + strind++; + tempY = -ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return 0; + strind = nextCharacter; + mask |= YNegative; + } + else + { + strind++; + tempY = ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return 0; + strind = nextCharacter; + } + mask |= YValue; + } + } + + /* If strind isn't at the end of the string the it's an invalid + geometry specification. */ + + if (*strind != '\0') return 0; + + if (mask & XValue) + *x = tempX; + if (mask & YValue) + *y = tempY; + if (mask & WidthValue) + *width = tempWidth; + if (mask & HeightValue) + *height = tempHeight; + return mask; +} +#endif + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Perform initialization. This usually happens on the program startup + * and restarting after glutMainLoop termination... + */ +void FGAPIENTRY glutInit( int* pargc, char** argv ) +{ + char* displayName = NULL; + char* geometry = NULL; + int i, j, argc = *pargc; + + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) +#if HAVE_ERRNO + size_t sLen; + errno_t err; +#endif +#endif + + if( fgState.Initialised ) + fgError( "illegal glutInit() reinitialization attempt" ); + + if (pargc && *pargc && argv && *argv && **argv) + { + fgState.ProgramName = strdup (*argv); + + if( !fgState.ProgramName ) + fgError ("Could not allocate space for the program's name."); + } + + fgCreateStructure( ); + + /* Get start time */ + fgState.Time = fgSystemTime(); + + /* check if GLUT_FPS env var is set */ +#ifndef _WIN32_WCE + { + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) && HAVE_ERRNO + char* fps = NULL; + err = _dupenv_s( &fps, &sLen, "GLUT_FPS" ); + if (err) + fgError("Error getting GLUT_FPS environment variable"); +#else + const char *fps = getenv( "GLUT_FPS" ); +#endif + if( fps ) + { + int interval; + sscanf( fps, "%d", &interval ); + + if( interval <= 0 ) + fgState.FPSInterval = 5000; /* 5000 millisecond default */ + else + fgState.FPSInterval = interval; + } + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) && HAVE_ERRNO + free ( fps ); fps = NULL; /* dupenv_s allocates a string that we must free */ +#endif + } + + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) && HAVE_ERRNO + err = _dupenv_s( &displayName, &sLen, "DISPLAY" ); + if (err) + fgError("Error getting DISPLAY environment variable"); +#else + displayName = getenv( "DISPLAY" ); +#endif + + for( i = 1; i < argc; i++ ) + { + if( strcmp( argv[ i ], "-display" ) == 0 ) + { + if( ++i >= argc ) + fgError( "-display parameter must be followed by display name" ); + + displayName = argv[ i ]; + + argv[ i - 1 ] = NULL; + argv[ i ] = NULL; + ( *pargc ) -= 2; + } + else if( strcmp( argv[ i ], "-geometry" ) == 0 ) + { + if( ++i >= argc ) + fgError( "-geometry parameter must be followed by window " + "geometry settings" ); + + geometry = argv[ i ]; + + argv[ i - 1 ] = NULL; + argv[ i ] = NULL; + ( *pargc ) -= 2; + } + else if( strcmp( argv[ i ], "-direct" ) == 0) + { + if( fgState.DirectContext == GLUT_FORCE_INDIRECT_CONTEXT ) + fgError( "parameters ambiguity, -direct and -indirect " + "cannot be both specified" ); + + fgState.DirectContext = GLUT_FORCE_DIRECT_CONTEXT; + argv[ i ] = NULL; + ( *pargc )--; + } + else if( strcmp( argv[ i ], "-indirect" ) == 0 ) + { + if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT ) + fgError( "parameters ambiguity, -direct and -indirect " + "cannot be both specified" ); + + fgState.DirectContext = GLUT_FORCE_INDIRECT_CONTEXT; + argv[ i ] = NULL; + (*pargc)--; + } + else if( strcmp( argv[ i ], "-iconic" ) == 0 ) + { + fgState.ForceIconic = GL_TRUE; + argv[ i ] = NULL; + ( *pargc )--; + } + else if( strcmp( argv[ i ], "-gldebug" ) == 0 ) + { + fgState.GLDebugSwitch = GL_TRUE; + argv[ i ] = NULL; + ( *pargc )--; + } + else if( strcmp( argv[ i ], "-sync" ) == 0 ) + { + fgState.XSyncSwitch = GL_TRUE; + argv[ i ] = NULL; + ( *pargc )--; + } + } + + /* Compact {argv}. */ + for( i = j = 1; i < *pargc; i++, j++ ) + { + /* Guaranteed to end because there are "*pargc" arguments left */ + while ( argv[ j ] == NULL ) + j++; + if ( i != j ) + argv[ i ] = argv[ j ]; + } + +#endif /* _WIN32_WCE */ + + /* + * Have the display created now. If there wasn't a "-display" + * in the program arguments, we will use the DISPLAY environment + * variable for opening the X display (see code above): + */ + fghInitialize( displayName ); + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) && HAVE_ERRNO + free ( displayName ); displayName = NULL; /* dupenv_s allocates a string that we must free */ +#endif + + /* + * Geometry parsing deffered until here because we may need the screen + * size. + */ + + if (geometry ) + { + unsigned int parsedWidth, parsedHeight; + int mask = XParseGeometry( geometry, + &fgState.Position.X, &fgState.Position.Y, + &parsedWidth, &parsedHeight ); + /* TODO: Check for overflow? */ + fgState.Size.X = parsedWidth; + fgState.Size.Y = parsedHeight; + + if( (mask & (WidthValue|HeightValue)) == (WidthValue|HeightValue) ) + fgState.Size.Use = GL_TRUE; + + if( mask & XNegative ) + fgState.Position.X += fgDisplay.ScreenWidth - fgState.Size.X; + + if( mask & YNegative ) + fgState.Position.Y += fgDisplay.ScreenHeight - fgState.Size.Y; + + if( (mask & (XValue|YValue)) == (XValue|YValue) ) + fgState.Position.Use = GL_TRUE; + } +} + +#if TARGET_HOST_MS_WINDOWS +void (__cdecl *__glutExitFunc)( int return_value ) = NULL; + +void FGAPIENTRY __glutInitWithExit( int *pargc, char **argv, void (__cdecl *exit_function)(int) ) +{ + __glutExitFunc = exit_function; + glutInit(pargc, argv); +} +#endif + +/* + * Undoes all the "glutInit" stuff + */ +void FGAPIENTRY glutExit ( void ) +{ + fgDeinitialize (); +} + +/* + * Sets the default initial window position for new windows + */ +void FGAPIENTRY glutInitWindowPosition( int x, int y ) +{ + fgState.Position.X = x; + fgState.Position.Y = y; + + if( ( x >= 0 ) && ( y >= 0 ) ) + fgState.Position.Use = GL_TRUE; + else + fgState.Position.Use = GL_FALSE; +} + +/* + * Sets the default initial window size for new windows + */ +void FGAPIENTRY glutInitWindowSize( int width, int height ) +{ + fgState.Size.X = width; + fgState.Size.Y = height; + + if( ( width > 0 ) && ( height > 0 ) ) + fgState.Size.Use = GL_TRUE; + else + fgState.Size.Use = GL_FALSE; +} + +/* + * Sets the default display mode for all new windows + */ +void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode ) +{ + /* We will make use of this value when creating a new OpenGL context... */ + fgState.DisplayMode = displayMode; +} + + +/* -- INIT DISPLAY STRING PARSING ------------------------------------------ */ + +static char* Tokens[] = +{ + "alpha", "acca", "acc", "blue", "buffer", "conformant", "depth", "double", + "green", "index", "num", "red", "rgba", "rgb", "luminance", "stencil", + "single", "stereo", "samples", "slow", "win32pdf", "win32pfd", "xvisual", + "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor", + "xtruecolor", "xdirectcolor", + "xstaticgrey", "xgreyscale", "xstaticcolour", "xpseudocolour", + "xtruecolour", "xdirectcolour", "borderless", "aux" +}; +#define NUM_TOKENS (sizeof(Tokens) / sizeof(*Tokens)) + +void FGAPIENTRY glutInitDisplayString( const char* displayMode ) +{ + int glut_state_flag = 0 ; + /* + * Unpack a lot of options from a character string. The options are + * delimited by blanks or tabs. + */ + char *token ; + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) + char *next_token = NULL; +#endif + size_t len = strlen ( displayMode ); + char *buffer = (char *)malloc ( (len+1) * sizeof(char) ); + memcpy ( buffer, displayMode, len ); + buffer[len] = '\0'; + + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) + token = strtok_s ( buffer, " \t", &next_token ); +#else + token = strtok ( buffer, " \t" ); +#endif + while ( token ) + { + /* Process this token */ + int i ; + + /* Temporary fix: Ignore any length specifications and at least + * process the basic token + * TODO: Fix this permanently + */ + size_t cleanlength = strcspn ( token, "=<>~!" ); + + for ( i = 0; i < NUM_TOKENS; i++ ) + { + if ( strncmp ( token, Tokens[i], cleanlength ) == 0 ) break ; + } + + switch ( i ) + { + case 0 : /* "alpha": Alpha color buffer precision in bits */ + glut_state_flag |= GLUT_ALPHA ; /* Somebody fix this for me! */ + break ; + + case 1 : /* "acca": Red, green, blue, and alpha accumulation buffer + precision in bits */ + break ; + + case 2 : /* "acc": Red, green, and blue accumulation buffer precision + in bits with zero bits alpha */ + glut_state_flag |= GLUT_ACCUM ; /* Somebody fix this for me! */ + break ; + + case 3 : /* "blue": Blue color buffer precision in bits */ + break ; + + case 4 : /* "buffer": Number of bits in the color index color buffer + */ + break ; + + case 5 : /* "conformant": Boolean indicating if the frame buffer + configuration is conformant or not */ + break ; + + case 6 : /* "depth": Number of bits of precsion in the depth buffer */ + glut_state_flag |= GLUT_DEPTH ; /* Somebody fix this for me! */ + break ; + + case 7 : /* "double": Boolean indicating if the color buffer is + double buffered */ + glut_state_flag |= GLUT_DOUBLE ; + break ; + + case 8 : /* "green": Green color buffer precision in bits */ + break ; + + case 9 : /* "index": Boolean if the color model is color index or not + */ + glut_state_flag |= GLUT_INDEX ; + break ; + + case 10 : /* "num": A special capability name indicating where the + value represents the Nth frame buffer configuration + matching the description string */ + break ; + + case 11 : /* "red": Red color buffer precision in bits */ + break ; + + case 12 : /* "rgba": Number of bits of red, green, blue, and alpha in + the RGBA color buffer */ + glut_state_flag |= GLUT_RGBA ; /* Somebody fix this for me! */ + break ; + + case 13 : /* "rgb": Number of bits of red, green, and blue in the + RGBA color buffer with zero bits alpha */ + glut_state_flag |= GLUT_RGB ; /* Somebody fix this for me! */ + break ; + + case 14 : /* "luminance": Number of bits of red in the RGBA and zero + bits of green, blue (alpha not specified) of color buffer + precision */ + glut_state_flag |= GLUT_LUMINANCE ; /* Somebody fix this for me! */ + break ; + + case 15 : /* "stencil": Number of bits in the stencil buffer */ + glut_state_flag |= GLUT_STENCIL; /* Somebody fix this for me! */ + break ; + + case 16 : /* "single": Boolean indicate the color buffer is single + buffered */ + glut_state_flag |= GLUT_SINGLE ; + break ; + + case 17 : /* "stereo": Boolean indicating the color buffer supports + OpenGL-style stereo */ + glut_state_flag |= GLUT_STEREO ; + break ; + + case 18 : /* "samples": Indicates the number of multisamples to use + based on GLX's SGIS_multisample extension (for + antialiasing) */ + glut_state_flag |= GLUT_MULTISAMPLE ; /*Somebody fix this for me!*/ + break ; + + case 19 : /* "slow": Boolean indicating if the frame buffer + configuration is slow or not */ + break ; + + case 20 : /* "win32pdf": (incorrect spelling but was there before */ + case 21 : /* "win32pfd": matches the Win32 Pixel Format Descriptor by + number */ +#if TARGET_HOST_MS_WINDOWS +#endif + break ; + + case 22 : /* "xvisual": matches the X visual ID by number */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 23 : /* "xstaticgray": */ + case 29 : /* "xstaticgrey": boolean indicating if the frame buffer + configuration's X visual is of type StaticGray */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 24 : /* "xgrayscale": */ + case 30 : /* "xgreyscale": boolean indicating if the frame buffer + configuration's X visual is of type GrayScale */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 25 : /* "xstaticcolor": */ + case 31 : /* "xstaticcolour": boolean indicating if the frame buffer + configuration's X visual is of type StaticColor */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 26 : /* "xpseudocolor": */ + case 32 : /* "xpseudocolour": boolean indicating if the frame buffer + configuration's X visual is of type PseudoColor */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 27 : /* "xtruecolor": */ + case 33 : /* "xtruecolour": boolean indicating if the frame buffer + configuration's X visual is of type TrueColor */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 28 : /* "xdirectcolor": */ + case 34 : /* "xdirectcolour": boolean indicating if the frame buffer + configuration's X visual is of type DirectColor */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 35 : /* "borderless": windows should not have borders */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 36 : /* "aux": some number of aux buffers */ + glut_state_flag |= GLUT_AUX; + break ; + + case 37 : /* Unrecognized */ + fgWarning ( "WARNING - Display string token not recognized: %s", + token ); + break ; + } + + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) + token = strtok_s ( NULL, " \t", &next_token ); +#else + token = strtok ( NULL, " \t" ); +#endif + } + + free ( buffer ); + + /* We will make use of this value when creating a new OpenGL context... */ + fgState.DisplayMode = glut_state_flag; +} + +/* -- SETTING OPENGL 3.0 CONTEXT CREATION PARAMETERS ---------------------- */ + +void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion ) +{ + /* We will make use of these valuse when creating a new OpenGL context... */ + fgState.MajorVersion = majorVersion; + fgState.MinorVersion = minorVersion; +} + + +void FGAPIENTRY glutInitContextFlags( int flags ) +{ + /* We will make use of this value when creating a new OpenGL context... */ + fgState.ContextFlags = flags; +} + +void FGAPIENTRY glutInitContextProfile( int profile ) +{ + /* We will make use of this value when creating a new OpenGL context... */ + fgState.ContextProfile = profile; +} + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_input_devices.c b/tests/Box2D_v2.2.1/freeglut/freeglut_input_devices.c new file mode 100755 index 0000000000000..b500e830c9d95 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_input_devices.c @@ -0,0 +1,395 @@ +/* + * freeglut_input_devices.c + * + * Handles miscellaneous input devices via direct serial-port access. + * Proper X11 XInput device support is not yet supported. + * Also lacks Mac support. + * + * Written by Joe Krahn 2005 + * + * Copyright (c) 2005 Stephen J. Baker. All Rights Reserved. + * + * 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 + * PAWEL W. OLSZTA OR STEPHEN J. BAKER 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "freeglut.h" +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 +#if HAVE_ERRNO +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + int fd; + struct termios termio, termio_save; +} SERIALPORT; + +#elif TARGET_HOST_MS_WINDOWS +#include +#include +typedef struct { + HANDLE fh; + COMMTIMEOUTS timeouts_save; + DCB dcb_save; +} SERIALPORT; + +#endif + +/********************* Dialbox definitions ***********************/ + +#define DIAL_NUM_VALUATORS 8 + +/* dial parser state machine states */ +#define DIAL_NEW (-1) +#define DIAL_WHICH_DEVICE 0 +#define DIAL_VALUE_HIGH 1 +#define DIAL_VALUE_LOW 2 + +/* dial/button box commands */ +#define DIAL_INITIALIZE 0x20 +#define DIAL_SET_LEDS 0x75 +#define DIAL_SET_TEXT 0x61 +#define DIAL_SET_AUTO_DIALS 0x50 +#define DIAL_SET_AUTO_DELTA_DIALS 0x51 +#define DIAL_SET_FILTER 0x53 +#define DIAL_SET_BUTTONS_MOM_TYPE 0x71 +#define DIAL_SET_AUTO_MOM_BUTTONS 0x73 +#define DIAL_SET_ALL_LEDS 0x4b +#define DIAL_CLEAR_ALL_LEDS 0x4c + +/* dial/button box replies and events */ +#define DIAL_INITIALIZED 0x20 +#define DIAL_BASE 0x30 +#define DIAL_DELTA_BASE 0x40 +#define DIAL_PRESS_BASE 0xc0 +#define DIAL_RELEASE_BASE 0xe0 + +/* macros to determine reply type */ +#define IS_DIAL_EVENT(ch) (((ch)>=DIAL_BASE)&&((ch)=DIAL_PRESS_BASE)&&((ch)=DIAL_RELEASE_BASE)&&((ch)= 1400 ) && HAVE_ERRNO + char *dial_device=NULL; + size_t sLen; + errno_t err = _dupenv_s( &dial_device, &sLen, "GLUT_DIALS_SERIAL" ); + if (err) + fgError("Error getting GLUT_DIALS_SERIAL environment variable"); +#else + const char *dial_device=NULL; + dial_device = getenv ( "GLUT_DIALS_SERIAL" ); +#endif +#if TARGET_HOST_MS_WINDOWS + if (!dial_device){ + static char devname[256]; + DWORD size=sizeof(devname); + DWORD type = REG_SZ; + HKEY key; + if (RegOpenKeyA(HKEY_LOCAL_MACHINE,"SOFTWARE\\FreeGLUT",&key)==ERROR_SUCCESS) { + if (RegQueryValueExA(key,"DialboxSerialPort",NULL,&type,(LPBYTE)devname,&size)==ERROR_SUCCESS){ + dial_device=devname; + } + RegCloseKey(key); + } + } +#endif + if ( !dial_device ) return; + if ( !( dialbox_port = serial_open ( dial_device ) ) ) return; + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) && HAVE_ERRNO + free ( dial_device ); dial_device = NULL; /* dupenv_s allocates a string that we must free */ +#endif + serial_putchar(dialbox_port,DIAL_INITIALIZE); + glutTimerFunc ( 10, poll_dials, 0 ); + fgState.InputDevsInitialised = GL_TRUE; + } +} + +/* + * + */ +void fgInputDeviceClose( void ) +{ + if ( fgState.InputDevsInitialised ) + { + serial_close ( dialbox_port ); + dialbox_port = NULL; + fgState.InputDevsInitialised = GL_FALSE; + } +} + +/********************************************************************/ + +/* Check all windows for dialbox callbacks */ +static void fghcbEnumDialCallbacks ( SFG_Window *window, SFG_Enumerator *enumerator ) +{ + /* Built-in to INVOKE_WCB(): if window->Callbacks[CB_Dials] */ + INVOKE_WCB ( *window,Dials, ( ((int*)enumerator->data)[0], ((int*)enumerator->data)[1]) ); + fgEnumSubWindows ( window, fghcbEnumDialCallbacks, enumerator ); +} + +static void send_dial_event ( int num, int value ) +{ + SFG_Enumerator enumerator; + int data[2]; + data[0] = num; + data[1] = value; + enumerator.found = GL_FALSE; + enumerator.data = data; + fgEnumWindows ( fghcbEnumDialCallbacks, &enumerator ); +} + +/********************************************************************/ +static void poll_dials ( int id ) +{ + int data; + static int dial_state = DIAL_NEW; + static int dial_which; + static int dial_value; + static int dials[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + if ( !dialbox_port ) return; + + while ( (data=serial_getchar(dialbox_port)) != EOF ) + { + if ( ( dial_state > DIAL_WHICH_DEVICE ) || IS_DIAL_EVENT ( data ) ) + { + switch ( dial_state ) + { + case DIAL_WHICH_DEVICE: + dial_which = data - DIAL_BASE; + dial_state++; + break; + case DIAL_VALUE_HIGH: + dial_value = ( data << 8 ); + dial_state++; + break; + case DIAL_VALUE_LOW: + dial_value |= data; + if ( dial_value & 0x8000 ) dial_value -= 0x10000; + dials[dial_which] = dial_value; + send_dial_event ( dial_which + 1, dial_value * 360 / 256 ); + dial_state = DIAL_WHICH_DEVICE; + break; + default: + /* error: Impossible state value! */ + break; + } + } + else if ( data == DIAL_INITIALIZED ) + { + fgState.InputDevsInitialised = GL_TRUE; + dial_state = DIAL_WHICH_DEVICE; + serial_putchar(dialbox_port,DIAL_SET_AUTO_DIALS); + serial_putchar(dialbox_port,0xff); + serial_putchar(dialbox_port,0xff); + } + else /* Unknown data; try flushing. */ + serial_flush(dialbox_port); + } + + glutTimerFunc ( 2, poll_dials, 0 ); +} + + +/******** OS Specific Serial I/O routines *******/ +#if TARGET_HOST_POSIX_X11 /* ==> Linux/BSD/UNIX POSIX serial I/O */ +static SERIALPORT *serial_open ( const char *device ) +{ + int fd; + struct termios termio; + SERIALPORT *port; + + fd = open(device, O_RDWR | O_NONBLOCK ); + if (fd <0) { + perror(device); + return NULL; + } + + port = malloc(sizeof(SERIALPORT)); + memset(port, 0, sizeof(SERIALPORT)); + port->fd = fd; + + /* save current port settings */ + tcgetattr(fd,&port->termio_save); + + memset(&termio, 0, sizeof(termio)); + termio.c_cflag = CS8 | CREAD | HUPCL ; + termio.c_iflag = IGNPAR | IGNBRK ; + termio.c_cc[VTIME] = 0; /* inter-character timer */ + termio.c_cc[VMIN] = 1; /* block read until 1 chars received, when blocking I/O */ + + cfsetispeed(&termio, B9600); + cfsetospeed(&termio, B9600); + tcsetattr(fd,TCSANOW,&termio); + + serial_flush(port); + return port; +} + +static void serial_close(SERIALPORT *port) +{ + if (port) + { + /* restore old port settings */ + tcsetattr(port->fd,TCSANOW,&port->termio_save); + close(port->fd); + free(port); + } +} + +static int serial_getchar(SERIALPORT *port) +{ + unsigned char ch; + if (!port) return EOF; + if (read(port->fd,&ch,1)) return ch; + return EOF; +} + +static int serial_putchar(SERIALPORT *port, unsigned char ch){ + if (!port) return 0; + return write(port->fd,&ch,1); +} + +static void serial_flush ( SERIALPORT *port ) +{ + tcflush ( port->fd, TCIOFLUSH ); +} + +#elif TARGET_HOST_MS_WINDOWS + +static SERIALPORT *serial_open(const char *device){ + HANDLE fh; + DCB dcb={sizeof(DCB)}; + COMMTIMEOUTS timeouts; + SERIALPORT *port; + + fh = CreateFile(device,GENERIC_READ|GENERIC_WRITE,0,NULL, + OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + if (!fh) return NULL; + + port = malloc(sizeof(SERIALPORT)); + ZeroMemory(port, sizeof(SERIALPORT)); + port->fh = fh; + + /* save current port settings */ + GetCommState(fh,&port->dcb_save); + GetCommTimeouts(fh,&port->timeouts_save); + + dcb.DCBlength=sizeof(DCB); + BuildCommDCB("96,n,8,1",&dcb); + SetCommState(fh,&dcb); + + ZeroMemory(&timeouts,sizeof(timeouts)); + timeouts.ReadTotalTimeoutConstant=1; + timeouts.WriteTotalTimeoutConstant=1; + SetCommTimeouts(fh,&timeouts); + + serial_flush(port); + + return port; +} + +static void serial_close(SERIALPORT *port){ + if (port){ + /* restore old port settings */ + SetCommState(port->fh,&port->dcb_save); + SetCommTimeouts(port->fh,&port->timeouts_save); + CloseHandle(port->fh); + free(port); + } +} + +static int serial_getchar(SERIALPORT *port){ + DWORD n; + unsigned char ch; + if (!port) return EOF; + if (!ReadFile(port->fh,&ch,1,&n,NULL)) return EOF; + if (n==1) return ch; + return EOF; +} + +static int serial_putchar(SERIALPORT *port, unsigned char ch){ + DWORD n; + if (!port) return 0; + return WriteFile(port->fh,&ch,1,&n,NULL); +} + +static void serial_flush ( SERIALPORT *port ) +{ + FlushFileBuffers(port->fh); +} + +#endif diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_internal.h b/tests/Box2D_v2.2.1/freeglut/freeglut_internal.h new file mode 100755 index 0000000000000..2d77ab014fd3c --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_internal.h @@ -0,0 +1,960 @@ +/* + * freeglut_internal.h + * + * The freeglut library private include file. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 2 1999 + * + * 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 + * PAWEL W. OLSZTA 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. + */ + +#ifndef FREEGLUT_INTERNAL_H +#define FREEGLUT_INTERNAL_H + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +/* XXX Update these for each release! */ +#define VERSION_MAJOR 2 +#define VERSION_MINOR 6 +#define VERSION_PATCH 0 + +/* Freeglut is intended to function under all Unix/X11 and Win32 platforms. */ +/* XXX: Don't all MS-Windows compilers (except Cygwin) have _WIN32 defined? + * XXX: If so, remove the first set of defined()'s below. + */ +#if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__MINGW32__) \ + || defined(_WIN32) || defined(_WIN32_WCE) \ + || ( defined(__CYGWIN__) && defined(X_DISPLAY_MISSING) ) +# define TARGET_HOST_MS_WINDOWS 1 + +#elif defined(__posix__) || defined(__unix__) || defined(__linux__) +# define TARGET_HOST_POSIX_X11 1 + +#elif defined(__APPLE__) +/* This is a placeholder until we get native OSX support ironed out -- JFF 11/18/09 */ +# define TARGET_HOST_POSIX_X11 1 +/* # define TARGET_HOST_MAC_OSX 1 */ + +#else +# error "Unrecognized target host!" +*/ +#endif + +/* Detect both SunPro and gcc compilers on Sun Solaris */ +#if defined (__SVR4) && defined (__sun) +# define TARGET_HOST_SOLARIS 1 +#endif + +#ifndef TARGET_HOST_MS_WINDOWS +# define TARGET_HOST_MS_WINDOWS 0 +#endif + +#ifndef TARGET_HOST_POSIX_X11 +# define TARGET_HOST_POSIX_X11 0 +#endif + +#ifndef TARGET_HOST_MAC_OSX +# define TARGET_HOST_MAC_OSX 0 +#endif + +#ifndef TARGET_HOST_SOLARIS +# define TARGET_HOST_SOLARIS 0 +#endif + +/* -- FIXED CONFIGURATION LIMITS ------------------------------------------- */ + +#define FREEGLUT_MAX_MENUS 3 + +/* -- PLATFORM-SPECIFIC INCLUDES ------------------------------------------- */ + +/* All Win32 headers depend on the huge Windows.h recursive include. + * Note: Let's use proper case for MS-Win headers. Even though it's + * not required due to case insensitivity, it's a good habit to keep + * because the cross-platform includes are case sensitive. + */ +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) +# include +# include +# include +/* CYGWIN does not have tchar.h, but has TEXT(x), defined in winnt.h. */ +# ifndef __CYGWIN__ +# include +# else +# define _TEXT(x) TEXT(x) +# define _T(x) TEXT(x) +# endif + +#elif TARGET_HOST_POSIX_X11 +# include +# include +# include +# include +# include +# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H +# include +# endif +/* If GLX is too old, we will fail during runtime when multisampling + is requested, but at least freeglut compiles. */ +# ifndef GLX_SAMPLE_BUFFERS +# define GLX_SAMPLE_BUFFERS 0x80A8 +# endif +# ifndef GLX_SAMPLES +# define GLX_SAMPLES 0x80A9 +# endif + +#endif + +/* These files should be available on every platform. */ +#include +#include +#include +#include + +/* These are included based on autoconf directives. */ +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_UNISTD_H +# include +#endif +#if TIME_WITH_SYS_TIME +# include +# include +#elif HAVE_SYS_TIME_H +# include +#else +# include +#endif + +/* -- AUTOCONF HACKS --------------------------------------------------------*/ + +/* XXX: Update autoconf to avoid these. + * XXX: Are non-POSIX platforms intended not to use autoconf? + * If so, perhaps there should be a config_guess.h for them. Alternatively, + * config guesses could be placed above, just after the config.h exclusion. + */ +#if defined(__FreeBSD__) || defined(__NetBSD__) +# define HAVE_USB_JS 1 +# if defined(__NetBSD__) || ( defined(__FreeBSD__) && __FreeBSD_version >= 500000) +# define HAVE_USBHID_H 1 +# endif +#endif + +#if TARGET_HOST_MS_WINDOWS +# define HAVE_VPRINTF 1 +#endif + +#if !defined(HAVE_VPRINTF) && !defined(HAVE_DOPRNT) +/* XXX warning directive here? */ +# define HAVE_VPRINTF 1 +#endif + +/* MinGW may lack a prototype for ChangeDisplaySettingsEx() (depending on the version?) */ +#if TARGET_HOST_MS_WINDOWS && !defined(ChangeDisplaySettingsEx) +LONG WINAPI ChangeDisplaySettingsExA(LPCSTR,LPDEVMODEA,HWND,DWORD,LPVOID); +LONG WINAPI ChangeDisplaySettingsExW(LPCWSTR,LPDEVMODEW,HWND,DWORD,LPVOID); +# ifdef UNICODE +# define ChangeDisplaySettingsEx ChangeDisplaySettingsExW +# else +# define ChangeDisplaySettingsEx ChangeDisplaySettingsExA +# endif +#endif + +#if defined(_MSC_VER) || defined(__WATCOMC__) +/* strdup() is non-standard, for all but POSIX-2001 */ +#define strdup _strdup +#endif + +/* M_PI is non-standard (defined by BSD, not ISO-C) */ +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +#ifndef TRUE +# define TRUE 1 +#endif + +#ifndef FALSE +# define FALSE 0 +#endif + +/* General defines */ + +#define INVALID_MODIFIERS 0xffffffff + +/* -- GLOBAL TYPE DEFINITIONS ---------------------------------------------- */ + +/* Freeglut callbacks type definitions */ +typedef void (* FGCBDisplay )( void ); +typedef void (* FGCBReshape )( int, int ); +typedef void (* FGCBVisibility )( int ); +typedef void (* FGCBKeyboard )( unsigned char, int, int ); +typedef void (* FGCBSpecial )( int, int, int ); +typedef void (* FGCBMouse )( int, int, int, int ); +typedef void (* FGCBMouseWheel )( int, int, int, int ); +typedef void (* FGCBMotion )( int, int ); +typedef void (* FGCBPassive )( int, int ); +typedef void (* FGCBEntry )( int ); +typedef void (* FGCBWindowStatus )( int ); +typedef void (* FGCBSelect )( int, int, int ); +typedef void (* FGCBJoystick )( unsigned int, int, int, int ); +typedef void (* FGCBKeyboardUp )( unsigned char, int, int ); +typedef void (* FGCBSpecialUp )( int, int, int ); +typedef void (* FGCBOverlayDisplay)( void ); +typedef void (* FGCBSpaceMotion )( int, int, int ); +typedef void (* FGCBSpaceRotation )( int, int, int ); +typedef void (* FGCBSpaceButton )( int, int ); +typedef void (* FGCBDials )( int, int ); +typedef void (* FGCBButtonBox )( int, int ); +typedef void (* FGCBTabletMotion )( int, int ); +typedef void (* FGCBTabletButton )( int, int, int, int ); +typedef void (* FGCBDestroy )( void ); + +/* The global callbacks type definitions */ +typedef void (* FGCBIdle )( void ); +typedef void (* FGCBTimer )( int ); +typedef void (* FGCBMenuState )( int ); +typedef void (* FGCBMenuStatus )( int, int, int ); + +/* The callback used when creating/using menus */ +typedef void (* FGCBMenu )( int ); + + +/* A list structure */ +typedef struct tagSFG_List SFG_List; +struct tagSFG_List +{ + void *First; + void *Last; +}; + +/* A list node structure */ +typedef struct tagSFG_Node SFG_Node; +struct tagSFG_Node +{ + void *Next; + void *Prev; +}; + +/* A helper structure holding two ints and a boolean */ +typedef struct tagSFG_XYUse SFG_XYUse; +struct tagSFG_XYUse +{ + GLint X, Y; /* The two integers... */ + GLboolean Use; /* ...and a single boolean. */ +}; + +/* + * An enumeration containing the state of the GLUT execution: + * initializing, running, or stopping + */ +typedef enum +{ + GLUT_EXEC_STATE_INIT, + GLUT_EXEC_STATE_RUNNING, + GLUT_EXEC_STATE_STOP +} fgExecutionState ; + +/* This structure holds different freeglut settings */ +typedef struct tagSFG_State SFG_State; +struct tagSFG_State +{ + SFG_XYUse Position; /* The default windows' position */ + SFG_XYUse Size; /* The default windows' size */ + unsigned int DisplayMode; /* Display mode for new windows */ + + GLboolean Initialised; /* freeglut has been initialised */ + + int DirectContext; /* Direct rendering state */ + + GLboolean ForceIconic; /* New top windows are iconified */ + GLboolean UseCurrentContext; /* New windows share with current */ + + GLboolean GLDebugSwitch; /* OpenGL state debugging switch */ + GLboolean XSyncSwitch; /* X11 sync protocol switch */ + + int KeyRepeat; /* Global key repeat mode. */ + int Modifiers; /* Current ALT/SHIFT/CTRL state */ + + GLuint FPSInterval; /* Interval between FPS printfs */ + GLuint SwapCount; /* Count of glutSwapBuffer calls */ + GLuint SwapTime; /* Time of last SwapBuffers */ + + unsigned long Time; /* Time that glutInit was called */ + SFG_List Timers; /* The freeglut timer hooks */ + SFG_List FreeTimers; /* The unused timer hooks */ + + FGCBIdle IdleCallback; /* The global idle callback */ + + int ActiveMenus; /* Num. of currently active menus */ + FGCBMenuState MenuStateCallback; /* Menu callbacks are global */ + FGCBMenuStatus MenuStatusCallback; + + SFG_XYUse GameModeSize; /* Game mode screen's dimensions */ + int GameModeDepth; /* The pixel depth for game mode */ + int GameModeRefresh; /* The refresh rate for game mode */ + + int ActionOnWindowClose; /* Action when user closes window */ + + fgExecutionState ExecState; /* Used for GLUT termination */ + char *ProgramName; /* Name of the invoking program */ + GLboolean JoysticksInitialised; /* Only initialize if application calls for them */ + GLboolean InputDevsInitialised; /* Only initialize if application calls for them */ + + int AuxiliaryBufferNumber; /* Number of auxiliary buffers */ + int SampleNumber; /* Number of samples per pixel */ + + int MajorVersion; /* Major OpenGL context version */ + int MinorVersion; /* Minor OpenGL context version */ + int ContextFlags; /* OpenGL context flags */ + int ContextProfile; /* OpenGL context profile */ +}; + +/* The structure used by display initialization in freeglut_init.c */ +typedef struct tagSFG_Display SFG_Display; +struct tagSFG_Display +{ +#if TARGET_HOST_POSIX_X11 + Display* Display; /* The display we are being run in. */ + int Screen; /* The screen we are about to use. */ + Window RootWindow; /* The screen's root window. */ + int Connection; /* The display's connection number */ + Atom DeleteWindow; /* The window deletion atom */ + Atom State; /* The state atom */ + Atom StateFullScreen; /* The full screen atom */ + +#ifdef X_XF86VidModeGetModeLine + /* + * XF86VidMode may be compilable even if it fails at runtime. Therefore, + * the validity of the VidMode has to be tracked + */ + int DisplayModeValid; /* Flag that indicates runtime status*/ + XF86VidModeModeLine DisplayMode; /* Current screen's display settings */ + int DisplayModeClock; /* The display mode's refresh rate */ + int DisplayViewPortX; /* saved X location of the viewport */ + int DisplayViewPortY; /* saved Y location of the viewport */ + int DisplayPointerX; /* saved X location of the pointer */ + int DisplayPointerY; /* saved Y location of the pointer */ + +#endif /* X_XF86VidModeGetModeLine */ + +#elif TARGET_HOST_MS_WINDOWS + HINSTANCE Instance; /* The application's instance */ + DEVMODE DisplayMode; /* Desktop's display settings */ + +#endif + + int ScreenWidth; /* The screen's width in pixels */ + int ScreenHeight; /* The screen's height in pixels */ + int ScreenWidthMM; /* The screen's width in milimeters */ + int ScreenHeightMM; /* The screen's height in milimeters */ +}; + + +/* The user can create any number of timer hooks */ +typedef struct tagSFG_Timer SFG_Timer; +struct tagSFG_Timer +{ + SFG_Node Node; + int ID; /* The timer ID integer */ + FGCBTimer Callback; /* The timer callback */ + long TriggerTime; /* The timer trigger time */ +}; + +/* + * Make "freeglut" window handle and context types so that we don't need so + * much conditionally-compiled code later in the library. + */ +#if TARGET_HOST_POSIX_X11 + +typedef Window SFG_WindowHandleType ; +typedef GLXContext SFG_WindowContextType ; + +#elif TARGET_HOST_MS_WINDOWS + +typedef HWND SFG_WindowHandleType ; +typedef HGLRC SFG_WindowContextType ; + +#endif + +/* + * A window and its OpenGL context. The contents of this structure + * are highly dependant on the target operating system we aim at... + */ +typedef struct tagSFG_Context SFG_Context; +struct tagSFG_Context +{ + SFG_WindowHandleType Handle; /* The window's handle */ + SFG_WindowContextType Context; /* The window's OpenGL/WGL context */ + +#if TARGET_HOST_POSIX_X11 + GLXFBConfig* FBConfig; /* The window's FBConfig */ +#elif TARGET_HOST_MS_WINDOWS + HDC Device; /* The window's device context */ +#endif + + int DoubleBuffered; /* Treat the window as double-buffered */ +}; + +/* Window's state description. This structure should be kept portable. */ +typedef struct tagSFG_WindowState SFG_WindowState; +struct tagSFG_WindowState +{ + int Width; /* Window's width in pixels */ + int Height; /* The same about the height */ + int OldWidth; /* Window width from before a resize */ + int OldHeight; /* " height " " " " */ + + GLboolean Redisplay; /* Do we have to redisplay? */ + GLboolean Visible; /* Is the window visible now */ + + int Cursor; /* The currently selected cursor */ + + long JoystickPollRate; /* The joystick polling rate */ + long JoystickLastPoll; /* When the last poll happened */ + + int MouseX, MouseY; /* The most recent mouse position */ + + GLboolean IgnoreKeyRepeat; /* Whether to ignore key repeat. */ + GLboolean KeyRepeating; /* Currently in repeat mode */ + + GLboolean NeedToResize; /* Do we need to resize the window? */ + + GLboolean IsFullscreen; /* is the window fullscreen? */ +}; + + +/* + * A generic function pointer. We should really use the GLUTproc type + * defined in freeglut_ext.h, but if we include that header in this file + * a bunch of other stuff (font-related) blows up! + */ +typedef void (*SFG_Proc)(); + + +/* + * SET_WCB() is used as: + * + * SET_WCB( window, cbname, func ); + * + * ...where {window} is the freeglut window to set the callback, + * {cbname} is the window-specific callback to set, + * {func} is a function-pointer. + * + * Originally, {FETCH_WCB( ... ) = func} was rather sloppily used, + * but this can cause warnings because the FETCH_WCB() macro type- + * casts its result, and a type-cast value shouldn't be an lvalue. + * + * The {if( FETCH_WCB( ... ) != func )} test is to do type-checking + * and for no other reason. Since it's hidden in the macro, the + * ugliness is felt to be rather benign. + */ +#define SET_WCB(window,cbname,func) \ +do \ +{ \ + if( FETCH_WCB( window, cbname ) != (SFG_Proc)(func) ) \ + (((window).CallBacks[CB_ ## cbname]) = (SFG_Proc)(func)); \ +} while( 0 ) + +/* + * FETCH_WCB() is used as: + * + * FETCH_WCB( window, cbname ); + * + * ...where {window} is the freeglut window to fetch the callback from, + * {cbname} is the window-specific callback to fetch. + * + * The result is correctly type-cast to the callback function pointer + * type. + */ +#define FETCH_WCB(window,cbname) \ + ((window).CallBacks[CB_ ## cbname]) + +/* + * INVOKE_WCB() is used as: + * + * INVOKE_WCB( window, cbname, ( arg_list ) ); + * + * ...where {window} is the freeglut window, + * {cbname} is the window-specific callback to be invoked, + * {(arg_list)} is the parameter list. + * + * The callback is invoked as: + * + * callback( arg_list ); + * + * ...so the parentheses are REQUIRED in the {arg_list}. + * + * NOTE that it does a sanity-check and also sets the + * current window. + * + */ +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: also WinCE? */ +#define INVOKE_WCB(window,cbname,arg_list) \ +do \ +{ \ + if( FETCH_WCB( window, cbname ) ) \ + { \ + FGCB ## cbname func = (FGCB ## cbname)(FETCH_WCB( window, cbname )); \ + fgSetWindow( &window ); \ + func arg_list; \ + } \ +} while( 0 ) +#else +#define INVOKE_WCB(window,cbname,arg_list) \ +do \ +{ \ + if( FETCH_WCB( window, cbname ) ) \ + { \ + fgSetWindow( &window ); \ + ((FGCB ## cbname)FETCH_WCB( window, cbname )) arg_list; \ + } \ +} while( 0 ) +#endif + +/* + * The window callbacks the user can supply us with. Should be kept portable. + * + * This enumeration provides the freeglut CallBack numbers. + * The symbolic constants are indices into a window's array of + * function callbacks. The names are formed by splicing a common + * prefix onto the callback's base name. (This was originally + * done so that an early stage of development could live side-by- + * side with the old callback code. The old callback code used + * the bare callback's name as a structure member, so I used a + * prefix for the array index name.) + * + * XXX For consistancy, perhaps the prefix should match the + * XXX FETCH* and INVOKE* macro suffices. I.e., WCB_, rather than + * XXX CB_. + */ +enum +{ + CB_Display, + CB_Reshape, + CB_Keyboard, + CB_KeyboardUp, + CB_Special, + CB_SpecialUp, + CB_Mouse, + CB_MouseWheel, + CB_Motion, + CB_Passive, + CB_Entry, + CB_Visibility, + CB_WindowStatus, + CB_Joystick, + CB_Destroy, + + /* Presently ignored */ + CB_Select, + CB_OverlayDisplay, + CB_SpaceMotion, /* presently implemented only on UNIX/X11 */ + CB_SpaceRotation, /* presently implemented only on UNIX/X11 */ + CB_SpaceButton, /* presently implemented only on UNIX/X11 */ + CB_Dials, + CB_ButtonBox, + CB_TabletMotion, + CB_TabletButton, + + /* Always make this the LAST one */ + TOTAL_CALLBACKS +}; + + +/* This structure holds the OpenGL rendering context for all the menu windows */ +typedef struct tagSFG_MenuContext SFG_MenuContext; +struct tagSFG_MenuContext +{ + SFG_WindowContextType MContext; /* The menu window's WGL context */ +}; + +/* This structure describes a menu */ +typedef struct tagSFG_Window SFG_Window; +typedef struct tagSFG_MenuEntry SFG_MenuEntry; +typedef struct tagSFG_Menu SFG_Menu; +struct tagSFG_Menu +{ + SFG_Node Node; + void *UserData; /* User data passed back at callback */ + int ID; /* The global menu ID */ + SFG_List Entries; /* The menu entries list */ + FGCBMenu Callback; /* The menu callback */ + FGCBDestroy Destroy; /* Destruction callback */ + GLboolean IsActive; /* Is the menu selected? */ + int Width; /* Menu box width in pixels */ + int Height; /* Menu box height in pixels */ + int X, Y; /* Menu box raster position */ + + SFG_MenuEntry *ActiveEntry; /* Currently active entry in the menu */ + SFG_Window *Window; /* Window for menu */ + SFG_Window *ParentWindow; /* Window in which the menu is invoked */ +}; + +/* This is a menu entry */ +struct tagSFG_MenuEntry +{ + SFG_Node Node; + int ID; /* The menu entry ID (local) */ + int Ordinal; /* The menu's ordinal number */ + char* Text; /* The text to be displayed */ + SFG_Menu* SubMenu; /* Optional sub-menu tree */ + GLboolean IsActive; /* Is the entry highlighted? */ + int Width; /* Label's width in pixels */ +}; + +/* + * A window, making part of freeglut windows hierarchy. + * Should be kept portable. + * + * NOTE that ActiveMenu is set to menu itself if the window is a menu. + */ +struct tagSFG_Window +{ + SFG_Node Node; + int ID; /* Window's ID number */ + + SFG_Context Window; /* Window and OpenGL context */ + SFG_WindowState State; /* The window state */ + SFG_Proc CallBacks[ TOTAL_CALLBACKS ]; /* Array of window callbacks */ + void *UserData ; /* For use by user */ + + SFG_Menu* Menu[ FREEGLUT_MAX_MENUS ]; /* Menus appended to window */ + SFG_Menu* ActiveMenu; /* The window's active menu */ + + SFG_Window* Parent; /* The parent to this window */ + SFG_List Children; /* The subwindows d.l. list */ + + GLboolean IsMenu; /* Set to 1 if we are a menu */ +}; + + +/* A linked list structure of windows */ +typedef struct tagSFG_WindowList SFG_WindowList ; +struct tagSFG_WindowList +{ + SFG_Node node; + SFG_Window *window ; +}; + +/* This holds information about all the windows, menus etc. */ +typedef struct tagSFG_Structure SFG_Structure; +struct tagSFG_Structure +{ + SFG_List Windows; /* The global windows list */ + SFG_List Menus; /* The global menus list */ + SFG_List WindowsToDestroy; + + SFG_Window* CurrentWindow; /* The currently set window */ + SFG_Menu* CurrentMenu; /* Same, but menu... */ + + SFG_MenuContext* MenuContext; /* OpenGL rendering context for menus */ + + SFG_Window* GameModeWindow; /* The game mode window */ + + int WindowID; /* The new current window ID */ + int MenuID; /* The new current menu ID */ +}; + +/* + * This structure is used for the enumeration purposes. + * You can easily extend its functionalities by declaring + * a structure containing enumerator's contents and custom + * data, then casting its pointer to (SFG_Enumerator *). + */ +typedef struct tagSFG_Enumerator SFG_Enumerator; +struct tagSFG_Enumerator +{ + GLboolean found; /* Used to terminate search */ + void* data; /* Custom data pointer */ +}; +typedef void (* FGCBenumerator )( SFG_Window *, SFG_Enumerator * ); + +/* The bitmap font structure */ +typedef struct tagSFG_Font SFG_Font; +struct tagSFG_Font +{ + char* Name; /* The source font name */ + int Quantity; /* Number of chars in font */ + int Height; /* Height of the characters */ + const GLubyte** Characters; /* The characters mapping */ + + float xorig, yorig; /* Relative origin of the character */ +}; + +/* The stroke font structures */ + +typedef struct tagSFG_StrokeVertex SFG_StrokeVertex; +struct tagSFG_StrokeVertex +{ + GLfloat X, Y; +}; + +typedef struct tagSFG_StrokeStrip SFG_StrokeStrip; +struct tagSFG_StrokeStrip +{ + int Number; + const SFG_StrokeVertex* Vertices; +}; + +typedef struct tagSFG_StrokeChar SFG_StrokeChar; +struct tagSFG_StrokeChar +{ + GLfloat Right; + int Number; + const SFG_StrokeStrip* Strips; +}; + +typedef struct tagSFG_StrokeFont SFG_StrokeFont; +struct tagSFG_StrokeFont +{ + char* Name; /* The source font name */ + int Quantity; /* Number of chars in font */ + GLfloat Height; /* Height of the characters */ + const SFG_StrokeChar** Characters; /* The characters mapping */ +}; + +/* -- GLOBAL VARIABLES EXPORTS --------------------------------------------- */ + +/* Freeglut display related stuff (initialized once per session) */ +extern SFG_Display fgDisplay; + +/* Freeglut internal structure */ +extern SFG_Structure fgStructure; + +/* The current freeglut settings */ +extern SFG_State fgState; + + +/* -- PRIVATE FUNCTION DECLARATIONS ---------------------------------------- */ + +/* + * A call to this function makes us sure that the Display and Structure + * subsystems have been properly initialized and are ready to be used + */ +#define FREEGLUT_EXIT_IF_NOT_INITIALISED( string ) \ + if ( ! fgState.Initialised ) \ + { \ + fgError ( " ERROR: Function <%s> called" \ + " without first calling 'glutInit'.", (string) ) ; \ + } + +#define FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED( string ) \ + if ( ! fgState.Initialised ) \ + { \ + fgError ( " ERROR: Internal <%s> function called" \ + " without first calling 'glutInit'.", (string) ) ; \ + } + +#define FREEGLUT_INTERNAL_ERROR_EXIT( cond, string, function ) \ + if ( ! ( cond ) ) \ + { \ + fgError ( " ERROR: Internal error <%s> in function %s", \ + (string), (function) ) ; \ + } + +/* + * Following definitions are somewhat similiar to GLib's, + * but do not generate any log messages: + */ +#define freeglut_return_if_fail( expr ) \ + if( !(expr) ) \ + return; +#define freeglut_return_val_if_fail( expr, val ) \ + if( !(expr) ) \ + return val ; + +/* + * A call to those macros assures us that there is a current + * window set, respectively: + */ +#define FREEGLUT_EXIT_IF_NO_WINDOW( string ) \ + if ( ! fgStructure.CurrentWindow ) \ + { \ + fgError ( " ERROR: Function <%s> called" \ + " with no current window defined.", (string) ) ; \ + } + +/* + * The deinitialize function gets called on glutMainLoop() end. It should clean up + * everything inside of the freeglut + */ +void fgDeinitialize( void ); + +/* + * Those two functions are used to create/destroy the freeglut internal + * structures. This actually happens when calling glutInit() and when + * quitting the glutMainLoop() (which actually happens, when all windows + * have been closed). + */ +void fgCreateStructure( void ); +void fgDestroyStructure( void ); + +/* A helper function to check if a display mode is possible to use */ +#if TARGET_HOST_POSIX_X11 +GLXFBConfig* fgChooseFBConfig( void ); +#endif + +/* The window procedure for Win32 events handling */ +#if TARGET_HOST_MS_WINDOWS +LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam ); +void fgNewWGLCreateContext( SFG_Window* window ); +GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, + unsigned char layer_type ); +#endif + +/* + * Window creation, opening, closing and destruction. + * Also CallBack clearing/initialization. + * Defined in freeglut_structure.c, freeglut_window.c. + */ +SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title, + GLboolean positionUse, int x, int y, + GLboolean sizeUse, int w, int h, + GLboolean gameMode, GLboolean isMenu ); +void fgSetWindow ( SFG_Window *window ); +void fgOpenWindow( SFG_Window* window, const char* title, + GLboolean positionUse, int x, int y, + GLboolean sizeUse, int w, int h, + GLboolean gameMode, GLboolean isSubWindow ); +void fgCloseWindow( SFG_Window* window ); +void fgAddToWindowDestroyList ( SFG_Window* window ); +void fgCloseWindows (); +void fgDestroyWindow( SFG_Window* window ); + +/* Menu creation and destruction. Defined in freeglut_structure.c */ +SFG_Menu* fgCreateMenu( FGCBMenu menuCallback ); +void fgDestroyMenu( SFG_Menu* menu ); + +/* Joystick device management functions, defined in freeglut_joystick.c */ +int fgJoystickDetect( void ); +void fgInitialiseJoysticks( void ); +void fgJoystickClose( void ); +void fgJoystickPollWindow( SFG_Window* window ); + +/* InputDevice Initialisation and Closure */ +int fgInputDeviceDetect( void ); +void fgInitialiseInputDevices( void ); +void fgInputDeviceClose( void ); + +/* spaceball device functions, defined in freeglut_spaceball.c */ +void fgInitialiseSpaceball( void ); +void fgSpaceballClose( void ); +void fgSpaceballSetWindow( SFG_Window *window ); + +int fgHasSpaceball( void ); +int fgSpaceballNumButtons( void ); + +#if TARGET_HOST_POSIX_X11 +int fgIsSpaceballXEvent( const XEvent *ev ); +void fgSpaceballHandleXEvent( const XEvent *ev ); +#endif + +/* Setting the cursor for a given window */ +void fgSetCursor ( SFG_Window *window, int cursorID ); + +/* + * Helper function to enumerate through all registered windows + * and one to enumerate all of a window's subwindows... + * + * The GFunc callback for those functions will be defined as: + * + * void enumCallback( gpointer window, gpointer enumerator ); + * + * where window is the enumerated (sub)window pointer (SFG_Window *), + * and userData is the a custom user-supplied pointer. Functions + * are defined and exported from freeglut_structure.c file. + */ +void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator ); +void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback, + SFG_Enumerator* enumerator ); + +/* + * fgWindowByHandle returns a (SFG_Window *) value pointing to the + * first window in the queue matching the specified window handle. + * The function is defined in freeglut_structure.c file. + */ +SFG_Window* fgWindowByHandle( SFG_WindowHandleType hWindow ); + +/* + * This function is similiar to the previous one, except it is + * looking for a specified (sub)window identifier. The function + * is defined in freeglut_structure.c file. + */ +SFG_Window* fgWindowByID( int windowID ); + +/* + * Looks up a menu given its ID. This is easier than fgWindowByXXX + * as all menus are placed in a single doubly linked list... + */ +SFG_Menu* fgMenuByID( int menuID ); + +/* + * The menu activation and deactivation the code. This is the meat + * of the menu user interface handling code... + */ +void fgUpdateMenuHighlight ( SFG_Menu *menu ); +GLboolean fgCheckActiveMenu ( SFG_Window *window, int button, GLboolean pressed, + int mouse_x, int mouse_y ); +void fgDeactivateMenu( SFG_Window *window ); + +/* + * This function gets called just before the buffers swap, so that + * freeglut can display the pull-down menus via OpenGL. The function + * is defined in freeglut_menu.c file. + */ +void fgDisplayMenu( void ); + +/* Elapsed time as per glutGet(GLUT_ELAPSED_TIME). */ +long fgElapsedTime( void ); + +/* System time in milliseconds */ +long unsigned fgSystemTime(void); + +/* List functions */ +void fgListInit(SFG_List *list); +void fgListAppend(SFG_List *list, SFG_Node *node); +void fgListRemove(SFG_List *list, SFG_Node *node); +int fgListLength(SFG_List *list); +void fgListInsert(SFG_List *list, SFG_Node *next, SFG_Node *node); + +/* Error Message functions */ +void fgError( const char *fmt, ... ); +void fgWarning( const char *fmt, ... ); + +/* + * Check if "hint" is present in "property" for "window". See freeglut_init.c + */ +#if TARGET_HOST_POSIX_X11 +int fgHintPresent(Window window, Atom property, Atom hint); +#endif + +SFG_Proc fghGetProcAddress( const char *procName ); + +#if TARGET_HOST_MS_WINDOWS +extern void (__cdecl *__glutExitFunc)( int return_value ); +#endif + +#endif /* FREEGLUT_INTERNAL_H */ + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_joystick.c b/tests/Box2D_v2.2.1/freeglut/freeglut_joystick.c new file mode 100755 index 0000000000000..47127f5453742 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_joystick.c @@ -0,0 +1,1801 @@ +/* + * freeglut_joystick.c + * + * Joystick handling code + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Steve Baker, + * + * 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 + * PAWEL W. OLSZTA 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. + */ + +/* + * FreeBSD port by Stephen Montgomery-Smith + * + * Redone by John Fay 2/4/04 with another look from the PLIB "js" library. + * Many thanks for Steve Baker for permission to pull from that library. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" +#if HAVE_SYS_PARAM_H +# include +#endif + +/* + * Initial defines from "js.h" starting around line 33 with the existing "freeglut_joystick.c" + * interspersed + */ + +/* XXX It might be better to poll the operating system for the numbers of buttons and + * XXX axes and then dynamically allocate the arrays. + */ +#define _JS_MAX_BUTTONS 32 + +#if TARGET_HOST_MACINTOSH +# define _JS_MAX_AXES 9 +# include +#endif + +#if TARGET_HOST_MAC_OSX +# define _JS_MAX_AXES 16 +# include +# include +# include +#endif + +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) +# define _JS_MAX_AXES 8 +# include +# include +# include + +#endif + +#if TARGET_HOST_POSIX_X11 +# define _JS_MAX_AXES 16 +# if HAVE_SYS_IOCTL_H +# include +# endif +# if HAVE_FCNTL_H +# include +# endif +# if HAVE_ERRNO +# include +# endif +# if defined(__FreeBSD__) || defined(__NetBSD__) +/* XXX The below hack is done until freeglut's autoconf is updated. */ +# define HAVE_USB_JS 1 + +# if defined(__FreeBSD__) +# include +# else +/* + * XXX NetBSD/amd64 systems may find that they have to steal the + * XXX /usr/include/machine/joystick.h from a NetBSD/i386 system. + * XXX I cannot comment whether that works for the interface, but + * XXX it lets you compile...(^& I do not think that we can do away + * XXX with this header. + */ +# include /* For analog joysticks */ +# endif +# define JS_DATA_TYPE joystick +# define JS_RETURN (sizeof(struct JS_DATA_TYPE)) +# endif + +# if defined(__linux__) +# include + +/* check the joystick driver version */ +# if defined(JS_VERSION) && JS_VERSION >= 0x010000 +# define JS_NEW +# endif +# else /* Not BSD or Linux */ +# ifndef JS_RETURN + + /* + * We'll put these values in and that should + * allow the code to at least compile when there is + * no support. The JS open routine should error out + * and shut off all the code downstream anyway and if + * the application doesn't use a joystick we'll be fine. + */ + + struct JS_DATA_TYPE + { + int buttons; + int x; + int y; + }; + +# define JS_RETURN (sizeof(struct JS_DATA_TYPE)) +# endif +# endif +#endif + +#define JS_TRUE 1 +#define JS_FALSE 0 + +/* BSD defines from "jsBSD.cxx" around lines 42-270 */ + +#if defined(__NetBSD__) || defined(__FreeBSD__) + +# ifdef HAVE_USB_JS +# if defined(__NetBSD__) +/* XXX The below hack is done until freeglut's autoconf is updated. */ +# define HAVE_USBHID_H 1 +# ifdef HAVE_USBHID_H +# include +# else +# include +# endif +# elif defined(__FreeBSD__) +# if __FreeBSD_version < 500000 +# include +# else +/* XXX The below hack is done until freeglut's autoconf is updated. */ +# define HAVE_USBHID_H 1 +# include +# endif +# endif +# include +# include + +/* Compatibility with older usb.h revisions */ +# if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES) +# define USB_MAX_DEVNAMES MAXDEVNAMES +# endif +# endif + +static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 }; +static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 }; +struct os_specific_s { + char fname [128 ]; + int fd; + int is_analog; + /* The following structure members are specific to analog joysticks */ + struct joystick ajs; +# ifdef HAVE_USB_JS + /* The following structure members are specific to USB joysticks */ + struct hid_item *hids; + int hid_dlen; + int hid_offset; + char *hid_data_buf; + int axes_usage [ _JS_MAX_AXES ]; +# endif + /* We keep button and axes state ourselves, as they might not be updated + * on every read of a USB device + */ + int cache_buttons; + float cache_axes [ _JS_MAX_AXES ]; +}; + +/* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */ +# define USB_IDENT_OFFSET 2 + +# define USBDEV "/dev/usb" +# define UHIDDEV "/dev/uhid" +# define AJSDEV "/dev/joy" + +# ifdef HAVE_USB_JS +/* + * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate + * the full name of a USB device. If /dev/usbN isn't readable, we punt and + * return the uhidN device name. We warn the user of this situation once. + */ +static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen) +{ + struct usb_device_info di; + int i, a; + char *cp; + + for (a = 1; a < USB_MAX_DEVICES; a++) { + di.udi_addr = a; + if (ioctl(f, USB_DEVICEINFO, &di) != 0) + return NULL; + for (i = 0; i < USB_MAX_DEVNAMES; i++) + if (di.udi_devnames[i][0] && + strcmp(di.udi_devnames[i], dev) == 0) { + cp = calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2); + strcpy(cp, di.udi_vendor); + strcat(cp, " "); + strcat(cp, di.udi_product); + strncpy(out, cp, outlen - 1); + out[outlen - 1] = 0; + free( cp ); + return out; + } + } + return NULL; +} + +static int fghJoystickFindUSBdev(char *name, char *out, int outlen) +{ + int i, f; + char buf[50]; + char *cp; + static int protection_warned = 0; + + for (i = 0; i < 16; i++) { + snprintf(buf, sizeof(buf), "%s%d", USBDEV, i); + f = open(buf, O_RDONLY); + if (f >= 0) { + cp = fghJoystickWalkUSBdev(f, name, out, outlen); + close(f); + if (cp) + return 1; + } +#if HAVE_ERRNO + else if (errno == EACCES) { + if (!protection_warned) { + fgWarning ( "Can't open %s for read!", buf ); + protection_warned = 1; + } + } +#endif + } + return 0; +} + +static int fghJoystickInitializeHID(struct os_specific_s *os, + int *num_axes, int *num_buttons) +{ + int size, is_joystick; +# ifdef HAVE_USBHID_H + int report_id = 0; +# endif + struct hid_data *d; + struct hid_item h; + report_desc_t rd; + + if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 ) + { +#if HAVE_ERRNO + fgWarning ( "error: %s: %s", os->fname, strerror( errno ) ); +#else + fgWarning ( "error: %s", os->fname ); +#endif + return FALSE; + } + + os->hids = NULL; + +# ifdef HAVE_USBHID_H + if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0) + { + /*** XXX {report_id} may not be the right variable? ***/ +#if HAVE_ERRNO + fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) ); +#else + fgWarning ( "error: %s%d", UHIDDEV, report_id ); +#endif + return FALSE; + } + + size = hid_report_size( rd, hid_input, report_id ); +# else + size = hid_report_size( rd, 0, hid_input ); +# endif + os->hid_data_buf = calloc( 1, size ); + os->hid_dlen = size; + + is_joystick = 0; +# ifdef HAVE_USBHID_H + d = hid_start_parse( rd, 1 << hid_input, report_id ); +# else + d = hid_start_parse( rd, 1 << hid_input ); +# endif + while( hid_get_item( d, &h ) ) + { + int usage, page, interesting_hid; + + page = HID_PAGE( h.usage ); + usage = HID_USAGE( h.usage ); + + /* This test is somewhat too simplistic, but this is how MicroSoft + * does, so I guess it works for all joysticks/game pads. */ + is_joystick = is_joystick || + ( h.kind == hid_collection && + page == HUP_GENERIC_DESKTOP && + ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) ); + + if( h.kind != hid_input ) + continue; + + if( !is_joystick ) + continue; + + interesting_hid = TRUE; + if( page == HUP_GENERIC_DESKTOP ) + { + switch( usage ) + { + case HUG_X: + case HUG_RX: + case HUG_Y: + case HUG_RY: + case HUG_Z: + case HUG_RZ: + case HUG_SLIDER: + if( *num_axes < _JS_MAX_AXES ) + { + os->axes_usage[ *num_axes ] = usage; + ( *num_axes )++; + } + break; + case HUG_HAT_SWITCH: + /* Allocate two axes for a hat */ + if( *num_axes + 1 < _JS_MAX_AXES ) + { + os->axes_usage[ *num_axes ] = usage; + (*num_axes)++; + os->axes_usage[ *num_axes ] = usage; + (*num_axes)++; + } + break; + default: + interesting_hid = FALSE; + break; + } + } + else if( page == HUP_BUTTON ) + { + interesting_hid = ( usage > 0 ) && + ( usage <= _JS_MAX_BUTTONS ); + + if( interesting_hid && usage - 1 > *num_buttons ) + *num_buttons = usage - 1; + } + + if( interesting_hid ) + { + h.next = os->hids; + os->hids = calloc( 1, sizeof ( struct hid_item ) ); + *os->hids = h; + } + } + hid_end_parse( d ); + + return os->hids != NULL; +} +# endif +#endif + +/* + * Definition of "SFG_Joystick" structure -- based on JS's "jsJoystick" object class. + * See "js.h" lines 80-178. + */ +typedef struct tagSFG_Joystick SFG_Joystick; +struct tagSFG_Joystick +{ +#if TARGET_HOST_MACINTOSH +#define ISP_NUM_AXIS 9 +#define ISP_NUM_NEEDS 41 + ISpElementReference isp_elem [ ISP_NUM_NEEDS ]; + ISpNeed isp_needs [ ISP_NUM_NEEDS ]; +#endif + +#if TARGET_HOST_MAC_OSX + IOHIDDeviceInterface ** hidDev; + IOHIDElementCookie buttonCookies[41]; + IOHIDElementCookie axisCookies[_JS_MAX_AXES]; + long minReport[_JS_MAX_AXES], + maxReport[_JS_MAX_AXES]; +#endif + +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + JOYCAPS jsCaps; + JOYINFOEX js; + UINT js_id; +#endif + + +#if TARGET_HOST_POSIX_X11 +# if defined(__FreeBSD__) || defined(__NetBSD__) + struct os_specific_s *os; +# endif + +# ifdef JS_NEW + struct js_event js; + int tmp_buttons; + float tmp_axes [ _JS_MAX_AXES ]; +# else + struct JS_DATA_TYPE js; +# endif + + char fname [ 128 ]; + int fd; +#endif + + int id; + GLboolean error; + char name [ 128 ]; + int num_axes; + int num_buttons; + + float dead_band[ _JS_MAX_AXES ]; + float saturate [ _JS_MAX_AXES ]; + float center [ _JS_MAX_AXES ]; + float max [ _JS_MAX_AXES ]; + float min [ _JS_MAX_AXES ]; +}; + +/* + * Functions associated with the "jsJoystick" class in PLIB + */ +#if TARGET_HOST_MAC_OSX +#define K_NUM_DEVICES 32 +int numDevices; +io_object_t ioDevices[K_NUM_DEVICES]; + +static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t ); +static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t ); + +static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element ); +/* callback for CFArrayApply */ +static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs ); + +static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis ); +static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button ); +static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat ); +#endif + + +/* + * The static joystick structure pointer + */ +#define MAX_NUM_JOYSTICKS 2 +static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ]; + + +/* + * Read the raw joystick data + */ +static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes ) +{ +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + MMRESULT status; +#else + int status; +#endif + +#if defined(__FreeBSD__) || defined(__NetBSD__) + int len; +#endif + + int i; + + /* Defaults */ + if( buttons ) + *buttons = 0; + + if( axes ) + for( i = 0; i < joy->num_axes; i++ ) + axes[ i ] = 1500.0f; + + if( joy->error ) + return; + +#if TARGET_HOST_MACINTOSH + if ( buttons ) + { + *buttons = 0; + + for ( i = 0; i < joy->num_buttons; i++ ) + { + UInt32 state; + int err = ISpElement_GetSimpleState ( isp_elem [ i + isp_num_axis ], &state); + ISP_CHECK_ERR(err) + + *buttons |= state << i; + } + } + + if ( axes ) + { + for ( i = 0; i < joy->num_axes; i++ ) + { + UInt32 state; + int err = ISpElement_GetSimpleState ( isp_elem [ i ], &state ); + ISP_CHECK_ERR(err) + + axes [i] = (float) state; + } + } +#endif + +#if TARGET_HOST_MAC_OSX + if ( buttons != NULL ) + { + *buttons = 0; + + for ( i = 0; i < joy->num_buttons; i++ ) + { + IOHIDEventStruct hidEvent; + (*(joy->hidDev))->getElementValue ( joy->hidDev, buttonCookies[i], &hidEvent ); + if ( hidEvent.value ) + *buttons |= 1 << i; + } + } + + if ( axes != NULL ) + { + for ( i = 0; i < joy->num_axes; i++ ) + { + IOHIDEventStruct hidEvent; + (*(joy->hidDev))->getElementValue ( joy->hidDev, axisCookies[i], &hidEvent ); + axes[i] = hidEvent.value; + } + } +#endif + +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + status = joyGetPosEx( joy->js_id, &joy->js ); + + if ( status != JOYERR_NOERROR ) + { + joy->error = GL_TRUE; + return; + } + + if ( buttons ) + *buttons = joy->js.dwButtons; + + if ( axes ) + { + /* + * WARNING - Fall through case clauses!! + */ + switch ( joy->num_axes ) + { + case 8: + /* Generate two POV axes from the POV hat angle. + * Low 16 bits of js.dwPOV gives heading (clockwise from ahead) in + * hundredths of a degree, or 0xFFFF when idle. + */ + if ( ( joy->js.dwPOV & 0xFFFF ) == 0xFFFF ) + { + axes [ 6 ] = 0.0; + axes [ 7 ] = 0.0; + } + else + { + /* This is the contentious bit: how to convert angle to X/Y. + * wk: I know of no define for PI that we could use here: + * SG_PI would pull in sg, M_PI is undefined for MSVC + * But the accuracy of the value of PI is very unimportant at + * this point. + */ + float s = (float) sin ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) ); + float c = (float) cos ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) ); + + /* Convert to coordinates on a square so that North-East + * is (1,1) not (.7,.7), etc. + * s and c cannot both be zero so we won't divide by zero. + */ + if ( fabs ( s ) < fabs ( c ) ) + { + axes [ 6 ] = ( c < 0.0 ) ? -s/c : s/c ; + axes [ 7 ] = ( c < 0.0 ) ? -1.0f : 1.0f; + } + else + { + axes [ 6 ] = ( s < 0.0 ) ? -1.0f : 1.0f; + axes [ 7 ] = ( s < 0.0 ) ? -c/s : c/s ; + } + } + + case 6: axes[5] = (float) joy->js.dwVpos; + case 5: axes[4] = (float) joy->js.dwUpos; + case 4: axes[3] = (float) joy->js.dwRpos; + case 3: axes[2] = (float) joy->js.dwZpos; + case 2: axes[1] = (float) joy->js.dwYpos; + case 1: axes[0] = (float) joy->js.dwXpos; + } + } +#endif + +#if TARGET_HOST_POSIX_X11 +# if defined(__FreeBSD__) || defined(__NetBSD__) + if ( joy->os->is_analog ) + { + int status = read ( joy->os->fd, &joy->os->ajs, sizeof(joy->os->ajs) ); + if ( status != sizeof(joy->os->ajs) ) { + perror ( joy->os->fname ); + joy->error = GL_TRUE; + return; + } + if ( buttons != NULL ) + *buttons = ( joy->os->ajs.b1 ? 1 : 0 ) | ( joy->os->ajs.b2 ? 2 : 0 ); + + if ( axes != NULL ) + { + axes[0] = (float) joy->os->ajs.x; + axes[1] = (float) joy->os->ajs.y; + } + + return; + } + +# ifdef HAVE_USB_JS + while ( ( len = read ( joy->os->fd, joy->os->hid_data_buf, joy->os->hid_dlen ) ) == joy->os->hid_dlen ) + { + struct hid_item *h; + + for ( h = joy->os->hids; h; h = h->next ) + { + int d = hid_get_data ( joy->os->hid_data_buf, h ); + + int page = HID_PAGE ( h->usage ); + int usage = HID_USAGE ( h->usage ); + + if ( page == HUP_GENERIC_DESKTOP ) + { + int i; + for ( i = 0; i < joy->num_axes; i++ ) + if (joy->os->axes_usage[i] == usage) + { + if (usage == HUG_HAT_SWITCH) + { + if (d < 0 || d > 8) + d = 0; /* safety */ + joy->os->cache_axes[i] = (float)hatmap_x[d]; + joy->os->cache_axes[i + 1] = (float)hatmap_y[d]; + } + else + { + joy->os->cache_axes[i] = (float)d; + } + break; + } + } + else if (page == HUP_BUTTON) + { + if (usage > 0 && usage < _JS_MAX_BUTTONS + 1) + { + if (d) + joy->os->cache_buttons |= (1 << ( usage - 1 )); + else + joy->os->cache_buttons &= ~(1 << ( usage - 1 )); + } + } + } + } +#if HAVE_ERRNO + if ( len < 0 && errno != EAGAIN ) +#else + if ( len < 0 ) +#endif + { + perror( joy->os->fname ); + joy->error = 1; + } + if ( buttons != NULL ) *buttons = joy->os->cache_buttons; + if ( axes != NULL ) + memcpy ( axes, joy->os->cache_axes, sizeof(float) * joy->num_axes ); +# endif +# endif + +# ifdef JS_NEW + + while ( 1 ) + { + status = read ( joy->fd, &joy->js, sizeof(struct js_event) ); + + if ( status != sizeof( struct js_event ) ) + { +#if HAVE_ERRNO + if ( errno == EAGAIN ) + { + /* Use the old values */ + if ( buttons ) + *buttons = joy->tmp_buttons; + if ( axes ) + memcpy( axes, joy->tmp_axes, + sizeof( float ) * joy->num_axes ); + return; + } +#endif + + fgWarning ( "%s", joy->fname ); + joy->error = GL_TRUE; + return; + } + + switch ( joy->js.type & ~JS_EVENT_INIT ) + { + case JS_EVENT_BUTTON: + if( joy->js.value == 0 ) /* clear the flag */ + joy->tmp_buttons &= ~( 1 << joy->js.number ); + else + joy->tmp_buttons |= ( 1 << joy->js.number ); + break; + + case JS_EVENT_AXIS: + if ( joy->js.number < joy->num_axes ) + { + joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value; + + if( axes ) + memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes ); + } + break; + + default: + fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" ); + + /* use the old values */ + + if ( buttons != NULL ) *buttons = joy->tmp_buttons; + if ( axes != NULL ) + memcpy ( axes, joy->tmp_axes, sizeof(float) * joy->num_axes ); + + return; + } + + if( buttons ) + *buttons = joy->tmp_buttons; + } +# else + + status = read( joy->fd, &joy->js, JS_RETURN ); + + if ( status != JS_RETURN ) + { + fgWarning( "%s", joy->fname ); + joy->error = GL_TRUE; + return; + } + + if ( buttons ) +# if defined( __FreeBSD__ ) || defined( __NetBSD__ ) + *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 ); /* XXX Should not be here -- BSD is handled earlier */ +# else + *buttons = joy->js.buttons; +# endif + + if ( axes ) + { + axes[ 0 ] = (float) joy->js.x; + axes[ 1 ] = (float) joy->js.y; + } +# endif +#endif +} + +/* + * Correct the joystick axis data + */ +static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis ) +{ + if( value < joy->center[ axis ] ) + { + float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] - + joy->min[ axis ] ); + + if( xx < -joy->saturate[ axis ] ) + return -1.0f; + + if( xx > -joy->dead_band [ axis ] ) + return 0.0f; + + xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] - + joy->dead_band[ axis ] ); + + return ( xx < -1.0f ) ? -1.0f : xx; + } + else + { + float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] - + joy->center[ axis ] ); + + if( xx > joy->saturate[ axis ] ) + return 1.0f; + + if( xx < joy->dead_band[ axis ] ) + return 0.0f; + + xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] - + joy->dead_band[ axis ] ); + + return ( xx > 1.0f ) ? 1.0f : xx; + } +} + +/* + * Read the corrected joystick data + */ +static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes ) +{ + float raw_axes[ _JS_MAX_AXES ]; + int i; + + if( joy->error ) + { + if( buttons ) + *buttons = 0; + + if( axes ) + for ( i=0; inum_axes; i++ ) + axes[ i ] = 0.0f; + } + + fghJoystickRawRead( joy, buttons, raw_axes ); + + if( axes ) + for( i=0; inum_axes; i++ ) + axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i ); +} + +/* + * Happy happy happy joy joy joy (happy new year toudi :D) + */ + + +#if TARGET_HOST_MAC_OSX +/** open the IOKit connection, enumerate all the HID devices, add their +interface references to the static array. We then use the array index +as the device number when we come to open() the joystick. */ +static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort ) +{ + CFMutableDictionaryRef hidMatch = NULL; + IOReturn rv = kIOReturnSuccess; + + io_iterator_t hidIterator; + io_object_t ioDev; + + /* build a dictionary matching HID devices */ + hidMatch = IOServiceMatching(kIOHIDDeviceKey); + + rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator); + if (rv != kIOReturnSuccess || !hidIterator) { + fgWarning( "no joystick (HID) devices found" ); + return; + } + + /* iterate */ + while ((ioDev = IOIteratorNext(hidIterator))) { + /* filter out keyboard and mouse devices */ + CFDictionaryRef properties = getCFProperties(ioDev); + long usage, page; + + CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey)); + CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey)); + CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage); + CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page); + + /* keep only joystick devices */ + if ( ( page == kHIDPage_GenericDesktop ) && ( + (usage == kHIDUsage_GD_Joystick) + || (usage == kHIDUsage_GD_GamePad) + || (usage == kHIDUsage_GD_MultiAxisController) + || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */ + /* add it to the array */ + ioDevices[numDevices++] = ioDev; + } + + IOObjectRelease(hidIterator); +} + +static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev ) +{ + IOReturn rv; + CFMutableDictionaryRef cfProperties; + +#if 0 + /* comment copied from darwin/SDL_sysjoystick.c */ + /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also + * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties + */ + + io_registry_entry_t parent1, parent2; + + rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1); + if (rv != kIOReturnSuccess) { + fgWarning ( "error getting device entry parent"); + return NULL; + } + + rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2); + if (rv != kIOReturnSuccess) { + fgWarning ( "error getting device entry parent 2"); + return NULL; + } +#endif + + rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/, + &cfProperties, kCFAllocatorDefault, kNilOptions); + if (rv != kIOReturnSuccess || !cfProperties) { + fgWarning ( "error getting device properties"); + return NULL; + } + + return cfProperties; +} + +static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs ) +{ + if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) { + fgError ( "%s", "element enumerator passed non-dictionary value"); + return; + } + + static_cast(vjs)->parseElement ( (CFDictionaryRef) element ); +} + +/** element enumerator function : pass NULL for top-level*/ +static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element ) +{ + FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(), + "Joystick element type mismatch", + "fghJoystickEnumerateElements" ); + + CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)}; + CFArrayApplyFunction((CFArrayRef) element, range, + &fghJoystickElementEnumerator, joy ); +} + +static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis ) +{ + long cookie, lmin, lmax; + int index = joy->num_axes++; + + CFNumberGetValue ((CFNumberRef) + CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ), + kCFNumberLongType, &cookie); + + axisCookies[index] = (IOHIDElementCookie) cookie; + + CFNumberGetValue ((CFNumberRef) + CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ), + kCFNumberLongType, &lmin); + + CFNumberGetValue ((CFNumberRef) + CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ), + kCFNumberLongType, &lmax); + + joy->min[index] = lmin; + joy->max[index] = lmax; + joy->dead_band[index] = 0.0; + joy->saturate[index] = 1.0; + joy->center[index] = (lmax + lmin) * 0.5; +} + +static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button ) +{ + long cookie; + CFNumberGetValue ((CFNumberRef) + CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ), + kCFNumberLongType, &cookie); + + joy->buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie; + /* anything else for buttons? */ +} + +static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button ) +{ + /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */ + /* do we map hats to axes or buttons? */ +} +#endif + +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) +/* Inspired by + http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp + */ +# if FREEGLUT_LIB_PRAGMAS +# pragma comment (lib, "advapi32.lib") +# endif + +static int fghJoystickGetOEMProductName ( SFG_Joystick* joy, char *buf, int buf_sz ) +{ + char buffer [ 256 ]; + + char OEMKey [ 256 ]; + + HKEY hKey; + DWORD dwcb; + LONG lr; + + if ( joy->error ) + return 0; + + /* Open .. MediaResources\CurrentJoystickSettings */ + _snprintf ( buffer, sizeof(buffer), "%s\\%s\\%s", + REGSTR_PATH_JOYCONFIG, joy->jsCaps.szRegKey, + REGSTR_KEY_JOYCURR ); + + lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey); + + if ( lr != ERROR_SUCCESS ) return 0; + + /* Get OEM Key name */ + dwcb = sizeof(OEMKey); + + /* JOYSTICKID1-16 is zero-based; registry entries for VJOYD are 1-based. */ + _snprintf ( buffer, sizeof(buffer), "Joystick%d%s", joy->js_id + 1, REGSTR_VAL_JOYOEMNAME ); + + lr = RegQueryValueEx ( hKey, buffer, 0, 0, (LPBYTE) OEMKey, &dwcb); + RegCloseKey ( hKey ); + + if ( lr != ERROR_SUCCESS ) return 0; + + /* Open OEM Key from ...MediaProperties */ + _snprintf ( buffer, sizeof(buffer), "%s\\%s", REGSTR_PATH_JOYOEM, OEMKey ); + + lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey ); + + if ( lr != ERROR_SUCCESS ) return 0; + + /* Get OEM Name */ + dwcb = buf_sz; + + lr = RegQueryValueEx ( hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buf, + &dwcb ); + RegCloseKey ( hKey ); + + if ( lr != ERROR_SUCCESS ) return 0; + + return 1; +} +#endif + + +static void fghJoystickOpen( SFG_Joystick* joy ) +{ + int i = 0; +#if TARGET_HOST_MACINTOSH + OSStatus err; +#endif +#if TARGET_HOST_MAC_OSX + IOReturn rv; + SInt32 score; + IOCFPlugInInterface **plugin; + + HRESULT pluginResult; + + CFDictionaryRef props; + CFTypeRef topLevelElement; +#endif +#if TARGET_HOST_POSIX_X11 +# if defined( __FreeBSD__ ) || defined( __NetBSD__ ) + char *cp; +# endif +# ifdef JS_NEW + unsigned char u; +# else +# if defined( __linux__ ) || TARGET_HOST_SOLARIS + int counter = 0; +# endif +# endif +#endif + + /* Silence gcc, the correct #ifdefs would be too fragile... */ + (void)i; + + /* + * Default values (for no joystick -- each conditional will reset the + * error flag) + */ + joy->error = TRUE; + joy->num_axes = joy->num_buttons = 0; + joy->name[ 0 ] = '\0'; + +#if TARGET_HOST_MACINTOSH + /* XXX FIXME: get joystick name in Mac */ + + err = ISpStartup( ); + + if( err == noErr ) + { +#define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; } + + joy->error = GL_TRUE; + + /* initialize the needs structure */ + ISpNeed temp_isp_needs[ isp_num_needs ] = + { + { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + + { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + }; + + memcpy( joy->isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) ); + + + /* next two calls allow keyboard and mouse to emulate other input + * devices (gamepads, joysticks, etc) + */ + /* + err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard ); + ISP_CHECK_ERR(err) + + + err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse ); + ISP_CHECK_ERR(err) + */ + + err = ISpElement_NewVirtualFromNeeds( joy->isp_num_needs, + joy->isp_needs, joy->isp_elem, + 0 ); + ISP_CHECK_ERR( err ) + + err = ISpInit( joy->isp_num_needs, joy->isp_needs, joy->isp_elem, + 'freeglut', nil, 0, 128, 0 ); + ISP_CHECK_ERR( err ) + + joy->num_buttons = joy->isp_num_needs - joy->isp_num_axis; + joy->num_axes = joy->isp_num_axis; + + for( i = 0; i < joy->num_axes; i++ ) + { + joy->dead_band[ i ] = 0; + joy->saturate [ i ] = 1; + joy->center [ i ] = kISpAxisMiddle; + joy->max [ i ] = kISpAxisMaximum; + joy->min [ i ] = kISpAxisMinimum; + } + + joy->error = GL_FALSE; + } + else + joy->num_buttons = joy->num_axes = 0; +#endif + +#if TARGET_HOST_MAC_OSX + if( joy->id >= numDevices ) + { + fgWarning( "device index out of range in fgJoystickOpen()" ); + return; + } + + /* create device interface */ + rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ], + kIOHIDDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, + &plugin, &score ); + + if( rv != kIOReturnSuccess ) + { + fgWarning( "error creating plugin for io device" ); + return; + } + + pluginResult = ( *plugin )->QueryInterface( + plugin, + CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), + &( LPVOID )joy->hidDev + ); + + if( pluginResult != S_OK ) + fgWarning ( "QI-ing IO plugin to HID Device interface failed" ); + + ( *plugin )->Release( plugin ); /* don't leak a ref */ + if( joy->hidDev == NULL ) + return; + + /* store the interface in this instance */ + rv = ( *( joy->hidDev ) )->open( joy->hidDev, 0 ); + if( rv != kIOReturnSuccess ) + { + fgWarning( "error opening device interface"); + return; + } + + props = getCFProperties( ioDevices[ joy->id ] ); + + /* recursively enumerate all the bits */ + CFTypeRef topLevelElement = + CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) ); + enumerateElements( topLevelElement ); + + CFRelease( props ); +#endif + +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + joy->js.dwFlags = JOY_RETURNALL; + joy->js.dwSize = sizeof( joy->js ); + + memset( &joy->jsCaps, 0, sizeof( joy->jsCaps ) ); + + joy->error = + ( joyGetDevCaps( joy->js_id, &joy->jsCaps, sizeof( joy->jsCaps ) ) != + JOYERR_NOERROR ); + + if( joy->jsCaps.wNumAxes == 0 ) + { + joy->num_axes = 0; + joy->error = GL_TRUE; + } + else + { + /* Device name from jsCaps is often "Microsoft PC-joystick driver", + * at least for USB. Try to get the real name from the registry. + */ + if ( ! fghJoystickGetOEMProductName( joy, joy->name, + sizeof( joy->name ) ) ) + { + fgWarning( "JS: Failed to read joystick name from registry" ); + strncpy( joy->name, joy->jsCaps.szPname, sizeof( joy->name ) ); + } + + /* Windows joystick drivers may provide any combination of + * X,Y,Z,R,U,V,POV - not necessarily the first n of these. + */ + if( joy->jsCaps.wCaps & JOYCAPS_HASPOV ) + { + joy->num_axes = _JS_MAX_AXES; + joy->min[ 7 ] = -1.0; joy->max[ 7 ] = 1.0; /* POV Y */ + joy->min[ 6 ] = -1.0; joy->max[ 6 ] = 1.0; /* POV X */ + } + else + joy->num_axes = 6; + + joy->min[ 5 ] = ( float )joy->jsCaps.wVmin; + joy->max[ 5 ] = ( float )joy->jsCaps.wVmax; + joy->min[ 4 ] = ( float )joy->jsCaps.wUmin; + joy->max[ 4 ] = ( float )joy->jsCaps.wUmax; + joy->min[ 3 ] = ( float )joy->jsCaps.wRmin; + joy->max[ 3 ] = ( float )joy->jsCaps.wRmax; + joy->min[ 2 ] = ( float )joy->jsCaps.wZmin; + joy->max[ 2 ] = ( float )joy->jsCaps.wZmax; + joy->min[ 1 ] = ( float )joy->jsCaps.wYmin; + joy->max[ 1 ] = ( float )joy->jsCaps.wYmax; + joy->min[ 0 ] = ( float )joy->jsCaps.wXmin; + joy->max[ 0 ] = ( float )joy->jsCaps.wXmax; + } + + /* Guess all the rest judging on the axes extremals */ + for( i = 0; i < joy->num_axes; i++ ) + { + joy->center [ i ] = ( joy->max[ i ] + joy->min[ i ] ) * 0.5f; + joy->dead_band[ i ] = 0.0f; + joy->saturate [ i ] = 1.0f; + } +#endif + +#if TARGET_HOST_POSIX_X11 +#if defined( __FreeBSD__ ) || defined( __NetBSD__ ) + for( i = 0; i < _JS_MAX_AXES; i++ ) + joy->os->cache_axes[ i ] = 0.0f; + + joy->os->cache_buttons = 0; + + joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK); + +#if HAVE_ERRNO + if( joy->os->fd < 0 && errno == EACCES ) + fgWarning ( "%s exists but is not readable by you", joy->os->fname ); +#endif + + joy->error =( joy->os->fd < 0 ); + + if( joy->error ) + return; + + joy->num_axes = 0; + joy->num_buttons = 0; + if( joy->os->is_analog ) + { + FILE *joyfile; + char joyfname[ 1024 ]; + int noargs, in_no_axes; + + float axes [ _JS_MAX_AXES ]; + int buttons[ _JS_MAX_AXES ]; + + joy->num_axes = 2; + joy->num_buttons = 32; + + fghJoystickRawRead( joy, buttons, axes ); + joy->error = axes[ 0 ] < -1000000000.0f; + if( joy->error ) + return; + + snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id ); + + joyfile = fopen( joyfname, "r" ); + joy->error =( joyfile == NULL ); + if( joy->error ) + return; + + noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes, + &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ], + &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] ); + joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES; + fclose( joyfile ); + if( joy->error ) + return; + + for( i = 0; i < _JS_MAX_AXES; i++ ) + { + joy->dead_band[ i ] = 0.0f; + joy->saturate [ i ] = 1.0f; + } + + return; /* End of analog code */ + } + +# ifdef HAVE_USB_JS + if( ! fghJoystickInitializeHID( joy->os, &joy->num_axes, + &joy->num_buttons ) ) + { + close( joy->os->fd ); + joy->error = GL_TRUE; + return; + } + + cp = strrchr( joy->os->fname, '/' ); + if( cp ) + { + if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) == + 0 ) + strcpy( joy->name, &cp[1] ); + } + + if( joy->num_axes > _JS_MAX_AXES ) + joy->num_axes = _JS_MAX_AXES; + + for( i = 0; i < _JS_MAX_AXES; i++ ) + { + /* We really should get this from the HID, but that data seems + * to be quite unreliable for analog-to-USB converters. Punt for + * now. + */ + if( joy->os->axes_usage[ i ] == HUG_HAT_SWITCH ) + { + joy->max [ i ] = 1.0f; + joy->center[ i ] = 0.0f; + joy->min [ i ] = -1.0f; + } + else + { + joy->max [ i ] = 255.0f; + joy->center[ i ] = 127.0f; + joy->min [ i ] = 0.0f; + } + + joy->dead_band[ i ] = 0.0f; + joy->saturate[ i ] = 1.0f; + } +# endif +#endif + +#if defined( __linux__ ) || TARGET_HOST_SOLARIS + /* Default for older Linux systems. */ + joy->num_axes = 2; + joy->num_buttons = 32; + +# ifdef JS_NEW + for( i = 0; i < _JS_MAX_AXES; i++ ) + joy->tmp_axes[ i ] = 0.0f; + + joy->tmp_buttons = 0; +# endif + + joy->fd = open( joy->fname, O_RDONLY ); + + joy->error =( joy->fd < 0 ); + + if( joy->error ) + return; + + /* Set the correct number of axes for the linux driver */ +# ifdef JS_NEW + /* Melchior Franz's fixes for big-endian Linuxes since writing + * to the upper byte of an uninitialized word doesn't work. + * 9 April 2003 + */ + ioctl( joy->fd, JSIOCGAXES, &u ); + joy->num_axes = u; + ioctl( joy->fd, JSIOCGBUTTONS, &u ); + joy->num_buttons = u; + ioctl( joy->fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name ); + fcntl( joy->fd, F_SETFL, O_NONBLOCK ); +# endif + + /* + * The Linux driver seems to return 512 for all axes + * when no stick is present - but there is a chance + * that could happen by accident - so it's gotta happen + * on both axes for at least 100 attempts. + * + * PWO: shouldn't be that done somehow wiser on the kernel level? + */ +# ifndef JS_NEW + counter = 0; + + do + { + fghJoystickRawRead( joy, NULL, joy->center ); + counter++; + } while( !joy->error && + counter < 100 && + joy->center[ 0 ] == 512.0f && + joy->center[ 1 ] == 512.0f ); + + if ( counter >= 100 ) + joy->error = GL_TRUE; +# endif + + for( i = 0; i < _JS_MAX_AXES; i++ ) + { +# ifdef JS_NEW + joy->max [ i ] = 32767.0f; + joy->center[ i ] = 0.0f; + joy->min [ i ] = -32767.0f; +# else + joy->max[ i ] = joy->center[ i ] * 2.0f; + joy->min[ i ] = 0.0f; +# endif + joy->dead_band[ i ] = 0.0f; + joy->saturate [ i ] = 1.0f; + } +#endif +#endif +} + +/* + * This function replaces the constructor method in the JS library. + */ +static void fghJoystickInit( int ident ) +{ + if( ident >= MAX_NUM_JOYSTICKS ) + fgError( "Too large a joystick number: %d", ident ); + + if( fgJoystick[ ident ] ) + fgError( "illegal attempt to initialize joystick device again" ); + + fgJoystick[ ident ] = + ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 ); + + /* Set defaults */ + fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0; + fgJoystick[ ident ]->error = GL_TRUE; + +#if TARGET_HOST_MACINTOSH + fgJoystick[ ident ]->id = ident; + snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident ); /* FIXME */ + fgJoystick[ ident ]->error = GL_FALSE; +#endif + +#if TARGET_HOST_MAC_OSX + fgJoystick[ ident ]->id = ident; + fgJoystick[ ident ]->error = GL_FALSE; + fgJoystick[ ident ]->num_axes = 0; + fgJoystick[ ident ]->num_buttons = 0; + + if( numDevices < 0 ) + { + /* do first-time init (since we can't over-ride jsInit, hmm */ + numDevices = 0; + + mach_port_t masterPort; + IOReturn rv = IOMasterPort( bootstrap_port, &masterPort ); + if( rv != kIOReturnSuccess ) + { + fgWarning( "error getting master Mach port" ); + return; + } + fghJoystickFindDevices( masterPort ); + } + + if ( ident >= numDevices ) + { + fgJoystick[ ident ]->error = GL_TRUE; + return; + } + + /* get the name now too */ + CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] ); + CFTypeRef ref = CFDictionaryGetValue( properties, + CFSTR( kIOHIDProductKey ) ); + if (!ref) + ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) ); + + if( !ref || + !CFStringGetCString( ( CFStringRef )ref, name, 128, + CFStringGetSystemEncoding( ) ) ) + { + fgWarning( "error getting device name" ); + name[ 0 ] = '\0'; + } +#endif + +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + switch( ident ) + { + case 0: + fgJoystick[ ident ]->js_id = JOYSTICKID1; + fgJoystick[ ident ]->error = GL_FALSE; + break; + case 1: + fgJoystick[ ident ]->js_id = JOYSTICKID2; + fgJoystick[ ident ]->error = GL_FALSE; + break; + default: + fgJoystick[ ident ]->num_axes = 0; + fgJoystick[ ident ]->error = GL_TRUE; + return; + } +#endif + +#if TARGET_HOST_POSIX_X11 +# if defined( __FreeBSD__ ) || defined( __NetBSD__ ) + fgJoystick[ ident ]->id = ident; + fgJoystick[ ident ]->error = GL_FALSE; + + fgJoystick[ ident ]->os = calloc( 1, sizeof( struct os_specific_s ) ); + memset( fgJoystick[ ident ]->os, 0, sizeof( struct os_specific_s ) ); + if( ident < USB_IDENT_OFFSET ) + fgJoystick[ ident ]->os->is_analog = 1; + if( fgJoystick[ ident ]->os->is_analog ) + snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", AJSDEV, ident ); + else + snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", UHIDDEV, + ident - USB_IDENT_OFFSET ); +# elif defined( __linux__ ) + fgJoystick[ ident ]->id = ident; + fgJoystick[ ident ]->error = GL_FALSE; + + snprintf( fgJoystick[ident]->fname, sizeof(fgJoystick[ident]->fname), "/dev/input/js%d", ident ); + + if( access( fgJoystick[ ident ]->fname, F_OK ) != 0 ) + snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident ); +# endif +#endif + + fghJoystickOpen( fgJoystick[ ident ] ); +} + +/* + * Try initializing all the joysticks (well, both of them) + */ +void fgInitialiseJoysticks ( void ) +{ + if( !fgState.JoysticksInitialised ) + { + int ident ; + for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ ) + fghJoystickInit( ident ); + + fgState.JoysticksInitialised = GL_TRUE; + } +} + +/* + * + */ +void fgJoystickClose( void ) +{ + int ident ; + for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ ) + { + if( fgJoystick[ ident ] ) + { + +#if TARGET_HOST_MACINTOSH + ISpSuspend( ); + ISpStop( ); + ISpShutdown( ); +#endif + +#if TARGET_HOST_MAC_OSX + ( *( fgJoystick[ ident ]->hidDev ) )-> + close( fgJoystick[ ident ]->hidDev ); +#endif + +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + /* Do nothing special */ +#endif + +#if TARGET_HOST_POSIX_X11 +#if defined( __FreeBSD__ ) || defined( __NetBSD__ ) + if( fgJoystick[ident]->os ) + { + if( ! fgJoystick[ ident ]->error ) + close( fgJoystick[ ident ]->os->fd ); +#ifdef HAVE_USB_JS + if( fgJoystick[ ident ]->os->hids ) + free (fgJoystick[ ident ]->os->hids); + if( fgJoystick[ ident ]->os->hid_data_buf ) + free( fgJoystick[ ident ]->os->hid_data_buf ); +#endif + free( fgJoystick[ident]->os ); + } +#endif + + if( ! fgJoystick[ident]->error ) + close( fgJoystick[ ident ]->fd ); +#endif + + free( fgJoystick[ ident ] ); + fgJoystick[ ident ] = NULL; + /* show joystick has been deinitialized */ + } + } +} + +/* + * Polls the joystick and executes the joystick callback hooked to the + * window specified in the function's parameter: + */ +void fgJoystickPollWindow( SFG_Window* window ) +{ + float axes[ _JS_MAX_AXES ]; + int buttons; + int ident; + + freeglut_return_if_fail( window ); + freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) ); + + for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ ) + { + if( fgJoystick[ident] ) + { + fghJoystickRead( fgJoystick[ident], &buttons, axes ); + + if( !fgJoystick[ident]->error ) + INVOKE_WCB( *window, Joystick, + ( buttons, + (int) ( axes[ 0 ] * 1000.0f ), + (int) ( axes[ 1 ] * 1000.0f ), + (int) ( axes[ 2 ] * 1000.0f ) ) + ); + } + } +} + +/* + * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK) + */ +int fgJoystickDetect( void ) +{ + int ident; + + fgInitialiseJoysticks (); + + if ( !fgState.JoysticksInitialised ) + return 0; + + for( ident=0; identerror ) + return 1; + + return 0; +} + +/* + * Joystick information functions + */ +int glutJoystickGetNumAxes( int ident ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" ); + return fgJoystick[ ident ]->num_axes; +} +int glutJoystickGetNumButtons( int ident ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" ); + return fgJoystick[ ident ]->num_buttons; +} +int glutJoystickNotWorking( int ident ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" ); + return fgJoystick[ ident ]->error; +} + +float glutJoystickGetDeadBand( int ident, int axis ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" ); + return fgJoystick[ ident ]->dead_band [ axis ]; +} +void glutJoystickSetDeadBand( int ident, int axis, float db ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" ); + fgJoystick[ ident ]->dead_band[ axis ] = db; +} + +float glutJoystickGetSaturation( int ident, int axis ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" ); + return fgJoystick[ ident ]->saturate[ axis ]; +} +void glutJoystickSetSaturation( int ident, int axis, float st ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" ); + fgJoystick[ ident ]->saturate [ axis ] = st; +} + +void glutJoystickSetMinRange( int ident, float *axes ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" ); + memcpy( fgJoystick[ ident ]->min, axes, + fgJoystick[ ident ]->num_axes * sizeof( float ) ); +} +void glutJoystickSetMaxRange( int ident, float *axes ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" ); + memcpy( fgJoystick[ ident ]->max, axes, + fgJoystick[ ident ]->num_axes * sizeof( float ) ); +} +void glutJoystickSetCenter( int ident, float *axes ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" ); + memcpy( fgJoystick[ ident ]->center, axes, + fgJoystick[ ident ]->num_axes * sizeof( float ) ); +} + +void glutJoystickGetMinRange( int ident, float *axes ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" ); + memcpy( axes, fgJoystick[ ident ]->min, + fgJoystick[ ident ]->num_axes * sizeof( float ) ); +} +void glutJoystickGetMaxRange( int ident, float *axes ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" ); + memcpy( axes, fgJoystick[ ident ]->max, + fgJoystick[ ident ]->num_axes * sizeof( float ) ); +} +void glutJoystickGetCenter( int ident, float *axes ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" ); + memcpy( axes, fgJoystick[ ident ]->center, + fgJoystick[ ident ]->num_axes * sizeof( float ) ); +} + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_main.c b/tests/Box2D_v2.2.1/freeglut/freeglut_main.c new file mode 100755 index 0000000000000..47043a03b4cf3 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_main.c @@ -0,0 +1,2296 @@ +/* + * freeglut_main.c + * + * The windows message processing methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Fri Dec 3 1999 + * + * 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 + * PAWEL W. OLSZTA 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 "freeglut.h" +#include "freeglut_internal.h" +#if HAVE_ERRNO +# include +#endif +#include +#if HAVE_VPRINTF +# define VFPRINTF(s,f,a) vfprintf((s),(f),(a)) +#elif HAVE_DOPRNT +# define VFPRINTF(s,f,a) _doprnt((f),(a),(s)) +#else +# define VFPRINTF(s,f,a) +#endif + +#ifdef _WIN32_WCE + +typedef struct GXDisplayProperties GXDisplayProperties; +typedef struct GXKeyList GXKeyList; +#include + +typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int); +typedef int (*GXOPENINPUT)(); + +GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL; +GXOPENINPUT GXOpenInput_ = NULL; + +struct GXKeyList gxKeyList; + +#endif /* _WIN32_WCE */ + +/* + * Try to get the maximum value allowed for ints, falling back to the minimum + * guaranteed by ISO C99 if there is no suitable header. + */ +#if HAVE_LIMITS_H +# include +#endif +#ifndef INT_MAX +# define INT_MAX 32767 +#endif + +#ifndef MIN +# define MIN(a,b) (((a)<(b)) ? (a) : (b)) +#endif + + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * There are some issues concerning window redrawing under X11, and maybe + * some events are not handled. The Win32 version lacks some more features, + * but seems acceptable for not demanding purposes. + * + * Need to investigate why the X11 version breaks out with an error when + * closing a window (using the window manager, not glutDestroyWindow)... + */ + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +/* + * Handle a window configuration change. When no reshape + * callback is hooked, the viewport size is updated to + * match the new window size. + */ +static void fghReshapeWindow ( SFG_Window *window, int width, int height ) +{ + SFG_Window *current_window = fgStructure.CurrentWindow; + + freeglut_return_if_fail( window != NULL ); + + +#if TARGET_HOST_POSIX_X11 + + XResizeWindow( fgDisplay.Display, window->Window.Handle, + width, height ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + { + RECT winRect; + int x, y, w, h; + + /* + * For windowed mode, get the current position of the + * window and resize taking the size of the frame + * decorations into account. + */ + + /* "GetWindowRect" returns the pixel coordinates of the outside of the window */ + GetWindowRect( window->Window.Handle, &winRect ); + x = winRect.left; + y = winRect.top; + w = width; + h = height; + + if ( window->Parent == NULL ) + { + if ( ! window->IsMenu && (window != fgStructure.GameModeWindow) ) + { + w += GetSystemMetrics( SM_CXSIZEFRAME ) * 2; + h += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + + GetSystemMetrics( SM_CYCAPTION ); + } + } + else + { + RECT parentRect; + GetWindowRect( window->Parent->Window.Handle, &parentRect ); + x -= parentRect.left + GetSystemMetrics( SM_CXSIZEFRAME ) * 2; + y -= parentRect.top + GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + + GetSystemMetrics( SM_CYCAPTION ); + } + + /* + * SWP_NOACTIVATE Do not activate the window + * SWP_NOOWNERZORDER Do not change position in z-order + * SWP_NOSENDCHANGING Supress WM_WINDOWPOSCHANGING message + * SWP_NOZORDER Retains the current Z order (ignore 2nd param) + */ + + SetWindowPos( window->Window.Handle, + HWND_TOP, + x, y, w, h, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | + SWP_NOZORDER + ); + } +#endif + + /* + * XXX Should update {window->State.OldWidth, window->State.OldHeight} + * XXX to keep in lockstep with POSIX_X11 code. + */ + if( FETCH_WCB( *window, Reshape ) ) + INVOKE_WCB( *window, Reshape, ( width, height ) ); + else + { + fgSetWindow( window ); + glViewport( 0, 0, width, height ); + } + + /* + * Force a window redraw. In Windows at least this is only a partial + * solution: if the window is increasing in size in either dimension, + * the already-drawn part does not get drawn again and things look funny. + * But without this we get this bad behaviour whenever we resize the + * window. + */ + window->State.Redisplay = GL_TRUE; + + if( window->IsMenu ) + fgSetWindow( current_window ); +} + +/* + * Calls a window's redraw method. This is used when + * a redraw is forced by the incoming window messages. + */ +static void fghRedrawWindow ( SFG_Window *window ) +{ + SFG_Window *current_window = fgStructure.CurrentWindow; + + freeglut_return_if_fail( window ); + freeglut_return_if_fail( FETCH_WCB ( *window, Display ) ); + + window->State.Redisplay = GL_FALSE; + + freeglut_return_if_fail( window->State.Visible ); + + fgSetWindow( window ); + + if( window->State.NeedToResize ) + { + fghReshapeWindow( + window, + window->State.Width, + window->State.Height + ); + + window->State.NeedToResize = GL_FALSE; + } + + INVOKE_WCB( *window, Display, ( ) ); + + fgSetWindow( current_window ); +} + +/* + * A static helper function to execute display callback for a window + */ +static void fghcbDisplayWindow( SFG_Window *window, + SFG_Enumerator *enumerator ) +{ + if( window->State.Redisplay && + window->State.Visible ) + { + window->State.Redisplay = GL_FALSE; + +#if TARGET_HOST_POSIX_X11 + fghRedrawWindow ( window ) ; +#elif TARGET_HOST_MS_WINDOWS + RedrawWindow( + window->Window.Handle, NULL, NULL, + RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW + ); +#endif + } + + fgEnumSubWindows( window, fghcbDisplayWindow, enumerator ); +} + +/* + * Make all windows perform a display call + */ +static void fghDisplayAll( void ) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + + fgEnumWindows( fghcbDisplayWindow, &enumerator ); +} + +/* + * Window enumerator callback to check for the joystick polling code + */ +static void fghcbCheckJoystickPolls( SFG_Window *window, + SFG_Enumerator *enumerator ) +{ + long int checkTime = fgElapsedTime( ); + + if( window->State.JoystickLastPoll + window->State.JoystickPollRate <= + checkTime ) + { +#if !defined(_WIN32_WCE) + fgJoystickPollWindow( window ); +#endif /* !defined(_WIN32_WCE) */ + window->State.JoystickLastPoll = checkTime; + } + + fgEnumSubWindows( window, fghcbCheckJoystickPolls, enumerator ); +} + +/* + * Check all windows for joystick polling + */ +static void fghCheckJoystickPolls( void ) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + + fgEnumWindows( fghcbCheckJoystickPolls, &enumerator ); +} + +/* + * Check the global timers + */ +static void fghCheckTimers( void ) +{ + long checkTime = fgElapsedTime( ); + + while( fgState.Timers.First ) + { + SFG_Timer *timer = fgState.Timers.First; + + if( timer->TriggerTime > checkTime ) + break; + + fgListRemove( &fgState.Timers, &timer->Node ); + fgListAppend( &fgState.FreeTimers, &timer->Node ); + + timer->Callback( timer->ID ); + } +} + + +/* Platform-dependent time in milliseconds, as an unsigned 32-bit integer. + * This value wraps every 49.7 days, but integer overflows cancel + * when subtracting an initial start time, unless the total time exceeds + * 32-bit, where the GLUT API return value is also overflowed. + */ +unsigned long fgSystemTime(void) { +#if TARGET_HOST_SOLARIS || HAVE_GETTIMEOFDAY + struct timeval now; + gettimeofday( &now, NULL ); + return now.tv_usec/1000 + now.tv_sec*1000; +#elif TARGET_HOST_MS_WINDOWS +# if defined(_WIN32_WCE) + return GetTickCount(); +# else + return timeGetTime(); +# endif +#endif +} + +/* + * Elapsed Time + */ +long fgElapsedTime( void ) +{ + return (long) (fgSystemTime() - fgState.Time); +} + +/* + * Error Messages. + */ +void fgError( const char *fmt, ... ) +{ + va_list ap; + + va_start( ap, fmt ); + + fprintf( stderr, "freeglut "); + if( fgState.ProgramName ) + fprintf( stderr, "(%s): ", fgState.ProgramName ); + VFPRINTF( stderr, fmt, ap ); + fprintf( stderr, "\n" ); + + va_end( ap ); + + if ( fgState.Initialised ) + fgDeinitialize (); + + exit( 1 ); +} + +void fgWarning( const char *fmt, ... ) +{ + va_list ap; + + va_start( ap, fmt ); + + fprintf( stderr, "freeglut "); + if( fgState.ProgramName ) + fprintf( stderr, "(%s): ", fgState.ProgramName ); + VFPRINTF( stderr, fmt, ap ); + fprintf( stderr, "\n" ); + + va_end( ap ); +} + +/* + * Indicates whether Joystick events are being used by ANY window. + * + * The current mechanism is to walk all of the windows and ask if + * there is a joystick callback. We have a short-circuit early + * return if we find any joystick handler registered. + * + * The real way to do this is to make use of the glutTimer() API + * to more cleanly re-implement the joystick API. Then, this code + * and all other "joystick timer" code can be yanked. + * + */ +static void fghCheckJoystickCallback( SFG_Window* w, SFG_Enumerator* e) +{ + if( FETCH_WCB( *w, Joystick ) ) + { + e->found = GL_TRUE; + e->data = w; + } + fgEnumSubWindows( w, fghCheckJoystickCallback, e ); +} +static int fghHaveJoystick( void ) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + fgEnumWindows( fghCheckJoystickCallback, &enumerator ); + return !!enumerator.data; +} +static void fghHavePendingRedisplaysCallback( SFG_Window* w, SFG_Enumerator* e) +{ + if( w->State.Redisplay && w->State.Visible ) + { + e->found = GL_TRUE; + e->data = w; + } + fgEnumSubWindows( w, fghHavePendingRedisplaysCallback, e ); +} +static int fghHavePendingRedisplays (void) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + fgEnumWindows( fghHavePendingRedisplaysCallback, &enumerator ); + return !!enumerator.data; +} +/* + * Returns the number of GLUT ticks (milliseconds) till the next timer event. + */ +static long fghNextTimer( void ) +{ + long ret = INT_MAX; + SFG_Timer *timer = fgState.Timers.First; + + if( timer ) + ret = timer->TriggerTime - fgElapsedTime(); + if( ret < 0 ) + ret = 0; + + return ret; +} +/* + * Does the magic required to relinquish the CPU until something interesting + * happens. + */ +static void fghSleepForEvents( void ) +{ + long msec; + + if( fgState.IdleCallback || fghHavePendingRedisplays( ) ) + return; + + msec = fghNextTimer( ); + /* XXX Use GLUT timers for joysticks... */ + /* XXX Dumb; forces granularity to .01sec */ + if( fghHaveJoystick( ) && ( msec > 10 ) ) + msec = 10; + +#if TARGET_HOST_POSIX_X11 + /* + * Possibly due to aggressive use of XFlush() and friends, + * it is possible to have our socket drained but still have + * unprocessed events. (Or, this may just be normal with + * X, anyway?) We do non-trivial processing of X events + * after the event-reading loop, in any case, so we + * need to allow that we may have an empty socket but non- + * empty event queue. + */ + if( ! XPending( fgDisplay.Display ) ) + { + fd_set fdset; + int err; + int socket; + struct timeval wait; + + socket = ConnectionNumber( fgDisplay.Display ); + FD_ZERO( &fdset ); + FD_SET( socket, &fdset ); + wait.tv_sec = msec / 1000; + wait.tv_usec = (msec % 1000) * 1000; + err = select( socket+1, &fdset, NULL, NULL, &wait ); + +#if HAVE_ERRNO + if( ( -1 == err ) && ( errno != EINTR ) ) + fgWarning ( "freeglut select() error: %d", errno ); +#endif + } +#elif TARGET_HOST_MS_WINDOWS + MsgWaitForMultipleObjects( 0, NULL, FALSE, msec, QS_ALLINPUT ); +#endif +} + +#if TARGET_HOST_POSIX_X11 +/* + * Returns GLUT modifier mask for the state field of an X11 event. + */ +static int fghGetXModifiers( int state ) +{ + int ret = 0; + + if( state & ( ShiftMask | LockMask ) ) + ret |= GLUT_ACTIVE_SHIFT; + if( state & ControlMask ) + ret |= GLUT_ACTIVE_CTRL; + if( state & Mod1Mask ) + ret |= GLUT_ACTIVE_ALT; + + return ret; +} +#endif + + +#if TARGET_HOST_POSIX_X11 && _DEBUG + +static const char* fghTypeToString( int type ) +{ + switch( type ) { + case KeyPress: return "KeyPress"; + case KeyRelease: return "KeyRelease"; + case ButtonPress: return "ButtonPress"; + case ButtonRelease: return "ButtonRelease"; + case MotionNotify: return "MotionNotify"; + case EnterNotify: return "EnterNotify"; + case LeaveNotify: return "LeaveNotify"; + case FocusIn: return "FocusIn"; + case FocusOut: return "FocusOut"; + case KeymapNotify: return "KeymapNotify"; + case Expose: return "Expose"; + case GraphicsExpose: return "GraphicsExpose"; + case NoExpose: return "NoExpose"; + case VisibilityNotify: return "VisibilityNotify"; + case CreateNotify: return "CreateNotify"; + case DestroyNotify: return "DestroyNotify"; + case UnmapNotify: return "UnmapNotify"; + case MapNotify: return "MapNotify"; + case MapRequest: return "MapRequest"; + case ReparentNotify: return "ReparentNotify"; + case ConfigureNotify: return "ConfigureNotify"; + case ConfigureRequest: return "ConfigureRequest"; + case GravityNotify: return "GravityNotify"; + case ResizeRequest: return "ResizeRequest"; + case CirculateNotify: return "CirculateNotify"; + case CirculateRequest: return "CirculateRequest"; + case PropertyNotify: return "PropertyNotify"; + case SelectionClear: return "SelectionClear"; + case SelectionRequest: return "SelectionRequest"; + case SelectionNotify: return "SelectionNotify"; + case ColormapNotify: return "ColormapNotify"; + case ClientMessage: return "ClientMessage"; + case MappingNotify: return "MappingNotify"; + default: return "UNKNOWN"; + } +} + +static const char* fghBoolToString( Bool b ) +{ + return b == False ? "False" : "True"; +} + +static const char* fghNotifyHintToString( char is_hint ) +{ + switch( is_hint ) { + case NotifyNormal: return "NotifyNormal"; + case NotifyHint: return "NotifyHint"; + default: return "UNKNOWN"; + } +} + +static const char* fghNotifyModeToString( int mode ) +{ + switch( mode ) { + case NotifyNormal: return "NotifyNormal"; + case NotifyGrab: return "NotifyGrab"; + case NotifyUngrab: return "NotifyUngrab"; + case NotifyWhileGrabbed: return "NotifyWhileGrabbed"; + default: return "UNKNOWN"; + } +} + +static const char* fghNotifyDetailToString( int detail ) +{ + switch( detail ) { + case NotifyAncestor: return "NotifyAncestor"; + case NotifyVirtual: return "NotifyVirtual"; + case NotifyInferior: return "NotifyInferior"; + case NotifyNonlinear: return "NotifyNonlinear"; + case NotifyNonlinearVirtual: return "NotifyNonlinearVirtual"; + case NotifyPointer: return "NotifyPointer"; + case NotifyPointerRoot: return "NotifyPointerRoot"; + case NotifyDetailNone: return "NotifyDetailNone"; + default: return "UNKNOWN"; + } +} + +static const char* fghVisibilityToString( int state ) { + switch( state ) { + case VisibilityUnobscured: return "VisibilityUnobscured"; + case VisibilityPartiallyObscured: return "VisibilityPartiallyObscured"; + case VisibilityFullyObscured: return "VisibilityFullyObscured"; + default: return "UNKNOWN"; + } +} + +static const char* fghConfigureDetailToString( int detail ) +{ + switch( detail ) { + case Above: return "Above"; + case Below: return "Below"; + case TopIf: return "TopIf"; + case BottomIf: return "BottomIf"; + case Opposite: return "Opposite"; + default: return "UNKNOWN"; + } +} + +static const char* fghPlaceToString( int place ) +{ + switch( place ) { + case PlaceOnTop: return "PlaceOnTop"; + case PlaceOnBottom: return "PlaceOnBottom"; + default: return "UNKNOWN"; + } +} + +static const char* fghMappingRequestToString( int request ) +{ + switch( request ) { + case MappingModifier: return "MappingModifier"; + case MappingKeyboard: return "MappingKeyboard"; + case MappingPointer: return "MappingPointer"; + default: return "UNKNOWN"; + } +} + +static const char* fghPropertyStateToString( int state ) +{ + switch( state ) { + case PropertyNewValue: return "PropertyNewValue"; + case PropertyDelete: return "PropertyDelete"; + default: return "UNKNOWN"; + } +} + +static const char* fghColormapStateToString( int state ) +{ + switch( state ) { + case ColormapUninstalled: return "ColormapUninstalled"; + case ColormapInstalled: return "ColormapInstalled"; + default: return "UNKNOWN"; + } +} + +static void fghPrintEvent( XEvent *event ) +{ + switch( event->type ) { + + case KeyPress: + case KeyRelease: { + XKeyEvent *e = &event->xkey; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " + "keycode=%u, same_screen=%s", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, e->x_root, e->y_root, e->state, e->keycode, + fghBoolToString( e->same_screen ) ); + break; + } + + case ButtonPress: + case ButtonRelease: { + XButtonEvent *e = &event->xbutton; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " + "button=%u, same_screen=%d", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, e->x_root, e->y_root, e->state, e->button, + fghBoolToString( e->same_screen ) ); + break; + } + + case MotionNotify: { + XMotionEvent *e = &event->xmotion; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " + "is_hint=%s, same_screen=%d", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, e->x_root, e->y_root, e->state, + fghNotifyHintToString( e->is_hint ), + fghBoolToString( e->same_screen ) ); + break; + } + + case EnterNotify: + case LeaveNotify: { + XCrossingEvent *e = &event->xcrossing; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), mode=%s, detail=%s, same_screen=%d, " + "focus=%d, state=0x%x", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, fghNotifyModeToString( e->mode ), + fghNotifyDetailToString( e->detail ), (int)e->same_screen, + (int)e->focus, e->state ); + break; + } + + case FocusIn: + case FocusOut: { + XFocusChangeEvent *e = &event->xfocus; + fgWarning( "%s: window=0x%x, mode=%s, detail=%s", + fghTypeToString( e->type ), e->window, + fghNotifyModeToString( e->mode ), + fghNotifyDetailToString( e->detail ) ); + break; + } + + case KeymapNotify: { + XKeymapEvent *e = &event->xkeymap; + char buf[32 * 2 + 1]; + int i; + for ( i = 0; i < 32; i++ ) { + snprintf( &buf[ i * 2 ], sizeof( buf ) - i * 2, + "%02x", e->key_vector[ i ] ); + } + buf[ i ] = '\0'; + fgWarning( "%s: window=0x%x, %s", fghTypeToString( e->type ), e->window, + buf ); + break; + } + + case Expose: { + XExposeEvent *e = &event->xexpose; + fgWarning( "%s: window=0x%x, (x,y)=(%d,%d), (width,height)=(%d,%d), " + "count=%d", fghTypeToString( e->type ), e->window, e->x, + e->y, e->width, e->height, e->count ); + break; + } + + case GraphicsExpose: { + XGraphicsExposeEvent *e = &event->xgraphicsexpose; + fgWarning( "%s: drawable=0x%x, (x,y)=(%d,%d), (width,height)=(%d,%d), " + "count=%d, (major_code,minor_code)=(%d,%d)", + fghTypeToString( e->type ), e->drawable, e->x, e->y, + e->width, e->height, e->count, e->major_code, + e->minor_code ); + break; + } + + case NoExpose: { + XNoExposeEvent *e = &event->xnoexpose; + fgWarning( "%s: drawable=0x%x, (major_code,minor_code)=(%d,%d)", + fghTypeToString( e->type ), e->drawable, e->major_code, + e->minor_code ); + break; + } + + case VisibilityNotify: { + XVisibilityEvent *e = &event->xvisibility; + fgWarning( "%s: window=0x%x, state=%s", fghTypeToString( e->type ), + e->window, fghVisibilityToString( e->state) ); + break; + } + + case CreateNotify: { + XCreateWindowEvent *e = &event->xcreatewindow; + fgWarning( "%s: (x,y)=(%d,%d), (width,height)=(%d,%d), border_width=%d, " + "window=0x%x, override_redirect=%s", + fghTypeToString( e->type ), e->x, e->y, e->width, e->height, + e->border_width, e->window, + fghBoolToString( e->override_redirect ) ); + break; + } + + case DestroyNotify: { + XDestroyWindowEvent *e = &event->xdestroywindow; + fgWarning( "%s: event=0x%x, window=0x%x", + fghTypeToString( e->type ), e->event, e->window ); + break; + } + + case UnmapNotify: { + XUnmapEvent *e = &event->xunmap; + fgWarning( "%s: event=0x%x, window=0x%x, from_configure=%s", + fghTypeToString( e->type ), e->event, e->window, + fghBoolToString( e->from_configure ) ); + break; + } + + case MapNotify: { + XMapEvent *e = &event->xmap; + fgWarning( "%s: event=0x%x, window=0x%x, override_redirect=%s", + fghTypeToString( e->type ), e->event, e->window, + fghBoolToString( e->override_redirect ) ); + break; + } + + case MapRequest: { + XMapRequestEvent *e = &event->xmaprequest; + fgWarning( "%s: parent=0x%x, window=0x%x", + fghTypeToString( event->type ), e->parent, e->window ); + break; + } + + case ReparentNotify: { + XReparentEvent *e = &event->xreparent; + fgWarning( "%s: event=0x%x, window=0x%x, parent=0x%x, (x,y)=(%d,%d), " + "override_redirect=%s", fghTypeToString( e->type ), + e->event, e->window, e->parent, e->x, e->y, + fghBoolToString( e->override_redirect ) ); + break; + } + + case ConfigureNotify: { + XConfigureEvent *e = &event->xconfigure; + fgWarning( "%s: event=0x%x, window=0x%x, (x,y)=(%d,%d), " + "(width,height)=(%d,%d), border_width=%d, above=0x%x, " + "override_redirect=%s", fghTypeToString( e->type ), e->event, + e->window, e->x, e->y, e->width, e->height, e->border_width, + e->above, fghBoolToString( e->override_redirect ) ); + break; + } + + case ConfigureRequest: { + XConfigureRequestEvent *e = &event->xconfigurerequest; + fgWarning( "%s: parent=0x%x, window=0x%x, (x,y)=(%d,%d), " + "(width,height)=(%d,%d), border_width=%d, above=0x%x, " + "detail=%s, value_mask=%lx", fghTypeToString( e->type ), + e->parent, e->window, e->x, e->y, e->width, e->height, + e->border_width, e->above, + fghConfigureDetailToString( e->detail ), e->value_mask ); + break; + } + + case GravityNotify: { + XGravityEvent *e = &event->xgravity; + fgWarning( "%s: event=0x%x, window=0x%x, (x,y)=(%d,%d)", + fghTypeToString( e->type ), e->event, e->window, e->x, e->y ); + break; + } + + case ResizeRequest: { + XResizeRequestEvent *e = &event->xresizerequest; + fgWarning( "%s: window=0x%x, (width,height)=(%d,%d)", + fghTypeToString( e->type ), e->window, e->width, e->height ); + break; + } + + case CirculateNotify: { + XCirculateEvent *e = &event->xcirculate; + fgWarning( "%s: event=0x%x, window=0x%x, place=%s", + fghTypeToString( e->type ), e->event, e->window, + fghPlaceToString( e->place ) ); + break; + } + + case CirculateRequest: { + XCirculateRequestEvent *e = &event->xcirculaterequest; + fgWarning( "%s: parent=0x%x, window=0x%x, place=%s", + fghTypeToString( e->type ), e->parent, e->window, + fghPlaceToString( e->place ) ); + break; + } + + case PropertyNotify: { + XPropertyEvent *e = &event->xproperty; + fgWarning( "%s: window=0x%x, atom=%lu, time=%lu, state=%s", + fghTypeToString( e->type ), e->window, + (unsigned long)e->atom, (unsigned long)e->time, + fghPropertyStateToString( e->state ) ); + break; + } + + case SelectionClear: { + XSelectionClearEvent *e = &event->xselectionclear; + fgWarning( "%s: window=0x%x, selection=%lu, time=%lu", + fghTypeToString( e->type ), e->window, + (unsigned long)e->selection, (unsigned long)e->time ); + break; + } + + case SelectionRequest: { + XSelectionRequestEvent *e = &event->xselectionrequest; + fgWarning( "%s: owner=0x%x, requestor=0x%x, selection=0x%x, " + "target=0x%x, property=%lu, time=%lu", + fghTypeToString( e->type ), e->owner, e->requestor, + (unsigned long)e->selection, (unsigned long)e->target, + (unsigned long)e->property, (unsigned long)e->time ); + break; + } + + case SelectionNotify: { + XSelectionEvent *e = &event->xselection; + fgWarning( "%s: requestor=0x%x, selection=0x%x, target=0x%x, " + "property=%lu, time=%lu", fghTypeToString( e->type ), + e->requestor, (unsigned long)e->selection, + (unsigned long)e->target, (unsigned long)e->property, + (unsigned long)e->time ); + break; + } + + case ColormapNotify: { + XColormapEvent *e = &event->xcolormap; + fgWarning( "%s: window=0x%x, colormap=%lu, new=%s, state=%s", + fghTypeToString( e->type ), e->window, + (unsigned long)e->colormap, fghBoolToString( e->new ), + fghColormapStateToString( e->state ) ); + break; + } + + case ClientMessage: { + XClientMessageEvent *e = &event->xclient; + char buf[ 61 ]; + char* p = buf; + char* end = buf + sizeof( buf ); + int i; + switch( e->format ) { + case 8: + for ( i = 0; i < 20; i++, p += 3 ) { + snprintf( p, end - p, " %02x", e->data.b[ i ] ); + } + break; + case 16: + for ( i = 0; i < 10; i++, p += 5 ) { + snprintf( p, end - p, " %04x", e->data.s[ i ] ); + } + break; + case 32: + for ( i = 0; i < 5; i++, p += 9 ) { + snprintf( p, end - p, " %08lx", e->data.l[ i ] ); + } + break; + } + *p = '\0'; + fgWarning( "%s: window=0x%x, message_type=%lu, format=%d, data=(%s )", + fghTypeToString( e->type ), e->window, + (unsigned long)e->message_type, e->format, buf ); + break; + } + + case MappingNotify: { + XMappingEvent *e = &event->xmapping; + fgWarning( "%s: window=0x%x, request=%s, first_keycode=%d, count=%d", + fghTypeToString( e->type ), e->window, + fghMappingRequestToString( e->request ), e->first_keycode, + e->count ); + break; + } + + default: { + fgWarning( "%s", fghTypeToString( event->type ) ); + break; + } + } +} + +#endif + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Executes a single iteration in the freeglut processing loop. + */ +void FGAPIENTRY glutMainLoopEvent( void ) +{ +#if TARGET_HOST_POSIX_X11 + SFG_Window* window; + XEvent event; + + /* This code was repeated constantly, so here it goes into a definition: */ +#define GETWINDOW(a) \ + window = fgWindowByHandle( event.a.window ); \ + if( window == NULL ) \ + break; + +#define GETMOUSE(a) \ + window->State.MouseX = event.a.x; \ + window->State.MouseY = event.a.y; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" ); + + while( XPending( fgDisplay.Display ) ) + { + XNextEvent( fgDisplay.Display, &event ); +#if _DEBUG + fghPrintEvent( &event ); +#endif + + switch( event.type ) + { + case ClientMessage: + if(fgIsSpaceballXEvent(&event)) { + fgSpaceballHandleXEvent(&event); + break; + } + /* Destroy the window when the WM_DELETE_WINDOW message arrives */ + if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.DeleteWindow ) + { + GETWINDOW( xclient ); + + fgDestroyWindow ( window ); + + if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) + { + fgDeinitialize( ); + exit( 0 ); + } + else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS ) + fgState.ExecState = GLUT_EXEC_STATE_STOP; + + return; + } + break; + + /* + * CreateNotify causes a configure-event so that sub-windows are + * handled compatibly with GLUT. Otherwise, your sub-windows + * (in freeglut only) will not get an initial reshape event, + * which can break things. + * + * GLUT presumably does this because it generally tries to treat + * sub-windows the same as windows. + */ + case CreateNotify: + case ConfigureNotify: + { + int width, height; + if( event.type == CreateNotify ) { + GETWINDOW( xcreatewindow ); + width = event.xcreatewindow.width; + height = event.xcreatewindow.height; + } else { + GETWINDOW( xconfigure ); + width = event.xconfigure.width; + height = event.xconfigure.height; + } + + if( ( width != window->State.OldWidth ) || + ( height != window->State.OldHeight ) ) + { + SFG_Window *current_window = fgStructure.CurrentWindow; + + window->State.OldWidth = width; + window->State.OldHeight = height; + if( FETCH_WCB( *window, Reshape ) ) + INVOKE_WCB( *window, Reshape, ( width, height ) ); + else + { + fgSetWindow( window ); + glViewport( 0, 0, width, height ); + } + glutPostRedisplay( ); + if( window->IsMenu ) + fgSetWindow( current_window ); + } + } + break; + + case DestroyNotify: + /* + * This is sent to confirm the XDestroyWindow call. + * + * XXX WHY is this commented out? Should we re-enable it? + */ + /* fgAddToWindowDestroyList ( window ); */ + break; + + case Expose: + /* + * We are too dumb to process partial exposes... + * + * XXX Well, we could do it. However, it seems to only + * XXX be potentially useful for single-buffered (since + * XXX double-buffered does not respect viewport when we + * XXX do a buffer-swap). + * + */ + if( event.xexpose.count == 0 ) + { + GETWINDOW( xexpose ); + window->State.Redisplay = GL_TRUE; + } + break; + + case MapNotify: + break; + + case UnmapNotify: + /* We get this when iconifying a window. */ + GETWINDOW( xunmap ); + INVOKE_WCB( *window, WindowStatus, ( GLUT_HIDDEN ) ); + window->State.Visible = GL_FALSE; + break; + + case MappingNotify: + /* + * Have the client's keyboard knowledge updated (xlib.ps, + * page 206, says that's a good thing to do) + */ + XRefreshKeyboardMapping( (XMappingEvent *) &event ); + break; + + case VisibilityNotify: + { + /* + * Sending this event, the X server can notify us that the window + * has just acquired one of the three possible visibility states: + * VisibilityUnobscured, VisibilityPartiallyObscured or + * VisibilityFullyObscured. Note that we DO NOT receive a + * VisibilityNotify event when iconifying a window, we only get an + * UnmapNotify then. + */ + GETWINDOW( xvisibility ); + switch( event.xvisibility.state ) + { + case VisibilityUnobscured: + INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) ); + window->State.Visible = GL_TRUE; + break; + + case VisibilityPartiallyObscured: + INVOKE_WCB( *window, WindowStatus, + ( GLUT_PARTIALLY_RETAINED ) ); + window->State.Visible = GL_TRUE; + break; + + case VisibilityFullyObscured: + INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_COVERED ) ); + window->State.Visible = GL_FALSE; + break; + + default: + fgWarning( "Unknown X visibility state: %d", + event.xvisibility.state ); + break; + } + } + break; + + case EnterNotify: + case LeaveNotify: + GETWINDOW( xcrossing ); + GETMOUSE( xcrossing ); + if( ( event.type == LeaveNotify ) && window->IsMenu && + window->ActiveMenu && window->ActiveMenu->IsActive ) + fgUpdateMenuHighlight( window->ActiveMenu ); + + INVOKE_WCB( *window, Entry, ( ( EnterNotify == event.type ) ? + GLUT_ENTERED : + GLUT_LEFT ) ); + break; + + case MotionNotify: + { + GETWINDOW( xmotion ); + GETMOUSE( xmotion ); + + if( window->ActiveMenu ) + { + if( window == window->ActiveMenu->ParentWindow ) + { + window->ActiveMenu->Window->State.MouseX = + event.xmotion.x_root - window->ActiveMenu->X; + window->ActiveMenu->Window->State.MouseY = + event.xmotion.y_root - window->ActiveMenu->Y; + } + + fgUpdateMenuHighlight( window->ActiveMenu ); + + break; + } + + /* + * XXX For more than 5 buttons, just check {event.xmotion.state}, + * XXX rather than a host of bit-masks? Or maybe we need to + * XXX track ButtonPress/ButtonRelease events in our own + * XXX bit-mask? + */ + fgState.Modifiers = fghGetXModifiers( event.xmotion.state ); + if ( event.xmotion.state & ( Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) ) { + INVOKE_WCB( *window, Motion, ( event.xmotion.x, + event.xmotion.y ) ); + } else { + INVOKE_WCB( *window, Passive, ( event.xmotion.x, + event.xmotion.y ) ); + } + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case ButtonRelease: + case ButtonPress: + { + GLboolean pressed = GL_TRUE; + int button; + + if( event.type == ButtonRelease ) + pressed = GL_FALSE ; + + /* + * A mouse button has been pressed or released. Traditionally, + * break if the window was found within the freeglut structures. + */ + GETWINDOW( xbutton ); + GETMOUSE( xbutton ); + + /* + * An X button (at least in XFree86) is numbered from 1. + * A GLUT button is numbered from 0. + * Old GLUT passed through buttons other than just the first + * three, though it only gave symbolic names and official + * support to the first three. + */ + button = event.xbutton.button - 1; + + /* + * Do not execute the application's mouse callback if a menu + * is hooked to this button. In that case an appropriate + * private call should be generated. + */ + if( fgCheckActiveMenu( window, button, pressed, + event.xbutton.x_root, event.xbutton.y_root ) ) + break; + + /* + * Check if there is a mouse or mouse wheel callback hooked to the + * window + */ + if( ! FETCH_WCB( *window, Mouse ) && + ! FETCH_WCB( *window, MouseWheel ) ) + break; + + fgState.Modifiers = fghGetXModifiers( event.xbutton.state ); + + /* Finally execute the mouse or mouse wheel callback */ + if( ( button < glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS ) ) || ( ! FETCH_WCB( *window, MouseWheel ) ) ) + INVOKE_WCB( *window, Mouse, ( button, + pressed ? GLUT_DOWN : GLUT_UP, + event.xbutton.x, + event.xbutton.y ) + ); + else + { + /* + * Map 4 and 5 to wheel zero; EVEN to +1, ODD to -1 + * " 6 and 7 " " one; ... + * + * XXX This *should* be behind some variables/macros, + * XXX since the order and numbering isn't certain + * XXX See XFree86 configuration docs (even back in the + * XXX 3.x days, and especially with 4.x). + * + * XXX Note that {button} has already been decremeted + * XXX in mapping from X button numbering to GLUT. + */ + int wheel_number = (button - glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS )) / 2; + int direction = -1; + if( button % 2 ) + direction = 1; + + if( pressed ) + INVOKE_WCB( *window, MouseWheel, ( wheel_number, + direction, + event.xbutton.x, + event.xbutton.y ) + ); + } + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case KeyRelease: + case KeyPress: + { + FGCBKeyboard keyboard_cb; + FGCBSpecial special_cb; + + GETWINDOW( xkey ); + GETMOUSE( xkey ); + + /* Detect auto repeated keys, if configured globally or per-window */ + + if ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) + { + if (event.type==KeyRelease) + { + /* + * Look at X11 keystate to detect repeat mode. + * While X11 says the key is actually held down, we'll ignore KeyRelease/KeyPress pairs. + */ + + char keys[32]; + XQueryKeymap( fgDisplay.Display, keys ); /* Look at X11 keystate to detect repeat mode */ + + if ( event.xkey.keycode<256 ) /* XQueryKeymap is limited to 256 keycodes */ + { + if ( keys[event.xkey.keycode>>3] & (1<<(event.xkey.keycode%8)) ) + window->State.KeyRepeating = GL_TRUE; + else + window->State.KeyRepeating = GL_FALSE; + } + } + } + else + window->State.KeyRepeating = GL_FALSE; + + /* Cease processing this event if it is auto repeated */ + + if (window->State.KeyRepeating) + { + if (event.type == KeyPress) window->State.KeyRepeating = GL_FALSE; + break; + } + + if( event.type == KeyPress ) + { + keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard )); + special_cb = (FGCBSpecial) ( FETCH_WCB( *window, Special )); + } + else + { + keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp )); + special_cb = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp )); + } + + /* Is there a keyboard/special callback hooked for this window? */ + if( keyboard_cb || special_cb ) + { + XComposeStatus composeStatus; + char asciiCode[ 32 ]; + KeySym keySym; + int len; + + /* Check for the ASCII/KeySym codes associated with the event: */ + len = XLookupString( &event.xkey, asciiCode, sizeof(asciiCode), + &keySym, &composeStatus + ); + + /* GLUT API tells us to have two separate callbacks... */ + if( len > 0 ) + { + /* ...one for the ASCII translateable keypresses... */ + if( keyboard_cb ) + { + fgSetWindow( window ); + fgState.Modifiers = fghGetXModifiers( event.xkey.state ); + keyboard_cb( asciiCode[ 0 ], + event.xkey.x, event.xkey.y + ); + fgState.Modifiers = INVALID_MODIFIERS; + } + } + else + { + int special = -1; + + /* + * ...and one for all the others, which need to be + * translated to GLUT_KEY_Xs... + */ + switch( keySym ) + { + case XK_F1: special = GLUT_KEY_F1; break; + case XK_F2: special = GLUT_KEY_F2; break; + case XK_F3: special = GLUT_KEY_F3; break; + case XK_F4: special = GLUT_KEY_F4; break; + case XK_F5: special = GLUT_KEY_F5; break; + case XK_F6: special = GLUT_KEY_F6; break; + case XK_F7: special = GLUT_KEY_F7; break; + case XK_F8: special = GLUT_KEY_F8; break; + case XK_F9: special = GLUT_KEY_F9; break; + case XK_F10: special = GLUT_KEY_F10; break; + case XK_F11: special = GLUT_KEY_F11; break; + case XK_F12: special = GLUT_KEY_F12; break; + + case XK_KP_Left: + case XK_Left: special = GLUT_KEY_LEFT; break; + case XK_KP_Right: + case XK_Right: special = GLUT_KEY_RIGHT; break; + case XK_KP_Up: + case XK_Up: special = GLUT_KEY_UP; break; + case XK_KP_Down: + case XK_Down: special = GLUT_KEY_DOWN; break; + + case XK_KP_Prior: + case XK_Prior: special = GLUT_KEY_PAGE_UP; break; + case XK_KP_Next: + case XK_Next: special = GLUT_KEY_PAGE_DOWN; break; + case XK_KP_Home: + case XK_Home: special = GLUT_KEY_HOME; break; + case XK_KP_End: + case XK_End: special = GLUT_KEY_END; break; + case XK_KP_Insert: + case XK_Insert: special = GLUT_KEY_INSERT; break; + + case XK_Num_Lock : special = GLUT_KEY_NUM_LOCK; break; + case XK_KP_Begin : special = GLUT_KEY_BEGIN; break; + case XK_KP_Delete: special = GLUT_KEY_DELETE; break; + } + + /* + * Execute the callback (if one has been specified), + * given that the special code seems to be valid... + */ + if( special_cb && (special != -1) ) + { + fgSetWindow( window ); + fgState.Modifiers = fghGetXModifiers( event.xkey.state ); + special_cb( special, event.xkey.x, event.xkey.y ); + fgState.Modifiers = INVALID_MODIFIERS; + } + } + } + } + break; + + case ReparentNotify: + break; /* XXX Should disable this event */ + + /* Not handled */ + case GravityNotify: + break; + + default: + fgWarning ("Unknown X event type: %d\n", event.type); + break; + } + } + +#elif TARGET_HOST_MS_WINDOWS + + MSG stMsg; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" ); + + while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) ) + { + if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 ) + { + if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) + { + fgDeinitialize( ); + exit( 0 ); + } + else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS ) + fgState.ExecState = GLUT_EXEC_STATE_STOP; + + return; + } + + TranslateMessage( &stMsg ); + DispatchMessage( &stMsg ); + } +#endif + + if( fgState.Timers.First ) + fghCheckTimers( ); + fghCheckJoystickPolls( ); + fghDisplayAll( ); + + fgCloseWindows( ); +} + +/* + * Enters the freeglut processing loop. + * Stays until the "ExecState" changes to "GLUT_EXEC_STATE_STOP". + */ +void FGAPIENTRY glutMainLoop( void ) +{ + int action; + +#if TARGET_HOST_MS_WINDOWS + SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ; +#endif + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoop" ); + +#if TARGET_HOST_MS_WINDOWS + /* + * Processing before the main loop: If there is a window which is open and + * which has a visibility callback, call it. I know this is an ugly hack, + * but I'm not sure what else to do about it. Ideally we should leave + * something uninitialized in the create window code and initialize it in + * the main loop, and have that initialization create a "WM_ACTIVATE" + * message. Then we would put the visibility callback code in the + * "case WM_ACTIVATE" block below. - John Fay -- 10/24/02 + */ + while( window ) + { + if ( FETCH_WCB( *window, Visibility ) ) + { + SFG_Window *current_window = fgStructure.CurrentWindow ; + + INVOKE_WCB( *window, Visibility, ( window->State.Visible ) ); + fgSetWindow( current_window ); + } + + window = (SFG_Window *)window->Node.Next ; + } +#endif + + fgState.ExecState = GLUT_EXEC_STATE_RUNNING ; + while( fgState.ExecState == GLUT_EXEC_STATE_RUNNING ) + { + SFG_Window *window; + + glutMainLoopEvent( ); + /* + * Step through the list of windows, seeing if there are any + * that are not menus + */ + for( window = ( SFG_Window * )fgStructure.Windows.First; + window; + window = ( SFG_Window * )window->Node.Next ) + if ( ! ( window->IsMenu ) ) + break; + + if( ! window ) + fgState.ExecState = GLUT_EXEC_STATE_STOP; + else + { + if( fgState.IdleCallback ) + { + if( fgStructure.CurrentWindow && + fgStructure.CurrentWindow->IsMenu ) + /* fail safe */ + fgSetWindow( window ); + fgState.IdleCallback( ); + } + + fghSleepForEvents( ); + } + } + + /* + * When this loop terminates, destroy the display, state and structure + * of a freeglut session, so that another glutInit() call can happen + * + * Save the "ActionOnWindowClose" because "fgDeinitialize" resets it. + */ + action = fgState.ActionOnWindowClose; + fgDeinitialize( ); + if( action == GLUT_ACTION_EXIT ) + exit( 0 ); +} + +/* + * Leaves the freeglut processing loop. + */ +void FGAPIENTRY glutLeaveMainLoop( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLeaveMainLoop" ); + fgState.ExecState = GLUT_EXEC_STATE_STOP ; +} + + +#if TARGET_HOST_MS_WINDOWS +/* + * Determine a GLUT modifer mask based on MS-WINDOWS system info. + */ +static int fghGetWin32Modifiers (void) +{ + return + ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) || + ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) | + ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) || + ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) | + ( ( ( GetKeyState( VK_LMENU ) < 0 ) || + ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 ); +} + +/* + * The window procedure for handling Win32 events + */ +LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, + LPARAM lParam ) +{ + SFG_Window* window; + PAINTSTRUCT ps; + LRESULT lRet = 1; + + FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ; + + window = fgWindowByHandle( hWnd ); + + if ( ( window == NULL ) && ( uMsg != WM_CREATE ) ) + return DefWindowProc( hWnd, uMsg, wParam, lParam ); + + /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0, + uMsg, wParam, lParam ); */ + switch( uMsg ) + { + case WM_CREATE: + /* The window structure is passed as the creation structure paramter... */ + window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams); + FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window", + "fgWindowProc" ); + + window->Window.Handle = hWnd; + window->Window.Device = GetDC( hWnd ); + if( window->IsMenu ) + { + unsigned int current_DisplayMode = fgState.DisplayMode; + fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH; +#if !defined(_WIN32_WCE) + fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); +#endif + fgState.DisplayMode = current_DisplayMode; + + if( fgStructure.MenuContext ) + wglMakeCurrent( window->Window.Device, + fgStructure.MenuContext->MContext + ); + else + { + fgStructure.MenuContext = + (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) ); + fgStructure.MenuContext->MContext = + wglCreateContext( window->Window.Device ); + } + + /* window->Window.Context = wglGetCurrentContext (); */ + window->Window.Context = wglCreateContext( window->Window.Device ); + } + else + { +#if !defined(_WIN32_WCE) + fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); +#endif + + if( ! fgState.UseCurrentContext ) + window->Window.Context = + wglCreateContext( window->Window.Device ); + else + { + window->Window.Context = wglGetCurrentContext( ); + if( ! window->Window.Context ) + window->Window.Context = + wglCreateContext( window->Window.Device ); + } + +#if !defined(_WIN32_WCE) + fgNewWGLCreateContext( window ); +#endif + } + + window->State.NeedToResize = GL_TRUE; + if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) ) + { + SFG_Window *current_window = fgStructure.CurrentWindow; + + fgSetWindow( window ); + window->State.Width = glutGet( GLUT_WINDOW_WIDTH ); + window->State.Height = glutGet( GLUT_WINDOW_HEIGHT ); + fgSetWindow( current_window ); + } + + ReleaseDC( window->Window.Handle, window->Window.Device ); + +#if defined(_WIN32_WCE) + /* Take over button handling */ + { + HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll")); + if (dxDllLib) + { + GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z")); + GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ")); + } + + if(GXOpenInput_) + (*GXOpenInput_)(); + if(GXGetDefaultKeys_) + gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS); + } + +#endif /* defined(_WIN32_WCE) */ + break; + + case WM_SIZE: + /* + * If the window is visible, then it is the user manually resizing it. + * If it is not, then it is the system sending us a dummy resize with + * zero dimensions on a "glutIconifyWindow" call. + */ + if( window->State.Visible ) + { + window->State.NeedToResize = GL_TRUE; +#if defined(_WIN32_WCE) + window->State.Width = HIWORD(lParam); + window->State.Height = LOWORD(lParam); +#else + window->State.Width = LOWORD(lParam); + window->State.Height = HIWORD(lParam); +#endif /* defined(_WIN32_WCE) */ + } + + break; + + case WM_SETFOCUS: +/* printf("WM_SETFOCUS: %p\n", window ); */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) ); + break; + + case WM_KILLFOCUS: +/* printf("WM_KILLFOCUS: %p\n", window ); */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) ); + + if( window->IsMenu && + window->ActiveMenu && window->ActiveMenu->IsActive ) + fgUpdateMenuHighlight( window->ActiveMenu ); + + break; + +#if 0 + case WM_ACTIVATE: + if (LOWORD(wParam) != WA_INACTIVE) + { +/* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window, + window->State.Cursor ); */ + fgSetCursor( window, window->State.Cursor ); + } + + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; +#endif + + case WM_SETCURSOR: +/* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */ + if( LOWORD( lParam ) == HTCLIENT ) + fgSetCursor ( window, window->State.Cursor ) ; + else + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + + case WM_SHOWWINDOW: + window->State.Visible = GL_TRUE; + window->State.Redisplay = GL_TRUE; + break; + + case WM_PAINT: + /* Turn on the visibility in case it was turned off somehow */ + window->State.Visible = GL_TRUE; + BeginPaint( hWnd, &ps ); + fghRedrawWindow( window ); + EndPaint( hWnd, &ps ); + break; + + case WM_CLOSE: + fgDestroyWindow ( window ); + if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION ) + PostQuitMessage(0); + break; + + case WM_DESTROY: + /* + * The window already got destroyed, so don't bother with it. + */ + return 0; + + case WM_MOUSEMOVE: + { +#if defined(_WIN32_WCE) + window->State.MouseX = 320-HIWORD( lParam ); + window->State.MouseY = LOWORD( lParam ); +#else + window->State.MouseX = LOWORD( lParam ); + window->State.MouseY = HIWORD( lParam ); +#endif /* defined(_WIN32_WCE) */ + /* Restrict to [-32768, 32767] to match X11 behaviour */ + /* See comment in "freeglut_developer" mailing list 10/4/04 */ + if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536; + if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536; + + if ( window->ActiveMenu ) + { + fgUpdateMenuHighlight( window->ActiveMenu ); + break; + } + + fgState.Modifiers = fghGetWin32Modifiers( ); + + if( ( wParam & MK_LBUTTON ) || + ( wParam & MK_MBUTTON ) || + ( wParam & MK_RBUTTON ) ) + INVOKE_WCB( *window, Motion, ( window->State.MouseX, + window->State.MouseY ) ); + else + INVOKE_WCB( *window, Passive, ( window->State.MouseX, + window->State.MouseY ) ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { + GLboolean pressed = GL_TRUE; + int button; + +#if defined(_WIN32_WCE) + window->State.MouseX = 320-HIWORD( lParam ); + window->State.MouseY = LOWORD( lParam ); +#else + window->State.MouseX = LOWORD( lParam ); + window->State.MouseY = HIWORD( lParam ); +#endif /* defined(_WIN32_WCE) */ + + /* Restrict to [-32768, 32767] to match X11 behaviour */ + /* See comment in "freeglut_developer" mailing list 10/4/04 */ + if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536; + if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536; + + switch( uMsg ) + { + case WM_LBUTTONDOWN: + pressed = GL_TRUE; + button = GLUT_LEFT_BUTTON; + break; + case WM_MBUTTONDOWN: + pressed = GL_TRUE; + button = GLUT_MIDDLE_BUTTON; + break; + case WM_RBUTTONDOWN: + pressed = GL_TRUE; + button = GLUT_RIGHT_BUTTON; + break; + case WM_LBUTTONUP: + pressed = GL_FALSE; + button = GLUT_LEFT_BUTTON; + break; + case WM_MBUTTONUP: + pressed = GL_FALSE; + button = GLUT_MIDDLE_BUTTON; + break; + case WM_RBUTTONUP: + pressed = GL_FALSE; + button = GLUT_RIGHT_BUTTON; + break; + default: + pressed = GL_FALSE; + button = -1; + break; + } + +#if !defined(_WIN32_WCE) + if( GetSystemMetrics( SM_SWAPBUTTON ) ) + { + if( button == GLUT_LEFT_BUTTON ) + button = GLUT_RIGHT_BUTTON; + else + if( button == GLUT_RIGHT_BUTTON ) + button = GLUT_LEFT_BUTTON; + } +#endif /* !defined(_WIN32_WCE) */ + + if( button == -1 ) + return DefWindowProc( hWnd, uMsg, lParam, wParam ); + + /* + * Do not execute the application's mouse callback if a menu + * is hooked to this button. In that case an appropriate + * private call should be generated. + */ + if( fgCheckActiveMenu( window, button, pressed, + window->State.MouseX, window->State.MouseY ) ) + break; + + /* Set capture so that the window captures all the mouse messages */ + /* + * XXX - Multiple button support: Under X11, the mouse is not released + * XXX - from the window until all buttons have been released, even if the + * XXX - user presses a button in another window. This will take more + * XXX - code changes than I am up to at the moment (10/5/04). The present + * XXX - is a 90 percent solution. + */ + if ( pressed == GL_TRUE ) + SetCapture ( window->Window.Handle ) ; + else + ReleaseCapture () ; + + if( ! FETCH_WCB( *window, Mouse ) ) + break; + + fgSetWindow( window ); + fgState.Modifiers = fghGetWin32Modifiers( ); + + INVOKE_WCB( + *window, Mouse, + ( button, + pressed ? GLUT_DOWN : GLUT_UP, + window->State.MouseX, + window->State.MouseY + ) + ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case 0x020a: + /* Should be WM_MOUSEWHEEL but my compiler doesn't recognize it */ + { + /* + * XXX THIS IS SPECULATIVE -- John Fay, 10/2/03 + * XXX Should use WHEEL_DELTA instead of 120 + */ + int wheel_number = LOWORD( wParam ); + short ticks = ( short )HIWORD( wParam ) / 120; + int direction = 1; + + if( ticks < 0 ) + { + direction = -1; + ticks = -ticks; + } + + /* + * The mouse cursor has moved. Remember the new mouse cursor's position + */ + /* window->State.MouseX = LOWORD( lParam ); */ + /* Need to adjust by window position, */ + /* window->State.MouseY = HIWORD( lParam ); */ + /* change "lParam" to other parameter */ + + if( ! FETCH_WCB( *window, MouseWheel ) && + ! FETCH_WCB( *window, Mouse ) ) + break; + + fgSetWindow( window ); + fgState.Modifiers = fghGetWin32Modifiers( ); + + while( ticks-- ) + if( FETCH_WCB( *window, MouseWheel ) ) + INVOKE_WCB( *window, MouseWheel, + ( wheel_number, + direction, + window->State.MouseX, + window->State.MouseY + ) + ); + else /* No mouse wheel, call the mouse button callback twice */ + { + /* + * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4 + * " " one +1 to 5, -1 to 6, ... + * + * XXX The below assumes that you have no more than 3 mouse + * XXX buttons. Sorry. + */ + int button = wheel_number * 2 + 3; + if( direction < 0 ) + ++button; + INVOKE_WCB( *window, Mouse, + ( button, GLUT_DOWN, + window->State.MouseX, window->State.MouseY ) + ); + INVOKE_WCB( *window, Mouse, + ( button, GLUT_UP, + window->State.MouseX, window->State.MouseY ) + ); + } + + fgState.Modifiers = INVALID_MODIFIERS; + } + break ; + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + { + int keypress = -1; + POINT mouse_pos ; + + if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) ) + break; + + /* + * Remember the current modifiers state. This is done here in order + * to make sure the VK_DELETE keyboard callback is executed properly. + */ + fgState.Modifiers = fghGetWin32Modifiers( ); + + GetCursorPos( &mouse_pos ); + ScreenToClient( window->Window.Handle, &mouse_pos ); + + window->State.MouseX = mouse_pos.x; + window->State.MouseY = mouse_pos.y; + + /* Convert the Win32 keystroke codes to GLUTtish way */ +# define KEY(a,b) case a: keypress = b; break; + + switch( wParam ) + { + KEY( VK_F1, GLUT_KEY_F1 ); + KEY( VK_F2, GLUT_KEY_F2 ); + KEY( VK_F3, GLUT_KEY_F3 ); + KEY( VK_F4, GLUT_KEY_F4 ); + KEY( VK_F5, GLUT_KEY_F5 ); + KEY( VK_F6, GLUT_KEY_F6 ); + KEY( VK_F7, GLUT_KEY_F7 ); + KEY( VK_F8, GLUT_KEY_F8 ); + KEY( VK_F9, GLUT_KEY_F9 ); + KEY( VK_F10, GLUT_KEY_F10 ); + KEY( VK_F11, GLUT_KEY_F11 ); + KEY( VK_F12, GLUT_KEY_F12 ); + KEY( VK_PRIOR, GLUT_KEY_PAGE_UP ); + KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN ); + KEY( VK_HOME, GLUT_KEY_HOME ); + KEY( VK_END, GLUT_KEY_END ); + KEY( VK_LEFT, GLUT_KEY_LEFT ); + KEY( VK_UP, GLUT_KEY_UP ); + KEY( VK_RIGHT, GLUT_KEY_RIGHT ); + KEY( VK_DOWN, GLUT_KEY_DOWN ); + KEY( VK_INSERT, GLUT_KEY_INSERT ); + + case VK_DELETE: + /* The delete key should be treated as an ASCII keypress: */ + INVOKE_WCB( *window, Keyboard, + ( 127, window->State.MouseX, window->State.MouseY ) + ); + } + +#if defined(_WIN32_WCE) + if(!(lParam & 0x40000000)) /* Prevent auto-repeat */ + { + if(wParam==(unsigned)gxKeyList.vkRight) + keypress = GLUT_KEY_RIGHT; + else if(wParam==(unsigned)gxKeyList.vkLeft) + keypress = GLUT_KEY_LEFT; + else if(wParam==(unsigned)gxKeyList.vkUp) + keypress = GLUT_KEY_UP; + else if(wParam==(unsigned)gxKeyList.vkDown) + keypress = GLUT_KEY_DOWN; + else if(wParam==(unsigned)gxKeyList.vkA) + keypress = GLUT_KEY_F1; + else if(wParam==(unsigned)gxKeyList.vkB) + keypress = GLUT_KEY_F2; + else if(wParam==(unsigned)gxKeyList.vkC) + keypress = GLUT_KEY_F3; + else if(wParam==(unsigned)gxKeyList.vkStart) + keypress = GLUT_KEY_F4; + } +#endif + + if( keypress != -1 ) + INVOKE_WCB( *window, Special, + ( keypress, + window->State.MouseX, window->State.MouseY ) + ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_SYSKEYUP: + case WM_KEYUP: + { + int keypress = -1; + POINT mouse_pos; + + /* + * Remember the current modifiers state. This is done here in order + * to make sure the VK_DELETE keyboard callback is executed properly. + */ + fgState.Modifiers = fghGetWin32Modifiers( ); + + GetCursorPos( &mouse_pos ); + ScreenToClient( window->Window.Handle, &mouse_pos ); + + window->State.MouseX = mouse_pos.x; + window->State.MouseY = mouse_pos.y; + + /* + * Convert the Win32 keystroke codes to GLUTtish way. + * "KEY(a,b)" was defined under "WM_KEYDOWN" + */ + + switch( wParam ) + { + KEY( VK_F1, GLUT_KEY_F1 ); + KEY( VK_F2, GLUT_KEY_F2 ); + KEY( VK_F3, GLUT_KEY_F3 ); + KEY( VK_F4, GLUT_KEY_F4 ); + KEY( VK_F5, GLUT_KEY_F5 ); + KEY( VK_F6, GLUT_KEY_F6 ); + KEY( VK_F7, GLUT_KEY_F7 ); + KEY( VK_F8, GLUT_KEY_F8 ); + KEY( VK_F9, GLUT_KEY_F9 ); + KEY( VK_F10, GLUT_KEY_F10 ); + KEY( VK_F11, GLUT_KEY_F11 ); + KEY( VK_F12, GLUT_KEY_F12 ); + KEY( VK_PRIOR, GLUT_KEY_PAGE_UP ); + KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN ); + KEY( VK_HOME, GLUT_KEY_HOME ); + KEY( VK_END, GLUT_KEY_END ); + KEY( VK_LEFT, GLUT_KEY_LEFT ); + KEY( VK_UP, GLUT_KEY_UP ); + KEY( VK_RIGHT, GLUT_KEY_RIGHT ); + KEY( VK_DOWN, GLUT_KEY_DOWN ); + KEY( VK_INSERT, GLUT_KEY_INSERT ); + + case VK_DELETE: + /* The delete key should be treated as an ASCII keypress: */ + INVOKE_WCB( *window, KeyboardUp, + ( 127, window->State.MouseX, window->State.MouseY ) + ); + break; + + default: + { +#if !defined(_WIN32_WCE) + BYTE state[ 256 ]; + WORD code[ 2 ]; + + GetKeyboardState( state ); + + if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 ) + wParam=code[ 0 ]; + + INVOKE_WCB( *window, KeyboardUp, + ( (char)wParam, + window->State.MouseX, window->State.MouseY ) + ); +#endif /* !defined(_WIN32_WCE) */ + } + } + + if( keypress != -1 ) + INVOKE_WCB( *window, SpecialUp, + ( keypress, + window->State.MouseX, window->State.MouseY ) + ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_SYSCHAR: + case WM_CHAR: + { + if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) ) + break; + + fgState.Modifiers = fghGetWin32Modifiers( ); + INVOKE_WCB( *window, Keyboard, + ( (char)wParam, + window->State.MouseX, window->State.MouseY ) + ); + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_CAPTURECHANGED: + /* User has finished resizing the window, force a redraw */ + INVOKE_WCB( *window, Display, ( ) ); + + /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */ + break; + + /* Other messages that I have seen and which are not handled already */ + case WM_SETTEXT: /* 0x000c */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + /* Pass it on to "DefWindowProc" to set the window text */ + break; + + case WM_GETTEXT: /* 0x000d */ + /* Ideally we would copy the title of the window into "lParam" */ + /* strncpy ( (char *)lParam, "Window Title", wParam ); + lRet = ( wParam > 12 ) ? 12 : wParam; */ + /* the number of characters copied */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + + case WM_GETTEXTLENGTH: /* 0x000e */ + /* Ideally we would get the length of the title of the window */ + lRet = 12; + /* the number of characters in "Window Title\0" (see above) */ + break; + + case WM_ERASEBKGND: /* 0x0014 */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + +#if !defined(_WIN32_WCE) + case WM_SYNCPAINT: /* 0x0088 */ + /* Another window has moved, need to update this one */ + window->State.Redisplay = GL_TRUE; + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + /* Help screen says this message must be passed to "DefWindowProc" */ + break; + + case WM_NCPAINT: /* 0x0085 */ + /* Need to update the border of this window */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + /* Pass it on to "DefWindowProc" to repaint a standard border */ + break; + + case WM_SYSCOMMAND : /* 0x0112 */ + { + /* + * We have received a system command message. Try to act on it. + * The commands are passed in through the "wParam" parameter: + * The least significant digit seems to be which edge of the window + * is being used for a resize event: + * 4 3 5 + * 1 2 + * 7 6 8 + * Congratulations and thanks to Richard Rauch for figuring this out.. + */ + switch ( wParam & 0xfff0 ) + { + case SC_SIZE : + break ; + + case SC_MOVE : + break ; + + case SC_MINIMIZE : + /* User has clicked on the "-" to minimize the window */ + /* Turn off the visibility */ + window->State.Visible = GL_FALSE ; + + break ; + + case SC_MAXIMIZE : + break ; + + case SC_NEXTWINDOW : + break ; + + case SC_PREVWINDOW : + break ; + + case SC_CLOSE : + /* Followed very closely by a WM_CLOSE message */ + break ; + + case SC_VSCROLL : + break ; + + case SC_HSCROLL : + break ; + + case SC_MOUSEMENU : + break ; + + case SC_KEYMENU : + break ; + + case SC_ARRANGE : + break ; + + case SC_RESTORE : + break ; + + case SC_TASKLIST : + break ; + + case SC_SCREENSAVE : + break ; + + case SC_HOTKEY : + break ; + +#if(WINVER >= 0x0400) + case SC_DEFAULT : + break ; + + case SC_MONITORPOWER : + break ; + + case SC_CONTEXTHELP : + break ; +#endif /* WINVER >= 0x0400 */ + + default: +#if _DEBUG + fgWarning( "Unknown wParam type 0x%x", wParam ); +#endif + break; + } + } +#endif /* !defined(_WIN32_WCE) */ + + /* We need to pass the message on to the operating system as well */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + + default: + /* Handle unhandled messages */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + } + + return lRet; +} +#endif + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_menu.c b/tests/Box2D_v2.2.1/freeglut/freeglut_menu.c new file mode 100755 index 0000000000000..9bdf8895cb65c --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_menu.c @@ -0,0 +1,1002 @@ +/* + * freeglut_menu.c + * + * Pull-down menu creation and handling. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 16 1999 + * + * 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 + * PAWEL W. OLSZTA 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. + */ + +#define FREEGLUT_BUILDING_LIB +#include "freeglut.h" +#include "freeglut_internal.h" + +/* -- DEFINITIONS ---------------------------------------------------------- */ + +/* + * FREEGLUT_MENU_FONT can be any freeglut bitmapped font. + * (Stroked fonts would not be out of the question, but we'd need to alter + * code, since GLUT (hence freeglut) does not quite unify stroked and + * bitmapped font handling.) + * Old UNIX/X11 GLUT (BSD, UNIX, IRIX, LINUX, HPUX, ...) used a system + * font best approximated by an 18-pixel HELVETICA, I think. MS-WINDOWS + * GLUT used something closest to the 8x13 fixed-width font. (Old + * GLUT apparently uses host-system menus rather than building its own. + * freeglut is building its own menus from scratch.) + * + * FREEGLUT_MENU_HEIGHT gives the height of ONE menu box. This should be + * the distances between two adjacent menu entries. It should scale + * automatically with the font choice, so you needn't alter it---unless you + * use a stroked font. + * + * FREEGLUT_MENU_BORDER says how many pixels to allow around the edge of a + * menu. (It also seems to be the same as the number of pixels used as + * a border around *items* to separate them from neighbors. John says + * that that wasn't the original intent...if not, perhaps we need another + * symbolic constant, FREEGLUT_MENU_ITEM_BORDER, or such.) + */ +#if TARGET_HOST_MS_WINDOWS +#define FREEGLUT_MENU_FONT GLUT_BITMAP_8_BY_13 +#else +#define FREEGLUT_MENU_FONT GLUT_BITMAP_HELVETICA_18 +#endif + +#define FREEGLUT_MENU_HEIGHT (glutBitmapHeight(FREEGLUT_MENU_FONT) + \ + FREEGLUT_MENU_BORDER) +#define FREEGLUT_MENU_BORDER 2 + + +/* + * These variables are for rendering the freeglut menu items. + * + * The choices are fore- and background, with and without h for Highlighting. + * Old GLUT appeared to be system-dependant for its colors (sigh) so we are + * too. These variables should be stuffed into global state and initialized + * via the glutInit*() system. + */ +#if TARGET_HOST_MS_WINDOWS +static float menu_pen_fore [4] = {0.0f, 0.0f, 0.0f, 1.0f}; +static float menu_pen_back [4] = {0.85f, 0.85f, 0.85f, 1.0f}; +static float menu_pen_hfore [4] = {1.0f, 1.0f, 1.0f, 1.0f}; +static float menu_pen_hback [4] = {0.15f, 0.15f, 0.45f, 1.0f}; +#else +static float menu_pen_fore [4] = {0.0f, 0.0f, 0.0f, 1.0f}; +static float menu_pen_back [4] = {0.70f, 0.70f, 0.70f, 1.0f}; +static float menu_pen_hfore [4] = {0.0f, 0.0f, 0.0f, 1.0f}; +static float menu_pen_hback [4] = {1.0f, 1.0f, 1.0f, 1.0f}; +#endif + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +/* + * Private function to find a menu entry by index + */ +static SFG_MenuEntry *fghFindMenuEntry( SFG_Menu* menu, int index ) +{ + SFG_MenuEntry *entry; + int i = 1; + + for( entry = (SFG_MenuEntry *)menu->Entries.First; + entry; + entry = (SFG_MenuEntry *)entry->Node.Next ) + { + if( i == index ) + break; + ++i; + } + + return entry; +} + +/* + * Deactivates a menu pointed by the function argument. + */ +static void fghDeactivateSubMenu( SFG_MenuEntry *menuEntry ) +{ + SFG_MenuEntry *subMenuIter; + /* Hide the present menu's window */ + fgSetWindow( menuEntry->SubMenu->Window ); + glutHideWindow( ); + + /* Forget about having that menu active anymore, now: */ + menuEntry->SubMenu->Window->ActiveMenu = NULL; + menuEntry->SubMenu->IsActive = GL_FALSE; + menuEntry->SubMenu->ActiveEntry = NULL; + + /* Hide all submenu windows, and the root menu's window. */ + for ( subMenuIter = (SFG_MenuEntry *)menuEntry->SubMenu->Entries.First; + subMenuIter; + subMenuIter = (SFG_MenuEntry *)subMenuIter->Node.Next ) + { + subMenuIter->IsActive = GL_FALSE; + + /* Is that an active submenu by any case? */ + if( subMenuIter->SubMenu ) + fghDeactivateSubMenu( subMenuIter ); + } + + fgSetWindow ( menuEntry->SubMenu->ParentWindow ) ; +} + +/* + * Private function to get the virtual maximum screen extent + */ +static GLvoid fghGetVMaxExtent( SFG_Window* window, int* x, int* y ) +{ + if( fgStructure.GameModeWindow ) + { +#if TARGET_HOST_POSIX_X11 + int wx, wy; + Window w; + + XTranslateCoordinates( + fgDisplay.Display, + window->Window.Handle, + fgDisplay.RootWindow, + 0, 0, &wx, &wy, &w); + + *x = fgState.GameModeSize.X + wx; + *y = fgState.GameModeSize.Y + wy; +#else + *x = glutGet ( GLUT_SCREEN_WIDTH ); + *y = glutGet ( GLUT_SCREEN_HEIGHT ); +#endif + } + else + { + *x = fgDisplay.ScreenWidth; + *y = fgDisplay.ScreenHeight; + } +} + +/* + * Private function to check for the current menu/sub menu activity state + */ +static GLboolean fghCheckMenuStatus( SFG_Menu* menu ) +{ + SFG_MenuEntry* menuEntry; + int x, y; + + /* First of all check any of the active sub menus... */ + for( menuEntry = (SFG_MenuEntry *)menu->Entries.First; + menuEntry; + menuEntry = (SFG_MenuEntry *)menuEntry->Node.Next ) + { + if( menuEntry->SubMenu && menuEntry->IsActive ) + { + /* + * OK, have the sub-menu checked, too. If it returns GL_TRUE, it + * will mean that it caught the mouse cursor and we do not need + * to regenerate the activity list, and so our parents do... + */ + GLboolean return_status; + + menuEntry->SubMenu->Window->State.MouseX = + menu->Window->State.MouseX + menu->X - menuEntry->SubMenu->X; + menuEntry->SubMenu->Window->State.MouseY = + menu->Window->State.MouseY + menu->Y - menuEntry->SubMenu->Y; + return_status = fghCheckMenuStatus( menuEntry->SubMenu ); + + if ( return_status ) + return GL_TRUE; + } + } + + /* That much about our sub menus, let's get to checking the current menu: */ + x = menu->Window->State.MouseX; + y = menu->Window->State.MouseY; + + /* Check if the mouse cursor is contained within the current menu box */ + if( ( x >= FREEGLUT_MENU_BORDER ) && + ( x < menu->Width - FREEGLUT_MENU_BORDER ) && + ( y >= FREEGLUT_MENU_BORDER ) && + ( y < menu->Height - FREEGLUT_MENU_BORDER ) ) + { + int menuID = ( y - FREEGLUT_MENU_BORDER ) / FREEGLUT_MENU_HEIGHT; + + /* The mouse cursor is somewhere over our box, check it out. */ + menuEntry = fghFindMenuEntry( menu, menuID + 1 ); + FREEGLUT_INTERNAL_ERROR_EXIT( menuEntry, "Cannot find menu entry", + "fghCheckMenuStatus" ); + + menuEntry->IsActive = GL_TRUE; + menuEntry->Ordinal = menuID; + + /* + * If this is not the same as the last active menu entry, deactivate + * the previous entry. Specifically, if the previous active entry + * was a submenu then deactivate it. + */ + if( menu->ActiveEntry && ( menuEntry != menu->ActiveEntry ) ) + if( menu->ActiveEntry->SubMenu ) + fghDeactivateSubMenu( menu->ActiveEntry ); + + if( menuEntry != menu->ActiveEntry ) + { + menu->Window->State.Redisplay = GL_TRUE; + if( menu->ActiveEntry ) + menu->ActiveEntry->IsActive = GL_FALSE; + } + + menu->ActiveEntry = menuEntry; + menu->IsActive = GL_TRUE; /* XXX Do we need this? */ + + /* + * OKi, we have marked that entry as active, but it would be also + * nice to have its contents updated, in case it's a sub menu. + * Also, ignore the return value of the check function: + */ + if( menuEntry->SubMenu ) + { + if ( ! menuEntry->SubMenu->IsActive ) + { + int max_x, max_y; + SFG_Window *current_window = fgStructure.CurrentWindow; + + /* Set up the initial menu position now... */ + menuEntry->SubMenu->IsActive = GL_TRUE; + + /* Set up the initial submenu position now: */ + fghGetVMaxExtent(menu->ParentWindow, &max_x, &max_y); + menuEntry->SubMenu->X = menu->X + menu->Width; + menuEntry->SubMenu->Y = menu->Y + + menuEntry->Ordinal * FREEGLUT_MENU_HEIGHT; + + if( menuEntry->SubMenu->X + menuEntry->SubMenu->Width > max_x ) + menuEntry->SubMenu->X = menu->X - menuEntry->SubMenu->Width; + + if( menuEntry->SubMenu->Y + menuEntry->SubMenu->Height > max_y ) + { + menuEntry->SubMenu->Y -= ( menuEntry->SubMenu->Height - + FREEGLUT_MENU_HEIGHT - + 2 * FREEGLUT_MENU_BORDER ); + if( menuEntry->SubMenu->Y < 0 ) + menuEntry->SubMenu->Y = 0; + } + + fgSetWindow( menuEntry->SubMenu->Window ); + glutPositionWindow( menuEntry->SubMenu->X, + menuEntry->SubMenu->Y ); + glutReshapeWindow( menuEntry->SubMenu->Width, + menuEntry->SubMenu->Height ); + glutPopWindow( ); + glutShowWindow( ); + menuEntry->SubMenu->Window->ActiveMenu = menuEntry->SubMenu; + fgSetWindow( current_window ); + menuEntry->SubMenu->Window->State.MouseX = + x + menu->X - menuEntry->SubMenu->X; + menuEntry->SubMenu->Window->State.MouseY = + y + menu->Y - menuEntry->SubMenu->Y; + fghCheckMenuStatus( menuEntry->SubMenu ); + } + + /* Activate it because its parent entry is active */ + menuEntry->SubMenu->IsActive = GL_TRUE; /* XXX Do we need this? */ + } + + /* Report back that we have caught the menu cursor */ + return GL_TRUE; + } + + /* Looks like the menu cursor is somewhere else... */ + if( menu->ActiveEntry && menu->ActiveEntry->IsActive && + ( !menu->ActiveEntry->SubMenu || + !menu->ActiveEntry->SubMenu->IsActive ) ) + { + menu->Window->State.Redisplay = GL_TRUE; + menu->ActiveEntry->IsActive = GL_FALSE; + menu->ActiveEntry = NULL; + } + + return GL_FALSE; +} + +/* + * Displays a menu box and all of its submenus (if they are active) + */ +static void fghDisplayMenuBox( SFG_Menu* menu ) +{ + SFG_MenuEntry *menuEntry; + int i; + int border = FREEGLUT_MENU_BORDER; + + /* + * Have the menu box drawn first. The +- values are + * here just to make it more nice-looking... + */ + /* a non-black dark version of the below. */ + glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); + glBegin( GL_QUAD_STRIP ); + glVertex2i( menu->Width , 0 ); + glVertex2i( menu->Width - border, border); + glVertex2i( 0 , 0 ); + glVertex2i( border, border); + glVertex2i( 0 , menu->Height ); + glVertex2i( border, menu->Height - border); + glEnd( ); + + /* a non-black dark version of the below. */ + glColor4f( 0.5f, 0.5f, 0.5f, 1.0f ); + glBegin( GL_QUAD_STRIP ); + glVertex2i( 0 , menu->Height ); + glVertex2i( border, menu->Height - border); + glVertex2i( menu->Width , menu->Height ); + glVertex2i( menu->Width - border, menu->Height - border); + glVertex2i( menu->Width , 0 ); + glVertex2i( menu->Width - border, border); + glEnd( ); + + glColor4fv( menu_pen_back ); + glBegin( GL_QUADS ); + glVertex2i( border, border); + glVertex2i( menu->Width - border, border); + glVertex2i( menu->Width - border, menu->Height - border); + glVertex2i( border, menu->Height - border); + glEnd( ); + + /* Check if any of the submenus is currently active... */ + for( menuEntry = (SFG_MenuEntry *)menu->Entries.First; + menuEntry; + menuEntry = (SFG_MenuEntry *)menuEntry->Node.Next ) + { + /* Has the menu been marked as active, maybe? */ + if( menuEntry->IsActive ) + { + /* + * That's truly right, and we need to have it highlighted. + * There is an assumption that mouse cursor didn't move + * since the last check of menu activity state: + */ + int menuID = menuEntry->Ordinal; + + /* So have the highlight drawn... */ + glColor4fv( menu_pen_hback ); + glBegin( GL_QUADS ); + glVertex2i( border, + (menuID + 0)*FREEGLUT_MENU_HEIGHT + border ); + glVertex2i( menu->Width - border, + (menuID + 0)*FREEGLUT_MENU_HEIGHT + border ); + glVertex2i( menu->Width - border, + (menuID + 1)*FREEGLUT_MENU_HEIGHT + border ); + glVertex2i( border, + (menuID + 1)*FREEGLUT_MENU_HEIGHT + border ); + glEnd( ); + } + } + + /* Print the menu entries now... */ + + glColor4fv( menu_pen_fore ); + + for( menuEntry = (SFG_MenuEntry *)menu->Entries.First, i = 0; + menuEntry; + menuEntry = (SFG_MenuEntry *)menuEntry->Node.Next, ++i ) + { + /* If the menu entry is active, set the color to white */ + if( menuEntry->IsActive ) + glColor4fv( menu_pen_hfore ); + + /* Move the raster into position... */ + /* Try to center the text - JCJ 31 July 2003*/ + glRasterPos2i( + 2 * border, + ( i + 1 )*FREEGLUT_MENU_HEIGHT - + ( int )( FREEGLUT_MENU_HEIGHT*0.3 - border ) + ); + + /* Have the label drawn, character after character: */ + glutBitmapString( FREEGLUT_MENU_FONT, + (unsigned char *)menuEntry->Text); + + /* If it's a submenu, draw a right arrow */ + if( menuEntry->SubMenu ) + { + int width = glutBitmapWidth( FREEGLUT_MENU_FONT, '_' ); + int x_base = menu->Width - 2 - width; + int y_base = i*FREEGLUT_MENU_HEIGHT + border; + glBegin( GL_TRIANGLES ); + glVertex2i( x_base, y_base + 2*border); + glVertex2i( menu->Width - 2, y_base + + ( FREEGLUT_MENU_HEIGHT + border) / 2 ); + glVertex2i( x_base, y_base + FREEGLUT_MENU_HEIGHT - border ); + glEnd( ); + } + + /* If the menu entry is active, reset the color */ + if( menuEntry->IsActive ) + glColor4fv( menu_pen_fore ); + } +} + +/* + * Private static function to set the parent window of a submenu and all + * of its submenus + */ +static void fghSetMenuParentWindow( SFG_Window *window, SFG_Menu *menu ) +{ + SFG_MenuEntry *menuEntry; + + menu->ParentWindow = window; + + for( menuEntry = ( SFG_MenuEntry * )menu->Entries.First; + menuEntry; + menuEntry = ( SFG_MenuEntry * )menuEntry->Node.Next ) + if( menuEntry->SubMenu ) + fghSetMenuParentWindow( window, menuEntry->SubMenu ); +} + +/* + * Function to check for menu entry selection on menu deactivation + */ +static void fghExecuteMenuCallback( SFG_Menu* menu ) +{ + SFG_MenuEntry *menuEntry; + + /* First of all check any of the active sub menus... */ + for( menuEntry = (SFG_MenuEntry *)menu->Entries.First; + menuEntry; + menuEntry = (SFG_MenuEntry *)menuEntry->Node.Next) + { + if( menuEntry->IsActive ) + { + if( menuEntry->SubMenu ) + fghExecuteMenuCallback( menuEntry->SubMenu ); + else + if( menu->Callback ) + { + SFG_Menu *save_menu = fgStructure.CurrentMenu; + fgStructure.CurrentMenu = menu; + menu->Callback( menuEntry->ID ); + fgStructure.CurrentMenu = save_menu; + } + + return; + } + } +} + + +/* + * Displays the currently active menu for the current window + */ +void fgDisplayMenu( void ) +{ + SFG_Window* window = fgStructure.CurrentWindow; + SFG_Menu* menu = NULL; + + FREEGLUT_INTERNAL_ERROR_EXIT ( fgStructure.CurrentWindow, "Displaying menu in nonexistent window", + "fgDisplayMenu" ); + + /* Check if there is an active menu attached to this window... */ + menu = window->ActiveMenu; + freeglut_return_if_fail( menu ); + + fgSetWindow( menu->Window ); + + glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_TEXTURE_BIT | GL_LIGHTING_BIT | + GL_POLYGON_BIT ); + + glDisable( GL_DEPTH_TEST ); + glDisable( GL_TEXTURE_2D ); + glDisable( GL_LIGHTING ); + glDisable( GL_CULL_FACE ); + + glMatrixMode( GL_PROJECTION ); + glPushMatrix( ); + glLoadIdentity( ); + glOrtho( + 0, glutGet( GLUT_WINDOW_WIDTH ), + glutGet( GLUT_WINDOW_HEIGHT ), 0, + -1, 1 + ); + + glMatrixMode( GL_MODELVIEW ); + glPushMatrix( ); + glLoadIdentity( ); + + fghDisplayMenuBox( menu ); + + glPopAttrib( ); + + glMatrixMode( GL_PROJECTION ); + glPopMatrix( ); + glMatrixMode( GL_MODELVIEW ); + glPopMatrix( ); + + glutSwapBuffers( ); + + fgSetWindow ( window ); +} + +/* + * Activates a menu pointed by the function argument + */ +static void fghActivateMenu( SFG_Window* window, int button ) +{ + int max_x, max_y; + + /* We'll be referencing this menu a lot, so remember its address: */ + SFG_Menu* menu = window->Menu[ button ]; + SFG_Window* current_window = fgStructure.CurrentWindow; + + /* If the menu is already active in another window, deactivate it there */ + if ( menu->ParentWindow ) + menu->ParentWindow->ActiveMenu = NULL ; + + /* Mark the menu as active, so that it gets displayed: */ + window->ActiveMenu = menu; + menu->IsActive = GL_TRUE; + fghSetMenuParentWindow ( window, menu ); + fgState.ActiveMenus++; + + /* Set up the initial menu position now: */ + fghGetVMaxExtent(menu->ParentWindow, &max_x, &max_y); + fgSetWindow( window ); + menu->X = window->State.MouseX + glutGet( GLUT_WINDOW_X ); + menu->Y = window->State.MouseY + glutGet( GLUT_WINDOW_Y ); + + if( menu->X + menu->Width > max_x ) + menu->X -=menu->Width; + + if( menu->Y + menu->Height > max_y ) + { + menu->Y -=menu->Height; + if( menu->Y < 0 ) + menu->Y = 0; + } + + menu->Window->State.MouseX = + window->State.MouseX + glutGet( GLUT_WINDOW_X ) - menu->X; + menu->Window->State.MouseY = + window->State.MouseY + glutGet( GLUT_WINDOW_Y ) - menu->Y; + + fgSetWindow( menu->Window ); + glutPositionWindow( menu->X, menu->Y ); + glutReshapeWindow( menu->Width, menu->Height ); + glutPopWindow( ); + glutShowWindow( ); + menu->Window->ActiveMenu = menu; + fghCheckMenuStatus( menu ); + fgSetWindow( current_window ); +} + +/* + * Update Highlight states of the menu + * + * Current mouse position is in menu->Window->State.MouseX/Y. + */ +void fgUpdateMenuHighlight ( SFG_Menu *menu ) +{ + fghCheckMenuStatus( menu ); +} + +/* + * Check whether an active menu absorbs a mouse click + */ +GLboolean fgCheckActiveMenu ( SFG_Window *window, int button, GLboolean pressed, + int mouse_x, int mouse_y ) +{ + /* + * Near as I can tell, this is the menu behaviour: + * - Down-click the menu button, menu not active: activate + * the menu with its upper left-hand corner at the mouse + * location. + * - Down-click any button outside the menu, menu active: + * deactivate the menu + * - Down-click any button inside the menu, menu active: + * select the menu entry and deactivate the menu + * - Up-click the menu button, menu not active: nothing happens + * - Up-click the menu button outside the menu, menu active: + * nothing happens + * - Up-click the menu button inside the menu, menu active: + * select the menu entry and deactivate the menu + * Since menus can have submenus, we need to check this recursively. + */ + if( window->ActiveMenu ) + { + if( window == window->ActiveMenu->ParentWindow ) + { + window->ActiveMenu->Window->State.MouseX = + mouse_x - window->ActiveMenu->X; + window->ActiveMenu->Window->State.MouseY = + mouse_y - window->ActiveMenu->Y; + } + + /* In the menu, invoke the callback and deactivate the menu */ + if( fghCheckMenuStatus( window->ActiveMenu ) ) + { + /* + * Save the current window and menu and set the current + * window to the window whose menu this is + */ + SFG_Window *save_window = fgStructure.CurrentWindow; + SFG_Menu *save_menu = fgStructure.CurrentMenu; + SFG_Window *parent_window = window->ActiveMenu->ParentWindow; + fgSetWindow( parent_window ); + fgStructure.CurrentMenu = window->ActiveMenu; + + /* Execute the menu callback */ + fghExecuteMenuCallback( window->ActiveMenu ); + fgDeactivateMenu( parent_window ); + + /* Restore the current window and menu */ + fgSetWindow( save_window ); + fgStructure.CurrentMenu = save_menu; + } + else if( pressed ) + /* + * Outside the menu, deactivate if it's a downclick + * + * XXX This isn't enough. A downclick outside of + * XXX the interior of our freeglut windows should also + * XXX deactivate the menu. This is more complicated. + */ + fgDeactivateMenu( window->ActiveMenu->ParentWindow ); + + /* + * XXX Why does an active menu require a redisplay at + * XXX this point? If this can come out cleanly, then + * XXX it probably should do so; if not, a comment should + * XXX explain it. + */ + if( ! window->IsMenu ) + window->State.Redisplay = GL_TRUE; + + return GL_TRUE; + } + + /* No active menu, let's check whether we need to activate one. */ + if( ( 0 <= button ) && + ( FREEGLUT_MAX_MENUS > button ) && + ( window->Menu[ button ] ) && + pressed ) + { + /* XXX Posting a requisite Redisplay seems bogus. */ + window->State.Redisplay = GL_TRUE; + fghActivateMenu( window, button ); + return GL_TRUE; + } + + return GL_FALSE; +} + +/* + * Deactivates a menu pointed by the function argument. + */ +void fgDeactivateMenu( SFG_Window *window ) +{ + SFG_Window *parent_window = NULL; + + /* Check if there is an active menu attached to this window... */ + SFG_Menu* menu = window->ActiveMenu; + SFG_MenuEntry *menuEntry; + + /* Did we find an active window? */ + freeglut_return_if_fail( menu ); + + parent_window = menu->ParentWindow; + + /* Hide the present menu's window */ + fgSetWindow( menu->Window ); + glutHideWindow( ); + + /* Forget about having that menu active anymore, now: */ + menu->Window->ActiveMenu = NULL; + menu->ParentWindow->ActiveMenu = NULL; + fghSetMenuParentWindow ( NULL, menu ); + menu->IsActive = GL_FALSE; + menu->ActiveEntry = NULL; + + fgState.ActiveMenus--; + + /* Hide all submenu windows, and the root menu's window. */ + for ( menuEntry = ( SFG_MenuEntry * )menu->Entries.First; + menuEntry; + menuEntry = ( SFG_MenuEntry * )menuEntry->Node.Next ) + { + menuEntry->IsActive = GL_FALSE; + + /* Is that an active submenu by any case? */ + if( menuEntry->SubMenu ) + fghDeactivateSubMenu( menuEntry ); + } + + fgSetWindow ( parent_window ) ; +} + +/* + * Recalculates current menu's box size + */ +void fghCalculateMenuBoxSize( void ) +{ + SFG_MenuEntry* menuEntry; + int width = 0, height = 0; + + /* Make sure there is a current menu set */ + freeglut_return_if_fail( fgStructure.CurrentMenu ); + + /* The menu's box size depends on the menu entries: */ + for( menuEntry = ( SFG_MenuEntry * )fgStructure.CurrentMenu->Entries.First; + menuEntry; + menuEntry = ( SFG_MenuEntry * )menuEntry->Node.Next ) + { + /* Update the menu entry's width value */ + menuEntry->Width = glutBitmapLength( + FREEGLUT_MENU_FONT, + (unsigned char *)menuEntry->Text + ); + + /* + * If the entry is a submenu, then it needs to be wider to + * accomodate the arrow. JCJ 31 July 2003 + */ + if (menuEntry->SubMenu ) + menuEntry->Width += glutBitmapLength( + FREEGLUT_MENU_FONT, + (unsigned char *)"_" + ); + + /* Check if it's the biggest we've found */ + if( menuEntry->Width > width ) + width = menuEntry->Width; + + height += FREEGLUT_MENU_HEIGHT; + } + + /* Store the menu's box size now: */ + fgStructure.CurrentMenu->Height = height + 2 * FREEGLUT_MENU_BORDER; + fgStructure.CurrentMenu->Width = width + 4 * FREEGLUT_MENU_BORDER; +} + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Creates a new menu object, adding it to the freeglut structure + */ +int FGAPIENTRY glutCreateMenu( void(* callback)( int ) ) +{ + /* The menu object creation code resides in freeglut_structure.c */ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateMenu" ); + return fgCreateMenu( callback )->ID; +} + +#if TARGET_HOST_MS_WINDOWS +int FGAPIENTRY __glutCreateMenuWithExit( void(* callback)( int ), void (__cdecl *exit_function)(int) ) +{ + __glutExitFunc = exit_function; + return glutCreateMenu( callback ); +} +#endif + +/* + * Destroys a menu object, removing all references to it + */ +void FGAPIENTRY glutDestroyMenu( int menuID ) +{ + SFG_Menu* menu; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyMenu" ); + menu = fgMenuByID( menuID ); + + freeglut_return_if_fail( menu ); + + /* The menu object destruction code resides in freeglut_structure.c */ + fgDestroyMenu( menu ); +} + +/* + * Returns the ID number of the currently active menu + */ +int FGAPIENTRY glutGetMenu( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetMenu" ); + + if( fgStructure.CurrentMenu ) + return fgStructure.CurrentMenu->ID; + + return 0; +} + +/* + * Sets the current menu given its menu ID + */ +void FGAPIENTRY glutSetMenu( int menuID ) +{ + SFG_Menu* menu; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetMenu" ); + menu = fgMenuByID( menuID ); + + freeglut_return_if_fail( menu ); + + fgStructure.CurrentMenu = menu; +} + +/* + * Adds a menu entry to the bottom of the current menu + */ +void FGAPIENTRY glutAddMenuEntry( const char* label, int value ) +{ + SFG_MenuEntry* menuEntry; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutAddMenuEntry" ); + menuEntry = (SFG_MenuEntry *)calloc( sizeof(SFG_MenuEntry), 1 ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + + menuEntry->Text = strdup( label ); + menuEntry->ID = value; + + /* Have the new menu entry attached to the current menu */ + fgListAppend( &fgStructure.CurrentMenu->Entries, &menuEntry->Node ); + + fghCalculateMenuBoxSize( ); +} + +/* + * Add a sub menu to the bottom of the current menu + */ +void FGAPIENTRY glutAddSubMenu( const char *label, int subMenuID ) +{ + SFG_MenuEntry *menuEntry; + SFG_Menu *subMenu; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutAddSubMenu" ); + menuEntry = ( SFG_MenuEntry * )calloc( sizeof( SFG_MenuEntry ), 1 ); + subMenu = fgMenuByID( subMenuID ); + + freeglut_return_if_fail( fgStructure.CurrentMenu ); + freeglut_return_if_fail( subMenu ); + + menuEntry->Text = strdup( label ); + menuEntry->SubMenu = subMenu; + menuEntry->ID = -1; + + fgListAppend( &fgStructure.CurrentMenu->Entries, &menuEntry->Node ); + fghCalculateMenuBoxSize( ); +} + +/* + * Changes the specified menu item in the current menu into a menu entry + */ +void FGAPIENTRY glutChangeToMenuEntry( int item, const char* label, int value ) +{ + SFG_MenuEntry* menuEntry = NULL; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutChangeToMenuEntry" ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + + /* Get n-th menu entry in the current menu, starting from one: */ + menuEntry = fghFindMenuEntry( fgStructure.CurrentMenu, item ); + + freeglut_return_if_fail( menuEntry ); + + /* We want it to become a normal menu entry, so: */ + if( menuEntry->Text ) + free( menuEntry->Text ); + + menuEntry->Text = strdup( label ); + menuEntry->ID = value; + menuEntry->SubMenu = NULL; + fghCalculateMenuBoxSize( ); +} + +/* + * Changes the specified menu item in the current menu into a sub-menu trigger. + */ +void FGAPIENTRY glutChangeToSubMenu( int item, const char* label, + int subMenuID ) +{ + SFG_Menu* subMenu; + SFG_MenuEntry* menuEntry; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutChangeToSubMenu" ); + subMenu = fgMenuByID( subMenuID ); + menuEntry = NULL; + + freeglut_return_if_fail( fgStructure.CurrentMenu ); + freeglut_return_if_fail( subMenu ); + + /* Get n-th menu entry in the current menu, starting from one: */ + menuEntry = fghFindMenuEntry( fgStructure.CurrentMenu, item ); + + freeglut_return_if_fail( menuEntry ); + + /* We want it to become a sub menu entry, so: */ + if( menuEntry->Text ) + free( menuEntry->Text ); + + menuEntry->Text = strdup( label ); + menuEntry->SubMenu = subMenu; + menuEntry->ID = -1; + fghCalculateMenuBoxSize( ); +} + +/* + * Removes the specified menu item from the current menu + */ +void FGAPIENTRY glutRemoveMenuItem( int item ) +{ + SFG_MenuEntry* menuEntry; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutRemoveMenuItem" ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + + /* Get n-th menu entry in the current menu, starting from one: */ + menuEntry = fghFindMenuEntry( fgStructure.CurrentMenu, item ); + + freeglut_return_if_fail( menuEntry ); + + fgListRemove( &fgStructure.CurrentMenu->Entries, &menuEntry->Node ); + if ( menuEntry->Text ) + free( menuEntry->Text ); + + free( menuEntry ); + fghCalculateMenuBoxSize( ); +} + +/* + * Attaches a menu to the current window + */ +void FGAPIENTRY glutAttachMenu( int button ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutAttachMenu" ); + + freeglut_return_if_fail( fgStructure.CurrentWindow ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + + freeglut_return_if_fail( button >= 0 ); + freeglut_return_if_fail( button < FREEGLUT_MAX_MENUS ); + + fgStructure.CurrentWindow->Menu[ button ] = fgStructure.CurrentMenu; +} + +/* + * Detaches a menu from the current window + */ +void FGAPIENTRY glutDetachMenu( int button ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDetachMenu" ); + + freeglut_return_if_fail( fgStructure.CurrentWindow ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + + freeglut_return_if_fail( button >= 0 ); + freeglut_return_if_fail( button < FREEGLUT_MAX_MENUS ); + + fgStructure.CurrentWindow->Menu[ button ] = NULL; +} + +/* + * A.Donev: Set and retrieve the menu's user data + */ +void* FGAPIENTRY glutGetMenuData( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetMenuData" ); + return fgStructure.CurrentMenu->UserData; +} + +void FGAPIENTRY glutSetMenuData(void* data) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetMenuData" ); + fgStructure.CurrentMenu->UserData=data; +} + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_misc.c b/tests/Box2D_v2.2.1/freeglut/freeglut_misc.c new file mode 100755 index 0000000000000..d0a65bde387ac --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_misc.c @@ -0,0 +1,214 @@ +/* + * freeglut_misc.c + * + * Functions that didn't fit anywhere else... + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 9 1999 + * + * 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 + * PAWEL W. OLSZTA 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 "freeglut.h" +#include "freeglut_internal.h" + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * glutSetColor() -- + * glutGetColor() -- + * glutCopyColormap() -- + * glutSetKeyRepeat() -- this is evil and should be removed from API + */ + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * This functions checks if an OpenGL extension is supported or not + * + * XXX Wouldn't this be simpler and clearer if we used strtok()? + */ +int FGAPIENTRY glutExtensionSupported( const char* extension ) +{ + const char *extensions, *start; + const size_t len = strlen( extension ); + + /* Make sure there is a current window, and thus a current context available */ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutExtensionSupported" ); + freeglut_return_val_if_fail( fgStructure.CurrentWindow != NULL, 0 ); + + if (strchr(extension, ' ')) + return 0; + start = extensions = (const char *) glGetString(GL_EXTENSIONS); + + /* XXX consider printing a warning to stderr that there's no current + * rendering context. + */ + freeglut_return_val_if_fail( extensions != NULL, 0 ); + + while (1) { + const char *p = strstr(extensions, extension); + if (!p) + return 0; /* not found */ + /* check that the match isn't a super string */ + if ((p == start || p[-1] == ' ') && (p[len] == ' ' || p[len] == 0)) + return 1; + /* skip the false match and continue */ + extensions = p + len; + } + + return 0 ; +} + +#ifndef GL_INVALID_FRAMEBUFFER_OPERATION +#ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT +#define GL_INVALID_FRAMEBUFFER_OPERATION GL_INVALID_FRAMEBUFFER_OPERATION_EXT +#else +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#endif +#endif + +#ifndef GL_TABLE_TOO_LARGE +#ifdef GL_TABLE_TOO_LARGE_EXT +#define GL_TABLE_TOO_LARGE GL_TABLE_TOO_LARGE_EXT +#else +#define GL_TABLE_TOO_LARGE 0x8031 +#endif +#endif + +#ifndef GL_TEXTURE_TOO_LARGE +#ifdef GL_TEXTURE_TOO_LARGE_EXT +#define GL_TEXTURE_TOO_LARGE GL_TEXTURE_TOO_LARGE_EXT +#else +#define GL_TEXTURE_TOO_LARGE 0x8065 +#endif +#endif + +/* + * A cut-down local version of gluErrorString to avoid depending on GLU. + */ +static const char* fghErrorString( GLenum error ) +{ + switch ( error ) { + case GL_INVALID_ENUM: return "invalid enumerant"; + case GL_INVALID_VALUE: return "invalid value"; + case GL_INVALID_OPERATION: return "invalid operation"; + case GL_STACK_OVERFLOW: return "stack overflow"; + case GL_STACK_UNDERFLOW: return "stack underflow"; + case GL_OUT_OF_MEMORY: return "out of memory"; + case GL_TABLE_TOO_LARGE: return "table too large"; + case GL_INVALID_FRAMEBUFFER_OPERATION: return "invalid framebuffer operation"; + case GL_TEXTURE_TOO_LARGE: return "texture too large"; + default: return "unknown GL error"; + } +} + +/* + * This function reports all the OpenGL errors that happened till now + */ +void FGAPIENTRY glutReportErrors( void ) +{ + GLenum error; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReportErrors" ); + while( ( error = glGetError() ) != GL_NO_ERROR ) + fgWarning( "GL error: %s", fghErrorString( error ) ); +} + +/* + * Control the auto-repeat of keystrokes to the current window + */ +void FGAPIENTRY glutIgnoreKeyRepeat( int ignore ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIgnoreKeyRepeat" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIgnoreKeyRepeat" ); + + fgStructure.CurrentWindow->State.IgnoreKeyRepeat = ignore ? GL_TRUE : GL_FALSE; +} + +/* + * Set global auto-repeat of keystrokes + * + * RepeatMode should be either: + * GLUT_KEY_REPEAT_OFF + * GLUT_KEY_REPEAT_ON + * GLUT_KEY_REPEAT_DEFAULT + */ +void FGAPIENTRY glutSetKeyRepeat( int repeatMode ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetKeyRepeat" ); + + switch( repeatMode ) + { + case GLUT_KEY_REPEAT_OFF: + case GLUT_KEY_REPEAT_ON: + fgState.KeyRepeat = repeatMode; + break; + + case GLUT_KEY_REPEAT_DEFAULT: + fgState.KeyRepeat = GLUT_KEY_REPEAT_ON; + break; + + default: + fgError ("Invalid glutSetKeyRepeat mode: %d", repeatMode); + break; + } +} + +/* + * Forces the joystick callback to be executed + */ +void FGAPIENTRY glutForceJoystickFunc( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutForceJoystickFunc" ); +#if !defined(_WIN32_WCE) + freeglut_return_if_fail( fgStructure.CurrentWindow != NULL ); + freeglut_return_if_fail( FETCH_WCB( *( fgStructure.CurrentWindow ), Joystick ) ); + fgJoystickPollWindow( fgStructure.CurrentWindow ); +#endif /* !defined(_WIN32_WCE) */ +} + +/* + * + */ +void FGAPIENTRY glutSetColor( int nColor, GLfloat red, GLfloat green, GLfloat blue ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetColor" ); + /* We really need to do something here. */ +} + +/* + * + */ +GLfloat FGAPIENTRY glutGetColor( int color, int component ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetColor" ); + /* We really need to do something here. */ + return( 0.0f ); +} + +/* + * + */ +void FGAPIENTRY glutCopyColormap( int window ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCopyColormap" ); + /* We really need to do something here. */ +} + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_overlay.c b/tests/Box2D_v2.2.1/freeglut/freeglut_overlay.c new file mode 100755 index 0000000000000..fbc3250dc427c --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_overlay.c @@ -0,0 +1,45 @@ +/* + * freeglut_overlay.c + * + * Overlay management functions (as defined by GLUT API) + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 16 1999 + * + * 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 + * PAWEL W. OLSZTA 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 "freeglut.h" +#include "freeglut_internal.h" + +/* + * NOTE: functions declared in this file probably will not be implemented. + */ + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +void FGAPIENTRY glutEstablishOverlay( void ) { /* Not implemented */ } +void FGAPIENTRY glutRemoveOverlay( void ) { /* Not implemented */ } +void FGAPIENTRY glutUseLayer( GLenum layer ) { /* Not implemented */ } +void FGAPIENTRY glutPostOverlayRedisplay( void ) { /* Not implemented */ } +void FGAPIENTRY glutPostWindowOverlayRedisplay( int ID ) { /* Not implemented */ } +void FGAPIENTRY glutShowOverlay( void ) { /* Not implemented */ } +void FGAPIENTRY glutHideOverlay( void ) { /* Not implemented */ } + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_spaceball.c b/tests/Box2D_v2.2.1/freeglut/freeglut_spaceball.c new file mode 100755 index 0000000000000..a92a75c4b4261 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_spaceball.c @@ -0,0 +1,454 @@ +/* Spaceball support for Linux. + * Written by John Tsiombikas + * + * This code supports 3Dconnexion's 6-dof space-whatever devices. + * It can communicate with either the proprietary 3Dconnexion daemon (3dxsrv) + * free spacenavd (http://spacenav.sourceforge.net), through the "standard" + * magellan X-based protocol. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 +#include + +enum { + SPNAV_EVENT_ANY, /* used by spnav_remove_events() */ + SPNAV_EVENT_MOTION, + SPNAV_EVENT_BUTTON /* includes both press and release */ +}; + +struct spnav_event_motion { + int type; + int x, y, z; + int rx, ry, rz; + unsigned int period; + int *data; +}; + +struct spnav_event_button { + int type; + int press; + int bnum; +}; + +typedef union spnav_event { + int type; + struct spnav_event_motion motion; + struct spnav_event_button button; +} spnav_event; + + +static int spnav_x11_open(Display *dpy, Window win); +static int spnav_x11_window(Window win); +static int spnav_x11_event(const XEvent *xev, spnav_event *event); +static int spnav_close(void); +static int spnav_fd(void); +static int spnav_remove_events(int type); + +static SFG_Window *spnav_win; +#endif + +static int sball_initialized; + + +void fgInitialiseSpaceball(void) +{ + if(sball_initialized) { + return; + } + +#if TARGET_HOST_POSIX_X11 + { + Window w; + + if(!fgStructure.CurrentWindow) + return; + + w = fgStructure.CurrentWindow->Window.Handle; + if(spnav_x11_open(fgDisplay.Display, w) == -1) { + return; + } + } +#endif + + sball_initialized = 1; +} + +void fgSpaceballClose(void) +{ +#if TARGET_HOST_POSIX_X11 + spnav_close(); +#endif +} + +int fgHasSpaceball(void) +{ + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + fgWarning("fgInitialiseSpaceball failed\n"); + return 0; + } + } + +#if TARGET_HOST_POSIX_X11 + /* XXX this function should somehow query the driver if there's a device + * plugged in, as opposed to just checking if there's a driver to talk to. + */ + return spnav_fd() == -1 ? 0 : 1; +#else + return 0; +#endif +} + +int fgSpaceballNumButtons(void) +{ + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + fgWarning("fgInitialiseSpaceball failed\n"); + return 0; + } + } + +#if TARGET_HOST_POSIX_X11 + return 2; /* TODO implement this properly */ +#else + return 0; +#endif +} + +void fgSpaceballSetWindow(SFG_Window *window) +{ + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + return; + } + } + +#if TARGET_HOST_POSIX_X11 + if(spnav_win != window) { + spnav_x11_window(window->Window.Handle); + spnav_win = window; + } +#endif +} + + +#if TARGET_HOST_POSIX_X11 +int fgIsSpaceballXEvent(const XEvent *xev) +{ + spnav_event sev; + + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + return 0; + } + } + + return spnav_x11_event(xev, &sev); +} + +void fgSpaceballHandleXEvent(const XEvent *xev) +{ + spnav_event sev; + + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + return; + } + } + + if(spnav_x11_event(xev, &sev)) { + switch(sev.type) { + case SPNAV_EVENT_MOTION: + if(sev.motion.x | sev.motion.y | sev.motion.z) { + INVOKE_WCB(*spnav_win, SpaceMotion, (sev.motion.x, sev.motion.y, sev.motion.z)); + } + if(sev.motion.rx | sev.motion.ry | sev.motion.rz) { + INVOKE_WCB(*spnav_win, SpaceRotation, (sev.motion.rx, sev.motion.ry, sev.motion.rz)); + } + spnav_remove_events(SPNAV_EVENT_MOTION); + break; + + case SPNAV_EVENT_BUTTON: + INVOKE_WCB(*spnav_win, SpaceButton, (sev.button.bnum, sev.button.press ? GLUT_DOWN : GLUT_UP)); + break; + + default: + break; + } + } +} + +/* +The following code is part of libspnav, part of the spacenav project (spacenav.sf.net) +Copyright (C) 2007-2009 John Tsiombikas + +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. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ +#include +#include +#include +#include + +#include +#include + +static Window get_daemon_window(Display *dpy); +static int catch_badwin(Display *dpy, XErrorEvent *err); + +static Display *dpy; +static Window app_win; +static Atom motion_event, button_press_event, button_release_event, command_event; + +enum { + CMD_APP_WINDOW = 27695, + CMD_APP_SENS +}; + +#define IS_OPEN dpy + +struct event_node { + spnav_event event; + struct event_node *next; +}; + +static int spnav_x11_open(Display *display, Window win) +{ + if(IS_OPEN) { + return -1; + } + + dpy = display; + + motion_event = XInternAtom(dpy, "MotionEvent", True); + button_press_event = XInternAtom(dpy, "ButtonPressEvent", True); + button_release_event = XInternAtom(dpy, "ButtonReleaseEvent", True); + command_event = XInternAtom(dpy, "CommandEvent", True); + + if(!motion_event || !button_press_event || !button_release_event || !command_event) { + dpy = 0; + return -1; /* daemon not started */ + } + + if(spnav_x11_window(win) == -1) { + dpy = 0; + return -1; /* daemon not started */ + } + + app_win = win; + return 0; +} + +static int spnav_close(void) +{ + if(dpy) { + spnav_x11_window(DefaultRootWindow(dpy)); + app_win = 0; + dpy = 0; + return 0; + } + return -1; +} + +static int spnav_x11_window(Window win) +{ + int (*prev_xerr_handler)(Display*, XErrorEvent*); + XEvent xev; + Window daemon_win; + + if(!IS_OPEN) { + return -1; + } + + if(!(daemon_win = get_daemon_window(dpy))) { + return -1; + } + + prev_xerr_handler = XSetErrorHandler(catch_badwin); + + xev.type = ClientMessage; + xev.xclient.send_event = False; + xev.xclient.display = dpy; + xev.xclient.window = win; + xev.xclient.message_type = command_event; + xev.xclient.format = 16; + xev.xclient.data.s[0] = ((unsigned int)win & 0xffff0000) >> 16; + xev.xclient.data.s[1] = (unsigned int)win & 0xffff; + xev.xclient.data.s[2] = CMD_APP_WINDOW; + + XSendEvent(dpy, daemon_win, False, 0, &xev); + XSync(dpy, False); + + XSetErrorHandler(prev_xerr_handler); + return 0; +} + +static int spnav_fd(void) +{ + if(dpy) { + return ConnectionNumber(dpy); + } + return -1; +} + +/*static int spnav_wait_event(spnav_event *event) +{ + if(dpy) { + for(;;) { + XEvent xev; + XNextEvent(dpy, &xev); + + if(spnav_x11_event(&xev, event) > 0) { + return event->type; + } + } + } + return 0; +} + +static int spnav_poll_event(spnav_event *event) +{ + if(dpy) { + if(XPending(dpy)) { + XEvent xev; + XNextEvent(dpy, &xev); + + return spnav_x11_event(&xev, event); + } + } + return 0; +}*/ + +static Bool match_events(Display *dpy, XEvent *xev, char *arg) +{ + int evtype = *(int*)arg; + + if(xev->type != ClientMessage) { + return False; + } + + if(xev->xclient.message_type == motion_event) { + return !evtype || evtype == SPNAV_EVENT_MOTION ? True : False; + } + if(xev->xclient.message_type == button_press_event || + xev->xclient.message_type == button_release_event) { + return !evtype || evtype == SPNAV_EVENT_BUTTON ? True : False; + } + return False; +} + +static int spnav_remove_events(int type) +{ + int rm_count = 0; + + if(dpy) { + XEvent xev; + + while(XCheckIfEvent(dpy, &xev, match_events, (char*)&type)) { + rm_count++; + } + return rm_count; + } + return 0; +} + +static int spnav_x11_event(const XEvent *xev, spnav_event *event) +{ + int i; + int xmsg_type; + + if(xev->type != ClientMessage) { + return 0; + } + + xmsg_type = xev->xclient.message_type; + + if(xmsg_type != motion_event && xmsg_type != button_press_event && + xmsg_type != button_release_event) { + return 0; + } + + if(xmsg_type == motion_event) { + event->type = SPNAV_EVENT_MOTION; + event->motion.data = &event->motion.x; + + for(i=0; i<6; i++) { + event->motion.data[i] = xev->xclient.data.s[i + 2]; + } + event->motion.period = xev->xclient.data.s[8]; + } else { + event->type = SPNAV_EVENT_BUTTON; + event->button.press = xmsg_type == button_press_event ? 1 : 0; + event->button.bnum = xev->xclient.data.s[2]; + } + return event->type; +} + + +static Window get_daemon_window(Display *dpy) +{ + Window win, root_win; + XTextProperty wname; + Atom type; + int fmt; + unsigned long nitems, bytes_after; + unsigned char *prop; + + root_win = DefaultRootWindow(dpy); + + XGetWindowProperty(dpy, root_win, command_event, 0, 1, False, AnyPropertyType, &type, &fmt, &nitems, &bytes_after, &prop); + if(!prop) { + return 0; + } + + win = *(Window*)prop; + XFree(prop); + + if(!XGetWMName(dpy, win, &wname) || strcmp("Magellan Window", (char*)wname.value) != 0) { + return 0; + } + + return win; +} + +static int catch_badwin(Display *dpy, XErrorEvent *err) +{ + char buf[256]; + + if(err->error_code == BadWindow) { + /* do nothing? */ + } else { + XGetErrorText(dpy, err->error_code, buf, sizeof buf); + fprintf(stderr, "Caught unexpected X error: %s\n", buf); + } + return 0; +} + +#endif /* TARGET_HOST_POSIX_X11 */ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_state.c b/tests/Box2D_v2.2.1/freeglut/freeglut_state.c new file mode 100755 index 0000000000000..783e7b443bd91 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_state.c @@ -0,0 +1,895 @@ +/* + * freeglut_state.c + * + * Freeglut state query methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 16 1999 + * + * 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 + * PAWEL W. OLSZTA 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 "freeglut.h" +#include "freeglut_internal.h" + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * glutGet() -- X11 tests passed, but check if all enums + * handled (what about Win32?) + * glutDeviceGet() -- X11 tests passed, but check if all enums + * handled (what about Win32?) + * glutGetModifiers() -- OK, but could also remove the limitation + * glutLayerGet() -- what about GLUT_NORMAL_DAMAGED? + * + * The fail-on-call policy will help adding the most needed things imho. + */ + +/* -- LOCAL DEFINITIONS ---------------------------------------------------- */ + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +#if TARGET_HOST_POSIX_X11 +/* + * Queries the GL context about some attributes + */ +static int fghGetConfig( int attribute ) +{ + int returnValue = 0; + int result; /* Not checked */ + + if( fgStructure.CurrentWindow ) + result = glXGetFBConfigAttrib( fgDisplay.Display, + *(fgStructure.CurrentWindow->Window.FBConfig), + attribute, + &returnValue ); + + return returnValue; +} +#endif + +/* Check if the window is in full screen state. */ +static int fghCheckFullScreen(void) +{ +#if TARGET_HOST_POSIX_X11 + return fgStructure.CurrentWindow->State.IsFullscreen; +#else + return 0; +#endif +} + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * General settings assignment method + */ +void FGAPIENTRY glutSetOption( GLenum eWhat, int value ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetOption" ); + + /* + * XXX In chronological code add order. (WHY in that order?) + */ + switch( eWhat ) + { + case GLUT_INIT_WINDOW_X: + fgState.Position.X = (GLint)value; + break; + + case GLUT_INIT_WINDOW_Y: + fgState.Position.Y = (GLint)value; + break; + + case GLUT_INIT_WINDOW_WIDTH: + fgState.Size.X = (GLint)value; + break; + + case GLUT_INIT_WINDOW_HEIGHT: + fgState.Size.Y = (GLint)value; + break; + + case GLUT_INIT_DISPLAY_MODE: + fgState.DisplayMode = (unsigned int)value; + break; + + case GLUT_ACTION_ON_WINDOW_CLOSE: + fgState.ActionOnWindowClose = value; + break; + + case GLUT_RENDERING_CONTEXT: + fgState.UseCurrentContext = + ( value == GLUT_USE_CURRENT_CONTEXT ) ? GL_TRUE : GL_FALSE; + break; + + case GLUT_DIRECT_RENDERING: + fgState.DirectContext = value; + break; + + case GLUT_WINDOW_CURSOR: + if( fgStructure.CurrentWindow != NULL ) + fgStructure.CurrentWindow->State.Cursor = value; + break; + + case GLUT_AUX: + fgState.AuxiliaryBufferNumber = value; + break; + + case GLUT_MULTISAMPLE: + fgState.SampleNumber = value; + break; + + default: + fgWarning( "glutSetOption(): missing enum handle %d", eWhat ); + break; + } +} + +#if TARGET_HOST_MS_WINDOWS +/* The following include file is available from SGI but is not standard: + * #include + * So we copy the necessary parts out of it to support the multisampling query + */ +#define WGL_SAMPLES_ARB 0x2042 +#endif + + +/* + * General settings query method + */ +int FGAPIENTRY glutGet( GLenum eWhat ) +{ +#if TARGET_HOST_MS_WINDOWS + int returnValue ; + GLboolean boolValue ; +#endif + + int nsamples = 0; + + switch (eWhat) + { + case GLUT_INIT_STATE: + return fgState.Initialised; + + case GLUT_ELAPSED_TIME: + return fgElapsedTime(); + } + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGet" ); + + /* XXX In chronological code add order. (WHY in that order?) */ + switch( eWhat ) + { + /* Following values are stored in fgState and fgDisplay global structures */ + case GLUT_SCREEN_WIDTH: return fgDisplay.ScreenWidth ; + case GLUT_SCREEN_HEIGHT: return fgDisplay.ScreenHeight ; + case GLUT_SCREEN_WIDTH_MM: return fgDisplay.ScreenWidthMM ; + case GLUT_SCREEN_HEIGHT_MM: return fgDisplay.ScreenHeightMM; + case GLUT_INIT_WINDOW_X: return fgState.Position.Use ? + fgState.Position.X : -1 ; + case GLUT_INIT_WINDOW_Y: return fgState.Position.Use ? + fgState.Position.Y : -1 ; + case GLUT_INIT_WINDOW_WIDTH: return fgState.Size.Use ? + fgState.Size.X : -1 ; + case GLUT_INIT_WINDOW_HEIGHT: return fgState.Size.Use ? + fgState.Size.Y : -1 ; + case GLUT_INIT_DISPLAY_MODE: return fgState.DisplayMode ; + case GLUT_INIT_MAJOR_VERSION: return fgState.MajorVersion ; + case GLUT_INIT_MINOR_VERSION: return fgState.MinorVersion ; + case GLUT_INIT_FLAGS: return fgState.ContextFlags ; + case GLUT_INIT_PROFILE: return fgState.ContextProfile ; + +#if TARGET_HOST_POSIX_X11 + /* + * The window/context specific queries are handled mostly by + * fghGetConfig(). + */ + case GLUT_WINDOW_NUM_SAMPLES: +#ifdef GLX_VERSION_1_3 + glGetIntegerv(GL_SAMPLES, &nsamples); +#endif + return nsamples; + + /* + * The rest of GLX queries under X are general enough to use a macro to + * check them + */ +# define GLX_QUERY(a,b) case a: return fghGetConfig( b ); + + GLX_QUERY( GLUT_WINDOW_RGBA, GLX_RGBA ); + GLX_QUERY( GLUT_WINDOW_DOUBLEBUFFER, GLX_DOUBLEBUFFER ); + GLX_QUERY( GLUT_WINDOW_BUFFER_SIZE, GLX_BUFFER_SIZE ); + GLX_QUERY( GLUT_WINDOW_STENCIL_SIZE, GLX_STENCIL_SIZE ); + GLX_QUERY( GLUT_WINDOW_DEPTH_SIZE, GLX_DEPTH_SIZE ); + GLX_QUERY( GLUT_WINDOW_RED_SIZE, GLX_RED_SIZE ); + GLX_QUERY( GLUT_WINDOW_GREEN_SIZE, GLX_GREEN_SIZE ); + GLX_QUERY( GLUT_WINDOW_BLUE_SIZE, GLX_BLUE_SIZE ); + GLX_QUERY( GLUT_WINDOW_ALPHA_SIZE, GLX_ALPHA_SIZE ); + GLX_QUERY( GLUT_WINDOW_ACCUM_RED_SIZE, GLX_ACCUM_RED_SIZE ); + GLX_QUERY( GLUT_WINDOW_ACCUM_GREEN_SIZE, GLX_ACCUM_GREEN_SIZE ); + GLX_QUERY( GLUT_WINDOW_ACCUM_BLUE_SIZE, GLX_ACCUM_BLUE_SIZE ); + GLX_QUERY( GLUT_WINDOW_ACCUM_ALPHA_SIZE, GLX_ACCUM_ALPHA_SIZE ); + GLX_QUERY( GLUT_WINDOW_STEREO, GLX_STEREO ); + +# undef GLX_QUERY + + /* Colormap size is handled in a bit different way than all the rest */ + case GLUT_WINDOW_COLORMAP_SIZE: + if( (fghGetConfig( GLX_RGBA )) || (fgStructure.CurrentWindow == NULL) ) + { + /* + * We've got a RGBA visual, so there is no colormap at all. + * The other possibility is that we have no current window set. + */ + return 0; + } + else + { + const GLXFBConfig * fbconfig = + fgStructure.CurrentWindow->Window.FBConfig; + + XVisualInfo * visualInfo = + glXGetVisualFromFBConfig( fgDisplay.Display, *fbconfig ); + + const int result = visualInfo->visual->map_entries; + + XFree(visualInfo); + + return result; + } + + /* + * Those calls are somewhat similiar, as they use XGetWindowAttributes() + * function + */ + case GLUT_WINDOW_X: + case GLUT_WINDOW_Y: + case GLUT_WINDOW_BORDER_WIDTH: + case GLUT_WINDOW_HEADER_HEIGHT: + { + int x, y; + Window w; + + if( fgStructure.CurrentWindow == NULL ) + return 0; + + XTranslateCoordinates( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + fgDisplay.RootWindow, + 0, 0, &x, &y, &w); + + switch ( eWhat ) + { + case GLUT_WINDOW_X: return x; + case GLUT_WINDOW_Y: return y; + } + + if ( w == 0 ) + return 0; + XTranslateCoordinates( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + w, 0, 0, &x, &y, &w); + + switch ( eWhat ) + { + case GLUT_WINDOW_BORDER_WIDTH: return x; + case GLUT_WINDOW_HEADER_HEIGHT: return y; + } + } + + case GLUT_WINDOW_WIDTH: + case GLUT_WINDOW_HEIGHT: + { + XWindowAttributes winAttributes; + + if( fgStructure.CurrentWindow == NULL ) + return 0; + XGetWindowAttributes( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &winAttributes + ); + switch ( eWhat ) + { + case GLUT_WINDOW_WIDTH: return winAttributes.width ; + case GLUT_WINDOW_HEIGHT: return winAttributes.height ; + } + } + + /* I do not know yet if there will be a fgChooseVisual() function for Win32 */ + case GLUT_DISPLAY_MODE_POSSIBLE: + { + /* We should not have to call fgChooseFBConfig again here. */ + GLXFBConfig * fbconfig; + int isPossible; + + fbconfig = fgChooseFBConfig(); + + if (fbconfig == NULL) + { + isPossible = 0; + } + else + { + isPossible = 1; + XFree(fbconfig); + } + + return isPossible; + } + + /* This is system-dependant */ + case GLUT_WINDOW_FORMAT_ID: + if( fgStructure.CurrentWindow == NULL ) + return 0; + + return fghGetConfig( GLX_VISUAL_ID ); + +#elif TARGET_HOST_MS_WINDOWS + + case GLUT_WINDOW_NUM_SAMPLES: + glGetIntegerv(WGL_SAMPLES_ARB, &nsamples); + return nsamples; + + /* Handle the OpenGL inquiries */ + case GLUT_WINDOW_RGBA: +#if defined(_WIN32_WCE) + boolValue = (GLboolean)0; /* WinCE doesn't support this feature */ +#else + glGetBooleanv ( GL_RGBA_MODE, &boolValue ); + returnValue = boolValue ? 1 : 0; +#endif + return returnValue; + case GLUT_WINDOW_DOUBLEBUFFER: +#if defined(_WIN32_WCE) + boolValue = (GLboolean)0; /* WinCE doesn't support this feature */ +#else + glGetBooleanv ( GL_DOUBLEBUFFER, &boolValue ); + returnValue = boolValue ? 1 : 0; +#endif + return returnValue; + case GLUT_WINDOW_STEREO: +#if defined(_WIN32_WCE) + boolValue = (GLboolean)0; /* WinCE doesn't support this feature */ +#else + glGetBooleanv ( GL_STEREO, &boolValue ); + returnValue = boolValue ? 1 : 0; +#endif + return returnValue; + + case GLUT_WINDOW_RED_SIZE: + glGetIntegerv ( GL_RED_BITS, &returnValue ); + return returnValue; + case GLUT_WINDOW_GREEN_SIZE: + glGetIntegerv ( GL_GREEN_BITS, &returnValue ); + return returnValue; + case GLUT_WINDOW_BLUE_SIZE: + glGetIntegerv ( GL_BLUE_BITS, &returnValue ); + return returnValue; + case GLUT_WINDOW_ALPHA_SIZE: + glGetIntegerv ( GL_ALPHA_BITS, &returnValue ); + return returnValue; + case GLUT_WINDOW_ACCUM_RED_SIZE: +#if defined(_WIN32_WCE) + returnValue = 0; /* WinCE doesn't support this feature */ +#else + glGetIntegerv ( GL_ACCUM_RED_BITS, &returnValue ); +#endif + return returnValue; + case GLUT_WINDOW_ACCUM_GREEN_SIZE: +#if defined(_WIN32_WCE) + returnValue = 0; /* WinCE doesn't support this feature */ +#else + glGetIntegerv ( GL_ACCUM_GREEN_BITS, &returnValue ); +#endif + return returnValue; + case GLUT_WINDOW_ACCUM_BLUE_SIZE: +#if defined(_WIN32_WCE) + returnValue = 0; /* WinCE doesn't support this feature */ +#else + glGetIntegerv ( GL_ACCUM_BLUE_BITS, &returnValue ); +#endif + return returnValue; + case GLUT_WINDOW_ACCUM_ALPHA_SIZE: +#if defined(_WIN32_WCE) + returnValue = 0; /* WinCE doesn't support this feature */ +#else + glGetIntegerv ( GL_ACCUM_ALPHA_BITS, &returnValue ); +#endif + return returnValue; + case GLUT_WINDOW_DEPTH_SIZE: + glGetIntegerv ( GL_DEPTH_BITS, &returnValue ); + return returnValue; + + case GLUT_WINDOW_BUFFER_SIZE: + returnValue = 1 ; /* ????? */ + return returnValue; + case GLUT_WINDOW_STENCIL_SIZE: + returnValue = 0 ; /* ????? */ + return returnValue; + + case GLUT_WINDOW_X: + case GLUT_WINDOW_Y: + case GLUT_WINDOW_WIDTH: + case GLUT_WINDOW_HEIGHT: + { + /* + * There is considerable confusion about the "right thing to + * do" concerning window size and position. GLUT itself is + * not consistent between Windows and UNIX/X11; since + * platform independence is a virtue for "freeglut", we + * decided to break with GLUT's behaviour. + * + * Under UNIX/X11, it is apparently not possible to get the + * window border sizes in order to subtract them off the + * window's initial position until some time after the window + * has been created. Therefore we decided on the following + * behaviour, both under Windows and under UNIX/X11: + * - When you create a window with position (x,y) and size + * (w,h), the upper left hand corner of the outside of the + * window is at (x,y) and the size of the drawable area is + * (w,h). + * - When you query the size and position of the window--as + * is happening here for Windows--"freeglut" will return + * the size of the drawable area--the (w,h) that you + * specified when you created the window--and the coordinates + * of the upper left hand corner of the drawable + * area--which is NOT the (x,y) you specified. + */ + + RECT winRect; + + freeglut_return_val_if_fail( fgStructure.CurrentWindow != NULL, 0 ); + + /* + * We need to call GetWindowRect() first... + * (this returns the pixel coordinates of the outside of the window) + */ + GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect ); + + /* ...then we've got to correct the results we've just received... */ + +#if !defined(_WIN32_WCE) + if ( ( fgStructure.GameModeWindow != fgStructure.CurrentWindow ) && ( fgStructure.CurrentWindow->Parent == NULL ) && + ( ! fgStructure.CurrentWindow->IsMenu ) ) + { + winRect.left += GetSystemMetrics( SM_CXSIZEFRAME ); + winRect.right -= GetSystemMetrics( SM_CXSIZEFRAME ); + winRect.top += GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION ); + winRect.bottom -= GetSystemMetrics( SM_CYSIZEFRAME ); + } +#endif /* !defined(_WIN32_WCE) */ + + switch( eWhat ) + { + case GLUT_WINDOW_X: return winRect.left ; + case GLUT_WINDOW_Y: return winRect.top ; + case GLUT_WINDOW_WIDTH: return winRect.right - winRect.left; + case GLUT_WINDOW_HEIGHT: return winRect.bottom - winRect.top; + } + } + break; + + case GLUT_WINDOW_BORDER_WIDTH : +#if defined(_WIN32_WCE) + return 0; +#else + return GetSystemMetrics( SM_CXSIZEFRAME ); +#endif /* !defined(_WIN32_WCE) */ + + case GLUT_WINDOW_HEADER_HEIGHT : +#if defined(_WIN32_WCE) + return 0; +#else + return GetSystemMetrics( SM_CYCAPTION ); +#endif /* defined(_WIN32_WCE) */ + + case GLUT_DISPLAY_MODE_POSSIBLE: +#if defined(_WIN32_WCE) + return 0; +#else + return fgSetupPixelFormat( fgStructure.CurrentWindow, GL_TRUE, + PFD_MAIN_PLANE ); +#endif /* defined(_WIN32_WCE) */ + + + case GLUT_WINDOW_FORMAT_ID: +#if !defined(_WIN32_WCE) + if( fgStructure.CurrentWindow != NULL ) + return GetPixelFormat( fgStructure.CurrentWindow->Window.Device ); +#endif /* defined(_WIN32_WCE) */ + return 0; + +#endif + + /* The window structure queries */ + case GLUT_WINDOW_PARENT: + if( fgStructure.CurrentWindow == NULL ) return 0; + if( fgStructure.CurrentWindow->Parent == NULL ) return 0; + return fgStructure.CurrentWindow->Parent->ID; + + case GLUT_WINDOW_NUM_CHILDREN: + if( fgStructure.CurrentWindow == NULL ) + return 0; + return fgListLength( &fgStructure.CurrentWindow->Children ); + + case GLUT_WINDOW_CURSOR: + if( fgStructure.CurrentWindow == NULL ) + return 0; + return fgStructure.CurrentWindow->State.Cursor; + + case GLUT_MENU_NUM_ITEMS: + if( fgStructure.CurrentMenu == NULL ) + return 0; + return fgListLength( &fgStructure.CurrentMenu->Entries ); + + case GLUT_ACTION_ON_WINDOW_CLOSE: + return fgState.ActionOnWindowClose; + + case GLUT_VERSION : + return VERSION_MAJOR * 10000 + VERSION_MINOR * 100 + VERSION_PATCH; + + case GLUT_RENDERING_CONTEXT: + return fgState.UseCurrentContext ? GLUT_USE_CURRENT_CONTEXT + : GLUT_CREATE_NEW_CONTEXT; + + case GLUT_DIRECT_RENDERING: + return fgState.DirectContext; + + case GLUT_FULL_SCREEN: + return fghCheckFullScreen(); + + case GLUT_AUX: + return fgState.AuxiliaryBufferNumber; + + case GLUT_MULTISAMPLE: + return fgState.SampleNumber; + + default: + fgWarning( "glutGet(): missing enum handle %d", eWhat ); + break; + } + return -1; +} + +/* + * Returns various device information. + */ +int FGAPIENTRY glutDeviceGet( GLenum eWhat ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDeviceGet" ); + + /* XXX WARNING: we are mostly lying in this function. */ + switch( eWhat ) + { + case GLUT_HAS_KEYBOARD: + /* + * Win32 is assumed a keyboard, and this cannot be queried, + * except for WindowsCE. + * + * X11 has a core keyboard by definition, although it can + * be present as a virtual/dummy keyboard. For now, there + * is no reliable way to tell if a real keyboard is present. + */ +#if defined(_WIN32_CE) + return ( GetKeyboardStatus() & KBDI_KEYBOARD_PRESENT ) ? 1 : 0; +# if FREEGLUT_LIB_PRAGMAS +# pragma comment (lib,"Kbdui.lib") +# endif + +#else + return 1; +#endif + +#if TARGET_HOST_POSIX_X11 + + /* X11 has a mouse by definition */ + case GLUT_HAS_MOUSE: + return 1 ; + + case GLUT_NUM_MOUSE_BUTTONS: + /* We should be able to pass NULL when the last argument is zero, + * but at least one X server has a bug where this causes a segfault. + * + * In XFree86/Xorg servers, a mouse wheel is seen as two buttons + * rather than an Axis; "freeglut_main.c" expects this when + * checking for a wheel event. + */ + { + unsigned char map; + int nbuttons = XGetPointerMapping(fgDisplay.Display, &map,0); + return nbuttons; + } + +#elif TARGET_HOST_MS_WINDOWS + + case GLUT_HAS_MOUSE: + /* + * MS Windows can be booted without a mouse. + */ + return GetSystemMetrics( SM_MOUSEPRESENT ); + + case GLUT_NUM_MOUSE_BUTTONS: +# if defined(_WIN32_WCE) + return 1; +# else + return GetSystemMetrics( SM_CMOUSEBUTTONS ); +# endif +#endif + + case GLUT_HAS_JOYSTICK: + return fgJoystickDetect (); + + case GLUT_OWNS_JOYSTICK: + return fgState.JoysticksInitialised; + + case GLUT_JOYSTICK_POLL_RATE: + return fgStructure.CurrentWindow ? fgStructure.CurrentWindow->State.JoystickPollRate : 0; + + /* XXX The following two are only for Joystick 0 but this is an improvement */ + case GLUT_JOYSTICK_BUTTONS: + return glutJoystickGetNumButtons ( 0 ); + + case GLUT_JOYSTICK_AXES: + return glutJoystickGetNumAxes ( 0 ); + + case GLUT_HAS_DIAL_AND_BUTTON_BOX: + return fgInputDeviceDetect (); + + case GLUT_NUM_DIALS: + if ( fgState.InputDevsInitialised ) return 8; + return 0; + + case GLUT_NUM_BUTTON_BOX_BUTTONS: + return 0; + + case GLUT_HAS_SPACEBALL: + return fgHasSpaceball(); + + case GLUT_HAS_TABLET: + return 0; + + case GLUT_NUM_SPACEBALL_BUTTONS: + return fgSpaceballNumButtons(); + + case GLUT_NUM_TABLET_BUTTONS: + return 0; + + case GLUT_DEVICE_IGNORE_KEY_REPEAT: + return fgStructure.CurrentWindow ? fgStructure.CurrentWindow->State.IgnoreKeyRepeat : 0; + + case GLUT_DEVICE_KEY_REPEAT: + return fgState.KeyRepeat; + + default: + fgWarning( "glutDeviceGet(): missing enum handle %d", eWhat ); + break; + } + + /* And now -- the failure. */ + return -1; +} + +/* + * This should return the current state of ALT, SHIFT and CTRL keys. + */ +int FGAPIENTRY glutGetModifiers( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetModifiers" ); + if( fgState.Modifiers == INVALID_MODIFIERS ) + { + fgWarning( "glutGetModifiers() called outside an input callback" ); + return 0; + } + + return fgState.Modifiers; +} + +/* + * Return the state of the GLUT API overlay subsystem. A misery ;-) + */ +int FGAPIENTRY glutLayerGet( GLenum eWhat ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLayerGet" ); + + /* + * This is easy as layers are not implemented ;-) + * + * XXX Can we merge the UNIX/X11 and WIN32 sections? Or + * XXX is overlay support planned? + */ + switch( eWhat ) + { + +#if TARGET_HOST_POSIX_X11 + + case GLUT_OVERLAY_POSSIBLE: + return 0; + + case GLUT_LAYER_IN_USE: + return GLUT_NORMAL; + + case GLUT_HAS_OVERLAY: + return 0; + + case GLUT_TRANSPARENT_INDEX: + /* + * Return just anything, which is always defined as zero + * + * XXX HUH? + */ + return 0; + + case GLUT_NORMAL_DAMAGED: + /* XXX Actually I do not know. Maybe. */ + return 0; + + case GLUT_OVERLAY_DAMAGED: + return -1; + +#elif TARGET_HOST_MS_WINDOWS + + case GLUT_OVERLAY_POSSIBLE: +/* return fgSetupPixelFormat( fgStructure.CurrentWindow, GL_TRUE, + PFD_OVERLAY_PLANE ); */ + return 0 ; + + case GLUT_LAYER_IN_USE: + return GLUT_NORMAL; + + case GLUT_HAS_OVERLAY: + return 0; + + case GLUT_TRANSPARENT_INDEX: + /* + * Return just anything, which is always defined as zero + * + * XXX HUH? + */ + return 0; + + case GLUT_NORMAL_DAMAGED: + /* XXX Actually I do not know. Maybe. */ + return 0; + + case GLUT_OVERLAY_DAMAGED: + return -1; +#endif + + default: + fgWarning( "glutLayerGet(): missing enum handle %d", eWhat ); + break; + } + + /* And fail. That's good. Programs do love failing. */ + return -1; +} + +int * FGAPIENTRY glutGetModeValues(GLenum eWhat, int * size) +{ + int * array; + +#if TARGET_HOST_POSIX_X11 + int attributes[9]; + GLXFBConfig * fbconfigArray; /* Array of FBConfigs */ + int fbconfigArraySize; /* Number of FBConfigs in the array */ + int attribute_name = 0; +#endif + + FREEGLUT_EXIT_IF_NOT_INITIALISED("glutGetModeValues"); + + array = NULL; + *size = 0; + + switch (eWhat) + { +#if TARGET_HOST_POSIX_X11 + case GLUT_AUX: + case GLUT_MULTISAMPLE: + + attributes[0] = GLX_BUFFER_SIZE; + attributes[1] = GLX_DONT_CARE; + + switch (eWhat) + { + case GLUT_AUX: + /* + FBConfigs are now sorted by increasing number of auxiliary + buffers. We want at least one buffer. + */ + attributes[2] = GLX_AUX_BUFFERS; + attributes[3] = 1; + attributes[4] = None; + + attribute_name = GLX_AUX_BUFFERS; + + break; + + + case GLUT_MULTISAMPLE: + attributes[2] = GLX_AUX_BUFFERS; + attributes[3] = GLX_DONT_CARE; + attributes[4] = GLX_SAMPLE_BUFFERS; + attributes[5] = 1; + /* + FBConfigs are now sorted by increasing number of samples per + pixel. We want at least one sample. + */ + attributes[6] = GLX_SAMPLES; + attributes[7] = 1; + attributes[8] = None; + + attribute_name = GLX_SAMPLES; + + break; + } + + fbconfigArray = glXChooseFBConfig(fgDisplay.Display, + fgDisplay.Screen, + attributes, + &fbconfigArraySize); + + if (fbconfigArray != NULL) + { + int * temp_array; + int result; /* Returned by glXGetFBConfigAttrib. Not checked. */ + int previous_value; + int i; + + temp_array = malloc(sizeof(int) * fbconfigArraySize); + previous_value = 0; + + for (i = 0; i < fbconfigArraySize; i++) + { + int value; + + result = glXGetFBConfigAttrib(fgDisplay.Display, + fbconfigArray[i], + attribute_name, + &value); + if (value > previous_value) + { + temp_array[*size] = value; + previous_value = value; + (*size)++; + } + } + + array = malloc(sizeof(int) * (*size)); + for (i = 0; i < *size; i++) + { + array[i] = temp_array[i]; + } + + free(temp_array); + XFree(fbconfigArray); + } + + break; +#endif + + default: + break; + } + + return array; +} + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_std.h b/tests/Box2D_v2.2.1/freeglut/freeglut_std.h new file mode 100755 index 0000000000000..3a4207faafdba --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_std.h @@ -0,0 +1,583 @@ +#ifndef __FREEGLUT_STD_H__ +#define __FREEGLUT_STD_H__ + +/* + * freeglut_std.h + * + * The GLUT-compatible part of the freeglut library include file + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 2 1999 + * + * 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 + * PAWEL W. OLSZTA 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. + */ + +#ifdef __cplusplus + extern "C" { +#endif + +#define FGAPI +#define FGAPIENTRY + +/* + * Under windows, we have to differentiate between static and dynamic libraries + */ +#ifdef _WIN32 +/* #pragma may not be supported by some compilers. + * Discussion by FreeGLUT developers suggests that + * Visual C++ specific code involving pragmas may + * need to move to a separate header. 24th Dec 2003 + */ + + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN 1 + #endif + + #define NOMINMAX + #include + +/* Drag in other Windows libraries as required by FreeGLUT */ +// # if FREEGLUT_LIB_PRAGMAS +// # pragma comment (lib, "glu32.lib") /* link OpenGL Utility lib */ +// # pragma comment (lib, "opengl32.lib") /* link Microsoft OpenGL lib */ +// # pragma comment (lib, "gdi32.lib") /* link Windows GDI lib */ +// # pragma comment (lib, "winmm.lib") /* link Windows MultiMedia lib */ +// # pragma comment (lib, "user32.lib") /* link Windows user lib */ +// # endif + +#endif + +/* + * The freeglut and GLUT API versions + */ +#define FREEGLUT 1 +#define GLUT_API_VERSION 4 +#define FREEGLUT_VERSION_2_0 1 +#define GLUT_XLIB_IMPLEMENTATION 13 + +/* + * Always include OpenGL and GLU headers + */ +#include +#include + +/* + * GLUT API macro definitions -- the special key codes: + */ +#define GLUT_KEY_F1 0x0001 +#define GLUT_KEY_F2 0x0002 +#define GLUT_KEY_F3 0x0003 +#define GLUT_KEY_F4 0x0004 +#define GLUT_KEY_F5 0x0005 +#define GLUT_KEY_F6 0x0006 +#define GLUT_KEY_F7 0x0007 +#define GLUT_KEY_F8 0x0008 +#define GLUT_KEY_F9 0x0009 +#define GLUT_KEY_F10 0x000A +#define GLUT_KEY_F11 0x000B +#define GLUT_KEY_F12 0x000C +#define GLUT_KEY_LEFT 0x0064 +#define GLUT_KEY_UP 0x0065 +#define GLUT_KEY_RIGHT 0x0066 +#define GLUT_KEY_DOWN 0x0067 +#define GLUT_KEY_PAGE_UP 0x0068 +#define GLUT_KEY_PAGE_DOWN 0x0069 +#define GLUT_KEY_HOME 0x006A +#define GLUT_KEY_END 0x006B +#define GLUT_KEY_INSERT 0x006C + +/* + * GLUT API macro definitions -- mouse state definitions + */ +#define GLUT_LEFT_BUTTON 0x0000 +#define GLUT_MIDDLE_BUTTON 0x0001 +#define GLUT_RIGHT_BUTTON 0x0002 +#define GLUT_DOWN 0x0000 +#define GLUT_UP 0x0001 +#define GLUT_LEFT 0x0000 +#define GLUT_ENTERED 0x0001 + +/* + * GLUT API macro definitions -- the display mode definitions + */ +#define GLUT_RGB 0x0000 +#define GLUT_RGBA 0x0000 +#define GLUT_INDEX 0x0001 +#define GLUT_SINGLE 0x0000 +#define GLUT_DOUBLE 0x0002 +#define GLUT_ACCUM 0x0004 +#define GLUT_ALPHA 0x0008 +#define GLUT_DEPTH 0x0010 +#define GLUT_STENCIL 0x0020 +#define GLUT_MULTISAMPLE 0x0080 +#define GLUT_STEREO 0x0100 +#define GLUT_LUMINANCE 0x0200 + +/* + * GLUT API macro definitions -- windows and menu related definitions + */ +#define GLUT_MENU_NOT_IN_USE 0x0000 +#define GLUT_MENU_IN_USE 0x0001 +#define GLUT_NOT_VISIBLE 0x0000 +#define GLUT_VISIBLE 0x0001 +#define GLUT_HIDDEN 0x0000 +#define GLUT_FULLY_RETAINED 0x0001 +#define GLUT_PARTIALLY_RETAINED 0x0002 +#define GLUT_FULLY_COVERED 0x0003 + +/* + * GLUT API macro definitions -- fonts definitions + * + * Steve Baker suggested to make it binary compatible with GLUT: + */ +#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WATCOMC__) +# define GLUT_STROKE_ROMAN ((void *)0x0000) +# define GLUT_STROKE_MONO_ROMAN ((void *)0x0001) +# define GLUT_BITMAP_9_BY_15 ((void *)0x0002) +# define GLUT_BITMAP_8_BY_13 ((void *)0x0003) +# define GLUT_BITMAP_TIMES_ROMAN_10 ((void *)0x0004) +# define GLUT_BITMAP_TIMES_ROMAN_24 ((void *)0x0005) +# define GLUT_BITMAP_HELVETICA_10 ((void *)0x0006) +# define GLUT_BITMAP_HELVETICA_12 ((void *)0x0007) +# define GLUT_BITMAP_HELVETICA_18 ((void *)0x0008) +#else + /* + * I don't really know if it's a good idea... But here it goes: + */ + extern void* glutStrokeRoman; + extern void* glutStrokeMonoRoman; + extern void* glutBitmap9By15; + extern void* glutBitmap8By13; + extern void* glutBitmapTimesRoman10; + extern void* glutBitmapTimesRoman24; + extern void* glutBitmapHelvetica10; + extern void* glutBitmapHelvetica12; + extern void* glutBitmapHelvetica18; + + /* + * Those pointers will be used by following definitions: + */ +# define GLUT_STROKE_ROMAN ((void *) &glutStrokeRoman) +# define GLUT_STROKE_MONO_ROMAN ((void *) &glutStrokeMonoRoman) +# define GLUT_BITMAP_9_BY_15 ((void *) &glutBitmap9By15) +# define GLUT_BITMAP_8_BY_13 ((void *) &glutBitmap8By13) +# define GLUT_BITMAP_TIMES_ROMAN_10 ((void *) &glutBitmapTimesRoman10) +# define GLUT_BITMAP_TIMES_ROMAN_24 ((void *) &glutBitmapTimesRoman24) +# define GLUT_BITMAP_HELVETICA_10 ((void *) &glutBitmapHelvetica10) +# define GLUT_BITMAP_HELVETICA_12 ((void *) &glutBitmapHelvetica12) +# define GLUT_BITMAP_HELVETICA_18 ((void *) &glutBitmapHelvetica18) +#endif + +/* + * GLUT API macro definitions -- the glutGet parameters + */ +#define GLUT_WINDOW_X 0x0064 +#define GLUT_WINDOW_Y 0x0065 +#define GLUT_WINDOW_WIDTH 0x0066 +#define GLUT_WINDOW_HEIGHT 0x0067 +#define GLUT_WINDOW_BUFFER_SIZE 0x0068 +#define GLUT_WINDOW_STENCIL_SIZE 0x0069 +#define GLUT_WINDOW_DEPTH_SIZE 0x006A +#define GLUT_WINDOW_RED_SIZE 0x006B +#define GLUT_WINDOW_GREEN_SIZE 0x006C +#define GLUT_WINDOW_BLUE_SIZE 0x006D +#define GLUT_WINDOW_ALPHA_SIZE 0x006E +#define GLUT_WINDOW_ACCUM_RED_SIZE 0x006F +#define GLUT_WINDOW_ACCUM_GREEN_SIZE 0x0070 +#define GLUT_WINDOW_ACCUM_BLUE_SIZE 0x0071 +#define GLUT_WINDOW_ACCUM_ALPHA_SIZE 0x0072 +#define GLUT_WINDOW_DOUBLEBUFFER 0x0073 +#define GLUT_WINDOW_RGBA 0x0074 +#define GLUT_WINDOW_PARENT 0x0075 +#define GLUT_WINDOW_NUM_CHILDREN 0x0076 +#define GLUT_WINDOW_COLORMAP_SIZE 0x0077 +#define GLUT_WINDOW_NUM_SAMPLES 0x0078 +#define GLUT_WINDOW_STEREO 0x0079 +#define GLUT_WINDOW_CURSOR 0x007A + +#define GLUT_SCREEN_WIDTH 0x00C8 +#define GLUT_SCREEN_HEIGHT 0x00C9 +#define GLUT_SCREEN_WIDTH_MM 0x00CA +#define GLUT_SCREEN_HEIGHT_MM 0x00CB +#define GLUT_MENU_NUM_ITEMS 0x012C +#define GLUT_DISPLAY_MODE_POSSIBLE 0x0190 +#define GLUT_INIT_WINDOW_X 0x01F4 +#define GLUT_INIT_WINDOW_Y 0x01F5 +#define GLUT_INIT_WINDOW_WIDTH 0x01F6 +#define GLUT_INIT_WINDOW_HEIGHT 0x01F7 +#define GLUT_INIT_DISPLAY_MODE 0x01F8 +#define GLUT_ELAPSED_TIME 0x02BC +#define GLUT_WINDOW_FORMAT_ID 0x007B + +/* + * GLUT API macro definitions -- the glutDeviceGet parameters + */ +#define GLUT_HAS_KEYBOARD 0x0258 +#define GLUT_HAS_MOUSE 0x0259 +#define GLUT_HAS_SPACEBALL 0x025A +#define GLUT_HAS_DIAL_AND_BUTTON_BOX 0x025B +#define GLUT_HAS_TABLET 0x025C +#define GLUT_NUM_MOUSE_BUTTONS 0x025D +#define GLUT_NUM_SPACEBALL_BUTTONS 0x025E +#define GLUT_NUM_BUTTON_BOX_BUTTONS 0x025F +#define GLUT_NUM_DIALS 0x0260 +#define GLUT_NUM_TABLET_BUTTONS 0x0261 +#define GLUT_DEVICE_IGNORE_KEY_REPEAT 0x0262 +#define GLUT_DEVICE_KEY_REPEAT 0x0263 +#define GLUT_HAS_JOYSTICK 0x0264 +#define GLUT_OWNS_JOYSTICK 0x0265 +#define GLUT_JOYSTICK_BUTTONS 0x0266 +#define GLUT_JOYSTICK_AXES 0x0267 +#define GLUT_JOYSTICK_POLL_RATE 0x0268 + +/* + * GLUT API macro definitions -- the glutLayerGet parameters + */ +#define GLUT_OVERLAY_POSSIBLE 0x0320 +#define GLUT_LAYER_IN_USE 0x0321 +#define GLUT_HAS_OVERLAY 0x0322 +#define GLUT_TRANSPARENT_INDEX 0x0323 +#define GLUT_NORMAL_DAMAGED 0x0324 +#define GLUT_OVERLAY_DAMAGED 0x0325 + +/* + * GLUT API macro definitions -- the glutVideoResizeGet parameters + */ +#define GLUT_VIDEO_RESIZE_POSSIBLE 0x0384 +#define GLUT_VIDEO_RESIZE_IN_USE 0x0385 +#define GLUT_VIDEO_RESIZE_X_DELTA 0x0386 +#define GLUT_VIDEO_RESIZE_Y_DELTA 0x0387 +#define GLUT_VIDEO_RESIZE_WIDTH_DELTA 0x0388 +#define GLUT_VIDEO_RESIZE_HEIGHT_DELTA 0x0389 +#define GLUT_VIDEO_RESIZE_X 0x038A +#define GLUT_VIDEO_RESIZE_Y 0x038B +#define GLUT_VIDEO_RESIZE_WIDTH 0x038C +#define GLUT_VIDEO_RESIZE_HEIGHT 0x038D + +/* + * GLUT API macro definitions -- the glutUseLayer parameters + */ +#define GLUT_NORMAL 0x0000 +#define GLUT_OVERLAY 0x0001 + +/* + * GLUT API macro definitions -- the glutGetModifiers parameters + */ +#define GLUT_ACTIVE_SHIFT 0x0001 +#define GLUT_ACTIVE_CTRL 0x0002 +#define GLUT_ACTIVE_ALT 0x0004 + +/* + * GLUT API macro definitions -- the glutSetCursor parameters + */ +#define GLUT_CURSOR_RIGHT_ARROW 0x0000 +#define GLUT_CURSOR_LEFT_ARROW 0x0001 +#define GLUT_CURSOR_INFO 0x0002 +#define GLUT_CURSOR_DESTROY 0x0003 +#define GLUT_CURSOR_HELP 0x0004 +#define GLUT_CURSOR_CYCLE 0x0005 +#define GLUT_CURSOR_SPRAY 0x0006 +#define GLUT_CURSOR_WAIT 0x0007 +#define GLUT_CURSOR_TEXT 0x0008 +#define GLUT_CURSOR_CROSSHAIR 0x0009 +#define GLUT_CURSOR_UP_DOWN 0x000A +#define GLUT_CURSOR_LEFT_RIGHT 0x000B +#define GLUT_CURSOR_TOP_SIDE 0x000C +#define GLUT_CURSOR_BOTTOM_SIDE 0x000D +#define GLUT_CURSOR_LEFT_SIDE 0x000E +#define GLUT_CURSOR_RIGHT_SIDE 0x000F +#define GLUT_CURSOR_TOP_LEFT_CORNER 0x0010 +#define GLUT_CURSOR_TOP_RIGHT_CORNER 0x0011 +#define GLUT_CURSOR_BOTTOM_RIGHT_CORNER 0x0012 +#define GLUT_CURSOR_BOTTOM_LEFT_CORNER 0x0013 +#define GLUT_CURSOR_INHERIT 0x0064 +#define GLUT_CURSOR_NONE 0x0065 +#define GLUT_CURSOR_FULL_CROSSHAIR 0x0066 + +/* + * GLUT API macro definitions -- RGB color component specification definitions + */ +#define GLUT_RED 0x0000 +#define GLUT_GREEN 0x0001 +#define GLUT_BLUE 0x0002 + +/* + * GLUT API macro definitions -- additional keyboard and joystick definitions + */ +#define GLUT_KEY_REPEAT_OFF 0x0000 +#define GLUT_KEY_REPEAT_ON 0x0001 +#define GLUT_KEY_REPEAT_DEFAULT 0x0002 + +#define GLUT_JOYSTICK_BUTTON_A 0x0001 +#define GLUT_JOYSTICK_BUTTON_B 0x0002 +#define GLUT_JOYSTICK_BUTTON_C 0x0004 +#define GLUT_JOYSTICK_BUTTON_D 0x0008 + +/* + * GLUT API macro definitions -- game mode definitions + */ +#define GLUT_GAME_MODE_ACTIVE 0x0000 +#define GLUT_GAME_MODE_POSSIBLE 0x0001 +#define GLUT_GAME_MODE_WIDTH 0x0002 +#define GLUT_GAME_MODE_HEIGHT 0x0003 +#define GLUT_GAME_MODE_PIXEL_DEPTH 0x0004 +#define GLUT_GAME_MODE_REFRESH_RATE 0x0005 +#define GLUT_GAME_MODE_DISPLAY_CHANGED 0x0006 + +/* + * Initialization functions, see fglut_init.c + */ +FGAPI void FGAPIENTRY glutInit( int* pargc, char** argv ); +FGAPI void FGAPIENTRY glutInitWindowPosition( int x, int y ); +FGAPI void FGAPIENTRY glutInitWindowSize( int width, int height ); +FGAPI void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode ); +FGAPI void FGAPIENTRY glutInitDisplayString( const char* displayMode ); + +/* + * Process loop function, see freeglut_main.c + */ +FGAPI void FGAPIENTRY glutMainLoop( void ); + +/* + * Window management functions, see freeglut_window.c + */ +FGAPI int FGAPIENTRY glutCreateWindow( const char* title ); +FGAPI int FGAPIENTRY glutCreateSubWindow( int window, int x, int y, int width, int height ); +FGAPI void FGAPIENTRY glutDestroyWindow( int window ); +FGAPI void FGAPIENTRY glutSetWindow( int window ); +FGAPI int FGAPIENTRY glutGetWindow( void ); +FGAPI void FGAPIENTRY glutSetWindowTitle( const char* title ); +FGAPI void FGAPIENTRY glutSetIconTitle( const char* title ); +FGAPI void FGAPIENTRY glutReshapeWindow( int width, int height ); +FGAPI void FGAPIENTRY glutPositionWindow( int x, int y ); +FGAPI void FGAPIENTRY glutShowWindow( void ); +FGAPI void FGAPIENTRY glutHideWindow( void ); +FGAPI void FGAPIENTRY glutIconifyWindow( void ); +FGAPI void FGAPIENTRY glutPushWindow( void ); +FGAPI void FGAPIENTRY glutPopWindow( void ); +FGAPI void FGAPIENTRY glutFullScreen( void ); + +/* + * Display-connected functions, see freeglut_display.c + */ +FGAPI void FGAPIENTRY glutPostWindowRedisplay( int window ); +FGAPI void FGAPIENTRY glutPostRedisplay( void ); +FGAPI void FGAPIENTRY glutSwapBuffers( void ); + +/* + * Mouse cursor functions, see freeglut_cursor.c + */ +FGAPI void FGAPIENTRY glutWarpPointer( int x, int y ); +FGAPI void FGAPIENTRY glutSetCursor( int cursor ); + +/* + * Overlay stuff, see freeglut_overlay.c + */ +FGAPI void FGAPIENTRY glutEstablishOverlay( void ); +FGAPI void FGAPIENTRY glutRemoveOverlay( void ); +FGAPI void FGAPIENTRY glutUseLayer( GLenum layer ); +FGAPI void FGAPIENTRY glutPostOverlayRedisplay( void ); +FGAPI void FGAPIENTRY glutPostWindowOverlayRedisplay( int window ); +FGAPI void FGAPIENTRY glutShowOverlay( void ); +FGAPI void FGAPIENTRY glutHideOverlay( void ); + +/* + * Menu stuff, see freeglut_menu.c + */ +FGAPI int FGAPIENTRY glutCreateMenu( void (* callback)( int menu ) ); +FGAPI void FGAPIENTRY glutDestroyMenu( int menu ); +FGAPI int FGAPIENTRY glutGetMenu( void ); +FGAPI void FGAPIENTRY glutSetMenu( int menu ); +FGAPI void FGAPIENTRY glutAddMenuEntry( const char* label, int value ); +FGAPI void FGAPIENTRY glutAddSubMenu( const char* label, int subMenu ); +FGAPI void FGAPIENTRY glutChangeToMenuEntry( int item, const char* label, int value ); +FGAPI void FGAPIENTRY glutChangeToSubMenu( int item, const char* label, int value ); +FGAPI void FGAPIENTRY glutRemoveMenuItem( int item ); +FGAPI void FGAPIENTRY glutAttachMenu( int button ); +FGAPI void FGAPIENTRY glutDetachMenu( int button ); + +/* + * Global callback functions, see freeglut_callbacks.c + */ +FGAPI void FGAPIENTRY glutTimerFunc( unsigned int time, void (* callback)( int ), int value ); +FGAPI void FGAPIENTRY glutIdleFunc( void (* callback)( void ) ); + +/* + * Window-specific callback functions, see freeglut_callbacks.c + */ +FGAPI void FGAPIENTRY glutKeyboardFunc( void (* callback)( unsigned char, int, int ) ); +FGAPI void FGAPIENTRY glutSpecialFunc( void (* callback)( int, int, int ) ); +FGAPI void FGAPIENTRY glutReshapeFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutVisibilityFunc( void (* callback)( int ) ); +FGAPI void FGAPIENTRY glutDisplayFunc( void (* callback)( void ) ); +FGAPI void FGAPIENTRY glutMouseFunc( void (* callback)( int, int, int, int ) ); +FGAPI void FGAPIENTRY glutMotionFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutPassiveMotionFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutEntryFunc( void (* callback)( int ) ); + +FGAPI void FGAPIENTRY glutKeyboardUpFunc( void (* callback)( unsigned char, int, int ) ); +FGAPI void FGAPIENTRY glutSpecialUpFunc( void (* callback)( int, int, int ) ); +FGAPI void FGAPIENTRY glutJoystickFunc( void (* callback)( unsigned int, int, int, int ), int pollInterval ); +FGAPI void FGAPIENTRY glutMenuStateFunc( void (* callback)( int ) ); +FGAPI void FGAPIENTRY glutMenuStatusFunc( void (* callback)( int, int, int ) ); +FGAPI void FGAPIENTRY glutOverlayDisplayFunc( void (* callback)( void ) ); +FGAPI void FGAPIENTRY glutWindowStatusFunc( void (* callback)( int ) ); + +FGAPI void FGAPIENTRY glutSpaceballMotionFunc( void (* callback)( int, int, int ) ); +FGAPI void FGAPIENTRY glutSpaceballRotateFunc( void (* callback)( int, int, int ) ); +FGAPI void FGAPIENTRY glutSpaceballButtonFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutButtonBoxFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutDialsFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutTabletMotionFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutTabletButtonFunc( void (* callback)( int, int, int, int ) ); + +/* + * State setting and retrieval functions, see freeglut_state.c + */ +FGAPI int FGAPIENTRY glutGet( GLenum query ); +FGAPI int FGAPIENTRY glutDeviceGet( GLenum query ); +FGAPI int FGAPIENTRY glutGetModifiers( void ); +FGAPI int FGAPIENTRY glutLayerGet( GLenum query ); + +/* + * Font stuff, see freeglut_font.c + */ +FGAPI void FGAPIENTRY glutBitmapCharacter( void* font, int character ); +FGAPI int FGAPIENTRY glutBitmapWidth( void* font, int character ); +FGAPI void FGAPIENTRY glutStrokeCharacter( void* font, int character ); +FGAPI int FGAPIENTRY glutStrokeWidth( void* font, int character ); +FGAPI int FGAPIENTRY glutBitmapLength( void* font, const unsigned char* string ); +FGAPI int FGAPIENTRY glutStrokeLength( void* font, const unsigned char* string ); + +/* + * Geometry functions, see freeglut_geometry.c + */ +FGAPI void FGAPIENTRY glutWireCube( GLdouble size ); +FGAPI void FGAPIENTRY glutSolidCube( GLdouble size ); +FGAPI void FGAPIENTRY glutWireSphere( GLdouble radius, GLint slices, GLint stacks ); +FGAPI void FGAPIENTRY glutSolidSphere( GLdouble radius, GLint slices, GLint stacks ); +FGAPI void FGAPIENTRY glutWireCone( GLdouble base, GLdouble height, GLint slices, GLint stacks ); +FGAPI void FGAPIENTRY glutSolidCone( GLdouble base, GLdouble height, GLint slices, GLint stacks ); + +FGAPI void FGAPIENTRY glutWireTorus( GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings ); +FGAPI void FGAPIENTRY glutSolidTorus( GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings ); +FGAPI void FGAPIENTRY glutWireDodecahedron( void ); +FGAPI void FGAPIENTRY glutSolidDodecahedron( void ); +FGAPI void FGAPIENTRY glutWireOctahedron( void ); +FGAPI void FGAPIENTRY glutSolidOctahedron( void ); +FGAPI void FGAPIENTRY glutWireTetrahedron( void ); +FGAPI void FGAPIENTRY glutSolidTetrahedron( void ); +FGAPI void FGAPIENTRY glutWireIcosahedron( void ); +FGAPI void FGAPIENTRY glutSolidIcosahedron( void ); + +/* + * Teapot rendering functions, found in freeglut_teapot.c + */ +FGAPI void FGAPIENTRY glutWireTeapot( GLdouble size ); +FGAPI void FGAPIENTRY glutSolidTeapot( GLdouble size ); + +/* + * Game mode functions, see freeglut_gamemode.c + */ +FGAPI void FGAPIENTRY glutGameModeString( const char* string ); +FGAPI int FGAPIENTRY glutEnterGameMode( void ); +FGAPI void FGAPIENTRY glutLeaveGameMode( void ); +FGAPI int FGAPIENTRY glutGameModeGet( GLenum query ); + +/* + * Video resize functions, see freeglut_videoresize.c + */ +FGAPI int FGAPIENTRY glutVideoResizeGet( GLenum query ); +FGAPI void FGAPIENTRY glutSetupVideoResizing( void ); +FGAPI void FGAPIENTRY glutStopVideoResizing( void ); +FGAPI void FGAPIENTRY glutVideoResize( int x, int y, int width, int height ); +FGAPI void FGAPIENTRY glutVideoPan( int x, int y, int width, int height ); + +/* + * Colormap functions, see freeglut_misc.c + */ +FGAPI void FGAPIENTRY glutSetColor( int color, GLfloat red, GLfloat green, GLfloat blue ); +FGAPI GLfloat FGAPIENTRY glutGetColor( int color, int component ); +FGAPI void FGAPIENTRY glutCopyColormap( int window ); + +/* + * Misc keyboard and joystick functions, see freeglut_misc.c + */ +FGAPI void FGAPIENTRY glutIgnoreKeyRepeat( int ignore ); +FGAPI void FGAPIENTRY glutSetKeyRepeat( int repeatMode ); +FGAPI void FGAPIENTRY glutForceJoystickFunc( void ); + +/* + * Misc functions, see freeglut_misc.c + */ +FGAPI int FGAPIENTRY glutExtensionSupported( const char* extension ); +FGAPI void FGAPIENTRY glutReportErrors( void ); + +/* Comment from glut.h of classic GLUT: + + Win32 has an annoying issue where there are multiple C run-time + libraries (CRTs). If the executable is linked with a different CRT + from the GLUT DLL, the GLUT DLL will not share the same CRT static + data seen by the executable. In particular, atexit callbacks registered + in the executable will not be called if GLUT calls its (different) + exit routine). GLUT is typically built with the + "/MD" option (the CRT with multithreading DLL support), but the Visual + C++ linker default is "/ML" (the single threaded CRT). + + One workaround to this issue is requiring users to always link with + the same CRT as GLUT is compiled with. That requires users supply a + non-standard option. GLUT 3.7 has its own built-in workaround where + the executable's "exit" function pointer is covertly passed to GLUT. + GLUT then calls the executable's exit function pointer to ensure that + any "atexit" calls registered by the application are called if GLUT + needs to exit. + + Note that the __glut*WithExit routines should NEVER be called directly. + To avoid the atexit workaround, #define GLUT_DISABLE_ATEXIT_HACK. */ + +/* to get the prototype for exit() */ +#include + +#if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) && !defined(__WATCOMC__) +FGAPI void FGAPIENTRY __glutInitWithExit(int *argcp, char **argv, void (__cdecl *exitfunc)(int)); +FGAPI int FGAPIENTRY __glutCreateWindowWithExit(const char *title, void (__cdecl *exitfunc)(int)); +FGAPI int FGAPIENTRY __glutCreateMenuWithExit(void (* func)(int), void (__cdecl *exitfunc)(int)); +#ifndef FREEGLUT_BUILDING_LIB +#if defined(__GNUC__) +#define FGUNUSED __attribute__((unused)) +#else +#define FGUNUSED +#endif +static void FGAPIENTRY FGUNUSED glutInit_ATEXIT_HACK(int *argcp, char **argv) { __glutInitWithExit(argcp, argv, exit); } +#define glutInit glutInit_ATEXIT_HACK +static int FGAPIENTRY FGUNUSED glutCreateWindow_ATEXIT_HACK(const char *title) { return __glutCreateWindowWithExit(title, exit); } +#define glutCreateWindow glutCreateWindow_ATEXIT_HACK +static int FGAPIENTRY FGUNUSED glutCreateMenu_ATEXIT_HACK(void (* func)(int)) { return __glutCreateMenuWithExit(func, exit); } +#define glutCreateMenu glutCreateMenu_ATEXIT_HACK +#endif +#endif + +#ifdef __cplusplus + } +#endif + +/*** END OF FILE ***/ + +#endif /* __FREEGLUT_STD_H__ */ + diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_stroke_mono_roman.c b/tests/Box2D_v2.2.1/freeglut/freeglut_stroke_mono_roman.c new file mode 100755 index 0000000000000..f2a0d6d6cf975 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_stroke_mono_roman.c @@ -0,0 +1,2849 @@ +/* + * freeglut_stroke_mono_roman.c + * + * freeglut Monospace Roman stroke font definition + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 16 1999 + * + * 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 + * PAWEL W. OLSZTA 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. + */ + + +/* This file has been automatically generated by the genstroke utility. */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* char: 0x20 */ + +static const SFG_StrokeStrip ch32st[] = +{ + { 0, NULL } +}; + +static const SFG_StrokeChar ch32 = {104.762f,0,ch32st}; + +/* char: 0x21 */ + +static const SFG_StrokeVertex ch33st0[] = +{ + {52.381f,100.0f}, + {52.381f,33.3333f} +}; + +static const SFG_StrokeVertex ch33st1[] = +{ + {52.381f,9.5238f}, + {47.6191f,4.7619f}, + {52.381f,0.0f}, + {57.1429f,4.7619f}, + {52.381f,9.5238f} +}; + +static const SFG_StrokeStrip ch33st[] = +{ + {2,ch33st0}, + {5,ch33st1} +}; + +static const SFG_StrokeChar ch33 = {104.762f,2,ch33st}; + +/* char: 0x22 */ + +static const SFG_StrokeVertex ch34st0[] = +{ + {33.3334f,100.0f}, + {33.3334f,66.6667f} +}; + +static const SFG_StrokeVertex ch34st1[] = +{ + {71.4286f,100.0f}, + {71.4286f,66.6667f} +}; + +static const SFG_StrokeStrip ch34st[] = +{ + {2,ch34st0}, + {2,ch34st1} +}; + +static const SFG_StrokeChar ch34 = {104.762f,2,ch34st}; + +/* char: 0x23 */ + +static const SFG_StrokeVertex ch35st0[] = +{ + {54.7619f,119.048f}, + {21.4286f,-33.3333f} +}; + +static const SFG_StrokeVertex ch35st1[] = +{ + {83.3334f,119.048f}, + {50.0f,-33.3333f} +}; + +static const SFG_StrokeVertex ch35st2[] = +{ + {21.4286f,57.1429f}, + {88.0952f,57.1429f} +}; + +static const SFG_StrokeVertex ch35st3[] = +{ + {16.6667f,28.5714f}, + {83.3334f,28.5714f} +}; + +static const SFG_StrokeStrip ch35st[] = +{ + {2,ch35st0}, + {2,ch35st1}, + {2,ch35st2}, + {2,ch35st3} +}; + +static const SFG_StrokeChar ch35 = {104.762f,4,ch35st}; + +/* char: 0x24 */ + +static const SFG_StrokeVertex ch36st0[] = +{ + {42.8571f,119.048f}, + {42.8571f,-19.0476f} +}; + +static const SFG_StrokeVertex ch36st1[] = +{ + {61.9047f,119.048f}, + {61.9047f,-19.0476f} +}; + +static const SFG_StrokeVertex ch36st2[] = +{ + {85.7143f,85.7143f}, + {76.1905f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f}, + {28.5714f,95.2381f}, + {19.0476f,85.7143f}, + {19.0476f,76.1905f}, + {23.8095f,66.6667f}, + {28.5714f,61.9048f}, + {38.0952f,57.1429f}, + {66.6666f,47.619f}, + {76.1905f,42.8571f}, + {80.9524f,38.0952f}, + {85.7143f,28.5714f}, + {85.7143f,14.2857f}, + {76.1905f,4.7619f}, + {61.9047f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {19.0476f,14.2857f} +}; + +static const SFG_StrokeStrip ch36st[] = +{ + {2,ch36st0}, + {2,ch36st1}, + {20,ch36st2} +}; + +static const SFG_StrokeChar ch36 = {104.762f,3,ch36st}; + +/* char: 0x25 */ + +static const SFG_StrokeVertex ch37st0[] = +{ + {95.2381f,100.0f}, + {9.5238f,0.0f} +}; + +static const SFG_StrokeVertex ch37st1[] = +{ + {33.3333f,100.0f}, + {42.8571f,90.4762f}, + {42.8571f,80.9524f}, + {38.0952f,71.4286f}, + {28.5714f,66.6667f}, + {19.0476f,66.6667f}, + {9.5238f,76.1905f}, + {9.5238f,85.7143f}, + {14.2857f,95.2381f}, + {23.8095f,100.0f}, + {33.3333f,100.0f}, + {42.8571f,95.2381f}, + {57.1428f,90.4762f}, + {71.4286f,90.4762f}, + {85.7143f,95.2381f}, + {95.2381f,100.0f} +}; + +static const SFG_StrokeVertex ch37st2[] = +{ + {76.1905f,33.3333f}, + {66.6667f,28.5714f}, + {61.9048f,19.0476f}, + {61.9048f,9.5238f}, + {71.4286f,0.0f}, + {80.9524f,0.0f}, + {90.4762f,4.7619f}, + {95.2381f,14.2857f}, + {95.2381f,23.8095f}, + {85.7143f,33.3333f}, + {76.1905f,33.3333f} +}; + +static const SFG_StrokeStrip ch37st[] = +{ + {2,ch37st0}, + {16,ch37st1}, + {11,ch37st2} +}; + +static const SFG_StrokeChar ch37 = {104.762f,3,ch37st}; + +/* char: 0x26 */ + +static const SFG_StrokeVertex ch38st0[] = +{ + {100.0f,57.1429f}, + {100.0f,61.9048f}, + {95.2381f,66.6667f}, + {90.4762f,66.6667f}, + {85.7143f,61.9048f}, + {80.9524f,52.381f}, + {71.4286f,28.5714f}, + {61.9048f,14.2857f}, + {52.3809f,4.7619f}, + {42.8571f,0.0f}, + {23.8095f,0.0f}, + {14.2857f,4.7619f}, + {9.5238f,9.5238f}, + {4.7619f,19.0476f}, + {4.7619f,28.5714f}, + {9.5238f,38.0952f}, + {14.2857f,42.8571f}, + {47.619f,61.9048f}, + {52.3809f,66.6667f}, + {57.1429f,76.1905f}, + {57.1429f,85.7143f}, + {52.3809f,95.2381f}, + {42.8571f,100.0f}, + {33.3333f,95.2381f}, + {28.5714f,85.7143f}, + {28.5714f,76.1905f}, + {33.3333f,61.9048f}, + {42.8571f,47.619f}, + {66.6667f,14.2857f}, + {76.1905f,4.7619f}, + {85.7143f,0.0f}, + {95.2381f,0.0f}, + {100.0f,4.7619f}, + {100.0f,9.5238f} +}; + +static const SFG_StrokeStrip ch38st[] = +{ + {34,ch38st0} +}; + +static const SFG_StrokeChar ch38 = {104.762f,1,ch38st}; + +/* char: 0x27 */ + +static const SFG_StrokeVertex ch39st0[] = +{ + {52.381f,100.0f}, + {52.381f,66.6667f} +}; + +static const SFG_StrokeStrip ch39st[] = +{ + {2,ch39st0} +}; + +static const SFG_StrokeChar ch39 = {104.762f,1,ch39st}; + +/* char: 0x28 */ + +static const SFG_StrokeVertex ch40st0[] = +{ + {69.0476f,119.048f}, + {59.5238f,109.524f}, + {50.0f,95.2381f}, + {40.4762f,76.1905f}, + {35.7143f,52.381f}, + {35.7143f,33.3333f}, + {40.4762f,9.5238f}, + {50.0f,-9.5238f}, + {59.5238f,-23.8095f}, + {69.0476f,-33.3333f} +}; + +static const SFG_StrokeStrip ch40st[] = +{ + {10,ch40st0} +}; + +static const SFG_StrokeChar ch40 = {104.762f,1,ch40st}; + +/* char: 0x29 */ + +static const SFG_StrokeVertex ch41st0[] = +{ + {35.7143f,119.048f}, + {45.2381f,109.524f}, + {54.7619f,95.2381f}, + {64.2857f,76.1905f}, + {69.0476f,52.381f}, + {69.0476f,33.3333f}, + {64.2857f,9.5238f}, + {54.7619f,-9.5238f}, + {45.2381f,-23.8095f}, + {35.7143f,-33.3333f} +}; + +static const SFG_StrokeStrip ch41st[] = +{ + {10,ch41st0} +}; + +static const SFG_StrokeChar ch41 = {104.762f,1,ch41st}; + +/* char: 0x2a */ + +static const SFG_StrokeVertex ch42st0[] = +{ + {52.381f,71.4286f}, + {52.381f,14.2857f} +}; + +static const SFG_StrokeVertex ch42st1[] = +{ + {28.5715f,57.1429f}, + {76.1905f,28.5714f} +}; + +static const SFG_StrokeVertex ch42st2[] = +{ + {76.1905f,57.1429f}, + {28.5715f,28.5714f} +}; + +static const SFG_StrokeStrip ch42st[] = +{ + {2,ch42st0}, + {2,ch42st1}, + {2,ch42st2} +}; + +static const SFG_StrokeChar ch42 = {104.762f,3,ch42st}; + +/* char: 0x2b */ + +static const SFG_StrokeVertex ch43st0[] = +{ + {52.3809f,85.7143f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeVertex ch43st1[] = +{ + {9.5238f,42.8571f}, + {95.2381f,42.8571f} +}; + +static const SFG_StrokeStrip ch43st[] = +{ + {2,ch43st0}, + {2,ch43st1} +}; + +static const SFG_StrokeChar ch43 = {104.762f,2,ch43st}; + +/* char: 0x2c */ + +static const SFG_StrokeVertex ch44st0[] = +{ + {57.1429f,4.7619f}, + {52.381f,0.0f}, + {47.6191f,4.7619f}, + {52.381f,9.5238f}, + {57.1429f,4.7619f}, + {57.1429f,-4.7619f}, + {52.381f,-14.2857f}, + {47.6191f,-19.0476f} +}; + +static const SFG_StrokeStrip ch44st[] = +{ + {8,ch44st0} +}; + +static const SFG_StrokeChar ch44 = {104.762f,1,ch44st}; + +/* char: 0x2d */ + +static const SFG_StrokeVertex ch45st0[] = +{ + {9.5238f,42.8571f}, + {95.2381f,42.8571f} +}; + +static const SFG_StrokeStrip ch45st[] = +{ + {2,ch45st0} +}; + +static const SFG_StrokeChar ch45 = {104.762f,1,ch45st}; + +/* char: 0x2e */ + +static const SFG_StrokeVertex ch46st0[] = +{ + {52.381f,9.5238f}, + {47.6191f,4.7619f}, + {52.381f,0.0f}, + {57.1429f,4.7619f}, + {52.381f,9.5238f} +}; + +static const SFG_StrokeStrip ch46st[] = +{ + {5,ch46st0} +}; + +static const SFG_StrokeChar ch46 = {104.762f,1,ch46st}; + +/* char: 0x2f */ + +static const SFG_StrokeVertex ch47st0[] = +{ + {19.0476f,-14.2857f}, + {85.7143f,100.0f} +}; + +static const SFG_StrokeStrip ch47st[] = +{ + {2,ch47st0} +}; + +static const SFG_StrokeChar ch47 = {104.762f,1,ch47st}; + +/* char: 0x30 */ + +static const SFG_StrokeVertex ch48st0[] = +{ + {47.619f,100.0f}, + {33.3333f,95.2381f}, + {23.8095f,80.9524f}, + {19.0476f,57.1429f}, + {19.0476f,42.8571f}, + {23.8095f,19.0476f}, + {33.3333f,4.7619f}, + {47.619f,0.0f}, + {57.1428f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,19.0476f}, + {85.7143f,42.8571f}, + {85.7143f,57.1429f}, + {80.9524f,80.9524f}, + {71.4286f,95.2381f}, + {57.1428f,100.0f}, + {47.619f,100.0f} +}; + +static const SFG_StrokeStrip ch48st[] = +{ + {17,ch48st0} +}; + +static const SFG_StrokeChar ch48 = {104.762f,1,ch48st}; + +/* char: 0x31 */ + +static const SFG_StrokeVertex ch49st0[] = +{ + {40.4762f,80.9524f}, + {50.0f,85.7143f}, + {64.2857f,100.0f}, + {64.2857f,0.0f} +}; + +static const SFG_StrokeStrip ch49st[] = +{ + {4,ch49st0} +}; + +static const SFG_StrokeChar ch49 = {104.762f,1,ch49st}; + +/* char: 0x32 */ + +static const SFG_StrokeVertex ch50st0[] = +{ + {23.8095f,76.1905f}, + {23.8095f,80.9524f}, + {28.5714f,90.4762f}, + {33.3333f,95.2381f}, + {42.8571f,100.0f}, + {61.9047f,100.0f}, + {71.4286f,95.2381f}, + {76.1905f,90.4762f}, + {80.9524f,80.9524f}, + {80.9524f,71.4286f}, + {76.1905f,61.9048f}, + {66.6666f,47.619f}, + {19.0476f,0.0f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeStrip ch50st[] = +{ + {14,ch50st0} +}; + +static const SFG_StrokeChar ch50 = {104.762f,1,ch50st}; + +/* char: 0x33 */ + +static const SFG_StrokeVertex ch51st0[] = +{ + {28.5714f,100.0f}, + {80.9524f,100.0f}, + {52.3809f,61.9048f}, + {66.6666f,61.9048f}, + {76.1905f,57.1429f}, + {80.9524f,52.381f}, + {85.7143f,38.0952f}, + {85.7143f,28.5714f}, + {80.9524f,14.2857f}, + {71.4286f,4.7619f}, + {57.1428f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {23.8095f,9.5238f}, + {19.0476f,19.0476f} +}; + +static const SFG_StrokeStrip ch51st[] = +{ + {15,ch51st0} +}; + +static const SFG_StrokeChar ch51 = {104.762f,1,ch51st}; + +/* char: 0x34 */ + +static const SFG_StrokeVertex ch52st0[] = +{ + {64.2857f,100.0f}, + {16.6667f,33.3333f}, + {88.0952f,33.3333f} +}; + +static const SFG_StrokeVertex ch52st1[] = +{ + {64.2857f,100.0f}, + {64.2857f,0.0f} +}; + +static const SFG_StrokeStrip ch52st[] = +{ + {3,ch52st0}, + {2,ch52st1} +}; + +static const SFG_StrokeChar ch52 = {104.762f,2,ch52st}; + +/* char: 0x35 */ + +static const SFG_StrokeVertex ch53st0[] = +{ + {76.1905f,100.0f}, + {28.5714f,100.0f}, + {23.8095f,57.1429f}, + {28.5714f,61.9048f}, + {42.8571f,66.6667f}, + {57.1428f,66.6667f}, + {71.4286f,61.9048f}, + {80.9524f,52.381f}, + {85.7143f,38.0952f}, + {85.7143f,28.5714f}, + {80.9524f,14.2857f}, + {71.4286f,4.7619f}, + {57.1428f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {23.8095f,9.5238f}, + {19.0476f,19.0476f} +}; + +static const SFG_StrokeStrip ch53st[] = +{ + {17,ch53st0} +}; + +static const SFG_StrokeChar ch53 = {104.762f,1,ch53st}; + +/* char: 0x36 */ + +static const SFG_StrokeVertex ch54st0[] = +{ + {78.5714f,85.7143f}, + {73.8096f,95.2381f}, + {59.5238f,100.0f}, + {50.0f,100.0f}, + {35.7143f,95.2381f}, + {26.1905f,80.9524f}, + {21.4286f,57.1429f}, + {21.4286f,33.3333f}, + {26.1905f,14.2857f}, + {35.7143f,4.7619f}, + {50.0f,0.0f}, + {54.7619f,0.0f}, + {69.0476f,4.7619f}, + {78.5714f,14.2857f}, + {83.3334f,28.5714f}, + {83.3334f,33.3333f}, + {78.5714f,47.619f}, + {69.0476f,57.1429f}, + {54.7619f,61.9048f}, + {50.0f,61.9048f}, + {35.7143f,57.1429f}, + {26.1905f,47.619f}, + {21.4286f,33.3333f} +}; + +static const SFG_StrokeStrip ch54st[] = +{ + {23,ch54st0} +}; + +static const SFG_StrokeChar ch54 = {104.762f,1,ch54st}; + +/* char: 0x37 */ + +static const SFG_StrokeVertex ch55st0[] = +{ + {85.7143f,100.0f}, + {38.0952f,0.0f} +}; + +static const SFG_StrokeVertex ch55st1[] = +{ + {19.0476f,100.0f}, + {85.7143f,100.0f} +}; + +static const SFG_StrokeStrip ch55st[] = +{ + {2,ch55st0}, + {2,ch55st1} +}; + +static const SFG_StrokeChar ch55 = {104.762f,2,ch55st}; + +/* char: 0x38 */ + +static const SFG_StrokeVertex ch56st0[] = +{ + {42.8571f,100.0f}, + {28.5714f,95.2381f}, + {23.8095f,85.7143f}, + {23.8095f,76.1905f}, + {28.5714f,66.6667f}, + {38.0952f,61.9048f}, + {57.1428f,57.1429f}, + {71.4286f,52.381f}, + {80.9524f,42.8571f}, + {85.7143f,33.3333f}, + {85.7143f,19.0476f}, + {80.9524f,9.5238f}, + {76.1905f,4.7619f}, + {61.9047f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {23.8095f,9.5238f}, + {19.0476f,19.0476f}, + {19.0476f,33.3333f}, + {23.8095f,42.8571f}, + {33.3333f,52.381f}, + {47.619f,57.1429f}, + {66.6666f,61.9048f}, + {76.1905f,66.6667f}, + {80.9524f,76.1905f}, + {80.9524f,85.7143f}, + {76.1905f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f} +}; + +static const SFG_StrokeStrip ch56st[] = +{ + {29,ch56st0} +}; + +static const SFG_StrokeChar ch56 = {104.762f,1,ch56st}; + +/* char: 0x39 */ + +static const SFG_StrokeVertex ch57st0[] = +{ + {83.3334f,66.6667f}, + {78.5714f,52.381f}, + {69.0476f,42.8571f}, + {54.7619f,38.0952f}, + {50.0f,38.0952f}, + {35.7143f,42.8571f}, + {26.1905f,52.381f}, + {21.4286f,66.6667f}, + {21.4286f,71.4286f}, + {26.1905f,85.7143f}, + {35.7143f,95.2381f}, + {50.0f,100.0f}, + {54.7619f,100.0f}, + {69.0476f,95.2381f}, + {78.5714f,85.7143f}, + {83.3334f,66.6667f}, + {83.3334f,42.8571f}, + {78.5714f,19.0476f}, + {69.0476f,4.7619f}, + {54.7619f,0.0f}, + {45.2381f,0.0f}, + {30.9524f,4.7619f}, + {26.1905f,14.2857f} +}; + +static const SFG_StrokeStrip ch57st[] = +{ + {23,ch57st0} +}; + +static const SFG_StrokeChar ch57 = {104.762f,1,ch57st}; + +/* char: 0x3a */ + +static const SFG_StrokeVertex ch58st0[] = +{ + {52.381f,66.6667f}, + {47.6191f,61.9048f}, + {52.381f,57.1429f}, + {57.1429f,61.9048f}, + {52.381f,66.6667f} +}; + +static const SFG_StrokeVertex ch58st1[] = +{ + {52.381f,9.5238f}, + {47.6191f,4.7619f}, + {52.381f,0.0f}, + {57.1429f,4.7619f}, + {52.381f,9.5238f} +}; + +static const SFG_StrokeStrip ch58st[] = +{ + {5,ch58st0}, + {5,ch58st1} +}; + +static const SFG_StrokeChar ch58 = {104.762f,2,ch58st}; + +/* char: 0x3b */ + +static const SFG_StrokeVertex ch59st0[] = +{ + {52.381f,66.6667f}, + {47.6191f,61.9048f}, + {52.381f,57.1429f}, + {57.1429f,61.9048f}, + {52.381f,66.6667f} +}; + +static const SFG_StrokeVertex ch59st1[] = +{ + {57.1429f,4.7619f}, + {52.381f,0.0f}, + {47.6191f,4.7619f}, + {52.381f,9.5238f}, + {57.1429f,4.7619f}, + {57.1429f,-4.7619f}, + {52.381f,-14.2857f}, + {47.6191f,-19.0476f} +}; + +static const SFG_StrokeStrip ch59st[] = +{ + {5,ch59st0}, + {8,ch59st1} +}; + +static const SFG_StrokeChar ch59 = {104.762f,2,ch59st}; + +/* char: 0x3c */ + +static const SFG_StrokeVertex ch60st0[] = +{ + {90.4762f,85.7143f}, + {14.2857f,42.8571f}, + {90.4762f,0.0f} +}; + +static const SFG_StrokeStrip ch60st[] = +{ + {3,ch60st0} +}; + +static const SFG_StrokeChar ch60 = {104.762f,1,ch60st}; + +/* char: 0x3d */ + +static const SFG_StrokeVertex ch61st0[] = +{ + {9.5238f,57.1429f}, + {95.2381f,57.1429f} +}; + +static const SFG_StrokeVertex ch61st1[] = +{ + {9.5238f,28.5714f}, + {95.2381f,28.5714f} +}; + +static const SFG_StrokeStrip ch61st[] = +{ + {2,ch61st0}, + {2,ch61st1} +}; + +static const SFG_StrokeChar ch61 = {104.762f,2,ch61st}; + +/* char: 0x3e */ + +static const SFG_StrokeVertex ch62st0[] = +{ + {14.2857f,85.7143f}, + {90.4762f,42.8571f}, + {14.2857f,0.0f} +}; + +static const SFG_StrokeStrip ch62st[] = +{ + {3,ch62st0} +}; + +static const SFG_StrokeChar ch62 = {104.762f,1,ch62st}; + +/* char: 0x3f */ + +static const SFG_StrokeVertex ch63st0[] = +{ + {23.8095f,76.1905f}, + {23.8095f,80.9524f}, + {28.5714f,90.4762f}, + {33.3333f,95.2381f}, + {42.8571f,100.0f}, + {61.9047f,100.0f}, + {71.4285f,95.2381f}, + {76.1905f,90.4762f}, + {80.9524f,80.9524f}, + {80.9524f,71.4286f}, + {76.1905f,61.9048f}, + {71.4285f,57.1429f}, + {52.3809f,47.619f}, + {52.3809f,33.3333f} +}; + +static const SFG_StrokeVertex ch63st1[] = +{ + {52.3809f,9.5238f}, + {47.619f,4.7619f}, + {52.3809f,0.0f}, + {57.1428f,4.7619f}, + {52.3809f,9.5238f} +}; + +static const SFG_StrokeStrip ch63st[] = +{ + {14,ch63st0}, + {5,ch63st1} +}; + +static const SFG_StrokeChar ch63 = {104.762f,2,ch63st}; + +/* char: 0x40 */ + +static const SFG_StrokeVertex ch64st0[] = +{ + {64.2857f,52.381f}, + {54.7619f,57.1429f}, + {45.2381f,57.1429f}, + {40.4762f,47.619f}, + {40.4762f,42.8571f}, + {45.2381f,33.3333f}, + {54.7619f,33.3333f}, + {64.2857f,38.0952f} +}; + +static const SFG_StrokeVertex ch64st1[] = +{ + {64.2857f,57.1429f}, + {64.2857f,38.0952f}, + {69.0476f,33.3333f}, + {78.5714f,33.3333f}, + {83.3334f,42.8571f}, + {83.3334f,47.619f}, + {78.5714f,61.9048f}, + {69.0476f,71.4286f}, + {54.7619f,76.1905f}, + {50.0f,76.1905f}, + {35.7143f,71.4286f}, + {26.1905f,61.9048f}, + {21.4286f,47.619f}, + {21.4286f,42.8571f}, + {26.1905f,28.5714f}, + {35.7143f,19.0476f}, + {50.0f,14.2857f}, + {54.7619f,14.2857f}, + {69.0476f,19.0476f} +}; + +static const SFG_StrokeStrip ch64st[] = +{ + {8,ch64st0}, + {19,ch64st1} +}; + +static const SFG_StrokeChar ch64 = {104.762f,2,ch64st}; + +/* char: 0x41 */ + +static const SFG_StrokeVertex ch65st0[] = +{ + {52.3809f,100.0f}, + {14.2857f,0.0f} +}; + +static const SFG_StrokeVertex ch65st1[] = +{ + {52.3809f,100.0f}, + {90.4762f,0.0f} +}; + +static const SFG_StrokeVertex ch65st2[] = +{ + {28.5714f,33.3333f}, + {76.1905f,33.3333f} +}; + +static const SFG_StrokeStrip ch65st[] = +{ + {2,ch65st0}, + {2,ch65st1}, + {2,ch65st2} +}; + +static const SFG_StrokeChar ch65 = {104.762f,3,ch65st}; + +/* char: 0x42 */ + +static const SFG_StrokeVertex ch66st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch66st1[] = +{ + {19.0476f,100.0f}, + {61.9047f,100.0f}, + {76.1905f,95.2381f}, + {80.9524f,90.4762f}, + {85.7143f,80.9524f}, + {85.7143f,71.4286f}, + {80.9524f,61.9048f}, + {76.1905f,57.1429f}, + {61.9047f,52.381f} +}; + +static const SFG_StrokeVertex ch66st2[] = +{ + {19.0476f,52.381f}, + {61.9047f,52.381f}, + {76.1905f,47.619f}, + {80.9524f,42.8571f}, + {85.7143f,33.3333f}, + {85.7143f,19.0476f}, + {80.9524f,9.5238f}, + {76.1905f,4.7619f}, + {61.9047f,0.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeStrip ch66st[] = +{ + {2,ch66st0}, + {9,ch66st1}, + {10,ch66st2} +}; + +static const SFG_StrokeChar ch66 = {104.762f,3,ch66st}; + +/* char: 0x43 */ + +static const SFG_StrokeVertex ch67st0[] = +{ + {88.0952f,76.1905f}, + {83.3334f,85.7143f}, + {73.8096f,95.2381f}, + {64.2857f,100.0f}, + {45.2381f,100.0f}, + {35.7143f,95.2381f}, + {26.1905f,85.7143f}, + {21.4286f,76.1905f}, + {16.6667f,61.9048f}, + {16.6667f,38.0952f}, + {21.4286f,23.8095f}, + {26.1905f,14.2857f}, + {35.7143f,4.7619f}, + {45.2381f,0.0f}, + {64.2857f,0.0f}, + {73.8096f,4.7619f}, + {83.3334f,14.2857f}, + {88.0952f,23.8095f} +}; + +static const SFG_StrokeStrip ch67st[] = +{ + {18,ch67st0} +}; + +static const SFG_StrokeChar ch67 = {104.762f,1,ch67st}; + +/* char: 0x44 */ + +static const SFG_StrokeVertex ch68st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch68st1[] = +{ + {19.0476f,100.0f}, + {52.3809f,100.0f}, + {66.6666f,95.2381f}, + {76.1905f,85.7143f}, + {80.9524f,76.1905f}, + {85.7143f,61.9048f}, + {85.7143f,38.0952f}, + {80.9524f,23.8095f}, + {76.1905f,14.2857f}, + {66.6666f,4.7619f}, + {52.3809f,0.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeStrip ch68st[] = +{ + {2,ch68st0}, + {12,ch68st1} +}; + +static const SFG_StrokeChar ch68 = {104.762f,2,ch68st}; + +/* char: 0x45 */ + +static const SFG_StrokeVertex ch69st0[] = +{ + {21.4286f,100.0f}, + {21.4286f,0.0f} +}; + +static const SFG_StrokeVertex ch69st1[] = +{ + {21.4286f,100.0f}, + {83.3334f,100.0f} +}; + +static const SFG_StrokeVertex ch69st2[] = +{ + {21.4286f,52.381f}, + {59.5238f,52.381f} +}; + +static const SFG_StrokeVertex ch69st3[] = +{ + {21.4286f,0.0f}, + {83.3334f,0.0f} +}; + +static const SFG_StrokeStrip ch69st[] = +{ + {2,ch69st0}, + {2,ch69st1}, + {2,ch69st2}, + {2,ch69st3} +}; + +static const SFG_StrokeChar ch69 = {104.762f,4,ch69st}; + +/* char: 0x46 */ + +static const SFG_StrokeVertex ch70st0[] = +{ + {21.4286f,100.0f}, + {21.4286f,0.0f} +}; + +static const SFG_StrokeVertex ch70st1[] = +{ + {21.4286f,100.0f}, + {83.3334f,100.0f} +}; + +static const SFG_StrokeVertex ch70st2[] = +{ + {21.4286f,52.381f}, + {59.5238f,52.381f} +}; + +static const SFG_StrokeStrip ch70st[] = +{ + {2,ch70st0}, + {2,ch70st1}, + {2,ch70st2} +}; + +static const SFG_StrokeChar ch70 = {104.762f,3,ch70st}; + +/* char: 0x47 */ + +static const SFG_StrokeVertex ch71st0[] = +{ + {88.0952f,76.1905f}, + {83.3334f,85.7143f}, + {73.8096f,95.2381f}, + {64.2857f,100.0f}, + {45.2381f,100.0f}, + {35.7143f,95.2381f}, + {26.1905f,85.7143f}, + {21.4286f,76.1905f}, + {16.6667f,61.9048f}, + {16.6667f,38.0952f}, + {21.4286f,23.8095f}, + {26.1905f,14.2857f}, + {35.7143f,4.7619f}, + {45.2381f,0.0f}, + {64.2857f,0.0f}, + {73.8096f,4.7619f}, + {83.3334f,14.2857f}, + {88.0952f,23.8095f}, + {88.0952f,38.0952f} +}; + +static const SFG_StrokeVertex ch71st1[] = +{ + {64.2857f,38.0952f}, + {88.0952f,38.0952f} +}; + +static const SFG_StrokeStrip ch71st[] = +{ + {19,ch71st0}, + {2,ch71st1} +}; + +static const SFG_StrokeChar ch71 = {104.762f,2,ch71st}; + +/* char: 0x48 */ + +static const SFG_StrokeVertex ch72st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch72st1[] = +{ + {85.7143f,100.0f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeVertex ch72st2[] = +{ + {19.0476f,52.381f}, + {85.7143f,52.381f} +}; + +static const SFG_StrokeStrip ch72st[] = +{ + {2,ch72st0}, + {2,ch72st1}, + {2,ch72st2} +}; + +static const SFG_StrokeChar ch72 = {104.762f,3,ch72st}; + +/* char: 0x49 */ + +static const SFG_StrokeVertex ch73st0[] = +{ + {52.381f,100.0f}, + {52.381f,0.0f} +}; + +static const SFG_StrokeStrip ch73st[] = +{ + {2,ch73st0} +}; + +static const SFG_StrokeChar ch73 = {104.762f,1,ch73st}; + +/* char: 0x4a */ + +static const SFG_StrokeVertex ch74st0[] = +{ + {76.1905f,100.0f}, + {76.1905f,23.8095f}, + {71.4286f,9.5238f}, + {66.6667f,4.7619f}, + {57.1429f,0.0f}, + {47.6191f,0.0f}, + {38.0953f,4.7619f}, + {33.3334f,9.5238f}, + {28.5715f,23.8095f}, + {28.5715f,33.3333f} +}; + +static const SFG_StrokeStrip ch74st[] = +{ + {10,ch74st0} +}; + +static const SFG_StrokeChar ch74 = {104.762f,1,ch74st}; + +/* char: 0x4b */ + +static const SFG_StrokeVertex ch75st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch75st1[] = +{ + {85.7143f,100.0f}, + {19.0476f,33.3333f} +}; + +static const SFG_StrokeVertex ch75st2[] = +{ + {42.8571f,57.1429f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeStrip ch75st[] = +{ + {2,ch75st0}, + {2,ch75st1}, + {2,ch75st2} +}; + +static const SFG_StrokeChar ch75 = {104.762f,3,ch75st}; + +/* char: 0x4c */ + +static const SFG_StrokeVertex ch76st0[] = +{ + {23.8095f,100.0f}, + {23.8095f,0.0f} +}; + +static const SFG_StrokeVertex ch76st1[] = +{ + {23.8095f,0.0f}, + {80.9524f,0.0f} +}; + +static const SFG_StrokeStrip ch76st[] = +{ + {2,ch76st0}, + {2,ch76st1} +}; + +static const SFG_StrokeChar ch76 = {104.762f,2,ch76st}; + +/* char: 0x4d */ + +static const SFG_StrokeVertex ch77st0[] = +{ + {14.2857f,100.0f}, + {14.2857f,0.0f} +}; + +static const SFG_StrokeVertex ch77st1[] = +{ + {14.2857f,100.0f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeVertex ch77st2[] = +{ + {90.4762f,100.0f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeVertex ch77st3[] = +{ + {90.4762f,100.0f}, + {90.4762f,0.0f} +}; + +static const SFG_StrokeStrip ch77st[] = +{ + {2,ch77st0}, + {2,ch77st1}, + {2,ch77st2}, + {2,ch77st3} +}; + +static const SFG_StrokeChar ch77 = {104.762f,4,ch77st}; + +/* char: 0x4e */ + +static const SFG_StrokeVertex ch78st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch78st1[] = +{ + {19.0476f,100.0f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeVertex ch78st2[] = +{ + {85.7143f,100.0f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeStrip ch78st[] = +{ + {2,ch78st0}, + {2,ch78st1}, + {2,ch78st2} +}; + +static const SFG_StrokeChar ch78 = {104.762f,3,ch78st}; + +/* char: 0x4f */ + +static const SFG_StrokeVertex ch79st0[] = +{ + {42.8571f,100.0f}, + {33.3333f,95.2381f}, + {23.8095f,85.7143f}, + {19.0476f,76.1905f}, + {14.2857f,61.9048f}, + {14.2857f,38.0952f}, + {19.0476f,23.8095f}, + {23.8095f,14.2857f}, + {33.3333f,4.7619f}, + {42.8571f,0.0f}, + {61.9047f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,14.2857f}, + {85.7143f,23.8095f}, + {90.4762f,38.0952f}, + {90.4762f,61.9048f}, + {85.7143f,76.1905f}, + {80.9524f,85.7143f}, + {71.4286f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f} +}; + +static const SFG_StrokeStrip ch79st[] = +{ + {21,ch79st0} +}; + +static const SFG_StrokeChar ch79 = {104.762f,1,ch79st}; + +/* char: 0x50 */ + +static const SFG_StrokeVertex ch80st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch80st1[] = +{ + {19.0476f,100.0f}, + {61.9047f,100.0f}, + {76.1905f,95.2381f}, + {80.9524f,90.4762f}, + {85.7143f,80.9524f}, + {85.7143f,66.6667f}, + {80.9524f,57.1429f}, + {76.1905f,52.381f}, + {61.9047f,47.619f}, + {19.0476f,47.619f} +}; + +static const SFG_StrokeStrip ch80st[] = +{ + {2,ch80st0}, + {10,ch80st1} +}; + +static const SFG_StrokeChar ch80 = {104.762f,2,ch80st}; + +/* char: 0x51 */ + +static const SFG_StrokeVertex ch81st0[] = +{ + {42.8571f,100.0f}, + {33.3333f,95.2381f}, + {23.8095f,85.7143f}, + {19.0476f,76.1905f}, + {14.2857f,61.9048f}, + {14.2857f,38.0952f}, + {19.0476f,23.8095f}, + {23.8095f,14.2857f}, + {33.3333f,4.7619f}, + {42.8571f,0.0f}, + {61.9047f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,14.2857f}, + {85.7143f,23.8095f}, + {90.4762f,38.0952f}, + {90.4762f,61.9048f}, + {85.7143f,76.1905f}, + {80.9524f,85.7143f}, + {71.4286f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f} +}; + +static const SFG_StrokeVertex ch81st1[] = +{ + {57.1428f,19.0476f}, + {85.7143f,-9.5238f} +}; + +static const SFG_StrokeStrip ch81st[] = +{ + {21,ch81st0}, + {2,ch81st1} +}; + +static const SFG_StrokeChar ch81 = {104.762f,2,ch81st}; + +/* char: 0x52 */ + +static const SFG_StrokeVertex ch82st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch82st1[] = +{ + {19.0476f,100.0f}, + {61.9047f,100.0f}, + {76.1905f,95.2381f}, + {80.9524f,90.4762f}, + {85.7143f,80.9524f}, + {85.7143f,71.4286f}, + {80.9524f,61.9048f}, + {76.1905f,57.1429f}, + {61.9047f,52.381f}, + {19.0476f,52.381f} +}; + +static const SFG_StrokeVertex ch82st2[] = +{ + {52.3809f,52.381f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeStrip ch82st[] = +{ + {2,ch82st0}, + {10,ch82st1}, + {2,ch82st2} +}; + +static const SFG_StrokeChar ch82 = {104.762f,3,ch82st}; + +/* char: 0x53 */ + +static const SFG_StrokeVertex ch83st0[] = +{ + {85.7143f,85.7143f}, + {76.1905f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f}, + {28.5714f,95.2381f}, + {19.0476f,85.7143f}, + {19.0476f,76.1905f}, + {23.8095f,66.6667f}, + {28.5714f,61.9048f}, + {38.0952f,57.1429f}, + {66.6666f,47.619f}, + {76.1905f,42.8571f}, + {80.9524f,38.0952f}, + {85.7143f,28.5714f}, + {85.7143f,14.2857f}, + {76.1905f,4.7619f}, + {61.9047f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {19.0476f,14.2857f} +}; + +static const SFG_StrokeStrip ch83st[] = +{ + {20,ch83st0} +}; + +static const SFG_StrokeChar ch83 = {104.762f,1,ch83st}; + +/* char: 0x54 */ + +static const SFG_StrokeVertex ch84st0[] = +{ + {52.3809f,100.0f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeVertex ch84st1[] = +{ + {19.0476f,100.0f}, + {85.7143f,100.0f} +}; + +static const SFG_StrokeStrip ch84st[] = +{ + {2,ch84st0}, + {2,ch84st1} +}; + +static const SFG_StrokeChar ch84 = {104.762f,2,ch84st}; + +/* char: 0x55 */ + +static const SFG_StrokeVertex ch85st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,28.5714f}, + {23.8095f,14.2857f}, + {33.3333f,4.7619f}, + {47.619f,0.0f}, + {57.1428f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,14.2857f}, + {85.7143f,28.5714f}, + {85.7143f,100.0f} +}; + +static const SFG_StrokeStrip ch85st[] = +{ + {10,ch85st0} +}; + +static const SFG_StrokeChar ch85 = {104.762f,1,ch85st}; + +/* char: 0x56 */ + +static const SFG_StrokeVertex ch86st0[] = +{ + {14.2857f,100.0f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeVertex ch86st1[] = +{ + {90.4762f,100.0f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeStrip ch86st[] = +{ + {2,ch86st0}, + {2,ch86st1} +}; + +static const SFG_StrokeChar ch86 = {104.762f,2,ch86st}; + +/* char: 0x57 */ + +static const SFG_StrokeVertex ch87st0[] = +{ + {4.7619f,100.0f}, + {28.5714f,0.0f} +}; + +static const SFG_StrokeVertex ch87st1[] = +{ + {52.3809f,100.0f}, + {28.5714f,0.0f} +}; + +static const SFG_StrokeVertex ch87st2[] = +{ + {52.3809f,100.0f}, + {76.1905f,0.0f} +}; + +static const SFG_StrokeVertex ch87st3[] = +{ + {100.0f,100.0f}, + {76.1905f,0.0f} +}; + +static const SFG_StrokeStrip ch87st[] = +{ + {2,ch87st0}, + {2,ch87st1}, + {2,ch87st2}, + {2,ch87st3} +}; + +static const SFG_StrokeChar ch87 = {104.762f,4,ch87st}; + +/* char: 0x58 */ + +static const SFG_StrokeVertex ch88st0[] = +{ + {19.0476f,100.0f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeVertex ch88st1[] = +{ + {85.7143f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeStrip ch88st[] = +{ + {2,ch88st0}, + {2,ch88st1} +}; + +static const SFG_StrokeChar ch88 = {104.762f,2,ch88st}; + +/* char: 0x59 */ + +static const SFG_StrokeVertex ch89st0[] = +{ + {14.2857f,100.0f}, + {52.3809f,52.381f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeVertex ch89st1[] = +{ + {90.4762f,100.0f}, + {52.3809f,52.381f} +}; + +static const SFG_StrokeStrip ch89st[] = +{ + {3,ch89st0}, + {2,ch89st1} +}; + +static const SFG_StrokeChar ch89 = {104.762f,2,ch89st}; + +/* char: 0x5a */ + +static const SFG_StrokeVertex ch90st0[] = +{ + {85.7143f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch90st1[] = +{ + {19.0476f,100.0f}, + {85.7143f,100.0f} +}; + +static const SFG_StrokeVertex ch90st2[] = +{ + {19.0476f,0.0f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeStrip ch90st[] = +{ + {2,ch90st0}, + {2,ch90st1}, + {2,ch90st2} +}; + +static const SFG_StrokeChar ch90 = {104.762f,3,ch90st}; + +/* char: 0x5b */ + +static const SFG_StrokeVertex ch91st0[] = +{ + {35.7143f,119.048f}, + {35.7143f,-33.3333f} +}; + +static const SFG_StrokeVertex ch91st1[] = +{ + {40.4762f,119.048f}, + {40.4762f,-33.3333f} +}; + +static const SFG_StrokeVertex ch91st2[] = +{ + {35.7143f,119.048f}, + {69.0476f,119.048f} +}; + +static const SFG_StrokeVertex ch91st3[] = +{ + {35.7143f,-33.3333f}, + {69.0476f,-33.3333f} +}; + +static const SFG_StrokeStrip ch91st[] = +{ + {2,ch91st0}, + {2,ch91st1}, + {2,ch91st2}, + {2,ch91st3} +}; + +static const SFG_StrokeChar ch91 = {104.762f,4,ch91st}; + +/* char: 0x5c */ + +static const SFG_StrokeVertex ch92st0[] = +{ + {19.0476f,100.0f}, + {85.7143f,-14.2857f} +}; + +static const SFG_StrokeStrip ch92st[] = +{ + {2,ch92st0} +}; + +static const SFG_StrokeChar ch92 = {104.762f,1,ch92st}; + +/* char: 0x5d */ + +static const SFG_StrokeVertex ch93st0[] = +{ + {64.2857f,119.048f}, + {64.2857f,-33.3333f} +}; + +static const SFG_StrokeVertex ch93st1[] = +{ + {69.0476f,119.048f}, + {69.0476f,-33.3333f} +}; + +static const SFG_StrokeVertex ch93st2[] = +{ + {35.7143f,119.048f}, + {69.0476f,119.048f} +}; + +static const SFG_StrokeVertex ch93st3[] = +{ + {35.7143f,-33.3333f}, + {69.0476f,-33.3333f} +}; + +static const SFG_StrokeStrip ch93st[] = +{ + {2,ch93st0}, + {2,ch93st1}, + {2,ch93st2}, + {2,ch93st3} +}; + +static const SFG_StrokeChar ch93 = {104.762f,4,ch93st}; + +/* char: 0x5e */ + +static const SFG_StrokeVertex ch94st0[] = +{ + {52.3809f,109.524f}, + {14.2857f,42.8571f} +}; + +static const SFG_StrokeVertex ch94st1[] = +{ + {52.3809f,109.524f}, + {90.4762f,42.8571f} +}; + +static const SFG_StrokeStrip ch94st[] = +{ + {2,ch94st0}, + {2,ch94st1} +}; + +static const SFG_StrokeChar ch94 = {104.762f,2,ch94st}; + +/* char: 0x5f */ + +static const SFG_StrokeVertex ch95st0[] = +{ + {0,-33.3333f}, + {104.762f,-33.3333f}, + {104.762f,-28.5714f}, + {0,-28.5714f}, + {0,-33.3333f} +}; + +static const SFG_StrokeStrip ch95st[] = +{ + {5,ch95st0} +}; + +static const SFG_StrokeChar ch95 = {104.762f,1,ch95st}; + +/* char: 0x60 */ + +static const SFG_StrokeVertex ch96st0[] = +{ + {42.8572f,100.0f}, + {66.6667f,71.4286f} +}; + +static const SFG_StrokeVertex ch96st1[] = +{ + {42.8572f,100.0f}, + {38.0953f,95.2381f}, + {66.6667f,71.4286f} +}; + +static const SFG_StrokeStrip ch96st[] = +{ + {2,ch96st0}, + {3,ch96st1} +}; + +static const SFG_StrokeChar ch96 = {104.762f,2,ch96st}; + +/* char: 0x61 */ + +static const SFG_StrokeVertex ch97st0[] = +{ + {80.9524f,66.6667f}, + {80.9524f,0.0f} +}; + +static const SFG_StrokeVertex ch97st1[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const SFG_StrokeStrip ch97st[] = +{ + {2,ch97st0}, + {14,ch97st1} +}; + +static const SFG_StrokeChar ch97 = {104.762f,2,ch97st}; + +/* char: 0x62 */ + +static const SFG_StrokeVertex ch98st0[] = +{ + {23.8095f,100.0f}, + {23.8095f,0.0f} +}; + +static const SFG_StrokeVertex ch98st1[] = +{ + {23.8095f,52.381f}, + {33.3333f,61.9048f}, + {42.8571f,66.6667f}, + {57.1428f,66.6667f}, + {66.6666f,61.9048f}, + {76.1905f,52.381f}, + {80.9524f,38.0952f}, + {80.9524f,28.5714f}, + {76.1905f,14.2857f}, + {66.6666f,4.7619f}, + {57.1428f,0.0f}, + {42.8571f,0.0f}, + {33.3333f,4.7619f}, + {23.8095f,14.2857f} +}; + +static const SFG_StrokeStrip ch98st[] = +{ + {2,ch98st0}, + {14,ch98st1} +}; + +static const SFG_StrokeChar ch98 = {104.762f,2,ch98st}; + +/* char: 0x63 */ + +static const SFG_StrokeVertex ch99st0[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const SFG_StrokeStrip ch99st[] = +{ + {14,ch99st0} +}; + +static const SFG_StrokeChar ch99 = {104.762f,1,ch99st}; + +/* char: 0x64 */ + +static const SFG_StrokeVertex ch100st0[] = +{ + {80.9524f,100.0f}, + {80.9524f,0.0f} +}; + +static const SFG_StrokeVertex ch100st1[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const SFG_StrokeStrip ch100st[] = +{ + {2,ch100st0}, + {14,ch100st1} +}; + +static const SFG_StrokeChar ch100 = {104.762f,2,ch100st}; + +/* char: 0x65 */ + +static const SFG_StrokeVertex ch101st0[] = +{ + {23.8095f,38.0952f}, + {80.9524f,38.0952f}, + {80.9524f,47.619f}, + {76.1905f,57.1429f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const SFG_StrokeStrip ch101st[] = +{ + {17,ch101st0} +}; + +static const SFG_StrokeChar ch101 = {104.762f,1,ch101st}; + +/* char: 0x66 */ + +static const SFG_StrokeVertex ch102st0[] = +{ + {71.4286f,100.0f}, + {61.9048f,100.0f}, + {52.381f,95.2381f}, + {47.6191f,80.9524f}, + {47.6191f,0.0f} +}; + +static const SFG_StrokeVertex ch102st1[] = +{ + {33.3334f,66.6667f}, + {66.6667f,66.6667f} +}; + +static const SFG_StrokeStrip ch102st[] = +{ + {5,ch102st0}, + {2,ch102st1} +}; + +static const SFG_StrokeChar ch102 = {104.762f,2,ch102st}; + +/* char: 0x67 */ + +static const SFG_StrokeVertex ch103st0[] = +{ + {80.9524f,66.6667f}, + {80.9524f,-9.5238f}, + {76.1905f,-23.8095f}, + {71.4285f,-28.5714f}, + {61.9047f,-33.3333f}, + {47.619f,-33.3333f}, + {38.0952f,-28.5714f} +}; + +static const SFG_StrokeVertex ch103st1[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const SFG_StrokeStrip ch103st[] = +{ + {7,ch103st0}, + {14,ch103st1} +}; + +static const SFG_StrokeChar ch103 = {104.762f,2,ch103st}; + +/* char: 0x68 */ + +static const SFG_StrokeVertex ch104st0[] = +{ + {26.1905f,100.0f}, + {26.1905f,0.0f} +}; + +static const SFG_StrokeVertex ch104st1[] = +{ + {26.1905f,47.619f}, + {40.4762f,61.9048f}, + {50.0f,66.6667f}, + {64.2857f,66.6667f}, + {73.8095f,61.9048f}, + {78.5715f,47.619f}, + {78.5715f,0.0f} +}; + +static const SFG_StrokeStrip ch104st[] = +{ + {2,ch104st0}, + {7,ch104st1} +}; + +static const SFG_StrokeChar ch104 = {104.762f,2,ch104st}; + +/* char: 0x69 */ + +static const SFG_StrokeVertex ch105st0[] = +{ + {47.6191f,100.0f}, + {52.381f,95.2381f}, + {57.1429f,100.0f}, + {52.381f,104.762f}, + {47.6191f,100.0f} +}; + +static const SFG_StrokeVertex ch105st1[] = +{ + {52.381f,66.6667f}, + {52.381f,0.0f} +}; + +static const SFG_StrokeStrip ch105st[] = +{ + {5,ch105st0}, + {2,ch105st1} +}; + +static const SFG_StrokeChar ch105 = {104.762f,2,ch105st}; + +/* char: 0x6a */ + +static const SFG_StrokeVertex ch106st0[] = +{ + {57.1429f,100.0f}, + {61.9048f,95.2381f}, + {66.6667f,100.0f}, + {61.9048f,104.762f}, + {57.1429f,100.0f} +}; + +static const SFG_StrokeVertex ch106st1[] = +{ + {61.9048f,66.6667f}, + {61.9048f,-14.2857f}, + {57.1429f,-28.5714f}, + {47.6191f,-33.3333f}, + {38.0953f,-33.3333f} +}; + +static const SFG_StrokeStrip ch106st[] = +{ + {5,ch106st0}, + {5,ch106st1} +}; + +static const SFG_StrokeChar ch106 = {104.762f,2,ch106st}; + +/* char: 0x6b */ + +static const SFG_StrokeVertex ch107st0[] = +{ + {26.1905f,100.0f}, + {26.1905f,0.0f} +}; + +static const SFG_StrokeVertex ch107st1[] = +{ + {73.8095f,66.6667f}, + {26.1905f,19.0476f} +}; + +static const SFG_StrokeVertex ch107st2[] = +{ + {45.2381f,38.0952f}, + {78.5715f,0.0f} +}; + +static const SFG_StrokeStrip ch107st[] = +{ + {2,ch107st0}, + {2,ch107st1}, + {2,ch107st2} +}; + +static const SFG_StrokeChar ch107 = {104.762f,3,ch107st}; + +/* char: 0x6c */ + +static const SFG_StrokeVertex ch108st0[] = +{ + {52.381f,100.0f}, + {52.381f,0.0f} +}; + +static const SFG_StrokeStrip ch108st[] = +{ + {2,ch108st0} +}; + +static const SFG_StrokeChar ch108 = {104.762f,1,ch108st}; + +/* char: 0x6d */ + +static const SFG_StrokeVertex ch109st0[] = +{ + {0,66.6667f}, + {0,0.0f} +}; + +static const SFG_StrokeVertex ch109st1[] = +{ + {0,47.619f}, + {14.2857f,61.9048f}, + {23.8095f,66.6667f}, + {38.0952f,66.6667f}, + {47.619f,61.9048f}, + {52.381f,47.619f}, + {52.381f,0.0f} +}; + +static const SFG_StrokeVertex ch109st2[] = +{ + {52.381f,47.619f}, + {66.6667f,61.9048f}, + {76.1905f,66.6667f}, + {90.4762f,66.6667f}, + {100.0f,61.9048f}, + {104.762f,47.619f}, + {104.762f,0.0f} +}; + +static const SFG_StrokeStrip ch109st[] = +{ + {2,ch109st0}, + {7,ch109st1}, + {7,ch109st2} +}; + +static const SFG_StrokeChar ch109 = {104.762f,3,ch109st}; + +/* char: 0x6e */ + +static const SFG_StrokeVertex ch110st0[] = +{ + {26.1905f,66.6667f}, + {26.1905f,0.0f} +}; + +static const SFG_StrokeVertex ch110st1[] = +{ + {26.1905f,47.619f}, + {40.4762f,61.9048f}, + {50.0f,66.6667f}, + {64.2857f,66.6667f}, + {73.8095f,61.9048f}, + {78.5715f,47.619f}, + {78.5715f,0.0f} +}; + +static const SFG_StrokeStrip ch110st[] = +{ + {2,ch110st0}, + {7,ch110st1} +}; + +static const SFG_StrokeChar ch110 = {104.762f,2,ch110st}; + +/* char: 0x6f */ + +static const SFG_StrokeVertex ch111st0[] = +{ + {45.2381f,66.6667f}, + {35.7143f,61.9048f}, + {26.1905f,52.381f}, + {21.4286f,38.0952f}, + {21.4286f,28.5714f}, + {26.1905f,14.2857f}, + {35.7143f,4.7619f}, + {45.2381f,0.0f}, + {59.5238f,0.0f}, + {69.0476f,4.7619f}, + {78.5714f,14.2857f}, + {83.3334f,28.5714f}, + {83.3334f,38.0952f}, + {78.5714f,52.381f}, + {69.0476f,61.9048f}, + {59.5238f,66.6667f}, + {45.2381f,66.6667f} +}; + +static const SFG_StrokeStrip ch111st[] = +{ + {17,ch111st0} +}; + +static const SFG_StrokeChar ch111 = {104.762f,1,ch111st}; + +/* char: 0x70 */ + +static const SFG_StrokeVertex ch112st0[] = +{ + {23.8095f,66.6667f}, + {23.8095f,-33.3333f} +}; + +static const SFG_StrokeVertex ch112st1[] = +{ + {23.8095f,52.381f}, + {33.3333f,61.9048f}, + {42.8571f,66.6667f}, + {57.1428f,66.6667f}, + {66.6666f,61.9048f}, + {76.1905f,52.381f}, + {80.9524f,38.0952f}, + {80.9524f,28.5714f}, + {76.1905f,14.2857f}, + {66.6666f,4.7619f}, + {57.1428f,0.0f}, + {42.8571f,0.0f}, + {33.3333f,4.7619f}, + {23.8095f,14.2857f} +}; + +static const SFG_StrokeStrip ch112st[] = +{ + {2,ch112st0}, + {14,ch112st1} +}; + +static const SFG_StrokeChar ch112 = {104.762f,2,ch112st}; + +/* char: 0x71 */ + +static const SFG_StrokeVertex ch113st0[] = +{ + {80.9524f,66.6667f}, + {80.9524f,-33.3333f} +}; + +static const SFG_StrokeVertex ch113st1[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const SFG_StrokeStrip ch113st[] = +{ + {2,ch113st0}, + {14,ch113st1} +}; + +static const SFG_StrokeChar ch113 = {104.762f,2,ch113st}; + +/* char: 0x72 */ + +static const SFG_StrokeVertex ch114st0[] = +{ + {33.3334f,66.6667f}, + {33.3334f,0.0f} +}; + +static const SFG_StrokeVertex ch114st1[] = +{ + {33.3334f,38.0952f}, + {38.0953f,52.381f}, + {47.6191f,61.9048f}, + {57.1429f,66.6667f}, + {71.4286f,66.6667f} +}; + +static const SFG_StrokeStrip ch114st[] = +{ + {2,ch114st0}, + {5,ch114st1} +}; + +static const SFG_StrokeChar ch114 = {104.762f,2,ch114st}; + +/* char: 0x73 */ + +static const SFG_StrokeVertex ch115st0[] = +{ + {78.5715f,52.381f}, + {73.8095f,61.9048f}, + {59.5238f,66.6667f}, + {45.2381f,66.6667f}, + {30.9524f,61.9048f}, + {26.1905f,52.381f}, + {30.9524f,42.8571f}, + {40.4762f,38.0952f}, + {64.2857f,33.3333f}, + {73.8095f,28.5714f}, + {78.5715f,19.0476f}, + {78.5715f,14.2857f}, + {73.8095f,4.7619f}, + {59.5238f,0.0f}, + {45.2381f,0.0f}, + {30.9524f,4.7619f}, + {26.1905f,14.2857f} +}; + +static const SFG_StrokeStrip ch115st[] = +{ + {17,ch115st0} +}; + +static const SFG_StrokeChar ch115 = {104.762f,1,ch115st}; + +/* char: 0x74 */ + +static const SFG_StrokeVertex ch116st0[] = +{ + {47.6191f,100.0f}, + {47.6191f,19.0476f}, + {52.381f,4.7619f}, + {61.9048f,0.0f}, + {71.4286f,0.0f} +}; + +static const SFG_StrokeVertex ch116st1[] = +{ + {33.3334f,66.6667f}, + {66.6667f,66.6667f} +}; + +static const SFG_StrokeStrip ch116st[] = +{ + {5,ch116st0}, + {2,ch116st1} +}; + +static const SFG_StrokeChar ch116 = {104.762f,2,ch116st}; + +/* char: 0x75 */ + +static const SFG_StrokeVertex ch117st0[] = +{ + {26.1905f,66.6667f}, + {26.1905f,19.0476f}, + {30.9524f,4.7619f}, + {40.4762f,0.0f}, + {54.7619f,0.0f}, + {64.2857f,4.7619f}, + {78.5715f,19.0476f} +}; + +static const SFG_StrokeVertex ch117st1[] = +{ + {78.5715f,66.6667f}, + {78.5715f,0.0f} +}; + +static const SFG_StrokeStrip ch117st[] = +{ + {7,ch117st0}, + {2,ch117st1} +}; + +static const SFG_StrokeChar ch117 = {104.762f,2,ch117st}; + +/* char: 0x76 */ + +static const SFG_StrokeVertex ch118st0[] = +{ + {23.8095f,66.6667f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeVertex ch118st1[] = +{ + {80.9524f,66.6667f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeStrip ch118st[] = +{ + {2,ch118st0}, + {2,ch118st1} +}; + +static const SFG_StrokeChar ch118 = {104.762f,2,ch118st}; + +/* char: 0x77 */ + +static const SFG_StrokeVertex ch119st0[] = +{ + {14.2857f,66.6667f}, + {33.3333f,0.0f} +}; + +static const SFG_StrokeVertex ch119st1[] = +{ + {52.3809f,66.6667f}, + {33.3333f,0.0f} +}; + +static const SFG_StrokeVertex ch119st2[] = +{ + {52.3809f,66.6667f}, + {71.4286f,0.0f} +}; + +static const SFG_StrokeVertex ch119st3[] = +{ + {90.4762f,66.6667f}, + {71.4286f,0.0f} +}; + +static const SFG_StrokeStrip ch119st[] = +{ + {2,ch119st0}, + {2,ch119st1}, + {2,ch119st2}, + {2,ch119st3} +}; + +static const SFG_StrokeChar ch119 = {104.762f,4,ch119st}; + +/* char: 0x78 */ + +static const SFG_StrokeVertex ch120st0[] = +{ + {26.1905f,66.6667f}, + {78.5715f,0.0f} +}; + +static const SFG_StrokeVertex ch120st1[] = +{ + {78.5715f,66.6667f}, + {26.1905f,0.0f} +}; + +static const SFG_StrokeStrip ch120st[] = +{ + {2,ch120st0}, + {2,ch120st1} +}; + +static const SFG_StrokeChar ch120 = {104.762f,2,ch120st}; + +/* char: 0x79 */ + +static const SFG_StrokeVertex ch121st0[] = +{ + {26.1905f,66.6667f}, + {54.7619f,0.0f} +}; + +static const SFG_StrokeVertex ch121st1[] = +{ + {83.3334f,66.6667f}, + {54.7619f,0.0f}, + {45.2381f,-19.0476f}, + {35.7143f,-28.5714f}, + {26.1905f,-33.3333f}, + {21.4286f,-33.3333f} +}; + +static const SFG_StrokeStrip ch121st[] = +{ + {2,ch121st0}, + {6,ch121st1} +}; + +static const SFG_StrokeChar ch121 = {104.762f,2,ch121st}; + +/* char: 0x7a */ + +static const SFG_StrokeVertex ch122st0[] = +{ + {78.5715f,66.6667f}, + {26.1905f,0.0f} +}; + +static const SFG_StrokeVertex ch122st1[] = +{ + {26.1905f,66.6667f}, + {78.5715f,66.6667f} +}; + +static const SFG_StrokeVertex ch122st2[] = +{ + {26.1905f,0.0f}, + {78.5715f,0.0f} +}; + +static const SFG_StrokeStrip ch122st[] = +{ + {2,ch122st0}, + {2,ch122st1}, + {2,ch122st2} +}; + +static const SFG_StrokeChar ch122 = {104.762f,3,ch122st}; + +/* char: 0x7b */ + +static const SFG_StrokeVertex ch123st0[] = +{ + {64.2857f,119.048f}, + {54.7619f,114.286f}, + {50.0f,109.524f}, + {45.2381f,100.0f}, + {45.2381f,90.4762f}, + {50.0f,80.9524f}, + {54.7619f,76.1905f}, + {59.5238f,66.6667f}, + {59.5238f,57.1429f}, + {50.0f,47.619f} +}; + +static const SFG_StrokeVertex ch123st1[] = +{ + {54.7619f,114.286f}, + {50.0f,104.762f}, + {50.0f,95.2381f}, + {54.7619f,85.7143f}, + {59.5238f,80.9524f}, + {64.2857f,71.4286f}, + {64.2857f,61.9048f}, + {59.5238f,52.381f}, + {40.4762f,42.8571f}, + {59.5238f,33.3333f}, + {64.2857f,23.8095f}, + {64.2857f,14.2857f}, + {59.5238f,4.7619f}, + {54.7619f,0.0f}, + {50.0f,-9.5238f}, + {50.0f,-19.0476f}, + {54.7619f,-28.5714f} +}; + +static const SFG_StrokeVertex ch123st2[] = +{ + {50.0f,38.0952f}, + {59.5238f,28.5714f}, + {59.5238f,19.0476f}, + {54.7619f,9.5238f}, + {50.0f,4.7619f}, + {45.2381f,-4.7619f}, + {45.2381f,-14.2857f}, + {50.0f,-23.8095f}, + {54.7619f,-28.5714f}, + {64.2857f,-33.3333f} +}; + +static const SFG_StrokeStrip ch123st[] = +{ + {10,ch123st0}, + {17,ch123st1}, + {10,ch123st2} +}; + +static const SFG_StrokeChar ch123 = {104.762f,3,ch123st}; + +/* char: 0x7c */ + +static const SFG_StrokeVertex ch124st0[] = +{ + {52.381f,119.048f}, + {52.381f,-33.3333f} +}; + +static const SFG_StrokeStrip ch124st[] = +{ + {2,ch124st0} +}; + +static const SFG_StrokeChar ch124 = {104.762f,1,ch124st}; + +/* char: 0x7d */ + +static const SFG_StrokeVertex ch125st0[] = +{ + {40.4762f,119.048f}, + {50.0f,114.286f}, + {54.7619f,109.524f}, + {59.5238f,100.0f}, + {59.5238f,90.4762f}, + {54.7619f,80.9524f}, + {50.0f,76.1905f}, + {45.2381f,66.6667f}, + {45.2381f,57.1429f}, + {54.7619f,47.619f} +}; + +static const SFG_StrokeVertex ch125st1[] = +{ + {50.0f,114.286f}, + {54.7619f,104.762f}, + {54.7619f,95.2381f}, + {50.0f,85.7143f}, + {45.2381f,80.9524f}, + {40.4762f,71.4286f}, + {40.4762f,61.9048f}, + {45.2381f,52.381f}, + {64.2857f,42.8571f}, + {45.2381f,33.3333f}, + {40.4762f,23.8095f}, + {40.4762f,14.2857f}, + {45.2381f,4.7619f}, + {50.0f,0.0f}, + {54.7619f,-9.5238f}, + {54.7619f,-19.0476f}, + {50.0f,-28.5714f} +}; + +static const SFG_StrokeVertex ch125st2[] = +{ + {54.7619f,38.0952f}, + {45.2381f,28.5714f}, + {45.2381f,19.0476f}, + {50.0f,9.5238f}, + {54.7619f,4.7619f}, + {59.5238f,-4.7619f}, + {59.5238f,-14.2857f}, + {54.7619f,-23.8095f}, + {50.0f,-28.5714f}, + {40.4762f,-33.3333f} +}; + +static const SFG_StrokeStrip ch125st[] = +{ + {10,ch125st0}, + {17,ch125st1}, + {10,ch125st2} +}; + +static const SFG_StrokeChar ch125 = {104.762f,3,ch125st}; + +/* char: 0x7e */ + +static const SFG_StrokeVertex ch126st0[] = +{ + {9.5238f,28.5714f}, + {9.5238f,38.0952f}, + {14.2857f,52.381f}, + {23.8095f,57.1429f}, + {33.3333f,57.1429f}, + {42.8571f,52.381f}, + {61.9048f,38.0952f}, + {71.4286f,33.3333f}, + {80.9524f,33.3333f}, + {90.4762f,38.0952f}, + {95.2381f,47.619f} +}; + +static const SFG_StrokeVertex ch126st1[] = +{ + {9.5238f,38.0952f}, + {14.2857f,47.619f}, + {23.8095f,52.381f}, + {33.3333f,52.381f}, + {42.8571f,47.619f}, + {61.9048f,33.3333f}, + {71.4286f,28.5714f}, + {80.9524f,28.5714f}, + {90.4762f,33.3333f}, + {95.2381f,47.619f}, + {95.2381f,57.1429f} +}; + +static const SFG_StrokeStrip ch126st[] = +{ + {11,ch126st0}, + {11,ch126st1} +}; + +static const SFG_StrokeChar ch126 = {104.762f,2,ch126st}; + +/* char: 0x7f */ + +static const SFG_StrokeVertex ch127st0[] = +{ + {71.4286f,100.0f}, + {33.3333f,-33.3333f} +}; + +static const SFG_StrokeVertex ch127st1[] = +{ + {47.619f,66.6667f}, + {33.3333f,61.9048f}, + {23.8095f,52.381f}, + {19.0476f,38.0952f}, + {19.0476f,23.8095f}, + {23.8095f,14.2857f}, + {33.3333f,4.7619f}, + {47.619f,0.0f}, + {57.1428f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,14.2857f}, + {85.7143f,28.5714f}, + {85.7143f,42.8571f}, + {80.9524f,52.381f}, + {71.4286f,61.9048f}, + {57.1428f,66.6667f}, + {47.619f,66.6667f} +}; + +static const SFG_StrokeStrip ch127st[] = +{ + {2,ch127st0}, + {17,ch127st1} +}; + +static const SFG_StrokeChar ch127 = {104.762f,2,ch127st}; + +static const SFG_StrokeChar *chars[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + &ch32, &ch33, &ch34, &ch35, &ch36, &ch37, &ch38, &ch39, + &ch40, &ch41, &ch42, &ch43, &ch44, &ch45, &ch46, &ch47, + &ch48, &ch49, &ch50, &ch51, &ch52, &ch53, &ch54, &ch55, + &ch56, &ch57, &ch58, &ch59, &ch60, &ch61, &ch62, &ch63, + &ch64, &ch65, &ch66, &ch67, &ch68, &ch69, &ch70, &ch71, + &ch72, &ch73, &ch74, &ch75, &ch76, &ch77, &ch78, &ch79, + &ch80, &ch81, &ch82, &ch83, &ch84, &ch85, &ch86, &ch87, + &ch88, &ch89, &ch90, &ch91, &ch92, &ch93, &ch94, &ch95, + &ch96, &ch97, &ch98, &ch99, &ch100, &ch101, &ch102, &ch103, + &ch104, &ch105, &ch106, &ch107, &ch108, &ch109, &ch110, &ch111, + &ch112, &ch113, &ch114, &ch115, &ch116, &ch117, &ch118, &ch119, + &ch120, &ch121, &ch122, &ch123, &ch124, &ch125, &ch126, &ch127 +}; + +const SFG_StrokeFont fgStrokeMonoRoman = {"MonoRoman",128,152.381f,chars}; diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_stroke_roman.c b/tests/Box2D_v2.2.1/freeglut/freeglut_stroke_roman.c new file mode 100755 index 0000000000000..619a904423cbe --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_stroke_roman.c @@ -0,0 +1,2849 @@ +/* + * freeglut_stroke_roman.c + * + * freeglut Roman stroke font definition + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 16 1999 + * + * 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 + * PAWEL W. OLSZTA 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. + */ + + +/* This file has been automatically generated by the genstroke utility. */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* char: 0x20 */ + +static const SFG_StrokeStrip ch32st[] = +{ + { 0, NULL } +}; + +static const SFG_StrokeChar ch32 = {104.762f,0,ch32st}; + +/* char: 0x21 */ + +static const SFG_StrokeVertex ch33st0[] = +{ + {13.3819f,100.0f}, + {13.3819f,33.3333f} +}; + +static const SFG_StrokeVertex ch33st1[] = +{ + {13.3819f,9.5238f}, + {8.62f,4.7619f}, + {13.3819f,0.0f}, + {18.1438f,4.7619f}, + {13.3819f,9.5238f} +}; + +static const SFG_StrokeStrip ch33st[] = +{ + {2,ch33st0}, + {5,ch33st1} +}; + +static const SFG_StrokeChar ch33 = {26.6238f,2,ch33st}; + +/* char: 0x22 */ + +static const SFG_StrokeVertex ch34st0[] = +{ + {4.02f,100.0f}, + {4.02f,66.6667f} +}; + +static const SFG_StrokeVertex ch34st1[] = +{ + {42.1152f,100.0f}, + {42.1152f,66.6667f} +}; + +static const SFG_StrokeStrip ch34st[] = +{ + {2,ch34st0}, + {2,ch34st1} +}; + +static const SFG_StrokeChar ch34 = {51.4352f,2,ch34st}; + +/* char: 0x23 */ + +static const SFG_StrokeVertex ch35st0[] = +{ + {41.2952f,119.048f}, + {7.9619f,-33.3333f} +}; + +static const SFG_StrokeVertex ch35st1[] = +{ + {69.8667f,119.048f}, + {36.5333f,-33.3333f} +}; + +static const SFG_StrokeVertex ch35st2[] = +{ + {7.9619f,57.1429f}, + {74.6286f,57.1429f} +}; + +static const SFG_StrokeVertex ch35st3[] = +{ + {3.2f,28.5714f}, + {69.8667f,28.5714f} +}; + +static const SFG_StrokeStrip ch35st[] = +{ + {2,ch35st0}, + {2,ch35st1}, + {2,ch35st2}, + {2,ch35st3} +}; + +static const SFG_StrokeChar ch35 = {79.4886f,4,ch35st}; + +/* char: 0x24 */ + +static const SFG_StrokeVertex ch36st0[] = +{ + {28.6295f,119.048f}, + {28.6295f,-19.0476f} +}; + +static const SFG_StrokeVertex ch36st1[] = +{ + {47.6771f,119.048f}, + {47.6771f,-19.0476f} +}; + +static const SFG_StrokeVertex ch36st2[] = +{ + {71.4867f,85.7143f}, + {61.9629f,95.2381f}, + {47.6771f,100.0f}, + {28.6295f,100.0f}, + {14.3438f,95.2381f}, + {4.82f,85.7143f}, + {4.82f,76.1905f}, + {9.5819f,66.6667f}, + {14.3438f,61.9048f}, + {23.8676f,57.1429f}, + {52.439f,47.619f}, + {61.9629f,42.8571f}, + {66.7248f,38.0952f}, + {71.4867f,28.5714f}, + {71.4867f,14.2857f}, + {61.9629f,4.7619f}, + {47.6771f,0.0f}, + {28.6295f,0.0f}, + {14.3438f,4.7619f}, + {4.82f,14.2857f} +}; + +static const SFG_StrokeStrip ch36st[] = +{ + {2,ch36st0}, + {2,ch36st1}, + {20,ch36st2} +}; + +static const SFG_StrokeChar ch36 = {76.2067f,3,ch36st}; + +/* char: 0x25 */ + +static const SFG_StrokeVertex ch37st0[] = +{ + {92.0743f,100.0f}, + {6.36f,0.0f} +}; + +static const SFG_StrokeVertex ch37st1[] = +{ + {30.1695f,100.0f}, + {39.6933f,90.4762f}, + {39.6933f,80.9524f}, + {34.9314f,71.4286f}, + {25.4076f,66.6667f}, + {15.8838f,66.6667f}, + {6.36f,76.1905f}, + {6.36f,85.7143f}, + {11.1219f,95.2381f}, + {20.6457f,100.0f}, + {30.1695f,100.0f}, + {39.6933f,95.2381f}, + {53.979f,90.4762f}, + {68.2648f,90.4762f}, + {82.5505f,95.2381f}, + {92.0743f,100.0f} +}; + +static const SFG_StrokeVertex ch37st2[] = +{ + {73.0267f,33.3333f}, + {63.5029f,28.5714f}, + {58.741f,19.0476f}, + {58.741f,9.5238f}, + {68.2648f,0.0f}, + {77.7886f,0.0f}, + {87.3124f,4.7619f}, + {92.0743f,14.2857f}, + {92.0743f,23.8095f}, + {82.5505f,33.3333f}, + {73.0267f,33.3333f} +}; + +static const SFG_StrokeStrip ch37st[] = +{ + {2,ch37st0}, + {16,ch37st1}, + {11,ch37st2} +}; + +static const SFG_StrokeChar ch37 = {96.5743f,3,ch37st}; + +/* char: 0x26 */ + +static const SFG_StrokeVertex ch38st0[] = +{ + {101.218f,57.1429f}, + {101.218f,61.9048f}, + {96.4562f,66.6667f}, + {91.6943f,66.6667f}, + {86.9324f,61.9048f}, + {82.1705f,52.381f}, + {72.6467f,28.5714f}, + {63.1229f,14.2857f}, + {53.599f,4.7619f}, + {44.0752f,0.0f}, + {25.0276f,0.0f}, + {15.5038f,4.7619f}, + {10.7419f,9.5238f}, + {5.98f,19.0476f}, + {5.98f,28.5714f}, + {10.7419f,38.0952f}, + {15.5038f,42.8571f}, + {48.8371f,61.9048f}, + {53.599f,66.6667f}, + {58.361f,76.1905f}, + {58.361f,85.7143f}, + {53.599f,95.2381f}, + {44.0752f,100.0f}, + {34.5514f,95.2381f}, + {29.7895f,85.7143f}, + {29.7895f,76.1905f}, + {34.5514f,61.9048f}, + {44.0752f,47.619f}, + {67.8848f,14.2857f}, + {77.4086f,4.7619f}, + {86.9324f,0.0f}, + {96.4562f,0.0f}, + {101.218f,4.7619f}, + {101.218f,9.5238f} +}; + +static const SFG_StrokeStrip ch38st[] = +{ + {34,ch38st0} +}; + +static const SFG_StrokeChar ch38 = {101.758f,1,ch38st}; + +/* char: 0x27 */ + +static const SFG_StrokeVertex ch39st0[] = +{ + {4.44f,100.0f}, + {4.44f,66.6667f} +}; + +static const SFG_StrokeStrip ch39st[] = +{ + {2,ch39st0} +}; + +static const SFG_StrokeChar ch39 = {13.62f,1,ch39st}; + +/* char: 0x28 */ + +static const SFG_StrokeVertex ch40st0[] = +{ + {40.9133f,119.048f}, + {31.3895f,109.524f}, + {21.8657f,95.2381f}, + {12.3419f,76.1905f}, + {7.58f,52.381f}, + {7.58f,33.3333f}, + {12.3419f,9.5238f}, + {21.8657f,-9.5238f}, + {31.3895f,-23.8095f}, + {40.9133f,-33.3333f} +}; + +static const SFG_StrokeStrip ch40st[] = +{ + {10,ch40st0} +}; + +static const SFG_StrokeChar ch40 = {47.1733f,1,ch40st}; + +/* char: 0x29 */ + +static const SFG_StrokeVertex ch41st0[] = +{ + {5.28f,119.048f}, + {14.8038f,109.524f}, + {24.3276f,95.2381f}, + {33.8514f,76.1905f}, + {38.6133f,52.381f}, + {38.6133f,33.3333f}, + {33.8514f,9.5238f}, + {24.3276f,-9.5238f}, + {14.8038f,-23.8095f}, + {5.28f,-33.3333f} +}; + +static const SFG_StrokeStrip ch41st[] = +{ + {10,ch41st0} +}; + +static const SFG_StrokeChar ch41 = {47.5333f,1,ch41st}; + +/* char: 0x2a */ + +static const SFG_StrokeVertex ch42st0[] = +{ + {30.7695f,71.4286f}, + {30.7695f,14.2857f} +}; + +static const SFG_StrokeVertex ch42st1[] = +{ + {6.96f,57.1429f}, + {54.579f,28.5714f} +}; + +static const SFG_StrokeVertex ch42st2[] = +{ + {54.579f,57.1429f}, + {6.96f,28.5714f} +}; + +static const SFG_StrokeStrip ch42st[] = +{ + {2,ch42st0}, + {2,ch42st1}, + {2,ch42st2} +}; + +static const SFG_StrokeChar ch42 = {59.439f,3,ch42st}; + +/* char: 0x2b */ + +static const SFG_StrokeVertex ch43st0[] = +{ + {48.8371f,85.7143f}, + {48.8371f,0.0f} +}; + +static const SFG_StrokeVertex ch43st1[] = +{ + {5.98f,42.8571f}, + {91.6943f,42.8571f} +}; + +static const SFG_StrokeStrip ch43st[] = +{ + {2,ch43st0}, + {2,ch43st1} +}; + +static const SFG_StrokeChar ch43 = {97.2543f,2,ch43st}; + +/* char: 0x2c */ + +static const SFG_StrokeVertex ch44st0[] = +{ + {18.2838f,4.7619f}, + {13.5219f,0.0f}, + {8.76f,4.7619f}, + {13.5219f,9.5238f}, + {18.2838f,4.7619f}, + {18.2838f,-4.7619f}, + {13.5219f,-14.2857f}, + {8.76f,-19.0476f} +}; + +static const SFG_StrokeStrip ch44st[] = +{ + {8,ch44st0} +}; + +static const SFG_StrokeChar ch44 = {26.0638f,1,ch44st}; + +/* char: 0x2d */ + +static const SFG_StrokeVertex ch45st0[] = +{ + {7.38f,42.8571f}, + {93.0943f,42.8571f} +}; + +static const SFG_StrokeStrip ch45st[] = +{ + {2,ch45st0} +}; + +static const SFG_StrokeChar ch45 = {100.754f,1,ch45st}; + +/* char: 0x2e */ + +static const SFG_StrokeVertex ch46st0[] = +{ + {13.1019f,9.5238f}, + {8.34f,4.7619f}, + {13.1019f,0.0f}, + {17.8638f,4.7619f}, + {13.1019f,9.5238f} +}; + +static const SFG_StrokeStrip ch46st[] = +{ + {5,ch46st0} +}; + +static const SFG_StrokeChar ch46 = {26.4838f,1,ch46st}; + +/* char: 0x2f */ + +static const SFG_StrokeVertex ch47st0[] = +{ + {7.24f,-14.2857f}, + {73.9067f,100.0f} +}; + +static const SFG_StrokeStrip ch47st[] = +{ + {2,ch47st0} +}; + +static const SFG_StrokeChar ch47 = {82.1067f,1,ch47st}; + +/* char: 0x30 */ + +static const SFG_StrokeVertex ch48st0[] = +{ + {33.5514f,100.0f}, + {19.2657f,95.2381f}, + {9.7419f,80.9524f}, + {4.98f,57.1429f}, + {4.98f,42.8571f}, + {9.7419f,19.0476f}, + {19.2657f,4.7619f}, + {33.5514f,0.0f}, + {43.0752f,0.0f}, + {57.361f,4.7619f}, + {66.8848f,19.0476f}, + {71.6467f,42.8571f}, + {71.6467f,57.1429f}, + {66.8848f,80.9524f}, + {57.361f,95.2381f}, + {43.0752f,100.0f}, + {33.5514f,100.0f} +}; + +static const SFG_StrokeStrip ch48st[] = +{ + {17,ch48st0} +}; + +static const SFG_StrokeChar ch48 = {77.0667f,1,ch48st}; + +/* char: 0x31 */ + +static const SFG_StrokeVertex ch49st0[] = +{ + {11.82f,80.9524f}, + {21.3438f,85.7143f}, + {35.6295f,100.0f}, + {35.6295f,0.0f} +}; + +static const SFG_StrokeStrip ch49st[] = +{ + {4,ch49st0} +}; + +static const SFG_StrokeChar ch49 = {66.5295f,1,ch49st}; + +/* char: 0x32 */ + +static const SFG_StrokeVertex ch50st0[] = +{ + {10.1819f,76.1905f}, + {10.1819f,80.9524f}, + {14.9438f,90.4762f}, + {19.7057f,95.2381f}, + {29.2295f,100.0f}, + {48.2771f,100.0f}, + {57.801f,95.2381f}, + {62.5629f,90.4762f}, + {67.3248f,80.9524f}, + {67.3248f,71.4286f}, + {62.5629f,61.9048f}, + {53.039f,47.619f}, + {5.42f,0.0f}, + {72.0867f,0.0f} +}; + +static const SFG_StrokeStrip ch50st[] = +{ + {14,ch50st0} +}; + +static const SFG_StrokeChar ch50 = {77.6467f,1,ch50st}; + +/* char: 0x33 */ + +static const SFG_StrokeVertex ch51st0[] = +{ + {14.5238f,100.0f}, + {66.9048f,100.0f}, + {38.3333f,61.9048f}, + {52.619f,61.9048f}, + {62.1429f,57.1429f}, + {66.9048f,52.381f}, + {71.6667f,38.0952f}, + {71.6667f,28.5714f}, + {66.9048f,14.2857f}, + {57.381f,4.7619f}, + {43.0952f,0.0f}, + {28.8095f,0.0f}, + {14.5238f,4.7619f}, + {9.7619f,9.5238f}, + {5.0f,19.0476f} +}; + +static const SFG_StrokeStrip ch51st[] = +{ + {15,ch51st0} +}; + +static const SFG_StrokeChar ch51 = {77.0467f,1,ch51st}; + +/* char: 0x34 */ + +static const SFG_StrokeVertex ch52st0[] = +{ + {51.499f,100.0f}, + {3.88f,33.3333f}, + {75.3086f,33.3333f} +}; + +static const SFG_StrokeVertex ch52st1[] = +{ + {51.499f,100.0f}, + {51.499f,0.0f} +}; + +static const SFG_StrokeStrip ch52st[] = +{ + {3,ch52st0}, + {2,ch52st1} +}; + +static const SFG_StrokeChar ch52 = {80.1686f,2,ch52st}; + +/* char: 0x35 */ + +static const SFG_StrokeVertex ch53st0[] = +{ + {62.0029f,100.0f}, + {14.3838f,100.0f}, + {9.6219f,57.1429f}, + {14.3838f,61.9048f}, + {28.6695f,66.6667f}, + {42.9552f,66.6667f}, + {57.241f,61.9048f}, + {66.7648f,52.381f}, + {71.5267f,38.0952f}, + {71.5267f,28.5714f}, + {66.7648f,14.2857f}, + {57.241f,4.7619f}, + {42.9552f,0.0f}, + {28.6695f,0.0f}, + {14.3838f,4.7619f}, + {9.6219f,9.5238f}, + {4.86f,19.0476f} +}; + +static const SFG_StrokeStrip ch53st[] = +{ + {17,ch53st0} +}; + +static const SFG_StrokeChar ch53 = {77.6867f,1,ch53st}; + +/* char: 0x36 */ + +static const SFG_StrokeVertex ch54st0[] = +{ + {62.7229f,85.7143f}, + {57.961f,95.2381f}, + {43.6752f,100.0f}, + {34.1514f,100.0f}, + {19.8657f,95.2381f}, + {10.3419f,80.9524f}, + {5.58f,57.1429f}, + {5.58f,33.3333f}, + {10.3419f,14.2857f}, + {19.8657f,4.7619f}, + {34.1514f,0.0f}, + {38.9133f,0.0f}, + {53.199f,4.7619f}, + {62.7229f,14.2857f}, + {67.4848f,28.5714f}, + {67.4848f,33.3333f}, + {62.7229f,47.619f}, + {53.199f,57.1429f}, + {38.9133f,61.9048f}, + {34.1514f,61.9048f}, + {19.8657f,57.1429f}, + {10.3419f,47.619f}, + {5.58f,33.3333f} +}; + +static const SFG_StrokeStrip ch54st[] = +{ + {23,ch54st0} +}; + +static const SFG_StrokeChar ch54 = {73.8048f,1,ch54st}; + +/* char: 0x37 */ + +static const SFG_StrokeVertex ch55st0[] = +{ + {72.2267f,100.0f}, + {24.6076f,0.0f} +}; + +static const SFG_StrokeVertex ch55st1[] = +{ + {5.56f,100.0f}, + {72.2267f,100.0f} +}; + +static const SFG_StrokeStrip ch55st[] = +{ + {2,ch55st0}, + {2,ch55st1} +}; + +static const SFG_StrokeChar ch55 = {77.2267f,2,ch55st}; + +/* char: 0x38 */ + +static const SFG_StrokeVertex ch56st0[] = +{ + {29.4095f,100.0f}, + {15.1238f,95.2381f}, + {10.3619f,85.7143f}, + {10.3619f,76.1905f}, + {15.1238f,66.6667f}, + {24.6476f,61.9048f}, + {43.6952f,57.1429f}, + {57.981f,52.381f}, + {67.5048f,42.8571f}, + {72.2667f,33.3333f}, + {72.2667f,19.0476f}, + {67.5048f,9.5238f}, + {62.7429f,4.7619f}, + {48.4571f,0.0f}, + {29.4095f,0.0f}, + {15.1238f,4.7619f}, + {10.3619f,9.5238f}, + {5.6f,19.0476f}, + {5.6f,33.3333f}, + {10.3619f,42.8571f}, + {19.8857f,52.381f}, + {34.1714f,57.1429f}, + {53.219f,61.9048f}, + {62.7429f,66.6667f}, + {67.5048f,76.1905f}, + {67.5048f,85.7143f}, + {62.7429f,95.2381f}, + {48.4571f,100.0f}, + {29.4095f,100.0f} +}; + +static const SFG_StrokeStrip ch56st[] = +{ + {29,ch56st0} +}; + +static const SFG_StrokeChar ch56 = {77.6667f,1,ch56st}; + +/* char: 0x39 */ + +static const SFG_StrokeVertex ch57st0[] = +{ + {68.5048f,66.6667f}, + {63.7429f,52.381f}, + {54.219f,42.8571f}, + {39.9333f,38.0952f}, + {35.1714f,38.0952f}, + {20.8857f,42.8571f}, + {11.3619f,52.381f}, + {6.6f,66.6667f}, + {6.6f,71.4286f}, + {11.3619f,85.7143f}, + {20.8857f,95.2381f}, + {35.1714f,100.0f}, + {39.9333f,100.0f}, + {54.219f,95.2381f}, + {63.7429f,85.7143f}, + {68.5048f,66.6667f}, + {68.5048f,42.8571f}, + {63.7429f,19.0476f}, + {54.219f,4.7619f}, + {39.9333f,0.0f}, + {30.4095f,0.0f}, + {16.1238f,4.7619f}, + {11.3619f,14.2857f} +}; + +static const SFG_StrokeStrip ch57st[] = +{ + {23,ch57st0} +}; + +static const SFG_StrokeChar ch57 = {74.0648f,1,ch57st}; + +/* char: 0x3a */ + +static const SFG_StrokeVertex ch58st0[] = +{ + {14.0819f,66.6667f}, + {9.32f,61.9048f}, + {14.0819f,57.1429f}, + {18.8438f,61.9048f}, + {14.0819f,66.6667f} +}; + +static const SFG_StrokeVertex ch58st1[] = +{ + {14.0819f,9.5238f}, + {9.32f,4.7619f}, + {14.0819f,0.0f}, + {18.8438f,4.7619f}, + {14.0819f,9.5238f} +}; + +static const SFG_StrokeStrip ch58st[] = +{ + {5,ch58st0}, + {5,ch58st1} +}; + +static const SFG_StrokeChar ch58 = {26.2238f,2,ch58st}; + +/* char: 0x3b */ + +static const SFG_StrokeVertex ch59st0[] = +{ + {12.9619f,66.6667f}, + {8.2f,61.9048f}, + {12.9619f,57.1429f}, + {17.7238f,61.9048f}, + {12.9619f,66.6667f} +}; + +static const SFG_StrokeVertex ch59st1[] = +{ + {17.7238f,4.7619f}, + {12.9619f,0.0f}, + {8.2f,4.7619f}, + {12.9619f,9.5238f}, + {17.7238f,4.7619f}, + {17.7238f,-4.7619f}, + {12.9619f,-14.2857f}, + {8.2f,-19.0476f} +}; + +static const SFG_StrokeStrip ch59st[] = +{ + {5,ch59st0}, + {8,ch59st1} +}; + +static const SFG_StrokeChar ch59 = {26.3038f,2,ch59st}; + +/* char: 0x3c */ + +static const SFG_StrokeVertex ch60st0[] = +{ + {79.2505f,85.7143f}, + {3.06f,42.8571f}, + {79.2505f,0.0f} +}; + +static const SFG_StrokeStrip ch60st[] = +{ + {3,ch60st0} +}; + +static const SFG_StrokeChar ch60 = {81.6105f,1,ch60st}; + +/* char: 0x3d */ + +static const SFG_StrokeVertex ch61st0[] = +{ + {5.7f,57.1429f}, + {91.4143f,57.1429f} +}; + +static const SFG_StrokeVertex ch61st1[] = +{ + {5.7f,28.5714f}, + {91.4143f,28.5714f} +}; + +static const SFG_StrokeStrip ch61st[] = +{ + {2,ch61st0}, + {2,ch61st1} +}; + +static const SFG_StrokeChar ch61 = {97.2543f,2,ch61st}; + +/* char: 0x3e */ + +static const SFG_StrokeVertex ch62st0[] = +{ + {2.78f,85.7143f}, + {78.9705f,42.8571f}, + {2.78f,0.0f} +}; + +static const SFG_StrokeStrip ch62st[] = +{ + {3,ch62st0} +}; + +static const SFG_StrokeChar ch62 = {81.6105f,1,ch62st}; + +/* char: 0x3f */ + +static const SFG_StrokeVertex ch63st0[] = +{ + {8.42f,76.1905f}, + {8.42f,80.9524f}, + {13.1819f,90.4762f}, + {17.9438f,95.2381f}, + {27.4676f,100.0f}, + {46.5152f,100.0f}, + {56.039f,95.2381f}, + {60.801f,90.4762f}, + {65.5629f,80.9524f}, + {65.5629f,71.4286f}, + {60.801f,61.9048f}, + {56.039f,57.1429f}, + {36.9914f,47.619f}, + {36.9914f,33.3333f} +}; + +static const SFG_StrokeVertex ch63st1[] = +{ + {36.9914f,9.5238f}, + {32.2295f,4.7619f}, + {36.9914f,0.0f}, + {41.7533f,4.7619f}, + {36.9914f,9.5238f} +}; + +static const SFG_StrokeStrip ch63st[] = +{ + {14,ch63st0}, + {5,ch63st1} +}; + +static const SFG_StrokeChar ch63 = {73.9029f,2,ch63st}; + +/* char: 0x40 */ + +static const SFG_StrokeVertex ch64st0[] = +{ + {49.2171f,52.381f}, + {39.6933f,57.1429f}, + {30.1695f,57.1429f}, + {25.4076f,47.619f}, + {25.4076f,42.8571f}, + {30.1695f,33.3333f}, + {39.6933f,33.3333f}, + {49.2171f,38.0952f} +}; + +static const SFG_StrokeVertex ch64st1[] = +{ + {49.2171f,57.1429f}, + {49.2171f,38.0952f}, + {53.979f,33.3333f}, + {63.5029f,33.3333f}, + {68.2648f,42.8571f}, + {68.2648f,47.619f}, + {63.5029f,61.9048f}, + {53.979f,71.4286f}, + {39.6933f,76.1905f}, + {34.9314f,76.1905f}, + {20.6457f,71.4286f}, + {11.1219f,61.9048f}, + {6.36f,47.619f}, + {6.36f,42.8571f}, + {11.1219f,28.5714f}, + {20.6457f,19.0476f}, + {34.9314f,14.2857f}, + {39.6933f,14.2857f}, + {53.979f,19.0476f} +}; + +static const SFG_StrokeStrip ch64st[] = +{ + {8,ch64st0}, + {19,ch64st1} +}; + +static const SFG_StrokeChar ch64 = {74.3648f,2,ch64st}; + +/* char: 0x41 */ + +static const SFG_StrokeVertex ch65st0[] = +{ + {40.5952f,100.0f}, + {2.5f,0.0f} +}; + +static const SFG_StrokeVertex ch65st1[] = +{ + {40.5952f,100.0f}, + {78.6905f,0.0f} +}; + +static const SFG_StrokeVertex ch65st2[] = +{ + {16.7857f,33.3333f}, + {64.4048f,33.3333f} +}; + +static const SFG_StrokeStrip ch65st[] = +{ + {2,ch65st0}, + {2,ch65st1}, + {2,ch65st2} +}; + +static const SFG_StrokeChar ch65 = {80.4905f,3,ch65st}; + +/* char: 0x42 */ + +static const SFG_StrokeVertex ch66st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeVertex ch66st1[] = +{ + {11.42f,100.0f}, + {54.2771f,100.0f}, + {68.5629f,95.2381f}, + {73.3248f,90.4762f}, + {78.0867f,80.9524f}, + {78.0867f,71.4286f}, + {73.3248f,61.9048f}, + {68.5629f,57.1429f}, + {54.2771f,52.381f} +}; + +static const SFG_StrokeVertex ch66st2[] = +{ + {11.42f,52.381f}, + {54.2771f,52.381f}, + {68.5629f,47.619f}, + {73.3248f,42.8571f}, + {78.0867f,33.3333f}, + {78.0867f,19.0476f}, + {73.3248f,9.5238f}, + {68.5629f,4.7619f}, + {54.2771f,0.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeStrip ch66st[] = +{ + {2,ch66st0}, + {9,ch66st1}, + {10,ch66st2} +}; + +static const SFG_StrokeChar ch66 = {83.6267f,3,ch66st}; + +/* char: 0x43 */ + +static const SFG_StrokeVertex ch67st0[] = +{ + {78.0886f,76.1905f}, + {73.3267f,85.7143f}, + {63.8029f,95.2381f}, + {54.279f,100.0f}, + {35.2314f,100.0f}, + {25.7076f,95.2381f}, + {16.1838f,85.7143f}, + {11.4219f,76.1905f}, + {6.66f,61.9048f}, + {6.66f,38.0952f}, + {11.4219f,23.8095f}, + {16.1838f,14.2857f}, + {25.7076f,4.7619f}, + {35.2314f,0.0f}, + {54.279f,0.0f}, + {63.8029f,4.7619f}, + {73.3267f,14.2857f}, + {78.0886f,23.8095f} +}; + +static const SFG_StrokeStrip ch67st[] = +{ + {18,ch67st0} +}; + +static const SFG_StrokeChar ch67 = {84.4886f,1,ch67st}; + +/* char: 0x44 */ + +static const SFG_StrokeVertex ch68st0[] = +{ + {11.96f,100.0f}, + {11.96f,0.0f} +}; + +static const SFG_StrokeVertex ch68st1[] = +{ + {11.96f,100.0f}, + {45.2933f,100.0f}, + {59.579f,95.2381f}, + {69.1029f,85.7143f}, + {73.8648f,76.1905f}, + {78.6267f,61.9048f}, + {78.6267f,38.0952f}, + {73.8648f,23.8095f}, + {69.1029f,14.2857f}, + {59.579f,4.7619f}, + {45.2933f,0.0f}, + {11.96f,0.0f} +}; + +static const SFG_StrokeStrip ch68st[] = +{ + {2,ch68st0}, + {12,ch68st1} +}; + +static const SFG_StrokeChar ch68 = {85.2867f,2,ch68st}; + +/* char: 0x45 */ + +static const SFG_StrokeVertex ch69st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeVertex ch69st1[] = +{ + {11.42f,100.0f}, + {73.3248f,100.0f} +}; + +static const SFG_StrokeVertex ch69st2[] = +{ + {11.42f,52.381f}, + {49.5152f,52.381f} +}; + +static const SFG_StrokeVertex ch69st3[] = +{ + {11.42f,0.0f}, + {73.3248f,0.0f} +}; + +static const SFG_StrokeStrip ch69st[] = +{ + {2,ch69st0}, + {2,ch69st1}, + {2,ch69st2}, + {2,ch69st3} +}; + +static const SFG_StrokeChar ch69 = {78.1848f,4,ch69st}; + +/* char: 0x46 */ + +static const SFG_StrokeVertex ch70st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeVertex ch70st1[] = +{ + {11.42f,100.0f}, + {73.3248f,100.0f} +}; + +static const SFG_StrokeVertex ch70st2[] = +{ + {11.42f,52.381f}, + {49.5152f,52.381f} +}; + +static const SFG_StrokeStrip ch70st[] = +{ + {2,ch70st0}, + {2,ch70st1}, + {2,ch70st2} +}; + +static const SFG_StrokeChar ch70 = {78.7448f,3,ch70st}; + +/* char: 0x47 */ + +static const SFG_StrokeVertex ch71st0[] = +{ + {78.4886f,76.1905f}, + {73.7267f,85.7143f}, + {64.2029f,95.2381f}, + {54.679f,100.0f}, + {35.6314f,100.0f}, + {26.1076f,95.2381f}, + {16.5838f,85.7143f}, + {11.8219f,76.1905f}, + {7.06f,61.9048f}, + {7.06f,38.0952f}, + {11.8219f,23.8095f}, + {16.5838f,14.2857f}, + {26.1076f,4.7619f}, + {35.6314f,0.0f}, + {54.679f,0.0f}, + {64.2029f,4.7619f}, + {73.7267f,14.2857f}, + {78.4886f,23.8095f}, + {78.4886f,38.0952f} +}; + +static const SFG_StrokeVertex ch71st1[] = +{ + {54.679f,38.0952f}, + {78.4886f,38.0952f} +}; + +static const SFG_StrokeStrip ch71st[] = +{ + {19,ch71st0}, + {2,ch71st1} +}; + +static const SFG_StrokeChar ch71 = {89.7686f,2,ch71st}; + +/* char: 0x48 */ + +static const SFG_StrokeVertex ch72st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeVertex ch72st1[] = +{ + {78.0867f,100.0f}, + {78.0867f,0.0f} +}; + +static const SFG_StrokeVertex ch72st2[] = +{ + {11.42f,52.381f}, + {78.0867f,52.381f} +}; + +static const SFG_StrokeStrip ch72st[] = +{ + {2,ch72st0}, + {2,ch72st1}, + {2,ch72st2} +}; + +static const SFG_StrokeChar ch72 = {89.0867f,3,ch72st}; + +/* char: 0x49 */ + +static const SFG_StrokeVertex ch73st0[] = +{ + {10.86f,100.0f}, + {10.86f,0.0f} +}; + +static const SFG_StrokeStrip ch73st[] = +{ + {2,ch73st0} +}; + +static const SFG_StrokeChar ch73 = {21.3f,1,ch73st}; + +/* char: 0x4a */ + +static const SFG_StrokeVertex ch74st0[] = +{ + {50.119f,100.0f}, + {50.119f,23.8095f}, + {45.3571f,9.5238f}, + {40.5952f,4.7619f}, + {31.0714f,0.0f}, + {21.5476f,0.0f}, + {12.0238f,4.7619f}, + {7.2619f,9.5238f}, + {2.5f,23.8095f}, + {2.5f,33.3333f} +}; + +static const SFG_StrokeStrip ch74st[] = +{ + {10,ch74st0} +}; + +static const SFG_StrokeChar ch74 = {59.999f,1,ch74st}; + +/* char: 0x4b */ + +static const SFG_StrokeVertex ch75st0[] = +{ + {11.28f,100.0f}, + {11.28f,0.0f} +}; + +static const SFG_StrokeVertex ch75st1[] = +{ + {77.9467f,100.0f}, + {11.28f,33.3333f} +}; + +static const SFG_StrokeVertex ch75st2[] = +{ + {35.0895f,57.1429f}, + {77.9467f,0.0f} +}; + +static const SFG_StrokeStrip ch75st[] = +{ + {2,ch75st0}, + {2,ch75st1}, + {2,ch75st2} +}; + +static const SFG_StrokeChar ch75 = {79.3267f,3,ch75st}; + +/* char: 0x4c */ + +static const SFG_StrokeVertex ch76st0[] = +{ + {11.68f,100.0f}, + {11.68f,0.0f} +}; + +static const SFG_StrokeVertex ch76st1[] = +{ + {11.68f,0.0f}, + {68.8229f,0.0f} +}; + +static const SFG_StrokeStrip ch76st[] = +{ + {2,ch76st0}, + {2,ch76st1} +}; + +static const SFG_StrokeChar ch76 = {71.3229f,2,ch76st}; + +/* char: 0x4d */ + +static const SFG_StrokeVertex ch77st0[] = +{ + {10.86f,100.0f}, + {10.86f,0.0f} +}; + +static const SFG_StrokeVertex ch77st1[] = +{ + {10.86f,100.0f}, + {48.9552f,0.0f} +}; + +static const SFG_StrokeVertex ch77st2[] = +{ + {87.0505f,100.0f}, + {48.9552f,0.0f} +}; + +static const SFG_StrokeVertex ch77st3[] = +{ + {87.0505f,100.0f}, + {87.0505f,0.0f} +}; + +static const SFG_StrokeStrip ch77st[] = +{ + {2,ch77st0}, + {2,ch77st1}, + {2,ch77st2}, + {2,ch77st3} +}; + +static const SFG_StrokeChar ch77 = {97.2105f,4,ch77st}; + +/* char: 0x4e */ + +static const SFG_StrokeVertex ch78st0[] = +{ + {11.14f,100.0f}, + {11.14f,0.0f} +}; + +static const SFG_StrokeVertex ch78st1[] = +{ + {11.14f,100.0f}, + {77.8067f,0.0f} +}; + +static const SFG_StrokeVertex ch78st2[] = +{ + {77.8067f,100.0f}, + {77.8067f,0.0f} +}; + +static const SFG_StrokeStrip ch78st[] = +{ + {2,ch78st0}, + {2,ch78st1}, + {2,ch78st2} +}; + +static const SFG_StrokeChar ch78 = {88.8067f,3,ch78st}; + +/* char: 0x4f */ + +static const SFG_StrokeVertex ch79st0[] = +{ + {34.8114f,100.0f}, + {25.2876f,95.2381f}, + {15.7638f,85.7143f}, + {11.0019f,76.1905f}, + {6.24f,61.9048f}, + {6.24f,38.0952f}, + {11.0019f,23.8095f}, + {15.7638f,14.2857f}, + {25.2876f,4.7619f}, + {34.8114f,0.0f}, + {53.859f,0.0f}, + {63.3829f,4.7619f}, + {72.9067f,14.2857f}, + {77.6686f,23.8095f}, + {82.4305f,38.0952f}, + {82.4305f,61.9048f}, + {77.6686f,76.1905f}, + {72.9067f,85.7143f}, + {63.3829f,95.2381f}, + {53.859f,100.0f}, + {34.8114f,100.0f} +}; + +static const SFG_StrokeStrip ch79st[] = +{ + {21,ch79st0} +}; + +static const SFG_StrokeChar ch79 = {88.8305f,1,ch79st}; + +/* char: 0x50 */ + +static const SFG_StrokeVertex ch80st0[] = +{ + {12.1f,100.0f}, + {12.1f,0.0f} +}; + +static const SFG_StrokeVertex ch80st1[] = +{ + {12.1f,100.0f}, + {54.9571f,100.0f}, + {69.2429f,95.2381f}, + {74.0048f,90.4762f}, + {78.7667f,80.9524f}, + {78.7667f,66.6667f}, + {74.0048f,57.1429f}, + {69.2429f,52.381f}, + {54.9571f,47.619f}, + {12.1f,47.619f} +}; + +static const SFG_StrokeStrip ch80st[] = +{ + {2,ch80st0}, + {10,ch80st1} +}; + +static const SFG_StrokeChar ch80 = {85.6667f,2,ch80st}; + +/* char: 0x51 */ + +static const SFG_StrokeVertex ch81st0[] = +{ + {33.8714f,100.0f}, + {24.3476f,95.2381f}, + {14.8238f,85.7143f}, + {10.0619f,76.1905f}, + {5.3f,61.9048f}, + {5.3f,38.0952f}, + {10.0619f,23.8095f}, + {14.8238f,14.2857f}, + {24.3476f,4.7619f}, + {33.8714f,0.0f}, + {52.919f,0.0f}, + {62.4429f,4.7619f}, + {71.9667f,14.2857f}, + {76.7286f,23.8095f}, + {81.4905f,38.0952f}, + {81.4905f,61.9048f}, + {76.7286f,76.1905f}, + {71.9667f,85.7143f}, + {62.4429f,95.2381f}, + {52.919f,100.0f}, + {33.8714f,100.0f} +}; + +static const SFG_StrokeVertex ch81st1[] = +{ + {48.1571f,19.0476f}, + {76.7286f,-9.5238f} +}; + +static const SFG_StrokeStrip ch81st[] = +{ + {21,ch81st0}, + {2,ch81st1} +}; + +static const SFG_StrokeChar ch81 = {88.0905f,2,ch81st}; + +/* char: 0x52 */ + +static const SFG_StrokeVertex ch82st0[] = +{ + {11.68f,100.0f}, + {11.68f,0.0f} +}; + +static const SFG_StrokeVertex ch82st1[] = +{ + {11.68f,100.0f}, + {54.5371f,100.0f}, + {68.8229f,95.2381f}, + {73.5848f,90.4762f}, + {78.3467f,80.9524f}, + {78.3467f,71.4286f}, + {73.5848f,61.9048f}, + {68.8229f,57.1429f}, + {54.5371f,52.381f}, + {11.68f,52.381f} +}; + +static const SFG_StrokeVertex ch82st2[] = +{ + {45.0133f,52.381f}, + {78.3467f,0.0f} +}; + +static const SFG_StrokeStrip ch82st[] = +{ + {2,ch82st0}, + {10,ch82st1}, + {2,ch82st2} +}; + +static const SFG_StrokeChar ch82 = {82.3667f,3,ch82st}; + +/* char: 0x53 */ + +static const SFG_StrokeVertex ch83st0[] = +{ + {74.6667f,85.7143f}, + {65.1429f,95.2381f}, + {50.8571f,100.0f}, + {31.8095f,100.0f}, + {17.5238f,95.2381f}, + {8.0f,85.7143f}, + {8.0f,76.1905f}, + {12.7619f,66.6667f}, + {17.5238f,61.9048f}, + {27.0476f,57.1429f}, + {55.619f,47.619f}, + {65.1429f,42.8571f}, + {69.9048f,38.0952f}, + {74.6667f,28.5714f}, + {74.6667f,14.2857f}, + {65.1429f,4.7619f}, + {50.8571f,0.0f}, + {31.8095f,0.0f}, + {17.5238f,4.7619f}, + {8.0f,14.2857f} +}; + +static const SFG_StrokeStrip ch83st[] = +{ + {20,ch83st0} +}; + +static const SFG_StrokeChar ch83 = {80.8267f,1,ch83st}; + +/* char: 0x54 */ + +static const SFG_StrokeVertex ch84st0[] = +{ + {35.6933f,100.0f}, + {35.6933f,0.0f} +}; + +static const SFG_StrokeVertex ch84st1[] = +{ + {2.36f,100.0f}, + {69.0267f,100.0f} +}; + +static const SFG_StrokeStrip ch84st[] = +{ + {2,ch84st0}, + {2,ch84st1} +}; + +static const SFG_StrokeChar ch84 = {71.9467f,2,ch84st}; + +/* char: 0x55 */ + +static const SFG_StrokeVertex ch85st0[] = +{ + {11.54f,100.0f}, + {11.54f,28.5714f}, + {16.3019f,14.2857f}, + {25.8257f,4.7619f}, + {40.1114f,0.0f}, + {49.6352f,0.0f}, + {63.921f,4.7619f}, + {73.4448f,14.2857f}, + {78.2067f,28.5714f}, + {78.2067f,100.0f} +}; + +static const SFG_StrokeStrip ch85st[] = +{ + {10,ch85st0} +}; + +static const SFG_StrokeChar ch85 = {89.4867f,1,ch85st}; + +/* char: 0x56 */ + +static const SFG_StrokeVertex ch86st0[] = +{ + {2.36f,100.0f}, + {40.4552f,0.0f} +}; + +static const SFG_StrokeVertex ch86st1[] = +{ + {78.5505f,100.0f}, + {40.4552f,0.0f} +}; + +static const SFG_StrokeStrip ch86st[] = +{ + {2,ch86st0}, + {2,ch86st1} +}; + +static const SFG_StrokeChar ch86 = {81.6105f,2,ch86st}; + +/* char: 0x57 */ + +static const SFG_StrokeVertex ch87st0[] = +{ + {2.22f,100.0f}, + {26.0295f,0.0f} +}; + +static const SFG_StrokeVertex ch87st1[] = +{ + {49.839f,100.0f}, + {26.0295f,0.0f} +}; + +static const SFG_StrokeVertex ch87st2[] = +{ + {49.839f,100.0f}, + {73.6486f,0.0f} +}; + +static const SFG_StrokeVertex ch87st3[] = +{ + {97.4581f,100.0f}, + {73.6486f,0.0f} +}; + +static const SFG_StrokeStrip ch87st[] = +{ + {2,ch87st0}, + {2,ch87st1}, + {2,ch87st2}, + {2,ch87st3} +}; + +static const SFG_StrokeChar ch87 = {100.518f,4,ch87st}; + +/* char: 0x58 */ + +static const SFG_StrokeVertex ch88st0[] = +{ + {2.5f,100.0f}, + {69.1667f,0.0f} +}; + +static const SFG_StrokeVertex ch88st1[] = +{ + {69.1667f,100.0f}, + {2.5f,0.0f} +}; + +static const SFG_StrokeStrip ch88st[] = +{ + {2,ch88st0}, + {2,ch88st1} +}; + +static const SFG_StrokeChar ch88 = {72.3667f,2,ch88st}; + +/* char: 0x59 */ + +static const SFG_StrokeVertex ch89st0[] = +{ + {1.52f,100.0f}, + {39.6152f,52.381f}, + {39.6152f,0.0f} +}; + +static const SFG_StrokeVertex ch89st1[] = +{ + {77.7105f,100.0f}, + {39.6152f,52.381f} +}; + +static const SFG_StrokeStrip ch89st[] = +{ + {3,ch89st0}, + {2,ch89st1} +}; + +static const SFG_StrokeChar ch89 = {79.6505f,2,ch89st}; + +/* char: 0x5a */ + +static const SFG_StrokeVertex ch90st0[] = +{ + {69.1667f,100.0f}, + {2.5f,0.0f} +}; + +static const SFG_StrokeVertex ch90st1[] = +{ + {2.5f,100.0f}, + {69.1667f,100.0f} +}; + +static const SFG_StrokeVertex ch90st2[] = +{ + {2.5f,0.0f}, + {69.1667f,0.0f} +}; + +static const SFG_StrokeStrip ch90st[] = +{ + {2,ch90st0}, + {2,ch90st1}, + {2,ch90st2} +}; + +static const SFG_StrokeChar ch90 = {73.7467f,3,ch90st}; + +/* char: 0x5b */ + +static const SFG_StrokeVertex ch91st0[] = +{ + {7.78f,119.048f}, + {7.78f,-33.3333f} +}; + +static const SFG_StrokeVertex ch91st1[] = +{ + {12.5419f,119.048f}, + {12.5419f,-33.3333f} +}; + +static const SFG_StrokeVertex ch91st2[] = +{ + {7.78f,119.048f}, + {41.1133f,119.048f} +}; + +static const SFG_StrokeVertex ch91st3[] = +{ + {7.78f,-33.3333f}, + {41.1133f,-33.3333f} +}; + +static const SFG_StrokeStrip ch91st[] = +{ + {2,ch91st0}, + {2,ch91st1}, + {2,ch91st2}, + {2,ch91st3} +}; + +static const SFG_StrokeChar ch91 = {46.1133f,4,ch91st}; + +/* char: 0x5c */ + +static const SFG_StrokeVertex ch92st0[] = +{ + {5.84f,100.0f}, + {72.5067f,-14.2857f} +}; + +static const SFG_StrokeStrip ch92st[] = +{ + {2,ch92st0} +}; + +static const SFG_StrokeChar ch92 = {78.2067f,1,ch92st}; + +/* char: 0x5d */ + +static const SFG_StrokeVertex ch93st0[] = +{ + {33.0114f,119.048f}, + {33.0114f,-33.3333f} +}; + +static const SFG_StrokeVertex ch93st1[] = +{ + {37.7733f,119.048f}, + {37.7733f,-33.3333f} +}; + +static const SFG_StrokeVertex ch93st2[] = +{ + {4.44f,119.048f}, + {37.7733f,119.048f} +}; + +static const SFG_StrokeVertex ch93st3[] = +{ + {4.44f,-33.3333f}, + {37.7733f,-33.3333f} +}; + +static const SFG_StrokeStrip ch93st[] = +{ + {2,ch93st0}, + {2,ch93st1}, + {2,ch93st2}, + {2,ch93st3} +}; + +static const SFG_StrokeChar ch93 = {46.3933f,4,ch93st}; + +/* char: 0x5e */ + +static const SFG_StrokeVertex ch94st0[] = +{ + {44.0752f,109.524f}, + {5.98f,42.8571f} +}; + +static const SFG_StrokeVertex ch94st1[] = +{ + {44.0752f,109.524f}, + {82.1705f,42.8571f} +}; + +static const SFG_StrokeStrip ch94st[] = +{ + {2,ch94st0}, + {2,ch94st1} +}; + +static const SFG_StrokeChar ch94 = {90.2305f,2,ch94st}; + +/* char: 0x5f */ + +static const SFG_StrokeVertex ch95st0[] = +{ + {-1.1f,-33.3333f}, + {103.662f,-33.3333f}, + {103.662f,-28.5714f}, + {-1.1f,-28.5714f}, + {-1.1f,-33.3333f} +}; + +static const SFG_StrokeStrip ch95st[] = +{ + {5,ch95st0} +}; + +static const SFG_StrokeChar ch95 = {104.062f,1,ch95st}; + +/* char: 0x60 */ + +static const SFG_StrokeVertex ch96st0[] = +{ + {33.0219f,100.0f}, + {56.8314f,71.4286f} +}; + +static const SFG_StrokeVertex ch96st1[] = +{ + {33.0219f,100.0f}, + {28.26f,95.2381f}, + {56.8314f,71.4286f} +}; + +static const SFG_StrokeStrip ch96st[] = +{ + {2,ch96st0}, + {3,ch96st1} +}; + +static const SFG_StrokeChar ch96 = {83.5714f,2,ch96st}; + +/* char: 0x61 */ + +static const SFG_StrokeVertex ch97st0[] = +{ + {63.8229f,66.6667f}, + {63.8229f,0.0f} +}; + +static const SFG_StrokeVertex ch97st1[] = +{ + {63.8229f,52.381f}, + {54.299f,61.9048f}, + {44.7752f,66.6667f}, + {30.4895f,66.6667f}, + {20.9657f,61.9048f}, + {11.4419f,52.381f}, + {6.68f,38.0952f}, + {6.68f,28.5714f}, + {11.4419f,14.2857f}, + {20.9657f,4.7619f}, + {30.4895f,0.0f}, + {44.7752f,0.0f}, + {54.299f,4.7619f}, + {63.8229f,14.2857f} +}; + +static const SFG_StrokeStrip ch97st[] = +{ + {2,ch97st0}, + {14,ch97st1} +}; + +static const SFG_StrokeChar ch97 = {66.6029f,2,ch97st}; + +/* char: 0x62 */ + +static const SFG_StrokeVertex ch98st0[] = +{ + {8.76f,100.0f}, + {8.76f,0.0f} +}; + +static const SFG_StrokeVertex ch98st1[] = +{ + {8.76f,52.381f}, + {18.2838f,61.9048f}, + {27.8076f,66.6667f}, + {42.0933f,66.6667f}, + {51.6171f,61.9048f}, + {61.141f,52.381f}, + {65.9029f,38.0952f}, + {65.9029f,28.5714f}, + {61.141f,14.2857f}, + {51.6171f,4.7619f}, + {42.0933f,0.0f}, + {27.8076f,0.0f}, + {18.2838f,4.7619f}, + {8.76f,14.2857f} +}; + +static const SFG_StrokeStrip ch98st[] = +{ + {2,ch98st0}, + {14,ch98st1} +}; + +static const SFG_StrokeChar ch98 = {70.4629f,2,ch98st}; + +/* char: 0x63 */ + +static const SFG_StrokeVertex ch99st0[] = +{ + {62.6629f,52.381f}, + {53.139f,61.9048f}, + {43.6152f,66.6667f}, + {29.3295f,66.6667f}, + {19.8057f,61.9048f}, + {10.2819f,52.381f}, + {5.52f,38.0952f}, + {5.52f,28.5714f}, + {10.2819f,14.2857f}, + {19.8057f,4.7619f}, + {29.3295f,0.0f}, + {43.6152f,0.0f}, + {53.139f,4.7619f}, + {62.6629f,14.2857f} +}; + +static const SFG_StrokeStrip ch99st[] = +{ + {14,ch99st0} +}; + +static const SFG_StrokeChar ch99 = {68.9229f,1,ch99st}; + +/* char: 0x64 */ + +static const SFG_StrokeVertex ch100st0[] = +{ + {61.7829f,100.0f}, + {61.7829f,0.0f} +}; + +static const SFG_StrokeVertex ch100st1[] = +{ + {61.7829f,52.381f}, + {52.259f,61.9048f}, + {42.7352f,66.6667f}, + {28.4495f,66.6667f}, + {18.9257f,61.9048f}, + {9.4019f,52.381f}, + {4.64f,38.0952f}, + {4.64f,28.5714f}, + {9.4019f,14.2857f}, + {18.9257f,4.7619f}, + {28.4495f,0.0f}, + {42.7352f,0.0f}, + {52.259f,4.7619f}, + {61.7829f,14.2857f} +}; + +static const SFG_StrokeStrip ch100st[] = +{ + {2,ch100st0}, + {14,ch100st1} +}; + +static const SFG_StrokeChar ch100 = {70.2629f,2,ch100st}; + +/* char: 0x65 */ + +static const SFG_StrokeVertex ch101st0[] = +{ + {5.72f,38.0952f}, + {62.8629f,38.0952f}, + {62.8629f,47.619f}, + {58.101f,57.1429f}, + {53.339f,61.9048f}, + {43.8152f,66.6667f}, + {29.5295f,66.6667f}, + {20.0057f,61.9048f}, + {10.4819f,52.381f}, + {5.72f,38.0952f}, + {5.72f,28.5714f}, + {10.4819f,14.2857f}, + {20.0057f,4.7619f}, + {29.5295f,0.0f}, + {43.8152f,0.0f}, + {53.339f,4.7619f}, + {62.8629f,14.2857f} +}; + +static const SFG_StrokeStrip ch101st[] = +{ + {17,ch101st0} +}; + +static const SFG_StrokeChar ch101 = {68.5229f,1,ch101st}; + +/* char: 0x66 */ + +static const SFG_StrokeVertex ch102st0[] = +{ + {38.7752f,100.0f}, + {29.2514f,100.0f}, + {19.7276f,95.2381f}, + {14.9657f,80.9524f}, + {14.9657f,0.0f} +}; + +static const SFG_StrokeVertex ch102st1[] = +{ + {0.68f,66.6667f}, + {34.0133f,66.6667f} +}; + +static const SFG_StrokeStrip ch102st[] = +{ + {5,ch102st0}, + {2,ch102st1} +}; + +static const SFG_StrokeChar ch102 = {38.6552f,2,ch102st}; + +/* char: 0x67 */ + +static const SFG_StrokeVertex ch103st0[] = +{ + {62.5029f,66.6667f}, + {62.5029f,-9.5238f}, + {57.741f,-23.8095f}, + {52.979f,-28.5714f}, + {43.4552f,-33.3333f}, + {29.1695f,-33.3333f}, + {19.6457f,-28.5714f} +}; + +static const SFG_StrokeVertex ch103st1[] = +{ + {62.5029f,52.381f}, + {52.979f,61.9048f}, + {43.4552f,66.6667f}, + {29.1695f,66.6667f}, + {19.6457f,61.9048f}, + {10.1219f,52.381f}, + {5.36f,38.0952f}, + {5.36f,28.5714f}, + {10.1219f,14.2857f}, + {19.6457f,4.7619f}, + {29.1695f,0.0f}, + {43.4552f,0.0f}, + {52.979f,4.7619f}, + {62.5029f,14.2857f} +}; + +static const SFG_StrokeStrip ch103st[] = +{ + {7,ch103st0}, + {14,ch103st1} +}; + +static const SFG_StrokeChar ch103 = {70.9829f,2,ch103st}; + +/* char: 0x68 */ + +static const SFG_StrokeVertex ch104st0[] = +{ + {9.6f,100.0f}, + {9.6f,0.0f} +}; + +static const SFG_StrokeVertex ch104st1[] = +{ + {9.6f,47.619f}, + {23.8857f,61.9048f}, + {33.4095f,66.6667f}, + {47.6952f,66.6667f}, + {57.219f,61.9048f}, + {61.981f,47.619f}, + {61.981f,0.0f} +}; + +static const SFG_StrokeStrip ch104st[] = +{ + {2,ch104st0}, + {7,ch104st1} +}; + +static const SFG_StrokeChar ch104 = {71.021f,2,ch104st}; + +/* char: 0x69 */ + +static const SFG_StrokeVertex ch105st0[] = +{ + {10.02f,100.0f}, + {14.7819f,95.2381f}, + {19.5438f,100.0f}, + {14.7819f,104.762f}, + {10.02f,100.0f} +}; + +static const SFG_StrokeVertex ch105st1[] = +{ + {14.7819f,66.6667f}, + {14.7819f,0.0f} +}; + +static const SFG_StrokeStrip ch105st[] = +{ + {5,ch105st0}, + {2,ch105st1} +}; + +static const SFG_StrokeChar ch105 = {28.8638f,2,ch105st}; + +/* char: 0x6a */ + +static const SFG_StrokeVertex ch106st0[] = +{ + {17.3876f,100.0f}, + {22.1495f,95.2381f}, + {26.9114f,100.0f}, + {22.1495f,104.762f}, + {17.3876f,100.0f} +}; + +static const SFG_StrokeVertex ch106st1[] = +{ + {22.1495f,66.6667f}, + {22.1495f,-14.2857f}, + {17.3876f,-28.5714f}, + {7.8638f,-33.3333f}, + {-1.66f,-33.3333f} +}; + +static const SFG_StrokeStrip ch106st[] = +{ + {5,ch106st0}, + {5,ch106st1} +}; + +static const SFG_StrokeChar ch106 = {36.2314f,2,ch106st}; + +/* char: 0x6b */ + +static const SFG_StrokeVertex ch107st0[] = +{ + {9.6f,100.0f}, + {9.6f,0.0f} +}; + +static const SFG_StrokeVertex ch107st1[] = +{ + {57.219f,66.6667f}, + {9.6f,19.0476f} +}; + +static const SFG_StrokeVertex ch107st2[] = +{ + {28.6476f,38.0952f}, + {61.981f,0.0f} +}; + +static const SFG_StrokeStrip ch107st[] = +{ + {2,ch107st0}, + {2,ch107st1}, + {2,ch107st2} +}; + +static const SFG_StrokeChar ch107 = {62.521f,3,ch107st}; + +/* char: 0x6c */ + +static const SFG_StrokeVertex ch108st0[] = +{ + {10.02f,100.0f}, + {10.02f,0.0f} +}; + +static const SFG_StrokeStrip ch108st[] = +{ + {2,ch108st0} +}; + +static const SFG_StrokeChar ch108 = {19.34f,1,ch108st}; + +/* char: 0x6d */ + +static const SFG_StrokeVertex ch109st0[] = +{ + {9.6f,66.6667f}, + {9.6f,0.0f} +}; + +static const SFG_StrokeVertex ch109st1[] = +{ + {9.6f,47.619f}, + {23.8857f,61.9048f}, + {33.4095f,66.6667f}, + {47.6952f,66.6667f}, + {57.219f,61.9048f}, + {61.981f,47.619f}, + {61.981f,0.0f} +}; + +static const SFG_StrokeVertex ch109st2[] = +{ + {61.981f,47.619f}, + {76.2667f,61.9048f}, + {85.7905f,66.6667f}, + {100.076f,66.6667f}, + {109.6f,61.9048f}, + {114.362f,47.619f}, + {114.362f,0.0f} +}; + +static const SFG_StrokeStrip ch109st[] = +{ + {2,ch109st0}, + {7,ch109st1}, + {7,ch109st2} +}; + +static const SFG_StrokeChar ch109 = {123.962f,3,ch109st}; + +/* char: 0x6e */ + +static const SFG_StrokeVertex ch110st0[] = +{ + {9.18f,66.6667f}, + {9.18f,0.0f} +}; + +static const SFG_StrokeVertex ch110st1[] = +{ + {9.18f,47.619f}, + {23.4657f,61.9048f}, + {32.9895f,66.6667f}, + {47.2752f,66.6667f}, + {56.799f,61.9048f}, + {61.561f,47.619f}, + {61.561f,0.0f} +}; + +static const SFG_StrokeStrip ch110st[] = +{ + {2,ch110st0}, + {7,ch110st1} +}; + +static const SFG_StrokeChar ch110 = {70.881f,2,ch110st}; + +/* char: 0x6f */ + +static const SFG_StrokeVertex ch111st0[] = +{ + {28.7895f,66.6667f}, + {19.2657f,61.9048f}, + {9.7419f,52.381f}, + {4.98f,38.0952f}, + {4.98f,28.5714f}, + {9.7419f,14.2857f}, + {19.2657f,4.7619f}, + {28.7895f,0.0f}, + {43.0752f,0.0f}, + {52.599f,4.7619f}, + {62.1229f,14.2857f}, + {66.8848f,28.5714f}, + {66.8848f,38.0952f}, + {62.1229f,52.381f}, + {52.599f,61.9048f}, + {43.0752f,66.6667f}, + {28.7895f,66.6667f} +}; + +static const SFG_StrokeStrip ch111st[] = +{ + {17,ch111st0} +}; + +static const SFG_StrokeChar ch111 = {71.7448f,1,ch111st}; + +/* char: 0x70 */ + +static const SFG_StrokeVertex ch112st0[] = +{ + {9.46f,66.6667f}, + {9.46f,-33.3333f} +}; + +static const SFG_StrokeVertex ch112st1[] = +{ + {9.46f,52.381f}, + {18.9838f,61.9048f}, + {28.5076f,66.6667f}, + {42.7933f,66.6667f}, + {52.3171f,61.9048f}, + {61.841f,52.381f}, + {66.6029f,38.0952f}, + {66.6029f,28.5714f}, + {61.841f,14.2857f}, + {52.3171f,4.7619f}, + {42.7933f,0.0f}, + {28.5076f,0.0f}, + {18.9838f,4.7619f}, + {9.46f,14.2857f} +}; + +static const SFG_StrokeStrip ch112st[] = +{ + {2,ch112st0}, + {14,ch112st1} +}; + +static const SFG_StrokeChar ch112 = {70.8029f,2,ch112st}; + +/* char: 0x71 */ + +static const SFG_StrokeVertex ch113st0[] = +{ + {61.9829f,66.6667f}, + {61.9829f,-33.3333f} +}; + +static const SFG_StrokeVertex ch113st1[] = +{ + {61.9829f,52.381f}, + {52.459f,61.9048f}, + {42.9352f,66.6667f}, + {28.6495f,66.6667f}, + {19.1257f,61.9048f}, + {9.6019f,52.381f}, + {4.84f,38.0952f}, + {4.84f,28.5714f}, + {9.6019f,14.2857f}, + {19.1257f,4.7619f}, + {28.6495f,0.0f}, + {42.9352f,0.0f}, + {52.459f,4.7619f}, + {61.9829f,14.2857f} +}; + +static const SFG_StrokeStrip ch113st[] = +{ + {2,ch113st0}, + {14,ch113st1} +}; + +static const SFG_StrokeChar ch113 = {70.7429f,2,ch113st}; + +/* char: 0x72 */ + +static const SFG_StrokeVertex ch114st0[] = +{ + {9.46f,66.6667f}, + {9.46f,0.0f} +}; + +static const SFG_StrokeVertex ch114st1[] = +{ + {9.46f,38.0952f}, + {14.2219f,52.381f}, + {23.7457f,61.9048f}, + {33.2695f,66.6667f}, + {47.5552f,66.6667f} +}; + +static const SFG_StrokeStrip ch114st[] = +{ + {2,ch114st0}, + {5,ch114st1} +}; + +static const SFG_StrokeChar ch114 = {49.4952f,2,ch114st}; + +/* char: 0x73 */ + +static const SFG_StrokeVertex ch115st0[] = +{ + {57.081f,52.381f}, + {52.319f,61.9048f}, + {38.0333f,66.6667f}, + {23.7476f,66.6667f}, + {9.4619f,61.9048f}, + {4.7f,52.381f}, + {9.4619f,42.8571f}, + {18.9857f,38.0952f}, + {42.7952f,33.3333f}, + {52.319f,28.5714f}, + {57.081f,19.0476f}, + {57.081f,14.2857f}, + {52.319f,4.7619f}, + {38.0333f,0.0f}, + {23.7476f,0.0f}, + {9.4619f,4.7619f}, + {4.7f,14.2857f} +}; + +static const SFG_StrokeStrip ch115st[] = +{ + {17,ch115st0} +}; + +static const SFG_StrokeChar ch115 = {62.321f,1,ch115st}; + +/* char: 0x74 */ + +static const SFG_StrokeVertex ch116st0[] = +{ + {14.8257f,100.0f}, + {14.8257f,19.0476f}, + {19.5876f,4.7619f}, + {29.1114f,0.0f}, + {38.6352f,0.0f} +}; + +static const SFG_StrokeVertex ch116st1[] = +{ + {0.54f,66.6667f}, + {33.8733f,66.6667f} +}; + +static const SFG_StrokeStrip ch116st[] = +{ + {5,ch116st0}, + {2,ch116st1} +}; + +static const SFG_StrokeChar ch116 = {39.3152f,2,ch116st}; + +/* char: 0x75 */ + +static const SFG_StrokeVertex ch117st0[] = +{ + {9.46f,66.6667f}, + {9.46f,19.0476f}, + {14.2219f,4.7619f}, + {23.7457f,0.0f}, + {38.0314f,0.0f}, + {47.5552f,4.7619f}, + {61.841f,19.0476f} +}; + +static const SFG_StrokeVertex ch117st1[] = +{ + {61.841f,66.6667f}, + {61.841f,0.0f} +}; + +static const SFG_StrokeStrip ch117st[] = +{ + {7,ch117st0}, + {2,ch117st1} +}; + +static const SFG_StrokeChar ch117 = {71.161f,2,ch117st}; + +/* char: 0x76 */ + +static const SFG_StrokeVertex ch118st0[] = +{ + {1.8f,66.6667f}, + {30.3714f,0.0f} +}; + +static const SFG_StrokeVertex ch118st1[] = +{ + {58.9429f,66.6667f}, + {30.3714f,0.0f} +}; + +static const SFG_StrokeStrip ch118st[] = +{ + {2,ch118st0}, + {2,ch118st1} +}; + +static const SFG_StrokeChar ch118 = {60.6029f,2,ch118st}; + +/* char: 0x77 */ + +static const SFG_StrokeVertex ch119st0[] = +{ + {2.5f,66.6667f}, + {21.5476f,0.0f} +}; + +static const SFG_StrokeVertex ch119st1[] = +{ + {40.5952f,66.6667f}, + {21.5476f,0.0f} +}; + +static const SFG_StrokeVertex ch119st2[] = +{ + {40.5952f,66.6667f}, + {59.6429f,0.0f} +}; + +static const SFG_StrokeVertex ch119st3[] = +{ + {78.6905f,66.6667f}, + {59.6429f,0.0f} +}; + +static const SFG_StrokeStrip ch119st[] = +{ + {2,ch119st0}, + {2,ch119st1}, + {2,ch119st2}, + {2,ch119st3} +}; + +static const SFG_StrokeChar ch119 = {80.4905f,4,ch119st}; + +/* char: 0x78 */ + +static const SFG_StrokeVertex ch120st0[] = +{ + {1.66f,66.6667f}, + {54.041f,0.0f} +}; + +static const SFG_StrokeVertex ch120st1[] = +{ + {54.041f,66.6667f}, + {1.66f,0.0f} +}; + +static const SFG_StrokeStrip ch120st[] = +{ + {2,ch120st0}, + {2,ch120st1} +}; + +static const SFG_StrokeChar ch120 = {56.401f,2,ch120st}; + +/* char: 0x79 */ + +static const SFG_StrokeVertex ch121st0[] = +{ + {6.5619f,66.6667f}, + {35.1333f,0.0f} +}; + +static const SFG_StrokeVertex ch121st1[] = +{ + {63.7048f,66.6667f}, + {35.1333f,0.0f}, + {25.6095f,-19.0476f}, + {16.0857f,-28.5714f}, + {6.5619f,-33.3333f}, + {1.8f,-33.3333f} +}; + +static const SFG_StrokeStrip ch121st[] = +{ + {2,ch121st0}, + {6,ch121st1} +}; + +static const SFG_StrokeChar ch121 = {66.0648f,2,ch121st}; + +/* char: 0x7a */ + +static const SFG_StrokeVertex ch122st0[] = +{ + {56.821f,66.6667f}, + {4.44f,0.0f} +}; + +static const SFG_StrokeVertex ch122st1[] = +{ + {4.44f,66.6667f}, + {56.821f,66.6667f} +}; + +static const SFG_StrokeVertex ch122st2[] = +{ + {4.44f,0.0f}, + {56.821f,0.0f} +}; + +static const SFG_StrokeStrip ch122st[] = +{ + {2,ch122st0}, + {2,ch122st1}, + {2,ch122st2} +}; + +static const SFG_StrokeChar ch122 = {61.821f,3,ch122st}; + +/* char: 0x7b */ + +static const SFG_StrokeVertex ch123st0[] = +{ + {31.1895f,119.048f}, + {21.6657f,114.286f}, + {16.9038f,109.524f}, + {12.1419f,100.0f}, + {12.1419f,90.4762f}, + {16.9038f,80.9524f}, + {21.6657f,76.1905f}, + {26.4276f,66.6667f}, + {26.4276f,57.1429f}, + {16.9038f,47.619f} +}; + +static const SFG_StrokeVertex ch123st1[] = +{ + {21.6657f,114.286f}, + {16.9038f,104.762f}, + {16.9038f,95.2381f}, + {21.6657f,85.7143f}, + {26.4276f,80.9524f}, + {31.1895f,71.4286f}, + {31.1895f,61.9048f}, + {26.4276f,52.381f}, + {7.38f,42.8571f}, + {26.4276f,33.3333f}, + {31.1895f,23.8095f}, + {31.1895f,14.2857f}, + {26.4276f,4.7619f}, + {21.6657f,0.0f}, + {16.9038f,-9.5238f}, + {16.9038f,-19.0476f}, + {21.6657f,-28.5714f} +}; + +static const SFG_StrokeVertex ch123st2[] = +{ + {16.9038f,38.0952f}, + {26.4276f,28.5714f}, + {26.4276f,19.0476f}, + {21.6657f,9.5238f}, + {16.9038f,4.7619f}, + {12.1419f,-4.7619f}, + {12.1419f,-14.2857f}, + {16.9038f,-23.8095f}, + {21.6657f,-28.5714f}, + {31.1895f,-33.3333f} +}; + +static const SFG_StrokeStrip ch123st[] = +{ + {10,ch123st0}, + {17,ch123st1}, + {10,ch123st2} +}; + +static const SFG_StrokeChar ch123 = {41.6295f,3,ch123st}; + +/* char: 0x7c */ + +static const SFG_StrokeVertex ch124st0[] = +{ + {11.54f,119.048f}, + {11.54f,-33.3333f} +}; + +static const SFG_StrokeStrip ch124st[] = +{ + {2,ch124st0} +}; + +static const SFG_StrokeChar ch124 = {23.78f,1,ch124st}; + +/* char: 0x7d */ + +static const SFG_StrokeVertex ch125st0[] = +{ + {9.18f,119.048f}, + {18.7038f,114.286f}, + {23.4657f,109.524f}, + {28.2276f,100.0f}, + {28.2276f,90.4762f}, + {23.4657f,80.9524f}, + {18.7038f,76.1905f}, + {13.9419f,66.6667f}, + {13.9419f,57.1429f}, + {23.4657f,47.619f} +}; + +static const SFG_StrokeVertex ch125st1[] = +{ + {18.7038f,114.286f}, + {23.4657f,104.762f}, + {23.4657f,95.2381f}, + {18.7038f,85.7143f}, + {13.9419f,80.9524f}, + {9.18f,71.4286f}, + {9.18f,61.9048f}, + {13.9419f,52.381f}, + {32.9895f,42.8571f}, + {13.9419f,33.3333f}, + {9.18f,23.8095f}, + {9.18f,14.2857f}, + {13.9419f,4.7619f}, + {18.7038f,0.0f}, + {23.4657f,-9.5238f}, + {23.4657f,-19.0476f}, + {18.7038f,-28.5714f} +}; + +static const SFG_StrokeVertex ch125st2[] = +{ + {23.4657f,38.0952f}, + {13.9419f,28.5714f}, + {13.9419f,19.0476f}, + {18.7038f,9.5238f}, + {23.4657f,4.7619f}, + {28.2276f,-4.7619f}, + {28.2276f,-14.2857f}, + {23.4657f,-23.8095f}, + {18.7038f,-28.5714f}, + {9.18f,-33.3333f} +}; + +static const SFG_StrokeStrip ch125st[] = +{ + {10,ch125st0}, + {17,ch125st1}, + {10,ch125st2} +}; + +static const SFG_StrokeChar ch125 = {41.4695f,3,ch125st}; + +/* char: 0x7e */ + +static const SFG_StrokeVertex ch126st0[] = +{ + {2.92f,28.5714f}, + {2.92f,38.0952f}, + {7.6819f,52.381f}, + {17.2057f,57.1429f}, + {26.7295f,57.1429f}, + {36.2533f,52.381f}, + {55.301f,38.0952f}, + {64.8248f,33.3333f}, + {74.3486f,33.3333f}, + {83.8724f,38.0952f}, + {88.6343f,47.619f} +}; + +static const SFG_StrokeVertex ch126st1[] = +{ + {2.92f,38.0952f}, + {7.6819f,47.619f}, + {17.2057f,52.381f}, + {26.7295f,52.381f}, + {36.2533f,47.619f}, + {55.301f,33.3333f}, + {64.8248f,28.5714f}, + {74.3486f,28.5714f}, + {83.8724f,33.3333f}, + {88.6343f,47.619f}, + {88.6343f,57.1429f} +}; + +static const SFG_StrokeStrip ch126st[] = +{ + {11,ch126st0}, + {11,ch126st1} +}; + +static const SFG_StrokeChar ch126 = {91.2743f,2,ch126st}; + +/* char: 0x7f */ + +static const SFG_StrokeVertex ch127st0[] = +{ + {52.381f,100.0f}, + {14.2857f,-33.3333f} +}; + +static const SFG_StrokeVertex ch127st1[] = +{ + {28.5714f,66.6667f}, + {14.2857f,61.9048f}, + {4.7619f,52.381f}, + {0.0f,38.0952f}, + {0.0f,23.8095f}, + {4.7619f,14.2857f}, + {14.2857f,4.7619f}, + {28.5714f,0.0f}, + {38.0952f,0.0f}, + {52.381f,4.7619f}, + {61.9048f,14.2857f}, + {66.6667f,28.5714f}, + {66.6667f,42.8571f}, + {61.9048f,52.381f}, + {52.381f,61.9048f}, + {38.0952f,66.6667f}, + {28.5714f,66.6667f} +}; + +static const SFG_StrokeStrip ch127st[] = +{ + {2,ch127st0}, + {17,ch127st1} +}; + +static const SFG_StrokeChar ch127 = {66.6667f,2,ch127st}; + +static const SFG_StrokeChar *chars[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + &ch32, &ch33, &ch34, &ch35, &ch36, &ch37, &ch38, &ch39, + &ch40, &ch41, &ch42, &ch43, &ch44, &ch45, &ch46, &ch47, + &ch48, &ch49, &ch50, &ch51, &ch52, &ch53, &ch54, &ch55, + &ch56, &ch57, &ch58, &ch59, &ch60, &ch61, &ch62, &ch63, + &ch64, &ch65, &ch66, &ch67, &ch68, &ch69, &ch70, &ch71, + &ch72, &ch73, &ch74, &ch75, &ch76, &ch77, &ch78, &ch79, + &ch80, &ch81, &ch82, &ch83, &ch84, &ch85, &ch86, &ch87, + &ch88, &ch89, &ch90, &ch91, &ch92, &ch93, &ch94, &ch95, + &ch96, &ch97, &ch98, &ch99, &ch100, &ch101, &ch102, &ch103, + &ch104, &ch105, &ch106, &ch107, &ch108, &ch109, &ch110, &ch111, + &ch112, &ch113, &ch114, &ch115, &ch116, &ch117, &ch118, &ch119, + &ch120, &ch121, &ch122, &ch123, &ch124, &ch125, &ch126, &ch127 +}; + +const SFG_StrokeFont fgStrokeRoman = {"Roman",128,152.381f,chars}; diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_structure.c b/tests/Box2D_v2.2.1/freeglut/freeglut_structure.c new file mode 100755 index 0000000000000..524242c9737d9 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_structure.c @@ -0,0 +1,596 @@ +/* + * freeglut_structure.c + * + * Windows and menus need tree structure + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Sat Dec 18 1999 + * + * 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 + * PAWEL W. OLSZTA 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 "freeglut.h" +#include "freeglut_internal.h" + +/* -- GLOBAL EXPORTS ------------------------------------------------------- */ + +/* + * The SFG_Structure container holds information about windows and menus + * created between glutInit() and glutMainLoop() return. + */ + +SFG_Structure fgStructure = { { NULL, NULL }, /* The list of windows */ + { NULL, NULL }, /* The list of menus */ + { NULL, NULL }, /* Windows to Destroy list */ + NULL, /* The current window */ + NULL, /* The current menu */ + NULL, /* The menu OpenGL context */ + NULL, /* The game mode window */ + 0, /* The current new window ID */ + 0 }; /* The current new menu ID */ + + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +static void fghClearCallBacks( SFG_Window *window ) +{ + if( window ) + { + int i; + for( i = 0; i < TOTAL_CALLBACKS; ++i ) + window->CallBacks[ i ] = NULL; + } +} + +/* + * This private function creates, opens and adds to the hierarchy + * a freeglut window complete with OpenGL context and stuff... + * + * If parent is set to NULL, the window created will be a topmost one. + */ +SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title, + GLboolean positionUse, int x, int y, + GLboolean sizeUse, int w, int h, + GLboolean gameMode, GLboolean isMenu ) +{ + /* Have the window object created */ + SFG_Window *window = (SFG_Window *)calloc( sizeof(SFG_Window), 1 ); + +#if TARGET_HOST_UNIX_X11 + window->Window.FBConfig = NULL; +#endif + fghClearCallBacks( window ); + + /* Initialize the object properties */ + window->ID = ++fgStructure.WindowID; + window->State.OldHeight = window->State.OldWidth = -1; + + fgListInit( &window->Children ); + if( parent ) + { + fgListAppend( &parent->Children, &window->Node ); + window->Parent = parent; + } + else + fgListAppend( &fgStructure.Windows, &window->Node ); + + /* Set the default mouse cursor and reset the modifiers value */ + window->State.Cursor = GLUT_CURSOR_INHERIT; + + window->IsMenu = isMenu; + + window->State.IgnoreKeyRepeat = GL_FALSE; + window->State.KeyRepeating = GL_FALSE; + window->State.IsFullscreen = GL_FALSE; + + /* + * Open the window now. The fgOpenWindow() function is system + * dependant, and resides in freeglut_window.c. Uses fgState. + */ + fgOpenWindow( window, title, positionUse, x, y, sizeUse, w, h, gameMode, + (GLboolean)(parent ? GL_TRUE : GL_FALSE) ); + + return window; +} + +/* + * This private function creates a menu and adds it to the menus list + */ +SFG_Menu* fgCreateMenu( FGCBMenu menuCallback ) +{ + int x = 100, y = 100, w = 100, h = 100; + SFG_Window *current_window = fgStructure.CurrentWindow; + + /* Have the menu object created */ + SFG_Menu* menu = (SFG_Menu *)calloc( sizeof(SFG_Menu), 1 ); + + menu->ParentWindow = NULL; + + /* Create a window for the menu to reside in. */ + + fgCreateWindow( NULL, "freeglut menu", GL_TRUE, x, y, GL_TRUE, w, h, + GL_FALSE, GL_TRUE ); + menu->Window = fgStructure.CurrentWindow; + glutDisplayFunc( fgDisplayMenu ); + + glutHideWindow( ); /* Hide the window for now */ + fgSetWindow( current_window ); + + /* Initialize the object properties: */ + menu->ID = ++fgStructure.MenuID; + menu->Callback = menuCallback; + menu->ActiveEntry = NULL; + + fgListInit( &menu->Entries ); + fgListAppend( &fgStructure.Menus, &menu->Node ); + + /* Newly created menus implicitly become current ones */ + fgStructure.CurrentMenu = menu; + + return menu; +} + +/* + * Function to add a window to the linked list of windows to destroy. + * Subwindows are automatically added because they hang from the window + * structure. + */ +void fgAddToWindowDestroyList( SFG_Window* window ) +{ + SFG_WindowList *new_list_entry = + ( SFG_WindowList* )malloc( sizeof(SFG_WindowList ) ); + new_list_entry->window = window; + fgListAppend( &fgStructure.WindowsToDestroy, &new_list_entry->node ); + + /* Check if the window is the current one... */ + if( fgStructure.CurrentWindow == window ) + fgStructure.CurrentWindow = NULL; + + /* + * Clear all window callbacks except Destroy, which will + * be invoked later. Right now, we are potentially carrying + * out a freeglut operation at the behest of a client callback, + * so we are reluctant to re-enter the client with the Destroy + * callback, right now. The others are all wiped out, however, + * to ensure that they are no longer called after this point. + */ + { + FGCBDestroy destroy = (FGCBDestroy)FETCH_WCB( *window, Destroy ); + fghClearCallBacks( window ); + SET_WCB( *window, Destroy, destroy ); + } +} + +/* + * Function to close down all the windows in the "WindowsToDestroy" list + */ +void fgCloseWindows( ) +{ + while( fgStructure.WindowsToDestroy.First ) + { + SFG_WindowList *window_ptr = fgStructure.WindowsToDestroy.First; + fgDestroyWindow( window_ptr->window ); + fgListRemove( &fgStructure.WindowsToDestroy, &window_ptr->node ); + free( window_ptr ); + } +} + +/* + * This function destroys a window and all of its subwindows. Actually, + * another function, defined in freeglut_window.c is called, but this is + * a whole different story... + */ +void fgDestroyWindow( SFG_Window* window ) +{ + FREEGLUT_INTERNAL_ERROR_EXIT ( window, "Window destroy function called with null window", + "fgDestroyWindow" ); + + while( window->Children.First ) + fgDestroyWindow( ( SFG_Window * )window->Children.First ); + + { + SFG_Window *activeWindow = fgStructure.CurrentWindow; + INVOKE_WCB( *window, Destroy, ( ) ); + fgSetWindow( activeWindow ); + } + + if( window->Parent ) + fgListRemove( &window->Parent->Children, &window->Node ); + else + fgListRemove( &fgStructure.Windows, &window->Node ); + + if( window->ActiveMenu ) + fgDeactivateMenu( window ); + + fghClearCallBacks( window ); + fgCloseWindow( window ); + free( window ); + if( fgStructure.CurrentWindow == window ) + fgStructure.CurrentWindow = NULL; +} + +/* + * This is a helper static function that removes a menu (given its pointer) + * from any windows that can be accessed from a given parent... + */ +static void fghRemoveMenuFromWindow( SFG_Window* window, SFG_Menu* menu ) +{ + SFG_Window *subWindow; + int i; + + /* Check whether this is the active menu in the window */ + if ( menu == window->ActiveMenu ) + window->ActiveMenu = NULL ; + + /* + * Check if the menu is attached to the current window, + * if so, have it detached (by overwriting with a NULL): + */ + for( i = 0; i < FREEGLUT_MAX_MENUS; i++ ) + if( window->Menu[ i ] == menu ) + window->Menu[ i ] = NULL; + + /* Call this function for all of the window's children recursively: */ + for( subWindow = (SFG_Window *)window->Children.First; + subWindow; + subWindow = (SFG_Window *)subWindow->Node.Next) + fghRemoveMenuFromWindow( subWindow, menu ); +} + +/* + * This is a static helper function that removes menu references + * from another menu, given two pointers to them... + */ +static void fghRemoveMenuFromMenu( SFG_Menu* from, SFG_Menu* menu ) +{ + SFG_MenuEntry *entry; + + for( entry = (SFG_MenuEntry *)from->Entries.First; + entry; + entry = ( SFG_MenuEntry * )entry->Node.Next ) + if( entry->SubMenu == menu ) + entry->SubMenu = NULL; +} + +/* + * This function destroys a menu specified by the parameter. All menus + * and windows are updated to make sure no ill pointers hang around. + */ +void fgDestroyMenu( SFG_Menu* menu ) +{ + SFG_Window *window; + SFG_Menu *from; + + FREEGLUT_INTERNAL_ERROR_EXIT ( menu, "Menu destroy function called with null menu", + "fgDestroyMenu" ); + + /* First of all, have all references to this menu removed from all windows: */ + for( window = (SFG_Window *)fgStructure.Windows.First; + window; + window = (SFG_Window *)window->Node.Next ) + fghRemoveMenuFromWindow( window, menu ); + + /* Now proceed with removing menu entries that lead to this menu */ + for( from = ( SFG_Menu * )fgStructure.Menus.First; + from; + from = ( SFG_Menu * )from->Node.Next ) + fghRemoveMenuFromMenu( from, menu ); + + /* + * If the programmer defined a destroy callback, call it + * A. Donev: But first make this the active menu + */ + if( menu->Destroy ) + { + SFG_Menu *activeMenu=fgStructure.CurrentMenu; + fgStructure.CurrentMenu = menu; + menu->Destroy( ); + fgStructure.CurrentMenu = activeMenu; + } + + /* + * Now we are pretty sure the menu is not used anywhere + * and that we can remove all of its entries + */ + while( menu->Entries.First ) + { + SFG_MenuEntry *entry = ( SFG_MenuEntry * ) menu->Entries.First; + + fgListRemove( &menu->Entries, &entry->Node ); + + if( entry->Text ) + free( entry->Text ); + entry->Text = NULL; + + free( entry ); + } + + if( fgStructure.CurrentWindow == menu->Window ) + fgSetWindow( NULL ); + fgDestroyWindow( menu->Window ); + fgListRemove( &fgStructure.Menus, &menu->Node ); + if( fgStructure.CurrentMenu == menu ) + fgStructure.CurrentMenu = NULL; + + free( menu ); +} + +/* + * This function should be called on glutInit(). It will prepare the internal + * structure of freeglut to be used in the application. The structure will be + * destroyed using fgDestroyStructure() on glutMainLoop() return. In that + * case further use of freeglut should be preceeded with a glutInit() call. + */ +void fgCreateStructure( void ) +{ + /* + * We will be needing two lists: the first containing windows, + * and the second containing the user-defined menus. + * Also, no current window/menu is set, as none has been created yet. + */ + + fgListInit(&fgStructure.Windows); + fgListInit(&fgStructure.Menus); + fgListInit(&fgStructure.WindowsToDestroy); + + fgStructure.CurrentWindow = NULL; + fgStructure.CurrentMenu = NULL; + fgStructure.MenuContext = NULL; + fgStructure.GameModeWindow = NULL; + fgStructure.WindowID = 0; + fgStructure.MenuID = 0; +} + +/* + * This function is automatically called on glutMainLoop() return. + * It should deallocate and destroy all remnants of previous + * glutInit()-enforced structure initialization... + */ +void fgDestroyStructure( void ) +{ + /* Clean up the WindowsToDestroy list. */ + fgCloseWindows( ); + + /* Make sure all windows and menus have been deallocated */ + while( fgStructure.Menus.First ) + fgDestroyMenu( ( SFG_Menu * )fgStructure.Menus.First ); + + while( fgStructure.Windows.First ) + fgDestroyWindow( ( SFG_Window * )fgStructure.Windows.First ); +} + +/* + * Helper function to enumerate through all registered top-level windows + */ +void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator ) +{ + SFG_Window *window; + + FREEGLUT_INTERNAL_ERROR_EXIT ( enumCallback && enumerator, + "Enumerator or callback missing from window enumerator call", + "fgEnumWindows" ); + + /* Check every of the top-level windows */ + for( window = ( SFG_Window * )fgStructure.Windows.First; + window; + window = ( SFG_Window * )window->Node.Next ) + { + enumCallback( window, enumerator ); + if( enumerator->found ) + return; + } +} + +/* + * Helper function to enumerate through all a window's subwindows + * (single level descent) + */ +void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback, + SFG_Enumerator* enumerator ) +{ + SFG_Window *child; + + FREEGLUT_INTERNAL_ERROR_EXIT ( enumCallback && enumerator, + "Enumerator or callback missing from subwindow enumerator call", + "fgEnumSubWindows" ); + FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Window Enumeration" ); + + for( child = ( SFG_Window * )window->Children.First; + child; + child = ( SFG_Window * )child->Node.Next ) + { + enumCallback( child, enumerator ); + if( enumerator->found ) + return; + } +} + +/* + * A static helper function to look for a window given its handle + */ +static void fghcbWindowByHandle( SFG_Window *window, + SFG_Enumerator *enumerator ) +{ + if ( enumerator->found ) + return; + + /* Check the window's handle. Hope this works. Looks ugly. That's for sure. */ + if( window->Window.Handle == (SFG_WindowHandleType) (enumerator->data) ) + { + enumerator->found = GL_TRUE; + enumerator->data = window; + + return; + } + + /* Otherwise, check this window's children */ + fgEnumSubWindows( window, fghcbWindowByHandle, enumerator ); +} + +/* + * fgWindowByHandle returns a (SFG_Window *) value pointing to the + * first window in the queue matching the specified window handle. + * The function is defined in freeglut_structure.c file. + */ +SFG_Window* fgWindowByHandle ( SFG_WindowHandleType hWindow ) +{ + SFG_Enumerator enumerator; + + /* This is easy and makes use of the windows enumeration defined above */ + enumerator.found = GL_FALSE; + enumerator.data = (void *)hWindow; + fgEnumWindows( fghcbWindowByHandle, &enumerator ); + + if( enumerator.found ) + return( SFG_Window *) enumerator.data; + return NULL; +} + +/* + * A static helper function to look for a window given its ID + */ +static void fghcbWindowByID( SFG_Window *window, SFG_Enumerator *enumerator ) +{ + /* Make sure we do not overwrite our precious results... */ + if( enumerator->found ) + return; + + /* Check the window's handle. Hope this works. Looks ugly. That's for sure. */ + if( window->ID == *( int *)(enumerator->data) ) + { + enumerator->found = GL_TRUE; + enumerator->data = window; + + return; + } + + /* Otherwise, check this window's children */ + fgEnumSubWindows( window, fghcbWindowByID, enumerator ); +} + +/* + * This function is similiar to the previous one, except it is + * looking for a specified (sub)window identifier. The function + * is defined in freeglut_structure.c file. + */ +SFG_Window* fgWindowByID( int windowID ) +{ + SFG_Enumerator enumerator; + + /* Uses a method very similiar for fgWindowByHandle... */ + enumerator.found = GL_FALSE; + enumerator.data = ( void * )&windowID; + fgEnumWindows( fghcbWindowByID, &enumerator ); + if( enumerator.found ) + return ( SFG_Window * )enumerator.data; + return NULL; +} + +/* + * Looks up a menu given its ID. This is easier that fgWindowByXXX + * as all menus are placed in one doubly linked list... + */ +SFG_Menu* fgMenuByID( int menuID ) +{ + SFG_Menu *menu = NULL; + + /* It's enough to check all entries in fgStructure.Menus... */ + for( menu = (SFG_Menu *)fgStructure.Menus.First; + menu; + menu = (SFG_Menu *)menu->Node.Next ) + if( menu->ID == menuID ) + return menu; + return NULL; +} + +/* + * List functions... + */ +void fgListInit(SFG_List *list) +{ + list->First = NULL; + list->Last = NULL; +} + +void fgListAppend(SFG_List *list, SFG_Node *node) +{ + if ( list->Last ) + { + SFG_Node *ln = (SFG_Node *) list->Last; + ln->Next = node; + node->Prev = ln; + } + else + { + node->Prev = NULL; + list->First = node; + } + + node->Next = NULL; + list->Last = node; +} + +void fgListRemove(SFG_List *list, SFG_Node *node) +{ + if( node->Next ) + ( ( SFG_Node * )node->Next )->Prev = node->Prev; + if( node->Prev ) + ( ( SFG_Node * )node->Prev )->Next = node->Next; + if( ( ( SFG_Node * )list->First ) == node ) + list->First = node->Next; + if( ( ( SFG_Node * )list->Last ) == node ) + list->Last = node->Prev; +} + +int fgListLength(SFG_List *list) +{ + SFG_Node *node; + int length = 0; + + for( node =( SFG_Node * )list->First; + node; + node = ( SFG_Node * )node->Next ) + ++length; + + return length; +} + + +void fgListInsert(SFG_List *list, SFG_Node *next, SFG_Node *node) +{ + SFG_Node *prev; + + if( (node->Next = next) ) + { + prev = next->Prev; + next->Prev = node; + } + else + { + prev = list->Last; + list->Last = node; + } + + if( (node->Prev = prev) ) + prev->Next = node; + else + list->First = node; +} + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_teapot.c b/tests/Box2D_v2.2.1/freeglut/freeglut_teapot.c new file mode 100755 index 0000000000000..2b4fc24e95d8b --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_teapot.c @@ -0,0 +1,200 @@ +/* + * freeglut_teapot.c + * + * Teapot(tm) rendering code. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Fri Dec 24 1999 + * + * 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 + * PAWEL W. OLSZTA 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. + */ + +/* + * Original teapot code copyright follows: + */ + +/* + * (c) Copyright 1993, Silicon Graphics, Inc. + * + * ALL RIGHTS RESERVED + * + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that + * both the copyright notice and this permission notice appear in + * supporting documentation, and that the name of Silicon + * Graphics, Inc. not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU + * "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR + * OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO + * EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE + * ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, + * INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, + * SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR + * NOT SILICON GRAPHICS, INC. HAS BEEN ADVISED OF THE POSSIBILITY + * OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer + * Software clause at DFARS 252.227-7013 and/or in similar or + * successor clauses in the FAR or the DOD or NASA FAR + * Supplement. Unpublished-- rights reserved under the copyright + * laws of the United States. Contractor/manufacturer is Silicon + * Graphics, Inc., 2011 N. Shoreline Blvd., Mountain View, CA + * 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" +#include "freeglut_teapot_data.h" + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + + +static void fghTeapot( GLint grid, GLdouble scale, GLenum type ) +{ +#if defined(_WIN32_WCE) + int i, numV=sizeof(strip_vertices)/4, numI=sizeof(strip_normals)/4; +#else + double p[4][4][3], q[4][4][3], r[4][4][3], s[4][4][3]; + long i, j, k, l; +#endif + + glPushAttrib( GL_ENABLE_BIT | GL_EVAL_BIT ); + glEnable( GL_AUTO_NORMAL ); + glEnable( GL_NORMALIZE ); + glEnable( GL_MAP2_VERTEX_3 ); + glEnable( GL_MAP2_TEXTURE_COORD_2 ); + + glPushMatrix(); + glRotated( 270.0, 1.0, 0.0, 0.0 ); + glScaled( 0.5 * scale, 0.5 * scale, 0.5 * scale ); + glTranslated( 0.0, 0.0, -1.5 ); + +#if defined(_WIN32_WCE) + glRotated( 90.0, 1.0, 0.0, 0.0 ); + glBegin( GL_TRIANGLE_STRIP ); + + for( i = 0; i < numV-1; i++ ) + { + int vidx = strip_vertices[i], + nidx = strip_normals[i]; + + if( vidx != -1 ) + { + glNormal3fv( normals[nidx] ); + glVertex3fv( vertices[vidx] ); + } + else + { + glEnd(); + glBegin( GL_TRIANGLE_STRIP ); + } + } + + glEnd(); +#else + for (i = 0; i < 10; i++) { + for (j = 0; j < 4; j++) { + for (k = 0; k < 4; k++) { + for (l = 0; l < 3; l++) { + p[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l]; + q[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l]; + if (l == 1) + q[j][k][l] *= -1.0; + if (i < 6) { + r[j][k][l] = + cpdata[patchdata[i][j * 4 + (3 - k)]][l]; + if (l == 0) + r[j][k][l] *= -1.0; + s[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l]; + if (l == 0) + s[j][k][l] *= -1.0; + if (l == 1) + s[j][k][l] *= -1.0; + } + } + } + } + + glMap2d(GL_MAP2_TEXTURE_COORD_2, 0.0, 1.0, 2, 2, 0.0, 1.0, 4, 2, + &tex[0][0][0]); + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &p[0][0][0]); + glMapGrid2d(grid, 0.0, 1.0, grid, 0.0, 1.0); + glEvalMesh2(type, 0, grid, 0, grid); + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &q[0][0][0]); + glEvalMesh2(type, 0, grid, 0, grid); + if (i < 6) { + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &r[0][0][0]); + glEvalMesh2(type, 0, grid, 0, grid); + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &s[0][0][0]); + glEvalMesh2(type, 0, grid, 0, grid); + } + } +#endif /* defined(_WIN32_WCE) */ + + glPopMatrix(); + glPopAttrib(); +} + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Renders a beautiful wired teapot... + */ +void FGAPIENTRY glutWireTeapot( GLdouble size ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTeapot" ); + /* We will use the general teapot rendering code */ + fghTeapot( 10, size, GL_LINE ); +} + +/* + * Renders a beautiful filled teapot... + */ +void FGAPIENTRY glutSolidTeapot( GLdouble size ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTeapot" ); + /* We will use the general teapot rendering code */ + fghTeapot( 7, size, GL_FILL ); +} + +/*** END OF FILE ***/ + + + + + diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_teapot_data.h b/tests/Box2D_v2.2.1/freeglut/freeglut_teapot_data.h new file mode 100755 index 0000000000000..3bf83e11f78db --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_teapot_data.h @@ -0,0 +1,2429 @@ +/* + * freeglut_teapot_data.h + * + * The freeglut library teapot data include file. + * + * 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 + * PAWEL W. OLSZTA 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. + */ + +#ifndef FREEGLUT_TEAPOT_DATA_H +#define FREEGLUT_TEAPOT_DATA_H + +#if defined(_WIN32_WCE) +/* + * Submitted through the kind offices of Daniel Wagner (daniel@ims.tuwien.ac.at) + */ + +/* 530 vertices */ + +const int numVertices = 530; +const float vertices[530][3] = { +2.1f, 3.6f, 0.0f, +2.071f, 3.711f, 0.0f, +2.105f, 3.748f, 0.0f, +2.174f, 3.711f, 0.0f, +2.25f, 3.6f, 0.0f, +1.937f, 3.6f, 0.8242f, +1.91f, 3.711f, 0.8128f, +1.942f, 3.748f, 0.8261f, +2.005f, 3.711f, 0.8532f, +2.076f, 3.6f, 0.8831f, +1.491f, 3.6f, 1.491f, +1.47f, 3.711f, 1.47f, +1.494f, 3.748f, 1.494f, +1.543f, 3.711f, 1.543f, +1.597f, 3.6f, 1.597f, +0.8242f, 3.6f, 1.937f, +0.8128f, 3.711f, 1.91f, +0.8261f, 3.748f, 1.942f, +0.8532f, 3.711f, 2.005f, +0.8831f, 3.6f, 2.076f, +0.0f, 3.6f, 2.1f, +0.0f, 3.711f, 2.071f, +0.0f, 3.748f, 2.105f, +0.0f, 3.711f, 2.174f, +0.0f, 3.6f, 2.25f, +-0.8812f, 3.6f, 1.937f, +-0.8368f, 3.711f, 1.91f, +-0.8332f, 3.748f, 1.942f, +-0.8541f, 3.711f, 2.005f, +-0.8831f, 3.6f, 2.076f, +-1.542f, 3.6f, 1.491f, +-1.492f, 3.711f, 1.47f, +-1.501f, 3.748f, 1.494f, +-1.544f, 3.711f, 1.543f, +-1.597f, 3.6f, 1.597f, +-1.956f, 3.6f, 0.8242f, +-1.918f, 3.711f, 0.8128f, +-1.944f, 3.748f, 0.8261f, +-2.006f, 3.711f, 0.8532f, +-2.076f, 3.6f, 0.8831f, +-2.1f, 3.6f, 0.0f, +-2.071f, 3.711f, 0.0f, +-2.105f, 3.748f, 0.0f, +-2.174f, 3.711f, 0.0f, +-2.25f, 3.6f, 0.0f, +-1.937f, 3.6f, -0.8242f, +-1.91f, 3.711f, -0.8128f, +-1.942f, 3.748f, -0.8261f, +-2.005f, 3.711f, -0.8532f, +-2.076f, 3.6f, -0.8831f, +-1.491f, 3.6f, -1.491f, +-1.47f, 3.711f, -1.47f, +-1.494f, 3.748f, -1.494f, +-1.543f, 3.711f, -1.543f, +-1.597f, 3.6f, -1.597f, +-0.8242f, 3.6f, -1.937f, +-0.8128f, 3.711f, -1.91f, +-0.8261f, 3.748f, -1.942f, +-0.8532f, 3.711f, -2.005f, +-0.8831f, 3.6f, -2.076f, +0.0f, 3.6f, -2.1f, +0.0f, 3.711f, -2.071f, +0.0f, 3.748f, -2.105f, +0.0f, 3.711f, -2.174f, +0.0f, 3.6f, -2.25f, +0.8242f, 3.6f, -1.937f, +0.8128f, 3.711f, -1.91f, +0.8261f, 3.748f, -1.942f, +0.8532f, 3.711f, -2.005f, +0.8831f, 3.6f, -2.076f, +1.491f, 3.6f, -1.491f, +1.47f, 3.711f, -1.47f, +1.494f, 3.748f, -1.494f, +1.543f, 3.711f, -1.543f, +1.597f, 3.6f, -1.597f, +1.937f, 3.6f, -0.8242f, +1.91f, 3.711f, -0.8128f, +1.942f, 3.748f, -0.8261f, +2.005f, 3.711f, -0.8532f, +2.076f, 3.6f, -0.8831f, +2.525f, 3.011f, 0.0f, +2.766f, 2.433f, 0.0f, +2.936f, 1.876f, 0.0f, +3.0f, 1.35f, 0.0f, +2.33f, 3.011f, 0.9912f, +2.551f, 2.433f, 1.086f, +2.708f, 1.876f, 1.152f, +2.767f, 1.35f, 1.178f, +1.793f, 3.011f, 1.793f, +1.964f, 2.433f, 1.964f, +2.084f, 1.876f, 2.084f, +2.13f, 1.35f, 2.13f, +0.9912f, 3.011f, 2.33f, +1.086f, 2.433f, 2.551f, +1.152f, 1.876f, 2.708f, +1.178f, 1.35f, 2.767f, +0.0f, 3.011f, 2.525f, +0.0f, 2.433f, 2.766f, +0.0f, 1.876f, 2.936f, +0.0f, 1.35f, 3.0f, +-0.9912f, 3.011f, 2.33f, +-1.086f, 2.433f, 2.551f, +-1.152f, 1.876f, 2.708f, +-1.178f, 1.35f, 2.767f, +-1.793f, 3.011f, 1.793f, +-1.964f, 2.433f, 1.964f, +-2.084f, 1.876f, 2.084f, +-2.13f, 1.35f, 2.13f, +-2.33f, 3.011f, 0.9912f, +-2.551f, 2.433f, 1.086f, +-2.708f, 1.876f, 1.152f, +-2.767f, 1.35f, 1.178f, +-2.525f, 3.011f, 0.0f, +-2.766f, 2.433f, 0.0f, +-2.936f, 1.876f, 0.0f, +-3.0f, 1.35f, 0.0f, +-2.33f, 3.011f, -0.9912f, +-2.551f, 2.433f, -1.086f, +-2.708f, 1.876f, -1.152f, +-2.767f, 1.35f, -1.178f, +-1.793f, 3.011f, -1.793f, +-1.964f, 2.433f, -1.964f, +-2.084f, 1.876f, -2.084f, +-2.13f, 1.35f, -2.13f, +-0.9912f, 3.011f, -2.33f, +-1.086f, 2.433f, -2.551f, +-1.152f, 1.876f, -2.708f, +-1.178f, 1.35f, -2.767f, +0.0f, 3.011f, -2.525f, +0.0f, 2.433f, -2.766f, +0.0f, 1.876f, -2.936f, +0.0f, 1.35f, -3.0f, +0.9912f, 3.011f, -2.33f, +1.086f, 2.433f, -2.551f, +1.152f, 1.876f, -2.708f, +1.178f, 1.35f, -2.767f, +1.793f, 3.011f, -1.793f, +1.964f, 2.433f, -1.964f, +2.084f, 1.876f, -2.084f, +2.13f, 1.35f, -2.13f, +2.33f, 3.011f, -0.9912f, +2.551f, 2.433f, -1.086f, +2.708f, 1.876f, -1.152f, +2.767f, 1.35f, -1.178f, +2.883f, 0.9053f, 0.0f, +2.625f, 0.5766f, 0.0f, +2.367f, 0.3533f, 0.0f, +2.25f, 0.225f, 0.0f, +2.659f, 0.9053f, 1.132f, +2.422f, 0.5766f, 1.03f, +2.184f, 0.3533f, 0.9291f, +2.076f, 0.225f, 0.8831f, +2.047f, 0.9053f, 2.047f, +1.864f, 0.5766f, 1.864f, +1.681f, 0.3533f, 1.681f, +1.597f, 0.225f, 1.597f, +1.132f, 0.9053f, 2.659f, +1.03f, 0.5766f, 2.422f, +0.9291f, 0.3533f, 2.184f, +0.8831f, 0.225f, 2.076f, +0.0f, 0.9053f, 2.883f, +0.0f, 0.5766f, 2.625f, +0.0f, 0.3533f, 2.367f, +0.0f, 0.225f, 2.25f, +-1.132f, 0.9053f, 2.659f, +-1.03f, 0.5766f, 2.422f, +-0.9291f, 0.3533f, 2.184f, +-0.8831f, 0.225f, 2.076f, +-2.047f, 0.9053f, 2.047f, +-1.864f, 0.5766f, 1.864f, +-1.681f, 0.3533f, 1.681f, +-1.597f, 0.225f, 1.597f, +-2.659f, 0.9053f, 1.132f, +-2.422f, 0.5766f, 1.03f, +-2.184f, 0.3533f, 0.9291f, +-2.076f, 0.225f, 0.8831f, +-2.883f, 0.9053f, 0.0f, +-2.625f, 0.5766f, 0.0f, +-2.367f, 0.3533f, 0.0f, +-2.25f, 0.225f, 0.0f, +-2.659f, 0.9053f, -1.132f, +-2.422f, 0.5766f, -1.03f, +-2.184f, 0.3533f, -0.9291f, +-2.076f, 0.225f, -0.8831f, +-2.047f, 0.9053f, -2.047f, +-1.864f, 0.5766f, -1.864f, +-1.681f, 0.3533f, -1.681f, +-1.597f, 0.225f, -1.597f, +-1.132f, 0.9053f, -2.659f, +-1.03f, 0.5766f, -2.422f, +-0.9291f, 0.3533f, -2.184f, +-0.8831f, 0.225f, -2.076f, +0.0f, 0.9053f, -2.883f, +0.0f, 0.5766f, -2.625f, +0.0f, 0.3533f, -2.367f, +0.0f, 0.225f, -2.25f, +1.132f, 0.9053f, -2.659f, +1.03f, 0.5766f, -2.422f, +0.9291f, 0.3533f, -2.184f, +0.8831f, 0.225f, -2.076f, +2.047f, 0.9053f, -2.047f, +1.864f, 0.5766f, -1.864f, +1.681f, 0.3533f, -1.681f, +1.597f, 0.225f, -1.597f, +2.659f, 0.9053f, -1.132f, +2.422f, 0.5766f, -1.03f, +2.184f, 0.3533f, -0.9291f, +2.076f, 0.225f, -0.8831f, +2.199f, 0.1424f, 0.0f, +1.927f, 0.07031f, 0.0f, +1.253f, 0.01934f, 0.0f, +0.0f, 0.0f, 0.0f, +2.029f, 0.1424f, 0.8631f, +1.777f, 0.07031f, 0.7562f, +1.156f, 0.01934f, 0.4919f, +1.561f, 0.1424f, 1.561f, +1.368f, 0.07031f, 1.368f, +0.8899f, 0.01934f, 0.8899f, +0.8631f, 0.1424f, 2.029f, +0.7562f, 0.07031f, 1.777f, +0.4919f, 0.01934f, 1.156f, +0.0f, 0.1424f, 2.199f, +0.0f, 0.07031f, 1.927f, +0.0f, 0.01934f, 1.253f, +-0.8631f, 0.1424f, 2.029f, +-0.7562f, 0.07031f, 1.777f, +-0.4919f, 0.01934f, 1.156f, +-1.561f, 0.1424f, 1.561f, +-1.368f, 0.07031f, 1.368f, +-0.8899f, 0.01934f, 0.8899f, +-2.029f, 0.1424f, 0.8631f, +-1.777f, 0.07031f, 0.7562f, +-1.156f, 0.01934f, 0.4919f, +-2.199f, 0.1424f, 0.0f, +-1.927f, 0.07031f, 0.0f, +-1.253f, 0.01934f, 0.0f, +-2.029f, 0.1424f, -0.8631f, +-1.777f, 0.07031f, -0.7562f, +-1.156f, 0.01934f, -0.4919f, +-1.561f, 0.1424f, -1.561f, +-1.368f, 0.07031f, -1.368f, +-0.8899f, 0.01934f, -0.8899f, +-0.8631f, 0.1424f, -2.029f, +-0.7562f, 0.07031f, -1.777f, +-0.4919f, 0.01934f, -1.156f, +0.0f, 0.1424f, -2.199f, +0.0f, 0.07031f, -1.927f, +0.0f, 0.01934f, -1.253f, +0.8631f, 0.1424f, -2.029f, +0.7562f, 0.07031f, -1.777f, +0.4919f, 0.01934f, -1.156f, +1.561f, 0.1424f, -1.561f, +1.368f, 0.07031f, -1.368f, +0.8899f, 0.01934f, -0.8899f, +2.029f, 0.1424f, -0.8631f, +1.777f, 0.07031f, -0.7562f, +1.156f, 0.01934f, -0.4919f, +-2.4f, 3.038f, 0.0f, +-3.101f, 3.032f, 0.0f, +-3.619f, 2.995f, 0.0f, +-3.94f, 2.895f, 0.0f, +-4.05f, 2.7f, 0.0f, +-2.377f, 3.09f, 0.2531f, +-3.122f, 3.084f, 0.2531f, +-3.669f, 3.041f, 0.2531f, +-4.005f, 2.926f, 0.2531f, +-4.12f, 2.7f, 0.2531f, +-2.325f, 3.206f, 0.3375f, +-3.168f, 3.198f, 0.3375f, +-3.778f, 3.143f, 0.3375f, +-4.15f, 2.993f, 0.3375f, +-4.275f, 2.7f, 0.3375f, +-2.273f, 3.322f, 0.2531f, +-3.214f, 3.313f, 0.2531f, +-3.888f, 3.244f, 0.2531f, +-4.294f, 3.06f, 0.2531f, +-4.43f, 2.7f, 0.2531f, +-2.25f, 3.375f, 0.0f, +-3.234f, 3.364f, 0.0f, +-3.938f, 3.291f, 0.0f, +-4.359f, 3.09f, 0.0f, +-4.5f, 2.7f, 0.0f, +-2.273f, 3.322f, -0.2531f, +-3.214f, 3.313f, -0.2531f, +-3.888f, 3.244f, -0.2531f, +-4.294f, 3.06f, -0.2531f, +-4.43f, 2.7f, -0.2531f, +-2.325f, 3.206f, -0.3375f, +-3.168f, 3.198f, -0.3375f, +-3.778f, 3.143f, -0.3375f, +-4.15f, 2.993f, -0.3375f, +-4.275f, 2.7f, -0.3375f, +-2.377f, 3.09f, -0.2531f, +-3.122f, 3.084f, -0.2531f, +-3.669f, 3.041f, -0.2531f, +-4.005f, 2.926f, -0.2531f, +-4.12f, 2.7f, -0.2531f, +-3.991f, 2.394f, 0.0f, +-3.806f, 2.025f, 0.0f, +-3.48f, 1.656f, 0.0f, +-3.0f, 1.35f, 0.0f, +-4.055f, 2.365f, 0.2531f, +-3.852f, 1.98f, 0.2531f, +-3.496f, 1.6f, 0.2531f, +-2.977f, 1.28f, 0.2531f, +-4.196f, 2.3f, 0.3375f, +-3.952f, 1.881f, 0.3375f, +-3.531f, 1.478f, 0.3375f, +-2.925f, 1.125f, 0.3375f, +-4.336f, 2.235f, 0.2531f, +-4.051f, 1.782f, 0.2531f, +-3.566f, 1.356f, 0.2531f, +-2.873f, 0.9703f, 0.2531f, +-4.4f, 2.205f, 0.0f, +-4.097f, 1.737f, 0.0f, +-3.582f, 1.3f, 0.0f, +-2.85f, 0.9f, 0.0f, +-4.336f, 2.235f, -0.2531f, +-4.051f, 1.782f, -0.2531f, +-3.566f, 1.356f, -0.2531f, +-2.873f, 0.9703f, -0.2531f, +-4.196f, 2.3f, -0.3375f, +-3.952f, 1.881f, -0.3375f, +-3.531f, 1.478f, -0.3375f, +-2.925f, 1.125f, -0.3375f, +-4.055f, 2.365f, -0.2531f, +-3.852f, 1.98f, -0.2531f, +-3.496f, 1.6f, -0.2531f, +-2.977f, 1.28f, -0.2531f, +2.55f, 2.137f, 0.0f, +3.27f, 2.303f, 0.0f, +3.581f, 2.7f, 0.0f, +3.752f, 3.182f, 0.0f, +4.05f, 3.6f, 0.0f, +2.55f, 1.944f, 0.5569f, +3.324f, 2.159f, 0.5028f, +3.652f, 2.617f, 0.3839f, +3.838f, 3.151f, 0.265f, +4.191f, 3.6f, 0.2109f, +2.55f, 1.519f, 0.7425f, +3.445f, 1.844f, 0.6704f, +3.806f, 2.433f, 0.5119f, +4.027f, 3.085f, 0.3533f, +4.5f, 3.6f, 0.2813f, +2.55f, 1.093f, 0.5569f, +3.566f, 1.529f, 0.5028f, +3.961f, 2.249f, 0.3839f, +4.215f, 3.018f, 0.265f, +4.809f, 3.6f, 0.2109f, +2.55f, 0.9f, 0.0f, +3.621f, 1.385f, 0.0f, +4.031f, 2.166f, 0.0f, +4.301f, 2.988f, 0.0f, +4.95f, 3.6f, 0.0f, +2.55f, 1.093f, -0.5569f, +3.566f, 1.529f, -0.5028f, +3.961f, 2.249f, -0.3839f, +4.215f, 3.018f, -0.265f, +4.809f, 3.6f, -0.2109f, +2.55f, 1.519f, -0.7425f, +3.445f, 1.844f, -0.6704f, +3.806f, 2.433f, -0.5119f, +4.027f, 3.085f, -0.3533f, +4.5f, 3.6f, -0.2813f, +2.55f, 1.944f, -0.5569f, +3.324f, 2.159f, -0.5028f, +3.652f, 2.617f, -0.3839f, +3.838f, 3.151f, -0.265f, +4.191f, 3.6f, -0.2109f, +4.158f, 3.663f, 0.0f, +4.238f, 3.684f, 0.0f, +4.261f, 3.663f, 0.0f, +4.2f, 3.6f, 0.0f, +4.308f, 3.666f, 0.1978f, +4.379f, 3.689f, 0.1687f, +4.381f, 3.668f, 0.1397f, +4.294f, 3.6f, 0.1266f, +4.64f, 3.673f, 0.2637f, +4.69f, 3.7f, 0.225f, +4.645f, 3.677f, 0.1863f, +4.5f, 3.6f, 0.1688f, +4.971f, 3.68f, 0.1978f, +5.001f, 3.711f, 0.1687f, +4.909f, 3.687f, 0.1397f, +4.706f, 3.6f, 0.1266f, +5.122f, 3.683f, 0.0f, +5.142f, 3.716f, 0.0f, +5.029f, 3.691f, 0.0f, +4.8f, 3.6f, 0.0f, +4.971f, 3.68f, -0.1978f, +5.001f, 3.711f, -0.1687f, +4.909f, 3.687f, -0.1397f, +4.706f, 3.6f, -0.1266f, +4.64f, 3.673f, -0.2637f, +4.69f, 3.7f, -0.225f, +4.645f, 3.677f, -0.1863f, +4.5f, 3.6f, -0.1688f, +4.308f, 3.666f, -0.1978f, +4.379f, 3.689f, -0.1687f, +4.381f, 3.668f, -0.1397f, +4.294f, 3.6f, -0.1266f, +0.0f, 4.725f, 0.0f, +0.5109f, 4.651f, 0.0f, +0.4875f, 4.472f, 0.0f, +0.2953f, 4.25f, 0.0f, +0.3f, 4.05f, 0.0f, +0.4715f, 4.651f, 0.2011f, +0.4499f, 4.472f, 0.1918f, +0.2725f, 4.25f, 0.1161f, +0.2768f, 4.05f, 0.1178f, +0.3632f, 4.651f, 0.3632f, +0.3465f, 4.472f, 0.3465f, +0.2098f, 4.25f, 0.2098f, +0.213f, 4.05f, 0.213f, +0.2011f, 4.651f, 0.4715f, +0.1918f, 4.472f, 0.4499f, +0.1161f, 4.25f, 0.2725f, +0.1178f, 4.05f, 0.2768f, +0.0f, 4.651f, 0.5109f, +0.0f, 4.472f, 0.4875f, +0.0f, 4.25f, 0.2953f, +0.0f, 4.05f, 0.3f, +-0.2011f, 4.651f, 0.4715f, +-0.1918f, 4.472f, 0.4499f, +-0.1161f, 4.25f, 0.2725f, +-0.1178f, 4.05f, 0.2768f, +-0.3632f, 4.651f, 0.3632f, +-0.3465f, 4.472f, 0.3465f, +-0.2098f, 4.25f, 0.2098f, +-0.213f, 4.05f, 0.213f, +-0.4715f, 4.651f, 0.2011f, +-0.4499f, 4.472f, 0.1918f, +-0.2725f, 4.25f, 0.1161f, +-0.2768f, 4.05f, 0.1178f, +-0.5109f, 4.651f, 0.0f, +-0.4875f, 4.472f, 0.0f, +-0.2953f, 4.25f, 0.0f, +-0.3f, 4.05f, 0.0f, +-0.4715f, 4.651f, -0.2011f, +-0.4499f, 4.472f, -0.1918f, +-0.2725f, 4.25f, -0.1161f, +-0.2768f, 4.05f, -0.1178f, +-0.3632f, 4.651f, -0.3632f, +-0.3465f, 4.472f, -0.3465f, +-0.2098f, 4.25f, -0.2098f, +-0.213f, 4.05f, -0.213f, +-0.2011f, 4.651f, -0.4715f, +-0.1918f, 4.472f, -0.4499f, +-0.1161f, 4.25f, -0.2725f, +-0.1178f, 4.05f, -0.2768f, +0.0f, 4.651f, -0.5109f, +0.0f, 4.472f, -0.4875f, +0.0f, 4.25f, -0.2953f, +0.0f, 4.05f, -0.3f, +0.2011f, 4.651f, -0.4715f, +0.1918f, 4.472f, -0.4499f, +0.1161f, 4.25f, -0.2725f, +0.1178f, 4.05f, -0.2768f, +0.3632f, 4.651f, -0.3632f, +0.3465f, 4.472f, -0.3465f, +0.2098f, 4.25f, -0.2098f, +0.213f, 4.05f, -0.213f, +0.4715f, 4.651f, -0.2011f, +0.4499f, 4.472f, -0.1918f, +0.2725f, 4.25f, -0.1161f, +0.2768f, 4.05f, -0.1178f, +0.6844f, 3.916f, 0.0f, +1.237f, 3.825f, 0.0f, +1.734f, 3.734f, 0.0f, +1.95f, 3.6f, 0.0f, +0.6313f, 3.916f, 0.2686f, +1.142f, 3.825f, 0.4857f, +1.6f, 3.734f, 0.6807f, +1.799f, 3.6f, 0.7654f, +0.4859f, 3.916f, 0.4859f, +0.8786f, 3.825f, 0.8786f, +1.231f, 3.734f, 1.231f, +1.385f, 3.6f, 1.385f, +0.2686f, 3.916f, 0.6313f, +0.4857f, 3.825f, 1.142f, +0.6807f, 3.734f, 1.6f, +0.7654f, 3.6f, 1.799f, +0.0f, 3.916f, 0.6844f, +0.0f, 3.825f, 1.237f, +0.0f, 3.734f, 1.734f, +0.0f, 3.6f, 1.95f, +-0.2686f, 3.916f, 0.6313f, +-0.4857f, 3.825f, 1.142f, +-0.6807f, 3.734f, 1.6f, +-0.7654f, 3.6f, 1.799f, +-0.4859f, 3.916f, 0.4859f, +-0.8786f, 3.825f, 0.8786f, +-1.231f, 3.734f, 1.231f, +-1.385f, 3.6f, 1.385f, +-0.6313f, 3.916f, 0.2686f, +-1.142f, 3.825f, 0.4857f, +-1.6f, 3.734f, 0.6807f, +-1.799f, 3.6f, 0.7654f, +-0.6844f, 3.916f, 0.0f, +-1.237f, 3.825f, 0.0f, +-1.734f, 3.734f, 0.0f, +-1.95f, 3.6f, 0.0f, +-0.6313f, 3.916f, -0.2686f, +-1.142f, 3.825f, -0.4857f, +-1.6f, 3.734f, -0.6807f, +-1.799f, 3.6f, -0.7654f, +-0.4859f, 3.916f, -0.4859f, +-0.8786f, 3.825f, -0.8786f, +-1.231f, 3.734f, -1.231f, +-1.385f, 3.6f, -1.385f, +-0.2686f, 3.916f, -0.6313f, +-0.4857f, 3.825f, -1.142f, +-0.6807f, 3.734f, -1.6f, +-0.7654f, 3.6f, -1.799f, +0.0f, 3.916f, -0.6844f, +0.0f, 3.825f, -1.237f, +0.0f, 3.734f, -1.734f, +0.0f, 3.6f, -1.95f, +0.2686f, 3.916f, -0.6313f, +0.4857f, 3.825f, -1.142f, +0.6807f, 3.734f, -1.6f, +0.7654f, 3.6f, -1.799f, +0.4859f, 3.916f, -0.4859f, +0.8786f, 3.825f, -0.8786f, +1.231f, 3.734f, -1.231f, +1.385f, 3.6f, -1.385f, +0.6313f, 3.916f, -0.2686f, +1.142f, 3.825f, -0.4857f, +1.6f, 3.734f, -0.6807f, +1.799f, 3.6f, -0.7654f +}; + + +/* 530 normals */ +const int numNormals = 530; +const float normals[530][3] = { +0.0486f, -0.9986f, 0.0168f, +0.9976f, -0.0678f, -0.0008f, +-0.233f, 0.8502f, -0.4719f, +-0.2299f, 0.9679f, 0.1004f, +-0.1648f, 0.985f, 0.0501f, +-0.0117f, 0.7461f, 0.6656f, +-0.0888f, 0.9692f, 0.2294f, +0.6449f, -0.7172f, -0.2637f, +-0.066f, 0.9851f, 0.1583f, +-0.6585f, -0.342f, -0.6703f, +-0.293f, 0.9558f, 0.0209f, +0.179f, 0.9825f, -0.0513f, +-0.0094f, 0.903f, 0.4295f, +-0.0059f, -0.986f, -0.1662f, +-0.7355f, 0.6774f, -0.0026f, +-0.997f, 0.0763f, 0.0019f, +-0.1478f, 0.9333f, 0.3271f, +-0.3014f, -0.6034f, -0.7382f, +-0.7048f, -0.0681f, 0.706f, +-0.3361f, 0.9332f, 0.1263f, +0.3709f, 0.1524f, -0.916f, +-0.3399f, -0.4121f, 0.8453f, +0.1921f, 0.9724f, -0.1316f, +-0.2671f, 0.7429f, 0.6137f, +0.0888f, 0.9692f, -0.2294f, +0.066f, 0.9851f, -0.1583f, +0.9411f, 0.338f, 0.001f, +0.8666f, -0.2559f, 0.4282f, +-0.8029f, 0.4968f, 0.3293f, +-0.0008f, -0.0678f, -0.9976f, +-0.8453f, -0.4121f, -0.3399f, +-0.4801f, -0.8741f, 0.0733f, +0.6355f, -0.772f, 0.0006f, +-0.9215f, -0.0678f, 0.3822f, +-0.6698f, -0.6907f, -0.2723f, +0.3734f, 0.876f, -0.3051f, +0.3548f, -0.4118f, 0.8393f, +-0.3629f, 0.2429f, 0.8995f, +0.9033f, 0.2079f, 0.375f, +-0.2824f, 0.5939f, 0.7532f, +0.8938f, 0.4452f, 0.0532f, +0.1478f, 0.9333f, -0.3271f, +0.0085f, -0.0031f, -0.9999f, +0.3595f, 0.933f, 0.0115f, +0.8995f, 0.2429f, 0.3629f, +0.7048f, -0.0681f, -0.706f, +-0.6428f, -0.7172f, -0.2688f, +0.6366f, -0.447f, 0.6283f, +-0.1213f, -0.9861f, -0.1128f, +0.8003f, 0.4978f, 0.334f, +0.3361f, 0.9332f, -0.1263f, +0.3399f, -0.4121f, -0.8453f, +-0.3909f, 0.4452f, 0.8055f, +0.0117f, 0.7462f, -0.6655f, +0.9215f, -0.0678f, -0.3822f, +0.3582f, -0.7656f, 0.5343f, +-0.9782f, 0.2075f, -0.0011f, +0.2824f, 0.5939f, -0.7532f, +0.035f, -0.8413f, 0.5393f, +-0.8044f, 0.5934f, 0.0262f, +-0.1128f, -0.9861f, 0.1213f, +0.13f, -0.1396f, 0.9816f, +0.6644f, 0.3392f, 0.6659f, +-0.0042f, -0.6898f, -0.7239f, +-0.1587f, 0.9851f, 0.065f, +-0.8719f, -0.3415f, 0.3508f, +0.6486f, 0.4756f, -0.5941f, +-0.4991f, 0.8499f, -0.1684f, +-0.3969f, 0.6342f, -0.6634f, +0.7041f, -0.3863f, -0.5956f, +0.3909f, 0.4452f, -0.8055f, +-0.0391f, -0.0113f, 0.9991f, +-0.3321f, 0.5936f, -0.733f, +0.8523f, -0.5219f, -0.0338f, +0.329f, 0.4978f, 0.8023f, +0.8044f, 0.5934f, -0.0262f, +0.1128f, -0.9861f, -0.1213f, +0.0178f, 0.9861f, -0.1651f, +0.3491f, 0.4045f, 0.8452f, +-0.2727f, 0.8505f, 0.4496f, +0.065f, 0.9851f, 0.1587f, +-0.0005f, 0.4037f, 0.9148f, +-0.0077f, -0.4109f, -0.9116f, +0.5609f, -0.604f, 0.5661f, +0.8236f, 0.5668f, -0.0138f, +0.1587f, 0.9851f, -0.065f, +0.8719f, -0.3415f, -0.3508f, +-0.7382f, -0.6034f, 0.3014f, +0.0346f, 0.8495f, 0.5263f, +-0.4373f, -0.7921f, -0.4257f, +-0.0532f, 0.4452f, 0.8938f, +0.0689f, -0.9861f, 0.1509f, +-0.1509f, -0.9861f, 0.0689f, +0.7706f, -0.2424f, -0.5893f, +-0.7543f, -0.6564f, 0.0105f, +0.0005f, 0.4037f, -0.9148f, +-0.9116f, -0.4109f, 0.0077f, +0.0058f, -0.0438f, 0.999f, +0.1719f, 0.985f, 0.0005f, +-0.1697f, 0.9693f, 0.1774f, +0.5874f, -0.5124f, 0.6263f, +0.7382f, -0.6034f, -0.3014f, +-0.1518f, 0.985f, -0.081f, +0.646f, 0.4051f, 0.6468f, +0.334f, 0.4978f, -0.8003f, +-0.7354f, -0.6034f, -0.3082f, +-0.6919f, 0.2428f, -0.6798f, +0.0532f, 0.4452f, -0.8938f, +0.3547f, -0.3173f, 0.8794f, +0.9879f, -0.1547f, -0.0033f, +-0.0462f, -0.9986f, 0.0223f, +-0.6088f, 0.4806f, 0.6311f, +-0.109f, -0.1969f, -0.9743f, +0.1509f, -0.9861f, -0.0689f, +-0.0568f, 0.9983f, 0.0009f, +0.9074f, -0.3096f, -0.2839f, +0.8677f, 0.4969f, 0.0026f, +-0.2723f, -0.6907f, 0.6698f, +-0.4734f, -0.6798f, 0.5599f, +0.9116f, -0.4109f, -0.0077f, +0.1697f, 0.9693f, -0.1774f, +0.5875f, 0.5937f, 0.5497f, +-0.3232f, 0.6846f, 0.6533f, +-0.5078f, -0.6913f, 0.5139f, +-0.4612f, 0.7474f, -0.478f, +-0.2071f, -0.8049f, 0.556f, +-0.6976f, -0.7164f, -0.0027f, +-0.8697f, 0.3388f, 0.3587f, +0.0462f, -0.9986f, -0.0223f, +0.2723f, -0.6907f, -0.6698f, +-0.829f, -0.4466f, -0.3365f, +0.9148f, 0.4037f, 0.0005f, +-0.1583f, 0.9851f, -0.066f, +0.148f, 0.9838f, 0.1002f, +-0.1717f, 0.985f, -0.0162f, +-0.4282f, -0.2559f, 0.8666f, +0.3094f, -0.2556f, 0.9159f, +0.2803f, -0.6907f, 0.6665f, +-0.6154f, 0.497f, 0.6117f, +-0.0262f, 0.5934f, -0.8044f, +0.0286f, 0.1639f, -0.986f, +-0.6924f, 0.2083f, 0.6907f, +-0.0105f, 0.9975f, -0.0685f, +0.5078f, -0.6913f, -0.5139f, +0.2071f, -0.8049f, -0.556f, +-0.4903f, -0.7178f, -0.4942f, +-0.2637f, -0.7172f, -0.6449f, +-0.3822f, -0.0678f, -0.9215f, +0.8697f, 0.3388f, -0.3587f, +0.2461f, -0.805f, 0.5397f, +-0.2615f, 0.9334f, 0.2452f, +0.6187f, 0.747f, -0.243f, +0.0375f, -0.8401f, -0.5411f, +0.0054f, 0.9691f, 0.2464f, +0.3587f, 0.3388f, 0.8697f, +0.3993f, 0.6582f, -0.6381f, +-0.3476f, -0.4464f, -0.8245f, +0.099f, 0.9692f, 0.2251f, +-0.3666f, -0.3412f, 0.8655f, +0.0396f, 0.153f, -0.9874f, +0.0349f, 0.9969f, -0.0698f, +0.1096f, 0.985f, 0.1324f, +-0.0578f, -0.9861f, 0.1556f, +0.4479f, -0.5145f, -0.7311f, +0.6924f, 0.2083f, -0.6907f, +0.6096f, 0.747f, 0.265f, +-0.3508f, -0.3415f, -0.8719f, +-0.6215f, 0.4454f, -0.6443f, +-0.4942f, -0.7178f, 0.4903f, +-0.9402f, -0.3403f, -0.0085f, +0.0056f, -0.0358f, 0.9993f, +0.2615f, 0.9334f, -0.2452f, +-0.0024f, 0.0291f, -0.9995f, +-0.2667f, 0.9637f, -0.001f, +0.0569f, -0.2712f, -0.9608f, +0.7463f, 0.254f, 0.615f, +0.5153f, 0.6516f, -0.5564f, +0.0223f, -0.9986f, 0.0462f, +0.3666f, -0.3412f, -0.8655f, +0.0578f, -0.9861f, -0.1556f, +0.6111f, 0.4984f, 0.6148f, +-0.243f, 0.747f, -0.6187f, +-0.0092f, 0.2338f, -0.9722f, +0.478f, 0.7474f, -0.4612f, +-0.0058f, -0.4457f, -0.8951f, +-0.4856f, -0.6774f, -0.5524f, +0.54f, 0.6414f, 0.5448f, +-0.3365f, -0.4466f, 0.829f, +-0.2257f, 0.795f, 0.5629f, +0.8055f, 0.4452f, 0.3909f, +0.3729f, 0.208f, 0.9042f, +-0.727f, -0.2562f, 0.6369f, +-0.0514f, -0.9986f, 0.0029f, +0.9159f, 0.1555f, -0.3699f, +0.0019f, -0.2377f, -0.9713f, +0.4942f, -0.7178f, -0.4903f, +0.6497f, -0.4127f, 0.6383f, +0.0089f, 0.0486f, -0.9987f, +-0.0213f, 0.6301f, -0.7761f, +-0.9269f, -0.3751f, 0.0038f, +-0.1215f, 0.9852f, 0.1207f, +-0.5856f, 0.5198f, 0.6218f, +0.8655f, -0.3412f, 0.3666f, +-0.2464f, 0.9691f, 0.0054f, +0.0123f, 0.1386f, 0.9902f, +0.0179f, -0.0369f, 0.9991f, +-0.1207f, 0.9852f, -0.1215f, +-0.0081f, 0.5671f, 0.8235f, +-0.8689f, 0.3387f, -0.3607f, +0.0062f, 0.0309f, -0.9995f, +0.3365f, -0.4466f, -0.829f, +-0.3787f, 0.2424f, -0.8931f, +-0.2904f, 0.4454f, -0.8468f, +-0.8707f, 0.4915f, 0.0133f, +0.163f, -0.8182f, 0.5512f, +0.4337f, -0.8052f, 0.4041f, +0.0514f, -0.9986f, -0.0029f, +-0.0084f, 0.1303f, 0.9914f, +-0.706f, -0.0681f, -0.7048f, +-0.556f, -0.8049f, -0.2071f, +0.8448f, 0.4045f, 0.3501f, +0.4259f, -0.5474f, 0.7203f, +-0.6907f, 0.2083f, -0.6924f, +0.1215f, 0.9852f, -0.1207f, +-0.1263f, 0.9332f, -0.3361f, +0.7711f, -0.0741f, -0.6323f, +0.2464f, 0.9691f, -0.0054f, +0.1774f, 0.9693f, 0.1697f, +-0.9042f, 0.208f, 0.3729f, +-0.8393f, -0.4118f, 0.3548f, +0.6888f, -0.7219f, -0.0648f, +0.1556f, -0.9861f, 0.0578f, +0.3271f, 0.9333f, 0.1478f, +-0.0024f, 0.2379f, 0.9712f, +-0.0026f, 0.4969f, 0.8677f, +0.0f, 1.0f, 0.0f, +0.1912f, -0.9815f, -0.0025f, +-0.3762f, -0.6681f, 0.6418f, +-0.7759f, 0.0432f, 0.6292f, +-0.0208f, -0.8044f, -0.5936f, +-0.2274f, 0.8822f, -0.4122f, +0.7532f, 0.5939f, 0.2824f, +-0.9221f, -0.0681f, -0.3807f, +-0.2198f, 0.8494f, 0.4796f, +0.0065f, -0.7656f, 0.6431f, +-0.5876f, 0.4472f, -0.6742f, +0.7981f, -0.6024f, 0.0036f, +-0.0383f, -0.9986f, -0.0341f, +-0.6369f, -0.2562f, -0.727f, +-0.5497f, 0.5937f, 0.5875f, +0.1084f, 0.9431f, 0.314f, +0.9042f, 0.208f, -0.3729f, +-0.6659f, 0.3392f, 0.6644f, +0.8393f, -0.4118f, -0.3548f, +0.0029f, -0.9986f, 0.0514f, +-0.9647f, -0.2552f, -0.0635f, +-0.2294f, 0.9692f, -0.0888f, +0.0026f, 0.4969f, -0.8677f, +0.2452f, 0.9334f, 0.2615f, +0.5171f, -0.4876f, -0.7033f, +-0.8951f, -0.4457f, 0.0058f, +-0.5936f, -0.8044f, 0.0208f, +0.5642f, -0.5426f, -0.6222f, +0.5938f, 0.4451f, 0.6702f, +0.5497f, 0.5937f, -0.5875f, +0.6657f, 0.4653f, 0.5832f, +0.4857f, -0.6243f, 0.6117f, +-0.0486f, -0.9986f, -0.0168f, +-0.6468f, 0.4051f, 0.646f, +0.6659f, 0.3392f, -0.6644f, +0.1833f, 0.9735f, -0.1365f, +0.3955f, 0.8505f, 0.3465f, +0.5139f, -0.6913f, 0.5078f, +0.8023f, 0.4978f, -0.329f, +-0.001f, 0.338f, 0.9411f, +-0.2496f, 0.8321f, -0.4951f, +0.8951f, -0.4457f, -0.0058f, +0.233f, 0.8502f, 0.4719f, +-0.0168f, -0.9986f, 0.0486f, +0.5936f, -0.8044f, -0.0208f, +-0.05f, 0.3155f, 0.9475f, +0.6585f, -0.342f, 0.6703f, +0.4909f, -0.1864f, -0.8509f, +-0.37f, 0.9238f, -0.0973f, +0.6468f, 0.4051f, -0.646f, +0.0059f, -0.986f, 0.1662f, +-0.3724f, 0.9278f, -0.0202f, +-0.3501f, 0.4045f, 0.8448f, +-0.0425f, 0.8398f, -0.5411f, +-0.1684f, 0.8499f, 0.4991f, +-0.6665f, -0.6907f, 0.2803f, +-0.2251f, 0.9692f, 0.099f, +0.9241f, -0.3816f, -0.0169f, +0.001f, 0.338f, -0.9411f, +-0.9411f, 0.338f, -0.001f, +-0.8666f, -0.2559f, -0.4282f, +0.0262f, 0.5183f, -0.8547f, +0.3014f, -0.6034f, 0.7382f, +0.0168f, -0.9986f, -0.0486f, +-0.3548f, -0.4118f, -0.8393f, +-0.6023f, -0.5297f, 0.5971f, +-0.9033f, 0.2079f, -0.375f, +-0.8938f, 0.4452f, -0.0532f, +0.6044f, 0.7397f, 0.2957f, +0.0008f, -0.0678f, 0.9976f, +0.7058f, 0.0906f, -0.7025f, +0.8453f, -0.4121f, 0.3399f, +-0.3595f, 0.933f, -0.0115f, +0.6698f, -0.6907f, 0.2723f, +-0.8995f, 0.2429f, -0.3629f, +-0.6366f, -0.447f, -0.6283f, +0.3501f, 0.4045f, -0.8448f, +-0.01f, -0.0605f, 0.9981f, +-0.8003f, 0.4978f, -0.334f, +0.1684f, 0.8499f, -0.4991f, +0.6665f, -0.6907f, -0.2803f, +0.2251f, 0.9692f, -0.099f, +-0.0036f, -0.6024f, 0.7981f, +0.6637f, -0.2967f, -0.6865f, +-0.081f, 0.985f, 0.1518f, +0.0084f, 0.2423f, 0.9701f, +0.0071f, -0.9029f, -0.4296f, +-0.8679f, 0.4966f, -0.0026f, +0.0123f, 0.5735f, 0.819f, +-0.0005f, 0.985f, 0.1719f, +0.6428f, -0.7172f, 0.2688f, +0.6588f, -0.3366f, 0.6727f, +0.1213f, -0.9861f, 0.1128f, +-0.8931f, 0.2424f, 0.3787f, +-0.1662f, -0.986f, 0.0059f, +0.9994f, 0.0313f, 0.0095f, +0.762f, -0.146f, 0.6308f, +-0.7731f, 0.0861f, -0.6283f, +-0.6644f, 0.3392f, -0.6659f, +-0.0027f, -0.7164f, 0.6976f, +0.0036f, -0.6024f, -0.7981f, +0.9782f, 0.2075f, 0.0011f, +0.0405f, -0.9991f, -0.0018f, +0.6882f, -0.703f, 0.179f, +-0.0115f, 0.933f, 0.3595f, +0.0911f, 0.0518f, -0.9944f, +0.0005f, 0.985f, -0.1719f, +0.5337f, -0.5852f, -0.6104f, +0.0042f, -0.6898f, 0.7239f, +0.4863f, 0.2366f, 0.8411f, +0.4991f, 0.8499f, 0.1684f, +-0.6543f, 0.7561f, 0.0071f, +0.265f, 0.747f, -0.6096f, +-0.329f, 0.4978f, -0.8023f, +0.1662f, -0.986f, -0.0059f, +-0.3491f, 0.4045f, -0.8452f, +0.3321f, 0.5936f, 0.733f, +-0.065f, 0.9851f, -0.1587f, +-0.6283f, -0.447f, 0.6366f, +0.0027f, -0.7164f, -0.6976f, +-0.1316f, 0.6339f, 0.762f, +-0.5609f, -0.604f, -0.5661f, +-0.8452f, 0.4045f, 0.3491f, +-0.5263f, 0.8495f, 0.0346f, +0.0115f, 0.933f, -0.3595f, +-0.0346f, 0.8495f, -0.5263f, +0.0077f, -0.4109f, 0.9116f, +0.5758f, -0.8175f, -0.0017f, +-0.0011f, 0.2075f, 0.9782f, +-0.0689f, -0.9861f, -0.1509f, +0.2934f, -0.5928f, -0.7499f, +0.0724f, 0.1198f, -0.9901f, +-0.7367f, -0.275f, -0.6176f, +-0.3131f, 0.8154f, 0.4868f, +-0.0114f, 0.0022f, 0.9999f, +0.6283f, -0.447f, -0.6366f, +0.8452f, 0.4045f, -0.3491f, +0.5263f, 0.8495f, -0.0346f, +-0.6383f, -0.4127f, 0.6497f, +-0.1719f, 0.985f, -0.0005f, +-0.6703f, -0.342f, 0.6585f, +-0.0085f, -0.3403f, 0.9402f, +-0.646f, 0.4051f, -0.6468f, +0.0011f, 0.2075f, -0.9782f, +-0.7216f, -0.3071f, 0.6204f, +0.0282f, 0.0023f, -0.9995f, +-0.2483f, 0.6806f, -0.6892f, +0.1518f, 0.985f, 0.081f, +0.047f, 0.0466f, -0.9978f, +0.7354f, -0.6034f, 0.3082f, +0.6919f, 0.2428f, 0.6798f, +0.4086f, -0.3626f, -0.8375f, +0.6383f, -0.4127f, -0.6497f, +-0.5875f, 0.5937f, -0.5497f, +0.6703f, -0.342f, -0.6585f, +-0.8245f, -0.4464f, 0.3476f, +0.0085f, -0.3403f, -0.9402f, +-0.0591f, -0.0663f, 0.996f, +0.0f, -1.0f, 0.0f, +0.4612f, 0.7474f, 0.478f, +0.6976f, -0.7164f, 0.0027f, +-0.9148f, 0.4037f, -0.0005f, +0.173f, -0.8158f, -0.5518f, +-0.3607f, 0.3387f, 0.8689f, +0.7836f, -0.2411f, 0.5724f, +-0.1985f, 0.8026f, -0.5623f, +-0.3094f, -0.2556f, -0.9159f, +-0.2803f, -0.6907f, -0.6665f, +0.8245f, -0.4464f, -0.3476f, +0.829f, -0.4466f, 0.3365f, +-0.4848f, 0.7385f, 0.4683f, +0.1583f, 0.9851f, 0.066f, +-0.0077f, 0.7656f, -0.6432f, +-0.0162f, 0.985f, 0.1717f, +0.1717f, 0.985f, 0.0162f, +0.0244f, 0.9805f, -0.1949f, +-0.2461f, -0.805f, -0.5397f, +0.0262f, 0.5934f, 0.8044f, +0.142f, 0.1881f, 0.9718f, +0.1846f, 0.1002f, 0.9776f, +0.4903f, -0.7178f, 0.4942f, +0.2637f, -0.7172f, 0.6449f, +0.3822f, -0.0678f, 0.9215f, +-0.0054f, 0.9691f, -0.2464f, +0.3607f, 0.3387f, -0.8689f, +-0.3587f, 0.3388f, -0.8697f, +-0.5694f, -0.8219f, 0.0081f, +-0.1324f, 0.985f, 0.1096f, +-0.099f, 0.9692f, -0.2251f, +-0.6702f, 0.4451f, 0.5938f, +0.0077f, -0.9976f, 0.0684f, +-0.5661f, -0.604f, 0.5609f, +-0.1096f, 0.985f, -0.1324f, +-0.6096f, 0.747f, -0.265f, +-0.0015f, 0.0295f, -0.9995f, +0.3476f, -0.4464f, 0.8245f, +-0.0635f, -0.2552f, 0.9647f, +-0.8468f, 0.4454f, 0.2904f, +-0.4719f, 0.8502f, 0.233f, +-0.0502f, 0.8385f, 0.5425f, +-0.6671f, 0.7448f, -0.0116f, +0.3508f, -0.3415f, 0.8719f, +-0.4119f, 0.6135f, -0.6736f, +-0.2688f, -0.7172f, 0.6428f, +-0.4041f, -0.8052f, 0.4337f, +-0.375f, 0.2079f, 0.9033f, +-0.0223f, -0.9986f, -0.0462f, +0.6702f, 0.4451f, -0.5938f, +0.9402f, -0.3403f, 0.0085f, +0.5661f, -0.604f, -0.5609f, +-0.6252f, 0.7406f, 0.246f, +-0.0341f, -0.9986f, 0.0383f, +-0.6111f, 0.4984f, -0.6148f, +0.6655f, 0.7462f, 0.0117f, +0.1233f, 0.199f, 0.9722f, +0.8468f, 0.4454f, -0.2904f, +0.7383f, 0.2702f, -0.6179f, +-0.8055f, 0.4452f, -0.3909f, +-0.3729f, 0.208f, -0.9042f, +0.4719f, 0.8502f, -0.233f, +0.243f, 0.747f, 0.6187f, +-0.6497f, -0.4127f, -0.6383f, +-0.5406f, 0.5651f, -0.623f, +0.0058f, -0.4457f, 0.8951f, +-0.3082f, -0.6034f, 0.7354f, +-0.8655f, -0.3412f, -0.3666f, +0.2688f, -0.7172f, -0.6428f, +0.4041f, -0.8052f, -0.4337f, +0.375f, 0.2079f, -0.9033f, +0.0341f, -0.9986f, -0.0383f, +-0.9701f, 0.2423f, 0.0084f, +-0.3807f, -0.0681f, 0.9221f, +0.9643f, -0.2551f, 0.0705f, +-0.8758f, 0.4808f, 0.0415f, +0.1207f, 0.9852f, 0.1215f, +0.4821f, 0.7724f, 0.4133f, +-0.0522f, 0.9982f, 0.0278f, +-0.4337f, -0.8052f, -0.4041f, +-0.6164f, 0.4198f, 0.6661f, +-0.8448f, 0.4045f, -0.3501f, +0.3082f, -0.6034f, -0.7354f, +0.8689f, 0.3387f, 0.3607f, +0.6894f, -0.7242f, 0.0091f, +0.3787f, 0.2424f, 0.8931f, +0.2904f, 0.4454f, 0.8468f, +0.6148f, 0.4984f, -0.6111f, +0.0501f, 0.985f, 0.1648f, +-0.5397f, -0.805f, 0.2461f, +-0.9159f, -0.2556f, 0.3094f, +0.706f, -0.0681f, 0.7048f, +-0.3341f, 0.4972f, 0.8006f, +0.556f, -0.8049f, 0.2071f, +-0.1774f, 0.9693f, -0.1697f, +0.6907f, 0.2083f, 0.6924f, +0.1263f, 0.9332f, 0.3361f, +0.3807f, -0.0681f, -0.9221f, +-0.1556f, -0.9861f, -0.0578f, +-0.3271f, 0.9333f, -0.1478f, +-0.3465f, 0.8505f, 0.3955f, +0.5315f, 0.8438f, -0.0735f, +0.9737f, 0.2276f, -0.0003f, +0.6441f, 0.7648f, -0.0112f, +-0.7239f, -0.6898f, 0.0042f, +-0.7532f, 0.5939f, -0.2824f, +0.1093f, 0.1415f, -0.9838f, +0.5397f, -0.805f, -0.2461f, +-0.7981f, -0.6024f, -0.0036f, +0.9456f, 0.3251f, -0.0052f, +0.1278f, 0.9696f, -0.2085f, +0.0208f, -0.8044f, 0.5936f, +0.1635f, 0.1348f, -0.9772f, +-0.733f, 0.5936f, 0.3321f, +-0.0505f, 0.9852f, -0.1635f, +0.4089f, -0.9069f, -0.1015f, +-0.0029f, -0.9986f, -0.0514f, +-0.1796f, 0.814f, -0.5522f, +0.9221f, -0.0681f, 0.3807f, +0.0383f, -0.9986f, 0.0341f, +0.6369f, -0.2562f, 0.727f, +0.3465f, 0.8505f, -0.3955f, +-0.2452f, 0.9334f, -0.2615f, +0.4921f, -0.247f, 0.8346f, +-0.9976f, -0.0678f, 0.0008f, +-0.5396f, 0.8418f, -0.0094f, +0.2294f, 0.9692f, 0.0888f, +0.7239f, -0.6898f, -0.0042f, +-0.4472f, 0.5952f, 0.6675f, +-0.6449f, -0.7172f, 0.2637f, +0.4543f, 0.2732f, -0.8478f, +-0.6798f, 0.2428f, 0.6919f, +-0.5938f, 0.4451f, -0.6702f, +0.733f, 0.5936f, -0.3321f, +-0.3955f, 0.8505f, -0.3465f, +-0.5139f, -0.6913f, -0.5078f, +-0.623f, -0.5156f, -0.5881f +}; + +/* 1 color */ +/*255 255 0 */ + +/* 1024 faces */ +/* numIdx fidx0 fidx1 fidx2 nidx0 nidx1 nidx2 coloridx */ + +const int numFaces = 1024; +const int faces[1024][8] = { +3, 0, 5, 6, 255, 295, 309, 0, +3, 6, 1, 0, 309, 465, 255, 0, +3, 1, 6, 7, 465, 309, 134, 0, +3, 7, 2, 1, 134, 4, 465, 0, +3, 2, 7, 8, 4, 134, 165, 0, +3, 8, 3, 2, 165, 448, 4, 0, +3, 3, 8, 9, 448, 165, 49, 0, +3, 9, 4, 3, 49, 116, 448, 0, +3, 5, 10, 11, 295, 248, 106, 0, +3, 11, 6, 5, 106, 309, 295, 0, +3, 6, 11, 12, 309, 106, 102, 0, +3, 12, 7, 6, 102, 134, 309, 0, +3, 7, 12, 13, 134, 102, 394, 0, +3, 13, 8, 7, 394, 165, 134, 0, +3, 8, 13, 14, 165, 394, 180, 0, +3, 14, 9, 8, 180, 49, 165, 0, +3, 10, 15, 16, 248, 401, 211, 0, +3, 16, 11, 10, 211, 106, 248, 0, +3, 11, 16, 17, 106, 211, 427, 0, +3, 17, 12, 11, 427, 102, 106, 0, +3, 12, 17, 18, 102, 427, 455, 0, +3, 18, 13, 12, 455, 394, 102, 0, +3, 13, 18, 19, 394, 455, 74, 0, +3, 19, 14, 13, 74, 180, 394, 0, +3, 15, 20, 21, 401, 174, 182, 0, +3, 21, 16, 15, 182, 211, 401, 0, +3, 16, 21, 22, 211, 182, 507, 0, +3, 22, 17, 16, 507, 427, 211, 0, +3, 17, 22, 23, 427, 507, 5, 0, +3, 23, 18, 17, 5, 455, 427, 0, +3, 18, 23, 24, 455, 5, 234, 0, +3, 24, 19, 18, 234, 74, 455, 0, +3, 20, 25, 26, 174, 386, 20, 0, +3, 26, 21, 20, 20, 182, 174, 0, +3, 21, 26, 27, 182, 20, 410, 0, +3, 27, 22, 21, 410, 507, 182, 0, +3, 22, 27, 28, 507, 410, 23, 0, +3, 28, 23, 22, 23, 5, 507, 0, +3, 23, 28, 29, 5, 23, 485, 0, +3, 29, 24, 23, 485, 234, 5, 0, +3, 25, 30, 31, 386, 69, 305, 0, +3, 31, 26, 25, 305, 20, 386, 0, +3, 26, 31, 32, 20, 305, 503, 0, +3, 32, 27, 26, 503, 410, 20, 0, +3, 27, 32, 33, 410, 503, 405, 0, +3, 33, 28, 27, 405, 23, 410, 0, +3, 28, 33, 34, 23, 405, 138, 0, +3, 34, 29, 28, 138, 485, 23, 0, +3, 30, 35, 36, 69, 115, 193, 0, +3, 36, 31, 30, 193, 305, 69, 0, +3, 31, 36, 37, 305, 193, 270, 0, +3, 37, 32, 31, 270, 503, 305, 0, +3, 32, 37, 38, 503, 270, 445, 0, +3, 38, 33, 32, 445, 405, 503, 0, +3, 33, 38, 39, 405, 445, 28, 0, +3, 39, 34, 33, 28, 138, 405, 0, +3, 35, 40, 41, 115, 467, 495, 0, +3, 41, 36, 35, 495, 193, 115, 0, +3, 36, 41, 42, 193, 495, 11, 0, +3, 42, 37, 36, 11, 270, 193, 0, +3, 37, 42, 43, 270, 11, 435, 0, +3, 43, 38, 37, 435, 445, 270, 0, +3, 38, 43, 44, 445, 435, 322, 0, +3, 44, 39, 38, 322, 28, 445, 0, +3, 40, 45, 46, 467, 27, 44, 0, +3, 46, 41, 40, 44, 495, 467, 0, +3, 41, 46, 47, 495, 44, 409, 0, +3, 47, 42, 41, 409, 11, 495, 0, +3, 42, 47, 48, 11, 409, 428, 0, +3, 48, 43, 42, 428, 435, 11, 0, +3, 43, 48, 49, 435, 428, 313, 0, +3, 49, 44, 43, 313, 322, 435, 0, +3, 45, 50, 51, 27, 513, 385, 0, +3, 51, 46, 45, 385, 44, 27, 0, +3, 46, 51, 52, 44, 385, 382, 0, +3, 52, 47, 46, 382, 409, 44, 0, +3, 47, 52, 53, 409, 382, 124, 0, +3, 53, 48, 47, 124, 428, 409, 0, +3, 48, 53, 54, 428, 124, 447, 0, +3, 54, 49, 48, 447, 313, 428, 0, +3, 50, 55, 56, 513, 136, 478, 0, +3, 56, 51, 50, 478, 385, 513, 0, +3, 51, 56, 57, 385, 478, 161, 0, +3, 57, 52, 51, 161, 382, 385, 0, +3, 52, 57, 58, 382, 161, 181, 0, +3, 58, 53, 52, 181, 124, 382, 0, +3, 53, 58, 59, 124, 181, 348, 0, +3, 59, 54, 53, 348, 447, 124, 0, +3, 55, 60, 61, 136, 431, 320, 0, +3, 61, 56, 55, 320, 478, 136, 0, +3, 56, 61, 62, 478, 320, 481, 0, +3, 62, 57, 56, 481, 161, 478, 0, +3, 57, 62, 63, 161, 481, 53, 0, +3, 63, 58, 57, 53, 181, 161, 0, +3, 58, 63, 64, 181, 53, 257, 0, +3, 64, 59, 58, 257, 348, 181, 0, +3, 60, 65, 66, 431, 135, 37, 0, +3, 66, 61, 60, 37, 320, 431, 0, +3, 61, 66, 67, 320, 37, 408, 0, +3, 67, 62, 61, 408, 481, 320, 0, +3, 62, 67, 68, 481, 408, 347, 0, +3, 68, 63, 62, 347, 53, 481, 0, +3, 63, 68, 69, 53, 347, 104, 0, +3, 69, 64, 63, 104, 257, 53, 0, +3, 65, 70, 71, 135, 191, 524, 0, +3, 71, 66, 65, 524, 37, 135, 0, +3, 66, 71, 72, 37, 524, 319, 0, +3, 72, 67, 66, 319, 408, 37, 0, +3, 67, 72, 73, 408, 319, 183, 0, +3, 73, 68, 67, 183, 347, 408, 0, +3, 68, 73, 74, 347, 183, 480, 0, +3, 74, 69, 68, 480, 104, 347, 0, +3, 70, 75, 76, 191, 483, 328, 0, +3, 76, 71, 70, 328, 524, 191, 0, +3, 71, 76, 77, 524, 328, 422, 0, +3, 77, 72, 71, 422, 319, 524, 0, +3, 72, 77, 78, 319, 422, 151, 0, +3, 78, 73, 72, 151, 183, 319, 0, +3, 73, 78, 79, 183, 151, 273, 0, +3, 79, 74, 73, 273, 480, 183, 0, +3, 75, 0, 1, 483, 255, 465, 0, +3, 1, 76, 75, 465, 328, 483, 0, +3, 76, 1, 2, 328, 465, 4, 0, +3, 2, 77, 76, 4, 422, 328, 0, +3, 77, 2, 3, 422, 4, 448, 0, +3, 3, 78, 77, 448, 151, 422, 0, +3, 78, 3, 4, 151, 448, 116, 0, +3, 4, 79, 78, 116, 273, 151, 0, +3, 4, 9, 84, 116, 49, 220, 0, +3, 84, 80, 4, 220, 131, 116, 0, +3, 80, 84, 85, 131, 220, 476, 0, +3, 85, 81, 80, 476, 26, 131, 0, +3, 81, 85, 86, 26, 476, 38, 0, +3, 86, 82, 81, 38, 336, 26, 0, +3, 82, 86, 87, 336, 38, 511, 0, +3, 87, 83, 82, 511, 1, 336, 0, +3, 9, 14, 88, 49, 180, 103, 0, +3, 88, 84, 9, 103, 220, 49, 0, +3, 84, 88, 89, 220, 103, 62, 0, +3, 89, 85, 84, 62, 476, 220, 0, +3, 85, 89, 90, 476, 62, 488, 0, +3, 90, 86, 85, 488, 38, 476, 0, +3, 86, 90, 91, 38, 488, 484, 0, +3, 91, 87, 86, 484, 511, 38, 0, +3, 14, 19, 92, 180, 74, 78, 0, +3, 92, 88, 14, 78, 103, 180, 0, +3, 88, 92, 93, 103, 78, 154, 0, +3, 93, 89, 88, 154, 62, 103, 0, +3, 89, 93, 94, 62, 154, 190, 0, +3, 94, 90, 89, 190, 488, 62, 0, +3, 90, 94, 95, 488, 190, 417, 0, +3, 95, 91, 90, 417, 484, 488, 0, +3, 19, 24, 96, 74, 234, 81, 0, +3, 96, 92, 19, 81, 78, 74, 0, +3, 92, 96, 97, 78, 81, 274, 0, +3, 97, 93, 92, 274, 154, 78, 0, +3, 93, 97, 98, 154, 274, 363, 0, +3, 98, 94, 93, 363, 190, 154, 0, +3, 94, 98, 99, 190, 363, 304, 0, +3, 99, 95, 94, 304, 417, 190, 0, +3, 24, 29, 100, 234, 485, 287, 0, +3, 100, 96, 24, 287, 81, 234, 0, +3, 96, 100, 101, 81, 287, 398, 0, +3, 101, 97, 96, 398, 274, 81, 0, +3, 97, 101, 102, 274, 398, 440, 0, +3, 102, 98, 97, 440, 363, 274, 0, +3, 98, 102, 103, 363, 440, 466, 0, +3, 103, 99, 98, 466, 304, 363, 0, +3, 29, 34, 104, 485, 138, 268, 0, +3, 104, 100, 29, 268, 287, 485, 0, +3, 100, 104, 105, 287, 268, 252, 0, +3, 105, 101, 100, 252, 398, 287, 0, +3, 101, 105, 106, 398, 252, 141, 0, +3, 106, 102, 101, 141, 440, 398, 0, +3, 102, 106, 107, 440, 141, 18, 0, +3, 107, 103, 102, 18, 466, 440, 0, +3, 34, 39, 108, 138, 28, 357, 0, +3, 108, 104, 34, 357, 268, 138, 0, +3, 104, 108, 109, 268, 357, 127, 0, +3, 109, 105, 104, 127, 252, 268, 0, +3, 105, 109, 110, 252, 127, 228, 0, +3, 110, 106, 105, 228, 141, 252, 0, +3, 106, 110, 111, 141, 228, 33, 0, +3, 111, 107, 106, 33, 18, 141, 0, +3, 39, 44, 112, 28, 322, 396, 0, +3, 112, 108, 39, 396, 357, 28, 0, +3, 108, 112, 113, 357, 396, 294, 0, +3, 113, 109, 108, 294, 127, 357, 0, +3, 109, 113, 114, 127, 294, 56, 0, +3, 114, 110, 109, 56, 228, 127, 0, +3, 110, 114, 115, 228, 56, 517, 0, +3, 115, 111, 110, 517, 33, 228, 0, +3, 44, 49, 116, 322, 313, 474, 0, +3, 116, 112, 44, 474, 396, 322, 0, +3, 112, 116, 117, 396, 474, 208, 0, +3, 117, 113, 112, 208, 294, 396, 0, +3, 113, 117, 118, 294, 208, 301, 0, +3, 118, 114, 113, 301, 56, 294, 0, +3, 114, 118, 119, 56, 301, 242, 0, +3, 119, 115, 114, 242, 517, 56, 0, +3, 49, 54, 120, 313, 447, 377, 0, +3, 120, 116, 49, 377, 474, 313, 0, +3, 116, 120, 121, 474, 377, 333, 0, +3, 121, 117, 116, 333, 208, 474, 0, +3, 117, 121, 122, 208, 333, 222, 0, +3, 122, 118, 117, 222, 301, 208, 0, +3, 118, 122, 123, 301, 222, 218, 0, +3, 123, 119, 118, 218, 242, 301, 0, +3, 54, 59, 124, 447, 348, 350, 0, +3, 124, 120, 54, 350, 377, 447, 0, +3, 120, 124, 125, 377, 350, 420, 0, +3, 125, 121, 120, 420, 333, 377, 0, +3, 121, 125, 126, 333, 420, 453, 0, +3, 126, 122, 121, 453, 222, 333, 0, +3, 122, 126, 127, 222, 453, 147, 0, +3, 127, 123, 122, 147, 218, 222, 0, +3, 59, 64, 128, 348, 257, 95, 0, +3, 128, 124, 59, 95, 350, 348, 0, +3, 124, 128, 129, 350, 95, 293, 0, +3, 129, 125, 124, 293, 420, 350, 0, +3, 125, 129, 130, 420, 293, 378, 0, +3, 130, 126, 125, 378, 453, 420, 0, +3, 126, 130, 131, 453, 378, 29, 0, +3, 131, 127, 126, 29, 147, 453, 0, +3, 64, 69, 132, 257, 104, 311, 0, +3, 132, 128, 64, 311, 95, 257, 0, +3, 128, 132, 133, 95, 311, 419, 0, +3, 133, 129, 128, 419, 293, 95, 0, +3, 129, 133, 134, 293, 419, 463, 0, +3, 134, 130, 129, 463, 378, 293, 0, +3, 130, 134, 135, 378, 463, 490, 0, +3, 135, 131, 130, 490, 29, 378, 0, +3, 69, 74, 136, 104, 480, 284, 0, +3, 136, 132, 69, 284, 311, 104, 0, +3, 132, 136, 137, 311, 284, 269, 0, +3, 137, 133, 132, 269, 419, 311, 0, +3, 133, 137, 138, 419, 269, 164, 0, +3, 138, 134, 133, 164, 463, 419, 0, +3, 134, 138, 139, 463, 164, 45, 0, +3, 139, 135, 134, 45, 490, 463, 0, +3, 74, 79, 140, 480, 273, 371, 0, +3, 140, 136, 74, 371, 284, 480, 0, +3, 136, 140, 141, 284, 371, 148, 0, +3, 141, 137, 136, 148, 269, 284, 0, +3, 137, 141, 142, 269, 148, 251, 0, +3, 142, 138, 137, 251, 164, 269, 0, +3, 138, 142, 143, 164, 251, 54, 0, +3, 143, 139, 138, 54, 45, 164, 0, +3, 79, 4, 80, 273, 116, 131, 0, +3, 80, 140, 79, 131, 371, 273, 0, +3, 140, 80, 81, 371, 131, 26, 0, +3, 81, 141, 140, 26, 148, 371, 0, +3, 141, 81, 82, 148, 26, 336, 0, +3, 82, 142, 141, 336, 251, 148, 0, +3, 142, 82, 83, 251, 336, 1, 0, +3, 83, 143, 142, 1, 54, 251, 0, +3, 83, 87, 148, 1, 511, 404, 0, +3, 148, 144, 83, 404, 276, 1, 0, +3, 144, 148, 149, 276, 404, 308, 0, +3, 149, 145, 144, 308, 520, 276, 0, +3, 145, 149, 150, 520, 308, 325, 0, +3, 150, 146, 145, 325, 395, 520, 0, +3, 146, 150, 151, 395, 325, 384, 0, +3, 151, 147, 146, 384, 246, 395, 0, +3, 87, 91, 152, 511, 484, 47, 0, +3, 152, 148, 87, 47, 404, 511, 0, +3, 148, 152, 153, 404, 47, 272, 0, +3, 153, 149, 148, 272, 308, 404, 0, +3, 149, 153, 154, 308, 272, 415, 0, +3, 154, 150, 149, 415, 325, 308, 0, +3, 150, 154, 155, 325, 415, 83, 0, +3, 155, 151, 150, 83, 384, 325, 0, +3, 91, 95, 156, 484, 417, 430, 0, +3, 156, 152, 91, 430, 47, 484, 0, +3, 152, 156, 157, 47, 430, 137, 0, +3, 157, 153, 152, 137, 272, 47, 0, +3, 153, 157, 158, 272, 137, 416, 0, +3, 158, 154, 153, 416, 415, 272, 0, +3, 154, 158, 159, 415, 416, 297, 0, +3, 159, 155, 154, 297, 83, 415, 0, +3, 95, 99, 160, 417, 304, 458, 0, +3, 160, 156, 95, 458, 430, 417, 0, +3, 156, 160, 161, 430, 458, 343, 0, +3, 161, 157, 156, 343, 137, 430, 0, +3, 157, 161, 162, 137, 343, 334, 0, +3, 162, 158, 157, 334, 416, 137, 0, +3, 158, 162, 163, 416, 334, 317, 0, +3, 163, 159, 158, 317, 297, 416, 0, +3, 99, 103, 164, 304, 466, 187, 0, +3, 164, 160, 99, 187, 458, 304, 0, +3, 160, 164, 165, 458, 187, 117, 0, +3, 165, 161, 160, 117, 343, 458, 0, +3, 161, 165, 166, 343, 117, 438, 0, +3, 166, 162, 161, 438, 334, 343, 0, +3, 162, 166, 167, 334, 438, 459, 0, +3, 167, 163, 162, 459, 317, 334, 0, +3, 103, 107, 168, 466, 18, 353, 0, +3, 168, 164, 103, 353, 187, 466, 0, +3, 164, 168, 169, 187, 353, 123, 0, +3, 169, 165, 164, 123, 117, 187, 0, +3, 165, 169, 170, 117, 123, 168, 0, +3, 170, 166, 165, 168, 438, 117, 0, +3, 166, 170, 171, 438, 168, 426, 0, +3, 171, 167, 166, 426, 459, 438, 0, +3, 107, 111, 172, 18, 33, 390, 0, +3, 172, 168, 107, 390, 353, 18, 0, +3, 168, 172, 173, 353, 390, 290, 0, +3, 173, 169, 168, 290, 123, 353, 0, +3, 169, 173, 174, 123, 290, 522, 0, +3, 174, 170, 169, 522, 168, 123, 0, +3, 170, 174, 175, 168, 522, 87, 0, +3, 175, 171, 170, 87, 426, 168, 0, +3, 111, 115, 176, 33, 517, 260, 0, +3, 176, 172, 111, 260, 390, 33, 0, +3, 172, 176, 177, 390, 260, 497, 0, +3, 177, 173, 172, 497, 290, 390, 0, +3, 173, 177, 178, 290, 497, 126, 0, +3, 178, 174, 173, 126, 522, 290, 0, +3, 174, 178, 179, 522, 126, 501, 0, +3, 179, 175, 174, 501, 87, 522, 0, +3, 115, 119, 180, 517, 242, 130, 0, +3, 180, 176, 115, 130, 260, 517, 0, +3, 176, 180, 181, 260, 130, 34, 0, +3, 181, 177, 176, 34, 497, 260, 0, +3, 177, 181, 182, 497, 34, 46, 0, +3, 182, 178, 177, 46, 126, 497, 0, +3, 178, 182, 183, 126, 46, 105, 0, +3, 183, 179, 178, 105, 501, 126, 0, +3, 119, 123, 184, 242, 218, 310, 0, +3, 184, 180, 119, 310, 130, 242, 0, +3, 180, 184, 185, 130, 310, 528, 0, +3, 185, 181, 180, 528, 34, 130, 0, +3, 181, 185, 186, 34, 528, 145, 0, +3, 186, 182, 181, 145, 46, 34, 0, +3, 182, 186, 187, 46, 145, 356, 0, +3, 187, 183, 182, 356, 105, 46, 0, +3, 123, 127, 188, 218, 147, 156, 0, +3, 188, 184, 123, 156, 310, 218, 0, +3, 184, 188, 189, 310, 156, 402, 0, +3, 189, 185, 184, 402, 528, 310, 0, +3, 185, 189, 190, 528, 402, 146, 0, +3, 190, 186, 185, 146, 145, 528, 0, +3, 186, 190, 191, 145, 146, 17, 0, +3, 191, 187, 186, 17, 356, 145, 0, +3, 127, 131, 192, 147, 29, 184, 0, +3, 192, 188, 127, 184, 156, 147, 0, +3, 188, 192, 193, 156, 184, 63, 0, +3, 193, 189, 188, 63, 402, 156, 0, +3, 189, 193, 194, 402, 63, 354, 0, +3, 194, 190, 189, 354, 146, 402, 0, +3, 190, 194, 195, 146, 354, 335, 0, +3, 195, 191, 190, 335, 17, 146, 0, +3, 131, 135, 196, 29, 490, 210, 0, +3, 196, 192, 131, 210, 184, 29, 0, +3, 192, 196, 197, 184, 210, 129, 0, +3, 197, 193, 192, 129, 63, 184, 0, +3, 193, 197, 198, 63, 129, 461, 0, +3, 198, 194, 193, 461, 354, 63, 0, +3, 194, 198, 199, 354, 461, 475, 0, +3, 199, 195, 194, 475, 335, 354, 0, +3, 135, 139, 200, 490, 45, 370, 0, +3, 200, 196, 135, 370, 210, 490, 0, +3, 196, 200, 201, 210, 370, 143, 0, +3, 201, 197, 196, 143, 129, 210, 0, +3, 197, 201, 202, 129, 143, 195, 0, +3, 202, 198, 197, 195, 461, 129, 0, +3, 198, 202, 203, 461, 195, 444, 0, +3, 203, 199, 198, 444, 475, 461, 0, +3, 139, 143, 204, 45, 54, 403, 0, +3, 204, 200, 139, 403, 370, 45, 0, +3, 200, 204, 205, 370, 403, 315, 0, +3, 205, 201, 200, 315, 143, 370, 0, +3, 201, 205, 206, 143, 315, 7, 0, +3, 206, 202, 201, 7, 195, 143, 0, +3, 202, 206, 207, 195, 7, 101, 0, +3, 207, 203, 202, 101, 444, 195, 0, +3, 143, 83, 144, 54, 1, 276, 0, +3, 144, 204, 143, 276, 403, 54, 0, +3, 204, 144, 145, 403, 276, 520, 0, +3, 145, 205, 204, 520, 315, 403, 0, +3, 205, 145, 146, 315, 520, 395, 0, +3, 146, 206, 205, 395, 7, 315, 0, +3, 206, 146, 147, 7, 395, 246, 0, +3, 147, 207, 206, 246, 101, 7, 0, +3, 147, 151, 212, 246, 384, 486, 0, +3, 212, 208, 147, 486, 279, 246, 0, +3, 208, 212, 213, 279, 486, 231, 0, +3, 213, 209, 208, 231, 349, 279, 0, +3, 209, 213, 214, 349, 231, 0, 0, +3, 214, 210, 209, 0, 216, 349, 0, +3, 210, 214, 211, 216, 0, 393, 0, +3, 211, 211, 210, 393, 393, 216, 0, +3, 151, 155, 215, 384, 83, 215, 0, +3, 215, 212, 151, 215, 486, 384, 0, +3, 212, 215, 216, 486, 215, 327, 0, +3, 216, 213, 212, 327, 231, 486, 0, +3, 213, 216, 217, 231, 327, 512, 0, +3, 217, 214, 213, 512, 0, 231, 0, +3, 214, 217, 211, 0, 512, 393, 0, +3, 211, 211, 214, 393, 393, 0, 0, +3, 155, 159, 218, 83, 297, 149, 0, +3, 218, 215, 155, 149, 215, 83, 0, +3, 215, 218, 219, 215, 149, 91, 0, +3, 219, 216, 215, 91, 327, 215, 0, +3, 216, 219, 220, 327, 91, 177, 0, +3, 220, 217, 216, 177, 512, 327, 0, +3, 217, 220, 211, 512, 177, 393, 0, +3, 211, 211, 217, 393, 393, 512, 0, +3, 159, 163, 221, 297, 317, 504, 0, +3, 221, 218, 159, 504, 149, 297, 0, +3, 218, 221, 222, 149, 504, 285, 0, +3, 222, 219, 218, 285, 91, 149, 0, +3, 219, 222, 223, 91, 285, 254, 0, +3, 223, 220, 219, 254, 177, 91, 0, +3, 220, 223, 211, 177, 254, 393, 0, +3, 211, 211, 220, 393, 393, 177, 0, +3, 163, 167, 224, 317, 459, 125, 0, +3, 224, 221, 163, 125, 504, 317, 0, +3, 221, 224, 225, 504, 125, 162, 0, +3, 225, 222, 221, 162, 285, 504, 0, +3, 222, 225, 226, 285, 162, 278, 0, +3, 226, 223, 222, 278, 254, 285, 0, +3, 223, 226, 211, 254, 278, 393, 0, +3, 211, 211, 223, 393, 393, 254, 0, +3, 167, 171, 227, 459, 426, 439, 0, +3, 227, 224, 167, 439, 125, 459, 0, +3, 224, 227, 228, 125, 439, 60, 0, +3, 228, 225, 224, 60, 162, 125, 0, +3, 225, 228, 229, 162, 60, 446, 0, +3, 229, 226, 225, 446, 278, 162, 0, +3, 226, 229, 211, 278, 446, 393, 0, +3, 211, 211, 226, 393, 393, 278, 0, +3, 171, 175, 230, 426, 87, 482, 0, +3, 230, 227, 171, 482, 439, 426, 0, +3, 227, 230, 231, 439, 482, 92, 0, +3, 231, 228, 227, 92, 60, 439, 0, +3, 228, 231, 232, 60, 92, 110, 0, +3, 232, 229, 228, 110, 446, 60, 0, +3, 229, 232, 211, 446, 110, 393, 0, +3, 211, 211, 229, 393, 393, 446, 0, +3, 175, 179, 233, 87, 501, 261, 0, +3, 233, 230, 175, 261, 482, 87, 0, +3, 230, 233, 234, 482, 261, 329, 0, +3, 234, 231, 230, 329, 92, 482, 0, +3, 231, 234, 235, 92, 329, 192, 0, +3, 235, 232, 231, 192, 110, 92, 0, +3, 232, 235, 211, 110, 192, 393, 0, +3, 211, 211, 232, 393, 393, 110, 0, +3, 179, 183, 236, 501, 105, 219, 0, +3, 236, 233, 179, 219, 261, 501, 0, +3, 233, 236, 237, 261, 219, 491, 0, +3, 237, 234, 233, 491, 329, 261, 0, +3, 234, 237, 238, 329, 491, 267, 0, +3, 238, 235, 234, 267, 192, 329, 0, +3, 235, 238, 211, 192, 267, 393, 0, +3, 211, 211, 235, 393, 393, 192, 0, +3, 183, 187, 239, 105, 356, 472, 0, +3, 239, 236, 183, 472, 219, 105, 0, +3, 236, 239, 240, 219, 472, 48, 0, +3, 240, 237, 236, 48, 491, 219, 0, +3, 237, 240, 241, 491, 48, 247, 0, +3, 241, 238, 237, 247, 267, 491, 0, +3, 238, 241, 211, 267, 247, 393, 0, +3, 211, 211, 238, 393, 393, 267, 0, +3, 187, 191, 242, 356, 17, 411, 0, +3, 242, 239, 187, 411, 472, 356, 0, +3, 239, 242, 243, 472, 411, 364, 0, +3, 243, 240, 239, 364, 48, 472, 0, +3, 240, 243, 244, 48, 364, 441, 0, +3, 244, 241, 240, 441, 247, 48, 0, +3, 241, 244, 211, 247, 441, 393, 0, +3, 211, 211, 241, 393, 393, 247, 0, +3, 191, 195, 245, 17, 335, 239, 0, +3, 245, 242, 191, 239, 411, 17, 0, +3, 242, 245, 246, 411, 239, 13, 0, +3, 246, 243, 242, 13, 364, 411, 0, +3, 243, 246, 247, 364, 13, 509, 0, +3, 247, 244, 243, 509, 441, 364, 0, +3, 244, 247, 211, 441, 509, 393, 0, +3, 211, 211, 244, 393, 393, 441, 0, +3, 195, 199, 248, 335, 475, 144, 0, +3, 248, 245, 195, 144, 239, 335, 0, +3, 245, 248, 249, 239, 144, 179, 0, +3, 249, 246, 245, 179, 13, 239, 0, +3, 246, 249, 250, 13, 179, 298, 0, +3, 250, 247, 246, 298, 509, 13, 0, +3, 247, 250, 211, 509, 298, 393, 0, +3, 211, 211, 247, 393, 393, 509, 0, +3, 199, 203, 251, 475, 444, 462, 0, +3, 251, 248, 199, 462, 144, 475, 0, +3, 248, 251, 252, 144, 462, 76, 0, +3, 252, 249, 248, 76, 179, 144, 0, +3, 249, 252, 253, 179, 76, 464, 0, +3, 253, 250, 249, 464, 298, 179, 0, +3, 250, 253, 211, 298, 464, 393, 0, +3, 211, 211, 250, 393, 393, 298, 0, +3, 203, 207, 254, 444, 101, 500, 0, +3, 254, 251, 203, 500, 462, 444, 0, +3, 251, 254, 255, 462, 500, 113, 0, +3, 255, 252, 251, 113, 76, 462, 0, +3, 252, 255, 256, 76, 113, 128, 0, +3, 256, 253, 252, 128, 464, 76, 0, +3, 253, 256, 211, 464, 128, 393, 0, +3, 211, 211, 253, 393, 393, 464, 0, +3, 207, 147, 208, 101, 246, 279, 0, +3, 208, 254, 207, 279, 500, 101, 0, +3, 254, 208, 209, 500, 279, 349, 0, +3, 209, 255, 254, 349, 113, 500, 0, +3, 255, 209, 210, 113, 349, 216, 0, +3, 210, 256, 255, 216, 128, 113, 0, +3, 256, 210, 211, 128, 216, 393, 0, +3, 211, 211, 256, 393, 393, 128, 0, +3, 257, 262, 263, 425, 244, 58, 0, +3, 263, 258, 257, 58, 337, 425, 0, +3, 258, 263, 264, 337, 58, 214, 0, +3, 264, 259, 258, 214, 236, 337, 0, +3, 259, 264, 265, 236, 214, 266, 0, +3, 265, 260, 259, 266, 32, 236, 0, +3, 260, 265, 266, 32, 266, 331, 0, +3, 266, 261, 260, 331, 109, 32, 0, +3, 262, 267, 268, 244, 233, 369, 0, +3, 268, 263, 262, 369, 58, 244, 0, +3, 263, 268, 269, 58, 369, 71, 0, +3, 269, 264, 263, 71, 214, 58, 0, +3, 264, 269, 270, 214, 71, 392, 0, +3, 270, 265, 264, 392, 266, 214, 0, +3, 265, 270, 271, 266, 392, 312, 0, +3, 271, 266, 265, 312, 331, 266, 0, +3, 267, 272, 273, 233, 12, 434, 0, +3, 273, 268, 267, 434, 369, 233, 0, +3, 268, 273, 274, 369, 434, 188, 0, +3, 274, 269, 268, 188, 71, 369, 0, +3, 269, 274, 275, 71, 188, 201, 0, +3, 275, 270, 269, 201, 392, 71, 0, +3, 270, 275, 276, 392, 201, 238, 0, +3, 276, 271, 270, 238, 312, 392, 0, +3, 272, 277, 278, 12, 142, 114, 0, +3, 278, 273, 272, 114, 434, 12, 0, +3, 273, 278, 279, 434, 114, 173, 0, +3, 279, 274, 273, 173, 188, 434, 0, +3, 274, 279, 280, 188, 173, 14, 0, +3, 280, 275, 274, 14, 201, 188, 0, +3, 275, 280, 281, 201, 14, 15, 0, +3, 281, 276, 275, 15, 238, 201, 0, +3, 277, 282, 283, 142, 407, 288, 0, +3, 283, 278, 277, 288, 114, 142, 0, +3, 278, 283, 284, 114, 288, 400, 0, +3, 284, 279, 278, 400, 173, 114, 0, +3, 279, 284, 285, 173, 400, 457, 0, +3, 285, 280, 279, 457, 14, 173, 0, +3, 280, 285, 286, 14, 457, 332, 0, +3, 286, 281, 280, 332, 15, 14, 0, +3, 282, 287, 288, 407, 194, 42, 0, +3, 288, 283, 282, 42, 288, 407, 0, +3, 283, 288, 289, 288, 42, 380, 0, +3, 289, 284, 283, 380, 400, 288, 0, +3, 284, 289, 290, 400, 380, 383, 0, +3, 290, 285, 284, 383, 457, 400, 0, +3, 285, 290, 291, 457, 383, 197, 0, +3, 291, 286, 285, 197, 332, 457, 0, +3, 287, 292, 293, 194, 321, 152, 0, +3, 293, 288, 287, 152, 42, 194, 0, +3, 288, 293, 294, 42, 152, 397, 0, +3, 294, 289, 288, 397, 380, 42, 0, +3, 289, 294, 295, 380, 397, 342, 0, +3, 295, 290, 289, 342, 383, 380, 0, +3, 290, 295, 296, 383, 342, 225, 0, +3, 296, 291, 290, 225, 197, 383, 0, +3, 292, 257, 258, 321, 425, 337, 0, +3, 258, 293, 292, 337, 152, 321, 0, +3, 293, 258, 259, 152, 337, 236, 0, +3, 259, 294, 293, 236, 397, 152, 0, +3, 294, 259, 260, 397, 236, 32, 0, +3, 260, 295, 294, 32, 342, 397, 0, +3, 295, 260, 261, 342, 32, 109, 0, +3, 261, 296, 295, 109, 225, 342, 0, +3, 261, 266, 301, 109, 331, 175, 0, +3, 301, 297, 261, 175, 502, 109, 0, +3, 297, 301, 302, 502, 175, 265, 0, +3, 302, 298, 297, 265, 84, 502, 0, +3, 298, 302, 303, 84, 265, 186, 0, +3, 303, 299, 298, 186, 496, 84, 0, +3, 299, 303, 304, 496, 186, 470, 0, +3, 304, 300, 299, 470, 494, 496, 0, +3, 266, 271, 305, 331, 312, 170, 0, +3, 305, 301, 266, 170, 175, 331, 0, +3, 301, 305, 306, 175, 170, 97, 0, +3, 306, 302, 301, 97, 265, 175, 0, +3, 302, 306, 307, 265, 97, 205, 0, +3, 307, 303, 302, 205, 186, 265, 0, +3, 303, 307, 308, 186, 205, 449, 0, +3, 308, 304, 303, 449, 470, 186, 0, +3, 271, 276, 309, 312, 238, 379, 0, +3, 309, 305, 271, 379, 170, 312, 0, +3, 305, 309, 310, 170, 379, 300, 0, +3, 310, 306, 305, 300, 97, 170, 0, +3, 306, 310, 311, 97, 300, 118, 0, +3, 311, 307, 306, 118, 205, 97, 0, +3, 307, 311, 312, 205, 118, 237, 0, +3, 312, 308, 307, 237, 449, 205, 0, +3, 276, 281, 313, 238, 15, 199, 0, +3, 313, 309, 276, 199, 379, 238, 0, +3, 309, 313, 314, 379, 199, 94, 0, +3, 314, 310, 309, 94, 300, 379, 0, +3, 310, 314, 315, 300, 94, 421, 0, +3, 315, 311, 310, 421, 118, 300, 0, +3, 311, 315, 316, 118, 421, 31, 0, +3, 316, 312, 311, 31, 237, 118, 0, +3, 281, 286, 317, 15, 332, 367, 0, +3, 317, 313, 281, 367, 199, 15, 0, +3, 313, 317, 318, 199, 367, 529, 0, +3, 318, 314, 313, 529, 94, 199, 0, +3, 314, 318, 319, 94, 529, 185, 0, +3, 319, 315, 314, 185, 421, 94, 0, +3, 315, 319, 320, 421, 185, 89, 0, +3, 320, 316, 315, 89, 31, 421, 0, +3, 286, 291, 321, 332, 197, 172, 0, +3, 321, 317, 286, 172, 367, 332, 0, +3, 317, 321, 322, 367, 172, 209, 0, +3, 322, 318, 317, 209, 529, 367, 0, +3, 318, 322, 323, 529, 209, 429, 0, +3, 323, 319, 318, 429, 185, 529, 0, +3, 319, 323, 324, 185, 429, 112, 0, +3, 324, 320, 319, 112, 89, 185, 0, +3, 291, 296, 325, 197, 225, 451, 0, +3, 325, 321, 291, 451, 172, 197, 0, +3, 321, 325, 326, 172, 451, 66, 0, +3, 326, 322, 321, 66, 209, 172, 0, +3, 322, 326, 327, 209, 66, 176, 0, +3, 327, 323, 322, 176, 429, 209, 0, +3, 323, 327, 328, 429, 176, 155, 0, +3, 328, 324, 323, 155, 112, 429, 0, +3, 296, 261, 297, 225, 109, 502, 0, +3, 297, 325, 296, 502, 451, 225, 0, +3, 325, 297, 298, 451, 502, 84, 0, +3, 298, 326, 325, 84, 66, 451, 0, +3, 326, 298, 299, 66, 84, 496, 0, +3, 299, 327, 326, 496, 176, 66, 0, +3, 327, 299, 300, 176, 496, 494, 0, +3, 300, 328, 327, 494, 155, 176, 0, +3, 329, 334, 335, 3, 355, 122, 0, +3, 335, 330, 329, 122, 518, 3, 0, +3, 330, 335, 336, 518, 122, 111, 0, +3, 336, 331, 330, 111, 213, 518, 0, +3, 331, 336, 337, 213, 111, 473, 0, +3, 337, 332, 331, 473, 468, 213, 0, +3, 332, 337, 338, 468, 473, 521, 0, +3, 338, 333, 332, 521, 346, 468, 0, +3, 334, 339, 340, 355, 61, 414, 0, +3, 340, 335, 334, 414, 122, 355, 0, +3, 335, 340, 341, 122, 414, 413, 0, +3, 341, 336, 335, 413, 111, 122, 0, +3, 336, 341, 342, 111, 413, 204, 0, +3, 342, 337, 336, 204, 473, 111, 0, +3, 337, 342, 343, 473, 204, 217, 0, +3, 343, 338, 337, 217, 521, 473, 0, +3, 339, 344, 345, 61, 55, 100, 0, +3, 345, 340, 339, 100, 414, 61, 0, +3, 340, 345, 346, 414, 100, 399, 0, +3, 346, 341, 340, 399, 413, 414, 0, +3, 341, 346, 347, 413, 399, 326, 0, +3, 347, 342, 341, 326, 204, 413, 0, +3, 342, 347, 348, 204, 326, 221, 0, +3, 348, 343, 342, 221, 217, 204, 0, +3, 344, 349, 350, 55, 508, 477, 0, +3, 350, 345, 344, 477, 100, 55, 0, +3, 345, 350, 351, 100, 477, 292, 0, +3, 351, 346, 345, 292, 399, 100, 0, +3, 346, 351, 352, 399, 292, 73, 0, +3, 352, 347, 346, 73, 326, 399, 0, +3, 347, 352, 353, 326, 73, 362, 0, +3, 353, 348, 347, 362, 221, 326, 0, +3, 349, 354, 355, 508, 365, 262, 0, +3, 355, 350, 349, 262, 477, 508, 0, +3, 350, 355, 356, 477, 262, 93, 0, +3, 356, 351, 350, 93, 292, 477, 0, +3, 351, 356, 357, 292, 93, 318, 0, +3, 357, 352, 351, 318, 73, 292, 0, +3, 352, 357, 358, 73, 318, 163, 0, +3, 358, 353, 352, 163, 362, 73, 0, +3, 354, 359, 360, 365, 140, 340, 0, +3, 360, 355, 354, 340, 262, 365, 0, +3, 355, 360, 361, 262, 340, 505, 0, +3, 361, 356, 355, 505, 93, 262, 0, +3, 356, 361, 362, 93, 505, 499, 0, +3, 362, 357, 356, 499, 318, 93, 0, +3, 357, 362, 363, 318, 499, 159, 0, +3, 363, 358, 357, 159, 163, 318, 0, +3, 359, 364, 365, 140, 510, 68, 0, +3, 365, 360, 359, 68, 340, 140, 0, +3, 360, 365, 366, 340, 68, 167, 0, +3, 366, 361, 360, 167, 505, 340, 0, +3, 361, 366, 367, 505, 167, 245, 0, +3, 367, 362, 361, 245, 499, 505, 0, +3, 362, 367, 368, 499, 245, 437, 0, +3, 368, 363, 362, 437, 159, 499, 0, +3, 364, 329, 330, 510, 3, 518, 0, +3, 330, 365, 364, 518, 68, 510, 0, +3, 365, 330, 331, 68, 518, 213, 0, +3, 331, 366, 365, 213, 167, 68, 0, +3, 366, 331, 332, 167, 213, 468, 0, +3, 332, 367, 366, 468, 245, 167, 0, +3, 367, 332, 333, 245, 468, 346, 0, +3, 333, 368, 367, 346, 437, 245, 0, +3, 333, 338, 373, 346, 521, 79, 0, +3, 373, 369, 333, 79, 286, 346, 0, +3, 369, 373, 374, 286, 79, 77, 0, +3, 374, 370, 369, 77, 22, 286, 0, +3, 370, 374, 375, 22, 77, 523, 0, +3, 375, 371, 370, 523, 330, 22, 0, +3, 371, 375, 376, 330, 523, 259, 0, +3, 376, 372, 371, 259, 338, 330, 0, +3, 338, 343, 377, 521, 217, 207, 0, +3, 377, 373, 338, 207, 79, 521, 0, +3, 373, 377, 378, 79, 207, 471, 0, +3, 378, 374, 373, 471, 77, 79, 0, +3, 374, 378, 379, 77, 471, 198, 0, +3, 379, 375, 374, 198, 523, 77, 0, +3, 375, 379, 380, 523, 198, 366, 0, +3, 380, 376, 375, 366, 259, 523, 0, +3, 343, 348, 381, 217, 221, 516, 0, +3, 381, 377, 343, 516, 207, 217, 0, +3, 377, 381, 382, 207, 516, 250, 0, +3, 382, 378, 377, 250, 471, 207, 0, +3, 378, 382, 383, 471, 250, 240, 0, +3, 383, 379, 378, 240, 198, 471, 0, +3, 379, 383, 384, 198, 240, 381, 0, +3, 384, 380, 379, 381, 366, 198, 0, +3, 348, 353, 385, 221, 362, 230, 0, +3, 385, 381, 348, 230, 516, 221, 0, +3, 381, 385, 386, 516, 230, 303, 0, +3, 386, 382, 381, 303, 250, 516, 0, +3, 382, 386, 387, 250, 303, 10, 0, +3, 387, 383, 382, 10, 240, 250, 0, +3, 383, 387, 388, 240, 10, 283, 0, +3, 388, 384, 383, 283, 381, 240, 0, +3, 353, 358, 389, 362, 163, 282, 0, +3, 389, 385, 353, 282, 230, 362, 0, +3, 385, 389, 390, 230, 282, 35, 0, +3, 390, 386, 385, 35, 303, 230, 0, +3, 386, 390, 391, 303, 35, 243, 0, +3, 391, 387, 386, 243, 10, 303, 0, +3, 387, 391, 392, 10, 243, 368, 0, +3, 392, 388, 387, 368, 283, 10, 0, +3, 358, 363, 393, 163, 159, 296, 0, +3, 393, 389, 358, 296, 282, 163, 0, +3, 389, 393, 394, 282, 296, 160, 0, +3, 394, 390, 389, 160, 35, 282, 0, +3, 390, 394, 395, 35, 160, 323, 0, +3, 395, 391, 390, 323, 243, 35, 0, +3, 391, 395, 396, 243, 323, 280, 0, +3, 396, 392, 391, 280, 368, 243, 0, +3, 363, 368, 397, 159, 437, 275, 0, +3, 397, 393, 363, 275, 296, 159, 0, +3, 393, 397, 398, 296, 275, 133, 0, +3, 398, 394, 393, 133, 160, 296, 0, +3, 394, 398, 399, 160, 133, 344, 0, +3, 399, 395, 394, 344, 323, 160, 0, +3, 395, 399, 400, 323, 344, 108, 0, +3, 400, 396, 395, 108, 280, 323, 0, +3, 368, 333, 369, 437, 346, 286, 0, +3, 369, 397, 368, 286, 275, 437, 0, +3, 397, 369, 370, 275, 286, 22, 0, +3, 370, 398, 397, 22, 133, 275, 0, +3, 398, 370, 371, 133, 22, 330, 0, +3, 371, 399, 398, 330, 344, 133, 0, +3, 399, 371, 372, 344, 330, 338, 0, +3, 372, 400, 399, 338, 108, 344, 0, +3, 401, 401, 406, 235, 235, 189, 0, +3, 406, 402, 401, 189, 40, 235, 0, +3, 402, 406, 407, 40, 189, 306, 0, +3, 407, 403, 402, 306, 119, 40, 0, +3, 403, 407, 408, 119, 306, 202, 0, +3, 408, 404, 403, 202, 443, 119, 0, +3, 404, 408, 409, 443, 202, 241, 0, +3, 409, 405, 404, 241, 75, 443, 0, +3, 401, 401, 410, 235, 235, 263, 0, +3, 410, 406, 401, 263, 189, 235, 0, +3, 406, 410, 411, 189, 263, 196, 0, +3, 411, 407, 406, 196, 306, 189, 0, +3, 407, 411, 412, 306, 196, 281, 0, +3, 412, 408, 407, 281, 202, 306, 0, +3, 408, 412, 413, 202, 281, 121, 0, +3, 413, 409, 408, 121, 241, 202, 0, +3, 401, 401, 414, 235, 235, 479, 0, +3, 414, 410, 401, 479, 263, 235, 0, +3, 410, 414, 415, 263, 479, 36, 0, +3, 415, 411, 410, 36, 196, 263, 0, +3, 411, 415, 416, 196, 36, 436, 0, +3, 416, 412, 411, 436, 281, 196, 0, +3, 412, 416, 417, 281, 436, 351, 0, +3, 417, 413, 412, 351, 121, 281, 0, +3, 401, 401, 418, 235, 235, 90, 0, +3, 418, 414, 401, 90, 479, 235, 0, +3, 414, 418, 419, 479, 90, 361, 0, +3, 419, 415, 414, 361, 36, 479, 0, +3, 415, 419, 420, 36, 361, 376, 0, +3, 420, 416, 415, 376, 436, 36, 0, +3, 416, 420, 421, 436, 376, 412, 0, +3, 421, 417, 416, 412, 351, 436, 0, +3, 401, 401, 422, 235, 235, 52, 0, +3, 422, 418, 401, 52, 90, 235, 0, +3, 418, 422, 423, 90, 52, 21, 0, +3, 423, 419, 418, 21, 361, 90, 0, +3, 419, 423, 424, 361, 21, 158, 0, +3, 424, 420, 419, 158, 376, 361, 0, +3, 420, 424, 425, 376, 158, 39, 0, +3, 425, 421, 420, 39, 412, 376, 0, +3, 401, 401, 426, 235, 235, 424, 0, +3, 426, 422, 401, 424, 52, 235, 0, +3, 422, 426, 427, 52, 424, 373, 0, +3, 427, 423, 422, 373, 21, 52, 0, +3, 423, 427, 428, 21, 373, 375, 0, +3, 428, 424, 423, 375, 158, 21, 0, +3, 424, 428, 429, 158, 375, 249, 0, +3, 429, 425, 424, 249, 39, 158, 0, +3, 401, 401, 430, 235, 235, 432, 0, +3, 430, 426, 401, 432, 424, 235, 0, +3, 426, 430, 431, 424, 432, 229, 0, +3, 431, 427, 426, 229, 373, 424, 0, +3, 427, 431, 432, 373, 229, 65, 0, +3, 432, 428, 427, 65, 375, 373, 0, +3, 428, 432, 433, 375, 65, 506, 0, +3, 433, 429, 428, 506, 249, 375, 0, +3, 401, 401, 434, 235, 235, 302, 0, +3, 434, 430, 401, 302, 432, 235, 0, +3, 430, 434, 435, 432, 302, 96, 0, +3, 435, 431, 430, 96, 229, 432, 0, +3, 431, 435, 436, 229, 96, 169, 0, +3, 436, 432, 431, 169, 65, 229, 0, +3, 432, 436, 437, 65, 169, 59, 0, +3, 437, 433, 432, 59, 506, 65, 0, +3, 401, 401, 438, 235, 235, 452, 0, +3, 438, 434, 401, 452, 302, 235, 0, +3, 434, 438, 439, 302, 452, 30, 0, +3, 439, 435, 434, 30, 96, 302, 0, +3, 435, 439, 440, 96, 30, 460, 0, +3, 440, 436, 435, 460, 169, 96, 0, +3, 436, 440, 441, 169, 460, 498, 0, +3, 441, 437, 436, 498, 59, 169, 0, +3, 401, 401, 442, 235, 235, 525, 0, +3, 442, 438, 401, 525, 452, 235, 0, +3, 438, 442, 443, 452, 525, 456, 0, +3, 443, 439, 438, 456, 30, 452, 0, +3, 439, 443, 444, 30, 456, 9, 0, +3, 444, 440, 439, 9, 460, 30, 0, +3, 440, 444, 445, 460, 9, 388, 0, +3, 445, 441, 440, 388, 498, 460, 0, +3, 401, 401, 446, 235, 235, 212, 0, +3, 446, 442, 401, 212, 525, 235, 0, +3, 442, 446, 447, 525, 212, 299, 0, +3, 447, 443, 442, 299, 456, 525, 0, +3, 443, 447, 448, 456, 299, 166, 0, +3, 448, 444, 443, 166, 9, 456, 0, +3, 444, 448, 449, 9, 166, 72, 0, +3, 449, 445, 444, 72, 388, 9, 0, +3, 401, 401, 450, 235, 235, 107, 0, +3, 450, 446, 401, 107, 212, 235, 0, +3, 446, 450, 451, 212, 107, 82, 0, +3, 451, 447, 446, 82, 299, 212, 0, +3, 447, 451, 452, 299, 82, 391, 0, +3, 452, 448, 447, 391, 166, 299, 0, +3, 448, 452, 453, 166, 391, 139, 0, +3, 453, 449, 448, 139, 72, 166, 0, +3, 401, 401, 454, 235, 235, 70, 0, +3, 454, 450, 401, 70, 107, 235, 0, +3, 450, 454, 455, 107, 70, 51, 0, +3, 455, 451, 450, 51, 82, 107, 0, +3, 451, 455, 456, 82, 51, 178, 0, +3, 456, 452, 451, 178, 391, 82, 0, +3, 452, 456, 457, 391, 178, 57, 0, +3, 457, 453, 452, 57, 139, 391, 0, +3, 401, 401, 458, 235, 235, 442, 0, +3, 458, 454, 401, 442, 70, 235, 0, +3, 454, 458, 459, 70, 442, 387, 0, +3, 459, 455, 454, 387, 51, 70, 0, +3, 455, 459, 460, 51, 387, 389, 0, +3, 460, 456, 455, 389, 178, 51, 0, +3, 456, 460, 461, 178, 389, 264, 0, +3, 461, 457, 456, 264, 57, 178, 0, +3, 401, 401, 462, 235, 235, 450, 0, +3, 462, 458, 401, 450, 442, 235, 0, +3, 458, 462, 463, 442, 450, 253, 0, +3, 463, 459, 458, 253, 387, 442, 0, +3, 459, 463, 464, 387, 253, 86, 0, +3, 464, 460, 459, 86, 389, 387, 0, +3, 460, 464, 465, 389, 86, 526, 0, +3, 465, 461, 460, 526, 264, 389, 0, +3, 401, 401, 402, 235, 235, 40, 0, +3, 402, 462, 401, 40, 450, 235, 0, +3, 462, 402, 403, 450, 40, 119, 0, +3, 403, 463, 462, 119, 253, 450, 0, +3, 463, 403, 404, 253, 119, 443, 0, +3, 404, 464, 463, 443, 86, 253, 0, +3, 464, 404, 405, 86, 443, 75, 0, +3, 405, 465, 464, 75, 526, 86, 0, +3, 405, 409, 470, 75, 241, 519, 0, +3, 470, 466, 405, 519, 226, 75, 0, +3, 466, 470, 471, 226, 519, 406, 0, +3, 471, 467, 466, 406, 98, 226, 0, +3, 467, 471, 472, 98, 406, 232, 0, +3, 472, 468, 467, 232, 43, 98, 0, +3, 468, 472, 473, 43, 232, 345, 0, +3, 473, 469, 468, 345, 372, 43, 0, +3, 409, 413, 474, 241, 121, 227, 0, +3, 474, 470, 409, 227, 519, 241, 0, +3, 470, 474, 475, 519, 227, 469, 0, +3, 475, 471, 470, 469, 406, 519, 0, +3, 471, 475, 476, 406, 469, 258, 0, +3, 476, 472, 471, 258, 232, 406, 0, +3, 472, 476, 477, 232, 258, 271, 0, +3, 477, 473, 472, 271, 345, 232, 0, +3, 413, 417, 478, 121, 351, 157, 0, +3, 478, 474, 413, 157, 227, 121, 0, +3, 474, 478, 479, 227, 157, 80, 0, +3, 479, 475, 474, 80, 469, 227, 0, +3, 475, 479, 480, 469, 80, 489, 0, +3, 480, 476, 475, 489, 258, 469, 0, +3, 476, 480, 481, 258, 489, 277, 0, +3, 481, 477, 476, 277, 271, 258, 0, +3, 417, 421, 482, 351, 412, 153, 0, +3, 482, 478, 417, 153, 157, 351, 0, +3, 478, 482, 483, 157, 153, 324, 0, +3, 483, 479, 478, 324, 80, 157, 0, +3, 479, 483, 484, 80, 324, 339, 0, +3, 484, 480, 479, 339, 489, 80, 0, +3, 480, 484, 485, 489, 339, 88, 0, +3, 485, 481, 480, 88, 277, 489, 0, +3, 421, 425, 486, 412, 39, 6, 0, +3, 486, 482, 421, 6, 153, 412, 0, +3, 482, 486, 487, 153, 6, 8, 0, +3, 487, 483, 482, 8, 324, 153, 0, +3, 483, 487, 488, 324, 8, 16, 0, +3, 488, 484, 483, 16, 339, 324, 0, +3, 484, 488, 489, 339, 16, 289, 0, +3, 489, 485, 484, 289, 88, 339, 0, +3, 425, 429, 490, 39, 249, 99, 0, +3, 490, 486, 425, 99, 6, 39, 0, +3, 486, 490, 491, 6, 99, 200, 0, +3, 491, 487, 486, 200, 8, 6, 0, +3, 487, 491, 492, 8, 200, 150, 0, +3, 492, 488, 487, 150, 16, 8, 0, +3, 488, 492, 493, 16, 150, 493, 0, +3, 493, 489, 488, 493, 289, 16, 0, +3, 429, 433, 494, 249, 506, 291, 0, +3, 494, 490, 429, 291, 99, 249, 0, +3, 490, 494, 495, 99, 291, 64, 0, +3, 495, 491, 490, 64, 200, 99, 0, +3, 491, 495, 496, 200, 64, 19, 0, +3, 496, 492, 491, 19, 150, 200, 0, +3, 492, 496, 497, 150, 19, 433, 0, +3, 497, 493, 492, 433, 493, 150, 0, +3, 433, 437, 498, 506, 59, 203, 0, +3, 498, 494, 433, 203, 291, 506, 0, +3, 494, 498, 499, 291, 203, 374, 0, +3, 499, 495, 494, 374, 64, 291, 0, +3, 495, 499, 500, 64, 374, 307, 0, +3, 500, 496, 495, 307, 19, 64, 0, +3, 496, 500, 501, 19, 307, 358, 0, +3, 501, 497, 496, 358, 433, 19, 0, +3, 437, 441, 502, 59, 498, 256, 0, +3, 502, 498, 437, 256, 203, 59, 0, +3, 498, 502, 503, 203, 256, 132, 0, +3, 503, 499, 498, 132, 374, 203, 0, +3, 499, 503, 504, 374, 132, 492, 0, +3, 504, 500, 499, 492, 307, 374, 0, +3, 500, 504, 505, 307, 492, 67, 0, +3, 505, 501, 500, 67, 358, 307, 0, +3, 441, 445, 506, 498, 388, 487, 0, +3, 506, 502, 441, 487, 256, 498, 0, +3, 502, 506, 507, 256, 487, 206, 0, +3, 507, 503, 502, 206, 132, 256, 0, +3, 503, 507, 508, 132, 206, 515, 0, +3, 508, 504, 503, 515, 492, 132, 0, +3, 504, 508, 509, 492, 515, 527, 0, +3, 509, 505, 504, 527, 67, 492, 0, +3, 445, 449, 510, 388, 72, 423, 0, +3, 510, 506, 445, 423, 487, 388, 0, +3, 506, 510, 511, 487, 423, 352, 0, +3, 511, 507, 506, 352, 206, 487, 0, +3, 507, 511, 512, 206, 352, 224, 0, +3, 512, 508, 507, 224, 515, 206, 0, +3, 508, 512, 513, 515, 224, 2, 0, +3, 513, 509, 508, 2, 527, 515, 0, +3, 449, 453, 514, 72, 139, 418, 0, +3, 514, 510, 449, 418, 423, 72, 0, +3, 510, 514, 515, 423, 418, 341, 0, +3, 515, 511, 510, 341, 352, 423, 0, +3, 511, 515, 516, 352, 341, 359, 0, +3, 516, 512, 511, 359, 224, 352, 0, +3, 512, 516, 517, 224, 359, 360, 0, +3, 517, 513, 512, 360, 2, 224, 0, +3, 453, 457, 518, 139, 57, 24, 0, +3, 518, 514, 453, 24, 418, 139, 0, +3, 514, 518, 519, 418, 24, 25, 0, +3, 519, 515, 514, 25, 341, 418, 0, +3, 515, 519, 520, 341, 25, 41, 0, +3, 520, 516, 515, 41, 359, 341, 0, +3, 516, 520, 521, 359, 41, 314, 0, +3, 521, 517, 516, 314, 360, 359, 0, +3, 457, 461, 522, 57, 264, 120, 0, +3, 522, 518, 457, 120, 24, 57, 0, +3, 518, 522, 523, 24, 120, 223, 0, +3, 523, 519, 518, 223, 25, 24, 0, +3, 519, 523, 524, 25, 223, 171, 0, +3, 524, 520, 519, 171, 41, 25, 0, +3, 520, 524, 525, 41, 171, 514, 0, +3, 525, 521, 520, 514, 314, 41, 0, +3, 461, 465, 526, 264, 526, 316, 0, +3, 526, 522, 461, 316, 120, 264, 0, +3, 522, 526, 527, 120, 316, 85, 0, +3, 527, 523, 522, 85, 223, 120, 0, +3, 523, 527, 528, 223, 85, 50, 0, +3, 528, 524, 523, 50, 171, 223, 0, +3, 524, 528, 529, 171, 50, 454, 0, +3, 529, 525, 524, 454, 514, 171, 0, +3, 465, 405, 466, 526, 75, 226, 0, +3, 466, 526, 465, 226, 316, 526, 0, +3, 526, 466, 467, 316, 226, 98, 0, +3, 467, 527, 526, 98, 85, 316, 0, +3, 527, 467, 468, 85, 98, 43, 0, +3, 468, 528, 527, 43, 50, 85, 0, +3, 528, 468, 469, 50, 43, 372, 0, +3, 469, 529, 528, 372, 454, 50, 0 +}; + + +const int strip_vertices[] = { +508, 508, 504, 509, 504, 505, 500, 501, 496, 497, 492, 493, 488, 489, 484, 485, 480, 481, 476, 477, 472, 473, -1, +476, 475, 480, 479, 484, 483, 488, 487, 492, 491, 496, 495, 500, 499, 504, 499, 503, 498, 502, 437, 441, -1, +527, 526, 467, 466, 471, 470, 475, 474, 479, 478, 483, 482, 487, 486, 491, 490, 495, 494, 499, 494, 498, -1, +490, 490, 425, 486, 421, 482, 417, 478, 413, 474, 409, 470, 405, 466, 465, 526, 465, 461, 460, 456, 455, 451, -1, +405, 465, 464, 460, 459, 455, 454, 450, -1, +455, 451, 450, 446, 450, 401, 454, 458, 459, 463, 464, 404, 405, 404, 409, 408, 413, 412, 417, 416, 421, 420, -1, +421, 420, 425, 420, 424, 419, 423, 418, 422, 418, 401, 414, 410, 415, 411, 416, 411, 412, 407, 408, 403, 404, 403, 463, -1, +418, 418, 414, 419, 415, 420, 416, -1, +407, 403, 402, 462, -1, +403, 463, 462, 458, 462, 401, 402, 406, 407, 406, 411, 406, 410, 401, -1, +494, 494, 498, 433, 437, 432, 436, 431, 435, 430, 434, 430, 401, 426, 422, 427, 423, 428, 424, 429, 425, 490, -1, +430, 430, 426, 431, 427, 432, 428, 433, 429, 494, 490, -1, +437, 437, 441, 436, 440, 435, 439, 434, 438, 401, 442, 446, 447, 451, 452, 456, 457, 461, 522, 526, 527, -1, +452, 448, 447, -1, +510, 445, 449, 444, 448, 443, 447, 443, 442, 443, 438, 443, 439, 444, 440, 445, 441, 506, 502, 507, 503, -1, +510, 506, 445, -1, +507, 506, 511, 510, 515, 510, 514, 449, 453, 448, 453, 452, 457, -1, +527, 523, 522, 518, 457, 518, 453, 518, 514, 519, 515, -1, +523, 519, 518, -1, +504, 503, 508, 507, 512, 511, 516, 515, 520, 519, 524, 523, 528, 527, 468, 467, 472, 471, 476, 475, -1, +472, 473, 468, 469, 528, 529, 524, 525, 520, 521, 516, 517, 512, 513, 508, 509, -1, +211, 211, 214, 210, 209, -1, +212, 215, 216, 219, 220, 223, 220, 211, 217, 214, 213, 209, 213, 208, 212, 147, -1, +220, 217, 216, 213, 212, -1, +251, 251, 248, 252, 249, 253, 250, 253, 211, 256, 210, 255, 209, 254, 208, 207, 147, 206, 147, 146, 147, 151, 212, 215, -1, +206, 206, 202, 207, 203, 254, 251, 255, 252, 256, 253, -1, +223, 223, 222, 219, 218, 215, 155, 151, 150, 146, 145, 146, 205, 206, 201, 202, 197, 202, 198, 203, 199, 251, 248, -1, +145, 149, 150, 154, 155, 159, 218, 221, 222, 225, 226, 229, -1, +204, 204, 145, 144, 149, 148, 149, 153, 154, 158, 159, 163, 221, 224, 225, 228, 229, 232, 229, 211, 226, 223, 222, -1, +224, 224, 167, 163, 162, 158, 157, 153, 152, 148, 87, 148, 83, 144, 143, 204, 139, 200, 135, 196, 131, 192, -1, +82, 83, 142, 143, 138, 139, 134, 135, 130, 131, 126, 127, 122, 123, 118, 123, 119, 184, 180, 185, 181, -1, +81, 82, 141, 142, 137, 138, 133, 134, 129, 130, 125, 126, 121, 122, 117, 118, 113, 114, 109, 110, -1, +80, 81, 140, 141, 136, 137, 132, 133, 128, 129, 124, 125, 120, 121, 116, 117, 112, 113, 108, 109, -1, +4, 80, 79, 140, 74, 136, 69, 132, 64, 128, 59, 124, 54, 120, 49, 116, 44, 112, 39, 108, -1, +79, 79, 73, 74, 68, 69, 63, 64, 58, 59, 53, 54, 48, 49, 48, 43, 42, 37, 36, 31, 30, 31, 25, -1, +42, 42, 48, 47, 53, 52, 58, 57, 63, 62, 68, 67, 73, 72, 78, 77, 3, 2, 8, 7, 13, -1, +36, 36, 42, 41, 47, 46, 52, 51, 57, 56, 62, 61, 67, 66, 72, 71, 77, 76, 2, 1, 7, -1, +66, 66, 60, 61, 55, 56, 50, 51, 45, 46, 40, 41, 35, 36, 30, -1, +31, 31, 25, 26, 20, 21, 15, 16, 10, 11, 5, 6, 0, 1, 75, 76, 70, 71, 65, 66, 60, -1, +1, 1, 7, 6, 12, 11, 17, 16, 22, 21, 27, 26, 32, 31, 32, 37, 38, 43, 44, 49, -1, +7, 7, 13, 12, 18, 17, 23, 22, 28, 27, 33, 32, 33, 38, -1, +44, 44, 38, 39, 33, 34, 28, 29, 23, 24, 18, 19, 13, 14, 8, 9, 3, 4, 78, 79, 73, -1, +39, 108, 34, 104, 29, 100, 24, 96, 19, 92, 14, 88, 9, 84, 4, 84, 80, 85, 81, 86, 81, 82, -1, +108, 109, 104, 105, 100, 101, 96, 97, 92, 93, 88, 89, 84, 85, -1, +109, 110, 105, 106, 101, 102, 97, 98, 93, 94, 89, 90, 85, 86, -1, +118, 119, 114, 115, 110, 111, 106, 107, 102, 103, 98, 99, 94, 95, 90, 91, 86, 87, 82, 83, -1, +111, 115, 176, -1, +107, 111, 172, 176, 177, -1, +103, 107, 168, 172, 173, 177, 178, -1, +99, 103, 164, 168, 169, 173, 174, 178, 179, -1, +95, 99, 160, 164, 165, 169, 170, 174, 175, 179, 233, -1, +91, 95, 156, 160, 161, 165, 166, 170, 171, 175, 230, 233, 234, -1, +87, 91, 152, 156, 157, 161, 162, 166, 167, 171, 227, 230, 231, 234, 235, 234, 238, 234, 237, 233, 236, 179, -1, +185, 185, 181, 186, 182, 187, 183, 239, 236, 240, 237, 241, 238, 211, 235, 232, 231, 228, 227, 224, 167, -1, +236, 179, 183, 178, 182, 177, 181, 176, 180, 115, 119, -1, +131, 192, 127, 188, 123, 188, 184, 189, 185, 190, 186, 191, 187, 242, 239, 243, 240, 244, 241, 244, 211, 247, -1, +192, 192, 188, 193, 189, 194, 190, 195, 191, 245, 242, 246, 243, 247, 244, -1, +211, 247, 250, 246, 249, 245, 248, 195, 199, 194, 198, 193, 197, 192, 197, 196, 201, 200, 205, 204, 145, -1, +393, 393, 394, 398, 399, 371, -1, +399, 395, 394, -1, +363, 363, 393, 397, 398, 370, 371, 375, -1, +379, 375, 374, 370, 369, 397, 368, 363, 362, -1, +396, 395, 400, 399, 372, 371, 376, 375, 380, 379, 384, 383, 388, 387, 392, 391, 396, 391, 395, 390, 394, -1, +374, 378, 379, 378, 383, 382, 387, 386, 391, 386, 390, 385, 389, 353, 358, 352, 357, 351, 356, 350, 355, -1, +341, 341, 347, 346, 352, 346, 351, 345, 350, -1, +335, 334, 340, 339, 345, 344, 350, 349, 355, 354, -1, +390, 390, 394, 389, 393, 358, 363, 357, 362, 356, 361, 355, 360, 354, 360, 359, 365, 364, 330, 329, 335, 334, -1, +345, 346, 340, 341, 335, 336, 330, 331, 365, 366, 360, 366, 361, 367, 362, 367, 368, 333, 369, 373, 374, 378, -1, +353, 353, 348, 385, 381, 386, 381, 382, 377, 378, 377, 373, 338, 333, 332, 367, 332, 366, 332, 331, 337, 336, 342, 341, 347, -1, +332, 337, 338, 343, 377, 343, 381, 343, 348, 342, 348, 347, 353, 352, -1, +337, 342, 343, -1, +314, 314, 319, 318, 323, 322, 323, 327, -1, +309, 309, 314, 313, 318, 317, 322, 321, 322, 326, 327, 299, -1, +271, 271, 309, 276, 313, 281, 317, 286, 321, 291, 321, 325, 326, 298, 299, 303, -1, +265, 265, 271, 270, 276, 275, 281, 280, 286, 285, 291, 290, 291, 296, 325, 297, 298, 302, 303, 307, -1, +259, 259, 265, 264, 270, 269, 275, 274, 280, 279, 285, 284, 290, 289, 290, 295, 296, 261, 297, 301, 302, 306, 307, 311, -1, +293, 293, 259, 258, 264, 263, 269, 268, 274, 273, 279, 278, 284, 283, 289, 288, 289, 294, 295, 260, 261, 266, -1, +309, 305, 271, 266, 265, 260, 259, 294, 293, 288, 287, 288, 282, 283, 277, 278, 272, 273, 267, 268, 262, -1, +268, 268, 262, 263, 257, 258, 292, 293, 287, -1, +261, 266, 301, 305, 306, 310, 311, 315, 316, 320, -1, +316, 316, 311, 312, 307, 308, 303, 304, 299, 300, 327, 328, 323, 324, 319, 320, 319, 315, 314, 310, 309, 305, -1 +}; + + +const int strip_normals[] = { +515, 515, 492, 527, 492, 67, 307, 358, 19, 433, 150, 493, 16, 289, 339, 88, 489, 277, 258, 271, 232, 345, -1, +258, 469, 489, 80, 339, 324, 16, 8, 150, 200, 19, 64, 307, 374, 492, 374, 132, 203, 256, 59, 498, -1, +85, 316, 98, 226, 406, 519, 469, 227, 80, 157, 324, 153, 8, 6, 200, 99, 64, 291, 374, 291, 203, -1, +99, 99, 39, 6, 412, 153, 351, 157, 121, 227, 241, 519, 75, 226, 526, 316, 526, 264, 389, 178, 51, 82, -1, +75, 526, 86, 389, 387, 51, 70, 107, -1, +51, 82, 107, 212, 107, 235, 70, 442, 387, 253, 86, 443, 75, 443, 241, 202, 121, 281, 351, 436, 412, 376, -1, +412, 376, 39, 376, 158, 361, 21, 90, 52, 90, 235, 479, 263, 36, 196, 436, 196, 281, 306, 202, 119, 443, 119, 253, -1, +90, 90, 479, 361, 36, 376, 436, -1, +306, 119, 40, 450, -1, +119, 253, 450, 442, 450, 235, 40, 189, 306, 189, 196, 189, 263, 235, -1, +291, 291, 203, 506, 59, 65, 169, 229, 96, 432, 302, 432, 235, 424, 52, 373, 21, 375, 158, 249, 39, 99, -1, +432, 432, 424, 229, 373, 65, 375, 506, 249, 291, 99, -1, +59, 59, 498, 169, 460, 96, 30, 302, 452, 235, 525, 212, 299, 82, 391, 178, 57, 264, 120, 316, 85, -1, +391, 166, 299, -1, +423, 388, 72, 9, 166, 456, 299, 456, 525, 456, 452, 456, 30, 9, 460, 388, 498, 487, 256, 206, 132, -1, +423, 487, 388, -1, +206, 487, 352, 423, 341, 423, 418, 72, 139, 166, 139, 391, 57, -1, +85, 223, 120, 24, 57, 24, 139, 24, 418, 25, 341, -1, +223, 25, 24, -1, +492, 132, 515, 206, 224, 352, 359, 341, 41, 25, 171, 223, 50, 85, 43, 98, 232, 406, 258, 469, -1, +232, 345, 43, 372, 50, 454, 171, 514, 41, 314, 359, 360, 224, 2, 515, 527, -1, +393, 393, 0, 216, 349, -1, +486, 215, 327, 91, 177, 254, 177, 393, 512, 0, 231, 349, 231, 279, 486, 246, -1, +177, 512, 327, 231, 486, -1, +462, 462, 144, 76, 179, 464, 298, 464, 393, 128, 216, 113, 349, 500, 279, 101, 246, 7, 246, 395, 246, 384, 486, 215, -1, +7, 7, 195, 101, 444, 500, 462, 113, 76, 128, 464, -1, +254, 254, 285, 91, 149, 215, 83, 384, 325, 395, 520, 395, 315, 7, 143, 195, 129, 195, 461, 444, 475, 462, 144, -1, +520, 308, 325, 415, 83, 297, 149, 504, 285, 162, 278, 446, -1, +403, 403, 520, 276, 308, 404, 308, 272, 415, 416, 297, 317, 504, 125, 162, 60, 446, 110, 446, 393, 278, 254, 285, -1, +125, 125, 459, 317, 334, 416, 137, 272, 47, 404, 511, 404, 1, 276, 54, 403, 45, 370, 490, 210, 29, 184, -1, +336, 1, 251, 54, 164, 45, 463, 490, 378, 29, 453, 147, 222, 218, 301, 218, 242, 310, 130, 528, 34, -1, +26, 336, 148, 251, 269, 164, 419, 463, 293, 378, 420, 453, 333, 222, 208, 301, 294, 56, 127, 228, -1, +131, 26, 371, 148, 284, 269, 311, 419, 95, 293, 350, 420, 377, 333, 474, 208, 396, 294, 357, 127, -1, +116, 131, 273, 371, 480, 284, 104, 311, 257, 95, 348, 350, 447, 377, 313, 474, 322, 396, 28, 357, -1, +273, 273, 183, 480, 347, 104, 53, 257, 181, 348, 124, 447, 428, 313, 428, 435, 11, 270, 193, 305, 69, 305, 386, -1, +11, 11, 428, 409, 124, 382, 181, 161, 53, 481, 347, 408, 183, 319, 151, 422, 448, 4, 165, 134, 394, -1, +193, 193, 11, 495, 409, 44, 382, 385, 161, 478, 481, 320, 408, 37, 319, 524, 422, 328, 4, 465, 134, -1, +37, 37, 431, 320, 136, 478, 513, 385, 27, 44, 467, 495, 115, 193, 69, -1, +305, 305, 386, 20, 174, 182, 401, 211, 248, 106, 295, 309, 255, 465, 483, 328, 191, 524, 135, 37, 431, -1, +465, 465, 134, 309, 102, 106, 427, 211, 507, 182, 410, 20, 503, 305, 503, 270, 445, 435, 322, 313, -1, +134, 134, 394, 102, 455, 427, 5, 507, 23, 410, 405, 503, 405, 445, -1, +322, 322, 445, 28, 405, 138, 23, 485, 5, 234, 455, 74, 394, 180, 165, 49, 448, 116, 151, 273, 183, -1, +28, 357, 138, 268, 485, 287, 234, 81, 74, 78, 180, 103, 49, 220, 116, 220, 131, 476, 26, 38, 26, 336, -1, +357, 127, 268, 252, 287, 398, 81, 274, 78, 154, 103, 62, 220, 476, -1, +127, 228, 252, 141, 398, 440, 274, 363, 154, 190, 62, 488, 476, 38, -1, +301, 242, 56, 517, 228, 33, 141, 18, 440, 466, 363, 304, 190, 417, 488, 484, 38, 511, 336, 1, -1, +33, 517, 260, -1, +18, 33, 390, 260, 497, -1, +466, 18, 353, 390, 290, 497, 126, -1, +304, 466, 187, 353, 123, 290, 522, 126, 501, -1, +417, 304, 458, 187, 117, 123, 168, 522, 87, 501, 261, -1, +484, 417, 430, 458, 343, 117, 438, 168, 426, 87, 482, 261, 329, -1, +511, 484, 47, 430, 137, 343, 334, 438, 459, 426, 439, 482, 92, 329, 192, 329, 267, 329, 491, 261, 219, 501, -1, +528, 528, 34, 145, 46, 356, 105, 472, 219, 48, 491, 247, 267, 393, 192, 110, 92, 60, 439, 125, 459, -1, +219, 501, 105, 126, 46, 497, 34, 260, 130, 517, 242, -1, +29, 184, 147, 156, 218, 156, 310, 402, 528, 146, 145, 17, 356, 411, 472, 364, 48, 441, 247, 441, 393, 509, -1, +184, 184, 156, 63, 402, 354, 146, 335, 17, 239, 411, 13, 364, 509, 441, -1, +393, 509, 298, 13, 179, 239, 144, 335, 475, 354, 461, 63, 129, 184, 129, 210, 143, 370, 315, 403, 520, -1, +296, 296, 160, 133, 344, 330, -1, +344, 323, 160, -1, +159, 159, 296, 275, 133, 22, 330, 523, -1, +198, 523, 77, 22, 286, 275, 437, 159, 499, -1, +280, 323, 108, 344, 338, 330, 259, 523, 366, 198, 381, 240, 283, 10, 368, 243, 280, 243, 323, 35, 160, -1, +77, 471, 198, 471, 240, 250, 10, 303, 243, 303, 35, 230, 282, 362, 163, 73, 318, 292, 93, 477, 262, -1, +413, 413, 326, 399, 73, 399, 292, 100, 477, -1, +122, 355, 414, 61, 100, 55, 477, 508, 262, 365, -1, +35, 35, 160, 282, 296, 163, 159, 318, 499, 93, 505, 262, 340, 365, 340, 140, 68, 510, 518, 3, 122, 355, -1, +100, 399, 414, 413, 122, 111, 518, 213, 68, 167, 340, 167, 505, 245, 499, 245, 437, 346, 286, 79, 77, 471, -1, +362, 362, 221, 230, 516, 303, 516, 250, 207, 471, 207, 79, 521, 346, 468, 245, 468, 167, 468, 213, 473, 111, 204, 413, 326, -1, +468, 473, 521, 217, 207, 217, 516, 217, 221, 204, 221, 326, 362, 73, -1, +473, 204, 217, -1, +94, 94, 185, 529, 429, 209, 429, 176, -1, +379, 379, 94, 199, 529, 367, 209, 172, 209, 66, 176, 496, -1, +312, 312, 379, 238, 199, 15, 367, 332, 172, 197, 172, 451, 66, 84, 496, 186, -1, +266, 266, 312, 392, 238, 201, 15, 14, 332, 457, 197, 383, 197, 225, 451, 502, 84, 265, 186, 205, -1, +236, 236, 266, 214, 392, 71, 201, 188, 14, 173, 457, 400, 383, 380, 383, 342, 225, 109, 502, 175, 265, 97, 205, 118, -1, +152, 152, 236, 337, 214, 58, 71, 369, 188, 434, 173, 114, 400, 288, 380, 42, 380, 397, 342, 32, 109, 331, -1, +379, 170, 312, 331, 266, 32, 236, 397, 152, 42, 194, 42, 407, 288, 142, 114, 12, 434, 233, 369, 244, -1, +369, 369, 244, 58, 425, 337, 321, 152, 194, -1, +109, 331, 175, 170, 97, 300, 118, 421, 31, 89, -1, +31, 31, 118, 237, 205, 449, 186, 470, 496, 494, 176, 155, 429, 112, 185, 89, 185, 421, 94, 300, 379, 170, -1 +}; + +#else /* defined(_WIN32_WCE) */ + +/* + * Original teapot code copyright follows: + */ + +/* + * (c) Copyright 1993, Silicon Graphics, Inc. + * + * ALL RIGHTS RESERVED + * + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that + * both the copyright notice and this permission notice appear in + * supporting documentation, and that the name of Silicon + * Graphics, Inc. not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU + * "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR + * OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO + * EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE + * ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, + * INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, + * SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR + * NOT SILICON GRAPHICS, INC. HAS BEEN ADVISED OF THE POSSIBILITY + * OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer + * Software clause at DFARS 252.227-7013 and/or in similar or + * successor clauses in the FAR or the DOD or NASA FAR + * Supplement. Unpublished-- rights reserved under the copyright + * laws of the United States. Contractor/manufacturer is Silicon + * Graphics, Inc., 2011 N. Shoreline Blvd., Mountain View, CA + * 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ + +/* + * Rim, body, lid, and bottom data must be reflected in x and y; + * handle and spout data across the y axis only. + */ +static int patchdata[][16] = +{ + { 102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, /* rim */ + { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 }, /* body */ + { 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 }, + { 96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101, 101, 0, 1, 2, 3 }, /* lid */ + { 0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117 }, + { 118, 118, 118, 118, 124, 122, 119, 121, 123, 126, 125, 120, 40, 39, 38, 37 }, /* bottom */ + { 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56 }, /* handle */ + { 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 28, 65, 66, 67 }, + { 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83 }, /* spout */ + { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95 } +}; + +static double cpdata[][3] = +{ + {0.2, 0, 2.7}, {0.2, -0.112, 2.7}, {0.112, -0.2, 2.7}, {0, + -0.2, 2.7}, {1.3375, 0, 2.53125}, {1.3375, -0.749, 2.53125}, + {0.749, -1.3375, 2.53125}, {0, -1.3375, 2.53125}, {1.4375, + 0, 2.53125}, {1.4375, -0.805, 2.53125}, {0.805, -1.4375, + 2.53125}, {0, -1.4375, 2.53125}, {1.5, 0, 2.4}, {1.5, -0.84, + 2.4}, {0.84, -1.5, 2.4}, {0, -1.5, 2.4}, {1.75, 0, 1.875}, + {1.75, -0.98, 1.875}, {0.98, -1.75, 1.875}, {0, -1.75, + 1.875}, {2, 0, 1.35}, {2, -1.12, 1.35}, {1.12, -2, 1.35}, + {0, -2, 1.35}, {2, 0, 0.9}, {2, -1.12, 0.9}, {1.12, -2, + 0.9}, {0, -2, 0.9}, {-2, 0, 0.9}, {2, 0, 0.45}, {2, -1.12, + 0.45}, {1.12, -2, 0.45}, {0, -2, 0.45}, {1.5, 0, 0.225}, + {1.5, -0.84, 0.225}, {0.84, -1.5, 0.225}, {0, -1.5, 0.225}, + {1.5, 0, 0.15}, {1.5, -0.84, 0.15}, {0.84, -1.5, 0.15}, {0, + -1.5, 0.15}, {-1.6, 0, 2.025}, {-1.6, -0.3, 2.025}, {-1.5, + -0.3, 2.25}, {-1.5, 0, 2.25}, {-2.3, 0, 2.025}, {-2.3, -0.3, + 2.025}, {-2.5, -0.3, 2.25}, {-2.5, 0, 2.25}, {-2.7, 0, + 2.025}, {-2.7, -0.3, 2.025}, {-3, -0.3, 2.25}, {-3, 0, + 2.25}, {-2.7, 0, 1.8}, {-2.7, -0.3, 1.8}, {-3, -0.3, 1.8}, + {-3, 0, 1.8}, {-2.7, 0, 1.575}, {-2.7, -0.3, 1.575}, {-3, + -0.3, 1.35}, {-3, 0, 1.35}, {-2.5, 0, 1.125}, {-2.5, -0.3, + 1.125}, {-2.65, -0.3, 0.9375}, {-2.65, 0, 0.9375}, {-2, + -0.3, 0.9}, {-1.9, -0.3, 0.6}, {-1.9, 0, 0.6}, {1.7, 0, + 1.425}, {1.7, -0.66, 1.425}, {1.7, -0.66, 0.6}, {1.7, 0, + 0.6}, {2.6, 0, 1.425}, {2.6, -0.66, 1.425}, {3.1, -0.66, + 0.825}, {3.1, 0, 0.825}, {2.3, 0, 2.1}, {2.3, -0.25, 2.1}, + {2.4, -0.25, 2.025}, {2.4, 0, 2.025}, {2.7, 0, 2.4}, {2.7, + -0.25, 2.4}, {3.3, -0.25, 2.4}, {3.3, 0, 2.4}, {2.8, 0, + 2.475}, {2.8, -0.25, 2.475}, {3.525, -0.25, 2.49375}, + {3.525, 0, 2.49375}, {2.9, 0, 2.475}, {2.9, -0.15, 2.475}, + {3.45, -0.15, 2.5125}, {3.45, 0, 2.5125}, {2.8, 0, 2.4}, + {2.8, -0.15, 2.4}, {3.2, -0.15, 2.4}, {3.2, 0, 2.4}, {0, 0, + 3.15}, {0.8, 0, 3.15}, {0.8, -0.45, 3.15}, {0.45, -0.8, + 3.15}, {0, -0.8, 3.15}, {0, 0, 2.85}, {1.4, 0, 2.4}, {1.4, + -0.784, 2.4}, {0.784, -1.4, 2.4}, {0, -1.4, 2.4}, {0.4, 0, + 2.55}, {0.4, -0.224, 2.55}, {0.224, -0.4, 2.55}, {0, -0.4, + 2.55}, {1.3, 0, 2.55}, {1.3, -0.728, 2.55}, {0.728, -1.3, + 2.55}, {0, -1.3, 2.55}, {1.3, 0, 2.4}, {1.3, -0.728, 2.4}, + {0.728, -1.3, 2.4}, {0, -1.3, 2.4}, {0, 0, 0}, {1.425, + -0.798, 0}, {1.5, 0, 0.075}, {1.425, 0, 0}, {0.798, -1.425, + 0}, {0, -1.5, 0.075}, {0, -1.425, 0}, {1.5, -0.84, 0.075}, + {0.84, -1.5, 0.075} +}; + +static double tex[2][2][2] = +{ + { {0.0, 0.0}, {1.0, 0.0} }, + { {0.0, 1.0}, {1.0, 1.0} } +}; +#endif /* defined(_WIN32_WCE) */ + + +#endif /* FREEGLUT_TEAPOT_DATA_H */ + diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_videoresize.c b/tests/Box2D_v2.2.1/freeglut/freeglut_videoresize.c new file mode 100755 index 0000000000000..2b27ddeb092e4 --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_videoresize.c @@ -0,0 +1,50 @@ +/* + * freeglut_videoresize.c + * + * Video resize functions (as defined by GLUT API) + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 16 1999 + * + * 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 + * PAWEL W. OLSZTA 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 "freeglut.h" +#include "freeglut_internal.h" + +/* + * NOTE: functions declared in this file probably will not be implemented. + */ + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +int FGAPIENTRY glutVideoResizeGet( GLenum eWhat ) { return( 0x00 ); } +void FGAPIENTRY glutSetupVideoResizing( void ) { /* Not implemented */ } +void FGAPIENTRY glutStopVideoResizing( void ) { /* Not implemented */ } +void FGAPIENTRY glutVideoResize( int x, int y, int w, int h ) { /* Not implemented */ } +void FGAPIENTRY glutVideoPan( int x, int y, int w, int h ) { /* Not implemented */ } + +/*** END OF FILE ***/ + + + + + + + diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_window.c b/tests/Box2D_v2.2.1/freeglut/freeglut_window.c new file mode 100755 index 0000000000000..176487e72edac --- /dev/null +++ b/tests/Box2D_v2.2.1/freeglut/freeglut_window.c @@ -0,0 +1,1743 @@ +/* + * freeglut_window.c + * + * Window management methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Fri Dec 3 1999 + * + * 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 + * PAWEL W. OLSZTA 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. + */ + +#define FREEGLUT_BUILDING_LIB +#include "freeglut.h" +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 +#include /* LONG_MAX */ +#endif + +#if defined(_WIN32_WCE) +# include +# ifdef FREEGLUT_LIB_PRAGMAS +# pragma comment( lib, "Aygshell.lib" ) +# endif + +static wchar_t* fghWstrFromStr(const char* str) +{ + int i,len=strlen(str); + wchar_t* wstr = (wchar_t*)malloc(2*len+2); + for(i=0; i 0 ) { + ATTRIB_VAL( GLX_AUX_BUFFERS, numAuxBuffers ); + } + + if( fgState.DisplayMode & GLUT_SRGB ) { + ATTRIB_VAL( GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, True ); + } + + if (fgState.DisplayMode & GLUT_MULTISAMPLE) { + ATTRIB_VAL(GLX_SAMPLE_BUFFERS, 1); + ATTRIB_VAL(GLX_SAMPLES, fgState.SampleNumber); + } + + /* Push a terminator at the end of the list */ + ATTRIB( None ); + + { + GLXFBConfig * fbconfigArray; /* Array of FBConfigs */ + GLXFBConfig * fbconfig; /* The FBConfig we want */ + int fbconfigArraySize; /* Number of FBConfigs in the array */ + + + /* Get all FBConfigs that match "attributes". */ + fbconfigArray = glXChooseFBConfig( fgDisplay.Display, + fgDisplay.Screen, + attributes, + &fbconfigArraySize ); + + if (fbconfigArray != NULL) + { + int result; /* Returned by glXGetFBConfigAttrib, not checked. */ + + + if( wantIndexedMode ) + { + /* + * In index mode, we want the largest buffer size, i.e. visual + * depth. Here, FBConfigs are sorted by increasing buffer size + * first, so FBConfigs with the largest size come last. + */ + + int bufferSizeMin, bufferSizeMax; + + /* Get bufferSizeMin. */ + result = + glXGetFBConfigAttrib( fgDisplay.Display, + fbconfigArray[0], + GLX_BUFFER_SIZE, + &bufferSizeMin ); + /* Get bufferSizeMax. */ + result = + glXGetFBConfigAttrib( fgDisplay.Display, + fbconfigArray[fbconfigArraySize - 1], + GLX_BUFFER_SIZE, + &bufferSizeMax ); + + if (bufferSizeMax > bufferSizeMin) + { + /* + * Free and reallocate fbconfigArray, keeping only FBConfigs + * with the largest buffer size. + */ + XFree(fbconfigArray); + + /* Add buffer size token at the end of the list. */ + where--; + ATTRIB_VAL( GLX_BUFFER_SIZE, bufferSizeMax ); + ATTRIB( None ); + + fbconfigArray = glXChooseFBConfig( fgDisplay.Display, + fgDisplay.Screen, + attributes, + &fbconfigArraySize ); + } + } + + /* + * We now have an array of FBConfigs, the first one being the "best" + * one. So we should return only this FBConfig: + * + * int fbconfigXID; + * + * - pick the XID of the FBConfig we want + * result = glXGetFBConfigAttrib( fgDisplay.Display, + * fbconfigArray[0], + * GLX_FBCONFIG_ID, + * &fbconfigXID ); + * + * - free the array + * XFree(fbconfigArray); + * + * - reset "attributes" with the XID + * where = 0; + * ATTRIB_VAL( GLX_FBCONFIG_ID, fbconfigXID ); + * ATTRIB( None ); + * + * - get our FBConfig only + * fbconfig = glXChooseFBConfig( fgDisplay.Display, + * fgDisplay.Screen, + * attributes, + * &fbconfigArraySize ); + * + * However, for some configurations (for instance multisampling with + * Mesa 6.5.2 and ATI drivers), this does not work: + * glXChooseFBConfig returns NULL, whereas fbconfigXID is a valid + * XID. Further investigation is needed. + * + * So, for now, we return the whole array of FBConfigs. This should + * not produce any side effects elsewhere. + */ + fbconfig = fbconfigArray; + } + else + { + fbconfig = NULL; + } + + return fbconfig; + } +} +#endif /* TARGET_HOST_POSIX_X11 */ + +/* + * Setup the pixel format for a Win32 window + */ +#if TARGET_HOST_MS_WINDOWS +/* The following include file is available from SGI but is not standard: + * #include + * So we copy the necessary parts out of it. + * XXX: should local definitions for extensions be put in a separate include file? + */ +typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); + +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); + +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_FULL_ACCELERATION_ARB 0x2027 + +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 + +#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 + +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 + +#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); + +#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 WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 + +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 + +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#endif + +static void fghFillContextAttributes( int *attributes ) { + int where = 0, contextFlags, contextProfile; + + if ( !fghIsLegacyContextVersionRequested() ) { + ATTRIB_VAL( WGL_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion ); + ATTRIB_VAL( WGL_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion ); + } + + contextFlags = + fghMapBit( fgState.ContextFlags, GLUT_DEBUG, WGL_CONTEXT_DEBUG_BIT_ARB ) | + fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB ); + if ( contextFlags != 0 ) { + ATTRIB_VAL( WGL_CONTEXT_FLAGS_ARB, contextFlags ); + } + + contextProfile = + fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, WGL_CONTEXT_CORE_PROFILE_BIT_ARB ) | + fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ); + if ( contextProfile != 0 ) { + ATTRIB_VAL( WGL_CONTEXT_PROFILE_MASK_ARB, contextProfile ); + } + + ATTRIB( 0 ); +} + +static int fghIsExtensionSupported( HDC hdc, const char *extension ) { + const char *pWglExtString; + PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetEntensionsStringARB = + (PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetProcAddress("wglGetExtensionsStringARB"); + if ( wglGetEntensionsStringARB == NULL ) + { + return FALSE; + } + pWglExtString = wglGetEntensionsStringARB( hdc ); + return ( pWglExtString != NULL ) && ( strstr(pWglExtString, extension) != NULL ); +} + +void fgNewWGLCreateContext( SFG_Window* window ) +{ + HGLRC context; + int attributes[9]; + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; + + /* If nothing fancy has been required, leave the context as it is */ + if ( fghIsLegacyContextRequested() ) + { + return; + } + + wglMakeCurrent( window->Window.Device, window->Window.Context ); + + if ( !fghIsExtensionSupported( window->Window.Device, "WGL_ARB_create_context" ) ) + { + return; + } + + /* new context creation */ + fghFillContextAttributes( attributes ); + + wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress( "wglCreateContextAttribsARB" ); + if ( wglCreateContextAttribsARB == NULL ) + { + fgError( "wglCreateContextAttribsARB not found" ); + } + + context = wglCreateContextAttribsARB( window->Window.Device, 0, attributes ); + if ( context == NULL ) + { + fghContextCreationError(); + } + + wglMakeCurrent( NULL, NULL ); + wglDeleteContext( window->Window.Context ); + window->Window.Context = context; +} + +#if !defined(_WIN32_WCE) + +static void fghFillPFD( PIXELFORMATDESCRIPTOR *ppfd, HDC hdc, unsigned char layer_type ) +{ + int flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; + if ( fgState.DisplayMode & GLUT_DOUBLE ) { + flags |= PFD_DOUBLEBUFFER; + } + if ( fgState.DisplayMode & GLUT_STEREO ) { + flags |= PFD_STEREO; + } + +//#if defined(_MSC_VER) +//#pragma message( "fgSetupPixelFormat(): there is still some work to do here!" ) +//#endif + + /* Specify which pixel format do we opt for... */ + ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR); + ppfd->nVersion = 1; + ppfd->dwFlags = flags; + + if( fgState.DisplayMode & GLUT_INDEX ) { + ppfd->iPixelType = PFD_TYPE_COLORINDEX; + ppfd->cRedBits = 0; + ppfd->cGreenBits = 0; + ppfd->cBlueBits = 0; + ppfd->cAlphaBits = 0; + } else { + ppfd->iPixelType = PFD_TYPE_RGBA; + ppfd->cRedBits = 8; + ppfd->cGreenBits = 8; + ppfd->cBlueBits = 8; + ppfd->cAlphaBits = ( fgState.DisplayMode & GLUT_ALPHA ) ? 8 : 0; + } + + ppfd->cColorBits = 24; + ppfd->cRedShift = 0; + ppfd->cGreenShift = 0; + ppfd->cBlueShift = 0; + ppfd->cAlphaShift = 0; + ppfd->cAccumBits = 0; + ppfd->cAccumRedBits = 0; + ppfd->cAccumGreenBits = 0; + ppfd->cAccumBlueBits = 0; + ppfd->cAccumAlphaBits = 0; + + /* Hmmm, or 32/0 instead of 24/8? */ + ppfd->cDepthBits = 24; + ppfd->cStencilBits = 8; + + ppfd->cAuxBuffers = fghNumberOfAuxBuffersRequested(); + ppfd->iLayerType = layer_type; + ppfd->bReserved = 0; + ppfd->dwLayerMask = 0; + ppfd->dwVisibleMask = 0; + ppfd->dwDamageMask = 0; + + ppfd->cColorBits = (BYTE) GetDeviceCaps( hdc, BITSPIXEL ); +} + +static void fghFillPixelFormatAttributes( int *attributes, const PIXELFORMATDESCRIPTOR *ppfd ) +{ + int where = 0; + + ATTRIB_VAL( WGL_DRAW_TO_WINDOW_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_SUPPORT_OPENGL_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB ); + + ATTRIB_VAL( WGL_COLOR_BITS_ARB, ppfd->cColorBits ); + ATTRIB_VAL( WGL_ALPHA_BITS_ARB, ppfd->cAlphaBits ); + ATTRIB_VAL( WGL_DEPTH_BITS_ARB, ppfd->cDepthBits ); + ATTRIB_VAL( WGL_STENCIL_BITS_ARB, ppfd->cStencilBits ); + + ATTRIB_VAL( WGL_DOUBLE_BUFFER_ARB, ( fgState.DisplayMode & GLUT_DOUBLE ) != 0 ); + + if ( fgState.DisplayMode & GLUT_SRGB ) { + ATTRIB_VAL( WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, TRUE ); + } + + ATTRIB_VAL( WGL_SAMPLE_BUFFERS_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_SAMPLES_ARB, fgState.SampleNumber ); + ATTRIB( 0 ); +} +#endif + +GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, + unsigned char layer_type ) +{ +#if defined(_WIN32_WCE) + return GL_TRUE; +#else + PIXELFORMATDESCRIPTOR pfd; + PIXELFORMATDESCRIPTOR* ppfd = &pfd; + int pixelformat; + + fghFillPFD( ppfd, window->Window.Device, layer_type ); + pixelformat = ChoosePixelFormat( window->Window.Device, ppfd ); + + /* windows hack for multismapling/sRGB */ + if ( ( fgState.DisplayMode & GLUT_MULTISAMPLE ) || + ( fgState.DisplayMode & GLUT_SRGB ) ) + { + HGLRC rc, rc_before=wglGetCurrentContext(); + HWND hWnd; + HDC hDC, hDC_before=wglGetCurrentDC(); + WNDCLASS wndCls; + + /* create a dummy window */ + ZeroMemory(&wndCls, sizeof(wndCls)); + wndCls.lpfnWndProc = DefWindowProc; + wndCls.hInstance = fgDisplay.Instance; + wndCls.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + wndCls.lpszClassName = _T("FREEGLUT_dummy"); + RegisterClass( &wndCls ); + + hWnd=CreateWindow(_T("FREEGLUT_dummy"), _T(""), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW , 0,0,0,0, 0, 0, fgDisplay.Instance, 0 ); + hDC=GetDC(hWnd); + SetPixelFormat( hDC, pixelformat, ppfd ); + + rc = wglCreateContext( hDC ); + wglMakeCurrent(hDC, rc); + + if ( fghIsExtensionSupported( hDC, "WGL_ARB_multisample" ) ) + { + PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARBProc = + (PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB"); + if ( wglChoosePixelFormatARBProc ) + { + int attributes[100]; + int iPixelFormat; + BOOL bValid; + float fAttributes[] = { 0, 0 }; + UINT numFormats; + fghFillPixelFormatAttributes( attributes, ppfd ); + bValid = wglChoosePixelFormatARBProc(window->Window.Device, attributes, fAttributes, 1, &iPixelFormat, &numFormats); + + if ( bValid && numFormats > 0 ) + { + pixelformat = iPixelFormat; + } + } + } + + wglMakeCurrent( hDC_before, rc_before); + wglDeleteContext(rc); + ReleaseDC(hWnd, hDC); + DestroyWindow(hWnd); + UnregisterClass(_T("FREEGLUT_dummy"), fgDisplay.Instance); + } + + return ( pixelformat != 0 ) && ( checkOnly || SetPixelFormat( window->Window.Device, pixelformat, ppfd ) ); +#endif /* defined(_WIN32_WCE) */ +} +#endif /* TARGET_HOST_MS_WINDOWS */ + +/* + * Sets the OpenGL context and the fgStructure "Current Window" pointer to + * the window structure passed in. + */ +void fgSetWindow ( SFG_Window *window ) +{ +#if TARGET_HOST_POSIX_X11 + if ( window ) + { + glXMakeContextCurrent( + fgDisplay.Display, + window->Window.Handle, + window->Window.Handle, + window->Window.Context + ); + + /* also register this window to receive spaceball events */ + fgSpaceballSetWindow(window); + } +#elif TARGET_HOST_MS_WINDOWS + if( fgStructure.CurrentWindow ) + ReleaseDC( fgStructure.CurrentWindow->Window.Handle, + fgStructure.CurrentWindow->Window.Device ); + + if ( window ) + { + window->Window.Device = GetDC( window->Window.Handle ); + wglMakeCurrent( + window->Window.Device, + window->Window.Context + ); + } +#endif + fgStructure.CurrentWindow = window; +} + + + +#if TARGET_HOST_POSIX_X11 + +#ifndef GLX_CONTEXT_MAJOR_VERSION_ARB +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#endif + +#ifndef GLX_CONTEXT_MINOR_VERSION_ARB +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#endif + +#ifndef GLX_CONTEXT_FLAGS_ARB +#define GLX_CONTEXT_FLAGS_ARB 0x2094 +#endif + +#ifndef GLX_CONTEXT_PROFILE_MASK_ARB +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#endif + +#ifndef GLX_CONTEXT_DEBUG_BIT_ARB +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 +#endif + +#ifndef GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#endif + +#ifndef GLX_CONTEXT_CORE_PROFILE_BIT_ARB +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#endif + +#ifndef GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#endif + +#ifndef GLX_RGBA_FLOAT_TYPE +#define GLX_RGBA_FLOAT_TYPE 0x20B9 +#endif + +#ifndef GLX_RGBA_FLOAT_BIT +#define GLX_RGBA_FLOAT_BIT 0x00000004 +#endif + +static void fghFillContextAttributes( int *attributes ) { + int where = 0, contextFlags, contextProfile; + + if ( !fghIsLegacyContextVersionRequested() ) { + ATTRIB_VAL( GLX_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion ); + ATTRIB_VAL( GLX_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion ); + } + + contextFlags = + fghMapBit( fgState.ContextFlags, GLUT_DEBUG, GLX_CONTEXT_DEBUG_BIT_ARB ) | + fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB ); + if ( contextFlags != 0 ) { + ATTRIB_VAL( GLX_CONTEXT_FLAGS_ARB, contextFlags ); + } + + contextProfile = + fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB ) | + fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ); + if ( contextProfile != 0 ) { + ATTRIB_VAL( GLX_CONTEXT_PROFILE_MASK_ARB, contextProfile ); + } + + ATTRIB( 0 ); +} + +typedef GLXContext (*CreateContextAttribsProc)(Display *dpy, GLXFBConfig config, + GLXContext share_list, Bool direct, + const int *attrib_list); + +static GLXContext fghCreateNewContext( SFG_Window* window ) +{ + /* for color model calculation */ + int menu = ( window->IsMenu && !fgStructure.MenuContext ); + int index_mode = ( fgState.DisplayMode & GLUT_INDEX ); + + /* "classic" context creation */ + Display *dpy = fgDisplay.Display; + GLXFBConfig config = *(window->Window.FBConfig); + int render_type = ( !menu && index_mode ) ? GLX_COLOR_INDEX_TYPE : GLX_RGBA_TYPE; + GLXContext share_list = NULL; + Bool direct = ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT ); + GLXContext context; + + /* new context creation */ + int attributes[9]; + CreateContextAttribsProc createContextAttribs; + + /* If nothing fancy has been required, simply use the old context creation GLX API entry */ + if ( fghIsLegacyContextRequested() ) + { + context = glXCreateNewContext( dpy, config, render_type, share_list, direct ); + if ( context == NULL ) { + fghContextCreationError(); + } + return context; + } + + /* color index mode is not available anymore with OpenGL 3.0 */ + if ( render_type == GLX_COLOR_INDEX_TYPE ) { + fgWarning( "color index mode is deprecated, using RGBA mode" ); + } + + fghFillContextAttributes( attributes ); + + createContextAttribs = (CreateContextAttribsProc) fghGetProcAddress( "glXCreateContextAttribsARB" ); + if ( createContextAttribs == NULL ) { + fgError( "glXCreateContextAttribsARB not found" ); + } + + context = createContextAttribs( dpy, config, share_list, direct, attributes ); + if ( context == NULL ) { + fghContextCreationError(); + } + return context; +} +#endif + + +/* + * Opens a window. Requires a SFG_Window object created and attached + * to the freeglut structure. OpenGL context is created here. + */ +void fgOpenWindow( SFG_Window* window, const char* title, + GLboolean positionUse, int x, int y, + GLboolean sizeUse, int w, int h, + GLboolean gameMode, GLboolean isSubWindow ) +{ +#if TARGET_HOST_POSIX_X11 + XVisualInfo * visualInfo; + XSetWindowAttributes winAttr; + XTextProperty textProperty; + XSizeHints sizeHints; + XWMHints wmHints; + unsigned long mask; + unsigned int current_DisplayMode = fgState.DisplayMode ; + + /* Save the display mode if we are creating a menu window */ + if( window->IsMenu && ( ! fgStructure.MenuContext ) ) + fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ; + + window->Window.FBConfig = fgChooseFBConfig( ); + + if( window->IsMenu && ( ! fgStructure.MenuContext ) ) + fgState.DisplayMode = current_DisplayMode ; + + if( ! window->Window.FBConfig ) + { + /* + * The "fgChooseFBConfig" returned a null meaning that the visual + * context is not available. + * Try a couple of variations to see if they will work. + */ + if( !( fgState.DisplayMode & GLUT_DOUBLE ) ) + { + fgState.DisplayMode |= GLUT_DOUBLE ; + window->Window.FBConfig = fgChooseFBConfig( ); + fgState.DisplayMode &= ~GLUT_DOUBLE; + } + + if( fgState.DisplayMode & GLUT_MULTISAMPLE ) + { + fgState.DisplayMode &= ~GLUT_MULTISAMPLE ; + window->Window.FBConfig = fgChooseFBConfig( ); + fgState.DisplayMode |= GLUT_MULTISAMPLE; + } + } + + FREEGLUT_INTERNAL_ERROR_EXIT( window->Window.FBConfig != NULL, + "FBConfig with necessary capabilities not found", "fgOpenWindow" ); + + /* Get the X visual. */ + visualInfo = glXGetVisualFromFBConfig( fgDisplay.Display, + *(window->Window.FBConfig) ); + + /* + * XXX HINT: the masks should be updated when adding/removing callbacks. + * XXX This might speed up message processing. Is that true? + * XXX + * XXX A: Not appreciably, but it WILL make it easier to debug. + * XXX Try tracing old GLUT and try tracing freeglut. Old GLUT + * XXX turns off events that it doesn't need and is a whole lot + * XXX more pleasant to trace. (Think mouse-motion! Tons of + * XXX ``bonus'' GUI events stream in.) + */ + winAttr.event_mask = + StructureNotifyMask | SubstructureNotifyMask | ExposureMask | + ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | + VisibilityChangeMask | EnterWindowMask | LeaveWindowMask | + PointerMotionMask | ButtonMotionMask; + winAttr.background_pixmap = None; + winAttr.background_pixel = 0; + winAttr.border_pixel = 0; + + winAttr.colormap = XCreateColormap( + fgDisplay.Display, fgDisplay.RootWindow, + visualInfo->visual, AllocNone + ); + + mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask; + + if( window->IsMenu || ( gameMode == GL_TRUE ) ) + { + winAttr.override_redirect = True; + mask |= CWOverrideRedirect; + } + + if( ! positionUse ) + x = y = -1; /* default window position */ + if( ! sizeUse ) + w = h = 300; /* default window size */ + + window->Window.Handle = XCreateWindow( + fgDisplay.Display, + window->Parent == NULL ? fgDisplay.RootWindow : + window->Parent->Window.Handle, + x, y, w, h, 0, + visualInfo->depth, InputOutput, + visualInfo->visual, mask, + &winAttr + ); + + /* + * The GLX context creation, possibly trying the direct context rendering + * or else use the current context if the user has so specified + */ + + if( window->IsMenu ) + { + /* + * If there isn't already an OpenGL rendering context for menu + * windows, make one + */ + if( !fgStructure.MenuContext ) + { + fgStructure.MenuContext = + (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) ); + fgStructure.MenuContext->MContext = fghCreateNewContext( window ); + } + + /* window->Window.Context = fgStructure.MenuContext->MContext; */ + window->Window.Context = fghCreateNewContext( window ); + } + else if( fgState.UseCurrentContext ) + { + window->Window.Context = glXGetCurrentContext( ); + + if( ! window->Window.Context ) + window->Window.Context = fghCreateNewContext( window ); + } + else + window->Window.Context = fghCreateNewContext( window ); + +#if !defined( __FreeBSD__ ) && !defined( __NetBSD__ ) + if( !glXIsDirect( fgDisplay.Display, window->Window.Context ) ) + { + if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT ) + fgError( "Unable to force direct context rendering for window '%s'", + title ); + } +#endif + + /* + * XXX Assume the new window is visible by default + * XXX Is this a safe assumption? + */ + window->State.Visible = GL_TRUE; + + sizeHints.flags = 0; + if ( positionUse ) + sizeHints.flags |= USPosition; + if ( sizeUse ) + sizeHints.flags |= USSize; + + /* + * Fill in the size hints values now (the x, y, width and height + * settings are obsolete, are there any more WMs that support them?) + * Unless the X servers actually stop supporting these, we should + * continue to fill them in. It is *not* our place to tell the user + * that they should replace a window manager that they like, and which + * works, just because *we* think that it's not "modern" enough. + */ + sizeHints.x = x; + sizeHints.y = y; + sizeHints.width = w; + sizeHints.height = h; + + wmHints.flags = StateHint; + wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState; + /* Prepare the window and iconified window names... */ + XStringListToTextProperty( (char **) &title, 1, &textProperty ); + + XSetWMProperties( + fgDisplay.Display, + window->Window.Handle, + &textProperty, + &textProperty, + 0, + 0, + &sizeHints, + &wmHints, + NULL + ); + XFree( textProperty.value ); + + XSetWMProtocols( fgDisplay.Display, window->Window.Handle, + &fgDisplay.DeleteWindow, 1 ); + + glXMakeContextCurrent( + fgDisplay.Display, + window->Window.Handle, + window->Window.Handle, + window->Window.Context + ); + + XMapWindow( fgDisplay.Display, window->Window.Handle ); + + XFree(visualInfo); + +#elif TARGET_HOST_MS_WINDOWS + + WNDCLASS wc; + DWORD flags; + DWORD exFlags = 0; + ATOM atom; + int WindowStyle = 0; + + /* Grab the window class we have registered on glutInit(): */ + atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc ); + FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found", + "fgOpenWindow" ); + + if( gameMode ) + { + FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL, + "Game mode being invoked on a subwindow", + "fgOpenWindow" ); + + /* + * Set the window creation flags appropriately to make the window + * entirely visible: + */ + flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; + } + else + { + int worig = w, horig = h; + +#if !defined(_WIN32_WCE) + if ( ( ! isSubWindow ) && ( ! window->IsMenu ) ) + { + /* + * Update the window dimensions, taking account of window + * decorations. "freeglut" is to create the window with the + * outside of its border at (x,y) and with dimensions (w,h). + */ + w += (GetSystemMetrics( SM_CXSIZEFRAME ) )*2; + h += (GetSystemMetrics( SM_CYSIZEFRAME ) )*2 + + GetSystemMetrics( SM_CYCAPTION ); + } +#endif /* defined(_WIN32_WCE) */ + + if( ! positionUse ) + { + x = CW_USEDEFAULT; + y = CW_USEDEFAULT; + } + /* setting State.Width/Height to call resize callback later */ + if( ! sizeUse ) + { + if( ! window->IsMenu ) + { + w = CW_USEDEFAULT; + h = CW_USEDEFAULT; + } + else /* fail safe - Windows can make a window of size (0, 0) */ + w = h = 300; /* default window size */ + window->State.Width = window->State.Height = -1; + } + else + { + window->State.Width = worig; + window->State.Height = horig; + } + + /* + * There's a small difference between creating the top, child and + * game mode windows + */ + flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; + + if ( window->IsMenu ) + { + flags |= WS_POPUP; + exFlags |= WS_EX_TOOLWINDOW; + } +#if !defined(_WIN32_WCE) + else if( window->Parent == NULL ) + flags |= WS_OVERLAPPEDWINDOW; +#endif + else + flags |= WS_CHILD; + } + +#if defined(_WIN32_WCE) + { + wchar_t* wstr = fghWstrFromStr(title); + + window->Window.Handle = CreateWindow( + _T("FREEGLUT"), + wstr, + WS_VISIBLE | WS_POPUP, + 0,0, 240,320, + NULL, + NULL, + fgDisplay.Instance, + (LPVOID) window + ); + + free(wstr); + + SHFullScreen(window->Window.Handle, SHFS_HIDESTARTICON); + SHFullScreen(window->Window.Handle, SHFS_HIDESIPBUTTON); + SHFullScreen(window->Window.Handle, SHFS_HIDETASKBAR); + MoveWindow(window->Window.Handle, 0, 0, 240, 320, TRUE); + ShowWindow(window->Window.Handle, SW_SHOW); + UpdateWindow(window->Window.Handle); + } +#else + window->Window.Handle = CreateWindowEx( + exFlags, + _T("FREEGLUT"), + title, + flags, + x, y, w, h, + (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle, + (HMENU) NULL, + fgDisplay.Instance, + (LPVOID) window + ); +#endif /* defined(_WIN32_WCE) */ + + if( !( window->Window.Handle ) ) + fgError( "Failed to create a window (%s)!", title ); + + /* Make a menu window always on top - fix Feature Request 947118 */ + if( window->IsMenu || gameMode ) + SetWindowPos( + window->Window.Handle, + HWND_TOPMOST, + 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE + ); + + /* Hack to remove the caption (title bar) and/or border + * and all the system menu controls. + */ + WindowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE); + if ( fgState.DisplayMode & GLUT_CAPTIONLESS ) + { + SetWindowLong ( window->Window.Handle, GWL_STYLE, + WindowStyle & ~(WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)); + } + else if ( fgState.DisplayMode & GLUT_BORDERLESS ) + { + SetWindowLong ( window->Window.Handle, GWL_STYLE, + WindowStyle & ~(WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)); + } +/* SetWindowPos(window->Window.Handle, NULL, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); */ + + +#if defined(_WIN32_WCE) + ShowWindow( window->Window.Handle, SW_SHOW ); +#else + ShowWindow( window->Window.Handle, + fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW ); +#endif /* defined(_WIN32_WCE) */ + + UpdateWindow( window->Window.Handle ); + ShowCursor( TRUE ); /* XXX Old comments say "hide cursor"! */ + +#endif + + fgSetWindow( window ); + + window->Window.DoubleBuffered = + ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0; + + if ( ! window->Window.DoubleBuffered ) + { + glDrawBuffer ( GL_FRONT ); + glReadBuffer ( GL_FRONT ); + } +} + +/* + * Closes a window, destroying the frame and OpenGL context + */ +void fgCloseWindow( SFG_Window* window ) +{ +#if TARGET_HOST_POSIX_X11 + + if( window->Window.Context ) + glXDestroyContext( fgDisplay.Display, window->Window.Context ); + XFree( window->Window.FBConfig ); + XDestroyWindow( fgDisplay.Display, window->Window.Handle ); + /* XFlush( fgDisplay.Display ); */ /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + /* Make sure we don't close a window with current context active */ + if( fgStructure.CurrentWindow == window ) + wglMakeCurrent( NULL, NULL ); + + /* + * Step through the list of windows. If the rendering context + * is not being used by another window, then we delete it. + */ + { + int used = FALSE ; + SFG_Window *iter ; + + for( iter = (SFG_Window *)fgStructure.Windows.First; + iter; + iter = (SFG_Window *)iter->Node.Next ) + { + if( ( iter->Window.Context == window->Window.Context ) && + ( iter != window ) ) + used = TRUE; + } + + if( ! used ) + wglDeleteContext( window->Window.Context ); + } + + DestroyWindow( window->Window.Handle ); +#endif +} + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Creates a new top-level freeglut window + */ +int FGAPIENTRY glutCreateWindow( const char* title ) +{ + /* XXX GLUT does not exit; it simply calls "glutInit" quietly if the + * XXX application has not already done so. The "freeglut" community + * XXX decided not to go this route (freeglut-developer e-mail from + * XXX Steve Baker, 12/16/04, 4:22 PM CST, "Re: [Freeglut-developer] + * XXX Desired 'freeglut' behaviour when there is no current window" + */ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateWindow" ); + + return fgCreateWindow( NULL, title, fgState.Position.Use, + fgState.Position.X, fgState.Position.Y, + fgState.Size.Use, fgState.Size.X, fgState.Size.Y, + GL_FALSE, GL_FALSE )->ID; +} + +#if TARGET_HOST_MS_WINDOWS +int FGAPIENTRY __glutCreateWindowWithExit( const char *title, void (__cdecl *exit_function)(int) ) +{ + __glutExitFunc = exit_function; + return glutCreateWindow( title ); +} +#endif + +/* + * This function creates a sub window. + */ +int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h ) +{ + int ret = 0; + SFG_Window* window = NULL; + SFG_Window* parent = NULL; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateSubWindow" ); + parent = fgWindowByID( parentID ); + freeglut_return_val_if_fail( parent != NULL, 0 ); + if ( x < 0 ) + { + x = parent->State.Width + x ; + if ( w >= 0 ) x -= w ; + } + + if ( w < 0 ) w = parent->State.Width - x + w ; + if ( w < 0 ) + { + x += w ; + w = -w ; + } + + if ( y < 0 ) + { + y = parent->State.Height + y ; + if ( h >= 0 ) y -= h ; + } + + if ( h < 0 ) h = parent->State.Height - y + h ; + if ( h < 0 ) + { + y += h ; + h = -h ; + } + + window = fgCreateWindow( parent, "", GL_TRUE, x, y, GL_TRUE, w, h, GL_FALSE, GL_FALSE ); + ret = window->ID; + + return ret; +} + +/* + * Destroys a window and all of its subwindows + */ +void FGAPIENTRY glutDestroyWindow( int windowID ) +{ + SFG_Window* window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" ); + window = fgWindowByID( windowID ); + freeglut_return_if_fail( window != NULL ); + { + fgExecutionState ExecState = fgState.ExecState; + fgAddToWindowDestroyList( window ); + fgState.ExecState = ExecState; + } +} + +/* + * This function selects the current window + */ +void FGAPIENTRY glutSetWindow( int ID ) +{ + SFG_Window* window = NULL; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" ); + if( fgStructure.CurrentWindow != NULL ) + if( fgStructure.CurrentWindow->ID == ID ) + return; + + window = fgWindowByID( ID ); + if( window == NULL ) + { + fgWarning( "glutSetWindow(): window ID %d not found!", ID ); + return; + } + + fgSetWindow( window ); +} + +/* + * This function returns the ID number of the current window, 0 if none exists + */ +int FGAPIENTRY glutGetWindow( void ) +{ + SFG_Window *win = fgStructure.CurrentWindow; + /* + * Since GLUT did not throw an error if this function was called without a prior call to + * "glutInit", this function shouldn't do so here. Instead let us return a zero. + * See Feature Request "[ 1307049 ] glutInit check". + */ + if ( ! fgState.Initialised ) + return 0; + + while ( win && win->IsMenu ) + win = win->Parent; + return win ? win->ID : 0; +} + +/* + * This function makes the current window visible + */ +void FGAPIENTRY glutShowWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" ); + +#if TARGET_HOST_POSIX_X11 + + XMapWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_SHOW ); + +#endif + + fgStructure.CurrentWindow->State.Redisplay = GL_TRUE; +} + +/* + * This function hides the current window + */ +void FGAPIENTRY glutHideWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" ); + +#if TARGET_HOST_POSIX_X11 + + if( fgStructure.CurrentWindow->Parent == NULL ) + XWithdrawWindow( fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + fgDisplay.Screen ); + else + XUnmapWindow( fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_HIDE ); + +#endif + + fgStructure.CurrentWindow->State.Redisplay = GL_FALSE; +} + +/* + * Iconify the current window (top-level windows only) + */ +void FGAPIENTRY glutIconifyWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" ); + + fgStructure.CurrentWindow->State.Visible = GL_FALSE; +#if TARGET_HOST_POSIX_X11 + + XIconifyWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, + fgDisplay.Screen ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_MINIMIZE ); + +#endif + + fgStructure.CurrentWindow->State.Redisplay = GL_FALSE; +} + +/* + * Set the current window's title + */ +void FGAPIENTRY glutSetWindowTitle( const char* title ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" ); + if( ! fgStructure.CurrentWindow->Parent ) + { +#if TARGET_HOST_POSIX_X11 + + XTextProperty text; + + text.value = (unsigned char *) title; + text.encoding = XA_STRING; + text.format = 8; + text.nitems = strlen( title ); + + XSetWMName( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &text + ); + + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS +# ifdef _WIN32_WCE + { + wchar_t* wstr = fghWstrFromStr(title); + SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr ); + free(wstr); + } +# else + SetWindowText( fgStructure.CurrentWindow->Window.Handle, title ); +# endif + +#endif + } +} + +/* + * Set the current window's iconified title + */ +void FGAPIENTRY glutSetIconTitle( const char* title ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" ); + + if( ! fgStructure.CurrentWindow->Parent ) + { +#if TARGET_HOST_POSIX_X11 + + XTextProperty text; + + text.value = (unsigned char *) title; + text.encoding = XA_STRING; + text.format = 8; + text.nitems = strlen( title ); + + XSetWMIconName( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &text + ); + + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS +# ifdef _WIN32_WCE + { + wchar_t* wstr = fghWstrFromStr(title); + SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr ); + free(wstr); + } +# else + SetWindowText( fgStructure.CurrentWindow->Window.Handle, title ); +# endif + +#endif + } +} + +/* + * Change the current window's size + */ +void FGAPIENTRY glutReshapeWindow( int width, int height ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" ); + + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before resizing. */ + glutFullScreenToggle(); + } + + fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; + fgStructure.CurrentWindow->State.Width = width ; + fgStructure.CurrentWindow->State.Height = height; +} + +/* + * Change the current window's position + */ +void FGAPIENTRY glutPositionWindow( int x, int y ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" ); + + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before moving. */ + glutFullScreenToggle(); + } + +#if TARGET_HOST_POSIX_X11 + + XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, + x, y ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + { + RECT winRect; + + /* "GetWindowRect" returns the pixel coordinates of the outside of the window */ + GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect ); + MoveWindow( + fgStructure.CurrentWindow->Window.Handle, + x, + y, + winRect.right - winRect.left, + winRect.bottom - winRect.top, + TRUE + ); + } + +#endif +} + +/* + * Lowers the current window (by Z order change) + */ +void FGAPIENTRY glutPushWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" ); + +#if TARGET_HOST_POSIX_X11 + + XLowerWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); + +#elif TARGET_HOST_MS_WINDOWS + + SetWindowPos( + fgStructure.CurrentWindow->Window.Handle, + HWND_BOTTOM, + 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE + ); + +#endif +} + +/* + * Raises the current window (by Z order change) + */ +void FGAPIENTRY glutPopWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" ); + +#if TARGET_HOST_POSIX_X11 + + XRaiseWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); + +#elif TARGET_HOST_MS_WINDOWS + + SetWindowPos( + fgStructure.CurrentWindow->Window.Handle, + HWND_TOP, + 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE + ); + +#endif +} + +#if TARGET_HOST_POSIX_X11 +static int ewmh_fullscr_toggle(void); +static int resize_fullscr_toogle(void); + +static int toggle_fullscreen(void) +{ + /* first try the EWMH (_NET_WM_STATE) method ... */ + if(ewmh_fullscr_toggle() != -1) { + return 0; + } + + /* fall back to resizing the window */ + if(resize_fullscr_toogle() != -1) { + return 0; + } + return -1; +} + +#define _NET_WM_STATE_TOGGLE 2 +static int ewmh_fullscr_toggle(void) +{ + XEvent xev; + long evmask = SubstructureRedirectMask | SubstructureNotifyMask; + + if(!fgDisplay.State || !fgDisplay.StateFullScreen) { + return -1; + } + + xev.type = ClientMessage; + xev.xclient.window = fgStructure.CurrentWindow->Window.Handle; + xev.xclient.message_type = fgDisplay.State; + xev.xclient.format = 32; + xev.xclient.data.l[0] = _NET_WM_STATE_TOGGLE; + xev.xclient.data.l[1] = fgDisplay.StateFullScreen; + xev.xclient.data.l[2] = 0; /* no second property to toggle */ + xev.xclient.data.l[3] = 1; /* source indication: application */ + xev.xclient.data.l[4] = 0; /* unused */ + + if(!XSendEvent(fgDisplay.Display, fgDisplay.RootWindow, 0, evmask, &xev)) { + return -1; + } + return 0; +} + +static int resize_fullscr_toogle(void) +{ + XWindowAttributes attributes; + + if(glutGet(GLUT_FULL_SCREEN)) { + /* restore original window size */ + SFG_Window *win = fgStructure.CurrentWindow; + fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; + fgStructure.CurrentWindow->State.Width = win->State.OldWidth; + fgStructure.CurrentWindow->State.Height = win->State.OldHeight; + + } else { + /* resize the window to cover the entire screen */ + XGetWindowAttributes(fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &attributes); + + /* + * The "x" and "y" members of "attributes" are the window's coordinates + * relative to its parent, i.e. to the decoration window. + */ + XMoveResizeWindow(fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + -attributes.x, + -attributes.y, + fgDisplay.ScreenWidth, + fgDisplay.ScreenHeight); + } + return 0; +} +#endif /* TARGET_HOST_POSIX_X11 */ + + +/* + * Resize the current window so that it fits the whole screen + */ +void FGAPIENTRY glutFullScreen( void ) +{ + SFG_Window *win; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); + + win = fgStructure.CurrentWindow; + +#if TARGET_HOST_POSIX_X11 + if(!glutGet(GLUT_FULL_SCREEN)) { + if(toggle_fullscreen() != -1) { + win->State.IsFullscreen = GL_TRUE; + } + } + +#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */ + + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before resizing. */ + glutFullScreenToggle(); + } + + { + RECT rect; + + /* For fullscreen mode, force the top-left corner to 0,0 + * and adjust the window rectangle so that the client area + * covers the whole screen. + */ + + rect.left = 0; + rect.top = 0; + rect.right = fgDisplay.ScreenWidth; + rect.bottom = fgDisplay.ScreenHeight; + + AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | + WS_CLIPCHILDREN, FALSE ); + + /* + * SWP_NOACTIVATE Do not activate the window + * SWP_NOOWNERZORDER Do not change position in z-order + * SWP_NOSENDCHANGING Supress WM_WINDOWPOSCHANGING message + * SWP_NOZORDER Retains the current Z order (ignore 2nd param) + */ + + SetWindowPos( fgStructure.CurrentWindow->Window.Handle, + HWND_TOP, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | + SWP_NOZORDER + ); + + win->State.IsFullscreen = GL_TRUE; + } +#endif +} + +/* + * Toggle the window's full screen state. + */ +void FGAPIENTRY glutFullScreenToggle( void ) +{ + SFG_Window *win; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" ); + + win = fgStructure.CurrentWindow; + +#if TARGET_HOST_POSIX_X11 + if(toggle_fullscreen() != -1) { + win->State.IsFullscreen = !win->State.IsFullscreen; + } +#elif TARGET_HOST_MS_WINDOWS + glutFullScreen(); + win->State.IsFullscreen = !win->State.IsFullscreen; +#endif +} + +/* + * A.Donev: Set and retrieve the window's user data + */ +void* FGAPIENTRY glutGetWindowData( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" ); + return fgStructure.CurrentWindow->UserData; +} + +void FGAPIENTRY glutSetWindowData(void* data) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" ); + fgStructure.CurrentWindow->UserData = data; +} + +/*** END OF FILE ***/ diff --git a/tests/Box2D_v2.2.1/glui/CMakeLists.txt b/tests/Box2D_v2.2.1/glui/CMakeLists.txt new file mode 100755 index 0000000000000..1e50298801350 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/CMakeLists.txt @@ -0,0 +1,49 @@ +add_definitions( -DFREEGLUT_STATIC -D_CRT_SECURE_NO_WARNINGS ) + +if(MSVC) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W1") +endif(MSVC) + +set(glui_SRCS + algebra3.cpp + arcball.cpp + glui_add_controls.cpp + glui_bitmap_img_data.cpp + glui_bitmaps.cpp + glui_button.cpp + glui_checkbox.cpp + glui_column.cpp + glui_commandline.cpp + glui_control.cpp + glui_edittext.cpp + glui_filebrowser.cpp + glui_list.cpp + glui_listbox.cpp + glui_mouse_iaction.cpp + glui_node.cpp + glui_panel.cpp + glui_radio.cpp + glui_rollout.cpp + glui_rotation.cpp + glui_scrollbar.cpp + glui_separator.cpp + glui_spinner.cpp + glui_statictext.cpp + glui_string.cpp + glui_textbox.cpp + glui_translation.cpp + glui_tree.cpp + glui_treepanel.cpp + glui_window.cpp + glui.cpp + quaternion.cpp +) + +include_directories ( + ${OPENGL_INCLUDE_DIR} + ../ +) + +add_library(glui + ${glui_SRCS} +) diff --git a/tests/Box2D_v2.2.1/glui/algebra3.cpp b/tests/Box2D_v2.2.1/glui/algebra3.cpp new file mode 100755 index 0000000000000..ddc18f4f89f21 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/algebra3.cpp @@ -0,0 +1,1609 @@ +/* + + algebra3.cpp, algebra3.h - C++ Vector and Matrix Algebra routines + + GLUI User Interface Toolkit (LGPL) + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +/************************************************************************** + + There are three vector classes and two matrix classes: vec2, vec3, + vec4, mat3, and mat4. + + All the standard arithmetic operations are defined, with '*' + for dot product of two vectors and multiplication of two matrices, + and '^' for cross product of two vectors. + + Additional functions include length(), normalize(), homogenize for + vectors, and print(), set(), apply() for all classes. + + There is a function transpose() for matrices, but note that it + does not actually change the matrix, + + When multiplied with a matrix, a vector is treated as a row vector + if it precedes the matrix (v*M), and as a column vector if it + follows the matrix (M*v). + + Matrices are stored in row-major form. + + A vector of one dimension (2d, 3d, or 4d) can be cast to a vector + of a higher or lower dimension. If casting to a higher dimension, + the new component is set by default to 1.0, unless a value is + specified: + vec3 a(1.0, 2.0, 3.0 ); + vec4 b( a, 4.0 ); // now b == {1.0, 2.0, 3.0, 4.0}; + When casting to a lower dimension, the vector is homogenized in + the lower dimension. E.g., if a 4d {X,Y,Z,W} is cast to 3d, the + resulting vector is {X/W, Y/W, Z/W}. It is up to the user to + insure the fourth component is not zero before casting. + + There are also the following function for building matrices: + identity2D(), translation2D(), rotation2D(), + scaling2D(), identity3D(), translation3D(), + rotation3D(), rotation3Drad(), scaling3D(), + perspective3D() + + + --------------------------------------------------------------------- + + Author: Jean-Francois DOUEg + Revised: Paul Rademacher + Version 3.2 - Feb 1998 + Revised: Nigel Stewart (GLUI Code Cleaning) + +**************************************************************************/ + +#include "algebra3.h" +#include "glui_internal.h" +#include + +#ifdef VEC_ERROR_FATAL +#ifndef VEC_ERROR +#define VEC_ERROR(E) { printf( "VERROR %s\n", E ); exit(1); } +#endif +#else +#ifndef VEC_ERROR +#define VEC_ERROR(E) { printf( "VERROR %s\n", E ); } +#endif +#endif + +/**************************************************************** + * * + * vec2 Member functions * + * * + ****************************************************************/ + +/******************** vec2 CONSTRUCTORS ********************/ + +vec2::vec2() +{ + n[VX] = n[VY] = 0.0; +} + +vec2::vec2(float x, float y) +{ + n[VX] = x; + n[VY] = y; +} + +vec2::vec2(const vec2 &v) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; +} + +vec2::vec2(const vec3 &v) // it is up to caller to avoid divide-by-zero +{ + n[VX] = v.n[VX]/v.n[VZ]; + n[VY] = v.n[VY]/v.n[VZ]; +} + +vec2::vec2(const vec3 &v, int dropAxis) +{ + switch (dropAxis) + { + case VX: n[VX] = v.n[VY]; n[VY] = v.n[VZ]; break; + case VY: n[VX] = v.n[VX]; n[VY] = v.n[VZ]; break; + default: n[VX] = v.n[VX]; n[VY] = v.n[VY]; break; + } +} + +/******************** vec2 ASSIGNMENT OPERATORS ******************/ + +vec2 & vec2::operator=(const vec2 &v) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + return *this; +} + +vec2 & vec2::operator+=(const vec2 &v) +{ + n[VX] += v.n[VX]; + n[VY] += v.n[VY]; + return *this; +} + +vec2 & vec2::operator-=(const vec2 &v) +{ + n[VX] -= v.n[VX]; + n[VY] -= v.n[VY]; + return *this; +} + +vec2 &vec2::operator*=(float d) +{ + n[VX] *= d; + n[VY] *= d; + return *this; +} + +vec2 &vec2::operator/=(float d) +{ + float d_inv = 1.0f/d; + n[VX] *= d_inv; + n[VY] *= d_inv; + return *this; +} + +float &vec2::operator[](int i) +{ + if (i < VX || i > VY) + //VEC_ERROR("vec2 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("vec2 [] operator: illegal access" ); + return n[i]; +} + +const float &vec2::operator[](int i) const +{ + if (i < VX || i > VY) + //VEC_ERROR("vec2 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("vec2 [] operator: illegal access" ); + + return n[i]; +} + +/******************** vec2 SPECIAL FUNCTIONS ********************/ + +float vec2::length() const +{ + return (float) sqrt(length2()); +} + +float vec2::length2() const +{ + return n[VX]*n[VX] + n[VY]*n[VY]; +} + +vec2 &vec2::normalize() // it is up to caller to avoid divide-by-zero +{ + *this /= length(); + return *this; +} + +vec2 &vec2::apply(V_FCT_PTR fct) +{ + n[VX] = (*fct)(n[VX]); + n[VY] = (*fct)(n[VY]); + return *this; +} + +void vec2::set( float x, float y ) +{ + n[VX] = x; n[VY] = y; +} + +/******************** vec2 FRIENDS *****************************/ + +vec2 operator-(const vec2 &a) +{ + return vec2(-a.n[VX],-a.n[VY]); +} + +vec2 operator+(const vec2 &a, const vec2& b) +{ + return vec2(a.n[VX]+b.n[VX], a.n[VY]+b.n[VY]); +} + +vec2 operator-(const vec2 &a, const vec2& b) +{ + return vec2(a.n[VX]-b.n[VX], a.n[VY]-b.n[VY]); +} + +vec2 operator*(const vec2 &a, float d) +{ + return vec2(d*a.n[VX], d*a.n[VY]); +} + +vec2 operator*(float d, const vec2 &a) +{ + return a*d; +} + +vec2 operator*(const mat3 &a, const vec2 &v) +{ + vec3 av; + + av.n[VX] = a.v[0].n[VX]*v.n[VX] + a.v[0].n[VY]*v.n[VY] + a.v[0].n[VZ]; + av.n[VY] = a.v[1].n[VX]*v.n[VX] + a.v[1].n[VY]*v.n[VY] + a.v[1].n[VZ]; + av.n[VZ] = a.v[2].n[VX]*v.n[VX] + a.v[2].n[VY]*v.n[VY] + a.v[2].n[VZ]; + + return av; +} + +vec2 operator*(const vec2 &v, const mat3 &a) +{ + return a.transpose() * v; +} + +vec3 operator*(const mat3 &a, const vec3 &v) +{ + vec3 av; + + av.n[VX] = a.v[0].n[VX]*v.n[VX] + a.v[0].n[VY]*v.n[VY] + a.v[0].n[VZ]*v.n[VZ]; + av.n[VY] = a.v[1].n[VX]*v.n[VX] + a.v[1].n[VY]*v.n[VY] + a.v[1].n[VZ]*v.n[VZ]; + av.n[VZ] = a.v[2].n[VX]*v.n[VX] + a.v[2].n[VY]*v.n[VY] + a.v[2].n[VZ]*v.n[VZ]; + + return av; +} + +vec3 operator*(const vec3 &v, const mat3 &a) +{ + return a.transpose() * v; +} + +float operator*(const vec2 &a, const vec2 &b) +{ + return a.n[VX]*b.n[VX] + a.n[VY]*b.n[VY]; +} + +vec2 operator/(const vec2 &a, float d) +{ + float d_inv = 1.0f/d; + return vec2(a.n[VX]*d_inv, a.n[VY]*d_inv); +} + +vec3 operator^(const vec2 &a, const vec2 &b) +{ + return vec3(0.0, 0.0, a.n[VX] * b.n[VY] - b.n[VX] * a.n[VY]); +} + +int operator==(const vec2 &a, const vec2 &b) +{ + return (a.n[VX] == b.n[VX]) && (a.n[VY] == b.n[VY]); +} + +int operator!=(const vec2 &a, const vec2 &b) +{ + return !(a == b); +} + +/*ostream& operator << (ostream& s, vec2& v) +{ return s << "| " << v.n[VX] << ' ' << v.n[VY] << " |"; } +*/ + +/*istream& operator >> (istream& s, vec2& v) { + vec2 v_tmp; + char c = ' '; + + while (isspace(c)) + s >> c; + // The vectors can be formatted either as x y or | x y | + if (c == '|') { + s >> v_tmp[VX] >> v_tmp[VY]; + while (s >> c && isspace(c)) ; + if (c != '|') + ;//s.set(_bad); + } + else { + s.putback(c); + s >> v_tmp[VX] >> v_tmp[VY]; + } + if (s) + v = v_tmp; + return s; +} +*/ + +void swap(vec2 &a, vec2 &b) +{ + vec2 tmp(a); + a = b; + b = tmp; +} + +vec2 min_vec(const vec2 &a, const vec2 &b) +{ + return vec2(MIN(a.n[VX], b.n[VX]), MIN(a.n[VY], b.n[VY])); +} + +vec2 max_vec(const vec2 &a, const vec2 &b) +{ + return vec2(MAX(a.n[VX], b.n[VX]), MAX(a.n[VY], b.n[VY])); +} + +vec2 prod(const vec2 &a, const vec2 &b) +{ + return vec2(a.n[VX] * b.n[VX], a.n[VY] * b.n[VY]); +} + +/**************************************************************** + * * + * vec3 Member functions * + * * + ****************************************************************/ + +// CONSTRUCTORS + +vec3::vec3() +{ + n[VX] = n[VY] = n[VZ] = 0.0; +} + +vec3::vec3(float x, float y, float z) +{ + n[VX] = x; + n[VY] = y; + n[VZ] = z; +} + +vec3::vec3(const vec3 &v) +{ + n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ]; +} + +vec3::vec3(const vec2 &v) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + n[VZ] = 1.0; +} + +vec3::vec3(const vec2 &v, float d) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + n[VZ] = d; +} + +vec3::vec3(const vec4 &v) // it is up to caller to avoid divide-by-zero +{ + n[VX] = v.n[VX] / v.n[VW]; + n[VY] = v.n[VY] / v.n[VW]; + n[VZ] = v.n[VZ] / v.n[VW]; +} + +vec3::vec3(const vec4 &v, int dropAxis) +{ + switch (dropAxis) + { + case VX: n[VX] = v.n[VY]; n[VY] = v.n[VZ]; n[VZ] = v.n[VW]; break; + case VY: n[VX] = v.n[VX]; n[VY] = v.n[VZ]; n[VZ] = v.n[VW]; break; + case VZ: n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VW]; break; + default: n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ]; break; + } +} + + +// ASSIGNMENT OPERATORS + +vec3 &vec3::operator=(const vec3 &v) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + n[VZ] = v.n[VZ]; + return *this; +} + +vec3 &vec3::operator+=(const vec3 &v) +{ + n[VX] += v.n[VX]; + n[VY] += v.n[VY]; + n[VZ] += v.n[VZ]; + return *this; +} + +vec3 &vec3::operator-=(const vec3& v) +{ + n[VX] -= v.n[VX]; + n[VY] -= v.n[VY]; + n[VZ] -= v.n[VZ]; + return *this; +} + +vec3 &vec3::operator*=(float d) +{ + n[VX] *= d; + n[VY] *= d; + n[VZ] *= d; + return *this; +} + +vec3 &vec3::operator/=(float d) +{ + float d_inv = 1.0f/d; + n[VX] *= d_inv; + n[VY] *= d_inv; + n[VZ] *= d_inv; + return *this; +} + +float &vec3::operator[](int i) +{ + if (i < VX || i > VZ) + //VEC_ERROR("vec3 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("vec3 [] operator: illegal access" ); + + return n[i]; +} + +const float &vec3::operator[](int i) const +{ + if (i < VX || i > VZ) + //VEC_ERROR("vec3 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("vec3 [] operator: illegal access" ); + + return n[i]; +} + +// SPECIAL FUNCTIONS + +float vec3::length() const +{ + return (float) sqrt(length2()); +} + +float vec3::length2() const +{ + return n[VX]*n[VX] + n[VY]*n[VY] + n[VZ]*n[VZ]; +} + +vec3 &vec3::normalize() // it is up to caller to avoid divide-by-zero +{ + *this /= length(); + return *this; +} + +vec3 &vec3::homogenize(void) // it is up to caller to avoid divide-by-zero +{ + n[VX] /= n[VZ]; + n[VY] /= n[VZ]; + n[VZ] = 1.0; + return *this; +} + +vec3 &vec3::apply(V_FCT_PTR fct) +{ + n[VX] = (*fct)(n[VX]); + n[VY] = (*fct)(n[VY]); + n[VZ] = (*fct)(n[VZ]); + return *this; +} + +void vec3::set(float x, float y, float z) // set vector +{ + n[VX] = x; + n[VY] = y; + n[VZ] = z; +} + +void vec3::print(FILE *file, const char *name) const // print vector to a file +{ + fprintf( file, "%s: <%f, %f, %f>\n", name, n[VX], n[VY], n[VZ] ); +} + +// FRIENDS + +vec3 operator-(const vec3 &a) +{ + return vec3(-a.n[VX],-a.n[VY],-a.n[VZ]); +} + +vec3 operator+(const vec3 &a, const vec3 &b) +{ + return vec3(a.n[VX]+ b.n[VX], a.n[VY] + b.n[VY], a.n[VZ] + b.n[VZ]); +} + +vec3 operator-(const vec3 &a, const vec3 &b) +{ + return vec3(a.n[VX]-b.n[VX], a.n[VY]-b.n[VY], a.n[VZ]-b.n[VZ]); +} + +vec3 operator*(const vec3 &a, float d) +{ + return vec3(d*a.n[VX], d*a.n[VY], d*a.n[VZ]); +} + +vec3 operator*(float d, const vec3 &a) +{ + return a*d; +} + +vec3 operator*(const mat4 &a, const vec3 &v) +{ + return a*vec4(v); +} + +vec3 operator*(const vec3 &v, mat4 &a) +{ + return a.transpose()*v; +} + +float operator*(const vec3 &a, const vec3 &b) +{ + return a.n[VX]*b.n[VX] + a.n[VY]*b.n[VY] + a.n[VZ]*b.n[VZ]; +} + +vec3 operator/(const vec3 &a, float d) +{ + float d_inv = 1.0f/d; + return vec3(a.n[VX]*d_inv, a.n[VY]*d_inv, a.n[VZ]*d_inv); +} + +vec3 operator^(const vec3 &a, const vec3 &b) +{ + return + vec3(a.n[VY]*b.n[VZ] - a.n[VZ]*b.n[VY], + a.n[VZ]*b.n[VX] - a.n[VX]*b.n[VZ], + a.n[VX]*b.n[VY] - a.n[VY]*b.n[VX]); +} + +int operator==(const vec3 &a, const vec3 &b) +{ + return (a.n[VX] == b.n[VX]) && (a.n[VY] == b.n[VY]) && (a.n[VZ] == b.n[VZ]); +} + +int operator!=(const vec3 &a, const vec3 &b) +{ + return !(a == b); +} + +/*ostream& operator << (ostream& s, vec3& v) +{ return s << "| " << v.n[VX] << ' ' << v.n[VY] << ' ' << v.n[VZ] << " |"; } + +istream& operator >> (istream& s, vec3& v) { + vec3 v_tmp; + char c = ' '; + + while (isspace(c)) + s >> c; + // The vectors can be formatted either as x y z or | x y z | + if (c == '|') { + s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ]; + while (s >> c && isspace(c)) ; + if (c != '|') + ;//s.set(_bad); + } + else { + s.putback(c); + s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ]; + } + if (s) + v = v_tmp; + return s; +} +*/ + +void swap(vec3 &a, vec3 &b) +{ + vec3 tmp(a); + a = b; + b = tmp; +} + +vec3 min_vec(const vec3 &a, const vec3 &b) +{ + return vec3( + MIN(a.n[VX], b.n[VX]), + MIN(a.n[VY], b.n[VY]), + MIN(a.n[VZ], b.n[VZ])); +} + +vec3 max_vec(const vec3 &a, const vec3 &b) +{ + return vec3( + MAX(a.n[VX], b.n[VX]), + MAX(a.n[VY], b.n[VY]), + MAX(a.n[VZ], b.n[VZ])); +} + +vec3 prod(const vec3 &a, const vec3 &b) +{ + return vec3(a.n[VX]*b.n[VX], a.n[VY]*b.n[VY], a.n[VZ]*b.n[VZ]); +} + +/**************************************************************** + * * + * vec4 Member functions * + * * + ****************************************************************/ + +// CONSTRUCTORS + +vec4::vec4() +{ + n[VX] = n[VY] = n[VZ] = 0.0; + n[VW] = 1.0; +} + +vec4::vec4(float x, float y, float z, float w) +{ + n[VX] = x; + n[VY] = y; + n[VZ] = z; + n[VW] = w; +} + +vec4::vec4(const vec4 &v) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + n[VZ] = v.n[VZ]; + n[VW] = v.n[VW]; +} + +vec4::vec4(const vec3 &v) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + n[VZ] = v.n[VZ]; + n[VW] = 1.0; +} + +vec4::vec4(const vec3 &v, float d) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + n[VZ] = v.n[VZ]; + n[VW] = d; +} + +// ASSIGNMENT OPERATORS + +vec4 &vec4::operator=(const vec4 &v) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + n[VZ] = v.n[VZ]; + n[VW] = v.n[VW]; + return *this; +} + +vec4 &vec4::operator+=(const vec4 &v) +{ + n[VX] += v.n[VX]; + n[VY] += v.n[VY]; + n[VZ] += v.n[VZ]; + n[VW] += v.n[VW]; + return *this; +} + +vec4 &vec4::operator-=(const vec4 &v) +{ + n[VX] -= v.n[VX]; + n[VY] -= v.n[VY]; + n[VZ] -= v.n[VZ]; + n[VW] -= v.n[VW]; + return *this; +} + +vec4 &vec4::operator*=(float d) +{ + n[VX] *= d; + n[VY] *= d; + n[VZ] *= d; + n[VW] *= d; + return *this; +} + +vec4 &vec4::operator/=(float d) +{ + float d_inv = 1.0f/d; + n[VX] *= d_inv; + n[VY] *= d_inv; + n[VZ] *= d_inv; + n[VW] *= d_inv; + return *this; +} + +float &vec4::operator[](int i) +{ + if (i < VX || i > VW) + //VEC_ERROR("vec4 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("vec4 [] operator: illegal access" ); + + return n[i]; +} + +const float &vec4::operator[](int i) const +{ + if (i < VX || i > VW) + //VEC_ERROR("vec4 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("vec4 [] operator: illegal access" ); + + return n[i]; +} + +// SPECIAL FUNCTIONS + +float vec4::length() const +{ + return (float) sqrt(length2()); +} + +float vec4::length2() const +{ + return n[VX]*n[VX] + n[VY]*n[VY] + n[VZ]*n[VZ] + n[VW]*n[VW]; +} + +vec4 &vec4::normalize() // it is up to caller to avoid divide-by-zero +{ + *this /= length(); + return *this; +} + +vec4 &vec4::homogenize() // it is up to caller to avoid divide-by-zero +{ + n[VX] /= n[VW]; + n[VY] /= n[VW]; + n[VZ] /= n[VW]; + n[VW] = 1.0; + return *this; +} + +vec4 &vec4::apply(V_FCT_PTR fct) +{ + n[VX] = (*fct)(n[VX]); + n[VY] = (*fct)(n[VY]); + n[VZ] = (*fct)(n[VZ]); + n[VW] = (*fct)(n[VW]); + return *this; +} + +void vec4::print(FILE *file, const char *name) const // print vector to a file +{ + fprintf( file, "%s: <%f, %f, %f, %f>\n", name, n[VX], n[VY], n[VZ], n[VW]); +} + +void vec4::set(float x, float y, float z, float a) +{ + n[0] = x; + n[1] = y; + n[2] = z; + n[3] = a; +} + + +// FRIENDS + +vec4 operator-(const vec4 &a) +{ + return vec4(-a.n[VX],-a.n[VY],-a.n[VZ],-a.n[VW]); +} + +vec4 operator+(const vec4 &a, const vec4 &b) +{ + return vec4( + a.n[VX] + b.n[VX], + a.n[VY] + b.n[VY], + a.n[VZ] + b.n[VZ], + a.n[VW] + b.n[VW]); +} + +vec4 operator-(const vec4 &a, const vec4 &b) +{ + return vec4( + a.n[VX] - b.n[VX], + a.n[VY] - b.n[VY], + a.n[VZ] - b.n[VZ], + a.n[VW] - b.n[VW]); +} + +vec4 operator*(const vec4 &a, float d) +{ + return vec4(d*a.n[VX], d*a.n[VY], d*a.n[VZ], d*a.n[VW]); +} + +vec4 operator*(float d, const vec4 &a) +{ + return a*d; +} + +vec4 operator*(const mat4 &a, const vec4 &v) +{ + #define ROWCOL(i) \ + a.v[i].n[0]*v.n[VX] + \ + a.v[i].n[1]*v.n[VY] + \ + a.v[i].n[2]*v.n[VZ] + \ + a.v[i].n[3]*v.n[VW] + + return vec4(ROWCOL(0), ROWCOL(1), ROWCOL(2), ROWCOL(3)); + + #undef ROWCOL +} + +vec4 operator*(const vec4 &v, const mat4 &a) +{ + return a.transpose()*v; +} + +float operator*(const vec4 &a, const vec4 &b) +{ + return + a.n[VX]*b.n[VX] + + a.n[VY]*b.n[VY] + + a.n[VZ]*b.n[VZ] + + a.n[VW]*b.n[VW]; +} + +vec4 operator/(const vec4 &a, float d) +{ + float d_inv = 1.0f/d; + return vec4( + a.n[VX]*d_inv, + a.n[VY]*d_inv, + a.n[VZ]*d_inv, + a.n[VW]*d_inv); +} + +int operator==(const vec4 &a, const vec4 &b) +{ + return + (a.n[VX] == b.n[VX]) && + (a.n[VY] == b.n[VY]) && + (a.n[VZ] == b.n[VZ]) && + (a.n[VW] == b.n[VW]); +} + +int operator!=(const vec4 &a, const vec4 &b) +{ + return !(a == b); +} + +/*ostream& operator << (ostream& s, vec4& v) +{ return s << "| " << v.n[VX] << ' ' << v.n[VY] << ' ' << v.n[VZ] << ' ' + << v.n[VW] << " |"; } + +istream& operator >> (istream& s, vec4& v) { + vec4 v_tmp; + char c = ' '; + + while (isspace(c)) + s >> c; + // The vectors can be formatted either as x y z w or | x y z w | + if (c == '|') { + s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ] >> v_tmp[VW]; + while (s >> c && isspace(c)) ; + if (c != '|') + ;//s.set(_bad); + } + else { + s.putback(c); + s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ] >> v_tmp[VW]; + } + if (s) + v = v_tmp; + return s; +} +*/ + +void swap(vec4 &a, vec4 &b) +{ + vec4 tmp(a); + a = b; + b = tmp; +} + +vec4 min_vec(const vec4 &a, const vec4 &b) +{ + return vec4( + MIN(a.n[VX], b.n[VX]), + MIN(a.n[VY], b.n[VY]), + MIN(a.n[VZ], b.n[VZ]), + MIN(a.n[VW], b.n[VW])); +} + +vec4 max_vec(const vec4 &a, const vec4 &b) +{ + return vec4( + MAX(a.n[VX], b.n[VX]), + MAX(a.n[VY], b.n[VY]), + MAX(a.n[VZ], b.n[VZ]), + MAX(a.n[VW], b.n[VW])); +} + +vec4 prod(const vec4 &a, const vec4 &b) +{ + return vec4( + a.n[VX] * b.n[VX], + a.n[VY] * b.n[VY], + a.n[VZ] * b.n[VZ], + a.n[VW] * b.n[VW]); +} + +/**************************************************************** + * * + * mat3 member functions * + * * + ****************************************************************/ + +// CONSTRUCTORS + +mat3::mat3() +{ + *this = identity2D(); +} + +mat3::mat3(const vec3 &v0, const vec3 &v1, const vec3 &v2) +{ + set(v0, v1, v2); +} + +mat3::mat3(const mat3 &m) +{ + v[0] = m.v[0]; + v[1] = m.v[1]; + v[2] = m.v[2]; +} + +// ASSIGNMENT OPERATORS + +mat3 &mat3::operator=(const mat3 &m) +{ + v[0] = m.v[0]; + v[1] = m.v[1]; + v[2] = m.v[2]; + return *this; +} + +mat3 &mat3::operator+=(const mat3& m) +{ + v[0] += m.v[0]; + v[1] += m.v[1]; + v[2] += m.v[2]; + return *this; +} + +mat3 &mat3::operator-=(const mat3& m) +{ + v[0] -= m.v[0]; + v[1] -= m.v[1]; + v[2] -= m.v[2]; + return *this; +} + +mat3 &mat3::operator*=(float d) +{ + v[0] *= d; + v[1] *= d; + v[2] *= d; + return *this; +} + +mat3 &mat3::operator/=(float d) +{ + v[0] /= d; + v[1] /= d; + v[2] /= d; + return *this; +} + +vec3 &mat3::operator[](int i) +{ + if (i < VX || i > VZ) + //VEC_ERROR("mat3 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("mat3 [] operator: illegal access" ); + + return v[i]; +} + +const vec3 &mat3::operator[](int i) const +{ + if (i < VX || i > VZ) + //VEC_ERROR("mat3 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("mat3 [] operator: illegal access" ); + + return v[i]; +} + +void mat3::set(const vec3 &v0, const vec3 &v1, const vec3 &v2) +{ + v[0] = v0; + v[1] = v1; + v[2] = v2; +} + +// SPECIAL FUNCTIONS + +mat3 mat3::transpose() const +{ + return mat3( + vec3(v[0][0], v[1][0], v[2][0]), + vec3(v[0][1], v[1][1], v[2][1]), + vec3(v[0][2], v[1][2], v[2][2])); +} + +mat3 mat3::inverse() const // Gauss-Jordan elimination with partial pivoting +{ + mat3 a(*this); // As a evolves from original mat into identity + mat3 b(identity2D()); // b evolves from identity into inverse(a) + int i, j, i1; + + // Loop over cols of a from left to right, eliminating above and below diag + for (j=0; j<3; j++) // Find largest pivot in column j among rows j..2 + { + i1 = j; // Row with largest pivot candidate + for (i=j+1; i<3; i++) + if (fabs(a.v[i].n[j]) > fabs(a.v[i1].n[j])) + i1 = i; + + // Swap rows i1 and j in a and b to put pivot on diagonal + swap(a.v[i1], a.v[j]); + swap(b.v[i1], b.v[j]); + + // Scale row j to have a unit diagonal + if (a.v[j].n[j]==0.) + VEC_ERROR("mat3::inverse: singular matrix; can't invert\n"); + + b.v[j] /= a.v[j].n[j]; + a.v[j] /= a.v[j].n[j]; + + // Eliminate off-diagonal elems in col j of a, doing identical ops to b + for (i=0; i<3; i++) + if (i!=j) + { + b.v[i] -= a.v[i].n[j]*b.v[j]; + a.v[i] -= a.v[i].n[j]*a.v[j]; + } + } + + return b; +} + +mat3 &mat3::apply(V_FCT_PTR fct) +{ + v[VX].apply(fct); + v[VY].apply(fct); + v[VZ].apply(fct); + return *this; +} + + +// FRIENDS + +mat3 operator-(const mat3 &a) +{ + return mat3(-a.v[0], -a.v[1], -a.v[2]); +} + +mat3 operator+(const mat3 &a, const mat3 &b) +{ + return mat3(a.v[0]+b.v[0], a.v[1]+b.v[1], a.v[2]+b.v[2]); +} + +mat3 operator-(const mat3 &a, const mat3 &b) +{ + return mat3(a.v[0]-b.v[0], a.v[1]-b.v[1], a.v[2]-b.v[2]); +} + +mat3 operator*(const mat3 &a, const mat3 &b) +{ + #define ROWCOL(i, j) \ + a.v[i].n[0]*b.v[0][j] + a.v[i].n[1]*b.v[1][j] + a.v[i].n[2]*b.v[2][j] + + return mat3( + vec3(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2)), + vec3(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2)), + vec3(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2))); + + #undef ROWCOL +} + +mat3 operator*(const mat3 &a, float d) +{ + return mat3(a.v[0]*d, a.v[1]*d, a.v[2]*d); +} + +mat3 operator*(float d, const mat3 &a) +{ + return a*d; +} + +mat3 operator/(const mat3 &a, float d) +{ + return mat3(a.v[0]/d, a.v[1]/d, a.v[2]/d); +} + +int operator==(const mat3 &a, const mat3 &b) +{ + return + (a.v[0] == b.v[0]) && + (a.v[1] == b.v[1]) && + (a.v[2] == b.v[2]); +} + +int operator!=(const mat3 &a, const mat3 &b) +{ + return !(a == b); +} + +/*ostream& operator << (ostream& s, mat3& m) +{ return s << m.v[VX] << '\n' << m.v[VY] << '\n' << m.v[VZ]; } + +istream& operator >> (istream& s, mat3& m) { + mat3 m_tmp; + + s >> m_tmp[VX] >> m_tmp[VY] >> m_tmp[VZ]; + if (s) + m = m_tmp; + return s; +} +*/ + +void swap(mat3 &a, mat3 &b) +{ + mat3 tmp(a); + a = b; + b = tmp; +} + +void mat3::print(FILE *file, const char *name) const +{ + int i, j; + + fprintf( stderr, "%s:\n", name ); + + for( i = 0; i < 3; i++ ) + { + fprintf( stderr, " " ); + for( j = 0; j < 3; j++ ) + { + fprintf( stderr, "%f ", v[i][j] ); + } + fprintf( stderr, "\n" ); + } +} + + + +/**************************************************************** + * * + * mat4 member functions * + * * + ****************************************************************/ + +// CONSTRUCTORS + +mat4::mat4() +{ + *this = identity3D(); +} + +mat4::mat4(const vec4& v0, const vec4& v1, const vec4& v2, const vec4& v3) +{ + v[0] = v0; + v[1] = v1; + v[2] = v2; + v[3] = v3; +} + +mat4::mat4(const mat4 &m) +{ + v[0] = m.v[0]; + v[1] = m.v[1]; + v[2] = m.v[2]; + v[3] = m.v[3]; +} + +mat4::mat4( + float a00, float a01, float a02, float a03, + float a10, float a11, float a12, float a13, + float a20, float a21, float a22, float a23, + float a30, float a31, float a32, float a33 ) +{ + v[0][0] = a00; v[0][1] = a01; v[0][2] = a02; v[0][3] = a03; + v[1][0] = a10; v[1][1] = a11; v[1][2] = a12; v[1][3] = a13; + v[2][0] = a20; v[2][1] = a21; v[2][2] = a22; v[2][3] = a23; + v[3][0] = a30; v[3][1] = a31; v[3][2] = a32; v[3][3] = a33; +} + +// ASSIGNMENT OPERATORS + +mat4 &mat4::operator=(const mat4 &m) +{ + v[0] = m.v[0]; + v[1] = m.v[1]; + v[2] = m.v[2]; + v[3] = m.v[3]; + return *this; +} + +mat4 &mat4::operator+=(const mat4 &m) +{ + v[0] += m.v[0]; + v[1] += m.v[1]; + v[2] += m.v[2]; + v[3] += m.v[3]; + return *this; +} + +mat4 &mat4::operator-=(const mat4 &m) +{ + v[0] -= m.v[0]; + v[1] -= m.v[1]; + v[2] -= m.v[2]; + v[3] -= m.v[3]; + return *this; +} + +mat4 &mat4::operator*=(float d) +{ + v[0] *= d; + v[1] *= d; + v[2] *= d; + v[3] *= d; + return *this; +} + +mat4 &mat4::operator/=(float d) +{ + v[0] /= d; + v[1] /= d; + v[2] /= d; + v[3] /= d; + return *this; +} + +vec4 &mat4::operator[](int i) +{ + if (i < VX || i > VW) + //VEC_ERROR("mat4 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("mat4 [] operator: illegal access" ); + return v[i]; +} + +const vec4 &mat4::operator[](int i) const +{ + if (i < VX || i > VW) + //VEC_ERROR("mat4 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("mat4 [] operator: illegal access" ); + return v[i]; +} + +// SPECIAL FUNCTIONS; + +mat4 mat4::transpose() const +{ + return mat4( + vec4(v[0][0], v[1][0], v[2][0], v[3][0]), + vec4(v[0][1], v[1][1], v[2][1], v[3][1]), + vec4(v[0][2], v[1][2], v[2][2], v[3][2]), + vec4(v[0][3], v[1][3], v[2][3], v[3][3])); +} + +mat4 mat4::inverse() const // Gauss-Jordan elimination with partial pivoting +{ + mat4 a(*this); // As a evolves from original mat into identity + mat4 b(identity3D()); // b evolves from identity into inverse(a) + int i, j, i1; + + // Loop over cols of a from left to right, eliminating above and below diag + for (j=0; j<4; j++) // Find largest pivot in column j among rows j..3 + { + i1 = j; // Row with largest pivot candidate + for (i=j+1; i<4; i++) + if (fabs(a.v[i].n[j]) > fabs(a.v[i1].n[j])) + i1 = i; + + // Swap rows i1 and j in a and b to put pivot on diagonal + swap(a.v[i1], a.v[j]); + swap(b.v[i1], b.v[j]); + + // Scale row j to have a unit diagonal + if (a.v[j].n[j]==0.) + VEC_ERROR("mat4::inverse: singular matrix; can't invert\n"); + + b.v[j] /= a.v[j].n[j]; + a.v[j] /= a.v[j].n[j]; + + // Eliminate off-diagonal elems in col j of a, doing identical ops to b + for (i=0; i<4; i++) + if (i!=j) + { + b.v[i] -= a.v[i].n[j]*b.v[j]; + a.v[i] -= a.v[i].n[j]*a.v[j]; + } + } + + return b; +} + +mat4 &mat4::apply(V_FCT_PTR fct) +{ + v[VX].apply(fct); + v[VY].apply(fct); + v[VZ].apply(fct); + v[VW].apply(fct); + return *this; +} + +void mat4::print(FILE *file, const char *name) const +{ + int i, j; + + fprintf( stderr, "%s:\n", name ); + + for( i = 0; i < 4; i++ ) + { + fprintf( stderr, " " ); + for( j = 0; j < 4; j++ ) + { + fprintf( stderr, "%f ", v[i][j] ); + } + fprintf( stderr, "\n" ); + } +} + +void mat4::swap_rows(int i, int j) +{ + vec4 t; + + t = v[i]; + v[i] = v[j]; + v[j] = t; +} + +void mat4::swap_cols(int i, int j) +{ + float t; + int k; + + for (k=0; k<4; k++) + { + t = v[k][i]; + v[k][i] = v[k][j]; + v[k][j] = t; + } +} + + +// FRIENDS + +mat4 operator-(const mat4 &a) +{ + return mat4(-a.v[0],-a.v[1],-a.v[2],-a.v[3]); +} + +mat4 operator+(const mat4 &a, const mat4 &b) +{ + return mat4( + a.v[0] + b.v[0], + a.v[1] + b.v[1], + a.v[2] + b.v[2], + a.v[3] + b.v[3]); +} + +mat4 operator-(const mat4 &a, const mat4 &b) +{ + return mat4( + a.v[0] - b.v[0], + a.v[1] - b.v[1], + a.v[2] - b.v[2], + a.v[3] - b.v[3]); +} + +mat4 operator*(const mat4 &a, const mat4 &b) +{ + #define ROWCOL(i, j) \ + a.v[i].n[0]*b.v[0][j] + \ + a.v[i].n[1]*b.v[1][j] + \ + a.v[i].n[2]*b.v[2][j] + \ + a.v[i].n[3]*b.v[3][j] + + return mat4( + vec4(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2), ROWCOL(0,3)), + vec4(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2), ROWCOL(1,3)), + vec4(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2), ROWCOL(2,3)), + vec4(ROWCOL(3,0), ROWCOL(3,1), ROWCOL(3,2), ROWCOL(3,3)) + ); + + #undef ROWCOL +} + +mat4 operator*(const mat4 &a, float d) +{ + return mat4(a.v[0]*d, a.v[1]*d, a.v[2]*d, a.v[3]*d); +} + +mat4 operator*(float d, const mat4 &a) +{ + return a*d; +} + +mat4 operator/(const mat4 &a, float d) +{ + return mat4(a.v[0]/d, a.v[1]/d, a.v[2]/d, a.v[3]/d); +} + +int operator==(const mat4 &a, const mat4 &b) +{ + return + (a.v[0] == b.v[0]) && + (a.v[1] == b.v[1]) && + (a.v[2] == b.v[2]) && + (a.v[3] == b.v[3]); +} + +int operator!=(const mat4 &a, const mat4 &b) +{ + return !(a == b); +} + +/*ostream& operator << (ostream& s, mat4& m) +{ return s << m.v[VX] << '\n' << m.v[VY] << '\n' << m.v[VZ] << '\n' << m.v[VW]; } + +istream& operator >> (istream& s, mat4& m) +{ + mat4 m_tmp; + + s >> m_tmp[VX] >> m_tmp[VY] >> m_tmp[VZ] >> m_tmp[VW]; + if (s) + m = m_tmp; + return s; +} +*/ + +void swap(mat4 &a, mat4 &b) +{ + mat4 tmp(a); + a = b; + b = tmp; +} + +/**************************************************************** + * * + * 2D functions and 3D functions * + * * + ****************************************************************/ + +mat3 identity2D() +{ + return mat3( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0)); +} + +mat3 translation2D(const vec2 &v) +{ + return mat3( + vec3(1.0, 0.0, v[VX]), + vec3(0.0, 1.0, v[VY]), + vec3(0.0, 0.0, 1.0)); +} + +mat3 rotation2D(const vec2 &Center, float angleDeg) +{ + float angleRad = (float) (angleDeg * M_PI / 180.0); + float c = (float) cos(angleRad); + float s = (float) sin(angleRad); + + return mat3( + vec3(c, -s, Center[VX] * (1.0f-c) + Center[VY] * s), + vec3(s, c, Center[VY] * (1.0f-c) - Center[VX] * s), + vec3(0.0, 0.0, 1.0)); +} + +mat3 scaling2D(const vec2 &scaleVector) +{ + return mat3( + vec3(scaleVector[VX], 0.0, 0.0), + vec3(0.0, scaleVector[VY], 0.0), + vec3(0.0, 0.0, 1.0)); +} + +mat4 identity3D() +{ + return mat4( + vec4(1.0, 0.0, 0.0, 0.0), + vec4(0.0, 1.0, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(0.0, 0.0, 0.0, 1.0)); +} + +mat4 translation3D(const vec3 &v) +{ + return mat4( + vec4(1.0, 0.0, 0.0, v[VX]), + vec4(0.0, 1.0, 0.0, v[VY]), + vec4(0.0, 0.0, 1.0, v[VZ]), + vec4(0.0, 0.0, 0.0, 1.0)); +} + +mat4 rotation3D(const vec3 &Axis, float angleDeg) +{ + float angleRad = (float) (angleDeg * M_PI / 180.0); + float c = (float) cos(angleRad); + float s = (float) sin(angleRad); + float t = 1.0f - c; + + vec3 axis(Axis); + axis.normalize(); + + return mat4( + vec4(t * axis[VX] * axis[VX] + c, + t * axis[VX] * axis[VY] - s * axis[VZ], + t * axis[VX] * axis[VZ] + s * axis[VY], + 0.0), + vec4(t * axis[VX] * axis[VY] + s * axis[VZ], + t * axis[VY] * axis[VY] + c, + t * axis[VY] * axis[VZ] - s * axis[VX], + 0.0), + vec4(t * axis[VX] * axis[VZ] - s * axis[VY], + t * axis[VY] * axis[VZ] + s * axis[VX], + t * axis[VZ] * axis[VZ] + c, + 0.0), + vec4(0.0, 0.0, 0.0, 1.0)); +} + +mat4 rotation3Drad(const vec3 &Axis, float angleRad) +{ + float c = (float) cos(angleRad); + float s = (float) sin(angleRad); + float t = 1.0f - c; + + vec3 axis(Axis); + axis.normalize(); + + return mat4( + vec4(t * axis[VX] * axis[VX] + c, + t * axis[VX] * axis[VY] - s * axis[VZ], + t * axis[VX] * axis[VZ] + s * axis[VY], + 0.0), + vec4(t * axis[VX] * axis[VY] + s * axis[VZ], + t * axis[VY] * axis[VY] + c, + t * axis[VY] * axis[VZ] - s * axis[VX], + 0.0), + vec4(t * axis[VX] * axis[VZ] - s * axis[VY], + t * axis[VY] * axis[VZ] + s * axis[VX], + t * axis[VZ] * axis[VZ] + c, + 0.0), + vec4(0.0, 0.0, 0.0, 1.0)); +} + +mat4 scaling3D(const vec3 &scaleVector) +{ + return mat4( + vec4(scaleVector[VX], 0.0, 0.0, 0.0), + vec4(0.0, scaleVector[VY], 0.0, 0.0), + vec4(0.0, 0.0, scaleVector[VZ], 0.0), + vec4(0.0, 0.0, 0.0, 1.0)); +} + +mat4 perspective3D(float d) +{ + return mat4( + vec4(1.0f, 0.0f, 0.0f, 0.0f), + vec4(0.0f, 1.0f, 0.0f, 0.0f), + vec4(0.0f, 0.0f, 1.0f, 0.0f), + vec4(0.0f, 0.0f, 1.0f/d, 0.0f)); +} diff --git a/tests/Box2D_v2.2.1/glui/algebra3.h b/tests/Box2D_v2.2.1/glui/algebra3.h new file mode 100755 index 0000000000000..7849673df6962 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/algebra3.h @@ -0,0 +1,475 @@ +/* + + algebra3.cpp, algebra3.h - C++ Vector and Matrix Algebra routines + + GLUI User Interface Toolkit (LGPL) + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +/************************************************************************** + + There are three vector classes and two matrix classes: vec2, vec3, + vec4, mat3, and mat4. + + All the standard arithmetic operations are defined, with '*' + for dot product of two vectors and multiplication of two matrices, + and '^' for cross product of two vectors. + + Additional functions include length(), normalize(), homogenize for + vectors, and print(), set(), apply() for all classes. + + There is a function transpose() for matrices, but note that it + does not actually change the matrix, + + When multiplied with a matrix, a vector is treated as a row vector + if it precedes the matrix (v*M), and as a column vector if it + follows the matrix (M*v). + + Matrices are stored in row-major form. + + A vector of one dimension (2d, 3d, or 4d) can be cast to a vector + of a higher or lower dimension. If casting to a higher dimension, + the new component is set by default to 1.0, unless a value is + specified: + vec3 a(1.0, 2.0, 3.0 ); + vec4 b( a, 4.0 ); // now b == {1.0, 2.0, 3.0, 4.0}; + When casting to a lower dimension, the vector is homogenized in + the lower dimension. E.g., if a 4d {X,Y,Z,W} is cast to 3d, the + resulting vector is {X/W, Y/W, Z/W}. It is up to the user to + insure the fourth component is not zero before casting. + + There are also the following function for building matrices: + identity2D(), translation2D(), rotation2D(), + scaling2D(), identity3D(), translation3D(), + rotation3D(), rotation3Drad(), scaling3D(), + perspective3D() + + NOTE: When compiling for Windows, include this file first, to avoid + certain name conflicts + + --------------------------------------------------------------------- + + Author: Jean-Francois DOUEg + Revised: Paul Rademacher + Version 3.2 - Feb 1998 + Revised: Nigel Stewart (GLUI Code Cleaning) + +**************************************************************************/ + +#ifndef GLUI_ALGEBRA3_H +#define GLUI_ALGEBRA3_H + +#include +#include +#include + +// this line defines a new type: pointer to a function which returns a +// float and takes as argument a float +typedef float (*V_FCT_PTR)(float); + +class vec2; +class vec3; +class vec4; +class mat3; +class mat4; + +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +enum {VX, VY, VZ, VW}; // axes +enum {PA, PB, PC, PD}; // planes +enum {RED, GREEN, BLUE, ALPHA}; // colors +enum {KA, KD, KS, ES}; // phong coefficients + +/**************************************************************** + * * + * 2D Vector * + * * + ****************************************************************/ + +class vec2 +{ + friend class vec3; + +protected: + + float n[2]; + +public: + + // Constructors + + vec2(); + vec2(float x, float y); + vec2(const vec2 &v); // copy constructor + vec2(const vec3 &v); // cast v3 to v2 + vec2(const vec3 &v, int dropAxis); // cast v3 to v2 + + // Assignment operators + + vec2 &operator = (const vec2 &v); // assignment of a vec2 + vec2 &operator += (const vec2 &v); // incrementation by a vec2 + vec2 &operator -= (const vec2 &v); // decrementation by a vec2 + vec2 &operator *= (float d); // multiplication by a constant + vec2 &operator /= (float d); // division by a constant + + // special functions + + float length() const; // length of a vec2 + float length2() const; // squared length of a vec2 + vec2 &normalize(); // normalize a vec2 + vec2 &apply(V_FCT_PTR fct); // apply a func. to each component + void set(float x, float y); // set vector + + float &operator [] (int i); // indexing + const float &operator [] (int i) const; // indexing + + // friends + + friend vec2 operator - (const vec2 &v); // -v1 + friend vec2 operator + (const vec2 &a, const vec2 &b); // v1 + v2 + friend vec2 operator - (const vec2 &a, const vec2 &b); // v1 - v2 + friend vec2 operator * (const vec2 &a, float d); // v1 * 3.0 + friend vec2 operator * (float d, const vec2 &a); // 3.0 * v1 + friend vec2 operator * (const mat3 &a, const vec2 &v); // M . v + friend vec2 operator * (const vec2 &v, const mat3 &a); // v . M + friend float operator * (const vec2 &a, const vec2 &b); // dot product + friend vec2 operator / (const vec2 &a, float d); // v1 / 3.0 + friend vec3 operator ^ (const vec2 &a, const vec2 &b); // cross product + friend int operator == (const vec2 &a, const vec2 &b); // v1 == v2 ? + friend int operator != (const vec2 &a, const vec2 &b); // v1 != v2 ? + //friend ostream& operator << (ostream& s, vec2& v); // output to stream + //friend istream& operator >> (istream& s, vec2& v); // input from strm. + friend void swap(vec2 &a, vec2 &b); // swap v1 & v2 + friend vec2 min_vec(const vec2 &a, const vec2 &b); // min(v1, v2) + friend vec2 max_vec(const vec2 &a, const vec2 &b); // max(v1, v2) + friend vec2 prod (const vec2 &a, const vec2 &b); // term by term * +}; + +/**************************************************************** + * * + * 3D Vector * + * * + ****************************************************************/ + +class vec3 +{ + friend class vec2; + friend class vec4; + friend class mat3; + +protected: + + float n[3]; + +public: + + // Constructors + + vec3(); + vec3(float x, float y, float z); + vec3(const vec3 &v); // copy constructor + vec3(const vec2 &v); // cast v2 to v3 + vec3(const vec2 &v, float d); // cast v2 to v3 + vec3(const vec4 &v); // cast v4 to v3 + vec3(const vec4 &v, int dropAxis); // cast v4 to v3 + + // Assignment operators + + vec3 &operator = (const vec3 &v); // assignment of a vec3 + vec3 &operator += (const vec3 &v); // incrementation by a vec3 + vec3 &operator -= (const vec3 &v); // decrementation by a vec3 + vec3 &operator *= (float d); // multiplication by a constant + vec3 &operator /= (float d); // division by a constant + + // special functions + + float length() const; // length of a vec3 + float length2() const; // squared length of a vec3 + vec3& normalize(); // normalize a vec3 + vec3& homogenize(); // homogenize (div by Z) + vec3& apply(V_FCT_PTR fct); // apply a func. to each component + void set(float x, float y, float z); // set vector + + void print(FILE *file, const char *name) const; // print vector to a file + + + float &operator [] (int i); // indexing + const float &operator [] (int i) const; // indexing + + // friends + + friend vec3 operator - (const vec3 &v); // -v1 + friend vec3 operator + (const vec3 &a, const vec3 &b); // v1 + v2 + friend vec3 operator - (const vec3 &a, const vec3 &b); // v1 - v2 + friend vec3 operator * (const vec3 &a, float d); // v1 * 3.0 + friend vec3 operator * (float d, const vec3 &a); // 3.0 * v1 + friend vec3 operator * (const mat4 &a, const vec3 &v); // M . v + friend vec3 operator * (const vec3 &v, const mat4 &a); // v . M + friend float operator * (const vec3 &a, const vec3 &b); // dot product + friend vec3 operator / (const vec3 &a, float d); // v1 / 3.0 + friend vec3 operator ^ (const vec3 &a, const vec3 &b); // cross product + friend int operator == (const vec3 &a, const vec3 &b); // v1 == v2 ? + friend int operator != (const vec3 &a, const vec3 &b); // v1 != v2 ? + //friend ostream& operator << (ostream& s, vec3& v); // output to stream + //friend istream& operator >> (istream& s, vec3& v); // input from strm. + friend void swap(vec3 &a, vec3 &b); // swap v1 & v2 + friend vec3 min_vec(const vec3 &a, const vec3 &b); // min(v1, v2) + friend vec3 max_vec(const vec3 &a, const vec3 &b); // max(v1, v2) + friend vec3 prod(const vec3 &a, const vec3 &b); // term by term * + + // necessary friend declarations + + friend vec2 operator * (const mat3 &a, const vec2 &v); // linear transform + friend vec3 operator * (const mat3 &a, const vec3 &v); // linear transform + friend mat3 operator * (const mat3 &a, const mat3 &b); // matrix 3 product +}; + +/**************************************************************** + * * + * 4D Vector * + * * + ****************************************************************/ + +class vec4 +{ + friend class vec3; + friend class mat4; + +protected: + + float n[4]; + +public: + + // Constructors + + vec4(); + vec4(float x, float y, float z, float w); + vec4(const vec4 &v); // copy constructor + vec4(const vec3 &v); // cast vec3 to vec4 + vec4(const vec3 &v, float d); // cast vec3 to vec4 + + // Assignment operators + + vec4 &operator = (const vec4 &v); // assignment of a vec4 + vec4 &operator += (const vec4 &v); // incrementation by a vec4 + vec4 &operator -= (const vec4 &v); // decrementation by a vec4 + vec4 &operator *= (float d); // multiplication by a constant + vec4 &operator /= (float d); // division by a constant + + // special functions + + float length() const; // length of a vec4 + float length2() const; // squared length of a vec4 + vec4 &normalize(); // normalize a vec4 + vec4 &apply(V_FCT_PTR fct); // apply a func. to each component + vec4 &homogenize(); + + void print(FILE *file, const char *name) const; // print vector to a file + + void set(float x, float y, float z, float a); + + float &operator [] (int i); // indexing + const float &operator [] (int i) const; // indexing + + // friends + + friend vec4 operator - (const vec4 &v); // -v1 + friend vec4 operator + (const vec4 &a, const vec4 &b); // v1 + v2 + friend vec4 operator - (const vec4 &a, const vec4 &b); // v1 - v2 + friend vec4 operator * (const vec4 &a, float d); // v1 * 3.0 + friend vec4 operator * (float d, const vec4 &a); // 3.0 * v1 + friend vec4 operator * (const mat4 &a, const vec4 &v); // M . v + friend vec4 operator * (const vec4 &v, const mat4 &a); // v . M + friend float operator * (const vec4 &a, const vec4 &b); // dot product + friend vec4 operator / (const vec4 &a, float d); // v1 / 3.0 + friend int operator == (const vec4 &a, const vec4 &b); // v1 == v2 ? + friend int operator != (const vec4 &a, const vec4 &b); // v1 != v2 ? + //friend ostream& operator << (ostream& s, vec4& v); // output to stream + //friend istream& operator >> (istream& s, vec4& v); // input from strm. + friend void swap(vec4 &a, vec4 &b); // swap v1 & v2 + friend vec4 min_vec(const vec4 &a, const vec4 &b); // min(v1, v2) + friend vec4 max_vec(const vec4 &a, const vec4 &b); // max(v1, v2) + friend vec4 prod (const vec4 &a, const vec4 &b); // term by term * + + // necessary friend declarations + + friend vec3 operator * (const mat4 &a, const vec3 &v); // linear transform + friend mat4 operator * (const mat4 &a, const mat4 &b); // matrix 4 product +}; + +/**************************************************************** + * * + * 3x3 Matrix * + * * + ****************************************************************/ + +class mat3 +{ +protected: + + vec3 v[3]; + +public: + + // Constructors + + mat3(); + mat3(const vec3 &v0, const vec3 &v1, const vec3 &v2); + mat3(const mat3 &m); + + // Assignment operators + + mat3 &operator = (const mat3 &m); // assignment of a mat3 + mat3 &operator += (const mat3 &m); // incrementation by a mat3 + mat3 &operator -= (const mat3 &m); // decrementation by a mat3 + mat3 &operator *= (float d); // multiplication by a constant + mat3 &operator /= (float d); // division by a constant + + // special functions + + mat3 transpose() const; // transpose + mat3 inverse() const; // inverse + mat3 &apply(V_FCT_PTR fct); // apply a func. to each element + + void print(FILE *file, const char *name ) const; // print matrix to a file + + void set(const vec3 &v0, const vec3 &v1, const vec3 &v2); + + vec3 &operator [] (int i); // indexing + const vec3 &operator [] (int i) const; // indexing + + // friends + + friend mat3 operator - (const mat3 &a); // -m1 + friend mat3 operator + (const mat3 &a, const mat3 &b); // m1 + m2 + friend mat3 operator - (const mat3 &a, const mat3 &b); // m1 - m2 + friend mat3 operator * (const mat3 &a, const mat3 &b); // m1 * m2 + friend mat3 operator * (const mat3 &a, float d); // m1 * 3.0 + friend mat3 operator * (float d, const mat3 &a); // 3.0 * m1 + friend mat3 operator / (const mat3 &a, float d); // m1 / 3.0 + friend int operator == (const mat3 &a, const mat3 &b); // m1 == m2 ? + friend int operator != (const mat3 &a, const mat3 &b); // m1 != m2 ? + //friend ostream& operator << (ostream& s, mat3& m); // output to stream + //friend istream& operator >> (istream& s, mat3& m); // input from strm. + friend void swap(mat3 &a, mat3 &b); // swap m1 & m2 + + // necessary friend declarations + + friend vec3 operator * (const mat3 &a, const vec3 &v); // linear transform + friend vec2 operator * (const mat3 &a, const vec2 &v); // linear transform +}; + +/**************************************************************** + * * + * 4x4 Matrix * + * * + ****************************************************************/ + +class mat4 +{ +protected: + + vec4 v[4]; + +public: + + // Constructors + + mat4(); + mat4(const vec4 &v0, const vec4 &v1, const vec4 &v2, const vec4 &v3); + mat4(const mat4 &m); + mat4(float a00, float a01, float a02, float a03, + float a10, float a11, float a12, float a13, + float a20, float a21, float a22, float a23, + float a30, float a31, float a32, float a33 ); + + + // Assignment operators + + mat4 &operator = (const mat4 &m); // assignment of a mat4 + mat4 &operator += (const mat4 &m); // incrementation by a mat4 + mat4 &operator -= (const mat4 &m); // decrementation by a mat4 + mat4 &operator *= (float d); // multiplication by a constant + mat4 &operator /= (float d); // division by a constant + + // special functions + + mat4 transpose() const; // transpose + mat4 inverse() const; // inverse + mat4 &apply(V_FCT_PTR fct); // apply a func. to each element + + void print(FILE *file, const char *name) const; // print matrix to a file + + vec4 &operator [] (int i); // indexing + const vec4 &operator [] (int i) const; // indexing + + void swap_rows(int i, int j); // swap rows i and j + void swap_cols(int i, int j); // swap cols i and j + + // friends + + friend mat4 operator - (const mat4 &a); // -m1 + friend mat4 operator + (const mat4 &a, const mat4 &b); // m1 + m2 + friend mat4 operator - (const mat4 &a, const mat4 &b); // m1 - m2 + friend mat4 operator * (const mat4 &a, const mat4 &b); // m1 * m2 + friend mat4 operator * (const mat4 &a, float d); // m1 * 4.0 + friend mat4 operator * (float d, const mat4 &a); // 4.0 * m1 + friend mat4 operator / (const mat4 &a, float d); // m1 / 3.0 + friend int operator == (const mat4 &a, const mat4 &b); // m1 == m2 ? + friend int operator != (const mat4 &a, const mat4 &b); // m1 != m2 ? + //friend ostream& operator << (ostream& s, mat4& m); // output to stream + //friend istream& operator >> (istream& s, mat4& m); // input from strm. + friend void swap(mat4 &a, mat4 &b); // swap m1 & m2 + + // necessary friend declarations + + friend vec4 operator * (const mat4 &a, const vec4 &v); // linear transform + //friend vec4 operator * (const vec4& v, const mat4& a); // linear transform + friend vec3 operator * (const mat4 &a, const vec3 &v); // linear transform + friend vec3 operator * (const vec3 &v, const mat4 &a); // linear transform +}; + +/**************************************************************** + * * + * 2D functions and 3D functions * + * * + ****************************************************************/ + +mat3 identity2D (); // identity 2D +mat3 translation2D(const vec2 &v); // translation 2D +mat3 rotation2D (const vec2 &Center, float angleDeg); // rotation 2D +mat3 scaling2D (const vec2 &scaleVector); // scaling 2D +mat4 identity3D (); // identity 3D +mat4 translation3D(const vec3 &v); // translation 3D +mat4 rotation3D (const vec3 &Axis, float angleDeg); // rotation 3D +mat4 rotation3Drad(const vec3 &Axis, float angleRad); // rotation 3D +mat4 scaling3D (const vec3 &scaleVector); // scaling 3D +mat4 perspective3D(float d); // perspective 3D + +vec3 operator * (const vec3 &v, const mat3 &a); +vec2 operator * (const vec2 &v, const mat3 &a); +vec3 operator * (const vec3 &v, const mat4 &a); +vec4 operator * (const vec4 &v, const mat4 &a); + +#endif diff --git a/tests/Box2D_v2.2.1/glui/arcball.cpp b/tests/Box2D_v2.2.1/glui/arcball.cpp new file mode 100755 index 0000000000000..d233c7fc0c807 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/arcball.cpp @@ -0,0 +1,237 @@ +/********************************************************************** + + arcball.cpp + + + -------------------------------------------------- + + GLUI User Interface Toolkit (LGPL) + Copyright (c) 1998 Paul Rademacher + Feb 1998, Paul Rademacher (rademach@cs.unc.edu) + Oct 2003, Nigel Stewart - GLUI Code Cleaning + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +**********************************************************************/ + +#include "arcball.h" + +#include + + +/**************************************** Arcball::Arcball() ****/ +/* Default (void) constructor for Arcball */ + +Arcball::Arcball() +{ + rot_ptr = &rot; + init(); +} + +/**************************************** Arcball::Arcball() ****/ +/* Takes as argument a mat4 to use instead of the internal rot */ + +Arcball::Arcball(mat4 *mtx) +{ + rot_ptr = mtx; +} + + +/**************************************** Arcball::Arcball() ****/ +/* A constructor that accepts the screen center and arcball radius*/ + +Arcball::Arcball(const vec2 &_center, float _radius) +{ + rot_ptr = &rot; + init(); + set_params(_center, _radius); +} + + +/************************************** Arcball::set_params() ****/ + +void Arcball::set_params(const vec2 &_center, float _radius) +{ + center = _center; + radius = _radius; +} + +/*************************************** Arcball::init() **********/ + +void Arcball::init() +{ + center.set( 0.0, 0.0 ); + radius = 1.0; + q_now = quat_identity(); + *rot_ptr = identity3D(); + q_increment = quat_identity(); + rot_increment = identity3D(); + is_mouse_down = false; + is_spinning = false; + damp_factor = 0.0; + zero_increment = true; +} + +/*********************************** Arcball::mouse_to_sphere() ****/ + +vec3 Arcball::mouse_to_sphere(const vec2 &p) +{ + float mag; + vec2 v2 = (p - center) / radius; + vec3 v3( v2[0], v2[1], 0.0 ); + + mag = v2*v2; + + if ( mag > 1.0 ) + v3.normalize(); + else + v3[VZ] = (float) sqrt( 1.0 - mag ); + + /* Now we add constraints - X takes precedence over Y */ + if ( constraint_x ) + { + v3 = constrain_vector( v3, vec3( 1.0, 0.0, 0.0 )); + } + else if ( constraint_y ) + { + v3 = constrain_vector( v3, vec3( 0.0, 1.0, 0.0 )); + } + + return v3; +} + + +/************************************ Arcball::constrain_vector() ****/ + +vec3 Arcball::constrain_vector(const vec3 &vector, const vec3 &axis) +{ + return (vector-(vector*axis)*axis).normalize(); +} + +/************************************ Arcball::mouse_down() **********/ + +void Arcball::mouse_down(int x, int y) +{ + down_pt.set( (float)x, (float) y ); + is_mouse_down = true; + + q_increment = quat_identity(); + rot_increment = identity3D(); + zero_increment = true; +} + + +/************************************ Arcball::mouse_up() **********/ + +void Arcball::mouse_up() +{ + q_now = q_drag * q_now; + is_mouse_down = false; +} + + +/********************************** Arcball::mouse_motion() **********/ + +void Arcball::mouse_motion(int x, int y, int shift, int ctrl, int alt) +{ + /* Set the X constraint if CONTROL key is pressed, Y if ALT key */ + set_constraints( ctrl != 0, alt != 0 ); + + vec2 new_pt( (float)x, (float) y ); + vec3 v0 = mouse_to_sphere( down_pt ); + vec3 v1 = mouse_to_sphere( new_pt ); + + vec3 cross = v0^v1; + + q_drag.set( cross, v0 * v1 ); + + // *rot_ptr = (q_drag * q_now).to_mat4(); + mat4 temp = q_drag.to_mat4(); + *rot_ptr = *rot_ptr * temp; + + down_pt = new_pt; + + /* We keep a copy of the current incremental rotation (= q_drag) */ + q_increment = q_drag; + rot_increment = q_increment.to_mat4(); + + set_constraints(false, false); + + if ( q_increment.s < .999999 ) + { + is_spinning = true; + zero_increment = false; + } + else + { + is_spinning = false; + zero_increment = true; + } +} + + +/********************************** Arcball::mouse_motion() **********/ + +void Arcball::mouse_motion(int x, int y) +{ + mouse_motion(x, y, 0, 0, 0); +} + + +/***************************** Arcball::set_constraints() **********/ + +void Arcball::set_constraints(bool _constraint_x, bool _constraint_y) +{ + constraint_x = _constraint_x; + constraint_y = _constraint_y; +} + +/***************************** Arcball::idle() *********************/ + +void Arcball::idle() +{ + if (is_mouse_down) + { + is_spinning = false; + zero_increment = true; + } + + if (damp_factor < 1.0f) + q_increment.scale_angle(1.0f - damp_factor); + + rot_increment = q_increment.to_mat4(); + + if (q_increment.s >= .999999f) + { + is_spinning = false; + zero_increment = true; + } +} + + +/************************ Arcball::set_damping() *********************/ + +void Arcball::set_damping(float d) +{ + damp_factor = d; +} + + + + + diff --git a/tests/Box2D_v2.2.1/glui/arcball.h b/tests/Box2D_v2.2.1/glui/arcball.h new file mode 100755 index 0000000000000..ef69afc9587ca --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/arcball.h @@ -0,0 +1,97 @@ +/********************************************************************** + + arcball.h + + GLUI User Interface Toolkit (LGPL) + Copyright (c) 1998 Paul Rademacher + Feb 1998, Paul Rademacher (rademach@cs.unc.edu) + Oct 2003, Nigel Stewart - GLUI Code Cleaning + + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + --------------------------------------------------------------------- + + A C++ class that implements the Arcball, as described by Ken + Shoemake in Graphics Gems IV. + This class takes as input mouse events (mouse down, mouse drag, + mouse up), and creates the appropriate quaternions and 4x4 matrices + to represent the rotation given by the mouse. + + This class is used as follows: + - initialize [either in the constructor or with set_params()], the + center position (x,y) of the arcball on the screen, and the radius + - on mouse down, call mouse_down(x,y) with the mouse position + - as the mouse is dragged, repeatedly call mouse_motion() with the + current x and y positions. One can optionally pass in the current + state of the SHIFT, ALT, and CONTROL keys (passing zero if keys + are not pressed, non-zero otherwise), which constrains + the rotation to certain axes (X for CONTROL, Y for ALT). + - when the mouse button is released, call mouse_up() + + Axis constraints can also be explicitly set with the + set_constraints() function. + + The current rotation is stored in the 4x4 float matrix 'rot'. + It is also stored in the quaternion 'q_now'. + +**********************************************************************/ + +#ifndef GLUI_ARCBALL_H +#define GLUI_ARCBALL_H + +#include "glui_internal.h" +#include "algebra3.h" +#include "quaternion.h" + +class Arcball +{ +public: + Arcball(); + Arcball(mat4 *mtx); + Arcball(const vec2 ¢er, float radius); + + void set_damping(float d); + void idle(); + void mouse_down(int x, int y); + void mouse_up(); + void mouse_motion(int x, int y, int shift, int ctrl, int alt); + void mouse_motion(int x, int y); + void set_constraints(bool constrain_x, bool constrain_y); + void set_params(const vec2 ¢er, float radius); + void reset_mouse(); + void init(); + + vec3 constrain_vector(const vec3 &vector, const vec3 &axis); + vec3 mouse_to_sphere(const vec2 &p); + + //public: + int is_mouse_down; /* true for down, false for up */ + int is_spinning; + quat q_now, q_down, q_drag, q_increment; + vec2 down_pt; + mat4 rot, rot_increment; + mat4 *rot_ptr; + + bool constraint_x, constraint_y; + vec2 center; + float radius, damp_factor; + int zero_increment; +}; + +#endif diff --git a/tests/Box2D_v2.2.1/glui/glui.cpp b/tests/Box2D_v2.2.1/glui/glui.cpp new file mode 100755 index 0000000000000..221e68d2cec83 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui.cpp @@ -0,0 +1,2105 @@ +/**************************************************************************** + + GLUI User Interface Toolkit (LGPL) + --------------------------- + + glui.cpp + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ +#include "glui_internal_control.h" + + +/** + Note: moving this routine here from glui_add_controls.cpp prevents the linker + from touching glui_add_controls.o in non-deprecated programs, which + descreases the linked size of small GLUI programs substantially (100K+). (OSL 2006/06) +*/ +void GLUI_Node::add_child_to_control(GLUI_Node *parent,GLUI_Control *child) +{ + GLUI_Control *parent_control; + + /*** Collapsible nodes have to be handled differently, b/c the first and + last children are swapped in and out ***/ + parent_control = ((GLUI_Control*)parent); + if ( parent_control->collapsible == true ) { + if ( NOT parent_control->is_open ) { + /** Swap in the original first and last children **/ + parent_control->child_head = parent_control->collapsed_node.child_head; + parent_control->child_tail = parent_control->collapsed_node.child_tail; + + /*** Link this control ***/ + child->link_this_to_parent_last( parent_control ); + + /** Swap the children back out ***/ + parent_control->collapsed_node.child_head = parent_control->child_head; + parent_control->collapsed_node.child_tail = parent_control->child_tail; + parent_control->child_head = NULL; + parent_control->child_tail = NULL; + } + else { + child->link_this_to_parent_last( parent_control ); + } + } + else { + child->link_this_to_parent_last( parent_control ); + } + child->glui = (GLUI*) parent_control->glui; + child->update_size(); + child->enabled = parent_control->enabled; + child->glui->refresh(); + + /** Now set the 'hidden' var based on the parent **/ + if ( parent_control->hidden OR + (parent_control->collapsible AND NOT parent_control->is_open ) ) + { + child->hidden = true; + } +} + + +/************************************ GLUI_Node::add_control() **************/ + +int GLUI_Node::add_control( GLUI_Control *child ) +{ + add_child_to_control(this,child); + return true; +} + +/************************************ GLUI_Main::add_control() **************/ + +int GLUI_Main::add_control( GLUI_Node *parent, GLUI_Control *control ) +{ + add_child_to_control(parent,control); + return true; +} + + + +/*** This object must be used to create a GLUI ***/ + +GLUI_Master_Object GLUI_Master; + +/************************************ finish_drawing() *********** + Probably a silly routine. Called after all event handling callbacks. +*/ + +static void finish_drawing(void) +{ + glFinish(); +} + +/************************************ GLUI_CB::operator()() ************/ +void GLUI_CB::operator()(GLUI_Control*ctrl) const +{ + if (idCB) idCB(ctrl->user_id); + if (objCB) objCB(ctrl); +} + + +/************************************************ GLUI::GLUI() **********/ + +int GLUI::init( const char *text, long flags, int x, int y, int parent_window ) +{ + int old_glut_window; + + this->flags = flags; + + window_name = text; + + buffer_mode = buffer_back; ///< New smooth way + //buffer_mode = buffer_front; ///< Old flickery way (a bit faster). + + /*** We copy over the current window callthroughs ***/ + /*** (I think this might actually only be needed for subwindows) ***/ + /* glut_keyboard_CB = GLUI_Master.glut_keyboard_CB; + glut_reshape_CB = GLUI_Master.glut_reshape_CB; + glut_special_CB = GLUI_Master.glut_special_CB; + glut_mouse_CB = GLUI_Master.glut_mouse_CB;*/ + + + if ( (flags & GLUI_SUBWINDOW) != GLUI_SUBWINDOW ) { /* not a subwindow, creating a new top-level window */ + old_glut_window = glutGetWindow(); + + create_standalone_window( window_name.c_str(), x, y ); + setup_default_glut_callbacks(); + + if ( old_glut_window > 0 ) + glutSetWindow( old_glut_window ); + + top_level_glut_window_id = glut_window_id; + } + else /* *is* a subwindow */ + { + old_glut_window = glutGetWindow(); + + create_subwindow( parent_window, flags ); + setup_default_glut_callbacks(); + + if ( old_glut_window > 0 ) + glutSetWindow( old_glut_window ); + + top_level_glut_window_id = parent_window; + + /* + glutReshapeFunc( glui_parent_window_reshape_func ); + glutSpecialFunc( glui_parent_window_special_func ); + glutKeyboardFunc( glui_parent_window_keyboard_func ); + glutMouseFunc( glui_parent_window_mouse_func ); + */ + + } + + return true; +} + + +/**************************** GLUI_Main::create_standalone_window() ********/ + +void GLUI_Main::create_standalone_window( const char *name, int x, int y ) +{ + glutInitWindowSize( 100, 100 ); + if ( x >= 0 OR y >= 0 ) + glutInitWindowPosition( x, y ); + glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE ); + glut_window_id = glutCreateWindow( name ); +} + + +/******************************** GLUI_Main::create_subwindow() **********/ + +void GLUI_Main::create_subwindow( int parent_window, int window_alignment ) +{ + glut_window_id = glutCreateSubWindow(parent_window, 0,0, 100, 100); + this->parent_window = parent_window; +} + + +/**************************** GLUI_Main::setup_default_glut_callbacks() *****/ + +void GLUI_Main::setup_default_glut_callbacks( void ) +{ + glutDisplayFunc( glui_display_func ); + glutReshapeFunc( glui_reshape_func ); + glutKeyboardFunc( glui_keyboard_func ); + glutSpecialFunc( glui_special_func ); + glutMouseFunc( glui_mouse_func ); + glutMotionFunc( glui_motion_func ); + glutPassiveMotionFunc( glui_passive_motion_func ); + glutEntryFunc( glui_entry_func ); + glutVisibilityFunc( glui_visibility_func ); + /* glutIdleFunc( glui_idle_func ); // FIXME! 100% CPU usage! */ +} + + +/********************************************** glui_display_func() ********/ + +void glui_display_func(void) +{ + GLUI *glui; + + /* printf( "display func\n" ); */ + + glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() ); + + if ( glui ) { + glui->display(); + /* + Do not do anything after the above line, b/c the GLUI + window might have just closed itself + */ + } +} + + +/********************************************** glui_reshape_func() ********/ + +void glui_reshape_func(int w,int h ) +{ + GLUI *glui; + GLUI_Glut_Window *glut_window; + int current_window; + + /*printf( "glui_reshape_func(): %d w/h: %d/%d\n", glutGetWindow(), w, h ); */ + + current_window = glutGetWindow(); + + /*** First check if this is main glut window ***/ + glut_window = GLUI_Master.find_glut_window( current_window ); + if ( glut_window ) { + if (glut_window->glut_reshape_CB) glut_window->glut_reshape_CB(w,h); + + /*** Now send reshape events to all subwindows ***/ + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while(glui) { + if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND + glui->parent_window == current_window ) { + glutSetWindow( glui->get_glut_window_id()); + glui->reshape(w,h); + /* glui->check_subwindow_position(); */ + } + glui = (GLUI*) glui->next(); + } + } + else { + /*** A standalone GLUI window ***/ + + glui = GLUI_Master.find_glui_by_window_id( current_window ); + + if ( glui ) { + glui->reshape(w,h); + } + } +} + +/********************************************** glui_keyboard_func() ********/ + +void glui_keyboard_func(unsigned char key, int x, int y) +{ + GLUI *glui; + int current_window; + GLUI_Glut_Window *glut_window; + + current_window = glutGetWindow(); + glut_window = GLUI_Master.find_glut_window( current_window ); + + /*printf( "key: %d\n", current_window ); */ + + if ( glut_window ) { /** Was event in a GLUT window? **/ + if ( GLUI_Master.active_control_glui AND GLUI_Master.active_control ) { + glutSetWindow( GLUI_Master.active_control_glui->get_glut_window_id() ); + + GLUI_Master.active_control_glui->keyboard(key,x,y); + finish_drawing(); + + glutSetWindow( current_window ); + } + else { + if (glut_window->glut_keyboard_CB) + glut_window->glut_keyboard_CB( key, x, y ); + } + } + else { /*** Nope, event was in a standalone GLUI window **/ + glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() ); + + if ( glui ) { + glui->keyboard(key,x,y); + finish_drawing(); + } + } +} + + +/************************************************ glui_special_func() ********/ + +void glui_special_func(int key, int x, int y) +{ + GLUI *glui; + int current_window; + GLUI_Glut_Window *glut_window; + + current_window = glutGetWindow(); + glut_window = GLUI_Master.find_glut_window( current_window ); + + if (glut_window) /** Was event in a GLUT window? **/ + { + if ( GLUI_Master.active_control_glui AND GLUI_Master.active_control ) + { + glutSetWindow( GLUI_Master.active_control_glui->get_glut_window_id() ); + + GLUI_Master.active_control_glui->special(key,x,y); + finish_drawing(); + + glutSetWindow( current_window ); + } + else + { + if (glut_window->glut_special_CB) + glut_window->glut_special_CB( key, x, y ); + } + } + else /*** Nope, event was in a standalone GLUI window **/ + { + glui = GLUI_Master.find_glui_by_window_id(glutGetWindow()); + + if ( glui ) + { + glui->special(key,x,y); + finish_drawing(); + } + } +} + +/********************************************** glui_mouse_func() ********/ + +void glui_mouse_func(int button, int state, int x, int y) +{ + GLUI *glui; + int current_window; + GLUI_Glut_Window *glut_window; + + current_window = glutGetWindow(); + glut_window = GLUI_Master.find_glut_window( current_window ); + + if ( glut_window ) { /** Was event in a GLUT window? **/ + if ( GLUI_Master.active_control_glui != NULL ) + GLUI_Master.active_control_glui->deactivate_current_control(); + + if (glut_window->glut_mouse_CB) + glut_window->glut_mouse_CB( button, state, x, y ); + finish_drawing(); + } + else { /** Nope - event was in a GLUI standalone window **/ + glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() ); + if ( glui ) { + glui->passive_motion( 0,0 ); + glui->mouse( button, state, x, y ); + finish_drawing(); + } + } +} + + +/********************************************** glui_motion_func() ********/ + +void glui_motion_func(int x, int y) +{ + GLUI *glui; + + glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() ); + + if ( glui ) { + glui->motion(x,y); + finish_drawing(); + } + +} + + +/**************************************** glui_passive_motion_func() ********/ + +void glui_passive_motion_func(int x, int y) +{ + GLUI *glui; + + glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() ); + + if ( glui ) { + glui->passive_motion(x,y); + finish_drawing(); + } +} + + +/********************************************** glui_entry_func() ********/ + +void glui_entry_func(int state) +{ + GLUI *glui; + + glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() ); + + if ( glui ) { + glui->entry(state); + } +} + + +/******************************************** glui_visibility_func() ********/ + +void glui_visibility_func(int state) +{ + GLUI *glui; + + /* printf( "IN GLUI VISIBILITY()\n" ); */ + /* fflush( stdout ); */ + + glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() ); + + if ( glui ) { + glui->visibility(state); + } +} + + +/********************************************** glui_idle_func() ********/ +/* Send idle event to each glui, then to the main window */ + +void glui_idle_func(void) +{ + GLUI *glui; + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + glui->idle(); + finish_drawing(); + + glui = (GLUI*) glui->next(); + } + + if ( GLUI_Master.glut_idle_CB ) { + /*** We set the current glut window before calling the user's + idle function, even though glut explicitly says the window id is + undefined in an idle callback. ***/ + + /** Check what the current window is first ***/ + + /*** Arbitrarily set the window id to the main gfx window of the + first glui window ***/ + /* int current_window, new_window; */ + /* current_window = glutGetWindow(); */ + /* if (GLUI_Master.gluis.first_child() != NULL ) { */ + /* new_window = ((GLUI_Main*)GLUI_Master.gluis.first_child())-> */ + /* main_gfx_window_id; */ + /* if ( new_window > 0 AND new_window != old_window ) { */ + /* --- Window is changed only if its not already the current window ---*/ + /* glutSetWindow( new_window ); */ + /* } */ + /*} */ + + GLUI_Master.glut_idle_CB(); + } +} + +/*********************************** GLUI_Master_Object::GLUI_Master_Object() ******/ + +GLUI_Master_Object::GLUI_Master_Object() +: glui_id_counter(1), + glut_idle_CB(NULL) +{ +} + +GLUI_Master_Object::~GLUI_Master_Object() +{ +} + +/*********************************** GLUI_Master_Object::create_glui() ******/ + +GLUI *GLUI_Master_Object::create_glui( const char *name, long flags,int x,int y ) +{ + GLUI *new_glui = new GLUI; + new_glui->init( name, flags, x, y, -1 ); + new_glui->link_this_to_parent_last( &this->gluis ); + return new_glui; +} + + +/************************** GLUI_Master_Object::create_glui_subwindow() ******/ + +GLUI *GLUI_Master_Object::create_glui_subwindow( int parent_window, + long flags ) +{ + GLUI *new_glui = new GLUI; + GLUI_String new_name; + glui_format_str( new_name, "subwin_%p", this ); + + new_glui->init( new_name.c_str(), flags | GLUI_SUBWINDOW, 0,0, + parent_window ); + new_glui->main_panel->set_int_val( GLUI_PANEL_EMBOSSED ); + new_glui->link_this_to_parent_last( &this->gluis ); + return new_glui; +} + + +/********************** GLUI_Master_Object::find_glui_by_window_id() ********/ + +GLUI *GLUI_Master_Object::find_glui_by_window_id( int window_id ) +{ + GLUI_Node *node; + + node = gluis.first_child(); + while( node ) { + if ( ((GLUI*)node)->get_glut_window_id() == window_id ) + return (GLUI*) node; + + node = node->next(); + } + return NULL; +} + + +/******************************************** GLUI_Main::display() **********/ + +void GLUI_Main::display( void ) +{ + int win_w, win_h; + + /* SUBTLE: on freeGLUT, the correct window is always already set. + But older versions of GLUT need this call, or else subwindows + don't update properly when resizing or damage-painting. + */ + glutSetWindow( glut_window_id ); + + /* Set up OpenGL state for widget drawing */ + glDisable( GL_DEPTH_TEST ); + glCullFace( GL_BACK ); + glDisable( GL_CULL_FACE ); + glDisable( GL_LIGHTING ); + set_current_draw_buffer(); + + /**** This function is used as a special place to do 'safe' processing, + e.g., handling window close requests. + That is, we can't close the window directly in the callback, so + we set a flag, post a redisplay message (which eventually calls + this function), then close the window safely in here. ****/ + if ( closing ) { + close_internal(); + return; + } + + /* if ( TEST_AND( this->flags, GLUI_SUBWINDOW )) + check_subwindow_position(); + */ + + win_w = glutGet( GLUT_WINDOW_WIDTH ); + win_h = glutGet( GLUT_WINDOW_HEIGHT ); + + /*** Check here if the window needs resizing ***/ + if ( win_w != main_panel->w OR win_h != main_panel->h ) { + glutReshapeWindow( main_panel->w, main_panel->h ); + return; + } + + /******* Draw GLUI window ******/ + glClearColor( (float) bkgd_color.r / 255.0, + (float) bkgd_color.g / 255.0, + (float) bkgd_color.b / 255.0, + 1.0 ); + glClear( GL_COLOR_BUFFER_BIT ); /* | GL_DEPTH_BUFFER_BIT ); */ + + set_ortho_projection(); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + /*** Rotate image so y increases downward. + In normal OpenGL, y increases upward. ***/ + glTranslatef( (float) win_w/2.0, (float) win_h/2.0, 0.0 ); + glRotatef( 180.0, 0.0, 1.0, 0.0 ); + glRotatef( 180.0, 0.0, 0.0, 1.0 ); + glTranslatef( (float) -win_w/2.0, (float) -win_h/2.0, 0.0 ); + + // Recursively draw the main panel + // main_panel->draw_bkgd_box( 0, 0, win_w, win_h ); + main_panel->draw_recursive( 0, 0 ); + + switch (buffer_mode) { + case buffer_front: /* Make sure drawing gets to screen */ + glFlush(); + break; + case buffer_back: /* Bring back buffer to front */ + glutSwapBuffers(); + break; + } +} + + + + +/*************************************** _glutBitmapWidthString() **********/ + +int _glutBitmapWidthString( void *font, const char *s ) +{ + const char *p = s; + int width = 0; + + while( *p != '\0' ) { + width += glutBitmapWidth( font, *p ); + p++; + } + + return width; +} + +/************************************ _glutBitmapString *********************/ +/* Displays the contents of a string using GLUT's bitmap character function */ +/* Does not handle newlines */ + +void _glutBitmapString( void *font, const char *s ) +{ + const char *p = s; + + while( *p != '\0' ) { + glutBitmapCharacter( font, *p ); + p++; + } +} + + + +/****************************** GLUI_Main::reshape() **************/ + +void GLUI_Main::reshape( int reshape_w, int reshape_h ) +{ + int new_w, new_h; + + pack_controls(); + + new_w = main_panel->w;/* + 1; */ + new_h = main_panel->h;/* + 1; */ + + if ( reshape_w != new_w OR reshape_h != new_h ) { + this->w = new_w; + this->h = new_h; + + glutReshapeWindow( new_w, new_h ); + } + else { + } + + if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) { + check_subwindow_position(); + + /***** if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) { + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) { + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) { + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_RIGHT )) { + } + ****/ + } + + glViewport( 0, 0, new_w, new_h ); + + /* printf( "%d: %d\n", glutGetWindow(), this->flags ); */ + + glutPostRedisplay(); +} + + +/****************************** GLUI_Main::keyboard() **************/ + +void GLUI_Main::keyboard(unsigned char key, int x, int y) +{ + GLUI_Control *new_control; + + curr_modifiers = glutGetModifiers(); + + /*** If it's a tab or shift tab, we don't pass it on to the controls. + Instead, we use it to cycle through active controls ***/ + if ( key == '\t' AND !mouse_button_down AND + (!active_control || !active_control->wants_tabs())) { + if ( curr_modifiers & GLUT_ACTIVE_SHIFT ) { + new_control = find_prev_control( active_control ); + } + else { + new_control = find_next_control( active_control ); + } + + /* if ( new_control ) + printf( "new_control: %s\n", new_control->name ); + */ + + deactivate_current_control(); + activate_control( new_control, GLUI_ACTIVATE_TAB ); + } + else if ( key == ' ' AND active_control + AND active_control->spacebar_mouse_click ) { + /*** If the user presses the spacebar, and a non-edittext control + is active, we send it a mouse down event followed by a mouse up + event (simulated mouse-click) ***/ + + active_control->mouse_down_handler( 0, 0 ); + active_control->mouse_up_handler( 0, 0, true ); + } else { + /*** Pass the keystroke onto the active control, if any ***/ + if ( active_control != NULL ) + active_control->key_handler( key, curr_modifiers ); + } +} + + +/****************************** GLUI_Main::special() **************/ + +void GLUI_Main::special(int key, int x, int y) +{ + curr_modifiers = glutGetModifiers(); + + /*** Pass the keystroke onto the active control, if any ***/ + if ( active_control != NULL ) + active_control->special_handler( key, glutGetModifiers() ); +} + + + +/****************************** GLUI_Main::mouse() **************/ + +void GLUI_Main::mouse(int button, int state, int x, int y) +{ + int callthrough; + GLUI_Control *control; + + /* printf( "MOUSE: %d %d\n", button, state ); */ + + callthrough = true; + + curr_modifiers = glutGetModifiers(); + + if ( button == GLUT_LEFT ) { + control = find_control( x, y ); + + /*if ( control ) printf( "control: %s\n", control->name.c_str() ); */ + + if ( mouse_button_down AND active_control != NULL AND + state == GLUT_UP ) + { + /** We just released the mouse, which was depressed at some control **/ + + callthrough = active_control-> + mouse_up_handler( x, y, control==active_control); + glutSetCursor( GLUT_CURSOR_LEFT_ARROW ); + + if ( active_control AND + active_control->active_type == GLUI_CONTROL_ACTIVE_MOUSEDOWN AND 0) + { + /*** This is a control that needs to be deactivated when the + mouse button is released ****/ + deactivate_current_control(); + } + } + else { + if ( control ) { + if ( NOT mouse_button_down AND state == GLUT_DOWN ) { + /*** We just pressed the mouse down at some control ***/ + + if ( active_control != control ) { + if ( active_control != NULL ) { + /** There is an active control still - deactivate it ***/ + deactivate_current_control(); + } + } + + if ( control->enabled ) { + activate_control( control, GLUI_ACTIVATE_MOUSE ); + callthrough = control->mouse_down_handler( x, y ); + } + } + } + } + + if ( state == GLUT_DOWN ) + mouse_button_down = true; + else if ( state == GLUT_UP ) + mouse_button_down = false; + } + + /** + NO CALLTHROUGH NEEDED FOR MOUSE EVENTS + if ( callthrough AND glut_mouse_CB ) + glut_mouse_CB( button, state, x, y ); + **/ + + callthrough=callthrough; /* To get rid of compiler warnings */ +} + + +/****************************** GLUI_Main::motion() **************/ + +void GLUI_Main::motion(int x, int y) +{ + int callthrough; + GLUI_Control *control; + + /* printf( "MOTION: %d %d\n", x, y ); */ + + callthrough = true; + + control = find_control(x,y); + + if ( mouse_button_down AND active_control != NULL ) { + callthrough = + active_control->mouse_held_down_handler(x,y,control==active_control); + } + + /** + NO CALLTHROUGH NEEDED FOR MOUSE EVENTS + + if ( callthrough AND glut_motion_CB ) + glut_motion_CB(x,y); + **/ + + callthrough=callthrough; /* To get rid of compiler warnings */ +} + + +/*********************** GLUI_Main::passive_motion() **************/ + +void GLUI_Main::passive_motion(int x, int y) +{ + GLUI_Control *control; + + control = find_control( x, y ); + + /* printf( "%p %p\n", control, mouse_over_control ); */ + + if ( control != mouse_over_control ) { + if ( mouse_over_control ) { + mouse_over_control->mouse_over( false, x, y ); + } + + if ( control ) { + control->mouse_over( true, x, y ); + mouse_over_control = control; + } + } + + /* + if ( curr_cursor != GLUT_CURSOR_INHERIT ) { + curr_cursor = GLUT_CURSOR_INHERIT; + glutSetCursor( GLUT_CURSOR_INHERIT ); + }*/ + +} + + +/****************************** GLUI_Main::entry() **************/ + +void GLUI_Main::entry(int state) +{ + /*if ( NOT active_control OR ( active_control AND ( active_control->type == GLUI_CONTROL_EDITTEXT + OR active_control->type == GLUI_CONTROL_SPINNER) ) )*/ + glutSetCursor( GLUT_CURSOR_LEFT_ARROW ); +} + + +/****************************** GLUI_Main::visibility() **************/ + +void GLUI_Main::visibility(int state) +{ +} + + +/****************************** GLUI_Main::idle() **************/ + +void GLUI_Main::idle(void) +{ + /*** Pass the idle event onto the active control, if any ***/ + + /* printf( "IDLE \t" ); */ + + if ( active_control != NULL ) { + /* First we check if the control actually needs the idle right now. + Otherwise, let's avoid wasting cycles and OpenGL context switching */ + + if ( active_control->needs_idle() ) { + /*** Set the current glut window to the glui window */ + /*** But don't change the window if we're already at that window ***/ + + if ( glut_window_id > 0 AND glutGetWindow() != glut_window_id ) { + glutSetWindow( glut_window_id ); + } + + active_control->idle(); + } + } +} + +int GLUI_Main::needs_idle( void ) +{ + return active_control != NULL && active_control->needs_idle(); +} + + +/******************************************* GLUI_Main::find_control() ******/ + +GLUI_Control *GLUI_Main::find_control( int x, int y ) +{ + GLUI_Control *node, *last_container; + + last_container = NULL; + + node = main_panel; + while( node != NULL ) { + if ( !dynamic_cast(node) AND + PT_IN_BOX( x, y, + node->x_abs, node->x_abs + node->w, + node->y_abs, node->y_abs + node->h ) + ) + { + /*** Point is inside current node ***/ + + if ( node->first_child() == NULL ) { + /*** SPECIAL CASE: for edittext boxes, we make sure click is + in box, and not on name string. This should be generalized + for all controls later... ***/ + if ( dynamic_cast(node) ) { + if ( x < node->x_abs + ((GLUI_EditText*)node)->text_x_offset ) + return (GLUI_Control*) node->parent(); + } + + return node; /* point is inside this node, and node has no children, + so return this node as the selected node */ + } + else { + /*** This is a container class ***/ + last_container = node; + node = (GLUI_Control*) node->first_child(); /* Descend into child */ + } + + } + else { + node = (GLUI_Control*) node->next(); + } + } + + /** No leaf-level nodes found to accept the mouse click, so + return the last container control found which DOES accept the click **/ + + if ( last_container ) { + /* printf( "ctrl: '%s'\n", last_container->name ); */ + + return last_container; + } + else { + return NULL; + } +} + + +/************************************* GLUI_Main::pack_controls() ***********/ + +void GLUI_Main::pack_controls( void ) +{ + main_panel->pack(0,0); + + /**** Now align controls within their bounds ****/ + align_controls( main_panel ); + + /*** If this is a subwindow, expand panel to fit parent window ***/ + if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) { + int parent_h, parent_w; + int orig_window; + + orig_window = glutGetWindow(); + glutSetWindow( this->top_level_glut_window_id ); + parent_h = glutGet( GLUT_WINDOW_HEIGHT ); + parent_w = glutGet( GLUT_WINDOW_WIDTH ); + + glutSetWindow( orig_window ); + + /* printf( "%d %d\n", parent_h, parent_w ); */ + + if ( 1 ) { + if ( TEST_AND(this->flags,GLUI_SUBWINDOW_TOP )) { + main_panel->w = MAX( main_panel->w, parent_w ); + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) { + main_panel->h = MAX( main_panel->h, parent_h ); + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_BOTTOM )) { + main_panel->w = MAX( main_panel->w, parent_w ); + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_RIGHT )) { + main_panel->h = MAX( main_panel->h, parent_h ); + } + } + } + + this->w = main_panel->w; + this->h = main_panel->h; +} + + +/************************************ GLUI_Main::align_controls() **********/ + +void GLUI_Main::align_controls( GLUI_Control *control ) +{ + GLUI_Control *child; + + control->align(); + + child = (GLUI_Control*) control->first_child(); + + while( child != NULL ) { + align_controls( child ); + + child = (GLUI_Control*)child->next(); + } +} + + + +/*********************************** GLUI::set_main_gfx_window() ************/ + +void GLUI::set_main_gfx_window( int window_id ) +{ + main_gfx_window_id = window_id; +} + + +/********************************* GLUI_Main::post_update_main_gfx() ********/ + +void GLUI_Main::post_update_main_gfx( void ) +{ + int old_window; + + if ( main_gfx_window_id > 0 ) { + old_window = glutGetWindow(); + glutSetWindow( main_gfx_window_id ); + glutPostRedisplay(); + if( old_window > 0 ) + glutSetWindow( old_window ); + } +} + +/********************************* GLUI_Main::should_redraw_now() ********/ +/** Return true if this control should redraw itself immediately (front buffer); + Or queue up a redraw and return false if it shouldn't (back buffer). + + Called from GLUI_Control::redraw. +*/ +bool GLUI_Main::should_redraw_now(GLUI_Control *ctl) +{ + switch (buffer_mode) { + case buffer_front: return true; /* always draw in front-buffer mode */ + case buffer_back: { + int orig = ctl->set_to_glut_window(); + glutPostRedisplay(); /* redraw soon */ + ctl->restore_window(orig); + return false; /* don't draw now. */ + } + } + return false; /* never executed */ +} + +/********************************* GLUI_Main::set_current_draw_buffer() ********/ + +int GLUI_Main::set_current_draw_buffer( void ) +{ + /* Save old buffer */ + GLint state; + glGetIntegerv( GL_DRAW_BUFFER, &state ); + /* Switch to new buffer */ + switch (buffer_mode) { + case buffer_front: glDrawBuffer(GL_FRONT); break; + case buffer_back: glDrawBuffer(GL_BACK); break; /* might not be needed... */ + } + return (int)state; +} + + +/********************************* GLUI_Main::restore_draw_buffer() **********/ + +void GLUI_Main::restore_draw_buffer( int buffer_state ) +{ + glDrawBuffer( buffer_state ); +} + + +/******************************************** GLUI_Main::GLUI_Main() ********/ + +GLUI_Main::GLUI_Main( void ) +{ + mouse_button_down = false; + w = 0; + h = 0; + active_control = NULL; + mouse_over_control = NULL; + main_gfx_window_id = -1; + glut_window_id = -1; + curr_modifiers = 0; + closing = false; + parent_window = -1; + glui_id = GLUI_Master.glui_id_counter; + GLUI_Master.glui_id_counter++; + + font = GLUT_BITMAP_HELVETICA_12; + curr_cursor = GLUT_CURSOR_LEFT_ARROW; + + int r=200, g=200, b=200; + bkgd_color.set( r,g,b ); + bkgd_color_f[0] = r / 255.0; + bkgd_color_f[1] = g / 255.0; + bkgd_color_f[2] = b / 255.0; + + /*** Create the main panel ***/ + main_panel = new GLUI_Panel; + main_panel->set_int_val( GLUI_PANEL_NONE ); + main_panel->glui = (GLUI*) this; + main_panel->name = "\0"; +} + +/************************************ GLUI_Main::draw_raised_box() **********/ + +void GLUI_Main::draw_raised_box( int x, int y, int w, int h ) +{ + w = w+x; + h = h+y; + + glColor3ub( bkgd_color.r, bkgd_color.g, bkgd_color.b ); + glBegin( GL_LINE_LOOP ); + glVertex2i( x+1, y+1 ); glVertex2i( w-1, y+1 ); + glVertex2i( w-1, h-1 ); glVertex2i( x+1, h-1 ); + glEnd(); + + glColor3d( 1.0, 1.0, 1.0 ); + glBegin( GL_LINE_STRIP ); + glVertex2i( x, h ); glVertex2i( x, y ); glVertex2i( w, y ); + glEnd(); + + glColor3d( 0.0, 0.0, 0.0 ); + glBegin( GL_LINE_STRIP ); + glVertex2i( w, y ); glVertex2i( w, h ); glVertex2i( x, h ); + glEnd(); + + glColor3d( .5, .5, .5 ); + glBegin( GL_LINE_STRIP ); + glVertex2i( w-1, y+1 ); glVertex2i( w-1, h-1 ); glVertex2i( x+1, h-1 ); + glEnd(); +} + + +/************************************ GLUI_Main::draw_lowered_box() **********/ +/* Not quite perfect... **/ + +void GLUI_Main::draw_lowered_box( int x, int y, int w, int h ) +{ + w = w+x; + h = h+y; + + glColor3ub( bkgd_color.r, bkgd_color.g, bkgd_color.b ); + glBegin( GL_LINE_LOOP ); + glVertex2i( x+1, y+1 ); glVertex2i( w-1, y+1 ); + glVertex2i( w-1, h-1 ); glVertex2i( x+1, h-1 ); + glEnd(); + + glColor3d( 0.0, 0.0, 0.0 ); + glBegin( GL_LINE_STRIP ); + glVertex2i( x, h ); glVertex2i( x, y ); glVertex2i( w, y ); + glEnd(); + + glColor3d( 1.0, 1.0, 1.0 ); + glBegin( GL_LINE_STRIP ); + glVertex2i( w, y ); glVertex2i( w, h ); glVertex2i( x, h ); + glEnd(); + + glColor3d( .5, .5, .5 ); + glBegin( GL_LINE_STRIP ); + glVertex2i( w-1, y+1 ); glVertex2i( w-1, h-1 ); glVertex2i( x+1, h-1 ); + glEnd(); +} + + +/************************************* GLUI_Main::activate_control() *********/ + +void GLUI_Main::activate_control( GLUI_Control *control, int how ) +{ + /** Are we not activating a control in the same window as the + previous active control? */ + if ( GLUI_Master.active_control_glui AND + this != (GLUI_Main*) GLUI_Master.active_control_glui ) { + GLUI_Master.active_control_glui->deactivate_current_control(); + } + + /******* Now activate it *****/ + if ( control != NULL AND control->can_activate AND control->enabled ) { + active_control = control; + + control->activate(how); + + /*if ( NOT active_control->is_container OR */ + /* active_control->type == GLUI_CONTROL_ROLLOUT) { */ + active_control->redraw(); + /*} */ + } + else { + active_control = NULL; + } + + /* printf( "activate: %d\n", glutGetWindow() ); */ + GLUI_Master.active_control = active_control; + GLUI_Master.active_control_glui = (GLUI*) this; +} + + +/************************* GLUI_Main::deactivate_current_control() **********/ + +void GLUI_Main::deactivate_current_control( void ) +{ + int orig; + + if ( active_control != NULL ) { + orig = active_control->set_to_glut_window(); + + active_control->deactivate(); + + /** If this isn't a container control, then redraw it in its + deactivated state. Container controls, such as panels, look + the same activated or not **/ + + /*if ( NOT active_control->is_container OR */ + /* active_control->type == GLUI_CONTROL_ROLLOUT ) { */ + active_control->redraw(); + /*} */ + + active_control->restore_window( orig ); + + active_control = NULL; + } + + /* printf( "deactivate: %d\n", glutGetWindow() ); */ + GLUI_Master.active_control = NULL; + GLUI_Master.active_control_glui = NULL; +} + + +/****************************** GLUI_Main::find_next_control() **************/ + +GLUI_Control *GLUI_Main::find_next_control_( GLUI_Control *control ) +{ + /*** THIS IS NOT find_next_control()! This is an unused older + version (look at the underscore at the end) ***/ + + if ( control == NULL ) + return find_next_control_rec( main_panel ); + else + return find_next_control_rec( control ); +} + +/****************************** GLUI_Main::find_next_control() **************/ + +GLUI_Control *GLUI_Main::find_next_control_rec( GLUI_Control *control ) +{ + GLUI_Control *child = NULL, *rec_control, *sibling; + + /*** Recursively investigate children ***/ + child = (GLUI_Control*) control->first_child(); + if ( child ) { + /*** If we can activate the first child, then do so ***/ + if ( child->can_activate AND child->enabled ) + return child; + else /*** Recurse into first child ***/ + rec_control = find_next_control_rec( child ); + + if ( rec_control ) + return rec_control; + } + + /*** At this point, either we don't have children, or the child cannot + be activated. So let's try the next sibling ***/ + + sibling = (GLUI_Control*) control->next(); + if ( sibling ) { + if ( sibling->can_activate AND sibling->enabled ) + return sibling; + else /*** Recurse into sibling ***/ + rec_control = find_next_control_rec( sibling ); + + if ( rec_control ) + return rec_control; + } + + return NULL; +} + + +/****************************** GLUI_Main::find_next_control() **************/ + +GLUI_Control *GLUI_Main::find_next_control( GLUI_Control *control ) +{ + GLUI_Control *tmp_control = NULL; + int back_up; + + if ( control == NULL ) + control = main_panel; + + while( control != NULL ) { + /** see if this control has a child **/ + tmp_control = (GLUI_Control*) control->first_child(); + + if ( tmp_control != NULL ) { + if ( tmp_control->can_activate AND tmp_control->enabled ) + return tmp_control; + + control = tmp_control; /* Descend into child */ + continue; + } + + /*** At this point, control has no children ***/ + + /** see if this control has a next sibling **/ + tmp_control = (GLUI_Control*) control->next(); + + if ( tmp_control != NULL ) { + if ( tmp_control->can_activate AND tmp_control->enabled ) + return tmp_control; + + control = tmp_control; + continue; + } + + /** back up until we find a sibling of an ancestor **/ + back_up = true; + while ( control->parent() AND back_up ) { + control = (GLUI_Control*) control->parent(); + + if ( control->next() ) { + control = (GLUI_Control*) control->next(); + if ( control->can_activate AND control->enabled ) + return control; + else + back_up = false; + + /*** if ( control->is_container ) { + tmp_control = control; + control = NULL; + break; + } + else { + back_up = false; + } + ***/ + } + } + + /** Check if we've cycled back to the top... if so, return NULL **/ + if ( control == main_panel ) { + return NULL; + } + } + /* + if ( tmp_control != NULL AND tmp_control->can_activate AND + tmp_control->enabled ) { + return tmp_control; + }*/ + + return NULL; +} + + +/****************************** GLUI_Main::find_prev_control() **************/ + +GLUI_Control *GLUI_Main::find_prev_control( GLUI_Control *control ) +{ + GLUI_Control *tmp_control, *next_control; + + if ( control == NULL ) { /* here we find the last valid control */ + next_control = main_panel; + + do { + tmp_control = next_control; + next_control = find_next_control( tmp_control ); + } while( next_control != NULL ); + + return tmp_control; + } + else { /* here we find the actual previous control */ + next_control = main_panel; + + do { + tmp_control = next_control; + next_control = find_next_control( tmp_control ); + } while( next_control != NULL AND next_control != control ); + + if ( next_control == NULL OR tmp_control == main_panel ) + return NULL; + else + return tmp_control; + } +} + +/************************* GLUI_Master_Object::set_glutIdleFunc() ***********/ + +void GLUI_Master_Object::set_glutIdleFunc(void (*f)(void)) +{ + glut_idle_CB = f; + GLUI_Master.glui_setIdleFuncIfNecessary(); +} + + +/**************************************** GLUI::disable() ********************/ + +void GLUI::disable( void ) +{ + deactivate_current_control(); + main_panel->disable(); +} + + +/******************************************** GLUI::sync_live() **************/ + +void GLUI::sync_live( void ) +{ + main_panel->sync_live(true, true); +} + + +/********************************* GLUI_Master_Object::sync_live_all() *****/ + +void GLUI_Master_Object::sync_live_all( void ) +{ + GLUI *glui; + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + + glui->sync_live(); /** sync it **/ + + glui = (GLUI*) glui->next(); + } +} + + +/************************************* GLUI_Master_Object::close() **********/ + +void GLUI_Master_Object::close_all( void ) +{ + GLUI *glui; + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + + glui->close(); /** Set flag to close **/ + + glui = (GLUI*) glui->next(); + } +} + + +/************************************* GLUI_Main::close_internal() **********/ + +void GLUI_Main::close_internal( void ) +{ + glutDestroyWindow(glutGetWindow()); /** Close this window **/ + + this->unlink(); + + if ( GLUI_Master.active_control_glui == this ) { + GLUI_Master.active_control = NULL; + GLUI_Master.active_control_glui = NULL; + } + + if ( parent_window != -1 ) { + glutSetWindow( parent_window ); + int win_w = glutGet( GLUT_WINDOW_WIDTH ); + int win_h = glutGet( GLUT_WINDOW_HEIGHT ); + glutReshapeWindow(win_w+1, win_h); + glutReshapeWindow(win_w-1, win_h); + } + + delete this->main_panel; + + delete this; +} + + +/************************************************** GLUI::close() **********/ + +void GLUI::close( void ) +{ + int old_glut_window; + + closing = true; + + old_glut_window = glutGetWindow(); + glutSetWindow( get_glut_window_id() ); + glutPostRedisplay(); + + glutSetWindow( old_glut_window ); +} + + +/************************** GLUI_Main::check_subwindow_position() **********/ + +void GLUI_Main::check_subwindow_position( void ) +{ + /*** Reposition this window if subwindow ***/ + if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) { + + int parent_w, parent_h, new_x, new_y; + int old_window = glutGetWindow(); + + glutSetWindow( glut_window_id ); + + glutSetWindow( glutGet( GLUT_WINDOW_PARENT )); + parent_w = glutGet( GLUT_WINDOW_WIDTH ); + parent_h = glutGet( GLUT_WINDOW_HEIGHT ); + + glutSetWindow( glut_window_id ); + + if ( TEST_AND(this->flags,GLUI_SUBWINDOW_RIGHT )) { + new_x = parent_w - this->w; + new_y = 0; + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) { + new_x = 0; + new_y = 0; + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_BOTTOM )) { + new_x = 0; + new_y = parent_h - this->h; + } + else { /*** GLUI_SUBWINDOW_TOP ***/ + new_x = 0; + new_y = 0; + } + + /** Now make adjustments based on presence of other subwindows **/ + GLUI *curr_glui; + curr_glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( curr_glui ) { + if ( TEST_AND( curr_glui->flags, GLUI_SUBWINDOW) AND + curr_glui->parent_window == this->parent_window ) { + + if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_LEFT ) ) { + } + else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_BOTTOM ) ) { + } + else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_RIGHT ) ) { + } + else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_TOP ) AND + ( TEST_AND( this->flags,GLUI_SUBWINDOW_LEFT ) OR + TEST_AND( this->flags,GLUI_SUBWINDOW_RIGHT ) ) ) { + /** If we are a RIGHT or LEFT subwindow, and there exists some + TOP subwindow, bump our position down **/ + + new_y += curr_glui->h; + } + + /** CHeck multiple subwins at same position **/ + /** We check the glui_id's: only the glui with the higher + ID number (meaning it was created later) gets bumped over **/ + if ( curr_glui != this AND this->glui_id > curr_glui->glui_id ) { + if ( TEST_AND( this->flags,GLUI_SUBWINDOW_LEFT ) AND + TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_LEFT ) ) { + new_x += curr_glui->w; + } + else if ( TEST_AND( this->flags,GLUI_SUBWINDOW_TOP ) AND + TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_TOP ) ) { + new_y += curr_glui->h; + } + else if ( TEST_AND( this->flags,GLUI_SUBWINDOW_BOTTOM ) AND + TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_BOTTOM ) ) { + new_y -= curr_glui->h; + } + else if ( TEST_AND( this->flags,GLUI_SUBWINDOW_RIGHT ) AND + TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_RIGHT ) ) { + new_x -= curr_glui->w; + } + + } + } + + curr_glui = (GLUI*) curr_glui->next(); + } + + + + CLAMP( new_x, 0, new_x ); + CLAMP( new_y, 0, new_y ); + + glutPositionWindow( new_x, new_y ); + /* glutPostRedisplay(); */ + + glutSetWindow( old_window ); + } +} + + +/********************************* GLUI_Master_Object::reshape() **********/ +/* This gets called by the user from a GLUT reshape callback. So we look */ +/* for subwindows that belong to the current window */ + +void GLUI_Master_Object::reshape( void ) +{ + GLUI *glui; + int current_window; + + current_window = glutGetWindow(); + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND + glui->parent_window == current_window ) { + glutSetWindow( glui->get_glut_window_id()); + glui->check_subwindow_position(); + } + + glui = (GLUI*) glui->next(); + } + + glutSetWindow(current_window); +} + + +/**************************** GLUI_Master_Object::set_glutReshapeFunc() *****/ + +void GLUI_Master_Object::set_glutReshapeFunc(void (*f)(int width, int height)) +{ + glutReshapeFunc( glui_reshape_func ); + add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_RESHAPE, (void*) f); +} + + +/**************************** GLUI_Master_Object::set_glutKeyboardFunc() ****/ + +void GLUI_Master_Object::set_glutKeyboardFunc(void (*f)(unsigned char key, + int x, int y)) +{ + glutKeyboardFunc( glui_keyboard_func ); + add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_KEYBOARD, (void*) f); +} + + +/*********************** GLUI_Master_Object::set_glutSpecialFunc() **********/ + +void GLUI_Master_Object::set_glutSpecialFunc(void (*f)(int key, + int x, int y)) +{ + glutSpecialFunc( glui_special_func ); + add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_SPECIAL, (void*) f); +} + + +/*********************** GLUI_Master_Object::set_glutMouseFunc() **********/ + +void GLUI_Master_Object::set_glutMouseFunc(void (*f)(int button, int state, + int x, int y)) +{ + glutMouseFunc( glui_mouse_func ); + add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_MOUSE, (void*) f); +} + + +/****************************** glui_parent_window_reshape_func() **********/ +/* This is the reshape callback for a window that contains subwindows */ + +void glui_parent_window_reshape_func( int w, int h ) +{ + int current_window; + GLUI *glui; + int first = true; + + /* printf( "glui_parent_window_reshape_func: %d\n", glutGetWindow() ); */ + + current_window = glutGetWindow(); + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND + glui->parent_window == current_window ) { + glutSetWindow( glui->get_glut_window_id()); + glui->check_subwindow_position(); + glutSetWindow( current_window ); + + if ( first ) { + if (glui->glut_reshape_CB) glui->glut_reshape_CB( w, h ); + + first = false; + } + } + + glui = (GLUI*) glui->next(); + } +} + + +/****************************** glui_parent_window_keyboard_func() **********/ + +void glui_parent_window_keyboard_func(unsigned char key, int x, int y) +{ + /* printf( "glui_parent_window_keyboard_func: %d\n", glutGetWindow() ); */ + + int current_window; + GLUI *glui; + + current_window = glutGetWindow(); + + if ( GLUI_Master.active_control_glui AND GLUI_Master.active_control ) { + glutSetWindow( GLUI_Master.active_control_glui->get_glut_window_id() ); + + GLUI_Master.active_control_glui->keyboard(key,x,y); + + glutSetWindow( current_window ); + } + else { + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND + glui->parent_window == current_window AND + glui->glut_keyboard_CB ) + { + glui->glut_keyboard_CB( key, x, y ); + break; + } + + glui = (GLUI*) glui->next(); + } + } +} + + +/****************************** glui_parent_window_special_func() **********/ + +void glui_parent_window_special_func(int key, int x, int y) +{ + /*printf( "glui_parent_window_special_func: %d\n", glutGetWindow() ); */ + + int current_window; + GLUI *glui; + + /** If clicking in the main area of a window w/subwindows, + deactivate any current control **/ + if ( GLUI_Master.active_control_glui != NULL ) + GLUI_Master.active_control_glui->deactivate_current_control(); + + /*** Now pass on the mouse event ***/ + + current_window = glutGetWindow(); + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND + glui->parent_window == current_window ) + { + glutSetWindow( glui->get_glut_window_id()); + if (glui->glut_special_CB) glui->glut_special_CB( key, x, y ); + break; + } + + glui = (GLUI*) glui->next(); + } +} + + +/****************************** glui_parent_window_mouse_func() **********/ + +void glui_parent_window_mouse_func(int button, int state, int x, int y) +{ + int current_window; + GLUI *glui; + + /** If clicking in the main area of a window w/subwindows, + deactivate any current control **/ + if ( GLUI_Master.active_control_glui != NULL ) + GLUI_Master.active_control_glui->deactivate_current_control(); + + + /*** Now pass on the mouse event ***/ + + current_window = glutGetWindow(); + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND + glui->parent_window == current_window AND + glui->glut_mouse_CB) + { + glutSetWindow( glui->get_glut_window_id()); + glui->glut_mouse_CB( button, state, x, y ); + break; + } + + glui = (GLUI*) glui->next(); + } +} + + +/************************** GLUI_Master_Object::find_glut_window() **********/ + +GLUI_Glut_Window *GLUI_Master_Object::find_glut_window( int window_id ) +{ + GLUI_Glut_Window *window; + + window = (GLUI_Glut_Window*) glut_windows.first_child(); + while( window ) { + if ( window->glut_window_id == window_id ) + return window; + + window = (GLUI_Glut_Window*) window->next(); + } + + /*** Window not found - return NULL ***/ + return NULL; +} + + +/******************** GLUI_Master_Object::add_cb_to_glut_window() **********/ + +void GLUI_Master_Object::add_cb_to_glut_window(int window_id, + int cb_type,void *cb) +{ + GLUI_Glut_Window *window; + + window = find_glut_window( window_id ); + if ( NOT window ) { + /*** Allocate new window structure ***/ + + window = new GLUI_Glut_Window; + window->glut_window_id = window_id; + window->link_this_to_parent_last( (GLUI_Node*) &this->glut_windows ); + } + + switch( cb_type ) { + case GLUI_GLUT_RESHAPE: + window->glut_reshape_CB = (void(*)(int,int)) cb; + break; + case GLUI_GLUT_DISPLAY: + window->glut_display_CB = (void(*)()) cb; + break; + case GLUI_GLUT_KEYBOARD: + window->glut_keyboard_CB = (void(*)(unsigned char,int,int)) cb; + break; + case GLUI_GLUT_SPECIAL: + window->glut_special_CB = (void(*)(int,int,int)) cb; + break; + case GLUI_GLUT_MOUSE: + window->glut_mouse_CB = (void(*)(int,int,int,int)) cb; + break; + case GLUI_GLUT_MOTION: + window->glut_motion_CB = (void(*)(int,int)) cb; + break; + case GLUI_GLUT_PASSIVE_MOTION: + window->glut_passive_motion_CB = (void(*)(int,int)) cb; + break; + case GLUI_GLUT_ENTRY: + window->glut_entry_CB = (void(*)(int)) cb; + break; + case GLUI_GLUT_VISIBILITY: + window->glut_visibility_CB= (void(*)(int)) cb; + break; + } +} + + +/************* GLUI_Master_Object::set_left_button_glut_menu_control() *****/ + +void GLUI_Master_Object::set_left_button_glut_menu_control( + GLUI_Control *control ) +{ + curr_left_button_glut_menu = control; +} + + +/******************************* GLUI_Main::set_ortho_projection() **********/ + +void GLUI_Main::set_ortho_projection( void ) +{ + int win_h, win_w; + + win_w = glutGet( GLUT_WINDOW_WIDTH ); + win_h = glutGet( GLUT_WINDOW_HEIGHT ); + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + /* gluOrtho2D( 0.0, (float) win_w, 0.0, (float) win_h ); */ + glOrtho( 0.0, (float)win_w, 0.0, (float) win_h, -1000.0, 1000.0 ); + + glMatrixMode( GL_MODELVIEW ); + + return; /****-----------------------------------------------***/ + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + /*** Rotate image so y increases upwards, contrary to OpenGL axes ***/ + glTranslatef( (float) win_w/2.0, (float) win_h/2.0, 0.0 ); + glRotatef( 180.0, 0.0, 1.0, 0.0 ); + glRotatef( 180.0, 0.0, 0.0, 1.0 ); + glTranslatef( (float) -win_w/2.0, (float) -win_h/2.0, 0.0 ); +} + + +/******************************* GLUI_Main::set_viewport() **********/ + +void GLUI_Main::set_viewport( void ) +{ + glViewport( 0, 0, main_panel->w, main_panel->h ); +} + + +/****************************** GLUI_Main::refresh() ****************/ + +void GLUI_Main::refresh( void ) +{ + int orig; + + /****** GLUI_Glut_Window *glut_window; + int current_window; + current_window = glutGetWindow(); + glut_window = GLUI_Master.find_glut_window( current_window ); + if ( glut_window ) { + glut_window->glut_reshape_CB(w,h); + ******/ + + orig = glutGetWindow(); + + pack_controls(); + + if ( glut_window_id > 0 ) + glutSetWindow( glut_window_id ); + + + if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) { + /*** GLUI subwindow ***/ + + check_subwindow_position(); + } + else { + /*** Standalone GLUI window ***/ + + glutReshapeWindow( this->h, this->w ); + + } + + glutPostRedisplay(); + glutSetWindow( orig); +} + + + +/***************** GLUI_Master_Object::get_main_gfx_viewport() ***********/ + +void GLUI_Master_Object::get_viewport_area( int *x, int *y, + int *w, int *h ) +{ + GLUI *curr_glui; + int curr_x, curr_y, curr_w, curr_h; + int curr_window; + + curr_window = glutGetWindow(); + curr_x = 0; + curr_y = 0; + curr_w = glutGet( GLUT_WINDOW_WIDTH ); + curr_h = glutGet( GLUT_WINDOW_HEIGHT ); + + curr_glui = (GLUI*) gluis.first_child(); + while( curr_glui ) { + if ( TEST_AND( curr_glui->flags, GLUI_SUBWINDOW) AND + curr_glui->parent_window == curr_window ) { + + /* printf( "%s -> %d %d %d\n", curr_glui->window_name.c_str(), curr_glui->flags, + curr_glui->w, curr_glui->h );*/ + + if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_LEFT ) ) { + curr_x += curr_glui->w; + curr_w -= curr_glui->w; + } + else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_BOTTOM ) ) { + curr_y += curr_glui->h; + curr_h -= curr_glui->h; + } + else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_RIGHT ) ) { + curr_w -= curr_glui->w; + } + else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_TOP ) ) { + curr_h -= curr_glui->h; + } + } + + curr_glui = (GLUI*) curr_glui->next(); + } + + curr_x = MAX( 0, curr_x ); + curr_y = MAX( 0, curr_y ); + curr_w = MAX( 0, curr_w ); + curr_h = MAX( 0, curr_h ); + + *x = curr_x; + *y = curr_y; + *w = curr_w; + *h = curr_h; +} + + +/*****************GLUI_Master_Object::auto_set_main_gfx_viewport() **********/ + +void GLUI_Master_Object::auto_set_viewport( void ) +{ + int x, y, w, h; + + get_viewport_area( &x, &y, &w, &h ); + glViewport( MAX(x,0), MAX(y,0), MAX(w,0), MAX(h,0) ); +} + + + +/***************************************** GLUI::show() **********************/ + +void GLUI::show( void ) +{ + int orig_window; + + orig_window = main_panel->set_to_glut_window(); + + glutShowWindow(); + + main_panel->restore_window(orig_window); +} + + + +/***************************************** GLUI::hide() **********************/ + +void GLUI::hide( void ) +{ + int orig_window; + + this->deactivate_current_control(); + + orig_window = main_panel->set_to_glut_window(); + + glutHideWindow(); + + main_panel->restore_window(orig_window); +} + + +/**************** GLUI_DrawingSentinal **************/ +GLUI_DrawingSentinal::GLUI_DrawingSentinal(GLUI_Control *c_) + :c(c_) +{ + orig_win = c->set_to_glut_window(); + orig_buf = c->glui->set_current_draw_buffer(); +} +GLUI_DrawingSentinal::~GLUI_DrawingSentinal() { + c->glui->restore_draw_buffer(orig_buf); + c->restore_window(orig_win); +} + + +void GLUI_Master_Object::glui_setIdleFuncIfNecessary( void ) +{ + GLUI *glui; + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + int necessary; + if (this->glut_idle_CB) + necessary = true; + else { + necessary = false; + while( glui ) { + if( glui->needs_idle() ) { + necessary = true; + break; + } + glui = (GLUI*) glui->next(); + } + } + if( necessary ) + glutIdleFunc( glui_idle_func ); + else + glutIdleFunc( NULL ); +} diff --git a/tests/Box2D_v2.2.1/glui/glui.h b/tests/Box2D_v2.2.1/glui/glui.h new file mode 100755 index 0000000000000..f1daea8e41463 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui.h @@ -0,0 +1,2568 @@ +/**************************************************************************** + + GLUI User Interface Toolkit (LGPL) + ---------------------------------- + + glui.h - Main (and only) external header for + GLUI User Interface Toolkit + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#ifndef GLUI_GLUI_H +#define GLUI_GLUI_H + +#ifdef __APPLE__ + #include +#else + #include "freeglut/freeglut.h" +#endif + +#include +#include +#include +#include +#include + +#define GLUI_VERSION 2.3f /********** Current version **********/ + +#if defined(_WIN32) +#if !defined(GLUI_NO_LIB_PRAGMA) +//#pragma comment(lib, "glui32.lib") // Link automatically with GLUI library +#endif +#endif + +/********** Do some basic defines *******/ + +#ifndef Byte +#define Byte unsigned char +#endif + +#ifndef _RGBC_ +class RGBc { +public: + Byte r, g, b; + + void set(Byte r,Byte g,Byte b) {this->r=r;this->g=g;this->b=b;} + + RGBc( void ) {} + RGBc( Byte r, Byte g, Byte b ) { set( r, g, b ); } +}; +#define _RGBC_ +#endif + +/********** List of GLUT callbacks ********/ + +enum GLUI_Glut_CB_Types +{ + GLUI_GLUT_RESHAPE, + GLUI_GLUT_KEYBOARD, + GLUI_GLUT_DISPLAY, + GLUI_GLUT_MOUSE, + GLUI_GLUT_MOTION, + GLUI_GLUT_SPECIAL, + GLUI_GLUT_PASSIVE_MOTION, + GLUI_GLUT_ENTRY, + GLUI_GLUT_VISIBILITY +}; + +/********* Constants for window placement **********/ + +#define GLUI_XOFF 6 +#define GLUI_YOFF 6 +#define GLUI_ITEMSPACING 3 +#define GLUI_CHECKBOX_SIZE 13 +#define GLUI_RADIOBUTTON_SIZE 13 +#define GLUI_BUTTON_SIZE 20 +#define GLUI_STATICTEXT_SIZE 13 +#define GLUI_SEPARATOR_HEIGHT 8 +#define GLUI_DEFAULT_CONTROL_WIDTH 100 +#define GLUI_DEFAULT_CONTROL_HEIGHT 13 +#define GLUI_EDITTEXT_BOXINNERMARGINX 3 +#define GLUI_EDITTEXT_HEIGHT 20 +#define GLUI_EDITTEXT_WIDTH 130 +#define GLUI_EDITTEXT_MIN_INT_WIDTH 35 +#define GLUI_EDITTEXT_MIN_TEXT_WIDTH 50 +#define GLUI_PANEL_NAME_DROP 8 +#define GLUI_PANEL_EMBOSS_TOP 4 +/* #define GLUI_ROTATION_WIDTH 60 */ +/* #define GLUI_ROTATION_HEIGHT 78 */ +#define GLUI_ROTATION_WIDTH 50 +#define GLUI_ROTATION_HEIGHT (GLUI_ROTATION_WIDTH+18) +#define GLUI_MOUSE_INTERACTION_WIDTH 50 +#define GLUI_MOUSE_INTERACTION_HEIGHT (GLUI_MOUSE_INTERACTION_WIDTH)+18 + +/** Different panel control types **/ +#define GLUI_PANEL_NONE 0 +#define GLUI_PANEL_EMBOSSED 1 +#define GLUI_PANEL_RAISED 2 + +/** Max # of els in control's float_array **/ +#define GLUI_DEF_MAX_ARRAY 30 + +/********* The control's 'active' behavior *********/ +#define GLUI_CONTROL_ACTIVE_MOUSEDOWN 1 +#define GLUI_CONTROL_ACTIVE_PERMANENT 2 + +/********* Control alignment types **********/ +#define GLUI_ALIGN_CENTER 1 +#define GLUI_ALIGN_RIGHT 2 +#define GLUI_ALIGN_LEFT 3 + +/********** Limit types - how to limit spinner values *********/ +#define GLUI_LIMIT_NONE 0 +#define GLUI_LIMIT_CLAMP 1 +#define GLUI_LIMIT_WRAP 2 + +/********** Translation control types ********************/ +#define GLUI_TRANSLATION_XY 0 +#define GLUI_TRANSLATION_Z 1 +#define GLUI_TRANSLATION_X 2 +#define GLUI_TRANSLATION_Y 3 + +#define GLUI_TRANSLATION_LOCK_NONE 0 +#define GLUI_TRANSLATION_LOCK_X 1 +#define GLUI_TRANSLATION_LOCK_Y 2 + +/********** How was a control activated? *****************/ +#define GLUI_ACTIVATE_MOUSE 1 +#define GLUI_ACTIVATE_TAB 2 + +/********** What type of live variable does a control have? **********/ +#define GLUI_LIVE_NONE 0 +#define GLUI_LIVE_INT 1 +#define GLUI_LIVE_FLOAT 2 +#define GLUI_LIVE_TEXT 3 +#define GLUI_LIVE_STRING 6 +#define GLUI_LIVE_DOUBLE 4 +#define GLUI_LIVE_FLOAT_ARRAY 5 + +/************* Textbox and List Defaults - JVK ******************/ +#define GLUI_TEXTBOX_HEIGHT 130 +#define GLUI_TEXTBOX_WIDTH 130 +#define GLUI_LIST_HEIGHT 130 +#define GLUI_LIST_WIDTH 130 +#define GLUI_DOUBLE_CLICK 1 +#define GLUI_SINGLE_CLICK 0 +#define GLUI_TAB_WIDTH 50 /* In pixels */ +#define GLUI_TEXTBOX_BOXINNERMARGINX 3 +#define GLUI_TEXTBOX_MIN_TEXT_WIDTH 50 +#define GLUI_LIST_BOXINNERMARGINX 3 +#define GLUI_LIST_MIN_TEXT_WIDTH 50 + +/*********************** TreePanel Defaults - JVK *****************************/ +#define GLUI_TREEPANEL_DEFAULTS 0 // bar, standard bar color +#define GLUI_TREEPANEL_ALTERNATE_COLOR 1 // Alternate between 8 different bar colors +#define GLUI_TREEPANEL_ENABLE_BAR 2 // enable the bar +#define GLUI_TREEPANEL_DISABLE_BAR 4 // disable the bar +#define GLUI_TREEPANEL_DISABLE_DEEPEST_BAR 8 // disable only the deepest bar +#define GLUI_TREEPANEL_CONNECT_CHILDREN_ONLY 16 // disable only the bar of the last child of each root +#define GLUI_TREEPANEL_DISPLAY_HIERARCHY 32 // display some sort of hierachy in the tree node title +#define GLUI_TREEPANEL_HIERARCHY_NUMERICDOT 64 // display hierarchy in 1.3.2 (etc... ) format +#define GLUI_TREEPANEL_HIERARCHY_LEVEL_ONLY 128 // display hierarchy as only the level depth + +/******************* GLUI Scrollbar Defaults - JVK ***************************/ +#define GLUI_SCROLL_ARROW_WIDTH 16 +#define GLUI_SCROLL_ARROW_HEIGHT 16 +#define GLUI_SCROLL_BOX_MIN_HEIGHT 5 +#define GLUI_SCROLL_BOX_STD_HEIGHT 16 +#define GLUI_SCROLL_STATE_NONE 0 +#define GLUI_SCROLL_STATE_UP 1 +#define GLUI_SCROLL_STATE_DOWN 2 +#define GLUI_SCROLL_STATE_BOTH 3 +#define GLUI_SCROLL_STATE_SCROLL 4 +#define GLUI_SCROLL_DEFAULT_GROWTH_EXP 1.05f +#define GLUI_SCROLL_VERTICAL 0 +#define GLUI_SCROLL_HORIZONTAL 1 + + +/** Size of the character width hash table for faster lookups. + Make sure to keep this a power of two to avoid the slow divide. + This is also a speed/memory tradeoff; 128 is enough for low ASCII. +*/ +#define CHAR_WIDTH_HASH_SIZE 128 + +/********** Translation codes **********/ + +enum TranslationCodes +{ + GLUI_TRANSLATION_MOUSE_NONE = 0, + GLUI_TRANSLATION_MOUSE_UP, + GLUI_TRANSLATION_MOUSE_DOWN, + GLUI_TRANSLATION_MOUSE_LEFT, + GLUI_TRANSLATION_MOUSE_RIGHT, + GLUI_TRANSLATION_MOUSE_UP_LEFT, + GLUI_TRANSLATION_MOUSE_UP_RIGHT, + GLUI_TRANSLATION_MOUSE_DOWN_LEFT, + GLUI_TRANSLATION_MOUSE_DOWN_RIGHT +}; + +/************ A string type for us to use **********/ + +typedef std::string GLUI_String; +GLUI_String& glui_format_str(GLUI_String &str, const char* fmt, ...); + +/********* Pre-declare classes as needed *********/ + +class GLUI; +class GLUI_Control; +class GLUI_Listbox; +class GLUI_StaticText; +class GLUI_EditText; +class GLUI_Panel; +class GLUI_Spinner; +class GLUI_RadioButton; +class GLUI_RadioGroup; +class GLUI_Glut_Window; +class GLUI_TreePanel; +class GLUI_Scrollbar; +class GLUI_List; + +class Arcball; + +/*** Flags for GLUI class constructor ***/ +#define GLUI_SUBWINDOW ((long)(1<<1)) +#define GLUI_SUBWINDOW_TOP ((long)(1<<2)) +#define GLUI_SUBWINDOW_BOTTOM ((long)(1<<3)) +#define GLUI_SUBWINDOW_LEFT ((long)(1<<4)) +#define GLUI_SUBWINDOW_RIGHT ((long)(1<<5)) + +/*** Codes for different type of edittext boxes and spinners ***/ +#define GLUI_EDITTEXT_TEXT 1 +#define GLUI_EDITTEXT_INT 2 +#define GLUI_EDITTEXT_FLOAT 3 +#define GLUI_SPINNER_INT GLUI_EDITTEXT_INT +#define GLUI_SPINNER_FLOAT GLUI_EDITTEXT_FLOAT +#define GLUI_SCROLL_INT GLUI_EDITTEXT_INT +#define GLUI_SCROLL_FLOAT GLUI_EDITTEXT_FLOAT +// This is only for deprecated interface +#define GLUI_EDITTEXT_STRING 4 + +/*** Definition of callbacks ***/ +typedef void (*GLUI_Update_CB) (int id); +typedef void (*GLUI_Control_CB)(GLUI_Control *); +typedef void (*Int1_CB) (int); +typedef void (*Int2_CB) (int, int); +typedef void (*Int3_CB) (int, int, int); +typedef void (*Int4_CB) (int, int, int, int); + +/************************************************************/ +/** + Callback Adapter Class + Allows us to support different types of callbacks; + like a GLUI_Update_CB function pointer--which takes an int; + and a GLUI_Control_CB function pointer--which takes a GUI_Control object. +*/ +class GLUI_CB +{ +public: + GLUI_CB() : idCB(0),objCB(0) {} + GLUI_CB(GLUI_Update_CB cb) : idCB(cb),objCB(0) {} + GLUI_CB(GLUI_Control_CB cb) : idCB(0),objCB(cb) {} + // (Compiler generated copy constructor) + + /** This control just activated. Fire our callback.*/ + void operator()(GLUI_Control *ctrl) const; + bool operator!() const { return !idCB && !objCB; } + operator bool() const { return !(!(*this)); } +private: + GLUI_Update_CB idCB; + GLUI_Control_CB objCB; +}; + +/************************************************************/ +/* */ +/* Base class, for hierarchical relationships */ +/* */ +/************************************************************/ + +class GLUI_Control; + +/** + GLUI_Node is a node in a sort of tree of GLUI controls. + Each GLUI_Node has a list of siblings (in a circular list) + and a linked list of children. + + Everything onscreen is a GLUI_Node--windows, buttons, etc. + The nodes are traversed for event processing, sizing, redraws, etc. +*/ +class GLUI_Node +{ + friend class GLUI_Tree; /* JVK */ + friend class GLUI_Rollout; + friend class GLUI_Main; + +public: + GLUI_Node(); + virtual ~GLUI_Node() {} + + GLUI_Node *first_sibling(); + GLUI_Node *last_sibling(); + GLUI_Node *prev(); + GLUI_Node *next(); + + GLUI_Node *first_child() { return child_head; } + GLUI_Node *last_child() { return child_tail; } + GLUI_Node *parent() { return parent_node; } + + /** Link in a new child control */ + virtual int add_control( GLUI_Control *control ); + + void link_this_to_parent_last (GLUI_Node *parent ); + void link_this_to_parent_first(GLUI_Node *parent ); + void link_this_to_sibling_next(GLUI_Node *sibling ); + void link_this_to_sibling_prev(GLUI_Node *sibling ); + void unlink(); + + void dump( FILE *out, const char *name ); + +protected: + static void add_child_to_control(GLUI_Node *parent,GLUI_Control *child); + GLUI_Node *parent_node; + GLUI_Node *child_head; + GLUI_Node *child_tail; + GLUI_Node *next_sibling; + GLUI_Node *prev_sibling; +}; + + +/************************************************************/ +/* */ +/* Standard Bitmap stuff */ +/* */ +/************************************************************/ + +enum GLUI_StdBitmaps_Codes +{ + GLUI_STDBITMAP_CHECKBOX_OFF = 0, + GLUI_STDBITMAP_CHECKBOX_ON, + GLUI_STDBITMAP_RADIOBUTTON_OFF, + GLUI_STDBITMAP_RADIOBUTTON_ON, + GLUI_STDBITMAP_UP_ARROW, + GLUI_STDBITMAP_DOWN_ARROW, + GLUI_STDBITMAP_LEFT_ARROW, + GLUI_STDBITMAP_RIGHT_ARROW, + GLUI_STDBITMAP_SPINNER_UP_OFF, + GLUI_STDBITMAP_SPINNER_UP_ON, + GLUI_STDBITMAP_SPINNER_DOWN_OFF, + GLUI_STDBITMAP_SPINNER_DOWN_ON, + GLUI_STDBITMAP_CHECKBOX_OFF_DIS, /*** Disactivated control bitmaps ***/ + GLUI_STDBITMAP_CHECKBOX_ON_DIS, + GLUI_STDBITMAP_RADIOBUTTON_OFF_DIS, + GLUI_STDBITMAP_RADIOBUTTON_ON_DIS, + GLUI_STDBITMAP_SPINNER_UP_DIS, + GLUI_STDBITMAP_SPINNER_DOWN_DIS, + GLUI_STDBITMAP_LISTBOX_UP, + GLUI_STDBITMAP_LISTBOX_DOWN, + GLUI_STDBITMAP_LISTBOX_UP_DIS, + GLUI_STDBITMAP_NUM_ITEMS +}; + +/************************************************************/ +/* */ +/* Class GLUI_Bitmap */ +/* */ +/************************************************************/ + +/** + GLUI_Bitmap is a simple 2D texture map. It's used + to represent small textures like checkboxes, arrows, etc. + via the GLUI_StdBitmaps class. +*/ +class GLUI_Bitmap +{ + friend class GLUI_StdBitmaps; + +public: + GLUI_Bitmap(); + ~GLUI_Bitmap(); + + /** Create bitmap from greyscale byte image */ + void init_grey(unsigned char *array); + + /** Create bitmap from color int image */ + void init(int *array); + +private: + /** RGB pixel data */ + unsigned char *pixels; + int w, h; +}; + + +/************************************************************/ +/* */ +/* Class GLUI_StdBitmap */ +/* */ +/************************************************************/ + +/** + Keeps an array of GLUI_Bitmap objects to represent all the + images used in the UI: checkboxes, arrows, etc. +*/ +class GLUI_StdBitmaps +{ +public: + GLUI_StdBitmaps(); + ~GLUI_StdBitmaps(); + + /** Return the width (in pixels) of the n'th standard bitmap. */ + int width (int n) const; + /** Return the height (in pixels) of the n'th standard bitmap. */ + int height(int n) const; + + /** Draw the n'th standard bitmap (one of the enums + listed in GLUI_StdBitmaps_Codes) at pixel corner (x,y). + */ + void draw(int n, int x, int y) const; + +private: + GLUI_Bitmap bitmaps[GLUI_STDBITMAP_NUM_ITEMS]; +}; + +/************************************************************/ +/* */ +/* Master GLUI Class */ +/* */ +/************************************************************/ + +/** + The master manages our interaction with GLUT. + There's only one GLUI_Master_Object. +*/ +class GLUI_Master_Object +{ + + friend void glui_idle_func(); + +public: + + GLUI_Master_Object(); + ~GLUI_Master_Object(); + + GLUI_Node gluis; + GLUI_Control *active_control, *curr_left_button_glut_menu; + GLUI *active_control_glui; + int glui_id_counter; + + GLUI_Glut_Window *find_glut_window( int window_id ); + + void set_glutIdleFunc(void (*f)(void)); + + /************** + void (*glut_keyboard_CB)(unsigned char, int, int); + void (*glut_reshape_CB)(int, int); + void (*glut_special_CB)(int, int, int); + void (*glut_mouse_CB)(int,int,int,int); + + void (*glut_passive_motion_CB)(int,int); + void (*glut_visibility_CB)(int); + void (*glut_motion_CB)(int,int); + void (*glut_display_CB)(void); + void (*glut_entry_CB)(int); + **********/ + + void set_left_button_glut_menu_control( GLUI_Control *control ); + + /********** GLUT callthroughs **********/ + /* These are the glut callbacks that we do not handle */ + + void set_glutReshapeFunc (void (*f)(int width, int height)); + void set_glutKeyboardFunc(void (*f)(unsigned char key, int x, int y)); + void set_glutSpecialFunc (void (*f)(int key, int x, int y)); + void set_glutMouseFunc (void (*f)(int, int, int, int )); + + void set_glutDisplayFunc(void (*f)(void)) {glutDisplayFunc(f);} + void set_glutTimerFunc(unsigned int millis, void (*f)(int value), int value) + { ::glutTimerFunc(millis,f,value);} + void set_glutOverlayDisplayFunc(void(*f)(void)){glutOverlayDisplayFunc(f);} + void set_glutSpaceballMotionFunc(Int3_CB f) {glutSpaceballMotionFunc(f);} + void set_glutSpaceballRotateFunc(Int3_CB f) {glutSpaceballRotateFunc(f);} + void set_glutSpaceballButtonFunc(Int2_CB f) {glutSpaceballButtonFunc(f);} + void set_glutTabletMotionFunc(Int2_CB f) {glutTabletMotionFunc(f);} + void set_glutTabletButtonFunc(Int4_CB f) {glutTabletButtonFunc(f);} + /* void set_glutWindowStatusFunc(Int1_CB f) {glutWindowStatusFunc(f);} */ + void set_glutMenuStatusFunc(Int3_CB f) {glutMenuStatusFunc(f);} + void set_glutMenuStateFunc(Int1_CB f) {glutMenuStateFunc(f);} + void set_glutButtonBoxFunc(Int2_CB f) {glutButtonBoxFunc(f);} + void set_glutDialsFunc(Int2_CB f) {glutDialsFunc(f);} + + + GLUI *create_glui( const char *name, long flags=0, int x=-1, int y=-1 ); + GLUI *create_glui_subwindow( int parent_window, long flags=0 ); + GLUI *find_glui_by_window_id( int window_id ); + void get_viewport_area( int *x, int *y, int *w, int *h ); + void auto_set_viewport(); + void close_all(); + void sync_live_all(); + + void reshape(); + + float get_version() { return GLUI_VERSION; } + + void glui_setIdleFuncIfNecessary(void); + +private: + GLUI_Node glut_windows; + void (*glut_idle_CB)(void); + + void add_cb_to_glut_window(int window,int cb_type,void *cb); +}; + +/** + This is the only GLUI_Master_Object in existence. +*/ +extern GLUI_Master_Object GLUI_Master; + +/************************************************************/ +/* */ +/* Class for managing a GLUT window */ +/* */ +/************************************************************/ + +/** + A top-level window. The GLUI_Master GLUT callback can route events + to the callbacks in this class, for arbitrary use by external users. + (see GLUI_Master_Object::set_glutKeyboardFunc). + + This entire approach seems to be superceded by the "subwindow" flavor + of GLUI. +*/ +class GLUI_Glut_Window : public GLUI_Node +{ +public: + GLUI_Glut_Window(); + + int glut_window_id; + + /*********** Pointers to GLUT callthrough functions *****/ + void (*glut_keyboard_CB)(unsigned char, int, int); + void (*glut_special_CB)(int, int, int); + void (*glut_reshape_CB)(int, int); + void (*glut_passive_motion_CB)(int,int); + void (*glut_mouse_CB)(int,int,int,int); + void (*glut_visibility_CB)(int); + void (*glut_motion_CB)(int,int); + void (*glut_display_CB)(void); + void (*glut_entry_CB)(int); +}; + +/************************************************************/ +/* */ +/* Main Window GLUI class (not user-level) */ +/* */ +/************************************************************/ + +/** + A GLUI_Main handles GLUT events for one window, routing them to the + appropriate controls. The central user-visible "GLUI" class + inherits from this class; users should not allocate GLUT_Main objects. + + There's a separate GLUI_Main object for: + - Each top-level window with GUI stuff in it. + - Each "subwindow" of another top-level window. + + All the GLUI_Main objects are listed in GLUI_Master.gluis. + A better name for this class might be "GLUI_Environment"; + this class provides the window-level context for every control. +*/ +class GLUI_Main : public GLUI_Node +{ + /********** Friend classes *************/ + + friend class GLUI_Control; + friend class GLUI_Rotation; + friend class GLUI_Translation; + friend class GLUI; + friend class GLUI_Master_Object; + + /*********** Friend functions **********/ + + friend void glui_mouse_func(int button, int state, int x, int y); + friend void glui_keyboard_func(unsigned char key, int x, int y); + friend void glui_special_func(int key, int x, int y); + friend void glui_passive_motion_func(int x, int y); + friend void glui_reshape_func( int w, int h ); + friend void glui_visibility_func(int state); + friend void glui_motion_func(int x, int y); + friend void glui_entry_func(int state); + friend void glui_display_func( void ); + friend void glui_idle_func(void); + + friend void glui_parent_window_reshape_func( int w, int h ); + friend void glui_parent_window_keyboard_func( unsigned char, int, int ); + friend void glui_parent_window_special_func( int, int, int ); + friend void glui_parent_window_mouse_func( int, int, int, int ); + +protected: + /*** Variables ***/ + int main_gfx_window_id; + int mouse_button_down; + int glut_window_id; + int top_level_glut_window_id; + GLUI_Control *active_control; + GLUI_Control *mouse_over_control; + GLUI_Panel *main_panel; + enum buffer_mode_t { + buffer_front=1, ///< Draw updated controls directly to screen. + buffer_back=2 ///< Double buffering: postpone updates until next redraw. + }; + buffer_mode_t buffer_mode; ///< Current drawing mode + int curr_cursor; + int w, h; + long flags; + bool closing; + int parent_window; + int glui_id; + + /********** Misc functions *************/ + + GLUI_Control *find_control( int x, int y ); + GLUI_Control *find_next_control( GLUI_Control *control ); + GLUI_Control *find_next_control_rec( GLUI_Control *control ); + GLUI_Control *find_next_control_( GLUI_Control *control ); + GLUI_Control *find_prev_control( GLUI_Control *control ); + void create_standalone_window( const char *name, int x=-1, int y=-1 ); + void create_subwindow( int parent,int window_alignment ); + void setup_default_glut_callbacks( void ); + + void mouse(int button, int state, int x, int y); + void keyboard(unsigned char key, int x, int y); + void special(int key, int x, int y); + void passive_motion(int x, int y); + void reshape( int w, int h ); + void visibility(int state); + void motion(int x, int y); + void entry(int state); + void display( void ); + void idle(void); + int needs_idle(void); + + void (*glut_mouse_CB)(int, int, int, int); + void (*glut_keyboard_CB)(unsigned char, int, int); + void (*glut_special_CB)(int, int, int); + void (*glut_reshape_CB)(int, int); + + + /*********** Controls ************/ + + virtual int add_control( GLUI_Node *parent, GLUI_Control *control ); + + + /********** Constructors and Destructors ***********/ + + GLUI_Main( void ); + +public: + GLUI_StdBitmaps std_bitmaps; + GLUI_String window_name; + RGBc bkgd_color; + float bkgd_color_f[3]; + + void *font; + int curr_modifiers; + + void adjust_glut_xy( int &x, int &y ) { x; y = h-y; } + void activate_control( GLUI_Control *control, int how ); + void align_controls( GLUI_Control *control ); + void deactivate_current_control( void ); + + /** Draw a 3D-look pushed-out box around this rectangle */ + void draw_raised_box( int x, int y, int w, int h ); + /** Draw a 3D-look pushed-in box around this rectangle */ + void draw_lowered_box( int x, int y, int w, int h ); + + /** Return true if this control should redraw itself immediately (front buffer); + Or queue up a redraw and return false if it shouldn't (back buffer). + */ + bool should_redraw_now(GLUI_Control *ctl); + + /** Switch to the appropriate draw buffer now. Returns the old draw buffer. + This routine should probably only be called from inside the GLUI_DrawingSentinal, + in glui_internal_control.h + */ + int set_current_draw_buffer(); + /** Go back to using this draw buffer. Undoes set_current_draw_buffer. */ + void restore_draw_buffer( int buffer_state ); + + /** Pack, resize the window, and redraw all the controls. */ + void refresh(); + + /** Redraw the main graphics window */ + void post_update_main_gfx(); + + /** Recompute the sizes and positions of all controls */ + void pack_controls(); + + void close_internal(); + void check_subwindow_position(); + void set_ortho_projection(); + void set_viewport(); + int get_glut_window_id( void ) { return glut_window_id; } /* JVK */ +}; + +/************************************************************/ +/* */ +/* GLUI_Control: base class for all controls */ +/* */ +/************************************************************/ + +/** + All the GUI objects inherit from GLUI_Control: buttons, + checkboxes, labels, edit boxes, scrollbars, etc. + Most of the work of this class is in routing events, + like keystrokes, mouseclicks, redraws, and sizing events. + + Yes, this is a huge and hideous class. It needs to be + split up into simpler subobjects. None of the data members + should be directly accessed by users (they should be protected, + not public); only subclasses. +*/ +class GLUI_Control : public GLUI_Node +{ +public: + +/** Onscreen coordinates */ + int w, h; /* dimensions of control */ + int x_abs, y_abs; + int x_off, y_off_top, y_off_bot; /* INNER margins, by which child + controls are indented */ + int contain_x, contain_y; + int contain_w, contain_h; + /* if this is a container control (e.g., + radiogroup or panel) this indicated dimensions + of inner area in which controls reside */ + +/** "activation" for tabbing between controls. */ + int active_type; ///< "GLUI_CONTROL_ACTIVE_..." + bool active; ///< If true, we've got the focus + bool can_activate; ///< If false, remove from tab order. + bool spacebar_mouse_click; ///< Spacebar simulates click. + +/** Callbacks */ + long user_id; ///< Integer to pass to callback function. + GLUI_CB callback; ///< User callback function, or NULL. + +/** Variable value storage */ + float float_val; /**< Our float value */ + int int_val; /**< Our integer value */ + float float_array_val[GLUI_DEF_MAX_ARRAY]; + int float_array_size; + GLUI_String text; /**< The text inside this control */ + +/** "Live variable" updating */ + void *ptr_val; /**< A pointer to the user's live variable value */ + int live_type; + bool live_inited; + /* These variables store the last value that live variable was known to have. */ + int last_live_int; + float last_live_float; + GLUI_String last_live_text; + float last_live_float_array[GLUI_DEF_MAX_ARRAY]; + +/** Properties of our control */ + GLUI *glui; /**< Our containing event handler (NEVER NULL during event processing!) */ + bool is_container; /**< Is this a container class (e.g., panel) */ + int alignment; + bool enabled; /**< Is this control grayed out? */ + GLUI_String name; /**< The name of this control */ + void *font; /**< Our glutbitmap font */ + bool collapsible, is_open; + GLUI_Node collapsed_node; + bool hidden; /* Collapsed controls (and children) are hidden */ + int char_widths[CHAR_WIDTH_HASH_SIZE][2]; /* Character width hash table */ + +public: + /*** Get/Set values ***/ + virtual void set_name( const char *string ); + virtual void set_int_val( int new_int ) { int_val = new_int; output_live(true); } + virtual void set_float_val( float new_float ) { float_val = new_float; output_live(true); } + virtual void set_ptr_val( void *new_ptr ) { ptr_val = new_ptr; output_live(true); } + virtual void set_float_array_val( float *array_ptr ); + + virtual float get_float_val( void ) { return float_val; } + virtual int get_int_val( void ) { return int_val; } + virtual void get_float_array_val( float *array_ptr ); + virtual int get_id( void ) const { return int(user_id); } + virtual void set_id( int id ) { user_id=id; } + + virtual int mouse_down_handler( int local_x, int local_y ) { local_x; local_y; return false; } + virtual int mouse_up_handler( int local_x, int local_y, bool inside ) { local_x; local_y; inside; return false; } + virtual int mouse_held_down_handler( int local_x, int local_y, bool inside) { local_x; local_y; inside; return false; } + virtual int key_handler( unsigned char key, int modifiers ) { key; modifiers; return false; } + virtual int special_handler( int key,int modifiers ) { key; modifiers; return false; } + + virtual void update_size( void ) { } + virtual void idle( void ) { } + virtual int mouse_over( int state, int x, int y ) { state; x; y; return false; } + + virtual void enable( void ); + virtual void disable( void ); + virtual void activate( int how ) { how; active = true; } + virtual void deactivate( void ) { active = false; } + + /** Hide (shrink into a rollout) and unhide (expose from a rollout) */ + void hide_internal( int recurse ); + void unhide_internal( int recurse ); + + /** Return true if it currently makes sense to draw this class. */ + int can_draw( void ) { return (glui != NULL && hidden == false); } + + /** Redraw this control. + In single-buffering mode (drawing to GL_FRONT), this is just + a call to translate_and_draw_front (after a can_draw() check). + In double-buffering mode (drawing to GL_BACK), this queues up + a redraw and returns false, since you shouldn't draw yet. + */ + void redraw(void); + + /** Redraw everybody in our window. */ + void redraw_window(void); + + virtual void align( void ); + void pack( int x, int y ); /* Recalculate positions and offsets */ + void pack_old( int x, int y ); + void draw_recursive( int x, int y ); + int set_to_glut_window( void ); + void restore_window( int orig ); + void translate_and_draw_front( void ); + void translate_to_origin( void ) + {glTranslatef((float)x_abs+.5f,(float)y_abs+.5f,0.0f);} + virtual void draw( int x, int y )=0; + void set_font( void *new_font ); + void *get_font( void ); + int string_width( const char *text ); + int string_width( const GLUI_String &str ) + { return string_width(str.c_str()); } + int char_width( char c ); + + void draw_name( int x, int y ); + void draw_box_inwards_outline( int x_min, int x_max, + int y_min, int y_max ); + void draw_box( int x_min, int x_max, int y_min, int y_max, + float r, float g, float b ); + void draw_bkgd_box( int x_min, int x_max, int y_min, int y_max ); + void draw_emboss_box( int x_min, int x_max,int y_min,int y_max); + void draw_string( const char *text ); + void draw_string( const GLUI_String &s ) + { draw_string(s.c_str()); } + void draw_char( char c ); + void draw_active_box( int x_min, int x_max, int y_min, int y_max ); + void set_to_bkgd_color( void ); + + void set_w( int new_w ); + void set_h( int new_w ); + void set_alignment( int new_align ); + void sync_live( int recurse, int draw ); /* Reads live variable */ + void init_live( void ); + void output_live( int update_main_gfx ); /** Writes live variable **/ + virtual void set_text( const char *t ) { t; } + void execute_callback( void ); + void get_this_column_dims( int *col_x, int *col_y, + int *col_w, int *col_h, + int *col_x_off, int *col_y_off ); + virtual bool needs_idle( void ) const; + virtual bool wants_tabs() const { return false; } + + GLUI_Control(void) + { + x_off = GLUI_XOFF; + y_off_top = GLUI_YOFF; + y_off_bot = GLUI_YOFF; + x_abs = GLUI_XOFF; + y_abs = GLUI_YOFF; + active = false; + enabled = true; + int_val = 0; + last_live_int = 0; + float_array_size = 0; + glui_format_str(name, "Control: %p", this); + float_val = 0.0; + last_live_float = 0.0; + ptr_val = NULL; + glui = NULL; + w = GLUI_DEFAULT_CONTROL_WIDTH; + h = GLUI_DEFAULT_CONTROL_HEIGHT; + font = NULL; + active_type = GLUI_CONTROL_ACTIVE_MOUSEDOWN; + alignment = GLUI_ALIGN_LEFT; + is_container = false; + can_activate = true; /* By default, you can activate a control */ + spacebar_mouse_click = true; /* Does spacebar simulate a mouse click? */ + live_type = GLUI_LIVE_NONE; + text = ""; + last_live_text == ""; + live_inited = false; + collapsible = false; + is_open = true; + hidden = false; + memset(char_widths, -1, sizeof(char_widths)); /* JVK */ + int i; + for( i=0; iint_val = 1; set_color(red, green, blue); } } + void disable_bar() { if (column) { column->int_val = 0; } } + void set_child_number(int c) { child_number = c; } + void set_level_color(float r, float g, float b) { + lred = r; + lgreen = g; + lblue = b; + } + void set_color(float r, float g, float b) { + red = r; + green = g; + blue = b; + } +protected: + void common_init() + { + currently_inside = false; + initially_inside = false; + can_activate = true; + is_container = true; + h = GLUI_DEFAULT_CONTROL_HEIGHT + 7; + w = GLUI_DEFAULT_CONTROL_WIDTH; + y_off_top = 21; + collapsible = true; + red = .5; + green = .5; + blue = .5; + lred = 0; + lgreen = 0; + lblue = 0; + column = NULL; + is_current = 0; + child_number = 0; + format = 0; + panel = NULL; + name = ""; + level_name = ""; + level = 0; + + }; +}; + + +/************************************************************/ +/* */ +/* TreePanel class (container) JVK */ +/* */ +/************************************************************/ + +/** + Manages, maintains, and formats a tree of GLUI_Tree objects. + These are shown in a heirarchical, collapsible display. + + FIXME: There's an infinite loop in the traversal code (OSL 2006/06) +*/ +class GLUI_TreePanel : public GLUI_Panel +{ +public: + GLUI_TreePanel(GLUI_Node *parent, const char *name, + bool open=false, int inset=0); + + int max_levels; + int next_id; + int format; + float red; + float green; + float blue; + float lred; + float lgreen; + float lblue; + int root_children; + /* These variables allow the tree panel to traverse the tree + using only two function calls. (Well, four, if you count + going in reverse */ + + GLUI_Tree *curr_branch; /* Current Branch */ + GLUI_Panel *curr_root; /* Current Root */ + +public: + void set_color(float r, float g, float b); + void set_level_color(float r, float g, float b); + void set_format(int f) { format = f; } + + /* Adds branch to curr_root */ + GLUI_Tree * ab(const char *name, GLUI_Tree *root = NULL); + /* Goes up one level, resets curr_root and curr_branch to parents*/ + void fb(GLUI_Tree *branch= NULL); + /* Deletes the curr_branch, goes up one level using fb */ + void db(GLUI_Tree *branch = NULL); + /* Finds the very last branch of curr_root, resets vars */ + void descendBranch(GLUI_Panel *root = NULL); + /* Resets curr_root and curr branch to TreePanel and lastChild */ + void resetToRoot(GLUI_Panel *new_root = NULL); + void next( void ); + void refresh( void ); + void expand_all( void ); + void collapse_all( void ); + void update_all( void ); + void initNode(GLUI_Tree *temp); + void formatNode(GLUI_Tree *temp); + +protected: + int uniqueID( void ) { next_id++; return next_id - 1; } + void common_init() + { + GLUI_Panel(); + next_id = 0; + curr_root = this; + curr_branch = NULL; + red = .5; + green = .5; + blue = .5; + root_children = 0; + } +}; + +/************************************************************/ +/* */ +/* User-Level GLUI class */ +/* */ +/************************************************************/ + +class GLUI_Rotation; +class GLUI_Translation; + +/** + The main user-visible interface object to GLUI. + +*/ +class GLUI : public GLUI_Main +{ +public: +/** DEPRECATED interface for creating new GLUI objects */ + int add_control( GLUI_Control *control ) { return main_panel->add_control(control); } + + void add_column( int draw_bar = true ); + void add_column_to_panel( GLUI_Panel *panel, int draw_bar = true ); + + void add_separator( void ); + void add_separator_to_panel( GLUI_Panel *panel ); + + GLUI_RadioGroup + *add_radiogroup( int *live_var=NULL, + int user_id=-1,GLUI_CB callback=GLUI_CB()); + + GLUI_RadioGroup + *add_radiogroup_to_panel( GLUI_Panel *panel, + int *live_var=NULL, + int user_id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_RadioButton + *add_radiobutton_to_group( GLUI_RadioGroup *group, + const char *name ); + + GLUI_Listbox *add_listbox( const char *name, int *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_Listbox *add_listbox_to_panel( GLUI_Panel *panel, + const char *name, int *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB()); + + GLUI_Rotation *add_rotation( const char *name, float *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_Rotation *add_rotation_to_panel( GLUI_Panel *panel, + const char *name, float *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB()); + + GLUI_Translation *add_translation( const char *name, + int trans_type, float *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_Translation *add_translation_to_panel( + GLUI_Panel *panel, const char *name, + int trans_type, float *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB()); + + GLUI_Checkbox *add_checkbox( const char *name, + int *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB()); + GLUI_Checkbox *add_checkbox_to_panel( GLUI_Panel *panel, const char *name, + int *live_var=NULL, int id=-1, + GLUI_CB callback=GLUI_CB()); + + GLUI_Button *add_button( const char *name, int id=-1, + GLUI_CB callback=GLUI_CB()); + GLUI_Button *add_button_to_panel( GLUI_Panel *panel, const char *name, + int id=-1, GLUI_CB callback=GLUI_CB() ); + + GLUI_StaticText *add_statictext( const char *name ); + GLUI_StaticText *add_statictext_to_panel( GLUI_Panel *panel, const char *name ); + + GLUI_EditText *add_edittext( const char *name, + int data_type=GLUI_EDITTEXT_TEXT, + void*live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_EditText *add_edittext_to_panel( GLUI_Panel *panel, + const char *name, + int data_type=GLUI_EDITTEXT_TEXT, + void *live_var=NULL, int id=-1, + GLUI_CB callback=GLUI_CB() ); + GLUI_EditText *add_edittext( const char *name, GLUI_String& live_var, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_EditText *add_edittext_to_panel( GLUI_Panel *panel, const char *name, + GLUI_String& live_var, int id=-1, + GLUI_CB callback=GLUI_CB() ); + + GLUI_Spinner *add_spinner( const char *name, + int data_type=GLUI_SPINNER_INT, + void *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_Spinner *add_spinner_to_panel( GLUI_Panel *panel, + const char *name, + int data_type=GLUI_SPINNER_INT, + void *live_var=NULL, + int id=-1, + GLUI_CB callback=GLUI_CB() ); + + GLUI_Panel *add_panel( const char *name, int type=GLUI_PANEL_EMBOSSED ); + GLUI_Panel *add_panel_to_panel( GLUI_Panel *panel, const char *name, + int type=GLUI_PANEL_EMBOSSED ); + + + GLUI_Rollout *add_rollout( const char *name, int open=true, + int type=GLUI_PANEL_EMBOSSED); + GLUI_Rollout *add_rollout_to_panel( GLUI_Panel *panel, const char *name, + int open=true, + int type=GLUI_PANEL_EMBOSSED); + + +/** Set the window where our widgets should be displayed. */ + void set_main_gfx_window( int window_id ); + int get_glut_window_id( void ) { return glut_window_id; } + + void enable( void ) { main_panel->enable(); } + void disable( void ); + + void sync_live( void ); + + void close( void ); + + void show( void ); + void hide( void ); + + /***** GLUT callback setup functions *****/ + /* + void set_glutDisplayFunc(void (*f)(void)); + void set_glutReshapeFunc(void (*f)(int width, int height)); + void set_glutKeyboardFunc(void (*f)(unsigned char key, int x, int y)); + void set_glutSpecialFunc(void (*f)(int key, int x, int y)); + void set_glutMouseFunc(void (*f)(int button, int state, int x, int y)); + void set_glutMotionFunc(void (*f)(int x, int y)); + void set_glutPassiveMotionFunc(void (*f)(int x, int y)); + void set_glutEntryFunc(void (*f)(int state)); + void set_glutVisibilityFunc(void (*f)(int state)); + void set_glutInit( int *argcp, const char **argv ); + void set_glutInitWindowSize(int width, int height); + void set_glutInitWindowPosition(int x, int y); + void set_glutInitDisplayMode(unsigned int mode); + int set_glutCreateWindow(const char *name); + */ + + /***** Constructors and desctructors *****/ + + int init( const char *name, long flags, int x, int y, int parent_window ); +protected: + virtual int add_control( GLUI_Node *parent, GLUI_Control *control ) { + return GLUI_Main::add_control( parent, control ); + } +}; + +/************************************************************/ +/* */ +/* EditText class */ +/* */ +/************************************************************/ + +class GLUI_EditText : public GLUI_Control +{ +public: + int has_limits; + int data_type; + GLUI_String orig_text; + int insertion_pt; + int title_x_offset; + int text_x_offset; + int substring_start; /*substring that gets displayed in box*/ + int substring_end; + int sel_start, sel_end; /* current selection */ + int num_periods; + int last_insertion_pt; + float float_low, float_high; + int int_low, int_high; + GLUI_Spinner *spinner; + int debug; + int draw_text_only; + + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + int key_handler( unsigned char key,int modifiers ); + int special_handler( int key, int modifiers ); + + void activate( int how ); + void deactivate( void ); + + void draw( int x, int y ); + + int mouse_over( int state, int x, int y ); + + int find_word_break( int start, int direction ); + int substring_width( int start, int end ); + void clear_substring( int start, int end ); + int find_insertion_pt( int x, int y ); + int update_substring_bounds( void ); + void update_and_draw_text( void ); + void draw_text( int x, int y ); + void draw_insertion_pt( void ); + void set_numeric_text( void ); + void update_x_offsets( void ); + void update_size( void ); + + void set_float_limits( float low,float high,int limit_type=GLUI_LIMIT_CLAMP); + void set_int_limits( int low, int high, int limit_type=GLUI_LIMIT_CLAMP ); + void set_float_val( float new_val ); + void set_int_val( int new_val ); + void set_text( const char *text ); + void set_text( const GLUI_String &s) { set_text(s.c_str()); } + const char *get_text() { return text.c_str(); } + + void dump( FILE *out, const char *text ); + + // Constructor, no live variable + GLUI_EditText( GLUI_Node *parent, const char *name, + int text_type=GLUI_EDITTEXT_TEXT, + int id=-1, GLUI_CB callback=GLUI_CB() ); + // Constructor, int live variable + GLUI_EditText( GLUI_Node *parent, const char *name, + int *live_var, + int id=-1, GLUI_CB callback=GLUI_CB() ); + // Constructor, float live variable + GLUI_EditText( GLUI_Node *parent, const char *name, + float *live_var, + int id=-1, GLUI_CB callback=GLUI_CB() ); + // Constructor, char* live variable + GLUI_EditText( GLUI_Node *parent, const char *name, + char *live_var, + int id=-1, GLUI_CB callback=GLUI_CB() ); + // Constructor, std::string live variable + GLUI_EditText( GLUI_Node *parent, const char *name, + std::string &live_var, + int id=-1, GLUI_CB callback=GLUI_CB() ); + + // Deprecated constructor, only called internally + GLUI_EditText( GLUI_Node *parent, const char *name, + int text_type, void *live_var, + int id, GLUI_CB callback ); + // Deprecated constructor, only called internally + GLUI_EditText( void ) { common_init(); } + +protected: + void common_init( void ) { + h = GLUI_EDITTEXT_HEIGHT; + w = GLUI_EDITTEXT_WIDTH; + title_x_offset = 0; + text_x_offset = 55; + insertion_pt = -1; + last_insertion_pt = -1; + name = ""; + substring_start = 0; + data_type = GLUI_EDITTEXT_TEXT; + substring_end = 2; + num_periods = 0; + has_limits = GLUI_LIMIT_NONE; + sel_start = 0; + sel_end = 0; + active_type = GLUI_CONTROL_ACTIVE_PERMANENT; + can_activate = true; + spacebar_mouse_click = false; + spinner = NULL; + debug = false; + draw_text_only = false; + } + void common_construct( GLUI_Node *parent, const char *name, + int data_type, int live_type, void *live_var, + int id, GLUI_CB callback ); +}; + +/************************************************************/ +/* */ +/* CommandLine class */ +/* */ +/************************************************************/ + +class GLUI_CommandLine : public GLUI_EditText +{ +public: + typedef GLUI_EditText Super; + + enum { HIST_SIZE = 100 }; + std::vector hist_list; + int curr_hist; + int oldest_hist; + int newest_hist; + bool commit_flag; + +public: + int key_handler( unsigned char key,int modifiers ); + int special_handler( int key,int modifiers ); + void deactivate( void ); + + virtual const char *get_history( int command_number ) const + { return hist_list[command_number - oldest_hist].c_str(); } + virtual GLUI_String& get_history_str( int command_number ) + { return hist_list[command_number - oldest_hist]; } + virtual const GLUI_String& get_history_str( int command_number ) const + { return hist_list[command_number - oldest_hist]; } + virtual void recall_history( int history_number ); + virtual void scroll_history( int direction ); + virtual void add_to_history( const char *text ); + virtual void reset_history( void ); + + void dump( FILE *out, const char *text ); + + + GLUI_CommandLine( GLUI_Node *parent, const char *name, void *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_CommandLine( void ) { common_init(); } +protected: + void common_init() { + hist_list.resize(HIST_SIZE); + curr_hist = 0; + oldest_hist = 0; + newest_hist = 0; + commit_flag = false; + } +}; + +/************************************************************/ +/* */ +/* RadioGroup class (container) */ +/* */ +/************************************************************/ + +class GLUI_RadioGroup : public GLUI_Control +{ +public: + int num_buttons; + + void draw( int x, int y ); + void set_name( const char *text ); + void set_int_val( int int_val ); + void set_selected( int int_val ); + + void draw_group( int translate ); + + GLUI_RadioGroup( GLUI_Node *parent, int *live_var=NULL, + int user_id=-1,GLUI_CB callback=GLUI_CB() ); + GLUI_RadioGroup( void ) { common_init(); } + +protected: + void common_init( void ) { + x_off = 0; + y_off_top = 0; + y_off_bot = 0; + is_container = true; + w = 300; + h = 300; + num_buttons = 0; + name = ""; + can_activate = false; + live_type = GLUI_LIVE_INT; + } +}; + +/************************************************************/ +/* */ +/* RadioButton class (container) */ +/* */ +/************************************************************/ + +class GLUI_RadioButton : public GLUI_Control +{ +public: + int orig_value; + bool currently_inside; + int text_x_offset; + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + + void draw( int x, int y ); + void update_size( void ); + + void draw_active_area( void ); + void draw_checked( void ); + void draw_unchecked( void ); + void draw_O( void ); + + GLUI_RadioButton( GLUI_RadioGroup *group, const char *name ); + GLUI_RadioGroup *group; + +protected: + void common_init() + { + glui_format_str( name, "RadioButton: %p", (void *) this ); + h = GLUI_RADIOBUTTON_SIZE; + group = NULL; + orig_value = -1; + text_x_offset = 18; + can_activate = true; + } +}; + + +/************************************************************/ +/* */ +/* Separator class (container) */ +/* */ +/************************************************************/ + +class GLUI_Separator : public GLUI_Control +{ +public: + void draw( int x, int y ); + + GLUI_Separator( GLUI_Node *parent ); + GLUI_Separator( void ) { common_init(); } + +protected: + void common_init() { + w = 100; + h = GLUI_SEPARATOR_HEIGHT; + can_activate = false; + } +}; + +#define GLUI_SPINNER_ARROW_WIDTH 12 +#define GLUI_SPINNER_ARROW_HEIGHT 8 +#define GLUI_SPINNER_ARROW_Y 2 + +#define GLUI_SPINNER_STATE_NONE 0 +#define GLUI_SPINNER_STATE_UP 1 +#define GLUI_SPINNER_STATE_DOWN 2 +#define GLUI_SPINNER_STATE_BOTH 3 + +#define GLUI_SPINNER_DEFAULT_GROWTH_EXP 1.05f + +/************************************************************/ +/* */ +/* Spinner class (container) */ +/* */ +/************************************************************/ + +class GLUI_Spinner : public GLUI_Control +{ +public: + // Constructor, no live var + GLUI_Spinner( GLUI_Node* parent, const char *name, + int data_type=GLUI_SPINNER_INT, int id=-1, GLUI_CB callback=GLUI_CB() ); + // Constructor, int live var + GLUI_Spinner( GLUI_Node* parent, const char *name, + int *live_var, int id=-1, GLUI_CB callback=GLUI_CB() ); + // Constructor, float live var + GLUI_Spinner( GLUI_Node* parent, const char *name, + float *live_var, int id=-1, GLUI_CB callback=GLUI_CB() ); + // Deprecated constructor + GLUI_Spinner( GLUI_Node* parent, const char *name, + int data_type, + void *live_var, + int id=-1, GLUI_CB callback=GLUI_CB() ); + // Deprecated constructor + GLUI_Spinner( void ) { common_init(); } + + bool currently_inside; + int state; + float growth, growth_exp; + int last_x, last_y; + int data_type; + int callback_count; + int last_int_val; + float last_float_val; + int first_callback; + float user_speed; + + GLUI_EditText *edittext; + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + int key_handler( unsigned char key,int modifiers ); + int special_handler( int key,int modifiers ); + + void draw( int x, int y ); + void draw_pressed( void ); + void draw_unpressed( void ); + void draw_text( int sunken ); + + void update_size( void ); + + void set_float_limits( float low,float high,int limit_type=GLUI_LIMIT_CLAMP); + void set_int_limits( int low, int high,int limit_type=GLUI_LIMIT_CLAMP); + int find_arrow( int local_x, int local_y ); + void do_drag( int x, int y ); + void do_callbacks( void ); + void do_click( void ); + void idle( void ); + bool needs_idle( void ) const; + + const char *get_text( void ); + + void set_float_val( float new_val ); + void set_int_val( int new_val ); + float get_float_val( void ); + int get_int_val( void ); + void increase_growth( void ); + void reset_growth( void ); + + void set_speed( float speed ) { user_speed = speed; } + +protected: + void common_init() { + glui_format_str( name, "Spinner: %p", this ); + h = GLUI_EDITTEXT_HEIGHT; + w = GLUI_EDITTEXT_WIDTH; + x_off = 0; + y_off_top = 0; + y_off_bot = 0; + can_activate = true; + state = GLUI_SPINNER_STATE_NONE; + edittext = NULL; + growth_exp = GLUI_SPINNER_DEFAULT_GROWTH_EXP; + callback_count = 0; + first_callback = true; + user_speed = 1.0; + } + void common_construct( GLUI_Node* parent, const char *name, + int data_type, void *live_var, + int id, GLUI_CB callback ); +}; + +/************************************************************/ +/* */ +/* StaticText class */ +/* */ +/************************************************************/ + +class GLUI_StaticText : public GLUI_Control +{ +public: + void set_text( const char *text ); + void draw( int x, int y ); + void draw_text( void ); + void update_size( void ); + void erase_text( void ); + + GLUI_StaticText(GLUI_Node *parent, const char *name); + GLUI_StaticText( void ) { common_init(); } + +protected: + void common_init() { + h = GLUI_STATICTEXT_SIZE; + name = ""; + can_activate = false; + } +}; + +/************************************************************/ +/* */ +/* TextBox class - JVK */ +/* */ +/************************************************************/ + +class GLUI_TextBox : public GLUI_Control +{ +public: + /* GLUI Textbox - JVK */ + GLUI_TextBox(GLUI_Node *parent, GLUI_String &live_var, + bool scroll = false, int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_TextBox( GLUI_Node *parent, + bool scroll = false, int id=-1, + GLUI_CB callback=GLUI_CB() ); + + GLUI_String orig_text; + int insertion_pt; + int substring_start; /*substring that gets displayed in box*/ + int substring_end; + int sel_start, sel_end; /* current selection */ + int last_insertion_pt; + int debug; + int draw_text_only; + int tab_width; + int start_line; + int num_lines; + int curr_line; + int visible_lines; + int insert_x; /* Similar to "insertion_pt", these variables keep */ + int insert_y; /* track of where the ptr is, but in pixels */ + int keygoal_x; /* where up down keys would like to put insertion pt*/ + GLUI_Scrollbar *scrollbar; + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + int key_handler( unsigned char key,int modifiers ); + int special_handler( int key,int modifiers ); + + void activate( int how ); + void deactivate( void ); + + void enable( void ); + void disable( void ); + + void draw( int x, int y ); + + int mouse_over( int state, int x, int y ); + + int get_box_width(); + int find_word_break( int start, int direction ); + int substring_width( int start, int end, int initial_width=0 ); + void clear_substring( int start, int end ); + int find_insertion_pt( int x, int y ); + int update_substring_bounds( void ); + void update_and_draw_text( void ); + void draw_text( int x, int y ); + void draw_insertion_pt( void ); + void update_x_offsets( void ); + void update_size( void ); + + void set_text( const char *text ); + const char *get_text( void ) { return text.c_str(); } + + void dump( FILE *out, char *text ); + void set_tab_w(int w) { tab_width = w; } + void set_start_line(int l) { start_line = l; } + static void scrollbar_callback(GLUI_Control*); + + bool wants_tabs( void ) const { return true; } + +protected: + void common_init() + { + h = GLUI_TEXTBOX_HEIGHT; + w = GLUI_TEXTBOX_WIDTH; + tab_width = GLUI_TAB_WIDTH; + num_lines = 0; + visible_lines = 0; + start_line = 0; + curr_line = 0; + insert_y = -1; + insert_x = -1; + insertion_pt = -1; + last_insertion_pt = -1; + name[0] = '\0'; + substring_start = 0; + substring_end = 2; + sel_start = 0; + sel_end = 0; + active_type = GLUI_CONTROL_ACTIVE_PERMANENT; + can_activate = true; + spacebar_mouse_click = false; + scrollbar = NULL; + debug = false; + draw_text_only = false; + } + void common_construct( + GLUI_Node *parent, GLUI_String *live_var, + bool scroll, int id, GLUI_CB callback); +}; + +/************************************************************/ +/* */ +/* List class - JVK */ +/* */ +/************************************************************/ + +class GLUI_List_Item : public GLUI_Node +{ +public: + GLUI_String text; + int id; +}; + +/************************************************************/ +/* */ +/* List class - JVK */ +/* */ +/************************************************************/ + +class GLUI_List : public GLUI_Control +{ +public: + /* GLUI List - JVK */ + GLUI_List( GLUI_Node *parent, bool scroll = false, + int id=-1, GLUI_CB callback=GLUI_CB() ); + /*, GLUI_Control *object = NULL + ,GLUI_InterObject_CB obj_cb = NULL);*/ + + GLUI_List( GLUI_Node *parent, + GLUI_String& live_var, bool scroll = false, + int id=-1, + GLUI_CB callback=GLUI_CB() + /*,GLUI_Control *object = NULL */ + /*,GLUI_InterObject_CB obj_cb = NULL*/); + + + GLUI_String orig_text; + int debug; + int draw_text_only; + int start_line; + int num_lines; + int curr_line; + int visible_lines; + GLUI_Scrollbar *scrollbar; + GLUI_List_Item items_list; + GLUI_Control *associated_object; + GLUI_CB obj_cb; + int cb_click_type; + int last_line; + int last_click_time; + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + int key_handler( unsigned char key,int modifiers ); + int special_handler( int key,int modifiers ); + + void activate( int how ); + void deactivate( void ); + + void draw( int x, int y ); + + int mouse_over( int state, int x, int y ); + + int get_box_width(); + int find_word_break( int start, int direction ); + int substring_width( const char *t, int start, int end ); + int find_line( int x, int y ); + void update_and_draw_text( void ); + void draw_text( const char *t, int selected, int x, int y ); + void update_size( void ); + + + int add_item( int id, const char *text ); + int delete_item( const char *text ); + int delete_item( int id ); + int delete_all(); + + GLUI_List_Item *get_item_ptr( const char *text ); + GLUI_List_Item *get_item_ptr( int id ); + + void dump( FILE *out, const char *text ); + void set_start_line(int l) { start_line = l; } + static void scrollbar_callback(GLUI_Control*); + int get_current_item() { return curr_line; } + void set_click_type(int d) { + cb_click_type = d; } + void set_object_callback(GLUI_CB cb=GLUI_CB(), GLUI_Control*obj=NULL) + { obj_cb=cb; associated_object=obj; } + +protected: + void common_init() + { + h = GLUI_LIST_HEIGHT; + w = GLUI_LIST_WIDTH; + num_lines = 0; + visible_lines = 0; + start_line = 0; + curr_line = 0; + name[0] = '\0'; + active_type = GLUI_CONTROL_ACTIVE_PERMANENT; + can_activate = true; + spacebar_mouse_click = false; + scrollbar = NULL; + debug = false; + draw_text_only = false; + cb_click_type = GLUI_SINGLE_CLICK; + last_line = -1; + last_click_time = 0; + associated_object = NULL; + }; + void common_construct( + GLUI_Node *parent, + GLUI_String* live_var, bool scroll, + int id, + GLUI_CB callback + /*,GLUI_Control *object*/ + /*,GLUI_InterObject_CB obj_cb*/); +}; + +/************************************************************/ +/* */ +/* Scrollbar class - JVK */ +/* */ +/************************************************************/ + +class GLUI_Scrollbar : public GLUI_Control +{ +public: + // Constructor, no live var + GLUI_Scrollbar( GLUI_Node *parent, + const char *name, + int horz_vert=GLUI_SCROLL_HORIZONTAL, + int data_type=GLUI_SCROLL_INT, + int id=-1, GLUI_CB callback=GLUI_CB() + /*,GLUI_Control *object = NULL*/ + /*,GLUI_InterObject_CB obj_cb = NULL*/ + ); + + // Constructor, int live var + GLUI_Scrollbar( GLUI_Node *parent, const char *name, int horz_vert, + int *live_var, + int id=-1, GLUI_CB callback=GLUI_CB() + /*,GLUI_Control *object = NULL*/ + /*,GLUI_InterObject_CB obj_cb = NULL*/ + ); + + // Constructor, float live var + GLUI_Scrollbar( GLUI_Node *parent, const char *name, int horz_vert, + float *live_var, + int id=-1, GLUI_CB callback=GLUI_CB() + /*,GLUI_Control *object = NULL*/ + /*,GLUI_InterObject_CB obj_cb = NULL*/ + ); + + bool currently_inside; + int state; + float growth, growth_exp; + int last_x, last_y; + int data_type; + int callback_count; + int last_int_val; ///< Used to prevent repeated callbacks. + float last_float_val; + int first_callback; + float user_speed; + float float_min, float_max; + int int_min, int_max; + int horizontal; + double last_update_time; ///< GLUI_Time() we last advanced scrollbar. + double velocity_limit; ///< Maximum distance to advance per second. + int box_length; + int box_start_position; + int box_end_position; + int track_length; + + + /* Rather than directly access an Editbox or Textbox for + changing variables, a pointer to some object is defined + along with a static callback in the form func(void *, int) - + the int is the new value, the void * must be cast to that + particular object type before use. + */ + void * associated_object; /* Lets the Spinner manage it's own callbacks */ + GLUI_CB object_cb; /* function pointer to object call_back */ + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + int key_handler( unsigned char key,int modifiers ); + int special_handler( int key,int modifiers ); + + void draw( int x, int y ); + void draw_pressed( void ); + void draw_unpressed( void ); + void draw_text( int sunken ); + + void update_size( void ); + + void set_int_limits( int low, int high,int limit_type=GLUI_LIMIT_CLAMP); + void set_float_limits( float low,float high,int limit_type=GLUI_LIMIT_CLAMP); + int find_arrow( int local_x, int local_y ); + void do_drag( int x, int y ); + void do_callbacks( void ); + void draw_scroll( void ); + void do_click( void ); + void idle( void ); + bool needs_idle( void ) const; + void set_int_val( int new_val ); + void set_float_val( float new_val ); + void increase_growth( void ); + void reset_growth( void ); + + void set_speed( float speed ) { user_speed = speed; }; + void update_scroll_parameters(); + void set_object_callback(GLUI_CB cb=GLUI_CB(), GLUI_Control*obj=NULL) + { object_cb=cb; associated_object=obj; } + +protected: + void common_init ( void ); + void common_construct( + GLUI_Node *parent, + const char *name, + int horz_vert, + int data_type, void* live_var, + int id, GLUI_CB callback + /*,GLUI_Control *object + ,GLUI_InterObject_CB obj_cb*/ + ); + + virtual void draw_scroll_arrow(int arrowtype, int x, int y); + virtual void draw_scroll_box(int x, int y, int w, int h); +}; + +/************************************************************/ +/* */ +/* Listbox class */ +/* */ +/************************************************************/ + +class GLUI_Listbox_Item : public GLUI_Node +{ +public: + GLUI_String text; + int id; +}; + +class GLUI_Listbox : public GLUI_Control +{ +public: + GLUI_String curr_text; + GLUI_Listbox_Item items_list; + int depressed; + + int orig_value; + bool currently_inside; + int text_x_offset, title_x_offset; + int glut_menu_id; + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + int key_handler( unsigned char key,int modifiers ); + int special_handler( int key,int modifiers ); + + void update_size( void ); + void draw( int x, int y ); + int mouse_over( int state, int x, int y ); + + void set_int_val( int new_val ); + void dump( FILE *output ); + + int add_item( int id, const char *text ); + int delete_item( const char *text ); + int delete_item( int id ); + int sort_items( void ); + + int do_selection( int item ); + + GLUI_Listbox_Item *get_item_ptr( const char *text ); + GLUI_Listbox_Item *get_item_ptr( int id ); + + + GLUI_Listbox( GLUI_Node *parent, + const char *name, int *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_Listbox( void ) { common_init(); } + +protected: + /** Change w and return true if we need to be widened to fit the current item. */ + bool recalculate_item_width( void ); + void common_init() { + glui_format_str( name, "Listbox: %p", this ); + w = GLUI_EDITTEXT_WIDTH; + h = GLUI_EDITTEXT_HEIGHT; + orig_value = -1; + title_x_offset = 0; + text_x_offset = 55; + can_activate = true; + curr_text = ""; + live_type = GLUI_LIVE_INT; /* This has an integer live var */ + depressed = false; + glut_menu_id = -1; + } + + ~GLUI_Listbox(); +}; + +/************************************************************/ +/* */ +/* Mouse_Interaction class */ +/* */ +/************************************************************/ + +/** + This is the superclass of translation and rotation widgets. +*/ +class GLUI_Mouse_Interaction : public GLUI_Control +{ +public: + /*int get_main_area_size( void ) { return MIN( h-18, */ + int draw_active_area_only; + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + int special_handler( int key, int modifiers ); + void update_size( void ); + void draw( int x, int y ); + void draw_active_area( void ); + + /*** The following methods (starting with "iaction_") need to + be overloaded ***/ + virtual int iaction_mouse_down_handler( int local_x, int local_y ) = 0; + virtual int iaction_mouse_up_handler( int local_x, int local_y, bool inside )=0; + virtual int iaction_mouse_held_down_handler( int local_x, int local_y, bool inside )=0; + virtual int iaction_special_handler( int key, int modifiers )=0; + virtual void iaction_draw_active_area_persp( void )=0; + virtual void iaction_draw_active_area_ortho( void )=0; + virtual void iaction_dump( FILE *output )=0; + virtual void iaction_init( void ) = 0; + + GLUI_Mouse_Interaction( void ) { + glui_format_str( name, "Mouse_Interaction: %p", this ); + w = GLUI_MOUSE_INTERACTION_WIDTH; + h = GLUI_MOUSE_INTERACTION_HEIGHT; + can_activate = true; + live_type = GLUI_LIVE_NONE; + alignment = GLUI_ALIGN_CENTER; + draw_active_area_only = false; + } +}; + +/************************************************************/ +/* */ +/* Rotation class */ +/* */ +/************************************************************/ + +/** + An onscreen rotation controller--allows the user to interact with + a 3D rotation via a spaceball-like interface. +*/ +class GLUI_Rotation : public GLUI_Mouse_Interaction +{ +public: + Arcball *ball; + GLUquadricObj *quadObj; + bool can_spin, spinning; + float damping; + + int iaction_mouse_down_handler( int local_x, int local_y ); + int iaction_mouse_up_handler( int local_x, int local_y, bool inside ); + int iaction_mouse_held_down_handler( int local_x, int local_y, bool inside ); + int iaction_special_handler( int key, int modifiers ); + void iaction_init( void ) { init_ball(); } + void iaction_draw_active_area_persp( void ); + void iaction_draw_active_area_ortho( void ); + void iaction_dump( FILE *output ); + + /* void update_size( void ); */ + /* void draw( int x, int y ); */ + /* int mouse_over( int state, int x, int y ); */ + + void setup_texture( void ); + void setup_lights( void ); + void draw_ball( float radius ); + + void init_ball( void ); + + void reset( void ); + + bool needs_idle( void ) const; + void idle( void ); + + void copy_float_array_to_ball( void ); + void copy_ball_to_float_array( void ); + + void set_spin( float damp_factor ); + + GLUI_Rotation( GLUI_Node *parent, const char *name, float *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_Rotation(void) { common_init(); } + +protected: + void common_init(); +}; + +/************************************************************/ +/* */ +/* Translation class */ +/* */ +/************************************************************/ + +/** + An onscreen translation controller--allows the user to interact with + a 3D translation. +*/ +class GLUI_Translation : public GLUI_Mouse_Interaction +{ +public: + int trans_type; /* Is this an XY or a Z controller? */ + int down_x, down_y; + float scale_factor; + GLUquadricObj *quadObj; + int trans_mouse_code; + float orig_x, orig_y, orig_z; + int locked; + + int iaction_mouse_down_handler( int local_x, int local_y ); + int iaction_mouse_up_handler( int local_x, int local_y, bool inside ); + int iaction_mouse_held_down_handler( int local_x, int local_y, bool inside ); + int iaction_special_handler( int key, int modifiers ); + void iaction_init( void ) { } + void iaction_draw_active_area_persp( void ); + void iaction_draw_active_area_ortho( void ); + void iaction_dump( FILE *output ); + + void set_speed( float s ) { scale_factor = s; } + + void setup_texture( void ); + void setup_lights( void ); + void draw_2d_arrow( int radius, int filled, int orientation ); + void draw_2d_x_arrows( int radius ); + void draw_2d_y_arrows( int radius ); + void draw_2d_z_arrows( int radius ); + void draw_2d_xy_arrows( int radius ); + + int get_mouse_code( int x, int y ); + + /* Float array is either a single float (for single-axis controls), + or two floats for X and Y (if an XY controller) */ + + float get_z( void ) { return float_array_val[0]; } + float get_x( void ) { return float_array_val[0]; } + float get_y( void ) { + if ( trans_type == GLUI_TRANSLATION_XY ) return float_array_val[1]; + else return float_array_val[0]; + } + + void set_z( float val ); + void set_x( float val ); + void set_y( float val ); + void set_one_val( float val, int index ); + + GLUI_Translation( GLUI_Node *parent, const char *name, + int trans_type, float *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_Translation( void ) { common_init(); } + +protected: + void common_init() { + locked = GLUI_TRANSLATION_LOCK_NONE; + glui_format_str( name, "Translation: %p", this ); + w = GLUI_MOUSE_INTERACTION_WIDTH; + h = GLUI_MOUSE_INTERACTION_HEIGHT; + can_activate = true; + live_type = GLUI_LIVE_FLOAT_ARRAY; + float_array_size = 0; + alignment = GLUI_ALIGN_CENTER; + trans_type = GLUI_TRANSLATION_XY; + scale_factor = 1.0; + quadObj = NULL; + trans_mouse_code = GLUI_TRANSLATION_MOUSE_NONE; + } +}; + +/********** Misc functions *********************/ +int _glutBitmapWidthString( void *font, const char *s ); +void _glutBitmapString( void *font, const char *s ); + +/********** Our own callbacks for glut *********/ +/* These are the callbacks that we pass to glut. They take + some action if necessary, then (possibly) call the user-level + glut callbacks. +*/ + +void glui_display_func( void ); +void glui_reshape_func( int w, int h ); +void glui_keyboard_func(unsigned char key, int x, int y); +void glui_special_func(int key, int x, int y); +void glui_mouse_func(int button, int state, int x, int y); +void glui_motion_func(int x, int y); +void glui_passive_motion_func(int x, int y); +void glui_entry_func(int state); +void glui_visibility_func(int state); +void glui_idle_func(void); + +void glui_parent_window_reshape_func( int w, int h ); +void glui_parent_window_keyboard_func(unsigned char key, int x, int y); +void glui_parent_window_mouse_func(int, int, int, int ); +void glui_parent_window_special_func(int key, int x, int y); + +#endif diff --git a/tests/Box2D_v2.2.1/glui/glui_add_controls.cpp b/tests/Box2D_v2.2.1/glui/glui_add_controls.cpp new file mode 100755 index 0000000000000..9db9293924c82 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_add_controls.cpp @@ -0,0 +1,319 @@ +/**************************************************************************** + + GLUI User Interface Toolkit (LGPL) + --------------------------- + + glui_add_controls.cpp - Routines for adding controls to a GLUI window + +Note: these routines are all deprecated. Keeping them all here +prevents the linker from dragging in all the .o files, even for controls +that aren't used. + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui.h" +#include "glui_internal.h" + + +/*********************************** GLUI:: add_checkbox() ************/ + +GLUI_Checkbox *GLUI:: add_checkbox( const char *name, int *value_ptr, + int id, GLUI_CB callback ) +{ + return add_checkbox_to_panel( main_panel, + name, value_ptr, id, callback ); +} + + +/*********************************** GLUI:: add_checkbox_to_panel() **********/ + +GLUI_Checkbox *GLUI::add_checkbox_to_panel( GLUI_Panel *panel, + const char *name, int *value_ptr, + int id, + GLUI_CB callback ) +{ + return new GLUI_Checkbox( panel, name, value_ptr, id, callback ); +} + +/********************************************* GLUI::add_panel() *************/ + +GLUI_Panel *GLUI::add_panel( const char *name, int type ) +{ + return add_panel_to_panel( main_panel, name, type ); +} + + +/**************************************** GLUI::add_panel_to_panel() *********/ + +GLUI_Panel *GLUI::add_panel_to_panel( GLUI_Panel *parent_panel, + const char *name, int type ) +{ + return new GLUI_Panel( parent_panel, name, type ); +} + + +/***************************** GLUI::add_radiogroup() ***************/ + +GLUI_RadioGroup *GLUI::add_radiogroup( int *value_ptr, + int user_id, GLUI_CB callback) +{ + return add_radiogroup_to_panel( main_panel, value_ptr, + user_id, callback ); +} + + +/***************************** GLUI::add_radiogroup_to_panel() ***************/ + +GLUI_RadioGroup *GLUI::add_radiogroup_to_panel( + GLUI_Panel *panel, int *value_ptr, + int user_id, GLUI_CB callback + ) +{ + return new GLUI_RadioGroup( panel, value_ptr, user_id, callback ); +} + + +/***************************** GLUI::add_radiobutton_to_group() *************/ + +GLUI_RadioButton *GLUI::add_radiobutton_to_group( GLUI_RadioGroup *group, + const char *name ) +{ + return new GLUI_RadioButton( group, name ); +} + + +/********************************** GLUI::add_statictext() ************/ + +GLUI_StaticText *GLUI::add_statictext( const char *name ) +{ + return add_statictext_to_panel( main_panel, name ); +} + + +/******************************* GLUI::add_statictext_to_panel() **********/ + +GLUI_StaticText *GLUI::add_statictext_to_panel( GLUI_Panel *panel, + const char *name ) +{ + return new GLUI_StaticText( panel, name ); +} + + +/***************************************** GLUI:: add_button() ************/ + +GLUI_Button *GLUI:: add_button( const char *name, + int id, GLUI_CB callback ) +{ + return add_button_to_panel( main_panel, + name, id, callback ); +} + +/*********************************** GLUI:: add_button_to_panel() **********/ + +GLUI_Button *GLUI::add_button_to_panel( GLUI_Panel *panel, + const char *name, + int id, + GLUI_CB callback ) +{ + return new GLUI_Button( panel, name, id, callback ); +} + +/********************************** GLUI::add_separator() ************/ + +void GLUI::add_separator( void ) +{ + add_separator_to_panel( main_panel ); +} + + +/******************************* GLUI::add_separator_to_panel() **********/ + +void GLUI::add_separator_to_panel( GLUI_Panel *panel ) +{ + new GLUI_Separator( panel ); +} + + +/********************************** GLUI::add_edittext() ************/ + +GLUI_EditText *GLUI::add_edittext( const char *name, + int data_type, void *data, + int id, GLUI_CB callback) +{ + return add_edittext_to_panel( main_panel, name, data_type, data, + id, callback ); +} + + +/******************************* GLUI::add_edittext_to_panel() **********/ + +GLUI_EditText *GLUI::add_edittext_to_panel( GLUI_Panel *panel, + const char *name, + int data_type, void *data, + int id, GLUI_CB callback) +{ + return new GLUI_EditText( panel, name, data_type, data, id, callback ); +} + +/********************************** GLUI::add_edittext() ************/ + +GLUI_EditText *GLUI::add_edittext( const char *name, + GLUI_String & data, + int id, GLUI_CB callback) +{ + return add_edittext_to_panel( main_panel, name, data, id, callback ); +} + + +/******************************* GLUI::add_edittext_to_panel() **********/ + +GLUI_EditText* +GLUI::add_edittext_to_panel( GLUI_Panel *panel, const char *name, + GLUI_String& data, + int id, GLUI_CB callback) +{ + return new GLUI_EditText( panel, name, GLUI_EDITTEXT_STRING, &data, id, callback ); +} + +/********************************** GLUI::add_spinner() ************/ + +GLUI_Spinner *GLUI::add_spinner( const char *name, + int data_type, void *data, + int id, GLUI_CB callback) +{ + return add_spinner_to_panel( main_panel, name, data_type, data, + id, callback ); +} + + +/******************************* GLUI::add_spinner_to_panel() **********/ + +GLUI_Spinner *GLUI::add_spinner_to_panel( + GLUI_Panel *panel, const char *name, + int data_type, void *data, + int id, GLUI_CB callback +) +{ + return new GLUI_Spinner( panel, name, data_type, data, id, callback ); +} + + +/********************************** GLUI::add_column() ************/ + +void GLUI::add_column( int draw_bar ) +{ + add_column_to_panel( main_panel, draw_bar ); +} + + +/******************************* GLUI::add_column_to_panel() **********/ + +void GLUI::add_column_to_panel( GLUI_Panel *panel, int draw_bar ) +{ + new GLUI_Column( panel, draw_bar ); +} + + +/*********************************** GLUI:: add_listbox() ************/ + +GLUI_Listbox *GLUI:: add_listbox( const char *name, int *value_ptr, + int id, GLUI_CB callback ) +{ + return add_listbox_to_panel( main_panel, + name, value_ptr, id, callback ); +} + + +/*********************************** GLUI:: add_listbox_to_panel() **********/ + +GLUI_Listbox *GLUI::add_listbox_to_panel( GLUI_Panel *panel, + const char *name, int *value_ptr, + int id, + GLUI_CB callback ) +{ + return new GLUI_Listbox( panel, name, value_ptr, id, callback ); +} + + +/*********************************** GLUI:: add_rotation() ************/ + +GLUI_Rotation *GLUI:: add_rotation( const char *name, float *value_ptr, + int id, GLUI_CB callback ) +{ + return add_rotation_to_panel( main_panel, name, value_ptr, id, callback ); +} + + +/*********************************** GLUI:: add_rotation_to_panel() **********/ + +GLUI_Rotation *GLUI::add_rotation_to_panel( GLUI_Panel *panel, + const char *name, float *value_ptr, + int id, + GLUI_CB callback ) +{ + return new GLUI_Rotation( panel, name, value_ptr, id, callback ); +} + + +/*********************************** GLUI:: add_translation() ************/ + +GLUI_Translation *GLUI:: add_translation( const char *name, int trans_type, + float *value_ptr, int id, + GLUI_CB callback ) +{ + return add_translation_to_panel( main_panel,name,trans_type, + value_ptr, id, callback ); +} + + +/*********************************** GLUI:: add_translation_to_panel() **********/ + +GLUI_Translation *GLUI::add_translation_to_panel( + GLUI_Panel *panel, const char *name, + int trans_type, float *value_ptr, + int id, GLUI_CB callback + ) +{ + return new GLUI_Translation(panel, name, trans_type, value_ptr, id, callback); +} + + +/********************************** GLUI::add_rollout() **************/ + +GLUI_Rollout *GLUI::add_rollout( const char *name, int open, int type) +{ + return add_rollout_to_panel( main_panel, name, open, type); +} + + +/****************************** GLUI::add_rollout_to_panel() *********/ + +GLUI_Rollout *GLUI::add_rollout_to_panel(GLUI_Panel *panel, const char *name, + int open, int type) +{ + return new GLUI_Rollout( panel, name, open, type ); +} + + + diff --git a/tests/Box2D_v2.2.1/glui/glui_bitmap_img_data.cpp b/tests/Box2D_v2.2.1/glui/glui_bitmap_img_data.cpp new file mode 100755 index 0000000000000..6ec7e6df46df6 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_bitmap_img_data.cpp @@ -0,0 +1,138 @@ +/** + Bitmaps for all GLUI images. + + These were converted from original PPM images + (mostly lost) with the tools/ppm2array program. + + The images here are extracted in typical OpenGL + bottom-to-top fashion. + + FIXME: don't use greyscale brightness here--this prevents + people changing the background color. Instead, use a code + indicating the underlying purpose of the pixel: + 0 = shadows; outlines; UI elements (check boxes, arrows) + 64 = disabled shadows and UI elements + 128 = shadowing, disabled + 192 = disabled white; background + 255 = highlights; checkbox/radio background + + I'm thinking the way to do this would be to have an +enum { + BG = 0, // Background shines through-- totally alpha transparent + BS, // Background of scrollbar/spin box-- opaque gray + SB, // Shadowed-black element-- strong alpha blend to black + SD, // Shadowed-dark element-- weak alpha blend to black + HL, // Highlight-light-- weak alpha blend to white + HW, // Highlight-white-- strong alpha blend to white + UB, // User-interface black-- arrows, checkboxes, radio buttons + UW, // User-interface white-- backgrounds of checkboxes and radio buttons +}; + + Orion Sky Lawlor, olawlor@acm.org, 2006/05/04 (LGPL) +*/ + +/*----------------------- checkboxes --------------------------*/ +unsigned char glui_img_checkbox_0[] = { 13, 13, /* width, height */ +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 255, +}; + + +unsigned char glui_img_checkbox_0_dis[] = { 13, 13, /* width, height */ +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 255, +}; + + +unsigned char glui_img_checkbox_1[] = { 13, 13, /* width, height */ +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 0, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 0, 0, 0, 255, 255, 255, 255, 192, 255, 128, 0, 255, 0, 0, 0, 0, 0, 255, 255, 255, 192, 255, 128, 0, 255, 0, 0, 255, 0, 0, 0, 255, 255, 192, 255, 128, 0, 255, 0, 255, 255, 255, 0, 0, 0, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 0, 0, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 255, +}; + + +unsigned char glui_img_checkbox_1_dis[] = { 13, 13, /* width, height */ +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 64, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 64, 64, 64, 192, 192, 192, 192, 192, 255, 128, 64, 192, 64, 64, 64, 64, 64, 192, 192, 192, 192, 255, 128, 64, 192, 64, 64, 192, 64, 64, 64, 192, 192, 192, 255, 128, 64, 192, 64, 192, 192, 192, 64, 64, 64, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 64, 64, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 64, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 255, +}; + + +/*------------------------------- arrows -------------------------------------*/ +unsigned char glui_img_downarrow[] = { 16, 16, /* width, height */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 0, 0, 0, 0, 0, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 0, 0, 0, 0, 0, 0, 0, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, +}; + + +unsigned char glui_img_leftarrow[] = { 16, 16, /* width, height */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 0, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, +}; + +unsigned char glui_img_rightarrow[] = { 16, 16, /* width, height */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 0, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, +}; + +unsigned char glui_img_uparrow[] = { 16, 16, /* width, height */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 0, 0, 0, 0, 0, 0, 0, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 0, 0, 0, 0, 0, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, +}; + +/*------------------ listboxes ---------------------*/ +unsigned char glui_img_listbox_down[] = { 11, 17, /* width, height */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 127, 191, 191, 191, 127, 0, 127, 191, 191, 191, 127, 127, 127, 191, 191, 127, 0, 127, 191, 191, 127, 127, 127, 127, 127, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, +}; + + +unsigned char glui_img_listbox_up[] = { 11, 17, /* width, height */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 0, 191, 191, 191, 127, 0, 191, 255, 191, 191, 0, 0, 0, 191, 191, 127, 0, 191, 255, 191, 0, 0, 0, 0, 0, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 255, 255, 255, 255, 255, 255, 255, 127, 0, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 0, +}; + +unsigned char glui_img_listbox_up_dis[] = { 11, 17, /* width, height */ +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 191, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 254, 191, 191, 191, 127, 127, 191, 255, 191, 191, 127, 127, 254, 191, 191, 127, 127, 191, 255, 191, 127, 127, 127, 127, 254, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 255, 255, 255, 255, 255, 255, 255, 127, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, +}; + +/*--------------------------- radio buttons -------------------------*/ +unsigned char glui_img_radiobutton_0[] = { 14, 14, /* width, height */ +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 255, 255, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 192, 128, 192, 192, 255, 255, 255, 255, 192, 192, 255, 192, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 192, 128, 0, 0, 255, 255, 255, 255, 0, 0, 255, 192, 192, 192, 192, 192, 128, 128, 0, 0, 0, 0, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +}; + + +unsigned char glui_img_radiobutton_0_dis[] = { 14, 14, /* width, height */ +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 255, 255, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 192, 128, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 192, 128, 64, 64, 192, 192, 192, 192, 64, 64, 255, 192, 192, 192, 192, 192, 128, 128, 64, 64, 64, 64, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +}; + + +unsigned char glui_img_radiobutton_1[] = { 14, 14, /* width, height */ +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 255, 255, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 192, 128, 192, 192, 255, 255, 255, 255, 192, 192, 255, 192, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 128, 0, 255, 255, 255, 0, 0, 255, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 0, 0, 0, 0, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 0, 0, 0, 0, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 255, 0, 0, 255, 255, 255, 192, 255, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 192, 128, 0, 0, 255, 255, 255, 255, 0, 0, 255, 192, 192, 192, 192, 192, 128, 128, 0, 0, 0, 0, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +}; + + +unsigned char glui_img_radiobutton_1_dis[] = { 14, 14, /* width, height */ +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 255, 255, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 192, 128, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 128, 64, 192, 192, 192, 64, 64, 192, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 64, 64, 64, 64, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 64, 64, 64, 64, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 192, 64, 64, 192, 192, 192, 192, 255, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 192, 128, 64, 64, 192, 192, 192, 192, 64, 64, 255, 192, 192, 192, 192, 192, 128, 128, 64, 64, 64, 64, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +}; + + + +/*----------------- spinners ----------------------------*/ +unsigned char glui_img_spindown_0[] = { 12, 8, /* width, height */ +255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 255, 191, 191, 191, 191, 0, 127, 191, 191, 191, 127, 0, 255, 191, 191, 191, 0, 0, 0, 127, 191, 191, 127, 0, 255, 191, 191, 0, 0, 0, 0, 0, 127, 191, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, +}; + + +unsigned char glui_img_spindown_1[] = { 12, 8, /* width, height */ +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 191, 191, 191, 127, 0, 191, 191, 191, 191, 255, 0, 127, 191, 191, 127, 0, 0, 0, 191, 191, 191, 255, 0, 127, 191, 127, 0, 0, 0, 0, 0, 191, 191, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 191, 255, +}; + + +unsigned char glui_img_spindown_dis[] = { 12, 8, /* width, height */ +255, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 255, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 64, 255, 191, 191, 191, 191, 127, 255, 191, 191, 191, 127, 64, 255, 191, 191, 191, 127, 127, 127, 255, 191, 191, 127, 64, 255, 191, 191, 127, 127, 127, 127, 127, 255, 191, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, +}; + + +unsigned char glui_img_spinup_0[] = { 12, 8, /* width, height */ +255, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 255, 191, 191, 0, 0, 0, 0, 0, 127, 191, 127, 0, 255, 191, 191, 191, 0, 0, 0, 127, 191, 191, 127, 0, 255, 191, 191, 191, 191, 0, 127, 191, 191, 191, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +}; + + +unsigned char glui_img_spinup_1[] = { 12, 8, /* width, height */ + 0, 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 191, 127, 0, 0, 0, 0, 0, 191, 191, 255, 0, 127, 191, 191, 127, 0, 0, 0, 191, 191, 191, 255, 0, 127, 191, 191, 191, 127, 0, 191, 191, 191, 191, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 191, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, +}; + + +unsigned char glui_img_spinup_dis[] = { 12, 8, /* width, height */ +255, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 64, 255, 191, 191, 127, 127, 127, 127, 127, 255, 191, 127, 64, 255, 191, 191, 191, 127, 127, 127, 255, 191, 191, 127, 64, 255, 191, 191, 191, 191, 127, 255, 191, 191, 191, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +}; + diff --git a/tests/Box2D_v2.2.1/glui/glui_bitmaps.cpp b/tests/Box2D_v2.2.1/glui/glui_bitmaps.cpp new file mode 100755 index 0000000000000..d04e9b116abd1 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_bitmaps.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_bitmaps.cpp + +Draws the hardcoded images listed in glui_bitmap_img_data with OpenGL. + +FIXME: upload the images to a texture. This will allow them to be: + - Drawn with alpha blending + - Drawn at random sizes and angles onscreen + - Drawn much faster than with glDrawPixels + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui.h" +#include "glui_internal.h" +#include + +/************ Image Bitmap arrays **********/ + +extern unsigned char glui_img_checkbox_0[]; +extern unsigned char glui_img_checkbox_1[]; +extern unsigned char glui_img_radiobutton_0[]; +extern unsigned char glui_img_radiobutton_1[]; +extern unsigned char glui_img_uparrow[]; +extern unsigned char glui_img_downarrow[]; +extern unsigned char glui_img_leftarrow[]; +extern unsigned char glui_img_rightarrow[]; +extern unsigned char glui_img_spinup_0[]; +extern unsigned char glui_img_spinup_1[]; +extern unsigned char glui_img_spindown_0[]; +extern unsigned char glui_img_spindown_1[]; +extern unsigned char glui_img_checkbox_0_dis[]; +extern unsigned char glui_img_checkbox_1_dis[]; +extern unsigned char glui_img_radiobutton_0_dis[]; +extern unsigned char glui_img_radiobutton_1_dis[]; +extern unsigned char glui_img_spinup_dis[]; +extern unsigned char glui_img_spindown_dis[]; +extern unsigned char glui_img_listbox_up[]; +extern unsigned char glui_img_listbox_down[]; +extern unsigned char glui_img_listbox_up_dis[]; + + +// These must be in the same order as the GLUI_STDBITMAP enums from glui.h! +unsigned char *bitmap_arrays[] = { + glui_img_checkbox_0, + glui_img_checkbox_1, + glui_img_radiobutton_0, + glui_img_radiobutton_1, + glui_img_uparrow, + glui_img_downarrow, + glui_img_leftarrow, + glui_img_rightarrow, + glui_img_spinup_0, + glui_img_spinup_1, + glui_img_spindown_0, + glui_img_spindown_1, + glui_img_checkbox_0_dis, + glui_img_checkbox_1_dis, + glui_img_radiobutton_0_dis, + glui_img_radiobutton_1_dis, + glui_img_spinup_dis, + glui_img_spindown_dis, + glui_img_listbox_up, + glui_img_listbox_down, + glui_img_listbox_up_dis, +}; + + +/************************************ GLUI_Bitmap::load_from_array() ********/ + +GLUI_Bitmap::GLUI_Bitmap() +: pixels(NULL), + w(0), + h(0) +{ +} + +GLUI_Bitmap::~GLUI_Bitmap() +{ + if (pixels) + { + free(pixels); + pixels = NULL; + } +} + +/* Create bitmap from greyscale byte array */ +void GLUI_Bitmap::init_grey(unsigned char *array) +{ + w = array[0]; h = array[1]; + pixels = (unsigned char *) malloc(w*h*3); + assert(pixels); + + for(int i = 0; i=0 && i=0 && i=0 && iadd_control( this ); +} + + +/****************************** GLUI_Button::mouse_down_handler() **********/ + +int GLUI_Button::mouse_down_handler( int local_x, int local_y ) +{ + int_val = 1; /** A button always in unpressed before here, so + now we invariably set it to 'depressed' **/ + + currently_inside = true; + redraw(); + + return false; +} + + +/****************************** GLUI_Button::mouse_up_handler() **********/ + +int GLUI_Button::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + set_int_val( 0 ); /** A button always turns off after you press it **/ + + currently_inside = false; + redraw(); + + if ( inside ) { + /*** Invoke the user's callback ***/ + execute_callback(); + } + + return false; +} + + +/****************************** GLUI_Button::mouse_held_down_handler() ******/ + +int GLUI_Button::mouse_held_down_handler( int local_x, int local_y, + bool new_inside) +{ + if (new_inside != currently_inside) { + currently_inside = new_inside; + redraw(); + } + + return false; +} + + +/****************************** GLUI_Button::key_handler() **********/ + +int GLUI_Button::key_handler( unsigned char key,int modifiers ) +{ + return false; +} + +/********************************************** GLUI_Button::draw() **********/ + +void GLUI_Button::draw( int x, int y ) +{ + if (currently_inside) draw_pressed(); + else { + glui->draw_raised_box( 0, 0, w, h ); + draw_text( 0 ); + } +} + + +/************************************** GLUI_Button::draw_pressed() ******/ + +void GLUI_Button::draw_pressed( void ) +{ + glColor3f( 0.0, 0.0, 0.0 ); + + draw_text( 1 ); + + glBegin( GL_LINE_LOOP ); + glVertex2i( 0, 0 ); glVertex2i( w, 0 ); + glVertex2i( w, h ); glVertex2i( 0, h ); + glEnd(); + + glBegin( GL_LINE_LOOP ); + glVertex2i( 1, 1 ); glVertex2i( w-1, 1 ); + glVertex2i( w-1, h-1 ); glVertex2i( 1, h-1 ); + glEnd(); +} + + +/**************************************** GLUI_Button::draw_text() **********/ + +void GLUI_Button::draw_text( int sunken ) +{ + int string_width; + + glColor3ub( glui->bkgd_color.r, glui->bkgd_color.g, glui->bkgd_color.b ); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( 2, 2 ); glVertex2i( w-2, 2 ); + glVertex2i( w-2, h-2 ); glVertex2i( 2, h-2 ); + glEnd(); + + glColor3ub( 0,0,0 ); + + string_width = _glutBitmapWidthString( glui->font, + this->name.c_str() ); + if ( NOT sunken ) { + draw_name( MAX((w-string_width),0)/2, 13); + } + else { + draw_name( MAX((w-string_width),0)/2 + 1, 13 + 1); + } + + if ( active ) { + glEnable( GL_LINE_STIPPLE ); + glLineStipple( 1, 0x5555 ); + + glColor3f( 0., 0., 0. ); + + glBegin( GL_LINE_LOOP ); + glVertex2i( 3, 3 ); glVertex2i( w-3, 3 ); + glVertex2i( w-3, h-3 ); glVertex2i( 3, h-3 ); + glEnd(); + + glDisable( GL_LINE_STIPPLE ); + } +} + + +/************************************** GLUI_Button::update_size() **********/ + +void GLUI_Button::update_size( void ) +{ + int text_size; + + if ( NOT glui ) + return; + + text_size = string_width( name ); + + if ( w < text_size + 16 ) + w = text_size + 16 ; +} diff --git a/tests/Box2D_v2.2.1/glui/glui_checkbox.cpp b/tests/Box2D_v2.2.1/glui/glui_checkbox.cpp new file mode 100755 index 0000000000000..3bf3984d3eaa3 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_checkbox.cpp @@ -0,0 +1,188 @@ + +/**************************************************************************** + + GLUI User Interface Toolkit (LGPL) + --------------------------- + + glui_checkbox - GLUI_Checkbox control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui_internal_control.h" + +/****************************** GLUI_Checkbox::GLUI_Checkbox() **********/ + +GLUI_Checkbox::GLUI_Checkbox( GLUI_Node *parent, + const char *name, int *value_ptr, + int id, + GLUI_CB cb ) +{ + common_init(); + + set_ptr_val( value_ptr ); + set_name( name ); + user_id = id; + callback = cb; + + parent->add_control( this ); + + init_live(); +} + +/****************************** GLUI_Checkbox::mouse_down_handler() **********/ + +int GLUI_Checkbox::mouse_down_handler( int local_x, int local_y ) +{ + orig_value = int_val; + int_val = !int_val; + + currently_inside = true; + redraw(); + + return false; +} + + +/****************************** GLUI_Checkbox::mouse_up_handler() **********/ + +int GLUI_Checkbox::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + if ( NOT inside ) { /* undo effect on value */ + int_val = orig_value; + } + else { + set_int_val( int_val ); + + /*** Invoke the callback ***/ + execute_callback(); + } + + return false; +} + + +/****************************** GLUI_Checkbox::mouse_held_down_handler() ******/ + +int GLUI_Checkbox::mouse_held_down_handler( int local_x, int local_y, + bool inside) +{ + /********** Toggle checked and unchecked bitmap if we're entering or + leaving the checkbox area **********/ + if ( inside != currently_inside ) { + int_val = !int_val; + currently_inside = inside; + redraw(); + } + + return false; +} + + +/****************************** GLUI_Checkbox::key_handler() **********/ + +int GLUI_Checkbox::key_handler( unsigned char key,int modifiers ) +{ + return false; +} + + +/****************************** GLUI_Checkbox::draw() **********/ + +void GLUI_Checkbox::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + if ( int_val != 0 ) { + if ( enabled ) + glui->std_bitmaps.draw( GLUI_STDBITMAP_CHECKBOX_ON, 0, 0 ); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_CHECKBOX_ON_DIS, 0, 0 ); + } + else { + if ( enabled ) + glui->std_bitmaps.draw( GLUI_STDBITMAP_CHECKBOX_OFF, 0, 0 ); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_CHECKBOX_OFF_DIS, 0, 0 ); + } + + draw_active_area(); + + draw_name( text_x_offset, 10); +} + +/**************************** GLUI_Checkbox::draw_active_area() **************/ + +void GLUI_Checkbox::draw_active_area( void ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int text_width, left, right; + + text_width = _glutBitmapWidthString( glui->font, name.c_str() ); + left = text_x_offset-3; + right = left + 7 + text_width; + + if ( active ) { + glEnable( GL_LINE_STIPPLE ); + glLineStipple( 1, 0x5555 ); + glColor3f( 0., 0., 0. ); + } else { + glColor3ub( glui->bkgd_color.r, glui->bkgd_color.g, glui->bkgd_color.b ); + } + + glBegin( GL_LINE_LOOP ); + glVertex2i(left,0); glVertex2i( right,0); + glVertex2i(right,h+1); glVertex2i( left,h+1); + glEnd(); + + glDisable( GL_LINE_STIPPLE ); +} + + +/************************************ GLUI_Checkbox::update_size() **********/ + +void GLUI_Checkbox::update_size( void ) +{ + int text_size; + + if ( NOT glui ) + return; + + text_size = _glutBitmapWidthString( glui->font, name.c_str() ); + + /* if ( w < text_x_offset + text_size + 6 ) */ + w = text_x_offset + text_size + 6 ; +} + + +/********************************* GLUI_Checkbox::set_int_val() **************/ + +void GLUI_Checkbox::set_int_val( int new_val ) +{ + int_val = new_val; + + /*** Update the variable we're (possibly) pointing to ***/ + output_live(true); + redraw(); +} diff --git a/tests/Box2D_v2.2.1/glui/glui_column.cpp b/tests/Box2D_v2.2.1/glui/glui_column.cpp new file mode 100755 index 0000000000000..172d3c1e608fb --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_column.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** + GLUI User Interface Toolkit + --------------------------- + + glui_column.cpp - GLUI_Column control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui_internal_control.h" + +/******************************** GLUI_Column::GLUI_Column() ************/ + +GLUI_Column::GLUI_Column( GLUI_Node *parent, int draw_bar ) +{ + common_init(); + int_val = draw_bar; /* Whether to draw vertical bar or not */ + + parent->add_control( this ); +} + +/**************************************** GLUI_Column::draw() ************/ + +void GLUI_Column::draw( int x, int y ) +{ + int panel_x, panel_y, panel_w, panel_h, panel_x_off, panel_y_off; + int y_diff; + + if ( int_val == 1 ) { /* Draw a vertical bar */ + GLUI_DRAWINGSENTINAL_IDIOM + if ( parent() != NULL ) { + get_this_column_dims(&panel_x, &panel_y, &panel_w, &panel_h, + &panel_x_off, &panel_y_off); + + y_diff = y_abs - panel_y; + + if ( 0 ) { + glLineWidth(1.0); + glBegin( GL_LINES ); + glColor3f( .5, .5, .5 ); + glVertex2i( -GLUI_XOFF+1, -y_diff + GLUI_SEPARATOR_HEIGHT/2 ); + glVertex2i( -GLUI_XOFF+1, -y_diff + panel_h - GLUI_SEPARATOR_HEIGHT/2); + + glColor3f( 1.0, 1.0, 1.0 ); + glVertex2i( -GLUI_XOFF+2, -y_diff + GLUI_SEPARATOR_HEIGHT/2 ); + glVertex2i( -GLUI_XOFF+2, -y_diff + panel_h - GLUI_SEPARATOR_HEIGHT/2); + glEnd(); + } + else { + glLineWidth(1.0); + glBegin( GL_LINES ); + glColor3f( .5, .5, .5 ); + glVertex2i( -2, 0 ); + glVertex2i( -2, h ); + /*glVertex2i( 0, -y_diff + GLUI_SEPARATOR_HEIGHT/2 ); */ + /*glVertex2i( 0, -y_diff + panel_h - GLUI_SEPARATOR_HEIGHT/2); */ + + glColor3f( 1.0, 1.0, 1.0 ); + glVertex2i( -1, 0 ); + glVertex2i( -1, h ); + /*glVertex2i( 1, -y_diff + GLUI_SEPARATOR_HEIGHT/2 ); */ + /*glVertex2i( 1, -y_diff + panel_h - GLUI_SEPARATOR_HEIGHT/2); */ + glEnd(); + } + } + } +} + diff --git a/tests/Box2D_v2.2.1/glui/glui_commandline.cpp b/tests/Box2D_v2.2.1/glui/glui_commandline.cpp new file mode 100755 index 0000000000000..e98c2e1eec247 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_commandline.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_commandline.cpp - GLUI_CommandLine control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher, 2005 William Baxter + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA + + This program is -not- in the public domain. + +*****************************************************************************/ + +#include "glui.h" +#include "glui_internal.h" + +/****************************** GLUI_CommandLine::GLUI_CommandLine() **********/ +GLUI_CommandLine::GLUI_CommandLine( GLUI_Node *parent, const char *name, + void *data, int id, GLUI_CB cb ) +{ + common_init(); + set_name( name ); + + data_type = GLUI_EDITTEXT_TEXT; + ptr_val = data; + user_id = id; + callback = cb; + + live_type = GLUI_LIVE_TEXT; + + parent->add_control( this ); + + init_live(); +} + +/****************************** GLUI_CommandLine::key_handler() **********/ + +int GLUI_CommandLine::key_handler( unsigned char key,int modifiers ) +{ + int ret; + + if ( NOT glui ) + return false; + + if ( debug ) + dump( stdout, "-> CMD_TEXT KEY HANDLER" ); + + if ( key == 13 ) { /* RETURN */ + commit_flag = true; + } + + ret = Super::key_handler( key, modifiers ); + + if ( debug ) + dump( stdout, "<- CMD_TEXT KEY HANDLER" ); + + return ret; +} + + +/****************************** GLUI_CommandLine::deactivate() **********/ + +void GLUI_CommandLine::deactivate( void ) +{ + // if the commit_flag is set, add the current command to + // history and call deactivate as normal + + // Trick deactivate into calling callback if and only if commit_flag set. + // A bit subtle, but deactivate checks that orig_text and text + // are the same to decide whether or not to call the callback. + // Force them to be different for commit, and the same for no commit. + if (commit_flag) { + add_to_history(text.c_str()); + orig_text = ""; + Super::deactivate( ); + set_text( "" ); + commit_flag = false; + } + else { + orig_text = text; + } +} + +/**************************** GLUI_CommandLine::special_handler() **********/ + +int GLUI_CommandLine::special_handler( int key,int modifiers ) +{ + if ( NOT glui ) + return false; + + if ( debug ) + printf( "CMD_TEXT SPECIAL:%d - mod:%d subs:%d/%d ins:%d sel:%d/%d\n", + key, modifiers, substring_start, substring_end,insertion_pt, + sel_start, sel_end ); + + if ( key == GLUT_KEY_UP ) // PREVIOUS HISTORY + { + scroll_history(-1); + } + else if ( key == GLUT_KEY_DOWN ) // NEXT HISTORY + { + scroll_history(+1); + } + else { + return Super::special_handler( key, modifiers ); + } + return false; +} + + + +/**************************** GLUI_CommandLine::scroll_history() ********/ + +void GLUI_CommandLine::scroll_history( int direction ) +{ + recall_history(curr_hist + direction); +} + +/**************************** GLUI_CommandLine::recall_history() ********/ + +void GLUI_CommandLine::recall_history( int hist_num ) +{ + if (hist_num < oldest_hist OR + hist_num > newest_hist OR + hist_num == curr_hist) + return; + + // Commit the current text first before we blow it away! + if (curr_hist == newest_hist) { + get_history_str(newest_hist) = text; + } + + curr_hist = hist_num; + set_text(get_history_str(curr_hist)); + sel_end = sel_start = insertion_pt = (int)text.length(); + update_and_draw_text(); +} + +/**************************** GLUI_CommandLine::add_to_history() ********/ + +void GLUI_CommandLine::add_to_history( const char *cmd ) +{ + if (cmd[0]=='\0') return; // don't add if it's empty + + curr_hist = newest_hist; + get_history_str(newest_hist) = text; + + newest_hist = ++curr_hist; + if ( newest_hist >= HIST_SIZE ) + { + // bump oldest off the list + hist_list.erase(hist_list.begin()); + hist_list.push_back(""); + + oldest_hist++; + } +} + +/**************************** GLUI_CommandLine::reset_history() ********/ + +void GLUI_CommandLine::reset_history( void ) +{ + oldest_hist = newest_hist = curr_hist = 0; +} + + + +/*************************************** GLUI_CommandLine::dump() **************/ + +void GLUI_CommandLine::dump( FILE *out, const char *name ) +{ + fprintf( out, + "%s (commandline@%p): ins_pt:%d subs:%d/%d sel:%d/%d len:%d\n", + name, this, + insertion_pt, substring_start, substring_end, sel_start, sel_end, + (int)text.length()); +} + + diff --git a/tests/Box2D_v2.2.1/glui/glui_control.cpp b/tests/Box2D_v2.2.1/glui/glui_control.cpp new file mode 100755 index 0000000000000..056916f3b23e4 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_control.cpp @@ -0,0 +1,1203 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_control.cpp - top-level GLUI_Control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui_internal_control.h" + +int _glui_draw_border_only = 0; + +/*************************** Drawing Utility routines *********************/ + +/* Redraw this control. */ +void GLUI_Control::redraw(void) { + if (glui==NULL || hidden) return; + if (glui->should_redraw_now(this)) + translate_and_draw_front(); +} + +/** Redraw everybody in our window. */ +void GLUI_Control::redraw_window(void) { + if (glui==NULL || hidden) return; + if ( glui->get_glut_window_id() == -1 ) return; + int orig = set_to_glut_window(); + glutPostRedisplay(); + restore_window(orig); +} + + + +/* GLUI_Control::translate_and_draw_front() ********/ + +void GLUI_Control::translate_and_draw_front() +{ + GLUI_DRAWINGSENTINAL_IDIOM + + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + translate_to_origin(); + draw(0,0); + glPopMatrix(); +} + + +/********** GLUI_Control::set_to_bkgd_color() ********/ + +void GLUI_Control::set_to_bkgd_color( void ) +{ + if ( NOT glui ) + return; + + glColor3ub( glui->bkgd_color.r, glui->bkgd_color.g, glui->bkgd_color.b ); +} + +/******** GLUI_Control::draw_box_inwards_outline() ********/ + +void GLUI_Control::draw_box_inwards_outline( int x_min, int x_max, int y_min, int y_max ) +{ + glBegin( GL_LINES ); + glColor3f( .5, .5, .5 ); + glVertex2i( x_min, y_min ); glVertex2i( x_max, y_min ); + glVertex2i( x_min, y_min ); glVertex2i( x_min, y_max ); + + glColor3f( 1., 1., 1. ); + glVertex2i( x_min, y_max ); glVertex2i( x_max, y_max ); + glVertex2i( x_max, y_max ); glVertex2i( x_max, y_min ); + + if ( enabled ) + glColor3f( 0., 0., 0. ); + else + glColor3f( .25, .25, .25 ); + + glVertex2i( x_min+1, y_min+1 ); glVertex2i( x_max-1, y_min+1 ); + glVertex2i( x_min+1, y_min+1 ); glVertex2i( x_min+1, y_max-1 ); + + glColor3f( .75, .75, .75 ); + glVertex2i( x_min+1, y_max-1 ); glVertex2i( x_max-1, y_max-1 ); + glVertex2i( x_max-1, y_max-1 ); glVertex2i( x_max-1, y_min+1 ); + glEnd(); +} + + +/******* GLUI_Control::draw_box() **********/ + +void GLUI_Control::draw_box( int x_min, int x_max, int y_min, int y_max, float r, float g, float b) +{ + if ( r == 1.0 AND g == 1.0 AND b == 1.0 AND NOT enabled AND glui ) { + draw_bkgd_box( x_min, x_max, y_min, y_max ); + return; + } + + glColor3f( r, g, b ); + glBegin( GL_QUADS ); + glVertex2i( x_min, y_min ); glVertex2i( x_max, y_min ); + glVertex2i( x_max, y_max ); glVertex2i( x_min, y_max ); + glEnd(); +} + + +/******* GLUI_Control::draw_bkgd_box() **********/ + +void GLUI_Control::draw_bkgd_box( int x_min, int x_max, int y_min, int y_max ) +{ + set_to_bkgd_color(); + + glBegin( GL_QUADS ); + glVertex2i( x_min, y_min ); glVertex2i( x_max, y_min ); + glVertex2i( x_max, y_max ); glVertex2i( x_min, y_max ); + glEnd(); +} + + +/**** GLUI_Control::draw_active_area() ********/ + +void GLUI_Control::draw_active_box( int x_min, int x_max, int y_min, int y_max ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + if ( active ) { + glEnable( GL_LINE_STIPPLE ); + glLineStipple( 1, 0x5555 ); + glColor3f( 0., 0., 0. ); + } else { + set_to_bkgd_color(); + } + + glBegin( GL_LINE_LOOP ); + glVertex2i(x_min, y_min); glVertex2i( x_max, y_min ); + glVertex2i(x_max, y_max); glVertex2i( x_min, y_max ); + glEnd(); + + glDisable( GL_LINE_STIPPLE ); +} + + +/**** GLUI_Control::draw_emboss_box() ********/ + +void GLUI_Control::draw_emboss_box(int x_min,int x_max,int y_min,int y_max) +{ + glLineWidth( 1.0 ); + glColor3f( 1.0, 1.0, 1.0 ); + + glBegin( GL_LINE_LOOP ); + glVertex2i( x_min, y_min ); glVertex2i( x_max, y_min ); + glVertex2i( x_max, y_max ); glVertex2i( x_min, y_max ); + glEnd(); + + glBegin( GL_LINE_LOOP ); + glVertex2i( x_min+1, y_min+1 ); glVertex2i( x_max-1, y_min+1 ); + glVertex2i( x_max-1, y_max-1 ); glVertex2i( x_min+1, y_max-1 ); + glEnd(); + + glColor3f( .5, .5, .5 ); + glBegin( GL_LINE_LOOP ); + glVertex2i( x_min, y_min ); + glVertex2i( x_max-1, y_min ); + glVertex2i( x_max-1, y_max-1 ); + glVertex2i( x_min, y_max-1 ); + glEnd(); +} + + + +/******* GLUT_Control::draw_recursive() **********/ + +void GLUI_Control::draw_recursive( int x, int y ) +{ + GLUI_Control *node; + + /* printf( "%s %d\n", this->name.c_str(), this->hidden );*/ + if ( NOT can_draw() ) + return; + + /*if ( 1 ) { -- Debugging to check control width + glColor3f( 1.0, 0.0, 0.0 ); + glBegin( GL_LINES ); + glVertex2i( x_abs, y_abs );00 + glVertex2i( x_abs+w, y_abs ); + + glEnd(); + }*/ + + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + + glTranslatef( (float) this->x_abs + .5, + (float) this->y_abs + .5, + 0.0 ); + + if ( NOT _glui_draw_border_only ) { + if ( NOT strcmp( name.c_str(), "Rollout" ) ) { + } + + this->draw( this->x_off, this->y_off_top ); + } + else + { + if ( dynamic_cast(this) ) { + /* printf( "%s w/h: %d/%d\n", (char*) name, w, h ); */ + /*w = 2; */ + } + + /* The following draws the area of each control */ + glColor3f( 1.0, 0.0, 0.0 ); + glBegin( GL_LINE_LOOP ); + glVertex2i( 0, 0 ); glVertex2i( w, 0 ); + glVertex2i( w, h ); glVertex2i( 0, h ); + glEnd(); + } + glPopMatrix(); + + node = (GLUI_Control*) first_child(); + while( node ) { + node->draw_recursive( node->x_abs, node->y_abs ); + node = (GLUI_Control*) node->next(); + } +} + + +/****** GLUI_Control::set_to_glut_window() *********/ +/* Sets the current window to the glut window associated with this control */ + +int GLUI_Control::set_to_glut_window() +{ + int orig_window; + + if ( NOT glui) + return 1; + + orig_window = glutGetWindow(); + + glutSetWindow( glui->get_glut_window_id()); + + return orig_window; +} + + +/********** GLUI_Control::restore_window() *********/ + +void GLUI_Control::restore_window(int orig) +{ + if ( orig > 0 ) + glutSetWindow( orig ); +} + + + +/****************************** Text ***************************/ + +/*************** GLUI_Control::set_font() **********/ + +void GLUI_Control::set_font(void *new_font) +{ + font = new_font; + redraw(); +} + + +/********** GLUI_Control::draw_string() ************/ + +void GLUI_Control::draw_string( const char *text ) +{ + _glutBitmapString( get_font(), text ); +} + + +/**************** GLUI_Control::draw_char() ********/ + +void GLUI_Control::draw_char(char c) +{ + glutBitmapCharacter( get_font(), c ); +} + + +/*********** GLUI_Control::string_width() **********/ + +int GLUI_Control::string_width(const char *text) +{ + return _glutBitmapWidthString( get_font(), text ); +} + + +/************* GLUI_Control::char_width() **********/ + +int GLUI_Control::char_width(char c) +{ /* Hash table for faster character width lookups - JVK + Speeds up the textbox a little bit. + */ + int hash_index = c % CHAR_WIDTH_HASH_SIZE; + if (char_widths[hash_index][0] != c) { + char_widths[hash_index][0] = c; + char_widths[hash_index][1] = glutBitmapWidth( get_font(), c ); + } + return char_widths[hash_index][1]; +} + + +/*************** GLUI_Control::get_font() **********/ + +void *GLUI_Control::get_font( void ) +{ + /*** Does this control have its own font? ***/ + if ( this->font != NULL ) + return this->font; + + /*** Does the parent glui have a font? ***/ + if ( glui ) + return glui->font; + + /*** Return the default font ***/ + return GLUT_BITMAP_HELVETICA_12; +} + + +/************* GLUI_Control::draw_name() ***********/ +/* This draws the name of the control as either black (if enabled), or */ +/* embossed if disabled. */ + +void GLUI_Control::draw_name(int x, int y) +{ + if ( NOT can_draw() ) + return; + + if ( enabled ) + { + set_to_bkgd_color(); + glRasterPos2i(x+1, y+1); + draw_string(name); + glColor3b( 0, 0, 0 ); + glRasterPos2i(x, y); + draw_string(name); + } + else + { /* Control is disabled - emboss the string */ + glColor3f( 1.0f, 1.0f, 1.0f ); + glRasterPos2i(x+1, y+1); + draw_string(name); + glColor3f( .4f, .4f, .4f ); + glRasterPos2i(x, y); + draw_string(name); + } +} + + +/**************************** Layout and Packing *********************/ + +/****** GLUI_Control::align() **************/ + +void GLUI_Control::align() +{ + int col_x, col_y, col_w, col_h, col_x_off, col_y_off; + int orig_x_abs; + + orig_x_abs = x_abs; + + /* Fix alignment bug relating to columns */ + /*return; */ + + if ( NOT parent() ) + return; /* Clearly this shouldn't happen, though */ + + get_this_column_dims(&col_x, &col_y, &col_w, &col_h, + &col_x_off, &col_y_off); + + if ( dynamic_cast(this) ) { + /* if ( this->prev() != NULL ) { + ((GLUI_Control*)prev())->get_this_column_dims(&col_x, &col_y, &col_w, &col_h, + &col_x_off, &col_y_off); + + x_abs = col_x + col_w; + } + else { + x_abs = ((GLUI_Control*)parent())->x_abs; + } + */ + return; + } + + if ( alignment == GLUI_ALIGN_LEFT ) { + x_abs = col_x + col_x_off; + } + else if ( alignment == GLUI_ALIGN_RIGHT ) { + x_abs = col_x + col_w - col_x_off - this->w; + } + else if ( alignment == GLUI_ALIGN_CENTER ) { + x_abs = col_x + (col_w - this->w) / 2; + } + + if ( this->is_container ) { + /*** Shift all child columns ***/ + int delta = x_abs - orig_x_abs; + + GLUI_Control *node; + + node = (GLUI_Control*) this->first_child(); + while( node != NULL ) { + if ( dynamic_cast(node) ) { + node->x_abs += delta; + } + + node = (GLUI_Control*) node->next(); + } + } + +} + + +/************** GLUI_Control::pack() ************/ +/* Recalculate positions and offsets */ + +void GLUI_Control::pack_old(int x, int y) +{ + GLUI_Control *node; + int max_w, curr_y, curr_x, max_y; + int x_in = x, y_in =y; + int x_margin, y_margin_top, y_margin_bot; + int y_top_column; + int column_x; + GLUI_Column *curr_column = NULL; + this->update_size(); + x_margin = this->x_off; + y_margin_top = this->y_off_top; + y_margin_bot = this->y_off_bot; + this->x_abs = x_in; + this->y_abs = y_in; + max_w = -1; + max_y = -1; + curr_x = this->x_abs + x_margin; + curr_y = this->y_abs + y_margin_top; + /*** Record start of this set of columns ***/ + y_top_column = curr_y; + column_x = 0; + if ( this == glui->main_panel ) { + x=x; + } + /*** Iterate over children, packing them first ***/ + node = (GLUI_Control*) this->first_child(); + while( node != NULL ) { + if ( dynamic_cast(node) && !node->collapsible) { + /* Pad some space above fixed size panels */ + curr_y += GLUI_ITEMSPACING; + } + else if ( dynamic_cast(node)) { + curr_column = (GLUI_Column*) node; + if ( 1 ) { + column_x += max_w + 2 * x_margin; + curr_x += max_w + 2 * x_margin; + } + else { + column_x += max_w + 0 * x_margin; + curr_x += max_w + 0 * x_margin; + } + /*node->pack( curr_x, curr_y ); */ + node->x_abs = curr_x; + node->y_abs = y_top_column; + node->w = 2; + node->h = curr_y - y_top_column; + curr_x += x_margin * 3 + 40; + curr_y = y_top_column; + max_w = 0; + node = (GLUI_Control*) node->next(); + continue; + } + node->pack( curr_x, curr_y ); + if ( dynamic_cast(node) && !node->collapsible) + /* Pad some space below fixed size panels */ + curr_y += GLUI_ITEMSPACING; + curr_y += node->h; + if ( node->w > max_w ) { + max_w = node->w; + if ( curr_column != NULL ) + curr_column->w = max_w; + } + node = (GLUI_Control*) node->next(); + if ( node ) { + curr_y += GLUI_ITEMSPACING; + } + if ( curr_y > max_y ) + max_y = curr_y; + } + if ( this->is_container ) { + max_y += y_margin_bot; /*** Add bottom border inside box */ + if ( this->first_child() ) { + if ( dynamic_cast(this) ) { + /** We don't want the rollout to shrink in width when it's + closed **/ + this->w = MAX(this->w, column_x + max_w + 2 * x_margin ); + } + else { + this->w = column_x + max_w + 2 * x_margin; + } + this->h = (max_y - y_in); + } + else { /* An empty container, so just assign default w & h */ + this->w = GLUI_DEFAULT_CONTROL_WIDTH; + this->h = GLUI_DEFAULT_CONTROL_HEIGHT; + } + /** Expand panel if necessary (e.g., to include all the text in + a panel label) **/ + this->update_size(); + } +} + +/*** GLUI_Control::get_this_column_dims() **********/ +/* Gets the x,y,w,h,and x/y offsets of the column to which a control belongs */ + +void GLUI_Control::get_this_column_dims( int *col_x, int *col_y, + int *col_w, int *col_h, + int *col_x_off, int *col_y_off ) +{ + GLUI_Control *node, *parent_ptr; + int parent_h, parent_y_abs; + + parent_ptr = (GLUI_Control*) parent(); + + if ( parent_ptr==NULL ) + return; + + parent_h = parent_ptr->h; + parent_y_abs = parent_ptr->y_abs; + + if ( dynamic_cast(parent_ptr) AND + parent_ptr->int_val == GLUI_PANEL_EMBOSSED AND + parent_ptr->name != "" ) { + parent_h -= GLUI_PANEL_EMBOSS_TOP; + parent_y_abs += GLUI_PANEL_EMBOSS_TOP; + } + + if ( 0 ) { + GLUI_Node *first, *last, *curr; + + /** Look for first control in this column **/ + first = this; + while (first->prev() AND !dynamic_cast(first->prev()) ) + first = first->prev(); + + /** Look for last control in this column **/ + last = this; + while ( last->next() AND !dynamic_cast(first->next()) ) + last = last->next(); + + curr = first; + int max_w = -1; + do { + if ( ((GLUI_Control*)curr)->w > max_w ) + max_w = ((GLUI_Control*)curr)->w; + + if ( curr == last ) + break; + + curr = curr->next(); + } while( curr != NULL ); + + *col_x = ((GLUI_Control*)first)->x_abs; + *col_y = ((GLUI_Control*)first)->y_abs; + *col_w = max_w; + if ( parent() ) { + *col_h = ((GLUI_Control*)parent())->h; + *col_x_off = ((GLUI_Control*)parent())->x_off; + } + else { + *col_h = 10; + *col_x_off = 0; + } + *col_y_off = 0; + + return; + } + + if ( 1 ) { /* IS THIS WRONG? */ + /*** Look for preceding column ***/ + node = (GLUI_Control*) this->prev(); + while( node ) { + if ( dynamic_cast(node) ) { + *col_x = node->x_abs; + *col_y = parent_y_abs; + *col_w = node->w; + *col_h = parent_h; + *col_x_off = node->x_off; + *col_y_off = 0; + + return; + } + + node = (GLUI_Control*) node->prev(); + } + + /*** Nope, Look for next column ***/ + node = (GLUI_Control*) this->next(); + while( node ) { + if ( dynamic_cast(node) ) { + *col_x = parent_ptr->x_abs; + *col_y = parent_y_abs; + *col_w = node->x_abs - parent_ptr->x_abs; + *col_h = parent_h; + *col_x_off = node->x_off; + *col_y_off = 0; + + return; + } + + node = (GLUI_Control*) node->next(); + } + + /*** This is single-column panel, so return panel dims ***/ + *col_x = parent_ptr->x_abs; + *col_y = parent_y_abs; + *col_w = parent_ptr->w; + *col_h = parent_h; + *col_x_off = parent_ptr->x_off; + *col_y_off = 0; + } +} + + +void GLUI_Control::pack( int x, int y ) +{ + GLUI_Control *node; + int max_w, curr_y, curr_x, max_y; + int x_in = x, y_in =y; + int x_margin, y_margin_top, y_margin_bot; + int y_top_column; + int column_x; + GLUI_Column *curr_column = NULL; + + this->update_size(); + + x_margin = this->x_off; + y_margin_top = this->y_off_top; + y_margin_bot = this->y_off_bot; + + this->x_abs = x_in; + this->y_abs = y_in; + + max_w = 0; + max_y = 0; + curr_x = this->x_abs + x_margin; + curr_y = this->y_abs + y_margin_top; + + /*** Record start of this set of columns ***/ + + y_top_column = curr_y; + column_x = curr_x; + + /*** Iterate over children, packing them first ***/ + + node = (GLUI_Control*) this->first_child(); + while( node != NULL ) { + if ( dynamic_cast(node) && !node->collapsible) { + /* Pad some space above fixed-size panels */ + curr_y += GLUI_ITEMSPACING; + } + else if ( dynamic_cast(node) ) { + curr_column = (GLUI_Column*) node; + curr_x += max_w + 1 * x_margin; + column_x = curr_x; + + node->x_abs = curr_x; + node->y_abs = y_top_column; + node->w = 2; + node->h = curr_y - y_top_column; + + curr_x += x_margin * 1; + curr_y = y_top_column; + max_w = 0; + + node = (GLUI_Control*) node->next(); + continue; + } + + node->pack( curr_x, curr_y ); + + if ( dynamic_cast(node) && !node->collapsible) + /* Pad some space below fixed-size panels */ + curr_y += GLUI_ITEMSPACING; + + curr_y += node->h; + + if ( node->w > max_w ) { + max_w = node->w; + if ( curr_column != NULL ) + curr_column->w = max_w + x_margin; + } + + if ( curr_y > max_y ) { + max_y = curr_y; + if ( curr_column != NULL ) + curr_column->h = max_y - y_top_column; + } + + node = (GLUI_Control*) node->next(); + + if ( node ) { + curr_y += GLUI_ITEMSPACING; + } + + } + + if ( this->is_container ) { + max_y += y_margin_bot; /*** Add bottom border inside box */ + + if ( this->first_child() ) { + this->w = column_x + max_w + 2 * x_margin - x_in; + this->h = (max_y - y_in); + } + else { /* An empty container, so just assign default w & h */ + if ( !dynamic_cast(this) && + !dynamic_cast(this) ) { + this->w = GLUI_DEFAULT_CONTROL_WIDTH; + this->h = GLUI_DEFAULT_CONTROL_HEIGHT; + } + } + + /** Expand panel if necessary (e.g., to include all the text in + a panel label) **/ + this->update_size(); + + + /*** Now we step through the GLUI_Columns, setting the 'h' ***/ + node = (GLUI_Control*) this->first_child(); + while( node != NULL ) { + if ( dynamic_cast(node) ) { + node->h = this->h - y_margin_bot - y_margin_top; + } + + node = (GLUI_Control*) node->next(); + } + } +} + + + +/******************************** Live Variables **************************/ +/*********** GLUI_Control::sync_live() ************/ +/* Reads live variable and sets control to its current value */ +/* This function is recursive, and operates on control's children */ + +void GLUI_Control::sync_live(int recurse, int draw_it) +{ + GLUI_Node *node; + int sync_it=true; + int i; + float *fp; + bool changed = false; + + /*** If this is currently active control, and mouse button is down, + don't sync ***/ + if ( glui ) + { + if ( this == glui->active_control AND glui->mouse_button_down ) + sync_it = false; + + /*** Actually, just disable syncing if button is down ***/ + /*** Nope, go ahead and sync if mouse is down - this allows syncing in + callbacks ***/ + if ( 0 ) { /* THIS CODE BELOW SHOULD NOT BE EXECUTED */ + if ( glui->mouse_button_down ) { + /* printf( "Can't sync\n" ); */ + return; + } + } + } + + /*** If this control has a live variable, we check its current value + against the stored value in the control ***/ + + if ( ptr_val != NULL ) { + if ( live_type == GLUI_LIVE_NONE OR NOT sync_it ) { + } + else if ( live_type == GLUI_LIVE_INT ) { + if ( *((int*)ptr_val) != last_live_int ) { + set_int_val( *((int*)ptr_val) ); + last_live_int = *((int*)ptr_val); + changed = true; + } + } + else if ( live_type == GLUI_LIVE_FLOAT ) { + if ( *((float*)ptr_val) != last_live_float ) { + set_float_val( *((float*)ptr_val) ); + last_live_float = *((float*)ptr_val); + changed = true; + } + } + else if ( live_type == GLUI_LIVE_TEXT ) { + if ( last_live_text.compare((const char*)ptr_val) != 0 ) { + set_text( (char*) ptr_val ); + last_live_text = (const char*)ptr_val; + changed = true; + } + } + else if ( live_type == GLUI_LIVE_STRING ) { + if ( last_live_text.compare(((std::string*) ptr_val)->c_str()) != 0 ) { + set_text( ((std::string*) ptr_val)->c_str()); + last_live_text = *((std::string*) ptr_val); + changed = true; + } + } + else if ( live_type == GLUI_LIVE_FLOAT_ARRAY ) { + /*** Step through the arrays, and see if they're the same ***/ + + fp = (float*) ptr_val; + for ( i=0; ifirst_child(); + while( node ) { + ((GLUI_Control*) node)->sync_live(true, true); + node = node->next(); + } + + if ( collapsible == true AND is_open == false ) { + /** Here we have a collapsed control (e.g., a rollout that is closed **/ + /** We need to go in and sync all the collapsed controls inside **/ + + node = this->collapsed_node.first_child(); + while( node ) { + ((GLUI_Control*) node)->sync_live(true, false); + node = node->next(); + } + } + } +} + + +/********** GLUI_Control::output_live() ************/ +/* Writes current value of control to live variable. */ + +void GLUI_Control::output_live(int update_main_gfx) +{ + int i; + float *fp; + + if ( ptr_val == NULL ) + return; + + if ( NOT live_inited ) + return; + + if ( live_type == GLUI_LIVE_NONE ) { + } + else if ( live_type == GLUI_LIVE_INT ) { + *((int*)ptr_val) = int_val; + last_live_int = int_val; + } + else if ( live_type == GLUI_LIVE_FLOAT ) { + *((float*)ptr_val) = float_val; + last_live_float = float_val; + } + else if ( live_type == GLUI_LIVE_TEXT ) { + strncpy( (char*) ptr_val, text.c_str(), text.length()+1); + last_live_text = text; + } + else if ( live_type == GLUI_LIVE_STRING ) { + (*(std::string*)ptr_val)= text.c_str(); + last_live_text = text; + } + else if ( live_type == GLUI_LIVE_FLOAT_ARRAY ) { + fp = (float*) ptr_val; + + for( i=0; iglui != NULL ) { + this->glui->post_update_main_gfx(); + } +} + + +/****** GLUI_Control::execute_callback() **********/ + +void GLUI_Control::execute_callback() +{ + int old_window; + + old_window = glutGetWindow(); + + if ( glui AND glui->main_gfx_window_id != -1 ) + glutSetWindow( glui->main_gfx_window_id ); + + this->callback( this ); +// if ( this->callback ) +// this->callback( this->user_id ); + + glutSetWindow( old_window ); +} + + +/************** GLUI_Control::init_live() **********/ +/* Reads in value of a live variable. Called once, when ctrl is created */ + +void GLUI_Control::init_live() +{ + int i; + float *fp; + + if ( ptr_val == NULL ) + return; + + if ( live_type == GLUI_LIVE_NONE ) { + } + else if ( live_type == GLUI_LIVE_INT ) { + set_int_val( *((int*)ptr_val) ); + last_live_int = *((int*)ptr_val); + } + else if ( live_type == GLUI_LIVE_FLOAT ) { + set_float_val( *((float*)ptr_val) ); + last_live_float = *((float*)ptr_val); + } + else if ( live_type == GLUI_LIVE_TEXT ) { + set_text( (const char*) ptr_val ); + last_live_text = (const char*) ptr_val; + } + else if ( live_type == GLUI_LIVE_STRING ) { + set_text( ((std::string*) ptr_val)->c_str() ); + last_live_text = ((std::string*) ptr_val)->c_str(); + } + else if ( live_type == GLUI_LIVE_FLOAT_ARRAY ) { + set_float_array_val( (float*) ptr_val ); + + fp = (float*) ptr_val; + + for( i=0; ienable(); + node = (GLUI_Control*) node->next(); + } +} + + +/***** GLUI_Control::disable() ****************/ + +void GLUI_Control::disable() +{ + GLUI_Control *node; + + enabled = false; + + if ( NOT glui ) + return; + + if ( glui->active_control == this ) + glui->deactivate_current_control(); + redraw(); + + /*** Now recursively disable all buttons below it ***/ + node = (GLUI_Control*) first_child(); + while(node) { + node->disable(); + node = (GLUI_Control*) node->next(); + } +} + +/******* GLUI_Control::set_w() **************/ + +void GLUI_Control::set_w(int new_w) +{ + w = new_w; + update_size(); /* Make sure control is big enough to fit text */ + if (glui) glui->refresh(); +} + + +/**** GLUI_Control::set_h() **************/ + +void GLUI_Control::set_h(int new_h) +{ + h = new_h; + update_size(); /* Make sure control is big enough to fit text */ + if (glui) glui->refresh(); +} + + +/***** GLUI_Control::set_alignment() ******/ + +void GLUI_Control::set_alignment(int new_align) +{ + alignment = new_align; + + if ( glui ) + { + glui->align_controls(this); + redraw_window(); + } +} + + +/***** GLUI_Control::needs_idle() *********/ +/* This method gets overloaded by specific classes, e.g. Spinner. */ +/* It returns whether or not a control needs to receive an idle event or not */ +/* For example, a spinner only needs idle events when the user is holding */ +/* the mouse down in one of the arrows. Otherwise, don't waste cycles */ +/* and OpenGL context switching by calling its idle. */ + +bool GLUI_Control::needs_idle() const +{ + return false; +} + + +/********* GLUI_Control::~GLUI_Control() **********/ + +GLUI_Control::~GLUI_Control() +{ + GLUI_Control *item = (GLUI_Control*) this->first_child(); + + while (item) + { + GLUI_Control *tmp = item; + item = (GLUI_Control*) item->next(); + delete tmp; + } +} + +/********* GLUI_Control::hide_internal() ********/ +/** Sets hidden==true for this control and all its siblings. */ +/** If recurse is true, we go to children as well */ + +void GLUI_Control::hide_internal( int recurse ) +{ + GLUI_Node *node; + + node = (GLUI_Node *) this; + while( node != NULL ) { + ((GLUI_Control*)node)->hidden = true; + + if ( recurse AND node->first_child() != NULL ) + ((GLUI_Control*) node->first_child())->hide_internal(true); + + node = node->next(); + } + + node = this->collapsed_node.first_child(); + while( node != NULL ) { + ((GLUI_Control*)node)->hidden = true; + + if ( recurse AND node->first_child() != NULL ) + ((GLUI_Control*) node->first_child())->hide_internal(true); + + node = node->next(); + } +} + + +/********* GLUI_Control::unhide_internal() ********/ +/** Sets hidden==false for this control and all its siblings. */ +/** If recurse is true, we go to children as well */ + +void GLUI_Control::unhide_internal( int recurse ) +{ + GLUI_Node *node; + + node = (GLUI_Node *) this; + while( node != NULL ) { + /* printf( "unhide: %s [%d]\n", ((GLUI_Control*)node)->name.c_str(), + ((GLUI_Control*)node)->hidden );*/ + ((GLUI_Control*)node)->hidden = false; + + if ( recurse AND node->first_child() != NULL ) + ((GLUI_Control*) node->first_child())->unhide_internal(true); + + node = node->next(); + } + + node = this->collapsed_node.first_child(); + while( node != NULL ) { + ((GLUI_Control*)node)->hidden = false; + + if ( recurse AND node->first_child() != NULL ) + ((GLUI_Control*) node->first_child())->unhide_internal(true); + + node = node->next(); + } +} diff --git a/tests/Box2D_v2.2.1/glui/glui_edittext.cpp b/tests/Box2D_v2.2.1/glui/glui_edittext.cpp new file mode 100755 index 0000000000000..5f2a1d84529ed --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_edittext.cpp @@ -0,0 +1,1198 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_edittext.cpp - GLUI_EditText control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui_internal_control.h" +#include + +/****************************** GLUI_EditText::GLUI_EditText() **********/ + +GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name, + int data_type, void *live_var, + int id, GLUI_CB callback ) +{ + if (data_type == GLUI_EDITTEXT_TEXT) { + live_type = GLUI_LIVE_TEXT; + } + else if (data_type == GLUI_EDITTEXT_STRING) { + data_type = GLUI_EDITTEXT_TEXT; // EDITTEXT_STRING doesn't really exist. + // Except as a signal to make a string. + // It's a backwards-compat hack. + live_type = GLUI_LIVE_STRING; + } + else if (data_type == GLUI_EDITTEXT_INT) { + live_type = GLUI_LIVE_INT; + } + else if (data_type == GLUI_EDITTEXT_FLOAT) { + live_type = GLUI_LIVE_FLOAT; + } + common_construct( parent, name, data_type, live_type, live_var, id, callback ); +} + +/****************************** GLUI_EditText::GLUI_EditText() **********/ + +GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name, + int text_type, int id, GLUI_CB callback ) +{ + common_construct( parent, name, text_type, GLUI_LIVE_NONE, 0, id, callback); +} + +/****************************** GLUI_EditText::GLUI_EditText() **********/ + +GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name, + int *live_var, + int id, GLUI_CB callback ) +{ + common_construct( parent, name, GLUI_EDITTEXT_INT, GLUI_LIVE_INT, live_var, id, callback); +} + +/****************************** GLUI_EditText::GLUI_EditText() **********/ + +GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name, + float *live_var, + int id, GLUI_CB callback ) +{ + common_construct( parent, name, GLUI_EDITTEXT_FLOAT, GLUI_LIVE_FLOAT, live_var, id, callback); +} + +/****************************** GLUI_EditText::GLUI_EditText() **********/ + +GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name, + char *live_var, + int id, GLUI_CB callback ) +{ + common_construct( parent, name, GLUI_EDITTEXT_TEXT, GLUI_LIVE_TEXT, live_var, id, callback); +} + +/****************************** GLUI_EditText::GLUI_EditText() **********/ + +GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name, + std::string &live_var, + int id, GLUI_CB callback ) +{ + common_construct( parent, name, GLUI_EDITTEXT_TEXT, GLUI_LIVE_STRING, &live_var, id, callback); +} + +/****************************** GLUI_EditText::common_construct() **********/ + +void GLUI_EditText::common_construct( GLUI_Node *parent, const char *name, + int data_t, int live_t, void *data, int id, + GLUI_CB cb ) +{ + common_init(); + set_name( name ); + + live_type = live_t; + data_type = data_t; + ptr_val = data; + user_id = id; + callback = cb; + + + if ( live_type == GLUI_LIVE_INT) { + if ( data == NULL ) + set_int_val(int_val); /** Set to some default, in case of no live var **/ + } + else if ( live_type == GLUI_LIVE_FLOAT ) { + num_periods = 1; + if ( data == NULL ) + set_float_val(float_val); /** Set to some default, in case of no live var **/ + } + + parent->add_control( this ); + + init_live(); +} + +/****************************** GLUI_EditText::mouse_down_handler() **********/ + +int GLUI_EditText::mouse_down_handler( int local_x, int local_y ) +{ + int tmp_insertion_pt; + + if ( debug ) dump( stdout, "-> MOUSE DOWN" ); + + tmp_insertion_pt = find_insertion_pt( local_x, local_y ); + if ( tmp_insertion_pt == -1 ) { + if ( glui ) + glui->deactivate_current_control( ); + return false; + } + + insertion_pt = tmp_insertion_pt; + + sel_start = sel_end = insertion_pt; + + if ( can_draw()) + update_and_draw_text(); + + if ( debug ) dump( stdout, "<- MOUSE UP" ); + + return true; +} + + +/******************************** GLUI_EditText::mouse_up_handler() **********/ + +int GLUI_EditText::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + return false; +} + + +/***************************** GLUI_EditText::mouse_held_down_handler() ******/ + +int GLUI_EditText::mouse_held_down_handler( int local_x, int local_y, + bool new_inside) +{ + int tmp_pt; + + if ( NOT new_inside ) + return false; + + if ( debug ) dump( stdout, "-> HELD DOWN" ); + + tmp_pt = find_insertion_pt( local_x, local_y ); + + if ( tmp_pt == -1 AND sel_end != 0 ) { /* moved mouse past left edge */ + special_handler( GLUT_KEY_LEFT, GLUT_ACTIVE_SHIFT ); + } + else if ( tmp_pt == substring_end+1 AND sel_end != (int) text.length()) { + /* moved mouse past right edge */ + special_handler( GLUT_KEY_RIGHT, GLUT_ACTIVE_SHIFT ); + } + else if ( tmp_pt != -1 AND tmp_pt != sel_end ) { + sel_end = insertion_pt = tmp_pt; + + update_and_draw_text(); + } + + if ( debug ) + dump( stdout, "<- HELD DOWN" ); + + return false; +} + + +/****************************** GLUI_EditText::key_handler() **********/ + +int GLUI_EditText::key_handler( unsigned char key,int modifiers ) +{ + int i, regular_key; + /* int has_selection; */ + + if ( NOT glui ) + return false; + + if ( debug ) + dump( stdout, "-> KEY HANDLER" ); + + regular_key = false; + bool ctrl_down = (modifiers & GLUT_ACTIVE_CTRL)!=0; + /* has_selection = (sel_start != sel_end); */ + + if ( key == CTRL('m') ) { /* RETURN */ + /* glui->deactivate_current_control(); */ + deactivate(); /** Force callbacks, etc **/ + activate(GLUI_ACTIVATE_TAB); /** Reselect all text **/ + redraw(); + return true; + } + else if ( key == CTRL('[')) { /* ESCAPE */ + glui->deactivate_current_control(); + return true; + } + else if ( (key == 127 AND !ctrl_down) OR /* FORWARD DELETE */ + ( key == CTRL('d') AND modifiers == GLUT_ACTIVE_CTRL) ) + { + if ( sel_start == sel_end ) { /* no selection */ + if ( insertion_pt < (int)text.length() ) { + /*** See if we're deleting a period in a float data-type box ***/ + if ( data_type == GLUI_EDITTEXT_FLOAT AND text[insertion_pt]=='.' ) + num_periods--; + + /*** Shift over string first ***/ + text.erase(insertion_pt,1); + } + } + else { /* There is a selection */ + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + } + else if ( ((key == 127) AND ctrl_down) OR // Delete word forward + ((key == 'd') AND (modifiers == GLUT_ACTIVE_ALT)) ) + { + if ( sel_start == sel_end ) { /* no selection */ + sel_start = insertion_pt; + sel_end = find_word_break( insertion_pt, +1 ); + } + + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + else if ( key == CTRL('h') ) { /* BACKSPACE */ + if ( sel_start == sel_end ) { /* no selection */ + if ( insertion_pt > 0 ) { + /*** See if we're deleting a period in a float data-type box ***/ + if ( data_type == GLUI_EDITTEXT_FLOAT AND text[insertion_pt-1]=='.' ) + num_periods--; + + /*** Shift over string first ***/ + insertion_pt--; + text.erase(insertion_pt,1); + } + } + else { /* There is a selection */ + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + } + else if ( modifiers == GLUT_ACTIVE_CTRL ) /* CTRL ONLY */ + { + /* Ctrl-key bindings */ + if ( key == CTRL('a') ) { + return special_handler( GLUT_KEY_HOME, 0 ); + } + else if ( key == CTRL('e') ) { + return special_handler( GLUT_KEY_END, 0 ); + } + else if ( key == CTRL('b') ) { + return special_handler( GLUT_KEY_LEFT, 0 ); + } + else if ( key == CTRL('f') ) { + return special_handler( GLUT_KEY_RIGHT, 0 ); + } + else if ( key == CTRL('p') ) { + return special_handler( GLUT_KEY_UP, 0 ); + } + else if ( key == CTRL('n') ) { + return special_handler( GLUT_KEY_DOWN, 0 ); + } + else if ( key == CTRL('u') ) { /* ERASE LINE */ + insertion_pt = 0; + text.erase(0,text.length()); + sel_start = sel_end = 0; + } + else if ( key == CTRL('k') ) { /* KILL TO END OF LINE */ + sel_start = sel_end = insertion_pt; + text.erase(insertion_pt,GLUI_String::npos); + } + } + else if ( modifiers == GLUT_ACTIVE_ALT ) /* ALT ONLY */ + { + if ( key == 'b' ) { // Backward word + return special_handler ( GLUT_KEY_LEFT, GLUT_ACTIVE_CTRL ); + } + if ( key == 'f' ) { // Forward word + return special_handler ( GLUT_KEY_RIGHT, GLUT_ACTIVE_CTRL ); + } + } + else if ( (modifiers & GLUT_ACTIVE_CTRL) OR + (modifiers & GLUT_ACTIVE_ALT) ) + { + /** ignore other keys with modifiers */ + return true; + } + else { /* Regular key */ + regular_key = true; + + /** Check if we only accept numbers **/ + if (data_type == GLUI_EDITTEXT_FLOAT ) { + if ( (key < '0' OR key > '9') AND key != '.' AND key != '-' ) + return true; + + if ( key == '-' ) { /* User typed a '-' */ + + /* If user has first character selected, then '-' is allowed */ + if ( NOT ( MIN(sel_start,sel_end) == 0 AND + MAX(sel_start,sel_end) > 0 ) ) { + + /* User does not have 1st char selected */ + if (insertion_pt != 0 OR text[0] == '-' ) { + return true; /* Can only place negative at beginning of text, + and only one of them */ + } + } + } + + if ( key == '.' ) { + /*printf( "PERIOD: %d\n", num_periods ); */ + + if ( num_periods > 0 ) { + /** We're trying to type a period, but the text already contains + a period. Check whether the period is contained within + is current selection (thus it will be safely replaced) **/ + + int period_found = false; + if ( sel_start != sel_end ) { + for( i=MIN(sel_end,sel_start); i '9') AND key != '-' ) + return true; + + if ( key == '-' ) { /* User typed a '-' */ + + /* If user has first character selected, then '-' is allowed */ + if ( NOT ( MIN(sel_start,sel_end) == 0 AND + MAX(sel_start,sel_end) > 0 ) ) { + + /* User does not have 1st char selected */ + if (insertion_pt != 0 OR text[0] == '-' ) { + return true; /* Can only place negative at beginning of text, + and only one of them */ + } + } + } + } + + /** This is just to get rid of warnings - the flag regular_key is + set if the key was not a backspace, return, whatever. But I + believe if we're here, we know it was a regular key anyway */ + if ( regular_key ) { + } + + /**** If there's a current selection, erase it ******/ + if ( sel_start != sel_end ) { + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + + /******** We insert the character into the string ***/ + + text.insert(insertion_pt,1,key); + + /******** Move the insertion point and substring_end one over ******/ + insertion_pt++; + substring_end++; + + sel_start = sel_end = insertion_pt; + } + + /******** Now redraw text ***********/ + /* Hack to prevent text box from being cleared first **/ + /** int substring_change = update_substring_bounds(); + draw_text_only = + (NOT substring_change AND NOT has_selection AND regular_key ); + */ + + draw_text_only = false; /** Well, hack is not yet working **/ + update_and_draw_text(); + draw_text_only = false; + + + if ( debug ) + dump( stdout, "<- KEY HANDLER" ); + + /*** Now look to see if this string has a period ***/ + num_periods = 0; + for( i=0; i<(int)text.length(); i++ ) + if ( text[i] == '.' ) + num_periods++; + + return true; +} + + +/****************************** GLUI_EditText::activate() **********/ + +void GLUI_EditText::activate( int how ) +{ + if ( debug ) + dump( stdout, "-> ACTIVATE" ); + + active = true; + + if ( how == GLUI_ACTIVATE_MOUSE ) + return; /* Don't select everything if activated with mouse */ + + orig_text = text; + + sel_start = 0; + sel_end = (int)text.length(); + insertion_pt = 0; + + if ( debug ) + dump( stdout, "<- ACTIVATE" ); +} + + +/****************************** GLUI_EditText::deactivate() **********/ + +void GLUI_EditText::deactivate( void ) +{ + int new_int_val; + float new_float_val; + + active = false; + + if ( NOT glui ) + return; + + if ( debug ) + dump( stdout, "-> DISACTIVATE" ); + + sel_start = sel_end = insertion_pt = -1; + + /***** Retrieve the current value from the text *****/ + /***** The live variable will be updated by set_text() ****/ + if ( data_type == GLUI_EDITTEXT_FLOAT ) { + if ( text.length() == 0 ) /* zero-length string - make it "0.0" */ + text = "0.0"; + + new_float_val = atof( text.c_str() ); + + set_float_val( new_float_val ); + } + else if ( data_type == GLUI_EDITTEXT_INT ) { + if ( text.length() == 0 ) /* zero-length string - make it "0" */ + text = "0"; + + new_int_val = atoi( text.c_str() ); + + set_int_val( new_int_val ); + } + else + if ( data_type == GLUI_EDITTEXT_TEXT ) { + set_text(text); /* This will force callbacks and gfx refresh */ + } + + update_substring_bounds(); + + /******** redraw text without insertion point ***********/ + redraw(); + + /***** Now do callbacks if value changed ******/ + if ( orig_text != text ) { + this->execute_callback(); + + if ( 0 ) { + /* THE CODE BELOW IS FROM WHEN SPINNER ALSO MAINTAINED CALLBACKS */ + if ( spinner == NULL ) { /** Are we independent of a spinner? **/ + if ( callback ) { + callback( this ); + } + } + else { /* We're attached to a spinner */ + spinner->do_callbacks(); /* Let the spinner do the callback stuff */ + } + } + } + + if ( debug ) + dump( stdout, "<- DISACTIVATE" ); +} + +/****************************** GLUI_EditText::draw() **********/ + +void GLUI_EditText::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int name_x; + + name_x = MAX(text_x_offset - string_width(this->name) - 3,0); + draw_name( name_x , 13); + + glBegin( GL_LINES ); + glColor3f( .5, .5, .5 ); + glVertex2i( text_x_offset, 0 ); glVertex2i( w, 0 ); + glVertex2i( text_x_offset, 0 ); glVertex2i( text_x_offset, h ); + + glColor3f( 1., 1., 1. ); + glVertex2i( text_x_offset, h ); glVertex2i( w, h ); + glVertex2i( w, h ); glVertex2i( w, 0 ); + + if ( enabled ) + glColor3f( 0., 0., 0. ); + else + glColor3f( .25, .25, .25 ); + glVertex2i( text_x_offset+1, 1 ); glVertex2i( w-1, 1 ); + glVertex2i( text_x_offset+1, 1 ); glVertex2i( text_x_offset+1, h-1 ); + + glColor3f( .75, .75, .75 ); + glVertex2i( text_x_offset+1, h-1 ); glVertex2i( w-1, h-1 ); + glVertex2i( w-1, h-1 ); glVertex2i( w-1, 1 ); + glEnd(); + + /** Find where to draw the text **/ + update_substring_bounds(); + draw_text(0,0); + + draw_insertion_pt(); +} + + + +/************************** GLUI_EditText::update_substring_bounds() *********/ + +int GLUI_EditText::update_substring_bounds( void ) +{ + int box_width; + int text_len = (int)text.length(); + int old_start, old_end; + + old_start = substring_start; + old_end = substring_end; + + /*** Calculate the width of the usable area of the edit box ***/ + box_width = MAX( this->w - this->text_x_offset + - 4 /* 2 * the two-line box border */ + - 2 * GLUI_EDITTEXT_BOXINNERMARGINX, 0 ); + + CLAMP( substring_end, 0, MAX(text_len-1,0) ); + CLAMP( substring_start, 0, MAX(text_len-1,0) ); + + if ( debug ) dump( stdout, "-> UPDATE SS" ); + + if ( insertion_pt >= 0 AND + insertion_pt < substring_start ) { /* cursor moved left */ + substring_start = insertion_pt; + + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_end--; + } + else if ( insertion_pt > substring_end ) { /* cursor moved right */ + substring_end = insertion_pt-1; + + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_start++; + } + else { /* cursor is within old substring bounds */ + if ( last_insertion_pt > insertion_pt ) { /* cursor moved left */ + } + else { + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_end--; + + while(substring_end < text_len-1 + AND substring_width( substring_start, substring_end ) <= box_width) + substring_end++; + } + } + + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_end--; + + last_insertion_pt = insertion_pt; + + /*** No selection if not enabled ***/ + if ( NOT enabled ) { + sel_start = sel_end = 0; + } + + if ( debug ) dump( stdout, "<- UPDATE SS" ); + + if ( substring_start == old_start AND substring_end == old_end ) + return false; /*** bounds did not change ***/ + else + return true; /*** bounds did change ***/ +} + + +/********************************* GLUI_EditText::update_x_offsets() *********/ + +void GLUI_EditText::update_x_offsets( void ) +{ +} + + +/********************************* GLUI_EditText::draw_text() ****************/ + +void GLUI_EditText::draw_text( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int text_x, i, sel_lo, sel_hi; + + if ( debug ) dump( stdout, "-> DRAW_TEXT" ); + + if ( NOT draw_text_only ) { + if ( enabled ) + glColor3f( 1., 1., 1. ); + else + set_to_bkgd_color(); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( text_x_offset+2, 2 ); glVertex2i( w-2, 2 ); + glVertex2i( w-2, h-2 ); glVertex2i( text_x_offset+2, h-2 ); + glEnd(); + } + + /** Find where to draw the text **/ + + text_x = text_x_offset + 2 + GLUI_EDITTEXT_BOXINNERMARGINX; + + /*printf( "text_x: %d substr_width: %d start/end: %d/%d\n", + text_x, substring_width( substring_start, substring_end ), + substring_start, substring_end ); + */ + /** Find lower and upper selection bounds **/ + sel_lo = MIN(sel_start, sel_end ); + sel_hi = MAX(sel_start, sel_end ); + + int sel_x_start, sel_x_end, delta; + + /** Draw selection area dark **/ + if ( sel_start != sel_end ) { + sel_x_start = text_x; + sel_x_end = text_x; + for( i=substring_start; i<=substring_end; i++ ) { + delta = char_width( text[i] ); + + if ( i < sel_lo ) { + sel_x_start += delta; + sel_x_end += delta; + } + else if ( i < sel_hi ) { + sel_x_end += delta; + } + } + + glColor3f( 0.0f, 0.0f, .6f ); + glBegin( GL_QUADS ); + glVertex2i( sel_x_start, 2 ); glVertex2i( sel_x_end, 2 ); + glVertex2i( sel_x_end, h-2 ); glVertex2i( sel_x_start, h-2 ); + glEnd(); + } + + + if ( sel_start == sel_end ) { /* No current selection */ + if ( enabled ) + glColor3b( 0, 0, 0 ); + else + glColor3b( 32, 32, 32 ); + + glRasterPos2i( text_x, 13); + for( i=substring_start; i<=substring_end; i++ ) { + glutBitmapCharacter( get_font(), this->text[i] ); + } + } + else { /* There is a selection */ + int x = text_x; + for( i=substring_start; i<=substring_end; i++ ) { + if ( IN_BOUNDS( i, sel_lo, sel_hi-1)) { /* This character is selected */ + glColor3f( 1., 1., 1. ); + glRasterPos2i( x, 13); + glutBitmapCharacter( get_font(), this->text[i] ); + } + else { + glColor3f( 0., 0., 0. ); + glRasterPos2i( x, 13); + glutBitmapCharacter( get_font(), this->text[i] ); + } + + x += char_width( text[i] ); + } + } + + if ( debug ) dump( stdout, "<- DRAW_TEXT" ); +} + + +/******************************** GLUI_EditText::find_insertion_pt() *********/ +/* This function returns the character numer *before which* the insertion */ +/* point goes */ + +int GLUI_EditText::find_insertion_pt( int x, int y ) +{ + int curr_x, i; + + /*** See if we clicked outside box ***/ + if ( x < this->x_abs + text_x_offset ) + return -1; + + /* We move from right to left, looking to see if the mouse was clicked + to the right of the ith character */ + + curr_x = this->x_abs + text_x_offset + + substring_width( substring_start, substring_end ) + + 2 /* The edittext box has a 2-pixel margin */ + + GLUI_EDITTEXT_BOXINNERMARGINX; /** plus this many pixels blank space + between the text and the box **/ + + /*** See if we clicked in an empty box ***/ + if ( (int) text.length() == 0 ) + return 0; + + /** find mouse click in text **/ + for( i=substring_end; i>=substring_start; i-- ) { + curr_x -= char_width( text[i] ); + + if ( x > curr_x ) { + /* printf( "-> %d\n", i ); */ + + return i+1; + } + } + + return 0; + + /* Well, the mouse wasn't after any of the characters...see if it's + before the beginning of the substring */ + if ( 0 ) { + if ( x > (x_abs + text_x_offset + 2 ) ) + return substring_start; + + return -1; /* Nothing found */ + } +} + + +/******************************** GLUI_EditText::draw_insertion_pt() *********/ + +void GLUI_EditText::draw_insertion_pt( void ) +{ + int curr_x, i; + + if ( NOT can_draw() ) + return; + + /*** Don't draw insertion pt if control is disabled ***/ + if ( NOT enabled ) + return; + + if ( debug ) dump( stdout, "-> DRAW_INS_PT" ); + + if ( sel_start != sel_end OR insertion_pt < 0 ) { + return; /* Don't draw insertion point if there is a current selection */ + } + + /* printf( "insertion pt: %d\n", insertion_pt ); */ + + curr_x = this->x_abs + text_x_offset + + substring_width( substring_start, substring_end ) + + 2 /* The edittext box has a 2-pixel margin */ + + GLUI_EDITTEXT_BOXINNERMARGINX; /** plus this many pixels blank space + between the text and the box **/ + + for( i=substring_end; i>=insertion_pt; i-- ) { + curr_x -= char_width( text[i] ); + } + + glColor3f( 0.0, 0.0, 0.0 ); + glBegin( GL_LINE_LOOP ); + /*** + glVertex2i( curr_x, y_abs + 4 ); + glVertex2i( curr_x, y_abs + 4 ); + glVertex2i( curr_x, y_abs + h - 3 ); + glVertex2i( curr_x, y_abs + h - 3 ); + ***/ + curr_x -= x_abs; + glVertex2i( curr_x, 0 + 4 ); + glVertex2i( curr_x, 0 + 4 ); + glVertex2i( curr_x, 0 + h - 3 ); + glVertex2i( curr_x, 0 + h - 3 ); + glEnd(); + + if ( debug ) dump( stdout, "-> DRAW_INS_PT" ); +} + + + +/******************************** GLUI_EditText::substring_width() *********/ + +int GLUI_EditText::substring_width( int start, int end ) +{ + int i, width; + + width = 0; + + for( i=start; i<=end; i++ ) + width += char_width( text[i] ); + + return width; +} + + +/***************************** GLUI_EditText::update_and_draw_text() ********/ + +void GLUI_EditText::update_and_draw_text( void ) +{ + if ( NOT can_draw() ) + return; + + update_substring_bounds(); + /* printf( "ss: %d/%d\n", substring_start, substring_end ); */ + + redraw(); +} + + +/********************************* GLUI_EditText::special_handler() **********/ + +int GLUI_EditText::special_handler( int key,int modifiers ) +{ + if ( NOT glui ) + return false; + + if ( debug ) + printf( "SPECIAL:%d - mod:%d subs:%d/%d ins:%d sel:%d/%d\n", + key, modifiers, substring_start, substring_end,insertion_pt, + sel_start, sel_end ); + + if ( key == GLUT_KEY_LEFT ) { + if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) { + insertion_pt = find_word_break( insertion_pt, -1 ); + } + else { + insertion_pt--; + } + } + else if ( key == GLUT_KEY_RIGHT ) { + if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) { + insertion_pt = find_word_break( insertion_pt, +1 ); + } + else { + insertion_pt++; + } + } + else if ( key == GLUT_KEY_HOME ) { + insertion_pt = 0; + } + else if ( key == GLUT_KEY_END ) { + insertion_pt = (int) text.length(); + } + + /*** Update selection if shift key is down ***/ + if ( (modifiers & GLUT_ACTIVE_SHIFT ) != 0 ) + sel_end = insertion_pt; + else + sel_start = sel_end = insertion_pt; + + + CLAMP( insertion_pt, 0, (int) text.length()); /* Make sure insertion_pt + is in bounds */ + CLAMP( sel_start, 0, (int) text.length()); /* Make sure insertion_pt + is in bounds */ + CLAMP( sel_end, 0, (int) text.length()); /* Make sure insertion_pt + is in bounds */ + + /******** Now redraw text ***********/ + if ( can_draw()) + update_and_draw_text(); + + return true; +} + + +/****************************** GLUI_EditText::find_word_break() **********/ +/* It looks either left or right (depending on value of 'direction' */ +/* for the beginning of the next 'word', where word are characters */ +/* separated by one of the following tokens: " :-.," */ +/* If there is no next word in the specified direction, this returns */ +/* the beginning of 'text', or the very end. */ + +int GLUI_EditText::find_word_break( int start, int direction ) +{ + int i, j; + char *breaks = " :-.,"; + int num_break_chars = (int)strlen(breaks), text_len = (int)text.length(); + int new_pt; + + /** If we're moving left, we have to start two back, in case we're either + already at the beginning of a word, or on a separating token. + Otherwise, this function would just return the word we're already at **/ + if ( direction == -1 ) { + start -= 2; + } + + /***** Iterate over text in the specified direction *****/ + for ( i=start; i >= 0 AND i < text_len; i += direction ) { + + /** For each character in text, iterate over list of separating tokens **/ + for( j=0; j 0 ) /* Return the end of string */ + return text_len; + else /* Return the beginning of the text */ + return 0; +} + + +/********************************** GLUI_EditText::clear_substring() ********/ + +void GLUI_EditText::clear_substring( int start, int end ) +{ + int i; + + /* + printf( "clearing: %d-%d '", start,end); + for(i=start;ifloat_val = this->float_val; + spinner->int_val = this->int_val; + } + + /*** Now update the live variable ***/ + output_live(true); +} + + +/******************************* GLUI_EditText::set_float_val() ************/ + +void GLUI_EditText::set_float_val( float new_val ) +{ + if ( has_limits == GLUI_LIMIT_CLAMP ) { + /*** Clamp the new value to the existing limits ***/ + + CLAMP( new_val, float_low, float_high ); + } + else if ( has_limits == GLUI_LIMIT_WRAP ) { + /*** Clamp the value cyclically to the limits - that is, if the + value exceeds the max, set it the the minimum, and conversely ***/ + + if ( new_val < float_low ) + new_val = float_high; + if ( new_val > float_high ) + new_val = float_low; + } + + float_val = new_val; + int_val = (int) new_val; /* Mirror the value as an int, too */ + + set_numeric_text(); +} + + +/********************************** GLUI_EditText::set_int_val() ************/ + +void GLUI_EditText::set_int_val( int new_val ) +{ + if ( has_limits == GLUI_LIMIT_CLAMP ) { + /*** Clamp the new value to the existing limits ***/ + + CLAMP( new_val, int_low, int_high ); + } + else if ( has_limits == GLUI_LIMIT_WRAP ) { + /*** Clamp the value cyclically to the limits - that is, if the + value exceeds the max, set it the the minimum, and conversely ***/ + + if ( new_val < int_low ) + new_val = int_high; + if ( new_val > int_high ) + new_val = int_low; + } + + int_val = new_val; + float_val = (float) new_val; /* We mirror the value as a float, too */ + + set_numeric_text(); +} + + +/********************************* GLUI_EditText::set_float_limits() *********/ + +void GLUI_EditText::set_float_limits( float low, float high, int limit_type ) +{ + has_limits = limit_type; + float_low = low; + float_high = high; + + if ( NOT IN_BOUNDS( float_val, float_low, float_high )) + set_float_val( float_low ); + + int_low = (int) float_low; + int_high = (int) float_high; +} + + +/*********************************** GLUI_EditText::set_int_limits() *********/ + +void GLUI_EditText::set_int_limits( int low, int high, int limit_type ) +{ + has_limits = limit_type; + int_low = low; + int_high = high; + + if ( NOT IN_BOUNDS( int_val, int_low, int_high )) + set_int_val( int_low ); + + float_low = (float) int_low; + float_high = (float) int_high; +} + + +/************************************ GLUI_EditText::set_numeric_text() ******/ + +void GLUI_EditText::set_numeric_text( void ) +{ + char buf_num[200]; + int i, text_len; + + if ( data_type == GLUI_EDITTEXT_FLOAT ) { + sprintf( buf_num, "%#g", float_val ); + + num_periods = 0; + text_len = (int) strlen(buf_num); + for ( i=0; i 0 ) { + text_len = (int) strlen(buf_num); + for ( i=text_len-1; i>0; i-- ) { + if ( buf_num[i] == '0' AND buf_num[i-1] != '.' ) + buf_num[i] = '\0'; + else + break; + } + } + set_text( buf_num ); + } + else { + sprintf( buf_num, "%d", int_val ); + set_text( buf_num ); + } + +} + + +/*************************************** GLUI_EditText::dump() **************/ + +void GLUI_EditText::dump( FILE *out, const char *name ) +{ + fprintf( out, + "%s (edittext@%p): ins_pt:%d subs:%d/%d sel:%d/%d len:%d\n", + name, this, + insertion_pt, + substring_start, + substring_end, + sel_start, + sel_end, + (int) text.length()); +} + + +/**************************************** GLUI_EditText::mouse_over() ********/ + +int GLUI_EditText::mouse_over( int state, int x, int y ) +{ + if ( state ) { + /* curr_cursor = GLUT_CURSOR_TEXT; */ + glutSetCursor( GLUT_CURSOR_TEXT ); + } + else { + /* printf( "OUT\n" ); */ + glutSetCursor( GLUT_CURSOR_LEFT_ARROW ); + } + + return true; +} diff --git a/tests/Box2D_v2.2.1/glui/glui_filebrowser.cpp b/tests/Box2D_v2.2.1/glui/glui_filebrowser.cpp new file mode 100755 index 0000000000000..13171fbf987a4 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_filebrowser.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_filebrowser.cpp - GLUI_FileBrowser control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + This program is freely distributable without licensing fees and is + provided without guarantee or warrantee expressed or implied. This + program is -not- in the public domain. + +*****************************************************************************/ + +#include "glui.h" +#include "glui_internal.h" +#include + +#ifdef __GNUC__ +#include +#include +#endif + +#ifdef _WIN32 +#include +#endif + +#include + +GLUI_FileBrowser::GLUI_FileBrowser( GLUI_Node *parent, + const char *name, + int type, + int id, + GLUI_CB cb) +{ + common_init(); + + set_name( name ); + user_id = id; + int_val = type; + callback = cb; + + parent->add_control( this ); + list = new GLUI_List(this, true, 1); + list->set_object_callback( GLUI_FileBrowser::dir_list_callback, this ); + list->set_click_type(GLUI_DOUBLE_CLICK); + this->fbreaddir(this->current_dir.c_str()); +} + +/****************************** GLUI_FileBrowser::draw() **********/ + +void GLUI_FileBrowser::dir_list_callback(GLUI_Control *glui_object) { + GLUI_List *list = dynamic_cast(glui_object); + if (!list) + return; + GLUI_FileBrowser* me = dynamic_cast(list->associated_object); + if (!me) + return; + int this_item; + const char *selected; + this_item = list->get_current_item(); + if (this_item > 0) { /* file or directory selected */ + selected = list->get_item_ptr( this_item )->text.c_str(); + if (selected[0] == '/' || selected[0] == '\\') { + if (me->allow_change_dir) { +#ifdef __GNUC__ + chdir(selected+1); +#endif +#ifdef _WIN32 + SetCurrentDirectory(selected+1); +#endif + me->fbreaddir("."); + } + } else { + me->file = selected; + me->execute_callback(); + } + } +} + + + +void GLUI_FileBrowser::fbreaddir(const char *d) { + GLUI_String item; + int i = 0; + + if (!d) + return; + +#ifdef _WIN32 + + WIN32_FIND_DATA FN; + HANDLE hFind; + //char search_arg[MAX_PATH], new_file_path[MAX_PATH]; + //sprintf(search_arg, "%s\\*.*", path_name); + + hFind = FindFirstFile("*.*", &FN); + if (list) { + list->delete_all(); + if (hFind != INVALID_HANDLE_VALUE) { + do { + int len = strlen(FN.cFileName); + if (FN.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + item = '\\'; + item += FN.cFileName; + } else { + item = FN.cFileName; + } + list->add_item(i,item.c_str()); + i++; + } while (FindNextFile(hFind, &FN) != 0); + + if (GetLastError() == ERROR_NO_MORE_FILES) + FindClose(&FN); + else + perror("fbreaddir"); + } + } + +#elif defined(__GNUC__) + + DIR *dir; + struct dirent *dirp; + struct stat dr; + + if (list) { + list->delete_all(); + if ((dir = opendir(d)) == NULL) + perror("fbreaddir:"); + else { + while ((dirp = readdir(dir)) != NULL) /* open directory */ + { + if (!lstat(dirp->d_name,&dr) && S_ISDIR(dr.st_mode)) /* dir is directory */ + item = dirp->d_name + GLUI_String("/"); + else + item = dirp->d_name; + + list->add_item(i,item.c_str()); + i++; + } + closedir(dir); + } + } +#endif +} + +void ProcessFiles(const char *path_name) +{ + +} + + +void GLUI_FileBrowser::set_w(int w) +{ + if (list) list->set_w(w); +} + +void GLUI_FileBrowser::set_h(int h) +{ + if (list) list->set_h(h); +} diff --git a/tests/Box2D_v2.2.1/glui/glui_internal.h b/tests/Box2D_v2.2.1/glui/glui_internal.h new file mode 100755 index 0000000000000..20efc6f93b5cc --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_internal.h @@ -0,0 +1,105 @@ +#ifndef GLUI_INTERNAL_H +#define GLUI_INTERNAL_H + +#include +#include + +#ifndef AND +#define AND && +#define OR || +#define NOT ! +#endif + +#ifndef MAX +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#define MIN(a,b) ((a)<(b) ? (a) : (b)) +#endif + +#ifndef ABS +#define ABS(a) ((a)>=0 ? (a) : (-(a))) +#endif + +/******************** bit comparisons and operations ***************/ +#ifndef TEST_BIT +#define TEST_BIT( x, b ) (((x) & (1<<(b))) != 0 ) +#define SET_BIT( x, b ) ((x) |= (1 << (b))) +#define CLEAR_BIT( x, b ) ((x) &= ~(1 << (b))) +#define TOGGLE_BIT( x, b ) ((TEST_BIT(x,b)) ?(CLEAR_BIT(x,b)):(SET_BIT(x,b))) +#endif + +#ifndef TEST_AND +#define TEST_AND( a, b ) ((a&b)==b) +#endif + + +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +/*********** flush the stdout and stderr output streams *************/ +#ifndef flushout +#define flushout fflush(stdout) +#define flusherr fflush(stderr) +#endif + +/********** Debugging functions *************************************/ +#ifndef error_return +#define error_return( c ); {fprintf(stderr,c);return;} +#endif + +/************************* floating-point random ********************/ +#ifndef randf +#define randf() ((float) rand() / (float)RAND_MAX ) +#endif + +#ifndef SIGN +#define SIGN(x) ((x)>=0 ? 1 : -1) +#endif + +/****************** conversion between degrees and radians **********/ +#ifndef DEG2RAD +#define DEG2RAD(x) ((x)/180.0*M_PI) +#define RAD2DEG(x) ((x)/M_PI*180.0) +#endif + +/***************** clamp a value to some fixed interval *************/ +#ifndef CLAMP +#define CLAMP(x,lo,hi) {if ((x) < (lo)) {(x)=(lo);} else if((x) > (hi)) {(x)=(hi);}} +#endif + +/************ check if a value lies within a closed interval *********/ +#ifndef IN_BOUNDS +#define IN_BOUNDS( x, lo, hi ) ( (x) >= (lo) AND (x) <= (hi) ) +#endif + +/************ check if a 2D point lies within a 2D box ***************/ +#ifndef PT_IN_BOX +#define PT_IN_BOX( x, y, lo_x, hi_x, lo_y, hi_y ) \ +( IN_BOUNDS(x,lo_x,hi_x) AND IN_BOUNDS(y,lo_y,hi_y) ) +#endif + +/****** check if value lies on proper side of another value *****/ +/*** if side is positive => proper side is positive, else negative **/ +#ifndef CHECK_PROPER_SIDE +#define CHECK_PROPER_SIDE(x,val,side) ((side) > 0 ? (x) > (val) : (x) < (val)) +#endif + + +/***** Small value when we want to do a comparison to 'close to zero' *****/ +#ifndef FUDGE +#define FUDGE .00001 +#endif + + +/******************* swap two values, using a temp variable *********/ +#ifndef SWAP2 +#define SWAP2(a,b,t) {t=a;a=b;b=t;} +#endif + +#define VEC3_TO_ARRAY(v,a) a[0]=v[0], a[1]=v[1], a[2]=v[2] + +/**** Return the ASCII control code given the non-control ASCII character */ +#define CTRL(c) ( (c>=('a'-1)) ? (c-'a'+1) : (c-'A'+1) ) + + +#endif /* GLUI_INTERNAL_H */ diff --git a/tests/Box2D_v2.2.1/glui/glui_internal_control.h b/tests/Box2D_v2.2.1/glui/glui_internal_control.h new file mode 100755 index 0000000000000..ef0db159deffe --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_internal_control.h @@ -0,0 +1,45 @@ +/* + Header file for use by GLUI controls. + Everything you need is right here. + + +*/ +#ifndef __GLUI_INTERNAL_CONTROL_H +#define __GLUI_INTERNAL_CONTROL_H + +/* This is the main GLUI external header */ +#include "glui.h" + +/* Here's some utility routines */ +#include "glui_internal.h" + + +/** + A GLUI_Control-drawing sentinal object. + On creation, saves the current draw buffer and window. + On destruction, restores draw buffer and window. + This is way nicer than calling save/restore manually. +*/ +class GLUI_DrawingSentinal { + int orig_buf, orig_win; + GLUI_Control *c; +public: + /** The constructor sets up the drawing system */ + GLUI_DrawingSentinal(GLUI_Control *c_); + /** The destructor cleans up drawing back how it was */ + ~GLUI_DrawingSentinal(); + + // Do-nothing routine to avoid compiler warning about unused variable + inline void avoid_warning(void) {} +}; +/** Just drop a GLUI_DRAWINGSENTINAL_IDIOM at the start of your draw methods, +and they'll return if we can't be drawn, and +automatically save and restore all needed state. +*/ +#define GLUI_DRAWINGSENTINAL_IDIOM if (NOT can_draw()) return; GLUI_DrawingSentinal drawSentinal(this); drawSentinal.avoid_warning(); + + +/** Return the time, in seconds. */ +inline double GLUI_Time(void) {return 0.001*glutGet(GLUT_ELAPSED_TIME);} + +#endif diff --git a/tests/Box2D_v2.2.1/glui/glui_list.cpp b/tests/Box2D_v2.2.1/glui/glui_list.cpp new file mode 100755 index 0000000000000..a5b0939354112 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_list.cpp @@ -0,0 +1,540 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_list.cpp - GLUI_List control class + + + -------------------------------------------------- + + Copyright (c) 2004 John Kew + + This program is freely distributable without licensing fees and is + provided without guarantee or warrantee expressed or implied. This + program is -not- in the public domain. + +*****************************************************************************/ + +#include "glui_internal_control.h" +#include +#include + +/****************************** GLUI_List::GLUI_List() **********/ + +GLUI_List::GLUI_List( GLUI_Node *parent, bool scroll, + int id, GLUI_CB callback + /*,GLUI_Control *object + GLUI_InterObject_CB obj_cb*/) +{ + common_construct(parent, NULL, scroll, id, callback/*, object, obj_cb*/); +} + +/****************************** GLUI_List::GLUI_List() **********/ + +GLUI_List::GLUI_List( GLUI_Node *parent, + GLUI_String& live_var, bool scroll, + int id, + GLUI_CB callback + /* ,GLUI_Control *object + ,GLUI_InterObject_CB obj_cb*/ ) +{ + common_construct(parent, &live_var, scroll, id, callback/*, object, obj_cb*/); +} + +/****************************** GLUI_List::common_construct() **********/ + +void GLUI_List::common_construct( + GLUI_Node *parent, + GLUI_String* data, bool scroll, + int id, + GLUI_CB callback + /*,GLUI_Control *object + , GLUI_InterObject_CB obj_cb*/) +{ + common_init(); + GLUI_Node *list_panel = parent; + + if (scroll) { + GLUI_Panel *p = new GLUI_Panel(parent,"",GLUI_PANEL_NONE); + p->x_off = 1; + list_panel = p; + } + this->ptr_val = data; + if (data) { + this->live_type = GLUI_LIVE_STRING; + } + this->user_id = id; + this->callback = callback; + this->name = "list"; + list_panel->add_control( this ); + if (scroll) + { + new GLUI_Column(list_panel, false); + scrollbar = + new GLUI_Scrollbar(list_panel, + "scrollbar", + GLUI_SCROLL_VERTICAL, + GLUI_SCROLL_INT); + scrollbar->set_object_callback(GLUI_List::scrollbar_callback, this); + scrollbar->set_alignment(GLUI_ALIGN_LEFT); + // scrollbar->can_activate = false; //kills ability to mouse drag too + } + init_live(); +} + +/****************************** GLUI_List::mouse_down_handler() **********/ +int GLUI_List::mouse_down_handler( int local_x, int local_y ) +{ + int tmp_line; + unsigned long int ms; + timeb time; + ftime(&time); + ms = time.millitm + (time.time)*1000; + + tmp_line = find_line( local_x-x_abs, local_y-y_abs-5 ); + if ( tmp_line == -1 ) { + if ( glui ) + glui->deactivate_current_control( ); + return false; + } + + if (tmp_line < num_lines) { + curr_line = tmp_line; + if (scrollbar) + scrollbar->set_int_val(curr_line); + this->execute_callback(); + if (associated_object != NULL) + if (cb_click_type == GLUI_SINGLE_CLICK) { + if (obj_cb) { + // obj_cb(associated_object, user_id); + obj_cb(this); + } + } else { + if (last_line == curr_line && (ms - last_click_time) < 300) { + //obj_cb(associated_object, user_id); + obj_cb(this); + } else { + last_click_time = ms; + last_line = curr_line; + } + } + if ( can_draw()) + update_and_draw_text(); + } + + return true; +} + + + + +/******************************** GLUI_List::mouse_up_handler() **********/ + +int GLUI_List::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + return false; +} + + +/***************************** GLUI_List::mouse_held_down_handler() ******/ + +int GLUI_List::mouse_held_down_handler( int local_x, int local_y, + bool new_inside) +{ + return false; +} + + +/****************************** GLUI_List::key_handler() **********/ + +int GLUI_List::key_handler( unsigned char key,int modifiers ) +{ + + + draw_text_only = false; /** Well, hack is not yet working **/ + update_and_draw_text(); + draw_text_only = false; + + return true; +} + + +/****************************** GLUI_List::activate() **********/ + +void GLUI_List::activate( int how ) +{ +// if ( debug ) +// dump( stdout, "-> ACTIVATE" ); + active = true; + + if ( how == GLUI_ACTIVATE_MOUSE ) + return; /* Don't select everything if activated with mouse */ + +} + + +/****************************** GLUI_List::deactivate() **********/ + +void GLUI_List::deactivate( void ) +{ + active = false; + redraw(); +} + +/****************************** GLUI_List::draw() **********/ + +void GLUI_List::draw( int x, int y ) +{ + int line = 0; + int box_width; + GLUI_List_Item *item; + + GLUI_DRAWINGSENTINAL_IDIOM + + /* Bevelled Border */ + glBegin( GL_LINES ); + glColor3f( .5, .5, .5 ); + glVertex2i( 0, 0 ); glVertex2i( w, 0 ); + glVertex2i( 0, 0 ); glVertex2i( 0, h ); + + glColor3f( 1., 1., 1. ); + glVertex2i( 0, h ); glVertex2i( w, h ); + glVertex2i( w, h ); glVertex2i( w, 0 ); + + if ( enabled ) + glColor3f( 0., 0., 0. ); + else + glColor3f( .25, .25, .25 ); + glVertex2i( 1, 1 ); glVertex2i( w-1, 1 ); + glVertex2i( 1, 1 ); glVertex2i( 1, h-1 ); + + glColor3f( .75, .75, .75 ); + glVertex2i( 1, h-1 ); glVertex2i( w-1, h-1 ); + glVertex2i( w-1, h-1 ); glVertex2i( w-1, 1 ); + glEnd(); + + /* Draw Background if enabled*/ + if (enabled) { + glColor3f( 1., 1., 1. ); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( 2, 2 ); glVertex2i( w-2, 2 ); + glVertex2i( w-2, h-2 ); glVertex2i(2, h-2 ); + glEnd(); + } else { + glColor3f( .8, .8, .8 ); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( 2, 2 ); glVertex2i( w-2, 2 ); + glVertex2i( w-2, h-2 ); glVertex2i(2, h-2 ); + glEnd(); + } + + /* Figure out how wide the box is */ + box_width = get_box_width(); + + /* Figure out which lines are visible*/ + + visible_lines = (int)(h-20)/15; + + item = (GLUI_List_Item *) items_list.first_child(); + + line = 0; + while (item) { + if (line < start_line) { + line++; + item = (GLUI_List_Item *) item->next(); + continue; + } + if (line >= start_line && line <= (start_line+visible_lines)) { + if (curr_line == line) + draw_text(item->text.c_str(),1,0,(line - start_line)*15); + else + draw_text(item->text.c_str(),0,0,(line - start_line)*15); + } + line++; + item = (GLUI_List_Item *) item->next(); + } + + if (scrollbar) { + scrollbar->set_int_limits(MAX(0,num_lines-visible_lines), 0); + glPushMatrix(); + glTranslatef(scrollbar->x_abs-x_abs, scrollbar->y_abs-y_abs,0.0); + scrollbar->draw_scroll(); + glPopMatrix(); + } +} + +/********************************* GLUI_List::draw_text() ****************/ + +void GLUI_List::draw_text(const char *t, int selected, int x, int y ) +{ + int text_x, i, x_pos; + int box_width; + + GLUI_DRAWINGSENTINAL_IDIOM + + /** Find where to draw the text **/ + + text_x = 2 + GLUI_LIST_BOXINNERMARGINX; + + /** Draw selection area dark **/ + if ( enabled && selected ) { + glColor3f( 0.0f, 0.0f, .6f ); + glBegin( GL_QUADS ); + glVertex2i(text_x, y+5 ); glVertex2i( w-text_x, y+5 ); + glVertex2i(w-text_x, y+19 ); glVertex2i(text_x, y+19 ); + glEnd(); + } + box_width = get_box_width(); + + if ( !selected || !enabled ) { /* No current selection */ + x_pos = text_x; /* or control disabled */ + if ( enabled ) + glColor3b( 0, 0, 0 ); + else + glColor3b( 32, 32, 32 ); + + glRasterPos2i( text_x, y+15); + i = 0; + while( t[i] != '\0' && substring_width(t,0,i) < box_width) { + glutBitmapCharacter( get_font(), t[i] ); + x_pos += char_width( t[i] ); + i++; + } + } + else { /* There is a selection */ + i = 0; + x_pos = text_x; + glColor3f( 1., 1., 1. ); + glRasterPos2i( text_x, y+15); + while( t[i] != '\0' && substring_width(t,0,i) < box_width) { + glutBitmapCharacter( get_font(), t[i] ); + x_pos += char_width( t[i] ); + i++; + } + } +} + + +int GLUI_List::find_line(int x, int y) { + return start_line + ((int)(y/15)); +} + +int GLUI_List::get_box_width() { + return MAX( this->w + - 6 /* 2 * the two-line box border */ + - 2 * GLUI_LIST_BOXINNERMARGINX, 0 ); + +} + +/******************************** GLUI_List::substring_width() *********/ +int GLUI_List::substring_width( const char *t, int start, int end ) +{ + int i, width; + + width = 0; + + for( i=start; i<=end; i++ ) + width += char_width( t[i] ); + + return width; +} + + +/***************************** GLUI_List::update_and_draw_text() ********/ + +void GLUI_List::update_and_draw_text( void ) +{ + if ( NOT can_draw() ) + return; + + //update_substring_bounds(); + /* printf( "ss: %d/%d\n", substring_start, substring_end ); */ + + redraw(); +} + + +/********************************* GLUI_List::special_handler() **********/ + +int GLUI_List::special_handler( int key,int modifiers ) +{ + if ( NOT glui ) + return false; + + if ( key == GLUT_KEY_DOWN ) { + if (curr_line < num_lines) { + curr_line++; + if (curr_line > start_line+visible_lines) + start_line++; + } + } else if ( key == GLUT_KEY_UP ) { + if (curr_line > 0) { + curr_line--; + if (curr_line < start_line) + start_line--; + } + } + + if (scrollbar) + scrollbar->set_int_val(curr_line); + redraw(); + return true; +} + + +/************************************ GLUI_List::update_size() **********/ + +void GLUI_List::update_size( void ) +{ + if ( NOT glui ) + return; + + if ( w < GLUI_LIST_MIN_TEXT_WIDTH ) + w = GLUI_LIST_MIN_TEXT_WIDTH; +} + +/**************************************** GLUI_Listbox::add_item() **********/ + +int GLUI_List::add_item( int id, const char *new_text ) +{ + GLUI_List_Item *new_node = new GLUI_List_Item; + GLUI_List_Item *head; + + new_node->text = new_text; + new_node->id = id; + + head = (GLUI_List_Item*) items_list.first_child(); + new_node->link_this_to_parent_last( &items_list ); + + if ( head == NULL ) { + /*** This is first item added ***/ + + int_val = id+1; /** Different than id **/ + // do_selection( id ); + last_live_int = id; + + if( glui ) + glui->post_update_main_gfx(); + } + num_lines++; + if (scrollbar) + scrollbar->set_int_limits(MAX(num_lines-visible_lines,0), 0); + + return true; +} + +/************************************** GLUI_Listbox::delete_() **********/ + +int GLUI_List::delete_all() +{ + GLUI_List_Item *item; + + item = (GLUI_List_Item *) items_list.first_child(); + while( item ) { + item->unlink(); + delete item; + item = (GLUI_List_Item *) items_list.first_child(); + } + + num_lines = 0; + curr_line = 0; + + return true; +} + + +/************************************** GLUI_Listbox::delete_item() **********/ + +int GLUI_List::delete_item( const char *text ) +{ + GLUI_List_Item *node = get_item_ptr( text ); + + if ( node ) { + node->unlink(); + delete node; + num_lines--; + return true; + } + else { + return false; + } +} + + +/************************************** GLUI_Listbox::delete_item() **********/ + +int GLUI_List::delete_item( int id ) +{ + GLUI_List_Item *node = get_item_ptr( id ); + + if ( node ) { + node->unlink(); + delete node; + num_lines--; + return true; + } + else { + return false; + } +} + + +/************************************ GLUI_Listbox::get_item_ptr() **********/ + +GLUI_List_Item *GLUI_List::get_item_ptr( const char *text ) +{ + GLUI_List_Item *item; + + item = (GLUI_List_Item *) items_list.first_child(); + while( item ) { + if ( item->text == text ) + return item; + + item = (GLUI_List_Item *) item->next(); + } + + return NULL; +} + + +/************************************ GLUI_Listbox::get_item_ptr() **********/ + +GLUI_List_Item *GLUI_List::get_item_ptr( int id ) +{ + GLUI_List_Item *item; + + item = (GLUI_List_Item *) items_list.first_child(); + while( item ) { + if ( item->id == id ) + return item; + + item = (GLUI_List_Item *) item->next(); + } + + return NULL; +} + +/**************************************** GLUI_List::mouse_over() ********/ + +int GLUI_List::mouse_over( int state, int x, int y ) +{ + glutSetCursor( GLUT_CURSOR_LEFT_ARROW ); + + return true; +} + +void GLUI_List::scrollbar_callback(GLUI_Control *my_scrollbar) { + GLUI_Scrollbar *sb = dynamic_cast(my_scrollbar); + if (!sb) return; + GLUI_List* me = (GLUI_List*) sb->associated_object; + if (me->scrollbar == NULL) + return; + int new_start_line = sb->get_int_val(); // TODO!! + me->start_line = new_start_line; + + if ( me->can_draw() ) + me->update_and_draw_text(); +} diff --git a/tests/Box2D_v2.2.1/glui/glui_listbox.cpp b/tests/Box2D_v2.2.1/glui/glui_listbox.cpp new file mode 100755 index 0000000000000..3eda31079cd0c --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_listbox.cpp @@ -0,0 +1,448 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_listbox - GLUI_ListBox control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui_internal_control.h" + +/****************************** GLUI_Listbox::GLUI_Listbox() **********/ +GLUI_Listbox::GLUI_Listbox( GLUI_Node *parent, + const char *name, int *value_ptr, + int id, + GLUI_CB cb) +{ + common_init(); + set_ptr_val( value_ptr ); + user_id = id; + set_name( name ); + callback = cb; + + parent->add_control( this ); + + init_live(); +} + + +/****************************** GLUI_Listbox::mouse_down_handler() **********/ + +int GLUI_Listbox::mouse_down_handler( int local_x, int local_y ) +{ + return false; +} + + +/****************************** GLUI_Listbox::mouse_up_handler() **********/ + +int GLUI_Listbox::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + + return false; +} + + +/****************************** GLUI_Listbox::mouse_held_down_handler() ******/ + +int GLUI_Listbox::mouse_held_down_handler( int local_x, int local_y, + bool inside) +{ + + return false; +} + + +/****************************** GLUI_Listbox::key_handler() **********/ + +int GLUI_Listbox::key_handler( unsigned char key,int modifiers ) +{ + return false; +} + + +/****************************** GLUI_Listbox::draw() **********/ + +void GLUI_Listbox::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int name_x; + + /* draw_active_area(); */ + + name_x = MAX(text_x_offset - string_width(this->name) - 3,0); + draw_name( name_x , 13); + draw_box_inwards_outline( text_x_offset, w, + 0, h ); + + if ( NOT active ) { + draw_box( text_x_offset+3, w-2, 2, h-2, 1.0, 1.0, 1.0 ); + if ( NOT enabled ) + glColor3b( 32, 32, 32 ); + else + glColor3f( 0.0, 0.0, 0.0 ); + glRasterPos2i( text_x_offset+5, 13 ); + draw_string( curr_text ); + } + else { + draw_box( text_x_offset+3, w-2, 2, h-2, .0, .0, .6 ); + glColor3f( 1.0, 1.0, 1.0 ); + glRasterPos2i( text_x_offset+5, 13 ); + draw_string( curr_text ); + } + + + if ( enabled ) { + glui->std_bitmaps. + draw(GLUI_STDBITMAP_LISTBOX_UP, + w-glui->std_bitmaps.width(GLUI_STDBITMAP_LISTBOX_UP)-1, + 2 ); + } + else { + glui->std_bitmaps. + draw(GLUI_STDBITMAP_LISTBOX_UP_DIS, + w-glui->std_bitmaps.width(GLUI_STDBITMAP_LISTBOX_UP)-1, + 2 ); + } +} + + +/************************************ GLUI_Listbox::update_si() **********/ +void GLUI_Listbox::update_size( void ) +{ + recalculate_item_width(); +} + +/********************************* GLUI_Listbox::set_int_val() **************/ + +void GLUI_Listbox::set_int_val( int new_val ) +{ + /* int_val = new_val; */ + + do_selection( new_val ); + + /*** Update the variable we're (possibly) pointing to, and update the main gfx ***/ + output_live(true); +} + +/**************************************** GLUI_Listbox::add_item() **********/ + +int GLUI_Listbox::add_item( int id, const char *new_text ) +{ + GLUI_Listbox_Item *new_node = new GLUI_Listbox_Item; + GLUI_Listbox_Item *head; + + new_node->text = new_text; + new_node->id = id; + + head = (GLUI_Listbox_Item*) items_list.first_child(); + new_node->link_this_to_parent_last( &items_list ); + + if ( head == NULL ) { + /*** This is first item added ***/ + + int_val = id+1; /** Different than id **/ + do_selection( id ); + last_live_int = id; + + if( glui ) + glui->post_update_main_gfx(); + } + if (recalculate_item_width()) glui->refresh(); + + return true; +} + + +/************************************** GLUI_Listbox::delete_item() **********/ + +int GLUI_Listbox::delete_item( const char *text ) +{ + GLUI_Listbox_Item *node = get_item_ptr(text); + + if (node) + { + node->unlink(); + delete node; + return true; + } + if (recalculate_item_width()) glui->refresh(); + + return false; +} + + +/************************************** GLUI_Listbox::delete_item() **********/ + +int GLUI_Listbox::delete_item(int id) +{ + GLUI_Listbox_Item *node = get_item_ptr(id); + + if (node) + { + node->unlink(); + delete node; + return true; + } + if (recalculate_item_width()) glui->refresh(); + + return false; +} + + +/************************************** GLUI_Listbox::sort_items() **********/ + +int GLUI_Listbox::sort_items( void ) +{ + return false; +} + + +/********************************************* GLUI_Listbox::dump() **********/ + +void GLUI_Listbox::dump( FILE *output ) +{ + GLUI_Listbox_Item *item; + + /* printf( "%p\n", (char*) name ); */ + + fprintf( output, "Listbox: %s\n", name.c_str() ); + + item = (GLUI_Listbox_Item *) items_list.first_child(); + while( item ) { + fprintf( output, " %3d : %s\n", item->id, item->text.c_str() ); + + item = (GLUI_Listbox_Item *) item->next(); + } +} + + +/************************************ GLUI_Listbox::get_item_ptr() **********/ + +GLUI_Listbox_Item *GLUI_Listbox::get_item_ptr( const char *text ) +{ + GLUI_Listbox_Item *item; + + item = (GLUI_Listbox_Item *) items_list.first_child(); + while( item ) { + if ( item->text == text ) + return item; + + item = (GLUI_Listbox_Item *) item->next(); + } + + return NULL; +} + + +/************************************ GLUI_Listbox::get_item_ptr() **********/ + +GLUI_Listbox_Item *GLUI_Listbox::get_item_ptr( int id ) +{ + GLUI_Listbox_Item *item; + + item = (GLUI_Listbox_Item *) items_list.first_child(); + while( item ) { + if ( item->id == id ) + return item; + + item = (GLUI_Listbox_Item *) item->next(); + } + + return NULL; +} + + +/************************************ GLUI_Listbox::mouse_over() **********/ + +static void listbox_callback( int i ) +{ + int old_val; + + if ( NOT GLUI_Master.curr_left_button_glut_menu OR + !dynamic_cast(GLUI_Master.curr_left_button_glut_menu) ) + return; + + old_val = ((GLUI_Listbox*)GLUI_Master.curr_left_button_glut_menu)->int_val; + ((GLUI_Listbox*)GLUI_Master.curr_left_button_glut_menu)->set_int_val(i); + + /**** If value changed, execute callback ****/ + if ( old_val != + ((GLUI_Listbox*)GLUI_Master.curr_left_button_glut_menu)->int_val ) { + ((GLUI_Listbox*)GLUI_Master.curr_left_button_glut_menu)->execute_callback(); + } +} + + +/*************************************** GLUI_Listbox::mouse_over() **********/ + +int GLUI_Listbox::mouse_over( int state, int x, int y ) +{ + GLUI_Listbox_Item *item; + + /* printf( "x/y: %d/%d\n", x, y ); */ + + if ( state AND enabled AND x > x_abs + text_x_offset) { + /**** Build a GLUT menu for this listbox ***/ + + /* printf( "%d %d\n", x, y ); */ + + glut_menu_id = glutCreateMenu(listbox_callback); + + item = (GLUI_Listbox_Item *) items_list.first_child(); + while( item ) { + glutAddMenuEntry( item->text.c_str(), item->id ); + item = (GLUI_Listbox_Item *) item->next(); + } + + glutAttachMenu( GLUT_LEFT_BUTTON); + + GLUI_Master.set_left_button_glut_menu_control( this ); + } + else if ( glut_menu_id != -1 ) { + /* printf( "OUT\n" ); */ + glutDetachMenu( GLUT_LEFT_BUTTON ); + glutDestroyMenu( glut_menu_id ); + glut_menu_id = -1; + } + + return true; +} + + +/************************************ GLUI_Listbox::do_selection() **********/ + +int GLUI_Listbox::do_selection( int item_num ) +{ + GLUI_Listbox_Item *item, *sel_item; + + /*** Is this item already selected? ***/ + if ( item_num == int_val ) + return false; + + sel_item = NULL; + item = (GLUI_Listbox_Item *) items_list.first_child(); + while( item ) { + if ( item->id == item_num ) { + sel_item = item; + break; + } + + item = (GLUI_Listbox_Item *) item->next(); + } + + if ( NOT sel_item ) + return false; + + /* printf( "-> %s\n", (char*) sel_item->text ); */ + + int_val = item_num; + curr_text = sel_item->text; + redraw(); + + return true; +} + + +/*********************************** GLUI_Listbox::~GLUI_Listbox() **********/ + +GLUI_Listbox::~GLUI_Listbox() +{ + GLUI_Listbox_Item *item = (GLUI_Listbox_Item *) items_list.first_child(); + + while (item) + { + GLUI_Listbox_Item *tmp = item; + item = (GLUI_Listbox_Item *) item->next(); + delete tmp; + } +} + +/****************************** GLUI_Listbox::special_handler() **********/ + +int GLUI_Listbox::special_handler( int key,int modifiers ) +{ + GLUI_Listbox_Item *node, *new_node; + + node = get_item_ptr( int_val ); + new_node = NULL; + + if ( key == GLUT_KEY_DOWN ) { + new_node = (GLUI_Listbox_Item*) node->next(); + } + else if ( key == GLUT_KEY_UP ) { + new_node = (GLUI_Listbox_Item*) node->prev(); + } + else if ( key == GLUT_KEY_HOME ) { + new_node = (GLUI_Listbox_Item*) items_list.first_child(); + } + else if ( key == GLUT_KEY_END ) { + new_node = (GLUI_Listbox_Item*) items_list.last_child(); + } + + if ( new_node != NULL AND new_node != node ) { + node = new_node; + set_int_val( node->id ); + execute_callback(); + return true; + } + else { + return false; + } +} + + +/************************* GLUI_Listbox::recalculate_item_width( void ) ***********/ +/** Change w and return true if we need to be widened to fit the current items. */ +bool GLUI_Listbox::recalculate_item_width( void ) +{ + int item_text_size; + + if ( NOT glui ) + return false; + + /* Find the title size */ + text_x_offset = string_width( name ); + + /* Find the longest item string ***/ + item_text_size = 0; + + GLUI_Listbox_Item *item = (GLUI_Listbox_Item *) items_list.first_child(); + while( item ) { + item_text_size = MAX(item_text_size,string_width(item->text)); + item = (GLUI_Listbox_Item *) item->next(); + } + + /* Sum up our layout: name, item, and drop-down marker */ + int new_wid=text_x_offset+MAX(GLUI_EDITTEXT_MIN_TEXT_WIDTH,item_text_size)+20; + if ( w != new_wid) { + w = new_wid; + return true; /* we gotta be shortened or widened */ + } + else { + return false; /* our current width is OK */ + } +} diff --git a/tests/Box2D_v2.2.1/glui/glui_mouse_iaction.cpp b/tests/Box2D_v2.2.1/glui/glui_mouse_iaction.cpp new file mode 100755 index 0000000000000..bc9f0610d3a82 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_mouse_iaction.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_mouse_iaction - GLUI Mouse Interaction control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui_internal_control.h" + +/********************** GLUI_Mouse_Interaction::mouse_down_handler() ******/ + +int GLUI_Mouse_Interaction::mouse_down_handler( int local_x, int local_y ) +{ + /* int win_h = glutGet( GLUT_WINDOW_HEIGHT ); */ + + /* iaction_mouse_down_handler( local_x, local_y ); */ + iaction_mouse_down_handler( local_x-x_abs, local_y-y_abs ); + /*local_x-x_abs, ((glui->h-local_y)-y_abs) ); */ + redraw(); + + return false; +} + + +/**************************** GLUI_Mouse_Interaction::mouse_up_handler() */ + +int GLUI_Mouse_Interaction::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + iaction_mouse_up_handler( local_x-x_abs, local_y-y_abs, inside ); + return false; +} + + +/****************************** GLUI_Mouse_Interaction::mouse_held_down_handler() ******/ + +int GLUI_Mouse_Interaction::mouse_held_down_handler( int local_x, int local_y, + bool inside) +{ + iaction_mouse_held_down_handler( local_x-x_abs, local_y-y_abs , inside ); + + redraw(); + + /** Tell the main graphics window to update iteself **/ + if( glui ) + glui->post_update_main_gfx(); + + execute_callback(); + + return false; +} + + + +/****************************** GLUI_Mouse_Interaction::draw() **********/ + +void GLUI_Mouse_Interaction::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int text_width = string_width( this->name ); + int x_left = this->w/2 - text_width/2; + + if ( NOT draw_active_area_only ) { + draw_name( x_left, h-4 ); + draw_active_box( x_left-4, x_left+string_width( name )+4, + h, h-14 ); + } + + draw_active_area(); +} + + +/************************************ GLUI_Mouse_Interaction::update_size() **********/ + +void GLUI_Mouse_Interaction::update_size( void ) +{ + if ( NOT glui ) + return; + + int text_width = string_width( this->name ); + + if ( w < text_width+6 ) + w = text_width+6; + + if ( h - 18 > w ) + w = h - 18; + + iaction_init(); +} + + +/****************************** GLUI_Mouse_Interaction::special_handler() **********/ + +int GLUI_Mouse_Interaction::special_handler( int key,int modifiers ) +{ + int center_x, center_y; + int drag_x, drag_y; + + center_x = w/2; + center_y = (h-18)/2; + drag_x = 0; + drag_y = 0; + + if ( key == GLUT_KEY_LEFT ) + drag_x = -6; + else if ( key == GLUT_KEY_RIGHT ) + drag_x = 6; + else if ( key == GLUT_KEY_UP ) + drag_y = -6; + else if ( key == GLUT_KEY_DOWN ) + drag_y = 6; + + if ( drag_x != 0 OR drag_y != 0 ) { + mouse_down_handler( center_x, center_y ); + mouse_held_down_handler( center_x + drag_x, center_y + drag_y,true ); + mouse_up_handler( center_x + drag_x, center_y + drag_y, true ); + } + + return false; +} + + +/****************************** GLUI_Mouse_Interaction::draw_active_area() **********/ + +void GLUI_Mouse_Interaction::draw_active_area( void ) +{ + int win_h = glutGet( GLUT_WINDOW_HEIGHT ), win_w = glutGet(GLUT_WINDOW_WIDTH); + + int text_height = 18; /* what a kludge */ + + int viewport_size = h-text_height; /*MIN(w,h); */ + + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + glLoadIdentity(); + glTranslatef( (float) win_w/2.0, (float) win_h/2.0, 0.0 ); + glRotatef( 180.0, 0.0, 1.0, 0.0 ); + glRotatef( 180.0, 0.0, 0.0, 1.0 ); + glTranslatef( (float) -win_w/2.0, (float) -win_h/2.0, 0.0 ); + + glTranslatef( (float) this->x_abs + .5, (float) this->y_abs + .5, 0.0 ); + + glTranslatef( (float)this->w/2.0, (float)viewport_size/2.0 + 2.0 , 0.0 ); + + /*** Draw the interaction control's orthographic elements ***/ + iaction_draw_active_area_ortho(); + + /*** Setup and draw the interaction control's perspective elements ***/ + + /*** Set the viewport to just the square of the drawing area ***/ + /* glViewport( this->x_abs , glui->main_panel->h - this->y_abs - this->h,*/ + /*glViewport( this->x_abs+1+(this->w/2-viewport_size/2), + this->h-this->y_abs-viewport_size-1, + viewport_size, viewport_size );*/ + + viewport_size -= 4; + int offset = 0; + if ( ((this->w-viewport_size) % 2) == 1 ) + offset = 1; + + glViewport( this->x_abs + (this->w-viewport_size)/2 + offset, + win_h - this->y_abs - this->h + text_height, + viewport_size, viewport_size ); + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + double xy=1.00,zc=50.0; /* X-Y size, and Z origin */ + glFrustum( -1.0*xy, 1.0*xy, -xy, xy, zc*0.7, zc*1.3 ); + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + glLoadIdentity(); + glTranslatef( 0.0, 0.0, -zc ); + glScalef(xy,xy,1.0); // xy); + + /* glutSolidTeapot( 1.0 ); */ + iaction_draw_active_area_persp(); + + glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); + + glui->set_viewport(); + glui->set_ortho_projection(); + + glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); +} + diff --git a/tests/Box2D_v2.2.1/glui/glui_node.cpp b/tests/Box2D_v2.2.1/glui/glui_node.cpp new file mode 100755 index 0000000000000..96aa1dd951dd4 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_node.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_node.cpp - linked-list tree structure + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui.h" +#include "glui_internal.h" + +/********************************************* GLUI_Node::GLUI_Node() *******/ + +GLUI_Node::GLUI_Node() +: + parent_node(NULL), + child_head(NULL), + child_tail(NULL), + next_sibling(NULL), + prev_sibling(NULL) +{ +} + +/********************************************* GLUI_Node::first() *******/ +/* Returns first sibling in 'this' node's sibling list */ + +GLUI_Node *GLUI_Node::first_sibling( void ) +{ + if ( parent_node == NULL ) + return this; /* root node has no siblings */ + else + return parent_node->child_head; +} + + +/******************************************** GLUI_Node::next() ********/ +/* Returns next sibling in 'this' node's sibling list */ + +GLUI_Node *GLUI_Node::next( void ) +{ + return next_sibling; +} + + +/******************************************** GLUI_Node::prev() ********/ +/* Returns prev sibling in 'this' node's sibling list */ + +GLUI_Node *GLUI_Node::prev( void ) +{ + return prev_sibling; +} + + +/********************************************* GLUI_Node::last() *******/ +/* Returns last sibling in 'this' node's sibling list */ + +GLUI_Node *GLUI_Node::last_sibling( void ) +{ + if ( parent_node == NULL ) + return this; /* root node has no siblings */ + else + return parent_node->child_tail; +} + + +/*************************** GLUI_Node::link_this_to_parent_last() *******/ +/* Links as last child of parent */ + +void GLUI_Node::link_this_to_parent_last( GLUI_Node *new_parent ) +{ + if ( new_parent->child_tail == NULL ) { /* parent has no children */ + new_parent->child_head = this; + new_parent->child_tail = this; + this->parent_node = new_parent; + } + else { /* parent has children */ + new_parent->child_tail->next_sibling = this; + this->prev_sibling = new_parent->child_tail; + new_parent->child_tail = this; + this->parent_node = new_parent; + } +} + + +/*************************** GLUI_Node::link_this_to_parent_first() *******/ +/* Links as first child of parent */ + +void GLUI_Node::link_this_to_parent_first( GLUI_Node *new_parent ) +{ + if ( new_parent->child_head == NULL ) { /* parent has no children */ + new_parent->child_head = this; + new_parent->child_tail = this; + this->parent_node = new_parent; + } + else { /* parent has children */ + new_parent->child_head->prev_sibling = this; + this->next_sibling = new_parent->child_head; + new_parent->child_head = this; + this->parent_node = new_parent; + } +} + +/**************************** GLUI_Node::link_this_to_sibling_next() *****/ + +void GLUI_Node::link_this_to_sibling_next( GLUI_Node *sibling ) +{ + if ( sibling->next_sibling == NULL ) { /* node has no next sibling */ + sibling->next_sibling = this; + this->prev_sibling = sibling; + + /* This was the parent's last child, so update that as well */ + if ( sibling->parent_node != NULL ) { + sibling->parent_node->child_tail = this; + } + } + else { /* node already has a next sibling */ + sibling->next_sibling->prev_sibling = this; + this->next_sibling = sibling->next_sibling; + sibling->next_sibling = this; + this->prev_sibling = sibling; + } + + this->parent_node = sibling->parent_node; +} + + +/**************************** GLUI_Node::link_this_to_sibling_prev() *****/ + +void GLUI_Node::link_this_to_sibling_prev( GLUI_Node *sibling ) +{ + if ( sibling->prev_sibling == NULL ) { /* node has no prev sibling */ + sibling->prev_sibling = this; + this->next_sibling = sibling; + + /* This was the parent's first child, so update that as well */ + if ( sibling->parent_node != NULL ) { + sibling->parent_node->child_head = this; + } + } + else { /* node already has a prev sibling */ + sibling->prev_sibling->next_sibling = this; + this->prev_sibling = sibling->prev_sibling; + sibling->prev_sibling = this; + this->next_sibling = sibling; + } + + this->parent_node = sibling->parent_node; +} + +/**************************************** GLUI_Node::unlink() **************/ + +void GLUI_Node::unlink( void ) +{ + /* Unlink from prev sibling */ + if ( this->prev_sibling != NULL ) { + this->prev_sibling->next_sibling = this->next_sibling; + } + else { /* No prev sibling: this was parent's first child */ + this->parent_node->child_head = this->next_sibling; + } + + /* Unlink from next sibling */ + if ( this->next_sibling != NULL ) { + this->next_sibling->prev_sibling = this->prev_sibling; + } + else { /* No next sibling: this was parent's last child */ + this->parent_node->child_tail = this->prev_sibling; + } + + this->parent_node = NULL; + this->next_sibling = NULL; + this->prev_sibling = NULL; + this->child_head = NULL; + this->child_tail = NULL; +} + +/**************************************** GLUI_Node::dump() **************/ + +void GLUI_Node::dump( FILE *out, const char *name ) +{ + fprintf( out, "GLUI_node: %s\n", name ); + fprintf( out, " parent: %p child_head: %p child_tail: %p\n", + (void *) parent_node, + (void *) child_head, + (void *) child_tail ); + fprintf( out, " next: %p prev: %p\n", + (void *) next_sibling, + (void *) prev_sibling ); +} diff --git a/tests/Box2D_v2.2.1/glui/glui_panel.cpp b/tests/Box2D_v2.2.1/glui/glui_panel.cpp new file mode 100755 index 0000000000000..687b77971be43 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_panel.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_panel.cpp - GLUI_Panel control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui_internal_control.h" + +GLUI_Panel::GLUI_Panel( GLUI_Node *parent, const char *name, int type ) +{ + common_init(); + set_name( name ); + user_id = -1; + int_val = type; + + parent->add_control( this ); +} + +/****************************** GLUI_Panel::draw() **********/ + +void GLUI_Panel::draw( int x, int y ) +{ + int top; + GLUI_DRAWINGSENTINAL_IDIOM + + if ( int_val == GLUI_PANEL_RAISED ) { + top = 0; + glLineWidth( 1.0 ); + glColor3f( 1.0, 1.0, 1.0 ); + glBegin( GL_LINE_LOOP ); + glVertex2i( 0, top ); glVertex2i( w, top ); + glVertex2i( 0, top ); glVertex2i( 0, h ); + glEnd(); + + glColor3f( .5, .5, .5 ); + glBegin( GL_LINE_LOOP ); + glVertex2i( w, top ); + glVertex2i( w, h ); + glVertex2i( 0, h ); + glVertex2i( w, h ); + glEnd(); + + /** ORIGINAL RAISED PANEL METHOD - A LITTLE TOO HIGH ** + glLineWidth(1.0); + glBegin( GL_LINES ); + glColor3f( 1.0, 1.0, 1.0 ); + glVertex2i( 1, 1 ); glVertex2i( w-2, 1 ); + glVertex2i( 1, 1 ); glVertex2i( 1, h-2 ); + + glColor3f( .5, .5, .5 ); + glVertex2i( w-1, 1 ); glVertex2i( w-1, h-1 ); + glVertex2i( 1, h-1 ); glVertex2i( w-1, h-1 ); + + glColor3f( 0.0, 0.0, 0.0 ); + glVertex2i( 0, h ); glVertex2i( w, h ); + glVertex2i( w, 0 ); glVertex2i( w, h ); + glEnd(); + + -- Touch up the lines a bit (needed in some opengl implementations + glBegin( GL_POINTS ); + glColor3f( .5, .5, .5 ); + glVertex2i( w-1, h-1 ); + glColor3f( 0.0, 0.0, 0.0 ); + glVertex2i( w, h ); + glEnd(); + **/ + } + else if ( int_val == GLUI_PANEL_EMBOSSED ) { + if ( parent_node == NULL || name == "" ) { + top = 0; + } + else { + top = GLUI_PANEL_EMBOSS_TOP; + } + + glLineWidth( 1.0 ); + glColor3f( 1.0, 1.0, 1.0 ); + glBegin( GL_LINE_LOOP ); + glVertex2i( 0, top ); glVertex2i( w, top ); + glVertex2i( w, h ); glVertex2i( 0, h ); + + glVertex2i( 1, top+1 ); glVertex2i( w-1, top+1 ); + glVertex2i( w-1, h-1 ); glVertex2i( 1, h-1 ); + glEnd(); + + glColor3f( .5, .5, .5 ); + glBegin( GL_LINE_LOOP ); + glVertex2i( 0, top ); + glVertex2i( w-1, top ); + glVertex2i( w-1, h-1 ); + glVertex2i( 0, h-1 ); + glEnd(); + + /**** Only display text in embossed panel ****/ + if ( parent_node != NULL && name != "" ) { /* Only draw non-null strings */ + int left = 7, height=GLUI_PANEL_NAME_DROP+1; + int str_width; + + str_width = string_width(name); + + if ( glui ) + glColor3ub(glui->bkgd_color.r,glui->bkgd_color.g,glui->bkgd_color.b); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( left-3, 0 ); glVertex2i( left+str_width+3, 0 ); + glVertex2i( left+str_width+3, height ); glVertex2i( left-3, height ); + glEnd(); + + draw_name( left, GLUI_PANEL_NAME_DROP ); + } + } + + glLineWidth( 1.0 ); +} + +/****************************** GLUI_Panel::set_name() **********/ + +void GLUI_Panel::set_name( const char *new_name ) +{ + name = new_name ? new_name : ""; + + update_size(); + + if ( glui ) + glui->refresh(); +} + + +/****************************** GLUI_Panel::set_type() **********/ + +void GLUI_Panel::set_type( int new_type ) +{ + if ( new_type != int_val ) { + int_val = new_type; + update_size(); + redraw(); + } +} + + +/************************************** GLUI_Panel::update_size() **********/ + +void GLUI_Panel::update_size( void ) +{ + int text_size; + + if ( NOT glui ) + return; + + text_size = string_width(name); + + if ( w < text_size + 16 ) + w = text_size + 16 ; + + if ( name != "" AND int_val == GLUI_PANEL_EMBOSSED ) { + this->y_off_top = GLUI_YOFF + 8; + } + else { + this->y_off_top = GLUI_YOFF; + } +} diff --git a/tests/Box2D_v2.2.1/glui/glui_radio.cpp b/tests/Box2D_v2.2.1/glui/glui_radio.cpp new file mode 100755 index 0000000000000..157d18e84c7c2 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_radio.cpp @@ -0,0 +1,362 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_radio.cpp - GLUI_RadioGroup and GLUI_RadioButton control classes + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui_internal_control.h" +#include + +/****************************** GLUI_RadioGroup::GLUI_RadioGroup() **********/ + +GLUI_RadioGroup::GLUI_RadioGroup(GLUI_Node *parent, + int *value_ptr, + int id, GLUI_CB cb) +{ + common_init(); + GLUI_String buf; + + set_ptr_val( value_ptr ); + if ( value_ptr ) { + int_val = *value_ptr; /** Can't call set_int_val(), b/c that + function will try to call the + callback, etc */ + /** Actually, maybe not **/ + last_live_int = *value_ptr; + } + + user_id = id; + glui_format_str( buf, "RadioGroup: %p", this ); + set_name( buf.c_str() ); + callback = cb; + + parent->add_control( this ); + + init_live(); +} + + +/****************************** GLUI_RadioGroup::draw() **********/ + +void GLUI_RadioGroup::draw( int x, int y ) +{ + if ( NOT can_draw() ) + return; + + draw_group(false); +} + + +/********************* GLUI_RadioGroup::draw_group(int translate) **********/ + +void GLUI_RadioGroup::draw_group( int translate ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + GLUI_RadioButton *button; + this->int_val = int_val; + + glMatrixMode(GL_MODELVIEW ); + + button = (GLUI_RadioButton*) first_child(); + while( button != NULL ) { + glPushMatrix(); + if (translate) { + button->translate_to_origin(); + } + else { + glTranslatef(button->x_abs-x_abs, + button->y_abs-y_abs,0.0); + } + + if ( button->int_val ) + button->draw_checked(); + else + button->draw_unchecked(); + + glPopMatrix(); + + button = (GLUI_RadioButton*) button->next(); + } +} + + +/****************************** GLUI_RadioGroup::set_name() **********/ + +void GLUI_RadioGroup::set_name( const char *text ) +{ + name = text; + + if ( glui ) + glui->refresh(); +} + + +/********************************* GLUI_RadioGroup::set_selected() **********/ + +void GLUI_RadioGroup::set_selected( int int_val ) +{ + GLUI_RadioButton *button; + + this->int_val = int_val; + + button = (GLUI_RadioButton*) first_child(); + while( button != NULL ) { + if ( int_val == -1 ) { /*** All buttons in group are deselected ***/ + button->set_int_val(0); + } + else if ( int_val == button->user_id ) { /*** This is selected button ***/ + button->set_int_val(1); + } + else { /*** This is NOT selected button ***/ + button->set_int_val(0); + + } + button = (GLUI_RadioButton*) button->next(); + } + redraw(); +} + + +/************************ GLUI_RadioButton::GLUI_RadioButton() **********/ + +GLUI_RadioButton::GLUI_RadioButton( GLUI_RadioGroup *grp, const char *name ) +{ + common_init(); + + set_int_val( 0 ); + + /** A radio button's user id is always its ordinal number (zero-indexed) + within the group */ + user_id = grp->num_buttons; + set_name( name ); + group = grp; + + group->num_buttons++; /* Increments radiogroup's button count */ + group->add_control( this ); + + /*** Now update button states ***/ + group->set_int_val( group->int_val ); /* This tells the group to + reset itself to its + current value, thereby + updating all its buttons */ +} + + +/************************ GLUI_RadioButton::mouse_down_handler() **********/ + +int GLUI_RadioButton::mouse_down_handler( int local_x, int local_y ) +{ + if ( NOT group ) + return false; + + orig_value = group->int_val; + + currently_inside = true; + + group->set_selected( this->user_id ); + redraw(); + + return false; +} + +/********************** GLUI_RadioButton::mouse_held_down_handler() ******/ + +int GLUI_RadioButton::mouse_held_down_handler( int local_x, int local_y, + bool inside) +{ + if (inside != currently_inside) { + if (inside) group->set_selected( this->user_id ); + else group->set_selected( orig_value ); + currently_inside = inside; + redraw(); + } + + return false; +} + + +/*************************** GLUI_RadioButton::mouse_up_handler() **********/ + +int GLUI_RadioButton::mouse_up_handler( int local_x, int local_y, + bool inside ) +{ + if ( NOT group ) + return false; + + if ( NOT inside ) { + group->set_selected( orig_value ); + redraw(); + } + else { + /** Now we update the radio button group. We tell the group + handler to set the currently-selected item to this button, which + is reference by its user_id/ordinal number within group **/ + + group->set_selected( this->user_id ); + redraw(); + + /*** Now update the linked variable, and call the callback, + but ONLY if the value of the radio group actually changed ***/ + if ( group->int_val != orig_value ) { + group->output_live(true); /** Output live and update gfx ***/ + + group->execute_callback(); + } + } + + return false; +} + +/****************************** GLUI_RadioButton::draw() **********/ + +void GLUI_RadioButton::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + if ( NOT group OR NOT can_draw() ) + return; + + /*** See if we're the currently-selected button. If so, draw ***/ + if ( group->int_val == this->user_id ) { + if ( enabled ) + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_ON, 0, 0 ); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_ON_DIS, 0, 0 ); + } + else { + if ( enabled ) + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_OFF, 0, 0 ); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_OFF_DIS, 0, 0 ); + } + + draw_active_area(); + + draw_name( text_x_offset, 10 ); +} + + +/************************************ GLUI_RadioButton::draw_checked() ******/ + +void GLUI_RadioButton::draw_checked( void ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + if ( enabled ) + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_ON, 0, 0 ); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_ON_DIS, 0, 0 ); + draw_active_area(); +} + + +/*********************************** GLUI_RadioButton::draw_unchecked() ******/ + +void GLUI_RadioButton::draw_unchecked( void ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + if ( enabled ) + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_OFF, 0, 0 ); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_OFF_DIS, 0, 0 ); + draw_active_area(); +} + + +/**************************************** GLUI_RadioButton::draw_O() ********/ + +void GLUI_RadioButton::draw_O( void ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int i, j; + + glBegin( GL_POINTS ); + for(i=3; i<=GLUI_RADIOBUTTON_SIZE-3; i++ ) + for(j=3; j<=GLUI_RADIOBUTTON_SIZE-3; j++ ) + glVertex2i(i,j); + glEnd(); +} + + +/******************************** GLUI_RadioButton::update_size() **********/ + +void GLUI_RadioButton::update_size( void ) +{ + int text_size; + + if ( NOT glui ) + return; + + text_size = _glutBitmapWidthString( glui->font, name.c_str() ); + + /* if ( w < text_x_offset + text_size + 6 ) */ + w = text_x_offset + text_size + 6 ; +} + + +/************************* GLUI_RadioButton::draw_active_area() **************/ + +void GLUI_RadioButton::draw_active_area( void ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int text_width, left, right; + + text_width = _glutBitmapWidthString( glui->font, name.c_str() ); + left = text_x_offset-3; + right = left + 7 + text_width; + + if ( active ) { + glEnable( GL_LINE_STIPPLE ); + glLineStipple( 1, 0x5555 ); + glColor3f( 0., 0., 0. ); + } else { + glColor3ub( glui->bkgd_color.r, glui->bkgd_color.g, glui->bkgd_color.b ); + } + + glBegin( GL_LINE_LOOP ); + glVertex2i(left,0); glVertex2i( right,0); + glVertex2i(right,h+1); glVertex2i( left,h+1); + glEnd(); + + glDisable( GL_LINE_STIPPLE ); +} + + +/********************************* GLUI_RadioGroup::set_int_val() **********/ + +void GLUI_RadioGroup::set_int_val( int new_val ) +{ + if ( new_val == int_val ) + return; + + set_selected( new_val ); + redraw(); + + output_live(true); + +} diff --git a/tests/Box2D_v2.2.1/glui/glui_rollout.cpp b/tests/Box2D_v2.2.1/glui/glui_rollout.cpp new file mode 100755 index 0000000000000..f0aa7fc4e9582 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_rollout.cpp @@ -0,0 +1,275 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_panel.cpp - GLUI_Panel control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui_internal_control.h" + +enum {rollout_height_pixels=GLUI_DEFAULT_CONTROL_HEIGHT + 7}; + +/****************************** GLUI_Rollout::GLUI_Rollout() **********/ + +GLUI_Rollout::GLUI_Rollout( GLUI_Node *parent, const char *name, + int open, int type ) +{ + common_init(); + set_name( name ); + user_id = -1; + int_val = type; + + if ( NOT open ) { + is_open = false; + h = rollout_height_pixels; + } + + parent->add_control( this ); +} + +/****************************** GLUI_Rollout::open() **********/ + +void GLUI_Rollout::open( void ) +{ + if ( NOT glui ) + return; + + if ( is_open ) + return; + is_open = true; + + GLUI_DRAWINGSENTINAL_IDIOM + + /* Copy hidden children into our private list "collapsed_node" */ + child_head = collapsed_node.child_head; + child_tail = collapsed_node.child_tail; + collapsed_node.child_head = NULL; + collapsed_node.child_tail = NULL; + + if ( child_head != NULL ) { + ((GLUI_Control*) child_head)->unhide_internal( true ); + } + + glui->refresh(); +} + + +/****************************** GLUI_Rollout::close() **********/ + +void GLUI_Rollout::close( void ) +{ + if ( NOT glui ) + return; + + if ( NOT is_open ) + return; + is_open = false; + + GLUI_DRAWINGSENTINAL_IDIOM + + if ( child_head != NULL ) { + ((GLUI_Control*) child_head)->hide_internal( true ); + } + + /* Move all children into a private list of hidden children */ + collapsed_node.child_head = first_child(); + collapsed_node.child_tail = last_child(); + child_head = NULL; + child_tail = NULL; + + this->h = rollout_height_pixels; + + glui->refresh(); +} + + +/**************************** GLUI_Rollout::mouse_down_handler() **********/ + + +int GLUI_Rollout::mouse_down_handler( int local_x, int local_y ) +{ + if ( local_y - y_abs > rollout_height_pixels ) { + initially_inside = currently_inside = false; + return false; + } + + currently_inside = true; + initially_inside = true; + redraw(); + + return false; +} + + +/**************************** GLUI_Rollout::mouse_held_down_handler() ****/ + +int GLUI_Rollout::mouse_held_down_handler( + int local_x, int local_y, + bool new_inside ) +{ + if ( NOT initially_inside ) + return false; + + if ( local_y - y_abs> rollout_height_pixels ) + new_inside = false; + + if (new_inside != currently_inside) { + currently_inside = new_inside; + redraw(); + } + + return false; +} + + +/**************************** GLUI_Rollout::mouse_down_handler() **********/ + +int GLUI_Rollout::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + if ( currently_inside ) { + if ( is_open ) + close(); + else + open(); + } + + currently_inside = false; + initially_inside = false; + redraw(); + + return false; +} + + +/********************************* GLUI_Rollout::draw() ***********/ + +void GLUI_Rollout::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + int left, right, top, bottom; + + left = 5; + right = w-left; + top = 3; + bottom = 3+16; + + if ( is_open ) + draw_emboss_box( 0, w, top+3, h ); + else + draw_emboss_box( 0, w, top+3, h-7 ); + + glui->draw_raised_box( left, top, w-left*2, 16 ); + + if ( glui ) + glColor3ub(glui->bkgd_color.r,glui->bkgd_color.g,glui->bkgd_color.b); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( left+1, top+1 ); glVertex2i( right-1, top+1 ); + glVertex2i( right-1, bottom-1 ); glVertex2i( left+1, bottom-1 ); + glEnd(); + + draw_name( left+8, top+11 ); + + if ( active ) + /*draw_active_box( left+4, left+string_width( name.c_str() )+12, */ + draw_active_box( left+4, right-17, + top+2, bottom-2 ); + + + /** Draw '+' or '-' **/ + + glBegin( GL_LINES ); + if ( is_open ) { + if ( enabled ) glColor3f( 0.0, 0.0, 0.0 ); + else glColor3f( 0.5, 0.5, 0.5 ); + glVertex2i(right-14,(top+bottom)/2); glVertex2i(right-5,(top+bottom)/2); + + glColor3f( 1.0, 1.0, 1.0 ); + glVertex2i(right-14,1+(top+bottom)/2);glVertex2i(right-5,1+(top+bottom)/2); + } + else + { + glColor3f( 1.0, 1.0, 1.0 ); + glVertex2i(right-9,top+3); glVertex2i(right-9,bottom-4); + glVertex2i(right-14,(top+bottom)/2); glVertex2i(right-5,(top+bottom)/2); + + if ( enabled ) glColor3f( 0.0, 0.0, 0.0 ); + else glColor3f( 0.5, 0.5, 0.5 ); + glVertex2i(right-14,-1+(top+bottom)/2); + glVertex2i(right-5,-1+(top+bottom)/2); + glVertex2i(right-10,top+3); + glVertex2i(right-10,bottom-4); + } + glEnd(); + + glLineWidth( 1.0 ); + + if (currently_inside) {draw_pressed(); /* heavy black outline when pressed */ } +} + + +/***************************** GLUI_Rollout::update_size() **********/ + +void GLUI_Rollout::update_size( void ) +{ + int text_size; + + if ( NOT glui ) + return; + + text_size = string_width(name); + + if ( w < text_size + 36 ) + w = text_size + 36; +} + + +/**************************** GLUI_Rollout::draw_pressed() ***********/ + +void GLUI_Rollout::draw_pressed( void ) +{ + int left, right, top, bottom; + + left = 5; + right = w-left; + top = 3; + bottom = 3+16; + + + glColor3f( 0.0, 0.0, 0.0 ); + + glBegin( GL_LINE_LOOP ); + glVertex2i( left, top ); glVertex2i( right, top ); + glVertex2i( right, bottom ); glVertex2i( left,bottom ); + glEnd(); + + glBegin( GL_LINE_LOOP ); + glVertex2i( left+1, top+1 ); glVertex2i( right-1, top+1 ); + glVertex2i( right-1, bottom-1 ); glVertex2i( left+1,bottom-1 ); + glEnd(); +} diff --git a/tests/Box2D_v2.2.1/glui/glui_rotation.cpp b/tests/Box2D_v2.2.1/glui/glui_rotation.cpp new file mode 100755 index 0000000000000..e3e84bed76e17 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_rotation.cpp @@ -0,0 +1,473 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_rotation - GLUI_Rotation control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui.h" +#include "arcball.h" +#include "algebra3.h" + +/*************************** GLUI_Rotation::iaction_mouse_down_handler() ***/ + +int GLUI_Rotation::iaction_mouse_down_handler( int local_x, int local_y ) +{ + copy_float_array_to_ball(); + + init_ball(); + + local_y = (int) floor(2.0 * ball->center[1] - local_y); + + ball->mouse_down( local_x, local_y ); + + /* printf( "%d %d - %f %f\n", local_x, local_y, ball->center[0], ball->center[1] ); */ + + copy_ball_to_float_array(); + + spinning = false; + + return false; +} + + +/*********************** GLUI_Rotation::iaction_mouse_up_handler() **********/ + +int GLUI_Rotation::iaction_mouse_up_handler( int local_x, int local_y, + bool inside ) +{ + copy_float_array_to_ball(); + + ball->mouse_up(); + + return false; +} + + +/******************* GLUI_Rotation::iaction_mouse_held_down_handler() ******/ + +int GLUI_Rotation::iaction_mouse_held_down_handler( int local_x, int local_y, + bool inside) +{ + if ( NOT glui ) + return 0; + + copy_float_array_to_ball(); + + local_y = (int) floor(2.0 * ball->center[1] - local_y); + + /* printf( "%d %d\n", local_x, local_y ); */ + + ball->mouse_motion( local_x, local_y, 0, + (glui->curr_modifiers & GLUT_ACTIVE_ALT) != 0, + (glui->curr_modifiers & GLUT_ACTIVE_CTRL) != 0 ); + + copy_ball_to_float_array(); + + if ( can_spin ) + spinning = true; + + return false; +} + + +/******************** GLUI_Rotation::iaction_draw_active_area_persp() **************/ + +void GLUI_Rotation::iaction_draw_active_area_persp( void ) +{ + /********** arcball *******/ + copy_float_array_to_ball(); + + setup_texture(); + setup_lights(); + + glEnable(GL_CULL_FACE ); + + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + + mat4 tmp_rot = *ball->rot_ptr; + glMultMatrixf( (float*) &tmp_rot[0][0] ); + + /*** Draw the checkered box ***/ + /*glDisable( GL_TEXTURE_2D ); */ + draw_ball(1.35); // 1.96 ); + + glPopMatrix(); + + glBindTexture(GL_TEXTURE_2D,0); /* unhook our checkerboard texture */ + glDisable( GL_TEXTURE_2D ); + glDisable( GL_LIGHTING ); + glDisable( GL_CULL_FACE ); +} + + +/******************** GLUI_Rotation::iaction_draw_active_area_ortho() **********/ + +void GLUI_Rotation::iaction_draw_active_area_ortho( void ) +{ + float radius; + radius = (float)(h-22)/2.0; /*MIN((float)w/2.0, (float)h/2.0); */ + + /********* Draw emboss circles around arcball control *********/ + int k; + glLineWidth( 1.0 ); + glBegin( GL_LINE_LOOP); + for( k=0; k<60; k++ ) { + float phi = 2*M_PI*(float)k/60.0; + vec2 p( cos(phi) * (2.0 + radius), sin(phi) * (2.0 + radius)); + if ( p[1] < -p[0] ) glColor3ub( 128,128,128 ); + else glColor3ub( 255,255,255 ); + glVertex2fv((float*)&p[0]); + } + glEnd(); + + glBegin( GL_LINE_LOOP); + for( k=0; k<60; k++ ) { + float phi = 2*M_PI*(float)k/60.0; + vec2 p( cos(phi) * (1.0 + radius), sin(phi) * (1.0 + radius)); + if ( enabled ) { + if ( p[1] < -p[0] ) glColor3ub( 0,0,0); + else glColor3ub( 192,192,192); + } + else + { + if ( p[1] < -p[0] ) glColor3ub( 180,180,180); + else glColor3ub( 192,192,192); + } + glVertex2fv((float*)&p[0]); + } + glEnd(); +} + + +/******************************** GLUI_Rotation::iaction_dump() **********/ + +void GLUI_Rotation::iaction_dump( FILE *output ) +{ +} + + +/******************** GLUI_Rotation::iaction_special_handler() **********/ + +int GLUI_Rotation::iaction_special_handler( int key,int modifiers ) +{ + + return false; +} + +/********************************** GLUI_Rotation::init_ball() **********/ + +void GLUI_Rotation::init_ball( void ) +{ + /*printf( "%f %f %f", float( MIN(w/2,h/2)), (float) w/2, (float) h/2 ); */ + + ball->set_params( vec2( (float)(w/2), (float)((h-18)/2)), + (float) 2.0*(h-18) ); + /*ball->set_damping( .05 ); */ + /*float( MIN(w/2,h/2))*2.0 ); */ + /* ball->reset_mouse(); */ +} + + +/****************************** GLUI_Rotation::setup_texture() *********/ + +void GLUI_Rotation::setup_texture( void ) +{ + static GLuint tex=0u; + GLenum t=GL_TEXTURE_2D; + glEnable(t); + glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + glColor3f( 1.0, 1.0, 1.0 ); + if (tex!=0u) { + /* (OSL 2006/06) Just use glBindTexture to avoid having to re-upload the whole checkerboard every frame. */ + glBindTexture(t,tex); + return; + } /* Else need to make a new checkerboard texture */ + glGenTextures(1,&tex); + glBindTexture(t,tex); + glEnable(t); + + unsigned int i, j; + int dark, light; /*** Dark and light colors for ball checkerboard ***/ + +/* Note: you can change the number of checkers across there sphere in draw_ball */ +#define CHECKBOARD_SIZE 64 /* pixels across whole texture */ +#define CHECKBOARD_REPEAT 32u /* pixels across one black/white sector */ + unsigned char texture_image[CHECKBOARD_SIZE] [CHECKBOARD_SIZE] [3]; + unsigned char c; + for( i=0; iinit(); /** reset quaternion, etc. **/ + ball->set_params( vec2( (float)(w/2), (float)((h-18)/2)), + (float) 2.0*(h-18) ); + + set_spin( this->damping ); + + copy_ball_to_float_array(); + + translate_and_draw_front(); + + output_live(true); /*** Output live and draw main grx window ***/ +} + + +/****************************** GLUI_Rotation::needs_idle() *********/ + +bool GLUI_Rotation::needs_idle( void ) const +{ + return can_spin; +} + + +/****************************** GLUI_Rotation::idle() ***************/ + +void GLUI_Rotation::idle( void ) +{ + spinning = ball->is_spinning?true:false; + + if ( can_spin AND spinning ) { + copy_float_array_to_ball(); + ball->idle(); + + *ball->rot_ptr = *ball->rot_ptr * ball->rot_increment; + + mat4 tmp_rot; + tmp_rot = *ball->rot_ptr; + + copy_ball_to_float_array(); + + draw_active_area_only = true; + translate_and_draw_front(); + draw_active_area_only = false; + + output_live(true); /** output live and update gfx **/ + } + else { + } +} + + +/********************** GLUI_Rotation::copy_float_array_to_ball() *********/ + +void GLUI_Rotation::copy_float_array_to_ball( void ) +{ + int i; + float *fp_src, *fp_dst; + + fp_src = &float_array_val[0]; + fp_dst = &((*ball->rot_ptr)[0][0]); + + for( i=0; i<16; i++ ) { + *fp_dst = *fp_src; + + fp_src++; + fp_dst++; + } +} + + +/********************** GLUI_Rotation::copy_ball_to_float_array() *********/ + +void GLUI_Rotation::copy_ball_to_float_array( void ) +{ + mat4 tmp_rot; + tmp_rot = *ball->rot_ptr; + + set_float_array_val( (float*) &tmp_rot[0][0] ); +} + + +/************************ GLUI_Rotation::set_spin() **********************/ + +void GLUI_Rotation::set_spin( float damp_factor ) +{ + if ( damp_factor == 0.0 ) + can_spin = false; + else + can_spin = true; + + ball->set_damping( 1.0 - damp_factor ); + + this->damping = damp_factor; +} + + +/************** GLUI_Rotation::GLUI_Rotation() ********************/ + +GLUI_Rotation::GLUI_Rotation( GLUI_Node *parent, + const char *name, float *value_ptr, + int id, + GLUI_CB cb ) +{ + common_init(); + set_ptr_val( value_ptr ); + user_id = id; + set_name( name ); + callback = cb; + parent->add_control( this ); + init_live(); + + /*** Init the live 4x4 matrix. This is different than the standard + live variable behavior, since the original value of the 4x4 matrix + is ignored and reset to Identity ***/ +/* +NO! WVB + if ( value_ptr != NULL ) { + int i, j, index; + for( i=0; i<4; i++ ) { + for( j=0; j<4; j++ ) { + index = i*4+j; + if ( i==j ) + value_ptr[index] = 1.0; + else + value_ptr[index] = 0.0; + } + } + } +*/ + /*init_ball(); */ + + +} + + +/************** GLUI_Rotation::common_init() ********************/ + +void GLUI_Rotation::common_init( void ) +{ + glui_format_str( name, "Rotation: %p", this ); +// type = GLUI_CONTROL_ROTATION; + w = GLUI_ROTATION_WIDTH; + h = GLUI_ROTATION_HEIGHT; + can_activate = true; + live_type = GLUI_LIVE_FLOAT_ARRAY; + float_array_size = 16; + quadObj = NULL; + alignment = GLUI_ALIGN_CENTER; + can_spin = false; + spinning = false; + damping = 0.0; + ball = new Arcball; + + reset(); +} diff --git a/tests/Box2D_v2.2.1/glui/glui_scrollbar.cpp b/tests/Box2D_v2.2.1/glui/glui_scrollbar.cpp new file mode 100755 index 0000000000000..9540d40792400 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_scrollbar.cpp @@ -0,0 +1,832 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_scrollbar.cpp - GLUI_Scrollbar class + + -------------------------------------------------- + + Copyright (c) 2004 John Kew, 1998 Paul Rademacher + + This program is freely distributable without licensing fees and is + provided without guarantee or warrantee expressed or implied. This + program is -not- in the public domain. + +*****************************************************************************/ + +#include "glui_internal_control.h" +#include +#include + +/*static int __debug=0; */ + +#define GLUI_SCROLL_GROWTH_STEPS 800 +#define GLUI_SCROLL_MIN_GROWTH_STEPS 100 +#define GLUI_SCROLL_CALLBACK_INTERVAL 1 /* Execute the user's callback every this many clicks */ + +enum { + GLUI_SCROLL_ARROW_UP, + GLUI_SCROLL_ARROW_DOWN, + GLUI_SCROLL_ARROW_LEFT, + GLUI_SCROLL_ARROW_RIGHT +}; + + +/****************************** GLUI_Scrollbar::GLUI_Scrollbar() **********/ +// Constructor, no live var +GLUI_Scrollbar::GLUI_Scrollbar( GLUI_Node *parent, + const char *name, + int horz_vert, + int data_type, + int id, GLUI_CB callback + /*,GLUI_Control *object + ,GLUI_InterObject_CB obj_cb*/ + ) +{ + common_construct(parent, name, horz_vert, data_type, NULL, id, callback/*, object, obj_cb*/); +} + +/****************************** GLUI_Scrollbar::GLUI_Scrollbar() **********/ +// Constructor, int live var +GLUI_Scrollbar::GLUI_Scrollbar( GLUI_Node *parent, const char *name, + int horz_vert, + int *live_var, + int id, GLUI_CB callback + /*,GLUI_Control *object + ,GLUI_InterObject_CB obj_cb*/ + ) +{ + common_construct(parent, name, horz_vert, GLUI_SCROLL_INT, live_var, id, callback/*, object, obj_cb*/); +} + +/****************************** GLUI_Scrollbar::GLUI_Scrollbar() **********/ +// Constructor, float live var +GLUI_Scrollbar::GLUI_Scrollbar( GLUI_Node *parent, const char *name, + int horz_vert, + float *live_var, + int id, GLUI_CB callback + /*,GLUI_Control *object + ,GLUI_InterObject_CB obj_cb*/ + ) +{ + common_construct(parent, name, horz_vert, GLUI_SCROLL_FLOAT, live_var, id, callback/*, object, obj_cb*/); +} + +/****************************** GLUI_Scrollbar::common_init() **********/ +void GLUI_Scrollbar::common_init(void) +{ + horizontal = true; + h = GLUI_SCROLL_ARROW_HEIGHT; + w = GLUI_TEXTBOX_WIDTH; + alignment = GLUI_ALIGN_CENTER; + x_off = 0; + y_off_top = 0; + y_off_bot = 0; + can_activate = true; + state = GLUI_SCROLL_STATE_NONE; + growth_exp = GLUI_SCROLL_DEFAULT_GROWTH_EXP; + callback_count = 0; + first_callback = true; + user_speed = 1.0; + float_min = 0.0; + float_max = 0.0; + int_min = 0; + int_max = 0; + associated_object = NULL; + last_update_time=0; + velocity_limit=50.0; /* Change value by at most 50 per second */ + box_length = 0; + box_start_position = 0; + box_end_position = 0; + track_length = 0; +} + +/****************************** GLUI_Scrollbar::common_construct() **********/ +void GLUI_Scrollbar::common_construct( + GLUI_Node *parent, + const char *name, + int horz_vert, + int data_type, + void *data, + int id, GLUI_CB callback + /*,GLUI_Control *object, + GLUI_InterObject_CB obj_cb*/ + ) +{ + common_init(); + + // make sure limits are wide enough to hold live value + if (data_type==GLUI_SCROLL_FLOAT) { + float lo = 0.0f, hi=1.0f; + if (data) { + float d = *(float*)(data); + lo = MIN(lo, d); + hi = MAX(hi, d); + } + this->set_float_limits(lo,hi); + this->set_float_val(lo); + this->live_type = GLUI_LIVE_FLOAT; + } else { + int lo = 0, hi=100; + if (data) { + int d = *(int*)(data); + lo = MIN(lo, d); + hi = MAX(hi, d); + } + this->set_int_limits(lo,hi); + this->set_int_val(0); + this->live_type = GLUI_LIVE_INT; + } + this->data_type = data_type; + this->set_ptr_val( data ); + this->set_name(name); + this->user_id = id; + this->callback = callback; + //this->associated_object = object; + //this->object_cb = obj_cb; + this->horizontal=(horz_vert==GLUI_SCROLL_HORIZONTAL); + if (this->horizontal) { + this->h = GLUI_SCROLL_ARROW_HEIGHT; + this->w = GLUI_TEXTBOX_WIDTH; + } else { + this->h = GLUI_TEXTBOX_HEIGHT; + this->w = GLUI_SCROLL_ARROW_WIDTH; + } + parent->add_control( this ); + this->init_live(); +} + +/****************************** GLUI_Scrollbar::mouse_down_handler() **********/ + +int GLUI_Scrollbar::mouse_down_handler( int local_x, int local_y ) +{ + last_update_time=GLUI_Time()-1.0; + this->state = find_arrow( local_x, local_y ); + GLUI_Master.glui_setIdleFuncIfNecessary(); + + /* printf( "spinner: mouse down : %d/%d arrow:%d\n", local_x, local_y, + find_arrow( local_x, local_y )); + */ + + if ( state != GLUI_SCROLL_STATE_UP AND state != GLUI_SCROLL_STATE_DOWN) + return true; + + reset_growth(); + + /*** ints and floats behave a bit differently. When you click on + an int spinner, you expect the value to immediately go up by 1, whereas + for a float it'll go up only by a fractional amount. Therefore, we + go ahead and increment by one for int spinners ***/ +#if 1 + if ( data_type == GLUI_SCROLL_INT ) { + // Allow for possibility of reversed limits + int lo = MIN(int_min,int_max); + int hi = MAX(int_min,int_max); + int increase = int_min < int_max ? 1 : -1; + int new_val = int_val; + if ( state == GLUI_SCROLL_STATE_UP ) { + new_val += increase; + } else if ( state == GLUI_SCROLL_STATE_DOWN ) { + new_val -= increase; + } + if (new_val >= lo && new_val <= hi && new_val!=int_val) { + set_int_val(new_val); + do_callbacks(); + } + } +#endif + do_click(); + redraw(); + + return false; +} + + +/******************************** GLUI_Scrollbar::mouse_up_handler() **********/ + +int GLUI_Scrollbar::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + state = GLUI_SCROLL_STATE_NONE; + GLUI_Master.glui_setIdleFuncIfNecessary(); + + /* printf("spinner: mouse up : %d/%d inside: %d\n",local_x,local_y,inside); */ + + /*glutSetCursor( GLUT_CURSOR_INHERIT ); */ + glutSetCursor( GLUT_CURSOR_LEFT_ARROW ); + + redraw(); + + /* do_callbacks(); --- stub */ + /* if ( callback ) */ + /* callback( this->user_id ); */ + + return false; +} + + +/***************************** GLUI_Scrollbar::mouse_held_down_handler() ******/ + +int GLUI_Scrollbar::mouse_held_down_handler( int local_x, int local_y, + bool new_inside) +{ + int new_state; + if ( state == GLUI_SCROLL_STATE_NONE ) + return false; + + /* printf("spinner: mouse held: %d/%d inside: %d\n",local_x,local_y, + new_inside); + */ + + if ( state == GLUI_SCROLL_STATE_SCROLL) { /* dragging? */ + do_drag( local_x-x_abs, local_y-y_abs ); + } + else { /* not dragging */ + new_state = find_arrow( local_x, local_y ); + + if ( new_state == state ) { + /** Still in same arrow **/ + do_click(); + } + } + redraw(); + + return false; +} + + +/****************************** GLUI_Scrollbar::key_handler() **********/ + +int GLUI_Scrollbar::key_handler( unsigned char key,int modifiers ) +{ + return true; +} + + +/****************************** GLUI_Scrollbar::draw() **********/ + +void GLUI_Scrollbar::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + if ( horizontal ) { + draw_scroll_arrow(GLUI_SCROLL_ARROW_LEFT, 0, 0); + draw_scroll_arrow(GLUI_SCROLL_ARROW_RIGHT, w-GLUI_SCROLL_ARROW_WIDTH, 0); + } else { + draw_scroll_arrow(GLUI_SCROLL_ARROW_UP, 0, 0); + draw_scroll_arrow(GLUI_SCROLL_ARROW_DOWN, 0, h-GLUI_SCROLL_ARROW_HEIGHT); + } + draw_scroll(); +} + + +/****************************** GLUI_Scrollbar::draw_scroll_arrow() **********/ + +void GLUI_Scrollbar::draw_scroll_arrow(int arrowtype, int x, int y) +{ + float offset=0; + float L=3.5f,HC=7.f,R=10.5f; + float T=4.5f,VC=8.f,B=11.5; + const float verts[][6]={ + { L,10.5f, R, 10.5f, HC, 6.5f }, // up arrow + { L,6.5f, R, 6.5f, HC,10.5f }, // down arrow + { R-2,T, R-2, B, L+1, VC }, // left arrow + { L+2,T, L+2, B, R-1, VC } // right arrow + }; + + const float *tri = NULL; + + switch (arrowtype) + { + case GLUI_SCROLL_ARROW_UP: + tri = verts[0]; + if (state & GLUI_SCROLL_STATE_UP) offset = 1; + break; + + case GLUI_SCROLL_ARROW_DOWN: + tri = verts[1]; + if (state & GLUI_SCROLL_STATE_DOWN) offset = 1; + break; + + case GLUI_SCROLL_ARROW_LEFT: + tri = verts[2]; + if (state & GLUI_SCROLL_STATE_DOWN) offset = 1; + break; + + case GLUI_SCROLL_ARROW_RIGHT: + tri = verts[3]; + if (state & GLUI_SCROLL_STATE_UP) offset = 1; + break; + + default: + return; /* tri is NULL */ + } + + glColor3ubv(&glui->bkgd_color.r); + glRecti(x,y,x+GLUI_SCROLL_ARROW_WIDTH,y+GLUI_SCROLL_ARROW_HEIGHT); + if (!offset) { + glui->draw_raised_box(x,y+1,GLUI_SCROLL_ARROW_WIDTH-1,GLUI_SCROLL_ARROW_HEIGHT-1); + } else { + glColor3ub(128,128,128); + glBegin(GL_LINE_LOOP); + int x2=x+GLUI_SCROLL_ARROW_WIDTH, y2=y+GLUI_SCROLL_ARROW_HEIGHT; + glVertex2i(x ,y); + glVertex2i(x2,y); + glVertex2i(x2,y2); + glVertex2i(x ,y2); + glEnd(); + } + + GLubyte black[]={0,0,0}; + GLubyte white[]={255,255,255}; + GLubyte gray[]={128,128,128}; + GLubyte *color=black; + if (!enabled) { + offset = 1; + color = white; + } + glTranslatef(x+offset,y+offset,0); + glColor3ubv(color); + glBegin(GL_TRIANGLES); + glVertex2fv(tri); glVertex2fv(tri+2), glVertex2fv(tri+4); + glEnd(); + glTranslatef(-(x+offset),-(y+offset),0); + + if (!enabled) { // once more! + glTranslatef(x,y,0); + glColor3ubv(gray); + glBegin(GL_TRIANGLES); + glVertex2fv(tri); glVertex2fv(tri+2), glVertex2fv(tri+4); + glEnd(); + glTranslatef(-x,-y,0); + } +} + + +void GLUI_Scrollbar::draw_scroll() { + update_scroll_parameters(); + + // Draw track using a checkerboard background + const unsigned char scroll_bg[] = { + 0xD4, 0xD0, 0xC8, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xD4, 0xD0, 0xC8 + }; + glColor3f( 1.0, 1.0, 1.0 ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glEnable( GL_TEXTURE_2D); + glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, + scroll_bg); + + float y0 = horizontal? 0 : GLUI_SCROLL_ARROW_HEIGHT; + float y1 = horizontal? h : h-GLUI_SCROLL_ARROW_HEIGHT; + float x0 = horizontal? GLUI_SCROLL_ARROW_WIDTH : 0; + float x1 = horizontal? w-GLUI_SCROLL_ARROW_WIDTH : w; + x0-=0.5; y0+=0.5; + x1-=0.5; y1+=0.5; + float dy = y1-y0; + float dx = x1-x0; + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(x0,y0); + glTexCoord2f(dx*0.5f,0); glVertex2f(x1,y0); + glTexCoord2f(dx*0.5f,dy*0.5f); glVertex2f(x1,y1); + glTexCoord2f(0, dy*0.5f); glVertex2f(x0,y1); + glEnd(); + glDisable(GL_TEXTURE_2D); + + // Draw scroll box + int box = box_start_position; + if (horizontal) { + box += GLUI_SCROLL_ARROW_WIDTH; + draw_scroll_box(box,1,box_length,h); + } else { + box += GLUI_SCROLL_ARROW_HEIGHT+1; + draw_scroll_box(0,box,w,box_length); + } +} + +/****************************** GLUI_Scrollbar::draw_scroll_box() **********/ + +void GLUI_Scrollbar::draw_scroll_box(int x, int y, int w, int h) +{ + if (!enabled) return; + glColor3ubv(&glui->bkgd_color.r); + glRecti(x,y,x+w,y+h); + glui->draw_raised_box(x,y, w-1, h-1); + + if (active) { + glEnable( GL_LINE_STIPPLE ); + glLineStipple( 1, 0x5555 ); + glColor3f( 0., 0., 0. ); + glBegin(GL_LINE_LOOP); + int x1 = x+2, y1 = y+2, x2 = x+w-4, y2 = y+h-4; + glVertex2i(x1,y1); + glVertex2i(x2,y1); + glVertex2i(x2,y2); + glVertex2i(x1,y2); + glEnd(); + glDisable( GL_LINE_STIPPLE ); + } +} + + + +/**************************** update_scroll_parameters ***********/ + +void GLUI_Scrollbar::update_scroll_parameters() { + track_length = horizontal? + this->w-GLUI_SCROLL_ARROW_WIDTH*2 : + this->h-GLUI_SCROLL_ARROW_HEIGHT*2; + if (data_type==GLUI_SCROLL_INT) + { + if (int_max==int_min) + box_length=track_length; + else { + const int MIN_TAB = GLUI_SCROLL_BOX_STD_HEIGHT; + //box_length = int(track_length/float(visible_range)); + //if (box_length < MIN_TAB) + box_length = MIN_TAB; + } + float pixels_per_unit = (track_length-box_length)/float(int_max-int_min); + if (horizontal) + box_start_position = int((int_val-int_min)*pixels_per_unit); + else + box_start_position = int((int_max-int_val)*pixels_per_unit); + box_end_position = box_start_position+box_length; + } + else if (data_type==GLUI_SCROLL_FLOAT) + { + if (float_max==float_min) + box_length=track_length; + else { + box_length = GLUI_SCROLL_BOX_STD_HEIGHT; + } + float pixels_per_unit = (track_length-box_length)/float(float_max-float_min); + if (horizontal) + box_start_position = int((float_val-float_min)*pixels_per_unit); + else + box_start_position = int((float_max-float_val)*pixels_per_unit); + box_end_position = box_start_position+box_length; + } +} + + +/********************************* GLUI_Scrollbar::special_handler() **********/ + +int GLUI_Scrollbar::special_handler( int key,int modifiers ) +{ + if ( !horizontal && key == GLUT_KEY_UP ) { + mouse_down_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1, + y_abs + 1 ); + mouse_up_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1, + y_abs + 1, true ); + } + else if ( !horizontal && key == GLUT_KEY_DOWN ) { + mouse_down_handler(x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1, + y_abs+1+GLUI_SCROLL_ARROW_HEIGHT); + mouse_up_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1, + y_abs+1 +GLUI_SCROLL_ARROW_HEIGHT, + true ); + } + if ( horizontal && key == GLUT_KEY_LEFT ) { + mouse_down_handler( x_abs + 1,y_abs + 1 ); + mouse_up_handler( x_abs + 1, y_abs + 1, true ); + } + else if ( horizontal && key == GLUT_KEY_RIGHT ) { + mouse_down_handler(x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1, + y_abs+1); + mouse_up_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1, + y_abs+1, + true ); + } + else if ( key == GLUT_KEY_HOME ) { /** Set value to limit top - + or increment by 10 **/ + } + else if ( key == GLUT_KEY_END ) { + } + + return true; +} + + +/************************************ GLUI_Scrollbar::update_size() **********/ + +void GLUI_Scrollbar::update_size( void ) +{ + if (horizontal) { + h = GLUI_SCROLL_ARROW_HEIGHT; + if (associated_object) { + this->w = ((GLUI_Control *)associated_object)->w; + } + } + else { + w = GLUI_SCROLL_ARROW_WIDTH; + if (associated_object) { + this->h = ((GLUI_Control *)associated_object)->h; + } + } +} + + +/************************************ GLUI_Scrollbar::find_arrow() ************/ + +int GLUI_Scrollbar::find_arrow( int local_x, int local_y ) +{ + + local_x = local_x-x_abs; + local_y = local_y-y_abs; + + if (horizontal) + { + if ( local_y >= h-GLUI_SCROLL_ARROW_HEIGHT-3 && local_y <= h) + { + update_scroll_parameters(); + if ( local_x >= 0 AND local_x <= (GLUI_SCROLL_ARROW_WIDTH+box_start_position) ) + { + return GLUI_SCROLL_STATE_DOWN; + } + if ( local_x >= (GLUI_SCROLL_ARROW_WIDTH+box_end_position) + AND local_x <= (w+GLUI_SCROLL_ARROW_WIDTH) ) + { + return GLUI_SCROLL_STATE_UP; + } + return GLUI_SCROLL_STATE_SCROLL; + } + } + else + { + if ( local_x >= w-GLUI_SCROLL_ARROW_WIDTH-3 && local_x <= w) + { + update_scroll_parameters(); + if ( local_y >= 0 AND local_y <= (GLUI_SCROLL_ARROW_HEIGHT+box_start_position) ) + { + return GLUI_SCROLL_STATE_UP; + } + if ( local_y >= (GLUI_SCROLL_ARROW_HEIGHT+box_end_position) + AND local_y <= (h+GLUI_SCROLL_ARROW_HEIGHT) ) + { + return GLUI_SCROLL_STATE_DOWN; + } + return GLUI_SCROLL_STATE_SCROLL; + } + } + + return GLUI_SCROLL_STATE_NONE; +} + +/***************************************** GLUI_Scrollbar::do_click() **********/ + +void GLUI_Scrollbar::do_click( void ) +{ + int direction = 0; + + if ( state == GLUI_SCROLL_STATE_UP ) + direction = +1; + else if ( state == GLUI_SCROLL_STATE_DOWN ) + direction = -1; + + if (data_type==GLUI_SCROLL_INT&&int_min>int_max) direction*=-1; + if (data_type==GLUI_SCROLL_FLOAT&&float_min>float_max) direction*=-1; + + increase_growth(); + + float modifier_factor = 1.0; + float incr = growth * modifier_factor * user_speed ; + + double frame_time=GLUI_Time()-last_update_time; + double frame_limit=velocity_limit*frame_time; + if (incr>frame_limit) incr=frame_limit; /* don't scroll faster than limit */ + last_update_time=GLUI_Time(); + + float new_val = float_val; + + new_val += direction * incr; + if (1 || data_type==GLUI_SCROLL_FLOAT) set_float_val(new_val); + if (0 && data_type==GLUI_SCROLL_INT) set_int_val((int)new_val); + //printf("do_click: incr %f val=%f float_val=%f\n",incr,new_val,float_val); + + /*** Now update live variable and do callback. We don't want + to do the callback on each iteration of this function, just on every + i^th iteration, where i is given by GLUI_SCROLL_CALLBACK_INTERVAL ****/ + callback_count++; + if ( (callback_count % GLUI_SCROLL_CALLBACK_INTERVAL ) == 0 ) + do_callbacks(); + +} + + +/***************************************** GLUI_Scrollbar::do_drag() **********/ + +void GLUI_Scrollbar::do_drag( int x, int y ) +{ + int direction = 0; + float incr, modifier_factor; + /* int delta_x; */ + int new_int_val = int_val; + float new_float_val = float_val; + + int free_len = track_length-box_length; + if (free_len == 0) return; + + modifier_factor = 1.0; + if ( state == GLUI_SCROLL_STATE_SCROLL) { + update_scroll_parameters(); + + int hbox = box_length/2; + if (horizontal) { + int track_v = x-GLUI_SCROLL_ARROW_WIDTH; + new_int_val = int_min + (track_v-hbox)*(int_max-int_min)/free_len; + new_float_val = float_min + (track_v-hbox)*(float_max-float_min)/float(free_len); + } else { + int track_v = y-GLUI_SCROLL_ARROW_HEIGHT; + new_int_val = int_max - (track_v-hbox)*(int_max-int_min)/free_len; + new_float_val = float_max - (track_v-hbox)*(float_max-float_min)/float(free_len); + } + } + else { + if ( state == GLUI_SCROLL_STATE_UP ) + direction = +1; + else if ( state == GLUI_SCROLL_STATE_DOWN ) + direction = -1; + incr = growth * direction * modifier_factor * user_speed; + new_int_val += direction; + new_float_val += direction * (float_max-float_min)/free_len; + } + last_y = y; + last_x = x; + + /*** Now update live variable and do callback. We don't want + to do the callback on each iteration of this function, just on every + i^th iteration, where i is given by GLUI_SCROLL_CALLBACK_INTERVAL ****/ + if(data_type==GLUI_SCROLL_INT) + set_int_val(new_int_val); + else if (data_type==GLUI_SCROLL_FLOAT) + set_float_val(new_float_val); + + callback_count++; + if ( (callback_count % GLUI_SCROLL_CALLBACK_INTERVAL ) == 0 ) + do_callbacks(); +} + + +/***************************************** GLUI_Scrollbar::needs_idle() ******/ + +bool GLUI_Scrollbar::needs_idle( void ) const +{ + if (state == GLUI_SCROLL_STATE_UP OR state == GLUI_SCROLL_STATE_DOWN ) { + return true; + } + else { + return false; + } +} + +/***************************************** GLUI_Scrollbar::idle() **********/ + +void GLUI_Scrollbar::idle( void ) +{ + if ( NOT needs_idle() ) + return; + else + do_click(); +} + + +/************************************ GLUI_Scrollbar::do_callbacks() **********/ + +void GLUI_Scrollbar::do_callbacks( void ) +{ + + /* *******************************************/ + + if ( NOT first_callback ) { + if ( data_type == GLUI_SCROLL_INT AND int_val == last_int_val ) { + return; + } + if ( data_type == GLUI_SPINNER_FLOAT AND float_val == last_float_val ) { + return; + } + } + + if (associated_object == NULL) { + this->execute_callback(); + } + else { // Use internal Callbacks + if (object_cb) { + //object_cb(associated_object, int_val); + object_cb(this); + } + } + last_int_val = int_val; + last_float_val = float_val; + first_callback = false; +} + + +/********************************** GLUI_Scrollbar::set_float_val() ************/ + +void GLUI_Scrollbar::set_float_val( float new_val ) +{ + // Allow for the possibility that the limits are reversed + float hi = MAX(float_min,float_max); + float lo = MIN(float_min,float_max); + if (new_val > hi) + new_val = hi; + if (new_val < lo) + new_val = lo; + last_float_val = float_val; + float_val = new_val; + int_val = (int)new_val; + + redraw(); + + /*** Now update the live variable ***/ + output_live(true); +} + + +/********************************** GLUI_Scrollbar::set_int_val() ************/ + +void GLUI_Scrollbar::set_int_val( int new_val ) +{ + // Allow for the possibility that the limits are reversed + int hi = MAX(int_min,int_max); + int lo = MIN(int_min,int_max); + if (new_val > hi) + new_val = hi; + if (new_val < lo) + new_val = lo; + last_int_val = int_val; + float_val = int_val = new_val; + + redraw(); + + /*** Now update the live variable ***/ + output_live(true); +} + +/*********************************** GLUI_Scrollbar::set_float_limits() *********/ + +void GLUI_Scrollbar::set_float_limits( float low, float high, int limit_type ) +{ + if (limit_type != GLUI_LIMIT_CLAMP) { + // error! + } + float_min = low; + float_max = high; + // Allow for possiblitly of reversed limits + float lo = MIN(low,high); + float hi = MAX(low,high); + if (float_valhi) set_float_val(hi); +} + + +/*********************************** GLUI_Scrollbar::set_int_limits() *********/ + +void GLUI_Scrollbar::set_int_limits( int low, int high, int limit_type ) +{ + if (limit_type != GLUI_LIMIT_CLAMP) { + // error! + } + int_min = low; + int_max = high; + // Allow for possiblitly of reversed limits + int lo = MIN(low,high); + int hi = MAX(low,high); + if (int_valhi) set_int_val(hi); + float_min = low; + float_max = high; +} + + +/*********************************** GLUI_Scrollbar::reset_growth() *************/ + +void GLUI_Scrollbar::reset_growth( void ) +{ + growth = fabs(float_max - float_min) / float(GLUI_SCROLL_GROWTH_STEPS); + if (data_type == GLUI_SCROLL_INT && growth<1) growth=1; +} + + +/******************************* GLUI_Scrollbar::increase_growth() *************/ + +void GLUI_Scrollbar::increase_growth( void ) +{ + float range=0; + if (data_type==GLUI_SCROLL_FLOAT) + range = fabs(float_max-float_min); + else + range = fabs(float(int_max-int_min)); + if ( growth < (range / float(GLUI_SCROLL_MIN_GROWTH_STEPS)) ) + growth *= growth_exp; + return; +} + + + diff --git a/tests/Box2D_v2.2.1/glui/glui_separator.cpp b/tests/Box2D_v2.2.1/glui/glui_separator.cpp new file mode 100755 index 0000000000000..b10cf361fda64 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_separator.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_separator.cpp - GLUI_Separator control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui_internal_control.h" + +/****************************** GLUI_Separator::GLUI_Separator() **********/ + +GLUI_Separator::GLUI_Separator( GLUI_Node *parent ) +{ + common_init(); + parent->add_control( this ); +} + +/****************************** GLUI_Separator::draw() **********/ + +void GLUI_Separator::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + int width, indent; + int cont_x, cont_y, cont_w, cont_h, cont_x_off, cont_y_off; + + if ( parent() != NULL ) { + get_this_column_dims(&cont_x, &cont_y, &cont_w, &cont_h, + &cont_x_off, &cont_y_off); + + width = cont_w - cont_x_off*2; + } + else { + width = this->w; + } + + indent = (int) floor(width * .05); + + glLineWidth( 1.0 ); + glBegin( GL_LINES ); + glColor3f( .5, .5, .5 ); + glVertex2i( indent, GLUI_SEPARATOR_HEIGHT/2-1 ); + glVertex2i( width-indent, GLUI_SEPARATOR_HEIGHT/2-1 ); + + glColor3f( 1., 1., 1. ); + glVertex2i( indent, GLUI_SEPARATOR_HEIGHT/2 ); + glVertex2i( width-indent, GLUI_SEPARATOR_HEIGHT/2 ); + glEnd(); +} + + diff --git a/tests/Box2D_v2.2.1/glui/glui_spinner.cpp b/tests/Box2D_v2.2.1/glui/glui_spinner.cpp new file mode 100755 index 0000000000000..85e7e3e00631d --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_spinner.cpp @@ -0,0 +1,647 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_spinner.cpp - GLUI_Spinner class + + + notes: + spinner does not explicitly keep track of the current value - this is all + handled by the underlying edittext control + -> thus, spinner->sync_live() has no meaning, nor spinner->output_live + -> BUT, edittext will alter this spinner's float_val and int_val, + so that spinner->get/set will work + + +FIXME: there's a heck of a lot of duplication between this and glui_scrollbar.cpp. + (OSL, 2006/06) + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui_internal_control.h" +#include +#include + +/*static int __debug=0; */ + +#define GLUI_SPINNER_GROWTH_STEPS 800 +#define GLUI_SPINNER_MIN_GROWTH_STEPS 100 +#define GLUI_SPINNER_CALLBACK_INTERVAL 1 + + +/****************************** spinner_edittext_callback() ******************/ +/* This function is not used anymore. It has been replaced by directly */ +/* Including an optional pointer to a spinner from an edittext box */ + +void spinner_edittext_callback( int id ) +{ + GLUI_Spinner *spinner; + + putchar( '.' ); flushout; + + spinner = (GLUI_Spinner*) id; + + if ( NOT spinner ) + return; + + spinner->do_callbacks(); +} + + +/****************************** GLUI_Spinner::GLUI_Spinner() ****************/ + +GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name, + int data_type, int id, GLUI_CB callback ) +{ + common_construct(parent, name, data_type, NULL, id, callback); +} + +/****************************** GLUI_Spinner::GLUI_Spinner() ****************/ + +GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name, + int *live_var, int id, GLUI_CB callback ) +{ + common_construct(parent, name, GLUI_SPINNER_INT, live_var, id, callback); +} + +/****************************** GLUI_Spinner::GLUI_Spinner() ****************/ + +GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name, + float *live_var, int id, GLUI_CB callback ) +{ + common_construct(parent, name, GLUI_SPINNER_FLOAT, live_var, id, callback); +} + +/****************************** GLUI_Spinner::GLUI_Spinner() ****************/ + +GLUI_Spinner::GLUI_Spinner( GLUI_Node *parent, const char *name, + int data_t, void *live_var, + int id, GLUI_CB callback ) +{ + common_construct(parent, name, data_t, live_var, id, callback); +} + +/****************************** GLUI_Spinner::common_construct() ************/ + +void GLUI_Spinner::common_construct( GLUI_Node* parent, const char *name, + int data_t, void *data, + int id, GLUI_CB cb ) +{ + common_init(); + + if ( NOT strcmp( name, "Spinner Test" )) + id=id; + + int text_type; + if ( data_t == GLUI_SPINNER_INT ) { + text_type = GLUI_EDITTEXT_INT; + } + else if ( data_t == GLUI_SPINNER_FLOAT ) { + text_type = GLUI_EDITTEXT_FLOAT; + } + else { + assert(0); /* Did not pass in a valid data type */ + } + + user_id = id; + data_type = data_t; + callback = cb; + set_name( name ); + //glui = parent->get_glui(); + + parent->add_control( this ); + + GLUI_EditText *txt = + new GLUI_EditText( this, name, text_type, data, id, cb); + + edittext = txt; /* Link the edittext to the spinner */ + /* control->ptr_val = data; */ + + edittext->spinner = this; /* Link the spinner to the edittext */ + +} + +/****************************** GLUI_Spinner::mouse_down_handler() **********/ + +int GLUI_Spinner::mouse_down_handler( int local_x, int local_y ) +{ + this->state = find_arrow( local_x, local_y ); + GLUI_Master.glui_setIdleFuncIfNecessary(); + + /* printf( "spinner: mouse down : %d/%d arrow:%d\n", local_x, local_y, + find_arrow( local_x, local_y )); + */ + + if ( state != GLUI_SPINNER_STATE_UP AND state != GLUI_SPINNER_STATE_DOWN ) + return true; + + reset_growth(); + redraw(); + + /*** ints and floats behave a bit differently. When you click on + an int spinner, you expect the value to immediately go up by 1, whereas + for a float it'll go up only by a fractional amount. Therefore, we + go ahead and increment by one for int spinners ***/ + if ( data_type == GLUI_SPINNER_INT ) { + if ( state == GLUI_SPINNER_STATE_UP ) + edittext->set_float_val( edittext->float_val + 1.0 ); + else if ( state == GLUI_SPINNER_STATE_DOWN ) + edittext->set_float_val( edittext->float_val - .9 ); + } + + do_click(); + + return false; +} + + +/******************************** GLUI_Spinner::mouse_up_handler() **********/ + +int GLUI_Spinner::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + state = GLUI_SPINNER_STATE_NONE; + GLUI_Master.glui_setIdleFuncIfNecessary(); + + /* printf("spinner: mouse up : %d/%d inside: %d\n",local_x,local_y,inside); */ + + /*glutSetCursor( GLUT_CURSOR_INHERIT ); */ + glutSetCursor( GLUT_CURSOR_LEFT_ARROW ); + redraw(); + + /* do_callbacks(); --- stub */ + /* if ( callback ) */ + /* callback( this->user_id ); */ + + return false; +} + + +/***************************** GLUI_Spinner::mouse_held_down_handler() ******/ + +int GLUI_Spinner::mouse_held_down_handler( int local_x, int local_y, + bool new_inside) +{ + int new_state; + + if ( state == GLUI_SPINNER_STATE_NONE ) + return false; + + /* printf("spinner: mouse held: %d/%d inside: %d\n",local_x,local_y, + new_inside); + */ + + if ( state == GLUI_SPINNER_STATE_BOTH ) { /* dragging? */ + do_drag( local_x, local_y ); + } + else { /* not dragging */ + new_state = find_arrow( local_x, local_y ); + + if ( new_state == state ) { + /** Still in same arrow **/ + do_click(); + } + else { + if ( new_inside OR 1) { + /** The state changed, but we're still inside - that + means we moved off the arrow: begin dragging **/ + state = GLUI_SPINNER_STATE_BOTH; + } + else { + /*** Here check y of mouse position to determine whether to + drag ***/ + + /* ... */ + } + } + + /*** We switched to up/down dragging ***/ + if ( state == GLUI_SPINNER_STATE_BOTH ) { + glutSetCursor( GLUT_CURSOR_UP_DOWN ); + last_x = local_x; + last_y = local_y; + + /** If the spinner has limits, we reset the growth value, since + reset_growth() will compute a new growth value for dragging + vs. clicking. If the spinner has no limits, then we just let the + growth remain at whatever the user has incremented it up to **/ + if ( edittext->has_limits != GLUI_LIMIT_NONE ) + reset_growth(); + } + + redraw(); + } + + return false; +} + + +/****************************** GLUI_Spinner::key_handler() **********/ + +int GLUI_Spinner::key_handler( unsigned char key,int modifiers ) +{ + + + return true; +} + + +/****************************** GLUI_Spinner::draw() **********/ + +void GLUI_Spinner::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + if ( enabled ) { + /*** Draw the up arrow either pressed or unrpessed ***/ + if ( state == GLUI_SPINNER_STATE_UP OR state == GLUI_SPINNER_STATE_BOTH ) + glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_ON, + w-GLUI_SPINNER_ARROW_WIDTH-1, + GLUI_SPINNER_ARROW_Y); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_OFF, + w-GLUI_SPINNER_ARROW_WIDTH-1, + GLUI_SPINNER_ARROW_Y); + + /*** Draw the down arrow either pressed or unrpessed ***/ + if (state == GLUI_SPINNER_STATE_DOWN OR state == GLUI_SPINNER_STATE_BOTH) + glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_ON, + w-GLUI_SPINNER_ARROW_WIDTH-1, + GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_OFF, + w-GLUI_SPINNER_ARROW_WIDTH-1, + GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y); + } + else { /**** The spinner is disabled ****/ + glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_DIS, + w-GLUI_SPINNER_ARROW_WIDTH-1, + GLUI_SPINNER_ARROW_Y); + glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_DIS, + w-GLUI_SPINNER_ARROW_WIDTH-1, + GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y); + } + + if ( active ) { + glColor3ub( 0, 0, 0 ); + glEnable( GL_LINE_STIPPLE ); + glLineStipple( 1, 0x5555 ); + } + else { + glColor3ub( glui->bkgd_color.r,glui->bkgd_color.g,glui->bkgd_color.b ); + } + + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( w-GLUI_SPINNER_ARROW_WIDTH-2, 0 ); + glVertex2i( w, 0 ); + glVertex2i( w, h ); + glVertex2i( w-GLUI_SPINNER_ARROW_WIDTH-2, h ); + glEnd(); + glDisable( GL_LINE_STIPPLE ); + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); +} + + +/********************************* GLUI_Spinner::special_handler() **********/ + +int GLUI_Spinner::special_handler( int key,int modifiers ) +{ + if ( key == GLUT_KEY_UP ) { /** Simulate a click in the up arrow **/ + mouse_down_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1, + y_abs + GLUI_SPINNER_ARROW_Y+1 ); + mouse_up_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1, + y_abs + GLUI_SPINNER_ARROW_Y+1, true ); + } + else if ( key == GLUT_KEY_DOWN ) { /** Simulate a click in the up arrow **/ + mouse_down_handler(x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1, + y_abs+GLUI_SPINNER_ARROW_Y+1+GLUI_SPINNER_ARROW_HEIGHT); + mouse_up_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1, + y_abs+GLUI_SPINNER_ARROW_Y+1 +GLUI_SPINNER_ARROW_HEIGHT, + true ); + } + else if ( key == GLUT_KEY_HOME ) { /** Set value to limit top - + or increment by 10 **/ + } + else if ( key == GLUT_KEY_END ) { + } + + return true; +} + + +/******************************* GLUI_Spinner::set_float_val() ************/ + +void GLUI_Spinner::set_float_val( float new_val ) +{ + if ( NOT edittext ) + return; + + edittext->set_float_val( new_val ); +} + + +/********************************** GLUI_Spinner::set_int_val() ************/ + +void GLUI_Spinner::set_int_val( int new_val ) +{ + if ( NOT edittext ) + return; + + edittext->set_int_val( new_val ); +} + + +/************************************ GLUI_Spinner::update_size() **********/ + +void GLUI_Spinner::update_size( void ) +{ + if (!edittext) return; + /*edittext->w = this->w - GLUI_SPINNER_ARROW_WIDTH-3; */ + this->w = edittext->w + GLUI_SPINNER_ARROW_WIDTH + 3; +} + + +/************************************ GLUI_Spinner::find_arrow() ************/ + +int GLUI_Spinner::find_arrow( int local_x, int local_y ) +{ + local_x -= x_abs; + local_y -= y_abs; + + if ( local_x >= (w - GLUI_SPINNER_ARROW_WIDTH) AND + local_x <= w ) { + + if ( local_y >= GLUI_SPINNER_ARROW_Y AND + local_y <= (GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT) ) + return GLUI_SPINNER_STATE_UP; + + if ( local_y >= GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT AND + local_y <= (GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT*2) ) + return GLUI_SPINNER_STATE_DOWN; + + } + + return GLUI_SPINNER_STATE_NONE; +} + + +/***************************************** GLUI_Spinner::do_click() **********/ + +void GLUI_Spinner::do_click( void ) +{ + int direction = 0; + float incr; + float modifier_factor; + + if ( state == GLUI_SPINNER_STATE_UP ) + direction = +1; + else if ( state == GLUI_SPINNER_STATE_DOWN ) + direction = -1; + + increase_growth(); + + modifier_factor = 1.0; + if ( glui ) { + if ( glui->curr_modifiers & GLUT_ACTIVE_SHIFT ) + modifier_factor = 100.0f; + else if ( glui->curr_modifiers & GLUT_ACTIVE_CTRL ) + modifier_factor = .01f; + } + + if ( this->data_type == GLUI_SPINNER_FLOAT OR 1) { + incr = growth * direction * modifier_factor * user_speed; + edittext->set_float_val( edittext->float_val + incr ); + /** Remember, edittext mirrors the float and int values ***/ + } + + /*** Now update live variable and do callback. We don't want + to do the callback on each iteration of this function, just on every + i^th iteration, where i is given by GLUI_SPINNER_CALLBACK_INTERVAL ****/ + callback_count++; + if ( (callback_count % GLUI_SPINNER_CALLBACK_INTERVAL ) == 0 ) + do_callbacks(); +} + + +/***************************************** GLUI_Spinner::do_drag() **********/ + +void GLUI_Spinner::do_drag( int x, int y ) +{ + int delta_y; + float incr, modifier_factor; + /* int delta_x; */ + + modifier_factor = 1.0f; + if ( glui ) { + if ( glui->curr_modifiers & GLUT_ACTIVE_SHIFT ) + modifier_factor = 100.0f; + else if ( glui->curr_modifiers & GLUT_ACTIVE_CTRL ) + modifier_factor = .01f; + } + + /* delta_x = x - last_x; */ + delta_y = -(y - last_y); + + if ( this->data_type == GLUI_SPINNER_FLOAT OR 1 ) { + incr = growth * delta_y * modifier_factor * user_speed; + edittext->set_float_val( edittext->float_val + incr ); + /** Remember, edittext mirrors the float and int values ***/ + } + + last_x = x; + last_y = y; + + /*** Now update live variable and do callback. We don't want + to do the callback on each iteration of this function, just on every + i^th iteration, where i is given by GLUI_SPINNER_CALLBACK_INTERVAL ****/ + + callback_count++; + if ( (callback_count % GLUI_SPINNER_CALLBACK_INTERVAL ) == 0 ) + do_callbacks(); +} + + +/***************************************** GLUI_Spinner::needs_idle() ******/ + +bool GLUI_Spinner::needs_idle( void ) const +{ + if (state == GLUI_SPINNER_STATE_UP OR state == GLUI_SPINNER_STATE_DOWN ) { + return true; + } + else { + return false; + } +} + +/***************************************** GLUI_Spinner::idle() **********/ + +void GLUI_Spinner::idle( void ) +{ + if ( NOT needs_idle() ) + return; + else + do_click(); +} + + +/************************************ GLUI_Spinner::do_callbacks() **********/ + +void GLUI_Spinner::do_callbacks( void ) +{ + /*** This is not necessary, b/c edittext automatically updates us ***/ + if ( NOT edittext ) + return; + this->float_val = edittext->float_val; + this->int_val = edittext->int_val; + /* *******************************************/ + + if ( NOT first_callback ) { + if ( data_type == GLUI_SPINNER_INT AND int_val == last_int_val ) { + return; + } + + if ( data_type == GLUI_SPINNER_FLOAT AND float_val == last_float_val ) { + return; + } + } + + this->execute_callback(); + + last_int_val = int_val; + last_float_val = float_val; + first_callback = false; +} + + +/********************************* GLUI_Spinner::set_float_limits() *********/ + +void GLUI_Spinner::set_float_limits( float low, float high, int limit_type ) +{ + if ( NOT edittext ) + return; + + edittext->set_float_limits( low, high, limit_type ); +} + + +/*********************************** GLUI_Spinner::set_int_limits() *********/ + +void GLUI_Spinner::set_int_limits( int low, int high, int limit_type ) +{ + if ( NOT edittext ) + return; + + edittext->set_int_limits( low, high, limit_type ); +} + + +/*********************************** GLUI_Spinner:reset_growth() *************/ + +void GLUI_Spinner::reset_growth( void ) +{ + float lo, hi; + + if ( edittext->has_limits == GLUI_LIMIT_NONE ) { + if ( data_type == GLUI_SPINNER_FLOAT ) + growth = sqrt(ABS(edittext->float_val)) * .05f; + else if ( data_type == GLUI_SPINNER_INT ) + growth = .4f; + } + else { + if ( data_type == GLUI_SPINNER_FLOAT ) { + lo = edittext->float_low; + hi = edittext->float_high; + growth = (hi-lo) / GLUI_SPINNER_GROWTH_STEPS; + } + else if ( data_type == GLUI_SPINNER_INT ) { + lo = (float) edittext->int_low; + hi = (float) edittext->int_high; + + growth = (hi-lo) / GLUI_SPINNER_GROWTH_STEPS; + } + } + + if ( growth == 0.0f ) + growth = .001f; +} + + +/******************************* GLUI_Spinner:increase_growth() *************/ + +void GLUI_Spinner::increase_growth( void ) +{ + float hi = 0.0,lo = 0.0; + + if ( data_type == GLUI_SPINNER_FLOAT ) { + lo = edittext->float_low; + hi = edittext->float_high; + } + else if ( data_type == GLUI_SPINNER_INT ) { + lo = (float) edittext->int_low; + hi = (float) edittext->int_high; + } + + if ( growth < (hi-lo) / GLUI_SPINNER_MIN_GROWTH_STEPS ) + growth *= growth_exp; + + /* printf( "growth: %f\n", growth ); */ +} + + +/*************************************** GLUI_Spinner:get_text() *************/ + +const char *GLUI_Spinner::get_text( void ) +{ + if (edittext) + return edittext->text.c_str(); + else + return ""; +} + + +/********************************** GLUI_Spinner:get_float_val() *************/ + +float GLUI_Spinner::get_float_val( void ) +{ + if (edittext) + return edittext->float_val; + else + return 0.0f; +} + + +/********************************** GLUI_Spinner:get_int_val() *************/ + +int GLUI_Spinner::get_int_val( void ) +{ + if (edittext) + return edittext->int_val; + else + return 0; +} + + diff --git a/tests/Box2D_v2.2.1/glui/glui_statictext.cpp b/tests/Box2D_v2.2.1/glui/glui_statictext.cpp new file mode 100755 index 0000000000000..b0db4b943e924 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_statictext.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_statictext.cpp - GLUI_StaticText Control + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui_internal_control.h" + +/****************************** GLUI_StaticText::GLUI_StaticText() **********/ +GLUI_StaticText::GLUI_StaticText( GLUI_Node *parent, const char *name ) +{ + common_init(); + set_name( name ); + parent->add_control( this ); +} + +/****************************** GLUI_StaticText::draw() **********/ + +void GLUI_StaticText::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + draw_text(); +} + + +/****************************** GLUI_StaticText::set_text() **********/ + +void GLUI_StaticText::set_text( const char *text ) +{ + set_name( text ); + redraw(); +} + + +/************************************ GLUI_StaticText::update_size() **********/ + +void GLUI_StaticText::update_size( void ) +{ + int text_size; + + if ( NOT glui ) + return; + + text_size = string_width( name ); + + if ( w < text_size ) + w = text_size; +} + + +/****************************** GLUI_StaticText::draw_text() **********/ + +void GLUI_StaticText::draw_text( void ) +{ + if ( NOT can_draw() ) + return; + + erase_text(); + draw_name( 0, 9 ); +} + + +/****************************** GLUI_StaticText::erase_text() **********/ + +void GLUI_StaticText::erase_text( void ) +{ + if ( NOT can_draw() ) + return; + + set_to_bkgd_color(); + glDisable( GL_CULL_FACE ); + glBegin( GL_TRIANGLES ); + glVertex2i( 0,0 ); glVertex2i( w, 0 ); glVertex2i( w, h ); + glVertex2i( 0, 0 ); glVertex2i( w, h ); glVertex2i( 0, h ); + glEnd(); +} + + + diff --git a/tests/Box2D_v2.2.1/glui/glui_string.cpp b/tests/Box2D_v2.2.1/glui/glui_string.cpp new file mode 100755 index 0000000000000..910e6eb854d65 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_string.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui.cpp + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher (this file, Bill Baxter 2005) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA + + This program is -not- in the public domain. + +*****************************************************************************/ + +#include "glui.h" +#include + +#ifdef _MSC_VER +#define vsnprintf _vsnprintf +#endif + +GLUI_String& glui_format_str(GLUI_String& str, const char* fmt, ...) +{ + const size_t ISIZE = 128; + char stackbuf[ISIZE]; + size_t bufsz = ISIZE; + char *buf = stackbuf; + str = ""; + va_list arg; + while (1) { + va_start(arg, fmt); + int ret = vsnprintf(buf,299,fmt,arg); + va_end(arg); + if (ret>=0) { + break; + } + // else make a bigger buf, try again + bufsz <<= 1; + if (buf==stackbuf) buf = (char*)malloc(sizeof(char)*bufsz); + else buf = (char*)realloc(buf, sizeof(char)*bufsz); + } + if (buf!=stackbuf) free(buf); + str=buf; + return str; +} diff --git a/tests/Box2D_v2.2.1/glui/glui_textbox.cpp b/tests/Box2D_v2.2.1/glui/glui_textbox.cpp new file mode 100755 index 0000000000000..56fc0158b515b --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_textbox.cpp @@ -0,0 +1,1108 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_textbox.cpp - GLUI_TextBox control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher, 2004 John Kew + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui_internal_control.h" +#include + + +static const int LINE_HEIGHT = 15; + +/****************************** GLUI_TextBox::GLUI_TextBox() **********/ + +GLUI_TextBox::GLUI_TextBox(GLUI_Node *parent, GLUI_String &live_var, + bool scroll, int id, GLUI_CB callback ) +{ + common_construct(parent, &live_var, scroll, id, callback); +} + +/****************************** GLUI_TextBox::GLUI_TextBox() **********/ + +GLUI_TextBox::GLUI_TextBox( GLUI_Node *parent, bool scroll, int id, + GLUI_CB callback ) +{ + common_construct(parent, NULL, scroll, id, callback); +} + +/****************************** GLUI_TextBox::common_construct() **********/ +void GLUI_TextBox::common_construct( + GLUI_Node *parent, GLUI_String *data, + bool scroll, int id, GLUI_CB callback) +{ + common_init(); + + GLUI_Node *tb_panel = parent; + + if (scroll) { + GLUI_Panel *p = new GLUI_Panel(parent,"",GLUI_PANEL_NONE); + p->x_off = 1; + tb_panel = p; + } + this->ptr_val = data; + if (data) { + this->live_type = GLUI_LIVE_STRING; + } else { + this->live_type = GLUI_LIVE_NONE; + } + this->user_id = id; + this->callback = callback; + this->name = "textbox"; + tb_panel->add_control( this ); + if (scroll) { + new GLUI_Column(tb_panel, false); + scrollbar = + new GLUI_Scrollbar(tb_panel, + "scrollbar", + GLUI_SCROLL_VERTICAL, + GLUI_SCROLL_INT); + scrollbar->set_object_callback(GLUI_TextBox::scrollbar_callback, this); + scrollbar->set_alignment(GLUI_ALIGN_LEFT); + // scrollbar->can_activate = false; //kills ability to mouse drag too + } + init_live(); +} + +/****************************** GLUI_TextBox::mouse_down_handler() **********/ + +int GLUI_TextBox::mouse_down_handler( int local_x, int local_y ) +{ + int tmp_insertion_pt; + + if ( debug ) dump( stdout, "-> MOUSE DOWN" ); + + tmp_insertion_pt = find_insertion_pt( local_x, local_y ); + if ( tmp_insertion_pt == -1 ) { + if ( glui ) + glui->deactivate_current_control( ); + return false; + } + + insertion_pt = tmp_insertion_pt; + + sel_start = sel_end = insertion_pt; + + keygoal_x = insert_x; + + if ( can_draw()) + update_and_draw_text(); + + if ( debug ) dump( stdout, "<- MOUSE UP" ); + + return true; +} + + +/******************************** GLUI_TextBox::mouse_up_handler() **********/ + +int GLUI_TextBox::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + return false; +} + + +/***************************** GLUI_TextBox::mouse_held_down_handler() ******/ + +int GLUI_TextBox::mouse_held_down_handler( int local_x, int local_y, + bool new_inside) +{ + int tmp_pt; + + if ( NOT new_inside ) return false; + + if ( debug ) dump( stdout, "-> HELD DOWN" ); + + tmp_pt = find_insertion_pt( local_x, local_y ); + keygoal_x = insert_x; + + if ( tmp_pt == -1 AND sel_end != 0 ) { /* moved mouse past left edge */ + special_handler( GLUT_KEY_LEFT, GLUT_ACTIVE_SHIFT ); + } + else if ( tmp_pt == substring_end+1 AND sel_end != (int) text.length()) { + /* moved mouse past right edge */ + special_handler( GLUT_KEY_RIGHT, GLUT_ACTIVE_SHIFT ); + } + else if ( tmp_pt != -1 AND tmp_pt != sel_end ) { + sel_end = insertion_pt = tmp_pt; + + update_and_draw_text(); + } + + if ( debug ) + dump( stdout, "<- HELD DOWN" ); + + return false; +} + + +/****************************** GLUI_TextBox::key_handler() **********/ +int GLUI_TextBox::key_handler( unsigned char key,int modifiers ) +{ + int regular_key; + /* int has_selection; */ + + if ( NOT glui ) + return false; + + if ( debug ) + dump( stdout, "-> KEY HANDLER" ); + + regular_key = false; + bool ctrl_down = (modifiers & GLUT_ACTIVE_CTRL)!=0; + /* has_selection = (sel_start != sel_end); */ + + if ( key == CTRL('[')) { /* ESCAPE */ + glui->deactivate_current_control(); + return true; + } + else if ( (key == 127 AND !ctrl_down) OR /* FORWARD DELETE */ + ( key == CTRL('d') AND modifiers == GLUT_ACTIVE_CTRL) ) + { + if ( sel_start == sel_end ) { /* no selection */ + if ( insertion_pt < (int)text.length() ) { + text.erase(insertion_pt,1); + } + } + else { /* There is a selection */ + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + } + else if ( ((key == 127) AND ctrl_down) OR // Delete word forward + ((key == 'd') AND (modifiers == GLUT_ACTIVE_ALT)) ) + { + if ( sel_start == sel_end ) { /* no selection */ + sel_start = insertion_pt; + sel_end = find_word_break( insertion_pt, +1 ); + } + + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + else if ( key == CTRL('h') ) { /* BACKSPACE */ + if ( sel_start == sel_end ) { /* no selection */ + if ( insertion_pt > 0 ) { + insertion_pt--; + text.erase(insertion_pt,1); + } + } + else { /* There is a selection */ + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + } + else if ( modifiers == GLUT_ACTIVE_CTRL ) /* CTRL ONLY */ + { + /* Ctrl-key bindings */ + if ( key == CTRL('a') ) { + return special_handler( GLUT_KEY_HOME, 0 ); + } + else if ( key == CTRL('e') ) { + return special_handler( GLUT_KEY_END, 0 ); + } + else if ( key == CTRL('b') ) { + return special_handler( GLUT_KEY_LEFT, 0 ); + } + else if ( key == CTRL('f') ) { + return special_handler( GLUT_KEY_RIGHT, 0 ); + } + else if ( key == CTRL('p') ) { + return special_handler( GLUT_KEY_UP, 0 ); + } + else if ( key == CTRL('n') ) { + return special_handler( GLUT_KEY_DOWN, 0 ); + } + else if ( key == CTRL('u') ) { /* ERASE LINE */ + insertion_pt = 0; + text.erase(0,text.length()); + sel_start = sel_end = 0; + } + else if ( key == CTRL('k') ) { /* KILL TO END OF LINE */ + sel_start = sel_end = insertion_pt; + text.erase(insertion_pt,GLUI_String::npos); + } + } + else if ( modifiers == GLUT_ACTIVE_ALT ) /* ALT ONLY */ + { + if ( key == 'b' ) { // Backward word + return special_handler ( GLUT_KEY_LEFT, GLUT_ACTIVE_CTRL ); + } + if ( key == 'f' ) { // Forward word + return special_handler ( GLUT_KEY_RIGHT, GLUT_ACTIVE_CTRL ); + } + } + else if ( (modifiers & GLUT_ACTIVE_CTRL) OR + (modifiers & GLUT_ACTIVE_ALT) ) + { + /** ignore other keys with modifiers */ + return true; + } + else { /* Regular key */ + if ( key == 13 ) /* RETURNS are written as newlines*/ + key = '\n'; + + regular_key = true; + + /** This is just to get rid of warnings - the flag regular_key is + set if the key was not a backspace, return, whatever. But I + believe if we're here, we know it was a regular key anyway */ + if ( regular_key ) { + } + + /**** If there's a current selection, erase it ******/ + if ( sel_start != sel_end ) { + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + + /******** We insert the character into the string ***/ + + text.insert(insertion_pt,1,key); + + /******** Move the insertion point and substring_end one over ******/ + insertion_pt++; + substring_end++; + + sel_start = sel_end = insertion_pt; + } + + /******** Now redraw text ***********/ + /* Hack to prevent text box from being cleared first **/ + /** int substring_change = update_substring_bounds(); + draw_text_only = + (NOT substring_change AND NOT has_selection AND regular_key ); + */ + + draw_text_only = false; /** Well, hack is not yet working **/ + update_and_draw_text(); + draw_text_only = false; + + + if ( debug ) + dump( stdout, "<- KEY HANDLER" ); + + return true; +} + +/****************************** GLUI_TextBox::enable() **********/ + +void GLUI_TextBox::enable( void ) +{ + GLUI_Control::enable(); + scrollbar->enable(); +} + +/****************************** GLUI_TextBox::disable() **********/ + +void GLUI_TextBox::disable( void ) +{ + GLUI_Control::disable(); + scrollbar->disable(); +} + +/****************************** GLUI_TextBox::activate() **********/ + +void GLUI_TextBox::activate( int how ) +{ + if ( debug ) + dump( stdout, "-> ACTIVATE" ); + active = true; + + if ( how == GLUI_ACTIVATE_MOUSE ) + return; /* Don't select everything if activated with mouse */ + + orig_text = text; + + sel_start = 0; + sel_end = text.length(); + insertion_pt = 0; + if ( debug ) + dump( stdout, "<- ACTIVATE" ); +} + + +/****************************** GLUI_TextBox::deactivate() **********/ + +void GLUI_TextBox::deactivate( void ) +{ + active = false; + + if ( NOT glui ) + return; + + if ( debug ) + dump( stdout, "-> DISACTIVATE" ); + + sel_start = sel_end = insertion_pt = -1; + + /***** Retrieve the current value from the text *****/ + /***** The live variable will be updated by set_text() ****/ + set_text(text.c_str()); /* This will force callbacks and gfx refresh */ + + update_substring_bounds(); + + /******** redraw text without insertion point ***********/ + redraw(); + + /***** Now do callbacks if value changed ******/ + if ( orig_text != text ) { + this->execute_callback(); + + + } + + + if ( debug ) + dump( stdout, "<- DISACTIVATE" ); +} + +/****************************** GLUI_TextBox::draw() **********/ + +void GLUI_TextBox::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int line = 0; + int text_length; + int box_width; + int i; + + /* Bevelled Border */ + glBegin( GL_LINES ); + glColor3f( .5, .5, .5 ); + glVertex2i( 0, 0 ); glVertex2i( w, 0 ); + glVertex2i( 0, 0 ); glVertex2i( 0, h ); + + glColor3f( 1., 1., 1. ); + glVertex2i( 0, h ); glVertex2i( w, h ); + glVertex2i( w, h ); glVertex2i( w, 0 ); + + if ( enabled ) + glColor3f( 0., 0., 0. ); + else + glColor3f( .25, .25, .25 ); + glVertex2i( 1, 1 ); glVertex2i( w-1, 1 ); + glVertex2i( 1, 1 ); glVertex2i( 1, h-1 ); + + glColor3f( .75, .75, .75 ); + glVertex2i( 1, h-1 ); glVertex2i( w-1, h-1 ); + glVertex2i( w-1, h-1 ); glVertex2i( w-1, 1 ); + glEnd(); + + /* Draw Background if enabled*/ + if (enabled) { + glColor3f( 1., 1., 1. ); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( 2, 2 ); glVertex2i( w-2, 2 ); + glVertex2i( w-2, h-2 ); glVertex2i(2, h-2 ); + glEnd(); + } else { + glColor3f( .8, .8, .8 ); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( 2, 2 ); glVertex2i( w-2, 2 ); + glVertex2i( w-2, h-2 ); glVertex2i(2, h-2 ); + glEnd(); + } + + /* Begin Drawing Lines of Text */ + substring_start = 0; + substring_end = 0; + text_length = text.length()-1; + + /* Figure out how wide the box is */ + box_width = get_box_width(); + + /* Get the first line substring */ + while (substring_width(substring_start, substring_end+1 ) < box_width && + substring_end < text_length && text[substring_end+1] != '\n') + substring_end++; + + /* Figure out which lines are visible*/ + + visible_lines = (int)(h-20)/LINE_HEIGHT; + if (start_line < (curr_line-visible_lines)) { + for (i = 0; ((curr_line-i)*LINE_HEIGHT+20) > h; i++); + start_line = i; + } else if ( start_line > curr_line) { + start_line = curr_line; + } + line = 0; + do { + if (line && substring_end < text_length) { + substring_start = substring_end+1; + while (substring_width(substring_start, substring_end+1 ) < box_width && + substring_end < text_length && text[substring_end+1] != '\n') + substring_end++; + } + if (text[substring_end+1] == '\n') { /* Skip newline */ + substring_end++; + } + if (line < start_line || (line > curr_line && curr_line > (start_line + visible_lines))) { + line++; + continue; + } + if ((line - start_line) <= visible_lines) + draw_text(0,(line - start_line)*LINE_HEIGHT); /* tabs and other nasties are handled by substring_width */ + line++; + } while (substring_end < text_length); + + num_lines = line; + + draw_insertion_pt(); + if (scrollbar) { + scrollbar->set_int_limits(MAX(0,num_lines/*-1*/-visible_lines),0); + glPushMatrix(); + glTranslatef(scrollbar->x_abs-x_abs, scrollbar->y_abs-y_abs,0.0); + scrollbar->draw_scroll(); + glPopMatrix(); + } +} + + + +/************************** GLUI_TextBox::update_substring_bounds() *********/ + +int GLUI_TextBox::update_substring_bounds( void ) +{ + int box_width; + int text_len = text.length(); + int old_start, old_end; + + old_start = substring_start; + old_end = substring_end; + + /*** Calculate the width of the usable area of the edit box ***/ + box_width = get_box_width(); + + CLAMP( substring_end, 0, MAX(text_len-1,0) ); + CLAMP( substring_start, 0, MAX(text_len-1,0) ); + + if ( debug ) dump( stdout, "-> UPDATE SS" ); + + if ( insertion_pt >= 0 AND + insertion_pt < substring_start ) { /* cursor moved left */ + substring_start = insertion_pt; + + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_end--; + } + else if ( insertion_pt > substring_end ) { /* cursor moved right */ + substring_end = insertion_pt-1; + + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_start++; + } + else { /* cursor is within old substring bounds */ + if ( last_insertion_pt > insertion_pt ) { /* cursor moved left */ + } + else { + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_end--; + + while(substring_width( substring_start, substring_end+1 ) <= box_width + AND substring_end < text_len-1 ) + substring_end++; + } + } + + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_end--; + + last_insertion_pt = insertion_pt; + + /*** No selection if not enabled ***/ + if ( NOT enabled ) { + sel_start = sel_end = 0; + } + + if ( debug ) dump( stdout, "<- UPDATE SS" ); + + if ( substring_start == old_start AND substring_end == old_end ) + return false; /*** bounds did not change ***/ + else + return true; /*** bounds did change ***/ + +} + + +/********************************* GLUI_TextBox::update_x_offsets() *********/ + +void GLUI_TextBox::update_x_offsets( void ) +{ +} + + +/********************************* GLUI_TextBox::draw_text() ****************/ + +void GLUI_TextBox::draw_text( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int text_x, i, sel_lo, sel_hi, x_pos; + + if ( debug ) dump( stdout, "-> DRAW_TEXT" ); + + /** Find where to draw the text **/ + + text_x = 2 + GLUI_TEXTBOX_BOXINNERMARGINX; + + /** Find lower and upper selection bounds **/ + sel_lo = MIN(sel_start, sel_end ); + sel_hi = MAX(sel_start, sel_end ); + + int sel_x_start, sel_x_end, delta; + + /** Draw selection area dark **/ + if ( sel_start != sel_end ) { + sel_x_start = text_x; + sel_x_end = text_x; + delta = 0; + for( i=substring_start; sel_x_end < (w - text_x) && i<=substring_end; i++ ) { + delta = 0; + if (text[i] == '\t') // Character is a tab, go to next tab stop + while (((delta + sel_x_end) < (w - text_x)) && + (delta == 0 || delta % tab_width)) + delta++; + else + delta = char_width( text[i] ); + + if ( i < sel_lo ) { + sel_x_start += delta; + sel_x_end += delta; + } + else if ( i < sel_hi ) { + sel_x_end += delta; + } + } + + glColor3f( 0.0f, 0.0f, .6f ); + glRecti(sel_x_start, y+5, sel_x_end, y+20); + } + + + if ( sel_start == sel_end ) { // No current selection + x_pos = text_x; + if ( enabled ) + glColor3b( 0, 0, 0 ); + else + glColor3b( 32, 32, 32 ); + + glRasterPos2i( text_x, y+LINE_HEIGHT); + for( i=substring_start; i<=substring_end; i++ ) { + if (this->text[i] == '\t') { // Character is a tab, go to next tab stop + x_pos = ((x_pos-text_x)/tab_width)*tab_width+tab_width+text_x; + glRasterPos2i( x_pos, y+LINE_HEIGHT); // Reposition pen after tab + } else { + glutBitmapCharacter( get_font(), this->text[i] ); + x_pos += char_width( this->text[i] ); + } + } + } + else { // There is a selection + x_pos = text_x; + for( i=substring_start; i<=substring_end; i++ ) { + if ( IN_BOUNDS( i, sel_lo, sel_hi-1)) { // This character is selected + glColor3f( 1., 1., 1. ); + glRasterPos2i( x_pos, y+LINE_HEIGHT); + if (this->text[i] == '\t') { // Character is a tab, go to next tab stop + x_pos = ((x_pos-text_x)/tab_width)*tab_width+tab_width+text_x; + } + else + glutBitmapCharacter( get_font(), this->text[i] ); + } + else { + glColor3f( 0., 0., 0. ); + glRasterPos2i( x_pos, y+LINE_HEIGHT); + if (this->text[i] == '\t') { // Character is a tab, go to next tab stop + x_pos = ((x_pos-text_x)/tab_width)*tab_width+tab_width+text_x; + glRasterPos2i( x_pos, y+LINE_HEIGHT); // Reposition pen after tab + } else + glutBitmapCharacter( get_font(), this->text[i] ); + } + + x_pos += char_width( text[i] ); + } + } + + if ( debug ) dump( stdout, "<- DRAW_TEXT" ); +} + + +/******************************** GLUI_TextBox::find_insertion_pt() *********/ +/* This function returns the character number *before which* the insertion */ +/* point goes */ + +int GLUI_TextBox::find_insertion_pt( int x, int y ) +{ + /*** See if we clicked outside box ***/ + if ( x < this->x_abs || y < this->y_abs) + return -1; + + /*** See if we clicked in an empty box ***/ + if ( text.empty() ) + return 0; + + /* update insert variables */ + insert_x = x; + insert_y = y; + + int text_length = text.length()-1; + int box_width = get_box_width(); + + int sol = 0; + int eol = 0; + int line = 0; + + int y_off = y - (y_abs + 2 + GLUI_TEXTBOX_BOXINNERMARGINX); + int x_off = x - (x_abs + 2 + GLUI_TEXTBOX_BOXINNERMARGINX); + + /* Find the line clicked, + The possibility of long lines getting wrapped complicates this. */ + while ((line-start_line+1)*LINE_HEIGHT < y_off && eol < text_length) + { + while (eol < text_length && text[eol] != '\n' && + substring_width(sol, eol+1) <= box_width) + { + eol++; + } + if (text[eol]=='\n' && eol=x_off) { + // did we go far enough? (see if click was >1/2 width of last char) + int decision_pt = prev_w+(total_w-prev_w)/2; + if (x_off>decision_pt) eol++; + } + return eol; + +#if 0 + while (eol < text_length && text[eol] != '\n' && + substring_width(sol, eol+1) < box_width ) + { + eol++; + } + + + /* We move from right to left, looking to see if the mouse was clicked + to the right of the ith character */ +#if 0 + int curr_x = this->x_abs + + substring_width( sol, eol ) + + 2 /* The edittext box has a 2-pixel margin */ + + GLUI_TEXTBOX_BOXINNERMARGINX; /** plus this many pixels blank space + between the text and the box **/ +#endif + + /** find mouse click in text **/ + + if (x_off > substring_width(sol, eol)) + return eol; + + for(i = sol; i <= eol+1; i++) { + if (x_off <= substring_width(sol, i)) + return i+1; + } + return 0; +#endif +} + + +int GLUI_TextBox::get_box_width() +{ + return MAX( this->w + - 4 /* 2 * the two-line box border */ + - 2 * GLUI_TEXTBOX_BOXINNERMARGINX, 0 ); + +} + +/******************************** GLUI_TextBox::draw_insertion_pt() *********/ + +void GLUI_TextBox::draw_insertion_pt( void ) +{ + int curr_x, box_width, text_length, eol, sol, line; + + if ( NOT can_draw() ) + return; + + /*** Don't draw insertion pt if control is disabled ***/ + if ( NOT enabled ) + return; + + if ( sel_start != sel_end OR insertion_pt < 0 ) { + return; /* Don't draw insertion point if there is a current selection */ + } + + if ( debug ) dump( stdout, "-> DRAW_INS_PT" ); + + /* printf( "insertion pt: %d\n", insertion_pt ); */ + + box_width = get_box_width(); + + // This function is unable to distinguish whether an insertion + // point on a line break should be drawn on the line before or the line after. + // This depends on the sequence of operations used to get there, and this + // function just doesn't have that information. If curr_line were kept up + // to date elsewhere that could be used here to disambiguate, but arrow keys + // and such do not update it. + + sol = 0; + eol = 0; + text_length = text.length()-1; + + //while (eol < text_length && text[eol] != '\n' + // && substring_width(sol, eol + 1) < box_width ) + // eol++; + line = 0; + while (eol < insertion_pt && eol <= text_length) + { + if (text[eol] == '\n' || substring_width(sol, eol + 1) >= box_width) + { + eol++; + if (text[eol]=='\n'||eol!=insertion_pt + ||(eol==insertion_pt && eol>0 && text[eol-1]=='\n')) { + sol = eol; + line++; + } + } + else { + eol++; + } + } + + //glColor3f(1,0,0); + //glRecti(0, curr_line*LINE_HEIGHT, 3, (curr_line+1)*LINE_HEIGHT); + + curr_line = line; + + if (scrollbar) + scrollbar->set_int_val(start_line); + if (curr_line < start_line || curr_line > (start_line + visible_lines)) /* Insertion pt out of draw area */ + return; + + curr_x = this->x_abs + + 2 /* The edittext box has a 2-pixel margin */ + + GLUI_TEXTBOX_BOXINNERMARGINX; /** plus this many pixels blank space + between the text and the box **/ + + curr_x += substring_width(sol,insertion_pt-1); + if (insertion_pt == text.length() && text[text.length()-1] == '\n' + || curr_x-this->x_abs > (w - 2 - GLUI_TEXTBOX_BOXINNERMARGINX)) { // Insert on the next line + curr_x = this->x_abs + GLUI_TEXTBOX_BOXINNERMARGINX; + line++; + } + /* update insertion coordinates */ + insert_x = curr_x+5; /* I hate magic numbers too, these offset the imagined insertion point */ + insert_y = (curr_line-start_line+2)*LINE_HEIGHT; + + + glColor3f( 0.0, 0.0, 0.0 ); + glBegin( GL_LINE_LOOP ); + + curr_x -= x_abs; + glVertex2i( curr_x+1, (curr_line-start_line)*LINE_HEIGHT + 4 ); + glVertex2i( curr_x, (curr_line-start_line)*LINE_HEIGHT + 4 ); + glVertex2i( curr_x+1, (curr_line-start_line)*LINE_HEIGHT + 16 ); + glVertex2i( curr_x, (curr_line-start_line)*LINE_HEIGHT + 16 ); + glEnd(); + + + if ( debug ) dump( stdout, "-> DRAW_INS_PT" ); +} + + + + +/******************************** GLUI_TextBox::substring_width() *********/ +int GLUI_TextBox::substring_width( int start, int end, int initial_width ) +{ + // This function only works properly if start is really the start of a line. + // Otherwise tabs will be messed up. + int i, width = initial_width; + + for( i=start; i<=end; i++ ) + if (text[i] == '\t') { // Character is a tab, jump to next tab stop + width += tab_width-(width%tab_width); + //while (width == 0 || width % tab_width) + // width++; + } + else + width += char_width( text[i] ); + + return width; +} + + +/***************************** GLUI_TextBox::update_and_draw_text() ********/ + +void GLUI_TextBox::update_and_draw_text( void ) +{ + //update_substring_bounds(); + /* printf( "ss: %d/%d\n", substring_start, substring_end ); */ + + redraw(); +} + + +/********************************* GLUI_TextBox::special_handler() **********/ + +int GLUI_TextBox::special_handler( int key,int modifiers ) +{ + int tmp_insertion_pt; + if ( NOT glui ) + return false; + + if ( debug ) + printf( "SPECIAL:%d - mod:%d subs:%d/%d ins:%d sel:%d/%d\n", + key, modifiers, substring_start, substring_end,insertion_pt, + sel_start, sel_end ); + + if ( key == GLUT_KEY_DOWN ) { + if (insert_x == -1 || insert_y == -1) + return false; + tmp_insertion_pt = find_insertion_pt( keygoal_x, insert_y+LINE_HEIGHT); + if (tmp_insertion_pt < 0) + return false; + insertion_pt = tmp_insertion_pt; + sel_end = insertion_pt; + if (!(modifiers & GLUT_ACTIVE_SHIFT)) { + sel_start = sel_end; + } + if ( can_draw()) + update_and_draw_text(); + } else if ( key == GLUT_KEY_UP ) { + if (insert_x == -1 || insert_y == -1) + return false; + tmp_insertion_pt = find_insertion_pt( keygoal_x, insert_y-LINE_HEIGHT); + if (tmp_insertion_pt < 0) + return false; + insertion_pt = tmp_insertion_pt; + sel_end = insertion_pt; + if (!(modifiers & GLUT_ACTIVE_SHIFT)) { + sel_start = sel_end; + } + if ( can_draw()) + update_and_draw_text(); + } else if ( key == GLUT_KEY_LEFT ) { + if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) { + insertion_pt = find_word_break( insertion_pt, -1 ); + } + else { + insertion_pt--; + } + // update keygoal_x! + } + else if ( key == GLUT_KEY_RIGHT ) { + if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) { + insertion_pt = find_word_break( insertion_pt, +1 ); + } + else { + insertion_pt++; + } + // update keygoal_x! + } + else if ( key == GLUT_KEY_HOME ) { + insertion_pt = 0; + // update keygoal_x! + } + else if ( key == GLUT_KEY_END ) { + insertion_pt = text.length(); + // update keygoal_x! + } + + /*** Update selection if shift key is down ***/ + if ( (modifiers & GLUT_ACTIVE_SHIFT ) != 0 ) + sel_end = insertion_pt; + else + sel_start = sel_end = insertion_pt; + + + CLAMP( insertion_pt, 0, (int)text.length()); /* Make sure insertion_pt + is in bounds */ + CLAMP( sel_start, 0, (int)text.length()); /* Make sure insertion_pt + is in bounds */ + CLAMP( sel_end, 0, (int)text.length()); /* Make sure insertion_pt + is in bounds */ + + /******** Now redraw text ***********/ + if ( can_draw()) + update_and_draw_text(); + + return true; +} + + +/****************************** GLUI_TextBox::find_word_break() **********/ +/* It looks either left or right (depending on value of 'direction' */ +/* for the beginning of the next 'word', where word are characters */ +/* separated by one of the following tokens: " :-.," */ +/* If there is no next word in the specified direction, this returns */ +/* the beginning of 'text', or the very end. */ + +int GLUI_TextBox::find_word_break( int start, int direction ) +{ + int i, j; + char breaks[] = " \n\t:-.,"; + int num_break_chars = (int)strlen(breaks), text_len = text.length(); + int new_pt; + + /** If we're moving left, we have to start two back, in case we're either + already at the beginning of a word, or on a separating token. + Otherwise, this function would just return the word we're already at **/ + if ( direction == -1 ) { + start -= 2; + } + + /***** Iterate over text in the specified direction *****/ + for ( i=start; i >= 0 AND i < text_len; i += direction ) { + + /** For each character in text, iterate over list of separating tokens **/ + for( j=0; j 0 ) /* Return the end of string */ + return text_len; + else /* Return the beginning of the text */ + return 0; +} + + +/********************************** GLUI_TextBox::clear_substring() ********/ + +void GLUI_TextBox::clear_substring( int start, int end ) +{ + text.erase(start,end-start); +} + + + +/************************************ GLUI_TextBox::update_size() **********/ + +void GLUI_TextBox::update_size( void ) +{ + if ( NOT glui ) + return; + + if ( w < GLUI_TEXTBOX_MIN_TEXT_WIDTH ) + w = GLUI_TEXTBOX_MIN_TEXT_WIDTH; +} + + +/****************************** GLUI_TextBox::set_text() **********/ + +void GLUI_TextBox::set_text( const char *new_text ) +{ + text = new_text; + + substring_start = 0; + substring_end = text.length() - 1; + insertion_pt = -1; + sel_start = 0; + sel_end = 0; + visible_lines = 0; + start_line = 0; + curr_line = 0; + num_lines = 0; + + if ( can_draw() ) + update_and_draw_text(); + + /*** Now update the live variable ***/ + output_live(true); +} + + +/*************************************** GLUI_TextBox::dump() **************/ + +void GLUI_TextBox::dump( FILE *out, char *name ) +{ + fprintf( out, + "%s (edittext@%p): line:%d ins_pt:%d subs:%d/%d sel:%d/%d len:%d\n", + name, this, curr_line, + insertion_pt, substring_start, substring_end, sel_start, sel_end, + text.length()); +} + + +/**************************************** GLUI_TextBox::mouse_over() ********/ + +int GLUI_TextBox::mouse_over( int state, int x, int y ) +{ + if ( state && enabled) { + /* curr_cursor = GLUT_CURSOR_TEXT; */ + glutSetCursor( GLUT_CURSOR_TEXT ); + } + else { + /* printf( "OUT\n" ); */ + glutSetCursor( GLUT_CURSOR_LEFT_ARROW ); + } + + return true; +} + +void GLUI_TextBox::scrollbar_callback(GLUI_Control *my_scrollbar) { + GLUI_Scrollbar *sb = dynamic_cast(my_scrollbar); + if (!sb) return; + GLUI_TextBox* me = (GLUI_TextBox*) sb->associated_object; + if (me->scrollbar == NULL) + return; + int new_start_line = sb->get_int_val(); // ?? + me->start_line = new_start_line; + if (new_start_line < (me->curr_line - me->visible_lines)) + me->curr_line = new_start_line + me->visible_lines; + if (new_start_line > me->curr_line) + me->curr_line = new_start_line; + if ( me->can_draw() ) + me->update_and_draw_text(); +} diff --git a/tests/Box2D_v2.2.1/glui/glui_translation.cpp b/tests/Box2D_v2.2.1/glui/glui_translation.cpp new file mode 100755 index 0000000000000..73b1fa3221810 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_translation.cpp @@ -0,0 +1,559 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_translation - GLUI_Translation control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#include "glui.h" +#include "glui_internal.h" +#include "algebra3.h" + +/********************** GLUI_Translation::GLUI_Translation() ***/ + +GLUI_Translation::GLUI_Translation( + GLUI_Node *parent, const char *name, + int trans_t, float *value_ptr, + int id, GLUI_CB cb ) +{ + common_init(); + + set_ptr_val( value_ptr ); + user_id = id; + set_name( name ); + callback = cb; + parent->add_control( this ); + //init_live(); + + trans_type = trans_t; + + if ( trans_type == GLUI_TRANSLATION_XY ) { + float_array_size = 2; + } + else if ( trans_type == GLUI_TRANSLATION_X ) { + float_array_size = 1; + } + else if ( trans_type == GLUI_TRANSLATION_Y ) { + float_array_size = 1; + } + else if ( trans_type == GLUI_TRANSLATION_Z ) { + float_array_size = 1; + } + init_live(); +} + +/********************** GLUI_Translation::iaction_mouse_down_handler() ***/ +/* These are really in local coords (5/10/99) */ + +int GLUI_Translation::iaction_mouse_down_handler( int local_x, + int local_y ) +{ + int center_x, center_y; + + down_x = local_x; + down_y = local_y; + + if ( trans_type == GLUI_TRANSLATION_XY ) { + orig_x = float_array_val[0]; + orig_y = float_array_val[1]; + + /** Check if the Alt key is down, which means lock to an axis **/ + + center_x = w/2; + center_y = (h-18)/2; + + if ( glui->curr_modifiers & GLUT_ACTIVE_ALT ) { + if ( ABS(local_y-center_y) > ABS(local_x-center_x) ) { + locked = GLUI_TRANSLATION_LOCK_Y; + glutSetCursor( GLUT_CURSOR_UP_DOWN ); + } + else { + locked = GLUI_TRANSLATION_LOCK_X; + glutSetCursor( GLUT_CURSOR_LEFT_RIGHT ); + } + } + else { + locked = GLUI_TRANSLATION_LOCK_NONE; + glutSetCursor( GLUT_CURSOR_SPRAY ); + } + } + else if ( trans_type == GLUI_TRANSLATION_X ) { + glutSetCursor( GLUT_CURSOR_LEFT_RIGHT ); + orig_x = float_array_val[0]; + } + else if ( trans_type == GLUI_TRANSLATION_Y ) { + glutSetCursor( GLUT_CURSOR_UP_DOWN ); + orig_y = float_array_val[0]; + } + else if ( trans_type == GLUI_TRANSLATION_Z ) { + glutSetCursor( GLUT_CURSOR_UP_DOWN ); + orig_z = float_array_val[0]; + } + + trans_mouse_code = 1; + redraw(); + + return false; +} + + +/*********************** GLUI_Translation::iaction_mouse_up_handler() **********/ + +int GLUI_Translation::iaction_mouse_up_handler( int local_x, int local_y, + bool inside ) +{ + trans_mouse_code = GLUI_TRANSLATION_MOUSE_NONE; + locked = GLUI_TRANSLATION_LOCK_NONE; + + redraw(); + + return false; +} + + +/******************* GLUI_Translation::iaction_mouse_held_down_handler() ******/ + +int GLUI_Translation::iaction_mouse_held_down_handler( int local_x, int local_y, + bool inside) +{ + float x_off, y_off; + float off_array[2]; + + x_off = scale_factor * (float)(local_x - down_x); + y_off = -scale_factor * (float)(local_y - down_y); + + if ( glui->curr_modifiers & GLUT_ACTIVE_SHIFT ) { + x_off *= 100.0f; + y_off *= 100.0f; + } + else if ( glui->curr_modifiers & GLUT_ACTIVE_CTRL ) { + x_off *= .01f; + y_off *= .01f; + } + + + if ( trans_type == GLUI_TRANSLATION_XY ) { + + if ( locked == GLUI_TRANSLATION_LOCK_X ) + y_off = 0.0; + else if ( locked == GLUI_TRANSLATION_LOCK_Y ) + x_off = 0.0; + + off_array[0] = x_off + orig_x; + off_array[1] = y_off + orig_y; + } + else if ( trans_type == GLUI_TRANSLATION_X ) { + off_array[0] = x_off + orig_x; + } + else if ( trans_type == GLUI_TRANSLATION_Y ) { + off_array[0] = y_off + orig_y; + } + else if ( trans_type == GLUI_TRANSLATION_Z ) { + off_array[0] = y_off + orig_z; + } + + set_float_array_val( (float*) &off_array[0] ); + + return false; +} + + +/******************** GLUI_Translation::iaction_draw_active_area_persp() **************/ + +void GLUI_Translation::iaction_draw_active_area_persp( void ) +{ +} + + +/******************** GLUI_Translation::iaction_draw_active_area_ortho() **********/ + +void GLUI_Translation::iaction_draw_active_area_ortho( void ) +{ + /********* Draw emboss circles around arcball control *********/ + float radius; + radius = (float)(h-22)/2.0; /* MIN((float)w/2.0, (float)h/2.0); */ + glLineWidth( 1.0 ); + + draw_emboss_box( (int) -radius-2, (int)radius+2, + (int)-radius-2, (int)radius+2 ); + + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + glTranslatef( .5, .5, .5 ); + /* glScalef( radius-1.0, radius-1.0, radius-1.0 ); */ + if ( trans_type == GLUI_TRANSLATION_Z ) + draw_2d_z_arrows((int)radius-1); + else if ( trans_type == GLUI_TRANSLATION_XY ) + draw_2d_xy_arrows((int)radius-1); + else if ( trans_type == GLUI_TRANSLATION_X ) + draw_2d_x_arrows((int)radius-1); + else if ( trans_type == GLUI_TRANSLATION_Y ) + draw_2d_y_arrows((int)radius-1); + + glPopMatrix(); +} + + +/******************************** GLUI_Translation::iaction_dump() **********/ + +void GLUI_Translation::iaction_dump( FILE *output ) +{ +} + + +/******************** GLUI_Translation::iaction_special_handler() **********/ + +int GLUI_Translation::iaction_special_handler( int key,int modifiers ) +{ + + return false; +} + + + +/*************************** GLUI_Translation::draw_2d_z_arrows() **************/ + +void GLUI_Translation::draw_2d_z_arrows( int radius ) +{ + if ( trans_mouse_code != GLUI_TRANSLATION_MOUSE_NONE ) { + draw_2d_arrow(radius, true, 2); + draw_2d_arrow(radius, true, 0); + } + else { + draw_2d_arrow(radius, false, 2); + draw_2d_arrow(radius, false, 0); + } +} + + +/*************************** GLUI_Translation::draw_2d_x_arrows() **************/ + +void GLUI_Translation::draw_2d_x_arrows( int radius ) +{ + if ( trans_mouse_code != GLUI_TRANSLATION_MOUSE_NONE ) { + draw_2d_arrow(radius, true, 1); + draw_2d_arrow(radius, true, 3); + } + else { + draw_2d_arrow(radius, false, 1); + draw_2d_arrow(radius, false, 3); + } +} + + +/*************************** GLUI_Translation::draw_2d_y_arrows() **************/ + +void GLUI_Translation::draw_2d_y_arrows( int radius ) +{ + if ( trans_mouse_code != GLUI_TRANSLATION_MOUSE_NONE ) { + draw_2d_arrow(radius, true, 0); + draw_2d_arrow(radius, true, 2); + } + else { + draw_2d_arrow(radius, false, 0); + draw_2d_arrow(radius, false, 2); + } +} + + +/************************** GLUI_Translation::draw_2d_xy_arrows() **************/ + +void GLUI_Translation::draw_2d_xy_arrows( int radius) +{ + if ( trans_mouse_code != GLUI_TRANSLATION_MOUSE_NONE ) { + if ( locked == GLUI_TRANSLATION_LOCK_X ) { + draw_2d_arrow(radius, false, 0); + draw_2d_arrow(radius, false, 2); + draw_2d_arrow(radius, true, 1); + draw_2d_arrow(radius, true, 3); + } + else if ( locked == GLUI_TRANSLATION_LOCK_Y ) { + draw_2d_arrow(radius, false, 1); + draw_2d_arrow(radius, false, 3); + draw_2d_arrow(radius, true, 0); + draw_2d_arrow(radius, true, 2); + } + else { + draw_2d_arrow(radius, true, 0); + draw_2d_arrow(radius, true, 1); + draw_2d_arrow(radius, true, 2); + draw_2d_arrow(radius, true, 3); + } + } + else { + draw_2d_arrow(radius, false, 0); + draw_2d_arrow(radius, false, 1); + draw_2d_arrow(radius, false, 2); + draw_2d_arrow(radius, false, 3); + } + + return; +} + + +/*************************** GLUI_Translation::draw_2d_arrow() **************/ +/* ori: 0=up, 1=left, 2=down, 3=right */ +/* */ +/* */ +/* 0, y2 */ +/* / \ */ +/* / \ */ +/* / \ */ +/* / \ */ +/* / \ */ +/* / \ */ +/* / \ */ +/* / \ */ +/* -x2,y1 -x1b,y1 x1b,y1 x2,y1 */ +/* | | */ +/* | | */ +/* | | */ +/* | | */ +/* | | */ +/* -x1a,y0 x1a,y0 */ +/* */ + + +void GLUI_Translation::draw_2d_arrow( int radius, int filled, int orientation ) +{ + float x1 = .2, x2 = .4, y1 = .54, y2 = .94, y0; + float x1a, x1b; +/* + vec3 col1( 0.0, 0.0, 0.0 ), col2( .45, .45, .45 ), + col3( .7, .7, .7 ), col4( 1.0, 1.0, 1.0 ); + vec3 c1, c2, c3, c4, c5, c6; +*/ + vec3 white(1.0,1.0,1.0), black(0.0,0.0,0.0), gray(.45,.45,.45), + bkgd(.7,.7,.7); + int c_off=0; /* color index offset */ + + if ( glui ) + bkgd.set(glui->bkgd_color_f[0], + glui->bkgd_color_f[1], + glui->bkgd_color_f[2]); + + /* bkgd[0] = 255.0; bkgd[1] = 0; */ + + /** The following 8 colors define the shading of an octagon, in + clockwise order, starting from the upstroke on the left **/ + /** This is for an outside and inside octagons **/ + vec3 colors_out[]={white, white, white, gray, black, black, black, gray}; + vec3 colors_in[] ={bkgd,white,bkgd,gray,gray,gray,gray,gray}; + +#define SET_COL_OUT(i) glColor3fv((float*) &colors_out[(i)%8][0]); +#define SET_COL_IN(i) glColor3fv((float*) &colors_in[(i)%8][0]); + + x1 = (float)radius * .2; + x2 = x1 * 2; + y1 = (float)radius * .54; + y2 = y1 + x2; + x1a = x1; + x1b = x1; + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + +#define DRAW_SEG( xa,ya,xb,yb ) glVertex2f(xa,ya); glVertex2f(xb,yb); + + glScalef( -1.0, 1.0, 1.0 ); + + if ( orientation == 2 ) { + c_off = 4; + } + else if ( orientation == 0 ) { + c_off = 0; + glRotatef( 180.0, 0.0, 0.0, 1.0 ); + } + else if ( orientation == 1 ) { + c_off = 2; + glRotatef( 90.0, 0.0, 0.0, 1.0 ); + } + else if ( orientation == 3 ) { + c_off = 6; + glRotatef( -90.0, 0.0, 0.0, 1.0 ); + } + + if ( trans_type == GLUI_TRANSLATION_Z ) + y0 = 0.0; + else if ( trans_type == GLUI_TRANSLATION_XY ) + y0 = x1; + else + y0 = 0.0; + + + if ( trans_type == GLUI_TRANSLATION_Z ) { + if ( orientation == 0 ) { + y1 += 2.0; + y2 += 0.0; + + x1b -= 2.0; + x2 -= 2.0; + x1a += 2.0; + } + else if ( orientation == 2 ) { + y1 -= 6.0; + x1a += 2.0; + x1b += 4.0; + x2 += 6.0; + } + } + + /*** Fill in inside of arrow ***/ + if ( NOT filled ) { /*** Means button is up - control is not clicked ***/ + /*glColor3f( .8, .8, .8 ); */ + set_to_bkgd_color(); + glColor3f( bkgd[0]+.07, bkgd[1]+.07, bkgd[2]+.07 ); + } + else { /*** Button is down on control ***/ + glColor3f( .6, .6, .6 ); + c_off += 4; /* Indents the shadows - goes from a raised look to embossed */ + } + + /*** Check if control is enabled or not ***/ + if ( NOT enabled ) { + set_to_bkgd_color(); + /*c_off += 4; -- Indents the shadows - goes from a raised look to embossed */ + colors_out[0] = colors_out[1] = colors_out[2] = colors_out[7] = gray; + colors_out[3] = colors_out[4] = colors_out[5] = colors_out[6] = white; + colors_in[0] = colors_in[1] = colors_in[2] = colors_in[7] = white; + colors_in[3] = colors_in[4] = colors_in[5] = colors_in[6] = gray; + + } + + glBegin( GL_POLYGON ); + glVertex2f( 0.0, 0.0 ); glVertex2f( -x1a, 0.0 ); + glVertex2f( -x1a, 0.0 ); glVertex2f( -x1b, y1 ); + glVertex2f( x1b, y1); glVertex2f( x1a, 0.0 ); + glVertex2f( x1a, 0.0 ); glVertex2f( 0.0, 0.0 ); + glEnd(); + glBegin( GL_TRIANGLES ); + glVertex2f( -x2, y1 ); glVertex2f( 0.0, y2 ); glVertex2f( x2, y1 ); + glEnd(); + + glLineWidth( 1.0 ); + /*** Draw arrow outline ***/ + glBegin( GL_LINES ); + + SET_COL_IN(1+c_off); DRAW_SEG( 0.0, y2-1.0, -x2, y1-1.0 ); + SET_COL_IN(6+c_off); DRAW_SEG( -x2+2.0, y1+1.0, -x1b+1.0, y1+1.0 ); + SET_COL_IN(0+c_off); DRAW_SEG( -x1b+1.0, y1+1.0, -x1a+1.0, y0 ); + SET_COL_IN(3+c_off); DRAW_SEG( 0.0, y2-1.0, x2, y1-1.0 ); + SET_COL_IN(6+c_off); DRAW_SEG( x2-1.0, y1+1.0, x1b-1.0, y1+1.0 ); + SET_COL_IN(4+c_off); DRAW_SEG( x1b-1.0, y1+1.0, x1a-1.0, y0 ); + + SET_COL_OUT(0+c_off); DRAW_SEG( -x1a, y0, -x1b, y1 ); + SET_COL_OUT(6+c_off); DRAW_SEG( -x1b, y1, -x2, y1 ); + SET_COL_OUT(1+c_off); DRAW_SEG( -x2, y1, 0.0, y2 ); + SET_COL_OUT(3+c_off); DRAW_SEG( 0.0, y2, x2, y1 ); + SET_COL_OUT(6+c_off); DRAW_SEG( x2, y1, x1b, y1 ); + SET_COL_OUT(4+c_off); DRAW_SEG( x1b, y1, x1a, y0 ); + + glEnd(); + +#undef DRAW_SEG + + glPopMatrix(); +} + + +/*************************** GLUI_Translation::get_mouse_code() *************/ + +int GLUI_Translation::get_mouse_code( int x, int y ) +{ + if ( x == 0 AND y < 0 ) + return GLUI_TRANSLATION_MOUSE_DOWN; + else if ( x == 0 AND y > 0 ) + return GLUI_TRANSLATION_MOUSE_UP; + else if ( x > 0 AND y == 0 ) + return GLUI_TRANSLATION_MOUSE_LEFT; + else if ( x < 0 AND y == 0 ) + return GLUI_TRANSLATION_MOUSE_RIGHT; + else if ( x < 0 AND y < 0 ) + return GLUI_TRANSLATION_MOUSE_DOWN_LEFT; + else if ( x < 0 AND y > 0 ) + return GLUI_TRANSLATION_MOUSE_DOWN_RIGHT; + else if ( x > 0 AND y < 0 ) + return GLUI_TRANSLATION_MOUSE_UP_LEFT; + else if ( x > 0 AND y > 0 ) + return GLUI_TRANSLATION_MOUSE_UP_RIGHT; + + + return GLUI_TRANSLATION_MOUSE_NONE; +} + + +/*********************************** GLUI_Translation::set_x() ******/ + +void GLUI_Translation::set_x( float val ) +{ + set_one_val( val, 0 ); +} + + +/*********************************** GLUI_Translation::set_y() ******/ + +void GLUI_Translation::set_y( float val ) +{ + if ( trans_type == GLUI_TRANSLATION_XY ) + set_one_val( val, 1 ); + else + set_one_val( val, 0 ); +} + + +/*********************************** GLUI_Translation::set_z() ******/ + +void GLUI_Translation::set_z( float val ) +{ + set_one_val( val, 0 ); +} + + +/******************************* GLUI_Translation::set_one_val() ****/ + +void GLUI_Translation::set_one_val( float val, int index ) +{ + float *fp; + + float_array_val[index] = val; /* set value in array */ + + /*** The code below is like output_live, except it only operates on + a single member of the float array (given by 'index') instead of + outputting the entire array ****/ + + if ( ptr_val == NULL OR NOT live_inited ) + return; + + fp = (float*) ptr_val; + fp[index] = float_array_val[index]; + last_live_float_array[index] = float_array_val[index]; + + /** Update the main gfx window? **/ + if ( this->glui != NULL ) { + this->glui->post_update_main_gfx(); + } +} diff --git a/tests/Box2D_v2.2.1/glui/glui_tree.cpp b/tests/Box2D_v2.2.1/glui/glui_tree.cpp new file mode 100755 index 0000000000000..1ed456d52ce41 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_tree.cpp @@ -0,0 +1,278 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_panel.cpp - GLUI_Panel control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + This program is freely distributable without licensing fees and is + provided without guarantee or warrantee expressed or implied. This + program is -not- in the public domain. + +*****************************************************************************/ + +#include "glui_internal_control.h" + + +/****************************** GLUI_Tree::GLUI_Tree() **********/ +GLUI_Tree::GLUI_Tree(GLUI_Node *parent, const char *name, + int open, int inset) +{ + common_init(); + GLUI_StaticText *inset_label; + GLUI_Column *col; + + this->set_name( name ); + this->user_id = -1; + + if ( NOT open ) { + this->is_open = false; + this->h = GLUI_DEFAULT_CONTROL_HEIGHT + 7; + } + + parent->add_control( this ); + inset_label = new GLUI_StaticText(this,""); + inset_label->set_w(inset); + col = new GLUI_Column(this,true); + this->set_column(col); + this->set_alignment(GLUI_ALIGN_LEFT); +} + + +/****************************** GLUI_Tree::open() **********/ + +void GLUI_Tree::open( void ) +{ + if ( is_open ) + return; + is_open = true; + + GLUI_DRAWINGSENTINAL_IDIOM + + child_head = collapsed_node.child_head; + child_tail = collapsed_node.child_tail; + + collapsed_node.child_head = NULL; + collapsed_node.child_tail = NULL; + + if ( child_head != NULL ) { + ((GLUI_Control*) child_head)->unhide_internal( true ); + } + + glui->refresh(); +} + + +/****************************** GLUI_Tree::close() **********/ + +void GLUI_Tree::close( void ) +{ + if ( NOT glui ) + return; + + if ( NOT is_open ) + return; + is_open = false; + + GLUI_DRAWINGSENTINAL_IDIOM + + if ( child_head != NULL ) { + ((GLUI_Control*) child_head)->hide_internal( true ); + } + + collapsed_node.child_head = first_child(); + collapsed_node.child_tail = last_child(); + + child_head = NULL; + child_tail = NULL; + + this->h = GLUI_DEFAULT_CONTROL_HEIGHT + 7; + + glui->refresh(); +} + + +/**************************** GLUI_Tree::mouse_down_handler() **********/ + + +int GLUI_Tree::mouse_down_handler( int local_x, int local_y ) +{ + if ( local_y - y_abs > 18 ) { + initially_inside = currently_inside = false; + return false; + } + + currently_inside = true; + initially_inside = true; + redraw(); + + return false; +} + +/**************************** GLUI_Tree::mouse_held_down_handler() ****/ + +int GLUI_Tree::mouse_held_down_handler( + int local_x, int local_y, + bool new_inside ) +{ + if ( NOT initially_inside ) + return false; + + if ( local_y - y_abs> 18 ) + new_inside = false; + + if (currently_inside != new_inside) + redraw(); + + return false; +} + + +/**************************** GLUI_Tree::mouse_down_handler() **********/ + +int GLUI_Tree::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + if ( currently_inside ) { + if ( is_open ) + close(); + else + open(); + } + + currently_inside = false; + initially_inside = false; + redraw(); + + return false; +} + + +/********************************* GLUI_Tree::draw() ***********/ + +void GLUI_Tree::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int left, right, top, bottom, delta_x; + + left = 5; + right = w-left; + top = 3; + bottom = 3+16; + delta_x = 0; + + glui->draw_raised_box( left, top, 16, 16 ); + + if ( glui ) + glColor3ub(glui->bkgd_color.r,glui->bkgd_color.g,glui->bkgd_color.b); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( left+17, top+1 ); glVertex2i( right-1, top+1 ); + glVertex2i( right-1, bottom-1 ); glVertex2i( left+17, bottom-1 ); + glEnd(); + + if (format & GLUI_TREEPANEL_DISPLAY_HIERARCHY) { + delta_x = string_width( level_name ) + char_width(' '); + glColor3f( lred, lgreen, lblue); /* The hierarchy is drawn in bold */ + glRasterPos2i(left + 25, top + 11); + draw_string(level_name); + glRasterPos2i(left + 24, top + 11); + draw_string(level_name); + } + + draw_name( delta_x+left+24, top+11 ); + + if ( active ) + draw_active_box( left+22, delta_x+left+string_width( name )+32, + top, bottom-2 ); + + + /** Draw '+' or '-' **/ + + glBegin( GL_LINES ); + if ( is_open ) { + if ( enabled ) + if (is_current) + glColor3f( 0, 0, 1 ); + else + glColor3f( 0.0, 0.0, 0.0 ); + else + glColor3f( 0.5, 0.5, 0.5 ); + glVertex2i(left+4,(top+bottom)/2); glVertex2i(left+13,(top+bottom)/2); + + glColor3f( 1.0, 1.0, 1.0 ); + glVertex2i(left+4,1+(top+bottom)/2);glVertex2i(left+13,1+(top+bottom)/2); + } + else + { + glColor3f( 1.0, 1.0, 1.0 ); + glVertex2i(left+9,top+3); glVertex2i(left+9,bottom-4); + glVertex2i(left+4,(top+bottom)/2); glVertex2i(left+13,(top+bottom)/2); + + if ( enabled ) + if (is_current) + glColor3f( 0, 0, 1 ); + else + glColor3f( 0.0, 0.0, 0.0 ); + else + glColor3f( 0.5, 0.5, 0.5 ); + glVertex2i(left+4,-1+(top+bottom)/2); + glVertex2i(left+13,-1+(top+bottom)/2); + glVertex2i(left+8,top+3); + glVertex2i(left+8,bottom-4); + } + glEnd(); + + glLineWidth( 1.0 ); + + if (currently_inside) draw_pressed(); +} + + +/***************************** GLUI_Tree::update_size() **********/ + +void GLUI_Tree::update_size( void ) +{ + int text_size = 0, delta_x = 0; + + if ( NOT glui ) + return; + + text_size = string_width(name); + + if (format & GLUI_TREEPANEL_DISPLAY_HIERARCHY) { + delta_x = string_width( level_name ); + } + + if ( w < text_size + 36 + delta_x) + w = text_size + 36 + delta_x; +} + + +/**************************** GLUI_Tree::draw_pressed() ***********/ + +void GLUI_Tree::draw_pressed( void ) +{ + int left, right, top, bottom; + + left = 5; + right = w-left; + top = 3; + bottom = 3+16; + + glColor3f( 0.0, 0.0, 0.0 ); + + glBegin( GL_LINE_LOOP ); + glVertex2i( left, top ); glVertex2i( right, top ); + glVertex2i( right, bottom ); glVertex2i( left,bottom ); + glEnd(); + + glBegin( GL_LINE_LOOP ); + glVertex2i( left+1, top+1 ); glVertex2i( right-1, top+1 ); + glVertex2i( right-1, bottom-1 ); glVertex2i( left+1,bottom-1 ); + glEnd(); +} diff --git a/tests/Box2D_v2.2.1/glui/glui_treepanel.cpp b/tests/Box2D_v2.2.1/glui/glui_treepanel.cpp new file mode 100755 index 0000000000000..4849aed494c80 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_treepanel.cpp @@ -0,0 +1,387 @@ +#include "glui.h" + + +/****************************** GLUI_TreePanel::GLUI_TreePanel() *********/ + +GLUI_TreePanel::GLUI_TreePanel(GLUI_Node *parent, const char *name, + bool open, int inset) +{ + common_init(); + + set_name( name ); + user_id = -1; + + if ( !open ) { + is_open = false; + h = GLUI_DEFAULT_CONTROL_HEIGHT + 7; + } + + parent->add_control( this ); +} + +/****************************** GLUI_TreePanel::set_color() *********/ + +void GLUI_TreePanel::set_color(float r, float g, float b) +{ + red = r; + green = g; + blue = b; + redraw(); +} + +/************************ GLUI_TreePanel::set_level_color() *********/ + +void GLUI_TreePanel::set_level_color(float r, float g, float b) +{ + lred = r; + lgreen = g; + lblue = b; + redraw(); +} + +/****************************** GLUI_TreePanel::ab() *********/ + +/* Adds branch to curr_root */ +GLUI_Tree *GLUI_TreePanel::ab(const char *name, GLUI_Tree *root) +{ + GLUI_Tree *temp; + + + if (root != NULL) { + resetToRoot(root); + } + + temp = new GLUI_Tree(curr_root, name); + initNode(temp); + formatNode(temp); + + curr_root = temp; + curr_branch = NULL; /* Currently at leaf */ + + if (dynamic_cast(temp)) + ((GLUI_Tree *)temp)->set_current(true); + //refresh(); + // glui->deactivate_current_control(); + //glui->activate_control( temp, GLUI_ACTIVATE_TAB ); + return temp; + +} + +/****************************** GLUI_TreePanel::fb() *********/ + +/* Goes up one level, resets curr_root and curr_branch to parents*/ +void GLUI_TreePanel::fb(GLUI_Tree *branch) +{ + if (((GLUI_Panel *)branch) == ((GLUI_Panel *)this)) + return; + + if (((GLUI_Panel *)curr_branch) == ((GLUI_Panel *)this)) { + resetToRoot(); + return; + } + if (((GLUI_Panel *)curr_root) == ((GLUI_Panel *)this)) { + resetToRoot(); + return; + } + + if (branch != NULL) { + + if ( dynamic_cast(branch) ) + ((GLUI_Tree *)branch)->set_current(false); + + curr_branch = (GLUI_Tree *)branch->next(); + curr_root = (GLUI_Panel *)branch->parent(); + + if (curr_branch == NULL && (curr_root->collapsed_node).first_child() != NULL) + curr_branch = (GLUI_Tree *)(curr_root->collapsed_node).first_child(); + + if ( dynamic_cast(curr_root) ) + ((GLUI_Tree *)curr_root)->set_current(true); + + } else { + if (curr_root != NULL) { /* up one parent */ + + if (dynamic_cast(curr_root)) + ((GLUI_Tree *)curr_root)->set_current(false); + + curr_branch = (GLUI_Tree *) curr_root->next(); + curr_root = (GLUI_Panel *) curr_root->parent(); + + if (curr_branch == NULL && (curr_root->collapsed_node).first_child() != NULL) + curr_branch = (GLUI_Tree *)(curr_root->collapsed_node).first_child(); + + if (dynamic_cast(curr_root)) + ((GLUI_Tree *)curr_root)->set_current(true); + + } + + } + //refresh(); +} + + +/****************************** GLUI_TreePanel::refresh() *********/ + +void GLUI_TreePanel::refresh() +{ + glui->deactivate_current_control(); + glui->activate_control( curr_root, GLUI_ACTIVATE_TAB ); + + redraw(); +} + +/****************************** GLUI_TreePanel::initNode() *********/ + +void GLUI_TreePanel::initNode(GLUI_Tree *temp) +{ + if (temp == NULL) + return; + int level = temp->get_level(); + int child_number = 1; + + GLUI_Tree *ptree = dynamic_cast(temp->parent()); + if (ptree) { + level = ptree->get_level() + 1; + GLUI_Tree *prevTree = dynamic_cast(temp->prev()); + if (prevTree) { + child_number = prevTree->get_child_number() + 1; + } + } else if (dynamic_cast(temp) && + dynamic_cast(temp->parent())) { + child_number = ++root_children; + } + temp->set_id(uniqueID()); // -1 if unset + temp->set_level(level); + temp->set_child_number(child_number); +} + +/****************************** GLUI_TreePanel::formatNode() *********/ + +void GLUI_TreePanel::formatNode(GLUI_Tree *temp) +{ + if (temp == NULL) + return; + int level = temp->get_level(); + int child_number = temp->get_child_number(); + GLUI_String level_name=""; + GLUI_String full_name=""; + + temp->level_name == ""; + + if (format & GLUI_TREEPANEL_DISPLAY_HIERARCHY) { + if (format & GLUI_TREEPANEL_HIERARCHY_LEVEL_ONLY) { + glui_format_str(level_name, "%d", level); + } + if (format & GLUI_TREEPANEL_HIERARCHY_NUMERICDOT) { + if ( dynamic_cast(temp->parent()) ) + glui_format_str(level_name, "%s.%d", + ((GLUI_Tree *)(temp->parent()))->level_name.c_str(), + child_number); + else + glui_format_str(level_name, "%d", child_number); + } + } + + temp->set_level_color(lred, lgreen, lblue); + temp->set_format(format); + temp->level_name = level_name; + + if (format & GLUI_TREEPANEL_ALTERNATE_COLOR) { + switch (level%8) { + case (7): temp->set_color(.5,.5,.5); break; + case (6): temp->set_color(.3,.5,.5); break; + case (5): temp->set_color(.5,.3,.5); break; + case (4): temp->set_color(.3,.3,.5); break; + case (3): temp->set_color(.5,.5,.3); break; + case (2): temp->set_color(.3,.5,.3); break; + case (1): temp->set_color(.5,.3,.3); break; + default: temp->set_color(.3,.3,.3); + } + } else { + temp->set_color(red,green,blue); + } + + if (format & GLUI_TREEPANEL_DISABLE_BAR) { + temp->disable_bar(); + } else { + if (format & GLUI_TREEPANEL_DISABLE_DEEPEST_BAR) { + temp->disable_bar(); + if ( dynamic_cast(curr_root) ) + ((GLUI_Tree *)curr_root)->enable_bar(); + } else + if (format & GLUI_TREEPANEL_CONNECT_CHILDREN_ONLY) { + temp->disable_bar(); + if (temp->prev() && dynamic_cast(temp->prev()) ) + { + ((GLUI_Tree *)temp->prev())->enable_bar(); + } + } + } +} + +/****************************** GLUI_TreePanel::update_all() *********/ + +void GLUI_TreePanel::update_all() +{ + printf("GLUI_TreePanel::update_all() doesn't work yet. - JVK\n"); + return; + GLUI_Panel *saved_root = curr_root; + GLUI_Tree *saved_branch = curr_branch; + root_children = 0; + resetToRoot(this); + if (curr_branch && dynamic_cast(curr_branch)) + formatNode((GLUI_Tree *)curr_branch); + next(); + while (curr_root && curr_branch != this->first_child()) { + if (curr_branch && dynamic_cast(curr_branch)) { + formatNode((GLUI_Tree *)curr_branch); + } + next(); + } + curr_root = saved_root; + curr_branch = saved_branch; +} + +/****************************** GLUI_TreePanel::expand_all() *********/ + +void GLUI_TreePanel::expand_all() +{ + GLUI_Panel *saved_root = curr_root; + GLUI_Tree *saved_branch = curr_branch; + + resetToRoot(this); + if (dynamic_cast(curr_root)) + ((GLUI_Tree*)curr_root)->open(); + next(); + while (curr_root != NULL && curr_branch != this->first_child()) { + if (dynamic_cast(curr_root)) + ((GLUI_Tree*)curr_root)->open(); + next(); + } + + curr_root = saved_root; + curr_branch = saved_branch; +} + +/****************************** GLUI_TreePanel::collapse_all() *********/ + +void GLUI_TreePanel::collapse_all() +{ + GLUI_Panel *saved_root = curr_root; + GLUI_Tree *saved_branch = curr_branch; + + resetToRoot(this); + next(); + while (curr_root != NULL && curr_branch != this->first_child()) { + if (dynamic_cast(curr_root) && + curr_branch == NULL) { /* we want to close everything leaf-first */ + ((GLUI_Tree*)curr_root)->close(); + /* Rather than simply next(), we need to manually move the + curr_root because this node has been moved to the + collapsed_node list */ + curr_branch = (GLUI_Tree *)curr_root->next(); + curr_root = (GLUI_Panel *)curr_root->parent(); + } else + next(); + } + + curr_root = saved_root; + curr_branch = saved_branch; + +} + +/****************************** GLUI_TreePanel::db() *********/ + +/* Deletes the curr_root */ +void GLUI_TreePanel::db(GLUI_Tree *root) +{ + GLUI_Tree *temp_branch; + GLUI_Panel *temp_root; + + if (((GLUI_Control *)root) == ((GLUI_Control *)this)) + return; + + if (root != NULL) { + curr_root = (GLUI_Tree *)root; + curr_branch = NULL; + } + + if (curr_root == NULL || ((GLUI_Panel *)curr_root) == ((GLUI_Panel *)this)) { + resetToRoot(); + return; + } + + + temp_branch = (GLUI_Tree *)curr_root->next(); /* Next branch, if any */ + temp_root = (GLUI_Panel *)curr_root->parent(); /* new root */ + curr_root->unlink(); + delete curr_root; + curr_branch = (GLUI_Tree *) temp_branch; + curr_root = (GLUI_Panel *) temp_root; + if (dynamic_cast(curr_root)) + ((GLUI_Tree *)curr_root)->open(); + + if ((format & GLUI_TREEPANEL_DISABLE_DEEPEST_BAR) == GLUI_TREEPANEL_DISABLE_DEEPEST_BAR) { + if (dynamic_cast(curr_root) && ((GLUI_Tree *)curr_root->next()) == NULL) + ((GLUI_Tree *)curr_root)->disable_bar(); + } + //refresh(); +} + +/****************************** GLUI_TreePanel::descendBranch() *********/ + +/* Finds the very last branch of curr_root, resets vars */ +void GLUI_TreePanel::descendBranch(GLUI_Panel *root) { + if (root) + resetToRoot(root); + else + resetToRoot(curr_root); + if (curr_branch != NULL && curr_branch != ((GLUI_Panel *)this)) { + if (dynamic_cast(curr_root)) + ((GLUI_Tree *)curr_root)->set_current(false); + descendBranch(curr_branch); + } +} + +/****************************** GLUI_TreePanel::next() *********/ + +void GLUI_TreePanel::next() +{ + if (curr_root == NULL) + resetToRoot(this); + + if (curr_branch == NULL && (curr_root->collapsed_node).first_child() != NULL) + curr_branch = (GLUI_Tree *)(curr_root->collapsed_node).first_child(); + + + if (curr_branch != NULL && curr_branch != ((GLUI_Panel *)this)) { /* Descend into branch */ + if (dynamic_cast(curr_root)) + ((GLUI_Tree *)curr_root)->set_current(false); + resetToRoot(curr_branch); + } else if (curr_branch == NULL) { + fb(NULL); /* Backup and move on */ + } +} + +/****************************** GLUI_TreePanel::resetToRoot() *********/ + +/* Resets curr_root and curr branch to TreePanel and lastChild */ +void GLUI_TreePanel::resetToRoot(GLUI_Panel *new_root) +{ + GLUI_Panel *root = this; + if (new_root != NULL) + root = new_root; + curr_root = root; + if (dynamic_cast(curr_root)) + ((GLUI_Tree *)curr_root)->set_current(true); + curr_branch = (GLUI_Tree *)root->first_child(); + + /* since Trees are collapsable, we need to check the collapsed nodes + in case the curr_root is collapsed */ + if (curr_branch == NULL && (root->collapsed_node).first_child() != NULL) { + curr_branch = (GLUI_Tree *)(root->collapsed_node).first_child(); + } + while (curr_branch && dynamic_cast(curr_branch)) { + curr_branch=(GLUI_Tree *)curr_branch->next(); + } +} diff --git a/tests/Box2D_v2.2.1/glui/glui_window.cpp b/tests/Box2D_v2.2.1/glui/glui_window.cpp new file mode 100755 index 0000000000000..8355978264038 --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/glui_window.cpp @@ -0,0 +1,44 @@ +/* + + glui_window.cpp - GLUI_Button control class + + GLUI User Interface Toolkit (LGPL) + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "glui.h" +#include "glui_internal.h" + +GLUI_Glut_Window::GLUI_Glut_Window() +: GLUI_Node(), + + glut_window_id(0), + glut_keyboard_CB(NULL), + glut_special_CB(NULL), + glut_reshape_CB(NULL), + glut_passive_motion_CB(NULL), + glut_mouse_CB(NULL), + glut_visibility_CB(NULL), + glut_motion_CB(NULL), + glut_display_CB(NULL), + glut_entry_CB(NULL) +{ +} diff --git a/tests/Box2D_v2.2.1/glui/quaternion.cpp b/tests/Box2D_v2.2.1/glui/quaternion.cpp new file mode 100755 index 0000000000000..3e80242af499b --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/quaternion.cpp @@ -0,0 +1,243 @@ +/*********************************************************************** + + quaternion.cpp - A quaternion class + + ------------------------------------------------------------------- + + GLUI User Interface Toolkit (LGPL) + Copyright (c) 1998 Paul Rademacher + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +************************************************************************ + + Feb 1998, Paul Rademacher (rademach@cs.unc.edu) + Oct 2003, Nigel Stewart - GLUI Code Cleaning + +************************************************************************/ + +#include "quaternion.h" +#include +#include "glui_internal.h" + +/******************************************* constructors **************/ + +quat::quat() +{ + *this = quat_identity(); +} + +quat::quat(const float x, const float y, const float z, const float w) +{ + v.set( x, y, z ); + s = w; +} + +quat::quat(const vec3 &_v, const float _s) +{ + set( _v, _s ); +} + +quat::quat(const float _s, const vec3 &_v) +{ + set( _v, _s ); +} + +quat::quat(const float *d) +{ + v[0] = d[0]; + v[1] = d[1]; + v[2] = d[2]; + s = d[3]; +} + +quat::quat(const double *d) +{ + v[0] = (float) d[0]; + v[1] = (float) d[1]; + v[2] = (float) d[2]; + s = (float) d[3]; +} + +quat::quat(const quat &q) +{ + v = q.v; + s = q.s; +} + +void quat::set(const vec3 &_v, const float _s) +{ + v = _v; + s = _s; +} + +quat &quat::operator=(const quat &q) +{ + v = q.v; + s = q.s; + return *this; +} + +/******** quat friends ************/ + +quat operator + (const quat &a, const quat &b) +{ + return quat( a.s+b.s, a.v+b.v ); +} + +quat operator - (const quat &a, const quat &b) +{ + return quat( a.s-b.s, a.v-b.v ); +} + +quat operator - (const quat &a ) +{ + return quat( -a.s, -a.v ); +} + +quat operator * ( const quat &a, const quat &b) +{ + return quat( a.s*b.s - a.v*b.v, a.s*b.v + b.s*a.v + a.v^b.v ); +} + +quat operator * ( const quat &a, const float t) +{ + return quat( a.v * t, a.s * t ); +} + +quat operator * ( const float t, const quat &a ) +{ + return quat( a.v * t, a.s * t ); +} + +mat4 quat::to_mat4() const +{ + float xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz; + + float t = 2.0f / (v*v + s*s); + + xs = v[VX]*t; ys = v[VY]*t; zs = v[VZ]*t; + wx = s*xs; wy = s*ys; wz = s*zs; + xx = v[VX]*xs; xy = v[VX]*ys; xz = v[VX]*zs; + yy = v[VY]*ys; yz = v[VY]*zs; zz = v[VZ]*zs; + + mat4 matrix( + 1.0f-(yy+zz), xy+wz, xz-wy, 0.0f, + xy-wz, 1.0f-(xx+zz), yz+wx, 0.0f, + xz+wy, yz-wx, 1.0f-(xx+yy), 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f ); + + return matrix; +} + +/************************************************* quat_identity() *****/ +/* Returns quaternion identity element */ + +quat quat_identity() +{ + return quat( vec3( 0.0, 0.0, 0.0 ), 1.0 ); +} + +/************************************************ quat_slerp() ********/ +/* Quaternion spherical interpolation */ + +quat quat_slerp(const quat &from, const quat &to, float t) +{ + quat to1; + float omega, cosom, sinom, scale0, scale1; + + /* calculate cosine */ + cosom = from.v * to.v + from.s + to.s; + + /* Adjust signs (if necessary) */ + if ( cosom < 0.0 ) + { + cosom = -cosom; + to1 = -to; + } + else + { + to1 = to; + } + + /* Calculate coefficients */ + if ((1.0 - cosom) > FUDGE ) + { + /* standard case (slerp) */ + omega = (float) acos( cosom ); + sinom = (float) sin( omega ); + scale0 = (float) sin((1.0 - t) * omega) / sinom; + scale1 = (float) sin(t * omega) / sinom; + } + else + { + /* 'from' and 'to' are very close - just do linear interpolation */ + scale0 = 1.0f - t; + scale1 = t; + } + + return scale0 * from + scale1 * to1; +} + +/********************************************** set_angle() ************/ +/* set rot angle (degrees) */ + +void quat::set_angle(float f) +{ + vec3 axis = get_axis(); + + s = (float) cos( DEG2RAD( f ) / 2.0 ); + + v = axis * (float) sin(DEG2RAD(f) / 2.0); +} + +/********************************************** scale_angle() ************/ +/* scale rot angle (degrees) */ + +void quat::scale_angle(float f) +{ + set_angle( f * get_angle() ); +} + +/********************************************** get_angle() ************/ +/* get rot angle (degrees). Assumes s is between -1 and 1 */ + +float quat::get_angle() const +{ + return (float) RAD2DEG( 2.0 * acos( s ) ); +} + +/********************************************* get_axis() **************/ + +vec3 quat::get_axis() const +{ + float scale = (float) sin( acos( s ) ); + + if ( scale < FUDGE AND scale > -FUDGE ) + return vec3( 0.0, 0.0, 0.0 ); + else + return v / scale; +} + +/******************************************* quat::print() ************/ + +void quat::print(FILE *dest, const char *name) const +{ + fprintf( dest, "%s: v:<%3.2f %3.2f %3.2f> s:%3.2f\n", + name, v[0], v[1], v[2], s ); +} diff --git a/tests/Box2D_v2.2.1/glui/quaternion.h b/tests/Box2D_v2.2.1/glui/quaternion.h new file mode 100755 index 0000000000000..8bd458232ad6f --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/quaternion.h @@ -0,0 +1,114 @@ +/**************************************************************************** + + quaternion.h - A quaternion class + + GLUI User Interface Toolkit (LGPL) + Copyright (c) 1998 Paul Rademacher + + --------------------------------------------------------------------- + + WWW: http://sourceforge.net/projects/glui/ + Forums: http://sourceforge.net/forum/?group_id=92496 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +#ifndef GLUI_QUATERNION_H +#define GLUI_QUATERNION_H + +#include "algebra3.h" +#include + +/* this line defines a new type: pointer to a function which returns a */ +/* float and takes as argument a float */ +typedef float (*V_FCT_PTR)(float); + +/**************************************************************** + * Quaternion * + ****************************************************************/ + +class quat +{ + /*protected: */ +public: + + vec3 v; /* vector component */ + float s; /* scalar component */ + + /*public: */ + + /* Constructors */ + + quat(); + quat(float x, float y, float z, float w); + quat(const vec3 &v, float s); + quat(float s, const vec3 &v); + quat(const float *d); /* copy from four-element float array */ + quat(const double *f); /* copy from four-element double array */ + quat(const quat &q); /* copy from other quat */ + + /* Assignment operators */ + + quat &operator = (const quat &v); /* assignment of a quat */ + quat &operator += (const quat &v); /* incrementation by a quat */ + quat &operator -= (const quat &v); /* decrementation by a quat */ + quat &operator *= (float d); /* multiplication by a constant */ + quat &operator /= (float d); /* division by a constant */ + + /* special functions */ + + float length() const; /* length of a quat */ + float length2() const; /* squared length of a quat */ + quat &normalize(); /* normalize a quat */ + quat &apply(V_FCT_PTR fct); /* apply a func. to each component */ + vec3 xform(const vec3 &v ); /* q*v*q-1 */ + mat4 to_mat4() const; + void set_angle(float f); /* set rot angle (degrees) */ + void scale_angle(float f); /* scale rot angle (degrees) */ + float get_angle() const; /* set rot angle (degrees) */ + vec3 get_axis() const; /* get axis */ + + void print( FILE *file, const char *name ) const; /* print to a file */ + + float &operator [] (int i); /* indexing */ + const float &operator [] (int i) const; /* indexing */ + + void set(float x, float y, float z); /* set quat */ + void set(const vec3 &v, float s); /* set quat */ + + /* friends */ + + friend quat operator - (const quat &v); /* -q1 */ + friend quat operator + (const quat &a, const quat &b); /* q1 + q2 */ + friend quat operator - (const quat &a, const quat &b); /* q1 - q2 */ + friend quat operator * (const quat &a, float d); /* q1 * 3.0 */ + friend quat operator * (float d, const quat &a); /* 3.0 * q1 */ + friend quat operator * (const quat &a, const quat &b); /* q1 * q2 */ + friend quat operator / (const quat &a, float d); /* q1 / 3.0 */ + friend int operator == (const quat &a, const quat &b); /* q1 == q2 ? */ + friend int operator != (const quat &a, const quat &b); /* q1 != q2 ? */ + friend void swap(quat &a, quat &b); /* swap q1 &q2 */ + /*friend quat min(const quat &a, const quat &b); -- min(q1, q2) */ + /*friend quat max(const quat &a, const quat &b); -- max(q1, q2) */ + friend quat prod(const quat &a, const quat &b); /* term by term mult*/ +}; + +/* Utility functions */ + +quat quat_identity(); /* Returns quaternion identity element */ +quat quat_slerp(const quat &from, const quat &to, float t); + +#endif diff --git a/tests/Box2D_v2.2.1/glui/readme.txt b/tests/Box2D_v2.2.1/glui/readme.txt new file mode 100755 index 0000000000000..43ba3ed526adf --- /dev/null +++ b/tests/Box2D_v2.2.1/glui/readme.txt @@ -0,0 +1,228 @@ +Welcome to the GLUI User Interface Library, v2.3! +March 22, 2005 +------------------------------------------------- + +This distribution contains the latest community-maintained fork of the +GLUI Library. It is based on the GLUI v2.1 beta version from Paul +Rademacher (http://www.cs.unc.edu/~rademach/glui/) plus the +compatibility changes made by Nigel Stewart in his "GLUI v2.2" +(http://www.nigels.com/glt/glui) In accordance with the LGPL under +which the library is released (according to Paul's web page at least), +these changes are available to everyone in the community. + +WARNING: This version (2.3) introduces some incompatible changes with +previous versions!! + +CHANGES: + +---------------------------------- +- GLUI_String is now a std::string + This is the main source of most incopatibilities, but I felt it was + a necessary change, because the previous usage of a fixed-sized + buffer was just too unsafe. I myself was bitten a few times passing + a char* buffer of insufficient size into GLUI as a live variable. + It is still possible to use a char buffer, but it is not recommended. + + If you used GLUI_String before as a live var type, the easiest way + to get your code compiling again is to change those to "char + buf[300]". The better way, though, is to update your code to treat + it as a std::string. + + For instance, if you used to pass mystr to functions that take + 'const char*', now use mystr.c_str() method, instead. + If you used strcpy(mystr, b) to set the value, now just do mystr=b. + If you used sprintf(mystr,...) to set the value, now do + glui_format_string(mystr,...). + If you used to clear the string with mystr[0]='\0', now just clear + it with mystr="". + +---------------------------------- +- Enhanced GLUI_EditText + Control keys can be used for navigation and control. The bindings + are bash-like: Ctrl-B for previous char, Ctrl-F for forward char, etc. + bindings. Also control keys that aren't bound to commands are + simply ignored, whereas before they would be inserted as invisible + characters. + +---------------------------------- +- Added GLUI_CommandLine class + This is a GLUI_EditText with a history mechanism. + +---------------------------------- +- New, more object oriented construction API. + Now instead of calling + + glui->add_button_to_panel( panel, "my button", myid, mycallback ); + + you should just call the button constructor: + + new GLUI_Button( panel, "my button", myid, mycallback ); + + And similarly to add it to a GLUI instead of a panel, rather than: + + glui->add_button( glui, "my button", myid, mycallback ); + + just call the constructor with the GLUI as the first argument: + + new GLUI_Button( glui, "my button", myid, mycallback ); + + The old scheme is now deprecated, but still works. The benefit of + this new scheme is that now the GLUI class doesn't have to know + about all the different types of GLUI_Controls that exist. + Previously GLUI had to both know about all the controls, and know + how to initialize them. Now the responsibility for initialization + belongs to the GLUI_Control subclasses themselves, where it + belongs. Additionally it means that you can create your own + GLUI_Control subclasses which will be on equal footing with the + built-in controls, whereas before any user-created controls would + always be "second-class citizens" since they would have to be + constructed differently from the built-ins. + + +---------------------------------- +- Removed need for type-declaring arguments when argment type suffices. + This effects GLUI_Spinner and GLUI_EditText (and GLUI_CommandLine?). + + For example, instead of calling + + new GLUI_Spinner( glui, "myspin", GLUI_SPINNER_INT, &live_int_var ); + + you can just omit the GLUI_SPINNER_INT part, because the type of the + live_int_var tells the compiler which type you want. + + new GLUI_Spinner( glui, "myspin", &live_int_var ); + + If you're not using a live, var, you can still use the + GLUI_SPINNER_INT type argument. See glui.h for all the new + constructor signatures. Note this only works with the new + construction API, not with the old "add_blah_to_panel" style of + API. + +---------------------------------- +- GLUI_Rotation uses your matrix live-variable now. + GLUI used to ignore the matrix in your live variable. This version + doesn't ignore it, so you'll need to set it to the identity matrix + yourself if that's what you want it to start as. There could + probably be some improvements to this API, though. + +---------------------------------- +- Improvements to 'const' usage. + Most char*'s in GLUI functions used to be non-const even when the + functions did not modify the string. I changed everywhere + appropriate to use const char* instead. + +---------------------------------- +- Updated license info in the headers + Paul's web page says that GLUI is LGPL, but that wasn't declared in + the code itself. I've modified all the headers with the standard + LGPL notice. + +---------------------------------- +- Updated examples for the API changes + +---------------------------------- +- Created project files for Visual Studio .NET (MSVC7.1) + + +That's about it. Enjoy! + + +If you find yourself with too much time on your hands, the things I +think would be most useful for future improvements to GLUI would be: + +1. The GLUI_TextBox and GLUI_Tree definitely need some work, still. +2. Clipboard integration under Windows/X-Win. I have some code that + works on Win32 that I once integrated with GLUI, but I lost that + version somewhere. I still have the Win32 clipboard code, though + if anyone wants to work on integrating it. I have some X-Win + clipboard code, too, but I never got it working quite right. +3. Remove the dependency on GLUT, making the connection with window + system APIs into a more plug-in/adapter modular design. + So e.g. if you want to use GLUT, you'd link with the GLUI lib and a + GLUI_GLUT lib, and call one extra GLUI_glut_init() function or + something. + + +Definitly consider submitting a patch if you've made some nice improvements +to GLUI. Hopefully being an LGPL sourceforge project will attract some new +interest to the GLUI project. + +Bill Baxter +baxter +at +cs unc edu + +================================================= +JOHN KEW'S ADDITIONS (March 2005) +================================================= + +Thanks to John Kew of Natural Solutions Inc., +there are some new widgets. These are demonstrated in example6.cpp. + +The new widgets are: + +* GLUI_Scrollbar - A scrollbar slider widget +* GLUI_TextBox - A multi-line text widget +* GLUI_List - A static choice list +* GLUI_FileBrowser - A simple filebrowser based on GLUI_List +* GLUI_Tree - Hierarchical tree widget +* GLUI_TreePanel - Manager for the tree widget + +And one other change: + +* GLUI_Rollout has optional embossed border + +================================================= +PAUL'S ORIGINAL GLUI 2.0/2.1 README +================================================= + +Welcome to the GLUI User Interface Library, v2.0 beta! +------------------------------------------------- + +This distribution contains the full GLUI sources, as well as 5 example +programs. You'll find the full manual under "glui_manual.pdf". The +GLUI web page is at + + http://www.cs.unc.edu/~rademach/glui + + + ---------- Windows ---------- + +The directory 'msvc' contains a Visual C++ workspace entitled +'glui.dsw'. To recompile the library and examples, open this +workspace and run the menu command "Build:Batch Build:Build". The 3 +executables will be in the 'bin' directory, and the library in the +'lib' directory. + +To create a new Windows executable using GLUI, create a "Win32 Console +Application" in VC++, add the GLUI library (in 'msvc/lib/glui32.lib'), +and add the OpenGL libs: + + glui32.lib glut32.lib glu32.lib opengl32.lib (Microsoft OpenGL) + +Include the file "glui.h" in any file that uses the GLUI library. + + + ---------- Unix ---------- + +An SGI/HP makefile is found in the file 'makefile' (certain lines may need +to be commented/uncommented). + +To include GLUI in your own apps, add the glui library to your +makefile (before the glut library 'libglut.a'), and include "glui.h" +in your sources. + + + +---------------------------------------------------------------------- + +Please let me know what you think, what you'd like to change or add, +and especially what bugs you encounter. Also, please send me your +e-mail so I can add you to a mailing list for updates. + +Good luck, and thanks for trying this out! + +Paul Rademacher +rademach +at +cs unc edu \ No newline at end of file diff --git a/tests/Box2D_v2.2.1/premake4.lua b/tests/Box2D_v2.2.1/premake4.lua new file mode 100755 index 0000000000000..dec685c3ef943 --- /dev/null +++ b/tests/Box2D_v2.2.1/premake4.lua @@ -0,0 +1,67 @@ +-- Box2D premake script. +-- http://industriousone.com/premake + +local action = _ACTION or "" + +solution "Box2D" + location ( "Build/" .. action ) + configurations { "Debug", "Release" } + + configuration "vs*" + defines { "_CRT_SECURE_NO_WARNINGS" } + + configuration "Debug" + targetdir ( "Build/" .. action .. "/bin/Debug" ) + flags { "Symbols" } + + configuration "Release" + targetdir ( "Build/" .. action .. "/bin/Release" ) + defines { "NDEBUG" } + flags { "Optimize" } + + project "Box2D" + kind "StaticLib" + language "C++" + files { "Box2D/**.h", "Box2D/**.cpp" } + vpaths { [""] = "Box2D" } + includedirs { "." } + + if os.get == "windows" then + project "FreeGLUT" + kind "StaticLib" + language "C" + files { "freeglut/*.h", "freeglut/*.c" } + vpaths { ["Headers"] = "**.h", ["Sources"] = "**.c" } + end + + project "GLUI" + kind "StaticLib" + language "C++" + files { "glui/*.h", "glui/*.cpp" } + vpaths { ["Headers"] = "**.h", ["Sources"] = "**.cpp" } + includedirs { "." } + configuration { "windows" } + buildoptions { "/W1" } + + project "HelloWorld" + kind "ConsoleApp" + language "C++" + files { "HelloWorld/Helloworld.cpp" } + vpaths { [""] = "HelloWorld" } + includedirs { "." } + links { "Box2D" } + + project "Testbed" + kind "ConsoleApp" + language "C++" + files { "Testbed/**.h", "Testbed/**.cpp" } + vpaths { [""] = "Testbed" } + includedirs { "." } + links { "Box2D", "GLUI" } + configuration { "windows" } + links { "FreeGLUT", "glu32", "opengl32", "winmm" } + configuration { "macosx" } + linkoptions { "-framework OpenGL -framework GLUT" } + configuration { "not windows", "not macosx" } + links { "X11", "GL", "GLU", "GLUT" } + From a4a20535e79f10c553b685b188fcfd6af12fac07 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 10 Apr 2013 15:45:53 -0700 Subject: [PATCH 114/544] work towards box2d benchmark --- tests/Box2D_v2.2.1/Benchmark.cpp | 122 +++++++++++++++++++++++++++++++ tests/Box2D_v2.2.1/Makefile | 63 ++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 tests/Box2D_v2.2.1/Benchmark.cpp create mode 100644 tests/Box2D_v2.2.1/Makefile diff --git a/tests/Box2D_v2.2.1/Benchmark.cpp b/tests/Box2D_v2.2.1/Benchmark.cpp new file mode 100644 index 0000000000000..914c13a0e584c --- /dev/null +++ b/tests/Box2D_v2.2.1/Benchmark.cpp @@ -0,0 +1,122 @@ + + +// +// Based on joelgwebber's Box2D benchmarks, +// https://github.com/joelgwebber/bench2d/blob/master/c/Bench2d.cpp +// + + +// Settings ===================== +// Turn this on to include the y-position of the top box in the output. +#define DEBUG 0 + +#define WARMUP 64 +#define FRAMES 256 + +typedef struct { + float mean; + float stddev; +} result_t; +// ============================== + + + +#include +#include +#include + +#include "Box2D/Box2D.h" +#include "Bench2d.h" + +using namespace std; + +const int e_count = 40; + +result_t measure(clock_t times[FRAMES]) { + float values[FRAMES]; + result_t r; + + float total = 0; + for (int i = 0; i < FRAMES; ++i) { + values[i] = (float)times[i] / CLOCKS_PER_SEC * 1000; + total += values[i]; + } + r.mean = total / FRAMES; + + float variance = 0; + for (int i = 0; i < FRAMES; ++i) { + float diff = values[i] - r.mean; + variance += diff * diff; + } + r.stddev = sqrt(variance / FRAMES); + + return r; +} + +result_t bench() { + // Define the gravity vector. + b2Vec2 gravity(0.0f, -10.0f); + + // Construct a world object, which will hold and simulate the rigid bodies. + b2World world(gravity); + world.SetAllowSleeping(false); + + { + b2BodyDef bd; + b2Body* ground = world.CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + b2Body* topBody; + + { + float32 a = 0.5f; + b2PolygonShape shape; + shape.SetAsBox(a, a); + + b2Vec2 x(-7.0f, 0.75f); + b2Vec2 y; + b2Vec2 deltaX(0.5625f, 1); + b2Vec2 deltaY(1.125f, 0.0f); + + for (int32 i = 0; i < e_count; ++i) { + y = x; + + for (int32 j = i; j < e_count; ++j) { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position = y; + b2Body* body = world.CreateBody(&bd); + body->CreateFixture(&shape, 5.0f); + + topBody = body; + + y += deltaY; + } + + x += deltaX; + } + } + + for (int32 i = 0; i < WARMUP; ++i) { + world.Step(1.0f/60.0f, 3, 3); + } + + clock_t times[FRAMES]; + for (int32 i = 0; i < FRAMES; ++i) { + clock_t start = clock(); + world.Step(1.0f/60.0f, 3, 3); + clock_t end = clock(); + times[i] = end - start; +#if DEBUG + printf("%f :: ", topBody->GetPosition().y); + printf("%f\n", (float32)(end - start) / CLOCKS_PER_SEC * 1000); +#endif + } + + return measure(times); +} + diff --git a/tests/Box2D_v2.2.1/Makefile b/tests/Box2D_v2.2.1/Makefile new file mode 100644 index 0000000000000..10f47ddb5d171 --- /dev/null +++ b/tests/Box2D_v2.2.1/Makefile @@ -0,0 +1,63 @@ +# Makefile for generating a Box2D library using Emscripten. + +O = Box2D_v2.2.1/Box2D +OBJECTS = \ + $(O)/Collision/b2BroadPhase.o \ + $(O)/Collision/b2CollideCircle.o \ + $(O)/Collision/b2CollideEdge.o \ + $(O)/Collision/b2CollidePolygon.o \ + $(O)/Collision/b2Collision.o \ + $(O)/Collision/b2Distance.o \ + $(O)/Collision/b2DynamicTree.o \ + $(O)/Collision/b2TimeOfImpact.o \ + $(O)/Collision/Shapes/b2ChainShape.o \ + $(O)/Collision/Shapes/b2CircleShape.o \ + $(O)/Collision/Shapes/b2EdgeShape.o \ + $(O)/Collision/Shapes/b2PolygonShape.o \ + $(O)/Common/b2BlockAllocator.o \ + $(O)/Common/b2Draw.o \ + $(O)/Common/b2Math.o \ + $(O)/Common/b2Settings.o \ + $(O)/Common/b2StackAllocator.o \ + $(O)/Common/b2Timer.o \ + $(O)/Dynamics/b2Body.o \ + $(O)/Dynamics/b2ContactManager.o \ + $(O)/Dynamics/b2Fixture.o \ + $(O)/Dynamics/b2Island.o \ + $(O)/Dynamics/b2World.o \ + $(O)/Dynamics/b2WorldCallbacks.o \ + $(O)/Dynamics/Contacts/b2ChainAndCircleContact.o \ + $(O)/Dynamics/Contacts/b2ChainAndPolygonContact.o \ + $(O)/Dynamics/Contacts/b2CircleContact.o \ + $(O)/Dynamics/Contacts/b2Contact.o \ + $(O)/Dynamics/Contacts/b2ContactSolver.o \ + $(O)/Dynamics/Contacts/b2EdgeAndCircleContact.o \ + $(O)/Dynamics/Contacts/b2EdgeAndPolygonContact.o \ + $(O)/Dynamics/Contacts/b2PolygonAndCircleContact.o \ + $(O)/Dynamics/Contacts/b2PolygonContact.o \ + $(O)/Dynamics/Joints/b2DistanceJoint.o \ + $(O)/Dynamics/Joints/b2FrictionJoint.o \ + $(O)/Dynamics/Joints/b2GearJoint.o \ + $(O)/Dynamics/Joints/b2Joint.o \ + $(O)/Dynamics/Joints/b2MouseJoint.o \ + $(O)/Dynamics/Joints/b2PrismaticJoint.o \ + $(O)/Dynamics/Joints/b2PulleyJoint.o \ + $(O)/Dynamics/Joints/b2RevoluteJoint.o \ + $(O)/Dynamics/Joints/b2RopeJoint.o \ + $(O)/Dynamics/Joints/b2WeldJoint.o \ + $(O)/Dynamics/Joints/b2WheelJoint.o \ + $(O)/Rope/b2Rope.o + +all: box2d.o + +OPTS = -O2 + +%.o: %.cpp + $(CXX) -IBox2D_v2.2.1 $< -o $@ $(OPTS) + +box2d.o: $(OBJECTS) + $(CXX) -o $@ $(OBJECTS) $(OPTS) + +clean: + rm box2d.o + From f84537c333524d0841923eaec66604584bf77326 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 10 Apr 2013 15:53:50 -0700 Subject: [PATCH 115/544] more work towards box2d benchmark --- tests/{Box2D_v2.2.1 => box2d}/Benchmark.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/Box2D/Box2D.h | 0 tests/{Box2D_v2.2.1 => box2d}/Box2D/Box2DConfig.cmake | 0 tests/{Box2D_v2.2.1 => box2d}/Box2D/CMakeLists.txt | 0 .../Box2D/Collision/Shapes/b2ChainShape.cpp | 0 .../Box2D/Collision/Shapes/b2ChainShape.h | 0 .../Box2D/Collision/Shapes/b2CircleShape.cpp | 0 .../Box2D/Collision/Shapes/b2CircleShape.h | 0 .../Box2D/Collision/Shapes/b2EdgeShape.cpp | 0 .../Box2D/Collision/Shapes/b2EdgeShape.h | 0 .../Box2D/Collision/Shapes/b2PolygonShape.cpp | 0 .../Box2D/Collision/Shapes/b2PolygonShape.h | 0 .../Box2D/Collision/Shapes/b2Shape.h | 0 .../Box2D/Collision/b2BroadPhase.cpp | 0 .../Box2D/Collision/b2BroadPhase.h | 0 .../Box2D/Collision/b2CollideCircle.cpp | 0 .../Box2D/Collision/b2CollideEdge.cpp | 0 .../Box2D/Collision/b2CollidePolygon.cpp | 0 .../Box2D/Collision/b2Collision.cpp | 0 .../Box2D/Collision/b2Collision.h | 0 .../Box2D/Collision/b2Distance.cpp | 0 .../Box2D/Collision/b2Distance.h | 0 .../Box2D/Collision/b2DynamicTree.cpp | 0 .../Box2D/Collision/b2DynamicTree.h | 0 .../Box2D/Collision/b2TimeOfImpact.cpp | 0 .../Box2D/Collision/b2TimeOfImpact.h | 0 .../Box2D/Common/b2BlockAllocator.cpp | 0 .../Box2D/Common/b2BlockAllocator.h | 0 tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Draw.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Draw.h | 0 .../Box2D/Common/b2GrowableStack.h | 0 tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Math.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Math.h | 0 .../Box2D/Common/b2Settings.cpp | 0 .../{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Settings.h | 0 .../Box2D/Common/b2StackAllocator.cpp | 0 .../Box2D/Common/b2StackAllocator.h | 0 .../{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Timer.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Timer.h | 0 .../Dynamics/Contacts/b2ChainAndCircleContact.cpp | 0 .../Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h | 0 .../Dynamics/Contacts/b2ChainAndPolygonContact.cpp | 0 .../Dynamics/Contacts/b2ChainAndPolygonContact.h | 0 .../Box2D/Dynamics/Contacts/b2CircleContact.cpp | 0 .../Box2D/Dynamics/Contacts/b2CircleContact.h | 0 .../Box2D/Dynamics/Contacts/b2Contact.cpp | 0 .../Box2D/Dynamics/Contacts/b2Contact.h | 0 .../Box2D/Dynamics/Contacts/b2ContactSolver.cpp | 0 .../Box2D/Dynamics/Contacts/b2ContactSolver.h | 0 .../Dynamics/Contacts/b2EdgeAndCircleContact.cpp | 0 .../Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h | 0 .../Dynamics/Contacts/b2EdgeAndPolygonContact.cpp | 0 .../Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h | 0 .../Dynamics/Contacts/b2PolygonAndCircleContact.cpp | 0 .../Dynamics/Contacts/b2PolygonAndCircleContact.h | 0 .../Box2D/Dynamics/Contacts/b2PolygonContact.cpp | 0 .../Box2D/Dynamics/Contacts/b2PolygonContact.h | 0 .../Box2D/Dynamics/Joints/b2DistanceJoint.cpp | 0 .../Box2D/Dynamics/Joints/b2DistanceJoint.h | 0 .../Box2D/Dynamics/Joints/b2FrictionJoint.cpp | 0 .../Box2D/Dynamics/Joints/b2FrictionJoint.h | 0 .../Box2D/Dynamics/Joints/b2GearJoint.cpp | 0 .../Box2D/Dynamics/Joints/b2GearJoint.h | 0 .../Box2D/Dynamics/Joints/b2Joint.cpp | 0 .../Box2D/Dynamics/Joints/b2Joint.h | 0 .../Box2D/Dynamics/Joints/b2MouseJoint.cpp | 0 .../Box2D/Dynamics/Joints/b2MouseJoint.h | 0 .../Box2D/Dynamics/Joints/b2PrismaticJoint.cpp | 0 .../Box2D/Dynamics/Joints/b2PrismaticJoint.h | 0 .../Box2D/Dynamics/Joints/b2PulleyJoint.cpp | 0 .../Box2D/Dynamics/Joints/b2PulleyJoint.h | 0 .../Box2D/Dynamics/Joints/b2RevoluteJoint.cpp | 0 .../Box2D/Dynamics/Joints/b2RevoluteJoint.h | 0 .../Box2D/Dynamics/Joints/b2RopeJoint.cpp | 0 .../Box2D/Dynamics/Joints/b2RopeJoint.h | 0 .../Box2D/Dynamics/Joints/b2WeldJoint.cpp | 0 .../Box2D/Dynamics/Joints/b2WeldJoint.h | 0 .../Box2D/Dynamics/Joints/b2WheelJoint.cpp | 0 .../Box2D/Dynamics/Joints/b2WheelJoint.h | 0 .../{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2Body.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2Body.h | 0 .../Box2D/Dynamics/b2ContactManager.cpp | 0 .../Box2D/Dynamics/b2ContactManager.h | 0 .../Box2D/Dynamics/b2Fixture.cpp | 0 .../Box2D/Dynamics/b2Fixture.h | 0 .../Box2D/Dynamics/b2Island.cpp | 0 .../{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2Island.h | 0 .../Box2D/Dynamics/b2TimeStep.h | 0 .../Box2D/Dynamics/b2World.cpp | 0 .../{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2World.h | 0 .../Box2D/Dynamics/b2WorldCallbacks.cpp | 0 .../Box2D/Dynamics/b2WorldCallbacks.h | 0 tests/{Box2D_v2.2.1 => box2d}/Box2D/Rope/b2Rope.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/Box2D/Rope/b2Rope.h | 0 tests/{Box2D_v2.2.1 => box2d}/Build/Readme.txt | 0 tests/{Box2D_v2.2.1 => box2d}/Build/vs2010/Box2D.sln | 0 .../Build/vs2010/Box2D.vcxproj | 0 .../Build/vs2010/Box2D.vcxproj.filters | 0 .../Build/vs2010/FreeGLUT.vcxproj | 0 .../Build/vs2010/FreeGLUT.vcxproj.filters | 0 .../{Box2D_v2.2.1 => box2d}/Build/vs2010/GLUI.vcxproj | 0 .../Build/vs2010/GLUI.vcxproj.filters | 0 .../Build/vs2010/HelloWorld.vcxproj | 0 .../Build/vs2010/HelloWorld.vcxproj.filters | 0 .../Build/vs2010/Testbed.vcxproj | 0 .../Build/vs2010/Testbed.vcxproj.filters | 0 .../Build/xcode4/Box2D.xcodeproj/project.pbxproj | 0 .../project.xcworkspace/contents.xcworkspacedata | 0 tests/{Box2D_v2.2.1 => box2d}/Building.txt | 0 tests/{Box2D_v2.2.1 => box2d}/CMakeLists.txt | 0 .../{Box2D_v2.2.1 => box2d}/HelloWorld/CMakeLists.txt | 0 .../{Box2D_v2.2.1 => box2d}/HelloWorld/HelloWorld.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/License.txt | 0 tests/{Box2D_v2.2.1 => box2d}/Makefile | 4 ++-- tests/{Box2D_v2.2.1 => box2d}/Readme.txt | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/CMakeLists.txt | 0 .../Testbed/Framework/Main.cpp | 0 .../Testbed/Framework/Render.cpp | 0 .../Testbed/Framework/Render.h | 0 .../Testbed/Framework/Test.cpp | 0 .../{Box2D_v2.2.1 => box2d}/Testbed/Framework/Test.h | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/AddPair.h | 0 .../Testbed/Tests/ApplyForce.h | 0 .../{Box2D_v2.2.1 => box2d}/Testbed/Tests/BodyTypes.h | 0 .../{Box2D_v2.2.1 => box2d}/Testbed/Tests/Breakable.h | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Bridge.h | 0 .../Testbed/Tests/BulletTest.h | 0 .../Testbed/Tests/Cantilever.h | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Car.h | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Chain.h | 0 .../Testbed/Tests/CharacterCollision.h | 0 .../Testbed/Tests/CollisionFiltering.h | 0 .../Testbed/Tests/CollisionProcessing.h | 0 .../Testbed/Tests/CompoundShapes.h | 0 .../{Box2D_v2.2.1 => box2d}/Testbed/Tests/Confined.h | 0 .../Testbed/Tests/ContinuousTest.h | 0 .../Testbed/Tests/DistanceTest.h | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Dominos.h | 0 .../{Box2D_v2.2.1 => box2d}/Testbed/Tests/DumpShell.h | 0 .../Testbed/Tests/DynamicTreeTest.h | 0 .../Testbed/Tests/EdgeShapes.h | 0 .../{Box2D_v2.2.1 => box2d}/Testbed/Tests/EdgeTest.h | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Gears.h | 0 .../Testbed/Tests/OneSidedPlatform.h | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Pinball.h | 0 .../Testbed/Tests/PolyCollision.h | 0 .../Testbed/Tests/PolyShapes.h | 0 .../{Box2D_v2.2.1 => box2d}/Testbed/Tests/Prismatic.h | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Pulleys.h | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Pyramid.h | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/RayCast.h | 0 .../{Box2D_v2.2.1 => box2d}/Testbed/Tests/Revolute.h | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Rope.h | 0 .../{Box2D_v2.2.1 => box2d}/Testbed/Tests/RopeJoint.h | 0 .../Testbed/Tests/SensorTest.h | 0 .../Testbed/Tests/ShapeEditing.h | 0 .../Testbed/Tests/SliderCrank.h | 0 .../Testbed/Tests/SphereStack.h | 0 .../Testbed/Tests/TestEntries.cpp | 0 .../Testbed/Tests/TheoJansen.h | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Tiles.h | 0 .../Testbed/Tests/TimeOfImpact.h | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Tumbler.h | 0 .../Testbed/Tests/VaryingFriction.h | 0 .../Testbed/Tests/VaryingRestitution.h | 0 .../Testbed/Tests/VerticalStack.h | 0 tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Web.h | 0 tests/{Box2D_v2.2.1 => box2d}/freeglut/CMakeLists.txt | 0 tests/{Box2D_v2.2.1 => box2d}/freeglut/COPYING | 0 tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut.h | 0 .../freeglut/freeglut_callbacks.c | 0 .../freeglut/freeglut_cursor.c | 0 .../freeglut/freeglut_display.c | 0 tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_ext.c | 0 tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_ext.h | 0 .../{Box2D_v2.2.1 => box2d}/freeglut/freeglut_font.c | 0 .../freeglut/freeglut_font_data.c | 0 .../freeglut/freeglut_gamemode.c | 0 .../freeglut/freeglut_geometry.c | 0 .../freeglut/freeglut_glutfont_definitions.c | 0 .../{Box2D_v2.2.1 => box2d}/freeglut/freeglut_init.c | 0 .../freeglut/freeglut_input_devices.c | 0 .../freeglut/freeglut_internal.h | 0 .../freeglut/freeglut_joystick.c | 0 .../{Box2D_v2.2.1 => box2d}/freeglut/freeglut_main.c | 0 .../{Box2D_v2.2.1 => box2d}/freeglut/freeglut_menu.c | 0 .../{Box2D_v2.2.1 => box2d}/freeglut/freeglut_misc.c | 0 .../freeglut/freeglut_overlay.c | 0 .../freeglut/freeglut_spaceball.c | 0 .../{Box2D_v2.2.1 => box2d}/freeglut/freeglut_state.c | 0 tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_std.h | 0 .../freeglut/freeglut_stroke_mono_roman.c | 0 .../freeglut/freeglut_stroke_roman.c | 0 .../freeglut/freeglut_structure.c | 0 .../freeglut/freeglut_teapot.c | 0 .../freeglut/freeglut_teapot_data.h | 0 .../freeglut/freeglut_videoresize.c | 0 .../freeglut/freeglut_window.c | 0 tests/{Box2D_v2.2.1 => box2d}/glui/CMakeLists.txt | 0 tests/{Box2D_v2.2.1 => box2d}/glui/algebra3.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/algebra3.h | 0 tests/{Box2D_v2.2.1 => box2d}/glui/arcball.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/arcball.h | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui.h | 0 .../glui/glui_add_controls.cpp | 0 .../glui/glui_bitmap_img_data.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_bitmaps.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_button.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_checkbox.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_column.cpp | 0 .../{Box2D_v2.2.1 => box2d}/glui/glui_commandline.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_control.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_edittext.cpp | 0 .../{Box2D_v2.2.1 => box2d}/glui/glui_filebrowser.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_internal.h | 0 .../glui/glui_internal_control.h | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_list.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_listbox.cpp | 0 .../glui/glui_mouse_iaction.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_node.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_panel.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_radio.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_rollout.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_rotation.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_scrollbar.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_separator.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_spinner.cpp | 0 .../{Box2D_v2.2.1 => box2d}/glui/glui_statictext.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_string.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_textbox.cpp | 0 .../{Box2D_v2.2.1 => box2d}/glui/glui_translation.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_tree.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_treepanel.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/glui_window.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/quaternion.cpp | 0 tests/{Box2D_v2.2.1 => box2d}/glui/quaternion.h | 0 tests/{Box2D_v2.2.1 => box2d}/glui/readme.txt | 0 tests/{Box2D_v2.2.1 => box2d}/premake4.lua | 0 tests/runner.py | 11 +++++++++++ 240 files changed, 13 insertions(+), 2 deletions(-) rename tests/{Box2D_v2.2.1 => box2d}/Benchmark.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Box2D.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Box2DConfig.cmake (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/CMakeLists.txt (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/Shapes/b2ChainShape.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/Shapes/b2ChainShape.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/Shapes/b2CircleShape.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/Shapes/b2CircleShape.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/Shapes/b2EdgeShape.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/Shapes/b2EdgeShape.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/Shapes/b2PolygonShape.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/Shapes/b2PolygonShape.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/Shapes/b2Shape.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/b2BroadPhase.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/b2BroadPhase.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/b2CollideCircle.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/b2CollideEdge.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/b2CollidePolygon.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/b2Collision.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/b2Collision.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/b2Distance.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/b2Distance.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/b2DynamicTree.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/b2DynamicTree.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/b2TimeOfImpact.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Collision/b2TimeOfImpact.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2BlockAllocator.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2BlockAllocator.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Draw.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Draw.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2GrowableStack.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Math.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Math.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Settings.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Settings.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2StackAllocator.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2StackAllocator.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Timer.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Common/b2Timer.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2CircleContact.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2CircleContact.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2Contact.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2Contact.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2ContactSolver.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2ContactSolver.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2PolygonContact.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Contacts/b2PolygonContact.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2DistanceJoint.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2DistanceJoint.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2FrictionJoint.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2FrictionJoint.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2GearJoint.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2GearJoint.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2Joint.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2Joint.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2MouseJoint.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2MouseJoint.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2PrismaticJoint.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2PulleyJoint.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2PulleyJoint.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2RevoluteJoint.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2RopeJoint.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2RopeJoint.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2WeldJoint.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2WeldJoint.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2WheelJoint.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/Joints/b2WheelJoint.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2Body.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2Body.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2ContactManager.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2ContactManager.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2Fixture.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2Fixture.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2Island.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2Island.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2TimeStep.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2World.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2World.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2WorldCallbacks.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Dynamics/b2WorldCallbacks.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Rope/b2Rope.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Box2D/Rope/b2Rope.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Build/Readme.txt (100%) rename tests/{Box2D_v2.2.1 => box2d}/Build/vs2010/Box2D.sln (100%) rename tests/{Box2D_v2.2.1 => box2d}/Build/vs2010/Box2D.vcxproj (100%) rename tests/{Box2D_v2.2.1 => box2d}/Build/vs2010/Box2D.vcxproj.filters (100%) rename tests/{Box2D_v2.2.1 => box2d}/Build/vs2010/FreeGLUT.vcxproj (100%) rename tests/{Box2D_v2.2.1 => box2d}/Build/vs2010/FreeGLUT.vcxproj.filters (100%) rename tests/{Box2D_v2.2.1 => box2d}/Build/vs2010/GLUI.vcxproj (100%) rename tests/{Box2D_v2.2.1 => box2d}/Build/vs2010/GLUI.vcxproj.filters (100%) rename tests/{Box2D_v2.2.1 => box2d}/Build/vs2010/HelloWorld.vcxproj (100%) rename tests/{Box2D_v2.2.1 => box2d}/Build/vs2010/HelloWorld.vcxproj.filters (100%) rename tests/{Box2D_v2.2.1 => box2d}/Build/vs2010/Testbed.vcxproj (100%) rename tests/{Box2D_v2.2.1 => box2d}/Build/vs2010/Testbed.vcxproj.filters (100%) rename tests/{Box2D_v2.2.1 => box2d}/Build/xcode4/Box2D.xcodeproj/project.pbxproj (100%) rename tests/{Box2D_v2.2.1 => box2d}/Build/xcode4/Box2D.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename tests/{Box2D_v2.2.1 => box2d}/Building.txt (100%) rename tests/{Box2D_v2.2.1 => box2d}/CMakeLists.txt (100%) rename tests/{Box2D_v2.2.1 => box2d}/HelloWorld/CMakeLists.txt (100%) rename tests/{Box2D_v2.2.1 => box2d}/HelloWorld/HelloWorld.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/License.txt (100%) rename tests/{Box2D_v2.2.1 => box2d}/Makefile (96%) rename tests/{Box2D_v2.2.1 => box2d}/Readme.txt (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/CMakeLists.txt (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Framework/Main.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Framework/Render.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Framework/Render.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Framework/Test.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Framework/Test.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/AddPair.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/ApplyForce.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/BodyTypes.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Breakable.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Bridge.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/BulletTest.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Cantilever.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Car.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Chain.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/CharacterCollision.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/CollisionFiltering.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/CollisionProcessing.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/CompoundShapes.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Confined.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/ContinuousTest.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/DistanceTest.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Dominos.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/DumpShell.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/DynamicTreeTest.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/EdgeShapes.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/EdgeTest.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Gears.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/OneSidedPlatform.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Pinball.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/PolyCollision.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/PolyShapes.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Prismatic.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Pulleys.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Pyramid.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/RayCast.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Revolute.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Rope.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/RopeJoint.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/SensorTest.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/ShapeEditing.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/SliderCrank.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/SphereStack.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/TestEntries.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/TheoJansen.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Tiles.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/TimeOfImpact.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Tumbler.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/VaryingFriction.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/VaryingRestitution.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/VerticalStack.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/Testbed/Tests/Web.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/CMakeLists.txt (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/COPYING (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_callbacks.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_cursor.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_display.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_ext.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_ext.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_font.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_font_data.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_gamemode.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_geometry.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_glutfont_definitions.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_init.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_input_devices.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_internal.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_joystick.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_main.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_menu.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_misc.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_overlay.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_spaceball.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_state.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_std.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_stroke_mono_roman.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_stroke_roman.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_structure.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_teapot.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_teapot_data.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_videoresize.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/freeglut/freeglut_window.c (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/CMakeLists.txt (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/algebra3.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/algebra3.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/arcball.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/arcball.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_add_controls.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_bitmap_img_data.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_bitmaps.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_button.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_checkbox.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_column.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_commandline.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_control.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_edittext.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_filebrowser.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_internal.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_internal_control.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_list.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_listbox.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_mouse_iaction.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_node.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_panel.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_radio.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_rollout.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_rotation.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_scrollbar.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_separator.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_spinner.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_statictext.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_string.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_textbox.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_translation.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_tree.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_treepanel.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/glui_window.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/quaternion.cpp (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/quaternion.h (100%) rename tests/{Box2D_v2.2.1 => box2d}/glui/readme.txt (100%) rename tests/{Box2D_v2.2.1 => box2d}/premake4.lua (100%) diff --git a/tests/Box2D_v2.2.1/Benchmark.cpp b/tests/box2d/Benchmark.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Benchmark.cpp rename to tests/box2d/Benchmark.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Box2D.h b/tests/box2d/Box2D/Box2D.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Box2D.h rename to tests/box2d/Box2D/Box2D.h diff --git a/tests/Box2D_v2.2.1/Box2D/Box2DConfig.cmake b/tests/box2d/Box2D/Box2DConfig.cmake similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Box2DConfig.cmake rename to tests/box2d/Box2D/Box2DConfig.cmake diff --git a/tests/Box2D_v2.2.1/Box2D/CMakeLists.txt b/tests/box2d/Box2D/CMakeLists.txt similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/CMakeLists.txt rename to tests/box2d/Box2D/CMakeLists.txt diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2ChainShape.cpp b/tests/box2d/Box2D/Collision/Shapes/b2ChainShape.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2ChainShape.cpp rename to tests/box2d/Box2D/Collision/Shapes/b2ChainShape.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2ChainShape.h b/tests/box2d/Box2D/Collision/Shapes/b2ChainShape.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2ChainShape.h rename to tests/box2d/Box2D/Collision/Shapes/b2ChainShape.h diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2CircleShape.cpp b/tests/box2d/Box2D/Collision/Shapes/b2CircleShape.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2CircleShape.cpp rename to tests/box2d/Box2D/Collision/Shapes/b2CircleShape.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2CircleShape.h b/tests/box2d/Box2D/Collision/Shapes/b2CircleShape.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2CircleShape.h rename to tests/box2d/Box2D/Collision/Shapes/b2CircleShape.h diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2EdgeShape.cpp b/tests/box2d/Box2D/Collision/Shapes/b2EdgeShape.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2EdgeShape.cpp rename to tests/box2d/Box2D/Collision/Shapes/b2EdgeShape.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2EdgeShape.h b/tests/box2d/Box2D/Collision/Shapes/b2EdgeShape.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2EdgeShape.h rename to tests/box2d/Box2D/Collision/Shapes/b2EdgeShape.h diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2PolygonShape.cpp b/tests/box2d/Box2D/Collision/Shapes/b2PolygonShape.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2PolygonShape.cpp rename to tests/box2d/Box2D/Collision/Shapes/b2PolygonShape.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2PolygonShape.h b/tests/box2d/Box2D/Collision/Shapes/b2PolygonShape.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2PolygonShape.h rename to tests/box2d/Box2D/Collision/Shapes/b2PolygonShape.h diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2Shape.h b/tests/box2d/Box2D/Collision/Shapes/b2Shape.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/Shapes/b2Shape.h rename to tests/box2d/Box2D/Collision/Shapes/b2Shape.h diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2BroadPhase.cpp b/tests/box2d/Box2D/Collision/b2BroadPhase.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/b2BroadPhase.cpp rename to tests/box2d/Box2D/Collision/b2BroadPhase.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2BroadPhase.h b/tests/box2d/Box2D/Collision/b2BroadPhase.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/b2BroadPhase.h rename to tests/box2d/Box2D/Collision/b2BroadPhase.h diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2CollideCircle.cpp b/tests/box2d/Box2D/Collision/b2CollideCircle.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/b2CollideCircle.cpp rename to tests/box2d/Box2D/Collision/b2CollideCircle.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2CollideEdge.cpp b/tests/box2d/Box2D/Collision/b2CollideEdge.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/b2CollideEdge.cpp rename to tests/box2d/Box2D/Collision/b2CollideEdge.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2CollidePolygon.cpp b/tests/box2d/Box2D/Collision/b2CollidePolygon.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/b2CollidePolygon.cpp rename to tests/box2d/Box2D/Collision/b2CollidePolygon.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2Collision.cpp b/tests/box2d/Box2D/Collision/b2Collision.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/b2Collision.cpp rename to tests/box2d/Box2D/Collision/b2Collision.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2Collision.h b/tests/box2d/Box2D/Collision/b2Collision.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/b2Collision.h rename to tests/box2d/Box2D/Collision/b2Collision.h diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2Distance.cpp b/tests/box2d/Box2D/Collision/b2Distance.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/b2Distance.cpp rename to tests/box2d/Box2D/Collision/b2Distance.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2Distance.h b/tests/box2d/Box2D/Collision/b2Distance.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/b2Distance.h rename to tests/box2d/Box2D/Collision/b2Distance.h diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2DynamicTree.cpp b/tests/box2d/Box2D/Collision/b2DynamicTree.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/b2DynamicTree.cpp rename to tests/box2d/Box2D/Collision/b2DynamicTree.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2DynamicTree.h b/tests/box2d/Box2D/Collision/b2DynamicTree.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/b2DynamicTree.h rename to tests/box2d/Box2D/Collision/b2DynamicTree.h diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2TimeOfImpact.cpp b/tests/box2d/Box2D/Collision/b2TimeOfImpact.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/b2TimeOfImpact.cpp rename to tests/box2d/Box2D/Collision/b2TimeOfImpact.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Collision/b2TimeOfImpact.h b/tests/box2d/Box2D/Collision/b2TimeOfImpact.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Collision/b2TimeOfImpact.h rename to tests/box2d/Box2D/Collision/b2TimeOfImpact.h diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2BlockAllocator.cpp b/tests/box2d/Box2D/Common/b2BlockAllocator.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Common/b2BlockAllocator.cpp rename to tests/box2d/Box2D/Common/b2BlockAllocator.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2BlockAllocator.h b/tests/box2d/Box2D/Common/b2BlockAllocator.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Common/b2BlockAllocator.h rename to tests/box2d/Box2D/Common/b2BlockAllocator.h diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Draw.cpp b/tests/box2d/Box2D/Common/b2Draw.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Common/b2Draw.cpp rename to tests/box2d/Box2D/Common/b2Draw.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Draw.h b/tests/box2d/Box2D/Common/b2Draw.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Common/b2Draw.h rename to tests/box2d/Box2D/Common/b2Draw.h diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2GrowableStack.h b/tests/box2d/Box2D/Common/b2GrowableStack.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Common/b2GrowableStack.h rename to tests/box2d/Box2D/Common/b2GrowableStack.h diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Math.cpp b/tests/box2d/Box2D/Common/b2Math.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Common/b2Math.cpp rename to tests/box2d/Box2D/Common/b2Math.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Math.h b/tests/box2d/Box2D/Common/b2Math.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Common/b2Math.h rename to tests/box2d/Box2D/Common/b2Math.h diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Settings.cpp b/tests/box2d/Box2D/Common/b2Settings.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Common/b2Settings.cpp rename to tests/box2d/Box2D/Common/b2Settings.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Settings.h b/tests/box2d/Box2D/Common/b2Settings.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Common/b2Settings.h rename to tests/box2d/Box2D/Common/b2Settings.h diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2StackAllocator.cpp b/tests/box2d/Box2D/Common/b2StackAllocator.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Common/b2StackAllocator.cpp rename to tests/box2d/Box2D/Common/b2StackAllocator.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2StackAllocator.h b/tests/box2d/Box2D/Common/b2StackAllocator.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Common/b2StackAllocator.h rename to tests/box2d/Box2D/Common/b2StackAllocator.h diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Timer.cpp b/tests/box2d/Box2D/Common/b2Timer.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Common/b2Timer.cpp rename to tests/box2d/Box2D/Common/b2Timer.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Common/b2Timer.h b/tests/box2d/Box2D/Common/b2Timer.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Common/b2Timer.h rename to tests/box2d/Box2D/Common/b2Timer.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp rename to tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h rename to tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp rename to tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h rename to tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2CircleContact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2CircleContact.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2CircleContact.cpp rename to tests/box2d/Box2D/Dynamics/Contacts/b2CircleContact.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2CircleContact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2CircleContact.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2CircleContact.h rename to tests/box2d/Box2D/Dynamics/Contacts/b2CircleContact.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2Contact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2Contact.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2Contact.cpp rename to tests/box2d/Box2D/Dynamics/Contacts/b2Contact.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2Contact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2Contact.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2Contact.h rename to tests/box2d/Box2D/Dynamics/Contacts/b2Contact.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ContactSolver.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2ContactSolver.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ContactSolver.cpp rename to tests/box2d/Box2D/Dynamics/Contacts/b2ContactSolver.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ContactSolver.h b/tests/box2d/Box2D/Dynamics/Contacts/b2ContactSolver.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2ContactSolver.h rename to tests/box2d/Box2D/Dynamics/Contacts/b2ContactSolver.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp rename to tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h rename to tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp rename to tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h rename to tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp rename to tests/box2d/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h rename to tests/box2d/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonContact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonContact.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonContact.cpp rename to tests/box2d/Box2D/Dynamics/Contacts/b2PolygonContact.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonContact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonContact.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Contacts/b2PolygonContact.h rename to tests/box2d/Box2D/Dynamics/Contacts/b2PolygonContact.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2DistanceJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2DistanceJoint.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2DistanceJoint.cpp rename to tests/box2d/Box2D/Dynamics/Joints/b2DistanceJoint.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2DistanceJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2DistanceJoint.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2DistanceJoint.h rename to tests/box2d/Box2D/Dynamics/Joints/b2DistanceJoint.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2FrictionJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2FrictionJoint.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2FrictionJoint.cpp rename to tests/box2d/Box2D/Dynamics/Joints/b2FrictionJoint.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2FrictionJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2FrictionJoint.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2FrictionJoint.h rename to tests/box2d/Box2D/Dynamics/Joints/b2FrictionJoint.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2GearJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2GearJoint.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2GearJoint.cpp rename to tests/box2d/Box2D/Dynamics/Joints/b2GearJoint.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2GearJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2GearJoint.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2GearJoint.h rename to tests/box2d/Box2D/Dynamics/Joints/b2GearJoint.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2Joint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2Joint.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2Joint.cpp rename to tests/box2d/Box2D/Dynamics/Joints/b2Joint.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2Joint.h b/tests/box2d/Box2D/Dynamics/Joints/b2Joint.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2Joint.h rename to tests/box2d/Box2D/Dynamics/Joints/b2Joint.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2MouseJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2MouseJoint.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2MouseJoint.cpp rename to tests/box2d/Box2D/Dynamics/Joints/b2MouseJoint.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2MouseJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2MouseJoint.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2MouseJoint.h rename to tests/box2d/Box2D/Dynamics/Joints/b2MouseJoint.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp rename to tests/box2d/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PrismaticJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2PrismaticJoint.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PrismaticJoint.h rename to tests/box2d/Box2D/Dynamics/Joints/b2PrismaticJoint.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PulleyJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PulleyJoint.cpp rename to tests/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PulleyJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2PulleyJoint.h rename to tests/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp rename to tests/box2d/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RevoluteJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2RevoluteJoint.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RevoluteJoint.h rename to tests/box2d/Box2D/Dynamics/Joints/b2RevoluteJoint.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RopeJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2RopeJoint.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RopeJoint.cpp rename to tests/box2d/Box2D/Dynamics/Joints/b2RopeJoint.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RopeJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2RopeJoint.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2RopeJoint.h rename to tests/box2d/Box2D/Dynamics/Joints/b2RopeJoint.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WeldJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2WeldJoint.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WeldJoint.cpp rename to tests/box2d/Box2D/Dynamics/Joints/b2WeldJoint.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WeldJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2WeldJoint.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WeldJoint.h rename to tests/box2d/Box2D/Dynamics/Joints/b2WeldJoint.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WheelJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2WheelJoint.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WheelJoint.cpp rename to tests/box2d/Box2D/Dynamics/Joints/b2WheelJoint.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WheelJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2WheelJoint.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/Joints/b2WheelJoint.h rename to tests/box2d/Box2D/Dynamics/Joints/b2WheelJoint.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Body.cpp b/tests/box2d/Box2D/Dynamics/b2Body.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/b2Body.cpp rename to tests/box2d/Box2D/Dynamics/b2Body.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Body.h b/tests/box2d/Box2D/Dynamics/b2Body.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/b2Body.h rename to tests/box2d/Box2D/Dynamics/b2Body.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2ContactManager.cpp b/tests/box2d/Box2D/Dynamics/b2ContactManager.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/b2ContactManager.cpp rename to tests/box2d/Box2D/Dynamics/b2ContactManager.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2ContactManager.h b/tests/box2d/Box2D/Dynamics/b2ContactManager.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/b2ContactManager.h rename to tests/box2d/Box2D/Dynamics/b2ContactManager.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Fixture.cpp b/tests/box2d/Box2D/Dynamics/b2Fixture.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/b2Fixture.cpp rename to tests/box2d/Box2D/Dynamics/b2Fixture.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Fixture.h b/tests/box2d/Box2D/Dynamics/b2Fixture.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/b2Fixture.h rename to tests/box2d/Box2D/Dynamics/b2Fixture.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Island.cpp b/tests/box2d/Box2D/Dynamics/b2Island.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/b2Island.cpp rename to tests/box2d/Box2D/Dynamics/b2Island.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2Island.h b/tests/box2d/Box2D/Dynamics/b2Island.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/b2Island.h rename to tests/box2d/Box2D/Dynamics/b2Island.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2TimeStep.h b/tests/box2d/Box2D/Dynamics/b2TimeStep.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/b2TimeStep.h rename to tests/box2d/Box2D/Dynamics/b2TimeStep.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2World.cpp b/tests/box2d/Box2D/Dynamics/b2World.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/b2World.cpp rename to tests/box2d/Box2D/Dynamics/b2World.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2World.h b/tests/box2d/Box2D/Dynamics/b2World.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/b2World.h rename to tests/box2d/Box2D/Dynamics/b2World.h diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2WorldCallbacks.cpp b/tests/box2d/Box2D/Dynamics/b2WorldCallbacks.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/b2WorldCallbacks.cpp rename to tests/box2d/Box2D/Dynamics/b2WorldCallbacks.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Dynamics/b2WorldCallbacks.h b/tests/box2d/Box2D/Dynamics/b2WorldCallbacks.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Dynamics/b2WorldCallbacks.h rename to tests/box2d/Box2D/Dynamics/b2WorldCallbacks.h diff --git a/tests/Box2D_v2.2.1/Box2D/Rope/b2Rope.cpp b/tests/box2d/Box2D/Rope/b2Rope.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Rope/b2Rope.cpp rename to tests/box2d/Box2D/Rope/b2Rope.cpp diff --git a/tests/Box2D_v2.2.1/Box2D/Rope/b2Rope.h b/tests/box2d/Box2D/Rope/b2Rope.h similarity index 100% rename from tests/Box2D_v2.2.1/Box2D/Rope/b2Rope.h rename to tests/box2d/Box2D/Rope/b2Rope.h diff --git a/tests/Box2D_v2.2.1/Build/Readme.txt b/tests/box2d/Build/Readme.txt similarity index 100% rename from tests/Box2D_v2.2.1/Build/Readme.txt rename to tests/box2d/Build/Readme.txt diff --git a/tests/Box2D_v2.2.1/Build/vs2010/Box2D.sln b/tests/box2d/Build/vs2010/Box2D.sln similarity index 100% rename from tests/Box2D_v2.2.1/Build/vs2010/Box2D.sln rename to tests/box2d/Build/vs2010/Box2D.sln diff --git a/tests/Box2D_v2.2.1/Build/vs2010/Box2D.vcxproj b/tests/box2d/Build/vs2010/Box2D.vcxproj similarity index 100% rename from tests/Box2D_v2.2.1/Build/vs2010/Box2D.vcxproj rename to tests/box2d/Build/vs2010/Box2D.vcxproj diff --git a/tests/Box2D_v2.2.1/Build/vs2010/Box2D.vcxproj.filters b/tests/box2d/Build/vs2010/Box2D.vcxproj.filters similarity index 100% rename from tests/Box2D_v2.2.1/Build/vs2010/Box2D.vcxproj.filters rename to tests/box2d/Build/vs2010/Box2D.vcxproj.filters diff --git a/tests/Box2D_v2.2.1/Build/vs2010/FreeGLUT.vcxproj b/tests/box2d/Build/vs2010/FreeGLUT.vcxproj similarity index 100% rename from tests/Box2D_v2.2.1/Build/vs2010/FreeGLUT.vcxproj rename to tests/box2d/Build/vs2010/FreeGLUT.vcxproj diff --git a/tests/Box2D_v2.2.1/Build/vs2010/FreeGLUT.vcxproj.filters b/tests/box2d/Build/vs2010/FreeGLUT.vcxproj.filters similarity index 100% rename from tests/Box2D_v2.2.1/Build/vs2010/FreeGLUT.vcxproj.filters rename to tests/box2d/Build/vs2010/FreeGLUT.vcxproj.filters diff --git a/tests/Box2D_v2.2.1/Build/vs2010/GLUI.vcxproj b/tests/box2d/Build/vs2010/GLUI.vcxproj similarity index 100% rename from tests/Box2D_v2.2.1/Build/vs2010/GLUI.vcxproj rename to tests/box2d/Build/vs2010/GLUI.vcxproj diff --git a/tests/Box2D_v2.2.1/Build/vs2010/GLUI.vcxproj.filters b/tests/box2d/Build/vs2010/GLUI.vcxproj.filters similarity index 100% rename from tests/Box2D_v2.2.1/Build/vs2010/GLUI.vcxproj.filters rename to tests/box2d/Build/vs2010/GLUI.vcxproj.filters diff --git a/tests/Box2D_v2.2.1/Build/vs2010/HelloWorld.vcxproj b/tests/box2d/Build/vs2010/HelloWorld.vcxproj similarity index 100% rename from tests/Box2D_v2.2.1/Build/vs2010/HelloWorld.vcxproj rename to tests/box2d/Build/vs2010/HelloWorld.vcxproj diff --git a/tests/Box2D_v2.2.1/Build/vs2010/HelloWorld.vcxproj.filters b/tests/box2d/Build/vs2010/HelloWorld.vcxproj.filters similarity index 100% rename from tests/Box2D_v2.2.1/Build/vs2010/HelloWorld.vcxproj.filters rename to tests/box2d/Build/vs2010/HelloWorld.vcxproj.filters diff --git a/tests/Box2D_v2.2.1/Build/vs2010/Testbed.vcxproj b/tests/box2d/Build/vs2010/Testbed.vcxproj similarity index 100% rename from tests/Box2D_v2.2.1/Build/vs2010/Testbed.vcxproj rename to tests/box2d/Build/vs2010/Testbed.vcxproj diff --git a/tests/Box2D_v2.2.1/Build/vs2010/Testbed.vcxproj.filters b/tests/box2d/Build/vs2010/Testbed.vcxproj.filters similarity index 100% rename from tests/Box2D_v2.2.1/Build/vs2010/Testbed.vcxproj.filters rename to tests/box2d/Build/vs2010/Testbed.vcxproj.filters diff --git a/tests/Box2D_v2.2.1/Build/xcode4/Box2D.xcodeproj/project.pbxproj b/tests/box2d/Build/xcode4/Box2D.xcodeproj/project.pbxproj similarity index 100% rename from tests/Box2D_v2.2.1/Build/xcode4/Box2D.xcodeproj/project.pbxproj rename to tests/box2d/Build/xcode4/Box2D.xcodeproj/project.pbxproj diff --git a/tests/Box2D_v2.2.1/Build/xcode4/Box2D.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/tests/box2d/Build/xcode4/Box2D.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from tests/Box2D_v2.2.1/Build/xcode4/Box2D.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to tests/box2d/Build/xcode4/Box2D.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/tests/Box2D_v2.2.1/Building.txt b/tests/box2d/Building.txt similarity index 100% rename from tests/Box2D_v2.2.1/Building.txt rename to tests/box2d/Building.txt diff --git a/tests/Box2D_v2.2.1/CMakeLists.txt b/tests/box2d/CMakeLists.txt similarity index 100% rename from tests/Box2D_v2.2.1/CMakeLists.txt rename to tests/box2d/CMakeLists.txt diff --git a/tests/Box2D_v2.2.1/HelloWorld/CMakeLists.txt b/tests/box2d/HelloWorld/CMakeLists.txt similarity index 100% rename from tests/Box2D_v2.2.1/HelloWorld/CMakeLists.txt rename to tests/box2d/HelloWorld/CMakeLists.txt diff --git a/tests/Box2D_v2.2.1/HelloWorld/HelloWorld.cpp b/tests/box2d/HelloWorld/HelloWorld.cpp similarity index 100% rename from tests/Box2D_v2.2.1/HelloWorld/HelloWorld.cpp rename to tests/box2d/HelloWorld/HelloWorld.cpp diff --git a/tests/Box2D_v2.2.1/License.txt b/tests/box2d/License.txt similarity index 100% rename from tests/Box2D_v2.2.1/License.txt rename to tests/box2d/License.txt diff --git a/tests/Box2D_v2.2.1/Makefile b/tests/box2d/Makefile similarity index 96% rename from tests/Box2D_v2.2.1/Makefile rename to tests/box2d/Makefile index 10f47ddb5d171..13f62093fc3fa 100644 --- a/tests/Box2D_v2.2.1/Makefile +++ b/tests/box2d/Makefile @@ -1,6 +1,6 @@ # Makefile for generating a Box2D library using Emscripten. -O = Box2D_v2.2.1/Box2D +O = Box2D OBJECTS = \ $(O)/Collision/b2BroadPhase.o \ $(O)/Collision/b2CollideCircle.o \ @@ -53,7 +53,7 @@ all: box2d.o OPTS = -O2 %.o: %.cpp - $(CXX) -IBox2D_v2.2.1 $< -o $@ $(OPTS) + $(CXX) -I. $< -o $@ $(OPTS) box2d.o: $(OBJECTS) $(CXX) -o $@ $(OBJECTS) $(OPTS) diff --git a/tests/Box2D_v2.2.1/Readme.txt b/tests/box2d/Readme.txt similarity index 100% rename from tests/Box2D_v2.2.1/Readme.txt rename to tests/box2d/Readme.txt diff --git a/tests/Box2D_v2.2.1/Testbed/CMakeLists.txt b/tests/box2d/Testbed/CMakeLists.txt similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/CMakeLists.txt rename to tests/box2d/Testbed/CMakeLists.txt diff --git a/tests/Box2D_v2.2.1/Testbed/Framework/Main.cpp b/tests/box2d/Testbed/Framework/Main.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Framework/Main.cpp rename to tests/box2d/Testbed/Framework/Main.cpp diff --git a/tests/Box2D_v2.2.1/Testbed/Framework/Render.cpp b/tests/box2d/Testbed/Framework/Render.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Framework/Render.cpp rename to tests/box2d/Testbed/Framework/Render.cpp diff --git a/tests/Box2D_v2.2.1/Testbed/Framework/Render.h b/tests/box2d/Testbed/Framework/Render.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Framework/Render.h rename to tests/box2d/Testbed/Framework/Render.h diff --git a/tests/Box2D_v2.2.1/Testbed/Framework/Test.cpp b/tests/box2d/Testbed/Framework/Test.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Framework/Test.cpp rename to tests/box2d/Testbed/Framework/Test.cpp diff --git a/tests/Box2D_v2.2.1/Testbed/Framework/Test.h b/tests/box2d/Testbed/Framework/Test.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Framework/Test.h rename to tests/box2d/Testbed/Framework/Test.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/AddPair.h b/tests/box2d/Testbed/Tests/AddPair.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/AddPair.h rename to tests/box2d/Testbed/Tests/AddPair.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/ApplyForce.h b/tests/box2d/Testbed/Tests/ApplyForce.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/ApplyForce.h rename to tests/box2d/Testbed/Tests/ApplyForce.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/BodyTypes.h b/tests/box2d/Testbed/Tests/BodyTypes.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/BodyTypes.h rename to tests/box2d/Testbed/Tests/BodyTypes.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Breakable.h b/tests/box2d/Testbed/Tests/Breakable.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Breakable.h rename to tests/box2d/Testbed/Tests/Breakable.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Bridge.h b/tests/box2d/Testbed/Tests/Bridge.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Bridge.h rename to tests/box2d/Testbed/Tests/Bridge.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/BulletTest.h b/tests/box2d/Testbed/Tests/BulletTest.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/BulletTest.h rename to tests/box2d/Testbed/Tests/BulletTest.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Cantilever.h b/tests/box2d/Testbed/Tests/Cantilever.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Cantilever.h rename to tests/box2d/Testbed/Tests/Cantilever.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Car.h b/tests/box2d/Testbed/Tests/Car.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Car.h rename to tests/box2d/Testbed/Tests/Car.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Chain.h b/tests/box2d/Testbed/Tests/Chain.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Chain.h rename to tests/box2d/Testbed/Tests/Chain.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/CharacterCollision.h b/tests/box2d/Testbed/Tests/CharacterCollision.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/CharacterCollision.h rename to tests/box2d/Testbed/Tests/CharacterCollision.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/CollisionFiltering.h b/tests/box2d/Testbed/Tests/CollisionFiltering.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/CollisionFiltering.h rename to tests/box2d/Testbed/Tests/CollisionFiltering.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/CollisionProcessing.h b/tests/box2d/Testbed/Tests/CollisionProcessing.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/CollisionProcessing.h rename to tests/box2d/Testbed/Tests/CollisionProcessing.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/CompoundShapes.h b/tests/box2d/Testbed/Tests/CompoundShapes.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/CompoundShapes.h rename to tests/box2d/Testbed/Tests/CompoundShapes.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Confined.h b/tests/box2d/Testbed/Tests/Confined.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Confined.h rename to tests/box2d/Testbed/Tests/Confined.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/ContinuousTest.h b/tests/box2d/Testbed/Tests/ContinuousTest.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/ContinuousTest.h rename to tests/box2d/Testbed/Tests/ContinuousTest.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/DistanceTest.h b/tests/box2d/Testbed/Tests/DistanceTest.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/DistanceTest.h rename to tests/box2d/Testbed/Tests/DistanceTest.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Dominos.h b/tests/box2d/Testbed/Tests/Dominos.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Dominos.h rename to tests/box2d/Testbed/Tests/Dominos.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/DumpShell.h b/tests/box2d/Testbed/Tests/DumpShell.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/DumpShell.h rename to tests/box2d/Testbed/Tests/DumpShell.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/DynamicTreeTest.h b/tests/box2d/Testbed/Tests/DynamicTreeTest.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/DynamicTreeTest.h rename to tests/box2d/Testbed/Tests/DynamicTreeTest.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/EdgeShapes.h b/tests/box2d/Testbed/Tests/EdgeShapes.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/EdgeShapes.h rename to tests/box2d/Testbed/Tests/EdgeShapes.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/EdgeTest.h b/tests/box2d/Testbed/Tests/EdgeTest.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/EdgeTest.h rename to tests/box2d/Testbed/Tests/EdgeTest.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Gears.h b/tests/box2d/Testbed/Tests/Gears.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Gears.h rename to tests/box2d/Testbed/Tests/Gears.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/OneSidedPlatform.h b/tests/box2d/Testbed/Tests/OneSidedPlatform.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/OneSidedPlatform.h rename to tests/box2d/Testbed/Tests/OneSidedPlatform.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Pinball.h b/tests/box2d/Testbed/Tests/Pinball.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Pinball.h rename to tests/box2d/Testbed/Tests/Pinball.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/PolyCollision.h b/tests/box2d/Testbed/Tests/PolyCollision.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/PolyCollision.h rename to tests/box2d/Testbed/Tests/PolyCollision.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/PolyShapes.h b/tests/box2d/Testbed/Tests/PolyShapes.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/PolyShapes.h rename to tests/box2d/Testbed/Tests/PolyShapes.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Prismatic.h b/tests/box2d/Testbed/Tests/Prismatic.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Prismatic.h rename to tests/box2d/Testbed/Tests/Prismatic.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Pulleys.h b/tests/box2d/Testbed/Tests/Pulleys.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Pulleys.h rename to tests/box2d/Testbed/Tests/Pulleys.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Pyramid.h b/tests/box2d/Testbed/Tests/Pyramid.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Pyramid.h rename to tests/box2d/Testbed/Tests/Pyramid.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/RayCast.h b/tests/box2d/Testbed/Tests/RayCast.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/RayCast.h rename to tests/box2d/Testbed/Tests/RayCast.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Revolute.h b/tests/box2d/Testbed/Tests/Revolute.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Revolute.h rename to tests/box2d/Testbed/Tests/Revolute.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Rope.h b/tests/box2d/Testbed/Tests/Rope.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Rope.h rename to tests/box2d/Testbed/Tests/Rope.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/RopeJoint.h b/tests/box2d/Testbed/Tests/RopeJoint.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/RopeJoint.h rename to tests/box2d/Testbed/Tests/RopeJoint.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/SensorTest.h b/tests/box2d/Testbed/Tests/SensorTest.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/SensorTest.h rename to tests/box2d/Testbed/Tests/SensorTest.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/ShapeEditing.h b/tests/box2d/Testbed/Tests/ShapeEditing.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/ShapeEditing.h rename to tests/box2d/Testbed/Tests/ShapeEditing.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/SliderCrank.h b/tests/box2d/Testbed/Tests/SliderCrank.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/SliderCrank.h rename to tests/box2d/Testbed/Tests/SliderCrank.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/SphereStack.h b/tests/box2d/Testbed/Tests/SphereStack.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/SphereStack.h rename to tests/box2d/Testbed/Tests/SphereStack.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/TestEntries.cpp b/tests/box2d/Testbed/Tests/TestEntries.cpp similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/TestEntries.cpp rename to tests/box2d/Testbed/Tests/TestEntries.cpp diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/TheoJansen.h b/tests/box2d/Testbed/Tests/TheoJansen.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/TheoJansen.h rename to tests/box2d/Testbed/Tests/TheoJansen.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Tiles.h b/tests/box2d/Testbed/Tests/Tiles.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Tiles.h rename to tests/box2d/Testbed/Tests/Tiles.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/TimeOfImpact.h b/tests/box2d/Testbed/Tests/TimeOfImpact.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/TimeOfImpact.h rename to tests/box2d/Testbed/Tests/TimeOfImpact.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Tumbler.h b/tests/box2d/Testbed/Tests/Tumbler.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Tumbler.h rename to tests/box2d/Testbed/Tests/Tumbler.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/VaryingFriction.h b/tests/box2d/Testbed/Tests/VaryingFriction.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/VaryingFriction.h rename to tests/box2d/Testbed/Tests/VaryingFriction.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/VaryingRestitution.h b/tests/box2d/Testbed/Tests/VaryingRestitution.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/VaryingRestitution.h rename to tests/box2d/Testbed/Tests/VaryingRestitution.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/VerticalStack.h b/tests/box2d/Testbed/Tests/VerticalStack.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/VerticalStack.h rename to tests/box2d/Testbed/Tests/VerticalStack.h diff --git a/tests/Box2D_v2.2.1/Testbed/Tests/Web.h b/tests/box2d/Testbed/Tests/Web.h similarity index 100% rename from tests/Box2D_v2.2.1/Testbed/Tests/Web.h rename to tests/box2d/Testbed/Tests/Web.h diff --git a/tests/Box2D_v2.2.1/freeglut/CMakeLists.txt b/tests/box2d/freeglut/CMakeLists.txt similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/CMakeLists.txt rename to tests/box2d/freeglut/CMakeLists.txt diff --git a/tests/Box2D_v2.2.1/freeglut/COPYING b/tests/box2d/freeglut/COPYING similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/COPYING rename to tests/box2d/freeglut/COPYING diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut.h b/tests/box2d/freeglut/freeglut.h similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut.h rename to tests/box2d/freeglut/freeglut.h diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_callbacks.c b/tests/box2d/freeglut/freeglut_callbacks.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_callbacks.c rename to tests/box2d/freeglut/freeglut_callbacks.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_cursor.c b/tests/box2d/freeglut/freeglut_cursor.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_cursor.c rename to tests/box2d/freeglut/freeglut_cursor.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_display.c b/tests/box2d/freeglut/freeglut_display.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_display.c rename to tests/box2d/freeglut/freeglut_display.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_ext.c b/tests/box2d/freeglut/freeglut_ext.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_ext.c rename to tests/box2d/freeglut/freeglut_ext.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_ext.h b/tests/box2d/freeglut/freeglut_ext.h similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_ext.h rename to tests/box2d/freeglut/freeglut_ext.h diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_font.c b/tests/box2d/freeglut/freeglut_font.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_font.c rename to tests/box2d/freeglut/freeglut_font.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_font_data.c b/tests/box2d/freeglut/freeglut_font_data.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_font_data.c rename to tests/box2d/freeglut/freeglut_font_data.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_gamemode.c b/tests/box2d/freeglut/freeglut_gamemode.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_gamemode.c rename to tests/box2d/freeglut/freeglut_gamemode.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_geometry.c b/tests/box2d/freeglut/freeglut_geometry.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_geometry.c rename to tests/box2d/freeglut/freeglut_geometry.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_glutfont_definitions.c b/tests/box2d/freeglut/freeglut_glutfont_definitions.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_glutfont_definitions.c rename to tests/box2d/freeglut/freeglut_glutfont_definitions.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_init.c b/tests/box2d/freeglut/freeglut_init.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_init.c rename to tests/box2d/freeglut/freeglut_init.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_input_devices.c b/tests/box2d/freeglut/freeglut_input_devices.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_input_devices.c rename to tests/box2d/freeglut/freeglut_input_devices.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_internal.h b/tests/box2d/freeglut/freeglut_internal.h similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_internal.h rename to tests/box2d/freeglut/freeglut_internal.h diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_joystick.c b/tests/box2d/freeglut/freeglut_joystick.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_joystick.c rename to tests/box2d/freeglut/freeglut_joystick.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_main.c b/tests/box2d/freeglut/freeglut_main.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_main.c rename to tests/box2d/freeglut/freeglut_main.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_menu.c b/tests/box2d/freeglut/freeglut_menu.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_menu.c rename to tests/box2d/freeglut/freeglut_menu.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_misc.c b/tests/box2d/freeglut/freeglut_misc.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_misc.c rename to tests/box2d/freeglut/freeglut_misc.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_overlay.c b/tests/box2d/freeglut/freeglut_overlay.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_overlay.c rename to tests/box2d/freeglut/freeglut_overlay.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_spaceball.c b/tests/box2d/freeglut/freeglut_spaceball.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_spaceball.c rename to tests/box2d/freeglut/freeglut_spaceball.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_state.c b/tests/box2d/freeglut/freeglut_state.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_state.c rename to tests/box2d/freeglut/freeglut_state.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_std.h b/tests/box2d/freeglut/freeglut_std.h similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_std.h rename to tests/box2d/freeglut/freeglut_std.h diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_stroke_mono_roman.c b/tests/box2d/freeglut/freeglut_stroke_mono_roman.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_stroke_mono_roman.c rename to tests/box2d/freeglut/freeglut_stroke_mono_roman.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_stroke_roman.c b/tests/box2d/freeglut/freeglut_stroke_roman.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_stroke_roman.c rename to tests/box2d/freeglut/freeglut_stroke_roman.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_structure.c b/tests/box2d/freeglut/freeglut_structure.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_structure.c rename to tests/box2d/freeglut/freeglut_structure.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_teapot.c b/tests/box2d/freeglut/freeglut_teapot.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_teapot.c rename to tests/box2d/freeglut/freeglut_teapot.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_teapot_data.h b/tests/box2d/freeglut/freeglut_teapot_data.h similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_teapot_data.h rename to tests/box2d/freeglut/freeglut_teapot_data.h diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_videoresize.c b/tests/box2d/freeglut/freeglut_videoresize.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_videoresize.c rename to tests/box2d/freeglut/freeglut_videoresize.c diff --git a/tests/Box2D_v2.2.1/freeglut/freeglut_window.c b/tests/box2d/freeglut/freeglut_window.c similarity index 100% rename from tests/Box2D_v2.2.1/freeglut/freeglut_window.c rename to tests/box2d/freeglut/freeglut_window.c diff --git a/tests/Box2D_v2.2.1/glui/CMakeLists.txt b/tests/box2d/glui/CMakeLists.txt similarity index 100% rename from tests/Box2D_v2.2.1/glui/CMakeLists.txt rename to tests/box2d/glui/CMakeLists.txt diff --git a/tests/Box2D_v2.2.1/glui/algebra3.cpp b/tests/box2d/glui/algebra3.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/algebra3.cpp rename to tests/box2d/glui/algebra3.cpp diff --git a/tests/Box2D_v2.2.1/glui/algebra3.h b/tests/box2d/glui/algebra3.h similarity index 100% rename from tests/Box2D_v2.2.1/glui/algebra3.h rename to tests/box2d/glui/algebra3.h diff --git a/tests/Box2D_v2.2.1/glui/arcball.cpp b/tests/box2d/glui/arcball.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/arcball.cpp rename to tests/box2d/glui/arcball.cpp diff --git a/tests/Box2D_v2.2.1/glui/arcball.h b/tests/box2d/glui/arcball.h similarity index 100% rename from tests/Box2D_v2.2.1/glui/arcball.h rename to tests/box2d/glui/arcball.h diff --git a/tests/Box2D_v2.2.1/glui/glui.cpp b/tests/box2d/glui/glui.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui.cpp rename to tests/box2d/glui/glui.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui.h b/tests/box2d/glui/glui.h similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui.h rename to tests/box2d/glui/glui.h diff --git a/tests/Box2D_v2.2.1/glui/glui_add_controls.cpp b/tests/box2d/glui/glui_add_controls.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_add_controls.cpp rename to tests/box2d/glui/glui_add_controls.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_bitmap_img_data.cpp b/tests/box2d/glui/glui_bitmap_img_data.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_bitmap_img_data.cpp rename to tests/box2d/glui/glui_bitmap_img_data.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_bitmaps.cpp b/tests/box2d/glui/glui_bitmaps.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_bitmaps.cpp rename to tests/box2d/glui/glui_bitmaps.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_button.cpp b/tests/box2d/glui/glui_button.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_button.cpp rename to tests/box2d/glui/glui_button.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_checkbox.cpp b/tests/box2d/glui/glui_checkbox.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_checkbox.cpp rename to tests/box2d/glui/glui_checkbox.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_column.cpp b/tests/box2d/glui/glui_column.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_column.cpp rename to tests/box2d/glui/glui_column.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_commandline.cpp b/tests/box2d/glui/glui_commandline.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_commandline.cpp rename to tests/box2d/glui/glui_commandline.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_control.cpp b/tests/box2d/glui/glui_control.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_control.cpp rename to tests/box2d/glui/glui_control.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_edittext.cpp b/tests/box2d/glui/glui_edittext.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_edittext.cpp rename to tests/box2d/glui/glui_edittext.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_filebrowser.cpp b/tests/box2d/glui/glui_filebrowser.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_filebrowser.cpp rename to tests/box2d/glui/glui_filebrowser.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_internal.h b/tests/box2d/glui/glui_internal.h similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_internal.h rename to tests/box2d/glui/glui_internal.h diff --git a/tests/Box2D_v2.2.1/glui/glui_internal_control.h b/tests/box2d/glui/glui_internal_control.h similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_internal_control.h rename to tests/box2d/glui/glui_internal_control.h diff --git a/tests/Box2D_v2.2.1/glui/glui_list.cpp b/tests/box2d/glui/glui_list.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_list.cpp rename to tests/box2d/glui/glui_list.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_listbox.cpp b/tests/box2d/glui/glui_listbox.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_listbox.cpp rename to tests/box2d/glui/glui_listbox.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_mouse_iaction.cpp b/tests/box2d/glui/glui_mouse_iaction.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_mouse_iaction.cpp rename to tests/box2d/glui/glui_mouse_iaction.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_node.cpp b/tests/box2d/glui/glui_node.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_node.cpp rename to tests/box2d/glui/glui_node.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_panel.cpp b/tests/box2d/glui/glui_panel.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_panel.cpp rename to tests/box2d/glui/glui_panel.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_radio.cpp b/tests/box2d/glui/glui_radio.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_radio.cpp rename to tests/box2d/glui/glui_radio.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_rollout.cpp b/tests/box2d/glui/glui_rollout.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_rollout.cpp rename to tests/box2d/glui/glui_rollout.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_rotation.cpp b/tests/box2d/glui/glui_rotation.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_rotation.cpp rename to tests/box2d/glui/glui_rotation.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_scrollbar.cpp b/tests/box2d/glui/glui_scrollbar.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_scrollbar.cpp rename to tests/box2d/glui/glui_scrollbar.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_separator.cpp b/tests/box2d/glui/glui_separator.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_separator.cpp rename to tests/box2d/glui/glui_separator.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_spinner.cpp b/tests/box2d/glui/glui_spinner.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_spinner.cpp rename to tests/box2d/glui/glui_spinner.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_statictext.cpp b/tests/box2d/glui/glui_statictext.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_statictext.cpp rename to tests/box2d/glui/glui_statictext.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_string.cpp b/tests/box2d/glui/glui_string.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_string.cpp rename to tests/box2d/glui/glui_string.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_textbox.cpp b/tests/box2d/glui/glui_textbox.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_textbox.cpp rename to tests/box2d/glui/glui_textbox.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_translation.cpp b/tests/box2d/glui/glui_translation.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_translation.cpp rename to tests/box2d/glui/glui_translation.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_tree.cpp b/tests/box2d/glui/glui_tree.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_tree.cpp rename to tests/box2d/glui/glui_tree.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_treepanel.cpp b/tests/box2d/glui/glui_treepanel.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_treepanel.cpp rename to tests/box2d/glui/glui_treepanel.cpp diff --git a/tests/Box2D_v2.2.1/glui/glui_window.cpp b/tests/box2d/glui/glui_window.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/glui_window.cpp rename to tests/box2d/glui/glui_window.cpp diff --git a/tests/Box2D_v2.2.1/glui/quaternion.cpp b/tests/box2d/glui/quaternion.cpp similarity index 100% rename from tests/Box2D_v2.2.1/glui/quaternion.cpp rename to tests/box2d/glui/quaternion.cpp diff --git a/tests/Box2D_v2.2.1/glui/quaternion.h b/tests/box2d/glui/quaternion.h similarity index 100% rename from tests/Box2D_v2.2.1/glui/quaternion.h rename to tests/box2d/glui/quaternion.h diff --git a/tests/Box2D_v2.2.1/glui/readme.txt b/tests/box2d/glui/readme.txt similarity index 100% rename from tests/Box2D_v2.2.1/glui/readme.txt rename to tests/box2d/glui/readme.txt diff --git a/tests/Box2D_v2.2.1/premake4.lua b/tests/box2d/premake4.lua similarity index 100% rename from tests/Box2D_v2.2.1/premake4.lua rename to tests/box2d/premake4.lua diff --git a/tests/runner.py b/tests/runner.py index 03299dd0c61ae..74e78f6167807 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -12376,6 +12376,17 @@ def test_zlib(self): ''', force_c=True, emcc_args=emcc_args, native_args=native_args) + def zzztest_yyy_box2d(self): # Called thus so it runs late in the alphabetical cycle... it is long + src = open(path_from_root('tests', 'box2d', 'Benchmark.cpp'), 'r').read() + + js_lib = self.get_library('box2d', [os.path.join('box2d.o')], configure=None) + js_lib = self.get_library('box2d_native', [os.path.join('box2d.o')], configure=None, native=True) + + emcc_args = js_lib + ['-I' + path_from_root('tests', 'box2d')] + native_args = native_lib + ['-I' + path_from_root('tests', 'box2d')] + + self.do_benchmark('box2d', src, [], '\nok.\n', emcc_args=emcc_args, native_args=native_args) + def test_zzz_bullet(self): # Called thus so it runs late in the alphabetical cycle... it is long src = open(path_from_root('tests', 'bullet', 'Demos', 'Benchmarks', 'BenchmarkDemo.cpp'), 'r').read() + \ open(path_from_root('tests', 'bullet', 'Demos', 'Benchmarks', 'main.cpp'), 'r').read() From 82fd5dba17bf753301c304e03ad75fab0c49d29a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 10 Apr 2013 16:02:03 -0700 Subject: [PATCH 116/544] box2d benchmark fixes --- tests/box2d/Benchmark.cpp | 1 - tests/box2d/Makefile | 12 +++++------- tests/runner.py | 4 ++-- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/tests/box2d/Benchmark.cpp b/tests/box2d/Benchmark.cpp index 914c13a0e584c..46dbbcb0ec82a 100644 --- a/tests/box2d/Benchmark.cpp +++ b/tests/box2d/Benchmark.cpp @@ -26,7 +26,6 @@ typedef struct { #include #include "Box2D/Box2D.h" -#include "Bench2d.h" using namespace std; diff --git a/tests/box2d/Makefile b/tests/box2d/Makefile index 13f62093fc3fa..d37adaa4e1d40 100644 --- a/tests/box2d/Makefile +++ b/tests/box2d/Makefile @@ -48,16 +48,14 @@ OBJECTS = \ $(O)/Dynamics/Joints/b2WheelJoint.o \ $(O)/Rope/b2Rope.o -all: box2d.o - -OPTS = -O2 +all: box2d.a %.o: %.cpp - $(CXX) -I. $< -o $@ $(OPTS) + $(CXX) -I. $< -o $@ -O2 -c -box2d.o: $(OBJECTS) - $(CXX) -o $@ $(OBJECTS) $(OPTS) +box2d.a: $(OBJECTS) + $(AR) rvs $@ $(OBJECTS) clean: - rm box2d.o + rm box2d.a diff --git a/tests/runner.py b/tests/runner.py index 74e78f6167807..eb6fb110513c5 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -12379,8 +12379,8 @@ def test_zlib(self): def zzztest_yyy_box2d(self): # Called thus so it runs late in the alphabetical cycle... it is long src = open(path_from_root('tests', 'box2d', 'Benchmark.cpp'), 'r').read() - js_lib = self.get_library('box2d', [os.path.join('box2d.o')], configure=None) - js_lib = self.get_library('box2d_native', [os.path.join('box2d.o')], configure=None, native=True) + js_lib = self.get_library('box2d', [os.path.join('box2d.a')], configure=None) + native_lib = self.get_library('box2d_native', [os.path.join('box2d.a')], configure=None, native=True) emcc_args = js_lib + ['-I' + path_from_root('tests', 'box2d')] native_args = native_lib + ['-I' + path_from_root('tests', 'box2d')] From f57081e7f1f4e8ab3b4be047a2a1f7217bb4dce3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 10 Apr 2013 16:12:18 -0700 Subject: [PATCH 117/544] finish box2d benchmark --- tests/box2d/Benchmark.cpp | 10 +++++++--- tests/runner.py | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/box2d/Benchmark.cpp b/tests/box2d/Benchmark.cpp index 46dbbcb0ec82a..8ebf0457e40e7 100644 --- a/tests/box2d/Benchmark.cpp +++ b/tests/box2d/Benchmark.cpp @@ -11,7 +11,7 @@ #define DEBUG 0 #define WARMUP 64 -#define FRAMES 256 +#define FRAMES 333 typedef struct { float mean; @@ -52,7 +52,7 @@ result_t measure(clock_t times[FRAMES]) { return r; } -result_t bench() { +int main() { // Define the gravity vector. b2Vec2 gravity(0.0f, -10.0f); @@ -116,6 +116,10 @@ result_t bench() { #endif } - return measure(times); + result_t result = measure(times); + + printf("frame averages: %.3f +- %.3f\n", result.mean, result.stddev); + + return 0; } diff --git a/tests/runner.py b/tests/runner.py index eb6fb110513c5..2865679b03ec9 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -12376,7 +12376,7 @@ def test_zlib(self): ''', force_c=True, emcc_args=emcc_args, native_args=native_args) - def zzztest_yyy_box2d(self): # Called thus so it runs late in the alphabetical cycle... it is long + def test_yyy_box2d(self): # Called thus so it runs late in the alphabetical cycle... it is long src = open(path_from_root('tests', 'box2d', 'Benchmark.cpp'), 'r').read() js_lib = self.get_library('box2d', [os.path.join('box2d.a')], configure=None) @@ -12385,7 +12385,7 @@ def zzztest_yyy_box2d(self): # Called thus so it runs late in the alphabetical c emcc_args = js_lib + ['-I' + path_from_root('tests', 'box2d')] native_args = native_lib + ['-I' + path_from_root('tests', 'box2d')] - self.do_benchmark('box2d', src, [], '\nok.\n', emcc_args=emcc_args, native_args=native_args) + self.do_benchmark('box2d', src, [], 'frame averages', emcc_args=emcc_args, native_args=native_args) def test_zzz_bullet(self): # Called thus so it runs late in the alphabetical cycle... it is long src = open(path_from_root('tests', 'bullet', 'Demos', 'Benchmarks', 'BenchmarkDemo.cpp'), 'r').read() + \ From bc234c204c0a1d6d02363e9a60418dd52a6c3c87 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 10 Apr 2013 17:30:40 -0700 Subject: [PATCH 118/544] do not use memory init file without ta2, since we lay out memory in ta2 format in binary files --- emcc | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/emcc b/emcc index 15c38cd418de4..adca126691b9f 100755 --- a/emcc +++ b/emcc @@ -1444,30 +1444,33 @@ try: open(final, 'w').write(src) if memory_init_file: - memfile = target + '.mem' - seen_memory_init = False - def repl(m): - seen_memory_init = True - # handle chunking of the memory initializer - s = re.sub('[\[\]\n\(\)\. ]', '', m.groups(0)[0]) - s = s.replace('concat', ',') - if s[-1] == ',': s = s[:-1] - open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), s.split(',')))) + if shared.Settings.USE_TYPED_ARRAYS != 2: + if type(memory_init_file) == int: print >> sys.stderr, 'emcc: warning: memory init file requires typed arrays mode 2' + else: + memfile = target + '.mem' + seen_memory_init = False + def repl(m): + seen_memory_init = True + # handle chunking of the memory initializer + s = re.sub('[\[\]\n\(\)\. ]', '', m.groups(0)[0]) + s = s.replace('concat', ',') + if s[-1] == ',': s = s[:-1] + open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), s.split(',')))) + if DEBUG: + # Copy into temp dir as well, so can be run there too + temp_memfile = os.path.join(shared.EMSCRIPTEN_TEMP_DIR, os.path.basename(memfile)) + if os.path.abspath(memfile) != os.path.abspath(memfile): + shutil.copyfile(memfile, temp_memfile) + return 'loadMemoryInitializer("%s");' % os.path.basename(memfile) + src = re.sub('/\* memory initializer \*/ allocate\(([\d,\.concat\(\)\[\]\\n ]+)"i8", ALLOC_NONE, TOTAL_STACK\)', repl, src, count=1) + open(final + '.mem.js', 'w').write(src) + final += '.mem.js' if DEBUG: - # Copy into temp dir as well, so can be run there too - temp_memfile = os.path.join(shared.EMSCRIPTEN_TEMP_DIR, os.path.basename(memfile)) - if os.path.abspath(memfile) != os.path.abspath(memfile): - shutil.copyfile(memfile, temp_memfile) - return 'loadMemoryInitializer("%s");' % os.path.basename(memfile) - src = re.sub('/\* memory initializer \*/ allocate\(([\d,\.concat\(\)\[\]\\n ]+)"i8", ALLOC_NONE, TOTAL_STACK\)', repl, src, count=1) - open(final + '.mem.js', 'w').write(src) - final += '.mem.js' - if DEBUG: - if seen_memory_init: - save_intermediate('meminit') - print >> sys.stderr, 'emcc: wrote memory initialization to %s' % memfile - else: - print >> sys.stderr, 'emcc: did not see memory initialization' + if seen_memory_init: + save_intermediate('meminit') + print >> sys.stderr, 'emcc: wrote memory initialization to %s' % memfile + else: + print >> sys.stderr, 'emcc: did not see memory initialization' # If we were asked to also generate HTML, do that if final_suffix == 'html': From 1c4f763de44601a8b5a50fd5f78a8fedd314c131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 6 Apr 2013 21:12:55 +0300 Subject: [PATCH 119/544] Extend the use of response files to cover the case when emcc invokes emscripten.py, so that Windows command line length limitations don't break the test_asm_pgo on Windows. --- emcc | 14 +++----------- emscripten.py | 13 +++++++++++++ tests/runner.py | 4 ++-- tools/response_file.py | 31 +++++++++++++++++++++++++++++++ tools/shared.py | 12 ++++++++++-- 5 files changed, 59 insertions(+), 15 deletions(-) create mode 100644 tools/response_file.py diff --git a/emcc b/emcc index adca126691b9f..bcd703fd6a7c4 100755 --- a/emcc +++ b/emcc @@ -79,6 +79,7 @@ import os, sys, shutil, tempfile, subprocess, shlex, time, re from subprocess import PIPE, STDOUT from tools import shared from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename +from tools.response_file import read_and_delete_response_file # Mapping of emcc opt levels to llvm opt levels. We use llvm opt level 3 in emcc opt # levels 2 and 3 (emcc 3 is unsafe opts, so unsuitable for the only level to get @@ -129,19 +130,10 @@ while response_file: for index in range(1, len(sys.argv)): if sys.argv[index][0] == '@': # found one, loop again next time - response_file = sys.argv[index][1:] - print >>sys.stderr, 'emcc: using response file: %s' % response_file - if not os.path.exists(response_file): - print >>sys.stderr, 'emcc: error: Response file not found: %s' % response_file - exit(1) - - response_fd = open(response_file, 'r') - extra_args = shlex.split(response_fd.read()) - response_fd.close() - + response_file = True + extra_args = read_and_delete_response_file(sys.argv[index]) # slice in extra_args in place of the response file arg sys.argv[index:index+1] = extra_args - #if DEBUG: print >>sys.stderr, "Expanded response file: " + " | ".join(sys.argv) break if sys.argv[1] == '--version': diff --git a/emscripten.py b/emscripten.py index efa6894aa05d0..02e28623eafb3 100755 --- a/emscripten.py +++ b/emscripten.py @@ -12,6 +12,7 @@ import os, sys, json, optparse, subprocess, re, time, multiprocessing, functools from tools import jsrun, cache as cache_module, tempfiles +from tools.response_file import read_and_delete_response_file __rootpath__ = os.path.abspath(os.path.dirname(__file__)) def path_from_root(*pathelems): @@ -629,6 +630,18 @@ def lookup(value): jcache=jcache, temp_files=temp_files, DEBUG=DEBUG, DEBUG_CACHE=DEBUG_CACHE) def _main(environ): + response_file = True + while response_file: + response_file = None + for index in range(1, len(sys.argv)): + if sys.argv[index][0] == '@': + # found one, loop again next time + response_file = True + response_file_args = read_and_delete_response_file(sys.argv[index]) + # slice in extra_args in place of the response file arg + sys.argv[index:index+1] = response_file_args + break + parser = optparse.OptionParser( usage='usage: %prog [-h] [-H HEADERS] [-o OUTFILE] [-c COMPILER_ENGINE] [-s FOO=BAR]* infile', description=('You should normally never use this! Use emcc instead. ' diff --git a/tests/runner.py b/tests/runner.py index 2865679b03ec9..705e96fee49a9 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -8079,11 +8079,11 @@ def test_asm_pgo(self): shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgo.js')) pgo_output = run_js(self.in_dir('pgo.js')).split('\n')[1] - open('pgo_data', 'w').write(pgo_output) + open('pgo_data.rsp', 'w').write(pgo_output) # with response file - self.emcc_args += ['@pgo_data'] + self.emcc_args += ['@pgo_data.rsp'] self.do_run(src, output) self.emcc_args.pop() shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgoed.js')) diff --git a/tools/response_file.py b/tools/response_file.py new file mode 100644 index 0000000000000..f622678334707 --- /dev/null +++ b/tools/response_file.py @@ -0,0 +1,31 @@ +import tempfile, os, sys, shlex +from tempfiles import try_delete + +# Routes the given cmdline param list in args into a new .rsp file and returns the filename to it. +# The returned filename has '@' prepended to it already for convenience. +def create_response_file(args, directory): + (response_fd, response_filename) = tempfile.mkstemp(prefix='emscripten_', suffix='.rsp', dir=directory, text=True) + response_fd = os.fdopen(response_fd, "w") + #print >> sys.stderr, "Creating response file '%s'" % response_filename + args = map(lambda p: p.replace(' ', '').replace('\\', '\\\\').replace('"', '\\"'), args) + response_fd.write(' '.join(args)) + response_fd.close + return '@' + response_filename + +# Reads and deletes a .rsp file, and returns the list of cmdline params found in the file. +def read_and_delete_response_file(response_filename): + # Ensure safety so that this function can never accidentally delete any non-.rsp files if things go wrong! + if not (response_filename.startswith('@') and response_filename.endswith('.rsp')): + raise Exception("'%s' is not a valid response file name! Response file names must start with '@' and end in '.rsp'!" % response_filename) + response_filename = response_filename[1:] + + #print >> sys.stderr, "Using response file '%s'" % response_filename + if not os.path.exists(response_filename): + raise Exception("Response file '%s' not found!" % response_filename) + + response_fd = open(response_filename, 'r') + args = response_fd.read() + response_fd.close() + try_delete(response_filename) + args = shlex.split(args) + return args diff --git a/tools/shared.py b/tools/shared.py index 72f4868e7c910..7692b4f8655da 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -2,6 +2,7 @@ from subprocess import Popen, PIPE, STDOUT from tempfile import mkstemp import jsrun, cache, tempfiles +from response_file import create_response_file def listify(x): if type(x) is not list: return [x] @@ -34,13 +35,20 @@ def __init__(self, args, bufsize=0, executable=None, stdin=None, stdout=None, st self.stdout_ = PIPE if self.stderr_ == None: self.stderr_ = PIPE - - # Call the process with fixed streams. + + # emscripten.py supports reading args from a response file instead of cmdline. + # Use .rsp to avoid cmdline length limitations on Windows. + if len(args) >= 2 and args[1].endswith("emscripten.py"): + response_filename = create_response_file(args[2:], TEMP_DIR) + args = args[0:2] + [response_filename] + try: + # Call the process with fixed streams. self.process = subprocess.Popen(args, bufsize, executable, self.stdin_, self.stdout_, self.stderr_, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags) except Exception, e: print >> sys.stderr, '\nsubprocess.Popen(args=%s) failed! Exception %s\n' % (' '.join(args), str(e)) raise e + raise def communicate(self, input=None): output = self.process.communicate(input) From 829add1ee972bc3f68cc065c5e9b69b8a6e3fa5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 6 Apr 2013 21:46:46 +0300 Subject: [PATCH 120/544] Fix typo. --- tools/response_file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/response_file.py b/tools/response_file.py index f622678334707..cb368d479d6e6 100644 --- a/tools/response_file.py +++ b/tools/response_file.py @@ -9,7 +9,7 @@ def create_response_file(args, directory): #print >> sys.stderr, "Creating response file '%s'" % response_filename args = map(lambda p: p.replace(' ', '').replace('\\', '\\\\').replace('"', '\\"'), args) response_fd.write(' '.join(args)) - response_fd.close + response_fd.close() return '@' + response_filename # Reads and deletes a .rsp file, and returns the list of cmdline params found in the file. From 5351b86b0768813c4c18bb61494c43b07bc00372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 8 Apr 2013 22:46:49 +0300 Subject: [PATCH 121/544] Don't require response files to end with '.rsp'. Only autodelete response files that end with the suffix '.tmp'. Use the suffix '.tmp' for all internally utilized response files. --- tools/response_file.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tools/response_file.py b/tools/response_file.py index cb368d479d6e6..29756833323b9 100644 --- a/tools/response_file.py +++ b/tools/response_file.py @@ -1,10 +1,11 @@ import tempfile, os, sys, shlex from tempfiles import try_delete -# Routes the given cmdline param list in args into a new .rsp file and returns the filename to it. +# Routes the given cmdline param list in args into a new response file and returns the filename to it. +# The response file has a suffix '.tmp' to signal that the process receiving the response file is free to delete it after it has consumed it. # The returned filename has '@' prepended to it already for convenience. def create_response_file(args, directory): - (response_fd, response_filename) = tempfile.mkstemp(prefix='emscripten_', suffix='.rsp', dir=directory, text=True) + (response_fd, response_filename) = tempfile.mkstemp(prefix='emscripten_', suffix='.tmp', dir=directory, text=True) response_fd = os.fdopen(response_fd, "w") #print >> sys.stderr, "Creating response file '%s'" % response_filename args = map(lambda p: p.replace(' ', '').replace('\\', '\\\\').replace('"', '\\"'), args) @@ -12,12 +13,11 @@ def create_response_file(args, directory): response_fd.close() return '@' + response_filename -# Reads and deletes a .rsp file, and returns the list of cmdline params found in the file. +# Reads a response file, and returns the list of cmdline params found in the file. +# If the response file ends with .tmp, it is automatically deleted after reading it. def read_and_delete_response_file(response_filename): - # Ensure safety so that this function can never accidentally delete any non-.rsp files if things go wrong! - if not (response_filename.startswith('@') and response_filename.endswith('.rsp')): - raise Exception("'%s' is not a valid response file name! Response file names must start with '@' and end in '.rsp'!" % response_filename) - response_filename = response_filename[1:] + if response_filename.startswith('@'): + response_filename = response_filename[1:] #print >> sys.stderr, "Using response file '%s'" % response_filename if not os.path.exists(response_filename): @@ -26,6 +26,9 @@ def read_and_delete_response_file(response_filename): response_fd = open(response_filename, 'r') args = response_fd.read() response_fd.close() - try_delete(response_filename) + # For conveniency, the receiver is allowed to immediately clean up response files ending with '.tmp' so that the + # caller doesn't have to do it. + if response_filename.endswith(".tmp"): + try_delete(response_filename) args = shlex.split(args) return args From 69c67542e76bcbc37563399eb3ab8716c6a37774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 11 Apr 2013 10:39:31 +0300 Subject: [PATCH 122/544] Remove the unwanted abstraction that callee is allowed to autodelete a response file after consuming it. Instead, manually track and delete response files by the caller and clean them up. --- emcc | 4 ++-- emscripten.py | 4 ++-- tools/response_file.py | 16 +++++----------- tools/shared.py | 11 +++++++++-- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/emcc b/emcc index bcd703fd6a7c4..17b8e6e81aa89 100755 --- a/emcc +++ b/emcc @@ -79,7 +79,7 @@ import os, sys, shutil, tempfile, subprocess, shlex, time, re from subprocess import PIPE, STDOUT from tools import shared from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename -from tools.response_file import read_and_delete_response_file +from tools.response_file import read_response_file # Mapping of emcc opt levels to llvm opt levels. We use llvm opt level 3 in emcc opt # levels 2 and 3 (emcc 3 is unsafe opts, so unsuitable for the only level to get @@ -131,7 +131,7 @@ while response_file: if sys.argv[index][0] == '@': # found one, loop again next time response_file = True - extra_args = read_and_delete_response_file(sys.argv[index]) + extra_args = read_response_file(sys.argv[index]) # slice in extra_args in place of the response file arg sys.argv[index:index+1] = extra_args break diff --git a/emscripten.py b/emscripten.py index 02e28623eafb3..bd6994fa26687 100755 --- a/emscripten.py +++ b/emscripten.py @@ -12,7 +12,7 @@ import os, sys, json, optparse, subprocess, re, time, multiprocessing, functools from tools import jsrun, cache as cache_module, tempfiles -from tools.response_file import read_and_delete_response_file +from tools.response_file import read_response_file __rootpath__ = os.path.abspath(os.path.dirname(__file__)) def path_from_root(*pathelems): @@ -637,7 +637,7 @@ def _main(environ): if sys.argv[index][0] == '@': # found one, loop again next time response_file = True - response_file_args = read_and_delete_response_file(sys.argv[index]) + response_file_args = read_response_file(sys.argv[index]) # slice in extra_args in place of the response file arg sys.argv[index:index+1] = response_file_args break diff --git a/tools/response_file.py b/tools/response_file.py index 29756833323b9..312cda73bcab2 100644 --- a/tools/response_file.py +++ b/tools/response_file.py @@ -1,21 +1,19 @@ import tempfile, os, sys, shlex -from tempfiles import try_delete # Routes the given cmdline param list in args into a new response file and returns the filename to it. -# The response file has a suffix '.tmp' to signal that the process receiving the response file is free to delete it after it has consumed it. -# The returned filename has '@' prepended to it already for convenience. +# The returned filename has a suffix '.rsp'. def create_response_file(args, directory): - (response_fd, response_filename) = tempfile.mkstemp(prefix='emscripten_', suffix='.tmp', dir=directory, text=True) + (response_fd, response_filename) = tempfile.mkstemp(prefix='emscripten_', suffix='.rsp', dir=directory, text=True) response_fd = os.fdopen(response_fd, "w") #print >> sys.stderr, "Creating response file '%s'" % response_filename args = map(lambda p: p.replace(' ', '').replace('\\', '\\\\').replace('"', '\\"'), args) response_fd.write(' '.join(args)) response_fd.close() - return '@' + response_filename + return response_filename # Reads a response file, and returns the list of cmdline params found in the file. -# If the response file ends with .tmp, it is automatically deleted after reading it. -def read_and_delete_response_file(response_filename): +# The parameter response_filename may start with '@'. +def read_response_file(response_filename): if response_filename.startswith('@'): response_filename = response_filename[1:] @@ -26,9 +24,5 @@ def read_and_delete_response_file(response_filename): response_fd = open(response_filename, 'r') args = response_fd.read() response_fd.close() - # For conveniency, the receiver is allowed to immediately clean up response files ending with '.tmp' so that the - # caller doesn't have to do it. - if response_filename.endswith(".tmp"): - try_delete(response_filename) args = shlex.split(args) return args diff --git a/tools/shared.py b/tools/shared.py index 7692b4f8655da..dce27a18a681e 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -39,8 +39,8 @@ def __init__(self, args, bufsize=0, executable=None, stdin=None, stdout=None, st # emscripten.py supports reading args from a response file instead of cmdline. # Use .rsp to avoid cmdline length limitations on Windows. if len(args) >= 2 and args[1].endswith("emscripten.py"): - response_filename = create_response_file(args[2:], TEMP_DIR) - args = args[0:2] + [response_filename] + self.response_filename = create_response_file(args[2:], TEMP_DIR) + args = args[0:2] + ['@' + self.response_filename] try: # Call the process with fixed streams. @@ -75,6 +75,13 @@ def poll(self): def kill(self): return self.process.kill() + + def __del__(self): + try: + # Clean up the temporary response file that was used to spawn this process, so that we don't leave temp files around. + tempfiles.try_delete(self.response_filename) + except: + pass # Mute all exceptions in dtor, particularly if we didn't use a response file, self.response_filename doesn't exist. # Install our replacement Popen handler if we are running on Windows to avoid python spawn process function. if os.name == 'nt': From 3299393a68844ca5d388808627892a57f92509b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 11 Apr 2013 10:46:14 +0300 Subject: [PATCH 123/544] Remove duplicate line from rebase. --- tools/shared.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index dce27a18a681e..d5a37c038aa03 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -48,7 +48,6 @@ def __init__(self, args, bufsize=0, executable=None, stdin=None, stdout=None, st except Exception, e: print >> sys.stderr, '\nsubprocess.Popen(args=%s) failed! Exception %s\n' % (' '.join(args), str(e)) raise e - raise def communicate(self, input=None): output = self.process.communicate(input) From 0d844ed7a717b13c14eac08fd9a9fbf63a45c071 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Apr 2013 14:59:38 -0700 Subject: [PATCH 124/544] clarify INVOKE_RUN --- src/settings.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/settings.js b/src/settings.js index 78a2161626fc4..08dad7f707c2b 100644 --- a/src/settings.js +++ b/src/settings.js @@ -36,7 +36,8 @@ var ASSERTIONS = 1; // Whether we should add runtime assertions, for example to var VERBOSE = 0; // When set to 1, will generate more verbose output during compilation. var INVOKE_RUN = 1; // Whether we will run the main() function. Disable if you embed the generated - // code in your own, and will call main() yourself at the right time. + // code in your own, and will call main() yourself at the right time (which you + // can do with Module.callMain(), with an optional parameter of commandline args). var INIT_HEAP = 0; // Whether to initialize memory anywhere other than the stack to 0. var TOTAL_STACK = 5*1024*1024; // The total stack size. There is no way to enlarge the stack, so this // value must be large enough for the program's requirements. If From 74e74ba24278a3e96a9e4dceaaf814e587ea5d0f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Apr 2013 15:55:21 -0700 Subject: [PATCH 125/544] remove unneeded variable --- emscripten.py | 1 - 1 file changed, 1 deletion(-) diff --git a/emscripten.py b/emscripten.py index efa6894aa05d0..19c7453117430 100755 --- a/emscripten.py +++ b/emscripten.py @@ -93,7 +93,6 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, # Split input into the relevant parts for each phase pre = [] funcs = [] # split up functions here, for parallelism later - func_idents = [] meta = [] # needed by each function XXX if DEBUG: t = time.time() From 76e2f101c8cf000583649862dd08d930d0bd6ed3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Apr 2013 16:12:21 -0700 Subject: [PATCH 126/544] refactor emscripten.py ll splitting --- emscripten.py | 13 ++++++++----- src/jsifier.js | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/emscripten.py b/emscripten.py index 19c7453117430..dbc7b551c31b1 100755 --- a/emscripten.py +++ b/emscripten.py @@ -98,19 +98,22 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, if DEBUG: t = time.time() in_func = False ll_lines = open(infile).readlines() + curr_func = None for line in ll_lines: if in_func: - funcs[-1][1].append(line) + curr_func.append(line) if line.startswith('}'): in_func = False - funcs[-1] = (funcs[-1][0], ''.join(funcs[-1][1])) - pre.append(line) # pre needs it to, so we know about all implemented functions + funcs.append((curr_func[0], ''.join(curr_func))) # use the entire line as the identifier + # pre needs to know about all implemented functions, even for non-pre func + pre.append(curr_func[0]) + pre.append(line) + curr_func = None else: if line.startswith(';'): continue if line.startswith('define '): in_func = True - funcs.append((line, [line])) # use the entire line as the identifier - pre.append(line) # pre needs it to, so we know about all implemented functions + curr_func = [line] elif line.find(' = type { ') > 0: pre.append(line) # type elif line.startswith('!'): diff --git a/src/jsifier.js b/src/jsifier.js index 23fbb4c5cfc77..0786f622cc91a 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -108,7 +108,7 @@ function JSify(data, functionsOnly, givenFunctions) { } }); - if (phase == 'funcs') { // pre has function shells, just to defined implementedFunctions + if (phase == 'funcs') { // || phase == 'pre') { // pre has function shells, just to defined implementedFunctions var MAX_BATCH_FUNC_LINES = 1000; while (data.unparsedFunctions.length > 0) { var currFuncLines = []; From f97347ec11f1f788148d1fac7c37afbcaa5b365f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Apr 2013 17:33:01 -0700 Subject: [PATCH 127/544] add test for addFunction --- tests/runner.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/runner.py b/tests/runner.py index 2865679b03ec9..fd9f784268c9d 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -8100,6 +8100,35 @@ def test_asm_pgo(self): shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgoed2.js')) assert open('pgoed.js').read() == open('pgoed2.js').read() + def test_add_function(self): + if self.emcc_args is None: return self.skip('requires emcc') + if Settings.ASM_JS: return self.skip('needs a singleton function table') + + Settings.INVOKE_RUN = 0 + + src = r''' + #include + #include + + int main(int argc, char **argv) { + int fp = atoi(argv[1]); + printf("fp: %d\n", fp); + void (*f)() = reinterpret_cast(fp); + f(); + return 0; + } + ''' + + open(os.path.join(self.get_dir(), 'post.js'), 'w').write(''' + var newFuncPtr = Runtime.addFunction(function() { + Module.print('Hello from JS!'); + }); + Module.callMain([newFuncPtr.toString()]); + ''') + + self.emcc_args += ['--post-js', 'post.js'] + self.do_run(src, '''Hello from JS!''') + def test_scriptaclass(self): if self.emcc_args is None: return self.skip('requires emcc') From c259c465431a8301c1b0f4e29370c70a9b3ccc03 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Apr 2013 20:03:13 -0700 Subject: [PATCH 128/544] autogenerate invoke_* functions for asm --- emscripten.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/emscripten.py b/emscripten.py index dbc7b551c31b1..e0e6293188648 100755 --- a/emscripten.py +++ b/emscripten.py @@ -413,6 +413,15 @@ def asm_coerce(value, sig): %s; } ''' % (sig, ',' if len(sig) > 1 else '', args, arg_coercions, ret)) + asm_setup += ''' +function invoke_%s(%s) { + try { + } catch(e) { + Module.setThrew(1); + } +} +''' % (sig, ','.join(['a' + str(i) for i in range(1, len(sig))])) + basic_funcs.append('invoke_%s' % sig) # calculate exports exported_implemented_functions = list(exported_implemented_functions) From 5ba4497c3b1751a9f212e0fe0fe1d10151fab209 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Apr 2013 20:14:19 -0700 Subject: [PATCH 129/544] implement contents of invoke_* --- emscripten.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/emscripten.py b/emscripten.py index e0e6293188648..8d46b888422c0 100755 --- a/emscripten.py +++ b/emscripten.py @@ -413,14 +413,16 @@ def asm_coerce(value, sig): %s; } ''' % (sig, ',' if len(sig) > 1 else '', args, arg_coercions, ret)) + args = ','.join(['a' + str(i) for i in range(1, len(sig))]) asm_setup += ''' function invoke_%s(%s) { try { + %sModule.dynCall_%s(%s); } catch(e) { Module.setThrew(1); } } -''' % (sig, ','.join(['a' + str(i) for i in range(1, len(sig))])) +''' % (sig, args, 'return ' if sig[0] != 'v' else '', sig, args) basic_funcs.append('invoke_%s' % sig) # calculate exports From 1bea45e1d749b7c4974c9d85daf2606e6ab0ec54 Mon Sep 17 00:00:00 2001 From: Joe Lee Date: Fri, 8 Feb 2013 18:20:19 -0800 Subject: [PATCH 130/544] Don't trigger 1-core assert when there are no chunks to work on. --- emscripten.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/emscripten.py b/emscripten.py index 8d46b888422c0..502e951c85ea5 100755 --- a/emscripten.py +++ b/emscripten.py @@ -225,10 +225,10 @@ def load_from_cache(chunk): # TODO: minimize size of forwarded data from funcs to what we actually need - if cores == 1 and total_ll_size < MAX_CHUNK_SIZE: - assert len(chunks) == 1, 'no point in splitting up without multiple cores' - if len(chunks) > 0: + if cores == 1 and total_ll_size < MAX_CHUNK_SIZE: + assert len(chunks) == 1, 'no point in splitting up without multiple cores' + if DEBUG: print >> sys.stderr, ' emscript: phase 2 working on %d chunks %s (intended chunk size: %.2f MB, meta: %.2f MB, forwarded: %.2f MB, total: %.2f MB)' % (len(chunks), ('using %d cores' % cores) if len(chunks) > 1 else '', chunk_size/(1024*1024.), len(meta)/(1024*1024.), len(forwarded_data)/(1024*1024.), total_ll_size/(1024*1024.)) commands = [ From de4f21890f44bedfca09ae7ef58ac45d00ca902b Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 12 Apr 2013 10:13:03 +0700 Subject: [PATCH 131/544] Add Joe Lee to AUTHORS. --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 35aa74a77a2d5..87a656d66caee 100644 --- a/AUTHORS +++ b/AUTHORS @@ -61,4 +61,5 @@ a license to everyone to use it as detailed in LICENSE.) * Alexander Gladysh * Arlo Breault * Jacob Lee (copyright owned by Google, Inc.) +* Joe Lee (copyright owned by IMVU) From 9e7a712c6b6186792f186ed6bd6d6af31d36a434 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Apr 2013 21:18:37 -0700 Subject: [PATCH 132/544] infrastructure for supporting exceptions in asm.js, by going through invoke_* calls --- emscripten.py | 3 ++- src/compiler.js | 1 - src/jsifier.js | 25 ++++++++++++++++++------- src/library.js | 1 + src/settings.js | 2 +- 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/emscripten.py b/emscripten.py index 502e951c85ea5..996e5cc35c636 100755 --- a/emscripten.py +++ b/emscripten.py @@ -414,12 +414,13 @@ def asm_coerce(value, sig): } ''' % (sig, ',' if len(sig) > 1 else '', args, arg_coercions, ret)) args = ','.join(['a' + str(i) for i in range(1, len(sig))]) + args = 'index' + (',' if args else '') + args asm_setup += ''' function invoke_%s(%s) { try { %sModule.dynCall_%s(%s); } catch(e) { - Module.setThrew(1); + asm.setThrew(1); } } ''' % (sig, args, 'return ' if sig[0] != 'v' else '', sig, args) diff --git a/src/compiler.js b/src/compiler.js index 7cf43f0953d7b..9c19aeb0f80dc 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -178,7 +178,6 @@ assert(!(USE_TYPED_ARRAYS === 2 && QUANTUM_SIZE !== 4), 'For USE_TYPED_ARRAYS == if (ASM_JS) { assert(!ALLOW_MEMORY_GROWTH, 'Cannot grow asm.js heap'); assert((TOTAL_MEMORY&(TOTAL_MEMORY-1)) == 0, 'asm.js heap must be power of 2'); - assert(DISABLE_EXCEPTION_CATCHING == 1, 'asm.js does not support C++ exceptions yet, you must compile with -s DISABLE_EXCEPTION_CATCHING=1'); } assert(!(!NAMED_GLOBALS && BUILD_AS_SHARED_LIB)); // shared libraries must have named globals diff --git a/src/jsifier.js b/src/jsifier.js index 0786f622cc91a..af07539fcbefd 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1156,12 +1156,13 @@ function JSify(data, functionsOnly, givenFunctions) { makeFuncLineActor('invoke', function(item) { // Wrapping in a function lets us easily return values if we are // in an assignment + var disabled = DISABLE_EXCEPTION_CATCHING == 2 && !(item.funcData.ident in EXCEPTION_CATCHING_WHITELIST); var phiSets = calcPhiSets(item); - var call_ = makeFunctionCall(item.ident, item.params, item.funcData, item.type); - + var call_ = makeFunctionCall(item.ident, item.params, item.funcData, item.type, ASM_JS && !disabled); + var ret; - if (DISABLE_EXCEPTION_CATCHING == 2 && !(item.funcData.ident in EXCEPTION_CATCHING_WHITELIST)) { + if (disabled || ASM_JS) { // TODO: EXCEPTION_DEBUG for asm.js ret = call_ + ';'; } else { ret = '(function() { try { __THREW__ = 0; return ' @@ -1173,7 +1174,6 @@ function JSify(data, functionsOnly, givenFunctions) { + 'return null } })();'; } - if (item.assignTo) { ret = 'var ' + item.assignTo + ' = ' + ret; if (USE_TYPED_ARRAYS == 2 && isIllegalType(item.type)) { @@ -1291,7 +1291,7 @@ function JSify(data, functionsOnly, givenFunctions) { return ret; }); - function makeFunctionCall(ident, params, funcData, type) { + function makeFunctionCall(ident, params, funcData, type, forceByPointer) { // We cannot compile assembly. See comment in intertyper.js:'Call' assert(ident != 'asm', 'Inline assembly cannot be compiled to JavaScript!'); @@ -1319,6 +1319,11 @@ function JSify(data, functionsOnly, givenFunctions) { var hasVarArgs = isVarArgsFunctionType(type); var normalArgs = (hasVarArgs && !useJSArgs) ? countNormalArgs(type) : -1; var byPointer = getVarData(funcData, ident); + var byPointerForced = false; + + if (forceByPointer && !byPointer) { + byPointer = byPointerForced = true; + } params.forEach(function(param, i) { var val = finalizeParam(param); @@ -1421,12 +1426,18 @@ function JSify(data, functionsOnly, givenFunctions) { var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs); if (ASM_JS) { assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out) - callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py + if (!forceByPointer) { + callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py + } else { + // add initial argument for invoke. note: no need to update argsTypes at this point + args.unshift(byPointerForced ? Functions.getIndex(callIdent) : callIdent); + callIdent = 'invoke_' + sig; + } } else if (SAFE_DYNCALLS) { assert(!ASM_JS, 'cannot emit safe dyncalls in asm'); callIdent = '(tempInt=' + callIdent + ',tempInt < 0 || tempInt >= FUNCTION_TABLE.length-1 || !FUNCTION_TABLE[tempInt] ? abort("dyncall error: ' + sig + ' " + FUNCTION_TABLE_NAMES[tempInt]) : tempInt)'; } - callIdent = Functions.getTable(sig) + '[' + callIdent + ']'; + if (!byPointerForced) callIdent = Functions.getTable(sig) + '[' + callIdent + ']'; } var ret = callIdent + '(' + args.join(', ') + ')'; diff --git a/src/library.js b/src/library.js index 01c0a3f347e7f..80c107a58afc7 100644 --- a/src/library.js +++ b/src/library.js @@ -5016,6 +5016,7 @@ LibraryManager.library = { __cxa_free_exception: function(ptr) { return _free(ptr); }, + __cxa_throw__sig: 'viii', __cxa_throw__deps: ['llvm_eh_exception', '_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch'], __cxa_throw: function(ptr, type, destructor) { if (!___cxa_throw.initialized) { diff --git a/src/settings.js b/src/settings.js index 08dad7f707c2b..8f31c2d896bfd 100644 --- a/src/settings.js +++ b/src/settings.js @@ -150,7 +150,7 @@ var LABEL_FUNCTION_FILTERS = []; // Filters for function label debug. // labels of functions that is equaled to // one of the filters are printed out // When the array is empty, the filter is disabled. -var EXCEPTION_DEBUG = 0; // Print out exceptions in emscriptened code +var EXCEPTION_DEBUG = 0; // Print out exceptions in emscriptened code. Does not work in asm.js mode var LIBRARY_DEBUG = 0; // Print out when we enter a library call (library*.js). You can also unset // Runtime.debug at runtime for logging to cease, and can set it when you From f54d0e6ccbbb702db125d8c9f86190cf37cfee0c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Apr 2013 21:22:49 -0700 Subject: [PATCH 133/544] avoid unnecessary array creation in cxa_find_matching_catch calls --- src/jsifier.js | 2 +- src/library.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index af07539fcbefd..2a9dc5bd32bbf 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1211,7 +1211,7 @@ function JSify(data, functionsOnly, givenFunctions) { }); makeFuncLineActor('landingpad', function(item) { var catchTypeArray = item.catchables.map(finalizeLLVMParameter).join(','); - var ret = '___cxa_find_matching_catch('+ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') +',' + makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') + ',[' + catchTypeArray +'])'; + var ret = '___cxa_find_matching_catch('+ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') +',' + makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') + (catchTypeArray.length > 0 ? ',' + catchTypeArray : '') +')'; if (USE_TYPED_ARRAYS == 2) { ret = makeVarDef(item.assignTo) + '$0 = ' + ret + '; ' + item.assignTo + '$1 = tempRet0;'; item.assignTo = null; diff --git a/src/library.js b/src/library.js index 80c107a58afc7..f58c7150727c3 100644 --- a/src/library.js +++ b/src/library.js @@ -5157,7 +5157,9 @@ LibraryManager.library = { // We'll do that here, instead, to keep things simpler. __cxa_find_matching_catch__deps: ['__cxa_does_inherit', '__cxa_is_number_type'], - __cxa_find_matching_catch: function(thrown, throwntype, typeArray) { + __cxa_find_matching_catch: function(thrown, throwntype) { + var typeArray = Array.prototype.slice.call(arguments, 2); + // If throwntype is a pointer, this means a pointer has been // thrown. When a pointer is thrown, actually what's thrown // is a pointer to the pointer. We'll dereference it. From a20c654c1fcbb877ff8bd0d305f0908695dc8c7e Mon Sep 17 00:00:00 2001 From: mey Date: Thu, 4 Oct 2012 15:57:49 -0700 Subject: [PATCH 134/544] Supporting returning std::unique_ptr from C++ to javascript. --- system/include/emscripten/bind.h | 116 +++++++++++++++---------------- system/include/emscripten/val.h | 14 ++-- system/include/emscripten/wire.h | 34 ++++++--- system/lib/embind/bind.cpp | 30 ++++---- 4 files changed, 106 insertions(+), 88 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 55fda986c752f..400a94728d840 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -19,56 +19,56 @@ namespace emscripten { const char* payload) __attribute__((noreturn)); void _embind_register_void( - TypeID voidType, + TYPEID voidType, const char* name); void _embind_register_bool( - TypeID boolType, + TYPEID boolType, const char* name, bool trueValue, bool falseValue); void _embind_register_integer( - TypeID integerType, + TYPEID integerType, const char* name); void _embind_register_float( - TypeID floatType, + TYPEID floatType, const char* name); void _embind_register_cstring( - TypeID stringType, + TYPEID stringType, const char* name); void _embind_register_emval( - TypeID emvalType, + TYPEID emvalType, const char* name); void _embind_register_function( const char* name, - TypeID returnType, + TYPEID returnType, unsigned argCount, - TypeID argTypes[], + TYPEID argTypes[], GenericFunction invoker, GenericFunction function); void _embind_register_tuple( - TypeID tupleType, + TYPEID tupleType, const char* name, GenericFunction constructor, GenericFunction destructor); void _embind_register_tuple_element( - TypeID tupleType, - TypeID elementType, + TYPEID tupleType, + TYPEID elementType, GenericFunction getter, GenericFunction setter, size_t memberPointerSize, void* memberPointer); void _embind_register_tuple_element_accessor( - TypeID tupleType, - TypeID elementType, + TYPEID tupleType, + TYPEID elementType, GenericFunction staticGetter, size_t getterSize, void* getter, @@ -77,69 +77,69 @@ namespace emscripten { void* setter); void _embind_register_struct( - TypeID structType, + TYPEID structType, const char* name, GenericFunction constructor, GenericFunction destructor); void _embind_register_struct_field( - TypeID structType, + TYPEID structType, const char* name, - TypeID fieldType, + TYPEID fieldType, GenericFunction getter, GenericFunction setter, size_t memberPointerSize, void* memberPointer); void _embind_register_class( - TypeID classType, + TYPEID classType, const char* className, GenericFunction destructor); void _embind_register_class_constructor( - TypeID classType, + TYPEID classType, unsigned argCount, - TypeID argTypes[], + TYPEID argTypes[], GenericFunction constructor); void _embind_register_class_method( - TypeID classType, + TYPEID classType, const char* methodName, - TypeID returnType, + TYPEID returnType, unsigned argCount, - TypeID argTypes[], + TYPEID argTypes[], GenericFunction invoker, size_t memberFunctionSize, void* memberFunction); void _embind_register_class_field( - TypeID classType, + TYPEID classType, const char* fieldName, - TypeID fieldType, + TYPEID fieldType, GenericFunction getter, GenericFunction setter, size_t memberPointerSize, void* memberPointer); void _embind_register_class_classmethod( - TypeID classType, + TYPEID classType, const char* methodName, - TypeID returnType, + TYPEID returnType, unsigned argCount, - TypeID argTypes[], + TYPEID argTypes[], GenericFunction method); void _embind_register_enum( - TypeID enumType, + TYPEID enumType, const char* name); void _embind_register_enum_value( - TypeID enumType, + TYPEID enumType, const char* valueName, GenericEnumValue value); void _embind_register_interface( - TypeID interfaceType, + TYPEID interfaceType, const char* name, GenericFunction constructor, GenericFunction destructor); @@ -193,7 +193,7 @@ namespace emscripten { internal::ArgTypeList args; internal::_embind_register_function( name, - internal::getTypeID(), + internal::TypeID::get(), args.count, args.types, reinterpret_cast(&internal::Invoker::invoke), @@ -321,7 +321,7 @@ namespace emscripten { value_tuple(const char* name) { internal::registerStandardTypes(); internal::_embind_register_tuple( - internal::getTypeID(), + internal::TypeID::get(), name, reinterpret_cast(&internal::raw_constructor), reinterpret_cast(&internal::raw_destructor)); @@ -330,8 +330,8 @@ namespace emscripten { template value_tuple& element(ElementType ClassType::*field) { internal::_embind_register_tuple_element( - internal::getTypeID(), - internal::getTypeID(), + internal::TypeID::get(), + internal::TypeID::get(), reinterpret_cast(&internal::FieldAccess::get), reinterpret_cast(&internal::FieldAccess::set), sizeof(field), @@ -343,8 +343,8 @@ namespace emscripten { template value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, ElementType)) { internal::_embind_register_tuple_element_accessor( - internal::getTypeID(), - internal::getTypeID(), + internal::TypeID::get(), + internal::TypeID::get(), reinterpret_cast(&internal::FieldAccess::template propertyGet), sizeof(getter), &getter, @@ -357,8 +357,8 @@ namespace emscripten { template value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, const ElementType&)) { internal::_embind_register_tuple_element_accessor( - internal::getTypeID(), - internal::getTypeID(), + internal::TypeID::get(), + internal::TypeID::get(), reinterpret_cast(&internal::FieldAccess::template propertyGet), sizeof(getter), &getter, @@ -371,8 +371,8 @@ namespace emscripten { template value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, const ElementType&&)) { internal::_embind_register_tuple_element_accessor( - internal::getTypeID(), - internal::getTypeID(), + internal::TypeID::get(), + internal::TypeID::get(), reinterpret_cast(&internal::FieldAccess::template propertyGet), sizeof(getter), &getter, @@ -385,8 +385,8 @@ namespace emscripten { template value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, ElementType&)) { internal::_embind_register_tuple_element_accessor( - internal::getTypeID(), - internal::getTypeID(), + internal::TypeID::get(), + internal::TypeID::get(), reinterpret_cast(&internal::FieldAccess::template propertyGet), sizeof(getter), &getter, @@ -403,7 +403,7 @@ namespace emscripten { value_struct(const char* name) { internal::registerStandardTypes(); internal::_embind_register_struct( - internal::getTypeID(), + internal::TypeID::get(), name, reinterpret_cast(&internal::raw_constructor), reinterpret_cast(&internal::raw_destructor)); @@ -412,9 +412,9 @@ namespace emscripten { template value_struct& field(const char* fieldName, FieldType ClassType::*field) { internal::_embind_register_struct_field( - internal::getTypeID(), + internal::TypeID::get(), fieldName, - internal::getTypeID(), + internal::TypeID::get(), reinterpret_cast(&internal::FieldAccess::get), reinterpret_cast(&internal::FieldAccess::set), sizeof(field), @@ -432,7 +432,7 @@ namespace emscripten { class_(const char* name) { internal::registerStandardTypes(); internal::_embind_register_class( - internal::getTypeID(), + internal::TypeID::get(), name, reinterpret_cast(&internal::raw_destructor)); } @@ -441,7 +441,7 @@ namespace emscripten { class_& constructor() { internal::ArgTypeList args; internal::_embind_register_class_constructor( - internal::getTypeID(), + internal::TypeID::get(), args.count, args.types, reinterpret_cast(&internal::raw_constructor)); @@ -452,9 +452,9 @@ namespace emscripten { class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...)) { internal::ArgTypeList args; internal::_embind_register_class_method( - internal::getTypeID(), + internal::TypeID::get(), methodName, - internal::getTypeID(), + internal::TypeID::get(), args.count, args.types, reinterpret_cast(&internal::MethodInvoker::invoke), @@ -467,9 +467,9 @@ namespace emscripten { class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const) { internal::ArgTypeList args; internal::_embind_register_class_method( - internal::getTypeID(), + internal::TypeID::get(), methodName, - internal::getTypeID(), + internal::TypeID::get(), args.count, args.types, reinterpret_cast(&internal::ConstMethodInvoker::invoke), @@ -481,9 +481,9 @@ namespace emscripten { template class_& field(const char* fieldName, FieldType ClassType::*field) { internal::_embind_register_class_field( - internal::getTypeID(), + internal::TypeID::get(), fieldName, - internal::getTypeID(), + internal::TypeID::get(), reinterpret_cast(&internal::FieldAccess::get), reinterpret_cast(&internal::FieldAccess::set), sizeof(field), @@ -495,9 +495,9 @@ namespace emscripten { class_& classmethod(const char* methodName, ReturnType (*classMethod)(Args...)) { internal::ArgTypeList args; internal::_embind_register_class_classmethod( - internal::getTypeID(), + internal::TypeID::get(), methodName, - internal::getTypeID(), + internal::TypeID::get(), args.count, args.types, reinterpret_cast(classMethod)); @@ -510,7 +510,7 @@ namespace emscripten { public: enum_(const char* name) { _embind_register_enum( - internal::getTypeID(), + internal::TypeID::get(), name); } @@ -520,7 +520,7 @@ namespace emscripten { static_assert(sizeof(value) <= sizeof(internal::GenericEnumValue), "enum type must fit in a GenericEnumValue"); _embind_register_enum_value( - internal::getTypeID(), + internal::TypeID::get(), name, static_cast(value)); return *this; @@ -637,7 +637,7 @@ namespace emscripten { interface(const char* name) { _embind_register_interface( - internal::getTypeID(), + internal::TypeID::get(), name, reinterpret_cast(&internal::create_interface_wrapper), reinterpret_cast(&internal::raw_destructor)); diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 96db93264a925..6dd4021c17791 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -19,17 +19,17 @@ namespace emscripten { EM_VAL _emval_get_property_by_unsigned_long(EM_VAL object, unsigned long key); void _emval_set_property(EM_VAL object, const char* key, EM_VAL value); void _emval_set_property_by_int(EM_VAL object, long key, EM_VAL value); - void _emval_as(EM_VAL value, emscripten::internal::TypeID returnType); + void _emval_as(EM_VAL value, emscripten::internal::TYPEID returnType); EM_VAL _emval_call( EM_VAL value, unsigned argCount, - internal::TypeID argTypes[] + internal::TYPEID argTypes[] /*, ... */); EM_VAL _emval_call_method( EM_VAL value, const char* methodName, unsigned argCount, - internal::TypeID argTypes[] + internal::TYPEID argTypes[] /*, ... */); } } @@ -106,7 +106,7 @@ namespace emscripten { typedef internal::EM_VAL (*TypedCall)( internal::EM_VAL, unsigned, - internal::TypeID argTypes[], + internal::TYPEID argTypes[], typename internal::BindingType::WireType...); TypedCall typedCall = reinterpret_cast(&internal::_emval_call); return val( @@ -124,7 +124,7 @@ namespace emscripten { internal::EM_VAL, const char* name, unsigned, - internal::TypeID argTypes[], + internal::TYPEID argTypes[], typename internal::BindingType::WireType...); TypedCall typedCall = reinterpret_cast(&internal::_emval_call_method); return val( @@ -142,10 +142,10 @@ namespace emscripten { typedef typename BT::WireType (*TypedAs)( internal::EM_VAL value, - emscripten::internal::TypeID returnType); + emscripten::internal::TYPEID returnType); TypedAs typedAs = reinterpret_cast(&internal::_emval_as); - typename BT::WireType wt = typedAs(handle, internal::getTypeID()); + typename BT::WireType wt = typedAs(handle, internal::TypeID::get()); internal::WireDeleter deleter(wt); return BT::fromWireType(wt); } diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index fbf0897d3c311..dcfd09d07c8f1 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -9,7 +9,7 @@ namespace emscripten { namespace internal { - typedef const struct _TypeID* TypeID; + typedef const struct _TYPEID* TYPEID; // This implementation is technically not legal, as it's not // required that two calls to typeid produce the same exact @@ -18,9 +18,18 @@ namespace emscripten { // an int, and store all TypeInfo we see in a map, allocating // new TypeIDs as we add new items to the map. template - inline TypeID getTypeID() { - return reinterpret_cast(&typeid(T)); - } + struct TypeID { + static TYPEID get() { + return reinterpret_cast(&typeid(T)); + } + }; + + template + struct TypeID> { + static TYPEID get() { + return TypeID::get(); + } + }; // count<> @@ -44,14 +53,14 @@ namespace emscripten { template<> struct ArgTypes<> { - static void fill(TypeID* argTypes) { + static void fill(TYPEID* argTypes) { } }; template struct ArgTypes { - static void fill(TypeID* argTypes) { - *argTypes = getTypeID(); + static void fill(TYPEID* argTypes) { + *argTypes = TypeID::get(); return ArgTypes::fill(argTypes + 1); } }; @@ -66,7 +75,7 @@ namespace emscripten { } unsigned count; - TypeID types[args_count]; + TYPEID types[args_count]; }; // BindingType @@ -191,6 +200,15 @@ namespace emscripten { } }; + template + struct GenericBindingType> { + typedef typename BindingType::WireType WireType; + + static WireType toWireType(std::unique_ptr p) { + return BindingType::toWireType(*p); + } + }; + template struct WireDeleter { typedef typename BindingType::WireType WireType; diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index b63a86aaeec48..befce08b1be81 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -9,25 +9,25 @@ namespace emscripten { if (first) { first = false; - _embind_register_void(getTypeID(), "void"); + _embind_register_void(TypeID::get(), "void"); - _embind_register_bool(getTypeID(), "bool", true, false); + _embind_register_bool(TypeID::get(), "bool", true, false); - _embind_register_integer(getTypeID(), "char"); - _embind_register_integer(getTypeID(), "signed char"); - _embind_register_integer(getTypeID(), "unsigned char"); - _embind_register_integer(getTypeID(), "short"); - _embind_register_integer(getTypeID(), "unsigned short"); - _embind_register_integer(getTypeID(), "int"); - _embind_register_integer(getTypeID(), "unsigned int"); - _embind_register_integer(getTypeID(), "long"); - _embind_register_integer(getTypeID(), "unsigned long"); + _embind_register_integer(TypeID::get(), "char"); + _embind_register_integer(TypeID::get(), "signed char"); + _embind_register_integer(TypeID::get(), "unsigned char"); + _embind_register_integer(TypeID::get(), "short"); + _embind_register_integer(TypeID::get(), "unsigned short"); + _embind_register_integer(TypeID::get(), "int"); + _embind_register_integer(TypeID::get(), "unsigned int"); + _embind_register_integer(TypeID::get(), "long"); + _embind_register_integer(TypeID::get(), "unsigned long"); - _embind_register_float(getTypeID(), "float"); - _embind_register_float(getTypeID(), "double"); + _embind_register_float(TypeID::get(), "float"); + _embind_register_float(TypeID::get(), "double"); - _embind_register_cstring(getTypeID(), "std::string"); - _embind_register_emval(getTypeID(), "emscripten::val"); + _embind_register_cstring(TypeID::get(), "std::string"); + _embind_register_emval(TypeID::get(), "emscripten::val"); } } } From db4baa7a70f37b6e4754dacf645d8674e52dad43 Mon Sep 17 00:00:00 2001 From: mey Date: Tue, 9 Oct 2012 17:54:38 -0700 Subject: [PATCH 135/544] Exposing std::shared_ptr to javascript. --- src/embind/embind.js | 82 +++++++++++++++++++++++++++++++- system/include/emscripten/bind.h | 26 ++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index d40d6ca2a543e..d9358afd9ba33 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -354,6 +354,86 @@ function __embind_register_struct_field( }; } +function __embind_register_shared_ptr( + ptrType, + classType, + name, + destructor, + internalPtrGetter +) { + name = Pointer_stringify(name); + classType = requireRegisteredType(classType, 'class'); + destructor = FUNCTION_TABLE[destructor]; + internalPtrGetter = FUNCTION_TABLE[internalPtrGetter]; + + var Handle = createNamedFunction(name, function(ptr) { + this.count = {value: 1}; + this.ptr = ptr; + + var args = new Array(1); + args[0] = ptr; + this.internalReference = classType.fromWireType(internalPtrGetter.apply(null, args)); + }); + + for(var prop in classType.Handle.prototype){ + if(prop === 'clone' || prop === 'move' === prop === 'delete'){ + continue; + } + + function createDuplicatedFunc(prop) { + return function() { + console.log(arguments); + return classType.Handle.prototype[prop].apply(this.internalReference, arguments); + } + } + + Handle.prototype[prop] = createDuplicatedFunc(prop); + } + + Handle.prototype.clone = function() { + if (!this.ptr) { + throw new BindingError(classType.name + ' instance already deleted'); + } + + var clone = Object.create(Handle.prototype); + clone.count = this.count; + clone.ptr = this.ptr; + + clone.count.value += 1; + return clone; + }; + + Handle.prototype.move = function() { + var rv = this.clone(); + this.delete(); + return rv; + }; + + Handle.prototype['delete'] = function() { + if (!this.ptr) { + throw new BindingError(classType.name + ' instance already deleted'); + } + + this.count.value -= 1; + if (0 === this.count.value) { + console.log(destructor); + destructor(this.ptr); + } + this.ptr = undefined; + } + + typeRegistry[ptrType] = { + name: name, + Handle: Handle, + fromWireType: function(ptr) { + return new Handle(ptr); + }, + toWireType: function(destructors, o) { + return o.ptr; + } + }; +} + function __embind_register_class( classType, name, @@ -479,7 +559,7 @@ function __embind_register_class_method( for (var i = 0; i < argCount; ++i) { args[i + 2] = argTypes[i].toWireType(destructors, arguments[i]); } - + var rv = returnType.fromWireType(invoker.apply(null, args)); runDestructors(destructors); return rv; diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 400a94728d840..2b84878e30215 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -91,6 +91,13 @@ namespace emscripten { size_t memberPointerSize, void* memberPointer); + void _embind_register_shared_ptr( + TYPEID ptrType, + TYPEID classType, + const char* ptrName, + GenericFunction destructor, + GenericFunction invoker); + void _embind_register_class( TYPEID classType, const char* className, @@ -215,6 +222,11 @@ namespace emscripten { delete ptr; } + template + ClassType* getSharedInternalPtr(std::shared_ptr* ptr) { + return ptr->get(); + } + template struct MethodInvoker { typedef ReturnType (ClassType::*MemberPointer)(Args...); @@ -424,6 +436,20 @@ namespace emscripten { } }; + template + class shared_ptr_ { + public: + shared_ptr_(const char* name) { + internal::registerStandardTypes(); + internal::_embind_register_shared_ptr( + internal::TypeID>::get(), + internal::TypeID::get(), + name, + reinterpret_cast(&internal::raw_destructor>), + reinterpret_cast(&internal::getSharedInternalPtr)); + } + }; + // TODO: support class definitions without constructors. // TODO: support external class constructors template From 60bae3faed65429634f1104531b08f938d20b7a3 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 10 Oct 2012 01:46:12 -0700 Subject: [PATCH 136/544] Some simplifications and optimizations to smart pointer support --- src/embind/embind.js | 92 ++++++++++++++------------------ system/include/emscripten/bind.h | 46 ++++++++-------- 2 files changed, 62 insertions(+), 76 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index d9358afd9ba33..790c097001927 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -354,49 +354,36 @@ function __embind_register_struct_field( }; } -function __embind_register_shared_ptr( - ptrType, - classType, - name, - destructor, - internalPtrGetter -) { - name = Pointer_stringify(name); - classType = requireRegisteredType(classType, 'class'); - destructor = FUNCTION_TABLE[destructor]; - internalPtrGetter = FUNCTION_TABLE[internalPtrGetter]; - - var Handle = createNamedFunction(name, function(ptr) { - this.count = {value: 1}; - this.ptr = ptr; - - var args = new Array(1); - args[0] = ptr; - this.internalReference = classType.fromWireType(internalPtrGetter.apply(null, args)); - }); +function __embind_register_smart_ptr( + pointerType, + pointeeType, + name, + destructor, + getPointee +) { + name = Pointer_stringify(name); + pointeeType = requireRegisteredType(pointeeType, 'class'); + destructor = FUNCTION_TABLE[destructor]; + getPointee = FUNCTION_TABLE[getPointee]; + + var Handle = createNamedFunction(name, function(ptr) { + this.count = {value: 1}; + this.smartPointer = ptr; + this.ptr = getPointee(ptr); + }); + + // TODO: test for SmartPtr.prototype.constructor property? + // We likely want it distinct from pointeeType.prototype.constructor + Handle.prototype = Object.create(pointeeType.Handle.prototype); - for(var prop in classType.Handle.prototype){ - if(prop === 'clone' || prop === 'move' === prop === 'delete'){ - continue; - } - - function createDuplicatedFunc(prop) { - return function() { - console.log(arguments); - return classType.Handle.prototype[prop].apply(this.internalReference, arguments); - } - } - - Handle.prototype[prop] = createDuplicatedFunc(prop); - } - - Handle.prototype.clone = function() { + Handle.prototype.clone = function() { if (!this.ptr) { - throw new BindingError(classType.name + ' instance already deleted'); + throw new BindingError(pointeeType.name + ' instance already deleted'); } var clone = Object.create(Handle.prototype); clone.count = this.count; + clone.smartPointer = this.smartPointer; clone.ptr = this.ptr; clone.count.value += 1; @@ -408,30 +395,29 @@ function __embind_register_shared_ptr( this.delete(); return rv; }; - - Handle.prototype['delete'] = function() { - if (!this.ptr) { - throw new BindingError(classType.name + ' instance already deleted'); + + Handle.prototype['delete'] = function() { + if (!this.ptr) { + throw new BindingError(pointeeType.name + ' instance already deleted'); } - + this.count.value -= 1; if (0 === this.count.value) { - console.log(destructor); - destructor(this.ptr); + destructor(this.smartPointer); } + this.smartPointer = undefined; this.ptr = undefined; - } - - typeRegistry[ptrType] = { - name: name, - Handle: Handle, - fromWireType: function(ptr) { - return new Handle(ptr); + } + + typeRegistry[pointerType] = { + name: name, + fromWireType: function(ptr) { + return new Handle(ptr); }, toWireType: function(destructors, o) { - return o.ptr; + return o.ptr; } - }; + }; } function __embind_register_class( diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 2b84878e30215..6902eb86a9d1a 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -91,12 +91,12 @@ namespace emscripten { size_t memberPointerSize, void* memberPointer); - void _embind_register_shared_ptr( - TYPEID ptrType, - TYPEID classType, - const char* ptrName, - GenericFunction destructor, - GenericFunction invoker); + void _embind_register_smart_ptr( + TYPEID pointerType, + TYPEID pointeeType, + const char* pointerName, + GenericFunction destructor, + GenericFunction getPointee); void _embind_register_class( TYPEID classType, @@ -157,7 +157,7 @@ namespace emscripten { class BindingsDefinition { public: template - BindingsDefinition(Function fn) { + BindingsDefinition(Function fn) { fn(); } }; @@ -222,9 +222,10 @@ namespace emscripten { delete ptr; } - template - ClassType* getSharedInternalPtr(std::shared_ptr* ptr) { - return ptr->get(); + template + typename PointerType::element_type* get_pointee(PointerType* ptr) { + // TODO: replace with general pointer traits implementation + return ptr->get(); } template @@ -436,19 +437,18 @@ namespace emscripten { } }; - template - class shared_ptr_ { - public: - shared_ptr_(const char* name) { - internal::registerStandardTypes(); - internal::_embind_register_shared_ptr( - internal::TypeID>::get(), - internal::TypeID::get(), - name, - reinterpret_cast(&internal::raw_destructor>), - reinterpret_cast(&internal::getSharedInternalPtr)); - } - }; + template + inline void register_smart_ptr(const char* name) { + typedef typename PointerType::element_type PointeeType; + + internal::registerStandardTypes(); + internal::_embind_register_smart_ptr( + internal::TypeID::get(), + internal::TypeID::get(), + name, + reinterpret_cast(&internal::raw_destructor), + reinterpret_cast(&internal::get_pointee)); + } // TODO: support class definitions without constructors. // TODO: support external class constructors From 681ea9fc51ee9908008f0913356f673018c11c2e Mon Sep 17 00:00:00 2001 From: mey Date: Wed, 10 Oct 2012 15:21:58 -0700 Subject: [PATCH 137/544] Fixing some tabs and removing some duplication in smart ptr embind. --- src/embind/embind.js | 20 ++++++++++++++------ system/include/emscripten/wire.h | 18 +++++++++--------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 790c097001927..56f3520a55bfe 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -389,12 +389,6 @@ function __embind_register_smart_ptr( clone.count.value += 1; return clone; }; - - Handle.prototype.move = function() { - var rv = this.clone(); - this.delete(); - return rv; - }; Handle.prototype['delete'] = function() { if (!this.ptr) { @@ -433,6 +427,20 @@ function __embind_register_class( this.ptr = ptr; }); + Handle.prototype.clone = function() { + if (!this.ptr) { + throw new BindingError(pointeeType.name + ' instance already deleted'); + } + + var clone = Object.create(Handle.prototype); + clone.count = this.count; + clone.smartPointer = this.smartPointer; + clone.ptr = this.ptr; + + clone.count.value += 1; + return clone; + }; + Handle.prototype.clone = function() { if (!this.ptr) { throw new BindingError(classType.name + ' instance already deleted'); diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index dcfd09d07c8f1..be8e4f6d76cab 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -19,17 +19,17 @@ namespace emscripten { // new TypeIDs as we add new items to the map. template struct TypeID { - static TYPEID get() { - return reinterpret_cast(&typeid(T)); - } + static TYPEID get() { + return reinterpret_cast(&typeid(T)); + } }; template - struct TypeID> { - static TYPEID get() { - return TypeID::get(); - } - }; + struct TypeID> { + static TYPEID get() { + return TypeID::get(); + } + }; // count<> @@ -205,7 +205,7 @@ namespace emscripten { typedef typename BindingType::WireType WireType; static WireType toWireType(std::unique_ptr p) { - return BindingType::toWireType(*p); + return BindingType::toWireType(*p); } }; From d0bf1b0aea625931255c31641ba53ad6d4cee7c3 Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Tue, 23 Oct 2012 12:23:03 -0700 Subject: [PATCH 138/544] Handle shared_ptr correctly.(keep underlying pointer point to the same address) There was some global variable dependency. These bleed thru tests and affected test result. Adding a way to reset this state. --- src/embind/embind.js | 2 +- src/embind/emval.js | 5 +++++ system/include/emscripten/bind.h | 4 ++-- system/include/emscripten/wire.h | 26 +++++++++++++++++++++++++- 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 56f3520a55bfe..f63a8eff33e89 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -409,7 +409,7 @@ function __embind_register_smart_ptr( return new Handle(ptr); }, toWireType: function(destructors, o) { - return o.ptr; + return o.smartPointer; } }; } diff --git a/src/embind/emval.js b/src/embind/emval.js index 9574ab3797fef..26ceaf4649595 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -13,12 +13,17 @@ Module.count_emval_handles = function() { return _emval_handle_array.length; }; +Module.reset_emval_handles = function() { + _emval_handle_array = []; + _emval_free_list = []; +} // Private C++ API function __emval_register(value) { var handle = _emval_free_list.length ? _emval_free_list.pop() : _emval_handle_array.length; + _emval_handle_array[handle] = {refcount: 1, value: value}; return handle; } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 6902eb86a9d1a..b8858284d6ee3 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -223,9 +223,9 @@ namespace emscripten { } template - typename PointerType::element_type* get_pointee(PointerType* ptr) { + typename PointerType::element_type* get_pointee(PointerType ptr) { // TODO: replace with general pointer traits implementation - return ptr->get(); + return ptr.get(); } template diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index be8e4f6d76cab..ab4caa97629ac 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -30,6 +30,13 @@ namespace emscripten { return TypeID::get(); } }; + + template + struct TypeID> { + static TYPEID get() { + return TypeID::get(); + } + }; // count<> @@ -209,6 +216,24 @@ namespace emscripten { } }; + template + struct GenericBindingType> { + typedef typename std::shared_ptr ActualT; + typedef ActualT* WireType; + + static WireType toWireType(std::shared_ptr p) { + return new std::shared_ptr(p); + } + + static std::shared_ptr fromWireType(WireType p) { + return *p; + } + + static void destroy(WireType p) { + delete p; + } + }; + template struct WireDeleter { typedef typename BindingType::WireType WireType; @@ -236,6 +261,5 @@ namespace emscripten { auto toWireType(const T& v) -> typename BindingType::WireType { return BindingType::toWireType(v); } - } } From f91f1ddf374b4f881cd5cf2ba35263cfbe965224 Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Fri, 26 Oct 2012 15:18:35 -0700 Subject: [PATCH 139/544] removed duplicate code / unnecessary code --- src/embind/embind.js | 19 +++---------------- system/include/emscripten/wire.h | 7 ------- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index f63a8eff33e89..1f5da572e5a73 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -402,7 +402,7 @@ function __embind_register_smart_ptr( this.smartPointer = undefined; this.ptr = undefined; } - + typeRegistry[pointerType] = { name: name, fromWireType: function(ptr) { @@ -427,20 +427,6 @@ function __embind_register_class( this.ptr = ptr; }); - Handle.prototype.clone = function() { - if (!this.ptr) { - throw new BindingError(pointeeType.name + ' instance already deleted'); - } - - var clone = Object.create(Handle.prototype); - clone.count = this.count; - clone.smartPointer = this.smartPointer; - clone.ptr = this.ptr; - - clone.count.value += 1; - return clone; - }; - Handle.prototype.clone = function() { if (!this.ptr) { throw new BindingError(classType.name + ' instance already deleted'); @@ -533,6 +519,7 @@ function __embind_register_class_method( classType = requireRegisteredType(classType, 'class'); methodName = Pointer_stringify(methodName); var humanName = classType.name + '.' + methodName; + returnType = requireRegisteredType(returnType, 'method ' + humanName + ' return value'); argTypes = requireArgumentTypes(argCount, argTypes, 'method ' + humanName); invoker = FUNCTION_TABLE[invoker]; @@ -553,7 +540,7 @@ function __embind_register_class_method( for (var i = 0; i < argCount; ++i) { args[i + 2] = argTypes[i].toWireType(destructors, arguments[i]); } - + var rv = returnType.fromWireType(invoker.apply(null, args)); runDestructors(destructors); return rv; diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index ab4caa97629ac..b618be83ca9fe 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -31,13 +31,6 @@ namespace emscripten { } }; - template - struct TypeID> { - static TYPEID get() { - return TypeID::get(); - } - }; - // count<> template From 1c0c7be7aaf6f231bd29d8b9db68506be6a0a5b1 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 30 Oct 2012 14:01:52 -0700 Subject: [PATCH 140/544] Some minor generated code size reductions. --- src/embind/emval.js | 46 +++++++++++++++++++++----------- system/include/emscripten/bind.h | 2 +- system/include/emscripten/val.h | 24 +++++++++++++++++ 3 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index 26ceaf4649595..b2adb89a3c4b0 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -16,7 +16,8 @@ Module.count_emval_handles = function() { Module.reset_emval_handles = function() { _emval_handle_array = []; _emval_free_list = []; -} +}; + // Private C++ API function __emval_register(value) { @@ -86,31 +87,46 @@ function __emval_as(handle, returnType) { return returnType.toWireType(destructors, _emval_handle_array[handle].value); } -function __emval_call(handle, argCount, argTypes) { - var args = Array.prototype.slice.call(arguments, 3); - var fn = _emval_handle_array[handle].value; +function parseParameters(argCount, argTypes, argWireTypes) { var a = new Array(argCount); for (var i = 0; i < argCount; ++i) { var argType = requireRegisteredType( HEAP32[(argTypes >> 2) + i], "parameter " + i); - a[i] = argType.fromWireType(args[i]); + a[i] = argType.fromWireType(argWireTypes[i]); } - var rv = fn.apply(undefined, a); + return a; +} + +function __emval_call(handle, argCount, argTypes) { + var fn = _emval_handle_array[handle].value; + var args = parseParameters( + argCount, + argTypes, + Array.prototype.slice.call(arguments, 3)); + var rv = fn.apply(undefined, args); return __emval_register(rv); } function __emval_call_method(handle, name, argCount, argTypes) { name = Pointer_stringify(name); - var args = Array.prototype.slice.call(arguments, 4); + + var args = parseParameters( + argCount, + argTypes, + Array.prototype.slice.call(arguments, 4)); var obj = _emval_handle_array[handle].value; - var a = new Array(argCount); - for (var i = 0; i < argCount; ++i) { - var argType = requireRegisteredType( - HEAP32[(argTypes >> 2) + i], - "parameter " + i); - a[i] = argType.fromWireType(args[i]); - } - var rv = obj[name].apply(obj, a); + var rv = obj[name].apply(obj, args); return __emval_register(rv); } + +function __emval_call_void_method(handle, name, argCount, argTypes) { + name = Pointer_stringify(name); + + var args = parseParameters( + argCount, + argTypes, + Array.prototype.slice.call(arguments, 4)); + var obj = _emval_handle_array[handle].value; + obj[name].apply(obj, args); +} diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index b8858284d6ee3..2de14fab76f2b 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -632,7 +632,7 @@ namespace emscripten { template struct Caller { static void call(val& v, const char* name, Args... args) { - v.call(name, args...); + v.call_void(name, args...); } }; diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 6dd4021c17791..ada896388c358 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -31,6 +31,12 @@ namespace emscripten { unsigned argCount, internal::TYPEID argTypes[] /*, ... */); + void _emval_call_void_method( + EM_VAL value, + const char* methodName, + unsigned argCount, + internal::TYPEID argTypes[] + /*, ...*/); } } @@ -136,6 +142,24 @@ namespace emscripten { internal::toWireType(args)...)); } + template + void call_void(const char* name, Args... args) { + internal::ArgTypeList argList; + typedef void (*TypedCall)( + internal::EM_VAL, + const char* name, + unsigned, + internal::TYPEID argTypes[], + typename internal::BindingType::WireType...); + TypedCall typedCall = reinterpret_cast(&internal::_emval_call_void_method); + return typedCall( + handle, + name, + argList.count, + argList.types, + internal::toWireType(args)...); + } + template T as() const { typedef internal::BindingType BT; From df6ba03eed0f08abe51fb1a5afd3e9d2c94a878f Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 30 Oct 2012 15:18:22 -0700 Subject: [PATCH 141/544] Fix several ownership/lifetime bugs in argument wire types --- src/embind/embind.js | 4 ++-- src/embind/emval.js | 5 ----- system/include/emscripten/bind.h | 2 +- system/include/emscripten/val.h | 2 +- system/include/emscripten/wire.h | 34 ++++++++------------------------ 5 files changed, 12 insertions(+), 35 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 1f5da572e5a73..3e916ed4b9350 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -368,8 +368,8 @@ function __embind_register_smart_ptr( var Handle = createNamedFunction(name, function(ptr) { this.count = {value: 1}; - this.smartPointer = ptr; - this.ptr = getPointee(ptr); + this.smartPointer = ptr; // std::shared_ptr* + this.ptr = getPointee(ptr); // T* }); // TODO: test for SmartPtr.prototype.constructor property? diff --git a/src/embind/emval.js b/src/embind/emval.js index b2adb89a3c4b0..6552b0a733117 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -13,11 +13,6 @@ Module.count_emval_handles = function() { return _emval_handle_array.length; }; -Module.reset_emval_handles = function() { - _emval_handle_array = []; - _emval_free_list = []; -}; - // Private C++ API function __emval_register(value) { diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 2de14fab76f2b..69d1f08c37b59 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -223,7 +223,7 @@ namespace emscripten { } template - typename PointerType::element_type* get_pointee(PointerType ptr) { + typename PointerType::element_type* get_pointee(const PointerType& ptr) { // TODO: replace with general pointer traits implementation return ptr.get(); } diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index ada896388c358..8369caf761d3f 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -194,7 +194,7 @@ namespace emscripten { return v.handle; } static val fromWireType(WireType v) { - return val(v); + return val::take_ownership(v); } }; } diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index b618be83ca9fe..ceabd28053689 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -130,7 +130,7 @@ namespace emscripten { template<> struct BindingType { typedef char* WireType; - static WireType toWireType(std::string v) { + static WireType toWireType(const std::string& v) { return strdup(v.c_str()); } static std::string fromWireType(char* v) { @@ -138,14 +138,14 @@ namespace emscripten { } }; - template<> - struct BindingType { - typedef char* WireType; - static WireType toWireType(std::string v) { - return strdup(v.c_str()); + template + struct BindingType { + typedef typename BindingType::WireType WireType; + static WireType toWireType(const T& v) { + return BindingType::toWireType(v); } - static std::string fromWireType(char* v) { - return std::string(v); + static T fromWireType(WireType wt) { + return BindingType::fromWireType(wt); } }; @@ -209,24 +209,6 @@ namespace emscripten { } }; - template - struct GenericBindingType> { - typedef typename std::shared_ptr ActualT; - typedef ActualT* WireType; - - static WireType toWireType(std::shared_ptr p) { - return new std::shared_ptr(p); - } - - static std::shared_ptr fromWireType(WireType p) { - return *p; - } - - static void destroy(WireType p) { - delete p; - } - }; - template struct WireDeleter { typedef typename BindingType::WireType WireType; From 6e2ce5357fb9938974201d8ab6e6d724d66987f5 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 30 Oct 2012 16:05:26 -0700 Subject: [PATCH 142/544] Add the ability to extend the prototype of native classes from JavaScript. --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 3e916ed4b9350..c4e7d843cd1ce 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -462,7 +462,7 @@ function __embind_register_class( var body = constructor.body; body.apply(this, arguments); }); - constructor.prototype = Object.create(Handle.prototype); + constructor.prototype = Handle.prototype; typeRegistry[classType] = { name: name, From e71c512ef802afce1f78cb589e4decd0dd695711 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 30 Oct 2012 16:41:25 -0700 Subject: [PATCH 143/544] Add validation that prevents registering the same type multiple times (either by name or type ID) --- src/embind/embind.js | 78 +++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index c4e7d843cd1ce..5c32383140c9b 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -4,6 +4,13 @@ /*global Pointer_stringify, writeStringToMemory*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ +function exposePublicSymbol(name, value) { + if (Module.hasOwnProperty(name)) { + throw new BindingError("Cannot register public name '" + name + "' twice"); + } + Module[name] = value; +} + function createNamedFunction(name, body) { /*jshint evil:true*/ return new Function( @@ -25,30 +32,29 @@ function _embind_repr(v) { var typeRegistry = {}; -function validateType(type, name) { +function registerType(type, name, info) { if (!type) { throw new BindingError('type "' + name + '" must have a positive integer typeid pointer'); } - if (undefined !== typeRegistry[type]) { - throw new BindingError('cannot register type "' + name + '" twice'); + if (typeRegistry.hasOwnProperty(type)) { + throw new BindingError("Cannot register type '" + name + "' twice"); } + typeRegistry[type] = info; } function __embind_register_void(voidType, name) { name = Pointer_stringify(name); - validateType(voidType, name); - typeRegistry[voidType] = { + registerType(voidType, name, { name: name, fromWireType: function() { return undefined; } - }; + }); } function __embind_register_bool(boolType, name, trueValue, falseValue) { name = Pointer_stringify(name); - validateType(boolType, name); - typeRegistry[boolType] = { + registerType(boolType, name, { name: name, toWireType: function(destructors, o) { return o ? trueValue : falseValue; @@ -56,13 +62,12 @@ function __embind_register_bool(boolType, name, trueValue, falseValue) { fromWireType: function(wt) { return wt === trueValue; }, - }; + }); } function __embind_register_integer(primitiveType, name) { name = Pointer_stringify(name); - validateType(primitiveType, name); - typeRegistry[primitiveType] = { + registerType(primitiveType, name, { name: name, toWireType: function(destructors, value) { if (typeof value !== "number") { @@ -73,13 +78,12 @@ function __embind_register_integer(primitiveType, name) { fromWireType: function(value) { return value; } - }; + }); } function __embind_register_float(primitiveType, name) { name = Pointer_stringify(name); - validateType(primitiveType, name); - typeRegistry[primitiveType] = { + registerType(primitiveType, name, { name: name, toWireType: function(destructors, value) { if (typeof value !== "number") { @@ -90,13 +94,12 @@ function __embind_register_float(primitiveType, name) { fromWireType: function(value) { return value; } - }; + }); } function __embind_register_cstring(stringType, name) { name = Pointer_stringify(name); - validateType(stringType, name); - typeRegistry[stringType] = { + registerType(stringType, name, { name: name, toWireType: function(destructors, value) { var ptr = _malloc(value.length + 1); @@ -110,13 +113,12 @@ function __embind_register_cstring(stringType, name) { _free(value); return rv; } - }; + }); } function __embind_register_emval(emvalType, name) { name = Pointer_stringify(name); - validateType(emvalType, name); - typeRegistry[emvalType] = { + registerType(emvalType, name, { name: name, toWireType: function(destructors, value) { return __emval_register(value); @@ -126,7 +128,7 @@ function __embind_register_emval(emvalType, name) { __emval_decref(handle); return rv; } - }; + }); } var BindingError = Error; @@ -169,7 +171,7 @@ function __embind_register_function(name, returnType, argCount, argTypes, invoke invoker = FUNCTION_TABLE[invoker]; argTypes = requireArgumentTypes(argCount, argTypes, name); - Module[name] = function() { + exposePublicSymbol(name, function() { if (arguments.length !== argCount) { throw new BindingError('emscripten binding function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + argCount); } @@ -182,7 +184,7 @@ function __embind_register_function(name, returnType, argCount, argTypes, invoke var rv = returnType.fromWireType(invoker.apply(null, args)); runDestructors(destructors); return rv; - }; + }); } function __embind_register_tuple(tupleType, name, constructor, destructor) { @@ -192,7 +194,7 @@ function __embind_register_tuple(tupleType, name, constructor, destructor) { var elements = []; - typeRegistry[tupleType] = { + registerType(tupleType, name, { name: name, elements: elements, fromWireType: function(ptr) { @@ -217,7 +219,7 @@ function __embind_register_tuple(tupleType, name, constructor, destructor) { destructors.push(ptr); return ptr; } - }; + }); } function copyMemberPointer(memberPointer, memberPointerSize) { @@ -297,7 +299,7 @@ function __embind_register_struct( constructor = FUNCTION_TABLE[constructor]; destructor = FUNCTION_TABLE[destructor]; - typeRegistry[structType] = { + registerType(structType, name, { fields: {}, fromWireType: function(ptr) { var fields = this.fields; @@ -323,7 +325,7 @@ function __embind_register_struct( destructors.push(ptr); return ptr; } - }; + }); } function __embind_register_struct_field( @@ -401,9 +403,9 @@ function __embind_register_smart_ptr( } this.smartPointer = undefined; this.ptr = undefined; - } + }; - typeRegistry[pointerType] = { + registerType(pointerType, name, { name: name, fromWireType: function(ptr) { return new Handle(ptr); @@ -411,7 +413,7 @@ function __embind_register_smart_ptr( toWireType: function(destructors, o) { return o.smartPointer; } - }; + }); } function __embind_register_class( @@ -464,7 +466,7 @@ function __embind_register_class( }); constructor.prototype = Handle.prototype; - typeRegistry[classType] = { + registerType(classType, name, { name: name, constructor: constructor, Handle: Handle, @@ -474,9 +476,9 @@ function __embind_register_class( toWireType: function(destructors, o) { return o.ptr; } - }; + }); - Module[name] = constructor; + exposePublicSymbol(name, constructor); } function __embind_register_class_constructor( @@ -625,7 +627,7 @@ function __embind_register_enum( } Enum.values = {}; - typeRegistry[enumType] = { + registerType(enumType, name, { name: name, constructor: Enum, toWireType: function(destructors, c) { @@ -634,9 +636,9 @@ function __embind_register_enum( fromWireType: function(c) { return Enum.values[c]; }, - }; + }); - Module[name] = Enum; + exposePublicSymbol(name, Enum); } function __embind_register_enum_value( @@ -667,7 +669,7 @@ function __embind_register_interface( constructor = FUNCTION_TABLE[constructor]; destructor = FUNCTION_TABLE[destructor]; - typeRegistry[interfaceType] = { + registerType(interfaceType, name, { name: name, toWireType: function(destructors, o) { var handle = __emval_register(o); @@ -676,6 +678,6 @@ function __embind_register_interface( destructors.push(ptr); return ptr; }, - }; + }); } From db7397e72edefdea48076e0087a08085658366f1 Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Thu, 1 Nov 2012 14:17:13 -0700 Subject: [PATCH 144/544] There can be an empty shared ptr. It is totally valid. --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 5c32383140c9b..e9c92f5e44a77 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -393,7 +393,7 @@ function __embind_register_smart_ptr( }; Handle.prototype['delete'] = function() { - if (!this.ptr) { + if (!this.ptr && !this.smartPointer) { throw new BindingError(pointeeType.name + ' instance already deleted'); } From 3703d2b5cdf66f7ef0ce6f56a54856102e4a1cfd Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 1 Nov 2012 18:13:48 -0700 Subject: [PATCH 145/544] Checkpoint work towards exposing call policies for raw pointers. --- src/embind/embind.js | 11 +++ system/include/emscripten/bind.h | 129 +++++++++++++++++++++++-------- system/include/emscripten/wire.h | 115 +++++++++++++++++++++------ 3 files changed, 198 insertions(+), 57 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index e9c92f5e44a77..e086883805904 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -416,6 +416,17 @@ function __embind_register_smart_ptr( }); } +function __embind_register_raw_pointer( + pointeeType, + pointerType +) { + pointeeType = requireRegisteredType(pointeeType, 'class'); + var name = pointeeType.name + '*'; + registerType(pointerType, name, { + name: name, + }); +} + function __embind_register_class( classType, name, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 69d1f08c37b59..f2e70b31dd0f9 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -165,6 +165,27 @@ namespace emscripten { } namespace emscripten { + //////////////////////////////////////////////////////////////////////////////// + // POLICIES + //////////////////////////////////////////////////////////////////////////////// + + template + struct arg { + static constexpr int index = Index; + }; + + template + struct allow_raw_pointer { + template + struct Transform { + typedef typename std::conditional< + Index == Slot::index, + internal::AllowedRawPointer::type>, + InputType + >::type type; + }; + }; + namespace internal { template struct Invoker { @@ -193,6 +214,10 @@ namespace emscripten { }; } + //////////////////////////////////////////////////////////////////////////////// + // FUNCTIONS + //////////////////////////////////////////////////////////////////////////////// + template void function(const char* name, ReturnType (fn)(Args...)) { internal::registerStandardTypes(); @@ -328,6 +353,10 @@ namespace emscripten { }; } + //////////////////////////////////////////////////////////////////////////////// + // VALUE TUPLES + //////////////////////////////////////////////////////////////////////////////// + template class value_tuple { public: @@ -410,6 +439,10 @@ namespace emscripten { } }; + //////////////////////////////////////////////////////////////////////////////// + // VALUE STRUCTS + //////////////////////////////////////////////////////////////////////////////// + template class value_struct { public: @@ -437,6 +470,10 @@ namespace emscripten { } }; + //////////////////////////////////////////////////////////////////////////////// + // SMART POINTERS + //////////////////////////////////////////////////////////////////////////////// + template inline void register_smart_ptr(const char* name) { typedef typename PointerType::element_type PointeeType; @@ -450,55 +487,67 @@ namespace emscripten { reinterpret_cast(&internal::get_pointee)); } + //////////////////////////////////////////////////////////////////////////////// + // CLASSES + //////////////////////////////////////////////////////////////////////////////// + // TODO: support class definitions without constructors. // TODO: support external class constructors template class class_ { public: class_(const char* name) { - internal::registerStandardTypes(); - internal::_embind_register_class( - internal::TypeID::get(), + using namespace internal; + + registerStandardTypes(); + _embind_register_class( + TypeID::get(), name, - reinterpret_cast(&internal::raw_destructor)); + reinterpret_cast(&raw_destructor)); } template class_& constructor() { - internal::ArgTypeList args; - internal::_embind_register_class_constructor( - internal::TypeID::get(), + using namespace internal; + + ArgTypeList args; + _embind_register_class_constructor( + TypeID::get(), args.count, args.types, - reinterpret_cast(&internal::raw_constructor)); + reinterpret_cast(&raw_constructor)); return *this; } - template - class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...)) { - internal::ArgTypeList args; - internal::_embind_register_class_method( - internal::TypeID::get(), + template + class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...), Policies...) { + using namespace internal; + + typename WithPolicies::template ArgTypeList args; + _embind_register_class_method( + TypeID::get(), methodName, - internal::TypeID::get(), + TypeID::get(), args.count, args.types, - reinterpret_cast(&internal::MethodInvoker::invoke), + reinterpret_cast(&MethodInvoker::invoke), sizeof(memberFunction), &memberFunction); return *this; } - template - class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const) { - internal::ArgTypeList args; - internal::_embind_register_class_method( - internal::TypeID::get(), + template + class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const, Policies...) { + using namespace internal; + + typename WithPolicies::template ArgTypeList args; + _embind_register_class_method( + TypeID::get(), methodName, - internal::TypeID::get(), + TypeID::get(), args.count, args.types, - reinterpret_cast(&internal::ConstMethodInvoker::invoke), + reinterpret_cast(&ConstMethodInvoker::invoke), sizeof(memberFunction), &memberFunction); return *this; @@ -506,31 +555,39 @@ namespace emscripten { template class_& field(const char* fieldName, FieldType ClassType::*field) { - internal::_embind_register_class_field( - internal::TypeID::get(), + using namespace internal; + + _embind_register_class_field( + TypeID::get(), fieldName, - internal::TypeID::get(), - reinterpret_cast(&internal::FieldAccess::get), - reinterpret_cast(&internal::FieldAccess::set), + TypeID::get(), + reinterpret_cast(&FieldAccess::get), + reinterpret_cast(&FieldAccess::set), sizeof(field), &field); return *this; } - template - class_& classmethod(const char* methodName, ReturnType (*classMethod)(Args...)) { - internal::ArgTypeList args; - internal::_embind_register_class_classmethod( - internal::TypeID::get(), + template + class_& classmethod(const char* methodName, ReturnType (*classMethod)(Args...), Policies...) { + using namespace internal; + + typename WithPolicies::template ArgTypeList args; + _embind_register_class_classmethod( + TypeID::get(), methodName, - internal::TypeID::get(), + TypeID::get(), args.count, args.types, - reinterpret_cast(classMethod)); + reinterpret_cast(classMethod)); return *this; } }; + //////////////////////////////////////////////////////////////////////////////// + // ENUMS + //////////////////////////////////////////////////////////////////////////////// + template class enum_ { public: @@ -597,6 +654,10 @@ namespace emscripten { }; } + //////////////////////////////////////////////////////////////////////////////// + // INTERFACES + //////////////////////////////////////////////////////////////////////////////// + template class wrapper : public InterfaceType { public: diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index ceabd28053689..ba78906b98808 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -11,12 +11,19 @@ namespace emscripten { namespace internal { typedef const struct _TYPEID* TYPEID; + extern "C" { + void _embind_register_raw_pointer( + TYPEID pointee, + TYPEID pointer); + } + // This implementation is technically not legal, as it's not // required that two calls to typeid produce the same exact - // std::type_info instance. That said, it's likely to work. - // Should it not work in the future: replace TypeID with - // an int, and store all TypeInfo we see in a map, allocating - // new TypeIDs as we add new items to the map. + // std::type_info instance. That said, it's likely to work + // given Emscripten compiles everything into one binary. + // Should it not work in the future: replace TypeID with an + // int, and store all TypeInfo we see in a map, allocating new + // TypeIDs as we add new items to the map. template struct TypeID { static TYPEID get() { @@ -30,6 +37,24 @@ namespace emscripten { return TypeID::get(); } }; + + template + struct TypeID { + static_assert(!std::is_pointer::value, "Implicitly binding raw pointers is illegal. Specify ???"); + }; + + template + struct AllowedRawPointer { + }; + + template + struct TypeID> { + static TYPEID get() { + TYPEID ptype = reinterpret_cast(&typeid(T*)); + _embind_register_raw_pointer(TypeID::get(), ptype); + return ptype; + } + }; // count<> @@ -38,44 +63,81 @@ namespace emscripten { template<> struct count<> { - enum { value = 0 }; + constexpr static unsigned value = 0; }; template struct count { - enum { value = 1 + count::value }; + constexpr static unsigned value = 1 + count::value; }; - // ArgTypeList<> + // ExecutePolicies<> - template - struct ArgTypes; + template + struct ExecutePolicies; template<> - struct ArgTypes<> { + struct ExecutePolicies<> { + template + struct With { + typedef T type; + }; + }; + + template + struct ExecutePolicies { + template + struct With { + typedef typename Policy::template Transform< + typename ExecutePolicies::template With::type, + Index + >::type type; + }; + }; + + // ArgTypes<> + + template + struct ArgTypes; + + template + struct ArgTypes { + template static void fill(TYPEID* argTypes) { } }; - template - struct ArgTypes { + template + struct ArgTypes { + template static void fill(TYPEID* argTypes) { - *argTypes = TypeID::get(); - return ArgTypes::fill(argTypes + 1); + typedef typename ExecutePolicies::template With::type TransformT; + + *argTypes = TypeID::get(); + return ArgTypes::fill(argTypes + 1); } }; - template - struct ArgTypeList { - enum { args_count = count::value }; + // WithPolicies<...>::ArgTypeList<...> + template + struct WithPolicies { + template + struct ArgTypeList { + enum { args_count = count::value }; - ArgTypeList() { - count = args_count; - ArgTypes::fill(types); - } + ArgTypeList() { + count = args_count; + ArgTypes<0, Args...>::template fill(types); + } - unsigned count; - TYPEID types[args_count]; + unsigned count; + TYPEID types[args_count]; + }; + }; + + // TODO: kill this and make every signature support policies + template + struct ArgTypeList : WithPolicies<>::ArgTypeList { }; // BindingType @@ -149,6 +211,13 @@ namespace emscripten { } }; + template + struct BindingType; + + template + struct BindingType> { + }; + template struct EnumBindingType { typedef Enum WireType; From eb5226e16cca6df5c4c889213150970dc9c6d5c3 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 1 Nov 2012 18:22:36 -0700 Subject: [PATCH 146/544] Class static methods were downright broken. --- src/embind/embind.js | 14 ++++++++------ system/include/emscripten/bind.h | 2 ++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index e086883805904..ef1851e139de7 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -566,27 +566,29 @@ function __embind_register_class_classmethod( returnType, argCount, argTypes, - method + invoker, + fn ) { classType = requireRegisteredType(classType, 'class'); methodName = Pointer_stringify(methodName); var humanName = classType.name + '.' + methodName; returnType = requireRegisteredType(returnType, 'classmethod ' + humanName + ' return value'); argTypes = requireArgumentTypes(argCount, argTypes, 'classmethod ' + humanName); - method = FUNCTION_TABLE[method]; + invoker = FUNCTION_TABLE[invoker]; classType.constructor[methodName] = function() { if (arguments.length !== argCount) { - throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + throw new BindingError('emscripten binding class method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); } var destructors = []; - var args = new Array(argCount); + var args = new Array(argCount + 1); + args[0] = fn; for (var i = 0; i < argCount; ++i) { - args[i] = argTypes[i].toWireType(destructors, arguments[i]); + args[i + 1] = argTypes[i].toWireType(destructors, arguments[i]); } - var rv = returnType.fromWireType(method.apply(null, args)); + var rv = returnType.fromWireType(invoker.apply(null, args)); runDestructors(destructors); return rv; }; diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index f2e70b31dd0f9..e48be414bffcc 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -134,6 +134,7 @@ namespace emscripten { TYPEID returnType, unsigned argCount, TYPEID argTypes[], + GenericFunction invoker, GenericFunction method); void _embind_register_enum( @@ -579,6 +580,7 @@ namespace emscripten { TypeID::get(), args.count, args.types, + reinterpret_cast(&internal::Invoker::invoke), reinterpret_cast(classMethod)); return *this; } From 8a4997cf16605a7811f32a30116356b9bc0e912e Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 1 Nov 2012 18:27:21 -0700 Subject: [PATCH 147/544] Kill some duplication --- src/embind/embind.js | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index ef1851e139de7..43238f07af97b 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -165,15 +165,10 @@ function runDestructors(destructors) { } } -function __embind_register_function(name, returnType, argCount, argTypes, invoker, fn) { - name = Pointer_stringify(name); - returnType = requireRegisteredType(returnType, "Function " + name + " return value"); - invoker = FUNCTION_TABLE[invoker]; - argTypes = requireArgumentTypes(argCount, argTypes, name); - - exposePublicSymbol(name, function() { +function makeInvoker(name, returnType, argCount, argTypes, invoker, fn) { + return function() { if (arguments.length !== argCount) { - throw new BindingError('emscripten binding function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + throw new BindingError('function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + argCount); } var destructors = []; var args = new Array(argCount + 1); @@ -184,7 +179,16 @@ function __embind_register_function(name, returnType, argCount, argTypes, invoke var rv = returnType.fromWireType(invoker.apply(null, args)); runDestructors(destructors); return rv; - }); + } +} + +function __embind_register_function(name, returnType, argCount, argTypes, invoker, fn) { + name = Pointer_stringify(name); + returnType = requireRegisteredType(returnType, "Function " + name + " return value"); + invoker = FUNCTION_TABLE[invoker]; + argTypes = requireArgumentTypes(argCount, argTypes, name); + + exposePublicSymbol(name, makeInvoker(name, returnType, argCount, argTypes, invoker, fn)); } function __embind_register_tuple(tupleType, name, constructor, destructor) { @@ -576,23 +580,7 @@ function __embind_register_class_classmethod( argTypes = requireArgumentTypes(argCount, argTypes, 'classmethod ' + humanName); invoker = FUNCTION_TABLE[invoker]; - classType.constructor[methodName] = function() { - if (arguments.length !== argCount) { - throw new BindingError('emscripten binding class method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); - } - - var destructors = []; - var args = new Array(argCount + 1); - args[0] = fn; - for (var i = 0; i < argCount; ++i) { - args[i + 1] = argTypes[i].toWireType(destructors, arguments[i]); - } - - var rv = returnType.fromWireType(invoker.apply(null, args)); - runDestructors(destructors); - return rv; - }; -} + classType.constructor[methodName] = makeInvoker(humanName, returnType, argCount, argTypes, invoker, fn);} function __embind_register_class_field( classType, From 3f20ded152916e31d7c85763074686461db7e3b8 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 1 Nov 2012 18:27:54 -0700 Subject: [PATCH 148/544] jshint --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 43238f07af97b..dd8e2b3b20f09 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -179,7 +179,7 @@ function makeInvoker(name, returnType, argCount, argTypes, invoker, fn) { var rv = returnType.fromWireType(invoker.apply(null, args)); runDestructors(destructors); return rv; - } + }; } function __embind_register_function(name, returnType, argCount, argTypes, invoker, fn) { From 6014feed714b61f57f26254de6a2d2c7d89363e5 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 1 Nov 2012 18:37:40 -0700 Subject: [PATCH 149/544] Add support for raw pointers to embind --- src/embind/embind.js | 3 +++ system/include/emscripten/wire.h | 8 +++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index dd8e2b3b20f09..8cfb87c8a9969 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -428,6 +428,9 @@ function __embind_register_raw_pointer( var name = pointeeType.name + '*'; registerType(pointerType, name, { name: name, + toWireType: function(destructors, o) { + return o.ptr; + } }); } diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index ba78906b98808..276042aa1fcff 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -212,10 +212,12 @@ namespace emscripten { }; template - struct BindingType; + struct BindingType { + typedef T* WireType; - template - struct BindingType> { + static T* fromWireType(WireType wt) { + return wt; + } }; template From 8691fb1726c63263f99e86b8dd29d1a90d639579 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 1 Nov 2012 19:33:42 -0700 Subject: [PATCH 150/544] Allow multiple pointer arguments and allow multiple functions taking the same raw pointer type --- src/embind/embind.js | 32 +++++++++-------- system/include/emscripten/bind.h | 38 ++++++++++++++------ system/include/emscripten/val.h | 62 ++++++++++++++++++-------------- system/include/emscripten/wire.h | 19 ++-------- 4 files changed, 84 insertions(+), 67 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 8cfb87c8a9969..bbbeb96c80dc8 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -420,22 +420,10 @@ function __embind_register_smart_ptr( }); } -function __embind_register_raw_pointer( - pointeeType, - pointerType -) { - pointeeType = requireRegisteredType(pointeeType, 'class'); - var name = pointeeType.name + '*'; - registerType(pointerType, name, { - name: name, - toWireType: function(destructors, o) { - return o.ptr; - } - }); -} - function __embind_register_class( classType, + pointerType, + constPointerType, name, destructor ) { @@ -496,6 +484,22 @@ function __embind_register_class( } }); + var pointerName = name + '*'; + registerType(pointerType, pointerName, { + name: pointerName, + toWireType: function(destructors, o) { + return o.ptr; + } + }); + + var constPointerName = name + ' const*'; + registerType(constPointerType, constPointerName, { + name: constPointerName, + toWireType: function(destructors, o) { + return o.ptr; + } + }); + exposePublicSymbol(name, constructor); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index e48be414bffcc..9bfef10beea64 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -100,6 +100,8 @@ namespace emscripten { void _embind_register_class( TYPEID classType, + TYPEID pointerType, + TYPEID constPointerType, const char* className, GenericFunction destructor); @@ -187,6 +189,18 @@ namespace emscripten { }; }; + // whitelist all raw pointers + struct allow_raw_pointers { + template + struct Transform { + typedef typename std::conditional< + std::is_pointer::value, + internal::AllowedRawPointer::type>, + InputType + >::type type; + }; + }; + namespace internal { template struct Invoker { @@ -219,18 +233,20 @@ namespace emscripten { // FUNCTIONS //////////////////////////////////////////////////////////////////////////////// - template + template void function(const char* name, ReturnType (fn)(Args...)) { - internal::registerStandardTypes(); + using namespace internal; + + registerStandardTypes(); - internal::ArgTypeList args; - internal::_embind_register_function( + typename WithPolicies::template ArgTypeList args; + _embind_register_function( name, - internal::TypeID::get(), + TypeID::get(), args.count, args.types, - reinterpret_cast(&internal::Invoker::invoke), - reinterpret_cast(fn)); + reinterpret_cast(&Invoker::invoke), + reinterpret_cast(fn)); } namespace internal { @@ -503,15 +519,17 @@ namespace emscripten { registerStandardTypes(); _embind_register_class( TypeID::get(), + TypeID>::get(), + TypeID>::get(), name, reinterpret_cast(&raw_destructor)); } - template - class_& constructor() { + template + class_& constructor(Policies...) { using namespace internal; - ArgTypeList args; + typename WithPolicies::template ArgTypeList args; _embind_register_class_constructor( TypeID::get(), args.count, diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 8369caf761d3f..e3e5790118ab4 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -19,7 +19,7 @@ namespace emscripten { EM_VAL _emval_get_property_by_unsigned_long(EM_VAL object, unsigned long key); void _emval_set_property(EM_VAL object, const char* key, EM_VAL value); void _emval_set_property_by_int(EM_VAL object, long key, EM_VAL value); - void _emval_as(EM_VAL value, emscripten::internal::TYPEID returnType); + void _emval_as(EM_VAL value, TYPEID returnType); EM_VAL _emval_call( EM_VAL value, unsigned argCount, @@ -108,69 +108,77 @@ namespace emscripten { template val operator()(Args... args) { - internal::ArgTypeList argList; - typedef internal::EM_VAL (*TypedCall)( - internal::EM_VAL, + using namespace internal; + + WithPolicies<>::ArgTypeList argList; + typedef EM_VAL (*TypedCall)( + EM_VAL, unsigned, - internal::TYPEID argTypes[], - typename internal::BindingType::WireType...); - TypedCall typedCall = reinterpret_cast(&internal::_emval_call); + TYPEID argTypes[], + typename BindingType::WireType...); + TypedCall typedCall = reinterpret_cast(&_emval_call); return val( typedCall( handle, argList.count, argList.types, - internal::toWireType(args)...)); + toWireType(args)...)); } template val call(const char* name, Args... args) { - internal::ArgTypeList argList; - typedef internal::EM_VAL (*TypedCall)( - internal::EM_VAL, + using namespace internal; + + WithPolicies<>::ArgTypeList argList; + typedef EM_VAL (*TypedCall)( + EM_VAL, const char* name, unsigned, - internal::TYPEID argTypes[], - typename internal::BindingType::WireType...); - TypedCall typedCall = reinterpret_cast(&internal::_emval_call_method); + TYPEID argTypes[], + typename BindingType::WireType...); + TypedCall typedCall = reinterpret_cast(&_emval_call_method); return val( typedCall( handle, name, argList.count, argList.types, - internal::toWireType(args)...)); + toWireType(args)...)); } template void call_void(const char* name, Args... args) { - internal::ArgTypeList argList; + using namespace internal; + + WithPolicies<>::ArgTypeList argList; typedef void (*TypedCall)( - internal::EM_VAL, + EM_VAL, const char* name, unsigned, - internal::TYPEID argTypes[], - typename internal::BindingType::WireType...); - TypedCall typedCall = reinterpret_cast(&internal::_emval_call_void_method); + TYPEID argTypes[], + typename BindingType::WireType...); + TypedCall typedCall = reinterpret_cast(&_emval_call_void_method); return typedCall( handle, name, argList.count, argList.types, - internal::toWireType(args)...); + toWireType(args)...); } template T as() const { - typedef internal::BindingType BT; + using namespace internal; + + typedef BindingType BT; typedef typename BT::WireType (*TypedAs)( - internal::EM_VAL value, - emscripten::internal::TYPEID returnType); - TypedAs typedAs = reinterpret_cast(&internal::_emval_as); + EM_VAL value, + TYPEID returnType); + TypedAs typedAs = reinterpret_cast(&_emval_as); - typename BT::WireType wt = typedAs(handle, internal::TypeID::get()); - internal::WireDeleter deleter(wt); + typename BT::WireType wt = typedAs(handle, TypeID::get()); + WireDeleter deleter(wt); return BT::fromWireType(wt); } diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 276042aa1fcff..cee0f5393d487 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -11,12 +11,6 @@ namespace emscripten { namespace internal { typedef const struct _TYPEID* TYPEID; - extern "C" { - void _embind_register_raw_pointer( - TYPEID pointee, - TYPEID pointer); - } - // This implementation is technically not legal, as it's not // required that two calls to typeid produce the same exact // std::type_info instance. That said, it's likely to work @@ -40,7 +34,7 @@ namespace emscripten { template struct TypeID { - static_assert(!std::is_pointer::value, "Implicitly binding raw pointers is illegal. Specify ???"); + static_assert(!std::is_pointer::value, "Implicitly binding raw pointers is illegal. Specify allow_raw_pointer>"); }; template @@ -50,9 +44,7 @@ namespace emscripten { template struct TypeID> { static TYPEID get() { - TYPEID ptype = reinterpret_cast(&typeid(T*)); - _embind_register_raw_pointer(TypeID::get(), ptype); - return ptype; + return reinterpret_cast(&typeid(T*)); } }; @@ -114,7 +106,7 @@ namespace emscripten { typedef typename ExecutePolicies::template With::type TransformT; *argTypes = TypeID::get(); - return ArgTypes::fill(argTypes + 1); + return ArgTypes::template fill(argTypes + 1); } }; @@ -135,11 +127,6 @@ namespace emscripten { }; }; - // TODO: kill this and make every signature support policies - template - struct ArgTypeList : WithPolicies<>::ArgTypeList { - }; - // BindingType template From ebbe87925570d572204c105ff15a1c5581c76d54 Mon Sep 17 00:00:00 2001 From: jinsuck Date: Fri, 2 Nov 2012 15:36:52 -0700 Subject: [PATCH 151/544] to get string from emval --- system/include/emscripten/wire.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index cee0f5393d487..89b18d7720846 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -185,6 +185,9 @@ namespace emscripten { static std::string fromWireType(char* v) { return std::string(v); } + static void destroy(WireType v) { + delete v; + } }; template From 848bdefa4e082936f3b1e26cbd9d0239efb9cf62 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 5 Nov 2012 12:26:16 -0800 Subject: [PATCH 152/544] std::string's WireType::destroy should be free(), not delete. --- system/include/emscripten/wire.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 89b18d7720846..89e68c684b894 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -186,7 +186,7 @@ namespace emscripten { return std::string(v); } static void destroy(WireType v) { - delete v; + free(v); } }; From 565823a14ad14a5c16f8c40f714963e7cb259e33 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 5 Nov 2012 13:20:13 -0800 Subject: [PATCH 153/544] Returning an empty shared_ptr returns null to JavaScript. Similarly, passing null into a shared_ptr creates an empty shared_ptr. --- src/embind/embind.js | 16 +++++++++++++--- system/include/emscripten/wire.h | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index bbbeb96c80dc8..98d4b13e44574 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -60,7 +60,9 @@ function __embind_register_bool(boolType, name, trueValue, falseValue) { return o ? trueValue : falseValue; }, fromWireType: function(wt) { - return wt === trueValue; + // ambiguous emscripten ABI: sometimes return values are + // true or false, and sometimes integers (0 or 1) + return !!wt; }, }); } @@ -397,7 +399,7 @@ function __embind_register_smart_ptr( }; Handle.prototype['delete'] = function() { - if (!this.ptr && !this.smartPointer) { + if (!this.ptr) { throw new BindingError(pointeeType.name + ' instance already deleted'); } @@ -412,10 +414,18 @@ function __embind_register_smart_ptr( registerType(pointerType, name, { name: name, fromWireType: function(ptr) { + if (!getPointee(ptr)) { + destructor(ptr); + return null; + } return new Handle(ptr); }, toWireType: function(destructors, o) { - return o.smartPointer; + if (null === o) { + return 0; + } else { + return o.smartPointer; + } } }); } diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 89e68c684b894..452628a05a1bc 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -210,6 +210,24 @@ namespace emscripten { } }; + template + struct BindingType> { + typedef std::shared_ptr shared_ptr; + typedef std::shared_ptr* WireType; + + static WireType toWireType(shared_ptr p) { + return new shared_ptr(p); + } + + static shared_ptr fromWireType(WireType wt) { + if (wt) { + return shared_ptr(*wt); + } else { + return shared_ptr(); + } + } + }; + template struct EnumBindingType { typedef Enum WireType; From 3c5dead6741c0a2f3268b04d1ee9a0262f368785 Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Mon, 5 Nov 2012 14:16:46 -0800 Subject: [PATCH 154/544] Add support for std::vector. --- src/embind/embind.js | 45 ++++++++++++++++++++++++ system/include/emscripten/bind.h | 59 ++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index 98d4b13e44574..0036013d639ca 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -430,6 +430,51 @@ function __embind_register_smart_ptr( }); } +function __embind_register_vector( + vectorType, + elementType, + name, + constructor, + destructor, + length, + getter, + setter +) { + name = Pointer_stringify(name); + elementType = requireRegisteredType(elementType, 'vector ' + name); + + constructor = FUNCTION_TABLE[constructor]; + destructor = FUNCTION_TABLE[destructor]; + length = FUNCTION_TABLE[length]; + getter = FUNCTION_TABLE[getter]; + setter = FUNCTION_TABLE[setter]; + + registerType(vectorType, name, { + name: name, + fromWireType: function(ptr) { + var arr = []; + var n = length(ptr); + + for (var i = 0; i < n; i++) { + var v = elementType.fromWireType(getter(ptr, i)); + arr.push(v); + } + + destructor(ptr); + return arr; + }, + toWireType: function(destructors, o) { + var vec = constructor(); + for (var val in o) { + setter(vec, elementType.toWireType(destructors, o[val])); + } + destructors.push(destructor); + destructors.push(vec); + return vec; + } + }); +} + function __embind_register_class( classType, pointerType, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 9bfef10beea64..d929337827024 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -98,6 +99,16 @@ namespace emscripten { GenericFunction destructor, GenericFunction getPointee); + void _embind_register_vector( + TYPEID vectorType, + TYPEID elementType, + const char* name, + GenericFunction constructor, + GenericFunction destructor, + GenericFunction length, + GenericFunction getter, + GenericFunction setter); + void _embind_register_class( TYPEID classType, TYPEID pointerType, @@ -368,6 +379,33 @@ namespace emscripten { setter(ptr, FieldBinding::fromWireType(value)); } }; + + template + struct Vector { + typedef typename VectorType::value_type ElementType; + typedef internal::BindingType FieldBinding; + typedef typename FieldBinding::WireType WireType; + + static int length( + VectorType* ptr + ) { + return (*ptr).size(); + } + + static WireType getAt( + VectorType* ptr, + int pos + ) { + return FieldBinding::toWireType((*ptr).at(pos)); + } + + static void push_back( + VectorType* ptr, + WireType val + ) { + (*ptr).push_back(FieldBinding::fromWireType(val)); + } + }; } //////////////////////////////////////////////////////////////////////////////// @@ -504,6 +542,27 @@ namespace emscripten { reinterpret_cast(&internal::get_pointee)); } + //////////////////////////////////////////////////////////////////////////////// + // VECTORS + //////////////////////////////////////////////////////////////////////////////// + + template + inline void register_vector(const char* name) { + typedef typename VectorType::value_type ElementType; + + internal::registerStandardTypes(); + internal::_embind_register_vector( + internal::TypeID::get(), + internal::TypeID::get(), + name, + reinterpret_cast(&internal::raw_constructor), + reinterpret_cast(&internal::raw_destructor), + reinterpret_cast(&internal::Vector::length), + reinterpret_cast(&internal::Vector::getAt), + reinterpret_cast(&internal::Vector::push_back) + ); + } + //////////////////////////////////////////////////////////////////////////////// // CLASSES //////////////////////////////////////////////////////////////////////////////// From d90ef85c03fa1094936d00b635df554c40ff0361 Mon Sep 17 00:00:00 2001 From: Llorens Marti Garcia Date: Mon, 5 Nov 2012 17:22:01 -0800 Subject: [PATCH 155/544] Fix on EnumBindingType --- system/include/emscripten/wire.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 452628a05a1bc..3e96482a552ac 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -238,6 +238,8 @@ namespace emscripten { static Enum fromWireType(WireType v) { return v; } + static void destroy(WireType) { + } }; template From 6326240227f217b85ac505163deb83990ecf92e6 Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Fri, 9 Nov 2012 15:54:58 -0800 Subject: [PATCH 156/544] This enables passing smart ptr as an element of val. --- system/include/emscripten/wire.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 3e96482a552ac..99c4f926d64b6 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -226,6 +226,10 @@ namespace emscripten { return shared_ptr(); } } + + static void destroy(WireType p) { + delete p; + } }; template From d622aa9caba106ddc31f6aee01082eb029a35515 Mon Sep 17 00:00:00 2001 From: mey Date: Fri, 9 Nov 2012 17:06:23 -0800 Subject: [PATCH 157/544] Exposing std::function to javascript. --- src/embind/embind.js | 81 +++++++++++++++++++++++++++++++- system/include/emscripten/bind.h | 48 +++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 0036013d639ca..1953542a9174a 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -421,6 +421,7 @@ function __embind_register_smart_ptr( return new Handle(ptr); }, toWireType: function(destructors, o) { + return o.smartPointer; if (null === o) { return 0; } else { @@ -430,6 +431,84 @@ function __embind_register_smart_ptr( }); } +function __embind_register_function_ptr( + name, + functorType, + returnType, + argCount, + argTypes, + destructor, + invoker +) { + name = Pointer_stringify(name); + var humanName = 'functor::' + name; + + returnType = requireRegisteredType(returnType); + argTypes = requireArgumentTypes(argCount, argTypes, humanName); + destructor = FUNCTION_TABLE[destructor]; + invoker = FUNCTION_TABLE[invoker]; + + var Handle = createNamedFunction(name, function(ptr) { + this.count = {value: 1}; + this.functorPtr = ptr; + }); + + Handle.prototype['delete'] = function() { + if (!this.functorPtr) { + throw new BindingError(functorType.name + ' instance already deleted'); + } + + this.count.value -= 1; + if(0 === this.count.value) { + destructor(this.functorPtr); + } + this.functorPtr = undefined; + }; + + function createFunctor(ptr) { + var h = new Handle(ptr); + + var invoke = function() { + if(!this.functorPtr) { + throw new BindingError('cannot call invoke functor ' + humanName + ' on deleted object'); + } + + if (arguments.length !== argCount) { + throw new BindingError('emscripten functor ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + } + + var destructors = []; + var args = new Array(argCount + 1); + args[0] = this.functorPtr; + + for (var i = 0; i < argCount; ++i) { + args[i + 1] = argTypes[i].toWireType(destructors, arguments[i]); + } + + var rv = returnType.fromWireType(invoker.apply(null, args)); + runDestructors(destructors); + return rv; + }.bind(h); + + invoke.handle = h; + invoke['delete'] = function() { + this.handle.delete(); + }; + + return invoke; + } + + registerType(functorType, name, { + name: name, + fromWireType: function(ptr) { + return createFunctor(ptr); + }, + toWireType: function(destructors, o) { + return o.ptr; + } + }); +} + function __embind_register_vector( vectorType, elementType, @@ -489,7 +568,7 @@ function __embind_register_class( this.count = {value: 1}; this.ptr = ptr; }); - + Handle.prototype.clone = function() { if (!this.ptr) { throw new BindingError(classType.name + ' instance already deleted'); diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index d929337827024..1ce7967d08807 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -99,6 +100,18 @@ namespace emscripten { GenericFunction destructor, GenericFunction getPointee); +<<<<<<< HEAD +======= + void _embind_register_function_ptr( + const char* name, + TYPEID functorType, + TYPEID returnType, + unsigned argCount, + TYPEID argTypes[], + GenericFunction destructor, + GenericFunction invoker); + +>>>>>>> Exposing std::function to javascript. void _embind_register_vector( TYPEID vectorType, TYPEID elementType, @@ -281,6 +294,21 @@ namespace emscripten { return ptr.get(); } + template + struct FunctorInvoker { + static typename internal::BindingType::WireType invoke( + const FunctorType& ptr, + typename internal::BindingType::WireType... args + ) { + return internal::BindingType::toWireType( + ptr( + internal::BindingType::fromWireType(args)... + ) + ); + } + }; + + template struct MethodInvoker { typedef ReturnType (ClassType::*MemberPointer)(Args...); @@ -542,6 +570,26 @@ namespace emscripten { reinterpret_cast(&internal::get_pointee)); } + //////////////////////////////////////////////////////////////////////////////// + // FUNCTION POINTERS + //////////////////////////////////////////////////////////////////////////////// + template + inline void register_function_ptr(const char* name) { + typedef std::function FunctorType; + + internal::registerStandardTypes(); + typename internal::WithPolicies::template ArgTypeList args; + internal::_embind_register_function_ptr( + name, + internal::TypeID::get(), + internal::TypeID::get(), + args.count, + args.types, + reinterpret_cast(&internal::raw_destructor), + reinterpret_cast(&internal::FunctorInvoker::invoke) + ); + } + //////////////////////////////////////////////////////////////////////////////// // VECTORS //////////////////////////////////////////////////////////////////////////////// From 01212260c27a76c7f02b62a4c42c3d4501351e60 Mon Sep 17 00:00:00 2001 From: mey Date: Fri, 9 Nov 2012 17:10:10 -0800 Subject: [PATCH 158/544] Merging. --- system/include/emscripten/bind.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 1ce7967d08807..97a9b5cc0bcab 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -100,8 +100,6 @@ namespace emscripten { GenericFunction destructor, GenericFunction getPointee); -<<<<<<< HEAD -======= void _embind_register_function_ptr( const char* name, TYPEID functorType, @@ -111,7 +109,6 @@ namespace emscripten { GenericFunction destructor, GenericFunction invoker); ->>>>>>> Exposing std::function to javascript. void _embind_register_vector( TYPEID vectorType, TYPEID elementType, From 8ff84649adf2120ad7800f9bba03fff194b657bb Mon Sep 17 00:00:00 2001 From: mey Date: Fri, 9 Nov 2012 17:14:07 -0800 Subject: [PATCH 159/544] Merging. --- src/embind/embind.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 1953542a9174a..4cf58028d65ea 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -421,7 +421,6 @@ function __embind_register_smart_ptr( return new Handle(ptr); }, toWireType: function(destructors, o) { - return o.smartPointer; if (null === o) { return 0; } else { From 69f2f335d3194ae6ef482169e23ad8edcd8dd1ca Mon Sep 17 00:00:00 2001 From: mey Date: Mon, 12 Nov 2012 16:47:03 -0800 Subject: [PATCH 160/544] Fleshing out functors and expanding them. --- src/embind/embind.js | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 4cf58028d65ea..74afda02abc58 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -492,7 +492,24 @@ function __embind_register_function_ptr( invoke.handle = h; invoke['delete'] = function() { this.handle.delete(); - }; + }.bind(invoke); + invoke.clone = function() { + if (!this.handle.functorPtr) { + throw new BindingError(functorType.name + ' instance already deleted'); + } + + var clone = createFunctor(this.handle.functorPtr); + clone.handle.count = this.handle.count; + clone.handle.ptr = this.handle.ptr; + + clone.handle.count.value += 1; + return clone; + }.bind(invoke); + invoke.move = function() { + var rv = this.clone(); + this.delete(); + return rv; + }.bind(invoke); return invoke; } @@ -503,7 +520,7 @@ function __embind_register_function_ptr( return createFunctor(ptr); }, toWireType: function(destructors, o) { - return o.ptr; + return o.handle.functorPtr; } }); } From 2c34b6dc6cf61087ff4f341bc33aefaa968803ba Mon Sep 17 00:00:00 2001 From: jinsuck Date: Tue, 13 Nov 2012 13:23:23 -0800 Subject: [PATCH 161/544] Allow constructing interface wrapper from existing interface object --- system/include/emscripten/bind.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 97a9b5cc0bcab..cb8f396de0979 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -767,7 +767,15 @@ namespace emscripten { initialized = true; return *this; } - + + optional& operator=(optional& o) { + if (initialized) { + get()->~T(); + } + new(get()) T(*o); + initialized = true; + } + private: T* get() { return reinterpret_cast(&data); @@ -785,6 +793,14 @@ namespace emscripten { template class wrapper : public InterfaceType { public: + wrapper() {} // to avoid error "call to implicitly deleted construrtor..." + + wrapper(InterfaceType* interface) { + // why dynamic_cast causes javascript crash? + wrapper* iw = static_cast*>(interface); + jsobj = iw->jsobj; + } + // Not necessary in any example so far, but appeases a compiler warning. virtual ~wrapper() {} From 778b8eb983544434b2350fe3bb36363bbef0b347 Mon Sep 17 00:00:00 2001 From: jinsuck Date: Wed, 14 Nov 2012 15:00:56 -0800 Subject: [PATCH 162/544] add a syntactic sugar to for cloning to a shared pointer of interface wrapper --- system/include/emscripten/bind.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index cb8f396de0979..ffbf940150542 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -806,6 +806,13 @@ namespace emscripten { typedef InterfaceType interface; + template + static std::shared_ptr cloneToSharedPtr(InterfaceType& i) { + ConcreteWrapperType* cw = new ConcreteWrapperType(&i); + InterfaceType* ip = dynamic_cast(cw); + return std::shared_ptr(ip); + } + void initialize(internal::EM_VAL handle) { if (jsobj) { internal::_embind_fatal_error( From 0d745fa1167007c29554da9f10bd6a92bc0d171b Mon Sep 17 00:00:00 2001 From: jinsuck Date: Fri, 16 Nov 2012 11:35:59 -0800 Subject: [PATCH 163/544] 1) add a method to run global javascript function on val 2) fix a bug to return val from interface wrapper --- src/embind/emval.js | 7 +++++++ system/include/emscripten/val.h | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/embind/emval.js b/src/embind/emval.js index 6552b0a733117..f74c0fd5482e3 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -66,6 +66,13 @@ function __emval_get_property_by_unsigned_long(handle, k) { return __emval_register(_emval_handle_array[handle].value[k]); } +function __emval_eval_global_method(handle, objectName, methodName) { + var objectNameStr = Pointer_stringify(objectName); + var methodNameStr = Pointer_stringify(methodName); + var result = eval.call(null, objectNameStr)[methodNameStr](_emval_handle_array[handle].value); + return __emval_register(result); +} + function __emval_set_property(handle, k, value) { k = Pointer_stringify(k); _emval_handle_array[handle].value[k] = _emval_handle_array[value].value; diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index e3e5790118ab4..68f5b63e3e379 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -17,6 +17,7 @@ namespace emscripten { EM_VAL _emval_get_property(EM_VAL object, const char* key); EM_VAL _emval_get_property_by_long(EM_VAL object, long key); EM_VAL _emval_get_property_by_unsigned_long(EM_VAL object, unsigned long key); + EM_VAL _emval_eval_global_method(EM_VAL object, const char* objectName, const char* methodName); void _emval_set_property(EM_VAL object, const char* key, EM_VAL value); void _emval_set_property_by_int(EM_VAL object, long key, EM_VAL value); void _emval_as(EM_VAL value, TYPEID returnType); @@ -98,6 +99,10 @@ namespace emscripten { return val(internal::_emval_get_property_by_unsigned_long(handle, key)); } + val eval_global_method(const char* objectName, const char* methodName) { + return val(internal::_emval_eval_global_method(handle, objectName, methodName)); + } + void set(const char* key, val v) { internal::_emval_set_property(handle, key, v.handle); } @@ -204,6 +209,8 @@ namespace emscripten { static val fromWireType(WireType v) { return val::take_ownership(v); } + static void destroy(WireType v) { + } }; } } From e237bfd79d7ae865f7eeaccefff5e8a9c7afe309 Mon Sep 17 00:00:00 2001 From: mey Date: Fri, 16 Nov 2012 13:56:27 -0800 Subject: [PATCH 164/544] Removing Functor as a specific type; folding operator call into the class definition. --- src/embind/embind.js | 159 +++++++++++-------------------- system/include/emscripten/bind.h | 62 ++++++------ 2 files changed, 90 insertions(+), 131 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 74afda02abc58..ff5adf645317f 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -430,101 +430,6 @@ function __embind_register_smart_ptr( }); } -function __embind_register_function_ptr( - name, - functorType, - returnType, - argCount, - argTypes, - destructor, - invoker -) { - name = Pointer_stringify(name); - var humanName = 'functor::' + name; - - returnType = requireRegisteredType(returnType); - argTypes = requireArgumentTypes(argCount, argTypes, humanName); - destructor = FUNCTION_TABLE[destructor]; - invoker = FUNCTION_TABLE[invoker]; - - var Handle = createNamedFunction(name, function(ptr) { - this.count = {value: 1}; - this.functorPtr = ptr; - }); - - Handle.prototype['delete'] = function() { - if (!this.functorPtr) { - throw new BindingError(functorType.name + ' instance already deleted'); - } - - this.count.value -= 1; - if(0 === this.count.value) { - destructor(this.functorPtr); - } - this.functorPtr = undefined; - }; - - function createFunctor(ptr) { - var h = new Handle(ptr); - - var invoke = function() { - if(!this.functorPtr) { - throw new BindingError('cannot call invoke functor ' + humanName + ' on deleted object'); - } - - if (arguments.length !== argCount) { - throw new BindingError('emscripten functor ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); - } - - var destructors = []; - var args = new Array(argCount + 1); - args[0] = this.functorPtr; - - for (var i = 0; i < argCount; ++i) { - args[i + 1] = argTypes[i].toWireType(destructors, arguments[i]); - } - - var rv = returnType.fromWireType(invoker.apply(null, args)); - runDestructors(destructors); - return rv; - }.bind(h); - - invoke.handle = h; - invoke['delete'] = function() { - this.handle.delete(); - }.bind(invoke); - invoke.clone = function() { - if (!this.handle.functorPtr) { - throw new BindingError(functorType.name + ' instance already deleted'); - } - - var clone = createFunctor(this.handle.functorPtr); - clone.handle.count = this.handle.count; - clone.handle.ptr = this.handle.ptr; - - clone.handle.count.value += 1; - return clone; - }.bind(invoke); - invoke.move = function() { - var rv = this.clone(); - this.delete(); - return rv; - }.bind(invoke); - - return invoke; - } - - registerType(functorType, name, { - name: name, - fromWireType: function(ptr) { - return createFunctor(ptr); - }, - toWireType: function(destructors, o) { - return o.handle.functorPtr; - } - }); -} - function __embind_register_vector( vectorType, elementType, @@ -579,10 +484,25 @@ function __embind_register_class( ) { name = Pointer_stringify(name); destructor = FUNCTION_TABLE[destructor]; - + var Handle = createNamedFunction(name, function(ptr) { - this.count = {value: 1}; - this.ptr = ptr; + var h = function() { + if(h.operator_call !== undefined) { + return h.operator_call.apply(h, arguments); + } else { + throw new BindingError(name + ' does not define call operator'); + } + }; + + h.count = {value: 1}; + h.ptr = ptr; + + for(var prop in Handle.prototype) { + var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop); + Object.defineProperty(h, prop, dp); + } + + return h; }); Handle.prototype.clone = function() { @@ -618,7 +538,7 @@ function __embind_register_class( var constructor = createNamedFunction(name, function() { var body = constructor.body; - body.apply(this, arguments); + return body.apply(this, arguments); }); constructor.prototype = Handle.prototype; @@ -676,7 +596,8 @@ function __embind_register_class_constructor( var ptr = constructor.apply(null, args); runDestructors(destructors); - classType.Handle.call(this, ptr); + + return classType.Handle.call(this, ptr); }; } @@ -700,6 +621,7 @@ function __embind_register_class_method( memberFunction = copyMemberPointer(memberFunction, memberFunctionSize); classType.Handle.prototype[methodName] = function() { + if (!this.ptr) { throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } @@ -737,7 +659,42 @@ function __embind_register_class_classmethod( argTypes = requireArgumentTypes(argCount, argTypes, 'classmethod ' + humanName); invoker = FUNCTION_TABLE[invoker]; - classType.constructor[methodName] = makeInvoker(humanName, returnType, argCount, argTypes, invoker, fn);} + classType.constructor[methodName] = makeInvoker(humanName, returnType, argCount, argTypes, invoker, fn); +} + +function __embind_register_class_operator_call( + classType, + returnType, + argCount, + argTypes, + invoker +) { + classType = requireRegisteredType(classType, 'class'); + returnType = requireRegisteredType(returnType, 'method ' + humanName + ' return value'); + argTypes = requireArgumentTypes(argCount, argTypes, 'method ' + humanName); + invoker = FUNCTION_TABLE[invoker]; + var humanName = classType.name + '.' + 'operator_call'; + + classType.Handle.prototype.operator_call = function() { + if (!this.ptr) { + throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } + if (arguments.length !== argCount) { + throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + } + + var destructors = []; + var args = new Array(argCount + 1); + args[0] = this.ptr; + for (var i = 0; i < argCount; ++i) { + args[i + 1] = argTypes[i].toWireType(destructors, arguments[i]); + } + + var rv = returnType.fromWireType(invoker.apply(null, args)); + runDestructors(destructors); + return rv; + } +} function __embind_register_class_field( classType, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index ffbf940150542..e20a5e688e965 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -100,15 +100,6 @@ namespace emscripten { GenericFunction destructor, GenericFunction getPointee); - void _embind_register_function_ptr( - const char* name, - TYPEID functorType, - TYPEID returnType, - unsigned argCount, - TYPEID argTypes[], - GenericFunction destructor, - GenericFunction invoker); - void _embind_register_vector( TYPEID vectorType, TYPEID elementType, @@ -160,6 +151,14 @@ namespace emscripten { GenericFunction invoker, GenericFunction method); + void _embind_register_class_operator_call( + TYPEID classType, + TYPEID returnType, + unsigned argCount, + TYPEID argTypes[], + GenericFunction invoker + ); + void _embind_register_enum( TYPEID enumType, const char* name); @@ -255,7 +254,7 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// template - void function(const char* name, ReturnType (fn)(Args...)) { + void function(const char* name, ReturnType (fn)(Args...), Policies...) { using namespace internal; registerStandardTypes(); @@ -305,6 +304,15 @@ namespace emscripten { } }; + template + struct FunctorInvoker { + static void invoke( + const FunctorType& ptr, + typename internal::BindingType::WireType... args + ) { + ptr(internal::BindingType::fromWireType(args)...); + } + }; template struct MethodInvoker { @@ -567,26 +575,6 @@ namespace emscripten { reinterpret_cast(&internal::get_pointee)); } - //////////////////////////////////////////////////////////////////////////////// - // FUNCTION POINTERS - //////////////////////////////////////////////////////////////////////////////// - template - inline void register_function_ptr(const char* name) { - typedef std::function FunctorType; - - internal::registerStandardTypes(); - typename internal::WithPolicies::template ArgTypeList args; - internal::_embind_register_function_ptr( - name, - internal::TypeID::get(), - internal::TypeID::get(), - args.count, - args.types, - reinterpret_cast(&internal::raw_destructor), - reinterpret_cast(&internal::FunctorInvoker::invoke) - ); - } - //////////////////////////////////////////////////////////////////////////////// // VECTORS //////////////////////////////////////////////////////////////////////////////// @@ -706,6 +694,20 @@ namespace emscripten { reinterpret_cast(classMethod)); return *this; } + + template + class_& calloperator(Policies...) { + using namespace internal; + + typename WithPolicies::template ArgTypeList args; + _embind_register_class_operator_call( + TypeID::get(), + TypeID::get(), + args.count, + args.types, + reinterpret_cast(&internal::FunctorInvoker::invoke)); + return *this; + } }; //////////////////////////////////////////////////////////////////////////////// From 61b2ff66ffe1aba9550c828d5df9ecc0d3af8f7b Mon Sep 17 00:00:00 2001 From: mey Date: Fri, 16 Nov 2012 14:02:34 -0800 Subject: [PATCH 165/544] JSHint corrections. --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index ff5adf645317f..6a59f11dd9cfc 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -693,7 +693,7 @@ function __embind_register_class_operator_call( var rv = returnType.fromWireType(invoker.apply(null, args)); runDestructors(destructors); return rv; - } + }; } function __embind_register_class_field( From 338d59e81e5467df7021ad0854cee83b043c1204 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Sat, 10 Nov 2012 13:01:34 -0800 Subject: [PATCH 166/544] More files for upcast/downcast commit. --- src/embind/embind.js | 61 +++++++++++++++++++++++++- system/include/emscripten/bind.h | 74 +++++++++++++++++++++++++++----- 2 files changed, 123 insertions(+), 12 deletions(-) mode change 100644 => 100755 src/embind/embind.js mode change 100644 => 100755 system/include/emscripten/bind.h diff --git a/src/embind/embind.js b/src/embind/embind.js old mode 100644 new mode 100755 index 6a59f11dd9cfc..f491c1ddb0230 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -413,6 +413,7 @@ function __embind_register_smart_ptr( registerType(pointerType, name, { name: name, + Handle: Handle, fromWireType: function(ptr) { if (!getPointee(ptr)) { destructor(ptr); @@ -541,7 +542,7 @@ function __embind_register_class( return body.apply(this, arguments); }); constructor.prototype = Handle.prototype; - + registerType(classType, name, { name: name, constructor: constructor, @@ -643,6 +644,64 @@ function __embind_register_class_method( }; } +function __embind_register_cast_method( + classType, + methodName, + returnType, + invoker +) { + classType = requireRegisteredType(classType, 'class'); + methodName = Pointer_stringify(methodName); + var humanName = classType.name + '.' + methodName; + + returnType = requireRegisteredType(returnType, 'method ' + humanName + ' return value'); + invoker = FUNCTION_TABLE[invoker]; + + classType.Handle.prototype[methodName] = function() { + if (!this.ptr) { + throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } + if (arguments.length !== 0) { + throw new BindingError('emscripten binding method ' + humanName + ' called with arguments, none expected'); + } + + var args = new Array(1); + args[0] = this.ptr; + var rv = returnType.fromWireType(invoker.apply(null, args)); // in case ptr needs to be adjusted for multiple inheritance + return rv; + }; +} + +function __embind_register_pointer_cast_method( + classType, + methodName, + returnType, + invoker +) { + classType = requireRegisteredType(classType, 'class'); + methodName = Pointer_stringify(methodName); + var humanName = classType.name + '.' + methodName; + + returnType = requireRegisteredType(returnType, 'method ' + humanName + ' return value'); + invoker = FUNCTION_TABLE[invoker]; + + classType.Handle.prototype[methodName] = function() { + if (!this.ptr) { + throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } + if (arguments.length !== 0) { + throw new BindingError('emscripten binding method ' + humanName + ' called with arguments, none expected'); + } + var args = new Array(2); + var newPtr = _malloc(8); + args[0] = newPtr; + args[1] = this.smartPointer; + invoker.apply(null,args); + var rv = returnType.fromWireType(newPtr); // in case ptr needs to be adjusted for multiple inheritance + return rv; + }; +} + function __embind_register_class_classmethod( classType, methodName, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h old mode 100644 new mode 100755 index e20a5e688e965..ec3db2d241dfb --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -133,6 +133,18 @@ namespace emscripten { size_t memberFunctionSize, void* memberFunction); + void _embind_register_cast_method( + TYPEID classType, + const char* methodName, + TYPEID returnType, + GenericFunction invoker); + + void _embind_register_pointer_cast_method( + TYPEID classType, + const char* methodName, + TYPEID returnType, + GenericFunction invoker); + void _embind_register_class_field( TYPEID classType, const char* fieldName, @@ -253,6 +265,17 @@ namespace emscripten { // FUNCTIONS //////////////////////////////////////////////////////////////////////////////// + + template + ToType& performCast(FromType& from) { + return *dynamic_cast(&from); + }; + + template + std::shared_ptr performPointerCast(std::shared_ptr from) { + return std::shared_ptr(from, dynamic_cast(from.get())); + }; + template void function(const char* name, ReturnType (fn)(Args...), Policies...) { using namespace internal; @@ -563,17 +586,35 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// template - inline void register_smart_ptr(const char* name) { - typedef typename PointerType::element_type PointeeType; + class register_smart_ptr { + public: + register_smart_ptr(const char* name) { + using namespace internal; + typedef typename PointerType::element_type PointeeType; - internal::registerStandardTypes(); - internal::_embind_register_smart_ptr( - internal::TypeID::get(), - internal::TypeID::get(), - name, - reinterpret_cast(&internal::raw_destructor), - reinterpret_cast(&internal::get_pointee)); - } + registerStandardTypes(); + _embind_register_smart_ptr( + TypeID::get(), + TypeID::get(), + name, + reinterpret_cast(&raw_destructor), + reinterpret_cast(&get_pointee)); + + } + + template + register_smart_ptr& cast(const char* methodName) { + using namespace internal; + typedef typename ReturnType::element_type ReturnPointeeType; + typedef typename PointerType::element_type PointeeType; + _embind_register_pointer_cast_method( + TypeID::get(), + methodName, + TypeID::get(), + reinterpret_cast(&performPointerCast)); + return *this; + } + }; //////////////////////////////////////////////////////////////////////////////// // VECTORS @@ -599,7 +640,6 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// // CLASSES //////////////////////////////////////////////////////////////////////////////// - // TODO: support class definitions without constructors. // TODO: support external class constructors template @@ -708,6 +748,18 @@ namespace emscripten { reinterpret_cast(&internal::FunctorInvoker::invoke)); return *this; } + + template + class_& cast(const char* methodName) { + using namespace internal; + + _embind_register_cast_method( + TypeID::get(), + methodName, + TypeID::get(), + reinterpret_cast(&performCast)); + return *this; + } }; //////////////////////////////////////////////////////////////////////////////// From 8b7abef9db95082d4791ce92f4b7b4a308e3ed25 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 5 Nov 2012 13:20:13 -0800 Subject: [PATCH 167/544] Returning an empty shared_ptr returns null to JavaScript. Similarly, passing null into a shared_ptr creates an empty shared_ptr. --- system/include/emscripten/wire.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 system/include/emscripten/wire.h diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h old mode 100644 new mode 100755 From ad45b65333af729c8ffd99a8e5264e6d4d40b028 Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Mon, 5 Nov 2012 14:16:46 -0800 Subject: [PATCH 168/544] Add support for std::vector. --- src/embind/embind.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index f491c1ddb0230..859181e791553 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -505,7 +505,6 @@ function __embind_register_class( return h; }); - Handle.prototype.clone = function() { if (!this.ptr) { throw new BindingError(classType.name + ' instance already deleted'); From d0de75a62241931436b3902d5bab9d0942a1db6c Mon Sep 17 00:00:00 2001 From: mey Date: Fri, 9 Nov 2012 17:06:23 -0800 Subject: [PATCH 169/544] Exposing std::function to javascript. --- src/embind/embind.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index 859181e791553..e121732fbb8c8 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -505,6 +505,7 @@ function __embind_register_class( return h; }); + Handle.prototype.clone = function() { if (!this.ptr) { throw new BindingError(classType.name + ' instance already deleted'); From 87b760c334d3b3d1df4a1920f545930c790e2df6 Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Mon, 5 Nov 2012 14:16:46 -0800 Subject: [PATCH 170/544] Add support for std::vector. --- system/include/emscripten/bind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index ec3db2d241dfb..7c59a0cee39c9 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -612,7 +612,7 @@ namespace emscripten { methodName, TypeID::get(), reinterpret_cast(&performPointerCast)); - return *this; + return *this; } }; From ae311d2e8d84f0b2dc8347d3b29c500604c4ecfa Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Mon, 26 Nov 2012 11:23:23 -0800 Subject: [PATCH 171/544] Allow raw pointer return values (requires allow_raw_pointer) --- src/embind/embind.js | 72 ++++++++++++++++---------------- system/include/emscripten/bind.h | 27 +++++------- system/include/emscripten/wire.h | 5 ++- 3 files changed, 49 insertions(+), 55 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index e121732fbb8c8..88a4ee8d4aec0 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -154,7 +154,11 @@ function requireArgumentTypes(argCount, argTypes, name) { var argTypeImpls = new Array(argCount); for (var i = 0; i < argCount; ++i) { var argType = HEAP32[(argTypes >> 2) + i]; - argTypeImpls[i] = requireRegisteredType(argType, name + " parameter " + i); + if (i == 0) { + argTypeImpls[i] = requireRegisteredType(argType, name + " return value"); + } else { + argTypeImpls[i] = requireRegisteredType(argType, name + " parameter " + i); + } } return argTypeImpls; } @@ -167,30 +171,28 @@ function runDestructors(destructors) { } } -function makeInvoker(name, returnType, argCount, argTypes, invoker, fn) { +function makeInvoker(name, argCount, argTypes, invoker, fn) { return function() { - if (arguments.length !== argCount) { - throw new BindingError('function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + if (arguments.length !== argCount - 1) { + throw new BindingError('function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + argCount - 1); } var destructors = []; - var args = new Array(argCount + 1); + var args = new Array(argCount); args[0] = fn; - for (var i = 0; i < argCount; ++i) { - args[i + 1] = argTypes[i].toWireType(destructors, arguments[i]); + for (var i = 1; i < argCount; ++i) { + args[i] = argTypes[i].toWireType(destructors, arguments[i-1]); } - var rv = returnType.fromWireType(invoker.apply(null, args)); + var rv = argTypes[0].fromWireType(invoker.apply(null, args)); runDestructors(destructors); return rv; }; } -function __embind_register_function(name, returnType, argCount, argTypes, invoker, fn) { +function __embind_register_function(name, argCount, argTypes, invoker, fn) { name = Pointer_stringify(name); - returnType = requireRegisteredType(returnType, "Function " + name + " return value"); invoker = FUNCTION_TABLE[invoker]; argTypes = requireArgumentTypes(argCount, argTypes, name); - - exposePublicSymbol(name, makeInvoker(name, returnType, argCount, argTypes, invoker, fn)); + exposePublicSymbol(name, makeInvoker(name, argCount, argTypes, invoker, fn)); } function __embind_register_tuple(tupleType, name, constructor, destructor) { @@ -558,6 +560,9 @@ function __embind_register_class( var pointerName = name + '*'; registerType(pointerType, pointerName, { name: pointerName, + fromWireType: function(ptr) { + return new Handle(ptr); + }, toWireType: function(destructors, o) { return o.ptr; } @@ -586,13 +591,13 @@ function __embind_register_class_constructor( constructor = FUNCTION_TABLE[constructor]; classType.constructor.body = function() { - if (arguments.length !== argCount) { - throw new BindingError('emscripten binding ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + if (arguments.length !== argCount - 1) { + throw new BindingError('emscripten binding ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } var destructors = []; - var args = new Array(argCount); - for (var i = 0; i < argCount; ++i) { - args[i] = argTypes[i].toWireType(destructors, arguments[i]); + var args = new Array(argCount-1); + for (var i = 1; i < argCount; ++i) { + args[i-1] = argTypes[i].toWireType(destructors, arguments[i-1]); } var ptr = constructor.apply(null, args); @@ -605,7 +610,6 @@ function __embind_register_class_constructor( function __embind_register_class_method( classType, methodName, - returnType, argCount, argTypes, invoker, @@ -616,7 +620,6 @@ function __embind_register_class_method( methodName = Pointer_stringify(methodName); var humanName = classType.name + '.' + methodName; - returnType = requireRegisteredType(returnType, 'method ' + humanName + ' return value'); argTypes = requireArgumentTypes(argCount, argTypes, 'method ' + humanName); invoker = FUNCTION_TABLE[invoker]; memberFunction = copyMemberPointer(memberFunction, memberFunctionSize); @@ -626,19 +629,19 @@ function __embind_register_class_method( if (!this.ptr) { throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } - if (arguments.length !== argCount) { - throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + if (arguments.length !== argCount - 1) { + throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } var destructors = []; - var args = new Array(argCount + 2); + var args = new Array(argCount + 1); args[0] = this.ptr; args[1] = memberFunction; - for (var i = 0; i < argCount; ++i) { - args[i + 2] = argTypes[i].toWireType(destructors, arguments[i]); + for (var i = 1; i < argCount; ++i) { + args[i + 1] = argTypes[i].toWireType(destructors, arguments[i-1]); } - var rv = returnType.fromWireType(invoker.apply(null, args)); + var rv = argTypes[0].fromWireType(invoker.apply(null, args)); runDestructors(destructors); return rv; }; @@ -705,7 +708,6 @@ function __embind_register_pointer_cast_method( function __embind_register_class_classmethod( classType, methodName, - returnType, argCount, argTypes, invoker, @@ -714,22 +716,18 @@ function __embind_register_class_classmethod( classType = requireRegisteredType(classType, 'class'); methodName = Pointer_stringify(methodName); var humanName = classType.name + '.' + methodName; - returnType = requireRegisteredType(returnType, 'classmethod ' + humanName + ' return value'); argTypes = requireArgumentTypes(argCount, argTypes, 'classmethod ' + humanName); invoker = FUNCTION_TABLE[invoker]; - - classType.constructor[methodName] = makeInvoker(humanName, returnType, argCount, argTypes, invoker, fn); + classType.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, invoker, fn); } function __embind_register_class_operator_call( classType, - returnType, argCount, argTypes, invoker ) { classType = requireRegisteredType(classType, 'class'); - returnType = requireRegisteredType(returnType, 'method ' + humanName + ' return value'); argTypes = requireArgumentTypes(argCount, argTypes, 'method ' + humanName); invoker = FUNCTION_TABLE[invoker]; var humanName = classType.name + '.' + 'operator_call'; @@ -738,18 +736,18 @@ function __embind_register_class_operator_call( if (!this.ptr) { throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } - if (arguments.length !== argCount) { - throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + if (arguments.length !== argCount - 1) { + throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } var destructors = []; - var args = new Array(argCount + 1); + var args = new Array(argCount); args[0] = this.ptr; - for (var i = 0; i < argCount; ++i) { - args[i + 1] = argTypes[i].toWireType(destructors, arguments[i]); + for (var i = 1; i < argCount; ++i) { + args[i] = argTypes[i].toWireType(destructors, arguments[i-1]); } - var rv = returnType.fromWireType(invoker.apply(null, args)); + var rv = argTypes[0].fromWireType(invoker.apply(null, args)); runDestructors(destructors); return rv; }; diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 7c59a0cee39c9..081182595c971 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -48,7 +48,6 @@ namespace emscripten { void _embind_register_function( const char* name, - TYPEID returnType, unsigned argCount, TYPEID argTypes[], GenericFunction invoker, @@ -126,7 +125,6 @@ namespace emscripten { void _embind_register_class_method( TYPEID classType, const char* methodName, - TYPEID returnType, unsigned argCount, TYPEID argTypes[], GenericFunction invoker, @@ -157,7 +155,6 @@ namespace emscripten { void _embind_register_class_classmethod( TYPEID classType, const char* methodName, - TYPEID returnType, unsigned argCount, TYPEID argTypes[], GenericFunction invoker, @@ -165,7 +162,6 @@ namespace emscripten { void _embind_register_class_operator_call( TYPEID classType, - TYPEID returnType, unsigned argCount, TYPEID argTypes[], GenericFunction invoker @@ -206,7 +202,11 @@ namespace emscripten { template struct arg { - static constexpr int index = Index; + static constexpr int index = Index + 1; + }; + + struct ret_val { + static constexpr int index = 0; }; template @@ -282,10 +282,9 @@ namespace emscripten { registerStandardTypes(); - typename WithPolicies::template ArgTypeList args; + typename WithPolicies::template ArgTypeList args; _embind_register_function( name, - TypeID::get(), args.count, args.types, reinterpret_cast(&Invoker::invoke), @@ -661,7 +660,7 @@ namespace emscripten { class_& constructor(Policies...) { using namespace internal; - typename WithPolicies::template ArgTypeList args; + typename WithPolicies::template ArgTypeList args; _embind_register_class_constructor( TypeID::get(), args.count, @@ -674,11 +673,10 @@ namespace emscripten { class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...), Policies...) { using namespace internal; - typename WithPolicies::template ArgTypeList args; + typename WithPolicies::template ArgTypeList args; _embind_register_class_method( TypeID::get(), methodName, - TypeID::get(), args.count, args.types, reinterpret_cast(&MethodInvoker::invoke), @@ -691,11 +689,10 @@ namespace emscripten { class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const, Policies...) { using namespace internal; - typename WithPolicies::template ArgTypeList args; + typename WithPolicies::template ArgTypeList args; _embind_register_class_method( TypeID::get(), methodName, - TypeID::get(), args.count, args.types, reinterpret_cast(&ConstMethodInvoker::invoke), @@ -723,11 +720,10 @@ namespace emscripten { class_& classmethod(const char* methodName, ReturnType (*classMethod)(Args...), Policies...) { using namespace internal; - typename WithPolicies::template ArgTypeList args; + typename WithPolicies::template ArgTypeList args; _embind_register_class_classmethod( TypeID::get(), methodName, - TypeID::get(), args.count, args.types, reinterpret_cast(&internal::Invoker::invoke), @@ -739,10 +735,9 @@ namespace emscripten { class_& calloperator(Policies...) { using namespace internal; - typename WithPolicies::template ArgTypeList args; + typename WithPolicies::template ArgTypeList args; _embind_register_class_operator_call( TypeID::get(), - TypeID::get(), args.count, args.types, reinterpret_cast(&internal::FunctorInvoker::invoke)); diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 99c4f926d64b6..bb70f26c6edf9 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -104,7 +104,6 @@ namespace emscripten { template static void fill(TYPEID* argTypes) { typedef typename ExecutePolicies::template With::type TransformT; - *argTypes = TypeID::get(); return ArgTypes::template fill(argTypes + 1); } @@ -204,7 +203,9 @@ namespace emscripten { template struct BindingType { typedef T* WireType; - + static WireType toWireType(T* p) { + return p; + } static T* fromWireType(WireType wt) { return wt; } From 50c29dc01ec880fbd8f708be7a3c9c865645d46f Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Mon, 26 Nov 2012 12:22:24 -0800 Subject: [PATCH 172/544] Commit hook fix. --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 88a4ee8d4aec0..1cae55ffccdaa 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -154,7 +154,7 @@ function requireArgumentTypes(argCount, argTypes, name) { var argTypeImpls = new Array(argCount); for (var i = 0; i < argCount; ++i) { var argType = HEAP32[(argTypes >> 2) + i]; - if (i == 0) { + if (i === 0) { argTypeImpls[i] = requireRegisteredType(argType, name + " return value"); } else { argTypeImpls[i] = requireRegisteredType(argType, name + " parameter " + i); From ab18c1107d8493b6a1ef0c19b5210a756cb4709c Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Mon, 26 Nov 2012 16:49:52 -0800 Subject: [PATCH 173/544] there were some incorrect handling of memory alloc/dealloc when passing around vector of smart pointer (or whatever type that needs manual deletion) --- src/embind/embind.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 1cae55ffccdaa..504db37cd50e6 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -456,8 +456,21 @@ function __embind_register_vector( name: name, fromWireType: function(ptr) { var arr = []; - var n = length(ptr); + Object.defineProperty(arr, 'delete', { + writable: false, + enumerable: false, + configurable: false, + value: function() { + var needsToBeDeleted = elementType.hasOwnProperty('Handle'); + for (var i = 0; i < arr.length; i++) { + if (needsToBeDeleted) { + arr[i].delete(); + } + } + } + }); + var n = length(ptr); for (var i = 0; i < n; i++) { var v = elementType.fromWireType(getter(ptr, i)); arr.push(v); @@ -471,6 +484,8 @@ function __embind_register_vector( for (var val in o) { setter(vec, elementType.toWireType(destructors, o[val])); } + runDestructors(destructors); + destructors.push(destructor); destructors.push(vec); return vec; From 1b9928686e2a3bd0d6394d79cab7b110cf35990f Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 27 Nov 2012 10:54:41 -0800 Subject: [PATCH 174/544] Automatic downcasting of function return values (first cut -- multiple inheritance still not supported). --- src/embind/embind.js | 139 +++++++++++++++++++++++++++++++ system/include/emscripten/bind.h | 8 +- 2 files changed, 146 insertions(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 504db37cd50e6..b50c7aca6e01d 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -493,15 +493,21 @@ function __embind_register_vector( }); } +// hang onto your hats, guys, we're going to try to make this one registration work for the class and all its +// derived classes function __embind_register_class( classType, pointerType, constPointerType, name, + getDynamicPointerType, destructor ) { name = Pointer_stringify(name); destructor = FUNCTION_TABLE[destructor]; + if (getDynamicPointerType) { + getDynamicPointerType = FUNCTION_TABLE[getDynamicPointerType]; + } var Handle = createNamedFunction(name, function(ptr) { var h = function() { @@ -562,6 +568,7 @@ function __embind_register_class( registerType(classType, name, { name: name, + pointerType: pointerType, constructor: constructor, Handle: Handle, fromWireType: function(ptr) { @@ -576,6 +583,19 @@ function __embind_register_class( registerType(pointerType, pointerName, { name: pointerName, fromWireType: function(ptr) { + var dynamicType = getDynamicPointerType && getDynamicPointerType(ptr); + if (dynamicType === null || dynamicType === pointerType) { + return new Handle(ptr); + } + try { + dynamicType = requireRegisteredType(dynamicType); + } catch (err) { + return new Handle(ptr); // I suppose we could work our way up the inheritance tree... + } + dynamicType = requireRegisteredType(dynamicType.pointerType); + return dynamicType.fromWireTypeStatic(ptr); + }, + fromWireTypeStatic: function(ptr) { return new Handle(ptr); }, toWireType: function(destructors, o) { @@ -586,6 +606,19 @@ function __embind_register_class( var constPointerName = name + ' const*'; registerType(constPointerType, constPointerName, { name: constPointerName, + fromWireType: function(ptr) { + var dynamicType = getDynamicPointerType && getDynamicPointerType(ptr); + if (dynamicType === null || dynamicType === pointerType) { + return new Handle(ptr); + } + try { + dynamicType = requireRegisteredType(dynamicType); + } catch (err) { + return new Handle(ptr); // I suppose we could work our way up the inheritance tree... + } + dynamicType = requireRegisteredType(dynamicType.pointerType); + return dynamicType.fromWireType(ptr); + }, toWireType: function(destructors, o) { return o.ptr; } @@ -594,6 +627,112 @@ function __embind_register_class( exposePublicSymbol(name, constructor); } +//function __embind_register_class( +// classType, +// pointerType, +// constPointerType, +// name, +// destructor +//) { +// name = Pointer_stringify(name); +// destructor = FUNCTION_TABLE[destructor]; +// +// var Handle = createNamedFunction(name, function(ptr) { +// var h = function() { +// if(h.operator_call !== undefined) { +// return h.operator_call.apply(h, arguments); +// } else { +// throw new BindingError(name + ' does not define call operator'); +// } +// }; +// +// h.count = {value: 1}; +// h.ptr = ptr; +// +// for(var prop in Handle.prototype) { +// var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop); +// Object.defineProperty(h, prop, dp); +// } +// +// return h; +// }); +// +// Handle.prototype.clone = function() { +// if (!this.ptr) { +// throw new BindingError(classType.name + ' instance already deleted'); +// } +// +// var clone = Object.create(Handle.prototype); +// clone.count = this.count; +// clone.ptr = this.ptr; +// +// clone.count.value += 1; +// return clone; +// }; +// +// Handle.prototype.move = function() { +// var rv = this.clone(); +// this.delete(); +// return rv; +// }; +// +// Handle.prototype['delete'] = function() { +// if (!this.ptr) { +// throw new BindingError(classType.name + ' instance already deleted'); +// } +// +// this.count.value -= 1; +// if (0 === this.count.value) { +// destructor(this.ptr); +// } +// this.ptr = undefined; +// }; +// +// var constructor = createNamedFunction(name, function() { +// var body = constructor.body; +// return body.apply(this, arguments); +// }); +// constructor.prototype = Handle.prototype; +// +// registerType(classType, name, { +// name: name, +// constructor: constructor, +// Handle: Handle, +// fromWireType: function(ptr) { +// return new Handle(ptr); +// }, +// toWireType: function(destructors, o) { +// return o.ptr; +// } +// }); +// +// var pointerName = name + '*'; +// registerType(pointerType, pointerName, { +// name: pointerName, +// fromWireType: function(ptr) { +// // based on the fully downcast type of the pointer, +// +// return new Handle(ptr); // if me +// }, +// toWireType: function(destructors, o) { +// return o.ptr; +// } +// }); +// +// var constPointerName = name + ' const*'; +// registerType(constPointerType, constPointerName, { +// name: constPointerName, +// fromWireType: function(ptr) { +// return new Handle(ptr); +// }, +// toWireType: function(destructors, o) { +// return o.ptr; +// } +// }); +// +// exposePublicSymbol(name, constructor); +//} +// function __embind_register_class_constructor( classType, argCount, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 081182595c971..3dc6b5e73c3d4 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -114,6 +114,7 @@ namespace emscripten { TYPEID pointerType, TYPEID constPointerType, const char* className, + GenericFunction getDynamicTypeInfo, GenericFunction destructor); void _embind_register_class_constructor( @@ -265,12 +266,16 @@ namespace emscripten { // FUNCTIONS //////////////////////////////////////////////////////////////////////////////// - template ToType& performCast(FromType& from) { return *dynamic_cast(&from); }; + template + internal::TYPEID getDynamicPointerType(PointerType *p) { + return reinterpret_cast(&typeid(*p)); + }; + template std::shared_ptr performPointerCast(std::shared_ptr from) { return std::shared_ptr(from, dynamic_cast(from.get())); @@ -653,6 +658,7 @@ namespace emscripten { TypeID>::get(), TypeID>::get(), name, + reinterpret_cast(&getDynamicPointerType), reinterpret_cast(&raw_destructor)); } From d161fccc9b662f073fd53d9de1d46f706de5ae10 Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Wed, 28 Nov 2012 13:05:37 -0800 Subject: [PATCH 175/544] added two utility functions to emval. - check if a given key exists. - return length of an array. --- src/embind/emval.js | 13 +++++++++++++ system/include/emscripten/val.h | 10 ++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/embind/emval.js b/src/embind/emval.js index f74c0fd5482e3..a3157d2a7240f 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -53,6 +53,10 @@ function __emval_new_cstring(str) { return __emval_register(Pointer_stringify(str)); } +function __emval_has_property(handle, k) { + return _emval_handle_array[handle].value.hasOwnProperty(k); +} + function __emval_get_property(handle, k) { k = Pointer_stringify(k); return __emval_register(_emval_handle_array[handle].value[k]); @@ -66,6 +70,15 @@ function __emval_get_property_by_unsigned_long(handle, k) { return __emval_register(_emval_handle_array[handle].value[k]); } +function __emval_get_length(handle) { + var val = _emval_handle_array[handle].value; + if (Object.prototype.toString.call(val) === "[object Array]") { + return val.length; + } + + return 0; +} + function __emval_eval_global_method(handle, objectName, methodName) { var objectNameStr = Pointer_stringify(objectName); var methodNameStr = Pointer_stringify(methodName); diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 68f5b63e3e379..945b0d8a62580 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -14,12 +14,14 @@ namespace emscripten { EM_VAL _emval_new_object(); EM_VAL _emval_new_long(long value); EM_VAL _emval_new_cstring(const char* str); + bool _emval_has_property(EM_VAL object, const char* key); EM_VAL _emval_get_property(EM_VAL object, const char* key); EM_VAL _emval_get_property_by_long(EM_VAL object, long key); EM_VAL _emval_get_property_by_unsigned_long(EM_VAL object, unsigned long key); EM_VAL _emval_eval_global_method(EM_VAL object, const char* objectName, const char* methodName); void _emval_set_property(EM_VAL object, const char* key, EM_VAL value); void _emval_set_property_by_int(EM_VAL object, long key, EM_VAL value); + unsigned int _emval_get_length(EM_VAL object); void _emval_as(EM_VAL value, TYPEID returnType); EM_VAL _emval_call( EM_VAL value, @@ -78,6 +80,10 @@ namespace emscripten { return *this; } + bool exist(const char* key) const { + return internal::_emval_has_property(handle, key); + } + val get(const char* key) const { return val(internal::_emval_get_property(handle, key)); } @@ -111,6 +117,10 @@ namespace emscripten { internal::_emval_set_property_by_int(handle, key, v.handle); } + unsigned int length() { + return internal::_emval_get_length(handle); + } + template val operator()(Args... args) { using namespace internal; From 88b63143fa199f6cf93d10434df9e9b0740c6895 Mon Sep 17 00:00:00 2001 From: jinsuck Date: Wed, 28 Nov 2012 13:44:41 -0800 Subject: [PATCH 176/544] Upgrade libcxx from 11-month-ago version to the latest. The new version has memory leak fixed in the weak_ptr. Note: to make this compile, I made two modifications (actually copied from the previous version) -- system/include/libcxx/__locale line 28 and system/include/libcxx/locale line 229. --- system/include/emscripten/wire.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index bb70f26c6edf9..ec302d3ab4588 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -7,6 +7,8 @@ // // We'll call the on-the-wire type WireType. +#include + namespace emscripten { namespace internal { typedef const struct _TYPEID* TYPEID; From 73d2de4105fd8f7200fe42e868e53fe2378fab83 Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Wed, 28 Nov 2012 15:18:07 -0800 Subject: [PATCH 177/544] use simpler way to get length of an array --- src/embind/emval.js | 9 --------- system/include/emscripten/val.h | 3 +-- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index a3157d2a7240f..65becfa344fd4 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -70,15 +70,6 @@ function __emval_get_property_by_unsigned_long(handle, k) { return __emval_register(_emval_handle_array[handle].value[k]); } -function __emval_get_length(handle) { - var val = _emval_handle_array[handle].value; - if (Object.prototype.toString.call(val) === "[object Array]") { - return val.length; - } - - return 0; -} - function __emval_eval_global_method(handle, objectName, methodName) { var objectNameStr = Pointer_stringify(objectName); var methodNameStr = Pointer_stringify(methodName); diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 945b0d8a62580..8db052e8cd1e0 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -21,7 +21,6 @@ namespace emscripten { EM_VAL _emval_eval_global_method(EM_VAL object, const char* objectName, const char* methodName); void _emval_set_property(EM_VAL object, const char* key, EM_VAL value); void _emval_set_property_by_int(EM_VAL object, long key, EM_VAL value); - unsigned int _emval_get_length(EM_VAL object); void _emval_as(EM_VAL value, TYPEID returnType); EM_VAL _emval_call( EM_VAL value, @@ -118,7 +117,7 @@ namespace emscripten { } unsigned int length() { - return internal::_emval_get_length(handle); + return get("length").as(); } template From 026a4d49e496339c0f31b79ca3b399c53dac5f7f Mon Sep 17 00:00:00 2001 From: jinsuck Date: Fri, 30 Nov 2012 14:38:54 -0800 Subject: [PATCH 178/544] support creating val with null (needed for sending null parameter to a WebGL function) --- src/embind/emval.js | 4 ++++ system/include/emscripten/val.h | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/embind/emval.js b/src/embind/emval.js index 65becfa344fd4..e8ee6baf5b9f6 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -45,6 +45,10 @@ function __emval_new_object() { return __emval_register({}); } +function __emval_new_null() { + return __emval_register(null); +} + function __emval_new_long(value) { return __emval_register(value); } diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 8db052e8cd1e0..e2d353823202f 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -12,6 +12,7 @@ namespace emscripten { void _emval_incref(EM_VAL value); void _emval_decref(EM_VAL value); EM_VAL _emval_new_object(); + EM_VAL _emval_new_null(); EM_VAL _emval_new_long(long value); EM_VAL _emval_new_cstring(const char* str); bool _emval_has_property(EM_VAL object, const char* key); @@ -48,6 +49,10 @@ namespace emscripten { return val(internal::_emval_new_object()); }; + static val null() { + return val(internal::_emval_new_null()); + }; + static val take_ownership(internal::EM_VAL e) { return val(e); } From 15603bbafc0aa68f9d8d843e083b89bfc566533d Mon Sep 17 00:00:00 2001 From: mey Date: Fri, 30 Nov 2012 14:56:58 -0800 Subject: [PATCH 179/544] Switching vector class_ instead of bound as an explicit type. --- src/embind/embind.js | 69 +++++++++++++++++- system/include/emscripten/bind.h | 121 +++++++++++++++++++++++++------ system/include/emscripten/wire.h | 27 ++++--- 3 files changed, 179 insertions(+), 38 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index b50c7aca6e01d..fa364900308f9 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -495,6 +495,7 @@ function __embind_register_vector( // hang onto your hats, guys, we're going to try to make this one registration work for the class and all its // derived classes + function __embind_register_class( classType, pointerType, @@ -882,9 +883,10 @@ function __embind_register_class_operator_call( invoker ) { classType = requireRegisteredType(classType, 'class'); + var humanName = classType.name + '.' + 'operator_call'; argTypes = requireArgumentTypes(argCount, argTypes, 'method ' + humanName); invoker = FUNCTION_TABLE[invoker]; - var humanName = classType.name + '.' + 'operator_call'; + classType.Handle.prototype.operator_call = function() { if (!this.ptr) { @@ -907,6 +909,71 @@ function __embind_register_class_operator_call( }; } +function __embind_register_class_operator_array_get( + classType, + elementType, + indexType, + invoker +) { + classType = requireRegisteredType(classType, 'class'); + indexType = requireRegisteredType(indexType, 'array access index ' + classType.name); + elementType = requireRegisteredType(elementType, 'array access element' + classType.name); + invoker = FUNCTION_TABLE[invoker]; + var humanName = classType.name + '.' + 'operator_array_get'; + + classType.Handle.prototype.array_get = function() { + if (!this.ptr) { + throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } + + if (arguments.length !== 1) { + throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + 1); + } + + var destructors = []; + var args = new Array(2); + args[0] = this.ptr; + args[1] = indexType.toWireType(destructors, arguments[0]); + + var rv = elementType.fromWireType(invoker.apply(null, args)); + runDestructors(destructors); + return rv; + }; +} + +function __embind_register_class_operator_array_set( + classType, + elementType, + indexType, + invoker +) { + classType = requireRegisteredType(classType, 'class'); + indexType = requireRegisteredType(indexType, 'array access index ' + classType.name); + elementType = requireRegisteredType(elementType, 'vector ' + classType.name); + invoker = FUNCTION_TABLE[invoker]; + var humanName = classType.name + '.' + 'operator_array_get'; + + classType.Handle.prototype.array_set = function() { + if (!this.ptr) { + throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } + + if (arguments.length !== 2) { + throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + 2); + } + + var destructors = []; + var args = new Array(2); + args[0] = this.ptr; + args[1] = indexType.toWireType(destructors, arguments[0]); + args[2] = elementType.toWireType(destructors, arguments[1]); + + var rv = elementType.fromWireType(invoker.apply(null, args)); + runDestructors(destructors); + return rv; + }; +} + function __embind_register_class_field( classType, fieldName, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 3dc6b5e73c3d4..6b8b6f101d6ea 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -165,8 +165,19 @@ namespace emscripten { TYPEID classType, unsigned argCount, TYPEID argTypes[], - GenericFunction invoker - ); + GenericFunction invoker); + + void _embind_register_class_operator_array_get( + TYPEID classType, + TYPEID elementType, + TYPEID indexType, + GenericFunction invoker); + + void _embind_register_class_operator_array_set( + TYPEID classType, + TYPEID elementType, + TYPEID indexType, + GenericFunction invoker); void _embind_register_enum( TYPEID enumType, @@ -341,6 +352,30 @@ namespace emscripten { } }; + template + struct ArrayAccessGetInvoker { + static typename internal::BindingType::WireType invoke( + ClassType* ptr, + size_t index, + typename internal::BindingType + ) { + return internal::BindingType::toWireType( + (*ptr)[index] + ); + } + }; + + template + struct ArrayAccessSetInvoker { + static void invoke( + ClassType* ptr, + size_t index, + typename internal::BindingType::WireType item + ) { + (*ptr)[index] = internal::BindingType::fromWireType(item); + } + }; + template struct MethodInvoker { typedef ReturnType (ClassType::*MemberPointer)(Args...); @@ -620,27 +655,6 @@ namespace emscripten { } }; - //////////////////////////////////////////////////////////////////////////////// - // VECTORS - //////////////////////////////////////////////////////////////////////////////// - - template - inline void register_vector(const char* name) { - typedef typename VectorType::value_type ElementType; - - internal::registerStandardTypes(); - internal::_embind_register_vector( - internal::TypeID::get(), - internal::TypeID::get(), - name, - reinterpret_cast(&internal::raw_constructor), - reinterpret_cast(&internal::raw_destructor), - reinterpret_cast(&internal::Vector::length), - reinterpret_cast(&internal::Vector::getAt), - reinterpret_cast(&internal::Vector::push_back) - ); - } - //////////////////////////////////////////////////////////////////////////////// // CLASSES //////////////////////////////////////////////////////////////////////////////// @@ -750,6 +764,44 @@ namespace emscripten { return *this; } + + /* + * void _embind_register_class_operator_array_get( + TYPEID classType, + TYPEID elementType, + GenericFunction invoker); + + void _embind_register_class_operator_array_set( + TYPEID classType, + TYPEID elementType, + GenericFunction invoker); + + ArrayAccessSetInvoker + */ + + template + class_& arrayoperatorget() { + using namespace internal; + + _embind_register_class_operator_array_get( + TypeID::get(), + TypeID::get(), + TypeID::get(), + reinterpret_cast(&internal::ArrayAccessGetInvoker::invoke)); + } + + template + class_& arrayoperatorset() { + using namespace internal; + + _embind_register_class_operator_array_set( + TypeID::get(), + TypeID::get(), + TypeID::get(), + reinterpret_cast(&internal::ArrayAccessSetInvoker::invoke)); + return *this; + } + template class_& cast(const char* methodName) { using namespace internal; @@ -763,6 +815,29 @@ namespace emscripten { } }; + //////////////////////////////////////////////////////////////////////////////// + // VECTORS + //////////////////////////////////////////////////////////////////////////////// + template + class_> register_vector(const char* name) { + using namespace std; + typedef vector VecType; + typedef typename vector::iterator IterType; + typedef typename vector::const_iterator ConstIterType; + + void (VecType::*push_back)(const T&) = &VecType::push_back; + const T& (VecType::*at)(size_t) const = &VecType::at; + auto c = class_>(name) + .template constructor<>() + .method("push_back", push_back) + .method("at", at) + .method("size", &vector::size) + .template arrayoperatorget() + .template arrayoperatorset() + ; + return c; + } + //////////////////////////////////////////////////////////////////////////////// // ENUMS //////////////////////////////////////////////////////////////////////////////// diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index ec302d3ab4588..5a2deb7a98cf1 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -133,19 +133,18 @@ namespace emscripten { template struct BindingType; -#define EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(type) \ - template<> \ - struct BindingType { \ - typedef type WireType; \ - \ - constexpr static WireType toWireType(type v) { \ - return v; \ - } \ - constexpr static type fromWireType(WireType v) { \ - return v; \ - } \ - static void destroy(WireType) { \ - } \ +#define EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(type) \ + template<> \ + struct BindingType { \ + typedef type WireType; \ + constexpr static WireType toWireType(const type& v) { \ + return v; \ + } \ + constexpr static type fromWireType(WireType v) { \ + return v; \ + } \ + static void destroy(WireType) { \ + } \ } EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(char); @@ -276,7 +275,7 @@ namespace emscripten { }; static WireType toWireType(T v) { - return new T(v); + return new ActualT(v); } static Marshaller fromWireType(WireType p) { From b5d84da03b83039a382494e2cfd1a125f0fb7199 Mon Sep 17 00:00:00 2001 From: mey Date: Fri, 30 Nov 2012 15:16:21 -0800 Subject: [PATCH 180/544] Removing ability to return by reference: dangerous. --- system/include/emscripten/wire.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 5a2deb7a98cf1..1173034f7fbca 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -275,7 +275,7 @@ namespace emscripten { }; static WireType toWireType(T v) { - return new ActualT(v); + return new T(v); } static Marshaller fromWireType(WireType p) { From c9eb75d64ab5735f15012c5839980edf3f1dd2ee Mon Sep 17 00:00:00 2001 From: mey Date: Mon, 3 Dec 2012 16:25:17 -0800 Subject: [PATCH 181/544] adding function to convert JS array to vector. --- system/include/emscripten/bind.h | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 6b8b6f101d6ea..281ae85beb145 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -764,21 +764,6 @@ namespace emscripten { return *this; } - - /* - * void _embind_register_class_operator_array_get( - TYPEID classType, - TYPEID elementType, - GenericFunction invoker); - - void _embind_register_class_operator_array_set( - TYPEID classType, - TYPEID elementType, - GenericFunction invoker); - - ArrayAccessSetInvoker - */ - template class_& arrayoperatorget() { using namespace internal; @@ -818,6 +803,18 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// // VECTORS //////////////////////////////////////////////////////////////////////////////// + template + std::vector vecFromJSArray(val v) { + auto l = v.get("length").as(); + + std::vector rv; + for(unsigned i = 0; i < l; ++i) { + rv.push_back(v.get(i).as()); + } + + return rv; + }; + template class_> register_vector(const char* name) { using namespace std; @@ -835,6 +832,7 @@ namespace emscripten { .template arrayoperatorget() .template arrayoperatorset() ; + return c; } From 1276f9f5b73b10c914aa8c2c1a675be526b57480 Mon Sep 17 00:00:00 2001 From: mey Date: Mon, 3 Dec 2012 17:26:59 -0800 Subject: [PATCH 182/544] Some additional clean up. --- src/embind/embind.js | 2 +- system/include/emscripten/bind.h | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index fa364900308f9..45341700c13e1 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -949,7 +949,7 @@ function __embind_register_class_operator_array_set( ) { classType = requireRegisteredType(classType, 'class'); indexType = requireRegisteredType(indexType, 'array access index ' + classType.name); - elementType = requireRegisteredType(elementType, 'vector ' + classType.name); + elementType = requireRegisteredType(elementType, 'array access element ' + classType.name); invoker = FUNCTION_TABLE[invoker]; var humanName = classType.name + '.' + 'operator_array_get'; diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 281ae85beb145..96e8dda5a3807 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -99,16 +99,6 @@ namespace emscripten { GenericFunction destructor, GenericFunction getPointee); - void _embind_register_vector( - TYPEID vectorType, - TYPEID elementType, - const char* name, - GenericFunction constructor, - GenericFunction destructor, - GenericFunction length, - GenericFunction getter, - GenericFunction setter); - void _embind_register_class( TYPEID classType, TYPEID pointerType, From 03d90a32db03078ff2666b4d8ca63d5f804e57f3 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 4 Dec 2012 10:56:59 -0800 Subject: [PATCH 183/544] More work toward dynamic downcasting of pointers. --- src/embind/embind.js | 136 ++----------------------------- system/include/emscripten/bind.h | 12 ++- system/lib/embind/bind.cpp | 102 +++++++++++++++++++++++ 3 files changed, 113 insertions(+), 137 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 45341700c13e1..7f4e0d2e2b058 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -493,23 +493,16 @@ function __embind_register_vector( }); } -// hang onto your hats, guys, we're going to try to make this one registration work for the class and all its -// derived classes - function __embind_register_class( classType, pointerType, constPointerType, name, - getDynamicPointerType, destructor ) { name = Pointer_stringify(name); destructor = FUNCTION_TABLE[destructor]; - if (getDynamicPointerType) { - getDynamicPointerType = FUNCTION_TABLE[getDynamicPointerType]; - } - + var Handle = createNamedFunction(name, function(ptr) { var h = function() { if(h.operator_call !== undefined) { @@ -521,7 +514,7 @@ function __embind_register_class( h.count = {value: 1}; h.ptr = ptr; - + for(var prop in Handle.prototype) { var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop); Object.defineProperty(h, prop, dp); @@ -566,6 +559,8 @@ function __embind_register_class( return body.apply(this, arguments); }); constructor.prototype = Handle.prototype; + constructor.classType = classType; + registerType(classType, name, { name: name, @@ -584,14 +579,14 @@ function __embind_register_class( registerType(pointerType, pointerName, { name: pointerName, fromWireType: function(ptr) { - var dynamicType = getDynamicPointerType && getDynamicPointerType(ptr); + var dynamicType = ___getDynamicPointerType(ptr); // !!! this won't work if pointer is not dynamic if (dynamicType === null || dynamicType === pointerType) { return new Handle(ptr); } try { dynamicType = requireRegisteredType(dynamicType); } catch (err) { - return new Handle(ptr); // I suppose we could work our way up the inheritance tree... + return new Handle(ptr); } dynamicType = requireRegisteredType(dynamicType.pointerType); return dynamicType.fromWireTypeStatic(ptr); @@ -607,19 +602,6 @@ function __embind_register_class( var constPointerName = name + ' const*'; registerType(constPointerType, constPointerName, { name: constPointerName, - fromWireType: function(ptr) { - var dynamicType = getDynamicPointerType && getDynamicPointerType(ptr); - if (dynamicType === null || dynamicType === pointerType) { - return new Handle(ptr); - } - try { - dynamicType = requireRegisteredType(dynamicType); - } catch (err) { - return new Handle(ptr); // I suppose we could work our way up the inheritance tree... - } - dynamicType = requireRegisteredType(dynamicType.pointerType); - return dynamicType.fromWireType(ptr); - }, toWireType: function(destructors, o) { return o.ptr; } @@ -628,112 +610,6 @@ function __embind_register_class( exposePublicSymbol(name, constructor); } -//function __embind_register_class( -// classType, -// pointerType, -// constPointerType, -// name, -// destructor -//) { -// name = Pointer_stringify(name); -// destructor = FUNCTION_TABLE[destructor]; -// -// var Handle = createNamedFunction(name, function(ptr) { -// var h = function() { -// if(h.operator_call !== undefined) { -// return h.operator_call.apply(h, arguments); -// } else { -// throw new BindingError(name + ' does not define call operator'); -// } -// }; -// -// h.count = {value: 1}; -// h.ptr = ptr; -// -// for(var prop in Handle.prototype) { -// var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop); -// Object.defineProperty(h, prop, dp); -// } -// -// return h; -// }); -// -// Handle.prototype.clone = function() { -// if (!this.ptr) { -// throw new BindingError(classType.name + ' instance already deleted'); -// } -// -// var clone = Object.create(Handle.prototype); -// clone.count = this.count; -// clone.ptr = this.ptr; -// -// clone.count.value += 1; -// return clone; -// }; -// -// Handle.prototype.move = function() { -// var rv = this.clone(); -// this.delete(); -// return rv; -// }; -// -// Handle.prototype['delete'] = function() { -// if (!this.ptr) { -// throw new BindingError(classType.name + ' instance already deleted'); -// } -// -// this.count.value -= 1; -// if (0 === this.count.value) { -// destructor(this.ptr); -// } -// this.ptr = undefined; -// }; -// -// var constructor = createNamedFunction(name, function() { -// var body = constructor.body; -// return body.apply(this, arguments); -// }); -// constructor.prototype = Handle.prototype; -// -// registerType(classType, name, { -// name: name, -// constructor: constructor, -// Handle: Handle, -// fromWireType: function(ptr) { -// return new Handle(ptr); -// }, -// toWireType: function(destructors, o) { -// return o.ptr; -// } -// }); -// -// var pointerName = name + '*'; -// registerType(pointerType, pointerName, { -// name: pointerName, -// fromWireType: function(ptr) { -// // based on the fully downcast type of the pointer, -// -// return new Handle(ptr); // if me -// }, -// toWireType: function(destructors, o) { -// return o.ptr; -// } -// }); -// -// var constPointerName = name + ' const*'; -// registerType(constPointerType, constPointerName, { -// name: constPointerName, -// fromWireType: function(ptr) { -// return new Handle(ptr); -// }, -// toWireType: function(destructors, o) { -// return o.ptr; -// } -// }); -// -// exposePublicSymbol(name, constructor); -//} -// function __embind_register_class_constructor( classType, argCount, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 96e8dda5a3807..54c017ef059a2 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -104,7 +104,6 @@ namespace emscripten { TYPEID pointerType, TYPEID constPointerType, const char* className, - GenericFunction getDynamicTypeInfo, GenericFunction destructor); void _embind_register_class_constructor( @@ -267,16 +266,16 @@ namespace emscripten { // FUNCTIONS //////////////////////////////////////////////////////////////////////////////// + extern "C" { + int __getDynamicPointerType(int p); + int __dynamicPointerCast(int p, int from, int to); + } + template ToType& performCast(FromType& from) { return *dynamic_cast(&from); }; - template - internal::TYPEID getDynamicPointerType(PointerType *p) { - return reinterpret_cast(&typeid(*p)); - }; - template std::shared_ptr performPointerCast(std::shared_ptr from) { return std::shared_ptr(from, dynamic_cast(from.get())); @@ -662,7 +661,6 @@ namespace emscripten { TypeID>::get(), TypeID>::get(), name, - reinterpret_cast(&getDynamicPointerType), reinterpret_cast(&raw_destructor)); } diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index befce08b1be81..c7c1f4b4474a1 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -1,7 +1,43 @@ #include +#include <..\lib\libcxxabi\src\private_typeinfo.h> +#include +#include +#include using namespace emscripten; +namespace __cxxabiv1 { + std::vector __getBaseClasses(const __class_type_info* cti) { + std::vector bases; + + const __si_class_type_info* scti = dynamic_cast(cti); + if (scti) { + bases.emplace_back(scti->__base_type); + } else { + const __vmi_class_type_info* vcti = dynamic_cast(cti); + if (vcti) { + for (int i = 0; i < vcti->__base_count; i++) { + bases.emplace_back(vcti->__base_info[i].__base_type); + } + } + } + return bases; + } + + void __getDerivationPaths1(const __class_type_info* dv, const __class_type_info* bs, std::vectorpath, std::vector>& paths) { + std::vector newPath(path); + newPath.emplace_back(dv); + if (dv == bs) { + paths.emplace_back(newPath); + } else { + std::vector bases = __getBaseClasses(dv); + for (int i = 0; i < bases.size(); i++) { + __getDerivationPaths1(bases[i], bs, newPath, paths); + } + } + } +} + namespace emscripten { namespace internal { void registerStandardTypes() { @@ -30,5 +66,71 @@ namespace emscripten { _embind_register_emval(TypeID::get(), "emscripten::val"); } } + + extern "C" { + // These three routines constitute an extension to the compiler's support for dynamic type conversion. + // They are used by embind.js to implement automatic downcasting of return values which are pointers to + // polymorphic objects. + + // __getDerivationPaths returns an array of arrays of type_info pointers (cast as integers to make + // the Javascript bindings simpler). Each element of the outer array is an array of type_info pointers + // identifying a derivation path from the derived type to the base type. If either of the type info + // pointer paramters does not specify a pointer to a class, or if there is no path from the derived type + // to the base type, this routine returns zero. + std::vector> __getDerivationPaths(int dv, const int bs) { + std::vector> paths; + + const std::type_info* dv1 = (std::type_info*)dv; + const std::type_info* bs1 = (std::type_info*)bs; + const __cxxabiv1::__class_type_info* dv2 = dynamic_cast(dv1); + const __cxxabiv1::__class_type_info* bs2 = dynamic_cast(bs1); + + if (dv2 && bs2) { + __cxxabiv1::__getDerivationPaths1(dv2, bs2, std::vector(), paths); + } + + std::vector> pathsAsTypeInfo; + for (int i = 0; i < paths.size(); i++) { + std::vector pathAsTypeInfo; + for (int j = 0; j < paths[i].size(); j++) { + pathAsTypeInfo.emplace_back((int)paths[i][j]); + } + pathsAsTypeInfo.emplace_back(pathAsTypeInfo); + } + + return pathsAsTypeInfo; + } + + // We bind __getDerivationPaths in order to take advantage of the std::vector to Javascript array + // conversion for the return value. This has the unfortunate side-effect of exposing it to third party + // developers, but perhaps the double underscore will scare them away from calling it. + EMSCRIPTEN_BINDINGS(([]() { + function("__getDerivationPaths", &__getDerivationPaths); + })); + + // __getDynamicPointerType returns (for polymorphic types only!) the type of the instance actually + // pointed to. + int EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(int p) { + void** vtable = *(void***)p; + return (int)static_cast(vtable[-1]); + } + + // Calls to __dynamic_cast are generated by the compiler to implement dynamic_cast<>() -- its prototype is + // not available through any header file. It is called directly here because it allows run-time + // specification of the target pointer type (which must be specified at compile time when using + // dynamic_cast<>(). + void* __dynamic_cast(void*, const std::type_info*, const std::type_info*, int); + + // __dynamicPointerCast performs a C++ dynamic_cast<>() operation, but allowing run-time specification of + // the from and to pointer types. + int EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(int p, int from, int to) { + // The final parameter is a place-holder for a hint, a feature which is not currently implemented + // in the emscripten runtime. The compiler passes a dummy value of -1, and so do we. + return (int)__dynamic_cast((void *)p, (const std::type_info*)from, (const std::type_info *)to, -1); + } + } } } + + + From 51cdfb5fdb74871c2d0ebb23635f5d28dfdacb43 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 4 Dec 2012 11:55:29 -0800 Subject: [PATCH 184/544] Fix a jshint issue --- src/embind/embind.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index 7f4e0d2e2b058..2c5d20c06890f 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -575,6 +575,7 @@ function __embind_register_class( } }); + /*global ___getDynamicPointerType: false*/ var pointerName = name + '*'; registerType(pointerType, pointerName, { name: pointerName, From 119ab2f1c412c7eb4863f852a690cdf215339b07 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Wed, 5 Dec 2012 12:27:06 -0800 Subject: [PATCH 185/544] Better error reporting Fixed demangling routine and added it to RTL New __typeName method to retrieve char* type name from type info --- src/embind/embind.js | 8 ++++---- system/lib/embind/bind.cpp | 36 ++++++++++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 2c5d20c06890f..e990c1a18c7b2 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -137,15 +137,15 @@ var BindingError = Error; /** @expose */ Module.BindingError = BindingError; -function typeName(typeID) { - // could use our carnal knowledge of RTTI but for now just return the pointer... - return typeID; +/*global ___typeName:false*/ +function typeName(type) { + return Pointer_stringify(___typeName(type)); } function requireRegisteredType(type, humanName) { var impl = typeRegistry[type]; if (undefined === impl) { - throw new BindingError(humanName + " has unknown type: " + typeName(type)); + throw new BindingError(humanName + " has unknown type " + typeName(type)); } return impl; } diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index c7c1f4b4474a1..673fdf1a97c8e 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -1,7 +1,10 @@ #include #include <..\lib\libcxxabi\src\private_typeinfo.h> +#include <..\lib\libcxxabi\include\cxxabi.h> #include #include +#include +#include #include using namespace emscripten; @@ -101,13 +104,6 @@ namespace emscripten { return pathsAsTypeInfo; } - // We bind __getDerivationPaths in order to take advantage of the std::vector to Javascript array - // conversion for the return value. This has the unfortunate side-effect of exposing it to third party - // developers, but perhaps the double underscore will scare them away from calling it. - EMSCRIPTEN_BINDINGS(([]() { - function("__getDerivationPaths", &__getDerivationPaths); - })); - // __getDynamicPointerType returns (for polymorphic types only!) the type of the instance actually // pointed to. int EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(int p) { @@ -117,7 +113,7 @@ namespace emscripten { // Calls to __dynamic_cast are generated by the compiler to implement dynamic_cast<>() -- its prototype is // not available through any header file. It is called directly here because it allows run-time - // specification of the target pointer type (which must be specified at compile time when using + // specification of the target pointer type (which can only be specified at compile time when using // dynamic_cast<>(). void* __dynamic_cast(void*, const std::type_info*, const std::type_info*, int); @@ -128,6 +124,30 @@ namespace emscripten { // in the emscripten runtime. The compiler passes a dummy value of -1, and so do we. return (int)__dynamic_cast((void *)p, (const std::type_info*)from, (const std::type_info *)to, -1); } + + const char* EMSCRIPTEN_KEEPALIVE __typeName(int p) { + const std::type_info* ti = (const std::type_info*)p; + size_t nameLen = std::min(strlen(ti->name()), (unsigned int)1024); + char* name = (char *)malloc(nameLen+1); + int stat; + + __cxxabiv1::__cxa_demangle(ti->name(), name, &nameLen, &stat); + + if (stat != 0) { + strncpy(name, ti->name(), nameLen); + name[nameLen] = '\0'; + } + return name; + } + + EMSCRIPTEN_BINDINGS(([]() { + // We bind __getDerivationPaths in order to take advantage of the std::vector to Javascript array + // conversion for the return value. This has the unfortunate side-effect of exposing it to third party + // developers, but perhaps the double underscore will scare them away from calling it. + function("__getDerivationPaths", &__getDerivationPaths); + })); + + } } } From 5fba40c9d81d8dc5ccb5fb9d12fa44eb884d96a6 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Wed, 5 Dec 2012 12:56:41 -0800 Subject: [PATCH 186/544] Forward slashes! --- system/lib/embind/bind.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 673fdf1a97c8e..1fcf987a6e4a1 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -1,6 +1,6 @@ #include -#include <..\lib\libcxxabi\src\private_typeinfo.h> -#include <..\lib\libcxxabi\include\cxxabi.h> +#include <../lib/libcxxabi/src/private_typeinfo.h> +#include <../lib/libcxxabi/include/cxxabi.h> #include #include #include From 77dd6c9e8355041fe9363c25b2e30dbc9836b13f Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Thu, 6 Dec 2012 09:35:28 -0800 Subject: [PATCH 187/544] First fully functional automatic downcasting implementation. --- src/embind/embind.js | 33 ++++++++++++++++------ system/include/emscripten/bind.h | 2 ++ system/lib/embind/bind.cpp | 48 ++++++++++++++++++++------------ 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index e990c1a18c7b2..4ff84005814bc 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -497,6 +497,7 @@ function __embind_register_class( classType, pointerType, constPointerType, + isPolymorphic, name, destructor ) { @@ -580,17 +581,31 @@ function __embind_register_class( registerType(pointerType, pointerName, { name: pointerName, fromWireType: function(ptr) { - var dynamicType = ___getDynamicPointerType(ptr); // !!! this won't work if pointer is not dynamic - if (dynamicType === null || dynamicType === pointerType) { - return new Handle(ptr); - } - try { - dynamicType = requireRegisteredType(dynamicType); - } catch (err) { + if (isPolymorphic) { + var toType = ___getDynamicPointerType(ptr); + var toTypeImpl = null; + if (toType === null || toType === pointerType) { + return new Handle(ptr); + } + var derivation = Module.__getDerivationPath(toType, classType); + var candidate = null; + for (var i = 0; i < derivation.size(); i++) { + candidate = derivation.at(i); + toTypeImpl = typeRegistry[candidate]; + if (toTypeImpl) { + break; + } + } + derivation.delete(); + if (toTypeImpl === null) { + return new Handle(ptr); + } + var toTypePointerImpl = requireRegisteredType(toTypeImpl.pointerType); + var castPtr = ___dynamicPointerCast(ptr, classType, candidate); + return toTypePointerImpl.fromWireTypeStatic(castPtr); + } else { return new Handle(ptr); } - dynamicType = requireRegisteredType(dynamicType.pointerType); - return dynamicType.fromWireTypeStatic(ptr); }, fromWireTypeStatic: function(ptr) { return new Handle(ptr); diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 54c017ef059a2..7dc3494919041 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -103,6 +103,7 @@ namespace emscripten { TYPEID classType, TYPEID pointerType, TYPEID constPointerType, + bool isPolymorphic, const char* className, GenericFunction destructor); @@ -660,6 +661,7 @@ namespace emscripten { TypeID::get(), TypeID>::get(), TypeID>::get(), + std::is_polymorphic::value, name, reinterpret_cast(&raw_destructor)); } diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 1fcf987a6e4a1..9663ad51b5ff9 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -27,7 +27,7 @@ namespace __cxxabiv1 { return bases; } - void __getDerivationPaths1(const __class_type_info* dv, const __class_type_info* bs, std::vectorpath, std::vector>& paths) { + void __getDerivationPaths(const __class_type_info* dv, const __class_type_info* bs, std::vectorpath, std::vector>& paths) { std::vector newPath(path); newPath.emplace_back(dv); if (dv == bs) { @@ -35,7 +35,7 @@ namespace __cxxabiv1 { } else { std::vector bases = __getBaseClasses(dv); for (int i = 0; i < bases.size(); i++) { - __getDerivationPaths1(bases[i], bs, newPath, paths); + __getDerivationPaths(bases[i], bs, newPath, paths); } } } @@ -75,12 +75,10 @@ namespace emscripten { // They are used by embind.js to implement automatic downcasting of return values which are pointers to // polymorphic objects. - // __getDerivationPaths returns an array of arrays of type_info pointers (cast as integers to make - // the Javascript bindings simpler). Each element of the outer array is an array of type_info pointers - // identifying a derivation path from the derived type to the base type. If either of the type info - // pointer paramters does not specify a pointer to a class, or if there is no path from the derived type - // to the base type, this routine returns zero. - std::vector> __getDerivationPaths(int dv, const int bs) { + // __getDerivationPath returns an array of type_info pointers describing the derivation chain starting with + // the derived type and proceeding toward (and ending with) the base type. Types are only included if they + // appear on all possible derivation paths. + std::vector __getDerivationPath(int dv, const int bs) { std::vector> paths; const std::type_info* dv1 = (std::type_info*)dv; @@ -89,19 +87,33 @@ namespace emscripten { const __cxxabiv1::__class_type_info* bs2 = dynamic_cast(bs1); if (dv2 && bs2) { - __cxxabiv1::__getDerivationPaths1(dv2, bs2, std::vector(), paths); + __cxxabiv1::__getDerivationPaths(dv2, bs2, std::vector(), paths); } - std::vector> pathsAsTypeInfo; - for (int i = 0; i < paths.size(); i++) { - std::vector pathAsTypeInfo; - for (int j = 0; j < paths[i].size(); j++) { - pathAsTypeInfo.emplace_back((int)paths[i][j]); + std::vector derivationPath; + if (paths.size() > 0) { + for (int j = 0; j < paths[0].size(); j++) { + bool disqualified = false; + for (int i = 1; i < paths.size(); i++) { + bool found = false; + for (int j2 = 0; j2 < paths[i].size(); j2++) { + if (paths[i][j2] == paths[0][j]) { + found = true; + break; + } + } + if (!found) { + disqualified = true; + break; + } + } + if (!disqualified) { + derivationPath.emplace_back((int)paths[0][j]); + } } - pathsAsTypeInfo.emplace_back(pathAsTypeInfo); } - return pathsAsTypeInfo; + return derivationPath; } // __getDynamicPointerType returns (for polymorphic types only!) the type of the instance actually @@ -141,10 +153,10 @@ namespace emscripten { } EMSCRIPTEN_BINDINGS(([]() { - // We bind __getDerivationPaths in order to take advantage of the std::vector to Javascript array + // We bind __getDerivationPath in order to take advantage of the std::vector to Javascript array // conversion for the return value. This has the unfortunate side-effect of exposing it to third party // developers, but perhaps the double underscore will scare them away from calling it. - function("__getDerivationPaths", &__getDerivationPaths); + function("__getDerivationPath", &__getDerivationPath); })); From c0fce04cc6ef9920f9d91dbd3720b58ae171e80c Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Thu, 6 Dec 2012 09:37:21 -0800 Subject: [PATCH 188/544] Suppress a lint warning --- src/embind/embind.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index 4ff84005814bc..5ceaf24647f37 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -577,6 +577,7 @@ function __embind_register_class( }); /*global ___getDynamicPointerType: false*/ + /*global ___dynamicPointerCast: false*/ var pointerName = name + '*'; registerType(pointerType, pointerName, { name: pointerName, From a668fe09c459f0a5691d43b81a16f09cfb9fd43a Mon Sep 17 00:00:00 2001 From: jinsuck Date: Mon, 10 Dec 2012 08:57:06 -0800 Subject: [PATCH 189/544] remove an unused method --- src/embind/emval.js | 4 ---- system/include/emscripten/val.h | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index e8ee6baf5b9f6..eb2cae0eed9f4 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -57,10 +57,6 @@ function __emval_new_cstring(str) { return __emval_register(Pointer_stringify(str)); } -function __emval_has_property(handle, k) { - return _emval_handle_array[handle].value.hasOwnProperty(k); -} - function __emval_get_property(handle, k) { k = Pointer_stringify(k); return __emval_register(_emval_handle_array[handle].value[k]); diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index e2d353823202f..91becb4f62cad 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -84,10 +84,6 @@ namespace emscripten { return *this; } - bool exist(const char* key) const { - return internal::_emval_has_property(handle, key); - } - val get(const char* key) const { return val(internal::_emval_get_property(handle, key)); } From 4f143f4638aa8239ed5ae6a69a9cfa4997254572 Mon Sep 17 00:00:00 2001 From: jinsuck Date: Mon, 10 Dec 2012 09:11:06 -0800 Subject: [PATCH 190/544] Revert "remove an unused method" This reverts commit 7300ba73d3004b8d5c69bd8e3dfbc971c3147ad8. --- src/embind/emval.js | 4 ++++ system/include/emscripten/val.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/embind/emval.js b/src/embind/emval.js index eb2cae0eed9f4..e8ee6baf5b9f6 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -57,6 +57,10 @@ function __emval_new_cstring(str) { return __emval_register(Pointer_stringify(str)); } +function __emval_has_property(handle, k) { + return _emval_handle_array[handle].value.hasOwnProperty(k); +} + function __emval_get_property(handle, k) { k = Pointer_stringify(k); return __emval_register(_emval_handle_array[handle].value[k]); diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 91becb4f62cad..e2d353823202f 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -84,6 +84,10 @@ namespace emscripten { return *this; } + bool exist(const char* key) const { + return internal::_emval_has_property(handle, key); + } + val get(const char* key) const { return val(internal::_emval_get_property(handle, key)); } From 89299704617493eef217c68194053884e55a71f5 Mon Sep 17 00:00:00 2001 From: mey Date: Mon, 10 Dec 2012 13:51:57 -0800 Subject: [PATCH 191/544] Removing unused vector binding code that was missed during previous vector refactorings. --- system/include/emscripten/bind.h | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 7dc3494919041..48da75289003d 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -464,33 +464,6 @@ namespace emscripten { setter(ptr, FieldBinding::fromWireType(value)); } }; - - template - struct Vector { - typedef typename VectorType::value_type ElementType; - typedef internal::BindingType FieldBinding; - typedef typename FieldBinding::WireType WireType; - - static int length( - VectorType* ptr - ) { - return (*ptr).size(); - } - - static WireType getAt( - VectorType* ptr, - int pos - ) { - return FieldBinding::toWireType((*ptr).at(pos)); - } - - static void push_back( - VectorType* ptr, - WireType val - ) { - (*ptr).push_back(FieldBinding::fromWireType(val)); - } - }; } //////////////////////////////////////////////////////////////////////////////// From 50ba3a6ff9933cca9a3f1f893648162c9910d9fb Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Wed, 12 Dec 2012 13:35:33 -0800 Subject: [PATCH 192/544] Benchmark work on pointer casting. --- src/embind/embind.js | 21 ++++++----- system/include/emscripten/bind.h | 4 +-- system/lib/embind/bind.cpp | 60 +++++++++++++++++++++++++++++++- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 5ceaf24647f37..643ce728b0b68 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -372,7 +372,7 @@ function __embind_register_smart_ptr( getPointee ) { name = Pointer_stringify(name); - pointeeType = requireRegisteredType(pointeeType, 'class'); + var pointeeTypeImpl = requireRegisteredType(pointeeType, 'class'); destructor = FUNCTION_TABLE[destructor]; getPointee = FUNCTION_TABLE[getPointee]; @@ -384,11 +384,11 @@ function __embind_register_smart_ptr( // TODO: test for SmartPtr.prototype.constructor property? // We likely want it distinct from pointeeType.prototype.constructor - Handle.prototype = Object.create(pointeeType.Handle.prototype); + Handle.prototype = Object.create(pointeeTypeImpl.Handle.prototype); Handle.prototype.clone = function() { if (!this.ptr) { - throw new BindingError(pointeeType.name + ' instance already deleted'); + throw new BindingError(pointeeTypeImpl.name + ' instance already deleted'); } var clone = Object.create(Handle.prototype); @@ -402,7 +402,7 @@ function __embind_register_smart_ptr( Handle.prototype['delete'] = function() { if (!this.ptr) { - throw new BindingError(pointeeType.name + ' instance already deleted'); + throw new BindingError(pointeeTypeImpl.name + ' instance already deleted'); } this.count.value -= 1; @@ -695,20 +695,21 @@ function __embind_register_class_method( }; } +/*global ___staticPointerCast: false*/ function __embind_register_cast_method( classType, methodName, returnType, invoker ) { - classType = requireRegisteredType(classType, 'class'); + var classTypeImpl = requireRegisteredType(classType, 'class'); methodName = Pointer_stringify(methodName); - var humanName = classType.name + '.' + methodName; + var humanName = classTypeImpl.name + '.' + methodName; - returnType = requireRegisteredType(returnType, 'method ' + humanName + ' return value'); + var returnTypeImpl = requireRegisteredType(returnType, 'method ' + humanName + ' return value'); invoker = FUNCTION_TABLE[invoker]; - classType.Handle.prototype[methodName] = function() { + classTypeImpl.Handle.prototype[methodName] = function() { if (!this.ptr) { throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } @@ -718,7 +719,9 @@ function __embind_register_cast_method( var args = new Array(1); args[0] = this.ptr; - var rv = returnType.fromWireType(invoker.apply(null, args)); // in case ptr needs to be adjusted for multiple inheritance + var rv = returnTypeImpl.fromWireType(invoker.apply(null, args)); + rv.count = this.count; // the cast value shares the reference count of the original pointer, but does not increment it + this.count.value ++; return rv; }; } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 48da75289003d..48a0fd58a29a6 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -279,7 +279,7 @@ namespace emscripten { template std::shared_ptr performPointerCast(std::shared_ptr from) { - return std::shared_ptr(from, dynamic_cast(from.get())); + return std::shared_ptr(from, static_cast(from.get())); }; template @@ -613,7 +613,7 @@ namespace emscripten { TypeID::get(), methodName, TypeID::get(), - reinterpret_cast(&performPointerCast)); + reinterpret_cast(&performPointerCast)); return *this; } }; diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 9663ad51b5ff9..de03052a49434 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -27,6 +27,21 @@ namespace __cxxabiv1 { return bases; } + int __getBaseOffset(const __class_type_info* ctiDv, const __class_type_info* ctiBs) { + int offset = 0; + + const __vmi_class_type_info* vcti = dynamic_cast(ctiDv); + if (vcti) { + for (int i = 0; i < vcti->__base_count; i++) { + if (vcti->__base_info[i].__base_type == ctiBs) { + offset = vcti->__base_info[i].__offset_flags >> __base_class_type_info::__offset_shift; + break; + } + } + } + return offset; + } + void __getDerivationPaths(const __class_type_info* dv, const __class_type_info* bs, std::vectorpath, std::vector>& paths) { std::vector newPath(path); newPath.emplace_back(dv); @@ -39,6 +54,14 @@ namespace __cxxabiv1 { } } } + + int __pathOffset(std::vector path) { + int offset = 0; + for (int i = 0; i < path.size()-1; i++) { + offset += __getBaseOffset(path[i], path[i+1]); + } + return offset; + } } namespace emscripten { @@ -112,10 +135,45 @@ namespace emscripten { } } } - return derivationPath; } + void* EMSCRIPTEN_KEEPALIVE __staticPointerCast(void* p, int dv, int bs) { + std::vector> paths; + int direction = 1; + + const std::type_info* dv1 = (std::type_info*)dv; + const std::type_info* bs1 = (std::type_info*)bs; + const __cxxabiv1::__class_type_info* dv2 = dynamic_cast(dv1); + const __cxxabiv1::__class_type_info* bs2 = dynamic_cast(bs1); + + if (dv2 && bs2) { + __cxxabiv1::__getDerivationPaths(dv2, bs2, std::vector(), paths); + if (paths.size() == 0) { + __cxxabiv1::__getDerivationPaths(bs2, dv2, std::vector(), paths); + direction = -1; + } + } + + int offset = -1; + for (int i = 0; i < paths.size(); i++) { + if (offset < 0) { + offset = __cxxabiv1::__pathOffset(paths[i]); + } else { + if (offset != __cxxabiv1::__pathOffset(paths[i])) { + return (void *)-2; // ambiguous cast -- throw instead? + } + } + } + if (offset < 0) { + return (void *)-1; // types are not related -- throw instead? + } + if (p == 0) { + return (void *)0; + } + return (void *)((int)p + offset * direction); + } + // __getDynamicPointerType returns (for polymorphic types only!) the type of the instance actually // pointed to. int EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(int p) { From eab7bc729e8c881ffdba9f47c00ad245709fa932 Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Mon, 17 Dec 2012 18:25:27 -0800 Subject: [PATCH 193/544] remove unnecessary code --- system/include/emscripten/val.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index e2d353823202f..de69d00f3b446 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -121,10 +121,6 @@ namespace emscripten { internal::_emval_set_property_by_int(handle, key, v.handle); } - unsigned int length() { - return get("length").as(); - } - template val operator()(Args... args) { using namespace internal; From a7733270b037dcb2e2cf97ecd17ce76f3d4a2da9 Mon Sep 17 00:00:00 2001 From: jinsuck Date: Tue, 18 Dec 2012 13:28:45 -0800 Subject: [PATCH 194/544] add const to val --- system/include/emscripten/val.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index de69d00f3b446..9e067a92f06d6 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -141,7 +141,7 @@ namespace emscripten { } template - val call(const char* name, Args... args) { + val call(const char* name, Args... args) const { using namespace internal; WithPolicies<>::ArgTypeList argList; @@ -162,7 +162,7 @@ namespace emscripten { } template - void call_void(const char* name, Args... args) { + void call_void(const char* name, Args... args) const { using namespace internal; WithPolicies<>::ArgTypeList argList; From 0e3ca9c9d67dfa7efd95d97d3c1a5d0edc6fdb24 Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Tue, 18 Dec 2012 15:02:40 -0800 Subject: [PATCH 195/544] add ability for descendent to clone interface --- system/include/emscripten/bind.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 48a0fd58a29a6..56a3b62cfeed7 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -887,9 +887,7 @@ namespace emscripten { wrapper() {} // to avoid error "call to implicitly deleted construrtor..." wrapper(InterfaceType* interface) { - // why dynamic_cast causes javascript crash? - wrapper* iw = static_cast*>(interface); - jsobj = iw->jsobj; + cloneInterface(interface); } // Not necessary in any example so far, but appeases a compiler warning. @@ -919,6 +917,13 @@ namespace emscripten { return Caller::call(*jsobj, name, args...); } + protected: + void cloneInterface(InterfaceType* interface) { + // why dynamic_cast causes javascript crash? + wrapper* iw = static_cast*>(interface); + jsobj = iw->jsobj; + } + private: // this class only exists because you can't partially specialize function templates template From 40773165f4b7481b1e62533cd94c75fa2d73622d Mon Sep 17 00:00:00 2001 From: jinsuck Date: Wed, 19 Dec 2012 16:56:06 -0800 Subject: [PATCH 196/544] add const to a function in val --- system/include/emscripten/val.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 9e067a92f06d6..8f7df8827c763 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -109,7 +109,7 @@ namespace emscripten { return val(internal::_emval_get_property_by_unsigned_long(handle, key)); } - val eval_global_method(const char* objectName, const char* methodName) { + val eval_global_method(const char* objectName, const char* methodName) const { return val(internal::_emval_eval_global_method(handle, objectName, methodName)); } From eca17e7c1b78673821cef5d093768d5dfbff329d Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Thu, 20 Dec 2012 10:47:30 -0800 Subject: [PATCH 197/544] stringify key name before checking if the key exists --- src/embind/emval.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/embind/emval.js b/src/embind/emval.js index e8ee6baf5b9f6..49424631fff7a 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -58,6 +58,7 @@ function __emval_new_cstring(str) { } function __emval_has_property(handle, k) { + k = Pointer_stringify(k); return _emval_handle_array[handle].value.hasOwnProperty(k); } From 77f2b4588b65c4c3641131ee71657eaaa8d3dcaf Mon Sep 17 00:00:00 2001 From: jinsuck Date: Thu, 20 Dec 2012 19:20:29 -0800 Subject: [PATCH 198/544] add a method to conveniently clone to shared pointer of wrapper --- system/include/emscripten/bind.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 56a3b62cfeed7..3f857a2ab7242 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -902,6 +902,11 @@ namespace emscripten { return std::shared_ptr(ip); } + template + static std::shared_ptr cloneToSharedWrapperPtr(InterfaceType& i) { + return std::dynamic_pointer_cast(cloneToSharedPtr(i)); + } + void initialize(internal::EM_VAL handle) { if (jsobj) { internal::_embind_fatal_error( From ea98beba7402b83a05434342d5b2af85aae3dd42 Mon Sep 17 00:00:00 2001 From: jinsuck Date: Fri, 21 Dec 2012 15:24:48 -0800 Subject: [PATCH 199/544] remove meaningless casting back and forth --- system/include/emscripten/bind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 3f857a2ab7242..90dca77cb5bb2 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -904,7 +904,7 @@ namespace emscripten { template static std::shared_ptr cloneToSharedWrapperPtr(InterfaceType& i) { - return std::dynamic_pointer_cast(cloneToSharedPtr(i)); + return std::make_shared(&i); } void initialize(internal::EM_VAL handle) { From 2308f2a5b19e92d9f974b4a7ee733d5c6f3da4bb Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Sat, 22 Dec 2012 10:19:52 -0800 Subject: [PATCH 200/544] More work on auto downcasting. --- src/embind/embind.js | 131 ++++++++++++++++++++++++++----- system/include/emscripten/bind.h | 26 +++--- system/lib/embind/bind.cpp | 24 +++--- 3 files changed, 141 insertions(+), 40 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 643ce728b0b68..285e632a0336f 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -182,7 +182,12 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { for (var i = 1; i < argCount; ++i) { args[i] = argTypes[i].toWireType(destructors, arguments[i-1]); } - var rv = argTypes[0].fromWireType(invoker.apply(null, args)); + var rv = invoker.apply(null, args); + if (argTypes[0].hasOwnProperty('fromWireTypeAutoDowncast')) { + rv = argTypes[0].fromWireTypeAutoDowncast(rv); + } else { + rv = argTypes[0].fromWireType(rv); + } runDestructors(destructors); return rv; }; @@ -367,12 +372,14 @@ function __embind_register_struct_field( function __embind_register_smart_ptr( pointerType, pointeeType, + isPolymorphic, name, destructor, getPointee ) { name = Pointer_stringify(name); var pointeeTypeImpl = requireRegisteredType(pointeeType, 'class'); + pointeeTypeImpl.smartPointerType = pointerType; destructor = FUNCTION_TABLE[destructor]; getPointee = FUNCTION_TABLE[getPointee]; @@ -416,6 +423,44 @@ function __embind_register_smart_ptr( registerType(pointerType, name, { name: name, Handle: Handle, + fromWireTypeAutoDowncast: function(ptr) { + if (!getPointee(ptr)) { + destructor(ptr); + return null; + } + if (isPolymorphic) { + // todo: clean up this code + var pointee = getPointee(ptr); + var toType = ___getDynamicPointerType(pointee); + var toTypeImpl = null; + if (toType === null || toType === pointeeType) { + return new Handle(ptr); + } + // todo: getDerivationPath is expensive -- cache the result + var derivation = Module.__getDerivationPath(toType, pointeeType); + var candidate = null; + for (var i = 0; i < derivation.size(); i++) { + candidate = derivation.at(i); + toTypeImpl = typeRegistry[candidate]; + if (toTypeImpl) { + break; + } + } + derivation.delete(); + if (toTypeImpl === null) { + return new Handle(ptr); + } + var toTypePointerImpl = requireRegisteredType(toTypeImpl.smartPointerType); + // todo: need to clone the ptr here (really??) + var castPtr = toTypePointerImpl.fromWireType(ptr); + // todo: do we really need ___dynamicPointerCast here? We know what type we're starting with. + castPtr.ptr = ___dynamicPointerCast(pointee, candidate); + // todo: we need to release the pre-cast pointer, don't we? how did this get past the tests? + return castPtr; + } else { + return new Handle(ptr); + } + }, fromWireType: function(ptr) { if (!getPointee(ptr)) { destructor(ptr); @@ -493,6 +538,7 @@ function __embind_register_vector( }); } +// TODO: null pointers are always zero (not a Handle) in Javascript function __embind_register_class( classType, pointerType, @@ -513,7 +559,7 @@ function __embind_register_class( } }; - h.count = {value: 1}; + h.count = {value: 1, ptr: ptr }; h.ptr = ptr; for(var prop in Handle.prototype) { @@ -532,7 +578,7 @@ function __embind_register_class( var clone = Object.create(Handle.prototype); clone.count = this.count; clone.ptr = this.ptr; - + clone.count.value += 1; return clone; }; @@ -543,6 +589,8 @@ function __embind_register_class( return rv; }; + // todo: test delete with upcast and downcast multiply derived pointers + // todo: then replace this.count.ptr below with this.ptr and make sure it fails Handle.prototype['delete'] = function() { if (!this.ptr) { throw new BindingError(classType.name + ' instance already deleted'); @@ -550,7 +598,7 @@ function __embind_register_class( this.count.value -= 1; if (0 === this.count.value) { - destructor(this.ptr); + destructor(this.count.ptr); } this.ptr = undefined; }; @@ -581,7 +629,7 @@ function __embind_register_class( var pointerName = name + '*'; registerType(pointerType, pointerName, { name: pointerName, - fromWireType: function(ptr) { + fromWireTypeAutoDowncast: function(ptr) { if (isPolymorphic) { var toType = ___getDynamicPointerType(ptr); var toTypeImpl = null; @@ -602,13 +650,16 @@ function __embind_register_class( return new Handle(ptr); } var toTypePointerImpl = requireRegisteredType(toTypeImpl.pointerType); - var castPtr = ___dynamicPointerCast(ptr, classType, candidate); - return toTypePointerImpl.fromWireTypeStatic(castPtr); + var handle = toTypePointerImpl.fromWireType(ptr); + handle.ptr = ___staticPointerCast(handle.ptr, classType, candidate); + // todo: can come back -1 or -2!! Throw appropriate exception + return handle; } else { - return new Handle(ptr); - } + handle = new Handle(ptr); + } + return handle; }, - fromWireTypeStatic: function(ptr) { + fromWireType: function(ptr) { return new Handle(ptr); }, toWireType: function(destructors, o) { @@ -688,8 +739,12 @@ function __embind_register_class_method( for (var i = 1; i < argCount; ++i) { args[i + 1] = argTypes[i].toWireType(destructors, arguments[i-1]); } - - var rv = argTypes[0].fromWireType(invoker.apply(null, args)); + var rv = invoker.apply(null, args); + if (argTypes[0].hasOwnProperty('fromWireTypeAutoDowncast')) { + rv = argTypes[0].fromWireTypeAutoDowncast(rv); + } else { + rv = argTypes[0].fromWireType(rv); + } runDestructors(destructors); return rv; }; @@ -698,6 +753,7 @@ function __embind_register_class_method( /*global ___staticPointerCast: false*/ function __embind_register_cast_method( classType, + isPolymorphic, methodName, returnType, invoker @@ -716,42 +772,75 @@ function __embind_register_cast_method( if (arguments.length !== 0) { throw new BindingError('emscripten binding method ' + humanName + ' called with arguments, none expected'); } - + if (isPolymorphic) { + // todo: this is all only to validate the cast -- cache the result + var runtimeType = ___getDynamicPointerType(this.ptr); + var derivation = Module.__getDerivationPath(returnType, runtimeType); // downcast is valid + var size = derivation.size(); + derivation.delete(); + if (size == 0) { + derivation = Module.__getDerivationPath(runtimeType, returnType); // upcast is valid + size = derivation.size(); + derivation.delete(); + if (size == 0) { + // todo: return zero + return returnTypeImpl.fromWireType(0); + } + } + } var args = new Array(1); args[0] = this.ptr; var rv = returnTypeImpl.fromWireType(invoker.apply(null, args)); - rv.count = this.count; // the cast value shares the reference count of the original pointer, but does not increment it + rv.count = this.count; this.count.value ++; return rv; }; } function __embind_register_pointer_cast_method( - classType, - methodName, + pointerType, returnType, + returnPointeeType, + isPolymorphic, + methodName, invoker ) { - classType = requireRegisteredType(classType, 'class'); + var pointerTypeImpl = requireRegisteredType(pointerType, 'smart pointer class'); methodName = Pointer_stringify(methodName); - var humanName = classType.name + '.' + methodName; + var humanName = pointerTypeImpl.name + '.' + methodName; - returnType = requireRegisteredType(returnType, 'method ' + humanName + ' return value'); + var returnTypeImpl = requireRegisteredType(returnType, 'method ' + humanName + ' return value'); invoker = FUNCTION_TABLE[invoker]; - classType.Handle.prototype[methodName] = function() { + pointerTypeImpl.Handle.prototype[methodName] = function() { if (!this.ptr) { throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } if (arguments.length !== 0) { throw new BindingError('emscripten binding method ' + humanName + ' called with arguments, none expected'); } + if (isPolymorphic) { + // todo: just validating the cast -- cache the result + // todo: throw exception instead of returning zero + var runtimeType = ___getDynamicPointerType(this.ptr); + var derivation = Module.__getDerivationPath(returnPointeeType, runtimeType); // downcast is valid + var size = derivation.size(); + derivation.delete(); + if (size == 0) { + derivation = Module.__getDerivationPath(runtimeType, returnPointeeType); // upcast is valid + size = derivation.size(); + derivation.delete(); + if (size == 0) { + return 0; + } + } + } var args = new Array(2); var newPtr = _malloc(8); args[0] = newPtr; args[1] = this.smartPointer; invoker.apply(null,args); - var rv = returnType.fromWireType(newPtr); // in case ptr needs to be adjusted for multiple inheritance + var rv = returnTypeImpl.fromWireType(newPtr); return rv; }; } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 90dca77cb5bb2..c37aed24c7686 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -95,6 +95,7 @@ namespace emscripten { void _embind_register_smart_ptr( TYPEID pointerType, TYPEID pointeeType, + bool isPolymorphic, const char* pointerName, GenericFunction destructor, GenericFunction getPointee); @@ -124,14 +125,17 @@ namespace emscripten { void _embind_register_cast_method( TYPEID classType, + bool isPolymorphic, const char* methodName, TYPEID returnType, GenericFunction invoker); void _embind_register_pointer_cast_method( - TYPEID classType, - const char* methodName, + TYPEID pointerType, TYPEID returnType, + TYPEID returnPointeeType, + bool isPolymorphic, + const char* methodName, GenericFunction invoker); void _embind_register_class_field( @@ -269,16 +273,16 @@ namespace emscripten { extern "C" { int __getDynamicPointerType(int p); - int __dynamicPointerCast(int p, int from, int to); + int __dynamicPointerCast(int p, int to); } template - ToType& performCast(FromType& from) { - return *dynamic_cast(&from); + ToType& performRawStaticCast(FromType& from) { + return *static_cast(&from); }; template - std::shared_ptr performPointerCast(std::shared_ptr from) { + std::shared_ptr performSharedStaticCast(std::shared_ptr from) { return std::shared_ptr(from, static_cast(from.get())); }; @@ -598,6 +602,7 @@ namespace emscripten { _embind_register_smart_ptr( TypeID::get(), TypeID::get(), + std::is_polymorphic::value, name, reinterpret_cast(&raw_destructor), reinterpret_cast(&get_pointee)); @@ -611,9 +616,11 @@ namespace emscripten { typedef typename PointerType::element_type PointeeType; _embind_register_pointer_cast_method( TypeID::get(), - methodName, TypeID::get(), - reinterpret_cast(&performPointerCast)); + TypeID::get(), + std::is_polymorphic::value, + methodName, + reinterpret_cast(&performSharedStaticCast)); return *this; } }; @@ -756,9 +763,10 @@ namespace emscripten { _embind_register_cast_method( TypeID::get(), + std::is_polymorphic::value, methodName, TypeID::get(), - reinterpret_cast(&performCast)); + reinterpret_cast(&performRawStaticCast)); return *this; } }; diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index de03052a49434..bc1e09ee45528 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -138,19 +138,19 @@ namespace emscripten { return derivationPath; } - void* EMSCRIPTEN_KEEPALIVE __staticPointerCast(void* p, int dv, int bs) { + void* EMSCRIPTEN_KEEPALIVE __staticPointerCast(void* p, int from, int to) { std::vector> paths; int direction = 1; - const std::type_info* dv1 = (std::type_info*)dv; - const std::type_info* bs1 = (std::type_info*)bs; - const __cxxabiv1::__class_type_info* dv2 = dynamic_cast(dv1); - const __cxxabiv1::__class_type_info* bs2 = dynamic_cast(bs1); + const std::type_info* from1 = (std::type_info*)from; + const std::type_info* to1 = (std::type_info*)to; + const __cxxabiv1::__class_type_info* from2 = dynamic_cast(from1); + const __cxxabiv1::__class_type_info* to2 = dynamic_cast(to1); - if (dv2 && bs2) { - __cxxabiv1::__getDerivationPaths(dv2, bs2, std::vector(), paths); + if (from2 && to2) { + __cxxabiv1::__getDerivationPaths(from2, to2, std::vector(), paths); if (paths.size() == 0) { - __cxxabiv1::__getDerivationPaths(bs2, dv2, std::vector(), paths); + __cxxabiv1::__getDerivationPaths(to2, from2, std::vector(), paths); direction = -1; } } @@ -189,10 +189,14 @@ namespace emscripten { // __dynamicPointerCast performs a C++ dynamic_cast<>() operation, but allowing run-time specification of // the from and to pointer types. - int EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(int p, int from, int to) { + int EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(int p, int to) { // The final parameter is a place-holder for a hint, a feature which is not currently implemented // in the emscripten runtime. The compiler passes a dummy value of -1, and so do we. - return (int)__dynamic_cast((void *)p, (const std::type_info*)from, (const std::type_info *)to, -1); + int ret = (int)__staticPointerCast((void *)p, __getDynamicPointerType(p), to); + if (ret < 0) { + return 0; + } + return ret; } const char* EMSCRIPTEN_KEEPALIVE __typeName(int p) { From fa4795fe6ca52b5c0b217be6108bf3c933dd84d2 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Mon, 24 Dec 2012 08:57:53 -0800 Subject: [PATCH 201/544] Continuing merge of auto downcasting. --- src/embind/embind.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 285e632a0336f..6683f5484dd18 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -174,7 +174,7 @@ function runDestructors(destructors) { function makeInvoker(name, argCount, argTypes, invoker, fn) { return function() { if (arguments.length !== argCount - 1) { - throw new BindingError('function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + argCount - 1); + throw new BindingError('function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + (argCount - 1)); } var destructors = []; var args = new Array(argCount); @@ -369,6 +369,7 @@ function __embind_register_struct_field( }; } +/*global ___dynamicPointerCast: false*/ function __embind_register_smart_ptr( pointerType, pointeeType, @@ -539,6 +540,7 @@ function __embind_register_vector( } // TODO: null pointers are always zero (not a Handle) in Javascript +/*global ___staticPointerCast: false*/ function __embind_register_class( classType, pointerType, @@ -625,11 +627,11 @@ function __embind_register_class( }); /*global ___getDynamicPointerType: false*/ - /*global ___dynamicPointerCast: false*/ var pointerName = name + '*'; registerType(pointerType, pointerName, { name: pointerName, fromWireTypeAutoDowncast: function(ptr) { + var handle; if (isPolymorphic) { var toType = ___getDynamicPointerType(ptr); var toTypeImpl = null; @@ -650,13 +652,13 @@ function __embind_register_class( return new Handle(ptr); } var toTypePointerImpl = requireRegisteredType(toTypeImpl.pointerType); - var handle = toTypePointerImpl.fromWireType(ptr); + handle = toTypePointerImpl.fromWireType(ptr); handle.ptr = ___staticPointerCast(handle.ptr, classType, candidate); // todo: can come back -1 or -2!! Throw appropriate exception return handle; } else { handle = new Handle(ptr); - } + } return handle; }, fromWireType: function(ptr) { @@ -750,7 +752,6 @@ function __embind_register_class_method( }; } -/*global ___staticPointerCast: false*/ function __embind_register_cast_method( classType, isPolymorphic, @@ -778,11 +779,11 @@ function __embind_register_cast_method( var derivation = Module.__getDerivationPath(returnType, runtimeType); // downcast is valid var size = derivation.size(); derivation.delete(); - if (size == 0) { + if (size === 0) { derivation = Module.__getDerivationPath(runtimeType, returnType); // upcast is valid size = derivation.size(); derivation.delete(); - if (size == 0) { + if (size === 0) { // todo: return zero return returnTypeImpl.fromWireType(0); } @@ -826,11 +827,11 @@ function __embind_register_pointer_cast_method( var derivation = Module.__getDerivationPath(returnPointeeType, runtimeType); // downcast is valid var size = derivation.size(); derivation.delete(); - if (size == 0) { + if (size === 0) { derivation = Module.__getDerivationPath(runtimeType, returnPointeeType); // upcast is valid size = derivation.size(); derivation.delete(); - if (size == 0) { + if (size === 0) { return 0; } } From 55c72d46d7c90a0e282b119c17496b2909784144 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Mon, 31 Dec 2012 07:40:08 -0800 Subject: [PATCH 202/544] Refactoring preparatory to code clean-up (no functional changes, all tests pass). --- src/embind/embind.js | 595 +++++++++++++++++++++++-------------------- src/embind/emval.js | 0 2 files changed, 322 insertions(+), 273 deletions(-) mode change 100644 => 100755 src/embind/emval.js diff --git a/src/embind/embind.js b/src/embind/embind.js index 6683f5484dd18..aa4dfdc755d29 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -3,6 +3,10 @@ /*global FUNCTION_TABLE, HEAP32*/ /*global Pointer_stringify, writeStringToMemory*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ +/*global ___getDynamicPointerType: false*/ +/*global ___dynamicPointerCast: false*/ +/*global ___typeName:false*/ +/*global ___staticPointerCast: false*/ function exposePublicSymbol(name, value) { if (Module.hasOwnProperty(name)) { @@ -32,112 +36,133 @@ function _embind_repr(v) { var typeRegistry = {}; -function registerType(type, name, info) { +function registerType(type, name, registeredInstance) { if (!type) { throw new BindingError('type "' + name + '" must have a positive integer typeid pointer'); } if (typeRegistry.hasOwnProperty(type)) { throw new BindingError("Cannot register type '" + name + "' twice"); } - typeRegistry[type] = info; + registeredInstance.type = type; + registeredInstance.name = name; + typeRegistry[type] = registeredInstance; } +function RegisteredVoid() { +} + +RegisteredVoid.prototype.fromWireType = function() { + return undefined; +}; + function __embind_register_void(voidType, name) { name = Pointer_stringify(name); - registerType(voidType, name, { - name: name, - fromWireType: function() { - return undefined; - } - }); + registerType(voidType, name, new RegisteredVoid()); } -function __embind_register_bool(boolType, name, trueValue, falseValue) { - name = Pointer_stringify(name); - registerType(boolType, name, { - name: name, - toWireType: function(destructors, o) { - return o ? trueValue : falseValue; - }, - fromWireType: function(wt) { +function RegisteredBool(trueValue, falseValue) { + this.trueValue = trueValue; + this.falseValue = falseValue; +} + +RegisteredBool.prototype.toWireType = function(destructors, o) { + return o ? this.trueValue : this.falseValue; +}; + +RegisteredBool.prototype.fromWireType = function(wt) { // ambiguous emscripten ABI: sometimes return values are // true or false, and sometimes integers (0 or 1) return !!wt; - }, - }); +}; + +function __embind_register_bool(boolType, name, trueValue, falseValue) { + name = Pointer_stringify(name); + registerType(boolType, name, new RegisteredBool(trueValue, falseValue)); +} + +function RegisteredInteger() { } +RegisteredInteger.prototype.toWireType = function(destructors, value) { + if (typeof value !== "number") { + throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + this.name); + } + return value | 0; +}; + +RegisteredInteger.prototype.fromWireType = function(value) { + return value; +}; + function __embind_register_integer(primitiveType, name) { name = Pointer_stringify(name); - registerType(primitiveType, name, { - name: name, - toWireType: function(destructors, value) { - if (typeof value !== "number") { - throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + name); - } - return value | 0; - }, - fromWireType: function(value) { - return value; - } - }); + registerType(primitiveType, name, new RegisteredInteger()); +} + +function RegisteredFloat() { } +RegisteredFloat.prototype.toWireType = function(destructors, value) { + if (typeof value !== "number") { + throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' +this.name); + } + return value; +}; + +RegisteredFloat.prototype.fromWireType = function(value) { + return value; +}; + function __embind_register_float(primitiveType, name) { name = Pointer_stringify(name); - registerType(primitiveType, name, { - name: name, - toWireType: function(destructors, value) { - if (typeof value !== "number") { - throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + name); - } - return value; - }, - fromWireType: function(value) { - return value; - } - }); + registerType(primitiveType, name, new RegisteredFloat()); } +function RegisteredString(stringType, name) { + +} + +RegisteredString.prototype.toWireType = function(destructors, value) { + var ptr = _malloc(value.length + 1); + writeStringToMemory(value, ptr); + destructors.push(_free); + destructors.push(ptr); + return ptr; +}; + +RegisteredString.prototype.fromWireType = function(value) { + var rv = Pointer_stringify(value); + _free(value); + return rv; +}; + function __embind_register_cstring(stringType, name) { name = Pointer_stringify(name); - registerType(stringType, name, { - name: name, - toWireType: function(destructors, value) { - var ptr = _malloc(value.length + 1); - writeStringToMemory(value, ptr); - destructors.push(_free); - destructors.push(ptr); - return ptr; - }, - fromWireType: function(value) { - var rv = Pointer_stringify(value); - _free(value); - return rv; - } - }); + registerType(stringType, name, new RegisteredString()); } +function RegisteredEmval() { +} + +RegisteredEmval.prototype.toWireType = function(destructors, value) { + return __emval_register(value); +}; + +RegisteredEmval.prototype.fromWireType = function(handle) { + var rv = _emval_handle_array[handle].value; + __emval_decref(handle); + return rv; +}; + function __embind_register_emval(emvalType, name) { name = Pointer_stringify(name); - registerType(emvalType, name, { - name: name, - toWireType: function(destructors, value) { - return __emval_register(value); - }, - fromWireType: function(handle) { - var rv = _emval_handle_array[handle].value; - __emval_decref(handle); - return rv; - } - }); + registerType(emvalType, name, new RegisteredEmval()); } var BindingError = Error; /** @expose */ Module.BindingError = BindingError; -/*global ___typeName:false*/ function typeName(type) { return Pointer_stringify(___typeName(type)); } @@ -183,7 +208,7 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { args[i] = argTypes[i].toWireType(destructors, arguments[i-1]); } var rv = invoker.apply(null, args); - if (argTypes[0].hasOwnProperty('fromWireTypeAutoDowncast')) { + if (argTypes[0].fromWireTypeAutoDowncast) { rv = argTypes[0].fromWireTypeAutoDowncast(rv); } else { rv = argTypes[0].fromWireType(rv); @@ -200,39 +225,41 @@ function __embind_register_function(name, argCount, argTypes, invoker, fn) { exposePublicSymbol(name, makeInvoker(name, argCount, argTypes, invoker, fn)); } +function RegisteredTuple(constructor, destructor) { + this.constructor = constructor; + this.destructor = destructor; + this.elements = []; +} + +RegisteredTuple.prototype.toWireType = function(destructors, o) { + var len = this.elements.length; + if (len !== o.length) { + throw new TypeError("Incorrect number of tuple elements"); + } + var ptr = this.constructor(); + for (var i = 0; i < len; ++i) { + this.elements[i].write(ptr, o[i]); + } + destructors.push(this.destructor); + destructors.push(ptr); + return ptr; +}; + +RegisteredTuple.prototype.fromWireType = function(ptr) { + var len = this.elements.length; + var rv = new Array(len); + for (var i = 0; i < len; ++i) { + rv[i] = this.elements[i].read(ptr); + } + this.destructor(ptr); + return rv; +}; + function __embind_register_tuple(tupleType, name, constructor, destructor) { name = Pointer_stringify(name); constructor = FUNCTION_TABLE[constructor]; destructor = FUNCTION_TABLE[destructor]; - - var elements = []; - - registerType(tupleType, name, { - name: name, - elements: elements, - fromWireType: function(ptr) { - var len = elements.length; - var rv = new Array(len); - for (var i = 0; i < len; ++i) { - rv[i] = elements[i].read(ptr); - } - destructor(ptr); - return rv; - }, - toWireType: function(destructors, o) { - var len = elements.length; - if (len !== o.length) { - throw new TypeError("Incorrect number of tuple elements"); - } - var ptr = constructor(); - for (var i = 0; i < len; ++i) { - elements[i].write(ptr, o[i]); - } - destructors.push(destructor); - destructors.push(ptr); - return ptr; - } - }); + registerType(tupleType, name, new RegisteredTuple(constructor, destructor)); } function copyMemberPointer(memberPointer, memberPointerSize) { @@ -302,6 +329,38 @@ function __embind_register_tuple_element_accessor( }); } +function RegisteredStruct(constructor, destructor) { + this.constructor = constructor; + this.destructor = destructor; + this.fields = {}; +} + +RegisteredStruct.prototype.toWireType = function(destructors, o) { + var fields = this.fields; + for (var fieldName in fields) { + if (!(fieldName in o)) { + throw new TypeError('Missing field'); + } + } + var ptr = this.constructor(); + for (fieldName in fields) { + fields[fieldName].write(ptr, o[fieldName]); + } + destructors.push(this.destructor); + destructors.push(ptr); + return ptr; +}; + +RegisteredStruct.prototype.fromWireType = function(ptr) { + var fields = this.fields; + var rv = {}; + for (var i in fields) { + rv[i] = fields[i].read(ptr); + } + this.destructor(ptr); + return rv; +}; + function __embind_register_struct( structType, name, @@ -312,33 +371,7 @@ function __embind_register_struct( constructor = FUNCTION_TABLE[constructor]; destructor = FUNCTION_TABLE[destructor]; - registerType(structType, name, { - fields: {}, - fromWireType: function(ptr) { - var fields = this.fields; - var rv = {}; - for (var i in fields) { - rv[i] = fields[i].read(ptr); - } - destructor(ptr); - return rv; - }, - toWireType: function(destructors, o) { - var fields = this.fields; - for (var fieldName in fields) { - if (!(fieldName in o)) { - throw new TypeError('Missing field'); - } - } - var ptr = constructor(); - for (var fieldName in fields) { - fields[fieldName].write(ptr, o[fieldName]); - } - destructors.push(destructor); - destructors.push(ptr); - return ptr; - } - }); + registerType(structType, name, new RegisteredStruct(constructor, destructor)); } function __embind_register_struct_field( @@ -369,7 +402,69 @@ function __embind_register_struct_field( }; } -/*global ___dynamicPointerCast: false*/ +function RegisteredSmartPointer(getPointee, Handle, destructor, isPolymorphic, pointeeType) { + this.getPointee = getPointee; + this.Handle = Handle; + this.destructor = destructor; + this.isPolymorphic = isPolymorphic; + this.pointeeType = pointeeType; +} + +RegisteredSmartPointer.prototype.toWireType = function(destructors, o) { + if (null === o) { + return 0; + } else { + return o.smartPointer; + } +}; + +RegisteredSmartPointer.prototype.fromWireType = function(ptr) { + if (!this.getPointee(ptr)) { + this.destructor(ptr); + return null; + } + return new this.Handle(ptr); +}; + +RegisteredSmartPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { + if (!this.getPointee(ptr)) { + this.destructor(ptr); + return null; + } + if (this.isPolymorphic) { + // todo: clean up this code + var pointee = this.getPointee(ptr); + var toType = ___getDynamicPointerType(pointee); + var toTypeImpl = null; + if (toType === null || toType === this.pointeeType) { + return new this.Handle(ptr); + } + // todo: getDerivationPath is expensive -- cache the result + var derivation = Module.__getDerivationPath(toType, this.pointeeType); + var candidate = null; + for (var i = 0; i < derivation.size(); i++) { + candidate = derivation.at(i); + toTypeImpl = typeRegistry[candidate]; + if (toTypeImpl) { + break; + } + } + derivation.delete(); + if (toTypeImpl === null) { + return new this.Handle(ptr); + } + var toTypePointerImpl = requireRegisteredType(toTypeImpl.smartPointerType); + // todo: need to clone the ptr here (really??) + var castPtr = toTypePointerImpl.fromWireType(ptr); + // todo: do we really need ___dynamicPointerCast here? We know what type we're starting with. + castPtr.ptr = ___dynamicPointerCast(pointee, candidate); + // todo: we need to release the pre-cast pointer, don't we? how did this get past the tests? + return castPtr; + } else { + return new this.Handle(ptr); + } +}; + function __embind_register_smart_ptr( pointerType, pointeeType, @@ -421,62 +516,58 @@ function __embind_register_smart_ptr( this.ptr = undefined; }; - registerType(pointerType, name, { - name: name, - Handle: Handle, - fromWireTypeAutoDowncast: function(ptr) { - if (!getPointee(ptr)) { - destructor(ptr); - return null; - } - if (isPolymorphic) { - // todo: clean up this code - var pointee = getPointee(ptr); - var toType = ___getDynamicPointerType(pointee); - var toTypeImpl = null; - if (toType === null || toType === pointeeType) { - return new Handle(ptr); - } - // todo: getDerivationPath is expensive -- cache the result - var derivation = Module.__getDerivationPath(toType, pointeeType); - var candidate = null; - for (var i = 0; i < derivation.size(); i++) { - candidate = derivation.at(i); - toTypeImpl = typeRegistry[candidate]; - if (toTypeImpl) { - break; - } - } - derivation.delete(); - if (toTypeImpl === null) { - return new Handle(ptr); - } - var toTypePointerImpl = requireRegisteredType(toTypeImpl.smartPointerType); - // todo: need to clone the ptr here (really??) - var castPtr = toTypePointerImpl.fromWireType(ptr); - // todo: do we really need ___dynamicPointerCast here? We know what type we're starting with. - castPtr.ptr = ___dynamicPointerCast(pointee, candidate); - // todo: we need to release the pre-cast pointer, don't we? how did this get past the tests? - return castPtr; - } else { - return new Handle(ptr); - } - }, - fromWireType: function(ptr) { - if (!getPointee(ptr)) { - destructor(ptr); - return null; - } - return new Handle(ptr); - }, - toWireType: function(destructors, o) { - if (null === o) { - return 0; - } else { - return o.smartPointer; + registerType(pointerType, name, new RegisteredSmartPointer(getPointee, Handle, destructor, isPolymorphic, pointeeType)); +} + +function RegisteredRawPointer(isPolymorphic, classType, Handle) { + this.isPolymorphic = isPolymorphic; + this.classType = classType; + this.Handle = Handle; +} + +RegisteredRawPointer.prototype.toWireType = function(destructors, o) { + return o.ptr; +}; + +RegisteredRawPointer.prototype.fromWireType = function(ptr) { + return new this.Handle(ptr); +}; + +RegisteredRawPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { + if (this.isPolymorphic) { + var toType = ___getDynamicPointerType(ptr); + var toTypeImpl = null; + if (toType === null || toType === this.pointerType) { + return new this.Handle(ptr); + } + var derivation = Module.__getDerivationPath(toType, this.classType); + var candidate = null; + for (var i = 0; i < derivation.size(); i++) { + candidate = derivation.at(i); + toTypeImpl = typeRegistry[candidate]; + if (toTypeImpl) { + break; } } - }); + derivation.delete(); + if (toTypeImpl === null) { + return new this.Handle(ptr); + } + var toTypePointerImpl = requireRegisteredType(toTypeImpl.type); + var handle = toTypePointerImpl.fromWireType(ptr); + handle.ptr = ___staticPointerCast(handle.ptr, this.classType, candidate); + // todo: can come back -1 or -2!! Throw appropriate exception + return handle; + } else { + handle = new this.Handle(ptr); + } + return handle; +}; + +function RegisteredClassInstance(pointerType, constructor, Handle) { + this.pointerType = pointerType; + this.constructor = constructor; + this.Handle = Handle; } function __embind_register_vector( @@ -539,6 +630,22 @@ function __embind_register_vector( }); } +RegisteredClassInstance.prototype.toWireType = function(destructors, o) { + return o.ptr; +}; + +RegisteredClassInstance.prototype.fromWireType = function(ptr) { + return new this.Handle(ptr); +}; + +function RegisteredRawConstPointer() { +} + +RegisteredRawConstPointer.prototype.toWireType = function(destructors, o) { + return o.ptr; +}; + +>>>>>>> Refactoring preparatory to code clean-up (no functional changes, all tests pass). // TODO: null pointers are always zero (not a Handle) in Javascript /*global ___staticPointerCast: false*/ function __embind_register_class( @@ -612,70 +719,9 @@ function __embind_register_class( constructor.prototype = Handle.prototype; constructor.classType = classType; - - registerType(classType, name, { - name: name, - pointerType: pointerType, - constructor: constructor, - Handle: Handle, - fromWireType: function(ptr) { - return new Handle(ptr); - }, - toWireType: function(destructors, o) { - return o.ptr; - } - }); - - /*global ___getDynamicPointerType: false*/ - var pointerName = name + '*'; - registerType(pointerType, pointerName, { - name: pointerName, - fromWireTypeAutoDowncast: function(ptr) { - var handle; - if (isPolymorphic) { - var toType = ___getDynamicPointerType(ptr); - var toTypeImpl = null; - if (toType === null || toType === pointerType) { - return new Handle(ptr); - } - var derivation = Module.__getDerivationPath(toType, classType); - var candidate = null; - for (var i = 0; i < derivation.size(); i++) { - candidate = derivation.at(i); - toTypeImpl = typeRegistry[candidate]; - if (toTypeImpl) { - break; - } - } - derivation.delete(); - if (toTypeImpl === null) { - return new Handle(ptr); - } - var toTypePointerImpl = requireRegisteredType(toTypeImpl.pointerType); - handle = toTypePointerImpl.fromWireType(ptr); - handle.ptr = ___staticPointerCast(handle.ptr, classType, candidate); - // todo: can come back -1 or -2!! Throw appropriate exception - return handle; - } else { - handle = new Handle(ptr); - } - return handle; - }, - fromWireType: function(ptr) { - return new Handle(ptr); - }, - toWireType: function(destructors, o) { - return o.ptr; - } - }); - - var constPointerName = name + ' const*'; - registerType(constPointerType, constPointerName, { - name: constPointerName, - toWireType: function(destructors, o) { - return o.ptr; - } - }); + registerType(classType, name, new RegisteredClassInstance(pointerType, constructor, Handle)); + registerType(pointerType, name + '*', new RegisteredRawPointer(isPolymorphic, classType, Handle)); + registerType(constPointerType, name + ' const*', new RegisteredRawConstPointer()); exposePublicSymbol(name, constructor); } @@ -742,7 +788,7 @@ function __embind_register_class_method( args[i + 1] = argTypes[i].toWireType(destructors, arguments[i-1]); } var rv = invoker.apply(null, args); - if (argTypes[0].hasOwnProperty('fromWireTypeAutoDowncast')) { + if (argTypes[0].fromWireTypeAutoDowncast) { rv = argTypes[0].fromWireTypeAutoDowncast(rv); } else { rv = argTypes[0].fromWireType(rv); @@ -996,28 +1042,27 @@ function __embind_register_class_field( }); } +function RegisteredEnum() { + this.constructor = function() {}; + this.constructor.values = {}; +} + +RegisteredEnum.prototype.toWireType = function(destructors, c) { + return c.value; +}; + +RegisteredEnum.prototype.fromWireType = function(c) { + return this.constructor.values[c]; +}; + function __embind_register_enum( enumType, name ) { name = Pointer_stringify(name); - - function Enum() { - } - Enum.values = {}; - - registerType(enumType, name, { - name: name, - constructor: Enum, - toWireType: function(destructors, c) { - return c.value; - }, - fromWireType: function(c) { - return Enum.values[c]; - }, - }); - - exposePublicSymbol(name, Enum); + var newEnum = new RegisteredEnum(); + registerType(enumType, name, newEnum); + exposePublicSymbol(name, newEnum.constructor); } function __embind_register_enum_value( @@ -1038,6 +1083,19 @@ function __embind_register_enum_value( Enum[name] = Value; } +function RegisteredInterface(constructor, destructor) { + this.constructor = constructor; + this.destructor = destructor; +} + +RegisteredInterface.prototype.toWireType = function(destructors, o) { + var handle = __emval_register(o); + var ptr = this.constructor(handle); + destructors.push(this.destructor); + destructors.push(ptr); + return ptr; +}; + function __embind_register_interface( interfaceType, name, @@ -1048,15 +1106,6 @@ function __embind_register_interface( constructor = FUNCTION_TABLE[constructor]; destructor = FUNCTION_TABLE[destructor]; - registerType(interfaceType, name, { - name: name, - toWireType: function(destructors, o) { - var handle = __emval_register(o); - var ptr = constructor(handle); - destructors.push(destructor); - destructors.push(ptr); - return ptr; - }, - }); + registerType(interfaceType, name, new RegisteredInterface(constructor, destructor)); } diff --git a/src/embind/emval.js b/src/embind/emval.js old mode 100644 new mode 100755 From d069ed414249db41a4dfa91061e8979d6c9dccca Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Mon, 31 Dec 2012 11:39:59 -0800 Subject: [PATCH 203/544] clear distinction between raw (C++) and cooked (Javascript class instances) types. --- src/embind/embind.js | 289 +++++++++++++++---------------- system/include/emscripten/bind.h | 8 +- 2 files changed, 144 insertions(+), 153 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index aa4dfdc755d29..fb56e7c0ce258 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -36,16 +36,42 @@ function _embind_repr(v) { var typeRegistry = {}; -function registerType(type, name, registeredInstance) { - if (!type) { +function registerType(rawType, name, registeredInstance) { + if (!rawType) { throw new BindingError('type "' + name + '" must have a positive integer typeid pointer'); } - if (typeRegistry.hasOwnProperty(type)) { + if (typeRegistry.hasOwnProperty(rawType)) { throw new BindingError("Cannot register type '" + name + "' twice"); } - registeredInstance.type = type; + registeredInstance.rawType = rawType; registeredInstance.name = name; - typeRegistry[type] = registeredInstance; + typeRegistry[rawType] = registeredInstance; + return registeredInstance; +} + +function requireRegisteredType(rawType, humanName) { + var impl = typeRegistry[rawType]; + if (undefined === impl) { + throw new BindingError(humanName + " has unknown type " + typeName(rawType)); + } + return impl; +} + +function typeName(rawType) { + return Pointer_stringify(___typeName(rawType)); +} + +function requireArgumentTypes(argCount, rawArgTypes, name) { + var argTypes = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + var rawArgType = HEAP32[(rawArgTypes >> 2) + i]; + if (i === 0) { + argTypes[i] = requireRegisteredType(rawArgType, name + " return value"); + } else { + argTypes[i] = requireRegisteredType(rawArgType, name + " parameter " + i); + } + } + return argTypes; } function RegisteredVoid() { @@ -55,9 +81,9 @@ RegisteredVoid.prototype.fromWireType = function() { return undefined; }; -function __embind_register_void(voidType, name) { +function __embind_register_void(rawType, name) { name = Pointer_stringify(name); - registerType(voidType, name, new RegisteredVoid()); + registerType(rawType, name, new RegisteredVoid()); } function RegisteredBool(trueValue, falseValue) { @@ -75,9 +101,9 @@ RegisteredBool.prototype.fromWireType = function(wt) { return !!wt; }; -function __embind_register_bool(boolType, name, trueValue, falseValue) { +function __embind_register_bool(rawType, name, trueValue, falseValue) { name = Pointer_stringify(name); - registerType(boolType, name, new RegisteredBool(trueValue, falseValue)); + registerType(rawType, name, new RegisteredBool(trueValue, falseValue)); } function RegisteredInteger() { @@ -94,9 +120,9 @@ RegisteredInteger.prototype.fromWireType = function(value) { return value; }; -function __embind_register_integer(primitiveType, name) { +function __embind_register_integer(rawType, name) { name = Pointer_stringify(name); - registerType(primitiveType, name, new RegisteredInteger()); + registerType(rawType, name, new RegisteredInteger()); } function RegisteredFloat() { @@ -113,9 +139,9 @@ RegisteredFloat.prototype.fromWireType = function(value) { return value; }; -function __embind_register_float(primitiveType, name) { +function __embind_register_float(rawType, name) { name = Pointer_stringify(name); - registerType(primitiveType, name, new RegisteredFloat()); + registerType(rawType, name, new RegisteredFloat()); } function RegisteredString(stringType, name) { @@ -136,9 +162,9 @@ RegisteredString.prototype.fromWireType = function(value) { return rv; }; -function __embind_register_cstring(stringType, name) { +function __embind_register_cstring(rawType, name) { name = Pointer_stringify(name); - registerType(stringType, name, new RegisteredString()); + registerType(rawType, name, new RegisteredString()); } function RegisteredEmval() { @@ -154,40 +180,15 @@ RegisteredEmval.prototype.fromWireType = function(handle) { return rv; }; -function __embind_register_emval(emvalType, name) { +function __embind_register_emval(rawType, name) { name = Pointer_stringify(name); - registerType(emvalType, name, new RegisteredEmval()); + registerType(rawType, name, new RegisteredEmval()); } var BindingError = Error; /** @expose */ Module.BindingError = BindingError; -function typeName(type) { - return Pointer_stringify(___typeName(type)); -} - -function requireRegisteredType(type, humanName) { - var impl = typeRegistry[type]; - if (undefined === impl) { - throw new BindingError(humanName + " has unknown type " + typeName(type)); - } - return impl; -} - -function requireArgumentTypes(argCount, argTypes, name) { - var argTypeImpls = new Array(argCount); - for (var i = 0; i < argCount; ++i) { - var argType = HEAP32[(argTypes >> 2) + i]; - if (i === 0) { - argTypeImpls[i] = requireRegisteredType(argType, name + " return value"); - } else { - argTypeImpls[i] = requireRegisteredType(argType, name + " parameter " + i); - } - } - return argTypeImpls; -} - function runDestructors(destructors) { while (destructors.length) { var ptr = destructors.pop(); @@ -218,10 +219,10 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { }; } -function __embind_register_function(name, argCount, argTypes, invoker, fn) { +function __embind_register_function(name, argCount, rawArgTypes, invoker, fn) { name = Pointer_stringify(name); invoker = FUNCTION_TABLE[invoker]; - argTypes = requireArgumentTypes(argCount, argTypes, name); + var argTypes = requireArgumentTypes(argCount, rawArgTypes, name); exposePublicSymbol(name, makeInvoker(name, argCount, argTypes, invoker, fn)); } @@ -255,11 +256,11 @@ RegisteredTuple.prototype.fromWireType = function(ptr) { return rv; }; -function __embind_register_tuple(tupleType, name, constructor, destructor) { +function __embind_register_tuple(type, name, constructor, destructor) { name = Pointer_stringify(name); constructor = FUNCTION_TABLE[constructor]; destructor = FUNCTION_TABLE[destructor]; - registerType(tupleType, name, new RegisteredTuple(constructor, destructor)); + registerType(type, name, new RegisteredTuple(constructor, destructor)); } function copyMemberPointer(memberPointer, memberPointerSize) { @@ -362,7 +363,7 @@ RegisteredStruct.prototype.fromWireType = function(ptr) { }; function __embind_register_struct( - structType, + type, name, constructor, destructor @@ -371,7 +372,7 @@ function __embind_register_struct( constructor = FUNCTION_TABLE[constructor]; destructor = FUNCTION_TABLE[destructor]; - registerType(structType, name, new RegisteredStruct(constructor, destructor)); + registerType(type, name, new RegisteredStruct(constructor, destructor)); } function __embind_register_struct_field( @@ -434,48 +435,43 @@ RegisteredSmartPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { if (this.isPolymorphic) { // todo: clean up this code var pointee = this.getPointee(ptr); - var toType = ___getDynamicPointerType(pointee); - var toTypeImpl = null; - if (toType === null || toType === this.pointeeType) { + var toRawType = ___getDynamicPointerType(pointee); + if (toRawType === null || toRawType === this.pointeeType.rawType) { return new this.Handle(ptr); } // todo: getDerivationPath is expensive -- cache the result - var derivation = Module.__getDerivationPath(toType, this.pointeeType); - var candidate = null; + var derivation = Module.__getDerivationPath(toRawType, this.pointeeType.rawType); + var rawCandidateType = null; + var candidateType = null; for (var i = 0; i < derivation.size(); i++) { - candidate = derivation.at(i); - toTypeImpl = typeRegistry[candidate]; - if (toTypeImpl) { + rawCandidateType = derivation.at(i); + candidateType = typeRegistry[rawCandidateType]; + if (candidateType) { break; } } derivation.delete(); - if (toTypeImpl === null) { + if (candidateType === null) { return new this.Handle(ptr); } - var toTypePointerImpl = requireRegisteredType(toTypeImpl.smartPointerType); // todo: need to clone the ptr here (really??) - var castPtr = toTypePointerImpl.fromWireType(ptr); - // todo: do we really need ___dynamicPointerCast here? We know what type we're starting with. - castPtr.ptr = ___dynamicPointerCast(pointee, candidate); // todo: we need to release the pre-cast pointer, don't we? how did this get past the tests? - return castPtr; + return candidateType.smartPointerType.fromWireType(ptr); } else { return new this.Handle(ptr); } }; function __embind_register_smart_ptr( - pointerType, - pointeeType, + rawType, + rawPointeeType, isPolymorphic, name, destructor, getPointee ) { name = Pointer_stringify(name); - var pointeeTypeImpl = requireRegisteredType(pointeeType, 'class'); - pointeeTypeImpl.smartPointerType = pointerType; + var pointeeType = requireRegisteredType(rawPointeeType, 'class'); destructor = FUNCTION_TABLE[destructor]; getPointee = FUNCTION_TABLE[getPointee]; @@ -487,11 +483,11 @@ function __embind_register_smart_ptr( // TODO: test for SmartPtr.prototype.constructor property? // We likely want it distinct from pointeeType.prototype.constructor - Handle.prototype = Object.create(pointeeTypeImpl.Handle.prototype); + Handle.prototype = Object.create(pointeeType.Handle.prototype); Handle.prototype.clone = function() { if (!this.ptr) { - throw new BindingError(pointeeTypeImpl.name + ' instance already deleted'); + throw new BindingError(pointeeType.name + ' instance already deleted'); } var clone = Object.create(Handle.prototype); @@ -505,7 +501,7 @@ function __embind_register_smart_ptr( Handle.prototype['delete'] = function() { if (!this.ptr) { - throw new BindingError(pointeeTypeImpl.name + ' instance already deleted'); + throw new BindingError(pointeeType.name + ' instance already deleted'); } this.count.value -= 1; @@ -515,13 +511,12 @@ function __embind_register_smart_ptr( this.smartPointer = undefined; this.ptr = undefined; }; - - registerType(pointerType, name, new RegisteredSmartPointer(getPointee, Handle, destructor, isPolymorphic, pointeeType)); + pointeeType.smartPointerType = registerType(rawType, name, new RegisteredSmartPointer(getPointee, Handle, destructor, isPolymorphic, pointeeType)); } function RegisteredRawPointer(isPolymorphic, classType, Handle) { this.isPolymorphic = isPolymorphic; - this.classType = classType; + this.pointeeType = classType; this.Handle = Handle; } @@ -535,27 +530,24 @@ RegisteredRawPointer.prototype.fromWireType = function(ptr) { RegisteredRawPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { if (this.isPolymorphic) { - var toType = ___getDynamicPointerType(ptr); - var toTypeImpl = null; - if (toType === null || toType === this.pointerType) { + var toRawType = ___getDynamicPointerType(ptr); + if (toRawType === null || toRawType === this.pointeeType.rawType) { return new this.Handle(ptr); } - var derivation = Module.__getDerivationPath(toType, this.classType); - var candidate = null; + var derivation = Module.__getDerivationPath(toRawType, this.pointeeType.rawType); + var candidateType = null; for (var i = 0; i < derivation.size(); i++) { - candidate = derivation.at(i); - toTypeImpl = typeRegistry[candidate]; - if (toTypeImpl) { + candidateType = typeRegistry[derivation.at(i)]; + if (candidateType) { break; } } derivation.delete(); - if (toTypeImpl === null) { + if (candidateType === null) { return new this.Handle(ptr); } - var toTypePointerImpl = requireRegisteredType(toTypeImpl.type); - var handle = toTypePointerImpl.fromWireType(ptr); - handle.ptr = ___staticPointerCast(handle.ptr, this.classType, candidate); + var handle = candidateType.fromWireType(ptr); + handle.ptr = ___staticPointerCast(handle.ptr, this.pointeeType.rawType, candidateType.rawType); // todo: can come back -1 or -2!! Throw appropriate exception return handle; } else { @@ -564,8 +556,7 @@ RegisteredRawPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { return handle; }; -function RegisteredClassInstance(pointerType, constructor, Handle) { - this.pointerType = pointerType; +function RegisteredClassInstance(constructor, Handle) { this.constructor = constructor; this.Handle = Handle; } @@ -649,9 +640,9 @@ RegisteredRawConstPointer.prototype.toWireType = function(destructors, o) { // TODO: null pointers are always zero (not a Handle) in Javascript /*global ___staticPointerCast: false*/ function __embind_register_class( - classType, - pointerType, - constPointerType, + rawType, + rawPointerType, + rawConstPointerType, isPolymorphic, name, destructor @@ -681,7 +672,7 @@ function __embind_register_class( Handle.prototype.clone = function() { if (!this.ptr) { - throw new BindingError(classType.name + ' instance already deleted'); + throw new BindingError(type.name + ' instance already deleted'); } var clone = Object.create(Handle.prototype); @@ -702,7 +693,7 @@ function __embind_register_class( // todo: then replace this.count.ptr below with this.ptr and make sure it fails Handle.prototype['delete'] = function() { if (!this.ptr) { - throw new BindingError(classType.name + ' instance already deleted'); + throw new BindingError(type.name + ' instance already deleted'); // todo: but 'type' hasn't been resolved!?! } this.count.value -= 1; @@ -717,24 +708,24 @@ function __embind_register_class( return body.apply(this, arguments); }); constructor.prototype = Handle.prototype; - constructor.classType = classType; + constructor.rawType = rawType; - registerType(classType, name, new RegisteredClassInstance(pointerType, constructor, Handle)); - registerType(pointerType, name + '*', new RegisteredRawPointer(isPolymorphic, classType, Handle)); - registerType(constPointerType, name + ' const*', new RegisteredRawConstPointer()); + var classType = registerType(rawType, name, new RegisteredClassInstance(constructor, Handle)); + registerType(rawPointerType, name + '*', new RegisteredRawPointer(isPolymorphic, classType, Handle)); + registerType(rawConstPointerType, name + ' const*', new RegisteredRawConstPointer()); exposePublicSymbol(name, constructor); } function __embind_register_class_constructor( - classType, + rawClassType, argCount, - argTypes, + rawArgTypes, constructor ) { - classType = requireRegisteredType(classType, 'class'); + var classType = requireRegisteredType(rawClassType, 'class'); var humanName = 'constructor ' + classType.name; - argTypes = requireArgumentTypes(argCount, argTypes, humanName); + var argTypes = requireArgumentTypes(argCount, rawArgTypes, humanName); constructor = FUNCTION_TABLE[constructor]; classType.constructor.body = function() { @@ -755,19 +746,19 @@ function __embind_register_class_constructor( } function __embind_register_class_method( - classType, + rawClassType, methodName, argCount, - argTypes, + rawArgTypes, invoker, memberFunctionSize, memberFunction ) { - classType = requireRegisteredType(classType, 'class'); + var classType = requireRegisteredType(rawClassType, 'class'); methodName = Pointer_stringify(methodName); var humanName = classType.name + '.' + methodName; - argTypes = requireArgumentTypes(argCount, argTypes, 'method ' + humanName); + var argTypes = requireArgumentTypes(argCount, rawArgTypes, 'method ' + humanName); invoker = FUNCTION_TABLE[invoker]; memberFunction = copyMemberPointer(memberFunction, memberFunctionSize); @@ -798,21 +789,21 @@ function __embind_register_class_method( }; } -function __embind_register_cast_method( - classType, +function __embind_register_raw_cast_method( + rawClassType, isPolymorphic, methodName, - returnType, + rawReturnType, invoker ) { - var classTypeImpl = requireRegisteredType(classType, 'class'); + var classType = requireRegisteredType(rawClassType, 'class'); methodName = Pointer_stringify(methodName); - var humanName = classTypeImpl.name + '.' + methodName; + var humanName = classType.name + '.' + methodName; - var returnTypeImpl = requireRegisteredType(returnType, 'method ' + humanName + ' return value'); + var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value'); invoker = FUNCTION_TABLE[invoker]; - classTypeImpl.Handle.prototype[methodName] = function() { + classType.Handle.prototype[methodName] = function() { if (!this.ptr) { throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } @@ -822,44 +813,44 @@ function __embind_register_cast_method( if (isPolymorphic) { // todo: this is all only to validate the cast -- cache the result var runtimeType = ___getDynamicPointerType(this.ptr); - var derivation = Module.__getDerivationPath(returnType, runtimeType); // downcast is valid + var derivation = Module.__getDerivationPath(rawReturnType, runtimeType); // downcast is valid var size = derivation.size(); derivation.delete(); if (size === 0) { - derivation = Module.__getDerivationPath(runtimeType, returnType); // upcast is valid + derivation = Module.__getDerivationPath(runtimeType, rawReturnType); // upcast is valid size = derivation.size(); derivation.delete(); if (size === 0) { // todo: return zero - return returnTypeImpl.fromWireType(0); + return returnType.fromWireType(0); } } } var args = new Array(1); args[0] = this.ptr; - var rv = returnTypeImpl.fromWireType(invoker.apply(null, args)); + var rv = returnType.fromWireType(invoker.apply(null, args)); rv.count = this.count; this.count.value ++; return rv; }; } -function __embind_register_pointer_cast_method( - pointerType, - returnType, +function __embind_register_smart_cast_method( + rawPointerType, + rawReturnType, returnPointeeType, isPolymorphic, methodName, invoker ) { - var pointerTypeImpl = requireRegisteredType(pointerType, 'smart pointer class'); + var pointerType = requireRegisteredType(rawPointerType, 'smart pointer class'); methodName = Pointer_stringify(methodName); - var humanName = pointerTypeImpl.name + '.' + methodName; + var humanName = pointerType.name + '.' + methodName; - var returnTypeImpl = requireRegisteredType(returnType, 'method ' + humanName + ' return value'); + var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value'); invoker = FUNCTION_TABLE[invoker]; - pointerTypeImpl.Handle.prototype[methodName] = function() { + pointerType.Handle.prototype[methodName] = function() { if (!this.ptr) { throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } @@ -887,36 +878,36 @@ function __embind_register_pointer_cast_method( args[0] = newPtr; args[1] = this.smartPointer; invoker.apply(null,args); - var rv = returnTypeImpl.fromWireType(newPtr); + var rv = returnType.fromWireType(newPtr); return rv; }; } function __embind_register_class_classmethod( - classType, + rawClassType, methodName, argCount, - argTypes, + rawArgTypes, invoker, fn ) { - classType = requireRegisteredType(classType, 'class'); + var classType = requireRegisteredType(rawClassType, 'class'); methodName = Pointer_stringify(methodName); var humanName = classType.name + '.' + methodName; - argTypes = requireArgumentTypes(argCount, argTypes, 'classmethod ' + humanName); + var argTypes = requireArgumentTypes(argCount, rawArgTypes, 'classmethod ' + humanName); invoker = FUNCTION_TABLE[invoker]; classType.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, invoker, fn); } function __embind_register_class_operator_call( - classType, + rawClassType, argCount, - argTypes, + rawArgTypes, invoker ) { - classType = requireRegisteredType(classType, 'class'); + var classType = requireRegisteredType(rawClassType, 'class'); var humanName = classType.name + '.' + 'operator_call'; - argTypes = requireArgumentTypes(argCount, argTypes, 'method ' + humanName); + var argTypes = requireArgumentTypes(argCount, rawArgTypes, 'method ' + humanName); invoker = FUNCTION_TABLE[invoker]; @@ -942,12 +933,12 @@ function __embind_register_class_operator_call( } function __embind_register_class_operator_array_get( - classType, + rawClassType, elementType, indexType, invoker ) { - classType = requireRegisteredType(classType, 'class'); + var classType = requireRegisteredType(rawClassType, 'class'); indexType = requireRegisteredType(indexType, 'array access index ' + classType.name); elementType = requireRegisteredType(elementType, 'array access element' + classType.name); invoker = FUNCTION_TABLE[invoker]; @@ -974,13 +965,13 @@ function __embind_register_class_operator_array_get( } function __embind_register_class_operator_array_set( - classType, + rawClassType, elementType, - indexType, + rawIndexType, invoker ) { - classType = requireRegisteredType(classType, 'class'); - indexType = requireRegisteredType(indexType, 'array access index ' + classType.name); + var classType = requireRegisteredType(rawClassType, 'class'); + var indexType = requireRegisteredType(rawIndexType, 'array access index ' + classType.name); elementType = requireRegisteredType(elementType, 'array access element ' + classType.name); invoker = FUNCTION_TABLE[invoker]; var humanName = classType.name + '.' + 'operator_array_get'; @@ -1007,18 +998,18 @@ function __embind_register_class_operator_array_set( } function __embind_register_class_field( - classType, + rawClassType, fieldName, - fieldType, + rawFieldType, getter, setter, memberPointerSize, memberPointer ) { - classType = requireRegisteredType(classType, 'class'); + var classType = requireRegisteredType(rawClassType, 'class'); fieldName = Pointer_stringify(fieldName); var humanName = classType.name + '.' + fieldName; - fieldType = requireRegisteredType(fieldType, 'field ' + humanName); + var fieldType = requireRegisteredType(rawFieldType, 'field ' + humanName); getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); @@ -1056,28 +1047,28 @@ RegisteredEnum.prototype.fromWireType = function(c) { }; function __embind_register_enum( - enumType, + rawType, name ) { name = Pointer_stringify(name); var newEnum = new RegisteredEnum(); - registerType(enumType, name, newEnum); + registerType(rawType, name, newEnum); exposePublicSymbol(name, newEnum.constructor); } function __embind_register_enum_value( - enumType, + rawType, name, enumValue ) { - enumType = requireRegisteredType(enumType, 'enum'); + var type = requireRegisteredType(rawType, 'enum'); name = Pointer_stringify(name); - var Enum = enumType.constructor; + var Enum = type.constructor; - var Value = Object.create(enumType.constructor.prototype, { + var Value = Object.create(type.constructor.prototype, { value: {value: enumValue}, - constructor: {value: createNamedFunction(enumType.name + '_' + name, function() {})}, + constructor: {value: createNamedFunction(type.name + '_' + name, function() {})}, }); Enum.values[enumValue] = Value; Enum[name] = Value; @@ -1097,7 +1088,7 @@ RegisteredInterface.prototype.toWireType = function(destructors, o) { }; function __embind_register_interface( - interfaceType, + rawType, name, constructor, destructor @@ -1106,6 +1097,6 @@ function __embind_register_interface( constructor = FUNCTION_TABLE[constructor]; destructor = FUNCTION_TABLE[destructor]; - registerType(interfaceType, name, new RegisteredInterface(constructor, destructor)); + registerType(rawType, name, new RegisteredInterface(constructor, destructor)); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index c37aed24c7686..a5985af50c5da 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -123,14 +123,14 @@ namespace emscripten { size_t memberFunctionSize, void* memberFunction); - void _embind_register_cast_method( + void _embind_register_raw_cast_method( TYPEID classType, bool isPolymorphic, const char* methodName, TYPEID returnType, GenericFunction invoker); - void _embind_register_pointer_cast_method( + void _embind_register_smart_cast_method( TYPEID pointerType, TYPEID returnType, TYPEID returnPointeeType, @@ -614,7 +614,7 @@ namespace emscripten { using namespace internal; typedef typename ReturnType::element_type ReturnPointeeType; typedef typename PointerType::element_type PointeeType; - _embind_register_pointer_cast_method( + _embind_register_smart_cast_method( TypeID::get(), TypeID::get(), TypeID::get(), @@ -761,7 +761,7 @@ namespace emscripten { class_& cast(const char* methodName) { using namespace internal; - _embind_register_cast_method( + _embind_register_raw_cast_method( TypeID::get(), std::is_polymorphic::value, methodName, From eac098fc2418d7c3c543daebdff8fd6c341312ce Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Wed, 2 Jan 2013 12:57:31 -0800 Subject: [PATCH 204/544] Major re-factoring for auto downcasting --- src/embind/embind.js | 323 +++++++++++++++++++++---------------- system/lib/embind/bind.cpp | 4 +- 2 files changed, 184 insertions(+), 143 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index fb56e7c0ce258..c0bceb9b4ba7d 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -219,16 +219,16 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { }; } -function __embind_register_function(name, argCount, rawArgTypes, invoker, fn) { +function __embind_register_function(name, argCount, rawArgTypes, rawInvoker, fn) { name = Pointer_stringify(name); - invoker = FUNCTION_TABLE[invoker]; + rawInvoker = FUNCTION_TABLE[rawInvoker]; var argTypes = requireArgumentTypes(argCount, rawArgTypes, name); - exposePublicSymbol(name, makeInvoker(name, argCount, argTypes, invoker, fn)); + exposePublicSymbol(name, makeInvoker(name, argCount, argTypes, rawInvoker, fn)); } -function RegisteredTuple(constructor, destructor) { - this.constructor = constructor; - this.destructor = destructor; +function RegisteredTuple(rawConstructor, rawDestructor) { + this.rawConstructor = rawConstructor; + this.rawDestructor = rawDestructor; this.elements = []; } @@ -237,11 +237,11 @@ RegisteredTuple.prototype.toWireType = function(destructors, o) { if (len !== o.length) { throw new TypeError("Incorrect number of tuple elements"); } - var ptr = this.constructor(); + var ptr = this.rawConstructor(); for (var i = 0; i < len; ++i) { this.elements[i].write(ptr, o[i]); } - destructors.push(this.destructor); + destructors.push(this.rawDestructor); destructors.push(ptr); return ptr; }; @@ -252,15 +252,15 @@ RegisteredTuple.prototype.fromWireType = function(ptr) { for (var i = 0; i < len; ++i) { rv[i] = this.elements[i].read(ptr); } - this.destructor(ptr); + this.rawDestructor(ptr); return rv; }; -function __embind_register_tuple(type, name, constructor, destructor) { +function __embind_register_tuple(rawType, name, rawConstructor, rawDestructor) { name = Pointer_stringify(name); - constructor = FUNCTION_TABLE[constructor]; - destructor = FUNCTION_TABLE[destructor]; - registerType(type, name, new RegisteredTuple(constructor, destructor)); + rawConstructor = FUNCTION_TABLE[rawConstructor]; + rawDestructor = FUNCTION_TABLE[rawDestructor]; + registerType(rawType, name, new RegisteredTuple(rawConstructor, rawDestructor)); } function copyMemberPointer(memberPointer, memberPointerSize) { @@ -273,55 +273,55 @@ function copyMemberPointer(memberPointer, memberPointerSize) { } function __embind_register_tuple_element( - tupleType, - elementType, + rawTupleType, + rawType, getter, setter, memberPointerSize, memberPointer ) { - tupleType = requireRegisteredType(tupleType, 'tuple'); - elementType = requireRegisteredType(elementType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); + var tupleType = requireRegisteredType(rawTupleType, 'tuple'); + var type = requireRegisteredType(rawType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); tupleType.elements.push({ read: function(ptr) { - return elementType.fromWireType(getter(ptr, memberPointer)); + return type.fromWireType(getter(ptr, memberPointer)); }, write: function(ptr, o) { var destructors = []; - setter(ptr, memberPointer, elementType.toWireType(destructors, o)); + setter(ptr, memberPointer, type.toWireType(destructors, o)); runDestructors(destructors); } }); } function __embind_register_tuple_element_accessor( - tupleType, - elementType, - staticGetter, + rawTupleType, + rawElementType, + rawStaticGetter, getterSize, getter, - staticSetter, + rawStaticSetter, setterSize, setter ) { - tupleType = requireRegisteredType(tupleType, 'tuple'); - elementType = requireRegisteredType(elementType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); - staticGetter = FUNCTION_TABLE[staticGetter]; + var tupleType = requireRegisteredType(rawTupleType, 'tuple'); + var elementType = requireRegisteredType(rawElementType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); + rawStaticGetter = FUNCTION_TABLE[rawStaticGetter]; getter = copyMemberPointer(getter, getterSize); - staticSetter = FUNCTION_TABLE[staticSetter]; + rawStaticSetter = FUNCTION_TABLE[rawStaticSetter]; setter = copyMemberPointer(setter, setterSize); tupleType.elements.push({ read: function(ptr) { - return elementType.fromWireType(staticGetter(ptr, HEAP32[getter >> 2])); + return elementType.fromWireType(rawStaticGetter(ptr, HEAP32[getter >> 2])); }, write: function(ptr, o) { var destructors = []; - staticSetter( + rawStaticSetter( ptr, HEAP32[setter >> 2], elementType.toWireType(destructors, o)); @@ -330,9 +330,9 @@ function __embind_register_tuple_element_accessor( }); } -function RegisteredStruct(constructor, destructor) { - this.constructor = constructor; - this.destructor = destructor; +function RegisteredStruct(rawConstructor, rawDestructor) { + this.rawConstructor = rawConstructor; + this.rawDestructor = rawDestructor; this.fields = {}; } @@ -343,11 +343,11 @@ RegisteredStruct.prototype.toWireType = function(destructors, o) { throw new TypeError('Missing field'); } } - var ptr = this.constructor(); + var ptr = this.rawConstructor(); for (fieldName in fields) { fields[fieldName].write(ptr, o[fieldName]); } - destructors.push(this.destructor); + destructors.push(this.rawDestructor); destructors.push(ptr); return ptr; }; @@ -358,108 +358,142 @@ RegisteredStruct.prototype.fromWireType = function(ptr) { for (var i in fields) { rv[i] = fields[i].read(ptr); } - this.destructor(ptr); + this.rawDestructor(ptr); return rv; }; function __embind_register_struct( - type, + rawType, name, - constructor, - destructor + rawConstructor, + rawDestructor ) { name = Pointer_stringify(name); - constructor = FUNCTION_TABLE[constructor]; - destructor = FUNCTION_TABLE[destructor]; + rawConstructor = FUNCTION_TABLE[rawConstructor]; + rawDestructor = FUNCTION_TABLE[rawDestructor]; - registerType(type, name, new RegisteredStruct(constructor, destructor)); + registerType(rawType, name, new RegisteredStruct(rawConstructor, rawDestructor)); } function __embind_register_struct_field( - structType, + rawStructType, fieldName, - fieldType, - getter, - setter, + rawFieldType, + rawGetter, + rawSetter, memberPointerSize, memberPointer ) { - structType = requireRegisteredType(structType, 'struct'); + var structType = requireRegisteredType(rawStructType, 'struct'); fieldName = Pointer_stringify(fieldName); - fieldType = requireRegisteredType(fieldType, 'field "' + structType.name + '.' + fieldName + '"'); - getter = FUNCTION_TABLE[getter]; - setter = FUNCTION_TABLE[setter]; + var fieldType = requireRegisteredType(rawFieldType, 'field "' + structType.name + '.' + fieldName + '"'); + rawGetter = FUNCTION_TABLE[rawGetter]; + rawSetter = FUNCTION_TABLE[rawSetter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); structType.fields[fieldName] = { read: function(ptr) { - return fieldType.fromWireType(getter(ptr, memberPointer)); + return fieldType.fromWireType(rawGetter(ptr, memberPointer)); }, write: function(ptr, o) { var destructors = []; - setter(ptr, memberPointer, fieldType.toWireType(destructors, o)); + rawSetter(ptr, memberPointer, fieldType.toWireType(destructors, o)); runDestructors(destructors); } }; } -function RegisteredSmartPointer(getPointee, Handle, destructor, isPolymorphic, pointeeType) { - this.getPointee = getPointee; +function RegisteredPointer(Handle, isPolymorphic, isSmartPointer, rawGetPointee, rawDestructor) { this.Handle = Handle; - this.destructor = destructor; this.isPolymorphic = isPolymorphic; - this.pointeeType = pointeeType; + this.isSmartPointer = isSmartPointer; + this.rawGetPointee = rawGetPointee; + this.rawDestructor = rawDestructor; } -RegisteredSmartPointer.prototype.toWireType = function(destructors, o) { +RegisteredPointer.prototype.toWireType = function(destructors, o) { if (null === o) { return 0; } else { - return o.smartPointer; + if (this.isSmartPointer) { + return o.smartPointer; + } else { + return o.ptr; // this allows passing a smart pointer to a raw pointer parameter (but it's not much of a conversion!)s/r + } } }; -RegisteredSmartPointer.prototype.fromWireType = function(ptr) { - if (!this.getPointee(ptr)) { - this.destructor(ptr); - return null; +RegisteredPointer.prototype.getPointee = function(ptr) { + if (this.rawGetPointee) { + ptr = this.rawGetPointee(ptr); + } + return ptr; +}; + +RegisteredPointer.prototype.destructor = function(ptr) { + if (this.rawDestructor) { + this.rawDestructor(ptr); } - return new this.Handle(ptr); }; -RegisteredSmartPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { +RegisteredPointer.prototype.fromWireType = function(ptr) { if (!this.getPointee(ptr)) { this.destructor(ptr); return null; } + return new this.Handle(ptr); +}; + +RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) { + var type = null; if (this.isPolymorphic) { - // todo: clean up this code - var pointee = this.getPointee(ptr); - var toRawType = ___getDynamicPointerType(pointee); - if (toRawType === null || toRawType === this.pointeeType.rawType) { - return new this.Handle(ptr); + if (this.rawGetPointee) { + type = ___getDynamicPointerType(this.rawGetPointee(ptr)); + } else { + type = ___getDynamicPointerType(ptr); } - // todo: getDerivationPath is expensive -- cache the result - var derivation = Module.__getDerivationPath(toRawType, this.pointeeType.rawType); - var rawCandidateType = null; - var candidateType = null; + } + return type; +}; + +RegisteredPointer.prototype.getDynamicDowncastType = function(ptr) { + var downcastType = null; + var type = this.getDynamicRawPointerType(ptr); + if (type && type != this.pointeeType.rawType) { + var derivation = Module.__getDerivationPath(type, this.pointeeType.rawType); for (var i = 0; i < derivation.size(); i++) { - rawCandidateType = derivation.at(i); - candidateType = typeRegistry[rawCandidateType]; - if (candidateType) { + downcastType = typeRegistry[derivation.at(i)]; + if (downcastType) { break; } } derivation.delete(); - if (candidateType === null) { - return new this.Handle(ptr); - } + } + return downcastType; +}; + +RegisteredPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // ptr is a raw pointer (or a raw smartpointer) + var handle; + if (!this.getPointee(ptr)) { + this.destructor(ptr); + return null; + } + var toType = this.getDynamicDowncastType(ptr); + if (toType) { // todo: need to clone the ptr here (really??) // todo: we need to release the pre-cast pointer, don't we? how did this get past the tests? - return candidateType.smartPointerType.fromWireType(ptr); + var fromType = this.pointeeType; + if (this.isSmartPointer) { + handle = toType.smartPointerType.fromWireType(ptr); + } else { + handle = toType.fromWireType(ptr); + } + // todo: staticPointerCast can return -1 or -2!! Throw appropriate exception + handle.ptr = ___staticPointerCast(handle.ptr, fromType.rawType, toType.rawType); } else { - return new this.Handle(ptr); + handle = this.fromWireType(ptr); } + return handle; }; function __embind_register_smart_ptr( @@ -467,18 +501,18 @@ function __embind_register_smart_ptr( rawPointeeType, isPolymorphic, name, - destructor, - getPointee + rawDestructor, + rawGetPointee ) { name = Pointer_stringify(name); var pointeeType = requireRegisteredType(rawPointeeType, 'class'); - destructor = FUNCTION_TABLE[destructor]; - getPointee = FUNCTION_TABLE[getPointee]; + rawDestructor = FUNCTION_TABLE[rawDestructor]; + rawGetPointee = FUNCTION_TABLE[rawGetPointee]; var Handle = createNamedFunction(name, function(ptr) { this.count = {value: 1}; this.smartPointer = ptr; // std::shared_ptr* - this.ptr = getPointee(ptr); // T* + this.ptr = rawGetPointee(ptr); // T* }); // TODO: test for SmartPtr.prototype.constructor property? @@ -506,12 +540,14 @@ function __embind_register_smart_ptr( this.count.value -= 1; if (0 === this.count.value) { - destructor(this.smartPointer); + rawDestructor(this.smartPointer); } this.smartPointer = undefined; this.ptr = undefined; }; - pointeeType.smartPointerType = registerType(rawType, name, new RegisteredSmartPointer(getPointee, Handle, destructor, isPolymorphic, pointeeType)); + var registeredPointer = new RegisteredPointer(Handle, isPolymorphic, true, rawGetPointee, rawDestructor); + registeredPointer.pointeeType = pointeeType; + pointeeType.smartPointerType = registerType(rawType, name, registeredPointer); } function RegisteredRawPointer(isPolymorphic, classType, Handle) { @@ -636,7 +672,6 @@ RegisteredRawConstPointer.prototype.toWireType = function(destructors, o) { return o.ptr; }; ->>>>>>> Refactoring preparatory to code clean-up (no functional changes, all tests pass). // TODO: null pointers are always zero (not a Handle) in Javascript /*global ___staticPointerCast: false*/ function __embind_register_class( @@ -645,10 +680,10 @@ function __embind_register_class( rawConstPointerType, isPolymorphic, name, - destructor + rawDestructor ) { name = Pointer_stringify(name); - destructor = FUNCTION_TABLE[destructor]; + rawDestructor = FUNCTION_TABLE[rawDestructor]; var Handle = createNamedFunction(name, function(ptr) { var h = function() { @@ -698,35 +733,42 @@ function __embind_register_class( this.count.value -= 1; if (0 === this.count.value) { - destructor(this.count.ptr); + rawDestructor(this.count.ptr); } this.ptr = undefined; }; - var constructor = createNamedFunction(name, function() { - var body = constructor.body; + var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); + var type = registerType(rawType, name, registeredClass); + registeredClass.pointeeType = type; + var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); + registerType(rawPointerType, name + '*', registeredClass); + registeredClass.pointeeType = type; + // todo: implement const pointers (no modification Javascript side) + var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); + registerType(rawConstPointerType, name + ' const*', registeredClass); + registeredClass.pointeeType = type; + + type.constructor = createNamedFunction(type.name, function() { + var body = type.constructor.body; return body.apply(this, arguments); }); - constructor.prototype = Handle.prototype; - constructor.rawType = rawType; + type.constructor.prototype = type.Handle.prototype; + type.constructor.type = type; - var classType = registerType(rawType, name, new RegisteredClassInstance(constructor, Handle)); - registerType(rawPointerType, name + '*', new RegisteredRawPointer(isPolymorphic, classType, Handle)); - registerType(rawConstPointerType, name + ' const*', new RegisteredRawConstPointer()); - - exposePublicSymbol(name, constructor); + exposePublicSymbol(name, type.constructor); } function __embind_register_class_constructor( rawClassType, argCount, rawArgTypes, - constructor + rawConstructor ) { var classType = requireRegisteredType(rawClassType, 'class'); var humanName = 'constructor ' + classType.name; var argTypes = requireArgumentTypes(argCount, rawArgTypes, humanName); - constructor = FUNCTION_TABLE[constructor]; + rawConstructor = FUNCTION_TABLE[rawConstructor]; classType.constructor.body = function() { if (arguments.length !== argCount - 1) { @@ -738,7 +780,7 @@ function __embind_register_class_constructor( args[i-1] = argTypes[i].toWireType(destructors, arguments[i-1]); } - var ptr = constructor.apply(null, args); + var ptr = rawConstructor.apply(null, args); runDestructors(destructors); return classType.Handle.call(this, ptr); @@ -750,7 +792,7 @@ function __embind_register_class_method( methodName, argCount, rawArgTypes, - invoker, + rawInvoker, memberFunctionSize, memberFunction ) { @@ -759,7 +801,7 @@ function __embind_register_class_method( var humanName = classType.name + '.' + methodName; var argTypes = requireArgumentTypes(argCount, rawArgTypes, 'method ' + humanName); - invoker = FUNCTION_TABLE[invoker]; + rawInvoker = FUNCTION_TABLE[rawInvoker]; memberFunction = copyMemberPointer(memberFunction, memberFunctionSize); classType.Handle.prototype[methodName] = function() { @@ -778,7 +820,7 @@ function __embind_register_class_method( for (var i = 1; i < argCount; ++i) { args[i + 1] = argTypes[i].toWireType(destructors, arguments[i-1]); } - var rv = invoker.apply(null, args); + var rv = rawInvoker.apply(null, args); if (argTypes[0].fromWireTypeAutoDowncast) { rv = argTypes[0].fromWireTypeAutoDowncast(rv); } else { @@ -794,14 +836,14 @@ function __embind_register_raw_cast_method( isPolymorphic, methodName, rawReturnType, - invoker + rawInvoker ) { var classType = requireRegisteredType(rawClassType, 'class'); methodName = Pointer_stringify(methodName); var humanName = classType.name + '.' + methodName; var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value'); - invoker = FUNCTION_TABLE[invoker]; + rawInvoker = FUNCTION_TABLE[rawInvoker]; classType.Handle.prototype[methodName] = function() { if (!this.ptr) { @@ -828,7 +870,7 @@ function __embind_register_raw_cast_method( } var args = new Array(1); args[0] = this.ptr; - var rv = returnType.fromWireType(invoker.apply(null, args)); + var rv = returnType.fromWireType(rawInvoker.apply(null, args)); rv.count = this.count; this.count.value ++; return rv; @@ -841,14 +883,14 @@ function __embind_register_smart_cast_method( returnPointeeType, isPolymorphic, methodName, - invoker + rawInvoker ) { var pointerType = requireRegisteredType(rawPointerType, 'smart pointer class'); methodName = Pointer_stringify(methodName); var humanName = pointerType.name + '.' + methodName; var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value'); - invoker = FUNCTION_TABLE[invoker]; + rawInvoker = FUNCTION_TABLE[rawInvoker]; pointerType.Handle.prototype[methodName] = function() { if (!this.ptr) { @@ -877,9 +919,8 @@ function __embind_register_smart_cast_method( var newPtr = _malloc(8); args[0] = newPtr; args[1] = this.smartPointer; - invoker.apply(null,args); - var rv = returnType.fromWireType(newPtr); - return rv; + rawInvoker.apply(null,args); + return returnType.fromWireType(newPtr); }; } @@ -888,27 +929,27 @@ function __embind_register_class_classmethod( methodName, argCount, rawArgTypes, - invoker, + rawInvoker, fn ) { var classType = requireRegisteredType(rawClassType, 'class'); methodName = Pointer_stringify(methodName); var humanName = classType.name + '.' + methodName; var argTypes = requireArgumentTypes(argCount, rawArgTypes, 'classmethod ' + humanName); - invoker = FUNCTION_TABLE[invoker]; - classType.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, invoker, fn); + rawInvoker = FUNCTION_TABLE[rawInvoker]; + classType.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn); } function __embind_register_class_operator_call( rawClassType, argCount, rawArgTypes, - invoker + rawInvoker ) { var classType = requireRegisteredType(rawClassType, 'class'); var humanName = classType.name + '.' + 'operator_call'; var argTypes = requireArgumentTypes(argCount, rawArgTypes, 'method ' + humanName); - invoker = FUNCTION_TABLE[invoker]; + rawInvoker = FUNCTION_TABLE[rawInvoker]; classType.Handle.prototype.operator_call = function() { @@ -926,7 +967,7 @@ function __embind_register_class_operator_call( args[i] = argTypes[i].toWireType(destructors, arguments[i-1]); } - var rv = argTypes[0].fromWireType(invoker.apply(null, args)); + var rv = argTypes[0].fromWireType(rawInvoker.apply(null, args)); runDestructors(destructors); return rv; }; @@ -936,12 +977,12 @@ function __embind_register_class_operator_array_get( rawClassType, elementType, indexType, - invoker + rawInvoker ) { var classType = requireRegisteredType(rawClassType, 'class'); indexType = requireRegisteredType(indexType, 'array access index ' + classType.name); elementType = requireRegisteredType(elementType, 'array access element' + classType.name); - invoker = FUNCTION_TABLE[invoker]; + rawInvoker = FUNCTION_TABLE[rawInvoker]; var humanName = classType.name + '.' + 'operator_array_get'; classType.Handle.prototype.array_get = function() { @@ -958,7 +999,7 @@ function __embind_register_class_operator_array_get( args[0] = this.ptr; args[1] = indexType.toWireType(destructors, arguments[0]); - var rv = elementType.fromWireType(invoker.apply(null, args)); + var rv = elementType.fromWireType(rawInvoker.apply(null, args)); runDestructors(destructors); return rv; }; @@ -968,12 +1009,12 @@ function __embind_register_class_operator_array_set( rawClassType, elementType, rawIndexType, - invoker + rawInvoker ) { var classType = requireRegisteredType(rawClassType, 'class'); var indexType = requireRegisteredType(rawIndexType, 'array access index ' + classType.name); elementType = requireRegisteredType(elementType, 'array access element ' + classType.name); - invoker = FUNCTION_TABLE[invoker]; + rawInvoker = FUNCTION_TABLE[rawInvoker]; var humanName = classType.name + '.' + 'operator_array_get'; classType.Handle.prototype.array_set = function() { @@ -991,7 +1032,7 @@ function __embind_register_class_operator_array_set( args[1] = indexType.toWireType(destructors, arguments[0]); args[2] = elementType.toWireType(destructors, arguments[1]); - var rv = elementType.fromWireType(invoker.apply(null, args)); + var rv = elementType.fromWireType(rawInvoker.apply(null, args)); runDestructors(destructors); return rv; }; @@ -1057,32 +1098,32 @@ function __embind_register_enum( } function __embind_register_enum_value( - rawType, + rawEnumType, name, enumValue ) { - var type = requireRegisteredType(rawType, 'enum'); + var enumType = requireRegisteredType(rawEnumType, 'enum'); name = Pointer_stringify(name); - var Enum = type.constructor; + var Enum = enumType.constructor; - var Value = Object.create(type.constructor.prototype, { + var Value = Object.create(enumType.constructor.prototype, { value: {value: enumValue}, - constructor: {value: createNamedFunction(type.name + '_' + name, function() {})}, + constructor: {value: createNamedFunction(enumType.name + '_' + name, function() {})}, }); Enum.values[enumValue] = Value; Enum[name] = Value; } -function RegisteredInterface(constructor, destructor) { - this.constructor = constructor; - this.destructor = destructor; +function RegisteredInterface(rawConstructor, rawDestructor) { + this.rawConstructor = rawConstructor; + this.rawDestructor = rawDestructor; } RegisteredInterface.prototype.toWireType = function(destructors, o) { var handle = __emval_register(o); - var ptr = this.constructor(handle); - destructors.push(this.destructor); + var ptr = this.rawConstructor(handle); + destructors.push(this.rawDestructor); destructors.push(ptr); return ptr; }; @@ -1090,13 +1131,13 @@ RegisteredInterface.prototype.toWireType = function(destructors, o) { function __embind_register_interface( rawType, name, - constructor, - destructor + rawConstructor, + rawDestructor ) { name = Pointer_stringify(name); - constructor = FUNCTION_TABLE[constructor]; - destructor = FUNCTION_TABLE[destructor]; + rawConstructor = FUNCTION_TABLE[rawConstructor]; + rawDestructor = FUNCTION_TABLE[rawDestructor]; - registerType(rawType, name, new RegisteredInterface(constructor, destructor)); + registerType(rawType, name, new RegisteredInterface(rawConstructor, rawDestructor)); } diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index bc1e09ee45528..c69c439923950 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -161,12 +161,12 @@ namespace emscripten { offset = __cxxabiv1::__pathOffset(paths[i]); } else { if (offset != __cxxabiv1::__pathOffset(paths[i])) { - return (void *)-2; // ambiguous cast -- throw instead? + return (void *)-2; } } } if (offset < 0) { - return (void *)-1; // types are not related -- throw instead? + return (void *)-1; } if (p == 0) { return (void *)0; From ff79babe5d207214631fbb8520caf93bcd7dab82 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Wed, 2 Jan 2013 13:12:05 -0800 Subject: [PATCH 205/544] Fixed a lint error --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index c0bceb9b4ba7d..c9a6a4f6e2340 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -459,7 +459,7 @@ RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) { RegisteredPointer.prototype.getDynamicDowncastType = function(ptr) { var downcastType = null; var type = this.getDynamicRawPointerType(ptr); - if (type && type != this.pointeeType.rawType) { + if (type && type !== this.pointeeType.rawType) { var derivation = Module.__getDerivationPath(type, this.pointeeType.rawType); for (var i = 0; i < derivation.size(); i++) { downcastType = typeRegistry[derivation.at(i)]; From 32ccee42ba92e8efc9b467af5e90bf424e0bb016 Mon Sep 17 00:00:00 2001 From: mey Date: Wed, 2 Jan 2013 13:53:03 -0800 Subject: [PATCH 206/544] Adding a register map function, fixing some errors in array access functions and invokers. --- system/include/emscripten/bind.h | 38 +++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index a5985af50c5da..a2c717f196c8f 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -346,27 +347,26 @@ namespace emscripten { } }; - template + template struct ArrayAccessGetInvoker { static typename internal::BindingType::WireType invoke( ClassType* ptr, - size_t index, - typename internal::BindingType + typename internal::BindingType::WireType index ) { return internal::BindingType::toWireType( - (*ptr)[index] + (*ptr)[internal::BindingType::fromWireType(index)] ); } }; - template + template struct ArrayAccessSetInvoker { static void invoke( ClassType* ptr, - size_t index, + typename internal::BindingType::WireType index, typename internal::BindingType::WireType item ) { - (*ptr)[index] = internal::BindingType::fromWireType(item); + (*ptr)[internal::BindingType::fromWireType(index)] = internal::BindingType::fromWireType(item); } }; @@ -742,7 +742,7 @@ namespace emscripten { TypeID::get(), TypeID::get(), TypeID::get(), - reinterpret_cast(&internal::ArrayAccessGetInvoker::invoke)); + reinterpret_cast(&internal::ArrayAccessGetInvoker::invoke)); } template @@ -753,7 +753,7 @@ namespace emscripten { TypeID::get(), TypeID::get(), TypeID::get(), - reinterpret_cast(&internal::ArrayAccessSetInvoker::invoke)); + reinterpret_cast(&internal::ArrayAccessSetInvoker::invoke)); return *this; } @@ -790,8 +790,6 @@ namespace emscripten { class_> register_vector(const char* name) { using namespace std; typedef vector VecType; - typedef typename vector::iterator IterType; - typedef typename vector::const_iterator ConstIterType; void (VecType::*push_back)(const T&) = &VecType::push_back; const T& (VecType::*at)(size_t) const = &VecType::at; @@ -807,6 +805,24 @@ namespace emscripten { return c; } + //////////////////////////////////////////////////////////////////////////////// + // MAPS + //////////////////////////////////////////////////////////////////////////////// + template + class_> register_map(const char* name) { + using namespace std; + typedef map MapType; + + auto c = class_(name) + .method("size", &MapType::size) + .template arrayoperatorget() + .template arrayoperatorset() + ; + + return c; + } + + //////////////////////////////////////////////////////////////////////////////// // ENUMS //////////////////////////////////////////////////////////////////////////////// From 5ea90f9345ebfb271dfd960f77fb0c669d30fca6 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Thu, 3 Jan 2013 08:35:48 -0800 Subject: [PATCH 207/544] Support for automatic upcasting of pointer parameters passed to C++. --- src/embind/embind.js | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index c9a6a4f6e2340..b9a16fbb1103f 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -206,7 +206,11 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { var args = new Array(argCount); args[0] = fn; for (var i = 1; i < argCount; ++i) { - args[i] = argTypes[i].toWireType(destructors, arguments[i-1]); + if (argTypes[i].toWireTypeAutoUpcast) { + args[i] = argTypes[i].toWireTypeAutoUpcast(destructors, arguments[i-1]); + } else { + args[i] = argTypes[i].toWireType(destructors, arguments[i-1]); + } } var rv = invoker.apply(null, args); if (argTypes[0].fromWireTypeAutoDowncast) { @@ -411,6 +415,7 @@ function RegisteredPointer(Handle, isPolymorphic, isSmartPointer, rawGetPointee, this.rawDestructor = rawDestructor; } +// todo: this will go away RegisteredPointer.prototype.toWireType = function(destructors, o) { if (null === o) { return 0; @@ -423,6 +428,21 @@ RegisteredPointer.prototype.toWireType = function(destructors, o) { } }; +// todo: distinguish ptr and rawPtr +RegisteredPointer.prototype.toWireTypeAutoUpcast = function(destructors, o) { + if (this.isSmartPointer) { + return this.toWireType(destructors, o); // for now + } else { + if (o.pointeeType.isPolymorphic) { + var dynamicType = o.pointeeType.getDynamicRawPointerType(o.ptr); + return ___staticPointerCast(o.ptr, dynamicType, this.pointeeType.rawType); + } else { + return ___staticPointerCast(o.ptr, o.pointeeType.rawType, this.pointeeType.rawType); + } + // todo: this cast can fail + } + }; + RegisteredPointer.prototype.getPointee = function(ptr) { if (this.rawGetPointee) { ptr = this.rawGetPointee(ptr); @@ -444,6 +464,7 @@ RegisteredPointer.prototype.fromWireType = function(ptr) { return new this.Handle(ptr); }; +// todo: could this return the actual type if not polymorphic? RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) { var type = null; if (this.isPolymorphic) { @@ -496,6 +517,7 @@ RegisteredPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // ptr is return handle; }; +// todo: don't need isPolymorphic parameter any more function __embind_register_smart_ptr( rawType, rawPointeeType, @@ -513,6 +535,7 @@ function __embind_register_smart_ptr( this.count = {value: 1}; this.smartPointer = ptr; // std::shared_ptr* this.ptr = rawGetPointee(ptr); // T* + this.pointeeType = pointeeType; }); // TODO: test for SmartPtr.prototype.constructor property? @@ -673,7 +696,6 @@ RegisteredRawConstPointer.prototype.toWireType = function(destructors, o) { }; // TODO: null pointers are always zero (not a Handle) in Javascript -/*global ___staticPointerCast: false*/ function __embind_register_class( rawType, rawPointerType, @@ -696,6 +718,7 @@ function __embind_register_class( h.count = {value: 1, ptr: ptr }; h.ptr = ptr; + h.pointeeType = type; // set below for(var prop in Handle.prototype) { var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop); @@ -738,6 +761,7 @@ function __embind_register_class( this.ptr = undefined; }; + // todo: clean this up! var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); var type = registerType(rawType, name, registeredClass); registeredClass.pointeeType = type; From cd3be4e930df1358d9b07746f774a6ad00f3f39c Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Tue, 8 Jan 2013 00:31:46 -0800 Subject: [PATCH 208/544] clean-up old interface binding implementation --- system/include/emscripten/bind.h | 74 ++++++++++---------------------- system/lib/embind/bind.cpp | 4 +- 2 files changed, 26 insertions(+), 52 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index a2c717f196c8f..592928f5e0764 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -902,58 +902,39 @@ namespace emscripten { } //////////////////////////////////////////////////////////////////////////////// - // INTERFACES + // NEW INTERFACE //////////////////////////////////////////////////////////////////////////////// - template - class wrapper : public InterfaceType { + class JSInterface { public: - wrapper() {} // to avoid error "call to implicitly deleted construrtor..." - - wrapper(InterfaceType* interface) { - cloneInterface(interface); + JSInterface(internal::EM_VAL handle) { + initialize(handle); } - // Not necessary in any example so far, but appeases a compiler warning. - virtual ~wrapper() {} - - typedef InterfaceType interface; + JSInterface(JSInterface& obj) { + jsobj = obj.jsobj; + } - template - static std::shared_ptr cloneToSharedPtr(InterfaceType& i) { - ConcreteWrapperType* cw = new ConcreteWrapperType(&i); - InterfaceType* ip = dynamic_cast(cw); - return std::shared_ptr(ip); + template + ReturnType call(const char* name, Args... args) { + assertInitialized(); + return Caller::call(*jsobj, name, args...); } - template - static std::shared_ptr cloneToSharedWrapperPtr(InterfaceType& i) { - return std::make_shared(&i); + static std::shared_ptr cloneToSharedPtr(JSInterface& i) { + return std::make_shared(i); } + private: void initialize(internal::EM_VAL handle) { if (jsobj) { internal::_embind_fatal_error( "Cannot initialize interface wrapper twice", - typeid(InterfaceType).name()); + "JSInterface"); } jsobj = val::take_ownership(handle); } - template - ReturnType call(const char* name, Args... args) { - assertInitialized(); - return Caller::call(*jsobj, name, args...); - } - - protected: - void cloneInterface(InterfaceType* interface) { - // why dynamic_cast causes javascript crash? - wrapper* iw = static_cast*>(interface); - jsobj = iw->jsobj; - } - - private: // this class only exists because you can't partially specialize function templates template struct Caller { @@ -972,8 +953,7 @@ namespace emscripten { void assertInitialized() { if (!jsobj) { internal::_embind_fatal_error( - "Cannot invoke call on uninitialized interface wrapper.", - typeid(InterfaceType).name()); + "Cannot invoke call on uninitialized Javascript interface wrapper.", "JSInterface"); } } @@ -981,25 +961,17 @@ namespace emscripten { }; namespace internal { - template - WrapperType* create_interface_wrapper(EM_VAL e) { - WrapperType* p = new WrapperType; - p->initialize(e); - return p; - } + extern JSInterface* create_js_interface(EM_VAL e); } - template - class interface { + class register_js_interface { public: - typedef typename WrapperType::interface InterfaceType; - - interface(const char* name) { + register_js_interface() { _embind_register_interface( - internal::TypeID::get(), - name, - reinterpret_cast(&internal::create_interface_wrapper), - reinterpret_cast(&internal::raw_destructor)); + internal::TypeID::get(), + "JSInterface", + reinterpret_cast(&internal::create_js_interface), + reinterpret_cast(&internal::raw_destructor)); } }; } diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index c69c439923950..469245058de36 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -220,8 +220,10 @@ namespace emscripten { // developers, but perhaps the double underscore will scare them away from calling it. function("__getDerivationPath", &__getDerivationPath); })); + } - + JSInterface* create_js_interface(EM_VAL e) { + return new JSInterface(e); } } } From cd535236f6bb28f7a3856fff148a49c261563db5 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 8 Jan 2013 07:45:50 -0800 Subject: [PATCH 209/544] Auto upcast of pointer parameters to C++ routines. --- src/embind/embind.js | 39 +++++++++++++++++++++----------- system/include/emscripten/bind.h | 27 ++++++++++++++++++---- system/lib/embind/bind.cpp | 7 ++++-- 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index b9a16fbb1103f..e02b9e014574f 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -407,11 +407,12 @@ function __embind_register_struct_field( }; } -function RegisteredPointer(Handle, isPolymorphic, isSmartPointer, rawGetPointee, rawDestructor) { +function RegisteredPointer(Handle, isPolymorphic, isSmartPointer, rawGetPointee, rawConstructor, rawDestructor) { this.Handle = Handle; this.isPolymorphic = isPolymorphic; this.isSmartPointer = isSmartPointer; this.rawGetPointee = rawGetPointee; + this.rawConstructor = rawConstructor; this.rawDestructor = rawDestructor; } @@ -428,19 +429,29 @@ RegisteredPointer.prototype.toWireType = function(destructors, o) { } }; -// todo: distinguish ptr and rawPtr -RegisteredPointer.prototype.toWireTypeAutoUpcast = function(destructors, o) { - if (this.isSmartPointer) { - return this.toWireType(destructors, o); // for now +RegisteredPointer.prototype.toWireTypeAutoUpcast = function(destructors, handle) { + var fromRawType; + if (!handle) { + return null; + } + if (handle.pointeeType.isPolymorphic) { + fromRawType = handle.pointeeType.getDynamicRawPointerType(handle.ptr); } else { - if (o.pointeeType.isPolymorphic) { - var dynamicType = o.pointeeType.getDynamicRawPointerType(o.ptr); - return ___staticPointerCast(o.ptr, dynamicType, this.pointeeType.rawType); - } else { - return ___staticPointerCast(o.ptr, o.pointeeType.rawType, this.pointeeType.rawType); - } - // todo: this cast can fail + fromRawType = handle.pointeeType.rawType; } + if (fromRawType == this.pointeeType.rawType) { + return this.isSmartPointer ? handle.smartPointer : handle.ptr; + } + var ptr = ___staticPointerCast(handle.ptr, fromRawType, this.pointeeType.rawType); + if (this.isSmartPointer) { + var smartPtr = _malloc(16); + // todo: this does not create a pointer that shares the reference count !?!? + handle.pointeeType.smartPointerType.rawConstructor(smartPtr, ptr); + ptr = smartPtr; + destructors.push(handle.pointeeType.smartPointerType.rawDestructor); + destructors.push(ptr); + } + return ptr; }; RegisteredPointer.prototype.getPointee = function(ptr) { @@ -523,11 +534,13 @@ function __embind_register_smart_ptr( rawPointeeType, isPolymorphic, name, + rawConstructor, rawDestructor, rawGetPointee ) { name = Pointer_stringify(name); var pointeeType = requireRegisteredType(rawPointeeType, 'class'); + rawConstructor = FUNCTION_TABLE[rawConstructor]; rawDestructor = FUNCTION_TABLE[rawDestructor]; rawGetPointee = FUNCTION_TABLE[rawGetPointee]; @@ -568,7 +581,7 @@ function __embind_register_smart_ptr( this.smartPointer = undefined; this.ptr = undefined; }; - var registeredPointer = new RegisteredPointer(Handle, isPolymorphic, true, rawGetPointee, rawDestructor); + var registeredPointer = new RegisteredPointer(Handle, isPolymorphic, true, rawGetPointee, rawConstructor, rawDestructor); registeredPointer.pointeeType = pointeeType; pointeeType.smartPointerType = registerType(rawType, name, registeredPointer); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 592928f5e0764..bbce9a93928bd 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -98,6 +98,7 @@ namespace emscripten { TYPEID pointeeType, bool isPolymorphic, const char* pointerName, + GenericFunction constructor, GenericFunction destructor, GenericFunction getPointee); @@ -282,9 +283,18 @@ namespace emscripten { return *static_cast(&from); }; + template + struct performShared { + static std::shared_ptr cast(std::shared_ptr from) { + return std::dynamic_pointer_cast(from); + }; + }; + template - std::shared_ptr performSharedStaticCast(std::shared_ptr from) { - return std::shared_ptr(from, static_cast(from.get())); + struct performShared { + static std::shared_ptr cast(std::shared_ptr from) { + return std::shared_ptr(from, static_cast(from.get())); + }; }; template @@ -312,6 +322,14 @@ namespace emscripten { ); } + template + void nullDeallocator(PointerType* p) {} + + template + typename std::shared_ptr raw_smart_pointer_constructor(PointerType *ptr, void (PointerType*)) { + return std::shared_ptr(ptr, nullDeallocator); + } + template void raw_destructor(ClassType* ptr) { delete ptr; @@ -604,6 +622,7 @@ namespace emscripten { TypeID::get(), std::is_polymorphic::value, name, + reinterpret_cast(&raw_smart_pointer_constructor), reinterpret_cast(&raw_destructor), reinterpret_cast(&get_pointee)); @@ -620,8 +639,8 @@ namespace emscripten { TypeID::get(), std::is_polymorphic::value, methodName, - reinterpret_cast(&performSharedStaticCast)); - return *this; + reinterpret_cast(&performShared::value>::cast)); + return *this; } }; diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 469245058de36..a4b67fa5ef987 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -190,8 +190,6 @@ namespace emscripten { // __dynamicPointerCast performs a C++ dynamic_cast<>() operation, but allowing run-time specification of // the from and to pointer types. int EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(int p, int to) { - // The final parameter is a place-holder for a hint, a feature which is not currently implemented - // in the emscripten runtime. The compiler passes a dummy value of -1, and so do we. int ret = (int)__staticPointerCast((void *)p, __getDynamicPointerType(p), to); if (ret < 0) { return 0; @@ -214,11 +212,16 @@ namespace emscripten { return name; } + int EMSCRIPTEN_KEEPALIVE __peek32(int p) { + return *(int *)p; + } + EMSCRIPTEN_BINDINGS(([]() { // We bind __getDerivationPath in order to take advantage of the std::vector to Javascript array // conversion for the return value. This has the unfortunate side-effect of exposing it to third party // developers, but perhaps the double underscore will scare them away from calling it. function("__getDerivationPath", &__getDerivationPath); + function("__peek32", &__peek32); })); } From 27100ac1f5bce45edf19c52d17f76a0c319aba9e Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 8 Jan 2013 07:47:45 -0800 Subject: [PATCH 210/544] Fix a lint error. --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index e02b9e014574f..1f8a66547116a 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -439,7 +439,7 @@ RegisteredPointer.prototype.toWireTypeAutoUpcast = function(destructors, handle) } else { fromRawType = handle.pointeeType.rawType; } - if (fromRawType == this.pointeeType.rawType) { + if (fromRawType === this.pointeeType.rawType) { return this.isSmartPointer ? handle.smartPointer : handle.ptr; } var ptr = ___staticPointerCast(handle.ptr, fromRawType, this.pointeeType.rawType); From f4480b5d9b8281911249eca0bff4fa86f249a467 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 8 Jan 2013 09:44:16 -0800 Subject: [PATCH 211/544] Revert "Fix a lint error." This reverts commit f7b63f2ed5f8fea7ed9c8d5b9116bc10bfbab7b7. --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 1f8a66547116a..e02b9e014574f 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -439,7 +439,7 @@ RegisteredPointer.prototype.toWireTypeAutoUpcast = function(destructors, handle) } else { fromRawType = handle.pointeeType.rawType; } - if (fromRawType === this.pointeeType.rawType) { + if (fromRawType == this.pointeeType.rawType) { return this.isSmartPointer ? handle.smartPointer : handle.ptr; } var ptr = ___staticPointerCast(handle.ptr, fromRawType, this.pointeeType.rawType); From 84b49c917c177e9fa49798b45a543f3ce68bf30b Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 8 Jan 2013 09:44:28 -0800 Subject: [PATCH 212/544] Revert "Auto upcast of pointer parameters to C++ routines." This reverts commit 64cc5c47bed294d5efa2433655552530c0242503. --- src/embind/embind.js | 39 +++++++++++--------------------- system/include/emscripten/bind.h | 27 ++++------------------ system/lib/embind/bind.cpp | 7 ++---- 3 files changed, 19 insertions(+), 54 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index e02b9e014574f..b9a16fbb1103f 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -407,12 +407,11 @@ function __embind_register_struct_field( }; } -function RegisteredPointer(Handle, isPolymorphic, isSmartPointer, rawGetPointee, rawConstructor, rawDestructor) { +function RegisteredPointer(Handle, isPolymorphic, isSmartPointer, rawGetPointee, rawDestructor) { this.Handle = Handle; this.isPolymorphic = isPolymorphic; this.isSmartPointer = isSmartPointer; this.rawGetPointee = rawGetPointee; - this.rawConstructor = rawConstructor; this.rawDestructor = rawDestructor; } @@ -429,29 +428,19 @@ RegisteredPointer.prototype.toWireType = function(destructors, o) { } }; -RegisteredPointer.prototype.toWireTypeAutoUpcast = function(destructors, handle) { - var fromRawType; - if (!handle) { - return null; - } - if (handle.pointeeType.isPolymorphic) { - fromRawType = handle.pointeeType.getDynamicRawPointerType(handle.ptr); - } else { - fromRawType = handle.pointeeType.rawType; - } - if (fromRawType == this.pointeeType.rawType) { - return this.isSmartPointer ? handle.smartPointer : handle.ptr; - } - var ptr = ___staticPointerCast(handle.ptr, fromRawType, this.pointeeType.rawType); +// todo: distinguish ptr and rawPtr +RegisteredPointer.prototype.toWireTypeAutoUpcast = function(destructors, o) { if (this.isSmartPointer) { - var smartPtr = _malloc(16); - // todo: this does not create a pointer that shares the reference count !?!? - handle.pointeeType.smartPointerType.rawConstructor(smartPtr, ptr); - ptr = smartPtr; - destructors.push(handle.pointeeType.smartPointerType.rawDestructor); - destructors.push(ptr); + return this.toWireType(destructors, o); // for now + } else { + if (o.pointeeType.isPolymorphic) { + var dynamicType = o.pointeeType.getDynamicRawPointerType(o.ptr); + return ___staticPointerCast(o.ptr, dynamicType, this.pointeeType.rawType); + } else { + return ___staticPointerCast(o.ptr, o.pointeeType.rawType, this.pointeeType.rawType); + } + // todo: this cast can fail } - return ptr; }; RegisteredPointer.prototype.getPointee = function(ptr) { @@ -534,13 +523,11 @@ function __embind_register_smart_ptr( rawPointeeType, isPolymorphic, name, - rawConstructor, rawDestructor, rawGetPointee ) { name = Pointer_stringify(name); var pointeeType = requireRegisteredType(rawPointeeType, 'class'); - rawConstructor = FUNCTION_TABLE[rawConstructor]; rawDestructor = FUNCTION_TABLE[rawDestructor]; rawGetPointee = FUNCTION_TABLE[rawGetPointee]; @@ -581,7 +568,7 @@ function __embind_register_smart_ptr( this.smartPointer = undefined; this.ptr = undefined; }; - var registeredPointer = new RegisteredPointer(Handle, isPolymorphic, true, rawGetPointee, rawConstructor, rawDestructor); + var registeredPointer = new RegisteredPointer(Handle, isPolymorphic, true, rawGetPointee, rawDestructor); registeredPointer.pointeeType = pointeeType; pointeeType.smartPointerType = registerType(rawType, name, registeredPointer); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index bbce9a93928bd..592928f5e0764 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -98,7 +98,6 @@ namespace emscripten { TYPEID pointeeType, bool isPolymorphic, const char* pointerName, - GenericFunction constructor, GenericFunction destructor, GenericFunction getPointee); @@ -283,18 +282,9 @@ namespace emscripten { return *static_cast(&from); }; - template - struct performShared { - static std::shared_ptr cast(std::shared_ptr from) { - return std::dynamic_pointer_cast(from); - }; - }; - template - struct performShared { - static std::shared_ptr cast(std::shared_ptr from) { - return std::shared_ptr(from, static_cast(from.get())); - }; + std::shared_ptr performSharedStaticCast(std::shared_ptr from) { + return std::shared_ptr(from, static_cast(from.get())); }; template @@ -322,14 +312,6 @@ namespace emscripten { ); } - template - void nullDeallocator(PointerType* p) {} - - template - typename std::shared_ptr raw_smart_pointer_constructor(PointerType *ptr, void (PointerType*)) { - return std::shared_ptr(ptr, nullDeallocator); - } - template void raw_destructor(ClassType* ptr) { delete ptr; @@ -622,7 +604,6 @@ namespace emscripten { TypeID::get(), std::is_polymorphic::value, name, - reinterpret_cast(&raw_smart_pointer_constructor), reinterpret_cast(&raw_destructor), reinterpret_cast(&get_pointee)); @@ -639,8 +620,8 @@ namespace emscripten { TypeID::get(), std::is_polymorphic::value, methodName, - reinterpret_cast(&performShared::value>::cast)); - return *this; + reinterpret_cast(&performSharedStaticCast)); + return *this; } }; diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index a4b67fa5ef987..469245058de36 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -190,6 +190,8 @@ namespace emscripten { // __dynamicPointerCast performs a C++ dynamic_cast<>() operation, but allowing run-time specification of // the from and to pointer types. int EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(int p, int to) { + // The final parameter is a place-holder for a hint, a feature which is not currently implemented + // in the emscripten runtime. The compiler passes a dummy value of -1, and so do we. int ret = (int)__staticPointerCast((void *)p, __getDynamicPointerType(p), to); if (ret < 0) { return 0; @@ -212,16 +214,11 @@ namespace emscripten { return name; } - int EMSCRIPTEN_KEEPALIVE __peek32(int p) { - return *(int *)p; - } - EMSCRIPTEN_BINDINGS(([]() { // We bind __getDerivationPath in order to take advantage of the std::vector to Javascript array // conversion for the return value. This has the unfortunate side-effect of exposing it to third party // developers, but perhaps the double underscore will scare them away from calling it. function("__getDerivationPath", &__getDerivationPath); - function("__peek32", &__peek32); })); } From cfb3df1b48f9e1b9c59fd27e0d2608c7fe29a78e Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 8 Jan 2013 10:33:53 -0800 Subject: [PATCH 213/544] Revert "Revert "Auto upcast of pointer parameters to C++ routines."" This reverts commit 07e0daa5aab716b38acf9041a8baec3816976579. --- src/embind/embind.js | 39 +++++++++++++++++++++----------- system/include/emscripten/bind.h | 27 ++++++++++++++++++---- system/lib/embind/bind.cpp | 7 ++++-- 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index b9a16fbb1103f..e02b9e014574f 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -407,11 +407,12 @@ function __embind_register_struct_field( }; } -function RegisteredPointer(Handle, isPolymorphic, isSmartPointer, rawGetPointee, rawDestructor) { +function RegisteredPointer(Handle, isPolymorphic, isSmartPointer, rawGetPointee, rawConstructor, rawDestructor) { this.Handle = Handle; this.isPolymorphic = isPolymorphic; this.isSmartPointer = isSmartPointer; this.rawGetPointee = rawGetPointee; + this.rawConstructor = rawConstructor; this.rawDestructor = rawDestructor; } @@ -428,19 +429,29 @@ RegisteredPointer.prototype.toWireType = function(destructors, o) { } }; -// todo: distinguish ptr and rawPtr -RegisteredPointer.prototype.toWireTypeAutoUpcast = function(destructors, o) { - if (this.isSmartPointer) { - return this.toWireType(destructors, o); // for now +RegisteredPointer.prototype.toWireTypeAutoUpcast = function(destructors, handle) { + var fromRawType; + if (!handle) { + return null; + } + if (handle.pointeeType.isPolymorphic) { + fromRawType = handle.pointeeType.getDynamicRawPointerType(handle.ptr); } else { - if (o.pointeeType.isPolymorphic) { - var dynamicType = o.pointeeType.getDynamicRawPointerType(o.ptr); - return ___staticPointerCast(o.ptr, dynamicType, this.pointeeType.rawType); - } else { - return ___staticPointerCast(o.ptr, o.pointeeType.rawType, this.pointeeType.rawType); - } - // todo: this cast can fail + fromRawType = handle.pointeeType.rawType; } + if (fromRawType == this.pointeeType.rawType) { + return this.isSmartPointer ? handle.smartPointer : handle.ptr; + } + var ptr = ___staticPointerCast(handle.ptr, fromRawType, this.pointeeType.rawType); + if (this.isSmartPointer) { + var smartPtr = _malloc(16); + // todo: this does not create a pointer that shares the reference count !?!? + handle.pointeeType.smartPointerType.rawConstructor(smartPtr, ptr); + ptr = smartPtr; + destructors.push(handle.pointeeType.smartPointerType.rawDestructor); + destructors.push(ptr); + } + return ptr; }; RegisteredPointer.prototype.getPointee = function(ptr) { @@ -523,11 +534,13 @@ function __embind_register_smart_ptr( rawPointeeType, isPolymorphic, name, + rawConstructor, rawDestructor, rawGetPointee ) { name = Pointer_stringify(name); var pointeeType = requireRegisteredType(rawPointeeType, 'class'); + rawConstructor = FUNCTION_TABLE[rawConstructor]; rawDestructor = FUNCTION_TABLE[rawDestructor]; rawGetPointee = FUNCTION_TABLE[rawGetPointee]; @@ -568,7 +581,7 @@ function __embind_register_smart_ptr( this.smartPointer = undefined; this.ptr = undefined; }; - var registeredPointer = new RegisteredPointer(Handle, isPolymorphic, true, rawGetPointee, rawDestructor); + var registeredPointer = new RegisteredPointer(Handle, isPolymorphic, true, rawGetPointee, rawConstructor, rawDestructor); registeredPointer.pointeeType = pointeeType; pointeeType.smartPointerType = registerType(rawType, name, registeredPointer); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 592928f5e0764..bbce9a93928bd 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -98,6 +98,7 @@ namespace emscripten { TYPEID pointeeType, bool isPolymorphic, const char* pointerName, + GenericFunction constructor, GenericFunction destructor, GenericFunction getPointee); @@ -282,9 +283,18 @@ namespace emscripten { return *static_cast(&from); }; + template + struct performShared { + static std::shared_ptr cast(std::shared_ptr from) { + return std::dynamic_pointer_cast(from); + }; + }; + template - std::shared_ptr performSharedStaticCast(std::shared_ptr from) { - return std::shared_ptr(from, static_cast(from.get())); + struct performShared { + static std::shared_ptr cast(std::shared_ptr from) { + return std::shared_ptr(from, static_cast(from.get())); + }; }; template @@ -312,6 +322,14 @@ namespace emscripten { ); } + template + void nullDeallocator(PointerType* p) {} + + template + typename std::shared_ptr raw_smart_pointer_constructor(PointerType *ptr, void (PointerType*)) { + return std::shared_ptr(ptr, nullDeallocator); + } + template void raw_destructor(ClassType* ptr) { delete ptr; @@ -604,6 +622,7 @@ namespace emscripten { TypeID::get(), std::is_polymorphic::value, name, + reinterpret_cast(&raw_smart_pointer_constructor), reinterpret_cast(&raw_destructor), reinterpret_cast(&get_pointee)); @@ -620,8 +639,8 @@ namespace emscripten { TypeID::get(), std::is_polymorphic::value, methodName, - reinterpret_cast(&performSharedStaticCast)); - return *this; + reinterpret_cast(&performShared::value>::cast)); + return *this; } }; diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 469245058de36..a4b67fa5ef987 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -190,8 +190,6 @@ namespace emscripten { // __dynamicPointerCast performs a C++ dynamic_cast<>() operation, but allowing run-time specification of // the from and to pointer types. int EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(int p, int to) { - // The final parameter is a place-holder for a hint, a feature which is not currently implemented - // in the emscripten runtime. The compiler passes a dummy value of -1, and so do we. int ret = (int)__staticPointerCast((void *)p, __getDynamicPointerType(p), to); if (ret < 0) { return 0; @@ -214,11 +212,16 @@ namespace emscripten { return name; } + int EMSCRIPTEN_KEEPALIVE __peek32(int p) { + return *(int *)p; + } + EMSCRIPTEN_BINDINGS(([]() { // We bind __getDerivationPath in order to take advantage of the std::vector to Javascript array // conversion for the return value. This has the unfortunate side-effect of exposing it to third party // developers, but perhaps the double underscore will scare them away from calling it. function("__getDerivationPath", &__getDerivationPath); + function("__peek32", &__peek32); })); } From 2665a390d2ec975c9a516fc98761b96c07c38085 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 8 Jan 2013 10:34:03 -0800 Subject: [PATCH 214/544] Revert "Revert "Fix a lint error."" This reverts commit 6bcd2b18c56448502c69bbfc960a3044c8955fd8. --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index e02b9e014574f..1f8a66547116a 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -439,7 +439,7 @@ RegisteredPointer.prototype.toWireTypeAutoUpcast = function(destructors, handle) } else { fromRawType = handle.pointeeType.rawType; } - if (fromRawType == this.pointeeType.rawType) { + if (fromRawType === this.pointeeType.rawType) { return this.isSmartPointer ? handle.smartPointer : handle.ptr; } var ptr = ___staticPointerCast(handle.ptr, fromRawType, this.pointeeType.rawType); From 34d32868ad6f6efdf466f90370a38dc26eb01159 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 8 Jan 2013 15:05:35 -0800 Subject: [PATCH 215/544] New CastError exception when explicit or implicit cast cannot be completed. --- src/embind/embind.js | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 1f8a66547116a..c755e22b99e17 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -74,6 +74,17 @@ function requireArgumentTypes(argCount, rawArgTypes, name) { return argTypes; } +function staticPointerCast(from, fromType, toType) { + if (!from) { + return from; + } + var to = ___staticPointerCast(from, fromType, toType); + if (to <= 0) { + throw new CastError("Pointer conversion is not available"); + } + return to; +} + function RegisteredVoid() { } @@ -186,8 +197,10 @@ function __embind_register_emval(rawType, name) { } var BindingError = Error; +var CastError = Error; /** @expose */ Module.BindingError = BindingError; +Module.CastError = CastError; function runDestructors(destructors) { while (destructors.length) { @@ -442,10 +455,10 @@ RegisteredPointer.prototype.toWireTypeAutoUpcast = function(destructors, handle) if (fromRawType === this.pointeeType.rawType) { return this.isSmartPointer ? handle.smartPointer : handle.ptr; } - var ptr = ___staticPointerCast(handle.ptr, fromRawType, this.pointeeType.rawType); + var ptr = staticPointerCast(handle.ptr, fromRawType, this.pointeeType.rawType); if (this.isSmartPointer) { var smartPtr = _malloc(16); - // todo: this does not create a pointer that shares the reference count !?!? + // todo: this does not create a pointer that shares the reference count ! handle.pointeeType.smartPointerType.rawConstructor(smartPtr, ptr); ptr = smartPtr; destructors.push(handle.pointeeType.smartPointerType.rawDestructor); @@ -520,8 +533,7 @@ RegisteredPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // ptr is } else { handle = toType.fromWireType(ptr); } - // todo: staticPointerCast can return -1 or -2!! Throw appropriate exception - handle.ptr = ___staticPointerCast(handle.ptr, fromType.rawType, toType.rawType); + handle.ptr = staticPointerCast(handle.ptr, fromType.rawType, toType.rawType); } else { handle = this.fromWireType(ptr); } @@ -900,14 +912,14 @@ function __embind_register_raw_cast_method( size = derivation.size(); derivation.delete(); if (size === 0) { - // todo: return zero - return returnType.fromWireType(0); + throw new CastError("Pointer conversion is not available"); } } } var args = new Array(1); args[0] = this.ptr; - var rv = returnType.fromWireType(rawInvoker.apply(null, args)); + var ptr = rawInvoker.apply(null, args); + var rv = returnType.fromWireType(ptr); rv.count = this.count; this.count.value ++; return rv; @@ -938,7 +950,6 @@ function __embind_register_smart_cast_method( } if (isPolymorphic) { // todo: just validating the cast -- cache the result - // todo: throw exception instead of returning zero var runtimeType = ___getDynamicPointerType(this.ptr); var derivation = Module.__getDerivationPath(returnPointeeType, runtimeType); // downcast is valid var size = derivation.size(); @@ -948,16 +959,16 @@ function __embind_register_smart_cast_method( size = derivation.size(); derivation.delete(); if (size === 0) { - return 0; + throw new CastError("Pointer conversion is not available"); } } } var args = new Array(2); - var newPtr = _malloc(8); - args[0] = newPtr; + var ptr = _malloc(8); + args[0] = ptr; args[1] = this.smartPointer; rawInvoker.apply(null,args); - return returnType.fromWireType(newPtr); + return returnType.fromWireType(ptr); }; } From c59bb0d3975d7e15faaab87f785ae66bf6730f35 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Thu, 10 Jan 2013 09:57:32 -0800 Subject: [PATCH 216/544] Minor clean-up of auto upcasting. --- src/embind/embind.js | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index c755e22b99e17..c37ef55bf8f67 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -211,6 +211,9 @@ function runDestructors(destructors) { } function makeInvoker(name, argCount, argTypes, invoker, fn) { + if (!FUNCTION_TABLE[fn]) { + throw new BindingError('function '+name+' is not defined'); + } return function() { if (arguments.length !== argCount - 1) { throw new BindingError('function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + (argCount - 1)); @@ -219,11 +222,7 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { var args = new Array(argCount); args[0] = fn; for (var i = 1; i < argCount; ++i) { - if (argTypes[i].toWireTypeAutoUpcast) { - args[i] = argTypes[i].toWireTypeAutoUpcast(destructors, arguments[i-1]); - } else { - args[i] = argTypes[i].toWireType(destructors, arguments[i-1]); - } + args[i] = argTypes[i].toWireType(destructors, arguments[i-1]); } var rv = invoker.apply(null, args); if (argTypes[0].fromWireTypeAutoDowncast) { @@ -429,20 +428,7 @@ function RegisteredPointer(Handle, isPolymorphic, isSmartPointer, rawGetPointee, this.rawDestructor = rawDestructor; } -// todo: this will go away -RegisteredPointer.prototype.toWireType = function(destructors, o) { - if (null === o) { - return 0; - } else { - if (this.isSmartPointer) { - return o.smartPointer; - } else { - return o.ptr; // this allows passing a smart pointer to a raw pointer parameter (but it's not much of a conversion!)s/r - } - } -}; - -RegisteredPointer.prototype.toWireTypeAutoUpcast = function(destructors, handle) { +RegisteredPointer.prototype.toWireType = function(destructors, handle) { var fromRawType; if (!handle) { return null; From d0969fc651367d801d28146ef6f4dbe1d26f2aa2 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Fri, 11 Jan 2013 14:28:56 -0800 Subject: [PATCH 217/544] o Temporary shared pointers created to hold upcast argument values now share ownership with the original pointer. o New test cases for edge cases. o Other minor clean-up. --- src/embind/embind.js | 10 +++------- system/include/emscripten/bind.h | 10 ++++------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index c37ef55bf8f67..39e120e012422 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -443,9 +443,9 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { } var ptr = staticPointerCast(handle.ptr, fromRawType, this.pointeeType.rawType); if (this.isSmartPointer) { + // todo: if ptr == handle.ptr, there's no need to allocate a new smartPtr! var smartPtr = _malloc(16); - // todo: this does not create a pointer that shares the reference count ! - handle.pointeeType.smartPointerType.rawConstructor(smartPtr, ptr); + handle.pointeeType.smartPointerType.rawConstructor(smartPtr, ptr, handle.smartPointer); ptr = smartPtr; destructors.push(handle.pointeeType.smartPointerType.rawDestructor); destructors.push(ptr); @@ -511,8 +511,6 @@ RegisteredPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // ptr is } var toType = this.getDynamicDowncastType(ptr); if (toType) { - // todo: need to clone the ptr here (really??) - // todo: we need to release the pre-cast pointer, don't we? how did this get past the tests? var fromType = this.pointeeType; if (this.isSmartPointer) { handle = toType.smartPointerType.fromWireType(ptr); @@ -526,11 +524,9 @@ RegisteredPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // ptr is return handle; }; -// todo: don't need isPolymorphic parameter any more function __embind_register_smart_ptr( rawType, rawPointeeType, - isPolymorphic, name, rawConstructor, rawDestructor, @@ -579,7 +575,7 @@ function __embind_register_smart_ptr( this.smartPointer = undefined; this.ptr = undefined; }; - var registeredPointer = new RegisteredPointer(Handle, isPolymorphic, true, rawGetPointee, rawConstructor, rawDestructor); + var registeredPointer = new RegisteredPointer(Handle, pointeeType.isPolymorphic, true, rawGetPointee, rawConstructor, rawDestructor); registeredPointer.pointeeType = pointeeType; pointeeType.smartPointerType = registerType(rawType, name, registeredPointer); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index bbce9a93928bd..652fb1b46ab6a 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -96,7 +96,6 @@ namespace emscripten { void _embind_register_smart_ptr( TYPEID pointerType, TYPEID pointeeType, - bool isPolymorphic, const char* pointerName, GenericFunction constructor, GenericFunction destructor, @@ -322,12 +321,12 @@ namespace emscripten { ); } - template - void nullDeallocator(PointerType* p) {} +// template +// void nullDeallocator(PointerType* p) {} template - typename std::shared_ptr raw_smart_pointer_constructor(PointerType *ptr, void (PointerType*)) { - return std::shared_ptr(ptr, nullDeallocator); + typename std::shared_ptr raw_smart_pointer_constructor(PointerType *ptr, std::shared_ptr basePtr, void (PointerType*)) { + return std::shared_ptr(basePtr, ptr); } template @@ -620,7 +619,6 @@ namespace emscripten { _embind_register_smart_ptr( TypeID::get(), TypeID::get(), - std::is_polymorphic::value, name, reinterpret_cast(&raw_smart_pointer_constructor), reinterpret_cast(&raw_destructor), From c5b8e64a0becd50f51ae50b1f4480f3274f680f6 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 15 Jan 2013 17:59:07 -0800 Subject: [PATCH 218/544] bring emscripten::val closer to the set of primitive operations provided by JS on values --- src/embind/emval.js | 12 ++++++------ system/include/emscripten/val.h | 32 +++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index 49424631fff7a..3df5a540676cc 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -41,6 +41,10 @@ function __emval_decref(handle) { } } +function __emval_new_array() { + return __emval_register([]); +} + function __emval_new_object() { return __emval_register({}); } @@ -49,12 +53,8 @@ function __emval_new_null() { return __emval_register(null); } -function __emval_new_long(value) { - return __emval_register(value); -} - -function __emval_new_cstring(str) { - return __emval_register(Pointer_stringify(str)); +function __emval_new_cstring(v) { + return __emval_register(Pointer_stringify(v)); } function __emval_has_property(handle, k) { diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 8f7df8827c763..65f5226634d6c 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -11,10 +11,13 @@ namespace emscripten { void _emval_incref(EM_VAL value); void _emval_decref(EM_VAL value); + + EM_VAL _emval_new_array(); EM_VAL _emval_new_object(); EM_VAL _emval_new_null(); - EM_VAL _emval_new_long(long value); - EM_VAL _emval_new_cstring(const char* str); + EM_VAL _emval_new_cstring(const char*); + void _emval_take_value(TYPEID type/*, ...*/); + bool _emval_has_property(EM_VAL object, const char* key); EM_VAL _emval_get_property(EM_VAL object, const char* key); EM_VAL _emval_get_property_by_long(EM_VAL object, long key); @@ -45,28 +48,35 @@ namespace emscripten { class val { public: + static val array() { + return val(internal::_emval_new_array()); + } + static val object() { return val(internal::_emval_new_object()); - }; + } static val null() { return val(internal::_emval_new_null()); - }; + } static val take_ownership(internal::EM_VAL e) { return val(e); } - explicit val(long l) - : handle(internal::_emval_new_long(l)) - {} - - explicit val(const char* str) - : handle(internal::_emval_new_cstring(str)) - {} + template + explicit val(const T& value) { + typedef internal::BindingType BT; + auto taker = reinterpret_cast(&internal::_emval_take_value); + handle = taker(internal::TypeID::get(), BT::toWireType(value)); + } val() = delete; + val(const char* v) + : handle(internal::_emval_new_cstring(v)) + {} + val(const val& v) : handle(v.handle) { From d893eed16b2257c3ffbb186c08d45a053cc5de68 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 15 Jan 2013 18:09:22 -0800 Subject: [PATCH 219/544] Forgot to implement take_value :) --- src/embind/emval.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/embind/emval.js b/src/embind/emval.js index 3df5a540676cc..1c4955c554ae9 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -57,6 +57,12 @@ function __emval_new_cstring(v) { return __emval_register(Pointer_stringify(v)); } +function __emval_take_value(type, v) { + type = requireRegisteredType(type, '_emval_take_value'); + v = type.fromWireType(v); + return __emval_register(v); +} + function __emval_has_property(handle, k) { k = Pointer_stringify(k); return _emval_handle_array[handle].value.hasOwnProperty(k); From 6c56bdda8d4f9ab4eb31e86ce71488106b061a33 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Wed, 16 Jan 2013 14:19:19 -0800 Subject: [PATCH 220/544] It is now possible to access base class properties and methods from a derived class (multiple inheritance not yet supported). --- src/embind/embind.js | 88 +++++++++++++++++++++++++++++++++++++- system/lib/embind/bind.cpp | 14 +++++- 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 39e120e012422..d6464d12d5475 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -36,6 +36,89 @@ function _embind_repr(v) { var typeRegistry = {}; +function resolveType(type) { + function createInheritedFunctionOrProperty(baseClassName, name, baseClassPrototype) { + if (!type.Handle.prototype.hasOwnProperty(name)) { + var desc = Object.getOwnPropertyDescriptor(baseClassPrototype, baseClassName); + if (desc) { // some names in the list may not be present in this particular base class + if ('get' in desc || 'put' in desc) { + Object.defineProperty(type.Handle.prototype, name, desc); + } else { + type.Handle.prototype[name] = createNamedFunction(name, function() { + return baseClassPrototype[baseClassName].apply(this, arguments); // todo: need to upcast "this" pointer + }); + } + } + } + } + if (!type.resolved) { + var i, j, rawBaseClassType, baseClassType, name; + var names = []; + var qualifiedNames = {}; + var rawBaseClassTypes = Module.__getBaseClasses(type.rawType); + for (i = 0; i < rawBaseClassTypes.size(); i++) { + rawBaseClassType = rawBaseClassTypes.at(i); + baseClassType = typeRegistry[rawBaseClassType]; + if (baseClassType) { + resolveType(baseClassType); + var proto = baseClassType.Handle.prototype; + for (name in proto) { + if (proto.hasOwnProperty(name)) { + var qualifiedName = baseClassType.name + "_" + name; + // todo: figure out how to exclude casting functions + if (['clone', 'move', 'delete'].indexOf(name) < 0) { + if (type.Handle.prototype.hasOwnProperty(qualifiedName)) { + if (names.indexOf(name) < 0) { + names.push(name); + } + if (names.indexOf(qualifiedName) < 0) { + qualifiedNames[name] = qualifiedName; + } + } else { + if (names.indexOf(name) >= 0) { + if (names.indexOf(qualifiedName) < 0) { + qualifiedNames[name] = qualifiedName; + } + } else { + names.push(name); + if (type.Handle.prototype.hasOwnProperty(name) && names.indexOf(qualifiedName) < 0) { + qualifiedNames[name] = qualifiedName; + } + } + } + } + } + } + } + } + for (i = 0; i < rawBaseClassTypes.size(); i++) { + rawBaseClassType = rawBaseClassTypes.at(i); + baseClassType = typeRegistry[rawBaseClassType]; + if (baseClassType) { + proto = baseClassType.Handle.prototype; + for (name in qualifiedNames) { + if (qualifiedNames.hasOwnProperty(name)) { + createInheritedFunctionOrProperty(name, qualifiedNames[name], proto); + } + } + for (j = 0; j < names.length; j++) { + name = names[j]; + if (!(name in qualifiedNames)) { + createInheritedFunctionOrProperty(name, name, proto); + } + } + } + } + type.resolved = true; + } +} + +function resolveBindings() { + for (var rawType in typeRegistry) { + resolveType(typeRegistry[rawType]); + } +} + function registerType(rawType, name, registeredInstance) { if (!rawType) { throw new BindingError('type "' + name + '" must have a positive integer typeid pointer'); @@ -731,8 +814,8 @@ function __embind_register_class( var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop); Object.defineProperty(h, prop, dp); } - - return h; + + return h; }); Handle.prototype.clone = function() { @@ -772,6 +855,7 @@ function __embind_register_class( var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); var type = registerType(rawType, name, registeredClass); registeredClass.pointeeType = type; + var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); registerType(rawPointerType, name + '*', registeredClass); registeredClass.pointeeType = type; diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index a4b67fa5ef987..5e82bb7eb4fba 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -10,7 +10,7 @@ using namespace emscripten; namespace __cxxabiv1 { - std::vector __getBaseClasses(const __class_type_info* cti) { + std::vector __internalGetBaseClasses(const __class_type_info* cti) { std::vector bases; const __si_class_type_info* scti = dynamic_cast(cti); @@ -48,7 +48,7 @@ namespace __cxxabiv1 { if (dv == bs) { paths.emplace_back(newPath); } else { - std::vector bases = __getBaseClasses(dv); + std::vector bases = __internalGetBaseClasses(dv); for (int i = 0; i < bases.size(); i++) { __getDerivationPaths(bases[i], bs, newPath, paths); } @@ -212,6 +212,15 @@ namespace emscripten { return name; } + std::vector __getBaseClasses(int tp) { + std::vector baseTypes = __internalGetBaseClasses((const __cxxabiv1::__class_type_info*)tp); + std::vector bases; + for (int j = 0; j < baseTypes.size(); j++) { + bases.emplace_back((int)baseTypes[j]); + } + return bases; + } + int EMSCRIPTEN_KEEPALIVE __peek32(int p) { return *(int *)p; } @@ -221,6 +230,7 @@ namespace emscripten { // conversion for the return value. This has the unfortunate side-effect of exposing it to third party // developers, but perhaps the double underscore will scare them away from calling it. function("__getDerivationPath", &__getDerivationPath); + function("__getBaseClasses", &__getBaseClasses); function("__peek32", &__peek32); })); } From 939e9dbbbdfc9b917a43d25ffb15a92147f0d5eb Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Wed, 16 Jan 2013 14:25:42 -0800 Subject: [PATCH 221/544] Fix for lint warning. --- src/embind/embind.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index d6464d12d5475..319306e2a5fe5 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -52,7 +52,7 @@ function resolveType(type) { } } if (!type.resolved) { - var i, j, rawBaseClassType, baseClassType, name; + var i, j, rawBaseClassType, baseClassType, name, proto; var names = []; var qualifiedNames = {}; var rawBaseClassTypes = Module.__getBaseClasses(type.rawType); @@ -61,7 +61,7 @@ function resolveType(type) { baseClassType = typeRegistry[rawBaseClassType]; if (baseClassType) { resolveType(baseClassType); - var proto = baseClassType.Handle.prototype; + proto = baseClassType.Handle.prototype; for (name in proto) { if (proto.hasOwnProperty(name)) { var qualifiedName = baseClassType.name + "_" + name; From 08f3047321014c06892e830ba45374fe93ad0ed4 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Fri, 18 Jan 2013 07:55:10 -0800 Subject: [PATCH 222/544] Work in progress for access to properties under multiple inheritance --- src/embind/embind.js | 99 +++++++++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 33 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 319306e2a5fe5..3f50ef219bf50 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -37,56 +37,80 @@ function _embind_repr(v) { var typeRegistry = {}; function resolveType(type) { - function createInheritedFunctionOrProperty(baseClassName, name, baseClassPrototype) { + function createInheritedFunctionOrProperty(baseClassName, name, baseClassPrototype, baseClassType) { if (!type.Handle.prototype.hasOwnProperty(name)) { var desc = Object.getOwnPropertyDescriptor(baseClassPrototype, baseClassName); if (desc) { // some names in the list may not be present in this particular base class - if ('get' in desc || 'put' in desc) { + if (baseClassPrototype.constructor.memberType[baseClassName] == 'field') { + var newDescriptor = { + enumerable: true, + get: function() { + var save = this.ptr; + var baseClassPtr = ___staticPointerCast(this.ptr, type.rawType, baseClassType.rawType); + try { + this.ptr = baseClassPtr; + return desc.get(); + } finally { + this.ptr = save; // todo: still not good, if the base class routine calls through the current handle + } + }, + set: function(v) { + var save = this.ptr; + var baseClassPtr = ___staticPointerCast(this.ptr, type.rawType, baseClassType.rawType); + try { + this.ptr = baseClassPtr; + desc.set(v); + } finally { + this.ptr = save; // todo: still not good, if the base class routine calls through the current handle + } + } + }; Object.defineProperty(type.Handle.prototype, name, desc); - } else { + } else if (baseClassPrototype.constructor.memberType[baseClassName] == 'method') { type.Handle.prototype[name] = createNamedFunction(name, function() { - return baseClassPrototype[baseClassName].apply(this, arguments); // todo: need to upcast "this" pointer + var save = this.ptr; + var baseClassPtr = ___staticPointerCast(this.ptr, type.rawType, baseClassType.rawType); + try { + this.ptr = baseClassPtr; + return baseClassPrototype[baseClassName].apply(this, arguments); + } finally { + this.ptr = save; // todo: still not good, if the base class routine calls through the current handle + } }); } } } } if (!type.resolved) { - var i, j, rawBaseClassType, baseClassType, name, proto; + var i, j, rawBaseClassType, baseClassType, name, baseProto; var names = []; + function addName(name) { + if (names.indexOf(name) < 0) { + names.push(name); + } + } var qualifiedNames = {}; + function addQualifiedName(name, qualifiedName) { + if (!(name in qualifiedNames)) { + qualifiedNames[name] = []; + } + if (qualifiedNames[name].indexOf(qualifiedName) < 0) { + qualifiedNames[name].push(qualifiedName); + } + } var rawBaseClassTypes = Module.__getBaseClasses(type.rawType); for (i = 0; i < rawBaseClassTypes.size(); i++) { rawBaseClassType = rawBaseClassTypes.at(i); baseClassType = typeRegistry[rawBaseClassType]; if (baseClassType) { resolveType(baseClassType); - proto = baseClassType.Handle.prototype; - for (name in proto) { - if (proto.hasOwnProperty(name)) { - var qualifiedName = baseClassType.name + "_" + name; - // todo: figure out how to exclude casting functions - if (['clone', 'move', 'delete'].indexOf(name) < 0) { - if (type.Handle.prototype.hasOwnProperty(qualifiedName)) { - if (names.indexOf(name) < 0) { - names.push(name); - } - if (names.indexOf(qualifiedName) < 0) { - qualifiedNames[name] = qualifiedName; - } - } else { - if (names.indexOf(name) >= 0) { - if (names.indexOf(qualifiedName) < 0) { - qualifiedNames[name] = qualifiedName; - } - } else { - names.push(name); - if (type.Handle.prototype.hasOwnProperty(name) && names.indexOf(qualifiedName) < 0) { - qualifiedNames[name] = qualifiedName; - } - } - } + baseProto = baseClassType.Handle.prototype; + for (name in baseProto) { + if (baseProto.hasOwnProperty(name) && baseClassType.Handle.memberType[name]) { + if (names.indexOf(name) >= 0 || type.Handle.prototype.hasOwnProperty(name)) { + addQualifiedName(name, baseClassType.name + "_" + name); } + addName(name); } } } @@ -95,16 +119,20 @@ function resolveType(type) { rawBaseClassType = rawBaseClassTypes.at(i); baseClassType = typeRegistry[rawBaseClassType]; if (baseClassType) { - proto = baseClassType.Handle.prototype; + var proto = baseClassType.Handle.prototype; for (name in qualifiedNames) { if (qualifiedNames.hasOwnProperty(name)) { - createInheritedFunctionOrProperty(name, qualifiedNames[name], proto); + for (j = 0; j < qualifiedNames[name].length; j++) { + if (qualifiedNames[name][j].indexOf(baseClassType.name + "_") == 0) { + createInheritedFunctionOrProperty(name, qualifiedNames[name][j], proto, baseClassType); + } + } } } for (j = 0; j < names.length; j++) { name = names[j]; if (!(name in qualifiedNames)) { - createInheritedFunctionOrProperty(name, name, proto); + createInheritedFunctionOrProperty(name, name, proto, baseClassType); } } } @@ -850,6 +878,7 @@ function __embind_register_class( } this.ptr = undefined; }; + Handle.memberType = {}; // todo: clean this up! var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); @@ -944,8 +973,10 @@ function __embind_register_class_method( runDestructors(destructors); return rv; }; + classType.Handle.memberType[methodName] = "method"; } +// todo: cast methods should require binding of their target types function __embind_register_raw_cast_method( rawClassType, isPolymorphic, @@ -992,6 +1023,7 @@ function __embind_register_raw_cast_method( }; } +// todo: cast methods should not be passed from the smart ptr to the contained object!! function __embind_register_smart_cast_method( rawPointerType, rawReturnType, @@ -1186,6 +1218,7 @@ function __embind_register_class_field( }, enumerable: true }); + classType.Handle.memberType[fieldName] = "field"; } function RegisteredEnum() { From 93b85047472fd07cb1f7530fca078ae6453a0968 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Fri, 18 Jan 2013 08:06:41 -0800 Subject: [PATCH 223/544] Fix lint warnings. --- src/embind/embind.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 3f50ef219bf50..6f8cba714c442 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -41,7 +41,7 @@ function resolveType(type) { if (!type.Handle.prototype.hasOwnProperty(name)) { var desc = Object.getOwnPropertyDescriptor(baseClassPrototype, baseClassName); if (desc) { // some names in the list may not be present in this particular base class - if (baseClassPrototype.constructor.memberType[baseClassName] == 'field') { + if (baseClassPrototype.constructor.memberType[baseClassName] === 'field') { var newDescriptor = { enumerable: true, get: function() { @@ -66,7 +66,7 @@ function resolveType(type) { } }; Object.defineProperty(type.Handle.prototype, name, desc); - } else if (baseClassPrototype.constructor.memberType[baseClassName] == 'method') { + } else if (baseClassPrototype.constructor.memberType[baseClassName] === 'method') { type.Handle.prototype[name] = createNamedFunction(name, function() { var save = this.ptr; var baseClassPtr = ___staticPointerCast(this.ptr, type.rawType, baseClassType.rawType); @@ -84,20 +84,20 @@ function resolveType(type) { if (!type.resolved) { var i, j, rawBaseClassType, baseClassType, name, baseProto; var names = []; - function addName(name) { + var addName = function(name) { if (names.indexOf(name) < 0) { names.push(name); } - } + }; var qualifiedNames = {}; - function addQualifiedName(name, qualifiedName) { + var addQualifiedName = function(name, qualifiedName) { if (!(name in qualifiedNames)) { qualifiedNames[name] = []; } if (qualifiedNames[name].indexOf(qualifiedName) < 0) { qualifiedNames[name].push(qualifiedName); } - } + }; var rawBaseClassTypes = Module.__getBaseClasses(type.rawType); for (i = 0; i < rawBaseClassTypes.size(); i++) { rawBaseClassType = rawBaseClassTypes.at(i); @@ -123,7 +123,7 @@ function resolveType(type) { for (name in qualifiedNames) { if (qualifiedNames.hasOwnProperty(name)) { for (j = 0; j < qualifiedNames[name].length; j++) { - if (qualifiedNames[name][j].indexOf(baseClassType.name + "_") == 0) { + if (qualifiedNames[name][j].indexOf(baseClassType.name + "_") === 0) { createInheritedFunctionOrProperty(name, qualifiedNames[name][j], proto, baseClassType); } } From e5a50ea590133df344bde9e1fda0f98afa755378 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Fri, 18 Jan 2013 13:04:57 -0800 Subject: [PATCH 224/544] Reconstruct code after git merge issue. --- src/embind/embind.js | 126 ++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 81 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 6f8cba714c442..07629135a6c70 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -36,103 +36,67 @@ function _embind_repr(v) { var typeRegistry = {}; -function resolveType(type) { - function createInheritedFunctionOrProperty(baseClassName, name, baseClassPrototype, baseClassType) { - if (!type.Handle.prototype.hasOwnProperty(name)) { - var desc = Object.getOwnPropertyDescriptor(baseClassPrototype, baseClassName); - if (desc) { // some names in the list may not be present in this particular base class - if (baseClassPrototype.constructor.memberType[baseClassName] === 'field') { - var newDescriptor = { - enumerable: true, - get: function() { - var save = this.ptr; - var baseClassPtr = ___staticPointerCast(this.ptr, type.rawType, baseClassType.rawType); - try { - this.ptr = baseClassPtr; - return desc.get(); - } finally { - this.ptr = save; // todo: still not good, if the base class routine calls through the current handle - } - }, - set: function(v) { - var save = this.ptr; - var baseClassPtr = ___staticPointerCast(this.ptr, type.rawType, baseClassType.rawType); - try { - this.ptr = baseClassPtr; - desc.set(v); - } finally { - this.ptr = save; // todo: still not good, if the base class routine calls through the current handle - } - } - }; - Object.defineProperty(type.Handle.prototype, name, desc); - } else if (baseClassPrototype.constructor.memberType[baseClassName] === 'method') { - type.Handle.prototype[name] = createNamedFunction(name, function() { - var save = this.ptr; - var baseClassPtr = ___staticPointerCast(this.ptr, type.rawType, baseClassType.rawType); - try { - this.ptr = baseClassPtr; - return baseClassPrototype[baseClassName].apply(this, arguments); - } finally { - this.ptr = save; // todo: still not good, if the base class routine calls through the current handle - } - }); +function createInheritedFunctionOrProperty(name, type, nameInBaseClass, baseClassType) { + function upcastingWrapper(method) { + return function() { + var baseClassPtr = ___staticPointerCast(this.ptr, type.rawType, baseClassType.rawType); + if (baseClassPtr === this.ptr) { + return method.apply(this, arguments); + } else { + var handle = this.clone(); + try { + handle.ptr = baseClassPtr; + return method.apply(handle, arguments); + } finally { + handle.delete(); } } - } + }; + } + var baseClassPrototype = baseClassType.Handle.prototype; + if (baseClassPrototype.constructor.memberType[nameInBaseClass] === 'field') { + var baseClassDescriptor = Object.getOwnPropertyDescriptor(baseClassPrototype, nameInBaseClass); + Object.defineProperty(type.Handle.prototype, name, { + enumerable: true, + get: upcastingWrapper(baseClassDescriptor.get), + set: upcastingWrapper(baseClassDescriptor.set) + }); + } else if (baseClassPrototype.constructor.memberType[nameInBaseClass] === 'method') { + var baseClassMethod = baseClassPrototype[nameInBaseClass]; + type.Handle.prototype[name] = createNamedFunction(name, upcastingWrapper(baseClassMethod)); } +} + +function resolveType(type) { if (!type.resolved) { - var i, j, rawBaseClassType, baseClassType, name, baseProto; - var names = []; - var addName = function(name) { - if (names.indexOf(name) < 0) { - names.push(name); - } - }; - var qualifiedNames = {}; - var addQualifiedName = function(name, qualifiedName) { - if (!(name in qualifiedNames)) { - qualifiedNames[name] = []; - } - if (qualifiedNames[name].indexOf(qualifiedName) < 0) { - qualifiedNames[name].push(qualifiedName); - } - }; + var baseClassType, name, baseProto; + var inheritedNames = {}; var rawBaseClassTypes = Module.__getBaseClasses(type.rawType); - for (i = 0; i < rawBaseClassTypes.size(); i++) { - rawBaseClassType = rawBaseClassTypes.at(i); + for (var i = 0; i < rawBaseClassTypes.size(); i++) { + var rawBaseClassType = rawBaseClassTypes.at(i); baseClassType = typeRegistry[rawBaseClassType]; if (baseClassType) { resolveType(baseClassType); baseProto = baseClassType.Handle.prototype; for (name in baseProto) { if (baseProto.hasOwnProperty(name) && baseClassType.Handle.memberType[name]) { - if (names.indexOf(name) >= 0 || type.Handle.prototype.hasOwnProperty(name)) { - addQualifiedName(name, baseClassType.name + "_" + name); + if (!(name in inheritedNames)) { + inheritedNames[name] = []; } - addName(name); + inheritedNames[name].push(baseClassType); } } } } - for (i = 0; i < rawBaseClassTypes.size(); i++) { - rawBaseClassType = rawBaseClassTypes.at(i); - baseClassType = typeRegistry[rawBaseClassType]; - if (baseClassType) { - var proto = baseClassType.Handle.prototype; - for (name in qualifiedNames) { - if (qualifiedNames.hasOwnProperty(name)) { - for (j = 0; j < qualifiedNames[name].length; j++) { - if (qualifiedNames[name][j].indexOf(baseClassType.name + "_") === 0) { - createInheritedFunctionOrProperty(name, qualifiedNames[name][j], proto, baseClassType); - } - } - } - } - for (j = 0; j < names.length; j++) { - name = names[j]; - if (!(name in qualifiedNames)) { - createInheritedFunctionOrProperty(name, name, proto, baseClassType); + for (name in inheritedNames) { + if (inheritedNames.hasOwnProperty(name)) { + if (!type.Handle.prototype.hasOwnProperty(name) && inheritedNames[name].length === 1) { + baseClassType = inheritedNames[name][0]; + createInheritedFunctionOrProperty(name, type, name, baseClassType); + } else { + for (var j = 0; j < inheritedNames[name].length; j++) { + baseClassType = inheritedNames[name][j]; + createInheritedFunctionOrProperty(baseClassType.name+"_"+name, type, name, baseClassType); } } } From 2b173301eface816c6f09f3e3d706571575a398a Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 21 Jan 2013 18:54:47 -0800 Subject: [PATCH 225/544] Simplify emscripten::val a bit, reducing it closer to its primitive operations. --- src/embind/emval.js | 14 ++++++++++---- system/include/emscripten/val.h | 19 ++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index 1c4955c554ae9..8ecef7f05cc44 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -49,7 +49,11 @@ function __emval_new_object() { return __emval_register({}); } -function __emval_new_null() { +function __emval_undefined() { + return __emval_register(undefined); +} + +function __emval_null() { return __emval_register(null); } @@ -63,9 +67,11 @@ function __emval_take_value(type, v) { return __emval_register(v); } -function __emval_has_property(handle, k) { - k = Pointer_stringify(k); - return _emval_handle_array[handle].value.hasOwnProperty(k); +var global = Function('return this')(); + +function __emval_get_global(name) { + name = Pointer_stringify(name); + return __emval_register(global[name]); } function __emval_get_property(handle, k) { diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 65f5226634d6c..b0f55ec6e923b 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -14,11 +14,12 @@ namespace emscripten { EM_VAL _emval_new_array(); EM_VAL _emval_new_object(); - EM_VAL _emval_new_null(); + EM_VAL _emval_undefined(); + EM_VAL _emval_null(); EM_VAL _emval_new_cstring(const char*); void _emval_take_value(TYPEID type/*, ...*/); - bool _emval_has_property(EM_VAL object, const char* key); + EM_VAL _emval_get_global(const char* name); EM_VAL _emval_get_property(EM_VAL object, const char* key); EM_VAL _emval_get_property_by_long(EM_VAL object, long key); EM_VAL _emval_get_property_by_unsigned_long(EM_VAL object, unsigned long key); @@ -56,14 +57,22 @@ namespace emscripten { return val(internal::_emval_new_object()); } + static val undefined() { + return val(internal::_emval_undefined()); + } + static val null() { - return val(internal::_emval_new_null()); + return val(internal::_emval_null()); } static val take_ownership(internal::EM_VAL e) { return val(e); } + static val global(const char* name) { + return val(internal::_emval_get_global(name)); + } + template explicit val(const T& value) { typedef internal::BindingType BT; @@ -94,8 +103,8 @@ namespace emscripten { return *this; } - bool exist(const char* key) const { - return internal::_emval_has_property(handle, key); + bool hasOwnProperty(const char* key) const { + return val::global("Object").get("prototype").get("hasOwnProperty").call("call", *this, val(key)).as(); } val get(const char* key) const { From a8a7f1b36580147b192f6b95940c5e9653bddea2 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 21 Jan 2013 18:54:47 -0800 Subject: [PATCH 226/544] Simplify emscripten::val a bit, reducing it closer to its primitive operations. --- src/embind/emval.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index 8ecef7f05cc44..1953428d9270c 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -67,7 +67,7 @@ function __emval_take_value(type, v) { return __emval_register(v); } -var global = Function('return this')(); +var global = (function(){return Function;})()('return this')(); function __emval_get_global(name) { name = Pointer_stringify(name); From 03180c51275bc913d21460772ad73b7be815c146 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 22 Jan 2013 15:22:11 -0800 Subject: [PATCH 227/544] Removed order dependencies from emscripten bindings. --- src/embind/embind.js | 562 +++++++++++++++++++++++-------------------- 1 file changed, 301 insertions(+), 261 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 07629135a6c70..86e24a9169cfa 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1,4 +1,5 @@ /*global Module*/ +/*global Module*/ /*global _malloc, _free, _memcpy*/ /*global FUNCTION_TABLE, HEAP32*/ /*global Pointer_stringify, writeStringToMemory*/ @@ -35,6 +36,18 @@ function _embind_repr(v) { } var typeRegistry = {}; +var deferredRegistrations = []; + +function requestDeferredRegistration(registrationFunction) { + deferredRegistrations.push(registrationFunction); +} + +function performDeferredRegistrations(){ + while(deferredRegistrations.length > 0) { + var registrationFunction = deferredRegistrations.shift(); + registrationFunction(); + } +} function createInheritedFunctionOrProperty(name, type, nameInBaseClass, baseClassType) { function upcastingWrapper(method) { @@ -106,8 +119,11 @@ function resolveType(type) { } function resolveBindings() { + performDeferredRegistrations(); for (var rawType in typeRegistry) { - resolveType(typeRegistry[rawType]); + if (typeRegistry.hasOwnProperty(rawType)) { + resolveType(typeRegistry[rawType]); + } } } @@ -136,14 +152,21 @@ function typeName(rawType) { return Pointer_stringify(___typeName(rawType)); } -function requireArgumentTypes(argCount, rawArgTypes, name) { - var argTypes = new Array(argCount); - for (var i = 0; i < argCount; ++i) { - var rawArgType = HEAP32[(rawArgTypes >> 2) + i]; +function heap32VectorToArray(count, firstElement) { + var array = []; + for (var i = 0; i < count; i++) { + array.push(HEAP32[(firstElement >> 2) + i]); + } + return array; +} + +function requireArgumentTypes(rawArgTypes, name) { + var argTypes = []; + for (var i = 0; i < rawArgTypes.length; ++i) { if (i === 0) { - argTypes[i] = requireRegisteredType(rawArgType, name + " return value"); + argTypes[i] = requireRegisteredType(rawArgTypes[i], name + " return value"); } else { - argTypes[i] = requireRegisteredType(rawArgType, name + " parameter " + i); + argTypes[i] = requireRegisteredType(rawArgTypes[i], name + " parameter " + i); } } return argTypes; @@ -310,11 +333,14 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { }; } -function __embind_register_function(name, argCount, rawArgTypes, rawInvoker, fn) { +function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, fn) { + var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); name = Pointer_stringify(name); rawInvoker = FUNCTION_TABLE[rawInvoker]; - var argTypes = requireArgumentTypes(argCount, rawArgTypes, name); - exposePublicSymbol(name, makeInvoker(name, argCount, argTypes, rawInvoker, fn)); + requestDeferredRegistration(function() { + var argTypes = requireArgumentTypes(rawArgTypes, name); + exposePublicSymbol(name, makeInvoker(name, argCount, argTypes, rawInvoker, fn)); + }); } function RegisteredTuple(rawConstructor, rawDestructor) { @@ -371,21 +397,22 @@ function __embind_register_tuple_element( memberPointerSize, memberPointer ) { - var tupleType = requireRegisteredType(rawTupleType, 'tuple'); - var type = requireRegisteredType(rawType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); - - tupleType.elements.push({ - read: function(ptr) { - return type.fromWireType(getter(ptr, memberPointer)); - }, - write: function(ptr, o) { - var destructors = []; - setter(ptr, memberPointer, type.toWireType(destructors, o)); - runDestructors(destructors); - } + requestDeferredRegistration(function() { + var tupleType = requireRegisteredType(rawTupleType, 'tuple'); + var type = requireRegisteredType(rawType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); + tupleType.elements.push({ + read: function(ptr) { + return type.fromWireType(getter(ptr, memberPointer)); + }, + write: function(ptr, o) { + var destructors = []; + setter(ptr, memberPointer, type.toWireType(destructors, o)); + runDestructors(destructors); + } + }); }); } @@ -399,25 +426,26 @@ function __embind_register_tuple_element_accessor( setterSize, setter ) { - var tupleType = requireRegisteredType(rawTupleType, 'tuple'); - var elementType = requireRegisteredType(rawElementType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); rawStaticGetter = FUNCTION_TABLE[rawStaticGetter]; getter = copyMemberPointer(getter, getterSize); rawStaticSetter = FUNCTION_TABLE[rawStaticSetter]; setter = copyMemberPointer(setter, setterSize); - - tupleType.elements.push({ - read: function(ptr) { - return elementType.fromWireType(rawStaticGetter(ptr, HEAP32[getter >> 2])); - }, - write: function(ptr, o) { - var destructors = []; - rawStaticSetter( - ptr, - HEAP32[setter >> 2], - elementType.toWireType(destructors, o)); - runDestructors(destructors); - } + requestDeferredRegistration(function() { + var tupleType = requireRegisteredType(rawTupleType, 'tuple'); + var elementType = requireRegisteredType(rawElementType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); + tupleType.elements.push({ + read: function(ptr) { + return elementType.fromWireType(rawStaticGetter(ptr, HEAP32[getter >> 2])); + }, + write: function(ptr, o) { + var destructors = []; + rawStaticSetter( + ptr, + HEAP32[setter >> 2], + elementType.toWireType(destructors, o)); + runDestructors(destructors); + } + }); }); } @@ -475,23 +503,24 @@ function __embind_register_struct_field( memberPointerSize, memberPointer ) { - var structType = requireRegisteredType(rawStructType, 'struct'); fieldName = Pointer_stringify(fieldName); - var fieldType = requireRegisteredType(rawFieldType, 'field "' + structType.name + '.' + fieldName + '"'); rawGetter = FUNCTION_TABLE[rawGetter]; rawSetter = FUNCTION_TABLE[rawSetter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); - - structType.fields[fieldName] = { - read: function(ptr) { - return fieldType.fromWireType(rawGetter(ptr, memberPointer)); - }, - write: function(ptr, o) { - var destructors = []; - rawSetter(ptr, memberPointer, fieldType.toWireType(destructors, o)); - runDestructors(destructors); - } - }; + requestDeferredRegistration(function() { + var structType = requireRegisteredType(rawStructType, 'struct'); + var fieldType = requireRegisteredType(rawFieldType, 'field "' + structType.name + '.' + fieldName + '"'); + structType.fields[fieldName] = { + read: function(ptr) { + return fieldType.fromWireType(rawGetter(ptr, memberPointer)); + }, + write: function(ptr, o) { + var destructors = []; + rawSetter(ptr, memberPointer, fieldType.toWireType(destructors, o)); + runDestructors(destructors); + } + }; + }); } function RegisteredPointer(Handle, isPolymorphic, isSmartPointer, rawGetPointee, rawConstructor, rawDestructor) { @@ -870,74 +899,77 @@ function __embind_register_class( function __embind_register_class_constructor( rawClassType, argCount, - rawArgTypes, + rawArgTypesAddr, rawConstructor ) { - var classType = requireRegisteredType(rawClassType, 'class'); - var humanName = 'constructor ' + classType.name; - var argTypes = requireArgumentTypes(argCount, rawArgTypes, humanName); + var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); rawConstructor = FUNCTION_TABLE[rawConstructor]; + requestDeferredRegistration(function() { + var classType = requireRegisteredType(rawClassType, 'class'); + var humanName = 'constructor ' + classType.name; + var argTypes = requireArgumentTypes(rawArgTypes, humanName); + classType.constructor.body = function() { + if (arguments.length !== argCount - 1) { + throw new BindingError('emscripten binding ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); + } + var destructors = []; + var args = new Array(argCount-1); + for (var i = 1; i < argCount; ++i) { + args[i-1] = argTypes[i].toWireType(destructors, arguments[i-1]); + } - classType.constructor.body = function() { - if (arguments.length !== argCount - 1) { - throw new BindingError('emscripten binding ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); - } - var destructors = []; - var args = new Array(argCount-1); - for (var i = 1; i < argCount; ++i) { - args[i-1] = argTypes[i].toWireType(destructors, arguments[i-1]); - } + var ptr = rawConstructor.apply(null, args); + runDestructors(destructors); - var ptr = rawConstructor.apply(null, args); - runDestructors(destructors); - - return classType.Handle.call(this, ptr); - }; + return classType.Handle.call(this, ptr); + }; + }); } function __embind_register_class_method( rawClassType, methodName, argCount, - rawArgTypes, + rawArgTypesAddr, rawInvoker, memberFunctionSize, memberFunction ) { - var classType = requireRegisteredType(rawClassType, 'class'); + var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = Pointer_stringify(methodName); - var humanName = classType.name + '.' + methodName; - - var argTypes = requireArgumentTypes(argCount, rawArgTypes, 'method ' + humanName); rawInvoker = FUNCTION_TABLE[rawInvoker]; memberFunction = copyMemberPointer(memberFunction, memberFunctionSize); + requestDeferredRegistration(function() { + var classType = requireRegisteredType(rawClassType, 'class'); + var humanName = classType.name + '.' + methodName; + var argTypes = requireArgumentTypes(rawArgTypes, 'method ' + humanName); + classType.Handle.prototype[methodName] = function() { - classType.Handle.prototype[methodName] = function() { - - if (!this.ptr) { - throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); - } - if (arguments.length !== argCount - 1) { - throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); - } - - var destructors = []; - var args = new Array(argCount + 1); - args[0] = this.ptr; - args[1] = memberFunction; - for (var i = 1; i < argCount; ++i) { - args[i + 1] = argTypes[i].toWireType(destructors, arguments[i-1]); - } - var rv = rawInvoker.apply(null, args); - if (argTypes[0].fromWireTypeAutoDowncast) { - rv = argTypes[0].fromWireTypeAutoDowncast(rv); - } else { - rv = argTypes[0].fromWireType(rv); - } - runDestructors(destructors); - return rv; - }; - classType.Handle.memberType[methodName] = "method"; + if (!this.ptr) { + throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } + if (arguments.length !== argCount - 1) { + throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); + } + + var destructors = []; + var args = new Array(argCount + 1); + args[0] = this.ptr; + args[1] = memberFunction; + for (var i = 1; i < argCount; ++i) { + args[i + 1] = argTypes[i].toWireType(destructors, arguments[i-1]); + } + var rv = rawInvoker.apply(null, args); + if (argTypes[0].fromWireTypeAutoDowncast) { + rv = argTypes[0].fromWireTypeAutoDowncast(rv); + } else { + rv = argTypes[0].fromWireType(rv); + } + runDestructors(destructors); + return rv; + }; + classType.Handle.memberType[methodName] = "method"; + }); } // todo: cast methods should require binding of their target types @@ -948,43 +980,43 @@ function __embind_register_raw_cast_method( rawReturnType, rawInvoker ) { - var classType = requireRegisteredType(rawClassType, 'class'); - methodName = Pointer_stringify(methodName); - var humanName = classType.name + '.' + methodName; - - var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value'); - rawInvoker = FUNCTION_TABLE[rawInvoker]; - - classType.Handle.prototype[methodName] = function() { - if (!this.ptr) { - throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); - } - if (arguments.length !== 0) { - throw new BindingError('emscripten binding method ' + humanName + ' called with arguments, none expected'); - } - if (isPolymorphic) { - // todo: this is all only to validate the cast -- cache the result - var runtimeType = ___getDynamicPointerType(this.ptr); - var derivation = Module.__getDerivationPath(rawReturnType, runtimeType); // downcast is valid - var size = derivation.size(); - derivation.delete(); - if (size === 0) { - derivation = Module.__getDerivationPath(runtimeType, rawReturnType); // upcast is valid - size = derivation.size(); + requestDeferredRegistration(function() { + var classType = requireRegisteredType(rawClassType, 'class'); + methodName = Pointer_stringify(methodName); + var humanName = classType.name + '.' + methodName; + var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value'); + rawInvoker = FUNCTION_TABLE[rawInvoker]; + classType.Handle.prototype[methodName] = function() { + if (!this.ptr) { + throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } + if (arguments.length !== 0) { + throw new BindingError('emscripten binding method ' + humanName + ' called with arguments, none expected'); + } + if (isPolymorphic) { + // todo: this is all only to validate the cast -- cache the result + var runtimeType = ___getDynamicPointerType(this.ptr); + var derivation = Module.__getDerivationPath(rawReturnType, runtimeType); // downcast is valid + var size = derivation.size(); derivation.delete(); if (size === 0) { - throw new CastError("Pointer conversion is not available"); + derivation = Module.__getDerivationPath(runtimeType, rawReturnType); // upcast is valid + size = derivation.size(); + derivation.delete(); + if (size === 0) { + throw new CastError("Pointer conversion is not available"); + } } } - } - var args = new Array(1); - args[0] = this.ptr; - var ptr = rawInvoker.apply(null, args); - var rv = returnType.fromWireType(ptr); - rv.count = this.count; - this.count.value ++; - return rv; - }; + var args = new Array(1); + args[0] = this.ptr; + var ptr = rawInvoker.apply(null, args); + var rv = returnType.fromWireType(ptr); + rv.count = this.count; + this.count.value ++; + return rv; + }; + }); } // todo: cast methods should not be passed from the smart ptr to the contained object!! @@ -996,91 +1028,96 @@ function __embind_register_smart_cast_method( methodName, rawInvoker ) { - var pointerType = requireRegisteredType(rawPointerType, 'smart pointer class'); - methodName = Pointer_stringify(methodName); - var humanName = pointerType.name + '.' + methodName; - - var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value'); - rawInvoker = FUNCTION_TABLE[rawInvoker]; - - pointerType.Handle.prototype[methodName] = function() { - if (!this.ptr) { - throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); - } - if (arguments.length !== 0) { - throw new BindingError('emscripten binding method ' + humanName + ' called with arguments, none expected'); - } - if (isPolymorphic) { - // todo: just validating the cast -- cache the result - var runtimeType = ___getDynamicPointerType(this.ptr); - var derivation = Module.__getDerivationPath(returnPointeeType, runtimeType); // downcast is valid - var size = derivation.size(); - derivation.delete(); - if (size === 0) { - derivation = Module.__getDerivationPath(runtimeType, returnPointeeType); // upcast is valid - size = derivation.size(); + requestDeferredRegistration(function() { + var pointerType = requireRegisteredType(rawPointerType, 'smart pointer class'); + methodName = Pointer_stringify(methodName); + var humanName = pointerType.name + '.' + methodName; + var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value'); + rawInvoker = FUNCTION_TABLE[rawInvoker]; + pointerType.Handle.prototype[methodName] = function() { + if (!this.ptr) { + throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } + if (arguments.length !== 0) { + throw new BindingError('emscripten binding method ' + humanName + ' called with arguments, none expected'); + } + if (isPolymorphic) { + // todo: just validating the cast -- cache the result + var runtimeType = ___getDynamicPointerType(this.ptr); + var derivation = Module.__getDerivationPath(returnPointeeType, runtimeType); // downcast is valid + var size = derivation.size(); derivation.delete(); if (size === 0) { - throw new CastError("Pointer conversion is not available"); + derivation = Module.__getDerivationPath(runtimeType, returnPointeeType); // upcast is valid + size = derivation.size(); + derivation.delete(); + if (size === 0) { + throw new CastError("Pointer conversion is not available"); + } } } - } - var args = new Array(2); - var ptr = _malloc(8); - args[0] = ptr; - args[1] = this.smartPointer; - rawInvoker.apply(null,args); - return returnType.fromWireType(ptr); - }; + var args = new Array(2); + var ptr = _malloc(8); + args[0] = ptr; + args[1] = this.smartPointer; + rawInvoker.apply(null,args); + return returnType.fromWireType(ptr); + }; + }); } function __embind_register_class_classmethod( rawClassType, methodName, argCount, - rawArgTypes, + rawArgTypesAddr, rawInvoker, fn ) { - var classType = requireRegisteredType(rawClassType, 'class'); + var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = Pointer_stringify(methodName); - var humanName = classType.name + '.' + methodName; - var argTypes = requireArgumentTypes(argCount, rawArgTypes, 'classmethod ' + humanName); rawInvoker = FUNCTION_TABLE[rawInvoker]; - classType.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn); + requestDeferredRegistration(function() { + var classType = requireRegisteredType(rawClassType, 'class'); + var humanName = classType.name + '.' + methodName; + var argTypes = requireArgumentTypes(rawArgTypes, 'classmethod ' + humanName); + classType.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn); + }) } function __embind_register_class_operator_call( rawClassType, argCount, - rawArgTypes, + rawArgTypesAddr, rawInvoker ) { - var classType = requireRegisteredType(rawClassType, 'class'); - var humanName = classType.name + '.' + 'operator_call'; - var argTypes = requireArgumentTypes(argCount, rawArgTypes, 'method ' + humanName); + var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); rawInvoker = FUNCTION_TABLE[rawInvoker]; - - - classType.Handle.prototype.operator_call = function() { - if (!this.ptr) { - throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); - } - if (arguments.length !== argCount - 1) { - throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); - } - - var destructors = []; - var args = new Array(argCount); - args[0] = this.ptr; - for (var i = 1; i < argCount; ++i) { - args[i] = argTypes[i].toWireType(destructors, arguments[i-1]); - } + requestDeferredRegistration(function() { + var classType = requireRegisteredType(rawClassType, 'class'); + var humanName = classType.name + '.' + 'operator_call'; + var argTypes = requireArgumentTypes(rawArgTypes, 'method ' + humanName); - var rv = argTypes[0].fromWireType(rawInvoker.apply(null, args)); - runDestructors(destructors); - return rv; - }; + classType.Handle.prototype.operator_call = function() { + if (!this.ptr) { + throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } + if (arguments.length !== argCount - 1) { + throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); + } + + var destructors = []; + var args = new Array(argCount); + args[0] = this.ptr; + for (var i = 1; i < argCount; ++i) { + args[i] = argTypes[i].toWireType(destructors, arguments[i-1]); + } + + var rv = argTypes[0].fromWireType(rawInvoker.apply(null, args)); + runDestructors(destructors); + return rv; + }; + }); } function __embind_register_class_operator_array_get( @@ -1089,30 +1126,31 @@ function __embind_register_class_operator_array_get( indexType, rawInvoker ) { - var classType = requireRegisteredType(rawClassType, 'class'); - indexType = requireRegisteredType(indexType, 'array access index ' + classType.name); - elementType = requireRegisteredType(elementType, 'array access element' + classType.name); rawInvoker = FUNCTION_TABLE[rawInvoker]; - var humanName = classType.name + '.' + 'operator_array_get'; - - classType.Handle.prototype.array_get = function() { - if (!this.ptr) { - throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); - } - - if (arguments.length !== 1) { - throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + 1); - } - - var destructors = []; - var args = new Array(2); - args[0] = this.ptr; - args[1] = indexType.toWireType(destructors, arguments[0]); - - var rv = elementType.fromWireType(rawInvoker.apply(null, args)); - runDestructors(destructors); - return rv; - }; + requestDeferredRegistration(function() { + var classType = requireRegisteredType(rawClassType, 'class'); + indexType = requireRegisteredType(indexType, 'array access index ' + classType.name); + elementType = requireRegisteredType(elementType, 'array access element' + classType.name); + var humanName = classType.name + '.' + 'operator_array_get'; + classType.Handle.prototype.array_get = function() { + if (!this.ptr) { + throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } + + if (arguments.length !== 1) { + throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + 1); + } + + var destructors = []; + var args = new Array(2); + args[0] = this.ptr; + args[1] = indexType.toWireType(destructors, arguments[0]); + + var rv = elementType.fromWireType(rawInvoker.apply(null, args)); + runDestructors(destructors); + return rv; + }; + }); } function __embind_register_class_operator_array_set( @@ -1121,31 +1159,32 @@ function __embind_register_class_operator_array_set( rawIndexType, rawInvoker ) { - var classType = requireRegisteredType(rawClassType, 'class'); - var indexType = requireRegisteredType(rawIndexType, 'array access index ' + classType.name); - elementType = requireRegisteredType(elementType, 'array access element ' + classType.name); rawInvoker = FUNCTION_TABLE[rawInvoker]; - var humanName = classType.name + '.' + 'operator_array_get'; - - classType.Handle.prototype.array_set = function() { - if (!this.ptr) { - throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); - } - - if (arguments.length !== 2) { - throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + 2); - } - - var destructors = []; - var args = new Array(2); - args[0] = this.ptr; - args[1] = indexType.toWireType(destructors, arguments[0]); - args[2] = elementType.toWireType(destructors, arguments[1]); - - var rv = elementType.fromWireType(rawInvoker.apply(null, args)); - runDestructors(destructors); - return rv; - }; + requestDeferredRegistration(function() { + var classType = requireRegisteredType(rawClassType, 'class'); + var indexType = requireRegisteredType(rawIndexType, 'array access index ' + classType.name); + elementType = requireRegisteredType(elementType, 'array access element ' + classType.name); + var humanName = classType.name + '.' + 'operator_array_get'; + classType.Handle.prototype.array_set = function() { + if (!this.ptr) { + throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } + + if (arguments.length !== 2) { + throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + 2); + } + + var destructors = []; + var args = new Array(2); + args[0] = this.ptr; + args[1] = indexType.toWireType(destructors, arguments[0]); + args[2] = elementType.toWireType(destructors, arguments[1]); + + var rv = elementType.fromWireType(rawInvoker.apply(null, args)); + runDestructors(destructors); + return rv; + }; + }); } function __embind_register_class_field( @@ -1157,32 +1196,33 @@ function __embind_register_class_field( memberPointerSize, memberPointer ) { - var classType = requireRegisteredType(rawClassType, 'class'); fieldName = Pointer_stringify(fieldName); - var humanName = classType.name + '.' + fieldName; - var fieldType = requireRegisteredType(rawFieldType, 'field ' + humanName); getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); - - Object.defineProperty(classType.Handle.prototype, fieldName, { - get: function() { - if (!this.ptr) { - throw new BindingError('cannot access emscripten binding field ' + humanName + ' on deleted object'); - } - return fieldType.fromWireType(getter(this.ptr, memberPointer)); - }, - set: function(v) { - if (!this.ptr) { - throw new BindingError('cannot modify emscripten binding field ' + humanName + ' on deleted object'); - } - var destructors = []; - setter(this.ptr, memberPointer, fieldType.toWireType(destructors, v)); - runDestructors(destructors); - }, - enumerable: true + requestDeferredRegistration(function() { + var classType = requireRegisteredType(rawClassType, 'class'); + var humanName = classType.name + '.' + fieldName; + var fieldType = requireRegisteredType(rawFieldType, 'field ' + humanName); + Object.defineProperty(classType.Handle.prototype, fieldName, { + get: function() { + if (!this.ptr) { + throw new BindingError('cannot access emscripten binding field ' + humanName + ' on deleted object'); + } + return fieldType.fromWireType(getter(this.ptr, memberPointer)); + }, + set: function(v) { + if (!this.ptr) { + throw new BindingError('cannot modify emscripten binding field ' + humanName + ' on deleted object'); + } + var destructors = []; + setter(this.ptr, memberPointer, fieldType.toWireType(destructors, v)); + runDestructors(destructors); + }, + enumerable: true + }); + classType.Handle.memberType[fieldName] = "field"; }); - classType.Handle.memberType[fieldName] = "field"; } function RegisteredEnum() { From 5701999237b30f3503b6ad2f20099e874561bdf9 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 22 Jan 2013 15:26:03 -0800 Subject: [PATCH 228/544] Fix a lint error. --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 86e24a9169cfa..ae61f09f20f06 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1082,7 +1082,7 @@ function __embind_register_class_classmethod( var humanName = classType.name + '.' + methodName; var argTypes = requireArgumentTypes(rawArgTypes, 'classmethod ' + humanName); classType.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn); - }) + }); } function __embind_register_class_operator_call( From 661e70cb38bbdd704821c50c4324b5675b41068c Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 22 Jan 2013 08:46:35 -0800 Subject: [PATCH 229/544] simplify emscripten::val set and get --- src/embind/emval.js | 22 ++++-------------- system/include/emscripten/val.h | 40 ++++++++------------------------- 2 files changed, 13 insertions(+), 49 deletions(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index 1953428d9270c..84ed19568fadc 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -74,17 +74,8 @@ function __emval_get_global(name) { return __emval_register(global[name]); } -function __emval_get_property(handle, k) { - k = Pointer_stringify(k); - return __emval_register(_emval_handle_array[handle].value[k]); -} - -function __emval_get_property_by_long(handle, k) { - return __emval_register(_emval_handle_array[handle].value[k]); -} - -function __emval_get_property_by_unsigned_long(handle, k) { - return __emval_register(_emval_handle_array[handle].value[k]); +function __emval_get_property(handle, key) { + return __emval_register(_emval_handle_array[handle].value[_emval_handle_array[key].value]); } function __emval_eval_global_method(handle, objectName, methodName) { @@ -94,13 +85,8 @@ function __emval_eval_global_method(handle, objectName, methodName) { return __emval_register(result); } -function __emval_set_property(handle, k, value) { - k = Pointer_stringify(k); - _emval_handle_array[handle].value[k] = _emval_handle_array[value].value; -} - -function __emval_set_property_by_int(handle, k, value) { - _emval_handle_array[handle].value[k] = _emval_handle_array[value].value; +function __emval_set_property(handle, key, value) { + _emval_handle_array[handle].value[_emval_handle_array[key].value] = _emval_handle_array[value].value; } function __emval_as(handle, returnType) { diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index b0f55ec6e923b..4903751bea451 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -20,12 +20,9 @@ namespace emscripten { void _emval_take_value(TYPEID type/*, ...*/); EM_VAL _emval_get_global(const char* name); - EM_VAL _emval_get_property(EM_VAL object, const char* key); - EM_VAL _emval_get_property_by_long(EM_VAL object, long key); - EM_VAL _emval_get_property_by_unsigned_long(EM_VAL object, unsigned long key); + EM_VAL _emval_get_property(EM_VAL object, EM_VAL key); EM_VAL _emval_eval_global_method(EM_VAL object, const char* objectName, const char* methodName); - void _emval_set_property(EM_VAL object, const char* key, EM_VAL value); - void _emval_set_property_by_int(EM_VAL object, long key, EM_VAL value); + void _emval_set_property(EM_VAL object, EM_VAL key, EM_VAL value); void _emval_as(EM_VAL value, TYPEID returnType); EM_VAL _emval_call( EM_VAL value, @@ -106,38 +103,19 @@ namespace emscripten { bool hasOwnProperty(const char* key) const { return val::global("Object").get("prototype").get("hasOwnProperty").call("call", *this, val(key)).as(); } - - val get(const char* key) const { - return val(internal::_emval_get_property(handle, key)); - } - - val get(int key) const { - return get(long(key)); - } - - val get(unsigned int key) const { - typedef unsigned long T; - return get(T(key)); - } - - val get(long key) const { - return val(internal::_emval_get_property_by_long(handle, key)); - } - - val get(unsigned long key) const { - return val(internal::_emval_get_property_by_unsigned_long(handle, key)); + + template + val get(const T& key) const { + return val(internal::_emval_get_property(handle, val(key).handle)); } val eval_global_method(const char* objectName, const char* methodName) const { return val(internal::_emval_eval_global_method(handle, objectName, methodName)); } - void set(const char* key, val v) { - internal::_emval_set_property(handle, key, v.handle); - } - - void set(long key, val v) { - internal::_emval_set_property_by_int(handle, key, v.handle); + template + void set(const T& key, val v) { + internal::_emval_set_property(handle, val(key).handle, v.handle); } template From 066540930e679a965fa002cb09b3e6cc3bcc2c97 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 22 Jan 2013 15:58:17 -0800 Subject: [PATCH 230/544] Switch from val::get to val[] --- system/include/emscripten/bind.h | 4 ++-- system/include/emscripten/val.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 652fb1b46ab6a..ce9053f26ceb8 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -793,11 +793,11 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// template std::vector vecFromJSArray(val v) { - auto l = v.get("length").as(); + auto l = v["length"].as(); std::vector rv; for(unsigned i = 0; i < l; ++i) { - rv.push_back(v.get(i).as()); + rv.push_back(v[i].as()); } return rv; diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 4903751bea451..87126d084a7ab 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -105,7 +105,7 @@ namespace emscripten { } template - val get(const T& key) const { + val operator[](const T& key) const { return val(internal::_emval_get_property(handle, val(key).handle)); } From 09bfd969bd413be3dbcdd5dbf89c17211efed85b Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 22 Jan 2013 16:15:18 -0800 Subject: [PATCH 231/544] after merge we need to fix hasOwnProperty to use [] --- system/include/emscripten/val.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 87126d084a7ab..d6b1ac04dca3b 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -101,7 +101,7 @@ namespace emscripten { } bool hasOwnProperty(const char* key) const { - return val::global("Object").get("prototype").get("hasOwnProperty").call("call", *this, val(key)).as(); + return val::global("Object")["prototype"]["hasOwnProperty"].call("call", *this, val(key)).as(); } template From bacb23ed1a80740b34e3a265a29be1d86dd72ff0 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 22 Jan 2013 16:39:06 -0800 Subject: [PATCH 232/544] Kill eval_global_method: it's replaced with more primitives --- src/embind/emval.js | 7 ------- system/include/emscripten/val.h | 5 ----- 2 files changed, 12 deletions(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index 84ed19568fadc..56c307bf5f1cb 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -78,13 +78,6 @@ function __emval_get_property(handle, key) { return __emval_register(_emval_handle_array[handle].value[_emval_handle_array[key].value]); } -function __emval_eval_global_method(handle, objectName, methodName) { - var objectNameStr = Pointer_stringify(objectName); - var methodNameStr = Pointer_stringify(methodName); - var result = eval.call(null, objectNameStr)[methodNameStr](_emval_handle_array[handle].value); - return __emval_register(result); -} - function __emval_set_property(handle, key, value) { _emval_handle_array[handle].value[_emval_handle_array[key].value] = _emval_handle_array[value].value; } diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index d6b1ac04dca3b..3d0a3e60b763b 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -21,7 +21,6 @@ namespace emscripten { EM_VAL _emval_get_global(const char* name); EM_VAL _emval_get_property(EM_VAL object, EM_VAL key); - EM_VAL _emval_eval_global_method(EM_VAL object, const char* objectName, const char* methodName); void _emval_set_property(EM_VAL object, EM_VAL key, EM_VAL value); void _emval_as(EM_VAL value, TYPEID returnType); EM_VAL _emval_call( @@ -109,10 +108,6 @@ namespace emscripten { return val(internal::_emval_get_property(handle, val(key).handle)); } - val eval_global_method(const char* objectName, const char* methodName) const { - return val(internal::_emval_eval_global_method(handle, objectName, methodName)); - } - template void set(const T& key, val v) { internal::_emval_set_property(handle, val(key).handle, v.handle); From 50e05c30bfcdf3b1c8aea0be0b631233e24f694c Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 22 Jan 2013 18:02:56 -0800 Subject: [PATCH 233/544] Introduce val::new_ for constructor invocation --- src/embind/emval.js | 4 ++++ system/include/emscripten/val.h | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/embind/emval.js b/src/embind/emval.js index 56c307bf5f1cb..39f23a6155aca 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -67,6 +67,10 @@ function __emval_take_value(type, v) { return __emval_register(v); } +function __emval_new(handle) { + return __emval_register(new (_emval_handle_array[handle].value)) +} + var global = (function(){return Function;})()('return this')(); function __emval_get_global(name) { diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 3d0a3e60b763b..22a7776a67c1e 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -19,6 +19,8 @@ namespace emscripten { EM_VAL _emval_new_cstring(const char*); void _emval_take_value(TYPEID type/*, ...*/); + EM_VAL _emval_new(EM_VAL value); + EM_VAL _emval_get_global(const char* name); EM_VAL _emval_get_property(EM_VAL object, EM_VAL key); void _emval_set_property(EM_VAL object, EM_VAL key, EM_VAL value); @@ -102,6 +104,10 @@ namespace emscripten { bool hasOwnProperty(const char* key) const { return val::global("Object")["prototype"]["hasOwnProperty"].call("call", *this, val(key)).as(); } + + val new_() const { + return val(internal::_emval_new(handle)); + } template val operator[](const T& key) const { From bf8a0f22d50d3ee8e19d9ec72a5ff563d42c570a Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 22 Jan 2013 18:28:22 -0800 Subject: [PATCH 234/544] Depending on the order of construction and destruction of val objects, count_emval_handles could be incorrect. --- src/embind/emval.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index 39f23a6155aca..e6ba566aa8743 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -10,7 +10,13 @@ var _emval_free_list = []; /** @expose */ Module.count_emval_handles = function() { - return _emval_handle_array.length; + var count = 0; + for (var i = 0; i < _emval_handle_array.length; ++i) { + if (_emval_handle_array[i] !== undefined) { + ++count; + } + } + return count; }; // Private C++ API From 15fa455b01fc5c498994c08882e80cfaeffc1983 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 22 Jan 2013 18:29:38 -0800 Subject: [PATCH 235/544] Missing semicolon --- src/embind/emval.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index e6ba566aa8743..bf31bdf3e1c65 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -74,7 +74,7 @@ function __emval_take_value(type, v) { } function __emval_new(handle) { - return __emval_register(new (_emval_handle_array[handle].value)) + return __emval_register(new (_emval_handle_array[handle].value)); } var global = (function(){return Function;})()('return this')(); From ba7a7200ec2737c9890408e906ebe6bc2b9ca69c Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 22 Jan 2013 19:14:02 -0800 Subject: [PATCH 236/544] Document operators that are not exposed --- system/include/emscripten/val.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 22a7776a67c1e..857a1bdf40c49 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -47,6 +47,22 @@ namespace emscripten { class val { public: + // missing operators: + // * delete + // * in + // * instanceof + // * typeof + // * ! ~ - + ++ -- + // * * / % + // * + - + // * << >> >>> + // * < <= > >= + // * == != === !== + // * & ^ | && || ?: + // + // exposing void, comma, and conditional is unnecessary + // same with: = += -= *= /= %= <<= >>= >>>= &= ^= |= + static val array() { return val(internal::_emval_new_array()); } From 8a12d4c1c4aa9a57fdc414b3304555de8c7158ac Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 23 Jan 2013 11:54:00 -0800 Subject: [PATCH 237/544] fix a rebase conflict --- src/embind/embind.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index ae61f09f20f06..d8a4a44024dcd 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -721,9 +721,8 @@ RegisteredRawPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // todo: can come back -1 or -2!! Throw appropriate exception return handle; } else { - handle = new this.Handle(ptr); + return new this.Handle(ptr); } - return handle; }; function RegisteredClassInstance(constructor, Handle) { From e5fca2885bf4d8066b9569548b4ced1b853f0414 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Mon, 28 Jan 2013 09:12:08 -0800 Subject: [PATCH 238/544] register_smart_ptr changed to .shared_ptr (mod to class definition) -- shared_ptr (outside of class definition) is still allowed shared pointers passed by reference can be modified by the called code -- the change is now reflected at the Javascript calling level other minor clean-up and small syntactic changes --- src/embind/embind.js | 155 ++++++++++++++----------------- system/include/emscripten/bind.h | 62 +++++++------ system/lib/embind/bind.cpp | 20 +--- 3 files changed, 104 insertions(+), 133 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index d8a4a44024dcd..7210dbc14f27b 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -5,7 +5,6 @@ /*global Pointer_stringify, writeStringToMemory*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ /*global ___getDynamicPointerType: false*/ -/*global ___dynamicPointerCast: false*/ /*global ___typeName:false*/ /*global ___staticPointerCast: false*/ @@ -308,6 +307,12 @@ function runDestructors(destructors) { } } +function refreshSmartPointee(handle) { + if (handle && handle.smartPointer) { + handle.ptr = handle.type.smartPointerType.getPointee(handle.smartPointer); + } +} + function makeInvoker(name, argCount, argTypes, invoker, fn) { if (!FUNCTION_TABLE[fn]) { throw new BindingError('function '+name+' is not defined'); @@ -329,6 +334,9 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { rv = argTypes[0].fromWireType(rv); } runDestructors(destructors); + for (i = 1; i < argCount; i++) { + refreshSmartPointee(arguments[i-1]); + } return rv; }; } @@ -537,21 +545,21 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { if (!handle) { return null; } - if (handle.pointeeType.isPolymorphic) { - fromRawType = handle.pointeeType.getDynamicRawPointerType(handle.ptr); + if (handle.type.isPolymorphic) { + fromRawType = handle.type.getDynamicRawPointerType(handle.ptr); } else { - fromRawType = handle.pointeeType.rawType; + fromRawType = handle.type.rawType; } - if (fromRawType === this.pointeeType.rawType) { + if (fromRawType === this.type.rawType) { return this.isSmartPointer ? handle.smartPointer : handle.ptr; } - var ptr = staticPointerCast(handle.ptr, fromRawType, this.pointeeType.rawType); + var ptr = staticPointerCast(handle.ptr, fromRawType, this.type.rawType); if (this.isSmartPointer) { // todo: if ptr == handle.ptr, there's no need to allocate a new smartPtr! - var smartPtr = _malloc(16); - handle.pointeeType.smartPointerType.rawConstructor(smartPtr, ptr, handle.smartPointer); + var smartPtr = _malloc(16); // todo: can we get C++ to tell us the size of the pointer? + handle.type.smartPointerType.rawConstructor(smartPtr, ptr, handle.smartPointer); ptr = smartPtr; - destructors.push(handle.pointeeType.smartPointerType.rawDestructor); + destructors.push(handle.type.smartPointerType.rawDestructor); destructors.push(ptr); } return ptr; @@ -582,7 +590,7 @@ RegisteredPointer.prototype.fromWireType = function(ptr) { RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) { var type = null; if (this.isPolymorphic) { - if (this.rawGetPointee) { + if (this.rawGetPointee) { // todo: did you mean isSmartPtr? type = ___getDynamicPointerType(this.rawGetPointee(ptr)); } else { type = ___getDynamicPointerType(ptr); @@ -594,8 +602,8 @@ RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) { RegisteredPointer.prototype.getDynamicDowncastType = function(ptr) { var downcastType = null; var type = this.getDynamicRawPointerType(ptr); - if (type && type !== this.pointeeType.rawType) { - var derivation = Module.__getDerivationPath(type, this.pointeeType.rawType); + if (type && type !== this.type.rawType) { + var derivation = Module.__getDerivationPath(type, this.type.rawType); for (var i = 0; i < derivation.size(); i++) { downcastType = typeRegistry[derivation.at(i)]; if (downcastType) { @@ -615,7 +623,7 @@ RegisteredPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // ptr is } var toType = this.getDynamicDowncastType(ptr); if (toType) { - var fromType = this.pointeeType; + var fromType = this.type; if (this.isSmartPointer) { handle = toType.smartPointerType.fromWireType(ptr); } else { @@ -641,12 +649,16 @@ function __embind_register_smart_ptr( rawConstructor = FUNCTION_TABLE[rawConstructor]; rawDestructor = FUNCTION_TABLE[rawDestructor]; rawGetPointee = FUNCTION_TABLE[rawGetPointee]; - + + if (name == "") { + name = pointeeType.name + "Ptr"; + } + var Handle = createNamedFunction(name, function(ptr) { this.count = {value: 1}; this.smartPointer = ptr; // std::shared_ptr* this.ptr = rawGetPointee(ptr); // T* - this.pointeeType = pointeeType; + this.type = pointeeType; }); // TODO: test for SmartPtr.prototype.constructor property? @@ -680,7 +692,7 @@ function __embind_register_smart_ptr( this.ptr = undefined; }; var registeredPointer = new RegisteredPointer(Handle, pointeeType.isPolymorphic, true, rawGetPointee, rawConstructor, rawDestructor); - registeredPointer.pointeeType = pointeeType; + registeredPointer.type = pointeeType; pointeeType.smartPointerType = registerType(rawType, name, registeredPointer); } @@ -828,11 +840,13 @@ function __embind_register_class( h.count = {value: 1, ptr: ptr }; h.ptr = ptr; - h.pointeeType = type; // set below + h.type = type; // set below for(var prop in Handle.prototype) { - var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop); - Object.defineProperty(h, prop, dp); + if (Handle.prototype.hasOwnProperty(prop)) { + var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop); + Object.defineProperty(h, prop, dp); + } } return h; @@ -875,15 +889,15 @@ function __embind_register_class( // todo: clean this up! var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); var type = registerType(rawType, name, registeredClass); - registeredClass.pointeeType = type; + registeredClass.type = type; - var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); + registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); registerType(rawPointerType, name + '*', registeredClass); - registeredClass.pointeeType = type; + registeredClass.type = type; // todo: implement const pointers (no modification Javascript side) - var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); + registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); registerType(rawConstPointerType, name + ' const*', registeredClass); - registeredClass.pointeeType = type; + registeredClass.type = type; type.constructor = createNamedFunction(type.name, function() { var body = type.constructor.body; @@ -965,26 +979,32 @@ function __embind_register_class_method( rv = argTypes[0].fromWireType(rv); } runDestructors(destructors); + for (i = 1; i < argCount; i++) { + refreshSmartPointee(arguments[i-1]); + } return rv; }; classType.Handle.memberType[methodName] = "method"; }); } -// todo: cast methods should require binding of their target types -function __embind_register_raw_cast_method( +function __embind_register_cast_method( rawClassType, isPolymorphic, methodName, - rawReturnType, - rawInvoker + rawRawReturnType, + rawSharedReturnType, + rawRawCaster, + rawSharedCaster ) { requestDeferredRegistration(function() { var classType = requireRegisteredType(rawClassType, 'class'); methodName = Pointer_stringify(methodName); var humanName = classType.name + '.' + methodName; - var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value'); - rawInvoker = FUNCTION_TABLE[rawInvoker]; + var rawReturnType = requireRegisteredType(rawRawReturnType, 'method ' + humanName + ' return value'); + var sharedReturnType = requireRegisteredType(rawSharedReturnType, 'method ' + humanName + ' shared pointer return value'); + var rawCaster = FUNCTION_TABLE[rawRawCaster]; + var sharedCaster = FUNCTION_TABLE[rawSharedCaster]; classType.Handle.prototype[methodName] = function() { if (!this.ptr) { throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); @@ -995,11 +1015,11 @@ function __embind_register_raw_cast_method( if (isPolymorphic) { // todo: this is all only to validate the cast -- cache the result var runtimeType = ___getDynamicPointerType(this.ptr); - var derivation = Module.__getDerivationPath(rawReturnType, runtimeType); // downcast is valid + var derivation = Module.__getDerivationPath(rawRawReturnType, runtimeType); // downcast is valid var size = derivation.size(); derivation.delete(); if (size === 0) { - derivation = Module.__getDerivationPath(runtimeType, rawReturnType); // upcast is valid + derivation = Module.__getDerivationPath(runtimeType, rawRawReturnType); // upcast is valid size = derivation.size(); derivation.delete(); if (size === 0) { @@ -1007,60 +1027,25 @@ function __embind_register_raw_cast_method( } } } - var args = new Array(1); - args[0] = this.ptr; - var ptr = rawInvoker.apply(null, args); - var rv = returnType.fromWireType(ptr); - rv.count = this.count; - this.count.value ++; - return rv; - }; - }); -} - -// todo: cast methods should not be passed from the smart ptr to the contained object!! -function __embind_register_smart_cast_method( - rawPointerType, - rawReturnType, - returnPointeeType, - isPolymorphic, - methodName, - rawInvoker -) { - requestDeferredRegistration(function() { - var pointerType = requireRegisteredType(rawPointerType, 'smart pointer class'); - methodName = Pointer_stringify(methodName); - var humanName = pointerType.name + '.' + methodName; - var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value'); - rawInvoker = FUNCTION_TABLE[rawInvoker]; - pointerType.Handle.prototype[methodName] = function() { - if (!this.ptr) { - throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); - } - if (arguments.length !== 0) { - throw new BindingError('emscripten binding method ' + humanName + ' called with arguments, none expected'); - } - if (isPolymorphic) { - // todo: just validating the cast -- cache the result - var runtimeType = ___getDynamicPointerType(this.ptr); - var derivation = Module.__getDerivationPath(returnPointeeType, runtimeType); // downcast is valid - var size = derivation.size(); - derivation.delete(); - if (size === 0) { - derivation = Module.__getDerivationPath(runtimeType, returnPointeeType); // upcast is valid - size = derivation.size(); - derivation.delete(); - if (size === 0) { - throw new CastError("Pointer conversion is not available"); - } - } + var args; + var ptr; + var rv; + if (this.smartPointer) { + args = new Array(2); + ptr = _malloc(8); + args[0] = ptr; + args[1] = this.smartPointer; + sharedCaster.apply(null,args); // need a smart pointer raw invoker + rv = sharedReturnType.fromWireType(ptr); + } else { + args = new Array(1); + args[0] = this.ptr; + ptr = rawCaster.apply(null, args); + rv = rawReturnType.fromWireType(ptr); + rv.count = this.count; + this.count.value ++; } - var args = new Array(2); - var ptr = _malloc(8); - args[0] = ptr; - args[1] = this.smartPointer; - rawInvoker.apply(null,args); - return returnType.fromWireType(ptr); + return rv; }; }); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index ce9053f26ceb8..a3789cabc171a 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -124,20 +124,14 @@ namespace emscripten { size_t memberFunctionSize, void* memberFunction); - void _embind_register_raw_cast_method( + void _embind_register_cast_method( TYPEID classType, bool isPolymorphic, const char* methodName, TYPEID returnType, - GenericFunction invoker); - - void _embind_register_smart_cast_method( - TYPEID pointerType, - TYPEID returnType, - TYPEID returnPointeeType, - bool isPolymorphic, - const char* methodName, - GenericFunction invoker); + TYPEID sharedReturnType, + GenericFunction rawInvoker, + GenericFunction sharedInvoker); void _embind_register_class_field( TYPEID classType, @@ -274,7 +268,6 @@ namespace emscripten { extern "C" { int __getDynamicPointerType(int p); - int __dynamicPointerCast(int p, int to); } template @@ -283,14 +276,14 @@ namespace emscripten { }; template - struct performShared { + struct performSharedCast { static std::shared_ptr cast(std::shared_ptr from) { return std::dynamic_pointer_cast(from); }; }; template - struct performShared { + struct performSharedCast { static std::shared_ptr cast(std::shared_ptr from) { return std::shared_ptr(from, static_cast(from.get())); }; @@ -300,7 +293,7 @@ namespace emscripten { void function(const char* name, ReturnType (fn)(Args...), Policies...) { using namespace internal; - registerStandardTypes(); + registerStandardTypes(); // todo: remove all typename WithPolicies::template ArgTypeList args; _embind_register_function( @@ -625,21 +618,12 @@ namespace emscripten { reinterpret_cast(&get_pointee)); } + }; - template - register_smart_ptr& cast(const char* methodName) { - using namespace internal; - typedef typename ReturnType::element_type ReturnPointeeType; - typedef typename PointerType::element_type PointeeType; - _embind_register_smart_cast_method( - TypeID::get(), - TypeID::get(), - TypeID::get(), - std::is_polymorphic::value, - methodName, - reinterpret_cast(&performShared::value>::cast)); - return *this; - } + template + class shared_ptr: public register_smart_ptr> { + public: + shared_ptr(const char* name): register_smart_ptr>(name) {}; }; //////////////////////////////////////////////////////////////////////////////// @@ -777,13 +761,31 @@ namespace emscripten { template class_& cast(const char* methodName) { using namespace internal; + //typedef typename std::shared_ptr PointerType; + typedef typename std::shared_ptr SharedReturnType; - _embind_register_raw_cast_method( + _embind_register_cast_method( TypeID::get(), std::is_polymorphic::value, methodName, TypeID::get(), - reinterpret_cast(&performRawStaticCast)); + TypeID::get(), + reinterpret_cast(&performRawStaticCast), + reinterpret_cast(&performSharedCast::value>::cast)); + return *this; + } + + class_& shared_ptr(const char* ptrName = "") { + using namespace internal; + typedef typename std::shared_ptr PointerType; + + _embind_register_smart_ptr( + TypeID::get(), + TypeID::get(), + ptrName, + reinterpret_cast(&raw_smart_pointer_constructor), + reinterpret_cast(&raw_destructor), + reinterpret_cast(&get_pointee)); return *this; } }; diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 5e82bb7eb4fba..bc79876fe8348 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -101,7 +101,7 @@ namespace emscripten { // __getDerivationPath returns an array of type_info pointers describing the derivation chain starting with // the derived type and proceeding toward (and ending with) the base type. Types are only included if they // appear on all possible derivation paths. - std::vector __getDerivationPath(int dv, const int bs) { + std::vector __getDerivationPath(int dv, const int bs) { // todo: use emval array to pass return value?? std::vector> paths; const std::type_info* dv1 = (std::type_info*)dv; @@ -176,27 +176,11 @@ namespace emscripten { // __getDynamicPointerType returns (for polymorphic types only!) the type of the instance actually // pointed to. - int EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(int p) { + int EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(int p) { // use size_t void** vtable = *(void***)p; return (int)static_cast(vtable[-1]); } - // Calls to __dynamic_cast are generated by the compiler to implement dynamic_cast<>() -- its prototype is - // not available through any header file. It is called directly here because it allows run-time - // specification of the target pointer type (which can only be specified at compile time when using - // dynamic_cast<>(). - void* __dynamic_cast(void*, const std::type_info*, const std::type_info*, int); - - // __dynamicPointerCast performs a C++ dynamic_cast<>() operation, but allowing run-time specification of - // the from and to pointer types. - int EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(int p, int to) { - int ret = (int)__staticPointerCast((void *)p, __getDynamicPointerType(p), to); - if (ret < 0) { - return 0; - } - return ret; - } - const char* EMSCRIPTEN_KEEPALIVE __typeName(int p) { const std::type_info* ti = (const std::type_info*)p; size_t nameLen = std::min(strlen(ti->name()), (unsigned int)1024); From 7c93292f7dc7cd0e445c0bf7d76c1dc4d9f49453 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Mon, 28 Jan 2013 09:15:36 -0800 Subject: [PATCH 239/544] fix lint warning --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 7210dbc14f27b..55866231a8e92 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -650,7 +650,7 @@ function __embind_register_smart_ptr( rawDestructor = FUNCTION_TABLE[rawDestructor]; rawGetPointee = FUNCTION_TABLE[rawGetPointee]; - if (name == "") { + if (name === "") { name = pointeeType.name + "Ptr"; } From ec5bc68515751aae5e90eb9a55af1908b2cb8329 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Mon, 28 Jan 2013 14:03:17 -0800 Subject: [PATCH 240/544] Revert "fix lint warning" This reverts commit 4a9e281a7d42595354c775ee1a79fdb9c3ec6354. --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 55866231a8e92..7210dbc14f27b 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -650,7 +650,7 @@ function __embind_register_smart_ptr( rawDestructor = FUNCTION_TABLE[rawDestructor]; rawGetPointee = FUNCTION_TABLE[rawGetPointee]; - if (name === "") { + if (name == "") { name = pointeeType.name + "Ptr"; } From 40ad51a5c81881ae0ddb5c36f19e7d362107ccc6 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Mon, 28 Jan 2013 14:03:27 -0800 Subject: [PATCH 241/544] Revert "register_smart_ptr changed to .shared_ptr (mod to class definition) -- shared_ptr (outside of class definition) is still allowed" This reverts commit c38bb38e9d6393dfacb4afb0e9ba80ce42aee965. --- src/embind/embind.js | 155 +++++++++++++++++-------------- system/include/emscripten/bind.h | 62 ++++++------- system/lib/embind/bind.cpp | 20 +++- 3 files changed, 133 insertions(+), 104 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 7210dbc14f27b..d8a4a44024dcd 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -5,6 +5,7 @@ /*global Pointer_stringify, writeStringToMemory*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ /*global ___getDynamicPointerType: false*/ +/*global ___dynamicPointerCast: false*/ /*global ___typeName:false*/ /*global ___staticPointerCast: false*/ @@ -307,12 +308,6 @@ function runDestructors(destructors) { } } -function refreshSmartPointee(handle) { - if (handle && handle.smartPointer) { - handle.ptr = handle.type.smartPointerType.getPointee(handle.smartPointer); - } -} - function makeInvoker(name, argCount, argTypes, invoker, fn) { if (!FUNCTION_TABLE[fn]) { throw new BindingError('function '+name+' is not defined'); @@ -334,9 +329,6 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { rv = argTypes[0].fromWireType(rv); } runDestructors(destructors); - for (i = 1; i < argCount; i++) { - refreshSmartPointee(arguments[i-1]); - } return rv; }; } @@ -545,21 +537,21 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { if (!handle) { return null; } - if (handle.type.isPolymorphic) { - fromRawType = handle.type.getDynamicRawPointerType(handle.ptr); + if (handle.pointeeType.isPolymorphic) { + fromRawType = handle.pointeeType.getDynamicRawPointerType(handle.ptr); } else { - fromRawType = handle.type.rawType; + fromRawType = handle.pointeeType.rawType; } - if (fromRawType === this.type.rawType) { + if (fromRawType === this.pointeeType.rawType) { return this.isSmartPointer ? handle.smartPointer : handle.ptr; } - var ptr = staticPointerCast(handle.ptr, fromRawType, this.type.rawType); + var ptr = staticPointerCast(handle.ptr, fromRawType, this.pointeeType.rawType); if (this.isSmartPointer) { // todo: if ptr == handle.ptr, there's no need to allocate a new smartPtr! - var smartPtr = _malloc(16); // todo: can we get C++ to tell us the size of the pointer? - handle.type.smartPointerType.rawConstructor(smartPtr, ptr, handle.smartPointer); + var smartPtr = _malloc(16); + handle.pointeeType.smartPointerType.rawConstructor(smartPtr, ptr, handle.smartPointer); ptr = smartPtr; - destructors.push(handle.type.smartPointerType.rawDestructor); + destructors.push(handle.pointeeType.smartPointerType.rawDestructor); destructors.push(ptr); } return ptr; @@ -590,7 +582,7 @@ RegisteredPointer.prototype.fromWireType = function(ptr) { RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) { var type = null; if (this.isPolymorphic) { - if (this.rawGetPointee) { // todo: did you mean isSmartPtr? + if (this.rawGetPointee) { type = ___getDynamicPointerType(this.rawGetPointee(ptr)); } else { type = ___getDynamicPointerType(ptr); @@ -602,8 +594,8 @@ RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) { RegisteredPointer.prototype.getDynamicDowncastType = function(ptr) { var downcastType = null; var type = this.getDynamicRawPointerType(ptr); - if (type && type !== this.type.rawType) { - var derivation = Module.__getDerivationPath(type, this.type.rawType); + if (type && type !== this.pointeeType.rawType) { + var derivation = Module.__getDerivationPath(type, this.pointeeType.rawType); for (var i = 0; i < derivation.size(); i++) { downcastType = typeRegistry[derivation.at(i)]; if (downcastType) { @@ -623,7 +615,7 @@ RegisteredPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // ptr is } var toType = this.getDynamicDowncastType(ptr); if (toType) { - var fromType = this.type; + var fromType = this.pointeeType; if (this.isSmartPointer) { handle = toType.smartPointerType.fromWireType(ptr); } else { @@ -649,16 +641,12 @@ function __embind_register_smart_ptr( rawConstructor = FUNCTION_TABLE[rawConstructor]; rawDestructor = FUNCTION_TABLE[rawDestructor]; rawGetPointee = FUNCTION_TABLE[rawGetPointee]; - - if (name == "") { - name = pointeeType.name + "Ptr"; - } - + var Handle = createNamedFunction(name, function(ptr) { this.count = {value: 1}; this.smartPointer = ptr; // std::shared_ptr* this.ptr = rawGetPointee(ptr); // T* - this.type = pointeeType; + this.pointeeType = pointeeType; }); // TODO: test for SmartPtr.prototype.constructor property? @@ -692,7 +680,7 @@ function __embind_register_smart_ptr( this.ptr = undefined; }; var registeredPointer = new RegisteredPointer(Handle, pointeeType.isPolymorphic, true, rawGetPointee, rawConstructor, rawDestructor); - registeredPointer.type = pointeeType; + registeredPointer.pointeeType = pointeeType; pointeeType.smartPointerType = registerType(rawType, name, registeredPointer); } @@ -840,13 +828,11 @@ function __embind_register_class( h.count = {value: 1, ptr: ptr }; h.ptr = ptr; - h.type = type; // set below + h.pointeeType = type; // set below for(var prop in Handle.prototype) { - if (Handle.prototype.hasOwnProperty(prop)) { - var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop); - Object.defineProperty(h, prop, dp); - } + var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop); + Object.defineProperty(h, prop, dp); } return h; @@ -889,15 +875,15 @@ function __embind_register_class( // todo: clean this up! var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); var type = registerType(rawType, name, registeredClass); - registeredClass.type = type; + registeredClass.pointeeType = type; - registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); + var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); registerType(rawPointerType, name + '*', registeredClass); - registeredClass.type = type; + registeredClass.pointeeType = type; // todo: implement const pointers (no modification Javascript side) - registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); + var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); registerType(rawConstPointerType, name + ' const*', registeredClass); - registeredClass.type = type; + registeredClass.pointeeType = type; type.constructor = createNamedFunction(type.name, function() { var body = type.constructor.body; @@ -979,32 +965,26 @@ function __embind_register_class_method( rv = argTypes[0].fromWireType(rv); } runDestructors(destructors); - for (i = 1; i < argCount; i++) { - refreshSmartPointee(arguments[i-1]); - } return rv; }; classType.Handle.memberType[methodName] = "method"; }); } -function __embind_register_cast_method( +// todo: cast methods should require binding of their target types +function __embind_register_raw_cast_method( rawClassType, isPolymorphic, methodName, - rawRawReturnType, - rawSharedReturnType, - rawRawCaster, - rawSharedCaster + rawReturnType, + rawInvoker ) { requestDeferredRegistration(function() { var classType = requireRegisteredType(rawClassType, 'class'); methodName = Pointer_stringify(methodName); var humanName = classType.name + '.' + methodName; - var rawReturnType = requireRegisteredType(rawRawReturnType, 'method ' + humanName + ' return value'); - var sharedReturnType = requireRegisteredType(rawSharedReturnType, 'method ' + humanName + ' shared pointer return value'); - var rawCaster = FUNCTION_TABLE[rawRawCaster]; - var sharedCaster = FUNCTION_TABLE[rawSharedCaster]; + var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value'); + rawInvoker = FUNCTION_TABLE[rawInvoker]; classType.Handle.prototype[methodName] = function() { if (!this.ptr) { throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); @@ -1015,11 +995,11 @@ function __embind_register_cast_method( if (isPolymorphic) { // todo: this is all only to validate the cast -- cache the result var runtimeType = ___getDynamicPointerType(this.ptr); - var derivation = Module.__getDerivationPath(rawRawReturnType, runtimeType); // downcast is valid + var derivation = Module.__getDerivationPath(rawReturnType, runtimeType); // downcast is valid var size = derivation.size(); derivation.delete(); if (size === 0) { - derivation = Module.__getDerivationPath(runtimeType, rawRawReturnType); // upcast is valid + derivation = Module.__getDerivationPath(runtimeType, rawReturnType); // upcast is valid size = derivation.size(); derivation.delete(); if (size === 0) { @@ -1027,29 +1007,64 @@ function __embind_register_cast_method( } } } - var args; - var ptr; - var rv; - if (this.smartPointer) { - args = new Array(2); - ptr = _malloc(8); - args[0] = ptr; - args[1] = this.smartPointer; - sharedCaster.apply(null,args); // need a smart pointer raw invoker - rv = sharedReturnType.fromWireType(ptr); - } else { - args = new Array(1); - args[0] = this.ptr; - ptr = rawCaster.apply(null, args); - rv = rawReturnType.fromWireType(ptr); - rv.count = this.count; - this.count.value ++; - } + var args = new Array(1); + args[0] = this.ptr; + var ptr = rawInvoker.apply(null, args); + var rv = returnType.fromWireType(ptr); + rv.count = this.count; + this.count.value ++; return rv; }; }); } +// todo: cast methods should not be passed from the smart ptr to the contained object!! +function __embind_register_smart_cast_method( + rawPointerType, + rawReturnType, + returnPointeeType, + isPolymorphic, + methodName, + rawInvoker +) { + requestDeferredRegistration(function() { + var pointerType = requireRegisteredType(rawPointerType, 'smart pointer class'); + methodName = Pointer_stringify(methodName); + var humanName = pointerType.name + '.' + methodName; + var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value'); + rawInvoker = FUNCTION_TABLE[rawInvoker]; + pointerType.Handle.prototype[methodName] = function() { + if (!this.ptr) { + throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } + if (arguments.length !== 0) { + throw new BindingError('emscripten binding method ' + humanName + ' called with arguments, none expected'); + } + if (isPolymorphic) { + // todo: just validating the cast -- cache the result + var runtimeType = ___getDynamicPointerType(this.ptr); + var derivation = Module.__getDerivationPath(returnPointeeType, runtimeType); // downcast is valid + var size = derivation.size(); + derivation.delete(); + if (size === 0) { + derivation = Module.__getDerivationPath(runtimeType, returnPointeeType); // upcast is valid + size = derivation.size(); + derivation.delete(); + if (size === 0) { + throw new CastError("Pointer conversion is not available"); + } + } + } + var args = new Array(2); + var ptr = _malloc(8); + args[0] = ptr; + args[1] = this.smartPointer; + rawInvoker.apply(null,args); + return returnType.fromWireType(ptr); + }; + }); +} + function __embind_register_class_classmethod( rawClassType, methodName, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index a3789cabc171a..ce9053f26ceb8 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -124,14 +124,20 @@ namespace emscripten { size_t memberFunctionSize, void* memberFunction); - void _embind_register_cast_method( + void _embind_register_raw_cast_method( TYPEID classType, bool isPolymorphic, const char* methodName, TYPEID returnType, - TYPEID sharedReturnType, - GenericFunction rawInvoker, - GenericFunction sharedInvoker); + GenericFunction invoker); + + void _embind_register_smart_cast_method( + TYPEID pointerType, + TYPEID returnType, + TYPEID returnPointeeType, + bool isPolymorphic, + const char* methodName, + GenericFunction invoker); void _embind_register_class_field( TYPEID classType, @@ -268,6 +274,7 @@ namespace emscripten { extern "C" { int __getDynamicPointerType(int p); + int __dynamicPointerCast(int p, int to); } template @@ -276,14 +283,14 @@ namespace emscripten { }; template - struct performSharedCast { + struct performShared { static std::shared_ptr cast(std::shared_ptr from) { return std::dynamic_pointer_cast(from); }; }; template - struct performSharedCast { + struct performShared { static std::shared_ptr cast(std::shared_ptr from) { return std::shared_ptr(from, static_cast(from.get())); }; @@ -293,7 +300,7 @@ namespace emscripten { void function(const char* name, ReturnType (fn)(Args...), Policies...) { using namespace internal; - registerStandardTypes(); // todo: remove all + registerStandardTypes(); typename WithPolicies::template ArgTypeList args; _embind_register_function( @@ -618,12 +625,21 @@ namespace emscripten { reinterpret_cast(&get_pointee)); } - }; - template - class shared_ptr: public register_smart_ptr> { - public: - shared_ptr(const char* name): register_smart_ptr>(name) {}; + template + register_smart_ptr& cast(const char* methodName) { + using namespace internal; + typedef typename ReturnType::element_type ReturnPointeeType; + typedef typename PointerType::element_type PointeeType; + _embind_register_smart_cast_method( + TypeID::get(), + TypeID::get(), + TypeID::get(), + std::is_polymorphic::value, + methodName, + reinterpret_cast(&performShared::value>::cast)); + return *this; + } }; //////////////////////////////////////////////////////////////////////////////// @@ -761,31 +777,13 @@ namespace emscripten { template class_& cast(const char* methodName) { using namespace internal; - //typedef typename std::shared_ptr PointerType; - typedef typename std::shared_ptr SharedReturnType; - _embind_register_cast_method( + _embind_register_raw_cast_method( TypeID::get(), std::is_polymorphic::value, methodName, TypeID::get(), - TypeID::get(), - reinterpret_cast(&performRawStaticCast), - reinterpret_cast(&performSharedCast::value>::cast)); - return *this; - } - - class_& shared_ptr(const char* ptrName = "") { - using namespace internal; - typedef typename std::shared_ptr PointerType; - - _embind_register_smart_ptr( - TypeID::get(), - TypeID::get(), - ptrName, - reinterpret_cast(&raw_smart_pointer_constructor), - reinterpret_cast(&raw_destructor), - reinterpret_cast(&get_pointee)); + reinterpret_cast(&performRawStaticCast)); return *this; } }; diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index bc79876fe8348..5e82bb7eb4fba 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -101,7 +101,7 @@ namespace emscripten { // __getDerivationPath returns an array of type_info pointers describing the derivation chain starting with // the derived type and proceeding toward (and ending with) the base type. Types are only included if they // appear on all possible derivation paths. - std::vector __getDerivationPath(int dv, const int bs) { // todo: use emval array to pass return value?? + std::vector __getDerivationPath(int dv, const int bs) { std::vector> paths; const std::type_info* dv1 = (std::type_info*)dv; @@ -176,11 +176,27 @@ namespace emscripten { // __getDynamicPointerType returns (for polymorphic types only!) the type of the instance actually // pointed to. - int EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(int p) { // use size_t + int EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(int p) { void** vtable = *(void***)p; return (int)static_cast(vtable[-1]); } + // Calls to __dynamic_cast are generated by the compiler to implement dynamic_cast<>() -- its prototype is + // not available through any header file. It is called directly here because it allows run-time + // specification of the target pointer type (which can only be specified at compile time when using + // dynamic_cast<>(). + void* __dynamic_cast(void*, const std::type_info*, const std::type_info*, int); + + // __dynamicPointerCast performs a C++ dynamic_cast<>() operation, but allowing run-time specification of + // the from and to pointer types. + int EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(int p, int to) { + int ret = (int)__staticPointerCast((void *)p, __getDynamicPointerType(p), to); + if (ret < 0) { + return 0; + } + return ret; + } + const char* EMSCRIPTEN_KEEPALIVE __typeName(int p) { const std::type_info* ti = (const std::type_info*)p; size_t nameLen = std::min(strlen(ti->name()), (unsigned int)1024); From c42eb7377eb547237d670238d7062c86e9b08673 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Mon, 28 Jan 2013 15:21:59 -0800 Subject: [PATCH 242/544] Removed explicit cast capability from bindings. --- src/embind/embind.js | 95 -------------------------------- system/include/emscripten/bind.h | 63 --------------------- 2 files changed, 158 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index d8a4a44024dcd..75450735ccf10 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -5,7 +5,6 @@ /*global Pointer_stringify, writeStringToMemory*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ /*global ___getDynamicPointerType: false*/ -/*global ___dynamicPointerCast: false*/ /*global ___typeName:false*/ /*global ___staticPointerCast: false*/ @@ -971,100 +970,6 @@ function __embind_register_class_method( }); } -// todo: cast methods should require binding of their target types -function __embind_register_raw_cast_method( - rawClassType, - isPolymorphic, - methodName, - rawReturnType, - rawInvoker -) { - requestDeferredRegistration(function() { - var classType = requireRegisteredType(rawClassType, 'class'); - methodName = Pointer_stringify(methodName); - var humanName = classType.name + '.' + methodName; - var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value'); - rawInvoker = FUNCTION_TABLE[rawInvoker]; - classType.Handle.prototype[methodName] = function() { - if (!this.ptr) { - throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); - } - if (arguments.length !== 0) { - throw new BindingError('emscripten binding method ' + humanName + ' called with arguments, none expected'); - } - if (isPolymorphic) { - // todo: this is all only to validate the cast -- cache the result - var runtimeType = ___getDynamicPointerType(this.ptr); - var derivation = Module.__getDerivationPath(rawReturnType, runtimeType); // downcast is valid - var size = derivation.size(); - derivation.delete(); - if (size === 0) { - derivation = Module.__getDerivationPath(runtimeType, rawReturnType); // upcast is valid - size = derivation.size(); - derivation.delete(); - if (size === 0) { - throw new CastError("Pointer conversion is not available"); - } - } - } - var args = new Array(1); - args[0] = this.ptr; - var ptr = rawInvoker.apply(null, args); - var rv = returnType.fromWireType(ptr); - rv.count = this.count; - this.count.value ++; - return rv; - }; - }); -} - -// todo: cast methods should not be passed from the smart ptr to the contained object!! -function __embind_register_smart_cast_method( - rawPointerType, - rawReturnType, - returnPointeeType, - isPolymorphic, - methodName, - rawInvoker -) { - requestDeferredRegistration(function() { - var pointerType = requireRegisteredType(rawPointerType, 'smart pointer class'); - methodName = Pointer_stringify(methodName); - var humanName = pointerType.name + '.' + methodName; - var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value'); - rawInvoker = FUNCTION_TABLE[rawInvoker]; - pointerType.Handle.prototype[methodName] = function() { - if (!this.ptr) { - throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); - } - if (arguments.length !== 0) { - throw new BindingError('emscripten binding method ' + humanName + ' called with arguments, none expected'); - } - if (isPolymorphic) { - // todo: just validating the cast -- cache the result - var runtimeType = ___getDynamicPointerType(this.ptr); - var derivation = Module.__getDerivationPath(returnPointeeType, runtimeType); // downcast is valid - var size = derivation.size(); - derivation.delete(); - if (size === 0) { - derivation = Module.__getDerivationPath(runtimeType, returnPointeeType); // upcast is valid - size = derivation.size(); - derivation.delete(); - if (size === 0) { - throw new CastError("Pointer conversion is not available"); - } - } - } - var args = new Array(2); - var ptr = _malloc(8); - args[0] = ptr; - args[1] = this.smartPointer; - rawInvoker.apply(null,args); - return returnType.fromWireType(ptr); - }; - }); -} - function __embind_register_class_classmethod( rawClassType, methodName, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index ce9053f26ceb8..70a5b60c8781e 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -124,21 +124,6 @@ namespace emscripten { size_t memberFunctionSize, void* memberFunction); - void _embind_register_raw_cast_method( - TYPEID classType, - bool isPolymorphic, - const char* methodName, - TYPEID returnType, - GenericFunction invoker); - - void _embind_register_smart_cast_method( - TYPEID pointerType, - TYPEID returnType, - TYPEID returnPointeeType, - bool isPolymorphic, - const char* methodName, - GenericFunction invoker); - void _embind_register_class_field( TYPEID classType, const char* fieldName, @@ -274,28 +259,8 @@ namespace emscripten { extern "C" { int __getDynamicPointerType(int p); - int __dynamicPointerCast(int p, int to); } - template - ToType& performRawStaticCast(FromType& from) { - return *static_cast(&from); - }; - - template - struct performShared { - static std::shared_ptr cast(std::shared_ptr from) { - return std::dynamic_pointer_cast(from); - }; - }; - - template - struct performShared { - static std::shared_ptr cast(std::shared_ptr from) { - return std::shared_ptr(from, static_cast(from.get())); - }; - }; - template void function(const char* name, ReturnType (fn)(Args...), Policies...) { using namespace internal; @@ -625,21 +590,6 @@ namespace emscripten { reinterpret_cast(&get_pointee)); } - - template - register_smart_ptr& cast(const char* methodName) { - using namespace internal; - typedef typename ReturnType::element_type ReturnPointeeType; - typedef typename PointerType::element_type PointeeType; - _embind_register_smart_cast_method( - TypeID::get(), - TypeID::get(), - TypeID::get(), - std::is_polymorphic::value, - methodName, - reinterpret_cast(&performShared::value>::cast)); - return *this; - } }; //////////////////////////////////////////////////////////////////////////////// @@ -773,19 +723,6 @@ namespace emscripten { reinterpret_cast(&internal::ArrayAccessSetInvoker::invoke)); return *this; } - - template - class_& cast(const char* methodName) { - using namespace internal; - - _embind_register_raw_cast_method( - TypeID::get(), - std::is_polymorphic::value, - methodName, - TypeID::get(), - reinterpret_cast(&performRawStaticCast)); - return *this; - } }; //////////////////////////////////////////////////////////////////////////////// From 79a7db6c2f1fee9e5822adbcbf102bea7aeb78ab Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Wed, 30 Jan 2013 14:58:27 -0800 Subject: [PATCH 243/544] - Classes now inherit elements from grandparent (etc.) as well as parent classes - Removed dead code --- src/embind/embind.js | 123 +------------------------------------------ 1 file changed, 2 insertions(+), 121 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 75450735ccf10..f875aa9ad0481 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -73,9 +73,11 @@ function createInheritedFunctionOrProperty(name, type, nameInBaseClass, baseClas get: upcastingWrapper(baseClassDescriptor.get), set: upcastingWrapper(baseClassDescriptor.set) }); + type.Handle.memberType[name] = 'field'; } else if (baseClassPrototype.constructor.memberType[nameInBaseClass] === 'method') { var baseClassMethod = baseClassPrototype[nameInBaseClass]; type.Handle.prototype[name] = createNamedFunction(name, upcastingWrapper(baseClassMethod)); + type.Handle.memberType[name] = 'method'; } } @@ -683,127 +685,6 @@ function __embind_register_smart_ptr( pointeeType.smartPointerType = registerType(rawType, name, registeredPointer); } -function RegisteredRawPointer(isPolymorphic, classType, Handle) { - this.isPolymorphic = isPolymorphic; - this.pointeeType = classType; - this.Handle = Handle; -} - -RegisteredRawPointer.prototype.toWireType = function(destructors, o) { - return o.ptr; -}; - -RegisteredRawPointer.prototype.fromWireType = function(ptr) { - return new this.Handle(ptr); -}; - -RegisteredRawPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { - if (this.isPolymorphic) { - var toRawType = ___getDynamicPointerType(ptr); - if (toRawType === null || toRawType === this.pointeeType.rawType) { - return new this.Handle(ptr); - } - var derivation = Module.__getDerivationPath(toRawType, this.pointeeType.rawType); - var candidateType = null; - for (var i = 0; i < derivation.size(); i++) { - candidateType = typeRegistry[derivation.at(i)]; - if (candidateType) { - break; - } - } - derivation.delete(); - if (candidateType === null) { - return new this.Handle(ptr); - } - var handle = candidateType.fromWireType(ptr); - handle.ptr = ___staticPointerCast(handle.ptr, this.pointeeType.rawType, candidateType.rawType); - // todo: can come back -1 or -2!! Throw appropriate exception - return handle; - } else { - return new this.Handle(ptr); - } -}; - -function RegisteredClassInstance(constructor, Handle) { - this.constructor = constructor; - this.Handle = Handle; -} - -function __embind_register_vector( - vectorType, - elementType, - name, - constructor, - destructor, - length, - getter, - setter -) { - name = Pointer_stringify(name); - elementType = requireRegisteredType(elementType, 'vector ' + name); - - constructor = FUNCTION_TABLE[constructor]; - destructor = FUNCTION_TABLE[destructor]; - length = FUNCTION_TABLE[length]; - getter = FUNCTION_TABLE[getter]; - setter = FUNCTION_TABLE[setter]; - - registerType(vectorType, name, { - name: name, - fromWireType: function(ptr) { - var arr = []; - Object.defineProperty(arr, 'delete', { - writable: false, - enumerable: false, - configurable: false, - value: function() { - var needsToBeDeleted = elementType.hasOwnProperty('Handle'); - for (var i = 0; i < arr.length; i++) { - if (needsToBeDeleted) { - arr[i].delete(); - } - } - } - }); - - var n = length(ptr); - for (var i = 0; i < n; i++) { - var v = elementType.fromWireType(getter(ptr, i)); - arr.push(v); - } - - destructor(ptr); - return arr; - }, - toWireType: function(destructors, o) { - var vec = constructor(); - for (var val in o) { - setter(vec, elementType.toWireType(destructors, o[val])); - } - runDestructors(destructors); - - destructors.push(destructor); - destructors.push(vec); - return vec; - } - }); -} - -RegisteredClassInstance.prototype.toWireType = function(destructors, o) { - return o.ptr; -}; - -RegisteredClassInstance.prototype.fromWireType = function(ptr) { - return new this.Handle(ptr); -}; - -function RegisteredRawConstPointer() { -} - -RegisteredRawConstPointer.prototype.toWireType = function(destructors, o) { - return o.ptr; -}; - // TODO: null pointers are always zero (not a Handle) in Javascript function __embind_register_class( rawType, From 5b3d12c90558f0472c374349c5a4cdce474832a4 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Thu, 31 Jan 2013 09:42:34 -0800 Subject: [PATCH 244/544] Can now reference base classes through multiple levels of inheritance if one or more intermediate classes are not bound. Warning: we know nothing about the members of the unbound classes, so you might end up inheriting the bound base class's member when a C++ routine would inherit the identically named member from the unbound class. --- src/embind/embind.js | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index f875aa9ad0481..21a5dc46e8180 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -81,24 +81,35 @@ function createInheritedFunctionOrProperty(name, type, nameInBaseClass, baseClas } } +function collectRegisteredBaseClasses(rawType) { + var rawBaseTypes = Module.__getBaseClasses(rawType); + var baseTypes = []; + for (var i = 0; i < rawBaseTypes.size(); i++) { + var baseType = typeRegistry[rawBaseTypes.at(i)]; + if (baseType) { + baseTypes.push(baseType); + } else { + baseTypes = baseTypes.concat(collectRegisteredBaseClasses(rawBaseTypes.at(i))); + } + } + return baseTypes; +} + function resolveType(type) { if (!type.resolved) { var baseClassType, name, baseProto; var inheritedNames = {}; - var rawBaseClassTypes = Module.__getBaseClasses(type.rawType); - for (var i = 0; i < rawBaseClassTypes.size(); i++) { - var rawBaseClassType = rawBaseClassTypes.at(i); - baseClassType = typeRegistry[rawBaseClassType]; - if (baseClassType) { - resolveType(baseClassType); - baseProto = baseClassType.Handle.prototype; - for (name in baseProto) { - if (baseProto.hasOwnProperty(name) && baseClassType.Handle.memberType[name]) { - if (!(name in inheritedNames)) { - inheritedNames[name] = []; - } - inheritedNames[name].push(baseClassType); + var baseTypes = collectRegisteredBaseClasses(type.rawType); + for (var i = 0; i < baseTypes.length; i++) { + var baseType = baseTypes[i]; + resolveType(baseType); + baseProto = baseType.Handle.prototype; + for (name in baseProto) { + if (baseProto.hasOwnProperty(name) && baseType.Handle.memberType[name]) { + if (!(name in inheritedNames)) { + inheritedNames[name] = []; } + inheritedNames[name].push(baseType); } } } From 3b6ea45565ae17f32d77933b505a6ccfe7a8967f Mon Sep 17 00:00:00 2001 From: Andy Friesen Date: Thu, 31 Jan 2013 10:10:49 -0800 Subject: [PATCH 245/544] emscripten::internal::optional is now copyable. Fix JSInterface::JSInterface copy constructor to take a const& --- system/include/emscripten/bind.h | 31 +++++++++++++++++++++++-------- tests/embind/embind_test.cpp | 21 +++++++++++++++++++++ tests/embind/embind_test.js | 5 +++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 70a5b60c8781e..99b29e9cb62d0 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -817,13 +817,22 @@ namespace emscripten { } } - optional(const optional&) = delete; + optional(const optional& rhs) + : initialized(false) + { + *this = rhs; + } T& operator*() { assert(initialized); return *get(); } + const T& operator*() const { + assert(initialized); + return *get(); + } + explicit operator bool() const { return initialized; } @@ -837,12 +846,14 @@ namespace emscripten { return *this; } - optional& operator=(optional& o) { + optional& operator=(const optional& o) { if (initialized) { get()->~T(); } - new(get()) T(*o); - initialized = true; + if (o.initialized) { + new(get()) T(*o); + } + initialized = o.initialized; } private: @@ -850,6 +861,10 @@ namespace emscripten { return reinterpret_cast(&data); } + T const* get() const { + return reinterpret_cast(&data); + } + bool initialized; typename std::aligned_storage::type data; }; @@ -865,9 +880,9 @@ namespace emscripten { initialize(handle); } - JSInterface(JSInterface& obj) { - jsobj = obj.jsobj; - } + JSInterface(const JSInterface& obj) + : jsobj(obj.jsobj) + {} template ReturnType call(const char* name, Args... args) { @@ -875,7 +890,7 @@ namespace emscripten { return Caller::call(*jsobj, name, args...); } - static std::shared_ptr cloneToSharedPtr(JSInterface& i) { + static std::shared_ptr cloneToSharedPtr(const JSInterface& i) { return std::make_shared(i); } diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index dc052d1af9295..485cdfcd825d4 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -233,6 +233,24 @@ void emval_test_call_function(val v, int i, float f, TupleVector tv, StructVecto v(i, f, tv, sv); } +void optional_test_copy() { + using emscripten::internal::optional; + + optional foo = 22; + optional bar(foo); + + return bool(bar); +} + +void optional_test_copy2() { + using emscripten::internal::optional; + + optional foo; + optional bar(foo); + + return bool(bar); +} + EMSCRIPTEN_BINDINGS(([]() { function("mallinfo", &emval_test_mallinfo); @@ -337,4 +355,7 @@ EMSCRIPTEN_BINDINGS(([]() { function("emval_test_call_method3", &emval_test_call_method3); function("emval_test_call_function", &emval_test_call_function); + + function('optional_test_copy', &optional_test_copy); + function('optional_test_copy2', &optional_test_copy2); })); diff --git a/tests/embind/embind_test.js b/tests/embind/embind_test.js index 8c61553bcff83..9ba6a48f55405 100644 --- a/tests/embind/embind_test.js +++ b/tests/embind/embind_test.js @@ -390,4 +390,9 @@ module({ assert.deepEqual(['called'], calls); }, }); + + test('emscripten::internal::optional', function () { + assert.true(cm.optional_test_copy()); + assert.false(cm.optional_test_copy2()); + }); }); From 62b9f6a00f0eee036e7dfb4326a813c31d3ba41e Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Thu, 31 Jan 2013 12:24:56 -0800 Subject: [PATCH 246/544] header dependency fix --- system/include/emscripten/wire.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 1173034f7fbca..dc612e11daed9 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -8,6 +8,8 @@ // We'll call the on-the-wire type WireType. #include +#include +#include namespace emscripten { namespace internal { From 4fa56f796784b44a2b70aa69c5c9de012634ecd4 Mon Sep 17 00:00:00 2001 From: Todd Lee Date: Thu, 31 Jan 2013 18:31:56 -0800 Subject: [PATCH 247/544] move vecFromJSArray from bind.h to val.h to make it unnecessary to include bind.h --- system/include/emscripten/bind.h | 12 ------------ system/include/emscripten/val.h | 13 +++++++++++++ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 99b29e9cb62d0..7a87107f1c0dc 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -728,18 +728,6 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// // VECTORS //////////////////////////////////////////////////////////////////////////////// - template - std::vector vecFromJSArray(val v) { - auto l = v["length"].as(); - - std::vector rv; - for(unsigned i = 0; i < l; ++i) { - rv.push_back(v[i].as()); - } - - return rv; - }; - template class_> register_vector(const char* name) { using namespace std; diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 857a1bdf40c49..3952e008d6fef 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -2,6 +2,7 @@ #include // uintptr_t #include +#include namespace emscripten { namespace internal { @@ -237,4 +238,16 @@ namespace emscripten { } }; } + + template + std::vector vecFromJSArray(val v) { + auto l = v["length"].as(); + + std::vector rv; + for(unsigned i = 0; i < l; ++i) { + rv.push_back(v[i].as()); + } + + return rv; + }; } From 70aebcde9e97a9befdb7b912d0a3c1f3b5b9a003 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 1 Feb 2013 17:15:19 -0800 Subject: [PATCH 248/544] EMSCRIPTEN_KEEPALIVE has been removed --- system/lib/embind/bind.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 5e82bb7eb4fba..cbb4b183309f6 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -138,7 +138,7 @@ namespace emscripten { return derivationPath; } - void* EMSCRIPTEN_KEEPALIVE __staticPointerCast(void* p, int from, int to) { + void* __staticPointerCast(void* p, int from, int to) { std::vector> paths; int direction = 1; @@ -176,7 +176,7 @@ namespace emscripten { // __getDynamicPointerType returns (for polymorphic types only!) the type of the instance actually // pointed to. - int EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(int p) { + int __getDynamicPointerType(int p) { void** vtable = *(void***)p; return (int)static_cast(vtable[-1]); } @@ -189,7 +189,7 @@ namespace emscripten { // __dynamicPointerCast performs a C++ dynamic_cast<>() operation, but allowing run-time specification of // the from and to pointer types. - int EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(int p, int to) { + int __dynamicPointerCast(int p, int to) { int ret = (int)__staticPointerCast((void *)p, __getDynamicPointerType(p), to); if (ret < 0) { return 0; @@ -197,7 +197,7 @@ namespace emscripten { return ret; } - const char* EMSCRIPTEN_KEEPALIVE __typeName(int p) { + const char* __typeName(int p) { const std::type_info* ti = (const std::type_info*)p; size_t nameLen = std::min(strlen(ti->name()), (unsigned int)1024); char* name = (char *)malloc(nameLen+1); @@ -221,7 +221,7 @@ namespace emscripten { return bases; } - int EMSCRIPTEN_KEEPALIVE __peek32(int p) { + int __peek32(int p) { return *(int *)p; } From 848c186df3a8f1eff6e7b1af0b08df25aefae0e3 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 1 Feb 2013 17:18:25 -0800 Subject: [PATCH 249/544] Fix cxa_demangle compile errors --- system/lib/libcxxabi/src/cxa_demangle.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/system/lib/libcxxabi/src/cxa_demangle.cpp b/system/lib/libcxxabi/src/cxa_demangle.cpp index c1e126035fbc1..804ea7ce5290c 100644 --- a/system/lib/libcxxabi/src/cxa_demangle.cpp +++ b/system/lib/libcxxabi/src/cxa_demangle.cpp @@ -5695,7 +5695,7 @@ class __array if (__right_ != 0) r += __right_->size(); else if (__size_ != 0) - r += static_cast(snprintf(0, 0, "%ld", __size_)); + r += static_cast(snprintf(0, 0, "%lu", static_cast(__size_))); const_cast(__cached_size_) = static_cast(r); } return static_cast(__cached_size_); @@ -5710,7 +5710,7 @@ class __array buf = __right_->get_demangled_name(buf); else if (__size_ != 0) { - int rs = sprintf(buf, "%ld", __size_); + int rs = sprintf(buf, "%lu", static_cast(__size_)); buf += rs; } *buf++ = ']'; @@ -5735,7 +5735,7 @@ class __array if (__right_ != 0) r += __right_->size(); else if (__size_ != 0) - r += static_cast(snprintf(0, 0, "%ld", __size_)); + r += static_cast(snprintf(0, 0, "%lu", static_cast(__size_))); return r; } @@ -5747,7 +5747,7 @@ class __array buf = __right_->get_demangled_name(buf); else if (__size_ != 0) { - int off = sprintf(buf, "%ld", __size_); + int off = sprintf(buf, "%lu", static_cast(__size_)); buf += off; } char* t = buf; From aef932e3a9278087e96b15c1d02e10e28ce58f47 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 1 Feb 2013 18:52:37 -0800 Subject: [PATCH 250/544] Bring back EMSCRIPTEN_KEEPALIVE --- system/include/emscripten/emscripten.h | 2 +- system/lib/embind/bind.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index 61634b0e4a6eb..a4474670d9214 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -24,7 +24,7 @@ extern "C" { * with closure, asm.js, etc. For example * -s EXPORTED_FUNCTIONS=["_main", "myfunc"] */ -/* #define EMSCRIPTEN_KEEPALIVE __attribute__((used)) */ +#define EMSCRIPTEN_KEEPALIVE __attribute__((used)) /* * Interface to the underlying JS engine. This function will diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index cbb4b183309f6..5e82bb7eb4fba 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -138,7 +138,7 @@ namespace emscripten { return derivationPath; } - void* __staticPointerCast(void* p, int from, int to) { + void* EMSCRIPTEN_KEEPALIVE __staticPointerCast(void* p, int from, int to) { std::vector> paths; int direction = 1; @@ -176,7 +176,7 @@ namespace emscripten { // __getDynamicPointerType returns (for polymorphic types only!) the type of the instance actually // pointed to. - int __getDynamicPointerType(int p) { + int EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(int p) { void** vtable = *(void***)p; return (int)static_cast(vtable[-1]); } @@ -189,7 +189,7 @@ namespace emscripten { // __dynamicPointerCast performs a C++ dynamic_cast<>() operation, but allowing run-time specification of // the from and to pointer types. - int __dynamicPointerCast(int p, int to) { + int EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(int p, int to) { int ret = (int)__staticPointerCast((void *)p, __getDynamicPointerType(p), to); if (ret < 0) { return 0; @@ -197,7 +197,7 @@ namespace emscripten { return ret; } - const char* __typeName(int p) { + const char* EMSCRIPTEN_KEEPALIVE __typeName(int p) { const std::type_info* ti = (const std::type_info*)p; size_t nameLen = std::min(strlen(ti->name()), (unsigned int)1024); char* name = (char *)malloc(nameLen+1); @@ -221,7 +221,7 @@ namespace emscripten { return bases; } - int __peek32(int p) { + int EMSCRIPTEN_KEEPALIVE __peek32(int p) { return *(int *)p; } From 771ee9e921504e77fe1750173e38c35857a3f016 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 4 Feb 2013 22:49:29 -0800 Subject: [PATCH 251/544] Fix a bunch of compiler warnings --- system/include/emscripten/bind.h | 2 + system/lib/embind/bind.cpp | 90 ++++++++++++++++---------------- 2 files changed, 47 insertions(+), 45 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 7a87107f1c0dc..28fe1f3a83bfb 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -710,6 +710,7 @@ namespace emscripten { TypeID::get(), TypeID::get(), reinterpret_cast(&internal::ArrayAccessGetInvoker::invoke)); + return *this; } template @@ -842,6 +843,7 @@ namespace emscripten { new(get()) T(*o); } initialized = o.initialized; + return *this; } private: diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 5e82bb7eb4fba..39ee02becf989 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -93,50 +93,59 @@ namespace emscripten { } } - extern "C" { - // These three routines constitute an extension to the compiler's support for dynamic type conversion. - // They are used by embind.js to implement automatic downcasting of return values which are pointers to - // polymorphic objects. - - // __getDerivationPath returns an array of type_info pointers describing the derivation chain starting with - // the derived type and proceeding toward (and ending with) the base type. Types are only included if they - // appear on all possible derivation paths. - std::vector __getDerivationPath(int dv, const int bs) { - std::vector> paths; - - const std::type_info* dv1 = (std::type_info*)dv; - const std::type_info* bs1 = (std::type_info*)bs; - const __cxxabiv1::__class_type_info* dv2 = dynamic_cast(dv1); - const __cxxabiv1::__class_type_info* bs2 = dynamic_cast(bs1); - - if (dv2 && bs2) { - __cxxabiv1::__getDerivationPaths(dv2, bs2, std::vector(), paths); - } + // __getDerivationPath returns an array of type_info pointers describing the derivation chain starting with + // the derived type and proceeding toward (and ending with) the base type. Types are only included if they + // appear on all possible derivation paths. + std::vector __getDerivationPath(int dv, const int bs) { + std::vector> paths; + + const std::type_info* dv1 = (std::type_info*)dv; + const std::type_info* bs1 = (std::type_info*)bs; + const __cxxabiv1::__class_type_info* dv2 = dynamic_cast(dv1); + const __cxxabiv1::__class_type_info* bs2 = dynamic_cast(bs1); + + if (dv2 && bs2) { + __cxxabiv1::__getDerivationPaths(dv2, bs2, std::vector(), paths); + } - std::vector derivationPath; - if (paths.size() > 0) { - for (int j = 0; j < paths[0].size(); j++) { - bool disqualified = false; - for (int i = 1; i < paths.size(); i++) { - bool found = false; - for (int j2 = 0; j2 < paths[i].size(); j2++) { - if (paths[i][j2] == paths[0][j]) { - found = true; - break; - } - } - if (!found) { - disqualified = true; + std::vector derivationPath; + if (paths.size() > 0) { + for (int j = 0; j < paths[0].size(); j++) { + bool disqualified = false; + for (int i = 1; i < paths.size(); i++) { + bool found = false; + for (int j2 = 0; j2 < paths[i].size(); j2++) { + if (paths[i][j2] == paths[0][j]) { + found = true; break; } } - if (!disqualified) { - derivationPath.emplace_back((int)paths[0][j]); + if (!found) { + disqualified = true; + break; } } + if (!disqualified) { + derivationPath.emplace_back((int)paths[0][j]); + } } - return derivationPath; } + return derivationPath; + } + + std::vector __getBaseClasses(int tp) { + std::vector baseTypes = __internalGetBaseClasses((const __cxxabiv1::__class_type_info*)tp); + std::vector bases; + for (int j = 0; j < baseTypes.size(); j++) { + bases.emplace_back((int)baseTypes[j]); + } + return bases; + } + + extern "C" { + // These three routines constitute an extension to the compiler's support for dynamic type conversion. + // They are used by embind.js to implement automatic downcasting of return values which are pointers to + // polymorphic objects. void* EMSCRIPTEN_KEEPALIVE __staticPointerCast(void* p, int from, int to) { std::vector> paths; @@ -212,15 +221,6 @@ namespace emscripten { return name; } - std::vector __getBaseClasses(int tp) { - std::vector baseTypes = __internalGetBaseClasses((const __cxxabiv1::__class_type_info*)tp); - std::vector bases; - for (int j = 0; j < baseTypes.size(); j++) { - bases.emplace_back((int)baseTypes[j]); - } - return bases; - } - int EMSCRIPTEN_KEEPALIVE __peek32(int p) { return *(int *)p; } From 51dfc764bd72ef54b00617e6dcedf017f52a53d0 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 5 Feb 2013 13:25:32 -0800 Subject: [PATCH 252/544] Fix a couple of merge issues bringing down the lastest emscripten. --- system/lib/embind/bind.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 39ee02becf989..705cc4db3cf49 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -241,5 +241,3 @@ namespace emscripten { } } - - From dd618d24fc2500ec49fe536936ea404e92cc7150 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 15 Feb 2013 16:49:36 -0800 Subject: [PATCH 253/544] implement an api for allowing JS subclasses of C++ interfaces --- system/include/emscripten/bind.h | 64 +++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 28fe1f3a83bfb..a807be4cb7aa5 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -277,6 +277,11 @@ namespace emscripten { } namespace internal { + template + ClassType* operator_new(Args... args) { + return new ClassType(args...); + } + template ClassType* raw_constructor( typename internal::BindingType::WireType... args @@ -595,7 +600,49 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// // CLASSES //////////////////////////////////////////////////////////////////////////////// - // TODO: support class definitions without constructors. + + // abstract classes + template + class wrapper : public T { + public: + wrapper(const val& wrapped) + : wrapped(wrapped) + {} + + template + ReturnType call(const char* name, Args... args) const { + return Caller::call(wrapped, name, args...); + } + + private: + // this class only exists because you can't partially specialize function templates + template + struct Caller { + static ReturnType call(const val& v, const char* name, Args... args) { + return v.call(name, args...).template as(); + } + }; + + template + struct Caller { + static void call(const val& v, const char* name, Args... args) { + v.call_void(name, args...); + } + }; + + /* + void assertInitialized() { + if (!jsobj) { + internal::_embind_fatal_error( + "Cannot invoke call on uninitialized Javascript interface wrapper.", "JSInterface"); + } + }*/ + val wrapped; + }; + +#define EMSCRIPTEN_WRAPPER(T) \ + T(const ::emscripten::val& v): wrapper(v) {} + // TODO: support external class constructors template class class_ { @@ -626,6 +673,21 @@ namespace emscripten { return *this; } + template + class_& allow_subclass() { + using namespace internal; + + // TODO: unique or anonymous name + class_("WrapperType") + .template constructor() + ; + + return classmethod( + "implement", + &operator_new, + allow_raw_pointer()); + } + template class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...), Policies...) { using namespace internal; From 494461157beba8f685349b2d35f73bb0a14070c5 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Mon, 18 Feb 2013 14:36:01 -0800 Subject: [PATCH 254/544] NSTAR-1099 Eliminate naming conflict in embind handles --- src/embind/embind.js | 116 +++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 60 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 21a5dc46e8180..b0eef51f4ead2 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -51,13 +51,13 @@ function performDeferredRegistrations(){ function createInheritedFunctionOrProperty(name, type, nameInBaseClass, baseClassType) { function upcastingWrapper(method) { return function() { - var baseClassPtr = ___staticPointerCast(this.ptr, type.rawType, baseClassType.rawType); - if (baseClassPtr === this.ptr) { + var baseClassPtr = ___staticPointerCast(this.$$.ptr, type.rawType, baseClassType.rawType); + if (baseClassPtr === this.$$.ptr) { return method.apply(this, arguments); } else { var handle = this.clone(); try { - handle.ptr = baseClassPtr; + handle.$$.ptr = baseClassPtr; return method.apply(handle, arguments); } finally { handle.delete(); @@ -549,21 +549,21 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { if (!handle) { return null; } - if (handle.pointeeType.isPolymorphic) { - fromRawType = handle.pointeeType.getDynamicRawPointerType(handle.ptr); + if (handle.$$.pointeeType.isPolymorphic) { + fromRawType = handle.$$.pointeeType.getDynamicRawPointerType(handle.$$.ptr); } else { - fromRawType = handle.pointeeType.rawType; + fromRawType = handle.$$.pointeeType.rawType; } if (fromRawType === this.pointeeType.rawType) { - return this.isSmartPointer ? handle.smartPointer : handle.ptr; + return this.isSmartPointer ? handle.$$.smartPtr : handle.$$.ptr; } - var ptr = staticPointerCast(handle.ptr, fromRawType, this.pointeeType.rawType); + var ptr = staticPointerCast(handle.$$.ptr, fromRawType, this.pointeeType.rawType); if (this.isSmartPointer) { - // todo: if ptr == handle.ptr, there's no need to allocate a new smartPtr! + // todo: if ptr == handle.$$.ptr, there's no need to allocate a new smartPtr! var smartPtr = _malloc(16); - handle.pointeeType.smartPointerType.rawConstructor(smartPtr, ptr, handle.smartPointer); + handle.$$.pointeeType.smartPointerType.rawConstructor(smartPtr, ptr, handle.$$.smartPtr); ptr = smartPtr; - destructors.push(handle.pointeeType.smartPointerType.rawDestructor); + destructors.push(handle.$$.pointeeType.smartPointerType.rawDestructor); destructors.push(ptr); } return ptr; @@ -633,7 +633,7 @@ RegisteredPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // ptr is } else { handle = toType.fromWireType(ptr); } - handle.ptr = staticPointerCast(handle.ptr, fromType.rawType, toType.rawType); + handle.$$.ptr = staticPointerCast(handle.$$.ptr, fromType.rawType, toType.rawType); } else { handle = this.fromWireType(ptr); } @@ -655,10 +655,11 @@ function __embind_register_smart_ptr( rawGetPointee = FUNCTION_TABLE[rawGetPointee]; var Handle = createNamedFunction(name, function(ptr) { - this.count = {value: 1}; - this.smartPointer = ptr; // std::shared_ptr* - this.ptr = rawGetPointee(ptr); // T* - this.pointeeType = pointeeType; + this.$$ = {}; + this.$$.count = {value: 1}; + this.$$.smartPtr = ptr; // std::shared_ptr* + this.$$.ptr = rawGetPointee(ptr); // T* + this.$$.pointeeType = pointeeType; }); // TODO: test for SmartPtr.prototype.constructor property? @@ -666,30 +667,31 @@ function __embind_register_smart_ptr( Handle.prototype = Object.create(pointeeType.Handle.prototype); Handle.prototype.clone = function() { - if (!this.ptr) { + if (!this.$$.ptr) { throw new BindingError(pointeeType.name + ' instance already deleted'); } var clone = Object.create(Handle.prototype); - clone.count = this.count; - clone.smartPointer = this.smartPointer; - clone.ptr = this.ptr; + clone.$$ = {}; + clone.$$.count = this.$$.count; + clone.$$.smartPtr = this.$$.smartPtr; + clone.$$.ptr = this.$$.ptr; - clone.count.value += 1; + clone.$$.count.value += 1; return clone; }; Handle.prototype['delete'] = function() { - if (!this.ptr) { + if (!this.$$.ptr) { throw new BindingError(pointeeType.name + ' instance already deleted'); } - this.count.value -= 1; - if (0 === this.count.value) { - rawDestructor(this.smartPointer); + this.$$.count.value -= 1; + if (0 === this.$$.count.value) { + rawDestructor(this.$$.smartPtr); } - this.smartPointer = undefined; - this.ptr = undefined; + this.$$.smartPtr = undefined; + this.$$.ptr = undefined; }; var registeredPointer = new RegisteredPointer(Handle, pointeeType.isPolymorphic, true, rawGetPointee, rawConstructor, rawDestructor); registeredPointer.pointeeType = pointeeType; @@ -716,10 +718,10 @@ function __embind_register_class( throw new BindingError(name + ' does not define call operator'); } }; - - h.count = {value: 1, ptr: ptr }; - h.ptr = ptr; - h.pointeeType = type; // set below + h.$$ = {}; + h.$$.count = {value: 1, ptr: ptr }; + h.$$.ptr = ptr; + h.$$.pointeeType = type; // set below for(var prop in Handle.prototype) { var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop); @@ -730,36 +732,31 @@ function __embind_register_class( }); Handle.prototype.clone = function() { - if (!this.ptr) { + if (!this.$$.ptr) { throw new BindingError(type.name + ' instance already deleted'); } var clone = Object.create(Handle.prototype); - clone.count = this.count; - clone.ptr = this.ptr; + clone.$$ = {}; + clone.$$.count = this.$$.count; + clone.$$.ptr = this.$$.ptr; - clone.count.value += 1; + clone.$$.count.value += 1; return clone; }; - Handle.prototype.move = function() { - var rv = this.clone(); - this.delete(); - return rv; - }; - // todo: test delete with upcast and downcast multiply derived pointers - // todo: then replace this.count.ptr below with this.ptr and make sure it fails + // todo: then replace this.$$.count.ptr below with this.$$.ptr and make sure it fails Handle.prototype['delete'] = function() { - if (!this.ptr) { + if (!this.$$.ptr) { throw new BindingError(type.name + ' instance already deleted'); // todo: but 'type' hasn't been resolved!?! } - this.count.value -= 1; - if (0 === this.count.value) { - rawDestructor(this.count.ptr); + this.$$.count.value -= 1; + if (0 === this.$$.count.value) { + rawDestructor(this.$$.count.ptr); } - this.ptr = undefined; + this.$$.ptr = undefined; }; Handle.memberType = {}; @@ -834,8 +831,7 @@ function __embind_register_class_method( var humanName = classType.name + '.' + methodName; var argTypes = requireArgumentTypes(rawArgTypes, 'method ' + humanName); classType.Handle.prototype[methodName] = function() { - - if (!this.ptr) { + if (!this.$$.ptr) { throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } if (arguments.length !== argCount - 1) { @@ -844,7 +840,7 @@ function __embind_register_class_method( var destructors = []; var args = new Array(argCount + 1); - args[0] = this.ptr; + args[0] = this.$$.ptr; args[1] = memberFunction; for (var i = 1; i < argCount; ++i) { args[i + 1] = argTypes[i].toWireType(destructors, arguments[i-1]); @@ -895,7 +891,7 @@ function __embind_register_class_operator_call( var argTypes = requireArgumentTypes(rawArgTypes, 'method ' + humanName); classType.Handle.prototype.operator_call = function() { - if (!this.ptr) { + if (!this.$$.ptr) { throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } if (arguments.length !== argCount - 1) { @@ -904,7 +900,7 @@ function __embind_register_class_operator_call( var destructors = []; var args = new Array(argCount); - args[0] = this.ptr; + args[0] = this.$$.ptr; for (var i = 1; i < argCount; ++i) { args[i] = argTypes[i].toWireType(destructors, arguments[i-1]); } @@ -929,7 +925,7 @@ function __embind_register_class_operator_array_get( elementType = requireRegisteredType(elementType, 'array access element' + classType.name); var humanName = classType.name + '.' + 'operator_array_get'; classType.Handle.prototype.array_get = function() { - if (!this.ptr) { + if (!this.$$.ptr) { throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } @@ -939,7 +935,7 @@ function __embind_register_class_operator_array_get( var destructors = []; var args = new Array(2); - args[0] = this.ptr; + args[0] = this.$$.ptr; args[1] = indexType.toWireType(destructors, arguments[0]); var rv = elementType.fromWireType(rawInvoker.apply(null, args)); @@ -962,7 +958,7 @@ function __embind_register_class_operator_array_set( elementType = requireRegisteredType(elementType, 'array access element ' + classType.name); var humanName = classType.name + '.' + 'operator_array_get'; classType.Handle.prototype.array_set = function() { - if (!this.ptr) { + if (!this.$$.ptr) { throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } @@ -972,7 +968,7 @@ function __embind_register_class_operator_array_set( var destructors = []; var args = new Array(2); - args[0] = this.ptr; + args[0] = this.$$.ptr; args[1] = indexType.toWireType(destructors, arguments[0]); args[2] = elementType.toWireType(destructors, arguments[1]); @@ -1002,17 +998,17 @@ function __embind_register_class_field( var fieldType = requireRegisteredType(rawFieldType, 'field ' + humanName); Object.defineProperty(classType.Handle.prototype, fieldName, { get: function() { - if (!this.ptr) { + if (!this.$$.ptr) { throw new BindingError('cannot access emscripten binding field ' + humanName + ' on deleted object'); } - return fieldType.fromWireType(getter(this.ptr, memberPointer)); + return fieldType.fromWireType(getter(this.$$.ptr, memberPointer)); }, set: function(v) { - if (!this.ptr) { + if (!this.$$.ptr) { throw new BindingError('cannot modify emscripten binding field ' + humanName + ' on deleted object'); } var destructors = []; - setter(this.ptr, memberPointer, fieldType.toWireType(destructors, v)); + setter(this.$$.ptr, memberPointer, fieldType.toWireType(destructors, v)); runDestructors(destructors); }, enumerable: true From 88e98068137d1b176415fa7e7419ad42e93a6fa1 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 19 Feb 2013 13:20:41 -0800 Subject: [PATCH 255/544] Change register_smart_ptr to smart_ptr. --- system/include/emscripten/bind.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index a807be4cb7aa5..fd949234f6044 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -579,9 +579,9 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// template - class register_smart_ptr { + class smart_ptr { public: - register_smart_ptr(const char* name) { + smart_ptr(const char* name) { using namespace internal; typedef typename PointerType::element_type PointeeType; From 7d1614a3ee806c5635d4c4d351611fba895fe02e Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 22 Feb 2013 13:33:28 -0800 Subject: [PATCH 256/544] simplify embind a bit and checkpoint progress towards external constructors --- src/embind/embind.js | 10 +++---- system/include/emscripten/bind.h | 50 +++++++++++++++++--------------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index b0eef51f4ead2..b823e281c0e66 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -332,7 +332,7 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { var args = new Array(argCount); args[0] = fn; for (var i = 1; i < argCount; ++i) { - args[i] = argTypes[i].toWireType(destructors, arguments[i-1]); + args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]); } var rv = invoker.apply(null, args); if (argTypes[0].fromWireTypeAutoDowncast) { @@ -800,9 +800,9 @@ function __embind_register_class_constructor( throw new BindingError('emscripten binding ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } var destructors = []; - var args = new Array(argCount-1); + var args = new Array(argCount - 1); for (var i = 1; i < argCount; ++i) { - args[i-1] = argTypes[i].toWireType(destructors, arguments[i-1]); + args[i - 1] = argTypes[i].toWireType(destructors, arguments[i - 1]); } var ptr = rawConstructor.apply(null, args); @@ -843,7 +843,7 @@ function __embind_register_class_method( args[0] = this.$$.ptr; args[1] = memberFunction; for (var i = 1; i < argCount; ++i) { - args[i + 1] = argTypes[i].toWireType(destructors, arguments[i-1]); + args[i + 1] = argTypes[i].toWireType(destructors, arguments[i - 1]); } var rv = rawInvoker.apply(null, args); if (argTypes[0].fromWireTypeAutoDowncast) { @@ -902,7 +902,7 @@ function __embind_register_class_operator_call( var args = new Array(argCount); args[0] = this.$$.ptr; for (var i = 1; i < argCount; ++i) { - args[i] = argTypes[i].toWireType(destructors, arguments[i-1]); + args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]); } var rv = argTypes[0].fromWireType(rawInvoker.apply(null, args)); diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index fd949234f6044..f4fe37afe91db 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -579,22 +579,18 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// template - class smart_ptr { - public: - smart_ptr(const char* name) { - using namespace internal; - typedef typename PointerType::element_type PointeeType; - - registerStandardTypes(); - _embind_register_smart_ptr( - TypeID::get(), - TypeID::get(), - name, - reinterpret_cast(&raw_smart_pointer_constructor), - reinterpret_cast(&raw_destructor), - reinterpret_cast(&get_pointee)); - - } + void smart_ptr(const char* name) { + using namespace internal; + typedef typename PointerType::element_type PointeeType; + + registerStandardTypes(); + _embind_register_smart_ptr( + TypeID::get(), + TypeID::get(), + name, + reinterpret_cast(&raw_smart_pointer_constructor), + reinterpret_cast(&raw_destructor), + reinterpret_cast(&get_pointee)); }; //////////////////////////////////////////////////////////////////////////////// @@ -630,13 +626,6 @@ namespace emscripten { } }; - /* - void assertInitialized() { - if (!jsobj) { - internal::_embind_fatal_error( - "Cannot invoke call on uninitialized Javascript interface wrapper.", "JSInterface"); - } - }*/ val wrapped; }; @@ -673,6 +662,21 @@ namespace emscripten { return *this; } + template + class_& constructor(SmartPtr (*factory)(Args...)) { + using namespace internal; + + smart_ptr("SmartPtr"); + + typename WithPolicies<>::template ArgTypeList args; + _embind_register_class_smart_ptr_constructor( + TypeID::get(), + args.count, + args.types, + reinterpret_cast(&raw_smart_ptr_constructor + return *this; + } + template class_& allow_subclass() { using namespace internal; From 68845c447da1f53441e0399279c6cb99535d3076 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 22 Feb 2013 13:58:30 -0800 Subject: [PATCH 257/544] fix a syntax error --- system/include/emscripten/bind.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index f4fe37afe91db..1ef462bc49daf 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -291,9 +291,6 @@ namespace emscripten { ); } -// template -// void nullDeallocator(PointerType* p) {} - template typename std::shared_ptr raw_smart_pointer_constructor(PointerType *ptr, std::shared_ptr basePtr, void (PointerType*)) { return std::shared_ptr(basePtr, ptr); @@ -668,12 +665,14 @@ namespace emscripten { smart_ptr("SmartPtr"); - typename WithPolicies<>::template ArgTypeList args; + typename WithPolicies<>::template ArgTypeList args; + /* _embind_register_class_smart_ptr_constructor( TypeID::get(), args.count, args.types, reinterpret_cast(&raw_smart_ptr_constructor + */ return *this; } From 04d596f0408ccd7b591cf323bf2602b545155dcc Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 25 Feb 2013 16:04:14 -0800 Subject: [PATCH 258/544] Replace operator call with a method invoking said operator call, so isinstance works again. When Function.create exists we can have the benefit of both worlds. --- src/embind/embind.js | 57 +++----------------------------- system/include/emscripten/bind.h | 18 ++-------- 2 files changed, 6 insertions(+), 69 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index b823e281c0e66..21eca35e9ed7d 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -711,24 +711,10 @@ function __embind_register_class( rawDestructor = FUNCTION_TABLE[rawDestructor]; var Handle = createNamedFunction(name, function(ptr) { - var h = function() { - if(h.operator_call !== undefined) { - return h.operator_call.apply(h, arguments); - } else { - throw new BindingError(name + ' does not define call operator'); - } - }; - h.$$ = {}; - h.$$.count = {value: 1, ptr: ptr }; - h.$$.ptr = ptr; - h.$$.pointeeType = type; // set below - - for(var prop in Handle.prototype) { - var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop); - Object.defineProperty(h, prop, dp); - } - - return h; + this.$$ = {}; + this.$$.count = {value: 1, ptr: ptr }; + this.$$.ptr = ptr; + this.$$.pointeeType = type; // set below }); Handle.prototype.clone = function() { @@ -877,41 +863,6 @@ function __embind_register_class_classmethod( }); } -function __embind_register_class_operator_call( - rawClassType, - argCount, - rawArgTypesAddr, - rawInvoker -) { - var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - rawInvoker = FUNCTION_TABLE[rawInvoker]; - requestDeferredRegistration(function() { - var classType = requireRegisteredType(rawClassType, 'class'); - var humanName = classType.name + '.' + 'operator_call'; - var argTypes = requireArgumentTypes(rawArgTypes, 'method ' + humanName); - - classType.Handle.prototype.operator_call = function() { - if (!this.$$.ptr) { - throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); - } - if (arguments.length !== argCount - 1) { - throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); - } - - var destructors = []; - var args = new Array(argCount); - args[0] = this.$$.ptr; - for (var i = 1; i < argCount; ++i) { - args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]); - } - - var rv = argTypes[0].fromWireType(rawInvoker.apply(null, args)); - runDestructors(destructors); - return rv; - }; - }); -} - function __embind_register_class_operator_array_get( rawClassType, elementType, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 1ef462bc49daf..5806d57f090f4 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -141,12 +141,6 @@ namespace emscripten { GenericFunction invoker, GenericFunction method); - void _embind_register_class_operator_call( - TYPEID classType, - unsigned argCount, - TYPEID argTypes[], - GenericFunction invoker); - void _embind_register_class_operator_array_get( TYPEID classType, TYPEID elementType, @@ -754,16 +748,8 @@ namespace emscripten { } template - class_& calloperator(Policies...) { - using namespace internal; - - typename WithPolicies::template ArgTypeList args; - _embind_register_class_operator_call( - TypeID::get(), - args.count, - args.types, - reinterpret_cast(&internal::FunctorInvoker::invoke)); - return *this; + class_& calloperator(const char* methodName, Policies... policies) { + return method(methodName, &ClassType::operator(), policies...); } template From 176000557d9d25d6eb14511413e23321ea94e0aa Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 25 Feb 2013 18:04:45 -0800 Subject: [PATCH 259/544] allow non-member functions bound as methods. --- system/include/emscripten/bind.h | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 5806d57f090f4..c83512c7b009c 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -348,6 +348,32 @@ namespace emscripten { } }; + template + struct FunctionInvoker { + typedef ReturnType (FunctionPointer)(ClassType& ct, Args...); + static typename internal::BindingType::WireType invoke( + ClassType* ptr, + FunctionPointer** function, + typename internal::BindingType::WireType... args + ) { + return internal::BindingType::toWireType( + (*function)(*ptr, internal::BindingType::toWireType(args)...) + ); + } + }; + + template + struct FunctionInvoker { + typedef void (FunctionPointer)(ClassType& ct, Args...); + static void invoke( + ClassType* ptr, + FunctionPointer** function, + typename internal::BindingType::WireType... args + ) { + (*function)(*ptr, internal::BindingType::toWireType(args)...); + } + }; + template struct MethodInvoker { typedef ReturnType (ClassType::*MemberPointer)(Args...); @@ -717,6 +743,22 @@ namespace emscripten { return *this; } + template + class_& method(const char* methodName, ReturnType (*function)(ClassType& ptr, Args...), Policies...) { + using namespace internal; + + typename WithPolicies::template ArgTypeList args; + _embind_register_class_method( + TypeID::get(), + methodName, + args.count, + args.types, + reinterpret_cast(&FunctionInvoker::invoke), + sizeof(function), + &function); + return *this; + } + template class_& field(const char* fieldName, FieldType ClassType::*field) { using namespace internal; From 07cd277b4df9308db695d8a96ab570b4205b9622 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 25 Feb 2013 18:29:41 -0800 Subject: [PATCH 260/544] Use standard method machinery for array access. --- src/embind/embind.js | 67 ----------------------------- system/include/emscripten/bind.h | 72 +++++++++----------------------- 2 files changed, 19 insertions(+), 120 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 21eca35e9ed7d..c7848d9c063a3 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -863,73 +863,6 @@ function __embind_register_class_classmethod( }); } -function __embind_register_class_operator_array_get( - rawClassType, - elementType, - indexType, - rawInvoker -) { - rawInvoker = FUNCTION_TABLE[rawInvoker]; - requestDeferredRegistration(function() { - var classType = requireRegisteredType(rawClassType, 'class'); - indexType = requireRegisteredType(indexType, 'array access index ' + classType.name); - elementType = requireRegisteredType(elementType, 'array access element' + classType.name); - var humanName = classType.name + '.' + 'operator_array_get'; - classType.Handle.prototype.array_get = function() { - if (!this.$$.ptr) { - throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); - } - - if (arguments.length !== 1) { - throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + 1); - } - - var destructors = []; - var args = new Array(2); - args[0] = this.$$.ptr; - args[1] = indexType.toWireType(destructors, arguments[0]); - - var rv = elementType.fromWireType(rawInvoker.apply(null, args)); - runDestructors(destructors); - return rv; - }; - }); -} - -function __embind_register_class_operator_array_set( - rawClassType, - elementType, - rawIndexType, - rawInvoker -) { - rawInvoker = FUNCTION_TABLE[rawInvoker]; - requestDeferredRegistration(function() { - var classType = requireRegisteredType(rawClassType, 'class'); - var indexType = requireRegisteredType(rawIndexType, 'array access index ' + classType.name); - elementType = requireRegisteredType(elementType, 'array access element ' + classType.name); - var humanName = classType.name + '.' + 'operator_array_get'; - classType.Handle.prototype.array_set = function() { - if (!this.$$.ptr) { - throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); - } - - if (arguments.length !== 2) { - throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + 2); - } - - var destructors = []; - var args = new Array(2); - args[0] = this.$$.ptr; - args[1] = indexType.toWireType(destructors, arguments[0]); - args[2] = elementType.toWireType(destructors, arguments[1]); - - var rv = elementType.fromWireType(rawInvoker.apply(null, args)); - runDestructors(destructors); - return rv; - }; - }); -} - function __embind_register_class_field( rawClassType, fieldName, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index c83512c7b009c..d99dd7638fc65 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -141,18 +141,6 @@ namespace emscripten { GenericFunction invoker, GenericFunction method); - void _embind_register_class_operator_array_get( - TYPEID classType, - TYPEID elementType, - TYPEID indexType, - GenericFunction invoker); - - void _embind_register_class_operator_array_set( - TYPEID classType, - TYPEID elementType, - TYPEID indexType, - GenericFunction invoker); - void _embind_register_enum( TYPEID enumType, const char* name); @@ -325,29 +313,6 @@ namespace emscripten { } }; - template - struct ArrayAccessGetInvoker { - static typename internal::BindingType::WireType invoke( - ClassType* ptr, - typename internal::BindingType::WireType index - ) { - return internal::BindingType::toWireType( - (*ptr)[internal::BindingType::fromWireType(index)] - ); - } - }; - - template - struct ArrayAccessSetInvoker { - static void invoke( - ClassType* ptr, - typename internal::BindingType::WireType index, - typename internal::BindingType::WireType item - ) { - (*ptr)[internal::BindingType::fromWireType(index)] = internal::BindingType::fromWireType(item); - } - }; - template struct FunctionInvoker { typedef ReturnType (FunctionPointer)(ClassType& ct, Args...); @@ -357,7 +322,7 @@ namespace emscripten { typename internal::BindingType::WireType... args ) { return internal::BindingType::toWireType( - (*function)(*ptr, internal::BindingType::toWireType(args)...) + (*function)(*ptr, internal::BindingType::fromWireType(args)...) ); } }; @@ -370,7 +335,7 @@ namespace emscripten { FunctionPointer** function, typename internal::BindingType::WireType... args ) { - (*function)(*ptr, internal::BindingType::toWireType(args)...); + (*function)(*ptr, internal::BindingType::fromWireType(args)...); } }; @@ -472,6 +437,17 @@ namespace emscripten { setter(ptr, FieldBinding::fromWireType(value)); } }; + + template + struct ArrayAccess { + static ElementType get(ClassType& ptr, IndexType index) { + return ptr[index]; + } + + static void set(ClassType& ptr, IndexType index, const ElementType& value) { + ptr[index] = value; + } + }; } //////////////////////////////////////////////////////////////////////////////// @@ -796,26 +772,16 @@ namespace emscripten { template class_& arrayoperatorget() { - using namespace internal; - - _embind_register_class_operator_array_get( - TypeID::get(), - TypeID::get(), - TypeID::get(), - reinterpret_cast(&internal::ArrayAccessGetInvoker::invoke)); - return *this; + return method( + "array_get", + internal::ArrayAccess::get); } template class_& arrayoperatorset() { - using namespace internal; - - _embind_register_class_operator_array_set( - TypeID::get(), - TypeID::get(), - TypeID::get(), - reinterpret_cast(&internal::ArrayAccessSetInvoker::invoke)); - return *this; + return method( + "array_set", + internal::ArrayAccess::set); } }; From 78548810ba0ec6386fc4c7ab1342fe55321dad40 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 25 Feb 2013 18:58:11 -0800 Subject: [PATCH 261/544] Allow const non-member functions --- system/include/emscripten/bind.h | 43 +++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index d99dd7638fc65..33e1cc43ad8df 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -440,7 +440,7 @@ namespace emscripten { template struct ArrayAccess { - static ElementType get(ClassType& ptr, IndexType index) { + static ElementType get(const ClassType& ptr, IndexType index) { return ptr[index]; } @@ -448,6 +448,18 @@ namespace emscripten { ptr[index] = value; } }; + + template + struct MapAccess { + static ValueType get(const std::map& m, const KeyType& k) { + auto i = m.find(k); + if (i == m.end()) { + return ValueType(); + } else { + return i->second; + } + } + }; } //////////////////////////////////////////////////////////////////////////////// @@ -735,6 +747,22 @@ namespace emscripten { return *this; } + template + class_& method(const char* methodName, ReturnType (*function)(const ClassType& ptr, Args...), Policies...) { + using namespace internal; + + typename WithPolicies::template ArgTypeList args; + _embind_register_class_method( + TypeID::get(), + methodName, + args.count, + args.types, + reinterpret_cast(&FunctionInvoker::invoke), + sizeof(function), + &function); + return *this; + } + template class_& field(const char* fieldName, FieldType ClassType::*field) { using namespace internal; @@ -795,7 +823,7 @@ namespace emscripten { void (VecType::*push_back)(const T&) = &VecType::push_back; const T& (VecType::*at)(size_t) const = &VecType::at; - auto c = class_>(name) + return class_>(name) .template constructor<>() .method("push_back", push_back) .method("at", at) @@ -803,8 +831,6 @@ namespace emscripten { .template arrayoperatorget() .template arrayoperatorset() ; - - return c; } //////////////////////////////////////////////////////////////////////////////// @@ -815,13 +841,12 @@ namespace emscripten { using namespace std; typedef map MapType; - auto c = class_(name) + return class_(name) .method("size", &MapType::size) - .template arrayoperatorget() + // make this map_get? + .method("array_get", internal::MapAccess::get) .template arrayoperatorset() - ; - - return c; + ; } From f7b5f283e123ef2cf892c9e5d8a97cbd9e68349c Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 25 Feb 2013 23:50:32 -0800 Subject: [PATCH 262/544] Use length-prefix strings instead of null-terminated strings to support passing strings with embedded nul characters. --- src/embind/embind.js | 15 +++++++++++---- system/include/emscripten/wire.h | 14 ++++++++++---- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index c7848d9c063a3..c164b3263b576 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -270,17 +270,24 @@ function RegisteredString(stringType, name) { } RegisteredString.prototype.toWireType = function(destructors, value) { - var ptr = _malloc(value.length + 1); - writeStringToMemory(value, ptr); + // assumes 4-byte alignment + var length = value.length; + var ptr = _malloc(4 + length); + HEAP32[ptr >> 2] = length; + writeStringToMemory(value, ptr + 4); destructors.push(_free); destructors.push(ptr); return ptr; }; RegisteredString.prototype.fromWireType = function(value) { - var rv = Pointer_stringify(value); + var length = HEAP32[value >> 2]; + var a = new Array(length); + for (var i = 0; i < length; ++i) { + a[i] = String.fromCharCode(HEAP8[value + 4 + i]); + } _free(value); - return rv; + return a.join(''); }; function __embind_register_cstring(rawType, name) { diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index dc612e11daed9..10484a61ec430 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -180,12 +180,18 @@ namespace emscripten { template<> struct BindingType { - typedef char* WireType; + typedef struct { + size_t length; + char data[1]; // trailing data + }* WireType; static WireType toWireType(const std::string& v) { - return strdup(v.c_str()); + WireType wt = (WireType)malloc(sizeof(size_t) + v.length()); + wt->length = v.length(); + memcpy(wt->data, v.data(), v.length()); + return wt; } - static std::string fromWireType(char* v) { - return std::string(v); + static std::string fromWireType(WireType v) { + return std::string(v->data, v->length); } static void destroy(WireType v) { free(v); From 5d119a9acbfd75413bb81fd87d858c9d4d1d6f0e Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 25 Feb 2013 23:55:26 -0800 Subject: [PATCH 263/544] jshint fix --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index c164b3263b576..29fb80bf0a01a 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1,7 +1,7 @@ /*global Module*/ /*global Module*/ /*global _malloc, _free, _memcpy*/ -/*global FUNCTION_TABLE, HEAP32*/ +/*global FUNCTION_TABLE, HEAP32, HEAP8*/ /*global Pointer_stringify, writeStringToMemory*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ /*global ___getDynamicPointerType: false*/ From 6a2a01fe0ec1a297c5a45e21a6107e592986e762 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 26 Feb 2013 00:57:45 -0800 Subject: [PATCH 264/544] We were misusing writeStringToMemory which could cause memory corruption. --- src/embind/embind.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 29fb80bf0a01a..91812697de795 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -2,7 +2,7 @@ /*global Module*/ /*global _malloc, _free, _memcpy*/ /*global FUNCTION_TABLE, HEAP32, HEAP8*/ -/*global Pointer_stringify, writeStringToMemory*/ +/*global Pointer_stringify*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ /*global ___getDynamicPointerType: false*/ /*global ___typeName:false*/ @@ -274,7 +274,9 @@ RegisteredString.prototype.toWireType = function(destructors, value) { var length = value.length; var ptr = _malloc(4 + length); HEAP32[ptr >> 2] = length; - writeStringToMemory(value, ptr + 4); + for (var i = 0; i < length; ++i) { + HEAPU8[ptr + 4 + i] = value.charCodeAt(i); + } destructors.push(_free); destructors.push(ptr); return ptr; From c776c8831f313adb61c1d0e749dc86fbddb9c632 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 26 Feb 2013 01:00:03 -0800 Subject: [PATCH 265/544] fix jshint --- src/embind/embind.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 91812697de795..71da1108d6c24 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1,7 +1,7 @@ /*global Module*/ /*global Module*/ /*global _malloc, _free, _memcpy*/ -/*global FUNCTION_TABLE, HEAP32, HEAP8*/ +/*global FUNCTION_TABLE, HEAP32, HEAPU8*/ /*global Pointer_stringify*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ /*global ___getDynamicPointerType: false*/ @@ -286,7 +286,7 @@ RegisteredString.prototype.fromWireType = function(value) { var length = HEAP32[value >> 2]; var a = new Array(length); for (var i = 0; i < length; ++i) { - a[i] = String.fromCharCode(HEAP8[value + 4 + i]); + a[i] = String.fromCharCode(HEAPU8[value + 4 + i]); } _free(value); return a.join(''); From d53d8001aaa3666eb6de40fec25dbec338a75c81 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 26 Feb 2013 01:20:43 -0800 Subject: [PATCH 266/544] Disallow direct embind constructor calls. --- src/embind/embind.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index 71da1108d6c24..742dbb942d234 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -769,6 +769,9 @@ function __embind_register_class( registeredClass.pointeeType = type; type.constructor = createNamedFunction(type.name, function() { + if (Object.getPrototypeOf(this) !== Handle.prototype) { + throw new BindingError("Use 'new' to construct " + name); + } var body = type.constructor.body; return body.apply(this, arguments); }); From 136c2c4457c87d5dbe9477b28b84362dd5a48b64 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 26 Feb 2013 11:41:19 -0800 Subject: [PATCH 267/544] Give a sensible error message if attempting to construct a class with no accessible constructor --- src/embind/embind.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index 742dbb942d234..5a49d1778ac1e 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -773,6 +773,9 @@ function __embind_register_class( throw new BindingError("Use 'new' to construct " + name); } var body = type.constructor.body; + if (undefined === body) { + throw new BindingError(name + " has no accessible constructor"); + } return body.apply(this, arguments); }); type.constructor.prototype = type.Handle.prototype; From 8e471a05c1d2e00a3d367cff36cb3788b9681491 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 26 Feb 2013 08:53:03 -0800 Subject: [PATCH 268/544] Fixed a problem where auto downcasting from a smart pointer to a derived class for which no smart pointer was registered would cause a crash. Now a smart pointer is only downcast to the most derived class which is bound and for which a smart pointer is registered. --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 5a49d1778ac1e..277515a5cec23 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -619,7 +619,7 @@ RegisteredPointer.prototype.getDynamicDowncastType = function(ptr) { var derivation = Module.__getDerivationPath(type, this.pointeeType.rawType); for (var i = 0; i < derivation.size(); i++) { downcastType = typeRegistry[derivation.at(i)]; - if (downcastType) { + if (downcastType && (!this.isSmartPointer || downcastType.smartPointerType)) { break; } } From 4185573aca1eeb4d088a227acbb995253e8f5b8c Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 27 Feb 2013 00:01:10 -0800 Subject: [PATCH 269/544] Support external raw pointer constructors. --- src/embind/embind.js | 12 ++++++++---- system/include/emscripten/bind.h | 19 ++++++++++++++----- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 277515a5cec23..5a0699bad2600 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -788,10 +788,13 @@ function __embind_register_class_constructor( rawClassType, argCount, rawArgTypesAddr, + invoker, rawConstructor ) { var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - rawConstructor = FUNCTION_TABLE[rawConstructor]; + invoker = FUNCTION_TABLE[invoker]; + rawConstructor = rawConstructor; + requestDeferredRegistration(function() { var classType = requireRegisteredType(rawClassType, 'class'); var humanName = 'constructor ' + classType.name; @@ -801,12 +804,13 @@ function __embind_register_class_constructor( throw new BindingError('emscripten binding ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } var destructors = []; - var args = new Array(argCount - 1); + var args = new Array(argCount); + args[0] = rawConstructor; for (var i = 1; i < argCount; ++i) { - args[i - 1] = argTypes[i].toWireType(destructors, arguments[i - 1]); + args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]); } - var ptr = rawConstructor.apply(null, args); + var ptr = invoker.apply(null, args); runDestructors(destructors); return classType.Handle.call(this, ptr); diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 33e1cc43ad8df..257c733444680 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -113,6 +113,7 @@ namespace emscripten { TYPEID classType, unsigned argCount, TYPEID argTypes[], + GenericFunction invoker, GenericFunction constructor); void _embind_register_class_method( @@ -211,7 +212,7 @@ namespace emscripten { template struct Invoker { static typename internal::BindingType::WireType invoke( - ReturnType (fn)(Args...), + ReturnType (*fn)(Args...), typename internal::BindingType::WireType... args ) { return internal::BindingType::toWireType( @@ -225,7 +226,7 @@ namespace emscripten { template struct Invoker { static void invoke( - void (fn)(Args...), + void (*fn)(Args...), typename internal::BindingType::WireType... args ) { return fn( @@ -655,15 +656,23 @@ namespace emscripten { } template - class_& constructor(Policies...) { + class_& constructor(Policies... policies) { + return constructor( + &internal::operator_new, + policies...); + } + + template + class_& constructor(ClassType* (*factory)(Args...), Policies...) { using namespace internal; - typename WithPolicies::template ArgTypeList args; + typename WithPolicies::template ArgTypeList args; _embind_register_class_constructor( TypeID::get(), args.count, args.types, - reinterpret_cast(&raw_constructor)); + reinterpret_cast(&Invoker::invoke), + reinterpret_cast(factory)); return *this; } From d0ab8be8b2ef3bb0016ae7d5f50518407b515d2d Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 27 Feb 2013 17:05:03 -0800 Subject: [PATCH 270/544] Support autodowncasting when passing pointers into val --- src/embind/emval.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index bf31bdf3e1c65..b1c9ed049b95a 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -69,7 +69,7 @@ function __emval_new_cstring(v) { function __emval_take_value(type, v) { type = requireRegisteredType(type, '_emval_take_value'); - v = type.fromWireType(v); + v = type.fromWireTypeAutoDowncast ? type.fromWireTypeAutoDowncast(v) : type.fromWireType(v); return __emval_register(v); } From 55ebc1f6697261ef6e6e4920a28d41db783dba8c Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 26 Feb 2013 17:52:47 -0800 Subject: [PATCH 271/544] Rework how vectors and maps are bound: add bounds checking and return undefined if out of bounds. --- src/embind/embind.js | 6 +- system/include/emscripten/bind.h | 140 ++++++++++++++----------------- 2 files changed, 67 insertions(+), 79 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 5a0699bad2600..38720db3681e1 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -85,11 +85,11 @@ function collectRegisteredBaseClasses(rawType) { var rawBaseTypes = Module.__getBaseClasses(rawType); var baseTypes = []; for (var i = 0; i < rawBaseTypes.size(); i++) { - var baseType = typeRegistry[rawBaseTypes.at(i)]; + var baseType = typeRegistry[rawBaseTypes.get(i)]; if (baseType) { baseTypes.push(baseType); } else { - baseTypes = baseTypes.concat(collectRegisteredBaseClasses(rawBaseTypes.at(i))); + baseTypes = baseTypes.concat(collectRegisteredBaseClasses(rawBaseTypes.get(i))); } } return baseTypes; @@ -618,7 +618,7 @@ RegisteredPointer.prototype.getDynamicDowncastType = function(ptr) { if (type && type !== this.pointeeType.rawType) { var derivation = Module.__getDerivationPath(type, this.pointeeType.rawType); for (var i = 0; i < derivation.size(); i++) { - downcastType = typeRegistry[derivation.at(i)]; + downcastType = typeRegistry[derivation.get(i)]; if (downcastType && (!this.isSmartPointer || downcastType.smartPointerType)) { break; } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 257c733444680..3ecd858b8f60c 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -290,36 +290,12 @@ namespace emscripten { return ptr.get(); } - template - struct FunctorInvoker { - static typename internal::BindingType::WireType invoke( - const FunctorType& ptr, - typename internal::BindingType::WireType... args - ) { - return internal::BindingType::toWireType( - ptr( - internal::BindingType::fromWireType(args)... - ) - ); - } - }; - - template - struct FunctorInvoker { - static void invoke( - const FunctorType& ptr, - typename internal::BindingType::WireType... args - ) { - ptr(internal::BindingType::fromWireType(args)...); - } - }; - template struct FunctionInvoker { - typedef ReturnType (FunctionPointer)(ClassType& ct, Args...); + typedef ReturnType (*FunctionPointer)(ClassType& ct, Args...); static typename internal::BindingType::WireType invoke( ClassType* ptr, - FunctionPointer** function, + FunctionPointer* function, typename internal::BindingType::WireType... args ) { return internal::BindingType::toWireType( @@ -330,10 +306,10 @@ namespace emscripten { template struct FunctionInvoker { - typedef void (FunctionPointer)(ClassType& ct, Args...); + typedef void (*FunctionPointer)(ClassType& ct, Args...); static void invoke( ClassType* ptr, - FunctionPointer** function, + FunctionPointer* function, typename internal::BindingType::WireType... args ) { (*function)(*ptr, internal::BindingType::fromWireType(args)...); @@ -439,28 +415,6 @@ namespace emscripten { } }; - template - struct ArrayAccess { - static ElementType get(const ClassType& ptr, IndexType index) { - return ptr[index]; - } - - static void set(ClassType& ptr, IndexType index, const ElementType& value) { - ptr[index] = value; - } - }; - - template - struct MapAccess { - static ValueType get(const std::map& m, const KeyType& k) { - auto i = m.find(k); - if (i == m.end()) { - return ValueType(); - } else { - return i->second; - } - } - }; } //////////////////////////////////////////////////////////////////////////////// @@ -806,55 +760,89 @@ namespace emscripten { class_& calloperator(const char* methodName, Policies... policies) { return method(methodName, &ClassType::operator(), policies...); } - - template - class_& arrayoperatorget() { - return method( - "array_get", - internal::ArrayAccess::get); - } - - template - class_& arrayoperatorset() { - return method( - "array_set", - internal::ArrayAccess::set); - } }; //////////////////////////////////////////////////////////////////////////////// // VECTORS //////////////////////////////////////////////////////////////////////////////// + + namespace internal { + template + struct VectorAccess { + static val get( + const VectorType& v, + typename VectorType::size_type index + ) { + if (index < v.size()) { + return val(v[index]); + } else { + return val::undefined(); + } + } + + static bool set( + VectorType& v, + typename VectorType::size_type index, + const typename VectorType::value_type& value + ) { + v[index] = value; + return true; + } + }; + } + template class_> register_vector(const char* name) { - using namespace std; - typedef vector VecType; + typedef std::vector VecType; void (VecType::*push_back)(const T&) = &VecType::push_back; - const T& (VecType::*at)(size_t) const = &VecType::at; return class_>(name) .template constructor<>() .method("push_back", push_back) - .method("at", at) - .method("size", &vector::size) - .template arrayoperatorget() - .template arrayoperatorset() + .method("size", &VecType::size) + .method("get", &internal::VectorAccess::get) + .method("set", &internal::VectorAccess::set) ; } //////////////////////////////////////////////////////////////////////////////// // MAPS //////////////////////////////////////////////////////////////////////////////// + + namespace internal { + template + struct MapAccess { + static val get( + const MapType& m, + const typename MapType::key_type& k + ) { + auto i = m.find(k); + if (i == m.end()) { + return val::undefined(); + } else { + return val(i->second); + } + } + + static void set( + MapType& m, + const typename MapType::key_type& k, + const typename MapType::mapped_type& v + ) { + m[k] = v; + } + }; + } + template class_> register_map(const char* name) { - using namespace std; - typedef map MapType; + typedef std::map MapType; return class_(name) + .template constructor<>() .method("size", &MapType::size) - // make this map_get? - .method("array_get", internal::MapAccess::get) - .template arrayoperatorset() + .method("get", internal::MapAccess::get) + .method("set", internal::MapAccess::set) ; } From 088e1af2f1311e9b6f9d5b73128794449d1b9adb Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 28 Feb 2013 00:29:10 -0800 Subject: [PATCH 272/544] allow specialization of get_element_type if using a smart pointer with a different mechanism for looking up the pointee type --- system/include/emscripten/bind.h | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 3ecd858b8f60c..298df4a45fd3c 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -538,10 +538,16 @@ namespace emscripten { // SMART POINTERS //////////////////////////////////////////////////////////////////////////////// + // specialize if you have a different pointer type + template + struct get_element_type { + typedef typename PointerType::element_type type; + }; + template void smart_ptr(const char* name) { using namespace internal; - typedef typename PointerType::element_type PointeeType; + typedef typename get_element_type::type PointeeType; registerStandardTypes(); _embind_register_smart_ptr( @@ -647,6 +653,23 @@ namespace emscripten { return *this; } + /* + template + class_& constructor(SmartPtr (*factory)(Args...)) { + using namespace internal; + + smart_ptr("SmartPtr"); + + typename WithPolicies<>::template ArgTypeList args; + _embind_register_class_smart_ptr_constructor( + TypeID::get(), + args.count, + args.types, + reinterpret_cast(&raw_smart_ptr_constructor + return *this; + } + */ + template class_& allow_subclass() { using namespace internal; From 0912a345d87ebaab6e6811135a065aade48bf39a Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 28 Feb 2013 00:29:47 -0800 Subject: [PATCH 273/544] comment --- src/embind/emval.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/embind/emval.js b/src/embind/emval.js index b1c9ed049b95a..37a4970ecb5da 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -77,6 +77,7 @@ function __emval_new(handle) { return __emval_register(new (_emval_handle_array[handle].value)); } +// appease jshint (technically this code uses eval) var global = (function(){return Function;})()('return this')(); function __emval_get_global(name) { From 92db1c8c8dd903f71da8a0c191b8c109322e2f48 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 28 Feb 2013 00:41:04 -0800 Subject: [PATCH 274/544] Use custom JavaScript exception types in embind and throw a BindingError when trying to pass a non-object to a function that expects an object reference. --- src/embind/embind.js | 85 +++++++++++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 24 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 38720db3681e1..08ed7ec10d63f 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1,5 +1,4 @@ /*global Module*/ -/*global Module*/ /*global _malloc, _free, _memcpy*/ /*global FUNCTION_TABLE, HEAP32, HEAPU8*/ /*global Pointer_stringify*/ @@ -8,13 +7,47 @@ /*global ___typeName:false*/ /*global ___staticPointerCast: false*/ +var BindingError = Module.BindingError = extendError(Error, 'BindingError'); +var CastError = Module.CastError = extendError(Error, 'CastError'); + +function throwBindingError(value) { + throw new BindingError(value); +} + function exposePublicSymbol(name, value) { if (Module.hasOwnProperty(name)) { - throw new BindingError("Cannot register public name '" + name + "' twice"); + throwBindingError("Cannot register public name '" + name + "' twice"); } Module[name] = value; } +// from https://github.com/imvu/imvujs/blob/master/src/error.js +function extendError(baseErrorType, errorName) { + var errorClass = createNamedFunction(errorName, function(message) { + this.name = errorName; + this.message = message; + + var stack = (new Error(message)).stack; + if (stack !== undefined) { + this.stack = this.toString() + '\n' + + stack.replace(/^Error(:[^\n]*)?\n/, ''); + } + }); + errorClass.prototype = Object.create(baseErrorType.prototype); + errorClass.prototype.constructor = errorClass; + errorClass.prototype.toString = function() { + if (this.message === undefined) { + return this.name; + } else { + return this.name + ': ' + this.message; + } + }; + + return errorClass; +} + + +// from https://github.com/imvu/imvujs/blob/master/src/function.js function createNamedFunction(name, body) { /*jshint evil:true*/ return new Function( @@ -141,10 +174,10 @@ function resolveBindings() { function registerType(rawType, name, registeredInstance) { if (!rawType) { - throw new BindingError('type "' + name + '" must have a positive integer typeid pointer'); + throwBindingError('type "' + name + '" must have a positive integer typeid pointer'); } if (typeRegistry.hasOwnProperty(rawType)) { - throw new BindingError("Cannot register type '" + name + "' twice"); + throwBindingError("Cannot register type '" + name + "' twice"); } registeredInstance.rawType = rawType; registeredInstance.name = name; @@ -155,7 +188,7 @@ function registerType(rawType, name, registeredInstance) { function requireRegisteredType(rawType, humanName) { var impl = typeRegistry[rawType]; if (undefined === impl) { - throw new BindingError(humanName + " has unknown type " + typeName(rawType)); + throwBindingError(humanName + " has unknown type " + typeName(rawType)); } return impl; } @@ -315,12 +348,6 @@ function __embind_register_emval(rawType, name) { registerType(rawType, name, new RegisteredEmval()); } -var BindingError = Error; -var CastError = Error; -/** @expose */ -Module.BindingError = BindingError; -Module.CastError = CastError; - function runDestructors(destructors) { while (destructors.length) { var ptr = destructors.pop(); @@ -331,11 +358,11 @@ function runDestructors(destructors) { function makeInvoker(name, argCount, argTypes, invoker, fn) { if (!FUNCTION_TABLE[fn]) { - throw new BindingError('function '+name+' is not defined'); + throwBindingError('function '+name+' is not defined'); } return function() { if (arguments.length !== argCount - 1) { - throw new BindingError('function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + (argCount - 1)); + throwBindingError('function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + (argCount - 1)); } var destructors = []; var args = new Array(argCount); @@ -555,8 +582,11 @@ function RegisteredPointer(Handle, isPolymorphic, isSmartPointer, rawGetPointee, RegisteredPointer.prototype.toWireType = function(destructors, handle) { var fromRawType; - if (!handle) { - return null; + if (handle === null) { + return 0; // todo: maybe this should return a zero-initialized smart pointer object + } + if (!(handle instanceof ClassHandle)) { + throwBindingError('Expected pointer or null, got ' + IMVU.repr(handle)); } if (handle.$$.pointeeType.isPolymorphic) { fromRawType = handle.$$.pointeeType.getDynamicRawPointerType(handle.$$.ptr); @@ -569,6 +599,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { var ptr = staticPointerCast(handle.$$.ptr, fromRawType, this.pointeeType.rawType); if (this.isSmartPointer) { // todo: if ptr == handle.$$.ptr, there's no need to allocate a new smartPtr! + // todo: _malloc(16) is not big enough var smartPtr = _malloc(16); handle.$$.pointeeType.smartPointerType.rawConstructor(smartPtr, ptr, handle.$$.smartPtr); ptr = smartPtr; @@ -677,7 +708,7 @@ function __embind_register_smart_ptr( Handle.prototype.clone = function() { if (!this.$$.ptr) { - throw new BindingError(pointeeType.name + ' instance already deleted'); + throwBindingError(pointeeType.name + ' instance already deleted'); } var clone = Object.create(Handle.prototype); @@ -692,7 +723,7 @@ function __embind_register_smart_ptr( Handle.prototype['delete'] = function() { if (!this.$$.ptr) { - throw new BindingError(pointeeType.name + ' instance already deleted'); + throwBindingError(pointeeType.name + ' instance already deleted'); } this.$$.count.value -= 1; @@ -707,6 +738,9 @@ function __embind_register_smart_ptr( pointeeType.smartPointerType = registerType(rawType, name, registeredPointer); } +function ClassHandle() { +} + // TODO: null pointers are always zero (not a Handle) in Javascript function __embind_register_class( rawType, @@ -726,9 +760,12 @@ function __embind_register_class( this.$$.pointeeType = type; // set below }); + Handle.prototype = Object.create(ClassHandle.prototype, { + constructor: { value: Handle }, + }); Handle.prototype.clone = function() { if (!this.$$.ptr) { - throw new BindingError(type.name + ' instance already deleted'); + throwBindingError(type.name + ' instance already deleted'); } var clone = Object.create(Handle.prototype); @@ -744,7 +781,7 @@ function __embind_register_class( // todo: then replace this.$$.count.ptr below with this.$$.ptr and make sure it fails Handle.prototype['delete'] = function() { if (!this.$$.ptr) { - throw new BindingError(type.name + ' instance already deleted'); // todo: but 'type' hasn't been resolved!?! + throwBindingError(type.name + ' instance already deleted'); // todo: but 'type' hasn't been resolved!?! } this.$$.count.value -= 1; @@ -801,7 +838,7 @@ function __embind_register_class_constructor( var argTypes = requireArgumentTypes(rawArgTypes, humanName); classType.constructor.body = function() { if (arguments.length !== argCount - 1) { - throw new BindingError('emscripten binding ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); + throwBindingError('emscripten binding ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } var destructors = []; var args = new Array(argCount); @@ -837,10 +874,10 @@ function __embind_register_class_method( var argTypes = requireArgumentTypes(rawArgTypes, 'method ' + humanName); classType.Handle.prototype[methodName] = function() { if (!this.$$.ptr) { - throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + throwBindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } if (arguments.length !== argCount - 1) { - throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); + throwBindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } var destructors = []; @@ -902,13 +939,13 @@ function __embind_register_class_field( Object.defineProperty(classType.Handle.prototype, fieldName, { get: function() { if (!this.$$.ptr) { - throw new BindingError('cannot access emscripten binding field ' + humanName + ' on deleted object'); + throwBindingError('cannot access emscripten binding field ' + humanName + ' on deleted object'); } return fieldType.fromWireType(getter(this.$$.ptr, memberPointer)); }, set: function(v) { if (!this.$$.ptr) { - throw new BindingError('cannot modify emscripten binding field ' + humanName + ' on deleted object'); + throwBindingError('cannot modify emscripten binding field ' + humanName + ' on deleted object'); } var destructors = []; setter(this.$$.ptr, memberPointer, fieldType.toWireType(destructors, v)); From 76705c9008a9f075f2c3447079a6650326488376 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 28 Feb 2013 00:58:29 -0800 Subject: [PATCH 275/544] Illegal to pass raw pointer object from JS into smart pointer parameter --- src/embind/embind.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index 08ed7ec10d63f..e850cc3f3abba 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -588,6 +588,9 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { if (!(handle instanceof ClassHandle)) { throwBindingError('Expected pointer or null, got ' + IMVU.repr(handle)); } + if (this.isSmartPointer && undefined === handle.$$.smartPtr) { + throwBindingError('Passing raw pointer to smart pointer is illegal'); + } if (handle.$$.pointeeType.isPolymorphic) { fromRawType = handle.$$.pointeeType.getDynamicRawPointerType(handle.$$.ptr); } else { From 612076a7cd5e24924f878873b01c321e0ccee444 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 28 Feb 2013 13:00:14 -0800 Subject: [PATCH 276/544] Kill a bunch of C-style casts --- system/include/emscripten/bind.h | 34 +++++++++++--------------------- system/lib/embind/bind.cpp | 25 +++++++++++------------ 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 298df4a45fd3c..bf9706d476254 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -116,6 +116,13 @@ namespace emscripten { GenericFunction invoker, GenericFunction constructor); + void _embind_register_class_smart_ptr_constructor( + TYPEID classType, + unsigned argCount, + TYPEID argTypes[], + GenericFunction invoker, + GenericFunction constructor); + void _embind_register_class_method( TYPEID classType, const char* methodName, @@ -241,11 +248,11 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// extern "C" { - int __getDynamicPointerType(int p); + void* __getDynamicPointerType(void* p); } template - void function(const char* name, ReturnType (fn)(Args...), Policies...) { + void function(const char* name, ReturnType (*fn)(Args...), Policies...) { using namespace internal; registerStandardTypes(); @@ -640,35 +647,18 @@ namespace emscripten { class_& constructor(SmartPtr (*factory)(Args...)) { using namespace internal; + // todo: generate unique name smart_ptr("SmartPtr"); typename WithPolicies<>::template ArgTypeList args; - /* _embind_register_class_smart_ptr_constructor( TypeID::get(), args.count, args.types, - reinterpret_cast(&raw_smart_ptr_constructor - */ - return *this; - } - - /* - template - class_& constructor(SmartPtr (*factory)(Args...)) { - using namespace internal; - - smart_ptr("SmartPtr"); - - typename WithPolicies<>::template ArgTypeList args; - _embind_register_class_smart_ptr_constructor( - TypeID::get(), - args.count, - args.types, - reinterpret_cast(&raw_smart_ptr_constructor + reinterpret_cast(&Invoker::invoke), + reinterpret_cast(factory)); return *this; } - */ template class_& allow_subclass() { diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 705cc4db3cf49..081db2cdd6016 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -147,7 +147,7 @@ namespace emscripten { // They are used by embind.js to implement automatic downcasting of return values which are pointers to // polymorphic objects. - void* EMSCRIPTEN_KEEPALIVE __staticPointerCast(void* p, int from, int to) { + void* EMSCRIPTEN_KEEPALIVE __staticPointerCast(void* p, const void* from, void* to) { std::vector> paths; int direction = 1; @@ -185,30 +185,29 @@ namespace emscripten { // __getDynamicPointerType returns (for polymorphic types only!) the type of the instance actually // pointed to. - int EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(int p) { - void** vtable = *(void***)p; - return (int)static_cast(vtable[-1]); + const void* EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(void* p) { + void** vtable = *reinterpret_cast(p); + return vtable[-1]; } // Calls to __dynamic_cast are generated by the compiler to implement dynamic_cast<>() -- its prototype is // not available through any header file. It is called directly here because it allows run-time // specification of the target pointer type (which can only be specified at compile time when using // dynamic_cast<>(). - void* __dynamic_cast(void*, const std::type_info*, const std::type_info*, int); + void* __dynamic_cast(void*, const std::type_info*, const std::type_info*, void*); // __dynamicPointerCast performs a C++ dynamic_cast<>() operation, but allowing run-time specification of // the from and to pointer types. - int EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(int p, int to) { - int ret = (int)__staticPointerCast((void *)p, __getDynamicPointerType(p), to); + void* EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(void* p, void* to) { + void* ret = __staticPointerCast(p, __getDynamicPointerType(p), to); if (ret < 0) { return 0; } return ret; } - const char* EMSCRIPTEN_KEEPALIVE __typeName(int p) { - const std::type_info* ti = (const std::type_info*)p; - size_t nameLen = std::min(strlen(ti->name()), (unsigned int)1024); + const char* EMSCRIPTEN_KEEPALIVE __typeName(const std::type_info* ti) { + size_t nameLen = std::min(strlen(ti->name()), 1024U); char* name = (char *)malloc(nameLen+1); int stat; @@ -221,8 +220,8 @@ namespace emscripten { return name; } - int EMSCRIPTEN_KEEPALIVE __peek32(int p) { - return *(int *)p; + size_t EMSCRIPTEN_KEEPALIVE __peek32(size_t p) { + return *reinterpret_cast(p); } EMSCRIPTEN_BINDINGS(([]() { @@ -231,7 +230,7 @@ namespace emscripten { // developers, but perhaps the double underscore will scare them away from calling it. function("__getDerivationPath", &__getDerivationPath); function("__getBaseClasses", &__getBaseClasses); - function("__peek32", &__peek32); + function("__peek32", &__peek32, allow_raw_pointers()); })); } From f22f5867872ffc07ba3e3a75472009d4fe4e0b42 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 28 Feb 2013 13:25:31 -0800 Subject: [PATCH 277/544] Apparently the WireType Marshaller is no longer necessary?? --- src/embind/embind.js | 34 +++++++++++++++++++++++++++++++- system/include/emscripten/bind.h | 2 +- system/include/emscripten/wire.h | 25 ++--------------------- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index e850cc3f3abba..589f7ba99ae87 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -833,7 +833,6 @@ function __embind_register_class_constructor( ) { var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); invoker = FUNCTION_TABLE[invoker]; - rawConstructor = rawConstructor; requestDeferredRegistration(function() { var classType = requireRegisteredType(rawClassType, 'class'); @@ -858,6 +857,39 @@ function __embind_register_class_constructor( }); } +function __embind_register_class_smart_ptr_constructor( + rawClassType, + argCount, + rawArgTypesAddr, + invoker, + rawConstructor +) { + var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); + invoker = FUNCTION_TABLE[invoker]; + + requestDeferredRegistration(function() { + var classType = requireRegisteredType(rawClassType, 'class'); + var humanName = 'constructor ' + classType.name; + var argTypes = requireArgumentTypes(rawArgTypes, humanName); + classType.constructor.body = function() { + if (arguments.length !== argCount - 1) { + throwBindingError(humanName + ' + called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); + } + var destructors = []; + var args = new Array(argCount); + args[0] = rawConstructor; + for (var i = 1; i < argCount; ++i) { + args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]); + } + + var ptr = invoker.apply(null, args); + runDestructors(destructors); + + return argTypes[0].fromWireType(ptr); + }; + }); +} + function __embind_register_class_method( rawClassType, methodName, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index bf9706d476254..baa579c6f1146 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -650,7 +650,7 @@ namespace emscripten { // todo: generate unique name smart_ptr("SmartPtr"); - typename WithPolicies<>::template ArgTypeList args; + typename WithPolicies<>::template ArgTypeList args; _embind_register_class_smart_ptr_constructor( TypeID::get(), args.count, diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 10484a61ec430..1be23e781be5c 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -261,33 +261,12 @@ namespace emscripten { typedef typename std::remove_reference::type ActualT; typedef ActualT* WireType; - struct Marshaller { - explicit Marshaller(WireType wt) - : wireType(wt) - {} - - Marshaller(Marshaller&& wt) - : wireType(wt.wireType) - { - wt.wireType = 0; - } - - operator ActualT&() const { - return *wireType; - } - - private: - Marshaller() = delete; - Marshaller(const Marshaller&) = delete; - ActualT* wireType; - }; - static WireType toWireType(T v) { return new T(v); } - static Marshaller fromWireType(WireType p) { - return Marshaller(p); + static ActualT& fromWireType(WireType p) { + return *p; } static void destroy(WireType p) { From f23cc669e328eec1c088b2a39637ccef7dfb5e84 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 28 Feb 2013 13:45:46 -0800 Subject: [PATCH 278/544] Add support for rvalue reference parameters on factories. I don't really understand this code. --- src/embind/embind.js | 4 ++-- system/include/emscripten/wire.h | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 589f7ba99ae87..b5be460243cf4 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -840,7 +840,7 @@ function __embind_register_class_constructor( var argTypes = requireArgumentTypes(rawArgTypes, humanName); classType.constructor.body = function() { if (arguments.length !== argCount - 1) { - throwBindingError('emscripten binding ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); + throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } var destructors = []; var args = new Array(argCount); @@ -873,7 +873,7 @@ function __embind_register_class_smart_ptr_constructor( var argTypes = requireArgumentTypes(rawArgTypes, humanName); classType.constructor.body = function() { if (arguments.length !== argCount - 1) { - throwBindingError(humanName + ' + called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); + throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } var destructors = []; var args = new Array(argCount); diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 1be23e781be5c..d4efc3acffa26 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -209,6 +209,17 @@ namespace emscripten { } }; + template + struct BindingType { + typedef typename BindingType::WireType WireType; + static WireType toWireType(const T& v) { + return BindingType::toWireType(v); + } + static T fromWireType(WireType wt) { + return BindingType::fromWireType(wt); + } + }; + template struct BindingType { typedef T* WireType; From 3adc0bd5ed011987ae2c396027e3dcc5ebdea92e Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 28 Feb 2013 16:33:00 -0800 Subject: [PATCH 279/544] Turns out we can simplify and reuse a lot of code :o --- src/embind/embind.js | 33 -------------------------------- system/include/emscripten/bind.h | 19 ++++++------------ 2 files changed, 6 insertions(+), 46 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index b5be460243cf4..d4d428ad9bd6b 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -834,39 +834,6 @@ function __embind_register_class_constructor( var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); invoker = FUNCTION_TABLE[invoker]; - requestDeferredRegistration(function() { - var classType = requireRegisteredType(rawClassType, 'class'); - var humanName = 'constructor ' + classType.name; - var argTypes = requireArgumentTypes(rawArgTypes, humanName); - classType.constructor.body = function() { - if (arguments.length !== argCount - 1) { - throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); - } - var destructors = []; - var args = new Array(argCount); - args[0] = rawConstructor; - for (var i = 1; i < argCount; ++i) { - args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]); - } - - var ptr = invoker.apply(null, args); - runDestructors(destructors); - - return classType.Handle.call(this, ptr); - }; - }); -} - -function __embind_register_class_smart_ptr_constructor( - rawClassType, - argCount, - rawArgTypesAddr, - invoker, - rawConstructor -) { - var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - invoker = FUNCTION_TABLE[invoker]; - requestDeferredRegistration(function() { var classType = requireRegisteredType(rawClassType, 'class'); var humanName = 'constructor ' + classType.name; diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index baa579c6f1146..15bbfc86561ef 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -116,13 +116,6 @@ namespace emscripten { GenericFunction invoker, GenericFunction constructor); - void _embind_register_class_smart_ptr_constructor( - TYPEID classType, - unsigned argCount, - TYPEID argTypes[], - GenericFunction invoker, - GenericFunction constructor); - void _embind_register_class_method( TYPEID classType, const char* methodName, @@ -633,7 +626,7 @@ namespace emscripten { class_& constructor(ClassType* (*factory)(Args...), Policies...) { using namespace internal; - typename WithPolicies::template ArgTypeList args; + typename WithPolicies::template ArgTypeList, Args...> args; _embind_register_class_constructor( TypeID::get(), args.count, @@ -643,15 +636,15 @@ namespace emscripten { return *this; } - template - class_& constructor(SmartPtr (*factory)(Args...)) { + template + class_& constructor(SmartPtr (*factory)(Args...), Policies...) { using namespace internal; - // todo: generate unique name + // TODO: generate unique name smart_ptr("SmartPtr"); - typename WithPolicies<>::template ArgTypeList args; - _embind_register_class_smart_ptr_constructor( + typename WithPolicies::template ArgTypeList args; + _embind_register_class_constructor( TypeID::get(), args.count, args.types, From 067dbfd94662027d220cd93085d67ca0bb3cf800 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 28 Feb 2013 16:57:56 -0800 Subject: [PATCH 280/544] Mike Ey and I decided the smart pointer constructor form is different enough to deserve its own name. --- system/include/emscripten/bind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 15bbfc86561ef..f6b640d11bf27 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -637,7 +637,7 @@ namespace emscripten { } template - class_& constructor(SmartPtr (*factory)(Args...), Policies...) { + class_& smart_ptr_constructor(SmartPtr (*factory)(Args...), Policies...) { using namespace internal; // TODO: generate unique name From 9008c4da5344b55d524a811567e611c901c5c16f Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 28 Feb 2013 17:07:48 -0800 Subject: [PATCH 281/544] smart ptr 5472 object is non-enumerable --- src/embind/embind.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index d4d428ad9bd6b..7000ddc48740f 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -698,11 +698,14 @@ function __embind_register_smart_ptr( rawGetPointee = FUNCTION_TABLE[rawGetPointee]; var Handle = createNamedFunction(name, function(ptr) { - this.$$ = {}; - this.$$.count = {value: 1}; - this.$$.smartPtr = ptr; // std::shared_ptr* - this.$$.ptr = rawGetPointee(ptr); // T* - this.$$.pointeeType = pointeeType; + Object.defineProperty(this, '$$', { + value: { + count: {value: 1}, + smartPtr: ptr, + ptr: rawGetPointee(ptr), + pointeeType: pointeeType, + }, + }); }); // TODO: test for SmartPtr.prototype.constructor property? From d824fcb7ba3f28987761a80a9645ca7c630eb97b Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 28 Feb 2013 17:15:20 -0800 Subject: [PATCH 282/544] $$ is never enumerable --- src/embind/embind.js | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 7000ddc48740f..aab20b69f8be5 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -718,10 +718,13 @@ function __embind_register_smart_ptr( } var clone = Object.create(Handle.prototype); - clone.$$ = {}; - clone.$$.count = this.$$.count; - clone.$$.smartPtr = this.$$.smartPtr; - clone.$$.ptr = this.$$.ptr; + Object.defineProperty(clone, '$$', { + value: { + count: this.$$.count, + smartPtr: this.$$.smartPtr, + ptr: this.$$.ptr, + }, + }); clone.$$.count.value += 1; return clone; @@ -760,10 +763,13 @@ function __embind_register_class( rawDestructor = FUNCTION_TABLE[rawDestructor]; var Handle = createNamedFunction(name, function(ptr) { - this.$$ = {}; - this.$$.count = {value: 1, ptr: ptr }; - this.$$.ptr = ptr; - this.$$.pointeeType = type; // set below + Object.defineProperty(this, '$$', { + value: { + count: {value: 1, ptr: ptr}, + ptr: ptr, + pointeeType: type, + } + }); }); Handle.prototype = Object.create(ClassHandle.prototype, { @@ -775,9 +781,12 @@ function __embind_register_class( } var clone = Object.create(Handle.prototype); - clone.$$ = {}; - clone.$$.count = this.$$.count; - clone.$$.ptr = this.$$.ptr; + Object.defineProperty(clone, '$$', { + value: { + count: this.$$.count, + ptr: this.$$.ptr, + }, + }); clone.$$.count.value += 1; return clone; From 1a352601847328eb9f60b5c7068b8f18ab28ddc6 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 1 Mar 2013 12:52:54 -0800 Subject: [PATCH 283/544] Preliminary support for custom smart pointers. --- system/include/emscripten/bind.h | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index f6b640d11bf27..e8f21be42cb08 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -284,12 +284,6 @@ namespace emscripten { delete ptr; } - template - typename PointerType::element_type* get_pointee(const PointerType& ptr) { - // TODO: replace with general pointer traits implementation - return ptr.get(); - } - template struct FunctionInvoker { typedef ReturnType (*FunctionPointer)(ClassType& ct, Args...); @@ -540,14 +534,24 @@ namespace emscripten { // specialize if you have a different pointer type template - struct get_element_type { - typedef typename PointerType::element_type type; + struct smart_ptr_trait { + typedef typename PointerType::element_type element_type; + static element_type* get(const PointerType& ptr) { + return ptr.get(); + } }; + namespace internal { + template + typename smart_ptr_trait::element_type* get_pointee(const PointerType& ptr) { + return smart_ptr_trait::get(ptr); + } + } + template void smart_ptr(const char* name) { using namespace internal; - typedef typename get_element_type::type PointeeType; + typedef typename smart_ptr_trait::element_type PointeeType; registerStandardTypes(); _embind_register_smart_ptr( From 50c5092c4a37565558e6ffab7602e778b6774e2a Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 1 Mar 2013 16:21:30 -0800 Subject: [PATCH 284/544] Kill the malloc(16) by writing a test with a 1 MB smart pointer type :) --- src/embind/embind.js | 6 +----- system/include/emscripten/bind.h | 7 +++++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index aab20b69f8be5..8da583ba149a5 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -601,11 +601,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { } var ptr = staticPointerCast(handle.$$.ptr, fromRawType, this.pointeeType.rawType); if (this.isSmartPointer) { - // todo: if ptr == handle.$$.ptr, there's no need to allocate a new smartPtr! - // todo: _malloc(16) is not big enough - var smartPtr = _malloc(16); - handle.$$.pointeeType.smartPointerType.rawConstructor(smartPtr, ptr, handle.$$.smartPtr); - ptr = smartPtr; + ptr = handle.$$.pointeeType.smartPointerType.rawConstructor(ptr, handle.$$.smartPtr); destructors.push(handle.$$.pointeeType.smartPointerType.rawDestructor); destructors.push(ptr); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index e8f21be42cb08..9120a09545809 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -275,8 +275,11 @@ namespace emscripten { } template - typename std::shared_ptr raw_smart_pointer_constructor(PointerType *ptr, std::shared_ptr basePtr, void (PointerType*)) { - return std::shared_ptr(basePtr, ptr); + typename std::shared_ptr* raw_smart_pointer_constructor( + PointerType *ptr, + std::shared_ptr* basePtr + ) { + return new std::shared_ptr(*basePtr, ptr); } template From ececfcc02e2020c2c965cb0d6edc0fc321def581 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 1 Mar 2013 17:31:44 -0800 Subject: [PATCH 285/544] Add support for marshalling custom smart pointer types in and out of parameters. --- src/embind/embind.js | 8 +++++++- system/include/emscripten/bind.h | 23 ++++++++++++++--------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 8da583ba149a5..3ecea3e0ab4cf 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -601,7 +601,13 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { } var ptr = staticPointerCast(handle.$$.ptr, fromRawType, this.pointeeType.rawType); if (this.isSmartPointer) { - ptr = handle.$$.pointeeType.smartPointerType.rawConstructor(ptr, handle.$$.smartPtr); + // If this is for smart ptr type conversion, I think it + // assumes that smart_ptr has an identical binary layout to + // smart_ptr. I wonder if that's untrue for any common + // smart pointer. - chad + ptr = handle.$$.pointeeType.smartPointerType.rawConstructor( + ptr, + handle.$$.smartPtr); destructors.push(handle.$$.pointeeType.smartPointerType.rawDestructor); destructors.push(ptr); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 9120a09545809..ad11395b852cf 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -274,14 +274,6 @@ namespace emscripten { ); } - template - typename std::shared_ptr* raw_smart_pointer_constructor( - PointerType *ptr, - std::shared_ptr* basePtr - ) { - return new std::shared_ptr(*basePtr, ptr); - } - template void raw_destructor(ClassType* ptr) { delete ptr; @@ -539,12 +531,25 @@ namespace emscripten { template struct smart_ptr_trait { typedef typename PointerType::element_type element_type; + static element_type* get(const PointerType& ptr) { return ptr.get(); } + + static PointerType share(const PointerType& r, element_type* ptr) { + return PointerType(r, ptr); + } }; namespace internal { + template + SmartPointerType* raw_smart_pointer_constructor( + typename smart_ptr_trait::element_type* ptr, + SmartPointerType* basePtr + ) { + return new SmartPointerType(smart_ptr_trait::share(*basePtr, ptr)); + } + template typename smart_ptr_trait::element_type* get_pointee(const PointerType& ptr) { return smart_ptr_trait::get(ptr); @@ -561,7 +566,7 @@ namespace emscripten { TypeID::get(), TypeID::get(), name, - reinterpret_cast(&raw_smart_pointer_constructor), + reinterpret_cast(&raw_smart_pointer_constructor), reinterpret_cast(&raw_destructor), reinterpret_cast(&get_pointee)); }; From 97373dc8c29bdc205ffc7f0674edaa9eff80fb0c Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 5 Mar 2013 14:02:29 -0800 Subject: [PATCH 286/544] kinda start thinking about making isinstance work with base classes --- src/embind/embind.js | 13 +++++++------ system/include/emscripten/bind.h | 4 +++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 3ecea3e0ab4cf..b33ff2238b9b7 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -42,7 +42,7 @@ function extendError(baseErrorType, errorName) { return this.name + ': ' + this.message; } }; - + return errorClass; } @@ -698,7 +698,7 @@ function __embind_register_smart_ptr( rawConstructor = FUNCTION_TABLE[rawConstructor]; rawDestructor = FUNCTION_TABLE[rawDestructor]; rawGetPointee = FUNCTION_TABLE[rawGetPointee]; - + var Handle = createNamedFunction(name, function(ptr) { Object.defineProperty(this, '$$', { value: { @@ -713,7 +713,7 @@ function __embind_register_smart_ptr( // TODO: test for SmartPtr.prototype.constructor property? // We likely want it distinct from pointeeType.prototype.constructor Handle.prototype = Object.create(pointeeType.Handle.prototype); - + Handle.prototype.clone = function() { if (!this.$$.ptr) { throwBindingError(pointeeType.name + ' instance already deleted'); @@ -727,16 +727,16 @@ function __embind_register_smart_ptr( ptr: this.$$.ptr, }, }); - + clone.$$.count.value += 1; return clone; }; - + Handle.prototype['delete'] = function() { if (!this.$$.ptr) { throwBindingError(pointeeType.name + ' instance already deleted'); } - + this.$$.count.value -= 1; if (0 === this.$$.count.value) { rawDestructor(this.$$.smartPtr); @@ -757,6 +757,7 @@ function __embind_register_class( rawType, rawPointerType, rawConstPointerType, + baseClassType, isPolymorphic, name, rawDestructor diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index ad11395b852cf..cbc5cb8e9b53b 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -105,6 +105,7 @@ namespace emscripten { TYPEID classType, TYPEID pointerType, TYPEID constPointerType, + TYPEID baseClassType, bool isPolymorphic, const char* className, GenericFunction destructor); @@ -610,7 +611,7 @@ namespace emscripten { #define EMSCRIPTEN_WRAPPER(T) \ T(const ::emscripten::val& v): wrapper(v) {} - // TODO: support external class constructors + // TODO: support base class template class class_ { public: @@ -622,6 +623,7 @@ namespace emscripten { TypeID::get(), TypeID>::get(), TypeID>::get(), + 0, std::is_polymorphic::value, name, reinterpret_cast(&raw_destructor)); From c2e001c109f50ecc4f49f977e15fb2440f93389d Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 5 Mar 2013 14:35:29 -0800 Subject: [PATCH 287/544] tiny refactoring --- src/embind/embind.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index b33ff2238b9b7..39f136f0bb01f 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -182,7 +182,6 @@ function registerType(rawType, name, registeredInstance) { registeredInstance.rawType = rawType; registeredInstance.name = name; typeRegistry[rawType] = registeredInstance; - return registeredInstance; } function requireRegisteredType(rawType, humanName) { @@ -746,12 +745,18 @@ function __embind_register_smart_ptr( }; var registeredPointer = new RegisteredPointer(Handle, pointeeType.isPolymorphic, true, rawGetPointee, rawConstructor, rawDestructor); registeredPointer.pointeeType = pointeeType; - pointeeType.smartPointerType = registerType(rawType, name, registeredPointer); + registerType(rawType, name, registeredPointer); + pointeeType.smartPointerType = registeredPointer; } function ClassHandle() { } +function RegisteredClass(name, isPolymorphic, baseClass) { + this.name = name; + this.isPolymorphic = isPolymorphic; +} + // TODO: null pointers are always zero (not a Handle) in Javascript function __embind_register_class( rawType, @@ -765,6 +770,8 @@ function __embind_register_class( name = Pointer_stringify(name); rawDestructor = FUNCTION_TABLE[rawDestructor]; + var registeredClass = new RegisteredClass(name, isPolymorphic); + var Handle = createNamedFunction(name, function(ptr) { Object.defineProperty(this, '$$', { value: { @@ -812,8 +819,9 @@ function __embind_register_class( // todo: clean this up! var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); - var type = registerType(rawType, name, registeredClass); - registeredClass.pointeeType = type; + var type = registeredClass; + registerType(rawType, name, registeredClass); + registeredClass.pointeeType = registeredClass; var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); registerType(rawPointerType, name + '*', registeredClass); From ea2b0db6e84393ad2c9406f9c58346d7bd6b5881 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 5 Mar 2013 15:15:12 -0800 Subject: [PATCH 288/544] Kill a bunch of unused classes and reduce the number of lines of code in embind.js --- src/embind/embind.js | 357 ++++++++++++++++++++----------------------- 1 file changed, 167 insertions(+), 190 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 39f136f0bb01f..5fd2fd1a535b8 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -180,7 +180,6 @@ function registerType(rawType, name, registeredInstance) { throwBindingError("Cannot register type '" + name + "' twice"); } registeredInstance.rawType = rawType; - registeredInstance.name = name; typeRegistry[rawType] = registeredInstance; } @@ -227,124 +226,104 @@ function staticPointerCast(from, fromType, toType) { return to; } -function RegisteredVoid() { -} - -RegisteredVoid.prototype.fromWireType = function() { - return undefined; -}; - function __embind_register_void(rawType, name) { name = Pointer_stringify(name); - registerType(rawType, name, new RegisteredVoid()); -} - -function RegisteredBool(trueValue, falseValue) { - this.trueValue = trueValue; - this.falseValue = falseValue; + registerType(rawType, name, { + name: name, + fromWireType: function() { + return undefined; + }, + }); } -RegisteredBool.prototype.toWireType = function(destructors, o) { - return o ? this.trueValue : this.falseValue; -}; - -RegisteredBool.prototype.fromWireType = function(wt) { +function __embind_register_bool(rawType, name, trueValue, falseValue) { + name = Pointer_stringify(name); + registerType(rawType, name, { + name: name, + fromWireType: function(wt) { // ambiguous emscripten ABI: sometimes return values are // true or false, and sometimes integers (0 or 1) return !!wt; -}; - -function __embind_register_bool(rawType, name, trueValue, falseValue) { - name = Pointer_stringify(name); - registerType(rawType, name, new RegisteredBool(trueValue, falseValue)); -} - -function RegisteredInteger() { + }, + toWireType: function(destructors, o) { + return o ? trueValue : falseValue; + }, + }); } -RegisteredInteger.prototype.toWireType = function(destructors, value) { - if (typeof value !== "number") { - throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + this.name); - } - return value | 0; -}; - -RegisteredInteger.prototype.fromWireType = function(value) { - return value; -}; - function __embind_register_integer(rawType, name) { name = Pointer_stringify(name); - registerType(rawType, name, new RegisteredInteger()); -} - -function RegisteredFloat() { + registerType(rawType, name, { + name: name, + fromWireType: function(value) { + return value; + }, + toWireType: function(destructors, value) { + if (typeof value !== "number") { + throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + this.name); + } + return value | 0; + }, + }); } -RegisteredFloat.prototype.toWireType = function(destructors, value) { - if (typeof value !== "number") { - throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' +this.name); - } - return value; -}; - -RegisteredFloat.prototype.fromWireType = function(value) { - return value; -}; - function __embind_register_float(rawType, name) { name = Pointer_stringify(name); - registerType(rawType, name, new RegisteredFloat()); -} - -function RegisteredString(stringType, name) { - + registerType(rawType, name, { + name: name, + fromWireType: function(value) { + return value; + }, + toWireType: function(destructors, value) { + if (typeof value !== "number") { + throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' +this.name); + } + return value; + }, + }); } -RegisteredString.prototype.toWireType = function(destructors, value) { - // assumes 4-byte alignment - var length = value.length; - var ptr = _malloc(4 + length); - HEAP32[ptr >> 2] = length; - for (var i = 0; i < length; ++i) { - HEAPU8[ptr + 4 + i] = value.charCodeAt(i); - } - destructors.push(_free); - destructors.push(ptr); - return ptr; -}; - -RegisteredString.prototype.fromWireType = function(value) { - var length = HEAP32[value >> 2]; - var a = new Array(length); - for (var i = 0; i < length; ++i) { - a[i] = String.fromCharCode(HEAPU8[value + 4 + i]); - } - _free(value); - return a.join(''); -}; - function __embind_register_cstring(rawType, name) { name = Pointer_stringify(name); - registerType(rawType, name, new RegisteredString()); -} - -function RegisteredEmval() { + registerType(rawType, name, { + name: name, + fromWireType: function(value) { + var length = HEAP32[value >> 2]; + var a = new Array(length); + for (var i = 0; i < length; ++i) { + a[i] = String.fromCharCode(HEAPU8[value + 4 + i]); + } + _free(value); + return a.join(''); + }, + toWireType: function(destructors, value) { + // assumes 4-byte alignment + var length = value.length; + var ptr = _malloc(4 + length); + HEAP32[ptr >> 2] = length; + for (var i = 0; i < length; ++i) { + HEAPU8[ptr + 4 + i] = value.charCodeAt(i); + } + destructors.push(_free); + destructors.push(ptr); + return ptr; + }, + }); } -RegisteredEmval.prototype.toWireType = function(destructors, value) { - return __emval_register(value); -}; - -RegisteredEmval.prototype.fromWireType = function(handle) { - var rv = _emval_handle_array[handle].value; - __emval_decref(handle); - return rv; -}; - function __embind_register_emval(rawType, name) { name = Pointer_stringify(name); - registerType(rawType, name, new RegisteredEmval()); + registerType(rawType, name, { + name: name, + fromWireType: function(handle) { + var rv = _emval_handle_array[handle].value; + __emval_decref(handle); + return rv; + }, + toWireType: function(destructors, value) { + return __emval_register(value); + }, + }); } function runDestructors(destructors) { @@ -390,41 +369,38 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, }); } -function RegisteredTuple(rawConstructor, rawDestructor) { - this.rawConstructor = rawConstructor; - this.rawDestructor = rawDestructor; - this.elements = []; -} - -RegisteredTuple.prototype.toWireType = function(destructors, o) { - var len = this.elements.length; - if (len !== o.length) { - throw new TypeError("Incorrect number of tuple elements"); - } - var ptr = this.rawConstructor(); - for (var i = 0; i < len; ++i) { - this.elements[i].write(ptr, o[i]); - } - destructors.push(this.rawDestructor); - destructors.push(ptr); - return ptr; -}; - -RegisteredTuple.prototype.fromWireType = function(ptr) { - var len = this.elements.length; - var rv = new Array(len); - for (var i = 0; i < len; ++i) { - rv[i] = this.elements[i].read(ptr); - } - this.rawDestructor(ptr); - return rv; -}; - function __embind_register_tuple(rawType, name, rawConstructor, rawDestructor) { name = Pointer_stringify(name); rawConstructor = FUNCTION_TABLE[rawConstructor]; rawDestructor = FUNCTION_TABLE[rawDestructor]; - registerType(rawType, name, new RegisteredTuple(rawConstructor, rawDestructor)); + registerType(rawType, name, { + name: name, + rawConstructor: rawConstructor, + rawDestructor: rawDestructor, + elements: [], + fromWireType: function(ptr) { + var len = this.elements.length; + var rv = new Array(len); + for (var i = 0; i < len; ++i) { + rv[i] = this.elements[i].read(ptr); + } + this.rawDestructor(ptr); + return rv; + }, + toWireType: function(destructors, o) { + var len = this.elements.length; + if (len !== o.length) { + throw new TypeError("Incorrect number of tuple elements"); + } + var ptr = this.rawConstructor(); + for (var i = 0; i < len; ++i) { + this.elements[i].write(ptr, o[i]); + } + destructors.push(rawDestructor); + destructors.push(ptr); + return ptr; + }, + }); } function copyMemberPointer(memberPointer, memberPointerSize) { @@ -447,6 +423,7 @@ function __embind_register_tuple_element( getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); + // TODO: this could register elements out of order requestDeferredRegistration(function() { var tupleType = requireRegisteredType(rawTupleType, 'tuple'); var type = requireRegisteredType(rawType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); @@ -496,38 +473,6 @@ function __embind_register_tuple_element_accessor( }); } -function RegisteredStruct(rawConstructor, rawDestructor) { - this.rawConstructor = rawConstructor; - this.rawDestructor = rawDestructor; - this.fields = {}; -} - -RegisteredStruct.prototype.toWireType = function(destructors, o) { - var fields = this.fields; - for (var fieldName in fields) { - if (!(fieldName in o)) { - throw new TypeError('Missing field'); - } - } - var ptr = this.rawConstructor(); - for (fieldName in fields) { - fields[fieldName].write(ptr, o[fieldName]); - } - destructors.push(this.rawDestructor); - destructors.push(ptr); - return ptr; -}; - -RegisteredStruct.prototype.fromWireType = function(ptr) { - var fields = this.fields; - var rv = {}; - for (var i in fields) { - rv[i] = fields[i].read(ptr); - } - this.rawDestructor(ptr); - return rv; -}; - function __embind_register_struct( rawType, name, @@ -538,7 +483,36 @@ function __embind_register_struct( rawConstructor = FUNCTION_TABLE[rawConstructor]; rawDestructor = FUNCTION_TABLE[rawDestructor]; - registerType(rawType, name, new RegisteredStruct(rawConstructor, rawDestructor)); + registerType(rawType, name, { + name: name, + rawConstructor: rawConstructor, + rawDestructor: rawDestructor, + fields: {}, + fromWireType: function(ptr) { + var fields = this.fields; + var rv = {}; + for (var i in fields) { + rv[i] = fields[i].read(ptr); + } + this.rawDestructor(ptr); + return rv; + }, + toWireType: function(destructors, o) { + var fields = this.fields; + for (var fieldName in fields) { + if (!(fieldName in o)) { + throw new TypeError('Missing field'); + } + } + var ptr = this.rawConstructor(); + for (fieldName in fields) { + fields[fieldName].write(ptr, o[fieldName]); + } + destructors.push(rawDestructor); + destructors.push(ptr); + return ptr; + }, + }); } function __embind_register_struct_field( @@ -554,6 +528,7 @@ function __embind_register_struct_field( rawGetter = FUNCTION_TABLE[rawGetter]; rawSetter = FUNCTION_TABLE[rawSetter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); + // TODO: this could register elements out of order requestDeferredRegistration(function() { var structType = requireRegisteredType(rawStructType, 'struct'); var fieldType = requireRegisteredType(rawFieldType, 'field "' + structType.name + '.' + fieldName + '"'); @@ -745,6 +720,7 @@ function __embind_register_smart_ptr( }; var registeredPointer = new RegisteredPointer(Handle, pointeeType.isPolymorphic, true, rawGetPointee, rawConstructor, rawDestructor); registeredPointer.pointeeType = pointeeType; + registeredPointer.name = name; registerType(rawType, name, registeredPointer); pointeeType.smartPointerType = registeredPointer; } @@ -819,15 +795,18 @@ function __embind_register_class( // todo: clean this up! var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); + registeredClass.name = name; var type = registeredClass; registerType(rawType, name, registeredClass); registeredClass.pointeeType = registeredClass; var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); + registeredClass.name = name; registerType(rawPointerType, name + '*', registeredClass); registeredClass.pointeeType = type; // todo: implement const pointers (no modification Javascript side) var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); + registeredClass.name = name; registerType(rawConstPointerType, name + ' const*', registeredClass); registeredClass.pointeeType = type; @@ -982,27 +961,27 @@ function __embind_register_class_field( }); } -function RegisteredEnum() { - this.constructor = function() {}; - this.constructor.values = {}; -} - -RegisteredEnum.prototype.toWireType = function(destructors, c) { - return c.value; -}; - -RegisteredEnum.prototype.fromWireType = function(c) { - return this.constructor.values[c]; -}; - function __embind_register_enum( rawType, name ) { name = Pointer_stringify(name); - var newEnum = new RegisteredEnum(); - registerType(rawType, name, newEnum); - exposePublicSymbol(name, newEnum.constructor); + + function constructor() { + } + constructor.values = {}; + + registerType(rawType, name, { + name: name, + constructor: constructor, + fromWireType: function(c) { + return this.constructor.values[c]; + }, + toWireType: function(destructors, c) { + return c.value; + }, + }); + exposePublicSymbol(name, constructor); } function __embind_register_enum_value( @@ -1023,19 +1002,6 @@ function __embind_register_enum_value( Enum[name] = Value; } -function RegisteredInterface(rawConstructor, rawDestructor) { - this.rawConstructor = rawConstructor; - this.rawDestructor = rawDestructor; -} - -RegisteredInterface.prototype.toWireType = function(destructors, o) { - var handle = __emval_register(o); - var ptr = this.rawConstructor(handle); - destructors.push(this.rawDestructor); - destructors.push(ptr); - return ptr; -}; - function __embind_register_interface( rawType, name, @@ -1046,6 +1012,17 @@ function __embind_register_interface( rawConstructor = FUNCTION_TABLE[rawConstructor]; rawDestructor = FUNCTION_TABLE[rawDestructor]; - registerType(rawType, name, new RegisteredInterface(rawConstructor, rawDestructor)); + registerType(rawType, name, { + name: name, + rawConstructor: rawConstructor, + rawDestructor: rawDestructor, + toWireType: function(destructors, o) { + var handle = __emval_register(o); + var ptr = this.rawConstructor(handle); + destructors.push(this.rawDestructor); + destructors.push(ptr); + return ptr; + }, + }); } From f013fe14077ad109db4d679d2406453814622d07 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 5 Mar 2013 18:39:02 -0800 Subject: [PATCH 289/544] registerType gets its name from the registered instance now --- src/embind/embind.js | 67 +++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 5fd2fd1a535b8..629e42ff4c012 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -172,7 +172,8 @@ function resolveBindings() { } } -function registerType(rawType, name, registeredInstance) { +function registerType(rawType, registeredInstance) { + var name = registeredInstance.name; if (!rawType) { throwBindingError('type "' + name + '" must have a positive integer typeid pointer'); } @@ -228,7 +229,7 @@ function staticPointerCast(from, fromType, toType) { function __embind_register_void(rawType, name) { name = Pointer_stringify(name); - registerType(rawType, name, { + registerType(rawType, { name: name, fromWireType: function() { return undefined; @@ -238,7 +239,7 @@ function __embind_register_void(rawType, name) { function __embind_register_bool(rawType, name, trueValue, falseValue) { name = Pointer_stringify(name); - registerType(rawType, name, { + registerType(rawType, { name: name, fromWireType: function(wt) { // ambiguous emscripten ABI: sometimes return values are @@ -253,7 +254,7 @@ function __embind_register_bool(rawType, name, trueValue, falseValue) { function __embind_register_integer(rawType, name) { name = Pointer_stringify(name); - registerType(rawType, name, { + registerType(rawType, { name: name, fromWireType: function(value) { return value; @@ -269,7 +270,7 @@ function __embind_register_integer(rawType, name) { function __embind_register_float(rawType, name) { name = Pointer_stringify(name); - registerType(rawType, name, { + registerType(rawType, { name: name, fromWireType: function(value) { return value; @@ -285,7 +286,7 @@ function __embind_register_float(rawType, name) { function __embind_register_cstring(rawType, name) { name = Pointer_stringify(name); - registerType(rawType, name, { + registerType(rawType, { name: name, fromWireType: function(value) { var length = HEAP32[value >> 2]; @@ -313,7 +314,7 @@ function __embind_register_cstring(rawType, name) { function __embind_register_emval(rawType, name) { name = Pointer_stringify(name); - registerType(rawType, name, { + registerType(rawType, { name: name, fromWireType: function(handle) { var rv = _emval_handle_array[handle].value; @@ -373,7 +374,7 @@ function __embind_register_tuple(rawType, name, rawConstructor, rawDestructor) { name = Pointer_stringify(name); rawConstructor = FUNCTION_TABLE[rawConstructor]; rawDestructor = FUNCTION_TABLE[rawDestructor]; - registerType(rawType, name, { + registerType(rawType, { name: name, rawConstructor: rawConstructor, rawDestructor: rawDestructor, @@ -483,7 +484,7 @@ function __embind_register_struct( rawConstructor = FUNCTION_TABLE[rawConstructor]; rawDestructor = FUNCTION_TABLE[rawDestructor]; - registerType(rawType, name, { + registerType(rawType, { name: name, rawConstructor: rawConstructor, rawDestructor: rawDestructor, @@ -545,15 +546,20 @@ function __embind_register_struct_field( }); } -function RegisteredPointer(Handle, isPolymorphic, isSmartPointer, rawGetPointee, rawConstructor, rawDestructor) { - this.Handle = Handle; - this.isPolymorphic = isPolymorphic; +function RegisteredPointer(name, registeredClass, Handle, isSmartPointer, rawGetPointee, rawConstructor, rawDestructor) { + this.name = name; + this.registeredClass = registeredClass; + this.Handle = Handle; // <-- I think I can kill this this.isSmartPointer = isSmartPointer; this.rawGetPointee = rawGetPointee; this.rawConstructor = rawConstructor; this.rawDestructor = rawDestructor; } +RegisteredPointer.prototype.isPolymorphic = function() { + return this.registeredClass.isPolymorphic; +}; + RegisteredPointer.prototype.toWireType = function(destructors, handle) { var fromRawType; if (handle === null) { @@ -565,7 +571,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { if (this.isSmartPointer && undefined === handle.$$.smartPtr) { throwBindingError('Passing raw pointer to smart pointer is illegal'); } - if (handle.$$.pointeeType.isPolymorphic) { + if (handle.$$.pointeeType.isPolymorphic()) { fromRawType = handle.$$.pointeeType.getDynamicRawPointerType(handle.$$.ptr); } else { fromRawType = handle.$$.pointeeType.rawType; @@ -586,7 +592,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { destructors.push(ptr); } return ptr; - }; +}; RegisteredPointer.prototype.getPointee = function(ptr) { if (this.rawGetPointee) { @@ -612,7 +618,7 @@ RegisteredPointer.prototype.fromWireType = function(ptr) { // todo: could this return the actual type if not polymorphic? RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) { var type = null; - if (this.isPolymorphic) { + if (this.isPolymorphic()) { if (this.rawGetPointee) { type = ___getDynamicPointerType(this.rawGetPointee(ptr)); } else { @@ -718,10 +724,16 @@ function __embind_register_smart_ptr( this.$$.smartPtr = undefined; this.$$.ptr = undefined; }; - var registeredPointer = new RegisteredPointer(Handle, pointeeType.isPolymorphic, true, rawGetPointee, rawConstructor, rawDestructor); + var registeredPointer = new RegisteredPointer( + name, + pointeeType.registeredClass, + Handle, + true, + rawGetPointee, + rawConstructor, + rawDestructor); registeredPointer.pointeeType = pointeeType; - registeredPointer.name = name; - registerType(rawType, name, registeredPointer); + registerType(rawType, registeredPointer); pointeeType.smartPointerType = registeredPointer; } @@ -794,20 +806,17 @@ function __embind_register_class( Handle.memberType = {}; // todo: clean this up! - var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); - registeredClass.name = name; + var registeredClass = new RegisteredPointer(name, registeredClass, Handle, false); var type = registeredClass; - registerType(rawType, name, registeredClass); + registerType(rawType, registeredClass); registeredClass.pointeeType = registeredClass; - var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); - registeredClass.name = name; - registerType(rawPointerType, name + '*', registeredClass); + var registeredClass = new RegisteredPointer(name + '*', registeredClass, Handle, false); + registerType(rawPointerType, registeredClass); registeredClass.pointeeType = type; // todo: implement const pointers (no modification Javascript side) - var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false); - registeredClass.name = name; - registerType(rawConstPointerType, name + ' const*', registeredClass); + var registeredClass = new RegisteredPointer(name + ' const*', registeredClass, Handle, false); + registerType(rawConstPointerType, registeredClass); registeredClass.pointeeType = type; type.constructor = createNamedFunction(type.name, function() { @@ -971,7 +980,7 @@ function __embind_register_enum( } constructor.values = {}; - registerType(rawType, name, { + registerType(rawType, { name: name, constructor: constructor, fromWireType: function(c) { @@ -1012,7 +1021,7 @@ function __embind_register_interface( rawConstructor = FUNCTION_TABLE[rawConstructor]; rawDestructor = FUNCTION_TABLE[rawDestructor]; - registerType(rawType, name, { + registerType(rawType, { name: name, rawConstructor: rawConstructor, rawDestructor: rawDestructor, From 32e54a09d2ecaf8543a5010b2f00a5ae677118b3 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 5 Mar 2013 23:56:25 -0800 Subject: [PATCH 290/544] More simplifications --- src/embind/embind.js | 54 +++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 629e42ff4c012..393319d303767 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -193,7 +193,10 @@ function requireRegisteredType(rawType, humanName) { } function typeName(rawType) { - return Pointer_stringify(___typeName(rawType)); + var bt = ___typeName(rawType); + var rv = Pointer_stringify(bt); + _free(bt); + return rv; } function heap32VectorToArray(count, firstElement) { @@ -222,7 +225,7 @@ function staticPointerCast(from, fromType, toType) { } var to = ___staticPointerCast(from, fromType, toType); if (to <= 0) { - throw new CastError("Pointer conversion is not available"); + throw new CastError("Pointer conversion from " + typeName(fromType) + " to " + typeName(toType) + " is not available"); } return to; } @@ -546,9 +549,10 @@ function __embind_register_struct_field( }); } -function RegisteredPointer(name, registeredClass, Handle, isSmartPointer, rawGetPointee, rawConstructor, rawDestructor) { +function RegisteredPointer(name, registeredClass, pointeeType, Handle, isSmartPointer, rawGetPointee, rawConstructor, rawDestructor) { this.name = name; this.registeredClass = registeredClass; + this.pointeeType = pointeeType; this.Handle = Handle; // <-- I think I can kill this this.isSmartPointer = isSmartPointer; this.rawGetPointee = rawGetPointee; @@ -571,10 +575,11 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { if (this.isSmartPointer && undefined === handle.$$.smartPtr) { throwBindingError('Passing raw pointer to smart pointer is illegal'); } - if (handle.$$.pointeeType.isPolymorphic()) { - fromRawType = handle.$$.pointeeType.getDynamicRawPointerType(handle.$$.ptr); + var pointeeType = handle.$$.pointeeType; + if (pointeeType.isPolymorphic()) { + fromRawType = pointeeType.getDynamicRawPointerType(handle.$$.ptr); } else { - fromRawType = handle.$$.pointeeType.rawType; + fromRawType = pointeeType.rawType; } if (fromRawType === this.pointeeType.rawType) { return this.isSmartPointer ? handle.$$.smartPtr : handle.$$.ptr; @@ -585,10 +590,10 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { // assumes that smart_ptr has an identical binary layout to // smart_ptr. I wonder if that's untrue for any common // smart pointer. - chad - ptr = handle.$$.pointeeType.smartPointerType.rawConstructor( + ptr = pointeeType.smartPointerType.rawConstructor( ptr, handle.$$.smartPtr); - destructors.push(handle.$$.pointeeType.smartPointerType.rawDestructor); + destructors.push(pointeeType.smartPointerType.rawDestructor); destructors.push(ptr); } return ptr; @@ -724,15 +729,16 @@ function __embind_register_smart_ptr( this.$$.smartPtr = undefined; this.$$.ptr = undefined; }; + var registeredPointer = new RegisteredPointer( name, pointeeType.registeredClass, + pointeeType, Handle, true, rawGetPointee, rawConstructor, rawDestructor); - registeredPointer.pointeeType = pointeeType; registerType(rawType, registeredPointer); pointeeType.smartPointerType = registeredPointer; } @@ -806,20 +812,26 @@ function __embind_register_class( Handle.memberType = {}; // todo: clean this up! - var registeredClass = new RegisteredPointer(name, registeredClass, Handle, false); - var type = registeredClass; - registerType(rawType, registeredClass); - registeredClass.pointeeType = registeredClass; - - var registeredClass = new RegisteredPointer(name + '*', registeredClass, Handle, false); - registerType(rawPointerType, registeredClass); - registeredClass.pointeeType = type; + var type = new RegisteredPointer(name, registeredClass, undefined, Handle, false); + type.pointeeType = type; + registerType(rawType, type); + + registerType(rawPointerType, new RegisteredPointer( + name + '*', + registeredClass, + type, + Handle, + false)); + // todo: implement const pointers (no modification Javascript side) - var registeredClass = new RegisteredPointer(name + ' const*', registeredClass, Handle, false); - registerType(rawConstPointerType, registeredClass); - registeredClass.pointeeType = type; + registerType(rawConstPointerType, new RegisteredPointer( + name + ' const*', + registeredClass, + type, + Handle, + false)); - type.constructor = createNamedFunction(type.name, function() { + type.constructor = createNamedFunction(name, function() { if (Object.getPrototypeOf(this) !== Handle.prototype) { throw new BindingError("Use 'new' to construct " + name); } From c1114a970b3eb8cb022aad9345289c81279c3c38 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 6 Mar 2013 00:16:55 -0800 Subject: [PATCH 291/544] registerType doesn't modify the type converter anymore --- src/embind/embind.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 393319d303767..447bea1b09d06 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -115,6 +115,9 @@ function createInheritedFunctionOrProperty(name, type, nameInBaseClass, baseClas } function collectRegisteredBaseClasses(rawType) { + if (undefined === rawType) { + return []; + } var rawBaseTypes = Module.__getBaseClasses(rawType); var baseTypes = []; for (var i = 0; i < rawBaseTypes.size(); i++) { @@ -180,7 +183,6 @@ function registerType(rawType, registeredInstance) { if (typeRegistry.hasOwnProperty(rawType)) { throwBindingError("Cannot register type '" + name + "' twice"); } - registeredInstance.rawType = rawType; typeRegistry[rawType] = registeredInstance; } @@ -549,8 +551,9 @@ function __embind_register_struct_field( }); } -function RegisteredPointer(name, registeredClass, pointeeType, Handle, isSmartPointer, rawGetPointee, rawConstructor, rawDestructor) { +function RegisteredPointer(name, rawType, registeredClass, pointeeType, Handle, isSmartPointer, rawGetPointee, rawConstructor, rawDestructor) { this.name = name; + this.rawType = rawType; this.registeredClass = registeredClass; this.pointeeType = pointeeType; this.Handle = Handle; // <-- I think I can kill this @@ -732,6 +735,7 @@ function __embind_register_smart_ptr( var registeredPointer = new RegisteredPointer( name, + rawType, pointeeType.registeredClass, pointeeType, Handle, @@ -812,12 +816,19 @@ function __embind_register_class( Handle.memberType = {}; // todo: clean this up! - var type = new RegisteredPointer(name, registeredClass, undefined, Handle, false); - type.pointeeType = type; + var type = new RegisteredPointer( + name, + rawType, + registeredClass, + undefined, + Handle, + false); + type.pointeeType = type; // :( registerType(rawType, type); registerType(rawPointerType, new RegisteredPointer( name + '*', + rawPointerType, registeredClass, type, Handle, @@ -826,6 +837,7 @@ function __embind_register_class( // todo: implement const pointers (no modification Javascript side) registerType(rawConstPointerType, new RegisteredPointer( name + ' const*', + rawConstPointerType, registeredClass, type, Handle, From 8be7ebc9ccc6281a9e7481340d28255567608920 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 6 Mar 2013 03:17:51 -0800 Subject: [PATCH 292/544] Explicitly specify base classes. Alas, but it must be done for instanceof :( --- src/embind/embind.js | 17 ++++++++++------ system/include/emscripten/bind.h | 34 ++++++++++++++++++++++++++++---- system/lib/embind/bind.cpp | 10 ---------- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 447bea1b09d06..b9507d5f8f4c8 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -69,6 +69,7 @@ function _embind_repr(v) { var typeRegistry = {}; var deferredRegistrations = []; +var baseClasses = {}; // rawType -> rawBaseType function requestDeferredRegistration(registrationFunction) { deferredRegistrations.push(registrationFunction); @@ -118,10 +119,10 @@ function collectRegisteredBaseClasses(rawType) { if (undefined === rawType) { return []; } - var rawBaseTypes = Module.__getBaseClasses(rawType); + var rawBaseTypes = baseClasses[rawType] || []; var baseTypes = []; - for (var i = 0; i < rawBaseTypes.size(); i++) { - var baseType = typeRegistry[rawBaseTypes.get(i)]; + for (var i = 0; i < rawBaseTypes.length; i++) { + var baseType = typeRegistry[rawBaseTypes[i]]; if (baseType) { baseTypes.push(baseType); } else { @@ -750,7 +751,7 @@ function __embind_register_smart_ptr( function ClassHandle() { } -function RegisteredClass(name, isPolymorphic, baseClass) { +function RegisteredClass(name, isPolymorphic, baseClassRawType) { this.name = name; this.isPolymorphic = isPolymorphic; } @@ -760,7 +761,7 @@ function __embind_register_class( rawType, rawPointerType, rawConstPointerType, - baseClassType, + baseClassRawType, isPolymorphic, name, rawDestructor @@ -768,7 +769,11 @@ function __embind_register_class( name = Pointer_stringify(name); rawDestructor = FUNCTION_TABLE[rawDestructor]; - var registeredClass = new RegisteredClass(name, isPolymorphic); + if (baseClassRawType) { + baseClasses[rawType] = [baseClassRawType]; + } + + var registeredClass = new RegisteredClass(name, isPolymorphic, baseClassRawType); var Handle = createNamedFunction(name, function(ptr) { Object.defineProperty(this, '$$', { diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index cbc5cb8e9b53b..24a7bf71e5c5d 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -611,19 +611,45 @@ namespace emscripten { #define EMSCRIPTEN_WRAPPER(T) \ T(const ::emscripten::val& v): wrapper(v) {} - // TODO: support base class - template + namespace internal { + struct NoBaseClass { + static TYPEID get() { + return 0; + } + + template + static void verify() { + } + }; + } + + template + struct base { + static internal::TYPEID get() { + return internal::TypeID::get(); + } + + template + static void verify() { + static_assert(!std::is_same::value, "Base must not have same type as class"); + static_assert(std::is_base_of::value, "Derived class must derive from base"); + } + }; + + template class class_ { public: class_(const char* name) { using namespace internal; + BaseSpecifier::template verify(); + registerStandardTypes(); _embind_register_class( TypeID::get(), TypeID>::get(), TypeID>::get(), - 0, + BaseSpecifier::get(), std::is_polymorphic::value, name, reinterpret_cast(&raw_destructor)); @@ -672,7 +698,7 @@ namespace emscripten { using namespace internal; // TODO: unique or anonymous name - class_("WrapperType") + class_>("WrapperType") .template constructor() ; diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 081db2cdd6016..cbff7cf1db2a2 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -133,15 +133,6 @@ namespace emscripten { return derivationPath; } - std::vector __getBaseClasses(int tp) { - std::vector baseTypes = __internalGetBaseClasses((const __cxxabiv1::__class_type_info*)tp); - std::vector bases; - for (int j = 0; j < baseTypes.size(); j++) { - bases.emplace_back((int)baseTypes[j]); - } - return bases; - } - extern "C" { // These three routines constitute an extension to the compiler's support for dynamic type conversion. // They are used by embind.js to implement automatic downcasting of return values which are pointers to @@ -229,7 +220,6 @@ namespace emscripten { // conversion for the return value. This has the unfortunate side-effect of exposing it to third party // developers, but perhaps the double underscore will scare them away from calling it. function("__getDerivationPath", &__getDerivationPath); - function("__getBaseClasses", &__getBaseClasses); function("__peek32", &__peek32, allow_raw_pointers()); })); } From 3f44445f45aae6b9014985d352dfb74674728881 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 6 Mar 2013 03:38:28 -0800 Subject: [PATCH 293/544] further simplifications --- src/embind/embind.js | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index b9507d5f8f4c8..3f10d886e2222 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -115,28 +115,28 @@ function createInheritedFunctionOrProperty(name, type, nameInBaseClass, baseClas } } -function collectRegisteredBaseClasses(rawType) { +function collectRegisteredBaseClasses(type) { + var rawType = type.rawType; if (undefined === rawType) { return []; } - var rawBaseTypes = baseClasses[rawType] || []; - var baseTypes = []; - for (var i = 0; i < rawBaseTypes.length; i++) { - var baseType = typeRegistry[rawBaseTypes[i]]; - if (baseType) { - baseTypes.push(baseType); - } else { - baseTypes = baseTypes.concat(collectRegisteredBaseClasses(rawBaseTypes.get(i))); - } + var rawBaseType = baseClasses[rawType]; + if (!rawBaseType) { + return []; + } + var baseType = typeRegistry[rawBaseType]; + if (baseType) { + return [baseType]; + } else { + return collectRegisteredBaseClasses(baseType); } - return baseTypes; } function resolveType(type) { if (!type.resolved) { var baseClassType, name, baseProto; var inheritedNames = {}; - var baseTypes = collectRegisteredBaseClasses(type.rawType); + var baseTypes = collectRegisteredBaseClasses(type); for (var i = 0; i < baseTypes.length; i++) { var baseType = baseTypes[i]; resolveType(baseType); @@ -754,6 +754,7 @@ function ClassHandle() { function RegisteredClass(name, isPolymorphic, baseClassRawType) { this.name = name; this.isPolymorphic = isPolymorphic; + this.baseClassRawType = baseClassRawType; } // TODO: null pointers are always zero (not a Handle) in Javascript @@ -770,7 +771,7 @@ function __embind_register_class( rawDestructor = FUNCTION_TABLE[rawDestructor]; if (baseClassRawType) { - baseClasses[rawType] = [baseClassRawType]; + baseClasses[rawType] = baseClassRawType; } var registeredClass = new RegisteredClass(name, isPolymorphic, baseClassRawType); From ec62a534e990b20a3ff85cf7aa6da96e6f41e446 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 6 Mar 2013 03:44:42 -0800 Subject: [PATCH 294/544] Remove support for base class method/field name disambiguation: we don't use it yet and I have a method that will match the convention of JavaScript code --- src/embind/embind.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 3f10d886e2222..4086e2a50dadc 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -155,11 +155,6 @@ function resolveType(type) { if (!type.Handle.prototype.hasOwnProperty(name) && inheritedNames[name].length === 1) { baseClassType = inheritedNames[name][0]; createInheritedFunctionOrProperty(name, type, name, baseClassType); - } else { - for (var j = 0; j < inheritedNames[name].length; j++) { - baseClassType = inheritedNames[name][j]; - createInheritedFunctionOrProperty(baseClassType.name+"_"+name, type, name, baseClassType); - } } } } From ba6204bd5ca458a3999b5f6f056b267bb1d92fed Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 6 Mar 2013 14:21:43 -0800 Subject: [PATCH 295/544] Rewrite how dependent type registrations are implemented. This reduces code size both in JS and C++. There are some known bugs. I'll get to those soon. --- src/embind/embind.js | 236 ++++++++++++------------------- system/include/emscripten/bind.h | 50 +++++-- system/lib/embind/bind.cpp | 47 +++--- 3 files changed, 149 insertions(+), 184 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 4086e2a50dadc..f970317e8c17c 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -67,127 +67,58 @@ function _embind_repr(v) { } } -var typeRegistry = {}; -var deferredRegistrations = []; var baseClasses = {}; // rawType -> rawBaseType -function requestDeferredRegistration(registrationFunction) { - deferredRegistrations.push(registrationFunction); -} - -function performDeferredRegistrations(){ - while(deferredRegistrations.length > 0) { - var registrationFunction = deferredRegistrations.shift(); - registrationFunction(); - } -} - -function createInheritedFunctionOrProperty(name, type, nameInBaseClass, baseClassType) { - function upcastingWrapper(method) { - return function() { - var baseClassPtr = ___staticPointerCast(this.$$.ptr, type.rawType, baseClassType.rawType); - if (baseClassPtr === this.$$.ptr) { - return method.apply(this, arguments); - } else { - var handle = this.clone(); - try { - handle.$$.ptr = baseClassPtr; - return method.apply(handle, arguments); - } finally { - handle.delete(); - } - } - }; - } - var baseClassPrototype = baseClassType.Handle.prototype; - if (baseClassPrototype.constructor.memberType[nameInBaseClass] === 'field') { - var baseClassDescriptor = Object.getOwnPropertyDescriptor(baseClassPrototype, nameInBaseClass); - Object.defineProperty(type.Handle.prototype, name, { - enumerable: true, - get: upcastingWrapper(baseClassDescriptor.get), - set: upcastingWrapper(baseClassDescriptor.set) - }); - type.Handle.memberType[name] = 'field'; - } else if (baseClassPrototype.constructor.memberType[nameInBaseClass] === 'method') { - var baseClassMethod = baseClassPrototype[nameInBaseClass]; - type.Handle.prototype[name] = createNamedFunction(name, upcastingWrapper(baseClassMethod)); - type.Handle.memberType[name] = 'method'; - } -} - -function collectRegisteredBaseClasses(type) { - var rawType = type.rawType; - if (undefined === rawType) { - return []; - } - var rawBaseType = baseClasses[rawType]; - if (!rawBaseType) { - return []; - } - var baseType = typeRegistry[rawBaseType]; - if (baseType) { - return [baseType]; - } else { - return collectRegisteredBaseClasses(baseType); - } -} +// typeID -> { toWireType: ..., fromWireType: ... } +var registeredTypes = {}; -function resolveType(type) { - if (!type.resolved) { - var baseClassType, name, baseProto; - var inheritedNames = {}; - var baseTypes = collectRegisteredBaseClasses(type); - for (var i = 0; i < baseTypes.length; i++) { - var baseType = baseTypes[i]; - resolveType(baseType); - baseProto = baseType.Handle.prototype; - for (name in baseProto) { - if (baseProto.hasOwnProperty(name) && baseType.Handle.memberType[name]) { - if (!(name in inheritedNames)) { - inheritedNames[name] = []; - } - inheritedNames[name].push(baseType); - } - } - } - for (name in inheritedNames) { - if (inheritedNames.hasOwnProperty(name)) { - if (!type.Handle.prototype.hasOwnProperty(name) && inheritedNames[name].length === 1) { - baseClassType = inheritedNames[name][0]; - createInheritedFunctionOrProperty(name, type, name, baseClassType); - } - } - } - type.resolved = true; - } -} - -function resolveBindings() { - performDeferredRegistrations(); - for (var rawType in typeRegistry) { - if (typeRegistry.hasOwnProperty(rawType)) { - resolveType(typeRegistry[rawType]); - } - } -} +// typeID -> [callback] +var awaitingDependencies = {}; function registerType(rawType, registeredInstance) { var name = registeredInstance.name; if (!rawType) { throwBindingError('type "' + name + '" must have a positive integer typeid pointer'); } - if (typeRegistry.hasOwnProperty(rawType)) { + if (registeredTypes.hasOwnProperty(rawType)) { throwBindingError("Cannot register type '" + name + "' twice"); } - typeRegistry[rawType] = registeredInstance; + + registeredTypes[rawType] = registeredInstance; + + if (awaitingDependencies.hasOwnProperty(rawType)) { + var callbacks = awaitingDependencies[rawType]; + delete awaitingDependencies[rawType]; + callbacks.forEach(function(cb) { + cb(); + }); + } } -function requireRegisteredType(rawType, humanName) { - var impl = typeRegistry[rawType]; - if (undefined === impl) { - throwBindingError(humanName + " has unknown type " + typeName(rawType)); +function whenDependentTypesAreResolved(dependentTypes, onComplete) { + var typeConverters = new Array(dependentTypes.length); + var unregisteredTypes = []; + var registered = 0; + dependentTypes.forEach(function(dt, i) { + if (registeredTypes.hasOwnProperty(dt)) { + typeConverters[i] = registeredTypes[dt]; + } else { + unregisteredTypes.push(dt); + if (!awaitingDependencies.hasOwnProperty(dt)) { + awaitingDependencies[dt] = []; + } + awaitingDependencies[dt].push(function() { + typeConverters[i] = registeredTypes[dt]; + ++registered; + if (registered === unregisteredTypes.length) { + onComplete(typeConverters); + } + }); + } + }); + if (0 === unregisteredTypes.length) { + onComplete(typeConverters); } - return impl; } function typeName(rawType) { @@ -205,17 +136,27 @@ function heap32VectorToArray(count, firstElement) { return array; } +function requireRegisteredType(rawType, humanName) { + var impl = registeredTypes[rawType]; + if (undefined === impl) { + throwBindingError(humanName + " has unknown type " + typeName(rawType)); + } + return impl; +} + +/* function requireArgumentTypes(rawArgTypes, name) { var argTypes = []; for (var i = 0; i < rawArgTypes.length; ++i) { - if (i === 0) { - argTypes[i] = requireRegisteredType(rawArgTypes[i], name + " return value"); - } else { - argTypes[i] = requireRegisteredType(rawArgTypes[i], name + " parameter " + i); - } + argTypes[i] = requireRegisteredType( + rawArgTypes[i], + i === 0 ? + name + " return value" : + name + " parameter " + i); } return argTypes; } +*/ function staticPointerCast(from, fromType, toType) { if (!from) { @@ -362,11 +303,10 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { } function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, fn) { - var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); + var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); name = Pointer_stringify(name); rawInvoker = FUNCTION_TABLE[rawInvoker]; - requestDeferredRegistration(function() { - var argTypes = requireArgumentTypes(rawArgTypes, name); + whenDependentTypesAreResolved(argTypes, function(argTypes) { exposePublicSymbol(name, makeInvoker(name, argCount, argTypes, rawInvoker, fn)); }); } @@ -425,10 +365,11 @@ function __embind_register_tuple_element( getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); + var tupleType = requireRegisteredType(rawTupleType, 'tuple'); + // TODO: this could register elements out of order - requestDeferredRegistration(function() { - var tupleType = requireRegisteredType(rawTupleType, 'tuple'); - var type = requireRegisteredType(rawType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); + whenDependentTypesAreResolved([rawType], function(type) { + type = type[0]; tupleType.elements.push({ read: function(ptr) { return type.fromWireType(getter(ptr, memberPointer)); @@ -452,13 +393,14 @@ function __embind_register_tuple_element_accessor( setterSize, setter ) { + var tupleType = requireRegisteredType(rawTupleType, 'tuple'); rawStaticGetter = FUNCTION_TABLE[rawStaticGetter]; getter = copyMemberPointer(getter, getterSize); rawStaticSetter = FUNCTION_TABLE[rawStaticSetter]; setter = copyMemberPointer(setter, setterSize); - requestDeferredRegistration(function() { - var tupleType = requireRegisteredType(rawTupleType, 'tuple'); - var elementType = requireRegisteredType(rawElementType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); + + whenDependentTypesAreResolved([rawElementType], function(elementType) { + elementType = elementType[0]; tupleType.elements.push({ read: function(ptr) { return elementType.fromWireType(rawStaticGetter(ptr, HEAP32[getter >> 2])); @@ -526,14 +468,14 @@ function __embind_register_struct_field( memberPointerSize, memberPointer ) { + var structType = requireRegisteredType(rawStructType, 'struct'); fieldName = Pointer_stringify(fieldName); rawGetter = FUNCTION_TABLE[rawGetter]; rawSetter = FUNCTION_TABLE[rawSetter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); // TODO: this could register elements out of order - requestDeferredRegistration(function() { - var structType = requireRegisteredType(rawStructType, 'struct'); - var fieldType = requireRegisteredType(rawFieldType, 'field "' + structType.name + '.' + fieldName + '"'); + whenDependentTypesAreResolved([rawFieldType], function(fieldType) { + fieldType = fieldType[0]; structType.fields[fieldName] = { read: function(ptr) { return fieldType.fromWireType(rawGetter(ptr, memberPointer)); @@ -638,7 +580,7 @@ RegisteredPointer.prototype.getDynamicDowncastType = function(ptr) { if (type && type !== this.pointeeType.rawType) { var derivation = Module.__getDerivationPath(type, this.pointeeType.rawType); for (var i = 0; i < derivation.size(); i++) { - downcastType = typeRegistry[derivation.get(i)]; + downcastType = registeredTypes[derivation.get(i)]; if (downcastType && (!this.isSmartPointer || downcastType.smartPointerType)) { break; } @@ -758,18 +700,34 @@ function __embind_register_class( rawPointerType, rawConstPointerType, baseClassRawType, + upcast, + downcast, isPolymorphic, name, rawDestructor ) { name = Pointer_stringify(name); rawDestructor = FUNCTION_TABLE[rawDestructor]; + upcast = FUNCTION_TABLE[upcast]; + downcast = FUNCTION_TABLE[downcast]; + var basePrototype; if (baseClassRawType) { baseClasses[rawType] = baseClassRawType; + + // TODO: allow registration of base after derived + var base = requireRegisteredType(baseClassRawType, 'base class'); + basePrototype = base.Handle.prototype; + } else { + basePrototype = ClassHandle.prototype; } - var registeredClass = new RegisteredClass(name, isPolymorphic, baseClassRawType); + var registeredClass = new RegisteredClass( + name, + isPolymorphic, + baseClassRawType, + upcast, + downcast); var Handle = createNamedFunction(name, function(ptr) { Object.defineProperty(this, '$$', { @@ -781,7 +739,7 @@ function __embind_register_class( }); }); - Handle.prototype = Object.create(ClassHandle.prototype, { + Handle.prototype = Object.create(basePrototype, { constructor: { value: Handle }, }); Handle.prototype.clone = function() { @@ -814,7 +772,6 @@ function __embind_register_class( } this.$$.ptr = undefined; }; - Handle.memberType = {}; // todo: clean this up! var type = new RegisteredPointer( @@ -867,13 +824,12 @@ function __embind_register_class_constructor( invoker, rawConstructor ) { + var classType = requireRegisteredType(rawClassType, 'class'); var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); invoker = FUNCTION_TABLE[invoker]; - requestDeferredRegistration(function() { - var classType = requireRegisteredType(rawClassType, 'class'); + whenDependentTypesAreResolved(rawArgTypes, function(argTypes) { var humanName = 'constructor ' + classType.name; - var argTypes = requireArgumentTypes(rawArgTypes, humanName); classType.constructor.body = function() { if (arguments.length !== argCount - 1) { throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); @@ -902,14 +858,13 @@ function __embind_register_class_method( memberFunctionSize, memberFunction ) { + var classType = requireRegisteredType(rawClassType, 'class'); var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = Pointer_stringify(methodName); rawInvoker = FUNCTION_TABLE[rawInvoker]; memberFunction = copyMemberPointer(memberFunction, memberFunctionSize); - requestDeferredRegistration(function() { - var classType = requireRegisteredType(rawClassType, 'class'); + whenDependentTypesAreResolved(rawArgTypes, function(argTypes) { var humanName = classType.name + '.' + methodName; - var argTypes = requireArgumentTypes(rawArgTypes, 'method ' + humanName); classType.Handle.prototype[methodName] = function() { if (!this.$$.ptr) { throwBindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); @@ -934,7 +889,6 @@ function __embind_register_class_method( runDestructors(destructors); return rv; }; - classType.Handle.memberType[methodName] = "method"; }); } @@ -946,13 +900,12 @@ function __embind_register_class_classmethod( rawInvoker, fn ) { + var classType = requireRegisteredType(rawClassType, 'class'); var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = Pointer_stringify(methodName); rawInvoker = FUNCTION_TABLE[rawInvoker]; - requestDeferredRegistration(function() { - var classType = requireRegisteredType(rawClassType, 'class'); + whenDependentTypesAreResolved(rawArgTypes, function(argTypes) { var humanName = classType.name + '.' + methodName; - var argTypes = requireArgumentTypes(rawArgTypes, 'classmethod ' + humanName); classType.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn); }); } @@ -966,14 +919,14 @@ function __embind_register_class_field( memberPointerSize, memberPointer ) { + var classType = requireRegisteredType(rawClassType, 'class'); fieldName = Pointer_stringify(fieldName); getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); - requestDeferredRegistration(function() { - var classType = requireRegisteredType(rawClassType, 'class'); + whenDependentTypesAreResolved([rawFieldType], function(fieldType) { var humanName = classType.name + '.' + fieldName; - var fieldType = requireRegisteredType(rawFieldType, 'field ' + humanName); + fieldType = fieldType[0]; Object.defineProperty(classType.Handle.prototype, fieldName, { get: function() { if (!this.$$.ptr) { @@ -991,7 +944,6 @@ function __embind_register_class_field( }, enumerable: true }); - classType.Handle.memberType[fieldName] = "field"; }); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 24a7bf71e5c5d..e8cedbe496891 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -106,6 +106,8 @@ namespace emscripten { TYPEID pointerType, TYPEID constPointerType, TYPEID baseClassType, + GenericFunction upcast, + GenericFunction downcast, bool isPolymorphic, const char* className, GenericFunction destructor); @@ -159,8 +161,6 @@ namespace emscripten { GenericFunction destructor); } - extern void registerStandardTypes(); - class BindingsDefinition { public: template @@ -248,9 +248,6 @@ namespace emscripten { template void function(const char* name, ReturnType (*fn)(Args...), Policies...) { using namespace internal; - - registerStandardTypes(); - typename WithPolicies::template ArgTypeList args; _embind_register_function( name, @@ -415,7 +412,6 @@ namespace emscripten { class value_tuple { public: value_tuple(const char* name) { - internal::registerStandardTypes(); internal::_embind_register_tuple( internal::TypeID::get(), name, @@ -501,7 +497,6 @@ namespace emscripten { class value_struct { public: value_struct(const char* name) { - internal::registerStandardTypes(); internal::_embind_register_struct( internal::TypeID::get(), name, @@ -562,7 +557,6 @@ namespace emscripten { using namespace internal; typedef typename smart_ptr_trait::element_type PointeeType; - registerStandardTypes(); _embind_register_smart_ptr( TypeID::get(), TypeID::get(), @@ -613,27 +607,52 @@ namespace emscripten { namespace internal { struct NoBaseClass { + template + static void verify() { + } + static TYPEID get() { - return 0; + return nullptr; } template - static void verify() { + static GenericFunction getUpcaster() { + return nullptr; + } + + template + static GenericFunction getDowncaster() { + return nullptr; } }; } template struct base { - static internal::TYPEID get() { - return internal::TypeID::get(); - } - template static void verify() { static_assert(!std::is_same::value, "Base must not have same type as class"); static_assert(std::is_base_of::value, "Derived class must derive from base"); } + + static internal::TYPEID get() { + return internal::TypeID::get(); + } + + template + static internal::GenericFunction getUpcaster() { + return reinterpret_cast(&convertPointer); + } + + template + static internal::GenericFunction getDowncaster() { + return reinterpret_cast(&convertPointer); + } + + template + static To* convertPointer(From* ptr) { + return static_cast(ptr); + } }; template @@ -644,12 +663,13 @@ namespace emscripten { BaseSpecifier::template verify(); - registerStandardTypes(); _embind_register_class( TypeID::get(), TypeID>::get(), TypeID>::get(), BaseSpecifier::get(), + BaseSpecifier::template getUpcaster(), + BaseSpecifier::template getDowncaster(), std::is_polymorphic::value, name, reinterpret_cast(&raw_destructor)); diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index cbff7cf1db2a2..6c792f7874151 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -66,33 +66,6 @@ namespace __cxxabiv1 { namespace emscripten { namespace internal { - void registerStandardTypes() { - static bool first = true; - if (first) { - first = false; - - _embind_register_void(TypeID::get(), "void"); - - _embind_register_bool(TypeID::get(), "bool", true, false); - - _embind_register_integer(TypeID::get(), "char"); - _embind_register_integer(TypeID::get(), "signed char"); - _embind_register_integer(TypeID::get(), "unsigned char"); - _embind_register_integer(TypeID::get(), "short"); - _embind_register_integer(TypeID::get(), "unsigned short"); - _embind_register_integer(TypeID::get(), "int"); - _embind_register_integer(TypeID::get(), "unsigned int"); - _embind_register_integer(TypeID::get(), "long"); - _embind_register_integer(TypeID::get(), "unsigned long"); - - _embind_register_float(TypeID::get(), "float"); - _embind_register_float(TypeID::get(), "double"); - - _embind_register_cstring(TypeID::get(), "std::string"); - _embind_register_emval(TypeID::get(), "emscripten::val"); - } - } - // __getDerivationPath returns an array of type_info pointers describing the derivation chain starting with // the derived type and proceeding toward (and ending with) the base type. Types are only included if they // appear on all possible derivation paths. @@ -216,6 +189,26 @@ namespace emscripten { } EMSCRIPTEN_BINDINGS(([]() { + _embind_register_void(TypeID::get(), "void"); + + _embind_register_bool(TypeID::get(), "bool", true, false); + + _embind_register_integer(TypeID::get(), "char"); + _embind_register_integer(TypeID::get(), "signed char"); + _embind_register_integer(TypeID::get(), "unsigned char"); + _embind_register_integer(TypeID::get(), "short"); + _embind_register_integer(TypeID::get(), "unsigned short"); + _embind_register_integer(TypeID::get(), "int"); + _embind_register_integer(TypeID::get(), "unsigned int"); + _embind_register_integer(TypeID::get(), "long"); + _embind_register_integer(TypeID::get(), "unsigned long"); + + _embind_register_float(TypeID::get(), "float"); + _embind_register_float(TypeID::get(), "double"); + + _embind_register_cstring(TypeID::get(), "std::string"); + _embind_register_emval(TypeID::get(), "emscripten::val"); + // We bind __getDerivationPath in order to take advantage of the std::vector to Javascript array // conversion for the return value. This has the unfortunate side-effect of exposing it to third party // developers, but perhaps the double underscore will scare them away from calling it. From 4f18c7eed89ad5f6b77c153f82618c8fe918c3c8 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 6 Mar 2013 19:16:19 -0800 Subject: [PATCH 296/544] test and fix for calling base class methods with pointer fixups --- src/embind/embind.js | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index f970317e8c17c..696b0c988ec4b 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -688,10 +688,20 @@ function __embind_register_smart_ptr( function ClassHandle() { } -function RegisteredClass(name, isPolymorphic, baseClassRawType) { +function RegisteredClass( + name, + isPolymorphic, + baseClassRawType, + baseClass, + upcast, + downcast +) { this.name = name; this.isPolymorphic = isPolymorphic; this.baseClassRawType = baseClassRawType; + this.baseClass = baseClass; + this.upcast = upcast; + this.downcast = downcast; } // TODO: null pointers are always zero (not a Handle) in Javascript @@ -711,12 +721,15 @@ function __embind_register_class( upcast = FUNCTION_TABLE[upcast]; downcast = FUNCTION_TABLE[downcast]; + var baseClass; var basePrototype; + var depth; if (baseClassRawType) { baseClasses[rawType] = baseClassRawType; // TODO: allow registration of base after derived var base = requireRegisteredType(baseClassRawType, 'base class'); + baseClass = base.registeredClass; basePrototype = base.Handle.prototype; } else { basePrototype = ClassHandle.prototype; @@ -726,6 +739,7 @@ function __embind_register_class( name, isPolymorphic, baseClassRawType, + baseClass, upcast, downcast); @@ -849,6 +863,14 @@ function __embind_register_class_constructor( }); } +function upcastPointer(ptr, ptrClass, desiredClass) { + while (ptrClass !== desiredClass) { + ptr = ptrClass.upcast(ptr); + ptrClass = ptrClass.baseClass; + } + return ptr; +} + function __embind_register_class_method( rawClassType, methodName, @@ -873,9 +895,15 @@ function __embind_register_class_method( throwBindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } + // TODO: error if pointer type doesn't match signature + var ptr = upcastPointer( + this.$$.ptr, + this.$$.pointeeType.registeredClass, + classType.registeredClass); + var destructors = []; var args = new Array(argCount + 1); - args[0] = this.$$.ptr; + args[0] = ptr; args[1] = memberFunction; for (var i = 1; i < argCount; ++i) { args[i + 1] = argTypes[i].toWireType(destructors, arguments[i - 1]); @@ -900,6 +928,7 @@ function __embind_register_class_classmethod( rawInvoker, fn ) { + // todo: whenDependentTypesAreResolved var classType = requireRegisteredType(rawClassType, 'class'); var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = Pointer_stringify(methodName); @@ -919,6 +948,7 @@ function __embind_register_class_field( memberPointerSize, memberPointer ) { + // todo: whenDependentTypesAreResolved var classType = requireRegisteredType(rawClassType, 'class'); fieldName = Pointer_stringify(fieldName); getter = FUNCTION_TABLE[getter]; From 2d45bdd07e5c45be824f42c715097341565cc8f3 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 6 Mar 2013 19:24:39 -0800 Subject: [PATCH 297/544] fix pointer adjustments in property access --- src/embind/embind.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 696b0c988ec4b..ea56097fcef05 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -962,14 +962,28 @@ function __embind_register_class_field( if (!this.$$.ptr) { throwBindingError('cannot access emscripten binding field ' + humanName + ' on deleted object'); } - return fieldType.fromWireType(getter(this.$$.ptr, memberPointer)); + + // TODO: error if pointer type doesn't match signature + var ptr = upcastPointer( + this.$$.ptr, + this.$$.pointeeType.registeredClass, + classType.registeredClass); + + return fieldType.fromWireType(getter(ptr, memberPointer)); }, set: function(v) { if (!this.$$.ptr) { throwBindingError('cannot modify emscripten binding field ' + humanName + ' on deleted object'); } + + // TODO: error if pointer type doesn't match signature + var ptr = upcastPointer( + this.$$.ptr, + this.$$.pointeeType.registeredClass, + classType.registeredClass); + var destructors = []; - setter(this.$$.ptr, memberPointer, fieldType.toWireType(destructors, v)); + setter(ptr, memberPointer, fieldType.toWireType(destructors, v)); runDestructors(destructors); }, enumerable: true From 6a1157c12b27a50dc129b05cdb47bf9adb8812b5 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 02:12:35 -0800 Subject: [PATCH 298/544] Make it possible (again) to define a class before its base class is defined. --- src/embind/embind.js | 339 +++++++++++++++---------------- system/include/emscripten/bind.h | 4 +- 2 files changed, 169 insertions(+), 174 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index ea56097fcef05..a644c16c4c6a4 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -144,20 +144,6 @@ function requireRegisteredType(rawType, humanName) { return impl; } -/* -function requireArgumentTypes(rawArgTypes, name) { - var argTypes = []; - for (var i = 0; i < rawArgTypes.length; ++i) { - argTypes[i] = requireRegisteredType( - rawArgTypes[i], - i === 0 ? - name + " return value" : - name + " parameter " + i); - } - return argTypes; -} -*/ - function staticPointerCast(from, fromType, toType) { if (!from) { return from; @@ -620,69 +606,72 @@ function __embind_register_smart_ptr( rawGetPointee ) { name = Pointer_stringify(name); - var pointeeType = requireRegisteredType(rawPointeeType, 'class'); rawConstructor = FUNCTION_TABLE[rawConstructor]; rawDestructor = FUNCTION_TABLE[rawDestructor]; rawGetPointee = FUNCTION_TABLE[rawGetPointee]; - var Handle = createNamedFunction(name, function(ptr) { - Object.defineProperty(this, '$$', { - value: { - count: {value: 1}, - smartPtr: ptr, - ptr: rawGetPointee(ptr), - pointeeType: pointeeType, - }, + whenDependentTypesAreResolved([rawPointeeType], function(pointeeType) { + pointeeType = pointeeType[0]; + + var Handle = createNamedFunction(name, function(ptr) { + Object.defineProperty(this, '$$', { + value: { + count: {value: 1}, + smartPtr: ptr, + ptr: rawGetPointee(ptr), + pointeeType: pointeeType, + }, + }); }); - }); - // TODO: test for SmartPtr.prototype.constructor property? - // We likely want it distinct from pointeeType.prototype.constructor - Handle.prototype = Object.create(pointeeType.Handle.prototype); - - Handle.prototype.clone = function() { - if (!this.$$.ptr) { - throwBindingError(pointeeType.name + ' instance already deleted'); - } + // TODO: test for SmartPtr.prototype.constructor property? + // We likely want it distinct from pointeeType.prototype.constructor + Handle.prototype = Object.create(pointeeType.Handle.prototype); - var clone = Object.create(Handle.prototype); - Object.defineProperty(clone, '$$', { - value: { - count: this.$$.count, - smartPtr: this.$$.smartPtr, - ptr: this.$$.ptr, - }, - }); + Handle.prototype.clone = function() { + if (!this.$$.ptr) { + throwBindingError(pointeeType.name + ' instance already deleted'); + } - clone.$$.count.value += 1; - return clone; - }; + var clone = Object.create(Handle.prototype); + Object.defineProperty(clone, '$$', { + value: { + count: this.$$.count, + smartPtr: this.$$.smartPtr, + ptr: this.$$.ptr, + }, + }); - Handle.prototype['delete'] = function() { - if (!this.$$.ptr) { - throwBindingError(pointeeType.name + ' instance already deleted'); - } + clone.$$.count.value += 1; + return clone; + }; - this.$$.count.value -= 1; - if (0 === this.$$.count.value) { - rawDestructor(this.$$.smartPtr); - } - this.$$.smartPtr = undefined; - this.$$.ptr = undefined; - }; + Handle.prototype['delete'] = function() { + if (!this.$$.ptr) { + throwBindingError(pointeeType.name + ' instance already deleted'); + } - var registeredPointer = new RegisteredPointer( - name, - rawType, - pointeeType.registeredClass, - pointeeType, - Handle, - true, - rawGetPointee, - rawConstructor, - rawDestructor); - registerType(rawType, registeredPointer); - pointeeType.smartPointerType = registeredPointer; + this.$$.count.value -= 1; + if (0 === this.$$.count.value) { + rawDestructor(this.$$.smartPtr); + } + this.$$.smartPtr = undefined; + this.$$.ptr = undefined; + }; + + var registeredPointer = new RegisteredPointer( + name, + rawType, + pointeeType.registeredClass, + pointeeType, + Handle, + true, + rawGetPointee, + rawConstructor, + rawDestructor); + registerType(rawType, registeredPointer); + pointeeType.smartPointerType = registeredPointer; + }); } function ClassHandle() { @@ -704,7 +693,6 @@ function RegisteredClass( this.downcast = downcast; } -// TODO: null pointers are always zero (not a Handle) in Javascript function __embind_register_class( rawType, rawPointerType, @@ -721,114 +709,116 @@ function __embind_register_class( upcast = FUNCTION_TABLE[upcast]; downcast = FUNCTION_TABLE[downcast]; - var baseClass; - var basePrototype; - var depth; - if (baseClassRawType) { - baseClasses[rawType] = baseClassRawType; - - // TODO: allow registration of base after derived - var base = requireRegisteredType(baseClassRawType, 'base class'); - baseClass = base.registeredClass; - basePrototype = base.Handle.prototype; - } else { - basePrototype = ClassHandle.prototype; - } + whenDependentTypesAreResolved(baseClassRawType ? [baseClassRawType] : [], function(base) { + base = base[0]; - var registeredClass = new RegisteredClass( - name, - isPolymorphic, - baseClassRawType, - baseClass, - upcast, - downcast); - - var Handle = createNamedFunction(name, function(ptr) { - Object.defineProperty(this, '$$', { - value: { - count: {value: 1, ptr: ptr}, - ptr: ptr, - pointeeType: type, - } - }); - }); + var baseClass; + var basePrototype; + var depth; + if (baseClassRawType) { + baseClasses[rawType] = baseClassRawType; - Handle.prototype = Object.create(basePrototype, { - constructor: { value: Handle }, - }); - Handle.prototype.clone = function() { - if (!this.$$.ptr) { - throwBindingError(type.name + ' instance already deleted'); + baseClass = base.registeredClass; + basePrototype = base.Handle.prototype; + } else { + basePrototype = ClassHandle.prototype; } - var clone = Object.create(Handle.prototype); - Object.defineProperty(clone, '$$', { - value: { - count: this.$$.count, - ptr: this.$$.ptr, - }, + var registeredClass = new RegisteredClass( + name, + isPolymorphic, + baseClassRawType, + baseClass, + upcast, + downcast); + + var Handle = createNamedFunction(name, function(ptr) { + Object.defineProperty(this, '$$', { + value: { + count: {value: 1, ptr: ptr}, + ptr: ptr, + pointeeType: type, + } + }); }); + + Handle.prototype = Object.create(basePrototype, { + constructor: { value: Handle }, + }); + Handle.prototype.clone = function() { + if (!this.$$.ptr) { + throwBindingError(type.name + ' instance already deleted'); + } - clone.$$.count.value += 1; - return clone; - }; + var clone = Object.create(Handle.prototype); + Object.defineProperty(clone, '$$', { + value: { + count: this.$$.count, + ptr: this.$$.ptr, + }, + }); - // todo: test delete with upcast and downcast multiply derived pointers - // todo: then replace this.$$.count.ptr below with this.$$.ptr and make sure it fails - Handle.prototype['delete'] = function() { - if (!this.$$.ptr) { - throwBindingError(type.name + ' instance already deleted'); // todo: but 'type' hasn't been resolved!?! - } + clone.$$.count.value += 1; + return clone; + }; - this.$$.count.value -= 1; - if (0 === this.$$.count.value) { - rawDestructor(this.$$.count.ptr); - } - this.$$.ptr = undefined; - }; + // todo: test delete with upcast and downcast multiply derived pointers + // todo: then replace this.$$.count.ptr below with this.$$.ptr and make sure it fails + Handle.prototype['delete'] = function() { + if (!this.$$.ptr) { + throwBindingError(type.name + ' instance already deleted'); // todo: but 'type' hasn't been resolved!?! + } + + this.$$.count.value -= 1; + if (0 === this.$$.count.value) { + rawDestructor(this.$$.count.ptr); + } + this.$$.ptr = undefined; + }; - // todo: clean this up! - var type = new RegisteredPointer( - name, - rawType, - registeredClass, - undefined, - Handle, - false); - type.pointeeType = type; // :( - registerType(rawType, type); - - registerType(rawPointerType, new RegisteredPointer( - name + '*', - rawPointerType, - registeredClass, - type, - Handle, - false)); - - // todo: implement const pointers (no modification Javascript side) - registerType(rawConstPointerType, new RegisteredPointer( - name + ' const*', - rawConstPointerType, - registeredClass, - type, - Handle, - false)); - - type.constructor = createNamedFunction(name, function() { - if (Object.getPrototypeOf(this) !== Handle.prototype) { - throw new BindingError("Use 'new' to construct " + name); - } - var body = type.constructor.body; - if (undefined === body) { - throw new BindingError(name + " has no accessible constructor"); - } - return body.apply(this, arguments); - }); - type.constructor.prototype = type.Handle.prototype; - type.constructor.type = type; + // todo: clean this up! + var type = new RegisteredPointer( + name, + rawType, + registeredClass, + undefined, + Handle, + false); + type.pointeeType = type; // :( + registerType(rawType, type); + + registerType(rawPointerType, new RegisteredPointer( + name + '*', + rawPointerType, + registeredClass, + type, + Handle, + false)); + + // todo: implement const pointers (no modification Javascript side) + registerType(rawConstPointerType, new RegisteredPointer( + name + ' const*', + rawConstPointerType, + registeredClass, + type, + Handle, + false)); + + type.constructor = createNamedFunction(name, function() { + if (Object.getPrototypeOf(this) !== Handle.prototype) { + throw new BindingError("Use 'new' to construct " + name); + } + var body = type.constructor_body; + if (undefined === body) { + throw new BindingError(name + " has no accessible constructor"); + } + return body.apply(this, arguments); + }); + type.constructor.prototype = type.Handle.prototype; + type.constructor.type = type; - exposePublicSymbol(name, type.constructor); + exposePublicSymbol(name, type.constructor); + }); } function __embind_register_class_constructor( @@ -838,13 +828,14 @@ function __embind_register_class_constructor( invoker, rawConstructor ) { - var classType = requireRegisteredType(rawClassType, 'class'); var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); invoker = FUNCTION_TABLE[invoker]; - whenDependentTypesAreResolved(rawArgTypes, function(argTypes) { + whenDependentTypesAreResolved([rawClassType].concat(rawArgTypes), function(argTypes) { + var classType = argTypes[0]; + argTypes = argTypes.slice(1); var humanName = 'constructor ' + classType.name; - classType.constructor.body = function() { + classType.constructor_body = function() { if (arguments.length !== argCount - 1) { throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } @@ -880,12 +871,14 @@ function __embind_register_class_method( memberFunctionSize, memberFunction ) { - var classType = requireRegisteredType(rawClassType, 'class'); var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = Pointer_stringify(methodName); rawInvoker = FUNCTION_TABLE[rawInvoker]; memberFunction = copyMemberPointer(memberFunction, memberFunctionSize); - whenDependentTypesAreResolved(rawArgTypes, function(argTypes) { + + whenDependentTypesAreResolved([rawClassType].concat(rawArgTypes), function(argTypes) { + var classType = argTypes[0]; + argTypes = argTypes.slice(1); var humanName = classType.name + '.' + methodName; classType.Handle.prototype[methodName] = function() { if (!this.$$.ptr) { @@ -949,14 +942,14 @@ function __embind_register_class_field( memberPointer ) { // todo: whenDependentTypesAreResolved - var classType = requireRegisteredType(rawClassType, 'class'); fieldName = Pointer_stringify(fieldName); getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); - whenDependentTypesAreResolved([rawFieldType], function(fieldType) { + whenDependentTypesAreResolved([rawClassType, rawFieldType], function(converters) { + var classType = converters[0]; + var fieldType = converters[1]; var humanName = classType.name + '.' + fieldName; - fieldType = fieldType[0]; Object.defineProperty(classType.Handle.prototype, fieldName, { get: function() { if (!this.$$.ptr) { diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index e8cedbe496891..e8a8dc1dd7092 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -658,7 +658,9 @@ namespace emscripten { template class class_ { public: - class_(const char* name) { + class_() = delete; + + explicit class_(const char* name) { using namespace internal; BaseSpecifier::template verify(); From b4b75b51bf0e8c72aa8514eaf708b1d1aae30a8e Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 03:08:35 -0800 Subject: [PATCH 299/544] Is this okay? It passes tests. --- src/embind/embind.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index a644c16c4c6a4..19c248128e653 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -517,10 +517,10 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { // assumes that smart_ptr has an identical binary layout to // smart_ptr. I wonder if that's untrue for any common // smart pointer. - chad - ptr = pointeeType.smartPointerType.rawConstructor( + ptr = this.rawConstructor( ptr, handle.$$.smartPtr); - destructors.push(pointeeType.smartPointerType.rawDestructor); + destructors.push(this.rawDestructor); destructors.push(ptr); } return ptr; From 612340cec2f3761efffc450e1de0adb445a45036 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 15:32:47 -0800 Subject: [PATCH 300/544] oh hey, you can use .push with multiple arguments Conflicts: src/embind/embind.js --- src/embind/embind.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 19c248128e653..5d6e6c21ec7b4 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -233,8 +233,7 @@ function __embind_register_cstring(rawType, name) { for (var i = 0; i < length; ++i) { HEAPU8[ptr + 4 + i] = value.charCodeAt(i); } - destructors.push(_free); - destructors.push(ptr); + destructors.push(_free, ptr); return ptr; }, }); @@ -324,8 +323,7 @@ function __embind_register_tuple(rawType, name, rawConstructor, rawDestructor) { for (var i = 0; i < len; ++i) { this.elements[i].write(ptr, o[i]); } - destructors.push(rawDestructor); - destructors.push(ptr); + destructors.push(rawDestructor, ptr); return ptr; }, }); @@ -438,8 +436,7 @@ function __embind_register_struct( for (fieldName in fields) { fields[fieldName].write(ptr, o[fieldName]); } - destructors.push(rawDestructor); - destructors.push(ptr); + destructors.push(rawDestructor, ptr); return ptr; }, }); @@ -520,8 +517,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { ptr = this.rawConstructor( ptr, handle.$$.smartPtr); - destructors.push(this.rawDestructor); - destructors.push(ptr); + destructors.push(this.rawDestructor, ptr); } return ptr; }; @@ -1042,8 +1038,7 @@ function __embind_register_interface( toWireType: function(destructors, o) { var handle = __emval_register(o); var ptr = this.rawConstructor(handle); - destructors.push(this.rawDestructor); - destructors.push(ptr); + destructors.push(this.rawDestructor, ptr); return ptr; }, }); From 6a0976ce2e1006cda317625e294aa878045e305a Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 15:42:13 -0800 Subject: [PATCH 301/544] checkpoint work towards unifying the binding type for classes and smart pointers. --- src/embind/embind.js | 8 +++++++- system/include/emscripten/bind.h | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 5d6e6c21ec7b4..83c3841f91a77 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -491,7 +491,13 @@ RegisteredPointer.prototype.isPolymorphic = function() { RegisteredPointer.prototype.toWireType = function(destructors, handle) { var fromRawType; if (handle === null) { - return 0; // todo: maybe this should return a zero-initialized smart pointer object + if (this.isSmartPointer) { + var ptr = this.rawConstructor(0, 0); + destructors.push(this.rawDestructor, ptr); + return ptr; + } else { + return 0; + } } if (!(handle instanceof ClassHandle)) { throwBindingError('Expected pointer or null, got ' + IMVU.repr(handle)); diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index e8a8dc1dd7092..7dcfa61b90381 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -543,7 +543,11 @@ namespace emscripten { typename smart_ptr_trait::element_type* ptr, SmartPointerType* basePtr ) { - return new SmartPointerType(smart_ptr_trait::share(*basePtr, ptr)); + if (ptr) { + return new SmartPointerType(smart_ptr_trait::share(*basePtr, ptr)); + } else { + return new SmartPointerType; + } } template From 3dd168f24a0294e7f306514d0bb71985457ab976 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 15:55:25 -0800 Subject: [PATCH 302/544] checkpoint work towards unifying the binding type for classes and smart pointers. --- system/include/emscripten/wire.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index d4efc3acffa26..f782d49e22e42 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -241,11 +241,7 @@ namespace emscripten { } static shared_ptr fromWireType(WireType wt) { - if (wt) { - return shared_ptr(*wt); - } else { - return shared_ptr(); - } + return *wt; } static void destroy(WireType p) { From 3ac210596939afee0397fac8d298975d2982bff1 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 16:04:16 -0800 Subject: [PATCH 303/544] Kill the custom bindingtype for shared_ptr :) --- system/include/emscripten/wire.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index f782d49e22e42..5126c4be76768 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -231,24 +231,6 @@ namespace emscripten { } }; - template - struct BindingType> { - typedef std::shared_ptr shared_ptr; - typedef std::shared_ptr* WireType; - - static WireType toWireType(shared_ptr p) { - return new shared_ptr(p); - } - - static shared_ptr fromWireType(WireType wt) { - return *wt; - } - - static void destroy(WireType p) { - delete p; - } - }; - template struct EnumBindingType { typedef Enum WireType; From e7faeb6d50e26e74d21cc06b7eae8929752f4526 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 16:29:10 -0800 Subject: [PATCH 304/544] reorder bindingtypes to make it easy to read --- system/include/emscripten/wire.h | 53 ++++++++++++++++---------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 5126c4be76768..07919a5e55a34 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -231,20 +231,6 @@ namespace emscripten { } }; - template - struct EnumBindingType { - typedef Enum WireType; - - static WireType toWireType(Enum v) { - return v; - } - static Enum fromWireType(WireType v) { - return v; - } - static void destroy(WireType) { - } - }; - template struct GenericBindingType { typedef typename std::remove_reference::type ActualT; @@ -263,6 +249,7 @@ namespace emscripten { } }; + // Is this necessary? template struct GenericBindingType> { typedef typename BindingType::WireType WireType; @@ -272,19 +259,18 @@ namespace emscripten { } }; - template - struct WireDeleter { - typedef typename BindingType::WireType WireType; - - WireDeleter(WireType wt) - : wt(wt) - {} - - ~WireDeleter() { - BindingType::destroy(wt); + template + struct EnumBindingType { + typedef Enum WireType; + + static WireType toWireType(Enum v) { + return v; + } + static Enum fromWireType(WireType v) { + return v; + } + static void destroy(WireType) { } - - WireType wt; }; // catch-all generic binding @@ -299,5 +285,20 @@ namespace emscripten { auto toWireType(const T& v) -> typename BindingType::WireType { return BindingType::toWireType(v); } + + template + struct WireDeleter { + typedef typename BindingType::WireType WireType; + + WireDeleter(WireType wt) + : wt(wt) + {} + + ~WireDeleter() { + BindingType::destroy(wt); + } + + WireType wt; + }; } } From 6a14788d73acac51770fd68d63cb8c5531efdfb2 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 17:30:06 -0800 Subject: [PATCH 305/544] It is illegal to pass null as a by-value argument. --- src/embind/embind.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index 83c3841f91a77..ed659a2b177ac 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -491,6 +491,10 @@ RegisteredPointer.prototype.isPolymorphic = function() { RegisteredPointer.prototype.toWireType = function(destructors, handle) { var fromRawType; if (handle === null) { + if (this.pointeeType === this) { + throwBindingError('null is not a valid ' + this.name); + } + if (this.isSmartPointer) { var ptr = this.rawConstructor(0, 0); destructors.push(this.rawDestructor, ptr); From 29425235762674d01013f73f669918df989fc311 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 17:50:53 -0800 Subject: [PATCH 306/544] methods now give sensible error messages when passing incompatible objects as 'this' --- src/embind/embind.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index ed659a2b177ac..470b03f702a6d 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -887,6 +887,9 @@ function __embind_register_class_method( argTypes = argTypes.slice(1); var humanName = classType.name + '.' + methodName; classType.Handle.prototype[methodName] = function() { + if (!(this instanceof classType.constructor)) { + throwBindingError(humanName + ' incompatible with object of type ' + this.constructor.name); + } if (!this.$$.ptr) { throwBindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } From 3be57ee250e6971708f60615ca26c3eba6ef80da Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 18:05:26 -0800 Subject: [PATCH 307/544] Validate this when calling methods or property accessors --- src/embind/embind.js | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 470b03f702a6d..940abaaa938be 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -868,6 +868,15 @@ function upcastPointer(ptr, ptrClass, desiredClass) { return ptr; } +function validateThis(this_, classType, humanName) { + if (!(this_ instanceof classType.constructor)) { + throwBindingError(humanName + ' incompatible with object of type ' + this_.constructor.name); + } + if (!this_.$$.ptr) { + throwBindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } +} + function __embind_register_class_method( rawClassType, methodName, @@ -887,17 +896,11 @@ function __embind_register_class_method( argTypes = argTypes.slice(1); var humanName = classType.name + '.' + methodName; classType.Handle.prototype[methodName] = function() { - if (!(this instanceof classType.constructor)) { - throwBindingError(humanName + ' incompatible with object of type ' + this.constructor.name); - } - if (!this.$$.ptr) { - throwBindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); - } + validateThis(this, classType, humanName); if (arguments.length !== argCount - 1) { throwBindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } - // TODO: error if pointer type doesn't match signature var ptr = upcastPointer( this.$$.ptr, this.$$.pointeeType.registeredClass, @@ -930,7 +933,6 @@ function __embind_register_class_classmethod( rawInvoker, fn ) { - // todo: whenDependentTypesAreResolved var classType = requireRegisteredType(rawClassType, 'class'); var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = Pointer_stringify(methodName); @@ -950,7 +952,6 @@ function __embind_register_class_field( memberPointerSize, memberPointer ) { - // todo: whenDependentTypesAreResolved fieldName = Pointer_stringify(fieldName); getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; @@ -961,11 +962,8 @@ function __embind_register_class_field( var humanName = classType.name + '.' + fieldName; Object.defineProperty(classType.Handle.prototype, fieldName, { get: function() { - if (!this.$$.ptr) { - throwBindingError('cannot access emscripten binding field ' + humanName + ' on deleted object'); - } + validateThis(this, classType, humanName + ' getter'); - // TODO: error if pointer type doesn't match signature var ptr = upcastPointer( this.$$.ptr, this.$$.pointeeType.registeredClass, @@ -974,11 +972,8 @@ function __embind_register_class_field( return fieldType.fromWireType(getter(ptr, memberPointer)); }, set: function(v) { - if (!this.$$.ptr) { - throwBindingError('cannot modify emscripten binding field ' + humanName + ' on deleted object'); - } + validateThis(this, classType, humanName + ' setter'); - // TODO: error if pointer type doesn't match signature var ptr = upcastPointer( this.$$.ptr, this.$$.pointeeType.registeredClass, From 138b83710a8fa76b2d1585eca5a8a293776c835f Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 18:14:59 -0800 Subject: [PATCH 308/544] Improve error output if calling emscripten methods with invalid 'this' --- src/embind/embind.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 940abaaa938be..87512ddac271a 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -869,8 +869,11 @@ function upcastPointer(ptr, ptrClass, desiredClass) { } function validateThis(this_, classType, humanName) { + if (!(this_ instanceof Object)) { + throwBindingError(humanName + ' with invalid "this": ' + this_); + } if (!(this_ instanceof classType.constructor)) { - throwBindingError(humanName + ' incompatible with object of type ' + this_.constructor.name); + throwBindingError(humanName + ' incompatible with "this" of type ' + this_.constructor.name); } if (!this_.$$.ptr) { throwBindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); From 66b9991931f6e69c86437ed25b0f0072af4e9a62 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 18:21:55 -0800 Subject: [PATCH 309/544] .method -> .function --- src/embind/embind.js | 2 +- system/include/emscripten/bind.h | 34 ++++++++++++++++---------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 87512ddac271a..bd952791f5ca5 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -880,7 +880,7 @@ function validateThis(this_, classType, humanName) { } } -function __embind_register_class_method( +function __embind_register_class_function( rawClassType, methodName, argCount, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 7dcfa61b90381..6e68c2064cec2 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -119,7 +119,7 @@ namespace emscripten { GenericFunction invoker, GenericFunction constructor); - void _embind_register_class_method( + void _embind_register_class_function( TYPEID classType, const char* methodName, unsigned argCount, @@ -735,11 +735,11 @@ namespace emscripten { } template - class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...), Policies...) { + class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...), Policies...) { using namespace internal; typename WithPolicies::template ArgTypeList args; - _embind_register_class_method( + _embind_register_class_function( TypeID::get(), methodName, args.count, @@ -751,11 +751,11 @@ namespace emscripten { } template - class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const, Policies...) { + class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const, Policies...) { using namespace internal; typename WithPolicies::template ArgTypeList args; - _embind_register_class_method( + _embind_register_class_function( TypeID::get(), methodName, args.count, @@ -767,11 +767,11 @@ namespace emscripten { } template - class_& method(const char* methodName, ReturnType (*function)(ClassType& ptr, Args...), Policies...) { + class_& function(const char* methodName, ReturnType (*function)(ClassType& ptr, Args...), Policies...) { using namespace internal; typename WithPolicies::template ArgTypeList args; - _embind_register_class_method( + _embind_register_class_function( TypeID::get(), methodName, args.count, @@ -783,11 +783,11 @@ namespace emscripten { } template - class_& method(const char* methodName, ReturnType (*function)(const ClassType& ptr, Args...), Policies...) { + class_& function(const char* methodName, ReturnType (*function)(const ClassType& ptr, Args...), Policies...) { using namespace internal; typename WithPolicies::template ArgTypeList args; - _embind_register_class_method( + _embind_register_class_function( TypeID::get(), methodName, args.count, @@ -830,7 +830,7 @@ namespace emscripten { template class_& calloperator(const char* methodName, Policies... policies) { - return method(methodName, &ClassType::operator(), policies...); + return function(methodName, &ClassType::operator(), policies...); } }; @@ -870,10 +870,10 @@ namespace emscripten { void (VecType::*push_back)(const T&) = &VecType::push_back; return class_>(name) .template constructor<>() - .method("push_back", push_back) - .method("size", &VecType::size) - .method("get", &internal::VectorAccess::get) - .method("set", &internal::VectorAccess::set) + .function("push_back", push_back) + .function("size", &VecType::size) + .function("get", &internal::VectorAccess::get) + .function("set", &internal::VectorAccess::set) ; } @@ -912,9 +912,9 @@ namespace emscripten { return class_(name) .template constructor<>() - .method("size", &MapType::size) - .method("get", internal::MapAccess::get) - .method("set", internal::MapAccess::set) + .function("size", &MapType::size) + .function("get", internal::MapAccess::get) + .function("set", internal::MapAccess::set) ; } From e698d8bbdb77dc7a3c10e2fa9f1676dee194f3ab Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 18:26:16 -0800 Subject: [PATCH 310/544] classmethod -> class_function --- src/embind/embind.js | 2 +- system/include/emscripten/bind.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index bd952791f5ca5..6595973e771ce 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -928,7 +928,7 @@ function __embind_register_class_function( }); } -function __embind_register_class_classmethod( +function __embind_register_class_class_function( rawClassType, methodName, argCount, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 6e68c2064cec2..2c4df7d306510 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -137,7 +137,7 @@ namespace emscripten { size_t memberPointerSize, void* memberPointer); - void _embind_register_class_classmethod( + void _embind_register_class_class_function( TYPEID classType, const char* methodName, unsigned argCount, @@ -728,7 +728,7 @@ namespace emscripten { .template constructor() ; - return classmethod( + return class_function( "implement", &operator_new, allow_raw_pointer()); @@ -814,11 +814,11 @@ namespace emscripten { } template - class_& classmethod(const char* methodName, ReturnType (*classMethod)(Args...), Policies...) { + class_& class_function(const char* methodName, ReturnType (*classMethod)(Args...), Policies...) { using namespace internal; typename WithPolicies::template ArgTypeList args; - _embind_register_class_classmethod( + _embind_register_class_class_function( TypeID::get(), methodName, args.count, From 770221aa384a9feb24d992ff697e6fba99049832 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 18:28:03 -0800 Subject: [PATCH 311/544] Kill some duplication --- src/embind/embind.js | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 6595973e771ce..9c5b52e8f5e4a 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -878,6 +878,11 @@ function validateThis(this_, classType, humanName) { if (!this_.$$.ptr) { throwBindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } + + return upcastPointer( + this_.$$.ptr, + this_.$$.pointeeType.registeredClass, + classType.registeredClass); } function __embind_register_class_function( @@ -899,16 +904,12 @@ function __embind_register_class_function( argTypes = argTypes.slice(1); var humanName = classType.name + '.' + methodName; classType.Handle.prototype[methodName] = function() { - validateThis(this, classType, humanName); if (arguments.length !== argCount - 1) { throwBindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } - var ptr = upcastPointer( - this.$$.ptr, - this.$$.pointeeType.registeredClass, - classType.registeredClass); - + var ptr = validateThis(this, classType, humanName); + var destructors = []; var args = new Array(argCount + 1); args[0] = ptr; @@ -965,23 +966,11 @@ function __embind_register_class_field( var humanName = classType.name + '.' + fieldName; Object.defineProperty(classType.Handle.prototype, fieldName, { get: function() { - validateThis(this, classType, humanName + ' getter'); - - var ptr = upcastPointer( - this.$$.ptr, - this.$$.pointeeType.registeredClass, - classType.registeredClass); - + var ptr = validateThis(this, classType, humanName + ' getter'); return fieldType.fromWireType(getter(ptr, memberPointer)); }, set: function(v) { - validateThis(this, classType, humanName + ' setter'); - - var ptr = upcastPointer( - this.$$.ptr, - this.$$.pointeeType.registeredClass, - classType.registeredClass); - + var ptr = validateThis(this, classType, humanName + ' setter'); var destructors = []; setter(ptr, memberPointer, fieldType.toWireType(destructors, v)); runDestructors(destructors); From b72bbd39389fed75dc6f0ecb594540a209363eff Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 7 Mar 2013 18:42:32 -0800 Subject: [PATCH 312/544] .field -> .property --- src/embind/embind.js | 2 +- system/include/emscripten/bind.h | 52 ++++++++++++++++---------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 9c5b52e8f5e4a..68cd0e7dc7651 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -947,7 +947,7 @@ function __embind_register_class_class_function( }); } -function __embind_register_class_field( +function __embind_register_class_property( rawClassType, fieldName, rawFieldType, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 2c4df7d306510..1923013f81f56 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -128,7 +128,7 @@ namespace emscripten { size_t memberFunctionSize, void* memberFunction); - void _embind_register_class_field( + void _embind_register_class_property( TYPEID classType, const char* fieldName, TYPEID fieldType, @@ -363,17 +363,17 @@ namespace emscripten { } }; - template - struct FieldAccess { - typedef FieldType ClassType::*MemberPointer; - typedef internal::BindingType FieldBinding; - typedef typename FieldBinding::WireType WireType; + template + struct MemberAccess { + typedef MemberType ClassType::*MemberPointer; + typedef internal::BindingType MemberBinding; + typedef typename MemberBinding::WireType WireType; static WireType get( ClassType& ptr, const MemberPointer& field ) { - return FieldBinding::toWireType(ptr.*field); + return MemberBinding::toWireType(ptr.*field); } static void set( @@ -381,7 +381,7 @@ namespace emscripten { const MemberPointer& field, WireType value ) { - ptr.*field = FieldBinding::fromWireType(value); + ptr.*field = MemberBinding::fromWireType(value); } template @@ -389,7 +389,7 @@ namespace emscripten { ClassType& ptr, const Getter& getter ) { - return FieldBinding::toWireType(getter(ptr)); + return MemberBinding::toWireType(getter(ptr)); } template @@ -398,7 +398,7 @@ namespace emscripten { const Setter& setter, WireType value ) { - setter(ptr, FieldBinding::fromWireType(value)); + setter(ptr, MemberBinding::fromWireType(value)); } }; @@ -424,8 +424,8 @@ namespace emscripten { internal::_embind_register_tuple_element( internal::TypeID::get(), internal::TypeID::get(), - reinterpret_cast(&internal::FieldAccess::get), - reinterpret_cast(&internal::FieldAccess::set), + reinterpret_cast(&internal::MemberAccess::get), + reinterpret_cast(&internal::MemberAccess::set), sizeof(field), &field); @@ -437,10 +437,10 @@ namespace emscripten { internal::_embind_register_tuple_element_accessor( internal::TypeID::get(), internal::TypeID::get(), - reinterpret_cast(&internal::FieldAccess::template propertyGet), + reinterpret_cast(&internal::MemberAccess::template propertyGet), sizeof(getter), &getter, - reinterpret_cast(&internal::FieldAccess::template propertySet), + reinterpret_cast(&internal::MemberAccess::template propertySet), sizeof(setter), &setter); return *this; @@ -451,10 +451,10 @@ namespace emscripten { internal::_embind_register_tuple_element_accessor( internal::TypeID::get(), internal::TypeID::get(), - reinterpret_cast(&internal::FieldAccess::template propertyGet), + reinterpret_cast(&internal::MemberAccess::template propertyGet), sizeof(getter), &getter, - reinterpret_cast(&internal::FieldAccess::template propertySet), + reinterpret_cast(&internal::MemberAccess::template propertySet), sizeof(setter), &setter); return *this; @@ -465,10 +465,10 @@ namespace emscripten { internal::_embind_register_tuple_element_accessor( internal::TypeID::get(), internal::TypeID::get(), - reinterpret_cast(&internal::FieldAccess::template propertyGet), + reinterpret_cast(&internal::MemberAccess::template propertyGet), sizeof(getter), &getter, - reinterpret_cast(&internal::FieldAccess::template propertySet), + reinterpret_cast(&internal::MemberAccess::template propertySet), sizeof(setter), &setter); return *this; @@ -479,10 +479,10 @@ namespace emscripten { internal::_embind_register_tuple_element_accessor( internal::TypeID::get(), internal::TypeID::get(), - reinterpret_cast(&internal::FieldAccess::template propertyGet), + reinterpret_cast(&internal::MemberAccess::template propertyGet), sizeof(getter), &getter, - reinterpret_cast(&internal::FieldAccess::template propertySet), + reinterpret_cast(&internal::MemberAccess::template propertySet), sizeof(setter), &setter); return *this; @@ -510,8 +510,8 @@ namespace emscripten { internal::TypeID::get(), fieldName, internal::TypeID::get(), - reinterpret_cast(&internal::FieldAccess::get), - reinterpret_cast(&internal::FieldAccess::set), + reinterpret_cast(&internal::MemberAccess::get), + reinterpret_cast(&internal::MemberAccess::set), sizeof(field), &field); @@ -799,15 +799,15 @@ namespace emscripten { } template - class_& field(const char* fieldName, FieldType ClassType::*field) { + class_& property(const char* fieldName, FieldType ClassType::*field) { using namespace internal; - _embind_register_class_field( + _embind_register_class_property( TypeID::get(), fieldName, TypeID::get(), - reinterpret_cast(&FieldAccess::get), - reinterpret_cast(&FieldAccess::set), + reinterpret_cast(&MemberAccess::get), + reinterpret_cast(&MemberAccess::set), sizeof(field), &field); return *this; From b2fb12ec07ac4ca271f7138f2bf0fa61f5a701e8 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 8 Mar 2013 00:17:49 -0800 Subject: [PATCH 313/544] I just learned about the sizeof... operator --- system/include/emscripten/wire.h | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 07919a5e55a34..3e4a77d9708c4 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -52,21 +52,6 @@ namespace emscripten { } }; - // count<> - - template - struct count; - - template<> - struct count<> { - constexpr static unsigned value = 0; - }; - - template - struct count { - constexpr static unsigned value = 1 + count::value; - }; - // ExecutePolicies<> template @@ -118,15 +103,13 @@ namespace emscripten { struct WithPolicies { template struct ArgTypeList { - enum { args_count = count::value }; - ArgTypeList() { - count = args_count; + count = sizeof...(Args); ArgTypes<0, Args...>::template fill(types); } unsigned count; - TYPEID types[args_count]; + TYPEID types[sizeof...(Args)]; }; }; From 4d5ff234202ea95a01e5882cf215cd03ce83260d Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 8 Mar 2013 12:44:16 -0800 Subject: [PATCH 314/544] give handles access to their associated pointer type --- src/embind/embind.js | 168 ++++++++++++++++++++++--------------------- 1 file changed, 87 insertions(+), 81 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 68cd0e7dc7651..f4d2fc6ec37b3 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -550,7 +550,7 @@ RegisteredPointer.prototype.fromWireType = function(ptr) { this.destructor(ptr); return null; } - return new this.Handle(ptr); + return new this.Handle(this, ptr); }; // todo: could this return the actual type if not polymorphic? @@ -603,83 +603,7 @@ RegisteredPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // ptr is return handle; }; -function __embind_register_smart_ptr( - rawType, - rawPointeeType, - name, - rawConstructor, - rawDestructor, - rawGetPointee -) { - name = Pointer_stringify(name); - rawConstructor = FUNCTION_TABLE[rawConstructor]; - rawDestructor = FUNCTION_TABLE[rawDestructor]; - rawGetPointee = FUNCTION_TABLE[rawGetPointee]; - - whenDependentTypesAreResolved([rawPointeeType], function(pointeeType) { - pointeeType = pointeeType[0]; - - var Handle = createNamedFunction(name, function(ptr) { - Object.defineProperty(this, '$$', { - value: { - count: {value: 1}, - smartPtr: ptr, - ptr: rawGetPointee(ptr), - pointeeType: pointeeType, - }, - }); - }); - - // TODO: test for SmartPtr.prototype.constructor property? - // We likely want it distinct from pointeeType.prototype.constructor - Handle.prototype = Object.create(pointeeType.Handle.prototype); - - Handle.prototype.clone = function() { - if (!this.$$.ptr) { - throwBindingError(pointeeType.name + ' instance already deleted'); - } - - var clone = Object.create(Handle.prototype); - Object.defineProperty(clone, '$$', { - value: { - count: this.$$.count, - smartPtr: this.$$.smartPtr, - ptr: this.$$.ptr, - }, - }); - - clone.$$.count.value += 1; - return clone; - }; - - Handle.prototype['delete'] = function() { - if (!this.$$.ptr) { - throwBindingError(pointeeType.name + ' instance already deleted'); - } - - this.$$.count.value -= 1; - if (0 === this.$$.count.value) { - rawDestructor(this.$$.smartPtr); - } - this.$$.smartPtr = undefined; - this.$$.ptr = undefined; - }; - - var registeredPointer = new RegisteredPointer( - name, - rawType, - pointeeType.registeredClass, - pointeeType, - Handle, - true, - rawGetPointee, - rawConstructor, - rawDestructor); - registerType(rawType, registeredPointer); - pointeeType.smartPointerType = registeredPointer; - }); -} - +// root of all class handles in embind function ClassHandle() { } @@ -738,12 +662,15 @@ function __embind_register_class( upcast, downcast); - var Handle = createNamedFunction(name, function(ptr) { + var Handle = createNamedFunction(name, function(registeredPointer, ptr) { Object.defineProperty(this, '$$', { value: { - count: {value: 1, ptr: ptr}, + registeredPointer: registeredPointer, + count: { + value: 1, + ptr: ptr }, // todo: is this necessary? ptr: ptr, - pointeeType: type, + pointeeType: type, // todo: is this necessary? } }); }); @@ -980,6 +907,85 @@ function __embind_register_class_property( }); } +function __embind_register_smart_ptr( + rawType, + rawPointeeType, + name, + rawConstructor, + rawDestructor, + rawGetPointee +) { + name = Pointer_stringify(name); + rawConstructor = FUNCTION_TABLE[rawConstructor]; + rawDestructor = FUNCTION_TABLE[rawDestructor]; + rawGetPointee = FUNCTION_TABLE[rawGetPointee]; + + whenDependentTypesAreResolved([rawPointeeType], function(pointeeType) { + pointeeType = pointeeType[0]; + + var Handle = createNamedFunction(name, function(registeredPointer, ptr) { + Object.defineProperty(this, '$$', { + value: { + registeredPointer: registeredPointer, + count: {value: 1}, + smartPtr: ptr, + ptr: rawGetPointee(ptr), + // todo: is this necessary? + pointeeType: pointeeType, + }, + }); + }); + + // TODO: test for SmartPtr.prototype.constructor property? + // We likely want it distinct from pointeeType.prototype.constructor + Handle.prototype = Object.create(pointeeType.Handle.prototype); + + Handle.prototype.clone = function() { + if (!this.$$.ptr) { + throwBindingError(pointeeType.name + ' instance already deleted'); + } + + var clone = Object.create(Handle.prototype); + Object.defineProperty(clone, '$$', { + value: { + count: this.$$.count, + smartPtr: this.$$.smartPtr, + ptr: this.$$.ptr, + }, + }); + + clone.$$.count.value += 1; + return clone; + }; + + Handle.prototype['delete'] = function() { + if (!this.$$.ptr) { + throwBindingError(pointeeType.name + ' instance already deleted'); + } + + this.$$.count.value -= 1; + if (0 === this.$$.count.value) { + rawDestructor(this.$$.smartPtr); + } + this.$$.smartPtr = undefined; + this.$$.ptr = undefined; + }; + + var registeredPointer = new RegisteredPointer( + name, + rawType, + pointeeType.registeredClass, + pointeeType, + Handle, + true, + rawGetPointee, + rawConstructor, + rawDestructor); + registerType(rawType, registeredPointer); + pointeeType.smartPointerType = registeredPointer; + }); +} + function __embind_register_enum( rawType, name From c7d580829e3423d2e0eea242006ebd6dce02c772 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 8 Mar 2013 13:00:30 -0800 Subject: [PATCH 315/544] count.ptr appears to be untested right now. remove it until we know we need it. --- src/embind/embind.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index f4d2fc6ec37b3..ac4bf1dfd7b8b 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -666,9 +666,7 @@ function __embind_register_class( Object.defineProperty(this, '$$', { value: { registeredPointer: registeredPointer, - count: { - value: 1, - ptr: ptr }, // todo: is this necessary? + count: { value: 1 }, ptr: ptr, pointeeType: type, // todo: is this necessary? } @@ -695,8 +693,6 @@ function __embind_register_class( return clone; }; - // todo: test delete with upcast and downcast multiply derived pointers - // todo: then replace this.$$.count.ptr below with this.$$.ptr and make sure it fails Handle.prototype['delete'] = function() { if (!this.$$.ptr) { throwBindingError(type.name + ' instance already deleted'); // todo: but 'type' hasn't been resolved!?! @@ -704,7 +700,7 @@ function __embind_register_class( this.$$.count.value -= 1; if (0 === this.$$.count.value) { - rawDestructor(this.$$.count.ptr); + rawDestructor(this.$$.ptr); } this.$$.ptr = undefined; }; From 88245a330e2db841f1eca2b49eae7e00e1292260 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 8 Mar 2013 15:21:47 -0800 Subject: [PATCH 316/544] CastError extend BindingError --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index ac4bf1dfd7b8b..ace6e7fc02842 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -8,7 +8,7 @@ /*global ___staticPointerCast: false*/ var BindingError = Module.BindingError = extendError(Error, 'BindingError'); -var CastError = Module.CastError = extendError(Error, 'CastError'); +var CastError = Module.CastError = extendError(BindingError, 'CastError'); function throwBindingError(value) { throw new BindingError(value); From 8a58711ab61ba62e10c87e7a1d873c38ff0757e0 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 8 Mar 2013 15:45:20 -0800 Subject: [PATCH 317/544] Throw an error if calling non-const methods on const objects. --- src/embind/embind.js | 11 ++++++++++- system/include/emscripten/bind.h | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index ace6e7fc02842..b52f9ff72dddb 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -472,12 +472,13 @@ function __embind_register_struct_field( }); } -function RegisteredPointer(name, rawType, registeredClass, pointeeType, Handle, isSmartPointer, rawGetPointee, rawConstructor, rawDestructor) { +function RegisteredPointer(name, rawType, registeredClass, pointeeType, Handle, isConst, isSmartPointer, rawGetPointee, rawConstructor, rawDestructor) { this.name = name; this.rawType = rawType; this.registeredClass = registeredClass; this.pointeeType = pointeeType; this.Handle = Handle; // <-- I think I can kill this + this.isConst = isConst; this.isSmartPointer = isSmartPointer; this.rawGetPointee = rawGetPointee; this.rawConstructor = rawConstructor; @@ -712,6 +713,7 @@ function __embind_register_class( registeredClass, undefined, Handle, + false, false); type.pointeeType = type; // :( registerType(rawType, type); @@ -722,6 +724,7 @@ function __embind_register_class( registeredClass, type, Handle, + false, false)); // todo: implement const pointers (no modification Javascript side) @@ -731,6 +734,7 @@ function __embind_register_class( registeredClass, type, Handle, + true, false)); type.constructor = createNamedFunction(name, function() { @@ -813,6 +817,7 @@ function __embind_register_class_function( methodName, argCount, rawArgTypesAddr, + isConst, rawInvoker, memberFunctionSize, memberFunction @@ -832,6 +837,9 @@ function __embind_register_class_function( } var ptr = validateThis(this, classType, humanName); + if (!isConst && this.$$.registeredPointer.isConst) { + throwBindingError('Cannot call non-const method ' + humanName + ' on const reference'); + } var destructors = []; var args = new Array(argCount + 1); @@ -973,6 +981,7 @@ function __embind_register_smart_ptr( pointeeType.registeredClass, pointeeType, Handle, + false, true, rawGetPointee, rawConstructor, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 1923013f81f56..bdcde6255bdb7 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -124,6 +124,7 @@ namespace emscripten { const char* methodName, unsigned argCount, TYPEID argTypes[], + bool isConst, GenericFunction invoker, size_t memberFunctionSize, void* memberFunction); @@ -744,6 +745,7 @@ namespace emscripten { methodName, args.count, args.types, + false, reinterpret_cast(&MethodInvoker::invoke), sizeof(memberFunction), &memberFunction); @@ -760,6 +762,7 @@ namespace emscripten { methodName, args.count, args.types, + true, reinterpret_cast(&ConstMethodInvoker::invoke), sizeof(memberFunction), &memberFunction); @@ -776,6 +779,7 @@ namespace emscripten { methodName, args.count, args.types, + false, reinterpret_cast(&FunctionInvoker::invoke), sizeof(function), &function); @@ -792,6 +796,7 @@ namespace emscripten { methodName, args.count, args.types, + true, reinterpret_cast(&FunctionInvoker::invoke), sizeof(function), &function); From 2025ba8cef32874d40be093edf4d560931e3b399 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 8 Mar 2013 15:58:36 -0800 Subject: [PATCH 318/544] Illegal to pass const pointers into non-const parameters. --- src/embind/embind.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index b52f9ff72dddb..ccab4c48dfb3a 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -510,6 +510,9 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { if (this.isSmartPointer && undefined === handle.$$.smartPtr) { throwBindingError('Passing raw pointer to smart pointer is illegal'); } + if (!this.isConst && handle.$$.registeredPointer.isConst) { + throwBindingError('Cannot pass argument of type ' + handle.$$.registeredPointer.name + ' to parameter of type ' + this.name); + } var pointeeType = handle.$$.pointeeType; if (pointeeType.isPolymorphic()) { fromRawType = pointeeType.getDynamicRawPointerType(handle.$$.ptr); From b54dbc819583d608d1a16c9c48fe9831443e96a4 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 8 Mar 2013 16:03:57 -0800 Subject: [PATCH 319/544] Oops I did this already. --- src/embind/embind.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index ccab4c48dfb3a..f44ee176a9afa 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -730,7 +730,6 @@ function __embind_register_class( false, false)); - // todo: implement const pointers (no modification Javascript side) registerType(rawConstPointerType, new RegisteredPointer( name + ' const*', rawConstPointerType, From 76bd2d5cc47468eaae1d9149d997c63b72aa18d3 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 8 Mar 2013 16:17:35 -0800 Subject: [PATCH 320/544] Work towards killing some pointeeType references. --- src/embind/embind.js | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index f44ee176a9afa..5aae8669e49c4 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -472,12 +472,26 @@ function __embind_register_struct_field( }); } -function RegisteredPointer(name, rawType, registeredClass, pointeeType, Handle, isConst, isSmartPointer, rawGetPointee, rawConstructor, rawDestructor) { +// I guarantee there is a way to simplify the following data structure. +function RegisteredPointer( + name, + rawType, + registeredClass, + pointeeType, + Handle, + isReference, + isConst, + isSmartPointer, + rawGetPointee, + rawConstructor, + rawDestructor +) { this.name = name; this.rawType = rawType; this.registeredClass = registeredClass; this.pointeeType = pointeeType; this.Handle = Handle; // <-- I think I can kill this + this.isReference = isReference; this.isConst = isConst; this.isSmartPointer = isSmartPointer; this.rawGetPointee = rawGetPointee; @@ -492,7 +506,7 @@ RegisteredPointer.prototype.isPolymorphic = function() { RegisteredPointer.prototype.toWireType = function(destructors, handle) { var fromRawType; if (handle === null) { - if (this.pointeeType === this) { + if (this.isReference) { throwBindingError('null is not a valid ' + this.name); } @@ -557,7 +571,6 @@ RegisteredPointer.prototype.fromWireType = function(ptr) { return new this.Handle(this, ptr); }; -// todo: could this return the actual type if not polymorphic? RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) { var type = null; if (this.isPolymorphic()) { @@ -716,6 +729,7 @@ function __embind_register_class( registeredClass, undefined, Handle, + true, false, false); type.pointeeType = type; // :( @@ -728,6 +742,7 @@ function __embind_register_class( type, Handle, false, + false, false)); registerType(rawConstPointerType, new RegisteredPointer( @@ -736,6 +751,7 @@ function __embind_register_class( registeredClass, type, Handle, + false, true, false)); @@ -810,7 +826,7 @@ function validateThis(this_, classType, humanName) { return upcastPointer( this_.$$.ptr, - this_.$$.pointeeType.registeredClass, + this_.$$.registeredPointer.registeredClass, classType.registeredClass); } @@ -984,6 +1000,7 @@ function __embind_register_smart_ptr( pointeeType, Handle, false, + false, true, rawGetPointee, rawConstructor, From 40976b0286d7b647777adc037976925c4c1505fd Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 8 Mar 2013 16:20:45 -0800 Subject: [PATCH 321/544] tiny refactoring --- src/embind/embind.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 5aae8669e49c4..82b9c5d4d1948 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -607,13 +607,12 @@ RegisteredPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // ptr is } var toType = this.getDynamicDowncastType(ptr); if (toType) { - var fromType = this.pointeeType; if (this.isSmartPointer) { handle = toType.smartPointerType.fromWireType(ptr); } else { handle = toType.fromWireType(ptr); } - handle.$$.ptr = staticPointerCast(handle.$$.ptr, fromType.rawType, toType.rawType); + handle.$$.ptr = staticPointerCast(handle.$$.ptr, this.pointeeType.rawType, toType.rawType); } else { handle = this.fromWireType(ptr); } From 808e914ce1a0a0388d0bb6f6c4dadf935ad35f4e Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 11 Mar 2013 13:02:30 -0700 Subject: [PATCH 322/544] Just toodling around with smart pointer binding syntax --- system/include/emscripten/bind.h | 40 ++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index bdcde6255bdb7..fd2e928a5bc23 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -660,6 +660,23 @@ namespace emscripten { } }; + template + struct ptr { + typedef PointerType pointer_type; + }; + + namespace internal { + template + struct is_ptr { + enum { value = false }; + }; + + template + struct is_ptr> { + enum { value = true }; + }; + }; + template class class_ { public: @@ -670,16 +687,19 @@ namespace emscripten { BaseSpecifier::template verify(); - _embind_register_class( - TypeID::get(), - TypeID>::get(), - TypeID>::get(), - BaseSpecifier::get(), - BaseSpecifier::template getUpcaster(), - BaseSpecifier::template getDowncaster(), - std::is_polymorphic::value, - name, - reinterpret_cast(&raw_destructor)); + if (is_ptr::value) { + } else { + _embind_register_class( + TypeID::get(), + TypeID>::get(), + TypeID>::get(), + BaseSpecifier::get(), + BaseSpecifier::template getUpcaster(), + BaseSpecifier::template getDowncaster(), + std::is_polymorphic::value, + name, + reinterpret_cast(&raw_destructor)); + } } template From 495c40ce186d5b852f3bc3430058a24a94c72dba Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 11 Mar 2013 13:12:42 -0700 Subject: [PATCH 323/544] enable_if is scary and cool --- system/include/emscripten/bind.h | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index fd2e928a5bc23..4b9968dc8c916 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -682,24 +682,22 @@ namespace emscripten { public: class_() = delete; + template::value>::type> explicit class_(const char* name) { using namespace internal; BaseSpecifier::template verify(); - if (is_ptr::value) { - } else { - _embind_register_class( - TypeID::get(), - TypeID>::get(), - TypeID>::get(), - BaseSpecifier::get(), - BaseSpecifier::template getUpcaster(), - BaseSpecifier::template getDowncaster(), - std::is_polymorphic::value, - name, - reinterpret_cast(&raw_destructor)); - } + _embind_register_class( + TypeID::get(), + TypeID>::get(), + TypeID>::get(), + BaseSpecifier::get(), + BaseSpecifier::template getUpcaster(), + BaseSpecifier::template getDowncaster(), + std::is_polymorphic::value, + name, + reinterpret_cast(&raw_destructor)); } template From de9a8d6fecd4f699b2f80d908c8c597dcc8f04bc Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 11 Mar 2013 18:42:13 -0700 Subject: [PATCH 324/544] make smart_ptr a method of class_ instead of a global --- system/include/emscripten/bind.h | 34 +++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 4b9968dc8c916..e3593196a8d2e 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -557,20 +557,6 @@ namespace emscripten { } } - template - void smart_ptr(const char* name) { - using namespace internal; - typedef typename smart_ptr_trait::element_type PointeeType; - - _embind_register_smart_ptr( - TypeID::get(), - TypeID::get(), - name, - reinterpret_cast(&raw_smart_pointer_constructor), - reinterpret_cast(&raw_destructor), - reinterpret_cast(&get_pointee)); - }; - //////////////////////////////////////////////////////////////////////////////// // CLASSES //////////////////////////////////////////////////////////////////////////////// @@ -700,6 +686,23 @@ namespace emscripten { reinterpret_cast(&raw_destructor)); } + template + class_& smart_ptr() { + using namespace internal; + typedef typename smart_ptr_trait::element_type PointeeType; + + // TODO: assert that PointeeType is identical to ClassType + + _embind_register_smart_ptr( + TypeID::get(), + TypeID::get(), + "SmartPtr", // TODO: generate unique name + reinterpret_cast(&raw_smart_pointer_constructor), + reinterpret_cast(&raw_destructor), + reinterpret_cast(&get_pointee)); + return *this; + }; + template class_& constructor(Policies... policies) { return constructor( @@ -725,8 +728,7 @@ namespace emscripten { class_& smart_ptr_constructor(SmartPtr (*factory)(Args...), Policies...) { using namespace internal; - // TODO: generate unique name - smart_ptr("SmartPtr"); + smart_ptr(); typename WithPolicies::template ArgTypeList args; _embind_register_class_constructor( From 7c49e9f8866314d688b07f99abb34ccdac442db3 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 12 Mar 2013 18:37:24 -0700 Subject: [PATCH 325/544] :O it works. Use a sharing policy approach to autocasting pointers. --- src/embind/embind.js | 49 ++++++++++++----- system/include/emscripten/bind.h | 91 ++++++++++++++++++++++---------- 2 files changed, 101 insertions(+), 39 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 82b9c5d4d1948..c52c6e4d32eef 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -482,8 +482,10 @@ function RegisteredPointer( isReference, isConst, isSmartPointer, + sharingPolicy, rawGetPointee, rawConstructor, + rawShare, rawDestructor ) { this.name = name; @@ -494,8 +496,10 @@ function RegisteredPointer( this.isReference = isReference; this.isConst = isConst; this.isSmartPointer = isSmartPointer; + this.sharingPolicy = sharingPolicy; this.rawGetPointee = rawGetPointee; this.rawConstructor = rawConstructor; + this.rawShare = rawShare; this.rawDestructor = rawDestructor; } @@ -511,7 +515,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { } if (this.isSmartPointer) { - var ptr = this.rawConstructor(0, 0); + var ptr = this.rawConstructor(); destructors.push(this.rawDestructor, ptr); return ptr; } else { @@ -538,14 +542,30 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { } var ptr = staticPointerCast(handle.$$.ptr, fromRawType, this.pointeeType.rawType); if (this.isSmartPointer) { - // If this is for smart ptr type conversion, I think it - // assumes that smart_ptr has an identical binary layout to - // smart_ptr. I wonder if that's untrue for any common - // smart pointer. - chad - ptr = this.rawConstructor( - ptr, - handle.$$.smartPtr); - destructors.push(this.rawDestructor, ptr); + switch (this.sharingPolicy) { + case 0: // NONE + throwBindingError('NONE sharing policy not yet supported'); + break; + + case 1: // INTRUSIVE + throwBindingError('INTRUSIVE sharing policy not yet supported'); + break; + + case 2: // BY_EMVAL + var clonedHandle = handle.clone(); + ptr = this.rawShare( + ptr, + __emval_register(function() { + clonedHandle.delete(); + }) + ); + destructors.push(this.rawDestructor, ptr); + break; + + default: + throwBindingError('Unsupporting sharing policy'); + + } } return ptr; }; @@ -932,14 +952,17 @@ function __embind_register_smart_ptr( rawType, rawPointeeType, name, + sharingPolicy, + rawGetPointee, rawConstructor, - rawDestructor, - rawGetPointee + rawShare, + rawDestructor ) { name = Pointer_stringify(name); + rawGetPointee = FUNCTION_TABLE[rawGetPointee]; rawConstructor = FUNCTION_TABLE[rawConstructor]; + rawShare = FUNCTION_TABLE[rawShare]; rawDestructor = FUNCTION_TABLE[rawDestructor]; - rawGetPointee = FUNCTION_TABLE[rawGetPointee]; whenDependentTypesAreResolved([rawPointeeType], function(pointeeType) { pointeeType = pointeeType[0]; @@ -1001,8 +1024,10 @@ function __embind_register_smart_ptr( false, false, true, + sharingPolicy, rawGetPointee, rawConstructor, + rawShare, rawDestructor); registerType(rawType, registeredPointer); pointeeType.smartPointerType = registeredPointer; diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index e3593196a8d2e..6f6a62558a575 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -11,6 +11,12 @@ #include namespace emscripten { + enum class sharing_policy { + NONE = 0, + INTRUSIVE = 1, + BY_EMVAL = 2, + }; + namespace internal { typedef void (*GenericFunction)(); typedef long GenericEnumValue; @@ -97,9 +103,11 @@ namespace emscripten { TYPEID pointerType, TYPEID pointeeType, const char* pointerName, + sharing_policy sharingPolicy, + GenericFunction getPointee, GenericFunction constructor, - GenericFunction destructor, - GenericFunction getPointee); + GenericFunction share, + GenericFunction destructor); void _embind_register_class( TYPEID classType, @@ -524,38 +532,62 @@ namespace emscripten { // SMART POINTERS //////////////////////////////////////////////////////////////////////////////// + template + struct default_smart_ptr_trait { + static sharing_policy get_sharing_policy() { + return sharing_policy::NONE; + } + + static void* share(void* v) { + return 0; // no sharing + } + }; + // specialize if you have a different pointer type template - struct smart_ptr_trait { + struct smart_ptr_trait : public default_smart_ptr_trait { typedef typename PointerType::element_type element_type; static element_type* get(const PointerType& ptr) { return ptr.get(); } + }; + + template + struct smart_ptr_trait> { + typedef std::shared_ptr PointerType; + typedef typename PointerType::element_type element_type; - static PointerType share(const PointerType& r, element_type* ptr) { - return PointerType(r, ptr); + static element_type* get(const PointerType& ptr) { + return ptr.get(); } - }; - namespace internal { - template - SmartPointerType* raw_smart_pointer_constructor( - typename smart_ptr_trait::element_type* ptr, - SmartPointerType* basePtr - ) { - if (ptr) { - return new SmartPointerType(smart_ptr_trait::share(*basePtr, ptr)); - } else { - return new SmartPointerType; - } + static sharing_policy get_sharing_policy() { + return sharing_policy::BY_EMVAL; } - template - typename smart_ptr_trait::element_type* get_pointee(const PointerType& ptr) { - return smart_ptr_trait::get(ptr); + static std::shared_ptr* share(PointeeType* p, internal::EM_VAL v) { + return new std::shared_ptr( + p, + val_deleter(val::take_ownership(v))); } - } + + private: + class val_deleter { + public: + val_deleter() = delete; + explicit val_deleter(val v) + : v(v) + {} + void operator()(void const*) { + v(); + // eventually we'll need to support emptied out val + v = val::undefined(); + } + private: + val v; + }; + }; //////////////////////////////////////////////////////////////////////////////// // CLASSES @@ -689,17 +721,22 @@ namespace emscripten { template class_& smart_ptr() { using namespace internal; - typedef typename smart_ptr_trait::element_type PointeeType; - + // TODO: assert that PointeeType is identical to ClassType + typedef smart_ptr_trait PointerTrait; + typedef typename PointerTrait::element_type PointeeType; + + _embind_register_smart_ptr( TypeID::get(), TypeID::get(), - "SmartPtr", // TODO: generate unique name - reinterpret_cast(&raw_smart_pointer_constructor), - reinterpret_cast(&raw_destructor), - reinterpret_cast(&get_pointee)); + "SmartPtr", // TODO: generate unique name, if one is needed at all + PointerTrait::get_sharing_policy(), + reinterpret_cast(&PointerTrait::get), + reinterpret_cast(&operator_new), + reinterpret_cast(&PointerTrait::share), + reinterpret_cast(&raw_destructor)); return *this; }; From 0badaf9b00289ffd204b88c8875f442822b1b704 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 13 Mar 2013 01:18:04 -0700 Subject: [PATCH 326/544] Allow smart pointers to have their actual type names. --- src/embind/embind.js | 29 ++++++++++++++++++----------- system/include/emscripten/bind.h | 2 +- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index c52c6e4d32eef..de6826aafc6ba 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -522,8 +522,8 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { return 0; } } - if (!(handle instanceof ClassHandle)) { - throwBindingError('Expected pointer or null, got ' + IMVU.repr(handle)); + if (!(handle instanceof this.registeredClass.constructor)) { + throwBindingError('Expected null or instance of ' + this.name + ', got ' + IMVU.repr(handle)); } if (this.isSmartPointer && undefined === handle.$$.smartPtr) { throwBindingError('Passing raw pointer to smart pointer is illegal'); @@ -645,6 +645,7 @@ function ClassHandle() { function RegisteredClass( name, + constructor, isPolymorphic, baseClassRawType, baseClass, @@ -652,6 +653,7 @@ function RegisteredClass( downcast ) { this.name = name; + this.constructor = constructor; this.isPolymorphic = isPolymorphic; this.baseClassRawType = baseClassRawType; this.baseClass = baseClass; @@ -690,14 +692,6 @@ function __embind_register_class( basePrototype = ClassHandle.prototype; } - var registeredClass = new RegisteredClass( - name, - isPolymorphic, - baseClassRawType, - baseClass, - upcast, - downcast); - var Handle = createNamedFunction(name, function(registeredPointer, ptr) { Object.defineProperty(this, '$$', { value: { @@ -709,6 +703,15 @@ function __embind_register_class( }); }); + var registeredClass = new RegisteredClass( + name, + Handle, + isPolymorphic, + baseClassRawType, + baseClass, + upcast, + downcast); + Handle.prototype = Object.create(basePrototype, { constructor: { value: Handle }, }); @@ -948,6 +951,10 @@ function __embind_register_class_property( }); } +function makeLegalFunctionName(name) { + return '_' + name.replace(/[^a-zA-Z0-9_]/g, '$'); +} + function __embind_register_smart_ptr( rawType, rawPointeeType, @@ -967,7 +974,7 @@ function __embind_register_smart_ptr( whenDependentTypesAreResolved([rawPointeeType], function(pointeeType) { pointeeType = pointeeType[0]; - var Handle = createNamedFunction(name, function(registeredPointer, ptr) { + var Handle = createNamedFunction(makeLegalFunctionName(name), function(registeredPointer, ptr) { Object.defineProperty(this, '$$', { value: { registeredPointer: registeredPointer, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 6f6a62558a575..f06ca69c181fc 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -731,7 +731,7 @@ namespace emscripten { _embind_register_smart_ptr( TypeID::get(), TypeID::get(), - "SmartPtr", // TODO: generate unique name, if one is needed at all + typeid(PointerType).name(), PointerTrait::get_sharing_policy(), reinterpret_cast(&PointerTrait::get), reinterpret_cast(&operator_new), From c8cdc3f73c486cc4ac2ac5da0de01f6072a092af Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 14 Mar 2013 00:22:27 -0700 Subject: [PATCH 327/544] Support the smart_ptr policy BY_EMVAL and pass the original smart pointer if the parameter has an identical type. --- src/embind/embind.js | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index de6826aafc6ba..89669172abbc8 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -508,7 +508,6 @@ RegisteredPointer.prototype.isPolymorphic = function() { }; RegisteredPointer.prototype.toWireType = function(destructors, handle) { - var fromRawType; if (handle === null) { if (this.isReference) { throwBindingError('null is not a valid ' + this.name); @@ -531,20 +530,17 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { if (!this.isConst && handle.$$.registeredPointer.isConst) { throwBindingError('Cannot pass argument of type ' + handle.$$.registeredPointer.name + ' to parameter of type ' + this.name); } - var pointeeType = handle.$$.pointeeType; - if (pointeeType.isPolymorphic()) { - fromRawType = pointeeType.getDynamicRawPointerType(handle.$$.ptr); - } else { - fromRawType = pointeeType.rawType; - } - if (fromRawType === this.pointeeType.rawType) { - return this.isSmartPointer ? handle.$$.smartPtr : handle.$$.ptr; - } - var ptr = staticPointerCast(handle.$$.ptr, fromRawType, this.pointeeType.rawType); + var handleClass = handle.$$.registeredPointer.registeredClass; + var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); if (this.isSmartPointer) { switch (this.sharingPolicy) { case 0: // NONE - throwBindingError('NONE sharing policy not yet supported'); + // no upcasting + if (handle.$$.registeredPointer === this) { + ptr = handle.$$.smartPtr; + } else { + throwBindingError('NONE sharing policy not yet supported'); + } break; case 1: // INTRUSIVE @@ -552,19 +548,22 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { break; case 2: // BY_EMVAL - var clonedHandle = handle.clone(); - ptr = this.rawShare( - ptr, - __emval_register(function() { - clonedHandle.delete(); - }) - ); - destructors.push(this.rawDestructor, ptr); - break; + if (handle.$$.registeredPointer === this) { + ptr = handle.$$.smartPtr; + } else { + var clonedHandle = handle.clone(); + ptr = this.rawShare( + ptr, + __emval_register(function() { + clonedHandle.delete(); + }) + ); + destructors.push(this.rawDestructor, ptr); + } + break; default: throwBindingError('Unsupporting sharing policy'); - } } return ptr; From ddb31f11310847b50e4e27f0d64390b55809eecd Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 14 Mar 2013 00:50:18 -0700 Subject: [PATCH 328/544] Implement a sane error message when passing an incompatible smart pointer type --- src/embind/embind.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 89669172abbc8..2f30750f8eacf 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -508,6 +508,11 @@ RegisteredPointer.prototype.isPolymorphic = function() { }; RegisteredPointer.prototype.toWireType = function(destructors, handle) { + var self = this; + function throwCannotConvert() { + throwBindingError('Cannot convert argument of type ' + handle.$$.registeredPointer.name + ' to parameter type ' + self.name); + } + if (handle === null) { if (this.isReference) { throwBindingError('null is not a valid ' + this.name); @@ -528,7 +533,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { throwBindingError('Passing raw pointer to smart pointer is illegal'); } if (!this.isConst && handle.$$.registeredPointer.isConst) { - throwBindingError('Cannot pass argument of type ' + handle.$$.registeredPointer.name + ' to parameter of type ' + this.name); + throwCannotConvert(); } var handleClass = handle.$$.registeredPointer.registeredClass; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); @@ -539,7 +544,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { if (handle.$$.registeredPointer === this) { ptr = handle.$$.smartPtr; } else { - throwBindingError('NONE sharing policy not yet supported'); + throwCannotConvert(); } break; From fb92020f00a7ae5b43927927b1ec571afc161bf1 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 14 Mar 2013 01:03:39 -0700 Subject: [PATCH 329/544] Add a static assertion that a classes's smart_ptr is compatible --- system/include/emscripten/bind.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index f06ca69c181fc..10d0d926e11ab 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -722,11 +722,10 @@ namespace emscripten { class_& smart_ptr() { using namespace internal; - // TODO: assert that PointeeType is identical to ClassType - typedef smart_ptr_trait PointerTrait; typedef typename PointerTrait::element_type PointeeType; + static_assert(std::is_same::type>::value, "smart pointer must point to this class"); _embind_register_smart_ptr( TypeID::get(), From 7d783d874a38b63515e8e3cc4c0c8ec15e428175 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 14 Mar 2013 01:18:18 -0700 Subject: [PATCH 330/544] Use typeid name for interface wrappers too. (Also introduce more uses of makeLegalFunctionName) --- src/embind/embind.js | 17 +++++++++++++---- system/include/emscripten/bind.h | 3 +-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 2f30750f8eacf..8810727d1f3bf 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -680,6 +680,7 @@ function __embind_register_class( rawDestructor = FUNCTION_TABLE[rawDestructor]; upcast = FUNCTION_TABLE[upcast]; downcast = FUNCTION_TABLE[downcast]; + var legalFunctionName = makeLegalFunctionName(name); whenDependentTypesAreResolved(baseClassRawType ? [baseClassRawType] : [], function(base) { base = base[0]; @@ -696,7 +697,7 @@ function __embind_register_class( basePrototype = ClassHandle.prototype; } - var Handle = createNamedFunction(name, function(registeredPointer, ptr) { + var Handle = createNamedFunction(legalFunctionName, function(registeredPointer, ptr) { Object.defineProperty(this, '$$', { value: { registeredPointer: registeredPointer, @@ -781,7 +782,7 @@ function __embind_register_class( true, false)); - type.constructor = createNamedFunction(name, function() { + type.constructor = createNamedFunction(legalFunctionName, function() { if (Object.getPrototypeOf(this) !== Handle.prototype) { throw new BindingError("Use 'new' to construct " + name); } @@ -794,7 +795,7 @@ function __embind_register_class( type.constructor.prototype = type.Handle.prototype; type.constructor.type = type; - exposePublicSymbol(name, type.constructor); + exposePublicSymbol(legalFunctionName, type.constructor); }); } @@ -955,8 +956,16 @@ function __embind_register_class_property( }); } +var char_0 = '0'.charCodeAt(0); +var char_9 = '9'.charCodeAt(0); function makeLegalFunctionName(name) { - return '_' + name.replace(/[^a-zA-Z0-9_]/g, '$'); + var rv = name.replace(/[^a-zA-Z0-9_]/g, '$'); + var f = rv.charCodeAt(0); + if (f >= char_0 && f <= char_9) { + return '_' + rv; + } else { + return rv; + } } function __embind_register_smart_ptr( diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 10d0d926e11ab..e58659716aa44 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -780,8 +780,7 @@ namespace emscripten { class_& allow_subclass() { using namespace internal; - // TODO: unique or anonymous name - class_>("WrapperType") + class_>(typeid(WrapperType).name()) .template constructor() ; From 8d178bb7a2fa5ee0751f4a4ec391db276e601d95 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 14 Mar 2013 01:31:47 -0700 Subject: [PATCH 331/544] Kill some dead todos --- src/embind/embind.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 8810727d1f3bf..805c8b1db72ec 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -703,7 +703,6 @@ function __embind_register_class( registeredPointer: registeredPointer, count: { value: 1 }, ptr: ptr, - pointeeType: type, // todo: is this necessary? } }); }); @@ -739,7 +738,7 @@ function __embind_register_class( Handle.prototype['delete'] = function() { if (!this.$$.ptr) { - throwBindingError(type.name + ' instance already deleted'); // todo: but 'type' hasn't been resolved!?! + throwBindingError(type.name + ' instance already deleted'); } this.$$.count.value -= 1; @@ -994,14 +993,10 @@ function __embind_register_smart_ptr( count: {value: 1}, smartPtr: ptr, ptr: rawGetPointee(ptr), - // todo: is this necessary? - pointeeType: pointeeType, }, }); }); - // TODO: test for SmartPtr.prototype.constructor property? - // We likely want it distinct from pointeeType.prototype.constructor Handle.prototype = Object.create(pointeeType.Handle.prototype); Handle.prototype.clone = function() { From cb2533c8538eba077c08102ae85f00a1231a14ca Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 14 Mar 2013 02:18:23 -0700 Subject: [PATCH 332/544] Rename registeredPointer to ptrType --- src/embind/embind.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 805c8b1db72ec..0eefef360cc6a 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -510,7 +510,7 @@ RegisteredPointer.prototype.isPolymorphic = function() { RegisteredPointer.prototype.toWireType = function(destructors, handle) { var self = this; function throwCannotConvert() { - throwBindingError('Cannot convert argument of type ' + handle.$$.registeredPointer.name + ' to parameter type ' + self.name); + throwBindingError('Cannot convert argument of type ' + handle.$$.ptrType.name + ' to parameter type ' + self.name); } if (handle === null) { @@ -532,16 +532,16 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { if (this.isSmartPointer && undefined === handle.$$.smartPtr) { throwBindingError('Passing raw pointer to smart pointer is illegal'); } - if (!this.isConst && handle.$$.registeredPointer.isConst) { + if (!this.isConst && handle.$$.ptrType.isConst) { throwCannotConvert(); } - var handleClass = handle.$$.registeredPointer.registeredClass; + var handleClass = handle.$$.ptrType.registeredClass; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); if (this.isSmartPointer) { switch (this.sharingPolicy) { case 0: // NONE // no upcasting - if (handle.$$.registeredPointer === this) { + if (handle.$$.ptrType === this) { ptr = handle.$$.smartPtr; } else { throwCannotConvert(); @@ -553,7 +553,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { break; case 2: // BY_EMVAL - if (handle.$$.registeredPointer === this) { + if (handle.$$.ptrType === this) { ptr = handle.$$.smartPtr; } else { var clonedHandle = handle.clone(); @@ -643,7 +643,7 @@ RegisteredPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // ptr is return handle; }; -// root of all class handles in embind +// root of all pointer and smart pointer handles in embind function ClassHandle() { } @@ -697,10 +697,10 @@ function __embind_register_class( basePrototype = ClassHandle.prototype; } - var Handle = createNamedFunction(legalFunctionName, function(registeredPointer, ptr) { + var Handle = createNamedFunction(legalFunctionName, function(ptrType, ptr) { Object.defineProperty(this, '$$', { value: { - registeredPointer: registeredPointer, + ptrType: ptrType, count: { value: 1 }, ptr: ptr, } @@ -852,7 +852,7 @@ function validateThis(this_, classType, humanName) { return upcastPointer( this_.$$.ptr, - this_.$$.registeredPointer.registeredClass, + this_.$$.ptrType.registeredClass, classType.registeredClass); } @@ -881,7 +881,7 @@ function __embind_register_class_function( } var ptr = validateThis(this, classType, humanName); - if (!isConst && this.$$.registeredPointer.isConst) { + if (!isConst && this.$$.ptrType.isConst) { throwBindingError('Cannot call non-const method ' + humanName + ' on const reference'); } @@ -986,10 +986,10 @@ function __embind_register_smart_ptr( whenDependentTypesAreResolved([rawPointeeType], function(pointeeType) { pointeeType = pointeeType[0]; - var Handle = createNamedFunction(makeLegalFunctionName(name), function(registeredPointer, ptr) { + var Handle = createNamedFunction(makeLegalFunctionName(name), function(ptrType, ptr) { Object.defineProperty(this, '$$', { value: { - registeredPointer: registeredPointer, + ptrType: ptrType, count: {value: 1}, smartPtr: ptr, ptr: rawGetPointee(ptr), From a09b543bf434b0f5e27b776f7a5a752f3e1c317d Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 14 Mar 2013 15:45:44 -0700 Subject: [PATCH 333/544] make a note that it's sometimes okay to pass raw pointers to smart pointers --- src/embind/embind.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index 0eefef360cc6a..d664435fe8415 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -529,6 +529,8 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { if (!(handle instanceof this.registeredClass.constructor)) { throwBindingError('Expected null or instance of ' + this.name + ', got ' + IMVU.repr(handle)); } + // TODO: this is not strictly true + // It seems legal to support BY_EMVAL and INTRUSIVE conversions from raw pointers to smart pointers if (this.isSmartPointer && undefined === handle.$$.smartPtr) { throwBindingError('Passing raw pointer to smart pointer is illegal'); } From bb23c470f034601b70136a3eb56f829e84674bc4 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 18 Mar 2013 16:33:44 -0700 Subject: [PATCH 334/544] Give each class a typeid function --- src/embind/embind.js | 5 +++++ system/include/emscripten/bind.h | 11 +++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index d664435fe8415..834aed740951a 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -655,6 +655,7 @@ function RegisteredClass( isPolymorphic, baseClassRawType, baseClass, + getActualType, upcast, downcast ) { @@ -663,6 +664,7 @@ function RegisteredClass( this.isPolymorphic = isPolymorphic; this.baseClassRawType = baseClassRawType; this.baseClass = baseClass; + this.getActualType = getActualType; this.upcast = upcast; this.downcast = downcast; } @@ -672,6 +674,7 @@ function __embind_register_class( rawPointerType, rawConstPointerType, baseClassRawType, + getActualType, upcast, downcast, isPolymorphic, @@ -680,6 +683,7 @@ function __embind_register_class( ) { name = Pointer_stringify(name); rawDestructor = FUNCTION_TABLE[rawDestructor]; + getActualType = FUNCTION_TABLE[getActualType]; upcast = FUNCTION_TABLE[upcast]; downcast = FUNCTION_TABLE[downcast]; var legalFunctionName = makeLegalFunctionName(name); @@ -715,6 +719,7 @@ function __embind_register_class( isPolymorphic, baseClassRawType, baseClass, + getActualType, upcast, downcast); diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index e58659716aa44..cd208d37091c9 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -114,6 +114,7 @@ namespace emscripten { TYPEID pointerType, TYPEID constPointerType, TYPEID baseClassType, + GenericFunction getActualType, GenericFunction upcast, GenericFunction downcast, bool isPolymorphic, @@ -648,6 +649,11 @@ namespace emscripten { return nullptr; } }; + + template + inline TYPEID getActualType(T* ptr) { + return reinterpret_cast(&typeid(ptr)); + }; } template @@ -692,7 +698,7 @@ namespace emscripten { template struct is_ptr> { enum { value = true }; - }; + }; }; template @@ -711,9 +717,10 @@ namespace emscripten { TypeID>::get(), TypeID>::get(), BaseSpecifier::get(), + reinterpret_cast(&getActualType), BaseSpecifier::template getUpcaster(), BaseSpecifier::template getDowncaster(), - std::is_polymorphic::value, + std::is_polymorphic::value, // TODO: may not be necessary name, reinterpret_cast(&raw_destructor)); } From fc3e58b6915368401a01da8587f014a94a31373d Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 18 Mar 2013 16:53:01 -0700 Subject: [PATCH 335/544] Kill fromWireTypeAutoDowncast --- src/embind/embind.js | 22 +++++++--------------- src/embind/emval.js | 2 +- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 834aed740951a..d3690a6591c49 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -277,11 +277,7 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]); } var rv = invoker.apply(null, args); - if (argTypes[0].fromWireTypeAutoDowncast) { - rv = argTypes[0].fromWireTypeAutoDowncast(rv); - } else { - rv = argTypes[0].fromWireType(rv); - } + rv = argTypes[0].fromWireType(rv); runDestructors(destructors); return rv; }; @@ -589,7 +585,7 @@ RegisteredPointer.prototype.destructor = function(ptr) { } }; -RegisteredPointer.prototype.fromWireType = function(ptr) { +RegisteredPointer.prototype._fromWireType = function(ptr) { if (!this.getPointee(ptr)) { this.destructor(ptr); return null; @@ -625,7 +621,7 @@ RegisteredPointer.prototype.getDynamicDowncastType = function(ptr) { return downcastType; }; -RegisteredPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // ptr is a raw pointer (or a raw smartpointer) +RegisteredPointer.prototype.fromWireType = function(ptr) { // ptr is a raw pointer (or a raw smartpointer) var handle; if (!this.getPointee(ptr)) { this.destructor(ptr); @@ -634,13 +630,13 @@ RegisteredPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // ptr is var toType = this.getDynamicDowncastType(ptr); if (toType) { if (this.isSmartPointer) { - handle = toType.smartPointerType.fromWireType(ptr); + handle = toType.smartPointerType._fromWireType(ptr); } else { - handle = toType.fromWireType(ptr); + handle = toType._fromWireType(ptr); } handle.$$.ptr = staticPointerCast(handle.$$.ptr, this.pointeeType.rawType, toType.rawType); } else { - handle = this.fromWireType(ptr); + handle = this._fromWireType(ptr); } return handle; }; @@ -900,11 +896,7 @@ function __embind_register_class_function( args[i + 1] = argTypes[i].toWireType(destructors, arguments[i - 1]); } var rv = rawInvoker.apply(null, args); - if (argTypes[0].fromWireTypeAutoDowncast) { - rv = argTypes[0].fromWireTypeAutoDowncast(rv); - } else { - rv = argTypes[0].fromWireType(rv); - } + rv = argTypes[0].fromWireType(rv); runDestructors(destructors); return rv; }; diff --git a/src/embind/emval.js b/src/embind/emval.js index 37a4970ecb5da..c60c62e0667f4 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -69,7 +69,7 @@ function __emval_new_cstring(v) { function __emval_take_value(type, v) { type = requireRegisteredType(type, '_emval_take_value'); - v = type.fromWireTypeAutoDowncast ? type.fromWireTypeAutoDowncast(v) : type.fromWireType(v); + v = type.fromWireType(v); return __emval_register(v); } From ecab6656e88f9399410f651c8fe4300dec103712 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 18 Mar 2013 18:40:24 -0700 Subject: [PATCH 336/544] Break some cyclic object dependencies. --- src/embind/embind.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index d3690a6591c49..f6c926b74f8ed 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -473,7 +473,6 @@ function RegisteredPointer( name, rawType, registeredClass, - pointeeType, Handle, isReference, isConst, @@ -487,7 +486,6 @@ function RegisteredPointer( this.name = name; this.rawType = rawType; this.registeredClass = registeredClass; - this.pointeeType = pointeeType; this.Handle = Handle; // <-- I think I can kill this this.isReference = isReference; this.isConst = isConst; @@ -608,8 +606,8 @@ RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) { RegisteredPointer.prototype.getDynamicDowncastType = function(ptr) { var downcastType = null; var type = this.getDynamicRawPointerType(ptr); - if (type && type !== this.pointeeType.rawType) { - var derivation = Module.__getDerivationPath(type, this.pointeeType.rawType); + if (type && type !== this.registeredClass.rawType) { + var derivation = Module.__getDerivationPath(type, this.registeredClass.rawType); for (var i = 0; i < derivation.size(); i++) { downcastType = registeredTypes[derivation.get(i)]; if (downcastType && (!this.isSmartPointer || downcastType.smartPointerType)) { @@ -634,7 +632,7 @@ RegisteredPointer.prototype.fromWireType = function(ptr) { // ptr is a raw point } else { handle = toType._fromWireType(ptr); } - handle.$$.ptr = staticPointerCast(handle.$$.ptr, this.pointeeType.rawType, toType.rawType); + handle.$$.ptr = staticPointerCast(handle.$$.ptr, this.registeredClass.rawType, toType.rawType); } else { handle = this._fromWireType(ptr); } @@ -647,6 +645,7 @@ function ClassHandle() { function RegisteredClass( name, + rawType, constructor, isPolymorphic, baseClassRawType, @@ -656,6 +655,7 @@ function RegisteredClass( downcast ) { this.name = name; + this.rawType = rawType; this.constructor = constructor; this.isPolymorphic = isPolymorphic; this.baseClassRawType = baseClassRawType; @@ -711,6 +711,7 @@ function __embind_register_class( var registeredClass = new RegisteredClass( name, + rawType, Handle, isPolymorphic, baseClassRawType, @@ -756,19 +757,16 @@ function __embind_register_class( name, rawType, registeredClass, - undefined, Handle, true, false, false); - type.pointeeType = type; // :( registerType(rawType, type); registerType(rawPointerType, new RegisteredPointer( name + '*', rawPointerType, registeredClass, - type, Handle, false, false, @@ -778,7 +776,6 @@ function __embind_register_class( name + ' const*', rawConstPointerType, registeredClass, - type, Handle, false, true, @@ -1033,7 +1030,6 @@ function __embind_register_smart_ptr( name, rawType, pointeeType.registeredClass, - pointeeType, Handle, false, false, From d235d3e4958154f8d6fdaea098e86b8495ee407e Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 18 Mar 2013 18:57:21 -0700 Subject: [PATCH 337/544] Simplify RegisteredPointer#fromWireType some --- src/embind/embind.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index f6c926b74f8ed..520ca269dcfad 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -583,14 +583,6 @@ RegisteredPointer.prototype.destructor = function(ptr) { } }; -RegisteredPointer.prototype._fromWireType = function(ptr) { - if (!this.getPointee(ptr)) { - this.destructor(ptr); - return null; - } - return new this.Handle(this, ptr); -}; - RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) { var type = null; if (this.isPolymorphic()) { @@ -620,6 +612,10 @@ RegisteredPointer.prototype.getDynamicDowncastType = function(ptr) { }; RegisteredPointer.prototype.fromWireType = function(ptr) { // ptr is a raw pointer (or a raw smartpointer) + function makeHandle(registeredType, ptr) { + return new registeredType.Handle(registeredType, ptr); + } + var handle; if (!this.getPointee(ptr)) { this.destructor(ptr); @@ -628,13 +624,13 @@ RegisteredPointer.prototype.fromWireType = function(ptr) { // ptr is a raw point var toType = this.getDynamicDowncastType(ptr); if (toType) { if (this.isSmartPointer) { - handle = toType.smartPointerType._fromWireType(ptr); + handle = makeHandle(toType.smartPointerType, ptr); } else { - handle = toType._fromWireType(ptr); + handle = makeHandle(toType, ptr); } handle.$$.ptr = staticPointerCast(handle.$$.ptr, this.registeredClass.rawType, toType.rawType); } else { - handle = this._fromWireType(ptr); + handle = makeHandle(this, ptr); } return handle; }; From 9ec4c29864a967186156a95a9ec8062d05ffa3c9 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 19 Mar 2013 01:15:49 -0700 Subject: [PATCH 338/544] Kill some embind duplication --- src/embind/embind.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 520ca269dcfad..de87dceb7b663 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -661,6 +661,14 @@ function RegisteredClass( this.downcast = downcast; } +function shallowCopy(o) { + var rv = {}; + for (var k in o) { + rv[k] = o[k]; + } + return rv; +} + function __embind_register_class( rawType, rawPointerType, @@ -726,10 +734,7 @@ function __embind_register_class( var clone = Object.create(Handle.prototype); Object.defineProperty(clone, '$$', { - value: { - count: this.$$.count, - ptr: this.$$.ptr, - }, + value: shallowCopy(this.$$), }); clone.$$.count.value += 1; @@ -998,11 +1003,7 @@ function __embind_register_smart_ptr( var clone = Object.create(Handle.prototype); Object.defineProperty(clone, '$$', { - value: { - count: this.$$.count, - smartPtr: this.$$.smartPtr, - ptr: this.$$.ptr, - }, + value: shallowCopy(this.$$), }); clone.$$.count.value += 1; From 09effb641c418d7b8751b04f215d7192075b72cb Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 19 Mar 2013 03:11:45 -0700 Subject: [PATCH 339/544] Simplify upcasting/downcasting, allow multiple smart pointer types per class, and use the same ClassHandle prototype so class handles and smart pointer handles share implementations for .clone() and .delete() --- src/embind/embind.js | 300 +++++++++++++++++-------------- system/include/emscripten/bind.h | 6 +- 2 files changed, 169 insertions(+), 137 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index de87dceb7b663..c1f9552d9aa6e 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -3,12 +3,14 @@ /*global FUNCTION_TABLE, HEAP32, HEAPU8*/ /*global Pointer_stringify*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ -/*global ___getDynamicPointerType: false*/ /*global ___typeName:false*/ -/*global ___staticPointerCast: false*/ +var InternalError = Module.InternalError = extendError(Error, 'InternalError'); var BindingError = Module.BindingError = extendError(Error, 'BindingError'); -var CastError = Module.CastError = extendError(BindingError, 'CastError'); + +function throwInternalError(value) { + throw new InternalError(value); +} function throwBindingError(value) { throw new BindingError(value); @@ -75,6 +77,9 @@ var registeredTypes = {}; // typeID -> [callback] var awaitingDependencies = {}; +// class typeID -> {pointerType: ..., constPointerType: ...} +var registeredPointers = {}; + function registerType(rawType, registeredInstance) { var name = registeredInstance.name; if (!rawType) { @@ -144,17 +149,6 @@ function requireRegisteredType(rawType, humanName) { return impl; } -function staticPointerCast(from, fromType, toType) { - if (!from) { - return from; - } - var to = ___staticPointerCast(from, fromType, toType); - if (to <= 0) { - throw new CastError("Pointer conversion from " + typeName(fromType) + " to " + typeName(toType) + " is not available"); - } - return to; -} - function __embind_register_void(rawType, name) { name = Pointer_stringify(name); registerType(rawType, { @@ -468,7 +462,7 @@ function __embind_register_struct_field( }); } -// I guarantee there is a way to simplify the following data structure. +// todo: I guarantee there is a way to simplify the following data structure. function RegisteredPointer( name, rawType, @@ -477,6 +471,7 @@ function RegisteredPointer( isReference, isConst, isSmartPointer, + pointeeType, sharingPolicy, rawGetPointee, rawConstructor, @@ -490,6 +485,7 @@ function RegisteredPointer( this.isReference = isReference; this.isConst = isConst; this.isSmartPointer = isSmartPointer; + this.pointeeType = pointeeType; this.sharingPolicy = sharingPolicy; this.rawGetPointee = rawGetPointee; this.rawConstructor = rawConstructor; @@ -497,14 +493,16 @@ function RegisteredPointer( this.rawDestructor = rawDestructor; } -RegisteredPointer.prototype.isPolymorphic = function() { - return this.registeredClass.isPolymorphic; -}; - RegisteredPointer.prototype.toWireType = function(destructors, handle) { var self = this; function throwCannotConvert() { - throwBindingError('Cannot convert argument of type ' + handle.$$.ptrType.name + ' to parameter type ' + self.name); + var name; + if (handle.$$.smartPtrType) { + name = handle.$$.smartPtrType.name; + } else { + name = handle.$$.ptrType.name; + } + throwBindingError('Cannot convert argument of type ' + name + ' to parameter type ' + self.name); } if (handle === null) { @@ -537,7 +535,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { switch (this.sharingPolicy) { case 0: // NONE // no upcasting - if (handle.$$.ptrType === this) { + if (handle.$$.smartPtrType === this) { ptr = handle.$$.smartPtr; } else { throwCannotConvert(); @@ -549,7 +547,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { break; case 2: // BY_EMVAL - if (handle.$$.ptrType === this) { + if (handle.$$.smartPtrType === this) { ptr = handle.$$.smartPtr; } else { var clonedHandle = handle.clone(); @@ -583,68 +581,133 @@ RegisteredPointer.prototype.destructor = function(ptr) { } }; -RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) { - var type = null; - if (this.isPolymorphic()) { - if (this.rawGetPointee) { - type = ___getDynamicPointerType(this.rawGetPointee(ptr)); - } else { - type = ___getDynamicPointerType(ptr); - } +RegisteredPointer.prototype.fromWireType = function(ptr) { + // ptr is a raw pointer (or a raw smartpointer) + + // rawPointer is a maybe-null raw pointer + var rawPointer = this.getPointee(ptr); + if (!rawPointer) { + this.destructor(ptr); + return null; } - return type; -}; -RegisteredPointer.prototype.getDynamicDowncastType = function(ptr) { - var downcastType = null; - var type = this.getDynamicRawPointerType(ptr); - if (type && type !== this.registeredClass.rawType) { - var derivation = Module.__getDerivationPath(type, this.registeredClass.rawType); - for (var i = 0; i < derivation.size(); i++) { - downcastType = registeredTypes[derivation.get(i)]; - if (downcastType && (!this.isSmartPointer || downcastType.smartPointerType)) { - break; - } + function makeDefaultHandle() { + if (this.isSmartPointer) { + return makeClassHandle(this.Handle.prototype, { + ptrType: this.pointeeType, + ptr: rawPointer, + smartPtrType: this, + smartPtr: ptr, + }); + } else { + return makeClassHandle(this.Handle.prototype, { + ptrType: this, + ptr: ptr, + }); } - derivation.delete(); } - return downcastType; -}; -RegisteredPointer.prototype.fromWireType = function(ptr) { // ptr is a raw pointer (or a raw smartpointer) - function makeHandle(registeredType, ptr) { - return new registeredType.Handle(registeredType, ptr); + var actualType = this.registeredClass.getActualType(rawPointer); + var registeredPointerRecord = registeredPointers[actualType]; + if (!registeredPointerRecord) { + return makeDefaultHandle.call(this); } - var handle; - if (!this.getPointee(ptr)) { - this.destructor(ptr); - return null; + var toType; + if (this.isConst) { + toType = registeredPointerRecord.constPointerType; + } else { + toType = registeredPointerRecord.pointerType; } - var toType = this.getDynamicDowncastType(ptr); - if (toType) { - if (this.isSmartPointer) { - handle = makeHandle(toType.smartPointerType, ptr); - } else { - handle = makeHandle(toType, ptr); - } - handle.$$.ptr = staticPointerCast(handle.$$.ptr, this.registeredClass.rawType, toType.rawType); + var dp = downcastPointer( + rawPointer, + this.registeredClass, + toType.registeredClass); + if (dp === null) { + return makeDefaultHandle.call(this); + } + if (this.isSmartPointer) { + return makeClassHandle(toType.Handle.prototype, { + ptrType: toType, + ptr: dp, + smartPtrType: this, + smartPtr: ptr, + }); } else { - handle = makeHandle(this, ptr); + return makeClassHandle(toType.Handle.prototype, { + ptrType: toType, + ptr: dp, + }); } - return handle; }; +function makeClassHandle(prototype, record) { + if (!record.ptrType || !record.ptr) { + throwInternalError('makeClassHandle requires ptr and ptrType'); + } + var hasSmartPtrType = !!record.smartPtrType; + var hasSmartPtr = !!record.smartPtr; + if (hasSmartPtrType !== hasSmartPtr) { + throwInternalError('Both smartPtrType and smartPtr must be specified'); + } + record.count = { value: 1 }; + return Object.create(prototype, { + '$$': { + value: record, + }, + }); +} + // root of all pointer and smart pointer handles in embind function ClassHandle() { } +function getInstanceTypeName(handle) { + return handle.$$.ptrType.registeredClass.name; +} + +ClassHandle.prototype.clone = function() { + if (!this.$$.ptr) { + throwBindingError(getInstanceTypeName(this) + ' instance already deleted'); + } + + var clone = Object.create(Object.getPrototypeOf(this), { + '$$': { + value: shallowCopy(this.$$), + } + }); + + clone.$$.count.value += 1; + return clone; +}; + +function runDestructor(handle) { + var $$ = handle.$$; + if ($$.smartPtr) { + $$.smartPtrType.rawDestructor($$.smartPtr); + } else { + $$.ptrType.registeredClass.rawDestructor($$.ptr); + } +} + +ClassHandle.prototype['delete'] = function() { + if (!this.$$.ptr) { + throwBindingError(getInstanceTypeName(this) + ' instance already deleted'); + } + + this.$$.count.value -= 1; + if (0 === this.$$.count.value) { + runDestructor(this); + } + this.$$.smartPtr = undefined; + this.$$.ptr = undefined; +}; + function RegisteredClass( name, rawType, constructor, - isPolymorphic, - baseClassRawType, + rawDestructor, baseClass, getActualType, upcast, @@ -653,8 +716,7 @@ function RegisteredClass( this.name = name; this.rawType = rawType; this.constructor = constructor; - this.isPolymorphic = isPolymorphic; - this.baseClassRawType = baseClassRawType; + this.rawDestructor = rawDestructor; this.baseClass = baseClass; this.getActualType = getActualType; this.upcast = upcast; @@ -677,7 +739,6 @@ function __embind_register_class( getActualType, upcast, downcast, - isPolymorphic, name, rawDestructor ) { @@ -713,46 +774,20 @@ function __embind_register_class( }); }); + Handle.prototype = Object.create(basePrototype, { + constructor: { value: Handle }, + }); + var registeredClass = new RegisteredClass( name, rawType, Handle, - isPolymorphic, - baseClassRawType, + rawDestructor, baseClass, getActualType, upcast, downcast); - Handle.prototype = Object.create(basePrototype, { - constructor: { value: Handle }, - }); - Handle.prototype.clone = function() { - if (!this.$$.ptr) { - throwBindingError(type.name + ' instance already deleted'); - } - - var clone = Object.create(Handle.prototype); - Object.defineProperty(clone, '$$', { - value: shallowCopy(this.$$), - }); - - clone.$$.count.value += 1; - return clone; - }; - - Handle.prototype['delete'] = function() { - if (!this.$$.ptr) { - throwBindingError(type.name + ' instance already deleted'); - } - - this.$$.count.value -= 1; - if (0 === this.$$.count.value) { - rawDestructor(this.$$.ptr); - } - this.$$.ptr = undefined; - }; - // todo: clean this up! var type = new RegisteredPointer( name, @@ -764,23 +799,30 @@ function __embind_register_class( false); registerType(rawType, type); - registerType(rawPointerType, new RegisteredPointer( + var pointerType = new RegisteredPointer( name + '*', rawPointerType, registeredClass, Handle, false, false, - false)); + false); + registerType(rawPointerType, pointerType); - registerType(rawConstPointerType, new RegisteredPointer( + var constPointerType = new RegisteredPointer( name + ' const*', rawConstPointerType, registeredClass, Handle, false, true, - false)); + false); + registerType(rawConstPointerType, constPointerType); + + registeredPointers[rawType] = { + pointerType: pointerType, + constPointerType: constPointerType + }; type.constructor = createNamedFunction(legalFunctionName, function() { if (Object.getPrototypeOf(this) !== Handle.prototype) { @@ -832,6 +874,18 @@ function __embind_register_class_constructor( }); } +function downcastPointer(ptr, ptrClass, desiredClass) { + if (ptrClass === desiredClass) { + return ptr; + } + if (undefined === desiredClass.baseClass) { + return null; // no conversion + } + // O(depth) stack space used + return desiredClass.downcast( + downcastPointer(ptr, ptrClass, desiredClass.baseClass)); +} + function upcastPointer(ptr, ptrClass, desiredClass) { while (ptrClass !== desiredClass) { ptr = ptrClass.upcast(ptr); @@ -983,46 +1037,23 @@ function __embind_register_smart_ptr( whenDependentTypesAreResolved([rawPointeeType], function(pointeeType) { pointeeType = pointeeType[0]; - var Handle = createNamedFunction(makeLegalFunctionName(name), function(ptrType, ptr) { + var Handle = createNamedFunction(makeLegalFunctionName(name), function(smartPtrType, smartPtr, ptrType, ptr) { + if (arguments.length !== 4) { + throwBindingError("internal error"); + } Object.defineProperty(this, '$$', { value: { - ptrType: ptrType, count: {value: 1}, - smartPtr: ptr, - ptr: rawGetPointee(ptr), + ptrType: ptrType, + ptr: ptr, + smartPtrType: registeredPointer, + smartPtr: smartPtr, }, }); }); Handle.prototype = Object.create(pointeeType.Handle.prototype); - Handle.prototype.clone = function() { - if (!this.$$.ptr) { - throwBindingError(pointeeType.name + ' instance already deleted'); - } - - var clone = Object.create(Handle.prototype); - Object.defineProperty(clone, '$$', { - value: shallowCopy(this.$$), - }); - - clone.$$.count.value += 1; - return clone; - }; - - Handle.prototype['delete'] = function() { - if (!this.$$.ptr) { - throwBindingError(pointeeType.name + ' instance already deleted'); - } - - this.$$.count.value -= 1; - if (0 === this.$$.count.value) { - rawDestructor(this.$$.smartPtr); - } - this.$$.smartPtr = undefined; - this.$$.ptr = undefined; - }; - var registeredPointer = new RegisteredPointer( name, rawType, @@ -1030,14 +1061,15 @@ function __embind_register_smart_ptr( Handle, false, false, + // smart pointer properties true, + pointeeType, sharingPolicy, rawGetPointee, rawConstructor, rawShare, rawDestructor); registerType(rawType, registeredPointer); - pointeeType.smartPointerType = registeredPointer; }); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index cd208d37091c9..a1b2a015f0b7c 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -117,7 +117,6 @@ namespace emscripten { GenericFunction getActualType, GenericFunction upcast, GenericFunction downcast, - bool isPolymorphic, const char* className, GenericFunction destructor); @@ -650,9 +649,11 @@ namespace emscripten { } }; + // NOTE: this returns the class type, not the pointer type template inline TYPEID getActualType(T* ptr) { - return reinterpret_cast(&typeid(ptr)); + assert(ptr); + return reinterpret_cast(&typeid(*ptr)); }; } @@ -720,7 +721,6 @@ namespace emscripten { reinterpret_cast(&getActualType), BaseSpecifier::template getUpcaster(), BaseSpecifier::template getDowncaster(), - std::is_polymorphic::value, // TODO: may not be necessary name, reinterpret_cast(&raw_destructor)); } From 78568fe4c2ba8fd014fd8af23453ac8b2d0728f5 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 19 Mar 2013 03:22:47 -0700 Subject: [PATCH 340/544] Remove some dead code --- src/embind/embind.js | 4 + system/lib/embind/bind.cpp | 208 ++++--------------------------------- 2 files changed, 27 insertions(+), 185 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index c1f9552d9aa6e..35d9dfdf50f88 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -470,6 +470,8 @@ function RegisteredPointer( Handle, isReference, isConst, + + // smart pointer properties isSmartPointer, pointeeType, sharingPolicy, @@ -484,6 +486,8 @@ function RegisteredPointer( this.Handle = Handle; // <-- I think I can kill this this.isReference = isReference; this.isConst = isConst; + + // smart pointer properties this.isSmartPointer = isSmartPointer; this.pointeeType = pointeeType; this.sharingPolicy = sharingPolicy; diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 6c792f7874151..e844e52e522a5 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -9,167 +9,9 @@ using namespace emscripten; -namespace __cxxabiv1 { - std::vector __internalGetBaseClasses(const __class_type_info* cti) { - std::vector bases; - - const __si_class_type_info* scti = dynamic_cast(cti); - if (scti) { - bases.emplace_back(scti->__base_type); - } else { - const __vmi_class_type_info* vcti = dynamic_cast(cti); - if (vcti) { - for (int i = 0; i < vcti->__base_count; i++) { - bases.emplace_back(vcti->__base_info[i].__base_type); - } - } - } - return bases; - } - - int __getBaseOffset(const __class_type_info* ctiDv, const __class_type_info* ctiBs) { - int offset = 0; - - const __vmi_class_type_info* vcti = dynamic_cast(ctiDv); - if (vcti) { - for (int i = 0; i < vcti->__base_count; i++) { - if (vcti->__base_info[i].__base_type == ctiBs) { - offset = vcti->__base_info[i].__offset_flags >> __base_class_type_info::__offset_shift; - break; - } - } - } - return offset; - } - - void __getDerivationPaths(const __class_type_info* dv, const __class_type_info* bs, std::vectorpath, std::vector>& paths) { - std::vector newPath(path); - newPath.emplace_back(dv); - if (dv == bs) { - paths.emplace_back(newPath); - } else { - std::vector bases = __internalGetBaseClasses(dv); - for (int i = 0; i < bases.size(); i++) { - __getDerivationPaths(bases[i], bs, newPath, paths); - } - } - } - - int __pathOffset(std::vector path) { - int offset = 0; - for (int i = 0; i < path.size()-1; i++) { - offset += __getBaseOffset(path[i], path[i+1]); - } - return offset; - } -} - namespace emscripten { namespace internal { - // __getDerivationPath returns an array of type_info pointers describing the derivation chain starting with - // the derived type and proceeding toward (and ending with) the base type. Types are only included if they - // appear on all possible derivation paths. - std::vector __getDerivationPath(int dv, const int bs) { - std::vector> paths; - - const std::type_info* dv1 = (std::type_info*)dv; - const std::type_info* bs1 = (std::type_info*)bs; - const __cxxabiv1::__class_type_info* dv2 = dynamic_cast(dv1); - const __cxxabiv1::__class_type_info* bs2 = dynamic_cast(bs1); - - if (dv2 && bs2) { - __cxxabiv1::__getDerivationPaths(dv2, bs2, std::vector(), paths); - } - - std::vector derivationPath; - if (paths.size() > 0) { - for (int j = 0; j < paths[0].size(); j++) { - bool disqualified = false; - for (int i = 1; i < paths.size(); i++) { - bool found = false; - for (int j2 = 0; j2 < paths[i].size(); j2++) { - if (paths[i][j2] == paths[0][j]) { - found = true; - break; - } - } - if (!found) { - disqualified = true; - break; - } - } - if (!disqualified) { - derivationPath.emplace_back((int)paths[0][j]); - } - } - } - return derivationPath; - } - extern "C" { - // These three routines constitute an extension to the compiler's support for dynamic type conversion. - // They are used by embind.js to implement automatic downcasting of return values which are pointers to - // polymorphic objects. - - void* EMSCRIPTEN_KEEPALIVE __staticPointerCast(void* p, const void* from, void* to) { - std::vector> paths; - int direction = 1; - - const std::type_info* from1 = (std::type_info*)from; - const std::type_info* to1 = (std::type_info*)to; - const __cxxabiv1::__class_type_info* from2 = dynamic_cast(from1); - const __cxxabiv1::__class_type_info* to2 = dynamic_cast(to1); - - if (from2 && to2) { - __cxxabiv1::__getDerivationPaths(from2, to2, std::vector(), paths); - if (paths.size() == 0) { - __cxxabiv1::__getDerivationPaths(to2, from2, std::vector(), paths); - direction = -1; - } - } - - int offset = -1; - for (int i = 0; i < paths.size(); i++) { - if (offset < 0) { - offset = __cxxabiv1::__pathOffset(paths[i]); - } else { - if (offset != __cxxabiv1::__pathOffset(paths[i])) { - return (void *)-2; - } - } - } - if (offset < 0) { - return (void *)-1; - } - if (p == 0) { - return (void *)0; - } - return (void *)((int)p + offset * direction); - } - - // __getDynamicPointerType returns (for polymorphic types only!) the type of the instance actually - // pointed to. - const void* EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(void* p) { - void** vtable = *reinterpret_cast(p); - return vtable[-1]; - } - - // Calls to __dynamic_cast are generated by the compiler to implement dynamic_cast<>() -- its prototype is - // not available through any header file. It is called directly here because it allows run-time - // specification of the target pointer type (which can only be specified at compile time when using - // dynamic_cast<>(). - void* __dynamic_cast(void*, const std::type_info*, const std::type_info*, void*); - - // __dynamicPointerCast performs a C++ dynamic_cast<>() operation, but allowing run-time specification of - // the from and to pointer types. - void* EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(void* p, void* to) { - void* ret = __staticPointerCast(p, __getDynamicPointerType(p), to); - if (ret < 0) { - return 0; - } - return ret; - } - const char* EMSCRIPTEN_KEEPALIVE __typeName(const std::type_info* ti) { size_t nameLen = std::min(strlen(ti->name()), 1024U); char* name = (char *)malloc(nameLen+1); @@ -188,33 +30,6 @@ namespace emscripten { return *reinterpret_cast(p); } - EMSCRIPTEN_BINDINGS(([]() { - _embind_register_void(TypeID::get(), "void"); - - _embind_register_bool(TypeID::get(), "bool", true, false); - - _embind_register_integer(TypeID::get(), "char"); - _embind_register_integer(TypeID::get(), "signed char"); - _embind_register_integer(TypeID::get(), "unsigned char"); - _embind_register_integer(TypeID::get(), "short"); - _embind_register_integer(TypeID::get(), "unsigned short"); - _embind_register_integer(TypeID::get(), "int"); - _embind_register_integer(TypeID::get(), "unsigned int"); - _embind_register_integer(TypeID::get(), "long"); - _embind_register_integer(TypeID::get(), "unsigned long"); - - _embind_register_float(TypeID::get(), "float"); - _embind_register_float(TypeID::get(), "double"); - - _embind_register_cstring(TypeID::get(), "std::string"); - _embind_register_emval(TypeID::get(), "emscripten::val"); - - // We bind __getDerivationPath in order to take advantage of the std::vector to Javascript array - // conversion for the return value. This has the unfortunate side-effect of exposing it to third party - // developers, but perhaps the double underscore will scare them away from calling it. - function("__getDerivationPath", &__getDerivationPath); - function("__peek32", &__peek32, allow_raw_pointers()); - })); } JSInterface* create_js_interface(EM_VAL e) { @@ -223,3 +38,26 @@ namespace emscripten { } } +EMSCRIPTEN_BINDINGS(([]() { + using namespace emscripten::internal; + + _embind_register_void(TypeID::get(), "void"); + + _embind_register_bool(TypeID::get(), "bool", true, false); + + _embind_register_integer(TypeID::get(), "char"); + _embind_register_integer(TypeID::get(), "signed char"); + _embind_register_integer(TypeID::get(), "unsigned char"); + _embind_register_integer(TypeID::get(), "short"); + _embind_register_integer(TypeID::get(), "unsigned short"); + _embind_register_integer(TypeID::get(), "int"); + _embind_register_integer(TypeID::get(), "unsigned int"); + _embind_register_integer(TypeID::get(), "long"); + _embind_register_integer(TypeID::get(), "unsigned long"); + + _embind_register_float(TypeID::get(), "float"); + _embind_register_float(TypeID::get(), "double"); + + _embind_register_cstring(TypeID::get(), "std::string"); + _embind_register_emval(TypeID::get(), "emscripten::val"); +})); From 4c10a08fc0d4f070a1e770c28aacfed226021456 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 19 Mar 2013 03:42:26 -0700 Subject: [PATCH 341/544] Simplify things even further, remove the Handle functions and replace with an instance prototype and a constructor function. --- src/embind/embind.js | 88 +++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 59 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 35d9dfdf50f88..e839793c1fecd 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -467,7 +467,6 @@ function RegisteredPointer( name, rawType, registeredClass, - Handle, isReference, isConst, @@ -483,7 +482,6 @@ function RegisteredPointer( this.name = name; this.rawType = rawType; this.registeredClass = registeredClass; - this.Handle = Handle; // <-- I think I can kill this this.isReference = isReference; this.isConst = isConst; @@ -597,14 +595,14 @@ RegisteredPointer.prototype.fromWireType = function(ptr) { function makeDefaultHandle() { if (this.isSmartPointer) { - return makeClassHandle(this.Handle.prototype, { + return makeClassHandle(this.registeredClass.instancePrototype, { ptrType: this.pointeeType, ptr: rawPointer, smartPtrType: this, smartPtr: ptr, }); } else { - return makeClassHandle(this.Handle.prototype, { + return makeClassHandle(this.registeredClass.instancePrototype, { ptrType: this, ptr: ptr, }); @@ -631,14 +629,14 @@ RegisteredPointer.prototype.fromWireType = function(ptr) { return makeDefaultHandle.call(this); } if (this.isSmartPointer) { - return makeClassHandle(toType.Handle.prototype, { + return makeClassHandle(toType.registeredClass.instancePrototype, { ptrType: toType, ptr: dp, smartPtrType: this, smartPtr: ptr, }); } else { - return makeClassHandle(toType.Handle.prototype, { + return makeClassHandle(toType.registeredClass.instancePrototype, { ptrType: toType, ptr: dp, }); @@ -711,6 +709,7 @@ function RegisteredClass( name, rawType, constructor, + instancePrototype, rawDestructor, baseClass, getActualType, @@ -720,6 +719,7 @@ function RegisteredClass( this.name = name; this.rawType = rawType; this.constructor = constructor; + this.instancePrototype = instancePrototype; this.rawDestructor = rawDestructor; this.baseClass = baseClass; this.getActualType = getActualType; @@ -763,29 +763,33 @@ function __embind_register_class( baseClasses[rawType] = baseClassRawType; baseClass = base.registeredClass; - basePrototype = base.Handle.prototype; + basePrototype = baseClass.instancePrototype; } else { basePrototype = ClassHandle.prototype; } - var Handle = createNamedFunction(legalFunctionName, function(ptrType, ptr) { - Object.defineProperty(this, '$$', { - value: { - ptrType: ptrType, - count: { value: 1 }, - ptr: ptr, - } - }); + var constructor = createNamedFunction(legalFunctionName, function() { + if (Object.getPrototypeOf(this) !== instancePrototype) { + throw new BindingError("Use 'new' to construct " + name); + } + var body = registeredClass.constructor_body; + if (undefined === body) { + throw new BindingError(name + " has no accessible constructor"); + } + return body.apply(this, arguments); }); - - Handle.prototype = Object.create(basePrototype, { - constructor: { value: Handle }, + + var instancePrototype = Object.create(basePrototype, { + constructor: { value: constructor }, }); + constructor.prototype = instancePrototype; + var registeredClass = new RegisteredClass( name, rawType, - Handle, + constructor, + instancePrototype, rawDestructor, baseClass, getActualType, @@ -797,7 +801,6 @@ function __embind_register_class( name, rawType, registeredClass, - Handle, true, false, false); @@ -807,7 +810,6 @@ function __embind_register_class( name + '*', rawPointerType, registeredClass, - Handle, false, false, false); @@ -817,7 +819,6 @@ function __embind_register_class( name + ' const*', rawConstPointerType, registeredClass, - Handle, false, true, false); @@ -828,20 +829,7 @@ function __embind_register_class( constPointerType: constPointerType }; - type.constructor = createNamedFunction(legalFunctionName, function() { - if (Object.getPrototypeOf(this) !== Handle.prototype) { - throw new BindingError("Use 'new' to construct " + name); - } - var body = type.constructor_body; - if (undefined === body) { - throw new BindingError(name + " has no accessible constructor"); - } - return body.apply(this, arguments); - }); - type.constructor.prototype = type.Handle.prototype; - type.constructor.type = type; - - exposePublicSymbol(legalFunctionName, type.constructor); + exposePublicSymbol(legalFunctionName, constructor); }); } @@ -859,7 +847,7 @@ function __embind_register_class_constructor( var classType = argTypes[0]; argTypes = argTypes.slice(1); var humanName = 'constructor ' + classType.name; - classType.constructor_body = function() { + classType.registeredClass.constructor_body = function() { if (arguments.length !== argCount - 1) { throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } @@ -902,7 +890,7 @@ function validateThis(this_, classType, humanName) { if (!(this_ instanceof Object)) { throwBindingError(humanName + ' with invalid "this": ' + this_); } - if (!(this_ instanceof classType.constructor)) { + if (!(this_ instanceof classType.registeredClass.constructor)) { throwBindingError(humanName + ' incompatible with "this" of type ' + this_.constructor.name); } if (!this_.$$.ptr) { @@ -934,7 +922,7 @@ function __embind_register_class_function( var classType = argTypes[0]; argTypes = argTypes.slice(1); var humanName = classType.name + '.' + methodName; - classType.Handle.prototype[methodName] = function() { + classType.registeredClass.instancePrototype[methodName] = function() { if (arguments.length !== argCount - 1) { throwBindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } @@ -973,7 +961,7 @@ function __embind_register_class_class_function( rawInvoker = FUNCTION_TABLE[rawInvoker]; whenDependentTypesAreResolved(rawArgTypes, function(argTypes) { var humanName = classType.name + '.' + methodName; - classType.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn); + classType.registeredClass.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn); }); } @@ -994,7 +982,7 @@ function __embind_register_class_property( var classType = converters[0]; var fieldType = converters[1]; var humanName = classType.name + '.' + fieldName; - Object.defineProperty(classType.Handle.prototype, fieldName, { + Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, { get: function() { var ptr = validateThis(this, classType, humanName + ' getter'); return fieldType.fromWireType(getter(ptr, memberPointer)); @@ -1041,28 +1029,10 @@ function __embind_register_smart_ptr( whenDependentTypesAreResolved([rawPointeeType], function(pointeeType) { pointeeType = pointeeType[0]; - var Handle = createNamedFunction(makeLegalFunctionName(name), function(smartPtrType, smartPtr, ptrType, ptr) { - if (arguments.length !== 4) { - throwBindingError("internal error"); - } - Object.defineProperty(this, '$$', { - value: { - count: {value: 1}, - ptrType: ptrType, - ptr: ptr, - smartPtrType: registeredPointer, - smartPtr: smartPtr, - }, - }); - }); - - Handle.prototype = Object.create(pointeeType.Handle.prototype); - var registeredPointer = new RegisteredPointer( name, rawType, pointeeType.registeredClass, - Handle, false, false, // smart pointer properties From a39afe6758e9aadffdd526a7f646293d31389e54 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 19 Mar 2013 03:46:39 -0700 Subject: [PATCH 342/544] Code keeps disappearing :) --- src/embind/embind.js | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index e839793c1fecd..48646dd75fcee 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -465,7 +465,6 @@ function __embind_register_struct_field( // todo: I guarantee there is a way to simplify the following data structure. function RegisteredPointer( name, - rawType, registeredClass, isReference, isConst, @@ -480,7 +479,6 @@ function RegisteredPointer( rawDestructor ) { this.name = name; - this.rawType = rawType; this.registeredClass = registeredClass; this.isReference = isReference; this.isConst = isConst; @@ -707,7 +705,6 @@ ClassHandle.prototype['delete'] = function() { function RegisteredClass( name, - rawType, constructor, instancePrototype, rawDestructor, @@ -717,7 +714,6 @@ function RegisteredClass( downcast ) { this.name = name; - this.rawType = rawType; this.constructor = constructor; this.instancePrototype = instancePrototype; this.rawDestructor = rawDestructor; @@ -758,7 +754,6 @@ function __embind_register_class( var baseClass; var basePrototype; - var depth; if (baseClassRawType) { baseClasses[rawType] = baseClassRawType; @@ -787,7 +782,6 @@ function __embind_register_class( var registeredClass = new RegisteredClass( name, - rawType, constructor, instancePrototype, rawDestructor, @@ -796,19 +790,15 @@ function __embind_register_class( upcast, downcast); - // todo: clean this up! - var type = new RegisteredPointer( + registerType(rawType, new RegisteredPointer( name, - rawType, registeredClass, true, false, - false); - registerType(rawType, type); + false)); var pointerType = new RegisteredPointer( name + '*', - rawPointerType, registeredClass, false, false, @@ -817,7 +807,6 @@ function __embind_register_class( var constPointerType = new RegisteredPointer( name + ' const*', - rawConstPointerType, registeredClass, false, true, @@ -1031,7 +1020,6 @@ function __embind_register_smart_ptr( var registeredPointer = new RegisteredPointer( name, - rawType, pointeeType.registeredClass, false, false, From f6b4ee3e883db2dd787fcde94909c5e91b2f8a92 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 19 Mar 2013 03:49:20 -0700 Subject: [PATCH 343/544] RegisteredPointer and RegisteredClass are pretty simple now. --- src/embind/embind.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 48646dd75fcee..caec797800f29 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -462,7 +462,6 @@ function __embind_register_struct_field( }); } -// todo: I guarantee there is a way to simplify the following data structure. function RegisteredPointer( name, registeredClass, From fe2bcf89921105ad3719655ec59905cc63be5c3d Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 19 Mar 2013 14:56:06 -0700 Subject: [PATCH 344/544] baseClasses is not necessary --- src/embind/embind.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index caec797800f29..48bf2a7f1838a 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -69,8 +69,6 @@ function _embind_repr(v) { } } -var baseClasses = {}; // rawType -> rawBaseType - // typeID -> { toWireType: ..., fromWireType: ... } var registeredTypes = {}; @@ -521,7 +519,8 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { throwBindingError('Expected null or instance of ' + this.name + ', got ' + IMVU.repr(handle)); } // TODO: this is not strictly true - // It seems legal to support BY_EMVAL and INTRUSIVE conversions from raw pointers to smart pointers + // We could support BY_EMVAL conversions from raw pointers to smart pointers + // because the smart pointer can hold a reference to the handle if (this.isSmartPointer && undefined === handle.$$.smartPtr) { throwBindingError('Passing raw pointer to smart pointer is illegal'); } @@ -754,8 +753,6 @@ function __embind_register_class( var baseClass; var basePrototype; if (baseClassRawType) { - baseClasses[rawType] = baseClassRawType; - baseClass = base.registeredClass; basePrototype = baseClass.instancePrototype; } else { From 6f219fd0caad22aadad34dd46bc8043d299b4299 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 19 Mar 2013 16:43:03 -0700 Subject: [PATCH 345/544] Change EMSCRIPTEN_BINDINGS syntax and allow for out-of-order registration of value_tuple elements. --- src/embind/embind.js | 8 +++++--- system/include/emscripten/bind.h | 26 +++++++++++++++++--------- system/lib/embind/bind.cpp | 4 ++-- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 48bf2a7f1838a..5dd631ff6fe08 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -339,10 +339,12 @@ function __embind_register_tuple_element( memberPointer = copyMemberPointer(memberPointer, memberPointerSize); var tupleType = requireRegisteredType(rawTupleType, 'tuple'); - // TODO: this could register elements out of order + var index = tupleType.elements.length; + tupleType.elements.push(undefined); + whenDependentTypesAreResolved([rawType], function(type) { type = type[0]; - tupleType.elements.push({ + tupleType.elements[index] = { read: function(ptr) { return type.fromWireType(getter(ptr, memberPointer)); }, @@ -351,7 +353,7 @@ function __embind_register_tuple_element( setter(ptr, memberPointer, type.toWireType(destructors, o)); runDestructors(destructors); } - }); + }; }); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index a1b2a015f0b7c..b7b17f20b70d1 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -169,14 +169,6 @@ namespace emscripten { GenericFunction constructor, GenericFunction destructor); } - - class BindingsDefinition { - public: - template - BindingsDefinition(Function fn) { - fn(); - } - }; } } @@ -1155,4 +1147,20 @@ namespace emscripten { }; } -#define EMSCRIPTEN_BINDINGS(fn) static emscripten::internal::BindingsDefinition anon_symbol(fn); +namespace emscripten { + namespace internal { + class BindingsDefinition { + public: + template + BindingsDefinition(Function fn) { + fn(); + } + }; + } +} + +#define EMSCRIPTEN_BINDINGS(name) \ + static struct BindingInitializer_##name { \ + BindingInitializer_##name(); \ + } BindingInitializer_##name##_instance; \ + BindingInitializer_##name::BindingInitializer_##name() diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index e844e52e522a5..6994ef0cb32be 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -38,7 +38,7 @@ namespace emscripten { } } -EMSCRIPTEN_BINDINGS(([]() { +EMSCRIPTEN_BINDINGS(native_and_builtin_types) { using namespace emscripten::internal; _embind_register_void(TypeID::get(), "void"); @@ -60,4 +60,4 @@ EMSCRIPTEN_BINDINGS(([]() { _embind_register_cstring(TypeID::get(), "std::string"); _embind_register_emval(TypeID::get(), "emscripten::val"); -})); +} From 46d7a60c3bf776b2994d091f2308ac777540f40c Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 19 Mar 2013 17:04:36 -0700 Subject: [PATCH 346/544] yay, out-of-order registration is tested --- src/embind/embind.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 5dd631ff6fe08..d3ab0bf5581fe 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -342,6 +342,7 @@ function __embind_register_tuple_element( var index = tupleType.elements.length; tupleType.elements.push(undefined); + // TODO: test incomplete registration of value tuples whenDependentTypesAreResolved([rawType], function(type) { type = type[0]; tupleType.elements[index] = { @@ -446,7 +447,7 @@ function __embind_register_struct_field( rawGetter = FUNCTION_TABLE[rawGetter]; rawSetter = FUNCTION_TABLE[rawSetter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); - // TODO: this could register elements out of order + // TODO: test incomplete registration of value structs whenDependentTypesAreResolved([rawFieldType], function(fieldType) { fieldType = fieldType[0]; structType.fields[fieldName] = { From 41b65f63c49bdbdc185d108885ea1c791994c99a Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 20 Mar 2013 13:52:09 -0700 Subject: [PATCH 347/544] Fix a bug in embind when using const return values --- system/include/emscripten/wire.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 3e4a77d9708c4..0c0f5eb811c9b 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -181,6 +181,17 @@ namespace emscripten { } }; + template + struct BindingType { + typedef typename BindingType::WireType WireType; + static WireType toWireType(const T& v) { + return BindingType::toWireType(v); + } + static T fromWireType(WireType wt) { + return BindingType::fromWireType(wt); + } + }; + template struct BindingType { typedef typename BindingType::WireType WireType; From bfcc6330b29040d837d4b7de123c106f3f661b15 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 20 Mar 2013 17:51:15 -0700 Subject: [PATCH 348/544] Simplify getTypeName --- src/embind/embind.js | 22 ++++++++++++-------- system/lib/embind/bind.cpp | 42 ++++++++++++++++++-------------------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index d3ab0bf5581fe..99d7005b26b20 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -3,10 +3,10 @@ /*global FUNCTION_TABLE, HEAP32, HEAPU8*/ /*global Pointer_stringify*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ -/*global ___typeName:false*/ var InternalError = Module.InternalError = extendError(Error, 'InternalError'); var BindingError = Module.BindingError = extendError(Error, 'BindingError'); +var UnboundTypeError = Module.UnboundTypeError = extendError(BindingError, 'UnboundTypeError'); function throwInternalError(value) { throw new InternalError(value); @@ -124,11 +124,8 @@ function whenDependentTypesAreResolved(dependentTypes, onComplete) { } } -function typeName(rawType) { - var bt = ___typeName(rawType); - var rv = Pointer_stringify(bt); - _free(bt); - return rv; +function getTypeName(type) { + return Module._embind_getTypeName(type); } function heap32VectorToArray(count, firstElement) { @@ -142,7 +139,7 @@ function heap32VectorToArray(count, firstElement) { function requireRegisteredType(rawType, humanName) { var impl = registeredTypes[rawType]; if (undefined === impl) { - throwBindingError(humanName + " has unknown type " + typeName(rawType)); + throwBindingError(humanName + " has unknown type " + getTypeName(rawType)); } return impl; } @@ -279,8 +276,17 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); name = Pointer_stringify(name); rawInvoker = FUNCTION_TABLE[rawInvoker]; + + var invoker = function() { + throw new UnboundTypeError('Cannot call ' + name + ' due to unbound types: UnboundFoo'); + } + + exposePublicSymbol(name, function() { + return invoker.apply(this, arguments); + }); + whenDependentTypesAreResolved(argTypes, function(argTypes) { - exposePublicSymbol(name, makeInvoker(name, argCount, argTypes, rawInvoker, fn)); + invoker = makeInvoker(name, argCount, argTypes, rawInvoker, fn); }); } diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 6994ef0cb32be..04a30dfcc2ab8 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -1,5 +1,4 @@ #include -#include <../lib/libcxxabi/src/private_typeinfo.h> #include <../lib/libcxxabi/include/cxxabi.h> #include #include @@ -9,29 +8,26 @@ using namespace emscripten; +static std::string _embind_getTypeName(intptr_t ti_raw) { + auto ti = reinterpret_cast(ti_raw); + int stat; + char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat); + switch (stat) { + case -1: + return ""; + case -2: + return ""; + case -3: + return ""; + } + + std::string rv(demangled); + free(demangled); + return rv; +} + namespace emscripten { namespace internal { - extern "C" { - const char* EMSCRIPTEN_KEEPALIVE __typeName(const std::type_info* ti) { - size_t nameLen = std::min(strlen(ti->name()), 1024U); - char* name = (char *)malloc(nameLen+1); - int stat; - - __cxxabiv1::__cxa_demangle(ti->name(), name, &nameLen, &stat); - - if (stat != 0) { - strncpy(name, ti->name(), nameLen); - name[nameLen] = '\0'; - } - return name; - } - - size_t EMSCRIPTEN_KEEPALIVE __peek32(size_t p) { - return *reinterpret_cast(p); - } - - } - JSInterface* create_js_interface(EM_VAL e) { return new JSInterface(e); } @@ -60,4 +56,6 @@ EMSCRIPTEN_BINDINGS(native_and_builtin_types) { _embind_register_cstring(TypeID::get(), "std::string"); _embind_register_emval(TypeID::get(), "emscripten::val"); + + function("_embind_getTypeName", &_embind_getTypeName); } From 4d6377d15e3ba48f4a6d5eb311bbd8afb618cf0d Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 20 Mar 2013 17:52:09 -0700 Subject: [PATCH 349/544] jshint --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 99d7005b26b20..72312af175d7c 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -279,7 +279,7 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, var invoker = function() { throw new UnboundTypeError('Cannot call ' + name + ' due to unbound types: UnboundFoo'); - } + }; exposePublicSymbol(name, function() { return invoker.apply(this, arguments); From 0a6f5476f19792164e122c27ffca83baa69c1ca3 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 20 Mar 2013 18:39:45 -0700 Subject: [PATCH 350/544] If calling function that uses unbound types, give a sensible error message. --- src/embind/embind.js | 214 +++++++++++++++++++++++-------------- system/lib/embind/bind.cpp | 12 ++- 2 files changed, 141 insertions(+), 85 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 72312af175d7c..c27c49b2d052f 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -8,12 +8,34 @@ var InternalError = Module.InternalError = extendError(Error, 'InternalError'); var BindingError = Module.BindingError = extendError(Error, 'BindingError'); var UnboundTypeError = Module.UnboundTypeError = extendError(BindingError, 'UnboundTypeError'); -function throwInternalError(value) { - throw new InternalError(value); +function throwInternalError(message) { + throw new InternalError(message); } -function throwBindingError(value) { - throw new BindingError(value); +function throwBindingError(message) { + throw new BindingError(message); +} + +function throwUnboundTypeError(message, types) { + var unboundTypes = []; + var seen = {}; + function visit(type) { + if (seen[type]) { + return; + } + if (registeredTypes[type]) { + return; + } + if (typeDependencies[type]) { + typeDependencies[type].forEach(visit); + return; + } + unboundTypes.push(type); + seen[type] = true; + } + types.forEach(visit); + + throw new UnboundTypeError(message + ': ' + unboundTypes.map(getTypeName).join([', '])); } function exposePublicSymbol(name, value) { @@ -75,6 +97,9 @@ var registeredTypes = {}; // typeID -> [callback] var awaitingDependencies = {}; +// typeID -> [dependentTypes] +var typeDependencies = {}; + // class typeID -> {pointerType: ..., constPointerType: ...} var registeredPointers = {}; @@ -88,6 +113,7 @@ function registerType(rawType, registeredInstance) { } registeredTypes[rawType] = registeredInstance; + delete typeDependencies[rawType]; if (awaitingDependencies.hasOwnProperty(rawType)) { var callbacks = awaitingDependencies[rawType]; @@ -98,7 +124,21 @@ function registerType(rawType, registeredInstance) { } } -function whenDependentTypesAreResolved(dependentTypes, onComplete) { +function whenDependentTypesAreResolved(myTypes, dependentTypes, getTypeConverters) { + myTypes.forEach(function(type) { + typeDependencies[type] = dependentTypes; + }); + + function onComplete(typeConverters) { + var myTypeConverters = getTypeConverters(typeConverters); + if (myTypeConverters.length !== myTypes.length) { + throwInternalError('Mismatched type converter count'); + } + for (var i = 0; i < myTypes.length; ++i) { + registerType(myTypes[i], myTypeConverters[i]); + } + } + var typeConverters = new Array(dependentTypes.length); var unregisteredTypes = []; var registered = 0; @@ -278,15 +318,16 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, rawInvoker = FUNCTION_TABLE[rawInvoker]; var invoker = function() { - throw new UnboundTypeError('Cannot call ' + name + ' due to unbound types: UnboundFoo'); + throwUnboundTypeError('Cannot call ' + name + ' due to unbound types', argTypes); }; exposePublicSymbol(name, function() { return invoker.apply(this, arguments); }); - whenDependentTypesAreResolved(argTypes, function(argTypes) { + whenDependentTypesAreResolved([], argTypes, function(argTypes) { invoker = makeInvoker(name, argCount, argTypes, rawInvoker, fn); + return []; }); } @@ -349,7 +390,7 @@ function __embind_register_tuple_element( tupleType.elements.push(undefined); // TODO: test incomplete registration of value tuples - whenDependentTypesAreResolved([rawType], function(type) { + whenDependentTypesAreResolved([], [rawType], function(type) { type = type[0]; tupleType.elements[index] = { read: function(ptr) { @@ -361,6 +402,7 @@ function __embind_register_tuple_element( runDestructors(destructors); } }; + return []; }); } @@ -380,7 +422,7 @@ function __embind_register_tuple_element_accessor( rawStaticSetter = FUNCTION_TABLE[rawStaticSetter]; setter = copyMemberPointer(setter, setterSize); - whenDependentTypesAreResolved([rawElementType], function(elementType) { + whenDependentTypesAreResolved([], [rawElementType], function(elementType) { elementType = elementType[0]; tupleType.elements.push({ read: function(ptr) { @@ -395,6 +437,7 @@ function __embind_register_tuple_element_accessor( runDestructors(destructors); } }); + return []; }); } @@ -454,7 +497,7 @@ function __embind_register_struct_field( rawSetter = FUNCTION_TABLE[rawSetter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); // TODO: test incomplete registration of value structs - whenDependentTypesAreResolved([rawFieldType], function(fieldType) { + whenDependentTypesAreResolved([], [rawFieldType], function(fieldType) { fieldType = fieldType[0]; structType.fields[fieldName] = { read: function(ptr) { @@ -466,6 +509,7 @@ function __embind_register_struct_field( runDestructors(destructors); } }; + return []; }); } @@ -756,75 +800,79 @@ function __embind_register_class( downcast = FUNCTION_TABLE[downcast]; var legalFunctionName = makeLegalFunctionName(name); - whenDependentTypesAreResolved(baseClassRawType ? [baseClassRawType] : [], function(base) { - base = base[0]; - - var baseClass; - var basePrototype; - if (baseClassRawType) { - baseClass = base.registeredClass; - basePrototype = baseClass.instancePrototype; - } else { - basePrototype = ClassHandle.prototype; - } - - var constructor = createNamedFunction(legalFunctionName, function() { - if (Object.getPrototypeOf(this) !== instancePrototype) { - throw new BindingError("Use 'new' to construct " + name); - } - var body = registeredClass.constructor_body; - if (undefined === body) { - throw new BindingError(name + " has no accessible constructor"); + whenDependentTypesAreResolved( + [rawType, rawPointerType, rawConstPointerType], + baseClassRawType ? [baseClassRawType] : [], + function(base) { + base = base[0]; + + var baseClass; + var basePrototype; + if (baseClassRawType) { + baseClass = base.registeredClass; + basePrototype = baseClass.instancePrototype; + } else { + basePrototype = ClassHandle.prototype; } - return body.apply(this, arguments); - }); - var instancePrototype = Object.create(basePrototype, { - constructor: { value: constructor }, - }); - - constructor.prototype = instancePrototype; - - var registeredClass = new RegisteredClass( - name, - constructor, - instancePrototype, - rawDestructor, - baseClass, - getActualType, - upcast, - downcast); - - registerType(rawType, new RegisteredPointer( - name, - registeredClass, - true, - false, - false)); - - var pointerType = new RegisteredPointer( - name + '*', - registeredClass, - false, - false, - false); - registerType(rawPointerType, pointerType); - - var constPointerType = new RegisteredPointer( - name + ' const*', - registeredClass, - false, - true, - false); - registerType(rawConstPointerType, constPointerType); + var constructor = createNamedFunction(legalFunctionName, function() { + if (Object.getPrototypeOf(this) !== instancePrototype) { + throw new BindingError("Use 'new' to construct " + name); + } + var body = registeredClass.constructor_body; + if (undefined === body) { + throw new BindingError(name + " has no accessible constructor"); + } + return body.apply(this, arguments); + }); - registeredPointers[rawType] = { - pointerType: pointerType, - constPointerType: constPointerType - }; + var instancePrototype = Object.create(basePrototype, { + constructor: { value: constructor }, + }); - exposePublicSymbol(legalFunctionName, constructor); - }); + constructor.prototype = instancePrototype; + + var registeredClass = new RegisteredClass( + name, + constructor, + instancePrototype, + rawDestructor, + baseClass, + getActualType, + upcast, + downcast); + + var referenceConverter = new RegisteredPointer( + name, + registeredClass, + true, + false, + false); + + var pointerConverter = new RegisteredPointer( + name + '*', + registeredClass, + false, + false, + false); + + var constPointerConverter = new RegisteredPointer( + name + ' const*', + registeredClass, + false, + true, + false); + + registeredPointers[rawType] = { + pointerType: pointerConverter, + constPointerType: constPointerConverter + }; + + exposePublicSymbol(legalFunctionName, constructor); + + return [referenceConverter, pointerConverter, constPointerConverter]; + } + ); } function __embind_register_class_constructor( @@ -837,7 +885,7 @@ function __embind_register_class_constructor( var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); invoker = FUNCTION_TABLE[invoker]; - whenDependentTypesAreResolved([rawClassType].concat(rawArgTypes), function(argTypes) { + whenDependentTypesAreResolved([], [rawClassType].concat(rawArgTypes), function(argTypes) { var classType = argTypes[0]; argTypes = argTypes.slice(1); var humanName = 'constructor ' + classType.name; @@ -857,6 +905,7 @@ function __embind_register_class_constructor( return argTypes[0].fromWireType(ptr); }; + return []; }); } @@ -912,7 +961,7 @@ function __embind_register_class_function( rawInvoker = FUNCTION_TABLE[rawInvoker]; memberFunction = copyMemberPointer(memberFunction, memberFunctionSize); - whenDependentTypesAreResolved([rawClassType].concat(rawArgTypes), function(argTypes) { + whenDependentTypesAreResolved([], [rawClassType].concat(rawArgTypes), function(argTypes) { var classType = argTypes[0]; argTypes = argTypes.slice(1); var humanName = classType.name + '.' + methodName; @@ -938,6 +987,7 @@ function __embind_register_class_function( runDestructors(destructors); return rv; }; + return []; }); } @@ -953,9 +1003,10 @@ function __embind_register_class_class_function( var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = Pointer_stringify(methodName); rawInvoker = FUNCTION_TABLE[rawInvoker]; - whenDependentTypesAreResolved(rawArgTypes, function(argTypes) { + whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { var humanName = classType.name + '.' + methodName; classType.registeredClass.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn); + return []; }); } @@ -972,7 +1023,7 @@ function __embind_register_class_property( getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); - whenDependentTypesAreResolved([rawClassType, rawFieldType], function(converters) { + whenDependentTypesAreResolved([], [rawClassType, rawFieldType], function(converters) { var classType = converters[0]; var fieldType = converters[1]; var humanName = classType.name + '.' + fieldName; @@ -989,6 +1040,7 @@ function __embind_register_class_property( }, enumerable: true }); + return []; }); } @@ -1020,7 +1072,7 @@ function __embind_register_smart_ptr( rawShare = FUNCTION_TABLE[rawShare]; rawDestructor = FUNCTION_TABLE[rawDestructor]; - whenDependentTypesAreResolved([rawPointeeType], function(pointeeType) { + whenDependentTypesAreResolved([rawType], [rawPointeeType], function(pointeeType) { pointeeType = pointeeType[0]; var registeredPointer = new RegisteredPointer( @@ -1036,7 +1088,7 @@ function __embind_register_smart_ptr( rawConstructor, rawShare, rawDestructor); - registerType(rawType, registeredPointer); + return [registeredPointer]; }); } diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 04a30dfcc2ab8..a75ba96a2aa09 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -12,6 +12,12 @@ static std::string _embind_getTypeName(intptr_t ti_raw) { auto ti = reinterpret_cast(ti_raw); int stat; char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat); + if (stat == 0) { + std::string rv(demangled); + free(demangled); + return rv; + } + switch (stat) { case -1: return ""; @@ -19,11 +25,9 @@ static std::string _embind_getTypeName(intptr_t ti_raw) { return ""; case -3: return ""; + default: + return ""; } - - std::string rv(demangled); - free(demangled); - return rv; } namespace emscripten { From e10ede1e07ee85d9d99bd34eb4ec8a62ae972616 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 20 Mar 2013 20:15:36 -0700 Subject: [PATCH 351/544] Add sensible error messages when working with classes that depend on unbound types. --- src/embind/embind.js | 172 ++++++++++++++++++++++++------------- system/lib/embind/bind.cpp | 37 ++++---- 2 files changed, 128 insertions(+), 81 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index c27c49b2d052f..ddfc4d4393de0 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -3,6 +3,7 @@ /*global FUNCTION_TABLE, HEAP32, HEAPU8*/ /*global Pointer_stringify*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ +/*global ___getTypeName*/ var InternalError = Module.InternalError = extendError(Error, 'InternalError'); var BindingError = Module.BindingError = extendError(Error, 'BindingError'); @@ -45,6 +46,13 @@ function exposePublicSymbol(name, value) { Module[name] = value; } +function replacePublicSymbol(name, value) { + if (!Module.hasOwnProperty(name)) { + throwInternalError('Replacing nonexistant public symbol'); + } + Module[name] = value; +} + // from https://github.com/imvu/imvujs/blob/master/src/error.js function extendError(baseErrorType, errorName) { var errorClass = createNamedFunction(errorName, function(message) { @@ -165,7 +173,10 @@ function whenDependentTypesAreResolved(myTypes, dependentTypes, getTypeConverter } function getTypeName(type) { - return Module._embind_getTypeName(type); + var ptr = ___getTypeName(type); + var rv = Pointer_stringify(ptr); + _free(ptr); + return rv; } function heap32VectorToArray(count, firstElement) { @@ -317,16 +328,12 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, name = Pointer_stringify(name); rawInvoker = FUNCTION_TABLE[rawInvoker]; - var invoker = function() { - throwUnboundTypeError('Cannot call ' + name + ' due to unbound types', argTypes); - }; - exposePublicSymbol(name, function() { - return invoker.apply(this, arguments); + throwUnboundTypeError('Cannot call ' + name + ' due to unbound types', argTypes); }); whenDependentTypesAreResolved([], argTypes, function(argTypes) { - invoker = makeInvoker(name, argCount, argTypes, rawInvoker, fn); + replacePublicSymbol(name, makeInvoker(name, argCount, argTypes, rawInvoker, fn)); return []; }); } @@ -800,6 +807,11 @@ function __embind_register_class( downcast = FUNCTION_TABLE[downcast]; var legalFunctionName = makeLegalFunctionName(name); + exposePublicSymbol(legalFunctionName, function() { + // this code cannot run if baseClassRawType is zero + throwUnboundTypeError('Cannot construct ' + name + ' due to unbound types', [baseClassRawType]); + }); + whenDependentTypesAreResolved( [rawType, rawPointerType, rawConstPointerType], baseClassRawType ? [baseClassRawType] : [], @@ -868,7 +880,7 @@ function __embind_register_class( constPointerType: constPointerConverter }; - exposePublicSymbol(legalFunctionName, constructor); + replacePublicSymbol(legalFunctionName, constructor); return [referenceConverter, pointerConverter, constPointerConverter]; } @@ -885,26 +897,33 @@ function __embind_register_class_constructor( var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); invoker = FUNCTION_TABLE[invoker]; - whenDependentTypesAreResolved([], [rawClassType].concat(rawArgTypes), function(argTypes) { - var classType = argTypes[0]; - argTypes = argTypes.slice(1); + whenDependentTypesAreResolved([], [rawClassType], function(classType) { + classType = classType[0]; var humanName = 'constructor ' + classType.name; - classType.registeredClass.constructor_body = function() { - if (arguments.length !== argCount - 1) { - throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); - } - var destructors = []; - var args = new Array(argCount); - args[0] = rawConstructor; - for (var i = 1; i < argCount; ++i) { - args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]); - } - - var ptr = invoker.apply(null, args); - runDestructors(destructors); - return argTypes[0].fromWireType(ptr); + classType.registeredClass.constructor_body = function() { + throwUnboundTypeError('Cannot construct ' + classType.name + ' due to unbound types', rawArgTypes); }; + + whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { + classType.registeredClass.constructor_body = function() { + if (arguments.length !== argCount - 1) { + throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); + } + var destructors = []; + var args = new Array(argCount); + args[0] = rawConstructor; + for (var i = 1; i < argCount; ++i) { + args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]); + } + + var ptr = invoker.apply(null, args); + runDestructors(destructors); + + return argTypes[0].fromWireType(ptr); + }; + return []; + }); return []; }); } @@ -961,32 +980,39 @@ function __embind_register_class_function( rawInvoker = FUNCTION_TABLE[rawInvoker]; memberFunction = copyMemberPointer(memberFunction, memberFunctionSize); - whenDependentTypesAreResolved([], [rawClassType].concat(rawArgTypes), function(argTypes) { - var classType = argTypes[0]; - argTypes = argTypes.slice(1); + whenDependentTypesAreResolved([], [rawClassType], function(classType) { + classType = classType[0]; var humanName = classType.name + '.' + methodName; + classType.registeredClass.instancePrototype[methodName] = function() { - if (arguments.length !== argCount - 1) { - throwBindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); - } + throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); + }; - var ptr = validateThis(this, classType, humanName); - if (!isConst && this.$$.ptrType.isConst) { - throwBindingError('Cannot call non-const method ' + humanName + ' on const reference'); - } + whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { + classType.registeredClass.instancePrototype[methodName] = function() { + if (arguments.length !== argCount - 1) { + throwBindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); + } - var destructors = []; - var args = new Array(argCount + 1); - args[0] = ptr; - args[1] = memberFunction; - for (var i = 1; i < argCount; ++i) { - args[i + 1] = argTypes[i].toWireType(destructors, arguments[i - 1]); - } - var rv = rawInvoker.apply(null, args); - rv = argTypes[0].fromWireType(rv); - runDestructors(destructors); - return rv; - }; + var ptr = validateThis(this, classType, humanName); + if (!isConst && this.$$.ptrType.isConst) { + throwBindingError('Cannot call non-const method ' + humanName + ' on const reference'); + } + + var destructors = []; + var args = new Array(argCount + 1); + args[0] = ptr; + args[1] = memberFunction; + for (var i = 1; i < argCount; ++i) { + args[i + 1] = argTypes[i].toWireType(destructors, arguments[i - 1]); + } + var rv = rawInvoker.apply(null, args); + rv = argTypes[0].fromWireType(rv); + runDestructors(destructors); + return rv; + }; + return []; + }); return []; }); } @@ -999,13 +1025,21 @@ function __embind_register_class_class_function( rawInvoker, fn ) { - var classType = requireRegisteredType(rawClassType, 'class'); var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = Pointer_stringify(methodName); rawInvoker = FUNCTION_TABLE[rawInvoker]; - whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { + whenDependentTypesAreResolved([], [rawClassType], function(classType) { + classType = classType[0]; var humanName = classType.name + '.' + methodName; - classType.registeredClass.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn); + + classType.registeredClass.constructor[methodName] = function() { + throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); + }; + + whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { + classType.registeredClass.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn); + return []; + }); return []; }); } @@ -1023,23 +1057,39 @@ function __embind_register_class_property( getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; memberPointer = copyMemberPointer(memberPointer, memberPointerSize); - whenDependentTypesAreResolved([], [rawClassType, rawFieldType], function(converters) { - var classType = converters[0]; - var fieldType = converters[1]; + whenDependentTypesAreResolved([], [rawClassType], function(classType) { + classType = classType[0]; var humanName = classType.name + '.' + fieldName; + Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, { get: function() { - var ptr = validateThis(this, classType, humanName + ' getter'); - return fieldType.fromWireType(getter(ptr, memberPointer)); + throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [rawFieldType]); }, - set: function(v) { - var ptr = validateThis(this, classType, humanName + ' setter'); - var destructors = []; - setter(ptr, memberPointer, fieldType.toWireType(destructors, v)); - runDestructors(destructors); + set: function() { + throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [rawFieldType]); }, - enumerable: true + enumerable: true, + configurable: true + }); + + whenDependentTypesAreResolved([], [rawFieldType], function(fieldType) { + fieldType = fieldType[0]; + Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, { + get: function() { + var ptr = validateThis(this, classType, humanName + ' getter'); + return fieldType.fromWireType(getter(ptr, memberPointer)); + }, + set: function(v) { + var ptr = validateThis(this, classType, humanName + ' setter'); + var destructors = []; + setter(ptr, memberPointer, fieldType.toWireType(destructors, v)); + runDestructors(destructors); + }, + enumerable: true + }); + return []; }); + return []; }); } diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index a75ba96a2aa09..a5c878f5fd967 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -8,25 +8,24 @@ using namespace emscripten; -static std::string _embind_getTypeName(intptr_t ti_raw) { - auto ti = reinterpret_cast(ti_raw); - int stat; - char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat); - if (stat == 0) { - std::string rv(demangled); - free(demangled); - return rv; - } +extern "C" { + const char* EMSCRIPTEN_KEEPALIVE __getTypeName(const std::type_info* ti) { + int stat; + char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat); + if (stat == 0 && demangled) { + return demangled; + } - switch (stat) { - case -1: - return ""; - case -2: - return ""; - case -3: - return ""; - default: - return ""; + switch (stat) { + case -1: + return strdup(""); + case -2: + return strdup(""); + case -3: + return strdup(""); + default: + return strdup(""); + } } } @@ -60,6 +59,4 @@ EMSCRIPTEN_BINDINGS(native_and_builtin_types) { _embind_register_cstring(TypeID::get(), "std::string"); _embind_register_emval(TypeID::get(), "emscripten::val"); - - function("_embind_getTypeName", &_embind_getTypeName); } From 0b8597a8dbf36b26dfb76df8d11fa7377bd810f1 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 21 Mar 2013 01:23:25 -0700 Subject: [PATCH 352/544] Some tweaks to facilitate making value_struct and value_tuple simpler. --- system/include/emscripten/bind.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index b7b17f20b70d1..ad7e7b35f4817 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -370,14 +370,14 @@ namespace emscripten { typedef internal::BindingType MemberBinding; typedef typename MemberBinding::WireType WireType; - static WireType get( - ClassType& ptr, + static WireType getWire( + const ClassType& ptr, const MemberPointer& field ) { return MemberBinding::toWireType(ptr.*field); } - static void set( + static void setWire( ClassType& ptr, const MemberPointer& field, WireType value @@ -387,7 +387,7 @@ namespace emscripten { template static WireType propertyGet( - ClassType& ptr, + const ClassType& ptr, const Getter& getter ) { return MemberBinding::toWireType(getter(ptr)); @@ -425,8 +425,8 @@ namespace emscripten { internal::_embind_register_tuple_element( internal::TypeID::get(), internal::TypeID::get(), - reinterpret_cast(&internal::MemberAccess::get), - reinterpret_cast(&internal::MemberAccess::set), + reinterpret_cast(&internal::MemberAccess::getWire), + reinterpret_cast(&internal::MemberAccess::setWire), sizeof(field), &field); @@ -511,8 +511,8 @@ namespace emscripten { internal::TypeID::get(), fieldName, internal::TypeID::get(), - reinterpret_cast(&internal::MemberAccess::get), - reinterpret_cast(&internal::MemberAccess::set), + reinterpret_cast(&internal::MemberAccess::getWire), + reinterpret_cast(&internal::MemberAccess::setWire), sizeof(field), &field); @@ -865,8 +865,8 @@ namespace emscripten { TypeID::get(), fieldName, TypeID::get(), - reinterpret_cast(&MemberAccess::get), - reinterpret_cast(&MemberAccess::set), + reinterpret_cast(&MemberAccess::getWire), + reinterpret_cast(&MemberAccess::setWire), sizeof(field), &field); return *this; From b7936b0a61a37b451b2e4f01cb02986d26640d35 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Sat, 23 Mar 2013 02:07:45 -0700 Subject: [PATCH 353/544] Unify 'this' handling in class functions. 'this' is just the first argument to the method. This removes several special cases and will remove even more soon. --- src/embind/embind.js | 23 +++--- system/include/emscripten/bind.h | 119 +++++++++++-------------------- 2 files changed, 50 insertions(+), 92 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index ddfc4d4393de0..d5e8659de1103 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -958,7 +958,8 @@ function validateThis(this_, classType, humanName) { if (!this_.$$.ptr) { throwBindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); } - + + // todo: kill this return upcastPointer( this_.$$.ptr, this_.$$.ptrType.registeredClass, @@ -969,8 +970,7 @@ function __embind_register_class_function( rawClassType, methodName, argCount, - rawArgTypesAddr, - isConst, + rawArgTypesAddr, // [ReturnType, ThisType, Args...] rawInvoker, memberFunctionSize, memberFunction @@ -990,21 +990,18 @@ function __embind_register_class_function( whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { classType.registeredClass.instancePrototype[methodName] = function() { - if (arguments.length !== argCount - 1) { - throwBindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); + if (arguments.length !== argCount - 2) { + throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } - var ptr = validateThis(this, classType, humanName); - if (!isConst && this.$$.ptrType.isConst) { - throwBindingError('Cannot call non-const method ' + humanName + ' on const reference'); - } + validateThis(this, classType, humanName); var destructors = []; var args = new Array(argCount + 1); - args[0] = ptr; - args[1] = memberFunction; - for (var i = 1; i < argCount; ++i) { - args[i + 1] = argTypes[i].toWireType(destructors, arguments[i - 1]); + args[0] = memberFunction; + args[1] = argTypes[1].toWireType(destructors, this); + for (var i = 2; i < argCount; ++i) { + args[i] = argTypes[i].toWireType(destructors, arguments[i - 2]); } var rv = rawInvoker.apply(null, args); rv = argTypes[0].fromWireType(rv); diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index ad7e7b35f4817..76ae7df62675e 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -132,7 +132,6 @@ namespace emscripten { const char* methodName, unsigned argCount, TYPEID argTypes[], - bool isConst, GenericFunction invoker, size_t memberFunctionSize, void* memberFunction); @@ -186,6 +185,7 @@ namespace emscripten { static constexpr int index = 0; }; + /* template struct allow_raw_pointer { template @@ -197,6 +197,7 @@ namespace emscripten { >::type type; }; }; + */ // whitelist all raw pointers struct allow_raw_pointers { @@ -210,6 +211,11 @@ namespace emscripten { }; }; + // this is temporary until arg policies are reworked + template + struct allow_raw_pointer : public allow_raw_pointers { + }; + namespace internal { template struct Invoker { @@ -278,87 +284,62 @@ namespace emscripten { delete ptr; } - template + template struct FunctionInvoker { - typedef ReturnType (*FunctionPointer)(ClassType& ct, Args...); static typename internal::BindingType::WireType invoke( - ClassType* ptr, - FunctionPointer* function, + FunctionPointerType* function, + typename internal::BindingType::WireType wireThis, typename internal::BindingType::WireType... args ) { return internal::BindingType::toWireType( - (*function)(*ptr, internal::BindingType::fromWireType(args)...) + (*function)( + internal::BindingType::fromWireType(wireThis), + internal::BindingType::fromWireType(args)...) ); } }; - template - struct FunctionInvoker { - typedef void (*FunctionPointer)(ClassType& ct, Args...); + template + struct FunctionInvoker { static void invoke( - ClassType* ptr, - FunctionPointer* function, + FunctionPointerType* function, + typename internal::BindingType::WireType wireThis, typename internal::BindingType::WireType... args ) { - (*function)(*ptr, internal::BindingType::fromWireType(args)...); + (*function)( + internal::BindingType::fromWireType(wireThis), + internal::BindingType::fromWireType(args)...); } }; - template + template struct MethodInvoker { - typedef ReturnType (ClassType::*MemberPointer)(Args...); - static typename internal::BindingType::WireType invoke( - ClassType* ptr, - const MemberPointer& method, - typename internal::BindingType::WireType... args - ) { - return internal::BindingType::toWireType( - (ptr->*method)( - internal::BindingType::fromWireType(args)... - ) - ); - } - }; - - template - struct MethodInvoker { - typedef void (ClassType::*MemberPointer)(Args...); - static void invoke( - ClassType* ptr, - const MemberPointer& method, - typename internal::BindingType::WireType... args - ) { - return (ptr->*method)( - internal::BindingType::fromWireType(args)... - ); - } - }; - - template - struct ConstMethodInvoker { - typedef ReturnType (ClassType::*MemberPointer)(Args...) const; static typename internal::BindingType::WireType invoke( - const ClassType* ptr, const MemberPointer& method, + typename internal::BindingType::WireType wireThis, typename internal::BindingType::WireType... args ) { return internal::BindingType::toWireType( - (ptr->*method)( + (internal::BindingType::fromWireType(wireThis)->*method)( internal::BindingType::fromWireType(args)... ) ); } }; - template - struct ConstMethodInvoker { - typedef void (ClassType::*MemberPointer)(Args...) const; + template + struct MethodInvoker { static void invoke( - const ClassType* ptr, const MemberPointer& method, + typename internal::BindingType::WireType wireThis, typename internal::BindingType::WireType... args ) { - return (ptr->*method)( + return (internal::BindingType::fromWireType(wireThis)->*method)( internal::BindingType::fromWireType(args)... ); } @@ -793,14 +774,13 @@ namespace emscripten { class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...), Policies...) { using namespace internal; - typename WithPolicies::template ArgTypeList args; + typename WithPolicies::template ArgTypeList, Args...> args; _embind_register_class_function( TypeID::get(), methodName, args.count, args.types, - false, - reinterpret_cast(&MethodInvoker::invoke), + reinterpret_cast(&MethodInvoker::invoke), sizeof(memberFunction), &memberFunction); return *this; @@ -810,48 +790,29 @@ namespace emscripten { class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const, Policies...) { using namespace internal; - typename WithPolicies::template ArgTypeList args; + typename WithPolicies::template ArgTypeList, Args...> args; _embind_register_class_function( TypeID::get(), methodName, args.count, args.types, - true, - reinterpret_cast(&ConstMethodInvoker::invoke), + reinterpret_cast(&MethodInvoker::invoke), sizeof(memberFunction), &memberFunction); return *this; } - template - class_& function(const char* methodName, ReturnType (*function)(ClassType& ptr, Args...), Policies...) { - using namespace internal; - - typename WithPolicies::template ArgTypeList args; - _embind_register_class_function( - TypeID::get(), - methodName, - args.count, - args.types, - false, - reinterpret_cast(&FunctionInvoker::invoke), - sizeof(function), - &function); - return *this; - } - - template - class_& function(const char* methodName, ReturnType (*function)(const ClassType& ptr, Args...), Policies...) { + template + class_& function(const char* methodName, ReturnType (*function)(ThisType, Args...), Policies...) { using namespace internal; - typename WithPolicies::template ArgTypeList args; + typename WithPolicies::template ArgTypeList args; _embind_register_class_function( TypeID::get(), methodName, args.count, args.types, - true, - reinterpret_cast(&FunctionInvoker::invoke), + reinterpret_cast(&FunctionInvoker::invoke), sizeof(function), &function); return *this; From d0d2471703ec6bd62a9d5557984a74a358c032f6 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Sat, 23 Mar 2013 23:52:27 -0700 Subject: [PATCH 354/544] Fix a bug in external class function definitions and allow specifying functions that take smart pointers for 'this' --- system/include/emscripten/bind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 76ae7df62675e..332c533b8c1cd 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -812,7 +812,7 @@ namespace emscripten { methodName, args.count, args.types, - reinterpret_cast(&FunctionInvoker::invoke), + reinterpret_cast(&FunctionInvoker::invoke), sizeof(function), &function); return *this; From 7973873abff495fab9f9193e057a6c6c52871d05 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 25 Mar 2013 16:39:21 -0700 Subject: [PATCH 355/544] Improve the names of functions registered by embind so they show up in the chrome profiler. --- src/embind/embind.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index d5e8659de1103..c7b1633a0f85c 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -85,6 +85,7 @@ function createNamedFunction(name, body) { return new Function( "body", "return function " + name + "() {\n" + + " \"use strict\";" + " return body.apply(this, arguments);\n" + "};\n" )(body); @@ -306,7 +307,7 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { if (!FUNCTION_TABLE[fn]) { throwBindingError('function '+name+' is not defined'); } - return function() { + return createNamedFunction(makeLegalFunctionName(name), function() { if (arguments.length !== argCount - 1) { throwBindingError('function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + (argCount - 1)); } @@ -320,7 +321,7 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { rv = argTypes[0].fromWireType(rv); runDestructors(destructors); return rv; - }; + }); } function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, fn) { @@ -989,7 +990,7 @@ function __embind_register_class_function( }; whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { - classType.registeredClass.instancePrototype[methodName] = function() { + classType.registeredClass.instancePrototype[methodName] = createNamedFunction(makeLegalFunctionName(humanName), function() { if (arguments.length !== argCount - 2) { throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } @@ -1007,7 +1008,7 @@ function __embind_register_class_function( rv = argTypes[0].fromWireType(rv); runDestructors(destructors); return rv; - }; + }); return []; }); return []; @@ -1094,12 +1095,12 @@ function __embind_register_class_property( var char_0 = '0'.charCodeAt(0); var char_9 = '9'.charCodeAt(0); function makeLegalFunctionName(name) { - var rv = name.replace(/[^a-zA-Z0-9_]/g, '$'); - var f = rv.charCodeAt(0); + name = name.replace(/[^a-zA-Z0-9_]/g, '$'); + var f = name.charCodeAt(0); if (f >= char_0 && f <= char_9) { - return '_' + rv; + return '_' + name; } else { - return rv; + return name; } } From dbd1a3bfe253ac1df0200427de10f60dc520cfb1 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 26 Mar 2013 12:39:57 -0700 Subject: [PATCH 356/544] Allow multiple arguments to emscripten::val::new_() --- src/embind/emval.js | 18 ++++++++++++++++-- system/include/emscripten/val.h | 29 +++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index c60c62e0667f4..eb31777b50959 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -73,8 +73,22 @@ function __emval_take_value(type, v) { return __emval_register(v); } -function __emval_new(handle) { - return __emval_register(new (_emval_handle_array[handle].value)); +function __emval_new(handle, argCount, argTypes) { + var args = parseParameters( + argCount, + argTypes, + Array.prototype.slice.call(arguments, 3)); + + // implement what amounts to operator new + var constructor = _emval_handle_array[handle].value; + function dummy(){} + dummy.prototype = constructor.prototype; + var obj = new constructor; + var rv = constructor.apply(obj, args); + if (typeof rv === 'object') { + obj = rv; + } + return __emval_register(obj); } // appease jshint (technically this code uses eval) diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 3952e008d6fef..48f8ef694aa41 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -20,7 +20,11 @@ namespace emscripten { EM_VAL _emval_new_cstring(const char*); void _emval_take_value(TYPEID type/*, ...*/); - EM_VAL _emval_new(EM_VAL value); + EM_VAL _emval_new( + EM_VAL value, + unsigned argCount, + internal::TYPEID argTypes[] + /*, ... */); EM_VAL _emval_get_global(const char* name); EM_VAL _emval_get_property(EM_VAL object, EM_VAL key); @@ -122,8 +126,25 @@ namespace emscripten { return val::global("Object")["prototype"]["hasOwnProperty"].call("call", *this, val(key)).as(); } - val new_() const { - return val(internal::_emval_new(handle)); + template + val new_(Args... args) const { + using namespace internal; + + WithPolicies<>::ArgTypeList argList; + // todo: this is awfully similar to operator(), can we + // merge them somehow? + typedef EM_VAL (*TypedNew)( + EM_VAL, + unsigned, + TYPEID argTypes[], + typename BindingType::WireType...); + TypedNew typedNew = reinterpret_cast(&_emval_new); + return val( + typedNew( + handle, + argList.count, + argList.types, + toWireType(args)...)); } template @@ -136,7 +157,7 @@ namespace emscripten { internal::_emval_set_property(handle, val(key).handle, v.handle); } - template + template val operator()(Args... args) { using namespace internal; From 56783851c34932a3e6196c38865905d966666ba0 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 26 Mar 2013 13:30:01 -0700 Subject: [PATCH 357/544] can look up module properties like HEAP8 from within C++ :) --- src/embind/emval.js | 5 +++++ system/include/emscripten/val.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/embind/emval.js b/src/embind/emval.js index eb31777b50959..7153ae6d9671d 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -99,6 +99,11 @@ function __emval_get_global(name) { return __emval_register(global[name]); } +function __emval_get_module_property(name) { + name = Pointer_stringify(name); + return __emval_register(Module[name]); +} + function __emval_get_property(handle, key) { return __emval_register(_emval_handle_array[handle].value[_emval_handle_array[key].value]); } diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 48f8ef694aa41..91f775a709fc2 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -27,6 +27,7 @@ namespace emscripten { /*, ... */); EM_VAL _emval_get_global(const char* name); + EM_VAL _emval_get_module_property(const char* name); EM_VAL _emval_get_property(EM_VAL object, EM_VAL key); void _emval_set_property(EM_VAL object, EM_VAL key, EM_VAL value); void _emval_as(EM_VAL value, TYPEID returnType); @@ -92,6 +93,10 @@ namespace emscripten { return val(internal::_emval_get_global(name)); } + static val module_property(const char* name) { + return val(internal::_emval_get_module_property(name)); + } + template explicit val(const T& value) { typedef internal::BindingType BT; From 638478a9a9234e7adb14259735432babd31bddba Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 26 Mar 2013 14:27:57 -0700 Subject: [PATCH 358/544] Typed array objects require use of operator new. You can't just call them directly. --- src/embind/emval.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index 7153ae6d9671d..7cdac6d93b979 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -73,14 +73,35 @@ function __emval_take_value(type, v) { return __emval_register(v); } +var __newers = {}; // arity -> function + function __emval_new(handle, argCount, argTypes) { var args = parseParameters( argCount, argTypes, Array.prototype.slice.call(arguments, 3)); - // implement what amounts to operator new + // Alas, we are forced to use operator new until WebKit enables + // constructing typed arrays without new. + // In WebKit, Uint8Array(10) throws an error. + // In every other browser, it's identical to new Uint8Array(10). + + var newer = __newers[argCount]; + if (!newer) { + var parameters = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + parameters[i] = 'a' + i; + } + /*jshint evil:true*/ + newer = __newers[argCount] = new Function( + ['c'].concat(parameters), + "return new c(" + parameters.join(',') + ");"); + } + var constructor = _emval_handle_array[handle].value; + var obj = newer.apply(undefined, [constructor].concat(args)); +/* + // implement what amounts to operator new function dummy(){} dummy.prototype = constructor.prototype; var obj = new constructor; @@ -88,6 +109,7 @@ function __emval_new(handle, argCount, argTypes) { if (typeof rv === 'object') { obj = rv; } +*/ return __emval_register(obj); } From 08881f98fdf4688afab03f4b0632f4d1385de969 Mon Sep 17 00:00:00 2001 From: jinsuck Date: Wed, 27 Mar 2013 14:35:59 -0700 Subject: [PATCH 359/544] add a helper method for Northstar unit testing (when emval leaks, we want to see what is left there) --- src/embind/emval.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/embind/emval.js b/src/embind/emval.js index 7cdac6d93b979..45030b99c633d 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -19,6 +19,16 @@ Module.count_emval_handles = function() { return count; }; +/** @expose */ +Module.get_first_emval = function() { + for (var i = 0; i < _emval_handle_array.length; ++i) { + if (_emval_handle_array[i] !== undefined) { + return _emval_handle_array[i]; + } + } + return null; +}; + // Private C++ API function __emval_register(value) { From 113721e6c6ca4cbde2bb39c4460269424ef3d81d Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Tue, 26 Mar 2013 12:18:13 +0200 Subject: [PATCH 360/544] Raise a TypeError if user tries to push an integer from JS side to C/C++ function exported with embind and the integer (char/short/int/long) is out of bounds of the data type expected by the C++ function. --- src/embind/embind.js | 9 ++++++++- system/include/emscripten/bind.h | 4 +++- system/lib/embind/bind.cpp | 19 ++++++++++--------- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index c7b1633a0f85c..ccce9f1919373 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -221,10 +221,14 @@ function __embind_register_bool(rawType, name, trueValue, falseValue) { }); } -function __embind_register_integer(rawType, name) { +// When converting a number from JS to C++ side, the valid range of the number is +// [minRange, maxRange], inclusive. +function __embind_register_integer(primitiveType, name, minRange, maxRange) { name = Pointer_stringify(name); registerType(rawType, { name: name, + minRange: minRange, + maxRange: maxRange, fromWireType: function(value) { return value; }, @@ -232,6 +236,9 @@ function __embind_register_integer(rawType, name) { if (typeof value !== "number") { throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + this.name); } + if (value < minRange || value > maxRange) { + throw new TypeError('Passing a number "' + _embind_repr(value) + '" from JS side to C/C++ side to an argument of type "' + name + '", which is outside the valid range [' + minRange + ', ' + maxRange + ']!'); + } return value | 0; }, }); diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 332c533b8c1cd..b30cf54b267fd 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -39,7 +39,9 @@ namespace emscripten { void _embind_register_integer( TYPEID integerType, - const char* name); + const char* name, + int minRange, + int maxRange); void _embind_register_float( TYPEID floatType, diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index a5c878f5fd967..417d9ffd6b356 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -5,6 +5,7 @@ #include #include #include +#include using namespace emscripten; @@ -44,15 +45,15 @@ EMSCRIPTEN_BINDINGS(native_and_builtin_types) { _embind_register_bool(TypeID::get(), "bool", true, false); - _embind_register_integer(TypeID::get(), "char"); - _embind_register_integer(TypeID::get(), "signed char"); - _embind_register_integer(TypeID::get(), "unsigned char"); - _embind_register_integer(TypeID::get(), "short"); - _embind_register_integer(TypeID::get(), "unsigned short"); - _embind_register_integer(TypeID::get(), "int"); - _embind_register_integer(TypeID::get(), "unsigned int"); - _embind_register_integer(TypeID::get(), "long"); - _embind_register_integer(TypeID::get(), "unsigned long"); + _embind_register_integer(TypeID::get(), "char", CHAR_MIN, CHAR_MAX); + _embind_register_integer(TypeID::get(), "signed char", SCHAR_MIN, SCHAR_MAX); + _embind_register_integer(TypeID::get(), "unsigned char", 0, UCHAR_MAX); + _embind_register_integer(TypeID::get(), "short", SHRT_MIN, SHRT_MAX); + _embind_register_integer(TypeID::get(), "unsigned short", 0, USHRT_MAX); + _embind_register_integer(TypeID::get(), "int", INT_MIN, INT_MAX); + _embind_register_integer(TypeID::get(), "unsigned int", 0, UINT_MAX); + _embind_register_integer(TypeID::get(), "long", LONG_MIN, LONG_MAX); + _embind_register_integer(TypeID::get(), "unsigned long", 0, ULONG_MAX); _embind_register_float(TypeID::get(), "float"); _embind_register_float(TypeID::get(), "double"); From 0c11a28ccfa3716962c7424fe227c82edc04de16 Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Wed, 27 Mar 2013 08:58:35 +0200 Subject: [PATCH 361/544] Fix passing of UINT_MAX and ULONG_MAX from C++ to JS function. LLVM doesn't have u32 type, so UINT_MAX literal comes out as 'i32 -1' literal to JS, which whould treat it as a negative -1.0 double. --- src/embind/embind.js | 5 ++++- system/include/emscripten/bind.h | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index ccce9f1919373..1a2cec4498237 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -225,7 +225,10 @@ function __embind_register_bool(rawType, name, trueValue, falseValue) { // [minRange, maxRange], inclusive. function __embind_register_integer(primitiveType, name, minRange, maxRange) { name = Pointer_stringify(name); - registerType(rawType, { + if (maxRange == -1) { // LLVM doesn't have signed and unsigned 32-bit types, so u32 literals come out as 'i32 -1'. Always treat those as max u32. + maxRange = 4294967295; + } + registerType(primitiveType, { name: name, minRange: minRange, maxRange: maxRange, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index b30cf54b267fd..211c67c00583c 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -40,8 +40,8 @@ namespace emscripten { void _embind_register_integer( TYPEID integerType, const char* name, - int minRange, - int maxRange); + long minRange, + unsigned long maxRange); void _embind_register_float( TYPEID floatType, From c424c0ac7f08fa4ce0e2eac1db1f5c53733bbb14 Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Wed, 27 Mar 2013 09:07:03 +0200 Subject: [PATCH 362/544] Annotate a few places where -O3 level unsafe optimizations could be performed by registering a faster form of toWireType function that omits type checks. toWireType can potentially be a 'hot' function in C++<->JS interop. --- src/embind/embind.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index 1a2cec4498237..f52e80ec69547 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -236,6 +236,8 @@ function __embind_register_integer(primitiveType, name, minRange, maxRange) { return value; }, toWireType: function(destructors, value) { + // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: we could + // avoid the following two if()s and assume value is of proper type. if (typeof value !== "number") { throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + this.name); } @@ -255,6 +257,8 @@ function __embind_register_float(rawType, name) { return value; }, toWireType: function(destructors, value) { + // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: we could + // avoid the following if() and assume value is of proper type. if (typeof value !== "number") { throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' +this.name); } @@ -485,6 +489,8 @@ function __embind_register_struct( }, toWireType: function(destructors, o) { var fields = this.fields; + // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: + // assume all fields are present without checking. for (var fieldName in fields) { if (!(fieldName in o)) { throw new TypeError('Missing field'); From da222ce8d8529d92d4256369bd910e4d5929a008 Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Thu, 28 Mar 2013 11:06:48 +0200 Subject: [PATCH 363/544] Fix equality testing in previous commit --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index f52e80ec69547..e0abe6f1d8391 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -225,7 +225,7 @@ function __embind_register_bool(rawType, name, trueValue, falseValue) { // [minRange, maxRange], inclusive. function __embind_register_integer(primitiveType, name, minRange, maxRange) { name = Pointer_stringify(name); - if (maxRange == -1) { // LLVM doesn't have signed and unsigned 32-bit types, so u32 literals come out as 'i32 -1'. Always treat those as max u32. + if (maxRange === -1) { // LLVM doesn't have signed and unsigned 32-bit types, so u32 literals come out as 'i32 -1'. Always treat those as max u32. maxRange = 4294967295; } registerType(primitiveType, { From 92dee924425cb3ee1b7a266ab7a280f94baf33be Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Fri, 29 Mar 2013 13:42:58 +0200 Subject: [PATCH 364/544] Migrate embind tests from IMVU repository to emscripten repository. --- tests/embind/embind.test.js | 1495 +++++++++++++++++++++++ tests/embind/embind_test.cpp | 1883 ++++++++++++++++++++++++++--- tests/embind/embind_test.js | 398 ------ tests/embind/imvu_test_adapter.js | 614 ++++++++++ tests/embind/underscore-1.4.2.js | 1200 ++++++++++++++++++ tests/runner.py | 54 +- 6 files changed, 5016 insertions(+), 628 deletions(-) create mode 100755 tests/embind/embind.test.js delete mode 100644 tests/embind/embind_test.js create mode 100755 tests/embind/imvu_test_adapter.js create mode 100755 tests/embind/underscore-1.4.2.js diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js new file mode 100755 index 0000000000000..94d935f2eadcc --- /dev/null +++ b/tests/embind/embind.test.js @@ -0,0 +1,1495 @@ +module({ + Emscripten: '../../../../build/embind_test.js', +}, function(imports) { + var cm = imports.Emscripten; + + var CheckForLeaks = fixture("check for leaks", function() { + this.setUp(function() { + if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! + cm._mallocDebug(2); + assert.equal(0, cm.count_emval_handles()); + cm._mallocAssertAllMemoryFree(); + } + }); + this.tearDown(function() { + if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! + cm._mallocAssertAllMemoryFree(); + assert.equal(0, cm.count_emval_handles()); + } + }); + }); + + var BaseFixture = CheckForLeaks; + + BaseFixture.extend("temp jig", function() { + test("temp test", function() { + }); + }); + + if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! + + BaseFixture.extend("leak testing", function() { + test("no memory allocated at start of test", function() { + cm._mallocAssertAllMemoryFree(); + }); + test("assert when memory is allocated", function() { + var ptr = cm._malloc(42); + assert.throws(cm._MemoryAllocationError, function() { + cm._mallocAssertAllMemoryFree(); + }); + cm._free(ptr); + }); + test("allocated memory counts down again for free", function() { + var ptr = cm._malloc(42); + cm._free(ptr); + cm._mallocAssertAllMemoryFree(); + }); + test("free without malloc throws MemoryAllocationError", function() { + var ptr = cm._malloc(42); + cm._free(ptr); + assert.throws(cm._MemoryAllocationError, function() { + cm._free(ptr); + }); + }); + }); + + } + + BaseFixture.extend("access to base class members", function() { + test("method name in derived class silently overrides inherited name", function() { + var derived = new cm.Derived(); + assert.equal("Derived", derived.getClassName()); + derived.delete(); + }); + test("can reference base method from derived class", function(){ + var derived = new cm.Derived(); + assert.equal("Base", derived.getClassNameFromBase()); + derived.delete(); + }); + test("can reference base method from doubly derived class", function() { + var derivedTwice = new cm.DerivedTwice(); + assert.equal("Base", derivedTwice.getClassNameFromBase()); + derivedTwice.delete(); + }); + test("can reference base method through unbound classes", function() { + var derivedThrice = new cm.DerivedThrice(); + assert.equal("Base", derivedThrice.getClassNameFromBase()); + derivedThrice.delete(); + }); + test("property name in derived class hides identically named property in base class for set", function() { + var derived = new cm.Derived(); + derived.setMember(7); + + derived.member = 17; + + assert.equal(17, derived.getMember()); + derived.delete(); + }); + test("can reference base property from derived class for get", function(){ + var derived = new cm.Derived(); + derived.setBaseMember(5); + + assert.equal(5, derived.baseMember); + + derived.delete(); + }); + test("can reference property of any base class for get when multiply derived", function(){ + var derived = new cm.MultiplyDerived(); + derived.setBaseMember(11); + + assert.equal(11, derived.baseMember); + + derived.delete(); + }); + test("can reference base property from derived class for set", function(){ + var derived = new cm.Derived(); + + derived.baseMember = 32; + + assert.equal(32, derived.getBaseMember()); + derived.delete(); + }); + test("can reference property of any base for set when multiply derived", function(){ + var derived = new cm.MultiplyDerived(); + derived.setBaseMember(97); + + derived.baseMember = 32; + + assert.equal(32, derived.getBaseMember()); + derived.delete(); + }); + test("can reach around derived property to access base property with same name for get", function() { + var derived = new cm.Derived(); + derived.setMember(12); + derived.delete(); + }); + + test("if deriving from second base adjusts pointer", function() { + var derived = new cm.HasTwoBases; + assert.equal("Base2", derived.getField()); + derived.delete(); + }); + + test("properties adjust pointer", function() { + var derived = new cm.HasTwoBases; + derived.field = "Foo"; + assert.equal("Foo", derived.getField()); + assert.equal("Foo", derived.field); + derived.delete(); + }); + + test("calling method on unrelated class throws error", function() { + var a = new cm.HasTwoBases; + var e = assert.throws(cm.BindingError, function() { + cm.Derived.prototype.setMember.call(a, "foo"); + }); + assert.equal('Derived.setMember incompatible with "this" of type HasTwoBases', e.message); + a.delete(); + }); + + test("calling method with invalid this throws error", function() { + var e = assert.throws(cm.BindingError, function() { + cm.Derived.prototype.setMember.call(undefined, "foo"); + }); + if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! + // got Error: expected: Derived.setMember with invalid "this": undefined, actual: Derived.setMember incompatible with "this" of type Object + assert.equal('Derived.setMember with invalid "this": undefined', e.message); + } + + var e = assert.throws(cm.BindingError, function() { + cm.Derived.prototype.setMember.call("this", "foo"); + }); + if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! + // TODO got 'Derived.setMember incompatible with "this" of type Object' + assert.equal('Derived.setMember with invalid "this": this', e.message); + } + + var e = assert.throws(cm.BindingError, function() { + cm.Derived.prototype.setMember.call({}, "foo"); + }); + if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! + assert.equal('Derived.setMember incompatible with "this" of type Object', e.message); + } + }); + + test("setting and getting property on unrelated class throws error", function() { + var a = new cm.HasTwoBases; + var e = assert.throws(cm.BindingError, function() { + Object.getOwnPropertyDescriptor(cm.HeldBySmartPtr.prototype, 'i').set.call(a, 10); + }); + assert.equal('HeldBySmartPtr.i setter incompatible with "this" of type HasTwoBases', e.message); + + var e = assert.throws(cm.BindingError, function() { + Object.getOwnPropertyDescriptor(cm.HeldBySmartPtr.prototype, 'i').get.call(a); + }); + assert.equal('HeldBySmartPtr.i getter incompatible with "this" of type HasTwoBases', e.message); + + a.delete(); + }); + }); + + BaseFixture.extend("automatic upcasting of parameters passed to C++", function() { + // raw + test("raw pointer argument is upcast to parameter type", function() { + var derived = new cm.Derived(); + var name = cm.embind_test_get_class_name_via_base_ptr(derived); + assert.equal("Base", name); + derived.delete(); + }); + + test("automatic raw pointer upcasting works with multiple inheritance", function() { + var derived = new cm.MultiplyDerived(); + var name = cm.embind_test_get_class_name_via_base_ptr(derived); + assert.equal("Base", name); + derived.delete(); + }); + + test("automatic raw pointer upcasting does not change local pointer", function() { + var derived = new cm.MultiplyDerived(); + cm.embind_test_get_class_name_via_base_ptr(derived); + assert.equal("MultiplyDerived", derived.getClassName()); + derived.delete(); + }); + + test("passing incompatible raw pointer to method throws exception", function() { + var base = new cm.Base(); + assert.throws(cm.BindingError, function() { + cm.embind_test_get_class_name_via_second_base_ptr(base); + }); + base.delete(); + }); + + // raw polymorphic + test("polymorphic raw pointer argument is upcast to parameter type", function() { + var derived = new cm.PolyDerived(); + var name = cm.embind_test_get_class_name_via_polymorphic_base_ptr(derived); + assert.equal("PolyBase", name); + derived.delete(); + }); + + test("automatic polymorphic raw pointer upcasting works with multiple inheritance", function() { + var derived = new cm.PolyMultiplyDerived(); + var name = cm.embind_test_get_class_name_via_polymorphic_base_ptr(derived); + assert.equal("PolyBase", name); + derived.delete(); + }); + + test("passing incompatible raw polymorphic pointer to method throws exception", function() { + var base = new cm.PolyBase(); + assert.throws(cm.BindingError, function() { + cm.embind_test_get_class_name_via_polymorphic_second_base_ptr(base); + }); + base.delete(); + + }); + + // smart + test("can pass smart pointer to raw pointer parameter", function() { + var smartBase = cm.embind_test_return_smart_base_ptr(); + assert.equal("Base", cm.embind_test_get_class_name_via_base_ptr(smartBase)); + smartBase.delete(); + }); + + test("can pass and upcast smart pointer to raw pointer parameter", function() { + var smartDerived = cm.embind_test_return_smart_derived_ptr(); + assert.equal("Base", cm.embind_test_get_class_name_via_base_ptr(smartDerived)); + smartDerived.delete(); + }); + + test("smart pointer argument is upcast to parameter type", function() { + var derived = cm.embind_test_return_smart_derived_ptr(); + assert.instanceof(derived, cm.Derived); + assert.instanceof(derived, cm.Base); + var name = cm.embind_test_get_class_name_via_smart_base_ptr(derived); + assert.equal("Base", name); + derived.delete(); + }); + + test("return smart derived ptr as base", function() { + var derived = cm.embind_test_return_smart_derived_ptr_as_base(); + assert.equal("PolyDerived", cm.embind_test_get_virtual_class_name_via_smart_polymorphic_base_ptr(derived)); + assert.equal("PolyDerived", derived.getClassName()); + derived.delete(); + }); + + test("return smart derived ptr as val", function() { + var derived = cm.embind_test_return_smart_derived_ptr_as_val(); + assert.equal("PolyDerived", cm.embind_test_get_virtual_class_name_via_smart_polymorphic_base_ptr(derived)); + derived.delete(); + }); + + test("automatic smart pointer upcasting works with multiple inheritance", function() { + var derived = cm.embind_test_return_smart_multiply_derived_ptr(); + var name = cm.embind_test_get_class_name_via_smart_base_ptr(derived); + assert.equal("Base", name); + derived.delete(); + }); + + test("automatically upcasted smart pointer parameter shares ownership with original argument", function() { + var derived = cm.embind_test_return_smart_multiply_derived_ptr(); + assert.equal(1, cm.MultiplyDerived.getInstanceCount()); + cm.embind_save_smart_base_pointer(derived); + assert.equal(1, cm.MultiplyDerived.getInstanceCount()); + derived.delete(); + assert.equal(1, cm.MultiplyDerived.getInstanceCount()); + cm.embind_save_smart_base_pointer(null); + assert.equal(0, cm.MultiplyDerived.getInstanceCount()); + }); + + // smart polymorphic + test("smart polymorphic pointer argument is upcast to parameter type", function() { + var derived = cm.embind_test_return_smart_polymorphic_derived_ptr(); + var name = cm.embind_test_get_class_name_via_smart_polymorphic_base_ptr(derived); + assert.equal("PolyBase", name); + derived.delete(); + }); + + test("automatic smart polymorphic pointer upcasting works with multiple inheritance", function() { + var derived = cm.embind_test_return_smart_polymorphic_multiply_derived_ptr(); + var name = cm.embind_test_get_class_name_via_smart_polymorphic_base_ptr(derived); + assert.equal("PolyBase", name); + derived.delete(); + }); + }); + + BaseFixture.extend("automatic downcasting of return values received from C++", function() { + // raw + test("non-polymorphic raw pointers are not downcast and do not break automatic casting mechanism", function() { + var base = cm.embind_test_return_raw_derived_ptr_as_base(); + assert.equal("Base", base.getClassName()); + assert.instanceof(base, cm.Base); + base.delete(); + }); + + // raw polymorphic + test("polymorphic raw pointer return value is downcast to allocated type (if that is bound)", function() { + var derived = cm.embind_test_return_raw_polymorphic_derived_ptr_as_base(); + assert.instanceof(derived, cm.PolyBase); + assert.instanceof(derived, cm.PolyDerived); + assert.equal("PolyDerived", derived.getClassName()); + var siblingDerived = cm.embind_test_return_raw_polymorphic_sibling_derived_ptr_as_base(); + assert.equal("PolySiblingDerived", siblingDerived.getClassName()); + siblingDerived.delete(); + derived.delete(); + }); + + test("polymorphic raw pointer return value is downcast to the most derived bound type", function() { + var derivedThrice = cm.embind_test_return_raw_polymorphic_derived_four_times_not_bound_as_base(); + // if the actual returned type is not bound, then don't assume anything + assert.equal("PolyBase", derivedThrice.getClassName()); + // if we ever fix this, then reverse the assertion + //assert.equal("PolyDerivedThrice", derivedThrice.getClassName()); + derivedThrice.delete(); + }); + + test("polymorphic smart pointer return value is downcast to the most derived type which has an associated smart pointer", function() { + var derived = cm.embind_test_return_poly_derived_twice_without_smart_pointer_as_poly_base(); + // if the actual returned type is not bound, then don't assume anything + assert.equal("PolyBase", derived.getClassName()); + // if we ever fix this, then remove the assertion + //assert.equal("PolyDerived", derived.getClassName()); + derived.delete(); + }); + + test("automatic downcasting works with multiple inheritance", function() { + var base = cm.embind_test_return_raw_polymorphic_multiply_derived_ptr_as_base(); + var secondBase = cm.embind_test_return_raw_polymorphic_multiply_derived_ptr_as_second_base(); + assert.equal("PolyMultiplyDerived", base.getClassName()); + // embind does not support multiple inheritance + //assert.equal("PolyMultiplyDerived", secondBase.getClassName()); + secondBase.delete(); + base.delete(); + }); + + // smart + test("non-polymorphic smart pointers do not break automatic casting mechanism", function() { + }); + + // smart polymorphic + test("automatically downcasting a smart pointer does not change the underlying pointer", function() { + cm.PolyDerived.setPtrDerived(); + assert.equal("PolyBase", cm.PolyDerived.getPtrClassName()); + var derived = cm.PolyDerived.getPtr(); + assert.equal("PolyDerived", derived.getClassName()); + assert.equal("PolyBase", cm.PolyDerived.getPtrClassName()); + derived.delete(); + cm.PolyDerived.releasePtr(); + }); + + test("polymorphic smart pointer return value is actual allocated type (when bound)", function() { + var derived = cm.embind_test_return_smart_polymorphic_derived_ptr_as_base(); + assert.equal("PolyDerived", derived.getClassName()); + + var siblingDerived = cm.embind_test_return_smart_polymorphic_sibling_derived_ptr_as_base(); + assert.equal("PolySiblingDerived", siblingDerived.getClassName()); + + siblingDerived.delete(); + derived.delete(); + }); + }); + + BaseFixture.extend("embind", function() { + test("value creation", function() { + assert.equal(15, cm.emval_test_new_integer()); + assert.equal("Hello everyone", cm.emval_test_new_string()); + assert.equal("Hello everyone", cm.emval_test_get_string_from_val({key: "Hello everyone"})); + + var object = cm.emval_test_new_object(); + assert.equal('bar', object.foo); + assert.equal(1, object.baz); + }); + + test("pass const reference to primitive", function() { + assert.equal(3, cm.const_ref_adder(1, 2)); + }); + + test("passthrough", function() { + var a = {foo: 'bar'}; + var b = cm.emval_test_passthrough(a); + a.bar = 'baz'; + assert.equal('baz', b.bar); + + assert.equal(0, cm.count_emval_handles()); + }); + + test("void return converts to undefined", function() { + assert.equal(undefined, cm.emval_test_return_void()); + }); + + test("booleans can be marshalled", function() { + assert.equal(false, cm.emval_test_not(true)); + assert.equal(true, cm.emval_test_not(false)); + }); + + test("convert double to unsigned", function() { + var rv = cm.emval_test_as_unsigned(1.5); + assert.equal('number', typeof rv); + assert.equal(1, rv); + assert.equal(0, cm.count_emval_handles()); + }); + + test("get length of array", function() { + assert.equal(10, cm.emval_test_get_length([0, 1, 2, 3, 4, 5, 'a', 'b', 'c', 'd'])); + assert.equal(0, cm.count_emval_handles()); + }); + + test("add a bunch of things", function() { + assert.equal(66.0, cm.emval_test_add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); + assert.equal(0, cm.count_emval_handles()); + }); + + test("sum array", function() { + assert.equal(66, cm.emval_test_sum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])); + assert.equal(0, cm.count_emval_handles()); + }); + + test("strings", function() { + assert.equal("foobar", "foo" + "bar"); + assert.equal("foobar", cm.emval_test_take_and_return_std_string("foobar")); + + assert.equal("foobar", cm.emval_test_take_and_return_std_string_const_ref("foobar")); + }); + + test("nuls pass through strings", function() { + assert.equal("foo\0bar", cm.emval_test_take_and_return_std_string("foo\0bar")); + }); + + test("no memory leak when passing strings in by const reference", function() { + cm.emval_test_take_and_return_std_string_const_ref("foobar"); + }); + + test("can create new object", function() { + assert.deepEqual({}, cm.embind_test_new_Object()); + }); + + test("can invoke constructors with arguments", function() { + function constructor(i, s, argument) { + this.i = i; + this.s = s; + this.argument = argument; + } + constructor.prototype.method = function() { + return this.argument; + }; + var x = {}; + var instance = cm.embind_test_new_factory(constructor, x); + assert.equal(10, instance.i); + assert.equal("hello", instance.s); + assert.equal(x, instance.argument); + }); + + test("can return module property objects", function() { + assert.equal(cm.HEAP8, cm.get_module_property("HEAP8")); + }); + + test("can return big class instances", function() { + var c = cm.embind_test_return_big_class_instance(); + assert.equal(11, c.member); + c.delete(); + }); + + test("can return small class instances", function() { + var c = cm.embind_test_return_small_class_instance(); + assert.equal(7, c.member); + c.delete(); + }); + + test("can pass small class instances", function() { + var c = new cm.SmallClass(); + var m = cm.embind_test_accept_small_class_instance(c); + assert.equal(7, m); + c.delete(); + }); + + test("can pass big class instances", function() { + var c = new cm.BigClass(); + var m = cm.embind_test_accept_big_class_instance(c); + assert.equal(11, m); + c.delete(); + }); + + test("can get member classes then call its member functions", function() { + var p = new cm.ParentClass(); + var c = p.getBigClass(); + var m = c.getMember(); + assert.equal(11, m); + c.delete(); + p.delete(); + }); + + test('C++ -> JS primitive type range checks', function() { + // all types should have zero. + assert.equal("0", cm.char_to_string(0)); + assert.equal("0", cm.signed_char_to_string(0)); + assert.equal("0", cm.unsigned_char_to_string(0)); + assert.equal("0", cm.short_to_string(0)); + assert.equal("0", cm.unsigned_short_to_string(0)); + assert.equal("0", cm.int_to_string(0)); + assert.equal("0", cm.unsigned_int_to_string(0)); + assert.equal("0", cm.long_to_string(0)); + assert.equal("0", cm.unsigned_long_to_string(0)); + + // all types should have positive values. + assert.equal("5", cm.char_to_string(5)); + assert.equal("5", cm.signed_char_to_string(5)); + assert.equal("5", cm.unsigned_char_to_string(5)); + assert.equal("5", cm.short_to_string(5)); + assert.equal("5", cm.unsigned_short_to_string(5)); + assert.equal("5", cm.int_to_string(5)); + assert.equal("5", cm.unsigned_int_to_string(5)); + assert.equal("5", cm.long_to_string(5)); + assert.equal("5", cm.unsigned_long_to_string(5)); + + // signed types should have negative values. + assert.equal("-5", cm.char_to_string(-5)); // Assuming char as signed. + assert.equal("-5", cm.signed_char_to_string(-5)); + assert.equal("-5", cm.short_to_string(-5)); + assert.equal("-5", cm.int_to_string(-5)); + assert.equal("-5", cm.long_to_string(-5)); + + // assumptions: char == signed char == 8 bits + // unsigned char == 8 bits + // short == 16 bits + // int == long == 32 bits + + // all types should have their max positive values. + assert.equal("127", cm.char_to_string(127)); + assert.equal("127", cm.signed_char_to_string(127)); + assert.equal("255", cm.unsigned_char_to_string(255)); + assert.equal("32767", cm.short_to_string(32767)); + assert.equal("65535", cm.unsigned_short_to_string(65535)); + assert.equal("2147483647", cm.int_to_string(2147483647)); + assert.equal("4294967295", cm.unsigned_int_to_string(4294967295)); + assert.equal("2147483647", cm.long_to_string(2147483647)); + assert.equal("4294967295", cm.unsigned_long_to_string(4294967295)); + + // signed types should have their min negative values. + assert.equal("-128", cm.char_to_string(-128)); + assert.equal("-128", cm.signed_char_to_string(-128)); + assert.equal("-32768", cm.short_to_string(-32768)); + assert.equal("-2147483648", cm.int_to_string(-2147483648)); + assert.equal("-2147483648", cm.long_to_string(-2147483648)); + + // passing out of range values should fail. + assert.throws(TypeError, function() { cm.char_to_string(-129); }); + assert.throws(TypeError, function() { cm.char_to_string(128); }); + assert.throws(TypeError, function() { cm.signed_char_to_string(-129); }); + assert.throws(TypeError, function() { cm.signed_char_to_string(128); }); + assert.throws(TypeError, function() { cm.unsigned_char_to_string(-1); }); + assert.throws(TypeError, function() { cm.unsigned_char_to_string(256); }); + assert.throws(TypeError, function() { cm.short_to_string(-32769); }); + assert.throws(TypeError, function() { cm.short_to_string(32768); }); + assert.throws(TypeError, function() { cm.unsigned_short_to_string(-1); }); + assert.throws(TypeError, function() { cm.unsigned_short_to_string(65536); }); + assert.throws(TypeError, function() { cm.int_to_string(-2147483649); }); + assert.throws(TypeError, function() { cm.int_to_string(2147483648); }); + assert.throws(TypeError, function() { cm.unsigned_int_to_string(-1); }); + assert.throws(TypeError, function() { cm.unsigned_int_to_string(4294967296); }); + assert.throws(TypeError, function() { cm.long_to_string(-2147483649); }); + assert.throws(TypeError, function() { cm.long_to_string(2147483648); }); + assert.throws(TypeError, function() { cm.unsigned_long_to_string(-1); }); + assert.throws(TypeError, function() { cm.unsigned_long_to_string(4294967296); }); + + }); + +/* + test("can get templated member classes then call its member functions", function() { + var p = new cm.ContainsTemplatedMemberClass(); + var c = p.getTestTemplate(); + var m = c.getMember(1); + assert.equal(87, m); + c.delete(); + p.delete(); + }); +*/ + }); + + BaseFixture.extend("vector", function() { + test("std::vector returns as an native object", function() { + var vec = cm.emval_test_return_vector(); + + assert.equal(3, vec.size()); + assert.equal(10, vec.get(0)); + assert.equal(20, vec.get(1)); + assert.equal(30, vec.get(2)); + vec.delete(); + }); + + test("out of bounds std::vector access returns undefined", function() { + var vec = cm.emval_test_return_vector(); + + assert.throws(TypeError, function() { vec.get(-1); }); + assert.equal(undefined, vec.get(4)); + + vec.delete(); + }); + + test("std::vector> can be passed back", function() { + var vec = cm.emval_test_return_shared_ptr_vector(); + + assert.equal(2, vec.size()); + var str0 = vec.get(0); + var str1 = vec.get(1); + + assert.equal('string #1', str0.get()); + assert.equal('string #2', str1.get()); + str0.delete(); + str1.delete(); + + vec.delete(); + }); + + test("objects can be pushed back", function() { + var vectorHolder = new cm.VectorHolder(); + var vec = vectorHolder.get(); + assert.equal(2, vec.size()); + + var str = new cm.StringHolder('abc'); + vec.push_back(str); + str.delete(); + assert.equal(3, vec.size()); + var str = vec.get(2); + assert.equal('abc', str.get()); + + str.delete(); + vec.delete(); + vectorHolder.delete(); + }); + + test("can get elements with array operator", function(){ + var vec = cm.emval_test_return_vector(); + assert.equal(10, vec.get(0)); + vec.delete(); + }); + + test("can set elements with array operator", function() { + var vec = cm.emval_test_return_vector(); + assert.equal(10, vec.get(0)); + vec.set(2, 60); + assert.equal(60, vec.get(2)); + vec.delete(); + }); + + test("can set and get objects", function() { + var vec = cm.emval_test_return_shared_ptr_vector(); + var str = vec.get(0); + assert.equal('string #1', str.get()); + str.delete(); + vec.delete(); + }); + }); + + BaseFixture.extend("map", function() { + test("std::map returns as native object", function() { + var map = cm.embind_test_get_string_int_map(); + + assert.equal(2, map.size()); + assert.equal(1, map.get("one")); + assert.equal(2, map.get("two")); + + map.delete(); + }); + + test("std::map can set keys and values", function() { + var map = cm.embind_test_get_string_int_map(); + + assert.equal(2, map.size()); + + map.set("three", 3); + + assert.equal(3, map.size()); + assert.equal(3, map.get("three")); + + map.set("three", 4); + + assert.equal(3, map.size()); + assert.equal(4, map.get("three")); + + map.delete(); + }); + }); + + BaseFixture.extend("functors", function() { + test("can get and call function ptrs", function() { + var ptr = cm.emval_test_get_function_ptr(); + assert.equal("foobar", ptr.opcall("foobar")); + ptr.delete(); + }); + + test("can pass functor to C++", function() { + var ptr = cm.emval_test_get_function_ptr(); + assert.equal("asdf", cm.emval_test_take_and_call_functor(ptr)); + ptr.delete(); + }); + + test("can clone handles", function() { + var a = cm.emval_test_get_function_ptr(); + assert.equal(1, a.$$.count.value); + var b = a.clone(); + assert.equal(2, a.$$.count.value); + assert.equal(2, b.$$.count.value); + a.delete(); + + assert.throws(cm.BindingError, function() { + a.delete(); + }); + b.delete(); + }); + }); + + BaseFixture.extend("classes", function() { + test("class instance", function() { + var a = {foo: 'bar'}; + assert.equal(0, cm.count_emval_handles()); + var c = new cm.ValHolder(a); + assert.equal(1, cm.count_emval_handles()); + assert.equal('bar', c.getVal().foo); + assert.equal(1, cm.count_emval_handles()); + + c.setVal('1234'); + assert.equal('1234', c.getVal()); + + c.delete(); + assert.equal(0, cm.count_emval_handles()); + }); + + test("class instance $$ property is non-enumerable", function() { + var c = new cm.ValHolder(undefined); + assert.deepEqual([], Object.keys(c)); + var d = c.clone(); + c.delete(); + + assert.deepEqual([], Object.keys(d)); + d.delete(); + }); + + test("class methods", function() { + assert.equal(10, cm.ValHolder.some_class_method(10)); + + var b = cm.ValHolder.makeValHolder("foo"); + assert.equal("foo", b.getVal()); + b.delete(); + }); + + test("can't call methods on deleted class instances", function() { + var c = new cm.ValHolder(undefined); + c.delete(); + assert.throws(cm.BindingError, function() { + c.getVal(); + }); + assert.throws(cm.BindingError, function() { + c.delete(); + }); + }); + + test("calling constructor without new raises BindingError", function() { + var e = assert.throws(cm.BindingError, function() { + cm.ValHolder(undefined); + }); + assert.equal("Use 'new' to construct ValHolder", e.message); + }); + + test("can return class instances by value", function() { + var c = cm.emval_test_return_ValHolder(); + assert.deepEqual({}, c.getVal()); + c.delete(); + }); + + test("can pass class instances to functions by reference", function() { + var a = {a:1}; + var c = new cm.ValHolder(a); + cm.emval_test_set_ValHolder_to_empty_object(c); + assert.deepEqual({}, c.getVal()); + c.delete(); + }); + + test("can pass smart pointer by reference", function() { + var base = cm.embind_test_return_smart_base_ptr(); + var name = cm.embind_test_get_class_name_via_reference_to_smart_base_ptr(base); + assert.equal("Base", name); + base.delete(); + }); + + test("can pass smart pointer by value", function() { + var base = cm.embind_test_return_smart_base_ptr(); + var name = cm.embind_test_get_class_name_via_smart_base_ptr(base); + assert.equal("Base", name); + base.delete(); + }); + + // todo: fix this + // This test does not work because we make no provision for argument values + // having been changed after returning from a C++ routine invocation. In + // this specific case, the original pointee of the smart pointer was + // freed and replaced by a new one, but the ptr in our local handle + // was never updated after returning from the call. + test("can modify smart pointers passed by reference", function() { +// var base = cm.embind_test_return_smart_base_ptr(); +// cm.embind_modify_smart_pointer_passed_by_reference(base); +// assert.equal("Changed", base.getClassName()); +// base.delete(); + }); + + test("can not modify smart pointers passed by value", function() { + var base = cm.embind_test_return_smart_base_ptr(); + cm.embind_attempt_to_modify_smart_pointer_when_passed_by_value(base); + assert.equal("Base", base.getClassName()); + base.delete(); + }); + + test("const return value", function() { + var c = new cm.ValHolder("foo"); + assert.equal("foo", c.getConstVal()); + c.delete(); + }); + + test("return object by const ref", function() { + var c = new cm.ValHolder("foo"); + assert.equal("foo", c.getValConstRef()); + c.delete(); + }); + + test("instanceof", function() { + var c = new cm.ValHolder("foo"); + assert.instanceof(c, cm.ValHolder); + c.delete(); + }); + + test("can access struct fields", function() { + var c = new cm.CustomStruct(); + assert.equal(10, c.field); + assert.equal(10, c.getField()); + c.delete(); + }); + + test("can set struct fields", function() { + var c = new cm.CustomStruct(); + c.field = 15; + assert.equal(15, c.field); + c.delete(); + }); + + test("assignment returns value", function() { + var c = new cm.CustomStruct(); + assert.equal(15, c.field = 15); + c.delete(); + }); + + test("assigning string to integer raises TypeError", function() { + var c = new cm.CustomStruct(); + + var e = assert.throws(TypeError, function() { + c.field = "hi"; + }); + assert.equal('Cannot convert "hi" to int', e.message); + + var e = assert.throws(TypeError, function() { + c.field = {foo:'bar'}; + }); + assert.equal('Cannot convert "[object Object]" to int', e.message); + + c.delete(); + }); + + test("can return tuples by value", function() { + var c = cm.emval_test_return_TupleVector(); + assert.deepEqual([1, 2, 3], c); + }); + + test("tuples can contain tuples", function() { + var c = cm.emval_test_return_TupleVectorTuple(); + assert.deepEqual([[1, 2, 3]], c); + }); + + test("can pass tuples by value", function() { + var c = cm.emval_test_take_and_return_TupleVector([4, 5, 6]); + assert.deepEqual([4, 5, 6], c); + }); + + test("can return structs by value", function() { + var c = cm.emval_test_return_StructVector(); + assert.deepEqual({x: 1, y: 2, z: 3}, c); + }); + + test("can pass structs by value", function() { + var c = cm.emval_test_take_and_return_StructVector({x: 4, y: 5, z: 6}); + assert.deepEqual({x: 4, y: 5, z: 6}, c); + }); + + test("can pass and return tuples in structs", function() { + var d = cm.emval_test_take_and_return_TupleInStruct({field: [1, 2, 3]}); + assert.deepEqual({field: [1, 2, 3]}, d); + }); + + test("can clone handles", function() { + var a = new cm.ValHolder({}); + assert.equal(1, cm.count_emval_handles()); + var b = a.clone(); + a.delete(); + + assert.equal(1, cm.count_emval_handles()); + + assert.throws(cm.BindingError, function() { + a.delete(); + }); + b.delete(); + + assert.equal(0, cm.count_emval_handles()); + }); + + test("A shared pointer set/get point to the same underlying pointer", function() { + var a = new cm.SharedPtrHolder(); + var b = a.get(); + + a.set(b); + var c = a.get(); + + assert.equal(b.$$.ptr, c.$$.ptr); + b.delete(); + c.delete(); + a.delete(); + }); + + test("can return shared ptrs from instance methods", function() { + var a = new cm.SharedPtrHolder(); + + // returns the shared_ptr. + var b = a.get(); + + assert.equal("a string", b.get()); + b.delete(); + a.delete(); + }); + + test("smart ptrs clone correctly", function() { + assert.equal(0, cm.count_emval_handles()); + + var a = cm.emval_test_return_shared_ptr(); + + var b = a.clone(); + a.delete(); + + assert.equal(1, cm.count_emval_handles()); + + assert.throws(cm.BindingError, function() { + a.delete(); + }); + b.delete(); + + assert.equal(0, cm.count_emval_handles()); + }); + + test("can't clone if already deleted", function() { + var a = new cm.ValHolder({}); + a.delete(); + assert.throws(cm.BindingError, function() { + a.clone(); + }); + }); + + test("virtual calls work correctly", function() { + var derived = cm.embind_test_return_raw_polymorphic_derived_ptr_as_base(); + assert.equal("PolyDerived", derived.virtualGetClassName()); + derived.delete(); + }); + + test("virtual calls work correctly on smart ptrs", function() { + var derived = cm.embind_test_return_smart_polymorphic_derived_ptr_as_base(); + assert.equal("PolyDerived", derived.virtualGetClassName()); + derived.delete(); + }); + + test("Empty smart ptr is null", function() { + var a = cm.emval_test_return_empty_shared_ptr(); + assert.equal(null, a); + }); + + test("string cannot be given as smart pointer argument", function() { + assert.throws(cm.BindingError, function() { + cm.emval_test_is_shared_ptr_null("hello world"); + }); + }); + + test("number cannot be given as smart pointer argument", function() { + assert.throws(cm.BindingError, function() { + cm.emval_test_is_shared_ptr_null(105); + }); + }); + + test("raw pointer cannot be given as smart pointer argument", function() { + var p = new cm.ValHolder({}); + assert.throws(cm.BindingError, function() { cm.emval_test_is_shared_ptr_null(p); }); + p.delete(); + }); + + test("null is passed as empty smart pointer", function() { + assert.true(cm.emval_test_is_shared_ptr_null(null)); + }); + + test("Deleting already deleted smart ptrs fails", function() { + var a = cm.emval_test_return_shared_ptr(); + a.delete(); + assert.throws(cm.BindingError, function() { + a.delete(); + }); + }); + + test("StringHolder", function() { + var a = new cm.StringHolder("foobar"); + assert.equal("foobar", a.get()); + + a.set("barfoo"); + assert.equal("barfoo", a.get()); + + assert.equal("barfoo", a.get_const_ref()); + + a.delete(); + }); + + test("can call methods on unique ptr", function() { + var result = cm.emval_test_return_unique_ptr(); + + result.setVal('1234'); + assert.equal('1234', result.getVal()); + result.delete(); + }); + + test("can call methods on shared ptr", function(){ + var result = cm.emval_test_return_shared_ptr(); + result.setVal('1234'); + + assert.equal('1234', result.getVal()); + result.delete(); + }); + + test("Non functors throw exception", function() { + var a = {foo: 'bar'}; + var c = new cm.ValHolder(a); + assert.throws(TypeError, function() { + c(); + }); + c.delete(); + }); + + test("non-member methods", function() { + var a = {foo: 'bar'}; + var c = new cm.ValHolder(a); + c.setEmpty(); // non-member method + assert.deepEqual({}, c.getValNonMember()); + c.delete(); + }); + + test("instantiating class without constructor gives error", function() { + var e = assert.throws(cm.BindingError, function() { + cm.AbstractClass(); + }); + assert.equal("Use 'new' to construct AbstractClass", e.message); + + var e = assert.throws(cm.BindingError, function() { + new cm.AbstractClass(); + }); + assert.equal("AbstractClass has no accessible constructor", e.message); + }); + + test("can construct class with external constructor", function() { + var e = new cm.HasExternalConstructor("foo"); + assert.instanceof(e, cm.HasExternalConstructor); + assert.equal("foo", e.getString()); + e.delete(); + }); + }); + + BaseFixture.extend("const", function() { + test("calling non-const method with const handle is error", function() { + var vh = cm.ValHolder.makeConst({}); + var e = assert.throws(cm.BindingError, function() { + vh.setVal({}); + }); + assert.equal('Cannot convert argument of type ValHolder const* to parameter type ValHolder*', e.message); + vh.delete(); + }); + + test("passing const pointer to non-const pointer is error", function() { + var vh = new cm.ValHolder.makeConst({}); + var e = assert.throws(cm.BindingError, function() { + cm.ValHolder.set_via_raw_pointer(vh, {}); + }); + assert.equal('Cannot convert argument of type ValHolder const* to parameter type ValHolder*', e.message); + vh.delete(); + }); + }); + + BaseFixture.extend("smart pointers", function() { + test("constructor can return smart pointer", function() { + var e = new cm.HeldBySmartPtr(10, "foo"); + assert.instanceof(e, cm.HeldBySmartPtr); + assert.equal(10, e.i); + assert.equal("foo", e.s); + var f = cm.takesHeldBySmartPtr(e); + f.delete(); + e.delete(); + }); + + test("cannot pass incorrect smart pointer type", function() { + var e = cm.emval_test_return_shared_ptr(); + assert.throws(cm.BindingError, function() { + cm.takesHeldBySmartPtr(e); + }); + e.delete(); + }); + + test("smart pointer object has no object keys", function() { + var e = new cm.HeldBySmartPtr(10, "foo"); + assert.deepEqual([], Object.keys(e)); + + var f = e.clone(); + e.delete(); + + assert.deepEqual([], Object.keys(f)); + f.delete(); + }); + + test("smart pointer object has correct constructor name", function() { + var e = new cm.HeldBySmartPtr(10, "foo"); + assert.equal('HeldBySmartPtr', e.constructor.name); + e.delete(); + }); + + test("constructor can return smart pointer", function() { + var e = new cm.HeldBySmartPtr(10, "foo"); + assert.instanceof(e, cm.HeldBySmartPtr); + assert.equal(10, e.i); + assert.equal("foo", e.s); + var f = cm.takesHeldBySmartPtr(e); + assert.instanceof(f, cm.HeldBySmartPtr); + f.delete(); + e.delete(); + }); + + test("custom smart pointer", function() { + var e = new cm.HeldByCustomSmartPtr(20, "bar"); + assert.instanceof(e, cm.HeldByCustomSmartPtr); + assert.equal(20, e.i); + assert.equal("bar", e.s); + e.delete(); + }); + + test("custom smart pointer passed through wiretype", function() { + var e = new cm.HeldByCustomSmartPtr(20, "bar"); + var f = cm.passThroughCustomSmartPtr(e); + e.delete(); + + assert.instanceof(f, cm.HeldByCustomSmartPtr); + assert.equal(20, f.i); + assert.equal("bar", f.s); + + f.delete(); + }); + + test("cannot give null to by-value argument", function() { + var e = assert.throws(cm.BindingError, function() { + cm.takesHeldBySmartPtr(null); + }); + assert.equal('null is not a valid HeldBySmartPtr', e.message); + }); + + test("raw pointer can take and give null", function() { + assert.equal(null, cm.passThroughRawPtr(null)); + }); + + test("custom smart pointer can take and give null", function() { + assert.equal(null, cm.passThroughCustomSmartPtr(null)); + }); + + test("cannot pass shared_ptr to CustomSmartPtr", function() { + var o = cm.HeldByCustomSmartPtr.createSharedPtr(10, "foo"); + var e = assert.throws(cm.BindingError, function() { + cm.passThroughCustomSmartPtr(o); + }); + assert.equal('Cannot convert argument of type NSt3__110shared_ptrI20HeldByCustomSmartPtrEE to parameter type 14CustomSmartPtrI20HeldByCustomSmartPtrE', e.message); + o.delete(); + }); + + test("custom smart pointers can be passed to shared_ptr parameter", function() { + var e = cm.HeldBySmartPtr.newCustomPtr(10, "abc"); + assert.equal(10, e.i); + assert.equal("abc", e.s); + + cm.takesHeldBySmartPtrSharedPtr(e).delete(); + e.delete(); + }); + + test("can call non-member functions as methods", function() { + var e = new cm.HeldBySmartPtr(20, "bar"); + var f = e.returnThis(); + e.delete(); + assert.equal(20, f.i); + assert.equal("bar", f.s); + f.delete(); + }); + }); + + BaseFixture.extend("enumerations", function() { + test("can compare enumeration values", function() { + assert.equal(cm.Enum.ONE, cm.Enum.ONE); + assert.notEqual(cm.Enum.ONE, cm.Enum.TWO); + }); + + if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! + test("repr includes enum value", function() { + assert.equal('<#Enum_ONE {}>', IMVU.repr(cm.Enum.ONE)); + assert.equal('<#Enum_TWO {}>', IMVU.repr(cm.Enum.TWO)); + }); + } + + test("instanceof", function() { + assert.instanceof(cm.Enum.ONE, cm.Enum); + }); + + test("can pass and return enumeration values to functions", function() { + assert.equal(cm.Enum.TWO, cm.emval_test_take_and_return_Enum(cm.Enum.TWO)); + }); + }); + + BaseFixture.extend("C++11 enum class", function() { + test("can compare enumeration values", function() { + assert.equal(cm.EnumClass.ONE, cm.EnumClass.ONE); + assert.notEqual(cm.EnumClass.ONE, cm.EnumClass.TWO); + }); + + if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! + test("repr includes enum value", function() { + assert.equal('<#EnumClass_ONE {}>', IMVU.repr(cm.EnumClass.ONE)); + assert.equal('<#EnumClass_TWO {}>', IMVU.repr(cm.EnumClass.TWO)); + }); + } + + test("instanceof", function() { + assert.instanceof(cm.EnumClass.ONE, cm.EnumClass); + }); + + test("can pass and return enumeration values to functions", function() { + assert.equal(cm.EnumClass.TWO, cm.emval_test_take_and_return_EnumClass(cm.EnumClass.TWO)); + }); + }); + + BaseFixture.extend("emval call tests", function() { + test("can call functions from C++", function() { + var called = false; + cm.emval_test_call_function(function(i, f, tv, sv) { + called = true; + assert.equal(10, i); + assert.equal(1.5, f); + assert.deepEqual([1.25, 2.5, 3.75], tv); + assert.deepEqual({x: 1.25, y: 2.5, z: 3.75}, sv); + }, 10, 1.5, [1.25, 2.5, 3.75], {x: 1.25, y: 2.5, z: 3.75}); + assert.true(called); + }); + }); + + BaseFixture.extend("extending built-in classes", function() { + // cm.ValHolder.prototype.patched = 10; // this sets instanceCounts.patched inside of Deletable module !?! + + test("can access patched value on new instances", function() { + cm.ValHolder.prototype.patched = 10; + var c = new cm.ValHolder(undefined); + assert.equal(10, c.patched); + c.delete(); + cm.ValHolder.prototype.patched = undefined; + }); + + test("can access patched value on returned instances", function() { + cm.ValHolder.prototype.patched = 10; + var c = cm.emval_test_return_ValHolder(); + assert.equal(10, c.patched); + c.delete(); + cm.ValHolder.prototype.patched = undefined; + }); + }); + + BaseFixture.extend("raw pointers", function() { + test("can pass raw pointers into functions if explicitly allowed", function() { + var vh = new cm.ValHolder({}); + cm.ValHolder.set_via_raw_pointer(vh, 10); + assert.equal(10, cm.ValHolder.get_via_raw_pointer(vh)); + vh.delete(); + }); + + test("can return raw pointers from functions if explicitly allowed", function() { + var p = cm.embind_test_return_raw_base_ptr(); + assert.equal("Base", p.getClassName()); + p.delete(); + }); + + test("can pass multiple raw pointers to functions", function() { + var target = new cm.ValHolder(undefined); + var source = new cm.ValHolder("hi"); + cm.ValHolder.transfer_via_raw_pointer(target, source); + assert.equal("hi", target.getVal()); + target.delete(); + source.delete(); + }); + }); + + BaseFixture.extend("JavaScript interface", function() { + this.setUp(function() { + this.testobj = { + "method1": function() { return 111; }, + "method2": function() { return 222; } + }; + }); + + test("pass js object to c++ and call its method", function() { + var obj = new cm.JSInterfaceHolder(this.testobj); + assert.equal(111, obj.callMethod("method1")); + assert.equal(222, obj.callMethod("method2")); + assert.equal(111, obj.callMethodUsingSharedPtr("method1")); + assert.equal(222, obj.callMethodUsingSharedPtr("method2")); + obj.delete(); + }); + }); + + BaseFixture.extend("abstract methods", function() { + test("can call abstract methods", function() { + var obj = cm.getAbstractClass(); + assert.equal("from concrete", obj.abstractMethod()); + obj.delete(); + }); + + test("can implement abstract methods in JavaScript", function() { + var expected = "my JS string"; + function MyImplementation() { + this.rv = expected; + } + MyImplementation.prototype.abstractMethod = function() { + return this.rv; + }; + + var impl = cm.AbstractClass.implement(new MyImplementation); + assert.equal(expected, impl.abstractMethod()); + assert.equal(expected, cm.callAbstractMethod(impl)); + impl.delete(); + }); + }); + + BaseFixture.extend("registration order", function() { + test("registration of tuple elements out of order leaves them in order", function() { + var ot = cm.getOrderedTuple(); + assert.instanceof(ot[0], cm.FirstElement); + assert.instanceof(ot[1], cm.SecondElement); + ot[0].delete(); + ot[1].delete(); + }); + + test("registration of struct elements out of order", function() { + var os = cm.getOrderedStruct(); + assert.instanceof(os.first, cm.FirstElement); + assert.instanceof(os.second, cm.SecondElement); + os.first.delete(); + os.second.delete(); + }); + }); + + if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! + + BaseFixture.extend("unbound types", function() { + function assertMessage(fn, message) { + var e = assert.throws(cm.UnboundTypeError, fn); + assert.equal(message, e.message); + } + + test("calling function with unbound types produces error", function() { + assertMessage( + function() { + cm.getUnboundClass(); + }, + 'Cannot call getUnboundClass due to unbound types: UnboundClass'); + }); + + test("unbound base class produces error", function() { + assertMessage( + function() { + cm.getHasUnboundBase(); + }, + 'Cannot call getHasUnboundBase due to unbound types: UnboundClass'); + }); + + test("construct of class with unbound base", function() { + assertMessage( + function() { + new cm.HasUnboundBase; + }, 'Cannot construct HasUnboundBase due to unbound types: UnboundClass'); + }); + + test("unbound constructor argument", function() { + assertMessage( + function() { + new cm.HasConstructorUsingUnboundArgument; + }, + 'Cannot construct HasConstructorUsingUnboundArgument due to unbound types: UnboundClass'); + }); + + test("unbound constructor argument of class with unbound base", function() { + assertMessage( + function() { + new cm.HasConstructorUsingUnboundArgumentAndUnboundBase; + }, + 'Cannot construct HasConstructorUsingUnboundArgumentAndUnboundBase due to unbound types: SecondUnboundClass'); + }); + + test('class function with unbound argument', function() { + var x = new cm.BoundClass; + assertMessage( + function() { + x.method(); + }, 'Cannot call BoundClass.method due to unbound types: UnboundClass'); + x.delete(); + }); + + test('class class function with unbound argument', function() { + assertMessage( + function() { + cm.BoundClass.classfunction(); + }, 'Cannot call BoundClass.classfunction due to unbound types: UnboundClass'); + }); + + test('class property of unbound type', function() { + var x = new cm.BoundClass; + var y; + assertMessage( + function() { + y = x.property; + }, 'Cannot access BoundClass.property due to unbound types: UnboundClass'); + assertMessage( + function() { + x.property = 10; + }, 'Cannot access BoundClass.property due to unbound types: UnboundClass'); + x.delete(); + }); + + // todo: tuple elements + // todo: tuple element accessors + // todo: struct fields + }); + + } + + BaseFixture.extend("noncopyable", function() { + test('can call method on noncopyable object', function() { + var x = new cm.Noncopyable; + assert.equal('foo', x.method()); + x.delete(); + }); + }); + + BaseFixture.extend("function names", function() { + assert.equal('ValHolder', cm.ValHolder.name); + assert.equal('ValHolder$setVal', cm.ValHolder.prototype.setVal.name); + assert.equal('ValHolder$makeConst', cm.ValHolder.makeConst.name); + }); +}); + +// If running as part of the emscripten test runner suite, and not as part of the IMVU suite, +// we launch the test execution from here. IMVU suite uses its own dedicated mechanism instead of this. +if (typeof run_all_tests !== "undefined") + run_all_tests(); diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 485cdfcd825d4..e9feccfef5b5c 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1,5 +1,6 @@ #include #include +#include #include using namespace emscripten; @@ -27,6 +28,10 @@ val emval_test_new_string() { return val("Hello everyone"); } +std::string emval_test_get_string_from_val(val v) { + return v["key"].as(); +} + val emval_test_new_object() { val rv(val::object()); rv.set("foo", val("bar")); @@ -54,18 +59,22 @@ unsigned emval_test_as_unsigned(val v) { } unsigned emval_test_get_length(val v) { - return v.get("length").as(); + return v["length"].as(); } double emval_test_add(char c, signed char sc, unsigned char uc, signed short ss, unsigned short us, signed int si, unsigned int ui, signed long sl, unsigned long ul, float f, double d) { return c + sc + uc + ss + us + si + ui + sl + ul + f + d; } +float const_ref_adder(const int& i, const float& f) { + return i + f; +} + unsigned emval_test_sum(val v) { - unsigned length = v.get("length").as(); + unsigned length = v["length"].as(); double rv = 0; for (unsigned i = 0; i < length; ++i) { - rv += v.get(i).as(); + rv += v[i].as(); } return rv; } @@ -82,30 +91,70 @@ std::string emval_test_take_and_return_std_string_const_ref(const std::string& s return str; } +std::function emval_test_get_function_ptr() { + return emval_test_take_and_return_std_string; +} + +std::string emval_test_take_and_call_functor(std::function func) { + return func("asdf"); +} + class ValHolder { public: ValHolder(val v) - : v(v) + : v_(v) {} val getVal() const { - return v; + return v_; } - void setVal(val v) { - this->v = v; + val getValNonConst() { + return v_; + } + + const val getConstVal() const { + return v_; + } + + const val& getValConstRef() const { + return v_; } - int returnIntPlusFive( int x ) { - return x + 5; + void setVal(val v) { + this->v_ = v; } static int some_class_method(int i) { return i; } + static const ValHolder* makeConst(val v) { + return new ValHolder(v); + } + + static ValHolder makeValHolder(val v) { + return ValHolder(v); + } + + static void set_via_raw_pointer(ValHolder* vh, val v) { + vh->setVal(v); + } + + static val get_via_raw_pointer(const ValHolder* vh) { + return vh->getVal(); + } + + static void transfer_via_raw_pointer(ValHolder* target, const ValHolder* source) { + target->setVal(source->getVal()); + } + + static val getValNonMember(const ValHolder& target) { + return target.getVal(); + } + private: - val v; + val v_; }; ValHolder emval_test_return_ValHolder() { @@ -119,243 +168,1717 @@ void emval_test_set_ValHolder_to_empty_object(ValHolder& vh) { class StringHolder { public: StringHolder(const std::string& s) - : str(s) + : str_(s) {} void set(const std::string& s) { - str = s; + str_ = s; } + std::string get() const { - return str; + return str_; + } + + std::string& get_ref() { + return str_; + } + + const std::string& get_const_ref() const { + return str_; } private: - std::string str; + std::string str_; }; -struct TupleVector { - float x, y, z; +class SharedPtrHolder { +public: + SharedPtrHolder() + : ptr_(new StringHolder("a string")) + {} + + std::shared_ptr get() const { + return ptr_; + } + + void set(std::shared_ptr p) { + ptr_ = p; + } +private: + std::shared_ptr ptr_; }; -float readTupleVectorZ(const TupleVector& v) { - return v.z; -} +class VectorHolder { +public: + VectorHolder() { + v_.push_back(StringHolder("string #1")); + v_.push_back(StringHolder("string #2")); + } -void writeTupleVectorZ(TupleVector& v, float z) { - v.z = z; -} + std::vector get() const { + return v_; + } -struct TupleVectorTuple { - TupleVector v; + void set(std::vector vec) { + v_ = vec; + } + +private: + std::vector v_; }; -TupleVector emval_test_return_TupleVector() { - TupleVector cv; - cv.x = 1; - cv.y = 2; - cv.z = 3; - return cv; -} +class SmallClass { +public: + SmallClass(): member(7) {}; + int member; +}; -TupleVector emval_test_take_and_return_TupleVector(TupleVector v) { - return v; -} +class BigClass { +public: + BigClass(): member(11) {}; + int member; + int otherMember; + int yetAnotherMember; -TupleVectorTuple emval_test_return_TupleVectorTuple() { - TupleVectorTuple cvt; - cvt.v = emval_test_return_TupleVector(); - return cvt; -} + int getMember() { + return member; + } +}; -struct StructVector { - float x, y, z; +class ParentClass { +public: + ParentClass(): bigClass() {}; + + BigClass bigClass; + + const BigClass& getBigClass() { + return bigClass; + }; }; -StructVector emval_test_return_StructVector() { - StructVector v; - v.x = 1; - v.y = 2; - v.z = 3; - return v; -} +template +class TemplateClass { +public: + TemplateClass(T a, T b, T c) { + members[0] = a; + members[1] = b; + members[2] = c; + }; -StructVector emval_test_take_and_return_StructVector(StructVector v) { - return v; -} + const T getMember(int n) { + return members[n]; + } -struct CustomStruct { - CustomStruct() - : field(10) - {} - int field; +protected: + T members[3]; }; -struct TupleInStruct { - TupleVector field; +class ContainsTemplatedMemberClass { +public: + ContainsTemplatedMemberClass(): testTemplate(86, 87, 88) {}; + + TemplateClass testTemplate; + + const TemplateClass& getTestTemplate() { + return testTemplate; + }; }; -TupleInStruct emval_test_take_and_return_TupleInStruct(TupleInStruct cs) { - return cs; -} +// Begin Inheritance Hierarchy Class Definitions -enum Enum { ONE, TWO }; +class Base { +public: + Base(): name("Base"), + member(0), + baseMember(0) + {} -Enum emval_test_take_and_return_Enum(Enum e) { - return e; -} + std::string getClassName() const { + return name; + } + std::string getClassNameFromBase() const { + return name; + } + std::string getClassNameNotAvailableInDerivedClasses() { + // but wait -- if you act now we will throw in a SECOND base class method ABSOLUTELY FREE!! + return name; + } + void setMember(int value) { + member = value; + } + int getMember() { + return member; + } + void setBaseMember(int value) { + baseMember = value; + } + int getBaseMember() { + return baseMember; + } + std::string name; + int member; + int baseMember; +}; -enum class EnumClass { ONE, TWO }; +class SecondBase { +public: + SecondBase() + : name("SecondBase"), + member(0), + secondBaseMember(0) + {} -EnumClass emval_test_take_and_return_EnumClass(EnumClass e) { - return e; -} + std::string getClassName() const { + return name; + } + std::string getClassNameNotAvailableInDerivedClasses() { + return name; + } + std::string getClassNameFromSecondBase() const { + return name; + } + void setMember(int value) { + member = value; + } + int getMember() { + return member; + } + void setSecondBaseMember(int value) { + secondBaseMember = value; + } + int getSecondBaseMember() { + return secondBaseMember; + } + std::string name; + int member; + int secondBaseMember; +}; -class Interface { +class Derived : public Base{ public: - virtual int method() = 0; - virtual TupleInStruct method2(const TupleInStruct& arg1, float arg2) = 0; - virtual void method3() = 0; + Derived() + : Base() + , member(0) + , name_("Derived") + {} + + std::string getClassName() const { + return name_; + } + void setMember(int value) { + member = value; + } + int getMember() { + return member; + } + int member; +private: + std::string name_; }; -int emval_test_call_method(Interface& i) { - return i.method(); -} +class DerivedHolder { +public: + DerivedHolder() { + derived_.reset(); + } + void newDerived() { + deleteDerived(); + derived_ = std::shared_ptr(new Derived()); + } + void deleteDerived() { + derived_.reset(); + } + std::shared_ptr getDerived() { + return derived_; + } + std::string getDerivedClassName() { + return derived_->getClassName(); + } +private: + std::shared_ptr derived_; +}; -TupleInStruct emval_test_call_method2(Interface& i, const TupleInStruct& arg1, float arg2) { - return i.method2(arg1, arg2); -} +class SiblingDerived : public Base { +public: + SiblingDerived() + : Base(), + name_("SiblingDerived") + {} -void emval_test_call_method3(Interface& i) { - i.method3(); -} + std::string getClassName() const { + return name_; + } -void emval_test_call_function(val v, int i, float f, TupleVector tv, StructVector sv) { - v(i, f, tv, sv); -} +private: + std::string name_; +}; -void optional_test_copy() { - using emscripten::internal::optional; +class MultiplyDerived : public Base, public SecondBase { +public: + MultiplyDerived() + : Base(), SecondBase(), + name_("MultiplyDerived") + { instanceCount_ ++; } - optional foo = 22; - optional bar(foo); + ~MultiplyDerived() + { instanceCount_ --; } - return bool(bar); -} + std::string getClassName() const { + return name_; + } -void optional_test_copy2() { - using emscripten::internal::optional; + static int getInstanceCount() { + return instanceCount_; + } +private: + std::string name_; + static int instanceCount_; +}; +int MultiplyDerived::instanceCount_ = 0; - optional foo; - optional bar(foo); +class DerivedTwice : public Derived { +public: + DerivedTwice() + : Derived(), + name_("DerivedTwice") + {} - return bool(bar); -} + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; -EMSCRIPTEN_BINDINGS(([]() { - function("mallinfo", &emval_test_mallinfo); +class DerivedTwiceNotBound : public Derived { +public: + DerivedTwiceNotBound() + : Derived(), + name_("DerivedTwiceNotBound") + {} - function("emval_test_new_integer", &emval_test_new_integer); - function("emval_test_new_string", &emval_test_new_string); - function("emval_test_new_object", &emval_test_new_object); - function("emval_test_passthrough_unsigned", &emval_test_passthrough_unsigned); - function("emval_test_passthrough", &emval_test_passthrough); - function("emval_test_return_void", &emval_test_return_void); - function("emval_test_not", &emval_test_not); + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; - function("emval_test_as_unsigned", &emval_test_as_unsigned); - function("emval_test_get_length", &emval_test_get_length); - function("emval_test_add", &emval_test_add); - function("emval_test_sum", &emval_test_sum); +class DerivedThrice: public DerivedTwiceNotBound { +public: + DerivedThrice() + : DerivedTwiceNotBound(), + name_("DerivedThrice") + {} - //function("emval_test_take_and_return_const_char_star", &emval_test_take_and_return_const_char_star); - function("emval_test_take_and_return_std_string", &emval_test_take_and_return_std_string); - function("emval_test_take_and_return_std_string_const_ref", &emval_test_take_and_return_std_string_const_ref); + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; - //function("emval_test_take_and_return_CustomStruct", &emval_test_take_and_return_CustomStruct); +class DerivedFourTimesNotBound: public DerivedThrice { +public: + DerivedFourTimesNotBound() + : DerivedThrice(), + name_("DerivedFourTimesNotBound") + {} - value_tuple("TupleVector") - .element(&TupleVector::x) - .element(&TupleVector::y) - //.element(&TupleVector::z) - .element(&readTupleVectorZ, &writeTupleVectorZ) - ; + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; - function("emval_test_return_TupleVector", &emval_test_return_TupleVector); - function("emval_test_take_and_return_TupleVector", &emval_test_take_and_return_TupleVector); +class PolyBase { +public: + PolyBase(const std::string& s) + : str_(s), + name_("PolyBase") + {} - value_tuple("TupleVectorTuple") - .element(&TupleVectorTuple::v) - ; + PolyBase(): name_("PolyBase") {} - function("emval_test_return_TupleVectorTuple", &emval_test_return_TupleVectorTuple); + virtual ~PolyBase() {} - value_struct("StructVector") - .field("x", &StructVector::x) - .field("y", &StructVector::y) - .field("z", &StructVector::z) - ; + virtual std::string virtualGetClassName() const { + return name_; + } - function("emval_test_return_StructVector", &emval_test_return_StructVector); - function("emval_test_take_and_return_StructVector", &emval_test_take_and_return_StructVector); + std::string getClassName() const { + return name_; + } - value_struct("TupleInStruct") - .field("field", &TupleInStruct::field) - ; +private: + std::string str_; + std::string name_; +}; - function("emval_test_take_and_return_TupleInStruct", &emval_test_take_and_return_TupleInStruct); +class PolySecondBase { +public: + PolySecondBase(): name_("PolySecondBase") + {} - class_("ValHolder") - .constructor() - .method("getVal", &ValHolder::getVal) - .method("setVal", &ValHolder::setVal) - .method("returnIntPlusFive", &ValHolder::returnIntPlusFive) - .classmethod("some_class_method", &ValHolder::some_class_method) - ; - function("emval_test_return_ValHolder", &emval_test_return_ValHolder); - function("emval_test_set_ValHolder_to_empty_object", &emval_test_set_ValHolder_to_empty_object); + virtual ~PolySecondBase() {} - class_("StringHolder") - .constructor() - .method("set", &StringHolder::set) - .method("get", &StringHolder::get) - ; + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; - class_("CustomStruct") - .constructor<>() - .field("field", &CustomStruct::field) - ; +class PolyDerived : public PolyBase{ +public: + PolyDerived() + : PolyBase("PolyDerived"), + name_("PolyDerived") + {} - enum_("Enum") - .value("ONE", ONE) - .value("TWO", TWO) - ; - function("emval_test_take_and_return_Enum", &emval_test_take_and_return_Enum); + std::string virtualGetClassName() const { + return name_; + } - enum_("EnumClass") + std::string getClassName() const { + return name_; + } + + static void setPtrDerived() { + ptr_ = std::shared_ptr(new PolyDerived()); + } + + static void releasePtr() { + ptr_.reset(); + } + + static std::string getPtrClassName() { + return ptr_->getClassName(); + } + + static std::shared_ptr getPtr() { + return ptr_; + } + +private: + std::string name_; + static std::shared_ptr ptr_; +}; +std::shared_ptr PolyDerived::ptr_; + +class PolySiblingDerived : public PolyBase { +public: + PolySiblingDerived() + : PolyBase(), + name_("PolySiblingDerived") + {} + + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; + +class PolyMultiplyDerived : public PolyBase, public PolySecondBase { +public: + PolyMultiplyDerived() + : PolyBase(), PolySecondBase(), + name_("PolyMultiplyDerived") + {} + + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; + +class PolyDerivedTwiceWithoutSmartPointer: public PolyDerived { +public: + PolyDerivedTwiceWithoutSmartPointer() + : PolyDerived(), + name_("PolyDerivedTwiceWithoutSmartPointer") + {} + + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; + +class PolyDerivedTwiceNotBound : public PolyDerived { +public: + PolyDerivedTwiceNotBound() + : PolyDerived(), + name_("PolyDerivedTwiceNotBound") + {} + + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; + +class PolyDerivedThrice: public PolyDerivedTwiceNotBound { +public: + PolyDerivedThrice() + : PolyDerivedTwiceNotBound(), + name_("PolyDerivedThrice") + {} + + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; + +class PolyDerivedFourTimesNotBound: public PolyDerivedThrice { +public: + PolyDerivedFourTimesNotBound() + : PolyDerivedThrice(), + name_("PolyDerivedFourTimesNotBound") + {} + + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; + +// todo: does it need to be polymorphic? +// todo: virtual diamond pattern +class PolyDiamondBase { +public: + PolyDiamondBase(): + name_("PolyBase") + {} + ~PolyDiamondBase() {} + + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; + +class PolyDiamondDerived: public PolyDiamondBase { +public: + PolyDiamondDerived() + : PolyDiamondBase(), + name_("PolyDiamondDerived") + {} + + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; + +class PolyDiamondSiblingDerived: public PolyDiamondBase { +public: + PolyDiamondSiblingDerived() + : PolyDiamondBase(), + name_("PolyDiamondSiblingDerived") + {} + + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; + +class PolyDiamondMultiplyDerived: public PolyDiamondDerived, public PolyDiamondSiblingDerived { +public: + PolyDiamondMultiplyDerived() + : PolyDiamondDerived(), PolyDiamondSiblingDerived(), + name_("PolyDiamondMultiplyDerived") + {} + + std::string getClassName() const { + return name_; + } +private: + std::string name_; +}; + +// End Inheritance Hierarchy Class Definitions + +std::map embind_test_get_string_int_map() { + std::map m; + + m["one"] = 1; + m["two"] = 2; + + return m; +}; + +struct TupleVector { + float x, y, z; +}; + +float readTupleVectorZ(const TupleVector& v) { + return v.z; +} + +void writeTupleVectorZ(TupleVector& v, float z) { + v.z = z; +} + +struct TupleVectorTuple { + TupleVector v; +}; + +TupleVector emval_test_return_TupleVector() { + TupleVector cv; + cv.x = 1; + cv.y = 2; + cv.z = 3; + return cv; +} + +TupleVector emval_test_take_and_return_TupleVector(TupleVector v) { + return v; +} + +TupleVectorTuple emval_test_return_TupleVectorTuple() { + TupleVectorTuple cvt; + cvt.v = emval_test_return_TupleVector(); + return cvt; +} + +struct StructVector { + float x, y, z; +}; + +StructVector emval_test_return_StructVector() { + StructVector v; + v.x = 1; + v.y = 2; + v.z = 3; + return v; +} + +StructVector emval_test_take_and_return_StructVector(StructVector v) { + return v; +} + +struct CustomStruct { + CustomStruct() + : field(10) + {} + + const int& getField() const { + return field; + } + + int field; +}; + +struct TupleInStruct { + TupleVector field; +}; + +TupleInStruct emval_test_take_and_return_TupleInStruct(TupleInStruct cs) { + return cs; +} + +enum Enum { ONE, TWO }; + +Enum emval_test_take_and_return_Enum(Enum e) { + return e; +} + +enum class EnumClass { ONE, TWO }; + +EnumClass emval_test_take_and_return_EnumClass(EnumClass e) { + return e; +} + +void emval_test_call_function(val v, int i, float f, TupleVector tv, StructVector sv) { + v(i, f, tv, sv); +} + +std::unique_ptr emval_test_return_unique_ptr() { + return std::unique_ptr(new ValHolder(val::object())); +} + +std::shared_ptr emval_test_return_shared_ptr() { + return std::shared_ptr(new ValHolder(val::object())); +} + +std::shared_ptr emval_test_return_empty_shared_ptr() { + return std::shared_ptr(); +} + +bool emval_test_is_shared_ptr_null(std::shared_ptr p) { + return !p; +} + +static SmallClass smallClass; +static BigClass bigClass; + +SmallClass embind_test_return_small_class_instance() { + return smallClass; +} + +BigClass embind_test_return_big_class_instance() { + return bigClass; +} + +int embind_test_accept_small_class_instance(SmallClass c) { + return c.member; +} + +int embind_test_accept_big_class_instance(BigClass c) { + return c.member; +} + +// Begin Inheritance Hierarchy Test Wrappers + +Base* embind_test_return_raw_base_ptr() { + return new Base(); +} + +Base* embind_test_return_raw_derived_ptr_as_base() { + return new Derived(); +} + +Base* embind_test_return_raw_sibling_derived_ptr_as_base() { + return new SiblingDerived(); +} + +PolyBase* embind_test_return_raw_polymorphic_derived_ptr_as_base() { + return new PolyDerived(); +} + +PolyBase* embind_test_return_raw_polymorphic_sibling_derived_ptr_as_base() { + return new PolySiblingDerived(); +} + +PolyBase* embind_test_return_raw_polymorphic_multiply_derived_ptr_as_base() { + return new PolyMultiplyDerived(); +} + +PolySecondBase* embind_test_return_raw_polymorphic_multiply_derived_ptr_as_second_base() { + return new PolyMultiplyDerived(); +} + +PolyBase* embind_test_return_raw_polymorphic_derived_four_times_not_bound_as_base() { + return new PolyDerivedFourTimesNotBound(); +} + +std::shared_ptr embind_test_return_smart_base_ptr() { + return std::shared_ptr(new Base()); +} + +std::shared_ptr embind_test_return_smart_polymorphic_base_ptr() { + return std::shared_ptr(new PolyBase("PolyBase")); +} + +std::shared_ptr embind_test_return_smart_derived_ptr() { + return std::shared_ptr(new Derived()); +} + +std::shared_ptr embind_test_return_smart_sibling_derived_ptr() { + return std::shared_ptr(new SiblingDerived()); +} + +std::shared_ptr embind_test_return_smart_multiply_derived_ptr() { + return std::shared_ptr(new MultiplyDerived()); +} + +std::shared_ptr embind_test_return_smart_derived_thrice_ptr() { + return std::shared_ptr(new DerivedThrice()); +} + +std::shared_ptr embind_test_return_smart_polymorphic_derived_ptr() { + return std::shared_ptr(new PolyDerived()); +} + +std::shared_ptr embind_test_return_smart_polymorphic_sibling_derived_ptr() { + return std::shared_ptr(new PolySiblingDerived()); +} + +std::shared_ptr embind_test_return_smart_polymorphic_multiply_derived_ptr() { + return std::shared_ptr(new PolyMultiplyDerived()); +} + +std::shared_ptr embind_test_return_poly_derived_twice_without_smart_pointer_as_poly_base() { + return std::shared_ptr(new PolyDerivedTwiceWithoutSmartPointer()); +} + +std::shared_ptr embind_test_return_smart_poly_derived_thrice_ptr() { + return std::shared_ptr(new PolyDerivedThrice()); +} + +std::shared_ptr embind_test_return_smart_derived_ptr_as_base() { + return std::shared_ptr(new PolyDerived()); +} + +val embind_test_return_smart_derived_ptr_as_val() { + return val(std::shared_ptr(new PolyDerived())); +} + +std::shared_ptr embind_test_return_smart_polymorphic_derived_ptr_as_base() { + return std::shared_ptr(new PolyDerived()); +} + +std::shared_ptr embind_test_return_smart_polymorphic_sibling_derived_ptr_as_base() { + return std::shared_ptr(new PolySiblingDerived()); +} + +std::string embind_test_get_class_name_via_base_ptr(Base *p) { + return p->getClassName(); +} + +std::string embind_test_get_class_name_via_second_base_ptr(SecondBase *p) { + return p->getClassName(); +} + +std::string embind_test_get_class_name_via_polymorphic_base_ptr(PolyBase *p) { + return p->getClassName(); +} + +std::string embind_test_get_class_name_via_polymorphic_second_base_ptr(PolySecondBase *p) { + return p->getClassName(); +} + +std::string embind_test_get_class_name_via_smart_base_ptr(std::shared_ptr p) { + return p->getClassName(); +} + +std::string embind_test_get_class_name_via_reference_to_smart_base_ptr(std::shared_ptr& p) { + return p->getClassName(); +} + +std::string embind_test_get_class_name_via_smart_second_base_ptr(std::shared_ptr p) { + return p->getClassName(); +} + +std::string embind_test_get_class_name_via_smart_polymorphic_base_ptr(std::shared_ptr p) { + return p->getClassName(); +} + +std::string embind_test_get_virtual_class_name_via_smart_polymorphic_base_ptr(std::shared_ptr p) { + return p->virtualGetClassName(); +} + +std::string embind_test_get_class_name_via_smart_polymorphic_second_base_ptr(std::shared_ptr p) { + return p->getClassName(); +} + +void embind_modify_smart_pointer_passed_by_reference(std::shared_ptr& p) { + p = std::shared_ptr(new Base()); + p->name = "Changed"; +} + +void embind_attempt_to_modify_smart_pointer_when_passed_by_value(std::shared_ptr p) { + p = std::shared_ptr(new Base()); + p->name = "Changed"; +} + +static std::shared_ptr savedBasePointer; + +void embind_save_smart_base_pointer(std::shared_ptr p) { + savedBasePointer = p; +} + +// End Inheritance Hierarchy Test Wrappers + +std::vector emval_test_return_vector() { + int myints[] = { 10, 20, 30 }; + return std::vector(myints, myints + sizeof(myints) / sizeof(int)); +} + +std::vector > emval_test_return_vector_of_vectors() { + int myints1[] = { 10, 20, 30 }; + int myints2[] = { 40, 50, 60 }; + std::vector vec1(myints1, myints1 + sizeof(myints1) / sizeof(int)); + std::vector vec2(myints2, myints2 + sizeof(myints2) / sizeof(int)); + std::vector>vec3; + vec3.emplace_back(vec1); + vec3.emplace_back(vec2); + return vec3; +} + +std::vector> emval_test_return_shared_ptr_vector() { + std::vector> sharedStrVector; + sharedStrVector.push_back(std::shared_ptr(new StringHolder("string #1"))); + sharedStrVector.push_back(std::shared_ptr(new StringHolder("string #2"))); + + return sharedStrVector; +} + +class JSInterfaceHolder { +public: + JSInterfaceHolder(JSInterface &jsobj) : jsobj_(jsobj) { + ptr_ = JSInterface::cloneToSharedPtr(jsobj_); + } + + int callMethod(std::string method) { return jsobj_.call(method.c_str()); } + int callMethodUsingSharedPtr(std::string method) { return ptr_->call(method.c_str()); } + +private: + JSInterface jsobj_; + std::shared_ptr ptr_; +}; + +void test_string_with_vec(const std::string& p1, std::vector& v1) { + // THIS DOES NOT WORK -- need to get as val and then call vecFromJSArray + printf("%s\n", p1.c_str()); +} + +val embind_test_new_Object() { + return val::global("Object").new_(); +} + +val embind_test_new_factory(val factory, val argument) { + return factory.new_(10, std::string("hello"), argument); +} + +class AbstractClass { +public: + virtual ~AbstractClass() {} + virtual std::string abstractMethod() const = 0; +}; + +class AbstractClassWrapper : public wrapper { +public: + EMSCRIPTEN_WRAPPER(AbstractClassWrapper); + + std::string abstractMethod() const { + return call("abstractMethod"); + } +}; + +class ConcreteClass : public AbstractClass { + std::string abstractMethod() const { + return "from concrete"; + } +}; + +std::shared_ptr getAbstractClass() { + return std::make_shared(); +} + +std::string callAbstractMethod(AbstractClass& ac) { + return ac.abstractMethod(); +} + +class HasExternalConstructor { +public: + HasExternalConstructor(const std::string& str) + : m(str) + {} + + std::string getString() const { + return m; + } + + std::string m; +}; + +HasExternalConstructor* createHasExternalConstructor(const std::string& str) { + return new HasExternalConstructor(str); +} + +template +class CustomSmartPtr { +public: + CustomSmartPtr() + : CustomSmartPtr(nullptr) + { + std::fill(d_, d_ + N_, Valid); + } + + explicit CustomSmartPtr(T* t) + : ptr_(t) + { + std::fill(d_, d_ + N_, Valid); + } + + CustomSmartPtr(const CustomSmartPtr& other) + : ptr_(other.ptr_) + { + other.verify(); + std::fill(d_, d_ + N_, Valid); + if (ptr_) { + ++(ptr_->refcount); + } + } + + ~CustomSmartPtr() { + verify(); + std::fill(d_, d_ + N_, Deleted); + + if (ptr_ && --ptr_->refcount == 0) { + delete ptr_; + } + } + + T* get_raw() const { + return ptr_; + } + +private: + void verify() const { + for (size_t i = 0; i < N_; ++i) { + if (d_[i] != Valid) { + abort(); + } + } + } + + enum { + Valid = 255, + Deleted = 127, + }; + static constexpr size_t N_ = 1000000; + unsigned char d_[N_]; + T* ptr_; + + CustomSmartPtr& operator=(const CustomSmartPtr&) = delete; +}; + +class HeldBySmartPtr { +public: + HeldBySmartPtr(int i, const std::string& s) + : i(i) + , s(s) + {} + + static CustomSmartPtr newCustomPtr(int i, const std::string& s) { + return CustomSmartPtr(new HeldBySmartPtr(i, s)); + } + + int refcount = 1; + int i; + std::string s; +}; + +HeldBySmartPtr takesHeldBySmartPtr(HeldBySmartPtr p) { + return p; +} +std::shared_ptr takesHeldBySmartPtrSharedPtr(std::shared_ptr p) { + return p; +} + +namespace emscripten { + template + struct smart_ptr_trait> { + typedef T element_type; + + static sharing_policy get_sharing_policy() { + return sharing_policy::NONE; + } + + static T* get(const CustomSmartPtr& p) { + return p.get_raw(); + } + + static CustomSmartPtr share(const CustomSmartPtr& r, T* ptr) { + ++ptr->refcount; // implement an adopt API? + return CustomSmartPtr(ptr); + } + }; +} + +typedef CustomSmartPtr HeldByCustomSmartPtrPtr; + +class HeldByCustomSmartPtr { +public: + HeldByCustomSmartPtr(int i, const std::string& s) + : i(i) + , s(s) + {} + + static HeldByCustomSmartPtrPtr create(int i, const std::string& s) { + return HeldByCustomSmartPtrPtr(new HeldByCustomSmartPtr(i, s)); + } + + static std::shared_ptr createSharedPtr(int i, const std::string& s) { + return std::make_shared(i, s); + }; + + int refcount = 1; + int i; + std::string s; +}; + +HeldByCustomSmartPtr* passThroughRawPtr(HeldByCustomSmartPtr* p) { + return p; +} +HeldByCustomSmartPtrPtr passThroughCustomSmartPtr(HeldByCustomSmartPtrPtr p) { + return p; +} + +struct Base1 { +public: + Base1(): field1("Base1") {} + std::string field1; + + std::string getField() const { + return field1; + } +}; + +struct Base2 { +public: + Base2(): field2("Base2") {} + std::string field2; + + std::string getField() const { + return field2; + } +}; + +struct HasTwoBases : public Base1, public Base2 { +}; + +val get_module_property(const std::string& s) { + return val::module_property(s.c_str()); +} + +std::string char_to_string(char ch) { + char str[256]; + sprintf(str, "%d", (int)ch); + return str; +} + +std::string signed_char_to_string(signed char ch) { + char str[256]; + sprintf(str, "%hhd", ch); + return str; +} + +std::string unsigned_char_to_string(unsigned char ch) { + char str[256]; + sprintf(str, "%hhu", ch); + return str; +} + +std::string short_to_string(short val) { + char str[256]; + sprintf(str, "%hd", val); + return str; +} + +std::string unsigned_short_to_string(unsigned short val) { + char str[256]; + sprintf(str, "%hu", val); + return str; +} + +std::string int_to_string(int val) { + char str[256]; + sprintf(str, "%d", val); + return str; +} + +std::string unsigned_int_to_string(unsigned int val) { + char str[256]; + sprintf(str, "%u", val); + return str; +} + +std::string long_to_string(long val) { + char str[256]; + sprintf(str, "%ld", val); + return str; +} + +std::string unsigned_long_to_string(unsigned long val) { + char str[256]; + sprintf(str, "%lu", val); + return str; +} + +EMSCRIPTEN_BINDINGS(tests) { + register_js_interface(); + + register_vector("IntegerVector"); + register_vector("CharVector"); + register_vector("VectorUnsigned"); + register_vector("VectorUnsignedChar"); + register_vector("StringVector"); + register_vector("EmValVector"); + register_vector("FloatVector"); + register_vector>("IntegerVectorVector"); + + function("mallinfo", &emval_test_mallinfo); + function("emval_test_new_integer", &emval_test_new_integer); + function("emval_test_new_string", &emval_test_new_string); + function("emval_test_get_string_from_val", &emval_test_get_string_from_val); + function("emval_test_new_object", &emval_test_new_object); + function("emval_test_passthrough_unsigned", &emval_test_passthrough_unsigned); + function("emval_test_passthrough", &emval_test_passthrough); + function("emval_test_return_void", &emval_test_return_void); + function("emval_test_not", &emval_test_not); + + function("emval_test_as_unsigned", &emval_test_as_unsigned); + function("emval_test_get_length", &emval_test_get_length); + function("emval_test_add", &emval_test_add); + function("const_ref_adder", &const_ref_adder); + function("emval_test_sum", &emval_test_sum); + + //function("emval_test_take_and_return_const_char_star", &emval_test_take_and_return_const_char_star); + function("emval_test_take_and_return_std_string", &emval_test_take_and_return_std_string); + function("emval_test_take_and_return_std_string_const_ref", &emval_test_take_and_return_std_string_const_ref); + + //function("emval_test_take_and_return_CustomStruct", &emval_test_take_and_return_CustomStruct); + + value_tuple("TupleVector") + .element(&TupleVector::x) + .element(&TupleVector::y) + //.element(&TupleVector::z) + .element(&readTupleVectorZ, &writeTupleVectorZ) + ; + + function("emval_test_return_TupleVector", &emval_test_return_TupleVector); + function("emval_test_take_and_return_TupleVector", &emval_test_take_and_return_TupleVector); + + value_tuple("TupleVectorTuple") + .element(&TupleVectorTuple::v) + ; + + function("emval_test_return_TupleVectorTuple", &emval_test_return_TupleVectorTuple); + + value_struct("StructVector") + .field("x", &StructVector::x) + .field("y", &StructVector::y) + .field("z", &StructVector::z) + ; + + function("emval_test_return_StructVector", &emval_test_return_StructVector); + function("emval_test_take_and_return_StructVector", &emval_test_take_and_return_StructVector); + + value_struct("TupleInStruct") + .field("field", &TupleInStruct::field) + ; + + function("emval_test_take_and_return_TupleInStruct", &emval_test_take_and_return_TupleInStruct); + + class_("ValHolder") + .smart_ptr>() + .constructor() + .function("getVal", &ValHolder::getVal) + .function("getValNonConst", &ValHolder::getValNonConst) + .function("getConstVal", &ValHolder::getConstVal) + .function("getValConstRef", &ValHolder::getValConstRef) + .function("setVal", &ValHolder::setVal) + .class_function("makeConst", &ValHolder::makeConst, allow_raw_pointer()) + .class_function("makeValHolder", &ValHolder::makeValHolder) + .class_function("some_class_method", &ValHolder::some_class_method) + .class_function("set_via_raw_pointer", + &ValHolder::set_via_raw_pointer, + allow_raw_pointer>()) + .class_function("get_via_raw_pointer", + &ValHolder::get_via_raw_pointer, + allow_raw_pointer>()) + .class_function("transfer_via_raw_pointer", + &ValHolder::transfer_via_raw_pointer, + allow_raw_pointers()) + + // non-member method + .function("setEmpty", &emval_test_set_ValHolder_to_empty_object) + .function("getValNonMember", &ValHolder::getValNonMember) + ; + + function("emval_test_return_ValHolder", &emval_test_return_ValHolder); + function("emval_test_set_ValHolder_to_empty_object", &emval_test_set_ValHolder_to_empty_object); + + class_>("StringFunctorString") + .constructor<>() + .calloperator("opcall") + ; + + function("emval_test_get_function_ptr", &emval_test_get_function_ptr); + function("emval_test_take_and_call_functor", &emval_test_take_and_call_functor); + + class_("StringHolder") + .smart_ptr>() + .constructor() + .function("set", &StringHolder::set) + .function("get", &StringHolder::get) + .function("get_const_ref", &StringHolder::get_const_ref) + ; + + class_("SharedPtrHolder") + .constructor<>() + .function("get", &SharedPtrHolder::get) + .function("set", &SharedPtrHolder::set) + ; + + class_("SmallClass") + .constructor<>() + .property("member", &SmallClass::member) + ; + + class_("BigClass") + .constructor<>() + .property("member", &BigClass::member) + .property("otherMember", &BigClass::otherMember) + .property("yetAnotherMember", &BigClass::yetAnotherMember) + .function("getMember", &BigClass::getMember) + ; + + class_("ParentClass") + .constructor<>() + .function("getBigClass", &ParentClass::getBigClass) + ; + + class_>("IntTemplateClass") + .constructor() + .function("getMember", &TemplateClass::getMember) + ; + + class_("ContainsTemplatedMemberClass") + .constructor<>() + .function("getTestTemplate", &ContainsTemplatedMemberClass::getTestTemplate) + ; + + // register Derived before Base as a test that it's possible to + // register base classes afterwards + class_>("Derived") + .smart_ptr>() + .constructor<>() + .function("getClassName", &Derived::getClassName) + .function("getMember", &Derived::getMember) + .function("setMember", &Derived::setMember) + .property("member", &Derived::member) + ; + + class_("Base") + .smart_ptr>() + .constructor<>() + .function("getClassName", &Base::getClassName) + .function("getClassNameFromBase", &Base::getClassNameFromBase) + .function("getClassNameNotAvailableInDerivedClasses", &Base::getClassNameNotAvailableInDerivedClasses) + .function("getMember", &Base::getMember) + .function("setMember", &Base::setMember) + .function("getBaseMember", &Base::getBaseMember) + .function("setBaseMember", &Base::setBaseMember) + .property("member", &Base::member) + .property("baseMember", &Base::baseMember) + ; + + class_("SecondBase") + .smart_ptr>() + .constructor<>() + .function("getClassName", &SecondBase::getClassName) + .function("getClassNameFromSecondBase", &SecondBase::getClassNameFromSecondBase) + .function("getClassNameNotAvailableInDerivedClasses", &SecondBase::getClassNameNotAvailableInDerivedClasses) + .function("getMember", &SecondBase::getMember) + .function("setMember", &SecondBase::setMember) + .function("getSecondBaseMember", &SecondBase::getSecondBaseMember) + .function("setSecondBaseMember", &SecondBase::setSecondBaseMember) + .property("member", &SecondBase::member) + .property("secondBaseMember", &SecondBase::secondBaseMember) + ; + + + class_("DerivedHolder") + .constructor<>() + .function("newDerived", &DerivedHolder::newDerived) + .function("deleteDerived", &DerivedHolder::deleteDerived) + .function("getDerived", &DerivedHolder::getDerived) + .function("getDerivedClassName", &DerivedHolder::getDerivedClassName) + ; + + class_("SiblingDerived") + .smart_ptr>() + .constructor<>() + .function("getClassName", &SiblingDerived::getClassName) + ; + + class_>("MultiplyDerived") + .smart_ptr>() + .constructor<>() + .function("getClassName", &MultiplyDerived::getClassName) + .class_function("getInstanceCount", &MultiplyDerived::getInstanceCount) + ; + + class_ >("DerivedTwice") + .constructor<>() + .function("getClassName", &DerivedTwice::getClassName) + ; + + class_ >("DerivedThrice") + .smart_ptr>() + .constructor<>() + .function("getClassName", &DerivedThrice::getClassName) + ; + + class_("PolyBase") + .smart_ptr>() + .constructor<>() + .function("virtualGetClassName", &PolyBase::virtualGetClassName) + .function("getClassName", &PolyBase::getClassName) + ; + + class_("PolySecondBase") + .smart_ptr>() + .constructor<>() + .function("getClassName", &PolySecondBase::getClassName) + ; + + class_>("PolyDerived") + .smart_ptr>() + .constructor<>() + .function("virtualGetClassName", &PolyDerived::virtualGetClassName) + .function("getClassName", &PolyDerived::getClassName) + .class_function("setPtrDerived", &PolyDerived::setPtrDerived) + .class_function("releasePtr", &PolyDerived::releasePtr) + .class_function("getPtrClassName", &PolyDerived::getPtrClassName) + .class_function("getPtr", &PolyDerived::getPtr) + ; +// static void setPtrDerived() { +// ptr = std::shared_ptr(new PolyDerived()); +// } +// +// static std::string getPtrClassName() { +// return ptr->getClassName(); +// } +// +// static std::shared_ptr getPtr() { +// return ptr; +// } + + class_>("PolySiblingDerived") + .smart_ptr>() + .constructor<>() + .function("getClassName", &PolySiblingDerived::getClassName) + ; + + class_>("PolyMultiplyDerived") + .smart_ptr>() + .constructor<>() + .function("getClassName", &PolyMultiplyDerived::getClassName) + ; + + class_>("PolyDerivedThrice") + .smart_ptr>() + .constructor<>() + .function("getClassName", &PolyDerivedThrice::getClassName) + ; + + class_("PolyDiamondBase") + .smart_ptr>() + .constructor<>() + .function("getClassName", &PolyDiamondBase::getClassName) + ; + + class_("PolyDiamondDerived") + .smart_ptr>() + .constructor<>() + .function("getClassName", &PolyDiamondDerived::getClassName) + ; + + class_("PolyDiamondSiblingDerived") + .smart_ptr>() + .constructor<>() + .function("getClassName", &PolyDiamondSiblingDerived::getClassName) + ; + + class_("PolyDiamondMultiplyDerived") + .smart_ptr>() + .constructor<>() + .function("getClassName", &PolyDiamondMultiplyDerived::getClassName) + ; + + function("embind_test_return_small_class_instance", &embind_test_return_small_class_instance); + function("embind_test_return_big_class_instance", &embind_test_return_big_class_instance); + function("embind_test_accept_small_class_instance", &embind_test_accept_small_class_instance); + function("embind_test_accept_big_class_instance", &embind_test_accept_big_class_instance); + + function("embind_test_return_raw_base_ptr", embind_test_return_raw_base_ptr, allow_raw_pointer()); + function("embind_test_return_raw_derived_ptr_as_base", embind_test_return_raw_derived_ptr_as_base, allow_raw_pointer()); + function("embind_test_return_raw_sibling_derived_ptr_as_base", embind_test_return_raw_sibling_derived_ptr_as_base, allow_raw_pointer()); + function("embind_test_return_raw_polymorphic_derived_ptr_as_base", embind_test_return_raw_polymorphic_derived_ptr_as_base, allow_raw_pointer()); + function("embind_test_return_raw_polymorphic_sibling_derived_ptr_as_base", embind_test_return_raw_polymorphic_sibling_derived_ptr_as_base, allow_raw_pointer()); + function("embind_test_return_raw_polymorphic_multiply_derived_ptr_as_base", embind_test_return_raw_polymorphic_multiply_derived_ptr_as_base, allow_raw_pointer()); + function("embind_test_return_raw_polymorphic_multiply_derived_ptr_as_second_base", embind_test_return_raw_polymorphic_multiply_derived_ptr_as_second_base, allow_raw_pointer()); + function("embind_test_return_raw_polymorphic_derived_four_times_not_bound_as_base", embind_test_return_raw_polymorphic_derived_four_times_not_bound_as_base, allow_raw_pointer()); + function("embind_test_return_smart_derived_ptr", embind_test_return_smart_derived_ptr); + function("embind_test_return_smart_sibling_derived_ptr", embind_test_return_smart_sibling_derived_ptr); + function("embind_test_return_smart_multiply_derived_ptr", embind_test_return_smart_multiply_derived_ptr); + function("embind_test_return_smart_derived_thrice_ptr", embind_test_return_smart_derived_thrice_ptr); + function("embind_test_return_smart_base_ptr", embind_test_return_smart_base_ptr); + function("embind_test_return_smart_polymorphic_base_ptr", embind_test_return_smart_polymorphic_base_ptr); + function("embind_test_return_smart_polymorphic_derived_ptr", embind_test_return_smart_polymorphic_derived_ptr); + function("embind_test_return_smart_polymorphic_sibling_derived_ptr", embind_test_return_smart_polymorphic_sibling_derived_ptr); + function("embind_test_return_smart_polymorphic_multiply_derived_ptr", embind_test_return_smart_polymorphic_multiply_derived_ptr); + function("embind_test_return_poly_derived_twice_without_smart_pointer_as_poly_base", embind_test_return_poly_derived_twice_without_smart_pointer_as_poly_base); + function("embind_test_return_smart_poly_derived_thrice_ptr", embind_test_return_smart_poly_derived_thrice_ptr); + function("embind_test_return_smart_derived_ptr_as_base", embind_test_return_smart_derived_ptr_as_base); + function("embind_test_return_smart_derived_ptr_as_val", embind_test_return_smart_derived_ptr_as_val); + function("embind_test_return_smart_polymorphic_derived_ptr_as_base", embind_test_return_smart_polymorphic_derived_ptr_as_base); + function("embind_test_return_smart_polymorphic_sibling_derived_ptr_as_base", embind_test_return_smart_polymorphic_sibling_derived_ptr_as_base); + function("embind_test_get_class_name_via_base_ptr", embind_test_get_class_name_via_base_ptr, allow_raw_pointer>()); + function("embind_test_get_class_name_via_second_base_ptr", embind_test_get_class_name_via_second_base_ptr, allow_raw_pointer>()); + function("embind_test_get_class_name_via_polymorphic_base_ptr", embind_test_get_class_name_via_polymorphic_base_ptr, allow_raw_pointer>()); + function("embind_test_get_class_name_via_polymorphic_second_base_ptr", embind_test_get_class_name_via_polymorphic_second_base_ptr, allow_raw_pointer>()); + // todo: allow_raw_pointer should fail earlier if argument is not a pointer + function("embind_test_get_class_name_via_smart_base_ptr", embind_test_get_class_name_via_smart_base_ptr); + function("embind_test_get_class_name_via_reference_to_smart_base_ptr", embind_test_get_class_name_via_reference_to_smart_base_ptr); + function("embind_test_get_class_name_via_smart_second_base_ptr", embind_test_get_class_name_via_smart_second_base_ptr); + function("embind_test_get_class_name_via_smart_polymorphic_base_ptr", embind_test_get_class_name_via_smart_polymorphic_base_ptr); + function("embind_test_get_virtual_class_name_via_smart_polymorphic_base_ptr", embind_test_get_virtual_class_name_via_smart_polymorphic_base_ptr); + function("embind_test_get_class_name_via_smart_polymorphic_second_base_ptr", embind_test_get_class_name_via_smart_polymorphic_second_base_ptr); + function("embind_modify_smart_pointer_passed_by_reference", embind_modify_smart_pointer_passed_by_reference); + function("embind_attempt_to_modify_smart_pointer_when_passed_by_value", embind_attempt_to_modify_smart_pointer_when_passed_by_value); + function("embind_save_smart_base_pointer", embind_save_smart_base_pointer); + + class_("Base2") + .function("getField", &Base2::getField) + .property("field", &Base2::field2) + ; + + class_>("HasTwoBases") + .constructor() + ; + + class_("CustomStruct") + .constructor<>() + .property("field", &CustomStruct::field) + .function("getField", &CustomStruct::getField) + ; + + enum_("Enum") + .value("ONE", ONE) + .value("TWO", TWO) + ; + function("emval_test_take_and_return_Enum", &emval_test_take_and_return_Enum); + + enum_("EnumClass") .value("ONE", EnumClass::ONE) .value("TWO", EnumClass::TWO) ; function("emval_test_take_and_return_EnumClass", &emval_test_take_and_return_EnumClass); - class InterfaceWrapper : public wrapper { - int method() { - return call("method"); - } - TupleInStruct method2(const TupleInStruct& arg1, float arg2) { - return call("method2", arg1, arg2); - } - void method3() { - return call("method3"); - } - }; - interface("Interface") + function("emval_test_call_function", &emval_test_call_function); + + function("emval_test_return_unique_ptr", &emval_test_return_unique_ptr); + + function("emval_test_return_shared_ptr", &emval_test_return_shared_ptr); + function("emval_test_return_empty_shared_ptr", &emval_test_return_empty_shared_ptr); + function("emval_test_is_shared_ptr_null", &emval_test_is_shared_ptr_null); + + function("emval_test_return_vector", &emval_test_return_vector); + function("emval_test_return_vector_of_vectors", &emval_test_return_vector_of_vectors); + + register_vector>("SharedPtrVector"); + function("emval_test_return_shared_ptr_vector", &emval_test_return_shared_ptr_vector); + + function("get_module_property", &get_module_property); + + register_vector("StringHolderVector"); + class_("VectorHolder") + .constructor<>() + .function("get", &VectorHolder::get) + .function("set", &VectorHolder::set) ; - function("emval_test_call_method", &emval_test_call_method); - function("emval_test_call_method2", &emval_test_call_method2); - function("emval_test_call_method3", &emval_test_call_method3); - function("emval_test_call_function", &emval_test_call_function); + function("test_string_with_vec", &test_string_with_vec); + + register_map("StringIntMap"); + function("embind_test_get_string_int_map", embind_test_get_string_int_map); + + class_("JSInterfaceHolder") + .constructor() + .function("callMethod", &JSInterfaceHolder::callMethod) + .function("callMethodUsingSharedPtr", &JSInterfaceHolder::callMethodUsingSharedPtr) + ; + + function("embind_test_new_Object", &embind_test_new_Object); + function("embind_test_new_factory", &embind_test_new_factory); + + class_("AbstractClass") + .smart_ptr>() + .allow_subclass() + .function("abstractMethod", &AbstractClass::abstractMethod) + ; + + function("getAbstractClass", &getAbstractClass); + function("callAbstractMethod", &callAbstractMethod); + + class_("HasExternalConstructor") + .constructor(&createHasExternalConstructor) + .function("getString", &HasExternalConstructor::getString) + ; + + auto HeldBySmartPtr_class = class_("HeldBySmartPtr"); + HeldBySmartPtr_class + .smart_ptr>() + .smart_ptr_constructor(&std::make_shared) + .class_function("newCustomPtr", HeldBySmartPtr::newCustomPtr) + .function("returnThis", &takesHeldBySmartPtrSharedPtr) + .property("i", &HeldBySmartPtr::i) + .property("s", &HeldBySmartPtr::s) + ; + function("takesHeldBySmartPtr", &takesHeldBySmartPtr); + function("takesHeldBySmartPtrSharedPtr", &takesHeldBySmartPtrSharedPtr); + + class_("HeldByCustomSmartPtr") + .smart_ptr>() + .smart_ptr_constructor(&HeldByCustomSmartPtr::create) + .class_function("createSharedPtr", &HeldByCustomSmartPtr::createSharedPtr) + .property("i", &HeldByCustomSmartPtr::i) + .property("s", &HeldByCustomSmartPtr::s) + ; + + function("passThroughRawPtr", &passThroughRawPtr, allow_raw_pointers()); + function("passThroughCustomSmartPtr", &passThroughCustomSmartPtr); + + function("char_to_string", &char_to_string); + function("signed_char_to_string", &signed_char_to_string); + function("unsigned_char_to_string", &unsigned_char_to_string); + function("short_to_string", &short_to_string); + function("unsigned_short_to_string", &unsigned_short_to_string); + function("int_to_string", &int_to_string); + function("unsigned_int_to_string", &unsigned_int_to_string); + function("long_to_string", &long_to_string); + function("unsigned_long_to_string", &unsigned_long_to_string); +} + +// tests for out-of-order registration - function('optional_test_copy', &optional_test_copy); - function('optional_test_copy2', &optional_test_copy2); -})); +class SecondElement { +}; + +class FirstElement { +}; + +struct OrderedTuple { + FirstElement first; + SecondElement second; +}; + +struct OrderedStruct { + FirstElement first; + SecondElement second; +}; + +OrderedTuple getOrderedTuple() { + return OrderedTuple(); +} + +OrderedStruct getOrderedStruct() { + return OrderedStruct(); +} + +EMSCRIPTEN_BINDINGS(order) { + value_tuple("OrderedTuple") + .element(&OrderedTuple::first) + .element(&OrderedTuple::second) + ; + + value_struct("OrderedStruct") + .field("first", &OrderedStruct::first) + .field("second", &OrderedStruct::second) + ; + + class_("SecondElement") + ; + + class_("FirstElement") + ; + + function("getOrderedTuple", &getOrderedTuple); + function("getOrderedStruct", &getOrderedStruct); +} + +// tests for unbound types + +template +T passThrough(T t) { + return t; +} + +struct UnboundClass { +}; + +struct HasUnboundBase : public UnboundClass { + static void noop() { + } +}; + +HasUnboundBase getHasUnboundBase(HasUnboundBase f) { + return f; +} + +struct HasConstructorUsingUnboundArgument { + HasConstructorUsingUnboundArgument(UnboundClass) { + } +}; + +struct SecondUnboundClass { +}; + +struct HasConstructorUsingUnboundArgumentAndUnboundBase : public SecondUnboundClass { + HasConstructorUsingUnboundArgumentAndUnboundBase(UnboundClass) { + } +}; + +struct BoundClass { + UnboundClass method(UnboundClass t) { + return t; + } + + static UnboundClass classfunction(UnboundClass t) { + return t; + } + + UnboundClass property; +}; + +EMSCRIPTEN_BINDINGS(incomplete) { + function("getUnboundClass", &passThrough); + + class_>("HasUnboundBase") + .class_function("noop", &HasUnboundBase::noop) + ; + function("getHasUnboundBase", &passThrough); + + class_("HasConstructorUsingUnboundArgument") + .constructor() + ; + + class_>("HasConstructorUsingUnboundArgumentAndUnboundBase") + .constructor() + ; + + class_("BoundClass") + .constructor<>() + .function("method", &BoundClass::method) + .class_function("classfunction", &BoundClass::classfunction) + .property("property", &BoundClass::property) + ; +} + +class Noncopyable { + Noncopyable(const Noncopyable&) = delete; + Noncopyable& operator=(const Noncopyable&) = delete; + +public: + Noncopyable() {} + + std::string method() const { + return "foo"; + } +}; + +EMSCRIPTEN_BINDINGS(noncopyable) { + class_("Noncopyable") + .constructor<>() + .function("method", &Noncopyable::method) + ; +} diff --git a/tests/embind/embind_test.js b/tests/embind/embind_test.js deleted file mode 100644 index 9ba6a48f55405..0000000000000 --- a/tests/embind/embind_test.js +++ /dev/null @@ -1,398 +0,0 @@ -//=== testing glue - -function module(ignore, func) { - func({ Emscripten: Module }); -} - -function fixture(name, info) { - Module.print('fixture: ' + name); - for (var test in info) { - var f = info[test]; - if (typeof f != 'function') continue; - Module.print('--test: ' + test); - // TODO: Base fixture! - f(); - } -} - -assert.true = assert; - -assert.equal = function(x, y) { - assert(x == y); -} - -assert.notEqual = function(x, y) { - assert(x != y); -} - -assert.throws = function(exc, func) { - var ret; - try { - func(); - } catch(e) { - ret = e; - } - assert(ret); // TODO: check exc vs e - return ret; -} - -assert.instanceof = function(inst, clazz) { - assert(inst instanceof clazz); -} - -assert.deepEqual = function(x, y) { - assert(JSON.stringify(x) == JSON.stringify(y)); -} - -//=== - -module({ - Emscripten: '../build/Emscripten.js' -}, function(imports) { - var cm = imports.Emscripten; - - var checkForLeaks = { - setUp: function() { - this.originalBlockCount = cm.mallinfo().uordblks; - }, - tearDown: function() { - assert.equal(this.originalBlockCount, cm.mallinfo().uordblks); - }, - }; - - fixture("embind", { - baseFixture: checkForLeaks, - - "test value creation": function() { - assert.equal(15, cm.emval_test_new_integer()); - assert.equal("Hello everyone", cm.emval_test_new_string()); - - var object = cm.emval_test_new_object(); - assert.equal('bar', object.foo); - assert.equal(1, object.baz); - }, - - "test passthrough": function() { - var a = {foo: 'bar'}; - var b = cm.emval_test_passthrough(a); - a.bar = 'baz'; - assert.equal('baz', b.bar); - - assert.equal(0, cm.count_emval_handles()); - }, - - "test void return converts to undefined": function() { - assert.equal(undefined, cm.emval_test_return_void()); - }, - - "test booleans can be marshalled": function() { - assert.equal(false, cm.emval_test_not(true)); - assert.equal(true, cm.emval_test_not(false)); - }, - - "test convert double to unsigned": function() { - var rv = cm.emval_test_as_unsigned(1.5); - assert.equal('number', typeof rv); - assert.equal(1, rv); - assert.equal(0, cm.count_emval_handles()); - }, - - "test get length of array": function() { - assert.equal(10, cm.emval_test_get_length([0, 1, 2, 3, 4, 5, 'a', 'b', 'c', 'd'])); - assert.equal(0, cm.count_emval_handles()); - }, - - "test add a bunch of things": function() { - assert.equal(66.0, cm.emval_test_add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); - assert.equal(0, cm.count_emval_handles()); - }, - - "test sum array": function() { - assert.equal(66, cm.emval_test_sum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])); - assert.equal(0, cm.count_emval_handles()); - }, - - "test strings": function() { - assert.equal("foobar", "foo" + "bar"); - assert.equal("foobar", cm.emval_test_take_and_return_std_string("foobar")); - - assert.equal("foobar", cm.emval_test_take_and_return_std_string_const_ref("foobar")); - }, - - "test no memory leak when passing strings in by const reference": function() { - var original = cm.mallinfo().uordblks; - cm.emval_test_take_and_return_std_string_const_ref("foobar"); - assert.equal(original, cm.mallinfo().uordblks); - }, - }); - - fixture("classes", { - baseFixture: checkForLeaks, - - "test class instance": function() { - var a = {foo: 'bar'}; - var c = new cm.ValHolder(a); - assert.equal('bar', c.getVal().foo); - - c.setVal('1234'); - assert.equal('1234', c.getVal()); - - assert.equal(1239, c.returnIntPlusFive(1234)); - - c.delete(); - assert.equal(0, cm.count_emval_handles()); - }, - - "test class methods": function() { - assert.equal(10, cm.ValHolder.some_class_method(10)); - }, - - "test can't call methods on deleted class instances": function() { - var c = new cm.ValHolder(undefined); - c.delete(); - assert.throws(cm.BindingError, function() { - c.getVal(); - }); - assert.throws(cm.BindingError, function() { - c.delete(); - }); - }, - - "test isinstance": function() { - var c = new cm.ValHolder(undefined); - assert.instanceof(c, cm.ValHolder); - c.delete(); - }, - - "test can return class instances by value": function() { - var c = cm.emval_test_return_ValHolder(); - assert.deepEqual({}, c.getVal()); - c.delete(); - }, - - "test can pass class instances to functions by reference": function() { - var a = {a:1}; - var c = new cm.ValHolder(a); - cm.emval_test_set_ValHolder_to_empty_object(c); - assert.deepEqual({}, c.getVal()); - c.delete(); - }, - - "test can access struct fields": function() { - var c = new cm.CustomStruct(); - assert.equal(10, c.field); - c.delete(); - }, - - "test can set struct fields": function() { - var c = new cm.CustomStruct(); - c.field = 15; - assert.equal(15, c.field); - c.delete(); - }, - - "test assignment returns value": function() { - var c = new cm.CustomStruct(); - assert.equal(15, c.field = 15); - c.delete(); - }, - - "test assigning string to integer raises TypeError": function() { - var c = new cm.CustomStruct(); - - var e = assert.throws(TypeError, function() { - c.field = "hi"; - }); - assert.equal('Cannot convert "hi" to int', e.message); - - var e = assert.throws(TypeError, function() { - c.field = {foo:'bar'}; - }); - assert.equal('Cannot convert "[object Object]" to int', e.message); - - c.delete(); - }, - - "test can return tuples by value": function() { - var c = cm.emval_test_return_TupleVector(); - assert.deepEqual([1, 2, 3], c); - }, - - "test tuples can contain tuples": function() { - var c = cm.emval_test_return_TupleVectorTuple(); - assert.deepEqual([[1, 2, 3]], c); - }, - - "test can pass tuples by value": function() { - var c = cm.emval_test_take_and_return_TupleVector([4, 5, 6]); - assert.deepEqual([4, 5, 6], c); - }, - - "test can return structs by value": function() { - var c = cm.emval_test_return_StructVector(); - assert.deepEqual({x: 1, y: 2, z: 3}, c); - }, - - "test can pass structs by value": function() { - var c = cm.emval_test_take_and_return_StructVector({x: 4, y: 5, z: 6}); - assert.deepEqual({x: 4, y: 5, z: 6}, c); - }, - - "test can pass and return tuples in structs": function() { - var d = cm.emval_test_take_and_return_TupleInStruct({field: [1, 2, 3]}); - assert.deepEqual({field: [1, 2, 3]}, d); - }, - - "test can clone handles": function() { - assert.equal(0, cm.count_emval_handles()); - - var a = new cm.ValHolder({}); - var b = a.clone(); - a.delete(); - - assert.equal(1, cm.count_emval_handles()); - - assert.throws(cm.BindingError, function() { - a.delete(); - }); - b.delete(); - - assert.equal(0, cm.count_emval_handles()); - }, - - "test can't clone if already deleted": function() { - var a = new cm.ValHolder({}); - a.delete(); - assert.throws(cm.BindingError, function() { - a.clone(); - }); - }, - - "test moving handles is a clone+delete": function() { - var a = new cm.ValHolder({}); - var b = a.move(); - assert.throws(cm.BindingError, function() { - a.delete(); - }); - assert.equal(1, cm.count_emval_handles()); - b.delete(); - assert.equal(0, cm.count_emval_handles()); - }, - - "test StringHolder": function() { - var a = new cm.StringHolder("foobar"); - assert.equal("foobar", a.get()); - - a.set("barfoo"); - assert.equal("barfoo", a.get()); - a.delete(); - }, - }); - - fixture("embind enumerations", { - baseFixture: checkForLeaks, - - "test can compare enumeration values": function() { - assert.equal(cm.Enum.ONE, cm.Enum.ONE); - assert.notEqual(cm.Enum.ONE, cm.Enum.TWO); - }, - - "test repr includes enum value": function() { - return; // XXX IMVU? - assert.equal('<#Enum_ONE {}>', IMVU.repr(cm.Enum.ONE)); - assert.equal('<#Enum_TWO {}>', IMVU.repr(cm.Enum.TWO)); - }, - - "test instanceof": function() { - assert.instanceof(cm.Enum.ONE, cm.Enum); - }, - - "test can pass and return enumeration values to functions": function() { - assert.equal(cm.Enum.TWO, cm.emval_test_take_and_return_Enum(cm.Enum.TWO)); - }, - }); - - fixture("C++11 enum class", { - baseFixture: checkForLeaks, - - "test can compare enumeration values": function() { - assert.equal(cm.EnumClass.ONE, cm.EnumClass.ONE); - assert.notEqual(cm.EnumClass.ONE, cm.EnumClass.TWO); - }, - - "test repr includes enum value": function() { - return; // XXX IMVU? - assert.equal('<#EnumClass_ONE {}>', IMVU.repr(cm.EnumClass.ONE)); - assert.equal('<#EnumClass_TWO {}>', IMVU.repr(cm.EnumClass.TWO)); - }, - - "test instanceof": function() { - assert.instanceof(cm.EnumClass.ONE, cm.EnumClass); - }, - - "test can pass and return enumeration values to functions": function() { - assert.equal(cm.EnumClass.TWO, cm.emval_test_take_and_return_EnumClass(cm.EnumClass.TWO)); - }, - }); - - fixture("emval call tests", { - "test can call functions from C++": function() { - var called = false; - cm.emval_test_call_function(function(i, f, tv, sv) { - called = true; - assert.equal(10, i); - assert.equal(1.5, f); - assert.deepEqual([1.25, 2.5, 3.75], tv); - assert.deepEqual({x: 1.25, y: 2.5, z: 3.75}, sv); - }, 10, 1.5, [1.25, 2.5, 3.75], {x: 1.25, y: 2.5, z: 3.75}); - assert.true(called); - }, - }); - - fixture("interfaces", { - baseFixture: checkForLeaks, - - "test can wrap JS object in native interface": function() { - var foo = { - calls: [], - method: function() { - this.calls.push('called'); - return 10; - } - }; - - assert.equal(10, cm.emval_test_call_method(foo)); - assert.deepEqual(['called'], foo.calls); - }, - - "test can pass arguments and return complicated values": function() { - var calls = []; - var foo = { - method2: function(arg1, arg2) { - calls.push([arg1, arg2]); - return arg1; - } - }; - - var result = cm.emval_test_call_method2(foo, {field: [1, 2, 3]}, 7); - assert.deepEqual({field: [1, 2, 3]}, result); - assert.deepEqual([[{field: [1, 2, 3]}, 7]], calls); - }, - - "test can call interface methods that return nothing": function() { - var calls = []; - var foo = { - method3: function() { - calls.push('called'); - } - }; - cm.emval_test_call_method3(foo); - assert.deepEqual(['called'], calls); - }, - }); - - test('emscripten::internal::optional', function () { - assert.true(cm.optional_test_copy()); - assert.false(cm.optional_test_copy2()); - }); -}); diff --git a/tests/embind/imvu_test_adapter.js b/tests/embind/imvu_test_adapter.js new file mode 100755 index 0000000000000..03405d0844203 --- /dev/null +++ b/tests/embind/imvu_test_adapter.js @@ -0,0 +1,614 @@ +/* The embind test suite (embind.test.js) is configured to be runnable in two different testing engines: + - The Emscripten python test runner (open-source in emscripten repository) and + - The IMVU test runner (closed-source in IMVU repository) + + Embind (and its tests) were originally developed in IMVU repository, which is the reason for two testing architectures. + This adapter file is used when the embind tests are run as part of the Emscripten test runner, to provide the necessary glue code to adapt the tests to Emscripten runner. + + To run the Embind tests using the Emscripten test runner, invoke 'python tests/runner.py other.test_embind' in the Emscripten root directory. +*/ + +//=== testing glue + +function module(ignore, func) { + func({ Emscripten: Module }); +} + +/*global IMVU:true, TEST_MAX_OUTPUT_SIZE*/ +//(function() { +// "use strict"; + + // { beforeTest: function, + // afterTest: function } + var superFixtures = []; + + function registerSuperFixture(superFixture) { + superFixtures.push(superFixture); + } + + // { fixture: Fixture instance, + // name: string, + // body: function() } + var allTests = []; + + function test(name, fn) { + if (arguments.length !== 2) { + throw new TypeError("test requires 2 arguments"); + } + + if (undefined !== activeFixture && activeFixture.abstract) { + activeFixture.abstractTests.push({ + name: name, + body: fn }); + } else { + var fixtureName = (undefined !== activeFixture)? activeFixture.name + ': ' : ''; + allTests.push({ + name: fixtureName + name, + body: fn, + fixture: activeFixture }); + } + } + + function runTest(test, continuation) { + try { + var afterTests = []; + + for (var i = 0; i < superFixtures.length; ++i) { + var superFixture = superFixtures[i]; + + var superScope = {}; + superFixture.beforeTest.call(superScope); + afterTests.push(superFixture.afterTest.bind(superScope)); + } + + var testScope = test.fixture ? + Object.create(test.fixture.scope) : + {}; + + var runSetUp = function(fixtureObject) { + if (undefined === fixtureObject) { + return; + } + runSetUp(fixtureObject.parent); + fixtureObject.setUp.call(testScope); + afterTests.push(fixtureObject.tearDown.bind(testScope)); + }; + runSetUp(test.fixture); + + test.body.call(testScope); + while (afterTests.length) { + afterTests.pop()(); + } + return false; + } catch (e) { + console.error('error:', e); + return {stack: e.stack, e: e}; + } + } + + function run_all(reporter) { + for (var i = 0; i < allTests.length; ++i) { + var test = allTests[i]; + reporter({ + type: 'test-start', + name: test.name + }); + + var failed = runTest(test); + if (failed) { + reporter({ + type: 'test-complete', + name: test.name, + verdict: 'FAIL', + stack: failed.stack, + e: failed.e + }); + return false; + } else { + reporter({ + type: 'test-complete', + name: test.name, + verdict: 'PASS' + }); + } + } + + reporter({ + type: 'all-tests-complete' + }); + + allTests = []; + return true; + } + + var activeFixture; + + function Fixture(parent, name, definition, abstract_) { + if (!(definition instanceof Function)) { + throw new TypeError("fixture's 2nd argument must be a function"); + } + + this.name = name; + this.parent = parent; + this.abstract = abstract_; + if (this.abstract) { + // { name: string, + // body: function } + this.abstractTests = []; + } + + if (this.parent !== undefined) { + this.parent.addAbstractTests(this); + } + + this.scope = (this.parent === undefined ? {} : Object.create(this.parent.scope)); + this.scope.setUp = function(setUp) { + this.setUp = setUp; + }.bind(this); + this.scope.tearDown = function(tearDown) { + this.tearDown = tearDown; + }.bind(this); + + if (undefined !== activeFixture) { + throw new TypeError("Cannot define a fixture within another fixture"); + } + + activeFixture = this; + try { + definition.call(this.scope); + } + finally { + activeFixture = undefined; + } + } + Fixture.prototype.setUp = function defaultSetUp() { + }; + Fixture.prototype.tearDown = function defaultTearDown() { + }; + Fixture.prototype.addAbstractTests = function(concreteFixture) { + if (this.abstract) { + for (var i = 0; i < this.abstractTests.length; ++i) { + var test = this.abstractTests[i]; + allTests.push({ + name: concreteFixture.name + ': ' + test.name, + body: test.body, + fixture: concreteFixture}); + } + } + if (this.parent) { + this.parent.addAbstractTests(concreteFixture); + } + }; + + Fixture.prototype.extend = function(fixtureName, definition) { + return new Fixture(this, fixtureName, definition, false); + }; + + function fixture(fixtureName, definition) { + return new Fixture(undefined, fixtureName, definition, false); + } + fixture.abstract = function(fixtureName, definition) { + return new Fixture(undefined, fixtureName, definition, true); + }; + + var AssertionError = Error; + + function fail(exception, info) { + exception.info = info; + throw exception; + } + + var formatTestValue = function(v) { + return v.toString(); + /* + var s = IMVU.repr(v, TEST_MAX_OUTPUT_SIZE + 1); + if (s.length <= TEST_MAX_OUTPUT_SIZE) { + return s; + } + return s.substring(0, TEST_MAX_OUTPUT_SIZE) + '...'; + */ + }; + +// var assert = { + + //////////////////////////////////////////////////////////////////////////////// + // GENERAL STATUS + + assert.fail = function(info) { + info = info || "assert.fail()"; + fail(new AssertionError(info)); + }, + + //////////////////////////////////////////////////////////////////////////////// + // BOOLEAN TESTS + + assert['true'] = function(value) { + if (!value) { + fail(new AssertionError("expected truthy, actual " + formatTestValue(value)), + {Value: value}); + } + }, + + assert['false'] = function(value) { + if (value) { + fail(new AssertionError("expected falsy, actual " + formatTestValue(value)), + {Value: value}); + } + }, + + //////////////////////////////////////////////////////////////////////////////// + // SCALAR COMPARISON + + assert.equal = function(expected, actual) { + if (expected !== actual) { + fail(new AssertionError('expected: ' + formatTestValue(expected) + ', actual: ' + formatTestValue(actual)), + {Expected: expected, Actual: actual}); + } + }, + + assert.notEqual = function(expected, actual) { + if (expected === actual) { + fail(new AssertionError('actual was equal to: ' + formatTestValue(expected))); + } + }, + + assert.greater = function(lhs, rhs) { + if (lhs <= rhs) { + fail(new AssertionError(formatTestValue(lhs) + ' not greater than ' + formatTestValue(rhs))); + } + }, + + assert.less = function(lhs, rhs) { + if (lhs >= rhs) { + fail(new AssertionError(formatTestValue(lhs) + ' not less than ' + formatTestValue(rhs))); + } + }, + + assert.greaterOrEqual = function(lhs, rhs) { + if (lhs < rhs) { + fail(new AssertionError(formatTestValue(lhs) + ' not greater than or equal to ' + formatTestValue(rhs))); + } + }, + + assert.lessOrEqual = function(lhs, rhs) { + if (lhs > rhs) { + fail(new AssertionError(formatTestValue(lhs) + ' not less than or equal to ' + formatTestValue(rhs))); + } + }, + + //////////////////////////////////////////////////////////////////////////////// + // DEEP COMPARISON + + assert.deepEqual = function(expected, actual) { + if (!_.isEqual(expected, actual)) { + fail(new AssertionError('expected: ' + formatTestValue(expected) + ', actual: ' + formatTestValue(actual)), + {Expected: expected, Actual: actual}); + } + }, + + assert.notDeepEqual = function(expected, actual) { + if (_.isEqual(expected, actual)) { + fail(new AssertionError('expected: ' + formatTestValue(expected) + ' and actual: ' + formatTestValue(actual) + ' were equal')); + } + }, + + //////////////////////////////////////////////////////////////////////////////// + // FLOATING POINT + + assert.nearEqual = function( expected, actual, tolerance ) { + if( tolerance === undefined ) { + tolerance = 0.0; + } + if( expected instanceof Array && actual instanceof Array ) { + assert.equal(expected.length, actual.length); + for( var i=0; i tolerance ) { + fail( new AssertionError('expected: ' + formatTestValue(expected) + ', actual: ' + formatTestValue(actual) + + ', tolerance: ' + formatTestValue(tolerance) + ', diff: ' + formatTestValue(actual-expected) ), + { Expected:expected, Actual:actual, Tolerance:tolerance } ); + } + }, + + //////////////////////////////////////////////////////////////////////////////// + // STRING + + assert.inString = function(expected, string){ + if (-1 === string.indexOf(expected)){ + fail(new AssertionError('expected: ' + formatTestValue(expected) + ' not in string: ' + formatTestValue(string)), + {Expected: expected, 'String': string}); + } + }, + + assert.notInString = function(expected, string){ + if (-1 !== string.indexOf(expected)){ + fail(new AssertionError('unexpected: ' + formatTestValue(expected) + ' in string: ' + formatTestValue(string)), + {Expected: expected, 'String': string}); + } + }, + + assert.matches = function(re, string) { + if (!re.test(string)) { + fail(new AssertionError('regexp ' + re + ' does not match: ' + string)); + } + }, + + //////////////////////////////////////////////////////////////////////////////// + // ARRAY + + assert.inArray = function(expected, array) { + var found = false; + _.each(array, function(element){ + if (_.isEqual(expected, element)){ + found = true; + } + }); + if (!found){ + fail(new AssertionError('expected: ' + formatTestValue(expected) + ' not found in array: ' + formatTestValue(array)), + {Expected: expected, 'Array': array}); + } + }, + + assert.notInArray = function(expected, array) { + var found = false; + _.each(array, function(element){ + if (_.isEqual(expected, element)){ + found = true; + } + }); + if (found){ + fail(new AssertionError('unexpected: ' + formatTestValue(expected) + ' found in array: ' + formatTestValue(array)), + {Expected: expected, 'Array': array}); + } + }, + + //////////////////////////////////////////////////////////////////////////////// + // OBJECTS + + assert.hasKey = function (key, object) { + if (!(key in object)) { + fail(new AssertionError('Key ' + formatTestValue(key) + ' is not in object: ' + formatTestValue(object))); + } + }, + + assert.notHasKey = function (key, object) { + if (key in object) { + fail(new AssertionError('Unexpected key ' + formatTestValue(key) + ' is found in object: ' + formatTestValue(object))); + } + }, + + //////////////////////////////////////////////////////////////////////////////// + // EXCEPTIONS + + assert['throws'] = function(exception, fn) { + try { + fn(); + } catch (e) { + if (e instanceof exception) { + return e; + } + fail(new AssertionError('Expected to throw "' + exception.name + '", actually threw: ' + formatTestValue(e) + ': ' + e.message), + {Expected: exception, Actual: e}); + } + throw new AssertionError('did not throw'); + }, + + //////////////////////////////////////////////////////////////////////////////// + // TYPE + + assert['instanceof'] = function(actual, type) { + if(!(actual instanceof type)) { + fail(new AssertionError(formatTestValue(actual) + ' not instance of ' + formatTestValue(type)), + {Type: type, Actual: actual}); + } + }, + + //////////////////////////////////////////////////////////////////////////////// + // DOM ASSERTIONS + + // TODO: lift into separate file? + assert.dom = { + present: function(domElement){ + if (!$(domElement).length) { + fail(new AssertionError(decipherDomElement(domElement) + ' should be present')); + } + }, + + notPresent: function(selector){ + assert.equal(0, $(selector).length); + }, + + hasTag: function(tag, domElement) { + var elementTag = $(domElement)[0].tagName.toLowerCase(); + if (elementTag !== tag.toLowerCase()) { + fail(new AssertionError(decipherDomElement(domElement) + ' expected to have tag name ' + formatTestValue(tag) + ', was ' + formatTestValue(elementTag) + ' instead')); + } + }, + + hasClass: function(className, domElement) { + if (!$(domElement).hasClass(className)){ + fail(new AssertionError(decipherDomElement(domElement) + ' expected to have class '+ formatTestValue(className) + ', has ' + formatTestValue($(domElement).attr('class')) + ' instead')); + } + }, + + notHasClass: function(className, domElement) { + assert.dom.present(domElement); // if domElement is empty, .hasClass will always return false + if ($(domElement).hasClass(className)){ + fail(new AssertionError(decipherDomElement(domElement) + ' expected NOT to have class '+ formatTestValue(className))); + } + }, + + hasAttribute: function(attributeName, selector) { + assert['true']($(selector).is('[' + attributeName + ']')); + }, + + notHasAttribute: function(attributeName, selector) { + assert.dom.present(selector); + assert['false']($(selector).is('[' + attributeName + ']')); + }, + + attr: function(value, attributeName, selector) { + assert.equal(value, $(selector).attr(attributeName)); + }, + + attributeValues: function (values, selector) { + var $el = $(selector); + _(values).each(function (val, key) { + assert.equal(val, $el.attr(key)); + }); + }, + + text: function(expected, selector) { + assert.equal(expected, $(selector).text()); + }, + + value: function(expected, selector) { + assert.equal(expected, $(selector).val()); + }, + + count: function(elementCount, selector) { + assert.equal(elementCount, $(selector).length); + }, + + visible: function(domElement) { + if (!$(domElement).is(':visible')) { + fail(new AssertionError(decipherDomElement(domElement) + ' expected to be visible')); + } + }, + + notVisible: function(domElement) { + assert.dom.present(domElement); + if ($(domElement).is(':visible')) { + fail(new AssertionError(decipherDomElement(domElement) + ' expected to be NOT visible')); + } + }, + + disabled: function(domElement) { + if (!$(domElement).is(':disabled')) { + fail(new AssertionError(decipherDomElement(domElement) + ' expected to be disabled')); + } + }, + + enabled: function(domElement) { + if (!$(domElement).is(':enabled')) { + fail(new AssertionError(decipherDomElement(domElement) + ' expected to be enabled')); + } + }, + + focused: function(selector) { + var expected = $(selector)[0]; + var actual = document.activeElement; + if (expected !== actual) { + throw new AssertionError(actual.outerHTML + ' has focus. expected: ' + expected.outerHTML); + } + }, + + notFocused: function(selector) { + var expected = $(selector)[0]; + var actual = document.activeElement; + if (expected === actual) { + throw new AssertionError(expected.outerHTML + ' expected not to have focus.'); + } + }, + + html: function(expected, selector) { + assert.equal(expected, $(selector).html()); + }, + + css: function(expected, propertyName, selector) { + assert.equal(expected, $(selector).css(propertyName)); + }, + + empty: function(selectorOrJQueryObject) { + var el = selectorOrJQueryObject; + assert.dom.present(el); + if (!$(el).is(':empty')) { + fail(new AssertionError(decipherDomElement(el) + ' expected to be empty')); + } + }, + + notEmpty: function(selectorOrJQueryObject) { + var el = selectorOrJQueryObject; + assert.dom.present(el); + if ($(el).is(':empty')) { + fail(new AssertionError(decipherDomElement(el) + ' expected NOT to be empty')); + } + } + } +// }; + + function decipherDomElement(selectorOrJQueryObject) { + if (typeof selectorOrJQueryObject === 'string') { + return 'Selector ' + formatTestValue(selectorOrJQueryObject); + } else if (typeof selectorOrJQueryObject === 'object') { + return "'" + selectorOrJQueryObject[0] + "'"; + } + } + + var g = 'undefined' === typeof window ? global : window; + + // synonyms + assert.equals = assert.equal; + assert.notEquals = assert.notEqual; + assert['null'] = assert.equal.bind(null, null); + assert.notNull = assert.notEqual.bind(null, null); + assert['undefined'] = assert.equal.bind(null, undefined); + assert.notUndefined = assert.notEqual.bind(null, undefined); + + // ES3 synonyms + assert.false_ = assert['false']; + assert.true_ = assert['true']; + + g.registerSuperFixture = registerSuperFixture; + g.test = test; + g.run_all = run_all; + g.fixture = fixture; +// g.repr = IMVU.repr; + g.AssertionError = AssertionError; + g.assert = assert; + g.test = test; + g.TEST_MAX_OUTPUT_SIZE = 1024; + + g.setTimeout = function(fn, time) { + if (time === 1 || time === 0){ + fn(); + return 0; + } + throw new AssertionError("Don't call setTimeout in tests. Use fakes."); + }; + + g.setInterval = function() { + throw new AssertionError("Don't call setInterval in tests. Use fakes."); + }; + + if (typeof process !== 'undefined') { + process.nextTick = function() { + throw new AssertionError("Don't call process.nextTick in tests. Use fakes."); + }; + } + + Math.random = function() { + throw new AssertionError("Don't call Math.random in tests. Use fakes."); + }; + + g.requestAnimationFrame = function() { + throw new AssertionError("Don't call requestAnimationFrame in tests. Use fakes."); + }; +//})(); + +// Emscripten runner starts all tests from this function. +// IMVU runner uses a separate runner & reporting mechanism. +function run_all_tests() { + function report_to_stdout(msg) { + if (msg.type == "test-complete") + console.log(msg.name + ": " + msg.verdict); + } + run_all(report_to_stdout); +} + +// Signal the embind test suite that it is being run from the Emscripten python test runner and not the +// IMVU test runner. +var INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER = 1; diff --git a/tests/embind/underscore-1.4.2.js b/tests/embind/underscore-1.4.2.js new file mode 100755 index 0000000000000..dd2740957a100 --- /dev/null +++ b/tests/embind/underscore-1.4.2.js @@ -0,0 +1,1200 @@ +// Underscore.js 1.4.2 +// http://underscorejs.org +// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore may be freely distributed under the MIT license. + +//(function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `global` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Establish the object that gets returned to break out of a loop iteration. + var breaker = {}; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var push = ArrayProto.push, + slice = ArrayProto.slice, + concat = ArrayProto.concat, + unshift = ArrayProto.unshift, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeForEach = ArrayProto.forEach, + nativeMap = ArrayProto.map, + nativeReduce = ArrayProto.reduce, + nativeReduceRight = ArrayProto.reduceRight, + nativeFilter = ArrayProto.filter, + nativeEvery = ArrayProto.every, + nativeSome = ArrayProto.some, + nativeIndexOf = ArrayProto.indexOf, + nativeLastIndexOf = ArrayProto.lastIndexOf, + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { + if (obj instanceof _) return obj; + if (!(this instanceof _)) return new _(obj); + this._wrapped = obj; + }; + + // Export the Underscore object for **Node.js**, with + // backwards-compatibility for the old `require()` API. If we're in + // the browser, add `_` as a global object via a string identifier, + // for Closure Compiler "advanced" mode. + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } else { + root['_'] = _; + } + + // Current version. + _.VERSION = '1.4.2'; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles objects with the built-in `forEach`, arrays, and raw objects. + // Delegates to **ECMAScript 5**'s native `forEach` if available. + var each = _.each = _.forEach = function(obj, iterator, context) { + if (obj == null) return; + if (nativeForEach && obj.forEach === nativeForEach) { + obj.forEach(iterator, context); + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + if (iterator.call(context, obj[i], i, obj) === breaker) return; + } + } else { + for (var key in obj) { + if (_.has(obj, key)) { + if (iterator.call(context, obj[key], key, obj) === breaker) return; + } + } + } + }; + + // Return the results of applying the iterator to each element. + // Delegates to **ECMAScript 5**'s native `map` if available. + _.map = _.collect = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); + each(obj, function(value, index, list) { + results[results.length] = iterator.call(context, value, index, list); + }); + return results; + }; + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. + _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduce && obj.reduce === nativeReduce) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); + } + each(obj, function(value, index, list) { + if (!initial) { + memo = value; + initial = true; + } else { + memo = iterator.call(context, memo, value, index, list); + } + }); + if (!initial) throw new TypeError('Reduce of empty array with no initial value'); + return memo; + }; + + // The right-associative version of reduce, also known as `foldr`. + // Delegates to **ECMAScript 5**'s native `reduceRight` if available. + _.reduceRight = _.foldr = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { + if (context) iterator = _.bind(iterator, context); + return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); + } + var length = obj.length; + if (length !== +length) { + var keys = _.keys(obj); + length = keys.length; + } + each(obj, function(value, index, list) { + index = keys ? keys[--length] : --length; + if (!initial) { + memo = obj[index]; + initial = true; + } else { + memo = iterator.call(context, memo, obj[index], index, list); + } + }); + if (!initial) throw new TypeError('Reduce of empty array with no initial value'); + return memo; + }; + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, iterator, context) { + var result; + any(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) { + result = value; + return true; + } + }); + return result; + }; + + // Return all the elements that pass a truth test. + // Delegates to **ECMAScript 5**'s native `filter` if available. + // Aliased as `select`. + _.filter = _.select = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); + each(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + each(obj, function(value, index, list) { + if (!iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Determine whether all of the elements match a truth test. + // Delegates to **ECMAScript 5**'s native `every` if available. + // Aliased as `all`. + _.every = _.all = function(obj, iterator, context) { + iterator || (iterator = _.identity); + var result = true; + if (obj == null) return result; + if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); + each(obj, function(value, index, list) { + if (!(result = result && iterator.call(context, value, index, list))) return breaker; + }); + return !!result; + }; + + // Determine if at least one element in the object matches a truth test. + // Delegates to **ECMAScript 5**'s native `some` if available. + // Aliased as `any`. + var any = _.some = _.any = function(obj, iterator, context) { + iterator || (iterator = _.identity); + var result = false; + if (obj == null) return result; + if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); + each(obj, function(value, index, list) { + if (result || (result = iterator.call(context, value, index, list))) return breaker; + }); + return !!result; + }; + + // Determine if the array or object contains a given value (using `===`). + // Aliased as `include`. + _.contains = _.include = function(obj, target) { + var found = false; + if (obj == null) return found; + if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; + found = any(obj, function(value) { + return value === target; + }); + return found; + }; + + // Invoke a method (with arguments) on every item in a collection. + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + return _.map(obj, function(value) { + return (_.isFunction(method) ? method : value[method]).apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, function(value){ return value[key]; }); + }; + + // Convenience version of a common use case of `filter`: selecting only objects + // with specific `key:value` pairs. + _.where = function(obj, attrs) { + if (_.isEmpty(attrs)) return []; + return _.filter(obj, function(value) { + for (var key in attrs) { + if (attrs[key] !== value[key]) return false; + } + return true; + }); + }; + + // Return the maximum element or (element-based computation). + // Can't optimize arrays of integers longer than 65,535 elements. + // See: https://bugs.webkit.org/show_bug.cgi?id=80797 + _.max = function(obj, iterator, context) { + if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { + return Math.max.apply(Math, obj); + } + if (!iterator && _.isEmpty(obj)) return -Infinity; + var result = {computed : -Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed >= result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iterator, context) { + if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { + return Math.min.apply(Math, obj); + } + if (!iterator && _.isEmpty(obj)) return Infinity; + var result = {computed : Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed < result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + // Shuffle an array. + _.shuffle = function(obj) { + var rand; + var index = 0; + var shuffled = []; + each(obj, function(value) { + rand = _.random(index++); + shuffled[index - 1] = shuffled[rand]; + shuffled[rand] = value; + }); + return shuffled; + }; + + // An internal function to generate lookup iterators. + var lookupIterator = function(value) { + return _.isFunction(value) ? value : function(obj){ return obj[value]; }; + }; + + // Sort the object's values by a criterion produced by an iterator. + _.sortBy = function(obj, value, context) { + var iterator = lookupIterator(value); + return _.pluck(_.map(obj, function(value, index, list) { + return { + value : value, + index : index, + criteria : iterator.call(context, value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria; + var b = right.criteria; + if (a !== b) { + if (a > b || a === void 0) return 1; + if (a < b || b === void 0) return -1; + } + return left.index < right.index ? -1 : 1; + }), 'value'); + }; + + // An internal function used for aggregate "group by" operations. + var group = function(obj, value, context, behavior) { + var result = {}; + var iterator = lookupIterator(value); + each(obj, function(value, index) { + var key = iterator.call(context, value, index, obj); + behavior(result, key, value); + }); + return result; + }; + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + _.groupBy = function(obj, value, context) { + return group(obj, value, context, function(result, key, value) { + (_.has(result, key) ? result[key] : (result[key] = [])).push(value); + }); + }; + + // Counts instances of an object that group by a certain criterion. Pass + // either a string attribute to count by, or a function that returns the + // criterion. + _.countBy = function(obj, value, context) { + return group(obj, value, context, function(result, key, value) { + if (!_.has(result, key)) result[key] = 0; + result[key]++; + }); + }; + + // Use a comparator function to figure out the smallest index at which + // an object should be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iterator, context) { + iterator = iterator == null ? _.identity : lookupIterator(iterator); + var value = iterator.call(context, obj); + var low = 0, high = array.length; + while (low < high) { + var mid = (low + high) >>> 1; + iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; + } + return low; + }; + + // Safely convert anything iterable into a real, live array. + _.toArray = function(obj) { + if (!obj) return []; + if (obj.length === +obj.length) return slice.call(obj); + return _.values(obj); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + return (obj.length === +obj.length) ? obj.length : _.keys(obj).length; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head` and `take`. The **guard** check + // allows it to work with `_.map`. + _.first = _.head = _.take = function(array, n, guard) { + return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; + }; + + // Returns everything but the last entry of the array. Especially useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. The **guard** check allows it to work with + // `_.map`. + _.initial = function(array, n, guard) { + return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); + }; + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. The **guard** check allows it to work with `_.map`. + _.last = function(array, n, guard) { + if ((n != null) && !guard) { + return slice.call(array, Math.max(array.length - n, 0)); + } else { + return array[array.length - 1]; + } + }; + + // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. + // Especially useful on the arguments object. Passing an **n** will return + // the rest N values in the array. The **guard** + // check allows it to work with `_.map`. + _.rest = _.tail = _.drop = function(array, n, guard) { + return slice.call(array, (n == null) || guard ? 1 : n); + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, function(value){ return !!value; }); + }; + + // Internal implementation of a recursive `flatten` function. + var flatten = function(input, shallow, output) { + each(input, function(value) { + if (_.isArray(value)) { + shallow ? push.apply(output, value) : flatten(value, shallow, output); + } else { + output.push(value); + } + }); + return output; + }; + + // Return a completely flattened version of an array. + _.flatten = function(array, shallow) { + return flatten(array, shallow, []); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted, iterator, context) { + var initial = iterator ? _.map(array, iterator, context) : array; + var results = []; + var seen = []; + each(initial, function(value, index) { + if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) { + seen.push(value); + results.push(array[index]); + } + }); + return results; + }; + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + _.union = function() { + return _.uniq(concat.apply(ArrayProto, arguments)); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. + _.intersection = function(array) { + var rest = slice.call(arguments, 1); + return _.filter(_.uniq(array), function(item) { + return _.every(rest, function(other) { + return _.indexOf(other, item) >= 0; + }); + }); + }; + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + _.difference = function(array) { + var rest = concat.apply(ArrayProto, slice.call(arguments, 1)); + return _.filter(array, function(value){ return !_.contains(rest, value); }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + var args = slice.call(arguments); + var length = _.max(_.pluck(args, 'length')); + var results = new Array(length); + for (var i = 0; i < length; i++) { + results[i] = _.pluck(args, "" + i); + } + return results; + }; + + // Converts lists into objects. Pass either a single array of `[key, value]` + // pairs, or two parallel arrays of the same length -- one of keys, and one of + // the corresponding values. + _.object = function(list, values) { + var result = {}; + for (var i = 0, l = list.length; i < l; i++) { + if (values) { + result[list[i]] = values[i]; + } else { + result[list[i][0]] = list[i][1]; + } + } + return result; + }; + + // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), + // we need this function. Return the position of the first occurrence of an + // item in an array, or -1 if the item is not included in the array. + // Delegates to **ECMAScript 5**'s native `indexOf` if available. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = function(array, item, isSorted) { + if (array == null) return -1; + var i = 0, l = array.length; + if (isSorted) { + if (typeof isSorted == 'number') { + i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted); + } else { + i = _.sortedIndex(array, item); + return array[i] === item ? i : -1; + } + } + if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); + for (; i < l; i++) if (array[i] === item) return i; + return -1; + }; + + // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. + _.lastIndexOf = function(array, item, from) { + if (array == null) return -1; + var hasIndex = from != null; + if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { + return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); + } + var i = (hasIndex ? from : array.length); + while (i--) if (array[i] === item) return i; + return -1; + }; + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (arguments.length <= 1) { + stop = start || 0; + start = 0; + } + step = arguments[2] || 1; + + var len = Math.max(Math.ceil((stop - start) / step), 0); + var idx = 0; + var range = new Array(len); + + while(idx < len) { + range[idx++] = start; + start += step; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Reusable constructor function for prototype setting. + var ctor = function(){}; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Binding with arguments is also known as `curry`. + // Delegates to **ECMAScript 5**'s native `Function.bind` if available. + // We check for `func.bind` first, to fail fast when `func` is undefined. + _.bind = function bind(func, context) { + var bound, args; + if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError; + args = slice.call(arguments, 2); + return bound = function() { + if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); + ctor.prototype = func.prototype; + var self = new ctor; + var result = func.apply(self, args.concat(slice.call(arguments))); + if (Object(result) === result) return result; + return self; + }; + }; + + // Bind all of an object's methods to that object. Useful for ensuring that + // all callbacks defined on an object belong to it. + _.bindAll = function(obj) { + var funcs = slice.call(arguments, 1); + if (funcs.length == 0) funcs = _.functions(obj); + each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memo = {}; + hasher || (hasher = _.identity); + return function() { + var key = hasher.apply(this, arguments); + return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); + }; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ return func.apply(null, args); }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = function(func) { + return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); + }; + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. + _.throttle = function(func, wait) { + var context, args, timeout, throttling, more, result; + var whenDone = _.debounce(function(){ more = throttling = false; }, wait); + return function() { + context = this; args = arguments; + var later = function() { + timeout = null; + if (more) { + result = func.apply(context, args); + } + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + throttling = true; + result = func.apply(context, args); + } + whenDone(); + return result; + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + _.debounce = function(func, wait, immediate) { + var timeout, result; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) result = func.apply(context, args); + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) result = func.apply(context, args); + return result; + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = function(func) { + var ran = false, memo; + return function() { + if (ran) return memo; + ran = true; + memo = func.apply(this, arguments); + func = null; + return memo; + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return function() { + var args = [func]; + push.apply(args, arguments); + return wrapper.apply(this, args); + }; + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var funcs = arguments; + return function() { + var args = arguments; + for (var i = funcs.length - 1; i >= 0; i--) { + args = [funcs[i].apply(this, args)]; + } + return args[0]; + }; + }; + + // Returns a function that will only be executed after being called N times. + _.after = function(times, func) { + if (times <= 0) return func(); + return function() { + if (--times < 1) { + return func.apply(this, arguments); + } + }; + }; + + // Object Functions + // ---------------- + + // Retrieve the names of an object's properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = nativeKeys || function(obj) { + if (obj !== Object(obj)) throw new TypeError('Invalid object'); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + var values = []; + for (var key in obj) if (_.has(obj, key)) values.push(obj[key]); + return values; + }; + + // Convert an object into a list of `[key, value]` pairs. + _.pairs = function(obj) { + var pairs = []; + for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]); + return pairs; + }; + + // Invert the keys and values of an object. The values must be serializable. + _.invert = function(obj) { + var result = {}; + for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key; + return result; + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Return a copy of the object only containing the whitelisted properties. + _.pick = function(obj) { + var copy = {}; + var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); + each(keys, function(key) { + if (key in obj) copy[key] = obj[key]; + }); + return copy; + }; + + // Return a copy of the object without the blacklisted properties. + _.omit = function(obj) { + var copy = {}; + var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); + for (var key in obj) { + if (!_.contains(keys, key)) copy[key] = obj[key]; + } + return copy; + }; + + // Fill in a given object with default properties. + _.defaults = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + if (obj[prop] == null) obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Internal recursive comparison function for `isEqual`. + var eq = function(a, b, aStack, bStack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. + if (a === b) return a !== 0 || 1 / a == 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) return a === b; + // Unwrap any wrapped objects. + if (a instanceof _) a = a._wrapped; + if (b instanceof _) b = b._wrapped; + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className != toString.call(b)) return false; + switch (className) { + // Strings, numbers, dates, and booleans are compared by value. + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return a == String(b); + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for + // other numeric values. + return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a == +b; + // RegExps are compared by their source patterns and flags. + case '[object RegExp]': + return a.source == b.source && + a.global == b.global && + a.multiline == b.multiline && + a.ignoreCase == b.ignoreCase; + } + if (typeof a != 'object' || typeof b != 'object') return false; + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + var length = aStack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (aStack[length] == a) return bStack[length] == b; + } + // Add the first object to the stack of traversed objects. + aStack.push(a); + bStack.push(b); + var size = 0, result = true; + // Recursively compare objects and arrays. + if (className == '[object Array]') { + // Compare array lengths to determine if a deep comparison is necessary. + size = a.length; + result = size == b.length; + if (result) { + // Deep compare the contents, ignoring non-numeric properties. + while (size--) { + if (!(result = eq(a[size], b[size], aStack, bStack))) break; + } + } + } else { + // Objects with different constructors are not equivalent, but `Object`s + // from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && + _.isFunction(bCtor) && (bCtor instanceof bCtor))) { + return false; + } + // Deep compare objects. + for (var key in a) { + if (_.has(a, key)) { + // Count the expected number of properties. + size++; + // Deep compare each member. + if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break; + } + } + // Ensure that both objects contain the same number of properties. + if (result) { + for (key in b) { + if (_.has(b, key) && !(size--)) break; + } + result = !size; + } + } + // Remove the first object from the stack of traversed objects. + aStack.pop(); + bStack.pop(); + return result; + }; + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + return eq(a, b, [], []); + }; + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + _.isEmpty = function(obj) { + if (obj == null) return true; + if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; + for (var key in obj) if (_.has(obj, key)) return false; + return true; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType === 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) == '[object Array]'; + }; + + // Is a given variable an object? + _.isObject = function(obj) { + return obj === Object(obj); + }; + + // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp. + each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) { + _['is' + name] = function(obj) { + return toString.call(obj) == '[object ' + name + ']'; + }; + }); + + // Define a fallback version of the method in browsers (ahem, IE), where + // there isn't any inspectable "Arguments" type. + if (!_.isArguments(arguments)) { + _.isArguments = function(obj) { + return !!(obj && _.has(obj, 'callee')); + }; + } + + // Optimize `isFunction` if appropriate. + if (typeof (/./) !== 'function') { + _.isFunction = function(obj) { + return typeof obj === 'function'; + }; + } + + // Is a given object a finite number? + _.isFinite = function(obj) { + return _.isNumber(obj) && isFinite(obj); + }; + + // Is the given value `NaN`? (NaN is the only number which does not equal itself). + _.isNaN = function(obj) { + return _.isNumber(obj) && obj != +obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Shortcut function for checking if an object has a given property directly + // on itself (in other words, not on a prototype). + _.has = function(obj, key) { + return hasOwnProperty.call(obj, key); + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iterators. + _.identity = function(value) { + return value; + }; + + // Run a function **n** times. + _.times = function(n, iterator, context) { + for (var i = 0; i < n; i++) iterator.call(context, i); + }; + + // Return a random integer between min and max (inclusive). + _.random = function(min, max) { + if (max == null) { + max = min; + min = 0; + } + return min + (0 | Math.random() * (max - min + 1)); + }; + + // List of HTML entities for escaping. + var entityMap = { + escape: { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '/': '/' + } + }; + entityMap.unescape = _.invert(entityMap.escape); + + // Regexes containing the keys and values listed immediately above. + var entityRegexes = { + escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'), + unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g') + }; + + // Functions for escaping and unescaping strings to/from HTML interpolation. + _.each(['escape', 'unescape'], function(method) { + _[method] = function(string) { + if (string == null) return ''; + return ('' + string).replace(entityRegexes[method], function(match) { + return entityMap[method][match]; + }); + }; + }); + + // If the value of the named property is a function then invoke it; + // otherwise, return it. + _.result = function(object, property) { + if (object == null) return null; + var value = object[property]; + return _.isFunction(value) ? value.call(object) : value; + }; + + // Add your own custom functions to the Underscore object. + _.mixin = function(obj) { + each(_.functions(obj), function(name){ + var func = _[name] = obj[name]; + _.prototype[name] = function() { + var args = [this._wrapped]; + push.apply(args, arguments); + return result.call(this, func.apply(_, args)); + }; + }); + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = idCounter++; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + source += + escape ? "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'" : + interpolate ? "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'" : + evaluate ? "';\n" + evaluate + "\n__p+='" : ''; + index = offset + match.length; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + var render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + // Add a "chain" function, which will delegate to the wrapper. + _.chain = function(obj) { + return _(obj).chain(); + }; + + // OOP + // --------------- + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + + // Helper function to continue chaining intermediate results. + var result = function(obj) { + return this._chain ? _(obj).chain() : obj; + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + var obj = this._wrapped; + method.apply(obj, arguments); + if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0]; + return result.call(this, obj); + }; + }); + + // Add all accessor Array functions to the wrapper. + each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + return result.call(this, method.apply(this._wrapped, arguments)); + }; + }); + + _.extend(_.prototype, { + + // Start chaining a wrapped Underscore object. + chain: function() { + this._chain = true; + return this; + }, + + // Extracts the result from a wrapped and chained object. + value: function() { + return this._wrapped; + } + + }); + +//}).call(this); diff --git a/tests/runner.py b/tests/runner.py index fd9f784268c9d..fa984f051f61e 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -10241,58 +10241,12 @@ def test_embind(self): print args, fail self.clear() try_delete(self.in_dir('a.out.js')) - Popen([PYTHON, EMCC, path_from_root('tests', 'embind', 'embind_test.cpp'), '--post-js', path_from_root('tests', 'embind', 'embind_test.js')] + args, stderr=PIPE if fail else None).communicate() + Popen([PYTHON, EMCC, path_from_root('tests', 'embind', 'embind_test.cpp'), '--post-js', path_from_root('tests', 'embind', 'underscore-1.4.2.js'), '--post-js', path_from_root('tests', 'embind', 'imvu_test_adapter.js'), '--post-js', path_from_root('tests', 'embind', 'embind.test.js')] + args, stderr=PIPE if fail else None).communicate() assert os.path.exists(self.in_dir('a.out.js')) == (not fail) if not fail: - output = run_js(self.in_dir('a.out.js')) - self.assertContained('''fixture: embind ---test: test value creation ---test: test passthrough ---test: test void return converts to undefined ---test: test booleans can be marshalled ---test: test convert double to unsigned ---test: test get length of array ---test: test add a bunch of things ---test: test sum array ---test: test strings ---test: test no memory leak when passing strings in by const reference -fixture: classes ---test: test class instance ---test: test class methods ---test: test can't call methods on deleted class instances ---test: test isinstance ---test: test can return class instances by value ---test: test can pass class instances to functions by reference ---test: test can access struct fields ---test: test can set struct fields ---test: test assignment returns value ---test: test assigning string to integer raises TypeError ---test: test can return tuples by value ---test: test tuples can contain tuples ---test: test can pass tuples by value ---test: test can return structs by value ---test: test can pass structs by value ---test: test can pass and return tuples in structs ---test: test can clone handles ---test: test can't clone if already deleted ---test: test moving handles is a clone+delete ---test: test StringHolder -fixture: embind enumerations ---test: test can compare enumeration values ---test: test repr includes enum value ---test: test instanceof ---test: test can pass and return enumeration values to functions -fixture: C++11 enum class ---test: test can compare enumeration values ---test: test repr includes enum value ---test: test instanceof ---test: test can pass and return enumeration values to functions -fixture: emval call tests ---test: test can call functions from C++ -fixture: interfaces ---test: test can wrap JS object in native interface ---test: test can pass arguments and return complicated values ---test: test can call interface methods that return nothing''', output) + output = run_js(self.in_dir('a.out.js'), stdout=PIPE, stderr=PIPE, full_output=True) + print >> sys.stderr, output + assert "FAIL" not in output def test_llvm_nativizer(self): try: From 8b1b35d8e34496a81967b2d08e2f7900111bba5e Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 1 Apr 2013 15:21:08 -0700 Subject: [PATCH 365/544] Move context generation/copying out of JavaScript and into C++, where we'll be able to do some cool things in the future. --- src/embind/embind.js | 53 ++++------ system/include/emscripten/bind.h | 167 +++++++++++++++---------------- 2 files changed, 98 insertions(+), 122 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index e0abe6f1d8391..f850c73f2c25c 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -386,26 +386,15 @@ function __embind_register_tuple(rawType, name, rawConstructor, rawDestructor) { }); } -function copyMemberPointer(memberPointer, memberPointerSize) { - var copy = _malloc(memberPointerSize); - if (!copy) { - throw new Error('Failed to allocate member pointer copy'); - } - _memcpy(copy, memberPointer, memberPointerSize); - return copy; -} - function __embind_register_tuple_element( rawTupleType, rawType, getter, setter, - memberPointerSize, - memberPointer + context ) { getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; - memberPointer = copyMemberPointer(memberPointer, memberPointerSize); var tupleType = requireRegisteredType(rawTupleType, 'tuple'); var index = tupleType.elements.length; @@ -416,11 +405,11 @@ function __embind_register_tuple_element( type = type[0]; tupleType.elements[index] = { read: function(ptr) { - return type.fromWireType(getter(ptr, memberPointer)); + return type.fromWireType(getter(context, ptr)); }, write: function(ptr, o) { var destructors = []; - setter(ptr, memberPointer, type.toWireType(destructors, o)); + setter(context, ptr, type.toWireType(destructors, o)); runDestructors(destructors); } }; @@ -432,29 +421,27 @@ function __embind_register_tuple_element_accessor( rawTupleType, rawElementType, rawStaticGetter, - getterSize, - getter, + getterContext, rawStaticSetter, - setterSize, - setter + setterContext ) { var tupleType = requireRegisteredType(rawTupleType, 'tuple'); rawStaticGetter = FUNCTION_TABLE[rawStaticGetter]; - getter = copyMemberPointer(getter, getterSize); rawStaticSetter = FUNCTION_TABLE[rawStaticSetter]; - setter = copyMemberPointer(setter, setterSize); whenDependentTypesAreResolved([], [rawElementType], function(elementType) { elementType = elementType[0]; tupleType.elements.push({ read: function(ptr) { - return elementType.fromWireType(rawStaticGetter(ptr, HEAP32[getter >> 2])); + return elementType.fromWireType(rawStaticGetter( + getterContext, + ptr)); }, write: function(ptr, o) { var destructors = []; rawStaticSetter( + setterContext, ptr, - HEAP32[setter >> 2], elementType.toWireType(destructors, o)); runDestructors(destructors); } @@ -512,24 +499,22 @@ function __embind_register_struct_field( rawFieldType, rawGetter, rawSetter, - memberPointerSize, - memberPointer + context ) { var structType = requireRegisteredType(rawStructType, 'struct'); fieldName = Pointer_stringify(fieldName); rawGetter = FUNCTION_TABLE[rawGetter]; rawSetter = FUNCTION_TABLE[rawSetter]; - memberPointer = copyMemberPointer(memberPointer, memberPointerSize); // TODO: test incomplete registration of value structs whenDependentTypesAreResolved([], [rawFieldType], function(fieldType) { fieldType = fieldType[0]; structType.fields[fieldName] = { read: function(ptr) { - return fieldType.fromWireType(rawGetter(ptr, memberPointer)); + return fieldType.fromWireType(rawGetter(context, ptr)); }, write: function(ptr, o) { var destructors = []; - rawSetter(ptr, memberPointer, fieldType.toWireType(destructors, o)); + rawSetter(context, ptr, fieldType.toWireType(destructors, o)); runDestructors(destructors); } }; @@ -989,13 +974,11 @@ function __embind_register_class_function( argCount, rawArgTypesAddr, // [ReturnType, ThisType, Args...] rawInvoker, - memberFunctionSize, - memberFunction + context ) { var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = Pointer_stringify(methodName); rawInvoker = FUNCTION_TABLE[rawInvoker]; - memberFunction = copyMemberPointer(memberFunction, memberFunctionSize); whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; @@ -1015,7 +998,7 @@ function __embind_register_class_function( var destructors = []; var args = new Array(argCount + 1); - args[0] = memberFunction; + args[0] = context; args[1] = argTypes[1].toWireType(destructors, this); for (var i = 2; i < argCount; ++i) { args[i] = argTypes[i].toWireType(destructors, arguments[i - 2]); @@ -1064,13 +1047,11 @@ function __embind_register_class_property( rawFieldType, getter, setter, - memberPointerSize, - memberPointer + context ) { fieldName = Pointer_stringify(fieldName); getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; - memberPointer = copyMemberPointer(memberPointer, memberPointerSize); whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; var humanName = classType.name + '.' + fieldName; @@ -1091,12 +1072,12 @@ function __embind_register_class_property( Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, { get: function() { var ptr = validateThis(this, classType, humanName + ' getter'); - return fieldType.fromWireType(getter(ptr, memberPointer)); + return fieldType.fromWireType(getter(context, ptr)); }, set: function(v) { var ptr = validateThis(this, classType, humanName + ' setter'); var destructors = []; - setter(ptr, memberPointer, fieldType.toWireType(destructors, v)); + setter(context, ptr, fieldType.toWireType(destructors, v)); runDestructors(destructors); }, enumerable: true diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 211c67c00583c..947f0b307e40d 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -73,18 +73,15 @@ namespace emscripten { TYPEID elementType, GenericFunction getter, GenericFunction setter, - size_t memberPointerSize, - void* memberPointer); + void* context); void _embind_register_tuple_element_accessor( TYPEID tupleType, TYPEID elementType, GenericFunction staticGetter, - size_t getterSize, - void* getter, + void* getterContext, GenericFunction staticSetter, - size_t setterSize, - void* setter); + void* setterContext); void _embind_register_struct( TYPEID structType, @@ -98,8 +95,7 @@ namespace emscripten { TYPEID fieldType, GenericFunction getter, GenericFunction setter, - size_t memberPointerSize, - void* memberPointer); + void* context); void _embind_register_smart_ptr( TYPEID pointerType, @@ -135,8 +131,7 @@ namespace emscripten { unsigned argCount, TYPEID argTypes[], GenericFunction invoker, - size_t memberFunctionSize, - void* memberFunction); + void* context); void _embind_register_class_property( TYPEID classType, @@ -144,8 +139,7 @@ namespace emscripten { TYPEID fieldType, GenericFunction getter, GenericFunction setter, - size_t memberPointerSize, - void* memberPointer); + void* context); void _embind_register_class_class_function( TYPEID classType, @@ -354,15 +348,15 @@ namespace emscripten { typedef typename MemberBinding::WireType WireType; static WireType getWire( - const ClassType& ptr, - const MemberPointer& field + const MemberPointer& field, + const ClassType& ptr ) { return MemberBinding::toWireType(ptr.*field); } static void setWire( - ClassType& ptr, const MemberPointer& field, + ClassType& ptr, WireType value ) { ptr.*field = MemberBinding::fromWireType(value); @@ -370,22 +364,31 @@ namespace emscripten { template static WireType propertyGet( - const ClassType& ptr, - const Getter& getter + const Getter& getter, + const ClassType& ptr ) { return MemberBinding::toWireType(getter(ptr)); } template static void propertySet( - ClassType& ptr, const Setter& setter, + ClassType& ptr, WireType value ) { setter(ptr, MemberBinding::fromWireType(value)); } }; + // TODO: This could do a reinterpret-cast if sizeof(T) === sizeof(void*) + template + inline void* getContext(const T& t) { + // not a leak because this is called once per binding + void* p = malloc(sizeof(T)); + assert(p); + memcpy(p, &t, sizeof(T)); + return p; + } } //////////////////////////////////////////////////////////////////////////////// @@ -396,79 +399,75 @@ namespace emscripten { class value_tuple { public: value_tuple(const char* name) { - internal::_embind_register_tuple( - internal::TypeID::get(), + using namespace internal; + _embind_register_tuple( + TypeID::get(), name, - reinterpret_cast(&internal::raw_constructor), - reinterpret_cast(&internal::raw_destructor)); + reinterpret_cast(&raw_constructor), + reinterpret_cast(&raw_destructor)); } template value_tuple& element(ElementType ClassType::*field) { - internal::_embind_register_tuple_element( - internal::TypeID::get(), - internal::TypeID::get(), - reinterpret_cast(&internal::MemberAccess::getWire), - reinterpret_cast(&internal::MemberAccess::setWire), - sizeof(field), - &field); - + using namespace internal; + _embind_register_tuple_element( + TypeID::get(), + TypeID::get(), + reinterpret_cast(&MemberAccess::getWire), + reinterpret_cast(&MemberAccess::setWire), + getContext(field)); return *this; } template value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, ElementType)) { - internal::_embind_register_tuple_element_accessor( - internal::TypeID::get(), - internal::TypeID::get(), - reinterpret_cast(&internal::MemberAccess::template propertyGet), - sizeof(getter), - &getter, - reinterpret_cast(&internal::MemberAccess::template propertySet), - sizeof(setter), - &setter); + using namespace internal; + _embind_register_tuple_element_accessor( + TypeID::get(), + TypeID::get(), + reinterpret_cast(&MemberAccess::template propertyGet), + getContext(getter), + reinterpret_cast(&MemberAccess::template propertySet), + getContext(setter)); return *this; } template value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, const ElementType&)) { - internal::_embind_register_tuple_element_accessor( - internal::TypeID::get(), - internal::TypeID::get(), - reinterpret_cast(&internal::MemberAccess::template propertyGet), - sizeof(getter), - &getter, - reinterpret_cast(&internal::MemberAccess::template propertySet), - sizeof(setter), - &setter); + using namespace internal; + _embind_register_tuple_element_accessor( + TypeID::get(), + TypeID::get(), + reinterpret_cast(&MemberAccess::template propertyGet), + getContext(getter), + reinterpret_cast(&MemberAccess::template propertySet), + getContext(setter)); return *this; } template value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, const ElementType&&)) { - internal::_embind_register_tuple_element_accessor( - internal::TypeID::get(), - internal::TypeID::get(), - reinterpret_cast(&internal::MemberAccess::template propertyGet), - sizeof(getter), - &getter, - reinterpret_cast(&internal::MemberAccess::template propertySet), - sizeof(setter), - &setter); + using namespace internal; + _embind_register_tuple_element_accessor( + TypeID::get(), + TypeID::get(), + reinterpret_cast(&MemberAccess::template propertyGet), + getContext(getter), + reinterpret_cast(&MemberAccess::template propertySet), + getContext(setter)); return *this; } template value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, ElementType&)) { - internal::_embind_register_tuple_element_accessor( - internal::TypeID::get(), - internal::TypeID::get(), - reinterpret_cast(&internal::MemberAccess::template propertyGet), - sizeof(getter), - &getter, - reinterpret_cast(&internal::MemberAccess::template propertySet), - sizeof(setter), - &setter); + using namespace internal; + _embind_register_tuple_element_accessor( + TypeID::get(), + TypeID::get(), + reinterpret_cast(&MemberAccess::template propertyGet), + getContext(getter), + reinterpret_cast(&MemberAccess::template propertySet), + getContext(setter)); return *this; } }; @@ -481,24 +480,24 @@ namespace emscripten { class value_struct { public: value_struct(const char* name) { - internal::_embind_register_struct( - internal::TypeID::get(), + using namespace internal; + _embind_register_struct( + TypeID::get(), name, - reinterpret_cast(&internal::raw_constructor), - reinterpret_cast(&internal::raw_destructor)); + reinterpret_cast(&raw_constructor), + reinterpret_cast(&raw_destructor)); } template value_struct& field(const char* fieldName, FieldType ClassType::*field) { - internal::_embind_register_struct_field( - internal::TypeID::get(), + using namespace internal; + _embind_register_struct_field( + TypeID::get(), fieldName, - internal::TypeID::get(), - reinterpret_cast(&internal::MemberAccess::getWire), - reinterpret_cast(&internal::MemberAccess::setWire), - sizeof(field), - &field); - + TypeID::get(), + reinterpret_cast(&MemberAccess::getWire), + reinterpret_cast(&MemberAccess::setWire), + getContext(field)); return *this; } }; @@ -783,8 +782,7 @@ namespace emscripten { args.count, args.types, reinterpret_cast(&MethodInvoker::invoke), - sizeof(memberFunction), - &memberFunction); + getContext(memberFunction)); return *this; } @@ -799,8 +797,7 @@ namespace emscripten { args.count, args.types, reinterpret_cast(&MethodInvoker::invoke), - sizeof(memberFunction), - &memberFunction); + getContext(memberFunction)); return *this; } @@ -815,8 +812,7 @@ namespace emscripten { args.count, args.types, reinterpret_cast(&FunctionInvoker::invoke), - sizeof(function), - &function); + getContext(function)); return *this; } @@ -830,8 +826,7 @@ namespace emscripten { TypeID::get(), reinterpret_cast(&MemberAccess::getWire), reinterpret_cast(&MemberAccess::setWire), - sizeof(field), - &field); + getContext(field)); return *this; } From e30dd3017a318d1f5862bd3688679c687c66d621 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 1 Apr 2013 17:42:50 -0700 Subject: [PATCH 366/544] Restructure and generalize tuple accessors. --- src/embind/embind.js | 28 ++++++++------- system/include/emscripten/bind.h | 60 ++++++++------------------------ 2 files changed, 31 insertions(+), 57 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index f850c73f2c25c..845bf98bb5f77 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -419,30 +419,34 @@ function __embind_register_tuple_element( function __embind_register_tuple_element_accessor( rawTupleType, - rawElementType, - rawStaticGetter, + getterReturnType, + getter, getterContext, - rawStaticSetter, + setterArgumentType, + setter, setterContext ) { var tupleType = requireRegisteredType(rawTupleType, 'tuple'); - rawStaticGetter = FUNCTION_TABLE[rawStaticGetter]; - rawStaticSetter = FUNCTION_TABLE[rawStaticSetter]; + getter = FUNCTION_TABLE[getter]; + setter = FUNCTION_TABLE[setter]; - whenDependentTypesAreResolved([], [rawElementType], function(elementType) { - elementType = elementType[0]; + // TODO: test incomplete registration of value tuples + whenDependentTypesAreResolved([], [getterReturnType, setterArgumentType], function(types) { + var getterReturnType = types[0]; + var setterArgumentType = types[1]; tupleType.elements.push({ read: function(ptr) { - return elementType.fromWireType(rawStaticGetter( - getterContext, - ptr)); + return getterReturnType.fromWireType( + getter( + getterContext, + ptr)); }, write: function(ptr, o) { var destructors = []; - rawStaticSetter( + setter( setterContext, ptr, - elementType.toWireType(destructors, o)); + setterArgumentType.toWireType(destructors, o)); runDestructors(destructors); } }); diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 947f0b307e40d..a002ca2395b41 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -77,9 +77,10 @@ namespace emscripten { void _embind_register_tuple_element_accessor( TYPEID tupleType, - TYPEID elementType, + TYPEID getterReturnType, GenericFunction staticGetter, void* getterContext, + TYPEID setterArgumentType, GenericFunction staticSetter, void* setterContext); @@ -419,54 +420,23 @@ namespace emscripten { return *this; } - template - value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, ElementType)) { - using namespace internal; - _embind_register_tuple_element_accessor( - TypeID::get(), - TypeID::get(), - reinterpret_cast(&MemberAccess::template propertyGet), - getContext(getter), - reinterpret_cast(&MemberAccess::template propertySet), - getContext(setter)); - return *this; - } - - template - value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, const ElementType&)) { - using namespace internal; - _embind_register_tuple_element_accessor( - TypeID::get(), - TypeID::get(), - reinterpret_cast(&MemberAccess::template propertyGet), - getContext(getter), - reinterpret_cast(&MemberAccess::template propertySet), - getContext(setter)); - return *this; - } - - template - value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, const ElementType&&)) { - using namespace internal; - _embind_register_tuple_element_accessor( - TypeID::get(), - TypeID::get(), - reinterpret_cast(&MemberAccess::template propertyGet), - getContext(getter), - reinterpret_cast(&MemberAccess::template propertySet), - getContext(setter)); - return *this; - } - - template - value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, ElementType&)) { + template + value_tuple& element( + GetterReturnType (*getter)(const ClassType&), + void (*setter)(ClassType&, SetterArgumentType) + ) { using namespace internal; _embind_register_tuple_element_accessor( TypeID::get(), - TypeID::get(), - reinterpret_cast(&MemberAccess::template propertyGet), + TypeID::get(), + reinterpret_cast( + &MemberAccess + ::template propertyGet), getContext(getter), - reinterpret_cast(&MemberAccess::template propertySet), + TypeID::get(), + reinterpret_cast( + &MemberAccess + ::template propertySet), getContext(setter)); return *this; } From de48fdc5b028df627b7070c17d37479654f71a13 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 1 Apr 2013 17:54:55 -0700 Subject: [PATCH 367/544] Further generalize support for tuple elements, and in the meantime, fix a bug that made it into one variant of the function but not the other... --- src/embind/embind.js | 38 +++++--------------------------- system/include/emscripten/bind.h | 17 ++++++-------- 2 files changed, 12 insertions(+), 43 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 845bf98bb5f77..3daa4b0186a51 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -387,37 +387,6 @@ function __embind_register_tuple(rawType, name, rawConstructor, rawDestructor) { } function __embind_register_tuple_element( - rawTupleType, - rawType, - getter, - setter, - context -) { - getter = FUNCTION_TABLE[getter]; - setter = FUNCTION_TABLE[setter]; - var tupleType = requireRegisteredType(rawTupleType, 'tuple'); - - var index = tupleType.elements.length; - tupleType.elements.push(undefined); - - // TODO: test incomplete registration of value tuples - whenDependentTypesAreResolved([], [rawType], function(type) { - type = type[0]; - tupleType.elements[index] = { - read: function(ptr) { - return type.fromWireType(getter(context, ptr)); - }, - write: function(ptr, o) { - var destructors = []; - setter(context, ptr, type.toWireType(destructors, o)); - runDestructors(destructors); - } - }; - return []; - }); -} - -function __embind_register_tuple_element_accessor( rawTupleType, getterReturnType, getter, @@ -430,11 +399,14 @@ function __embind_register_tuple_element_accessor( getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; + var index = tupleType.elements.length; + tupleType.elements.push(undefined); + // TODO: test incomplete registration of value tuples whenDependentTypesAreResolved([], [getterReturnType, setterArgumentType], function(types) { var getterReturnType = types[0]; var setterArgumentType = types[1]; - tupleType.elements.push({ + tupleType.elements[index] = { read: function(ptr) { return getterReturnType.fromWireType( getter( @@ -449,7 +421,7 @@ function __embind_register_tuple_element_accessor( setterArgumentType.toWireType(destructors, o)); runDestructors(destructors); } - }); + }; return []; }); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index a002ca2395b41..a5530744b756e 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -69,13 +69,6 @@ namespace emscripten { GenericFunction destructor); void _embind_register_tuple_element( - TYPEID tupleType, - TYPEID elementType, - GenericFunction getter, - GenericFunction setter, - void* context); - - void _embind_register_tuple_element_accessor( TYPEID tupleType, TYPEID getterReturnType, GenericFunction staticGetter, @@ -414,8 +407,12 @@ namespace emscripten { _embind_register_tuple_element( TypeID::get(), TypeID::get(), - reinterpret_cast(&MemberAccess::getWire), - reinterpret_cast(&MemberAccess::setWire), + reinterpret_cast( + &MemberAccess::getWire), + getContext(field), + TypeID::get(), + reinterpret_cast( + &MemberAccess::setWire), getContext(field)); return *this; } @@ -426,7 +423,7 @@ namespace emscripten { void (*setter)(ClassType&, SetterArgumentType) ) { using namespace internal; - _embind_register_tuple_element_accessor( + _embind_register_tuple_element( TypeID::get(), TypeID::get(), reinterpret_cast( From e5af621a189f729d8c1513f739a6a085adf39842 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 1 Apr 2013 18:47:55 -0700 Subject: [PATCH 368/544] Generalize support for struct fields --- src/embind/embind.js | 29 +++++++++++--------- system/include/emscripten/bind.h | 45 ++++++++++++++++++++++++++------ tests/embind/embind_test.cpp | 10 ++++++- 3 files changed, 63 insertions(+), 21 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 3daa4b0186a51..16e29d9e24f40 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -470,27 +470,32 @@ function __embind_register_struct( } function __embind_register_struct_field( - rawStructType, + structType, fieldName, - rawFieldType, - rawGetter, - rawSetter, - context + getterReturnType, + getter, + getterContext, + setterArgumentType, + setter, + setterContext ) { - var structType = requireRegisteredType(rawStructType, 'struct'); + structType = requireRegisteredType(structType, 'struct'); fieldName = Pointer_stringify(fieldName); - rawGetter = FUNCTION_TABLE[rawGetter]; - rawSetter = FUNCTION_TABLE[rawSetter]; + getter = FUNCTION_TABLE[getter]; + setter = FUNCTION_TABLE[setter]; + // TODO: test incomplete registration of value structs - whenDependentTypesAreResolved([], [rawFieldType], function(fieldType) { - fieldType = fieldType[0]; + whenDependentTypesAreResolved([], [getterReturnType, setterArgumentType], function(types) { + var getterReturnType = types[0]; + var setterArgumentType = types[1]; structType.fields[fieldName] = { read: function(ptr) { - return fieldType.fromWireType(rawGetter(context, ptr)); + return getterReturnType.fromWireType( + getter(getterContext, ptr)); }, write: function(ptr, o) { var destructors = []; - rawSetter(context, ptr, fieldType.toWireType(destructors, o)); + setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o)); runDestructors(destructors); } }; diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index a5530744b756e..fe0c971196273 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -71,25 +71,27 @@ namespace emscripten { void _embind_register_tuple_element( TYPEID tupleType, TYPEID getterReturnType, - GenericFunction staticGetter, + GenericFunction getter, void* getterContext, TYPEID setterArgumentType, - GenericFunction staticSetter, + GenericFunction setter, void* setterContext); void _embind_register_struct( TYPEID structType, - const char* name, + const char* fieldName, GenericFunction constructor, GenericFunction destructor); void _embind_register_struct_field( TYPEID structType, - const char* name, - TYPEID fieldType, + const char* fieldName, + TYPEID getterReturnType, GenericFunction getter, + void* getterContext, + TYPEID setterArgumentType, GenericFunction setter, - void* context); + void* setterContext); void _embind_register_smart_ptr( TYPEID pointerType, @@ -462,11 +464,38 @@ namespace emscripten { TypeID::get(), fieldName, TypeID::get(), - reinterpret_cast(&MemberAccess::getWire), - reinterpret_cast(&MemberAccess::setWire), + reinterpret_cast( + &MemberAccess::getWire), + getContext(field), + TypeID::get(), + reinterpret_cast( + &MemberAccess::setWire), getContext(field)); return *this; } + + template + value_struct& field( + const char* fieldName, + GetterReturnType (*getter)(const ClassType&), + void (*setter)(ClassType&, SetterArgumentType) + ) { + using namespace internal; + _embind_register_struct_field( + TypeID::get(), + fieldName, + TypeID::get(), + reinterpret_cast( + &MemberAccess + ::template propertyGet), + getContext(getter), + TypeID::get(), + reinterpret_cast( + &MemberAccess + ::template propertySet), + getContext(setter)); + return *this; + } }; //////////////////////////////////////////////////////////////////////////////// diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index e9feccfef5b5c..156c86808a05d 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -758,6 +758,14 @@ struct StructVector { float x, y, z; }; +float readStructVectorZ(const StructVector& v) { + return v.z; +} + +void writeStructVectorZ(StructVector& v, float z) { + v.z = z; +} + StructVector emval_test_return_StructVector() { StructVector v; v.x = 1; @@ -1354,7 +1362,7 @@ EMSCRIPTEN_BINDINGS(tests) { value_struct("StructVector") .field("x", &StructVector::x) .field("y", &StructVector::y) - .field("z", &StructVector::z) + .field("z", &readStructVectorZ, &writeStructVectorZ) ; function("emval_test_return_StructVector", &emval_test_return_StructVector); From ecb01ee4b190a7351e8240df103614e705540f90 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 1 Apr 2013 19:13:17 -0700 Subject: [PATCH 369/544] Support accessing value struct and tuple fields and elements via base class pointers. --- system/include/emscripten/bind.h | 72 ++++++++++++++++++++------------ tests/embind/embind_test.cpp | 32 +++++++------- 2 files changed, 61 insertions(+), 43 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index fe0c971196273..1828d95c1df95 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -337,12 +337,13 @@ namespace emscripten { } }; - template + template struct MemberAccess { - typedef MemberType ClassType::*MemberPointer; + typedef MemberType InstanceType::*MemberPointer; typedef internal::BindingType MemberBinding; typedef typename MemberBinding::WireType WireType; + template static WireType getWire( const MemberPointer& field, const ClassType& ptr @@ -350,6 +351,7 @@ namespace emscripten { return MemberBinding::toWireType(ptr.*field); } + template static void setWire( const MemberPointer& field, ClassType& ptr, @@ -357,6 +359,12 @@ namespace emscripten { ) { ptr.*field = MemberBinding::fromWireType(value); } + }; + + template + struct PropertyAccess { + typedef internal::BindingType MemberBinding; + typedef typename MemberBinding::WireType WireType; template static WireType propertyGet( @@ -403,39 +411,45 @@ namespace emscripten { reinterpret_cast(&raw_destructor)); } - template - value_tuple& element(ElementType ClassType::*field) { + template + value_tuple& element(ElementType InstanceType::*field) { using namespace internal; _embind_register_tuple_element( TypeID::get(), TypeID::get(), reinterpret_cast( - &MemberAccess::getWire), + &MemberAccess + ::template getWire), getContext(field), TypeID::get(), reinterpret_cast( - &MemberAccess::setWire), + &MemberAccess + ::template setWire), getContext(field)); return *this; } - template + template< + typename GetterReturnType, + typename GetterThisType, + typename SetterArgumentType, + typename SetterThisType> value_tuple& element( - GetterReturnType (*getter)(const ClassType&), - void (*setter)(ClassType&, SetterArgumentType) + GetterReturnType (*getter)(const GetterThisType&), + void (*setter)(SetterThisType&, SetterArgumentType) ) { using namespace internal; _embind_register_tuple_element( TypeID::get(), TypeID::get(), reinterpret_cast( - &MemberAccess - ::template propertyGet), + &PropertyAccess + ::template propertyGet), getContext(getter), TypeID::get(), reinterpret_cast( - &MemberAccess - ::template propertySet), + &PropertyAccess + ::template propertySet), getContext(setter)); return *this; } @@ -457,28 +471,34 @@ namespace emscripten { reinterpret_cast(&raw_destructor)); } - template - value_struct& field(const char* fieldName, FieldType ClassType::*field) { + template + value_struct& field(const char* fieldName, FieldType InstanceType::*field) { using namespace internal; _embind_register_struct_field( TypeID::get(), fieldName, TypeID::get(), reinterpret_cast( - &MemberAccess::getWire), + &MemberAccess + ::template getWire), getContext(field), TypeID::get(), reinterpret_cast( - &MemberAccess::setWire), + &MemberAccess + ::template setWire), getContext(field)); return *this; } - template + template< + typename GetterReturnType, + typename GetterThisType, + typename SetterArgumentType, + typename SetterThisType> value_struct& field( const char* fieldName, - GetterReturnType (*getter)(const ClassType&), - void (*setter)(ClassType&, SetterArgumentType) + GetterReturnType (*getter)(const GetterThisType&), + void (*setter)(SetterThisType&, SetterArgumentType) ) { using namespace internal; _embind_register_struct_field( @@ -486,13 +506,13 @@ namespace emscripten { fieldName, TypeID::get(), reinterpret_cast( - &MemberAccess - ::template propertyGet), + &PropertyAccess + ::template propertyGet), getContext(getter), TypeID::get(), reinterpret_cast( - &MemberAccess - ::template propertySet), + &PropertyAccess + ::template propertySet), getContext(setter)); return *this; } @@ -820,8 +840,8 @@ namespace emscripten { TypeID::get(), fieldName, TypeID::get(), - reinterpret_cast(&MemberAccess::getWire), - reinterpret_cast(&MemberAccess::setWire), + reinterpret_cast(&MemberAccess::template getWire), + reinterpret_cast(&MemberAccess::template setWire), getContext(field)); return *this; } diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 156c86808a05d..229d30d1644fc 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -720,15 +720,25 @@ std::map embind_test_get_string_int_map() { return m; }; -struct TupleVector { +struct Vector { float x, y, z; }; -float readTupleVectorZ(const TupleVector& v) { +struct DummyDataToTestPointerAdjustment { + std::string dummy; +}; + +struct TupleVector : DummyDataToTestPointerAdjustment, Vector { +}; + +struct StructVector : DummyDataToTestPointerAdjustment, Vector { +}; + +float readVectorZ(const Vector& v) { return v.z; } -void writeTupleVectorZ(TupleVector& v, float z) { +void writeVectorZ(Vector& v, float z) { v.z = z; } @@ -754,18 +764,6 @@ TupleVectorTuple emval_test_return_TupleVectorTuple() { return cvt; } -struct StructVector { - float x, y, z; -}; - -float readStructVectorZ(const StructVector& v) { - return v.z; -} - -void writeStructVectorZ(StructVector& v, float z) { - v.z = z; -} - StructVector emval_test_return_StructVector() { StructVector v; v.x = 1; @@ -1347,7 +1345,7 @@ EMSCRIPTEN_BINDINGS(tests) { .element(&TupleVector::x) .element(&TupleVector::y) //.element(&TupleVector::z) - .element(&readTupleVectorZ, &writeTupleVectorZ) + .element(&readVectorZ, &writeVectorZ) ; function("emval_test_return_TupleVector", &emval_test_return_TupleVector); @@ -1362,7 +1360,7 @@ EMSCRIPTEN_BINDINGS(tests) { value_struct("StructVector") .field("x", &StructVector::x) .field("y", &StructVector::y) - .field("z", &readStructVectorZ, &writeStructVectorZ) + .field("z", &readVectorZ, &writeVectorZ) ; function("emval_test_return_StructVector", &emval_test_return_StructVector); From fbcb6a4b34c0d0e4b16cbcdfccdb11a9e3a6b080 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 1 Apr 2013 19:44:01 -0700 Subject: [PATCH 370/544] add value_struct and value_tuple support for member function getters and setters. --- system/include/emscripten/bind.h | 81 +++++++++++++++++++++++++++++--- tests/embind/embind_test.cpp | 12 +++-- 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 1828d95c1df95..6e420a2936d4e 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -367,21 +367,38 @@ namespace emscripten { typedef typename MemberBinding::WireType WireType; template - static WireType propertyGet( + static WireType getByFunction( const Getter& getter, const ClassType& ptr ) { return MemberBinding::toWireType(getter(ptr)); } + template + static WireType getByMemberFunction( + const Getter& getter, + const ClassType& ptr + ) { + return MemberBinding::toWireType((ptr.*getter)()); + } + template - static void propertySet( + static void setByFunction( const Setter& setter, ClassType& ptr, WireType value ) { setter(ptr, MemberBinding::fromWireType(value)); } + + template + static void setByMemberFunction( + const Setter& setter, + ClassType& ptr, + WireType value + ) { + (ptr.*setter)(MemberBinding::fromWireType(value)); + } }; // TODO: This could do a reinterpret-cast if sizeof(T) === sizeof(void*) @@ -429,6 +446,31 @@ namespace emscripten { return *this; } + template< + typename GetterReturnType, + typename GetterThisType, + typename SetterArgumentType, + typename SetterThisType> + value_tuple& element( + GetterReturnType (GetterThisType::*getter)() const, + void (SetterThisType::*setter)(SetterArgumentType) + ) { + using namespace internal; + _embind_register_tuple_element( + TypeID::get(), + TypeID::get(), + reinterpret_cast( + &PropertyAccess + ::template getByMemberFunction), + getContext(getter), + TypeID::get(), + reinterpret_cast( + &PropertyAccess + ::template setByMemberFunction), + getContext(setter)); + return *this; + } + template< typename GetterReturnType, typename GetterThisType, @@ -444,12 +486,12 @@ namespace emscripten { TypeID::get(), reinterpret_cast( &PropertyAccess - ::template propertyGet), + ::template getByFunction), getContext(getter), TypeID::get(), reinterpret_cast( &PropertyAccess - ::template propertySet), + ::template setByFunction), getContext(setter)); return *this; } @@ -490,6 +532,33 @@ namespace emscripten { return *this; } + template< + typename GetterReturnType, + typename GetterThisType, + typename SetterArgumentType, + typename SetterThisType> + value_struct& field( + const char* fieldName, + GetterReturnType (GetterThisType::*getter)() const, + void (SetterThisType::*setter)(SetterArgumentType) + ) { + using namespace internal; + _embind_register_struct_field( + TypeID::get(), + fieldName, + TypeID::get(), + reinterpret_cast( + &PropertyAccess + ::template getByMemberFunction), + getContext(getter), + TypeID::get(), + reinterpret_cast( + &PropertyAccess + ::template setByMemberFunction), + getContext(setter)); + return *this; + } + template< typename GetterReturnType, typename GetterThisType, @@ -507,12 +576,12 @@ namespace emscripten { TypeID::get(), reinterpret_cast( &PropertyAccess - ::template propertyGet), + ::template getByFunction), getContext(getter), TypeID::get(), reinterpret_cast( &PropertyAccess - ::template propertySet), + ::template setByFunction), getContext(setter)); return *this; } diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 229d30d1644fc..470309aa2b8cd 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -722,6 +722,13 @@ std::map embind_test_get_string_int_map() { struct Vector { float x, y, z; + + float getY() const { + return y; + } + void setY(float _y) { + y = _y; + } }; struct DummyDataToTestPointerAdjustment { @@ -1343,8 +1350,7 @@ EMSCRIPTEN_BINDINGS(tests) { value_tuple("TupleVector") .element(&TupleVector::x) - .element(&TupleVector::y) - //.element(&TupleVector::z) + .element(&Vector::getY, &Vector::setY) .element(&readVectorZ, &writeVectorZ) ; @@ -1359,7 +1365,7 @@ EMSCRIPTEN_BINDINGS(tests) { value_struct("StructVector") .field("x", &StructVector::x) - .field("y", &StructVector::y) + .field("y", &Vector::getY, &Vector::setY) .field("z", &readVectorZ, &writeVectorZ) ; From def5681c4f191c5e273765624b200619a50cf805 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 2 Apr 2013 02:24:21 -0700 Subject: [PATCH 371/544] Generalize and support mix-and-match member/non-member getter/setter for value types. --- system/include/emscripten/bind.h | 223 ++++++++++++++----------------- 1 file changed, 97 insertions(+), 126 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 6e420a2936d4e..3161289d67ff2 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -361,55 +361,93 @@ namespace emscripten { } }; - template - struct PropertyAccess { - typedef internal::BindingType MemberBinding; - typedef typename MemberBinding::WireType WireType; + // TODO: This could do a reinterpret-cast if sizeof(T) === sizeof(void*) + template + inline void* getContext(const T& t) { + // not a leak because this is called once per binding + void* p = malloc(sizeof(T)); + assert(p); + memcpy(p, &t, sizeof(T)); + return p; + } - template - static WireType getByFunction( - const Getter& getter, - const ClassType& ptr - ) { - return MemberBinding::toWireType(getter(ptr)); + template + struct GetterPolicy; + + template + struct GetterPolicy { + typedef GetterReturnType ReturnType; + typedef GetterReturnType (GetterThisType::*Context)() const; + + typedef internal::BindingType Binding; + typedef typename Binding::WireType WireType; + + template + static WireType get(const Context& context, const ClassType& ptr) { + return Binding::toWireType((ptr.*context)()); } - template - static WireType getByMemberFunction( - const Getter& getter, - const ClassType& ptr - ) { - return MemberBinding::toWireType((ptr.*getter)()); + static void* getContext(Context context) { + return internal::getContext(context); } + }; - template - static void setByFunction( - const Setter& setter, - ClassType& ptr, - WireType value - ) { - setter(ptr, MemberBinding::fromWireType(value)); + template + struct GetterPolicy { + typedef GetterReturnType ReturnType; + typedef GetterReturnType (*Context)(const GetterThisType&); + + typedef internal::BindingType Binding; + typedef typename Binding::WireType WireType; + + template + static WireType get(const Context& context, const ClassType& ptr) { + return Binding::toWireType(context(ptr)); } - template - static void setByMemberFunction( - const Setter& setter, - ClassType& ptr, - WireType value - ) { - (ptr.*setter)(MemberBinding::fromWireType(value)); + static void* getContext(Context context) { + return internal::getContext(context); } }; - // TODO: This could do a reinterpret-cast if sizeof(T) === sizeof(void*) template - inline void* getContext(const T& t) { - // not a leak because this is called once per binding - void* p = malloc(sizeof(T)); - assert(p); - memcpy(p, &t, sizeof(T)); - return p; - } + struct SetterPolicy; + + template + struct SetterPolicy { + typedef SetterArgumentType ArgumentType; + typedef void (SetterThisType::*Context)(SetterArgumentType); + + typedef internal::BindingType Binding; + typedef typename Binding::WireType WireType; + + template + static void set(const Context& context, ClassType& ptr, WireType wt) { + (ptr.*context)(Binding::fromWireType(wt)); + } + + static void* getContext(Context context) { + return internal::getContext(context); + } + }; + + template + struct SetterPolicy { + typedef SetterArgumentType ArgumentType; + typedef void (*Context)(SetterThisType&, SetterArgumentType); + + typedef internal::BindingType Binding; + typedef typename Binding::WireType WireType; + + template + static void set(const Context& context, ClassType& ptr, WireType wt) { + context(ptr, Binding::fromWireType(wt)); + } + + static void* getContext(Context context) { + return internal::getContext(context); + } + }; } //////////////////////////////////////////////////////////////////////////////// @@ -446,55 +484,21 @@ namespace emscripten { return *this; } - template< - typename GetterReturnType, - typename GetterThisType, - typename SetterArgumentType, - typename SetterThisType> - value_tuple& element( - GetterReturnType (GetterThisType::*getter)() const, - void (SetterThisType::*setter)(SetterArgumentType) - ) { + template + value_tuple& element(Getter getter, Setter setter) { using namespace internal; + typedef GetterPolicy GP; + typedef SetterPolicy SP; _embind_register_tuple_element( TypeID::get(), - TypeID::get(), - reinterpret_cast( - &PropertyAccess - ::template getByMemberFunction), - getContext(getter), - TypeID::get(), - reinterpret_cast( - &PropertyAccess - ::template setByMemberFunction), - getContext(setter)); + TypeID::get(), + reinterpret_cast(&GP::template get), + GP::getContext(getter), + TypeID::get(), + reinterpret_cast(&SP::template set), + SP::getContext(setter)); return *this; } - - template< - typename GetterReturnType, - typename GetterThisType, - typename SetterArgumentType, - typename SetterThisType> - value_tuple& element( - GetterReturnType (*getter)(const GetterThisType&), - void (*setter)(SetterThisType&, SetterArgumentType) - ) { - using namespace internal; - _embind_register_tuple_element( - TypeID::get(), - TypeID::get(), - reinterpret_cast( - &PropertyAccess - ::template getByFunction), - getContext(getter), - TypeID::get(), - reinterpret_cast( - &PropertyAccess - ::template setByFunction), - getContext(setter)); - return *this; - } }; //////////////////////////////////////////////////////////////////////////////// @@ -532,57 +536,24 @@ namespace emscripten { return *this; } - template< - typename GetterReturnType, - typename GetterThisType, - typename SetterArgumentType, - typename SetterThisType> + template value_struct& field( const char* fieldName, - GetterReturnType (GetterThisType::*getter)() const, - void (SetterThisType::*setter)(SetterArgumentType) + Getter getter, + Setter setter ) { using namespace internal; + typedef GetterPolicy GP; + typedef SetterPolicy SP; _embind_register_struct_field( TypeID::get(), fieldName, - TypeID::get(), - reinterpret_cast( - &PropertyAccess - ::template getByMemberFunction), - getContext(getter), - TypeID::get(), - reinterpret_cast( - &PropertyAccess - ::template setByMemberFunction), - getContext(setter)); - return *this; - } - - template< - typename GetterReturnType, - typename GetterThisType, - typename SetterArgumentType, - typename SetterThisType> - value_struct& field( - const char* fieldName, - GetterReturnType (*getter)(const GetterThisType&), - void (*setter)(SetterThisType&, SetterArgumentType) - ) { - using namespace internal; - _embind_register_struct_field( - TypeID::get(), - fieldName, - TypeID::get(), - reinterpret_cast( - &PropertyAccess - ::template getByFunction), - getContext(getter), - TypeID::get(), - reinterpret_cast( - &PropertyAccess - ::template setByFunction), - getContext(setter)); + TypeID::get(), + reinterpret_cast(&GP::template get), + GP::getContext(getter), + TypeID::get(), + reinterpret_cast(&SP::template set), + SP::getContext(setter)); return *this; } }; From e8afd54698387cb38dafdea9317c764440063909 Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Tue, 2 Apr 2013 12:26:32 +0300 Subject: [PATCH 372/544] Add support for binding multiple class constructors with embind. The ctors must have different number of arguments each. --- src/embind/embind.js | 17 +++++++++++++---- tests/embind/embind.test.js | 20 ++++++++++++++++++-- tests/embind/embind_test.cpp | 31 +++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 16e29d9e24f40..c298d8ba7a418 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -814,10 +814,13 @@ function __embind_register_class( if (Object.getPrototypeOf(this) !== instancePrototype) { throw new BindingError("Use 'new' to construct " + name); } - var body = registeredClass.constructor_body; - if (undefined === body) { + if (undefined === registeredClass.constructor_body) { throw new BindingError(name + " has no accessible constructor"); } + var body = registeredClass.constructor_body[arguments.length]; + if (undefined === body) { + throw new BindingError("Tried to invoke ctor of " + name + " with invalid number of parameters (" + arguments.length + ") - expected (" + Object.keys(registeredClass.constructor_body).toString() + ") parameters instead!"); + } return body.apply(this, arguments); }); @@ -884,12 +887,18 @@ function __embind_register_class_constructor( classType = classType[0]; var humanName = 'constructor ' + classType.name; - classType.registeredClass.constructor_body = function() { + if (undefined === classType.registeredClass.constructor_body) { + classType.registeredClass.constructor_body = []; + } + if (undefined !== classType.registeredClass.constructor_body[argCount - 1]) { + throw new BindingError("Cannot register multiple constructors with identical number of parameters (" + (argCount-1) + ") for class '" + classType.name + "'! Overload resolution is currently only performed using the parameter count, not actual type info!"); + } + classType.registeredClass.constructor_body[argCount - 1] = function() { throwUnboundTypeError('Cannot construct ' + classType.name + ' due to unbound types', rawArgTypes); }; whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { - classType.registeredClass.constructor_body = function() { + classType.registeredClass.constructor_body[argCount - 1] = function() { if (arguments.length !== argCount - 1) { throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); } diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 94d935f2eadcc..46b7646deb344 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -589,8 +589,24 @@ module({ assert.throws(TypeError, function() { cm.long_to_string(2147483648); }); assert.throws(TypeError, function() { cm.unsigned_long_to_string(-1); }); assert.throws(TypeError, function() { cm.unsigned_long_to_string(4294967296); }); + }); - }); + test("access multiple class ctors", function() { + var a = new cm.MultipleCtors(10); + assert.equal(a.WhichCtorCalled(), 1); + var b = new cm.MultipleCtors(20, 20); + assert.equal(b.WhichCtorCalled(), 2); + var c = new cm.MultipleCtors(30, 30, 30); + assert.equal(c.WhichCtorCalled(), 3); + a.delete(); + b.delete(); + c.delete(); + }); + + test("wrong number of constructor arguments throws", function() { + assert.throws(cm.BindingError, function() { new cm.MultipleCtors(); }); + assert.throws(cm.BindingError, function() { new cm.MultipleCtors(1,2,3,4); }); + }); /* test("can get templated member classes then call its member functions", function() { @@ -1424,7 +1440,7 @@ module({ test("unbound constructor argument", function() { assertMessage( function() { - new cm.HasConstructorUsingUnboundArgument; + new cm.HasConstructorUsingUnboundArgument(1); }, 'Cannot construct HasConstructorUsingUnboundArgument due to unbound types: UnboundClass'); }); diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 470309aa2b8cd..f23b91521c608 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1314,6 +1314,31 @@ std::string unsigned_long_to_string(unsigned long val) { return str; } +class MultipleCtors { +public: + int value; + + MultipleCtors(int i) { + value = 1; + assert(i == 10); + } + MultipleCtors(int i, int j) { + value = 2; + assert(i == 20); + assert(j == 20); + } + MultipleCtors(int i, int j, int k) { + value = 3; + assert(i == 30); + assert(j == 30); + assert(k == 30); + } + + int WhichCtorCalled() const { + return value; + } +}; + EMSCRIPTEN_BINDINGS(tests) { register_js_interface(); @@ -1759,6 +1784,12 @@ EMSCRIPTEN_BINDINGS(tests) { function("unsigned_int_to_string", &unsigned_int_to_string); function("long_to_string", &long_to_string); function("unsigned_long_to_string", &unsigned_long_to_string); + + class_("MultipleCtors") + .constructor() + .constructor() + .constructor() + .function("WhichCtorCalled", &MultipleCtors::WhichCtorCalled); } // tests for out-of-order registration From 034ebb08d36e282d0cd48d31c86ce995fa432b7b Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 2 Apr 2013 02:45:39 -0700 Subject: [PATCH 373/544] add a convenience for selecting a particular overload when binding a function. --- system/include/emscripten/bind.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 3161289d67ff2..4ecd35e960734 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -208,6 +208,11 @@ namespace emscripten { struct allow_raw_pointer : public allow_raw_pointers { }; + template + typename std::add_pointer::type select_overload(typename std::add_pointer::type fn) { + return fn; + } + namespace internal { template struct Invoker { From 783c443cc84ca990e181b07f2ba7f310368d9b75 Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Tue, 2 Apr 2013 12:48:45 +0300 Subject: [PATCH 374/544] Clean up issues found with jshint. --- tests/embind/embind.test.js | 1 + tests/embind/imvu_test_adapter.js | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 46b7646deb344..539b837fa0aa8 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -1505,6 +1505,7 @@ module({ }); }); +/* global run_all_tests */ // If running as part of the emscripten test runner suite, and not as part of the IMVU suite, // we launch the test execution from here. IMVU suite uses its own dedicated mechanism instead of this. if (typeof run_all_tests !== "undefined") diff --git a/tests/embind/imvu_test_adapter.js b/tests/embind/imvu_test_adapter.js index 03405d0844203..421e86c8a7854 100755 --- a/tests/embind/imvu_test_adapter.js +++ b/tests/embind/imvu_test_adapter.js @@ -8,6 +8,8 @@ To run the Embind tests using the Emscripten test runner, invoke 'python tests/runner.py other.test_embind' in the Emscripten root directory. */ +/* global Module, console, global, process */ + //=== testing glue function module(ignore, func) { @@ -383,7 +385,7 @@ function module(ignore, func) { //////////////////////////////////////////////////////////////////////////////// // EXCEPTIONS - assert['throws'] = function(exception, fn) { + assert.throws = function(exception, fn) { try { fn(); } catch (e) { @@ -537,7 +539,7 @@ function module(ignore, func) { fail(new AssertionError(decipherDomElement(el) + ' expected NOT to be empty')); } } - } + }; // }; function decipherDomElement(selectorOrJQueryObject) { @@ -603,7 +605,7 @@ function module(ignore, func) { // IMVU runner uses a separate runner & reporting mechanism. function run_all_tests() { function report_to_stdout(msg) { - if (msg.type == "test-complete") + if (msg.type === "test-complete") console.log(msg.name + ": " + msg.verdict); } run_all(report_to_stdout); From 616b5c3579556c5e1be6ba1063c132680d9e2d43 Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Tue, 2 Apr 2013 15:35:36 +0300 Subject: [PATCH 375/544] Add support for registering overloads of free functions based on argument count. --- src/embind/embind.js | 68 ++++++++++++++++++++++++++++++++---- tests/embind/embind.test.js | 12 +++++++ tests/embind/embind_test.cpp | 16 +++++++++ 3 files changed, 89 insertions(+), 7 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index c298d8ba7a418..e050d3c24a3e0 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -39,18 +39,72 @@ function throwUnboundTypeError(message, types) { throw new UnboundTypeError(message + ': ' + unboundTypes.map(getTypeName).join([', '])); } -function exposePublicSymbol(name, value) { +/* Registers a symbol (function, class, enum, ...) as part of the Module JS object so that + hand-written code is able to access that symbol via 'Module.name'. + name: The name of the symbol that's being exposed. + value: The object itself to expose (function, class, ...) + numArguments: For functions, specifies the number of arguments the function takes in. For other types, unused and undefined. + + To implement support for multiple overloads of a function, an 'overload selector' function is used. That selector function chooses + the appropriate overload to call from an function overload table. This selector function is only used if multiple overloads are + actually registered, since it carries a slight performance penalty. */ +function exposePublicSymbol(name, value, numArguments) { if (Module.hasOwnProperty(name)) { - throwBindingError("Cannot register public name '" + name + "' twice"); + if (undefined === numArguments || (undefined !== Module[name].overloadTable && undefined !== Module[name].overloadTable[numArguments])) { + throwBindingError("Cannot register public name '" + name + "' twice"); + } + + // We are exposing a function with the same name as an existing function. Create an overload table and a function selector + // that routes between the two. + + // If we don't yet have an overload selector, install an overload selector that routes the function call to a table of overloads based on # of arguments to function. + if (undefined === Module[name].overloadTable) { + var prevFunc = Module[name]; + + // Inject an overload selector in place of the previous function. + Module[name] = function() { + // TODO This check can be removed in -O3 level "unsafe" optimizations. + if (!Module[name].overloadTable.hasOwnProperty(arguments.length)) { + throwBindingError("Function '" + name + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + Object.keys(Module[name].overloadTable) + ")!"); + } + return Module[name].overloadTable[arguments.length].apply(this, arguments); + }; + // An overloadTable maintains a registry of all function overloads. + Module[name].overloadTable = []; + // Move the old function into the overload table. + Module[name].overloadTable[prevFunc.numArguments] = prevFunc; + } + + if (Module.hasOwnProperty(numArguments)) { + throwBindingError("Cannot register multiple overloads of a function with the same number of arguments (" + numArguments + ")!"); + } + // Add the new function into the overload table. + Module[name].overloadTable[numArguments] = value; + } + else { + Module[name] = value; + if (undefined !== numArguments) { + Module[name].numArguments = numArguments; + } } - Module[name] = value; } -function replacePublicSymbol(name, value) { +function replacePublicSymbol(name, value, numArguments) { if (!Module.hasOwnProperty(name)) { throwInternalError('Replacing nonexistant public symbol'); } - Module[name] = value; + // If there's an overload table for this symbol, replace the symbol in the overload table instead. + if (undefined !== Module[name].overloadTable && undefined !== numArguments) { + Module[name].overloadTable[numArguments] = value; + } + else { + Module[name] = value; + /* XXX TODO unneeded?! + if (undefined !== numArguments) { + Module[name].numArguments = numArguments; + } + */ + } } // from https://github.com/imvu/imvujs/blob/master/src/error.js @@ -345,10 +399,10 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, exposePublicSymbol(name, function() { throwUnboundTypeError('Cannot call ' + name + ' due to unbound types', argTypes); - }); + }, argCount - 1); whenDependentTypesAreResolved([], argTypes, function(argTypes) { - replacePublicSymbol(name, makeInvoker(name, argCount, argTypes, rawInvoker, fn)); + replacePublicSymbol(name, makeInvoker(name, argCount, argTypes, rawInvoker, fn), argCount - 1); return []; }); } diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 539b837fa0aa8..a577cd3774a11 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -608,6 +608,18 @@ module({ assert.throws(cm.BindingError, function() { new cm.MultipleCtors(1,2,3,4); }); }); + test("overloading of free functions", function() { + var a = cm.overloaded_function(10); + assert.equal(a, 1); + var b = cm.overloaded_function(20, 20); + assert.equal(b, 2); + }); + + test("wrong number of arguments to an overloaded free function", function() { + assert.throws(cm.BindingError, function() { cm.overloaded_function(); }); + assert.throws(cm.BindingError, function() { cm.overloaded_function(30, 30, 30); }); + }); + /* test("can get templated member classes then call its member functions", function() { var p = new cm.ContainsTemplatedMemberClass(); diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index f23b91521c608..0ae1801a3001f 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1339,6 +1339,19 @@ class MultipleCtors { } }; +int overloaded_function(int i) +{ + assert(i == 10); + return 1; +} + +int overloaded_function(int i, int j) +{ + assert(i == 20); + assert(j == 20); + return 2; +} + EMSCRIPTEN_BINDINGS(tests) { register_js_interface(); @@ -1785,6 +1798,9 @@ EMSCRIPTEN_BINDINGS(tests) { function("long_to_string", &long_to_string); function("unsigned_long_to_string", &unsigned_long_to_string); + function("overloaded_function", (int(*)(int))&overloaded_function); + function("overloaded_function", (int(*)(int, int))&overloaded_function); + class_("MultipleCtors") .constructor() .constructor() From d4bf6fbe297ea7e5720b49bfa6fc58b696540144 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 3 Apr 2013 17:28:11 -0700 Subject: [PATCH 376/544] Add support for global constants. --- src/embind/embind.js | 12 ++++++++++++ system/include/emscripten/bind.h | 31 +++++++++++++++++++++++++++++++ system/include/emscripten/wire.h | 2 +- tests/embind/embind.test.js | 6 ++++++ tests/embind/embind_test.cpp | 10 ++++++++++ 5 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index e050d3c24a3e0..46fdeee4e1970 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1245,3 +1245,15 @@ function __embind_register_interface( }); } +function __embind_register_constant(name, type, value, destructor) { + name = Pointer_stringify(name); + whenDependentTypesAreResolved([], [type], function(type) { + type = type[0]; + /*global console*/ + //console.log('type', type); + //console.log('value', value); + Module[name] = type.fromWireType(value); + // todo: I need to natively destruct 'value' here + return []; + }); +} diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 4ecd35e960734..e767afaa4576b 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -159,6 +159,11 @@ namespace emscripten { const char* name, GenericFunction constructor, GenericFunction destructor); + + void _embind_register_constant( + const char* name, + TYPEID constantType, + uintptr_t value); } } } @@ -1023,6 +1028,32 @@ namespace emscripten { } }; + //////////////////////////////////////////////////////////////////////////////// + // CONSTANTS + //////////////////////////////////////////////////////////////////////////////// + + namespace internal { + template + uintptr_t asGenericValue(T t) { + return static_cast(t); + } + + template + uintptr_t asGenericValue(T* p) { + return reinterpret_cast(p); + } + } + + template + void constant(const char* name, const ConstantType& v) { + using namespace internal; + typedef BindingType BT; + _embind_register_constant( + name, + TypeID::get(), + asGenericValue(BindingType::toWireType(v))); + } + namespace internal { template class optional { diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 0c0f5eb811c9b..9c8cd096f6d93 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -122,7 +122,7 @@ namespace emscripten { template<> \ struct BindingType { \ typedef type WireType; \ - constexpr static WireType toWireType(const type& v) { \ + constexpr static WireType toWireType(const type& v) { \ return v; \ } \ constexpr static type fromWireType(WireType v) { \ diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index a577cd3774a11..7bb3985ff5e9d 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -1515,6 +1515,12 @@ module({ assert.equal('ValHolder$setVal', cm.ValHolder.prototype.setVal.name); assert.equal('ValHolder$makeConst', cm.ValHolder.makeConst.name); }); + + BaseFixture.extend("constants", function() { + assert.equal(10, cm.INT_CONSTANT); + assert.equal("some string", cm.STRING_CONSTANT); + //assert.deepEqual([1, 2, 3], cm.VALUE_TUPLE_CONSTANT); + }); }); /* global run_all_tests */ diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 0ae1801a3001f..4d1b376b930ec 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1352,6 +1352,16 @@ int overloaded_function(int i, int j) return 2; } +EMSCRIPTEN_BINDINGS(constants) { + constant("INT_CONSTANT", 10); + constant("STRING_CONSTANT", std::string("some string")); + TupleVector tv; + tv.x = 1; + tv.y = 2; + tv.z = 3; + constant("VALUE_TUPLE_CONSTANT", tv); +} + EMSCRIPTEN_BINDINGS(tests) { register_js_interface(); From f508d6306ff0be4966d3f26b99a26c46f7c2c1ef Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 3 Apr 2013 19:50:50 -0700 Subject: [PATCH 377/544] Allow value_tuple and value_struct to be registered as global constants. This involved reworking how value_struct and value_tuple are registered. --- src/embind/embind.js | 248 +++++++++++++++++-------------- system/include/emscripten/bind.h | 26 +++- tests/embind/embind.test.js | 3 +- tests/embind/embind_test.cpp | 7 + 4 files changed, 173 insertions(+), 111 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 46fdeee4e1970..37439912c7d0c 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -407,37 +407,15 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, }); } +var tupleRegistrations = {}; + function __embind_register_tuple(rawType, name, rawConstructor, rawDestructor) { - name = Pointer_stringify(name); - rawConstructor = FUNCTION_TABLE[rawConstructor]; - rawDestructor = FUNCTION_TABLE[rawDestructor]; - registerType(rawType, { - name: name, - rawConstructor: rawConstructor, - rawDestructor: rawDestructor, + tupleRegistrations[rawType] = { + name: Pointer_stringify(name), + rawConstructor: FUNCTION_TABLE[rawConstructor], + rawDestructor: FUNCTION_TABLE[rawDestructor], elements: [], - fromWireType: function(ptr) { - var len = this.elements.length; - var rv = new Array(len); - for (var i = 0; i < len; ++i) { - rv[i] = this.elements[i].read(ptr); - } - this.rawDestructor(ptr); - return rv; - }, - toWireType: function(destructors, o) { - var len = this.elements.length; - if (len !== o.length) { - throw new TypeError("Incorrect number of tuple elements"); - } - var ptr = this.rawConstructor(); - for (var i = 0; i < len; ++i) { - this.elements[i].write(ptr, o[i]); - } - destructors.push(rawDestructor, ptr); - return ptr; - }, - }); + }; } function __embind_register_tuple_element( @@ -449,78 +427,84 @@ function __embind_register_tuple_element( setter, setterContext ) { - var tupleType = requireRegisteredType(rawTupleType, 'tuple'); - getter = FUNCTION_TABLE[getter]; - setter = FUNCTION_TABLE[setter]; + tupleRegistrations[rawTupleType].elements.push({ + getterReturnType: getterReturnType, + getter: FUNCTION_TABLE[getter], + getterContext: getterContext, + setterArgumentType: setterArgumentType, + setter: FUNCTION_TABLE[setter], + setterContext: setterContext, + }); +} - var index = tupleType.elements.length; - tupleType.elements.push(undefined); - - // TODO: test incomplete registration of value tuples - whenDependentTypesAreResolved([], [getterReturnType, setterArgumentType], function(types) { - var getterReturnType = types[0]; - var setterArgumentType = types[1]; - tupleType.elements[index] = { - read: function(ptr) { - return getterReturnType.fromWireType( - getter( - getterContext, - ptr)); - }, - write: function(ptr, o) { +function __embind_finalize_tuple(rawTupleType) { + var reg = tupleRegistrations[rawTupleType]; + delete tupleRegistrations[rawTupleType]; + var elements = reg.elements; + var elementsLength = elements.length; + var elementTypes = elements.map(function(elt) { return elt.getterReturnType; }). + concat(elements.map(function(elt) { return elt.setterArgumentType; })); + + var rawConstructor = reg.rawConstructor; + var rawDestructor = reg.rawDestructor; + + whenDependentTypesAreResolved([rawTupleType], elementTypes, function(elementTypes) { + elements.forEach(function(elt, i) { + var getterReturnType = elementTypes[i]; + var getter = elt.getter; + var getterContext = elt.getterContext; + var setterArgumentType = elementTypes[i + elementsLength]; + var setter = elt.setter; + var setterContext = elt.setterContext; + elt.read = function(ptr) { + return getterReturnType.fromWireType(getter(getterContext, ptr)); + }; + elt.write = function(ptr, o) { var destructors = []; - setter( - setterContext, - ptr, - setterArgumentType.toWireType(destructors, o)); + setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o)); runDestructors(destructors); - } - }; - return []; + }; + }); + + return [{ + name: reg.name, + fromWireType: function(ptr) { + var rv = new Array(elementsLength); + for (var i = 0; i < elementsLength; ++i) { + rv[i] = elements[i].read(ptr); + } + rawDestructor(ptr); + return rv; + }, + toWireType: function(destructors, o) { + if (elementsLength !== o.length) { + throw new TypeError("Incorrect number of tuple elements"); + } + var ptr = rawConstructor(); + for (var i = 0; i < elementsLength; ++i) { + elements[i].write(ptr, o[i]); + } + destructors.push(rawDestructor, ptr); + return ptr; + }, + }]; }); } +var structRegistrations = {}; + function __embind_register_struct( rawType, name, rawConstructor, rawDestructor ) { - name = Pointer_stringify(name); - rawConstructor = FUNCTION_TABLE[rawConstructor]; - rawDestructor = FUNCTION_TABLE[rawDestructor]; - - registerType(rawType, { - name: name, - rawConstructor: rawConstructor, - rawDestructor: rawDestructor, - fields: {}, - fromWireType: function(ptr) { - var fields = this.fields; - var rv = {}; - for (var i in fields) { - rv[i] = fields[i].read(ptr); - } - this.rawDestructor(ptr); - return rv; - }, - toWireType: function(destructors, o) { - var fields = this.fields; - // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: - // assume all fields are present without checking. - for (var fieldName in fields) { - if (!(fieldName in o)) { - throw new TypeError('Missing field'); - } - } - var ptr = this.rawConstructor(); - for (fieldName in fields) { - fields[fieldName].write(ptr, o[fieldName]); - } - destructors.push(rawDestructor, ptr); - return ptr; - }, - }); + structRegistrations[rawType] = { + name: Pointer_stringify(name), + rawConstructor: FUNCTION_TABLE[rawConstructor], + rawDestructor: FUNCTION_TABLE[rawDestructor], + fields: [], + }; } function __embind_register_struct_field( @@ -533,27 +517,75 @@ function __embind_register_struct_field( setter, setterContext ) { - structType = requireRegisteredType(structType, 'struct'); - fieldName = Pointer_stringify(fieldName); - getter = FUNCTION_TABLE[getter]; - setter = FUNCTION_TABLE[setter]; + structRegistrations[structType].fields.push({ + fieldName: Pointer_stringify(fieldName), + getterReturnType: getterReturnType, + getter: FUNCTION_TABLE[getter], + getterContext: getterContext, + setterArgumentType: setterArgumentType, + setter: FUNCTION_TABLE[setter], + setterContext: setterContext, + }); +} + +function __embind_finalize_struct(structType) { + var reg = structRegistrations[structType]; + delete structRegistrations[structType]; + + var rawConstructor = reg.rawConstructor; + var rawDestructor = reg.rawDestructor; + var fieldRecords = reg.fields; + var fieldTypes = fieldRecords.map(function(field) { return field.getterReturnType; }). + concat(fieldRecords.map(function(field) { return field.setterArgumentType; })); + whenDependentTypesAreResolved([structType], fieldTypes, function(fieldTypes) { + var fields = {}; + fieldRecords.forEach(function(field, i) { + var fieldName = field.fieldName; + var getterReturnType = fieldTypes[i]; + var getter = field.getter; + var getterContext = field.getterContext; + var setterArgumentType = fieldTypes[i + fieldRecords.length]; + var setter = field.setter; + var setterContext = field.setterContext; + fields[fieldName] = { + read: function(ptr) { + return getterReturnType.fromWireType( + getter(getterContext, ptr)); + }, + write: function(ptr, o) { + var destructors = []; + setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o)); + runDestructors(destructors); + } + }; + }); - // TODO: test incomplete registration of value structs - whenDependentTypesAreResolved([], [getterReturnType, setterArgumentType], function(types) { - var getterReturnType = types[0]; - var setterArgumentType = types[1]; - structType.fields[fieldName] = { - read: function(ptr) { - return getterReturnType.fromWireType( - getter(getterContext, ptr)); + return [{ + name: reg.name, + fromWireType: function(ptr) { + var rv = {}; + for (var i in fields) { + rv[i] = fields[i].read(ptr); + } + rawDestructor(ptr); + return rv; }, - write: function(ptr, o) { - var destructors = []; - setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o)); - runDestructors(destructors); - } - }; - return []; + toWireType: function(destructors, o) { + // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: + // assume all fields are present without checking. + for (var fieldName in fields) { + if (!(fieldName in o)) { + throw new TypeError('Missing field'); + } + } + var ptr = rawConstructor(); + for (fieldName in fields) { + fields[fieldName].write(ptr, o[fieldName]); + } + destructors.push(rawDestructor, ptr); + return ptr; + }, + }]; }); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index e767afaa4576b..bd170dea6f16b 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -77,6 +77,8 @@ namespace emscripten { GenericFunction setter, void* setterContext); + void _embind_finalize_tuple(TYPEID tupleType); + void _embind_register_struct( TYPEID structType, const char* fieldName, @@ -93,6 +95,8 @@ namespace emscripten { GenericFunction setter, void* setterContext); + void _embind_finalize_struct(TYPEID structType); + void _embind_register_smart_ptr( TYPEID pointerType, TYPEID pointeeType, @@ -458,6 +462,15 @@ namespace emscripten { return internal::getContext(context); } }; + + class noncopyable { + protected: + noncopyable() {} + ~noncopyable() {} + private: + noncopyable(const noncopyable&) = delete; + const noncopyable& operator=(const noncopyable&) = delete; + }; } //////////////////////////////////////////////////////////////////////////////// @@ -465,7 +478,7 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// template - class value_tuple { + class value_tuple : public internal::noncopyable { public: value_tuple(const char* name) { using namespace internal; @@ -476,6 +489,11 @@ namespace emscripten { reinterpret_cast(&raw_destructor)); } + ~value_tuple() { + using namespace internal; + _embind_finalize_tuple(TypeID::get()); + } + template value_tuple& element(ElementType InstanceType::*field) { using namespace internal; @@ -516,7 +534,7 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// template - class value_struct { + class value_struct : public internal::noncopyable { public: value_struct(const char* name) { using namespace internal; @@ -527,6 +545,10 @@ namespace emscripten { reinterpret_cast(&raw_destructor)); } + ~value_struct() { + _embind_finalize_struct(internal::TypeID::get()); + } + template value_struct& field(const char* fieldName, FieldType InstanceType::*field) { using namespace internal; diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 7bb3985ff5e9d..11746214eeb25 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -1519,7 +1519,8 @@ module({ BaseFixture.extend("constants", function() { assert.equal(10, cm.INT_CONSTANT); assert.equal("some string", cm.STRING_CONSTANT); - //assert.deepEqual([1, 2, 3], cm.VALUE_TUPLE_CONSTANT); + assert.deepEqual([1, 2, 3], cm.VALUE_TUPLE_CONSTANT); + assert.deepEqual({x:1,y:2,z:3}, cm.VALUE_STRUCT_CONSTANT); }); }); diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 4d1b376b930ec..be089f9f2273f 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1355,11 +1355,18 @@ int overloaded_function(int i, int j) EMSCRIPTEN_BINDINGS(constants) { constant("INT_CONSTANT", 10); constant("STRING_CONSTANT", std::string("some string")); + TupleVector tv; tv.x = 1; tv.y = 2; tv.z = 3; constant("VALUE_TUPLE_CONSTANT", tv); + + StructVector sv; + sv.x = 1; + sv.y = 2; + sv.z = 3; + constant("VALUE_STRUCT_CONSTANT", sv); } EMSCRIPTEN_BINDINGS(tests) { From 7eb89c3e4feabd85b50cfad9f3c44a9235540a05 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 3 Apr 2013 20:03:18 -0700 Subject: [PATCH 378/544] refactoring --- src/embind/embind.js | 6 +----- system/include/emscripten/wire.h | 18 ++---------------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 37439912c7d0c..df581298503f5 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1277,15 +1277,11 @@ function __embind_register_interface( }); } -function __embind_register_constant(name, type, value, destructor) { +function __embind_register_constant(name, type, value) { name = Pointer_stringify(name); whenDependentTypesAreResolved([], [type], function(type) { type = type[0]; - /*global console*/ - //console.log('type', type); - //console.log('value', value); Module[name] = type.fromWireType(value); - // todo: I need to natively destruct 'value' here return []; }); } diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 9c8cd096f6d93..64114491ab1b5 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -182,25 +182,11 @@ namespace emscripten { }; template - struct BindingType { - typedef typename BindingType::WireType WireType; - static WireType toWireType(const T& v) { - return BindingType::toWireType(v); - } - static T fromWireType(WireType wt) { - return BindingType::fromWireType(wt); - } + struct BindingType : public BindingType { }; template - struct BindingType { - typedef typename BindingType::WireType WireType; - static WireType toWireType(const T& v) { - return BindingType::toWireType(v); - } - static T fromWireType(WireType wt) { - return BindingType::fromWireType(wt); - } + struct BindingType : public BindingType { }; template From f80caa7c2dbfbba8b6988168715ce3421322191c Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Thu, 4 Apr 2013 09:19:18 +0300 Subject: [PATCH 379/544] Add support for overloading class member functions and class static functions based on function argument count. --- src/embind/embind.js | 87 +++++++++++++++++++++++++++++---- tests/embind/embind.test.js | 56 ++++++++++++++++++++++ tests/embind/embind_test.cpp | 93 ++++++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+), 9 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index df581298503f5..f48bcf7b8e031 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1060,14 +1060,40 @@ function __embind_register_class_function( classType = classType[0]; var humanName = classType.name + '.' + methodName; - classType.registeredClass.instancePrototype[methodName] = function() { - throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); - }; + var unboundTypesHandler = function() { + throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); + }; + + var method = classType.registeredClass.instancePrototype[methodName]; + if (undefined === method || (undefined === method.overloadTable && method.className !== classType.name && method.argCount === argCount-2)) { + // This is the first overload to be registered, OR we are replacing a function in the base class with a function in the derived class. + classType.registeredClass.instancePrototype[methodName] = unboundTypesHandler; + classType.registeredClass.instancePrototype[methodName].argCount = argCount-2; + classType.registeredClass.instancePrototype[methodName].className = classType.name; + } else { + // There was an existing function with the same name registered. Set up a function overload routing table. + if (undefined === classType.registeredClass.instancePrototype[methodName].overloadTable) { + var prevFunc = classType.registeredClass.instancePrototype[methodName]; + + // Inject an overload resolver function that routes to the appropriate overload based on the number of arguments. + classType.registeredClass.instancePrototype[methodName] = function() { + // TODO This check can be removed in -O3 level "unsafe" optimizations. + if (!classType.registeredClass.instancePrototype[methodName].overloadTable.hasOwnProperty(arguments.length)) { + throwBindingError("Member function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + classType.registeredClass.instancePrototype[methodName].overloadTable + ")!"); + } + return classType.registeredClass.instancePrototype[methodName].overloadTable[arguments.length].apply(this, arguments); + }; + // Move the previous function into the overload table. + classType.registeredClass.instancePrototype[methodName].overloadTable = []; + classType.registeredClass.instancePrototype[methodName].overloadTable[prevFunc.argCount] = prevFunc; + } + classType.registeredClass.instancePrototype[methodName].overloadTable[argCount-2] = unboundTypesHandler; + } whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { - classType.registeredClass.instancePrototype[methodName] = createNamedFunction(makeLegalFunctionName(humanName), function() { + var memberFunction = createNamedFunction(makeLegalFunctionName(humanName), function() { if (arguments.length !== argCount - 2) { - throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); + throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-2)); } validateThis(this, classType, humanName); @@ -1084,6 +1110,15 @@ function __embind_register_class_function( runDestructors(destructors); return rv; }); + + // Replace the initial unbound-handler-stub function with the appropriate member function, now that all types + // are resolved. If multiple overloads are registered for this function, the function goes into an overload table. + if (undefined === classType.registeredClass.instancePrototype[methodName].overloadTable) { + classType.registeredClass.instancePrototype[methodName] = memberFunction; + } else { + classType.registeredClass.instancePrototype[methodName].overloadTable[argCount-2] = memberFunction; + } + return []; }); return []; @@ -1105,12 +1140,46 @@ function __embind_register_class_class_function( classType = classType[0]; var humanName = classType.name + '.' + methodName; - classType.registeredClass.constructor[methodName] = function() { - throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); - }; + var unboundTypesHandler = function() { + throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); + }; + + if (undefined === classType.registeredClass.constructor[methodName]) { + // This is the first function to be registered with this name. + classType.registeredClass.constructor[methodName] = unboundTypesHandler; + classType.registeredClass.constructor[methodName].argCount = argCount-1; + } else { + // There was an existing function to be registered with this name. Set up an overload table to + // resolve between them. + if (undefined === classType.registeredClass.constructor[methodName].overloadTable) { + var prevFunc = classType.registeredClass.constructor[methodName]; + + // Inject an overload handler function that resolves the proper function to call based on the + // number of parameters passed to the function. + classType.registeredClass.constructor[methodName] = function() { + // TODO This check can be removed in -O3 level "unsafe" optimizations. + if (!classType.registeredClass.constructor[methodName].overloadTable.hasOwnProperty(arguments.length)) { + throwBindingError("Static member function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + classType.registeredClass.constructor[methodName].overloadTable + ")!"); + } + return classType.registeredClass.constructor[methodName].overloadTable[arguments.length].apply(this, arguments); + }; + + classType.registeredClass.constructor[methodName].overloadTable = []; + // Move the old function into the overload table. + classType.registeredClass.constructor[methodName].overloadTable[prevFunc.argCount] = prevFunc; + } + classType.registeredClass.constructor[methodName].overloadTable[argCount-1] = unboundTypesHandler; + } whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { - classType.registeredClass.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn); + // Replace the initial unbound-types-handler stub with the proper function. If multiple overloads are registered, + // the function handlers go into an overload table. + var func = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn); + if (undefined === classType.registeredClass.constructor[methodName].overloadTable) { + classType.registeredClass.constructor[methodName] = func; + } else { + classType.registeredClass.constructor[methodName].overloadTable[argCount-1] = func; + } return []; }); return []; diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 11746214eeb25..020719d5f772d 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -620,6 +620,62 @@ module({ assert.throws(cm.BindingError, function() { cm.overloaded_function(30, 30, 30); }); }); + test("overloading of class member functions", function() { + var foo = new cm.MultipleOverloads(); + assert.equal(foo.Func(10), 1); + assert.equal(foo.WhichFuncCalled(), 1); + assert.equal(foo.Func(20, 20), 2); + assert.equal(foo.WhichFuncCalled(), 2); + foo.delete(); + }); + + test("wrong number of arguments to an overloaded class member function", function() { + var foo = new cm.MultipleOverloads(); + assert.throws(cm.BindingError, function() { foo.Func(); }); + assert.throws(cm.BindingError, function() { foo.Func(30, 30, 30); }); + foo.delete(); + }); + + test("wrong number of arguments to an overloaded class static function", function() { + assert.throws(cm.BindingError, function() { cm.MultipleOverloads.StaticFunc(); }); + assert.throws(cm.BindingError, function() { cm.MultipleOverloads.StaticFunc(30, 30, 30); }); + }); + + test("overloading of derived class member functions", function() { + var foo = new cm.MultipleOverloadsDerived(); + + // NOTE: In C++, default lookup rules will hide overloads from base class if derived class creates them. + // In JS, we make the base class overloads implicitly available. In C++, they would need to be explicitly + // invoked, like foo.MultipleOverloads::Func(10); + assert.equal(foo.Func(10), 1); + assert.equal(foo.WhichFuncCalled(), 1); + assert.equal(foo.Func(20, 20), 2); + assert.equal(foo.WhichFuncCalled(), 2); + + assert.equal(foo.Func(30, 30, 30), 3); + assert.equal(foo.WhichFuncCalled(), 3); + assert.equal(foo.Func(40, 40, 40, 40), 4); + assert.equal(foo.WhichFuncCalled(), 4); + foo.delete(); + }); + + test("overloading of class static functions", function() { + assert.equal(cm.MultipleOverloads.StaticFunc(10), 1); + assert.equal(cm.MultipleOverloads.WhichStaticFuncCalled(), 1); + assert.equal(cm.MultipleOverloads.StaticFunc(20, 20), 2); + assert.equal(cm.MultipleOverloads.WhichStaticFuncCalled(), 2); + }); + + test("overloading of derived class static functions", function() { + assert.equal(cm.MultipleOverloadsDerived.StaticFunc(30, 30, 30), 3); + // TODO: Cannot access static member functions of a Base class via Derived. +// assert.equal(cm.MultipleOverloadsDerived.WhichStaticFuncCalled(), 3); + assert.equal(cm.MultipleOverloads.WhichStaticFuncCalled(), 3); + assert.equal(cm.MultipleOverloadsDerived.StaticFunc(40, 40, 40, 40), 4); + // TODO: Cannot access static member functions of a Base class via Derived. +// assert.equal(cm.MultipleOverloadsDerived.WhichStaticFuncCalled(), 4); + assert.equal(cm.MultipleOverloads.WhichStaticFuncCalled(), 4); + }); /* test("can get templated member classes then call its member functions", function() { var p = new cm.ContainsTemplatedMemberClass(); diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index be089f9f2273f..1ef3fb16937cf 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1339,6 +1339,83 @@ class MultipleCtors { } }; +class MultipleOverloads { +public: + MultipleOverloads() {} + + int value; + static int staticValue; + + int Func(int i) { + assert(i == 10); + value = 1; + return 1; + } + int Func(int i, int j) { + assert(i == 20); + assert(j == 20); + value = 2; + return 2; + } + + int WhichFuncCalled() const { + return value; + } + + static int StaticFunc(int i) { + assert(i == 10); + staticValue = 1; + return 1; + } + static int StaticFunc(int i, int j) { + assert(i == 20); + assert(j == 20); + staticValue = 2; + return 2; + } + + static int WhichStaticFuncCalled() { + return staticValue; + } +}; + +class MultipleOverloadsDerived : public MultipleOverloads { +public: + MultipleOverloadsDerived() {} + + int Func(int i, int j, int k) { + assert(i == 30); + assert(j == 30); + assert(k == 30); + value = 3; + return 3; + } + int Func(int i, int j, int k, int l) { + assert(i == 40); + assert(j == 40); + assert(k == 40); + assert(l == 40); + value = 4; + return 4; + } + + static int StaticFunc(int i, int j, int k) { + assert(i == 30); + assert(j == 30); + assert(k == 30); + staticValue = 3; + return 3; + } + static int StaticFunc(int i, int j, int k, int l) { + assert(i == 40); + assert(j == 40); + assert(k == 40); + assert(l == 40); + staticValue = 4; + return 4; + } +}; + int overloaded_function(int i) { assert(i == 10); @@ -1823,6 +1900,22 @@ EMSCRIPTEN_BINDINGS(tests) { .constructor() .constructor() .function("WhichCtorCalled", &MultipleCtors::WhichCtorCalled); + + class_("MultipleOverloads") + .constructor<>() + .function("Func", (int(MultipleOverloads::*)(int))&MultipleOverloads::Func) + .function("Func", (int(MultipleOverloads::*)(int,int))&MultipleOverloads::Func) + .function("WhichFuncCalled", &MultipleOverloads::WhichFuncCalled) + .class_function("StaticFunc", (int(*)(int))&MultipleOverloads::StaticFunc) + .class_function("StaticFunc", (int(*)(int,int))&MultipleOverloads::StaticFunc) + .class_function("WhichStaticFuncCalled", &MultipleOverloads::WhichStaticFuncCalled); + + class_ >("MultipleOverloadsDerived") + .constructor<>() + .function("Func", (int(MultipleOverloadsDerived::*)(int,int,int))&MultipleOverloadsDerived::Func) + .function("Func", (int(MultipleOverloadsDerived::*)(int,int,int,int))&MultipleOverloadsDerived::Func) + .class_function("StaticFunc", (int(*)(int,int,int))&MultipleOverloadsDerived::StaticFunc) + .class_function("StaticFunc", (int(*)(int,int,int,int))&MultipleOverloadsDerived::StaticFunc); } // tests for out-of-order registration From 3585aa62068fbfe453e0b12ff577a1950a4094fd Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Thu, 4 Apr 2013 10:36:53 +0300 Subject: [PATCH 380/544] Cleaned up some code repetition in embind --- src/embind/embind.js | 64 ++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index f48bcf7b8e031..0361d8daa635b 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1064,30 +1064,29 @@ function __embind_register_class_function( throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); }; - var method = classType.registeredClass.instancePrototype[methodName]; + var proto = classType.registeredClass.instancePrototype; + var method = proto[methodName]; if (undefined === method || (undefined === method.overloadTable && method.className !== classType.name && method.argCount === argCount-2)) { // This is the first overload to be registered, OR we are replacing a function in the base class with a function in the derived class. - classType.registeredClass.instancePrototype[methodName] = unboundTypesHandler; - classType.registeredClass.instancePrototype[methodName].argCount = argCount-2; - classType.registeredClass.instancePrototype[methodName].className = classType.name; + unboundTypesHandler.argCount = argCount-2; + unboundTypesHandler.className = classType.name; + proto[methodName] = unboundTypesHandler; } else { // There was an existing function with the same name registered. Set up a function overload routing table. - if (undefined === classType.registeredClass.instancePrototype[methodName].overloadTable) { - var prevFunc = classType.registeredClass.instancePrototype[methodName]; - + if (undefined === method.overloadTable) { // Inject an overload resolver function that routes to the appropriate overload based on the number of arguments. - classType.registeredClass.instancePrototype[methodName] = function() { + proto[methodName] = function() { // TODO This check can be removed in -O3 level "unsafe" optimizations. - if (!classType.registeredClass.instancePrototype[methodName].overloadTable.hasOwnProperty(arguments.length)) { - throwBindingError("Member function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + classType.registeredClass.instancePrototype[methodName].overloadTable + ")!"); + if (!proto[methodName].overloadTable.hasOwnProperty(arguments.length)) { + throwBindingError("Member function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + proto[methodName].overloadTable + ")!"); } - return classType.registeredClass.instancePrototype[methodName].overloadTable[arguments.length].apply(this, arguments); + return proto[methodName].overloadTable[arguments.length].apply(this, arguments); }; // Move the previous function into the overload table. - classType.registeredClass.instancePrototype[methodName].overloadTable = []; - classType.registeredClass.instancePrototype[methodName].overloadTable[prevFunc.argCount] = prevFunc; + proto[methodName].overloadTable = []; + proto[methodName].overloadTable[method.argCount] = method; } - classType.registeredClass.instancePrototype[methodName].overloadTable[argCount-2] = unboundTypesHandler; + proto[methodName].overloadTable[argCount-2] = unboundTypesHandler; } whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { @@ -1113,10 +1112,10 @@ function __embind_register_class_function( // Replace the initial unbound-handler-stub function with the appropriate member function, now that all types // are resolved. If multiple overloads are registered for this function, the function goes into an overload table. - if (undefined === classType.registeredClass.instancePrototype[methodName].overloadTable) { - classType.registeredClass.instancePrototype[methodName] = memberFunction; + if (undefined === proto[methodName].overloadTable) { + proto[methodName] = memberFunction; } else { - classType.registeredClass.instancePrototype[methodName].overloadTable[argCount-2] = memberFunction; + proto[methodName].overloadTable[argCount-2] = memberFunction; } return []; @@ -1144,41 +1143,42 @@ function __embind_register_class_class_function( throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); }; - if (undefined === classType.registeredClass.constructor[methodName]) { + var proto = classType.registeredClass.constructor; + if (undefined === proto[methodName]) { // This is the first function to be registered with this name. - classType.registeredClass.constructor[methodName] = unboundTypesHandler; - classType.registeredClass.constructor[methodName].argCount = argCount-1; + unboundTypesHandler.argCount = argCount-1; + proto[methodName] = unboundTypesHandler; } else { // There was an existing function to be registered with this name. Set up an overload table to // resolve between them. - if (undefined === classType.registeredClass.constructor[methodName].overloadTable) { - var prevFunc = classType.registeredClass.constructor[methodName]; + if (undefined === proto[methodName].overloadTable) { + var prevFunc = proto[methodName]; // Inject an overload handler function that resolves the proper function to call based on the // number of parameters passed to the function. - classType.registeredClass.constructor[methodName] = function() { + proto[methodName] = function() { // TODO This check can be removed in -O3 level "unsafe" optimizations. - if (!classType.registeredClass.constructor[methodName].overloadTable.hasOwnProperty(arguments.length)) { - throwBindingError("Static member function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + classType.registeredClass.constructor[methodName].overloadTable + ")!"); + if (!proto[methodName].overloadTable.hasOwnProperty(arguments.length)) { + throwBindingError("Static member function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + proto[methodName].overloadTable + ")!"); } - return classType.registeredClass.constructor[methodName].overloadTable[arguments.length].apply(this, arguments); + return proto[methodName].overloadTable[arguments.length].apply(this, arguments); }; - classType.registeredClass.constructor[methodName].overloadTable = []; + proto[methodName].overloadTable = []; // Move the old function into the overload table. - classType.registeredClass.constructor[methodName].overloadTable[prevFunc.argCount] = prevFunc; + proto[methodName].overloadTable[prevFunc.argCount] = prevFunc; } - classType.registeredClass.constructor[methodName].overloadTable[argCount-1] = unboundTypesHandler; + proto[methodName].overloadTable[argCount-1] = unboundTypesHandler; } whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { // Replace the initial unbound-types-handler stub with the proper function. If multiple overloads are registered, // the function handlers go into an overload table. var func = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn); - if (undefined === classType.registeredClass.constructor[methodName].overloadTable) { - classType.registeredClass.constructor[methodName] = func; + if (undefined === proto[methodName].overloadTable) { + proto[methodName] = func; } else { - classType.registeredClass.constructor[methodName].overloadTable[argCount-1] = func; + proto[methodName].overloadTable[argCount-1] = func; } return []; }); From 31f2ba4afbc2a5f5ae2ff859a3a5cecf1393c25e Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Thu, 4 Apr 2013 11:08:00 +0300 Subject: [PATCH 381/544] Remove code duplication on embind --- src/embind/embind.js | 54 ++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 0361d8daa635b..db10e03e1ec1a 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1044,6 +1044,25 @@ function validateThis(this_, classType, humanName) { classType.registeredClass); } +// Creates a function overload resolution table to the given method 'methodName' in the given prototype, +// if the overload table doesn't yet exist. +function ensureOverloadTable(proto, methodName, humanName) { + if (undefined === proto[methodName].overloadTable) { + var prevFunc = proto[methodName]; + // Inject an overload resolver function that routes to the appropriate overload based on the number of arguments. + proto[methodName] = function() { + // TODO This check can be removed in -O3 level "unsafe" optimizations. + if (!proto[methodName].overloadTable.hasOwnProperty(arguments.length)) { + throwBindingError("Function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + proto[methodName].overloadTable + ")!"); + } + return proto[methodName].overloadTable[arguments.length].apply(this, arguments); + }; + // Move the previous function into the overload table. + proto[methodName].overloadTable = []; + proto[methodName].overloadTable[prevFunc.argCount] = prevFunc; + } +} + function __embind_register_class_function( rawClassType, methodName, @@ -1073,19 +1092,7 @@ function __embind_register_class_function( proto[methodName] = unboundTypesHandler; } else { // There was an existing function with the same name registered. Set up a function overload routing table. - if (undefined === method.overloadTable) { - // Inject an overload resolver function that routes to the appropriate overload based on the number of arguments. - proto[methodName] = function() { - // TODO This check can be removed in -O3 level "unsafe" optimizations. - if (!proto[methodName].overloadTable.hasOwnProperty(arguments.length)) { - throwBindingError("Member function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + proto[methodName].overloadTable + ")!"); - } - return proto[methodName].overloadTable[arguments.length].apply(this, arguments); - }; - // Move the previous function into the overload table. - proto[methodName].overloadTable = []; - proto[methodName].overloadTable[method.argCount] = method; - } + ensureOverloadTable(proto, methodName, humanName); proto[methodName].overloadTable[argCount-2] = unboundTypesHandler; } @@ -1149,25 +1156,8 @@ function __embind_register_class_class_function( unboundTypesHandler.argCount = argCount-1; proto[methodName] = unboundTypesHandler; } else { - // There was an existing function to be registered with this name. Set up an overload table to - // resolve between them. - if (undefined === proto[methodName].overloadTable) { - var prevFunc = proto[methodName]; - - // Inject an overload handler function that resolves the proper function to call based on the - // number of parameters passed to the function. - proto[methodName] = function() { - // TODO This check can be removed in -O3 level "unsafe" optimizations. - if (!proto[methodName].overloadTable.hasOwnProperty(arguments.length)) { - throwBindingError("Static member function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + proto[methodName].overloadTable + ")!"); - } - return proto[methodName].overloadTable[arguments.length].apply(this, arguments); - }; - - proto[methodName].overloadTable = []; - // Move the old function into the overload table. - proto[methodName].overloadTable[prevFunc.argCount] = prevFunc; - } + // There was an existing function with the same name registered. Set up a function overload routing table. + ensureOverloadTable(proto, methodName, humanName); proto[methodName].overloadTable[argCount-1] = unboundTypesHandler; } From 2466f601dbc72ff04421904e216cbd966530d0a1 Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Thu, 4 Apr 2013 11:49:51 +0300 Subject: [PATCH 382/544] More code duplication cleanup on embind --- src/embind/embind.js | 63 ++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 43 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index db10e03e1ec1a..a38e0bcc67e01 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -39,6 +39,25 @@ function throwUnboundTypeError(message, types) { throw new UnboundTypeError(message + ': ' + unboundTypes.map(getTypeName).join([', '])); } +// Creates a function overload resolution table to the given method 'methodName' in the given prototype, +// if the overload table doesn't yet exist. +function ensureOverloadTable(proto, methodName, humanName) { + if (undefined === proto[methodName].overloadTable) { + var prevFunc = proto[methodName]; + // Inject an overload resolver function that routes to the appropriate overload based on the number of arguments. + proto[methodName] = function() { + // TODO This check can be removed in -O3 level "unsafe" optimizations. + if (!proto[methodName].overloadTable.hasOwnProperty(arguments.length)) { + throwBindingError("Function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + proto[methodName].overloadTable + ")!"); + } + return proto[methodName].overloadTable[arguments.length].apply(this, arguments); + }; + // Move the previous function into the overload table. + proto[methodName].overloadTable = []; + proto[methodName].overloadTable[prevFunc.argCount] = prevFunc; + } +} + /* Registers a symbol (function, class, enum, ...) as part of the Module JS object so that hand-written code is able to access that symbol via 'Module.name'. name: The name of the symbol that's being exposed. @@ -56,25 +75,7 @@ function exposePublicSymbol(name, value, numArguments) { // We are exposing a function with the same name as an existing function. Create an overload table and a function selector // that routes between the two. - - // If we don't yet have an overload selector, install an overload selector that routes the function call to a table of overloads based on # of arguments to function. - if (undefined === Module[name].overloadTable) { - var prevFunc = Module[name]; - - // Inject an overload selector in place of the previous function. - Module[name] = function() { - // TODO This check can be removed in -O3 level "unsafe" optimizations. - if (!Module[name].overloadTable.hasOwnProperty(arguments.length)) { - throwBindingError("Function '" + name + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + Object.keys(Module[name].overloadTable) + ")!"); - } - return Module[name].overloadTable[arguments.length].apply(this, arguments); - }; - // An overloadTable maintains a registry of all function overloads. - Module[name].overloadTable = []; - // Move the old function into the overload table. - Module[name].overloadTable[prevFunc.numArguments] = prevFunc; - } - + ensureOverloadTable(Module, name, name); if (Module.hasOwnProperty(numArguments)) { throwBindingError("Cannot register multiple overloads of a function with the same number of arguments (" + numArguments + ")!"); } @@ -99,11 +100,6 @@ function replacePublicSymbol(name, value, numArguments) { } else { Module[name] = value; - /* XXX TODO unneeded?! - if (undefined !== numArguments) { - Module[name].numArguments = numArguments; - } - */ } } @@ -1044,25 +1040,6 @@ function validateThis(this_, classType, humanName) { classType.registeredClass); } -// Creates a function overload resolution table to the given method 'methodName' in the given prototype, -// if the overload table doesn't yet exist. -function ensureOverloadTable(proto, methodName, humanName) { - if (undefined === proto[methodName].overloadTable) { - var prevFunc = proto[methodName]; - // Inject an overload resolver function that routes to the appropriate overload based on the number of arguments. - proto[methodName] = function() { - // TODO This check can be removed in -O3 level "unsafe" optimizations. - if (!proto[methodName].overloadTable.hasOwnProperty(arguments.length)) { - throwBindingError("Function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + proto[methodName].overloadTable + ")!"); - } - return proto[methodName].overloadTable[arguments.length].apply(this, arguments); - }; - // Move the previous function into the overload table. - proto[methodName].overloadTable = []; - proto[methodName].overloadTable[prevFunc.argCount] = prevFunc; - } -} - function __embind_register_class_function( rawClassType, methodName, From 9baac4cd7c98e5e8e3b96926ac300701dbdf0950 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 4 Apr 2013 01:53:47 -0700 Subject: [PATCH 383/544] Add support for index access to value_tuple and value_struct --- system/include/emscripten/bind.h | 63 +++++++++++++++++++++++++++++++- tests/embind/embind.test.js | 28 +++++++------- tests/embind/embind_test.cpp | 45 +++++++++++++---------- 3 files changed, 101 insertions(+), 35 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index bd170dea6f16b..81ee38e98805c 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -471,8 +471,30 @@ namespace emscripten { noncopyable(const noncopyable&) = delete; const noncopyable& operator=(const noncopyable&) = delete; }; + + template + struct ReturnType; + + template + struct ReturnType { + typedef RT type; + }; + + template + typename BindingType::WireType get_by_index(int index, ClassType& ptr) { + return BindingType::toWireType(ptr[index]); + } + + template + void set_by_index(int index, ClassType& ptr, typename BindingType::WireType wt) { + ptr[index] = BindingType::fromWireType(wt); + } } + template + struct index { + }; + //////////////////////////////////////////////////////////////////////////////// // VALUE TUPLES //////////////////////////////////////////////////////////////////////////////// @@ -526,7 +548,26 @@ namespace emscripten { reinterpret_cast(&SP::template set), SP::getContext(setter)); return *this; - } + } + + template + value_tuple& element(index) { + using namespace internal; + typedef + typename std::remove_reference< + typename ReturnType::type + >::type + ElementType; + _embind_register_tuple_element( + TypeID::get(), + TypeID::get(), + reinterpret_cast(&internal::get_by_index), + reinterpret_cast(Index), + TypeID::get(), + reinterpret_cast(&internal::set_by_index), + reinterpret_cast(Index)); + return *this; + } }; //////////////////////////////////////////////////////////////////////////////// @@ -588,6 +629,26 @@ namespace emscripten { SP::getContext(setter)); return *this; } + + template + value_struct& field(const char* fieldName, index) { + using namespace internal; + typedef + typename std::remove_reference< + typename ReturnType::type + >::type + ElementType; + _embind_register_struct_field( + TypeID::get(), + fieldName, + TypeID::get(), + reinterpret_cast(&internal::get_by_index), + reinterpret_cast(Index), + TypeID::get(), + reinterpret_cast(&internal::set_by_index), + reinterpret_cast(Index)); + return *this; + } }; //////////////////////////////////////////////////////////////////////////////// diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 020719d5f772d..f365c1b8617fa 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -977,32 +977,32 @@ module({ test("can return tuples by value", function() { var c = cm.emval_test_return_TupleVector(); - assert.deepEqual([1, 2, 3], c); + assert.deepEqual([1, 2, 3, 4], c); }); test("tuples can contain tuples", function() { var c = cm.emval_test_return_TupleVectorTuple(); - assert.deepEqual([[1, 2, 3]], c); + assert.deepEqual([[1, 2, 3, 4]], c); }); test("can pass tuples by value", function() { - var c = cm.emval_test_take_and_return_TupleVector([4, 5, 6]); - assert.deepEqual([4, 5, 6], c); + var c = cm.emval_test_take_and_return_TupleVector([4, 5, 6, 7]); + assert.deepEqual([4, 5, 6, 7], c); }); test("can return structs by value", function() { var c = cm.emval_test_return_StructVector(); - assert.deepEqual({x: 1, y: 2, z: 3}, c); + assert.deepEqual({x: 1, y: 2, z: 3, w: 4}, c); }); test("can pass structs by value", function() { - var c = cm.emval_test_take_and_return_StructVector({x: 4, y: 5, z: 6}); - assert.deepEqual({x: 4, y: 5, z: 6}, c); + var c = cm.emval_test_take_and_return_StructVector({x: 4, y: 5, z: 6, w: 7}); + assert.deepEqual({x: 4, y: 5, z: 6, w: 7}, c); }); test("can pass and return tuples in structs", function() { - var d = cm.emval_test_take_and_return_TupleInStruct({field: [1, 2, 3]}); - assert.deepEqual({field: [1, 2, 3]}, d); + var d = cm.emval_test_take_and_return_TupleInStruct({field: [1, 2, 3, 4]}); + assert.deepEqual({field: [1, 2, 3, 4]}, d); }); test("can clone handles", function() { @@ -1364,9 +1364,9 @@ module({ called = true; assert.equal(10, i); assert.equal(1.5, f); - assert.deepEqual([1.25, 2.5, 3.75], tv); - assert.deepEqual({x: 1.25, y: 2.5, z: 3.75}, sv); - }, 10, 1.5, [1.25, 2.5, 3.75], {x: 1.25, y: 2.5, z: 3.75}); + assert.deepEqual([1.25, 2.5, 3.75, 4], tv); + assert.deepEqual({x: 1.25, y: 2.5, z: 3.75, w:4}, sv); + }, 10, 1.5, [1.25, 2.5, 3.75, 4], {x: 1.25, y: 2.5, z: 3.75, w:4}); assert.true(called); }); }); @@ -1575,8 +1575,8 @@ module({ BaseFixture.extend("constants", function() { assert.equal(10, cm.INT_CONSTANT); assert.equal("some string", cm.STRING_CONSTANT); - assert.deepEqual([1, 2, 3], cm.VALUE_TUPLE_CONSTANT); - assert.deepEqual({x:1,y:2,z:3}, cm.VALUE_STRUCT_CONSTANT); + assert.deepEqual([1, 2, 3, 4], cm.VALUE_TUPLE_CONSTANT); + assert.deepEqual({x:1,y:2,z:3,w:4}, cm.VALUE_STRUCT_CONSTANT); }); }); diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 1ef3fb16937cf..ea332f2d9c6e0 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -721,7 +721,20 @@ std::map embind_test_get_string_int_map() { }; struct Vector { - float x, y, z; + Vector() = delete; + + Vector(float x_, float y_, float z_, float w_) + : x(x_) + , y(y_) + , z(z_) + , w(w_) + {} + + float x, y, z, w; + + float& operator[](int i) { + return (&x)[i]; + } float getY() const { return y; @@ -736,9 +749,13 @@ struct DummyDataToTestPointerAdjustment { }; struct TupleVector : DummyDataToTestPointerAdjustment, Vector { + TupleVector(): Vector(0, 0, 0, 0) {} + TupleVector(float x, float y, float z, float w): Vector(x, y, z, w) {} }; struct StructVector : DummyDataToTestPointerAdjustment, Vector { + StructVector(): Vector(0, 0, 0, 0) {} + StructVector(float x, float y, float z, float w): Vector(x, y, z, w) {} }; float readVectorZ(const Vector& v) { @@ -750,15 +767,11 @@ void writeVectorZ(Vector& v, float z) { } struct TupleVectorTuple { - TupleVector v; + TupleVector v = TupleVector(0, 0, 0, 0); }; TupleVector emval_test_return_TupleVector() { - TupleVector cv; - cv.x = 1; - cv.y = 2; - cv.z = 3; - return cv; + return TupleVector(1, 2, 3, 4); } TupleVector emval_test_take_and_return_TupleVector(TupleVector v) { @@ -772,11 +785,7 @@ TupleVectorTuple emval_test_return_TupleVectorTuple() { } StructVector emval_test_return_StructVector() { - StructVector v; - v.x = 1; - v.y = 2; - v.z = 3; - return v; + return StructVector(1, 2, 3, 4); } StructVector emval_test_take_and_return_StructVector(StructVector v) { @@ -1433,16 +1442,10 @@ EMSCRIPTEN_BINDINGS(constants) { constant("INT_CONSTANT", 10); constant("STRING_CONSTANT", std::string("some string")); - TupleVector tv; - tv.x = 1; - tv.y = 2; - tv.z = 3; + TupleVector tv(1, 2, 3, 4); constant("VALUE_TUPLE_CONSTANT", tv); - StructVector sv; - sv.x = 1; - sv.y = 2; - sv.z = 3; + StructVector sv(1, 2, 3, 4); constant("VALUE_STRUCT_CONSTANT", sv); } @@ -1484,6 +1487,7 @@ EMSCRIPTEN_BINDINGS(tests) { .element(&TupleVector::x) .element(&Vector::getY, &Vector::setY) .element(&readVectorZ, &writeVectorZ) + .element(index<3>()) ; function("emval_test_return_TupleVector", &emval_test_return_TupleVector); @@ -1499,6 +1503,7 @@ EMSCRIPTEN_BINDINGS(tests) { .field("x", &StructVector::x) .field("y", &Vector::getY, &Vector::setY) .field("z", &readVectorZ, &writeVectorZ) + .field("w", index<3>()) ; function("emval_test_return_StructVector", &emval_test_return_StructVector); From 545dc8ef97e90ffc1a5a62c59edffdc6e3b8e0b3 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 4 Apr 2013 02:03:48 -0700 Subject: [PATCH 384/544] support overloaded index access --- system/include/emscripten/bind.h | 22 ++++------------------ tests/embind/embind_test.cpp | 4 ++++ 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 81ee38e98805c..a0e825ad15cda 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -472,14 +472,6 @@ namespace emscripten { const noncopyable& operator=(const noncopyable&) = delete; }; - template - struct ReturnType; - - template - struct ReturnType { - typedef RT type; - }; - template typename BindingType::WireType get_by_index(int index, ClassType& ptr) { return BindingType::toWireType(ptr[index]); @@ -553,11 +545,8 @@ namespace emscripten { template value_tuple& element(index) { using namespace internal; - typedef - typename std::remove_reference< - typename ReturnType::type - >::type - ElementType; + ClassType* null = 0; + typedef typename std::remove_reference::type ElementType; _embind_register_tuple_element( TypeID::get(), TypeID::get(), @@ -633,11 +622,8 @@ namespace emscripten { template value_struct& field(const char* fieldName, index) { using namespace internal; - typedef - typename std::remove_reference< - typename ReturnType::type - >::type - ElementType; + ClassType* null = 0; + typedef typename std::remove_reference::type ElementType; _embind_register_struct_field( TypeID::get(), fieldName, diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index ea332f2d9c6e0..1384406a00008 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -736,6 +736,10 @@ struct Vector { return (&x)[i]; } + const float& operator[](int i) const { + return (&x)[i]; + } + float getY() const { return y; } From 8ee0c6a12d1488c2fa131da25db91de0d2d44203 Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Thu, 4 Apr 2013 18:08:04 +0300 Subject: [PATCH 385/544] Use _embind_repr instead of IMVU.repr in embind.js, since IMVU.repr is not available in kripken/emscripten. --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index a38e0bcc67e01..ee717f4be2409 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -641,7 +641,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { } } if (!(handle instanceof this.registeredClass.constructor)) { - throwBindingError('Expected null or instance of ' + this.name + ', got ' + IMVU.repr(handle)); + throwBindingError('Expected null or instance of ' + this.name + ', got ' + _embind_repr(handle)); } // TODO: this is not strictly true // We could support BY_EMVAL conversions from raw pointers to smart pointers From 01c2ac873fdd7c219bea0dfa8cf3ba9580d8a933 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Thu, 4 Apr 2013 22:45:40 +0700 Subject: [PATCH 386/544] Stop using cxa_demangle in embind. With an updated libcxx, we no longer have libcxxabi in the include path, so we can't have the demangling code in the build. --- system/lib/embind/bind.cpp | 6 ++++++ tests/embind/embind.test.js | 18 +++++++++--------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 417d9ffd6b356..1619eddcb2c35 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -1,5 +1,7 @@ #include +#ifdef USE_CXA_DEMANGLE #include <../lib/libcxxabi/include/cxxabi.h> +#endif #include #include #include @@ -11,6 +13,7 @@ using namespace emscripten; extern "C" { const char* EMSCRIPTEN_KEEPALIVE __getTypeName(const std::type_info* ti) { +#ifdef USE_CXA_DEMANGLE int stat; char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat); if (stat == 0 && demangled) { @@ -27,6 +30,9 @@ extern "C" { default: return strdup(""); } +#else + return strdup(ti->name()); +#endif } } diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index f365c1b8617fa..290fed7238c22 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -1487,7 +1487,7 @@ module({ function() { cm.getUnboundClass(); }, - 'Cannot call getUnboundClass due to unbound types: UnboundClass'); + 'Cannot call getUnboundClass due to unbound types: 12UnboundClass'); }); test("unbound base class produces error", function() { @@ -1495,14 +1495,14 @@ module({ function() { cm.getHasUnboundBase(); }, - 'Cannot call getHasUnboundBase due to unbound types: UnboundClass'); + 'Cannot call getHasUnboundBase due to unbound types: 12UnboundClass'); }); test("construct of class with unbound base", function() { assertMessage( function() { new cm.HasUnboundBase; - }, 'Cannot construct HasUnboundBase due to unbound types: UnboundClass'); + }, 'Cannot construct HasUnboundBase due to unbound types: 12UnboundClass'); }); test("unbound constructor argument", function() { @@ -1510,7 +1510,7 @@ module({ function() { new cm.HasConstructorUsingUnboundArgument(1); }, - 'Cannot construct HasConstructorUsingUnboundArgument due to unbound types: UnboundClass'); + 'Cannot construct HasConstructorUsingUnboundArgument due to unbound types: 12UnboundClass'); }); test("unbound constructor argument of class with unbound base", function() { @@ -1518,7 +1518,7 @@ module({ function() { new cm.HasConstructorUsingUnboundArgumentAndUnboundBase; }, - 'Cannot construct HasConstructorUsingUnboundArgumentAndUnboundBase due to unbound types: SecondUnboundClass'); + 'Cannot construct HasConstructorUsingUnboundArgumentAndUnboundBase due to unbound types: 18SecondUnboundClass'); }); test('class function with unbound argument', function() { @@ -1526,7 +1526,7 @@ module({ assertMessage( function() { x.method(); - }, 'Cannot call BoundClass.method due to unbound types: UnboundClass'); + }, 'Cannot call BoundClass.method due to unbound types: 12UnboundClass'); x.delete(); }); @@ -1534,7 +1534,7 @@ module({ assertMessage( function() { cm.BoundClass.classfunction(); - }, 'Cannot call BoundClass.classfunction due to unbound types: UnboundClass'); + }, 'Cannot call BoundClass.classfunction due to unbound types: 12UnboundClass'); }); test('class property of unbound type', function() { @@ -1543,11 +1543,11 @@ module({ assertMessage( function() { y = x.property; - }, 'Cannot access BoundClass.property due to unbound types: UnboundClass'); + }, 'Cannot access BoundClass.property due to unbound types: 12UnboundClass'); assertMessage( function() { x.property = 10; - }, 'Cannot access BoundClass.property due to unbound types: UnboundClass'); + }, 'Cannot access BoundClass.property due to unbound types: 12UnboundClass'); x.delete(); }); From a28ef129d6a56ae671d1f2d3aa287bbdaffc7442 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Fri, 5 Apr 2013 02:21:15 -0700 Subject: [PATCH 387/544] Allow instantiation of subclass wrappers with smart pointers. --- system/include/emscripten/bind.h | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index a0e825ad15cda..57e44c0c2b06e 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -276,6 +276,11 @@ namespace emscripten { return new ClassType(args...); } + template + WrapperType wrapped_new(Args... args) { + return WrapperType(new ClassType(args...)); + } + template ClassType* raw_constructor( typename internal::BindingType::WireType... args @@ -808,7 +813,22 @@ namespace emscripten { template struct is_ptr> { enum { value = true }; - }; + }; + + template + struct SmartPtrIfNeeded { + template + SmartPtrIfNeeded(U& cls) { + cls.template smart_ptr(); + } + }; + + template + struct SmartPtrIfNeeded { + template + SmartPtrIfNeeded(U&) { + } + }; }; template @@ -892,17 +912,17 @@ namespace emscripten { return *this; } - template + template class_& allow_subclass() { using namespace internal; - class_>(typeid(WrapperType).name()) - .template constructor() + auto cls = class_>(typeid(WrapperType).name()) ; + SmartPtrIfNeeded _(cls); return class_function( "implement", - &operator_new, + &wrapped_new, allow_raw_pointer()); } From af586c3c8e712751f2f99e10aa71c749edaeca41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 12 Apr 2013 13:03:13 +0300 Subject: [PATCH 388/544] Revert "Bring back EMSCRIPTEN_KEEPALIVE" - instead directly use the __attribute__((used)) macro in embind/bind.cpp. This reverts commit cbf636a88bcfcabf084331fc4d8a445cacb158f9. --- system/include/emscripten/emscripten.h | 2 +- system/lib/embind/bind.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index a4474670d9214..61634b0e4a6eb 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -24,7 +24,7 @@ extern "C" { * with closure, asm.js, etc. For example * -s EXPORTED_FUNCTIONS=["_main", "myfunc"] */ -#define EMSCRIPTEN_KEEPALIVE __attribute__((used)) +/* #define EMSCRIPTEN_KEEPALIVE __attribute__((used)) */ /* * Interface to the underlying JS engine. This function will diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 1619eddcb2c35..deb55138ff2f2 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -12,7 +12,7 @@ using namespace emscripten; extern "C" { - const char* EMSCRIPTEN_KEEPALIVE __getTypeName(const std::type_info* ti) { + const char* __attribute__((used)) __getTypeName(const std::type_info* ti) { #ifdef USE_CXA_DEMANGLE int stat; char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat); From 9437ede8d7d46da1715948f67b97d39475028e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 12 Apr 2013 13:26:45 +0300 Subject: [PATCH 389/544] Update AUTHORS to refer to all people who contributed to embind. --- AUTHORS | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/AUTHORS b/AUTHORS index 87a656d66caee..d3463c8d4d9a0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -24,7 +24,7 @@ a license to everyone to use it as detailed in LICENSE.) * Pierre Renaux * Brian Anderson * Jon Bardin -* Jukka Jylänki +* Jukka Jylänki * Aleksander Guryanov * Chad Austin (copyright owned by IMVU) * nandhp @@ -46,7 +46,7 @@ a license to everyone to use it as detailed in LICENSE.) * Anthony Liot * Michael Riss * Jasper St. Pierre -* Manuel Schölling +* Manuel Schölling * Bruce Mitchener, Jr. * Michael Bishop * Roger Braun @@ -57,9 +57,13 @@ a license to everyone to use it as detailed in LICENSE.) * Ting-Yuan Huang * Joshua Granick * Felix H. Dahlke -* Éloi Rivard +* Éloi Rivard * Alexander Gladysh -* Arlo Breault -* Jacob Lee (copyright owned by Google, Inc.) +* Arlo Breault * Jacob Lee (copyright owned by Google, Inc.) * Joe Lee (copyright owned by IMVU) - +* Andy Friesen (copyright owned by IMVU) +* Bill Welden (copyright owned by IMVU) +* Michael Ey (copyright owned by IMVU) +* Llorens Marti Garcia (copyright owned by IMVU) +* Jinsuck Kim (copyright owned by IMVU) +* Todd Lee (copyright owned by IMVU) From 26f97461214052df80f3310f856670aebcf84d37 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Apr 2013 09:30:04 -0700 Subject: [PATCH 390/544] avoid emitting non-asm code for cxa_find_matching_catch --- src/jsifier.js | 2 +- src/library.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/jsifier.js b/src/jsifier.js index 2a9dc5bd32bbf..82cdced6a3b82 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1211,7 +1211,7 @@ function JSify(data, functionsOnly, givenFunctions) { }); makeFuncLineActor('landingpad', function(item) { var catchTypeArray = item.catchables.map(finalizeLLVMParameter).join(','); - var ret = '___cxa_find_matching_catch('+ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') +',' + makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') + (catchTypeArray.length > 0 ? ',' + catchTypeArray : '') +')'; + var ret = asmCoercion('___cxa_find_matching_catch(-1, -1' + (catchTypeArray.length > 0 ? ',' + catchTypeArray : '') +')', 'i32'); if (USE_TYPED_ARRAYS == 2) { ret = makeVarDef(item.assignTo) + '$0 = ' + ret + '; ' + item.assignTo + '$1 = tempRet0;'; item.assignTo = null; diff --git a/src/library.js b/src/library.js index f58c7150727c3..294ab200a4504 100644 --- a/src/library.js +++ b/src/library.js @@ -5158,6 +5158,8 @@ LibraryManager.library = { __cxa_find_matching_catch__deps: ['__cxa_does_inherit', '__cxa_is_number_type'], __cxa_find_matching_catch: function(thrown, throwntype) { + if (thrown == -1) thrown = {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}}; + if (throwntype == -1) throwntype = {{{ makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') }}}; var typeArray = Array.prototype.slice.call(arguments, 2); // If throwntype is a pointer, this means a pointer has been From 835c1e426ab0967d65bd41303c646c8e904a82d3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Apr 2013 10:55:50 -0700 Subject: [PATCH 391/544] fix forced calls through invoke_* --- src/jsifier.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 82cdced6a3b82..8a3ac25ed80c2 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1426,10 +1426,12 @@ function JSify(data, functionsOnly, givenFunctions) { var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs); if (ASM_JS) { assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out) - if (!forceByPointer) { + if (!byPointerForced) { callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py } else { - // add initial argument for invoke. note: no need to update argsTypes at this point + // This is a forced call, through an invoke_*. + // note: no need to update argsTypes at this point + Functions.unimplementedFunctions[callIdent] = sig; args.unshift(byPointerForced ? Functions.getIndex(callIdent) : callIdent); callIdent = 'invoke_' + sig; } From 2d9dd53139cfa452d4eaa4c2df7ac70ddac640c9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Apr 2013 11:34:53 -0700 Subject: [PATCH 392/544] move exception resuming into a dedicated function --- src/jsifier.js | 4 +--- src/library.js | 11 ++++++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 8a3ac25ed80c2..08126e45775d1 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1149,9 +1149,7 @@ function JSify(data, functionsOnly, givenFunctions) { } // If there is no current exception, set this one as it (during a resume, the current exception can be wiped out) var ptr = makeStructuralAccess(item.ident, 0); - return (EXCEPTION_DEBUG ? 'Module.print("Resuming exception");' : '') + - 'if (' + makeGetValue('_llvm_eh_exception.buf', 0, 'void*') + ' == 0) { ' + makeSetValue('_llvm_eh_exception.buf', 0, ptr, 'void*') + ' } ' + - makeThrow(ptr) + ';'; + return '___resumeException(' + asmCoercion(ptr, 'i32') + ')'; }); makeFuncLineActor('invoke', function(item) { // Wrapping in a function lets us easily return values if we are diff --git a/src/library.js b/src/library.js index 294ab200a4504..2e0f3afb02e2e 100644 --- a/src/library.js +++ b/src/library.js @@ -5156,7 +5156,7 @@ LibraryManager.library = { // functionality boils down to picking a suitable 'catch' block. // We'll do that here, instead, to keep things simpler. - __cxa_find_matching_catch__deps: ['__cxa_does_inherit', '__cxa_is_number_type'], + __cxa_find_matching_catch__deps: ['__cxa_does_inherit', '__cxa_is_number_type', '__resumeException'], __cxa_find_matching_catch: function(thrown, throwntype) { if (thrown == -1) thrown = {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}}; if (throwntype == -1) throwntype = {{{ makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') }}}; @@ -5185,6 +5185,15 @@ LibraryManager.library = { {{{ makeStructuralReturn(['thrown', 'throwntype']) }}}; }, + __resumeException__deps: [function() { Functions.libraryFunctions['__resumeException'] = 1 }], // will be called directly from compiled code + __resumeException: function(ptr) { +#if EXCEPTION_DEBUG + Module.print("Resuming exception"); +#endif + if ({{{ makeGetValue('_llvm_eh_exception.buf', 0, 'void*') }}} == 0) {{{ makeSetValue('_llvm_eh_exception.buf', 0, 'ptr', 'void*') }}}; + {{{ makeThrow('ptr') }}}; + }, + // Recursively walks up the base types of 'possibilityType' // to see if any of them match 'definiteType'. __cxa_does_inherit__deps: ['__cxa_is_number_type'], From 1ea464d00828740ed7c898a9ac9eefdedbb2f7da Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Apr 2013 11:38:54 -0700 Subject: [PATCH 393/544] asm-coerce arguments to invoke_* --- src/jsifier.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jsifier.js b/src/jsifier.js index 08126e45775d1..927ffcb985d1f 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1346,7 +1346,7 @@ function JSify(data, functionsOnly, givenFunctions) { args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) }); if (ASM_JS) { - if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions) { + if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced) { args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) }); } else { args = args.map(function(arg, i) { return asmEnsureFloat(arg, argsTypes[i]) }); From 3a4bb38d59ae7008faad2a304534bb29b213e8d8 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Apr 2013 15:41:12 -0700 Subject: [PATCH 394/544] fix __THREW__ initialization in asm.js invokes; test_exceptions now enabled and working in asm.js --- src/jsifier.js | 4 +++- tests/runner.py | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 927ffcb985d1f..fb5e9a5fca683 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1160,8 +1160,10 @@ function JSify(data, functionsOnly, givenFunctions) { var ret; - if (disabled || ASM_JS) { // TODO: EXCEPTION_DEBUG for asm.js + if (disabled) { ret = call_ + ';'; + } else if (ASM_JS) { + ret = '(__THREW__ = 0,' + call_ + ');'; } else { ret = '(function() { try { __THREW__ = 0; return ' + call_ + ' ' diff --git a/tests/runner.py b/tests/runner.py index fd9f784268c9d..3c8f2d161f78e 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -2486,7 +2486,6 @@ def test_longjmp4(self): ''') def test_exceptions(self): - if Settings.ASM_JS: return self.skip('no exceptions support in asm') if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1") if self.emcc_args is None: return self.skip('need emcc to add in libcxx properly') From aeb63def9502e56437b74e222739c36af0b9c72f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Apr 2013 15:44:56 -0700 Subject: [PATCH 395/544] enable two more exceptions tests in asm.js --- tests/runner.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 3c8f2d161f78e..def4bfc9c3e01 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -2575,7 +2575,6 @@ class MyException self.do_run(src, 'Throw...Construct...Catched...Destruct...Throw...Construct...Copy...Catched...Destruct...Destruct...') def test_white_list_exception(self): - if Settings.ASM_JS: return self.skip('no exceptions support in asm') Settings.DISABLE_EXCEPTION_CATCHING = 2 Settings.EXCEPTION_CATCHING_WHITELIST = ["__Z12somefunctionv"] Settings.INLINING_LIMIT = 50 # otherwise it is inlined and not identified @@ -2607,9 +2606,7 @@ def test_white_list_exception(self): Settings.DISABLE_EXCEPTION_CATCHING = 0 Settings.EXCEPTION_CATCHING_WHITELIST = [] - def test_uncaught_exception(self): - if Settings.ASM_JS: return self.skip('no exceptions support in asm') if self.emcc_args is None: return self.skip('no libcxx inclusion without emcc') Settings.DISABLE_EXCEPTION_CATCHING = 0 From 94aa7b917086053fbf4f6125daad8bb1bd889190 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Apr 2013 15:52:13 -0700 Subject: [PATCH 396/544] coerce arguments to cxa_find_matching_catch; enable remaining asm.js exceptions tests --- src/jsifier.js | 2 +- tests/runner.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index fb5e9a5fca683..262dd3eb97bac 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1210,7 +1210,7 @@ function JSify(data, functionsOnly, givenFunctions) { } }); makeFuncLineActor('landingpad', function(item) { - var catchTypeArray = item.catchables.map(finalizeLLVMParameter).join(','); + var catchTypeArray = item.catchables.map(finalizeLLVMParameter).map(function(element) { return asmCoercion(element, 'i32') }).join(','); var ret = asmCoercion('___cxa_find_matching_catch(-1, -1' + (catchTypeArray.length > 0 ? ',' + catchTypeArray : '') +')', 'i32'); if (USE_TYPED_ARRAYS == 2) { ret = makeVarDef(item.assignTo) + '$0 = ' + ret + '; ' + item.assignTo + '$1 = tempRet0;'; diff --git a/tests/runner.py b/tests/runner.py index def4bfc9c3e01..890d42e7c3f7f 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -2646,7 +2646,6 @@ def test_uncaught_exception(self): self.do_run(src, 'success') def test_typed_exceptions(self): - if Settings.ASM_JS: return self.skip('no exceptions support in asm') Settings.DISABLE_EXCEPTION_CATCHING = 0 Settings.SAFE_HEAP = 0 # Throwing null will cause an ignorable null pointer access. src = open(path_from_root('tests', 'exceptions', 'typed.cpp'), 'r').read() @@ -2654,7 +2653,6 @@ def test_typed_exceptions(self): self.do_run(src, expected) def test_multiexception(self): - if Settings.ASM_JS: return self.skip('no exceptions support in asm') Settings.DISABLE_EXCEPTION_CATCHING = 0 src = r''' #include From f0c69a1cfeb7ec8050f3f22a05087335b6f56f38 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Apr 2013 16:55:36 -0700 Subject: [PATCH 397/544] handle inline struct definitions (assuming zeroinit) in illegal insertvalue, and add testcase based on gmp.js --- src/analyzer.js | 4 ++++ tests/cases/uadd_overflow_ta2.ll | 6 ++++++ tests/cases/uadd_overflow_ta2.txt | 1 + 3 files changed, 11 insertions(+) diff --git a/src/analyzer.js b/src/analyzer.js index c10f18cc4b09d..3921cab8e644f 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -124,6 +124,10 @@ function analyzer(data, sidePass) { bits = bits || 32; // things like pointers are all i32, but show up as 0 bits from getBits if (allowLegal && bits <= 32) return [{ ident: base + ('i' + bits in Runtime.INT_TYPES ? '' : '$0'), bits: bits }]; if (isNumber(base)) return getLegalLiterals(base, bits); + if (base[0] == '{') { + warnOnce('seeing source of illegal data ' + base + ', likely an inline struct - assuming zeroinit'); + return getLegalLiterals('0', bits); + } var ret = new Array(Math.ceil(bits/32)); var i = 0; if (base == 'zeroinitializer' || base == 'undef') base = 0; diff --git a/tests/cases/uadd_overflow_ta2.ll b/tests/cases/uadd_overflow_ta2.ll index 81a76bcdf4731..feac60e3f6db1 100644 --- a/tests/cases/uadd_overflow_ta2.ll +++ b/tests/cases/uadd_overflow_ta2.ll @@ -33,6 +33,12 @@ entry: %64ba2 = zext i1 %64ba1 to i32 call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @.str2, i32 0, i32 0), i32 %64ba0, i32 %64ba2) ; [#uses=0] + %zbuadd1 = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 10, 0 ; undef and explicit + %zba0 = extractvalue { i32, i1 } %zbuadd1, 0 + %zba1 = extractvalue { i32, i1 } %zbuadd1, 1 + %zba2 = zext i1 %ba1 to i32 + call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @.str2, i32 0, i32 0), i32 %zba0, i32 %zba2) ; [#uses=0] + ret i32 1 } diff --git a/tests/cases/uadd_overflow_ta2.txt b/tests/cases/uadd_overflow_ta2.txt index bcd04599696a5..81513080d9bd6 100644 --- a/tests/cases/uadd_overflow_ta2.txt +++ b/tests/cases/uadd_overflow_ta2.txt @@ -1,3 +1,4 @@ *3319578,1* *5177,0* *9875,1* +*10,0* From 06876b9f0ef559553afb708462042fbade0a33c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Fri, 12 Apr 2013 02:05:52 +0200 Subject: [PATCH 398/544] * Little improvements of file_packager.py --- tools/file_packager.py | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/tools/file_packager.py b/tools/file_packager.py index 73ff4919bc83b..8a7cca853eade 100644 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -11,7 +11,7 @@ Usage: - file_packager.py TARGET [--preload A [B..]] [--embed C [D..]] [--compress COMPRESSION_DATA] [--pre-run] [--crunch[=X]] + file_packager.py TARGET [--preload A [B..]] [--embed C [D..]] [--compress COMPRESSION_DATA] [--pre-run] [--crunch[=X]] [--js-output=OUTPUT.js] --pre-run Will generate wrapper code that does preloading in Module.preRun. This is necessary if you add this code before the main file has been loading, which includes necessary components like addRunDependency. @@ -39,6 +39,11 @@ from shared import Compression, execute, suffix, unsuffixed from subprocess import Popen, PIPE, STDOUT +if len(sys.argv) == 1: + print '''Usage: file_packager.py TARGET [--preload A...] [--embed C...] [--compress COMPRESSION_DATA] [--pre-run] [--crunch[=X]] [--js-output=OUTPUT.js] +See the source for more details.''' + sys.exit(0) + data_target = sys.argv[1] IMAGE_SUFFIXES = ('.jpg', '.png', '.bmp') @@ -59,6 +64,7 @@ pre_run = False crunch = 0 plugins = [] +jsoutput = None for arg in sys.argv[1:]: if arg == '--preload': @@ -80,6 +86,8 @@ in_preload = False in_embed = False in_compress = 0 + elif arg.startswith('--js-output'): + jsoutput = arg.split('=')[1] if '=' in arg else None elif arg.startswith('--crunch'): from shared import CRUNCH crunch = arg.split('=')[1] if '=' in arg else '128' @@ -93,9 +101,11 @@ in_embed = False in_compress = 0 elif in_preload: - data_files.append({ 'name': arg, 'mode': 'preload' }) + if os.path.isfile(arg): + data_files.append({ 'name': arg, 'mode': 'preload' }) elif in_embed: - data_files.append({ 'name': arg, 'mode': 'embed' }) + if os.path.isfile(arg): + data_files.append({ 'name': arg, 'mode': 'embed' }) elif in_compress: if in_compress == 1: Compression.encoder = arg @@ -107,7 +117,7 @@ Compression.js_name = arg in_compress = 0 -print ''' +ret = ''' (function() { ''' @@ -152,7 +162,7 @@ def was_seen(name): # Crunch files if crunch: shutil.copyfile(shared.path_from_root('tools', 'crunch-worker.js'), 'crunch-worker.js') - print ''' + ret += ''' var decrunchWorker = new Worker('crunch-worker.js'); var decrunchCallbacks = []; decrunchWorker.onmessage = function(msg) { @@ -386,26 +396,30 @@ def was_seen(name): ''' % (data_target, os.path.basename(Compression.compressed_name(data_target) if Compression.on else data_target), use_data, data_target) # use basename because from the browser's point of view, we need to find the datafile in the same dir as the html file if pre_run: - print ''' + ret += ''' if (typeof Module == 'undefined') Module = {}; if (!Module['preRun']) Module['preRun'] = []; Module["preRun"].push(function() { ''' - -print code +ret += code if pre_run: - print ' });\n' + ret += ' });\n' if crunch: - print ''' + ret += ''' if (!Module['postRun']) Module['postRun'] = []; Module["postRun"].push(function() { decrunchWorker.terminate(); }); ''' -print ''' +ret += ''' })(); ''' +if jsoutput == None: + print ret +else: + f = open(jsoutput, 'w') + f.write(ret) From 3868ec7853d6fcdb7c4183b18137f10739ed8b39 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 13 Apr 2013 09:16:19 -0700 Subject: [PATCH 399/544] refactor option to use full js in configure, add EMCONFIGURE_JS option --- emcc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/emcc b/emcc index adca126691b9f..03d92fd3664c3 100755 --- a/emcc +++ b/emcc @@ -519,7 +519,7 @@ CONFIGURE_CONFIG = (os.environ.get('EMMAKEN_JUST_CONFIGURE') or 'conftest.c' in CMAKE_CONFIG = 'CMakeFiles/cmTryCompileExec.dir' in ' '.join(sys.argv)# or 'CMakeCCompilerId' in ' '.join(sys.argv) if CONFIGURE_CONFIG or CMAKE_CONFIG: debug_configure = 0 # XXX use this to debug configure stuff. ./configure's generally hide our normal output including stderr so we write to a file - use_clang = 1 # whether we fake configure tests using clang - the local, native compiler - or not. if not we generate JS and use node with a shebang + use_js = os.environ.get('EMCONFIGURE_JS') # whether we fake configure tests using clang - the local, native compiler - or not. if not we generate JS and use node with a shebang # neither approach is perfect, you can try both, but may need to edit configure scripts in some cases # XXX False is not fully tested yet @@ -536,13 +536,16 @@ if CONFIGURE_CONFIG or CMAKE_CONFIG: if debug_configure: open(tempout, 'a').write('============= ' + sys.argv[i] + '\n' + src + '\n=============\n\n') except: pass + if sys.argv[i].endswith('.s'): + if debug_configure: open(tempout, 'a').write('(compiling .s assembly, must use clang\n') + use_js = 0 if src: if 'fopen' in src and '"w"' in src: - use_clang = True # we cannot write to files from js! + use_js = 0 # we cannot write to files from js! if debug_configure: open(tempout, 'a').write('Forcing clang since uses fopen to write\n') - compiler = os.environ.get('CONFIGURE_CC') or (shared.CLANG if use_clang else shared.EMCC) # if CONFIGURE_CC is defined, use that. let's you use local gcc etc. if you need that + compiler = os.environ.get('CONFIGURE_CC') or (shared.CLANG if not use_js else shared.EMCC) # if CONFIGURE_CC is defined, use that. let's you use local gcc etc. if you need that if not ('CXXCompiler' in ' '.join(sys.argv) or os.environ.get('EMMAKEN_CXX')): compiler = shared.to_cc(compiler) @@ -561,12 +564,12 @@ if CONFIGURE_CONFIG or CMAKE_CONFIG: idx += 1 cmd = [compiler] + list(filter_emscripten_options(sys.argv[1:])) - if use_clang: cmd += shared.EMSDK_OPTS + ['-DEMSCRIPTEN'] + if not use_js: cmd += shared.EMSDK_OPTS + ['-DEMSCRIPTEN'] if DEBUG: print >> sys.stderr, 'emcc, just configuring: ', ' '.join(cmd) if debug_configure: open(tempout, 'a').write('emcc, just configuring: ' + ' '.join(cmd) + '\n\n') - if use_clang: + if not use_js: exit(subprocess.call(cmd)) else: only_object = '-c' in cmd @@ -589,7 +592,7 @@ if CONFIGURE_CONFIG or CMAKE_CONFIG: shutil.copyfile(target, target[:-3]) target = target[:-3] src = open(target).read() - full_node = shared.NODE_JS + full_node = ' '.join(shared.listify(shared.NODE_JS)) if os.path.sep not in full_node: full_node = '/usr/bin/' + full_node # TODO: use whereis etc. And how about non-*NIX? open(target, 'w').write('#!' + full_node + '\n' + src) # add shebang From 447c639b3bb7bbf4a37c53243d2948fadfba4ce6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 13 Apr 2013 09:27:31 -0700 Subject: [PATCH 400/544] fix legalization of nonexistent call return values --- src/analyzer.js | 5 +++-- tests/cases/call_i64_noret.ll | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 tests/cases/call_i64_noret.ll diff --git a/src/analyzer.js b/src/analyzer.js index 3921cab8e644f..df5a435e52254 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -324,12 +324,13 @@ function analyzer(data, sidePass) { } // call, return: Return the first 32 bits, the rest are in temp case 'call': { - bits = getBits(value.type); - var elements = getLegalVars(item.assignTo, bits); var toAdd = [value]; // legalize parameters legalizeFunctionParameters(value.params); + // legalize return value, if any if (value.assignTo && isIllegalType(item.type)) { + bits = getBits(value.type); + var elements = getLegalVars(item.assignTo, bits); // legalize return value value.assignTo = elements[0].ident; for (var j = 1; j < elements.length; j++) { diff --git a/tests/cases/call_i64_noret.ll b/tests/cases/call_i64_noret.ll new file mode 100644 index 0000000000000..a8a30fc0f3eff --- /dev/null +++ b/tests/cases/call_i64_noret.ll @@ -0,0 +1,17 @@ +; ModuleID = 'tests/hello_world.bc' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128" +target triple = "i386-pc-linux-gnu" + +@.str = private unnamed_addr constant [15 x i8] c"hello, world!\0A\00", align 1 ; [#uses=1 type=[15 x i8]*] + +; [#uses=0] +define i32 @main() { +entry: + %retval = alloca i32, align 4 ; [#uses=1 type=i32*] + store i32 0, i32* %retval + call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0), i64 0) ; [#uses=0 type=i32] + ret i32 1 +} + +; [#uses=1] +declare i32 @printf(i8*, ...) From 2ce87cf7d9c3ce1ccb5ad13dc21d0d31599f7396 Mon Sep 17 00:00:00 2001 From: Arlo Breault Date: Sat, 13 Apr 2013 14:57:50 -0700 Subject: [PATCH 401/544] socketpair --- src/library.js | 15 +++++++++++++++ system/include/sys/socket.h | 1 + 2 files changed, 16 insertions(+) diff --git a/src/library.js b/src/library.js index 2e0f3afb02e2e..2e24a462ef2c3 100644 --- a/src/library.js +++ b/src/library.js @@ -6568,6 +6568,7 @@ LibraryManager.library = { ENOTSUP: 95, ENOTTY: 25, ENXIO: 6, + EOPNOTSUPP: 45, EOVERFLOW: 75, EOWNERDEAD: 130, EPERM: 1, @@ -6649,6 +6650,7 @@ LibraryManager.library = { 95: 'Operation not supported', 25: 'Inappropriate ioctl for device', 6: 'No such device or address', + 45: 'Op not supported on transport endpoint', 75: 'Value too large for defined data type', 130: 'Owner died', 1: 'Operation not permitted', @@ -7393,6 +7395,19 @@ LibraryManager.library = { } }, + socketpair__deps: ['__setErrNo', '$ERRNO_CODES', 'pipe'], + socketpair: function(domain, type, protocol, sv) { + // int socketpair(int domain, int type, int protocol, int sv[2]); + // http://sources.iwp9.org/files/plan9/sys/src/ape/lib/bsd/socketpair.c + switch (domain) { + case {{{ cDefine('PF_UNIX') }}}: + return _pipe(sv); + default: + ___setErrNo(ERRNO_CODES.EOPNOTSUPP); + return -1; + } + }, + // pty.h openpty: function() { throw 'openpty: TODO' }, diff --git a/system/include/sys/socket.h b/system/include/sys/socket.h index 8ca6eccf8380b..56a37375247e2 100644 --- a/system/include/sys/socket.h +++ b/system/include/sys/socket.h @@ -68,6 +68,7 @@ ssize_t recv(int s, void *buf, size_t len, int flags); ssize_t send(int s, const void *buf, size_t len, int flags); int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen); ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); +int socketpair(int domain, int type, int protocol, int sv[2]); struct msghdr { From 346766e19c90bda92232815d93ea29e88563b7fe Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 13 Apr 2013 15:33:47 -0700 Subject: [PATCH 402/544] disable memory init file in benchmarks --- tests/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runner.py b/tests/runner.py index 890d42e7c3f7f..37cb30adc0350 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -12130,7 +12130,7 @@ def do_benchmark(self, name, src, args=[], expected_output='FAIL', emcc_args=[], try_delete(final_filename) output = Popen([PYTHON, EMCC, filename, #'-O3', '-O2', '-s', 'INLINING_LIMIT=0', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0',# '-s', 'EXPLICIT_ZEXT=1', - '-s', 'ASM_JS=1', '-s', 'USE_MATH_IMUL=1', '--llvm-lto', '1', + '-s', 'ASM_JS=1', '-s', 'USE_MATH_IMUL=1', '--llvm-lto', '1', '--memory-init-file', '0', '-s', 'TOTAL_MEMORY=128*1024*1024', '-s', 'FAST_MEMORY=10*1024*1024', '-o', final_filename] + shared_args + emcc_args, stdout=PIPE, stderr=self.stderr_redirect).communicate() assert os.path.exists(final_filename), 'Failed to compile file: ' + output[0] From e216a8e3d7312b97e9d0822aaab27247a29d341d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 13 Apr 2013 18:12:21 -0700 Subject: [PATCH 403/544] find structural returns of >64 bits --- src/parseTools.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parseTools.js b/src/parseTools.js index 7dafbebedadb8..010f498866003 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1756,7 +1756,7 @@ function makeStructuralReturn(values, inAsm) { return 'return ' + asmCoercion(values.slice(1).map(function(value) { i++; return ASM_JS ? (inAsm ? 'tempRet' + i + ' = ' + value : 'asm.setTempRet' + i + '(' + value + ')') - : 'tempRet' + (i++) + ' = ' + value; + : 'tempRet' + i + ' = ' + value; }).concat([values[0]]).join(','), 'i32'); } else { var i = 0; From 252ca4a148b0a210f2ba8ec817981aa9557c1ffe Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 13 Apr 2013 18:13:57 -0700 Subject: [PATCH 404/544] fix overflow detection in i64 uadd, and add testcase --- src/library.js | 5 +++-- tests/cases/uadd_overflow_64_ta2.ll | 30 ++++++++++++++++++++++++++++ tests/cases/uadd_overflow_64_ta2.txt | 2 ++ 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 tests/cases/uadd_overflow_64_ta2.ll create mode 100644 tests/cases/uadd_overflow_64_ta2.txt diff --git a/src/library.js b/src/library.js index 2e0f3afb02e2e..f986413446d43 100644 --- a/src/library.js +++ b/src/library.js @@ -7482,9 +7482,10 @@ LibraryManager.library = { var l = 0, h = 0, overflow = 0; l = (a + c)>>>0; h = (b + d)>>>0; - if ((l>>>0) < (a>>>0)) { // iff we overflowed + if ((h>>>0) < (b>>>0)) overflow = 1; + if ((l>>>0) < (a>>>0)) { h = (h+1)>>>0; - overflow = 1; + if ((h>>>0) == 0) overflow = 1; // two possibilities to overflow here } {{{ makeStructuralReturn(['l|0', 'h', 'overflow'], true) }}}; }, diff --git a/tests/cases/uadd_overflow_64_ta2.ll b/tests/cases/uadd_overflow_64_ta2.ll new file mode 100644 index 0000000000000..a4f3e40ba10e6 --- /dev/null +++ b/tests/cases/uadd_overflow_64_ta2.ll @@ -0,0 +1,30 @@ +; ModuleID = 'tests/hello_world.bc' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128" +target triple = "i386-pc-linux-gnu" + +@.str2 = private constant [11 x i8] c"*%llx,%d*\0A\00", align 1 ; [#uses=1] + +; [#uses=0] +define i32 @main() { +entry: + %uadd1 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 18446744073709551606, i64 9999) + %a0 = extractvalue { i64, i1 } %uadd1, 0 + %a1 = extractvalue { i64, i1 } %uadd1, 1 + %a2 = zext i1 %a1 to i32 + call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([11 x i8]* @.str2, i32 0, i32 0), i64 %a0, i32 %a2) ; [#uses=0] + + %uadd2 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 18446744073709, i64 9999) + %b0 = extractvalue { i64, i1 } %uadd2, 0 + %b1 = extractvalue { i64, i1 } %uadd2, 1 + %b2 = zext i1 %b1 to i32 + call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([11 x i8]* @.str2, i32 0, i32 0), i64 %b0, i32 %b2) ; [#uses=0] + + ret i32 1 +} + +; [#uses=1] +declare i32 @printf(i8*, ...) + +declare { i32, i1 } @llvm.uadd.with.overflow.i32(i32, i32) nounwind readnone +declare { i64, i1 } @llvm.uadd.with.overflow.i64(i64, i64) nounwind readnone + diff --git a/tests/cases/uadd_overflow_64_ta2.txt b/tests/cases/uadd_overflow_64_ta2.txt new file mode 100644 index 0000000000000..f571130930876 --- /dev/null +++ b/tests/cases/uadd_overflow_64_ta2.txt @@ -0,0 +1,2 @@ +*2705,1* +*10c6f7a0dcfc,0* From 9445eb9e23a53e04d68cd1d9b18db1f17ad02e56 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 13 Apr 2013 22:28:59 -0700 Subject: [PATCH 405/544] remove unneeded i64Math.add import to asm --- emscripten.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten.py b/emscripten.py index 996e5cc35c636..5c3cfa3b4ff51 100755 --- a/emscripten.py +++ b/emscripten.py @@ -385,7 +385,7 @@ def make_table(sig, raw): basic_vars = ['STACKTOP', 'STACK_MAX', 'tempDoublePtr', 'ABORT'] basic_float_vars = ['NaN', 'Infinity'] if forwarded_json['Types']['preciseI64MathUsed']: - basic_funcs += ['i64Math_' + op for op in ['add', 'subtract', 'multiply', 'divide', 'modulo']] + basic_funcs += ['i64Math_' + op for op in ['subtract', 'multiply', 'divide', 'modulo']] asm_setup += ''' var i64Math_add = function(a, b, c, d) { i64Math.add(a, b, c, d) }; var i64Math_subtract = function(a, b, c, d) { i64Math.subtract(a, b, c, d) }; From be558b354748757c88d7476c490c2825ebf67539 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sun, 14 Apr 2013 09:07:48 -0700 Subject: [PATCH 406/544] remove i64Math_add --- emscripten.py | 1 - 1 file changed, 1 deletion(-) diff --git a/emscripten.py b/emscripten.py index 5c3cfa3b4ff51..a5ebbb317e4ed 100755 --- a/emscripten.py +++ b/emscripten.py @@ -387,7 +387,6 @@ def make_table(sig, raw): if forwarded_json['Types']['preciseI64MathUsed']: basic_funcs += ['i64Math_' + op for op in ['subtract', 'multiply', 'divide', 'modulo']] asm_setup += ''' -var i64Math_add = function(a, b, c, d) { i64Math.add(a, b, c, d) }; var i64Math_subtract = function(a, b, c, d) { i64Math.subtract(a, b, c, d) }; var i64Math_multiply = function(a, b, c, d) { i64Math.multiply(a, b, c, d) }; var i64Math_divide = function(a, b, c, d, e) { i64Math.divide(a, b, c, d, e) }; From eeaacf90a9e80f0b295b16233ea09d1be9cc2222 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sun, 14 Apr 2013 09:10:15 -0700 Subject: [PATCH 407/544] add compiler-rt files for 64-bit math --- system/lib/compiler-rt/LICENSE.TXT | 97 +++++++++ system/lib/compiler-rt/divdi3.c | 31 +++ system/lib/compiler-rt/int_endianness.h | 116 +++++++++++ system/lib/compiler-rt/int_lib.h | 46 +++++ system/lib/compiler-rt/int_math.h | 67 +++++++ system/lib/compiler-rt/int_types.h | 140 +++++++++++++ system/lib/compiler-rt/int_util.h | 29 +++ system/lib/compiler-rt/muldi3.c | 56 ++++++ system/lib/compiler-rt/readme.txt | 16 ++ system/lib/compiler-rt/udivdi3.c | 25 +++ system/lib/compiler-rt/udivmoddi4.c | 251 ++++++++++++++++++++++++ 11 files changed, 874 insertions(+) create mode 100644 system/lib/compiler-rt/LICENSE.TXT create mode 100644 system/lib/compiler-rt/divdi3.c create mode 100644 system/lib/compiler-rt/int_endianness.h create mode 100644 system/lib/compiler-rt/int_lib.h create mode 100644 system/lib/compiler-rt/int_math.h create mode 100644 system/lib/compiler-rt/int_types.h create mode 100644 system/lib/compiler-rt/int_util.h create mode 100644 system/lib/compiler-rt/muldi3.c create mode 100644 system/lib/compiler-rt/readme.txt create mode 100644 system/lib/compiler-rt/udivdi3.c create mode 100644 system/lib/compiler-rt/udivmoddi4.c diff --git a/system/lib/compiler-rt/LICENSE.TXT b/system/lib/compiler-rt/LICENSE.TXT new file mode 100644 index 0000000000000..6aab1f694cc2d --- /dev/null +++ b/system/lib/compiler-rt/LICENSE.TXT @@ -0,0 +1,97 @@ +============================================================================== +compiler_rt License +============================================================================== + +The compiler_rt library is dual licensed under both the University of Illinois +"BSD-Like" license and the MIT license. As a user of this code you may choose +to use it under either license. As a contributor, you agree to allow your code +to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +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 +CONTRIBUTORS 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 WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT + +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. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- +mach_override lib/interception/mach_override diff --git a/system/lib/compiler-rt/divdi3.c b/system/lib/compiler-rt/divdi3.c new file mode 100644 index 0000000000000..2c2bcc26d5811 --- /dev/null +++ b/system/lib/compiler-rt/divdi3.c @@ -0,0 +1,31 @@ +/* ===-- divdi3.c - Implement __divdi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem); + +/* Returns: a / b */ + +COMPILER_RT_ABI di_int +__divdi3(di_int a, di_int b) +{ + const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1; + di_int s_a = a >> bits_in_dword_m1; /* s_a = a < 0 ? -1 : 0 */ + di_int s_b = b >> bits_in_dword_m1; /* s_b = b < 0 ? -1 : 0 */ + a = (a ^ s_a) - s_a; /* negate if s_a == -1 */ + b = (b ^ s_b) - s_b; /* negate if s_b == -1 */ + s_a ^= s_b; /*sign of quotient */ + return (__udivmoddi4(a, b, (du_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */ +} diff --git a/system/lib/compiler-rt/int_endianness.h b/system/lib/compiler-rt/int_endianness.h new file mode 100644 index 0000000000000..1790535503cfb --- /dev/null +++ b/system/lib/compiler-rt/int_endianness.h @@ -0,0 +1,116 @@ +/* ===-- int_endianness.h - configuration header for compiler-rt ------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is a configuration header for compiler-rt. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef INT_ENDIANNESS_H +#define INT_ENDIANNESS_H + +#if defined(__SVR4) && defined(__sun) +#include + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* Solaris and AuroraUX. */ + +/* .. */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__minix) +#include + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* *BSD */ + +#if defined(__OpenBSD__) || defined(__Bitrig__) +#include + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* OpenBSD and Bitrig. */ + +/* .. */ + +/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the compiler (at least with GCC) */ +#if defined(__APPLE__) && defined(__MACH__) || defined(__ellcc__ ) + +#ifdef __BIG_ENDIAN__ +#if __BIG_ENDIAN__ +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#endif +#endif /* __BIG_ENDIAN__ */ + +#ifdef __LITTLE_ENDIAN__ +#if __LITTLE_ENDIAN__ +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif +#endif /* __LITTLE_ENDIAN__ */ + +#endif /* Mac OSX */ + +/* .. */ + +#if defined(__linux__) +#include + +#if __BYTE_ORDER == __BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* __BYTE_ORDER */ + +#endif /* GNU/Linux */ + +#if defined(_WIN32) + +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 + +#endif /* Windows */ + +#if defined(EMSCRIPTEN) + +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 + +#endif /* emscripten */ + +/* . */ + +#if !defined(_YUGA_LITTLE_ENDIAN) || !defined(_YUGA_BIG_ENDIAN) +#error Unable to determine endian +#endif /* Check we found an endianness correctly. */ + +#endif /* INT_ENDIANNESS_H */ diff --git a/system/lib/compiler-rt/int_lib.h b/system/lib/compiler-rt/int_lib.h new file mode 100644 index 0000000000000..a87426c513c66 --- /dev/null +++ b/system/lib/compiler-rt/int_lib.h @@ -0,0 +1,46 @@ +/* ===-- int_lib.h - configuration header for compiler-rt -----------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is a configuration header for compiler-rt. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef INT_LIB_H +#define INT_LIB_H + +/* Assumption: Signed integral is 2's complement. */ +/* Assumption: Right shift of signed negative is arithmetic shift. */ +/* Assumption: Endianness is little or big (not mixed). */ + +/* ABI macro definitions */ + +#if __ARM_EABI__ +# define ARM_EABI_FNALIAS(aeabi_name, name) \ + void __aeabi_##aeabi_name() __attribute__((alias("__" #name))); +# define COMPILER_RT_ABI __attribute__((pcs("aapcs"))) +#else +# define ARM_EABI_FNALIAS(aeabi_name, name) +# define COMPILER_RT_ABI +#endif + +/* Include the standard compiler builtin headers we use functionality from. */ +#include +#include +#include +#include + +/* Include the commonly used internal type definitions. */ +#include "int_types.h" + +/* Include internal utility function declarations. */ +#include "int_util.h" + +#endif /* INT_LIB_H */ diff --git a/system/lib/compiler-rt/int_math.h b/system/lib/compiler-rt/int_math.h new file mode 100644 index 0000000000000..d6b4bdae162b9 --- /dev/null +++ b/system/lib/compiler-rt/int_math.h @@ -0,0 +1,67 @@ +/* ===-- int_math.h - internal math inlines ---------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===-----------------------------------------------------------------------=== + * + * This file is not part of the interface of this library. + * + * This file defines substitutes for the libm functions used in some of the + * compiler-rt implementations, defined in such a way that there is not a direct + * dependency on libm or math.h. Instead, we use the compiler builtin versions + * where available. This reduces our dependencies on the system SDK by foisting + * the responsibility onto the compiler. + * + * ===-----------------------------------------------------------------------=== + */ + +#ifndef INT_MATH_H +#define INT_MATH_H + +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +#define CRT_INFINITY __builtin_huge_valf() + +#define crt_isinf(x) __builtin_isinf((x)) +#define crt_isnan(x) __builtin_isnan((x)) + +/* Define crt_isfinite in terms of the builtin if available, otherwise provide + * an alternate version in terms of our other functions. This supports some + * versions of GCC which didn't have __builtin_isfinite. + */ +#if __has_builtin(__builtin_isfinite) +# define crt_isfinite(x) __builtin_isfinite((x)) +#else +# define crt_isfinite(x) \ + __extension__(({ \ + __typeof((x)) x_ = (x); \ + !crt_isinf(x_) && !crt_isnan(x_); \ + })) +#endif + +#define crt_copysign(x, y) __builtin_copysign((x), (y)) +#define crt_copysignf(x, y) __builtin_copysignf((x), (y)) +#define crt_copysignl(x, y) __builtin_copysignl((x), (y)) + +#define crt_fabs(x) __builtin_fabs((x)) +#define crt_fabsf(x) __builtin_fabsf((x)) +#define crt_fabsl(x) __builtin_fabsl((x)) + +#define crt_fmax(x, y) __builtin_fmax((x), (y)) +#define crt_fmaxf(x, y) __builtin_fmaxf((x), (y)) +#define crt_fmaxl(x, y) __builtin_fmaxl((x), (y)) + +#define crt_logb(x) __builtin_logb((x)) +#define crt_logbf(x) __builtin_logbf((x)) +#define crt_logbl(x) __builtin_logbl((x)) + +#define crt_scalbn(x, y) __builtin_scalbn((x), (y)) +#define crt_scalbnf(x, y) __builtin_scalbnf((x), (y)) +#define crt_scalbnl(x, y) __builtin_scalbnl((x), (y)) + +#endif /* INT_MATH_H */ diff --git a/system/lib/compiler-rt/int_types.h b/system/lib/compiler-rt/int_types.h new file mode 100644 index 0000000000000..fcce390f9a9bf --- /dev/null +++ b/system/lib/compiler-rt/int_types.h @@ -0,0 +1,140 @@ +/* ===-- int_lib.h - configuration header for compiler-rt -----------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is not part of the interface of this library. + * + * This file defines various standard types, most importantly a number of unions + * used to access parts of larger types. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef INT_TYPES_H +#define INT_TYPES_H + +#include "int_endianness.h" + +typedef int si_int; +typedef unsigned su_int; + +typedef long long di_int; +typedef unsigned long long du_int; + +typedef union +{ + di_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + su_int low; + si_int high; +#else + si_int high; + su_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} dwords; + +typedef union +{ + du_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + su_int low; + su_int high; +#else + su_int high; + su_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} udwords; + +#if __x86_64 + +typedef int ti_int __attribute__ ((mode (TI))); +typedef unsigned tu_int __attribute__ ((mode (TI))); + +typedef union +{ + ti_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + du_int low; + di_int high; +#else + di_int high; + du_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} twords; + +typedef union +{ + tu_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + du_int low; + du_int high; +#else + du_int high; + du_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} utwords; + +static inline ti_int make_ti(di_int h, di_int l) { + twords r; + r.s.high = h; + r.s.low = l; + return r.all; +} + +static inline tu_int make_tu(du_int h, du_int l) { + utwords r; + r.s.high = h; + r.s.low = l; + return r.all; +} + +#endif /* __x86_64 */ + +typedef union +{ + su_int u; + float f; +} float_bits; + +typedef union +{ + udwords u; + double f; +} double_bits; + +typedef struct +{ +#if _YUGA_LITTLE_ENDIAN + udwords low; + udwords high; +#else + udwords high; + udwords low; +#endif /* _YUGA_LITTLE_ENDIAN */ +} uqwords; + +typedef union +{ + uqwords u; + long double f; +} long_double_bits; + +#endif /* INT_TYPES_H */ + diff --git a/system/lib/compiler-rt/int_util.h b/system/lib/compiler-rt/int_util.h new file mode 100644 index 0000000000000..1348b85eb923e --- /dev/null +++ b/system/lib/compiler-rt/int_util.h @@ -0,0 +1,29 @@ +/* ===-- int_util.h - internal utility functions ----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===-----------------------------------------------------------------------=== + * + * This file is not part of the interface of this library. + * + * This file defines non-inline utilities which are available for use in the + * library. The function definitions themselves are all contained in int_util.c + * which will always be compiled into any compiler-rt library. + * + * ===-----------------------------------------------------------------------=== + */ + +#ifndef INT_UTIL_H +#define INT_UTIL_H + +/** \brief Trigger a program abort (or panic for kernel code). */ +#define compilerrt_abort() compilerrt_abort_impl(__FILE__, __LINE__, \ + __FUNCTION__) + +void compilerrt_abort_impl(const char *file, int line, + const char *function) __attribute__((noreturn)); + +#endif /* INT_UTIL_H */ diff --git a/system/lib/compiler-rt/muldi3.c b/system/lib/compiler-rt/muldi3.c new file mode 100644 index 0000000000000..2dae44c11b959 --- /dev/null +++ b/system/lib/compiler-rt/muldi3.c @@ -0,0 +1,56 @@ +/* ===-- muldi3.c - Implement __muldi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __muldi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a * b */ + +static +di_int +__muldsi3(su_int a, su_int b) +{ + dwords r; + const int bits_in_word_2 = (int)(sizeof(si_int) * CHAR_BIT) / 2; + const su_int lower_mask = (su_int)~0 >> bits_in_word_2; + r.s.low = (a & lower_mask) * (b & lower_mask); + su_int t = r.s.low >> bits_in_word_2; + r.s.low &= lower_mask; + t += (a >> bits_in_word_2) * (b & lower_mask); + r.s.low += (t & lower_mask) << bits_in_word_2; + r.s.high = t >> bits_in_word_2; + t = r.s.low >> bits_in_word_2; + r.s.low &= lower_mask; + t += (b >> bits_in_word_2) * (a & lower_mask); + r.s.low += (t & lower_mask) << bits_in_word_2; + r.s.high += t >> bits_in_word_2; + r.s.high += (a >> bits_in_word_2) * (b >> bits_in_word_2); + return r.all; +} + +/* Returns: a * b */ + +ARM_EABI_FNALIAS(lmul, muldi3) + +COMPILER_RT_ABI di_int +__muldi3(di_int a, di_int b) +{ + dwords x; + x.all = a; + dwords y; + y.all = b; + dwords r; + r.all = __muldsi3(x.s.low, y.s.low); + r.s.high += x.s.high * y.s.low + x.s.low * y.s.high; + return r.all; +} diff --git a/system/lib/compiler-rt/readme.txt b/system/lib/compiler-rt/readme.txt new file mode 100644 index 0000000000000..1fc97635f343c --- /dev/null +++ b/system/lib/compiler-rt/readme.txt @@ -0,0 +1,16 @@ +These files are from compiler-rt, + +Last Changed Rev: 179380 +Last Changed Date: 2013-04-12 07:57:03 -0700 (Fri, 12 Apr 2013) + +=========================================================================== + +Changes: add emscripten endianness to int_endianness.h + +=========================================================================== + +Compile with something like + +./emcc system/lib/compiler-rt/*.c -Isystem/lib/compiler-rt/ -o rt.bc +./emcc -O2 -s ASM_JS=1 -g rt.bc -s LINKABLE=1 + diff --git a/system/lib/compiler-rt/udivdi3.c b/system/lib/compiler-rt/udivdi3.c new file mode 100644 index 0000000000000..6c0303df3d408 --- /dev/null +++ b/system/lib/compiler-rt/udivdi3.c @@ -0,0 +1,25 @@ +/* ===-- udivdi3.c - Implement __udivdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem); + +/* Returns: a / b */ + +COMPILER_RT_ABI du_int +__udivdi3(du_int a, du_int b) +{ + return __udivmoddi4(a, b, 0); +} diff --git a/system/lib/compiler-rt/udivmoddi4.c b/system/lib/compiler-rt/udivmoddi4.c new file mode 100644 index 0000000000000..57282d5b51c04 --- /dev/null +++ b/system/lib/compiler-rt/udivmoddi4.c @@ -0,0 +1,251 @@ +/* ===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivmoddi4 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Effects: if rem != 0, *rem = a % b + * Returns: a / b + */ + +/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */ + +COMPILER_RT_ABI du_int +__udivmoddi4(du_int a, du_int b, du_int* rem) +{ + const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT; + const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; + udwords n; + n.all = a; + udwords d; + d.all = b; + udwords q; + udwords r; + unsigned sr; + /* special cases, X is unknown, K != 0 */ + if (n.s.high == 0) + { + if (d.s.high == 0) + { + /* 0 X + * --- + * 0 X + */ + if (rem) + *rem = n.s.low % d.s.low; + return n.s.low / d.s.low; + } + /* 0 X + * --- + * K X + */ + if (rem) + *rem = n.s.low; + return 0; + } + /* n.s.high != 0 */ + if (d.s.low == 0) + { + if (d.s.high == 0) + { + /* K X + * --- + * 0 0 + */ + if (rem) + *rem = n.s.high % d.s.low; + return n.s.high / d.s.low; + } + /* d.s.high != 0 */ + if (n.s.low == 0) + { + /* K 0 + * --- + * K 0 + */ + if (rem) + { + r.s.high = n.s.high % d.s.high; + r.s.low = 0; + *rem = r.all; + } + return n.s.high / d.s.high; + } + /* K K + * --- + * K 0 + */ + if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) + { + r.s.low = n.s.low; + r.s.high = n.s.high & (d.s.high - 1); + *rem = r.all; + } + return n.s.high >> __builtin_ctz(d.s.high); + } + /* K K + * --- + * K 0 + */ + sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); + /* 0 <= sr <= n_uword_bits - 2 or sr large */ + if (sr > n_uword_bits - 2) + { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + /* 1 <= sr <= n_uword_bits - 1 */ + /* q.all = n.all << (n_udword_bits - sr); */ + q.s.low = 0; + q.s.high = n.s.low << (n_uword_bits - sr); + /* r.all = n.all >> sr; */ + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + } + else /* d.s.low != 0 */ + { + if (d.s.high == 0) + { + /* K X + * --- + * 0 K + */ + if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) + *rem = n.s.low & (d.s.low - 1); + if (d.s.low == 1) + return n.all; + sr = __builtin_ctz(d.s.low); + q.s.high = n.s.high >> sr; + q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + return q.all; + } + /* K X + * --- + *0 K + */ + sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high); + /* 2 <= sr <= n_udword_bits - 1 + * q.all = n.all << (n_udword_bits - sr); + * r.all = n.all >> sr; + * if (sr == n_uword_bits) + * { + * q.s.low = 0; + * q.s.high = n.s.low; + * r.s.high = 0; + * r.s.low = n.s.high; + * } + * else if (sr < n_uword_bits) // 2 <= sr <= n_uword_bits - 1 + * { + * q.s.low = 0; + * q.s.high = n.s.low << (n_uword_bits - sr); + * r.s.high = n.s.high >> sr; + * r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + * } + * else // n_uword_bits + 1 <= sr <= n_udword_bits - 1 + * { + * q.s.low = n.s.low << (n_udword_bits - sr); + * q.s.high = (n.s.high << (n_udword_bits - sr)) | + * (n.s.low >> (sr - n_uword_bits)); + * r.s.high = 0; + * r.s.low = n.s.high >> (sr - n_uword_bits); + * } + */ + q.s.low = (n.s.low << (n_udword_bits - sr)) & + ((si_int)(n_uword_bits - sr) >> (n_uword_bits-1)); + q.s.high = ((n.s.low << ( n_uword_bits - sr)) & + ((si_int)(sr - n_uword_bits - 1) >> (n_uword_bits-1))) | + (((n.s.high << (n_udword_bits - sr)) | + (n.s.low >> (sr - n_uword_bits))) & + ((si_int)(n_uword_bits - sr) >> (n_uword_bits-1))); + r.s.high = (n.s.high >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1)); + r.s.low = ((n.s.high >> (sr - n_uword_bits)) & + ((si_int)(n_uword_bits - sr - 1) >> (n_uword_bits-1))) | + (((n.s.high << (n_uword_bits - sr)) | + (n.s.low >> sr)) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1))); + } + else + { + /* K X + * --- + * K K + */ + sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); + /* 0 <= sr <= n_uword_bits - 1 or sr large */ + if (sr > n_uword_bits - 1) + { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + /* 1 <= sr <= n_uword_bits */ + /* q.all = n.all << (n_udword_bits - sr); */ + q.s.low = 0; + q.s.high = n.s.low << (n_uword_bits - sr); + /* r.all = n.all >> sr; + * if (sr < n_uword_bits) + * { + * r.s.high = n.s.high >> sr; + * r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + * } + * else + * { + * r.s.high = 0; + * r.s.low = n.s.high; + * } + */ + r.s.high = (n.s.high >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1)); + r.s.low = (n.s.high << (n_uword_bits - sr)) | + ((n.s.low >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1))); + } + } + /* Not a special case + * q and r are initialized with: + * q.all = n.all << (n_udword_bits - sr); + * r.all = n.all >> sr; + * 1 <= sr <= n_udword_bits - 1 + */ + su_int carry = 0; + for (; sr > 0; --sr) + { + /* r:q = ((r:q) << 1) | carry */ + r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1)); + r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1)); + q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1)); + q.s.low = (q.s.low << 1) | carry; + /* carry = 0; + * if (r.all >= d.all) + * { + * r.all -= d.all; + * carry = 1; + * } + */ + const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1); + carry = s & 1; + r.all -= d.all & s; + } + q.all = (q.all << 1) | carry; + if (rem) + *rem = r.all; + return q.all; +} From 90c4b12c0b07ca889eb5521b434f5ce258b651a1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sun, 14 Apr 2013 09:33:53 -0700 Subject: [PATCH 408/544] add handwritten asm i64Subtract --- emscripten.py | 3 +-- src/jsifier.js | 2 +- src/library.js | 13 +++++++++++++ src/long.js | 7 ------- src/parseTools.js | 2 +- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/emscripten.py b/emscripten.py index a5ebbb317e4ed..bfcc3ea5f2e97 100755 --- a/emscripten.py +++ b/emscripten.py @@ -385,9 +385,8 @@ def make_table(sig, raw): basic_vars = ['STACKTOP', 'STACK_MAX', 'tempDoublePtr', 'ABORT'] basic_float_vars = ['NaN', 'Infinity'] if forwarded_json['Types']['preciseI64MathUsed']: - basic_funcs += ['i64Math_' + op for op in ['subtract', 'multiply', 'divide', 'modulo']] + basic_funcs += ['i64Math_' + op for op in ['multiply', 'divide', 'modulo']] asm_setup += ''' -var i64Math_subtract = function(a, b, c, d) { i64Math.subtract(a, b, c, d) }; var i64Math_multiply = function(a, b, c, d) { i64Math.multiply(a, b, c, d) }; var i64Math_divide = function(a, b, c, d, e) { i64Math.divide(a, b, c, d, e) }; var i64Math_modulo = function(a, b, c, d, e) { i64Math.modulo(a, b, c, d, e) }; diff --git a/src/jsifier.js b/src/jsifier.js index 262dd3eb97bac..2cf94a0dfa439 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1606,7 +1606,7 @@ function JSify(data, functionsOnly, givenFunctions) { // "Final shape that will be created"). if (PRECISE_I64_MATH && Types.preciseI64MathUsed) { if (!INCLUDE_FULL_LIBRARY) { - ['i64Add', 'bitshift64Shl', 'bitshift64Lshr', 'bitshift64Ashr'].forEach(function(func) { + ['i64Add', 'i64Subtract', 'bitshift64Shl', 'bitshift64Lshr', 'bitshift64Ashr'].forEach(function(func) { print(processLibraryFunction(LibraryManager.library[func], func)); // must be first to be close to generated code Functions.implementedFunctions['_' + func] = LibraryManager.library[func + '__sig']; }); diff --git a/src/library.js b/src/library.js index f986413446d43..a792a681033d5 100644 --- a/src/library.js +++ b/src/library.js @@ -7490,6 +7490,19 @@ LibraryManager.library = { {{{ makeStructuralReturn(['l|0', 'h', 'overflow'], true) }}}; }, + i64Subtract__asm: true, + i64Subtract__sig: 'iiiii', + i64Subtract: function(a, b, c, d) { + a = a|0; b = b|0; c = c|0; d = d|0; + var l = 0, h = 0; + l = (a - c)>>>0; + h = (b - d)>>>0; + if ((l>>>0) > (a>>>0)) { // iff we overflowed + h = (h-1)>>>0; + } + {{{ makeStructuralReturn(['l|0', 'h'], true) }}}; + }, + bitshift64Shl__asm: true, bitshift64Shl__sig: 'iiii', bitshift64Shl: function(low, high, bits) { diff --git a/src/long.js b/src/long.js index 6d0e873d9c94f..b3d19bd34748d 100644 --- a/src/long.js +++ b/src/long.js @@ -1530,13 +1530,6 @@ var i64Math = (function() { // Emscripten wrapper // Emscripten wrapper var Wrapper = { - subtract: function(xl, xh, yl, yh) { - var x = new goog.math.Long(xl, xh); - var y = new goog.math.Long(yl, yh); - var ret = x.subtract(y); - HEAP32[tempDoublePtr>>2] = ret.low_; - HEAP32[tempDoublePtr+4>>2] = ret.high_; - }, multiply: function(xl, xh, yl, yh) { var x = new goog.math.Long(xl, xh); var y = new goog.math.Long(yl, yh); diff --git a/src/parseTools.js b/src/parseTools.js index 010f498866003..a568b7183c031 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -2062,7 +2062,7 @@ function processMathop(item) { } case 'sub': { if (PRECISE_I64_MATH) { - return i64PreciseOp('subtract'); + return i64PreciseLib('subtract'); } else { warnI64_1(); return finish(splitI64(mergeI64(idents[0]) + '-' + mergeI64(idents[1]), true)); From 2cdb053aedf15cb565553be44fe8c68a44a693c3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sun, 14 Apr 2013 09:39:23 -0700 Subject: [PATCH 409/544] add i64 testing --- tests/runner.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 37cb30adc0350..8fb6cada6005f 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -735,7 +735,8 @@ def test_i64(self): uint64_t a = 5; double b = 6.8; uint64_t c = a * b; - printf("*prod:%llu*\n*%d,%d,%d*\n", c, (int)&a, (int)&b, (int)&c); // printing addresses prevents optimizations + if (truthy()) printf("*%d,%d,%d*\n", (int)&a, (int)&b, (int)&c); // printing addresses prevents optimizations + printf("*prod:%llu*\n", c); } // Basic (rounded, for now) math. Just check compilation. @@ -764,7 +765,8 @@ def test_i64(self): '*-1,34359738367,4294967295,1073741823*\n' + '*-1,-1,-1,-1*\n' + '*-1,34359738367,4294967295,1073741823*\n' + - '*prod:34*') + '*prod:34*\n' + + '*524718382041609,49025451137,787151111239120,52476740749274*') src = r''' #include From 8bd76a3488ead4b0125e04e144a2f91e45124425 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sun, 14 Apr 2013 09:47:40 -0700 Subject: [PATCH 410/544] add more i64Subtract testing --- tests/runner.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/runner.py b/tests/runner.py index 8fb6cada6005f..8997475536b43 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -746,6 +746,14 @@ def test_i64(self): b++; if (truthy()) b--; // confuse optimizer printf("*%Ld,%Ld,%Ld,%Ld*\n", (a+b)/5000, (a-b)/5000, (a*3)/5000, (a/5)/5000); + a -= 17; if (truthy()) a += 5; // confuse optimizer + b -= 17; if (truthy()) b += 121; // confuse optimizer + printf("*%Lx,%Lx,%Lx,%Lx*\n", b - a, b - a/2, b/2 - a, b - 20); + + if (truthy()) a += 5/b; // confuse optimizer + if (truthy()) b += 121*(3+a/b); // confuse optimizer + printf("*%Lx,%Lx,%Lx,%Lx*\n", a - b, a - b/2, a/2 - b, a - 20); + return 0; } ''' @@ -766,7 +774,9 @@ def test_i64(self): '*-1,-1,-1,-1*\n' + '*-1,34359738367,4294967295,1073741823*\n' + '*prod:34*\n' + - '*524718382041609,49025451137,787151111239120,52476740749274*') + '*524718382041609,49025451137,787151111239120,52476740749274*\n' + + '*ffff210edd000002,91990876ea283be,f6e5210edcdd7c45,1234000000450765*\n' + + '*def122fffffe,91adef1232283bb,f6e66f78915d7c42,1234def123450763*\n') src = r''' #include From d18d12ccd38f7c3749ce8ead9daeef638df11212 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sun, 14 Apr 2013 11:31:56 -0700 Subject: [PATCH 411/544] asmify ctlz/cttz --- emscripten.py | 7 +++++++ src/library.js | 40 ++++++++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/emscripten.py b/emscripten.py index bfcc3ea5f2e97..7d1d82f2997a8 100755 --- a/emscripten.py +++ b/emscripten.py @@ -391,6 +391,13 @@ def make_table(sig, raw): var i64Math_divide = function(a, b, c, d, e) { i64Math.divide(a, b, c, d, e) }; var i64Math_modulo = function(a, b, c, d, e) { i64Math.modulo(a, b, c, d, e) }; ''' + + if forwarded_json['Functions']['libraryFunctions'].get('llvm_cttz_i32') or \ + forwarded_json['Functions']['libraryFunctions'].get('llvm_ctlz_i32') or \ + forwarded_json['Functions']['libraryFunctions'].get('llvm_cttz_i64') or \ + forwarded_json['Functions']['libraryFunctions'].get('llvm_ctlz_i64'): + basic_vars += ['cttz_i8', 'ctlz_i8'] + asm_runtime_funcs = ['stackAlloc', 'stackSave', 'stackRestore', 'setThrew'] + ['setTempRet%d' % i for i in range(10)] # function tables def asm_coerce(value, sig): diff --git a/src/library.js b/src/library.js index a792a681033d5..c9f161f2da4e4 100644 --- a/src/library.js +++ b/src/library.js @@ -4913,16 +4913,20 @@ LibraryManager.library = { } return 8; } - return 'var ctlz_i8 = [' + range(256).map(function(x) { return ctlz(x) }).join(',') + '];'; + return 'var ctlz_i8 = allocate([' + range(256).map(function(x) { return ctlz(x) }).join(',') + '], "i8", ALLOC_STACK);'; }], + llvm_ctlz_i32__asm: true, + llvm_ctlz_i32__sig: 'ii', llvm_ctlz_i32: function(x) { - var ret = ctlz_i8[x >>> 24]; - if (ret < 8) return ret; - var ret = ctlz_i8[(x >> 16)&0xff]; - if (ret < 8) return ret + 8; - var ret = ctlz_i8[(x >> 8)&0xff]; - if (ret < 8) return ret + 16; - return ctlz_i8[x&0xff] + 24; + x = x|0; + var ret = 0; + ret = {{{ makeGetValueAsm('ctlz_i8', 'x >>> 24', 'i8') }}}; + if ((ret|0) < 8) return ret|0; + var ret = {{{ makeGetValueAsm('ctlz_i8', '(x >> 16)&0xff', 'i8') }}}; + if ((ret|0) < 8) return (ret + 8)|0; + var ret = {{{ makeGetValueAsm('ctlz_i8', '(x >> 8)&0xff', 'i8') }}}; + if ((ret|0) < 8) return (ret + 16)|0; + return ({{{ makeGetValueAsm('ctlz_i8', 'x&0xff', 'i8') }}} + 24)|0; }, llvm_ctlz_i64__deps: ['llvm_ctlz_i32'], @@ -4945,16 +4949,20 @@ LibraryManager.library = { } return 8; } - return 'var cttz_i8 = [' + range(256).map(function(x) { return cttz(x) }).join(',') + '];'; + return 'var cttz_i8 = allocate([' + range(256).map(function(x) { return cttz(x) }).join(',') + '], "i8", ALLOC_STACK);'; }], + llvm_cttz_i32__asm: true, + llvm_cttz_i32__sig: 'ii', llvm_cttz_i32: function(x) { - var ret = cttz_i8[x & 0xff]; - if (ret < 8) return ret; - var ret = cttz_i8[(x >> 8)&0xff]; - if (ret < 8) return ret + 8; - var ret = cttz_i8[(x >> 16)&0xff]; - if (ret < 8) return ret + 16; - return cttz_i8[x >>> 24] + 24; + x = x|0; + var ret = 0; + ret = {{{ makeGetValueAsm('cttz_i8', 'x & 0xff', 'i8') }}}; + if ((ret|0) < 8) return ret|0; + var ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 8)&0xff', 'i8') }}}; + if ((ret|0) < 8) return (ret + 8)|0; + var ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 16)&0xff', 'i8') }}}; + if ((ret|0) < 8) return (ret + 16)|0; + return ({{{ makeGetValueAsm('cttz_i8', 'x >>> 24', 'i8') }}} + 24)|0; }, llvm_cttz_i64__deps: ['llvm_cttz_i32'], From cb52c13b00f65b8955f812448db15058e4303295 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sun, 14 Apr 2013 14:09:10 -0700 Subject: [PATCH 412/544] add option to move elements from post into before the asm block --- emscripten.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/emscripten.py b/emscripten.py index 7d1d82f2997a8..cec28faac4a1c 100755 --- a/emscripten.py +++ b/emscripten.py @@ -349,6 +349,13 @@ def blockaddrsize(js): post = post_rest funcs_js += ['\n' + post_funcs + '// EMSCRIPTEN_END_FUNCS\n'] + # Move preAsms to their right place + def move_preasm(m): + contents = m.groups(0)[0] + outfile.write(contents + '\n') + return '' + post = re.sub(r'/\* PRE_ASM \*/(.*)\n', lambda m: move_preasm(m), post) + simple = os.environ.get('EMCC_SIMPLE_ASM') class Counter: i = 0 From 84c58ecc4abb7af1c88cce1af3d86ffa106f22d2 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sun, 14 Apr 2013 16:17:56 -0700 Subject: [PATCH 413/544] use compiled compiler-rt code for i64 multiplication --- emscripten.py | 17 +- src/fastLong.js | 263 ++++++++++++++++++++++++++++++ src/jsifier.js | 24 ++- src/library.js | 8 +- src/long.js | 7 - src/modules.js | 2 +- src/parseTools.js | 9 +- system/lib/compiler-rt/readme.txt | 1 + 8 files changed, 304 insertions(+), 27 deletions(-) create mode 100644 src/fastLong.js diff --git a/emscripten.py b/emscripten.py index cec28faac4a1c..bae6d8cd02458 100755 --- a/emscripten.py +++ b/emscripten.py @@ -347,14 +347,15 @@ def blockaddrsize(js): if settings.get('ASM_JS'): post_funcs, post_rest = post.split('// EMSCRIPTEN_END_FUNCS\n') post = post_rest - funcs_js += ['\n' + post_funcs + '// EMSCRIPTEN_END_FUNCS\n'] # Move preAsms to their right place def move_preasm(m): contents = m.groups(0)[0] outfile.write(contents + '\n') return '' - post = re.sub(r'/\* PRE_ASM \*/(.*)\n', lambda m: move_preasm(m), post) + post_funcs = re.sub(r'/\* PRE_ASM \*/(.*)\n', lambda m: move_preasm(m), post_funcs) + + funcs_js += ['\n' + post_funcs + '// EMSCRIPTEN_END_FUNCS\n'] simple = os.environ.get('EMCC_SIMPLE_ASM') class Counter: @@ -392,17 +393,15 @@ def make_table(sig, raw): basic_vars = ['STACKTOP', 'STACK_MAX', 'tempDoublePtr', 'ABORT'] basic_float_vars = ['NaN', 'Infinity'] if forwarded_json['Types']['preciseI64MathUsed']: - basic_funcs += ['i64Math_' + op for op in ['multiply', 'divide', 'modulo']] + basic_funcs += ['i64Math_' + op for op in ['divide', 'modulo']] asm_setup += ''' -var i64Math_multiply = function(a, b, c, d) { i64Math.multiply(a, b, c, d) }; var i64Math_divide = function(a, b, c, d, e) { i64Math.divide(a, b, c, d, e) }; var i64Math_modulo = function(a, b, c, d, e) { i64Math.modulo(a, b, c, d, e) }; ''' - if forwarded_json['Functions']['libraryFunctions'].get('llvm_cttz_i32') or \ - forwarded_json['Functions']['libraryFunctions'].get('llvm_ctlz_i32') or \ - forwarded_json['Functions']['libraryFunctions'].get('llvm_cttz_i64') or \ - forwarded_json['Functions']['libraryFunctions'].get('llvm_ctlz_i64'): + if forwarded_json['Types']['preciseI64MathUsed'] or \ + forwarded_json['Functions']['libraryFunctions'].get('llvm_cttz_i32') or \ + forwarded_json['Functions']['libraryFunctions'].get('llvm_ctlz_i32'): basic_vars += ['cttz_i8', 'ctlz_i8'] asm_runtime_funcs = ['stackAlloc', 'stackSave', 'stackRestore', 'setThrew'] + ['setTempRet%d' % i for i in range(10)] @@ -454,7 +453,7 @@ def asm_coerce(value, sig): pass # If no named globals, only need externals global_vars = map(lambda g: g['name'], filter(lambda g: settings['NAMED_GLOBALS'] or g.get('external') or g.get('unIndexable'), forwarded_json['Variables']['globals'].values())) - global_funcs = ['_' + x for x in forwarded_json['Functions']['libraryFunctions'].keys()] + global_funcs = ['_' + key for key, value in forwarded_json['Functions']['libraryFunctions'].iteritems() if value != 2] def math_fix(g): return g if not g.startswith('Math_') else g.split('_')[1]; asm_global_funcs = ''.join([' var ' + g.replace('.', '_') + '=global.' + g + ';\n' for g in maths]) + \ diff --git a/src/fastLong.js b/src/fastLong.js new file mode 100644 index 0000000000000..b4bdece00e02c --- /dev/null +++ b/src/fastLong.js @@ -0,0 +1,263 @@ +// ======== compiled code from system/lib/compiler-rt , see readme therein +function ___muldsi3($a, $b) { + $a = $a | 0; + $b = $b | 0; + var $1 = 0, $2 = 0, $3 = 0, $6 = 0, $8 = 0, $11 = 0, $12 = 0; + $1 = $a & 65535; + $2 = $b & 65535; + $3 = Math.imul($2, $1); + $6 = $a >>> 16; + $8 = ($3 >>> 16) + Math.imul($2, $6) | 0; + $11 = $b >>> 16; + $12 = Math.imul($11, $1); + return (tempRet0 = (($8 >>> 16) + Math.imul($11, $6) | 0) + ((($8 & 65535) + $12 | 0) >>> 16) | 0, 0 | ($8 + $12 << 16 | $3 & 65535)) | 0; +} +function ___divdi3($a$0, $a$1, $b$0, $b$1) { + $a$0 = $a$0 | 0; + $a$1 = $a$1 | 0; + $b$0 = $b$0 | 0; + $b$1 = $b$1 | 0; + var $1$0 = 0, $1$1 = 0, $2$0 = 0, $2$1 = 0, $4$0 = 0, $4$1 = 0, $6$0 = 0, $7$0 = 0, $7$1 = 0, $8$0 = 0, $10$0 = 0; + $1$0 = $a$1 >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1; + $1$1 = (($a$1 | 0) < 0 ? -1 : 0) >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1; + $2$0 = $b$1 >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; + $2$1 = (($b$1 | 0) < 0 ? -1 : 0) >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; + $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1); + $4$1 = tempRet0; + $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1); + $7$0 = $2$0 ^ $1$0; + $7$1 = $2$1 ^ $1$1; + $8$0 = ___udivmoddi4($4$0, $4$1, $6$0, tempRet0, 0) | 0; + $10$0 = _i64Subtract($8$0 ^ $7$0, tempRet0 ^ $7$1, $7$0, $7$1); + return (tempRet0 = tempRet0, $10$0) | 0; +} +function ___muldi3($a$0, $a$1, $b$0, $b$1) { + $a$0 = $a$0 | 0; + $a$1 = $a$1 | 0; + $b$0 = $b$0 | 0; + $b$1 = $b$1 | 0; + var $x_sroa_0_0_extract_trunc = 0, $y_sroa_0_0_extract_trunc = 0, $1$0 = 0, $1$1 = 0, $2 = 0; + $x_sroa_0_0_extract_trunc = $a$0; + $y_sroa_0_0_extract_trunc = $b$0; + $1$0 = ___muldsi3($x_sroa_0_0_extract_trunc, $y_sroa_0_0_extract_trunc) | 0; + $1$1 = tempRet0; + $2 = Math.imul($a$1, $y_sroa_0_0_extract_trunc); + return (tempRet0 = (Math.imul($b$1, $x_sroa_0_0_extract_trunc) + $2 | 0) + $1$1 | $1$1 & 0, 0 | $1$0 & -1) | 0; +} +function ___udivdi3($a$0, $a$1, $b$0, $b$1) { + $a$0 = $a$0 | 0; + $a$1 = $a$1 | 0; + $b$0 = $b$0 | 0; + $b$1 = $b$1 | 0; + var $1$0 = 0; + $1$0 = ___udivmoddi4($a$0, $a$1, $b$0, $b$1, 0) | 0; + return (tempRet0 = tempRet0, $1$0) | 0; +} +function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) { + $a$0 = $a$0 | 0; + $a$1 = $a$1 | 0; + $b$0 = $b$0 | 0; + $b$1 = $b$1 | 0; + $rem = $rem | 0; + var $n_sroa_0_0_extract_trunc = 0, $n_sroa_1_4_extract_shift$0 = 0, $n_sroa_1_4_extract_trunc = 0, $d_sroa_0_0_extract_trunc = 0, $d_sroa_1_4_extract_shift$0 = 0, $d_sroa_1_4_extract_trunc = 0, $4 = 0, $17 = 0, $37 = 0, $49 = 0, $51 = 0, $57 = 0, $58 = 0, $66 = 0, $78 = 0, $86 = 0, $88 = 0, $89 = 0, $91 = 0, $92 = 0, $95 = 0, $105 = 0, $117 = 0, $119 = 0, $125 = 0, $126 = 0, $130 = 0, $q_sroa_1_1_ph = 0, $q_sroa_0_1_ph = 0, $r_sroa_1_1_ph = 0, $r_sroa_0_1_ph = 0, $sr_1_ph = 0, $d_sroa_0_0_insert_insert99$0 = 0, $d_sroa_0_0_insert_insert99$1 = 0, $137$0 = 0, $137$1 = 0, $carry_0203 = 0, $sr_1202 = 0, $r_sroa_0_1201 = 0, $r_sroa_1_1200 = 0, $q_sroa_0_1199 = 0, $q_sroa_1_1198 = 0, $147 = 0, $149 = 0, $r_sroa_0_0_insert_insert42$0 = 0, $r_sroa_0_0_insert_insert42$1 = 0, $150$1 = 0, $151$0 = 0, $152 = 0, $154$0 = 0, $r_sroa_0_0_extract_trunc = 0, $r_sroa_1_4_extract_trunc = 0, $155 = 0, $carry_0_lcssa$0 = 0, $carry_0_lcssa$1 = 0, $r_sroa_0_1_lcssa = 0, $r_sroa_1_1_lcssa = 0, $q_sroa_0_1_lcssa = 0, $q_sroa_1_1_lcssa = 0, $q_sroa_0_0_insert_ext75$0 = 0, $q_sroa_0_0_insert_ext75$1 = 0, $q_sroa_0_0_insert_insert77$1 = 0, $_0$0 = 0, $_0$1 = 0; + $n_sroa_0_0_extract_trunc = $a$0; + $n_sroa_1_4_extract_shift$0 = $a$1; + $n_sroa_1_4_extract_trunc = $n_sroa_1_4_extract_shift$0; + $d_sroa_0_0_extract_trunc = $b$0; + $d_sroa_1_4_extract_shift$0 = $b$1; + $d_sroa_1_4_extract_trunc = $d_sroa_1_4_extract_shift$0; + if (($n_sroa_1_4_extract_trunc | 0) == 0) { + $4 = ($rem | 0) != 0; + if (($d_sroa_1_4_extract_trunc | 0) == 0) { + if ($4) { + HEAP32[$rem >> 2] = ($n_sroa_0_0_extract_trunc >>> 0) % ($d_sroa_0_0_extract_trunc >>> 0); + HEAP32[$rem + 4 >> 2] = 0; + } + $_0$1 = 0; + $_0$0 = ($n_sroa_0_0_extract_trunc >>> 0) / ($d_sroa_0_0_extract_trunc >>> 0) >>> 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } else { + if (!$4) { + $_0$1 = 0; + $_0$0 = 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + HEAP32[$rem >> 2] = $a$0 & -1; + HEAP32[$rem + 4 >> 2] = $a$1 & 0; + $_0$1 = 0; + $_0$0 = 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + } + $17 = ($d_sroa_1_4_extract_trunc | 0) == 0; + do { + if (($d_sroa_0_0_extract_trunc | 0) == 0) { + if ($17) { + if (($rem | 0) != 0) { + HEAP32[$rem >> 2] = ($n_sroa_1_4_extract_trunc >>> 0) % ($d_sroa_0_0_extract_trunc >>> 0); + HEAP32[$rem + 4 >> 2] = 0; + } + $_0$1 = 0; + $_0$0 = ($n_sroa_1_4_extract_trunc >>> 0) / ($d_sroa_0_0_extract_trunc >>> 0) >>> 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + if (($n_sroa_0_0_extract_trunc | 0) == 0) { + if (($rem | 0) != 0) { + HEAP32[$rem >> 2] = 0; + HEAP32[$rem + 4 >> 2] = ($n_sroa_1_4_extract_trunc >>> 0) % ($d_sroa_1_4_extract_trunc >>> 0); + } + $_0$1 = 0; + $_0$0 = ($n_sroa_1_4_extract_trunc >>> 0) / ($d_sroa_1_4_extract_trunc >>> 0) >>> 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + $37 = $d_sroa_1_4_extract_trunc - 1 | 0; + if (($37 & $d_sroa_1_4_extract_trunc | 0) == 0) { + if (($rem | 0) != 0) { + HEAP32[$rem >> 2] = 0 | $a$0 & -1; + HEAP32[$rem + 4 >> 2] = $37 & $n_sroa_1_4_extract_trunc | $a$1 & 0; + } + $_0$1 = 0; + $_0$0 = $n_sroa_1_4_extract_trunc >>> ((_llvm_cttz_i32($d_sroa_1_4_extract_trunc) | 0) >>> 0); + return (tempRet0 = $_0$1, $_0$0) | 0; + } + $49 = _llvm_ctlz_i32($d_sroa_1_4_extract_trunc) | 0; + $51 = $49 - (_llvm_ctlz_i32($n_sroa_1_4_extract_trunc) | 0) | 0; + if ($51 >>> 0 <= 30) { + $57 = $51 + 1 | 0; + $58 = 31 - $51 | 0; + $sr_1_ph = $57; + $r_sroa_0_1_ph = $n_sroa_1_4_extract_trunc << $58 | $n_sroa_0_0_extract_trunc >>> ($57 >>> 0); + $r_sroa_1_1_ph = $n_sroa_1_4_extract_trunc >>> ($57 >>> 0); + $q_sroa_0_1_ph = 0; + $q_sroa_1_1_ph = $n_sroa_0_0_extract_trunc << $58; + break; + } + if (($rem | 0) == 0) { + $_0$1 = 0; + $_0$0 = 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + HEAP32[$rem >> 2] = 0 | $a$0 & -1; + HEAP32[$rem + 4 >> 2] = $n_sroa_1_4_extract_shift$0 | $a$1 & 0; + $_0$1 = 0; + $_0$0 = 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } else { + if (!$17) { + $117 = _llvm_ctlz_i32($d_sroa_1_4_extract_trunc) | 0; + $119 = $117 - (_llvm_ctlz_i32($n_sroa_1_4_extract_trunc) | 0) | 0; + if ($119 >>> 0 <= 31) { + $125 = $119 + 1 | 0; + $126 = 31 - $119 | 0; + $130 = $119 - 31 >> 31; + $sr_1_ph = $125; + $r_sroa_0_1_ph = $n_sroa_0_0_extract_trunc >>> ($125 >>> 0) & $130 | $n_sroa_1_4_extract_trunc << $126; + $r_sroa_1_1_ph = $n_sroa_1_4_extract_trunc >>> ($125 >>> 0) & $130; + $q_sroa_0_1_ph = 0; + $q_sroa_1_1_ph = $n_sroa_0_0_extract_trunc << $126; + break; + } + if (($rem | 0) == 0) { + $_0$1 = 0; + $_0$0 = 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + HEAP32[$rem >> 2] = 0 | $a$0 & -1; + HEAP32[$rem + 4 >> 2] = $n_sroa_1_4_extract_shift$0 | $a$1 & 0; + $_0$1 = 0; + $_0$0 = 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + $66 = $d_sroa_0_0_extract_trunc - 1 | 0; + if (($66 & $d_sroa_0_0_extract_trunc | 0) != 0) { + $86 = (_llvm_ctlz_i32($d_sroa_0_0_extract_trunc) | 0) + 33 | 0; + $88 = $86 - (_llvm_ctlz_i32($n_sroa_1_4_extract_trunc) | 0) | 0; + $89 = 64 - $88 | 0; + $91 = 32 - $88 | 0; + $92 = $91 >> 31; + $95 = $88 - 32 | 0; + $105 = $95 >> 31; + $sr_1_ph = $88; + $r_sroa_0_1_ph = $91 - 1 >> 31 & $n_sroa_1_4_extract_trunc >>> ($95 >>> 0) | ($n_sroa_1_4_extract_trunc << $91 | $n_sroa_0_0_extract_trunc >>> ($88 >>> 0)) & $105; + $r_sroa_1_1_ph = $105 & $n_sroa_1_4_extract_trunc >>> ($88 >>> 0); + $q_sroa_0_1_ph = $n_sroa_0_0_extract_trunc << $89 & $92; + $q_sroa_1_1_ph = ($n_sroa_1_4_extract_trunc << $89 | $n_sroa_0_0_extract_trunc >>> ($95 >>> 0)) & $92 | $n_sroa_0_0_extract_trunc << $91 & $88 - 33 >> 31; + break; + } + if (($rem | 0) != 0) { + HEAP32[$rem >> 2] = $66 & $n_sroa_0_0_extract_trunc; + HEAP32[$rem + 4 >> 2] = 0; + } + if (($d_sroa_0_0_extract_trunc | 0) == 1) { + $_0$1 = $n_sroa_1_4_extract_shift$0 | $a$1 & 0; + $_0$0 = 0 | $a$0 & -1; + return (tempRet0 = $_0$1, $_0$0) | 0; + } else { + $78 = _llvm_cttz_i32($d_sroa_0_0_extract_trunc) | 0; + $_0$1 = 0 | $n_sroa_1_4_extract_trunc >>> ($78 >>> 0); + $_0$0 = $n_sroa_1_4_extract_trunc << 32 - $78 | $n_sroa_0_0_extract_trunc >>> ($78 >>> 0) | 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + } + } while (0); + if (($sr_1_ph | 0) == 0) { + $q_sroa_1_1_lcssa = $q_sroa_1_1_ph; + $q_sroa_0_1_lcssa = $q_sroa_0_1_ph; + $r_sroa_1_1_lcssa = $r_sroa_1_1_ph; + $r_sroa_0_1_lcssa = $r_sroa_0_1_ph; + $carry_0_lcssa$1 = 0; + $carry_0_lcssa$0 = 0; + } else { + $d_sroa_0_0_insert_insert99$0 = 0 | $b$0 & -1; + $d_sroa_0_0_insert_insert99$1 = $d_sroa_1_4_extract_shift$0 | $b$1 & 0; + $137$0 = _i64Add($d_sroa_0_0_insert_insert99$0, $d_sroa_0_0_insert_insert99$1, -1, -1); + $137$1 = tempRet0; + $q_sroa_1_1198 = $q_sroa_1_1_ph; + $q_sroa_0_1199 = $q_sroa_0_1_ph; + $r_sroa_1_1200 = $r_sroa_1_1_ph; + $r_sroa_0_1201 = $r_sroa_0_1_ph; + $sr_1202 = $sr_1_ph; + $carry_0203 = 0; + while (1) { + $147 = $q_sroa_0_1199 >>> 31 | $q_sroa_1_1198 << 1; + $149 = $carry_0203 | $q_sroa_0_1199 << 1; + $r_sroa_0_0_insert_insert42$0 = 0 | ($r_sroa_0_1201 << 1 | $q_sroa_1_1198 >>> 31); + $r_sroa_0_0_insert_insert42$1 = $r_sroa_0_1201 >>> 31 | $r_sroa_1_1200 << 1 | 0; + _i64Subtract($137$0, $137$1, $r_sroa_0_0_insert_insert42$0, $r_sroa_0_0_insert_insert42$1); + $150$1 = tempRet0; + $151$0 = $150$1 >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1; + $152 = $151$0 & 1; + $154$0 = _i64Subtract($r_sroa_0_0_insert_insert42$0, $r_sroa_0_0_insert_insert42$1, $151$0 & $d_sroa_0_0_insert_insert99$0, ((($150$1 | 0) < 0 ? -1 : 0) >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1) & $d_sroa_0_0_insert_insert99$1); + $r_sroa_0_0_extract_trunc = $154$0; + $r_sroa_1_4_extract_trunc = tempRet0; + $155 = $sr_1202 - 1 | 0; + if (($155 | 0) == 0) { + break; + } else { + $q_sroa_1_1198 = $147; + $q_sroa_0_1199 = $149; + $r_sroa_1_1200 = $r_sroa_1_4_extract_trunc; + $r_sroa_0_1201 = $r_sroa_0_0_extract_trunc; + $sr_1202 = $155; + $carry_0203 = $152; + } + } + $q_sroa_1_1_lcssa = $147; + $q_sroa_0_1_lcssa = $149; + $r_sroa_1_1_lcssa = $r_sroa_1_4_extract_trunc; + $r_sroa_0_1_lcssa = $r_sroa_0_0_extract_trunc; + $carry_0_lcssa$1 = 0; + $carry_0_lcssa$0 = $152; + } + $q_sroa_0_0_insert_ext75$0 = $q_sroa_0_1_lcssa; + $q_sroa_0_0_insert_ext75$1 = 0; + $q_sroa_0_0_insert_insert77$1 = $q_sroa_1_1_lcssa | $q_sroa_0_0_insert_ext75$1; + if (($rem | 0) != 0) { + HEAP32[$rem >> 2] = 0 | $r_sroa_0_1_lcssa; + HEAP32[$rem + 4 >> 2] = $r_sroa_1_1_lcssa | 0; + } + $_0$1 = (0 | $q_sroa_0_0_insert_ext75$0) >>> 31 | $q_sroa_0_0_insert_insert77$1 << 1 | ($q_sroa_0_0_insert_ext75$1 << 1 | $q_sroa_0_0_insert_ext75$0 >>> 31) & 0 | $carry_0_lcssa$1; + $_0$0 = ($q_sroa_0_0_insert_ext75$0 << 1 | 0 >>> 31) & -2 | $carry_0_lcssa$0; + return (tempRet0 = $_0$1, $_0$0) | 0; +} +// ======================================================================= diff --git a/src/jsifier.js b/src/jsifier.js index 2cf94a0dfa439..926be71aa69bd 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -468,7 +468,7 @@ function JSify(data, functionsOnly, givenFunctions) { asmLibraryFunctions.push(contentText); contentText = ' '; EXPORTED_FUNCTIONS[ident] = 1; - delete Functions.libraryFunctions[ident.substr(1)]; + Functions.libraryFunctions[ident.substr(1)] = 2; } } if ((!ASM_JS || phase == 'pre') && @@ -1606,10 +1606,26 @@ function JSify(data, functionsOnly, givenFunctions) { // "Final shape that will be created"). if (PRECISE_I64_MATH && Types.preciseI64MathUsed) { if (!INCLUDE_FULL_LIBRARY) { - ['i64Add', 'i64Subtract', 'bitshift64Shl', 'bitshift64Lshr', 'bitshift64Ashr'].forEach(function(func) { - print(processLibraryFunction(LibraryManager.library[func], func)); // must be first to be close to generated code - Functions.implementedFunctions['_' + func] = LibraryManager.library[func + '__sig']; + // first row are utilities called from generated code, second are needed from fastLong + ['i64Add', 'i64Subtract', 'bitshift64Shl', 'bitshift64Lshr', 'bitshift64Ashr', + 'llvm_ctlz_i32', 'llvm_cttz_i32'].forEach(function(func) { + if (!Functions.libraryFunctions[func]) { + print(processLibraryFunction(LibraryManager.library[func], func)); // must be first to be close to generated code + Functions.implementedFunctions['_' + func] = LibraryManager.library[func + '__sig']; + Functions.libraryFunctions[func] = 1; + // limited dependency handling + var deps = LibraryManager.library[func + '__deps']; + if (deps) { + deps.forEach(function(dep) { + assert(typeof dep == 'function'); + var text = dep(); + assert(text.indexOf('\n') < 0); + print('/* PRE_ASM */ ' + text + '\n'); + }); + } + } }); + print(read('fastLong.js')); } print('// EMSCRIPTEN_END_FUNCS\n'); print(read('long.js')); diff --git a/src/library.js b/src/library.js index c9f161f2da4e4..11f30a1cdb782 100644 --- a/src/library.js +++ b/src/library.js @@ -5304,9 +5304,11 @@ LibraryManager.library = { llvm_umul_with_overflow_i64__deps: [function() { Types.preciseI64MathUsed = 1 }], llvm_umul_with_overflow_i64: function(xl, xh, yl, yh) { - i64Math.multiply(xl, xh, yl, yh); - {{{ makeStructuralReturn([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32'), '0']) }}}; - // XXX Need to hack support for second param in long.js +#if ASSERTIONS + Runtime.warnOnce('no overflow support in llvm_umul_with_overflow_i64'); +#endif + var low = ___muldi3(xl, xh, yl, yh); + {{{ makeStructuralReturn(['low', 'tempRet0', '0']) }}}; }, llvm_stacksave: function() { diff --git a/src/long.js b/src/long.js index b3d19bd34748d..9550a48a3909c 100644 --- a/src/long.js +++ b/src/long.js @@ -1530,13 +1530,6 @@ var i64Math = (function() { // Emscripten wrapper // Emscripten wrapper var Wrapper = { - multiply: function(xl, xh, yl, yh) { - var x = new goog.math.Long(xl, xh); - var y = new goog.math.Long(yl, yh); - var ret = x.multiply(y); - HEAP32[tempDoublePtr>>2] = ret.low_; - HEAP32[tempDoublePtr+4>>2] = ret.high_; - }, abs: function(l, h) { var x = new goog.math.Long(l, h); var ret; diff --git a/src/modules.js b/src/modules.js index f2994adae31db..5b5f79477a2cc 100644 --- a/src/modules.js +++ b/src/modules.js @@ -230,7 +230,7 @@ var Types = { var Functions = { // All functions that will be implemented in this file. Maps id to signature implementedFunctions: {}, - libraryFunctions: {}, // functions added from the library + libraryFunctions: {}, // functions added from the library. value 2 means asmLibraryFunction unimplementedFunctions: {}, // library etc. functions that we need to index, maps id to signature indexedFunctions: {}, diff --git a/src/parseTools.js b/src/parseTools.js index a568b7183c031..8a6daaf3be13c 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1998,9 +1998,12 @@ function processMathop(item) { return finish(['(i64Math' + (ASM_JS ? '_' : '.') + type + '(' + asmCoercion(low1, 'i32') + ',' + asmCoercion(high1, 'i32') + ',' + asmCoercion(low2, 'i32') + ',' + asmCoercion(high2, 'i32') + (lastArg ? ',' + asmCoercion(+lastArg, 'i32') : '') + '),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')', makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32'), 'i32')]); } - function i64PreciseLib(type) { + function preciseCall(name) { Types.preciseI64MathUsed = true; - return finish(['_i64' + type[0].toUpperCase() + type.substr(1) + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + ')', 'tempRet0']); + return finish([name + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + ')', 'tempRet0']); + } + function i64PreciseLib(type) { + return preciseCall('_i64' + type[0].toUpperCase() + type.substr(1)); } switch (op) { // basic integer ops @@ -2078,7 +2081,7 @@ function processMathop(item) { } case 'mul': { if (PRECISE_I64_MATH) { - return i64PreciseOp('multiply'); + return preciseCall('___muldi3'); } else { warnI64_1(); return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '*' + mergeI64(idents[1], op[0] === 'u'), true)); diff --git a/system/lib/compiler-rt/readme.txt b/system/lib/compiler-rt/readme.txt index 1fc97635f343c..d32e4600d6254 100644 --- a/system/lib/compiler-rt/readme.txt +++ b/system/lib/compiler-rt/readme.txt @@ -13,4 +13,5 @@ Compile with something like ./emcc system/lib/compiler-rt/*.c -Isystem/lib/compiler-rt/ -o rt.bc ./emcc -O2 -s ASM_JS=1 -g rt.bc -s LINKABLE=1 +manually replace Math_imul with Math.imul From 6749401c21206655e57db30664faff12cdfae138 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sun, 14 Apr 2013 17:19:50 -0700 Subject: [PATCH 414/544] use compiled i64 div and rem --- emscripten.py | 6 ---- src/fastLong.js | 51 ++++++++++++++++++++++++++----- src/long.js | 42 ------------------------- src/parseTools.js | 4 +-- system/lib/compiler-rt/divdi3.c | 16 ++++++++++ system/lib/compiler-rt/readme.txt | 5 ++- system/lib/compiler-rt/udivdi3.c | 11 +++++++ 7 files changed, 76 insertions(+), 59 deletions(-) diff --git a/emscripten.py b/emscripten.py index bae6d8cd02458..b49008cd4c1fb 100755 --- a/emscripten.py +++ b/emscripten.py @@ -392,12 +392,6 @@ def make_table(sig, raw): if settings['CHECK_HEAP_ALIGN']: basic_funcs += ['CHECK_ALIGN_2', 'CHECK_ALIGN_4', 'CHECK_ALIGN_8'] basic_vars = ['STACKTOP', 'STACK_MAX', 'tempDoublePtr', 'ABORT'] basic_float_vars = ['NaN', 'Infinity'] - if forwarded_json['Types']['preciseI64MathUsed']: - basic_funcs += ['i64Math_' + op for op in ['divide', 'modulo']] - asm_setup += ''' -var i64Math_divide = function(a, b, c, d, e) { i64Math.divide(a, b, c, d, e) }; -var i64Math_modulo = function(a, b, c, d, e) { i64Math.modulo(a, b, c, d, e) }; -''' if forwarded_json['Types']['preciseI64MathUsed'] or \ forwarded_json['Functions']['libraryFunctions'].get('llvm_cttz_i32') or \ diff --git a/src/fastLong.js b/src/fastLong.js index b4bdece00e02c..95f398db216bf 100644 --- a/src/fastLong.js +++ b/src/fastLong.js @@ -31,6 +31,28 @@ function ___divdi3($a$0, $a$1, $b$0, $b$1) { $10$0 = _i64Subtract($8$0 ^ $7$0, tempRet0 ^ $7$1, $7$0, $7$1); return (tempRet0 = tempRet0, $10$0) | 0; } +function ___remdi3($a$0, $a$1, $b$0, $b$1) { + $a$0 = $a$0 | 0; + $a$1 = $a$1 | 0; + $b$0 = $b$0 | 0; + $b$1 = $b$1 | 0; + var $rem = 0, $1$0 = 0, $1$1 = 0, $2$0 = 0, $2$1 = 0, $4$0 = 0, $4$1 = 0, $6$0 = 0, $10$0 = 0, $10$1 = 0, __stackBase__ = 0; + __stackBase__ = STACKTOP; + STACKTOP = STACKTOP + 8 | 0; + $rem = __stackBase__ | 0; + $1$0 = $a$1 >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1; + $1$1 = (($a$1 | 0) < 0 ? -1 : 0) >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1; + $2$0 = $b$1 >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; + $2$1 = (($b$1 | 0) < 0 ? -1 : 0) >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; + $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1); + $4$1 = tempRet0; + $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1); + ___udivmoddi4($4$0, $4$1, $6$0, tempRet0, $rem); + $10$0 = _i64Subtract(HEAP32[$rem >> 2] ^ $1$0, HEAP32[$rem + 4 >> 2] ^ $1$1, $1$0, $1$1); + $10$1 = tempRet0; + STACKTOP = __stackBase__; + return (tempRet0 = $10$1, $10$0) | 0; +} function ___muldi3($a$0, $a$1, $b$0, $b$1) { $a$0 = $a$0 | 0; $a$1 = $a$1 | 0; @@ -53,6 +75,19 @@ function ___udivdi3($a$0, $a$1, $b$0, $b$1) { $1$0 = ___udivmoddi4($a$0, $a$1, $b$0, $b$1, 0) | 0; return (tempRet0 = tempRet0, $1$0) | 0; } +function ___uremdi3($a$0, $a$1, $b$0, $b$1) { + $a$0 = $a$0 | 0; + $a$1 = $a$1 | 0; + $b$0 = $b$0 | 0; + $b$1 = $b$1 | 0; + var $rem = 0, __stackBase__ = 0; + __stackBase__ = STACKTOP; + STACKTOP = STACKTOP + 8 | 0; + $rem = __stackBase__ | 0; + ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem); + STACKTOP = __stackBase__; + return (tempRet0 = HEAP32[$rem + 4 >> 2] | 0, HEAP32[$rem >> 2] | 0) | 0; +} function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) { $a$0 = $a$0 | 0; $a$1 = $a$1 | 0; @@ -117,11 +152,11 @@ function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) { HEAP32[$rem + 4 >> 2] = $37 & $n_sroa_1_4_extract_trunc | $a$1 & 0; } $_0$1 = 0; - $_0$0 = $n_sroa_1_4_extract_trunc >>> ((_llvm_cttz_i32($d_sroa_1_4_extract_trunc) | 0) >>> 0); + $_0$0 = $n_sroa_1_4_extract_trunc >>> ((_llvm_cttz_i32($d_sroa_1_4_extract_trunc | 0) | 0) >>> 0); return (tempRet0 = $_0$1, $_0$0) | 0; } - $49 = _llvm_ctlz_i32($d_sroa_1_4_extract_trunc) | 0; - $51 = $49 - (_llvm_ctlz_i32($n_sroa_1_4_extract_trunc) | 0) | 0; + $49 = _llvm_ctlz_i32($d_sroa_1_4_extract_trunc | 0) | 0; + $51 = $49 - (_llvm_ctlz_i32($n_sroa_1_4_extract_trunc | 0) | 0) | 0; if ($51 >>> 0 <= 30) { $57 = $51 + 1 | 0; $58 = 31 - $51 | 0; @@ -144,8 +179,8 @@ function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) { return (tempRet0 = $_0$1, $_0$0) | 0; } else { if (!$17) { - $117 = _llvm_ctlz_i32($d_sroa_1_4_extract_trunc) | 0; - $119 = $117 - (_llvm_ctlz_i32($n_sroa_1_4_extract_trunc) | 0) | 0; + $117 = _llvm_ctlz_i32($d_sroa_1_4_extract_trunc | 0) | 0; + $119 = $117 - (_llvm_ctlz_i32($n_sroa_1_4_extract_trunc | 0) | 0) | 0; if ($119 >>> 0 <= 31) { $125 = $119 + 1 | 0; $126 = 31 - $119 | 0; @@ -170,8 +205,8 @@ function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) { } $66 = $d_sroa_0_0_extract_trunc - 1 | 0; if (($66 & $d_sroa_0_0_extract_trunc | 0) != 0) { - $86 = (_llvm_ctlz_i32($d_sroa_0_0_extract_trunc) | 0) + 33 | 0; - $88 = $86 - (_llvm_ctlz_i32($n_sroa_1_4_extract_trunc) | 0) | 0; + $86 = (_llvm_ctlz_i32($d_sroa_0_0_extract_trunc | 0) | 0) + 33 | 0; + $88 = $86 - (_llvm_ctlz_i32($n_sroa_1_4_extract_trunc | 0) | 0) | 0; $89 = 64 - $88 | 0; $91 = 32 - $88 | 0; $92 = $91 >> 31; @@ -193,7 +228,7 @@ function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) { $_0$0 = 0 | $a$0 & -1; return (tempRet0 = $_0$1, $_0$0) | 0; } else { - $78 = _llvm_cttz_i32($d_sroa_0_0_extract_trunc) | 0; + $78 = _llvm_cttz_i32($d_sroa_0_0_extract_trunc | 0) | 0; $_0$1 = 0 | $n_sroa_1_4_extract_trunc >>> ($78 >>> 0); $_0$0 = $n_sroa_1_4_extract_trunc << 32 - $78 | $n_sroa_0_0_extract_trunc >>> ($78 >>> 0) | 0; return (tempRet0 = $_0$1, $_0$0) | 0; diff --git a/src/long.js b/src/long.js index 9550a48a3909c..42c86c232f2e4 100644 --- a/src/long.js +++ b/src/long.js @@ -1562,48 +1562,6 @@ var i64Math = (function() { // Emscripten wrapper c.addTo(b, d); return d; }, - divide: function(xl, xh, yl, yh, unsigned) { - Wrapper.ensureTemps(); - if (!unsigned) { - var x = new goog.math.Long(xl, xh); - var y = new goog.math.Long(yl, yh); - var ret = x.div(y); - HEAP32[tempDoublePtr>>2] = ret.low_; - HEAP32[tempDoublePtr+4>>2] = ret.high_; - } else { - // slow precise bignum division - var x = Wrapper.lh2bignum(xl >>> 0, xh >>> 0); - var y = Wrapper.lh2bignum(yl >>> 0, yh >>> 0); - var z = new BigInteger(); - x.divRemTo(y, z, null); - var l = new BigInteger(); - var h = new BigInteger(); - z.divRemTo(Wrapper.two32, h, l); - HEAP32[tempDoublePtr>>2] = parseInt(l.toString()) | 0; - HEAP32[tempDoublePtr+4>>2] = parseInt(h.toString()) | 0; - } - }, - modulo: function(xl, xh, yl, yh, unsigned) { - Wrapper.ensureTemps(); - if (!unsigned) { - var x = new goog.math.Long(xl, xh); - var y = new goog.math.Long(yl, yh); - var ret = x.modulo(y); - HEAP32[tempDoublePtr>>2] = ret.low_; - HEAP32[tempDoublePtr+4>>2] = ret.high_; - } else { - // slow precise bignum division - var x = Wrapper.lh2bignum(xl >>> 0, xh >>> 0); - var y = Wrapper.lh2bignum(yl >>> 0, yh >>> 0); - var z = new BigInteger(); - x.divRemTo(y, null, z); - var l = new BigInteger(); - var h = new BigInteger(); - z.divRemTo(Wrapper.two32, h, l); - HEAP32[tempDoublePtr>>2] = parseInt(l.toString()) | 0; - HEAP32[tempDoublePtr+4>>2] = parseInt(h.toString()) | 0; - } - }, stringify: function(l, h, unsigned) { var ret = new goog.math.Long(l, h).toString(); if (unsigned && ret[0] == '-') { diff --git a/src/parseTools.js b/src/parseTools.js index 8a6daaf3be13c..2eb456f1ede10 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -2073,7 +2073,7 @@ function processMathop(item) { } case 'sdiv': case 'udiv': { if (PRECISE_I64_MATH) { - return i64PreciseOp('divide', op[0] === 'u'); + return preciseCall(op[0] === 'u' ? '___udivdi3' : '___divdi3'); } else { warnI64_1(); return finish(splitI64(makeRounding(mergeI64(idents[0], op[0] === 'u') + '/' + mergeI64(idents[1], op[0] === 'u'), bits, op[0] === 's'), true)); @@ -2089,7 +2089,7 @@ function processMathop(item) { } case 'urem': case 'srem': { if (PRECISE_I64_MATH) { - return i64PreciseOp('modulo', op[0] === 'u'); + return preciseCall(op[0] === 'u' ? '___uremdi3' : '___remdi3'); } else { warnI64_1(); return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '%' + mergeI64(idents[1], op[0] === 'u'), true)); diff --git a/system/lib/compiler-rt/divdi3.c b/system/lib/compiler-rt/divdi3.c index 2c2bcc26d5811..09f4a04edd65c 100644 --- a/system/lib/compiler-rt/divdi3.c +++ b/system/lib/compiler-rt/divdi3.c @@ -29,3 +29,19 @@ __divdi3(di_int a, di_int b) s_a ^= s_b; /*sign of quotient */ return (__udivmoddi4(a, b, (du_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */ } + +/* XXX EMSCRIPTEN */ + +COMPILER_RT_ABI di_int +__remdi3(di_int a, di_int b) +{ + const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1; + di_int s_a = a >> bits_in_dword_m1; /* s_a = a < 0 ? -1 : 0 */ + di_int s_b = b >> bits_in_dword_m1; /* s_b = b < 0 ? -1 : 0 */ + a = (a ^ s_a) - s_a; /* negate if s_a == -1 */ + b = (b ^ s_b) - s_b; /* negate if s_b == -1 */ + du_int rem; + __udivmoddi4(a, b, &rem); + return (rem ^ s_a) - s_a; /* negate if s_a == -1 */ +} + diff --git a/system/lib/compiler-rt/readme.txt b/system/lib/compiler-rt/readme.txt index d32e4600d6254..d10f53e4e6443 100644 --- a/system/lib/compiler-rt/readme.txt +++ b/system/lib/compiler-rt/readme.txt @@ -5,7 +5,10 @@ Last Changed Date: 2013-04-12 07:57:03 -0700 (Fri, 12 Apr 2013) =========================================================================== -Changes: add emscripten endianness to int_endianness.h +Changes: + + * add emscripten endianness to int_endianness.h + * add rem functions =========================================================================== diff --git a/system/lib/compiler-rt/udivdi3.c b/system/lib/compiler-rt/udivdi3.c index 6c0303df3d408..3d55785ca8136 100644 --- a/system/lib/compiler-rt/udivdi3.c +++ b/system/lib/compiler-rt/udivdi3.c @@ -23,3 +23,14 @@ __udivdi3(du_int a, du_int b) { return __udivmoddi4(a, b, 0); } + +/* XXX EMSCRIPTEN */ + +COMPILER_RT_ABI du_int +__uremdi3(du_int a, du_int b) +{ + du_int rem; + __udivmoddi4(a, b, &rem); + return rem; +} + From 6ee3943a67687e64f69ed68ce0856ae280061373 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sun, 14 Apr 2013 18:54:31 -0700 Subject: [PATCH 415/544] update test_unistd_misc --- tests/unistd/misc.out | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unistd/misc.out b/tests/unistd/misc.out index 810da2151ef59..a872a2581fbb6 100644 --- a/tests/unistd/misc.out +++ b/tests/unistd/misc.out @@ -29,7 +29,7 @@ alarm: 0, errno: 0 ualarm: 0, errno: 0 fork: -1, errno: 11 vfork: -1, errno: 11 -crypt: 0, errno: 38 +crypt: (null), errno: 38 encrypt, errno: 38 getgid: 0, errno: 0 getegid: 0, errno: 0 From fa7a4cc43366577220336e191c068e6300c00f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Sun, 14 Apr 2013 20:13:26 +0200 Subject: [PATCH 416/544] * Added --no-force argument. --- tools/file_packager.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/tools/file_packager.py b/tools/file_packager.py index 8a7cca853eade..f1f1d5e30294b 100644 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -11,7 +11,7 @@ Usage: - file_packager.py TARGET [--preload A [B..]] [--embed C [D..]] [--compress COMPRESSION_DATA] [--pre-run] [--crunch[=X]] [--js-output=OUTPUT.js] + file_packager.py TARGET [--preload A [B..]] [--embed C [D..]] [--compress COMPRESSION_DATA] [--pre-run] [--crunch[=X]] [--js-output=OUTPUT.js] [--no-force] --pre-run Will generate wrapper code that does preloading in Module.preRun. This is necessary if you add this code before the main file has been loading, which includes necessary components like addRunDependency. @@ -24,6 +24,10 @@ DDS files will not be crunched if the .crn is more recent than the .dds. This prevents a lot of unneeded computation. + --js-output=FILE Writes output in FILE, if not specified, standard output is used. + + --no-force Don't create output if no valid input file is specified. + Notes: * The file packager generates unix-style file paths. So if you are on windows and a file is accessed at @@ -40,7 +44,7 @@ from subprocess import Popen, PIPE, STDOUT if len(sys.argv) == 1: - print '''Usage: file_packager.py TARGET [--preload A...] [--embed C...] [--compress COMPRESSION_DATA] [--pre-run] [--crunch[=X]] [--js-output=OUTPUT.js] + print '''Usage: file_packager.py TARGET [--preload A...] [--embed B...] [--compress COMPRESSION_DATA] [--pre-run] [--crunch[=X]] [--js-output=OUTPUT.js] [--no-force] See the source for more details.''' sys.exit(0) @@ -65,6 +69,7 @@ crunch = 0 plugins = [] jsoutput = None +force = True for arg in sys.argv[1:]: if arg == '--preload': @@ -86,6 +91,8 @@ in_preload = False in_embed = False in_compress = 0 + elif arg == '--no-force': + force = False elif arg.startswith('--js-output'): jsoutput = arg.split('=')[1] if '=' in arg else None elif arg.startswith('--crunch'): @@ -101,10 +108,10 @@ in_embed = False in_compress = 0 elif in_preload: - if os.path.isfile(arg): + if os.path.isfile(arg) or os.path.isdir(arg): data_files.append({ 'name': arg, 'mode': 'preload' }) elif in_embed: - if os.path.isfile(arg): + if os.path.isfile(arg) or os.path.isdir(arg): data_files.append({ 'name': arg, 'mode': 'embed' }) elif in_compress: if in_compress == 1: @@ -117,6 +124,9 @@ Compression.js_name = arg in_compress = 0 +if (not force) and len(data_files) == 0: + has_preloaded = False + ret = ''' (function() { ''' @@ -417,9 +427,9 @@ def was_seen(name): ret += ''' })(); ''' - -if jsoutput == None: - print ret -else: - f = open(jsoutput, 'w') - f.write(ret) +if force or len(data_files) > 0: + if jsoutput == None: + print ret + else: + f = open(jsoutput, 'w') + f.write(ret) From 17da251d334ce62d633d51f874b92e19ad9dbf45 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 15 Apr 2013 10:43:01 -0700 Subject: [PATCH 417/544] default memory initializer to off, and add testing coverage --- emcc | 8 ++++---- tests/runner.py | 13 +++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/emcc b/emcc index 03d92fd3664c3..6c7ed2f56b33f 100755 --- a/emcc +++ b/emcc @@ -473,7 +473,7 @@ Options that are modified or new in %s include: --memory-init-file If on, we generate a separate memory initialization file. This is more efficient than storing the memory initialization data embedded inside - JavaScript as text. (default is on) + JavaScript as text. (default is off) The target file, if specified (-o ), defines what will be generated: @@ -483,8 +483,8 @@ be generated: .bc LLVM bitcode (default) .o LLVM bitcode (same as .bc) -Note that if --memory-init-file is used, then in addition to a -.js or .html file that is generated, a .mem file will also appear. +(Note that if --memory-init-file is used, then in addition to a +.js or .html file that is generated, a .mem file will also appear.) The -c option (which tells gcc not to run the linker) will cause LLVM bitcode to be generated, as %s only generates @@ -727,7 +727,7 @@ try: bind = False jcache = False save_bc = False - memory_init_file = True + memory_init_file = False if use_cxx: default_cxx_std = '-std=c++03' # Enforce a consistent C++ standard when compiling .cpp files, if user does not specify one on the cmdline. diff --git a/tests/runner.py b/tests/runner.py index 8997475536b43..77b156a0dc05e 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -266,11 +266,11 @@ def build(self, src, dirname, filename, output_processor=None, main_file=None, a if output_processor is not None: output_processor(open(filename + '.o.js').read()) - if self.emcc_args is not None: + if self.emcc_args is not None and 'ASM_JS=1' in self.emcc_args: if '--memory-init-file' in self.emcc_args: memory_init_file = int(self.emcc_args[self.emcc_args.index('--memory-init-file')+1]) else: - memory_init_file = 1 + memory_init_file = 0 if memory_init_file: assert '/* memory initializer */' not in open(filename + '.o.js').read() else: @@ -9002,7 +9002,7 @@ def setUp(self): # asm.js exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1"])') - exec('asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "0"])') + exec('asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1"])') # Make custom runs with various options for compiler, quantum, embetter, typed_arrays, llvm_opts in [ @@ -11031,12 +11031,13 @@ def test_compressed_file(self): self.run_browser('page.html', '', '/report_result?1') def test_sdl_image(self): - # load an image file, get pixel data. Also O2 coverage for --preload-file + # load an image file, get pixel data. Also O2 coverage for --preload-file, and memory-init shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.jpg')) open(os.path.join(self.get_dir(), 'sdl_image.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_image.c')).read())) - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image.c'), '-O2', '--preload-file', 'screenshot.jpg', '-o', 'page.html']).communicate() - self.run_browser('page.html', '', '/report_result?600') + for mem in [0, 1]: + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image.c'), '-O2', '--preload-file', 'screenshot.jpg', '-o', 'page.html', '--memory-init-file', str(mem)]).communicate() + self.run_browser('page.html', '', '/report_result?600') def test_sdl_image_jpeg(self): shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.jpeg')) From 3400e5810c1a741a6d322f1ab71cfe3d15f865da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Tue, 16 Apr 2013 09:51:42 +0200 Subject: [PATCH 418/544] * Added a warning to file_packager when an input file does not exist. --- tools/file_packager.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/file_packager.py b/tools/file_packager.py index f1f1d5e30294b..e434e81305a90 100644 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -110,9 +110,13 @@ elif in_preload: if os.path.isfile(arg) or os.path.isdir(arg): data_files.append({ 'name': arg, 'mode': 'preload' }) + else: + print >> sys.stderr, 'Warning: ' + arg + ' does not exist, ignoring.' elif in_embed: if os.path.isfile(arg) or os.path.isdir(arg): data_files.append({ 'name': arg, 'mode': 'embed' }) + else: + print >> sys.stderr, 'Warning:' + arg + ' does not exist, ignoring.' elif in_compress: if in_compress == 1: Compression.encoder = arg From 2f7322d0d0987c66c6ab15d34357db8ab054ae74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 16 Apr 2013 11:44:51 +0300 Subject: [PATCH 419/544] Revert "Fix cxa_demangle compile errors". By feedback from azakai, we want to keep our libcxxabi clean from custom changes w.r.t. upsstream libcxxabi. This reverts commit 848c186df3a8f1eff6e7b1af0b08df25aefae0e3. --- system/lib/libcxxabi/src/cxa_demangle.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/system/lib/libcxxabi/src/cxa_demangle.cpp b/system/lib/libcxxabi/src/cxa_demangle.cpp index 804ea7ce5290c..c1e126035fbc1 100644 --- a/system/lib/libcxxabi/src/cxa_demangle.cpp +++ b/system/lib/libcxxabi/src/cxa_demangle.cpp @@ -5695,7 +5695,7 @@ class __array if (__right_ != 0) r += __right_->size(); else if (__size_ != 0) - r += static_cast(snprintf(0, 0, "%lu", static_cast(__size_))); + r += static_cast(snprintf(0, 0, "%ld", __size_)); const_cast(__cached_size_) = static_cast(r); } return static_cast(__cached_size_); @@ -5710,7 +5710,7 @@ class __array buf = __right_->get_demangled_name(buf); else if (__size_ != 0) { - int rs = sprintf(buf, "%lu", static_cast(__size_)); + int rs = sprintf(buf, "%ld", __size_); buf += rs; } *buf++ = ']'; @@ -5735,7 +5735,7 @@ class __array if (__right_ != 0) r += __right_->size(); else if (__size_ != 0) - r += static_cast(snprintf(0, 0, "%lu", static_cast(__size_))); + r += static_cast(snprintf(0, 0, "%ld", __size_)); return r; } @@ -5747,7 +5747,7 @@ class __array buf = __right_->get_demangled_name(buf); else if (__size_ != 0) { - int off = sprintf(buf, "%lu", static_cast(__size_)); + int off = sprintf(buf, "%ld", __size_); buf += off; } char* t = buf; From 8ae67d7642ebdd77a3c5f0d8fa7115fb372e98ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 16 Apr 2013 11:45:11 +0300 Subject: [PATCH 420/544] Fix newline typo in AUTHORS. --- AUTHORS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index d3463c8d4d9a0..1c6cf0ecd9360 100644 --- a/AUTHORS +++ b/AUTHORS @@ -59,7 +59,8 @@ a license to everyone to use it as detailed in LICENSE.) * Felix H. Dahlke * Éloi Rivard * Alexander Gladysh -* Arlo Breault * Jacob Lee (copyright owned by Google, Inc.) +* Arlo Breault +* Jacob Lee (copyright owned by Google, Inc.) * Joe Lee (copyright owned by IMVU) * Andy Friesen (copyright owned by IMVU) * Bill Welden (copyright owned by IMVU) From 7df317fe4bb814f7deffc75c2c9b86663aefb7e7 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 17 Apr 2013 17:20:37 +0700 Subject: [PATCH 421/544] Use -target rather than -triple with clang. Apparently -target replaced -triple in the past. Using -target also makes the behavior of clang match the target rather than the host platform. --- tools/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index d5a37c038aa03..2eca57420cfa8 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -404,7 +404,7 @@ def clean_temp(): # -fno-delayed-template-parsing is needed on Windows due to http://llvm.org/PR15651 COMPILER_OPTS = COMPILER_OPTS + ['-m32', '-U__i386__', '-U__x86_64__', '-U__i386', '-U__x86_64', '-Ui386', '-Ux86_64', '-U__SSE__', '-U__SSE2__', '-U__MMX__', '-UX87_DOUBLE_ROUNDING', '-UHAVE_GCC_ASM_FOR_X87', '-DEMSCRIPTEN', '-U__STRICT_ANSI__', '-U__CYGWIN__', - '-D__STDC__', '-Xclang', '-triple=i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno', + '-D__STDC__', '-target', 'i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno', '-fno-ms-compatibility', '-fno-delayed-template-parsing'] USE_EMSDK = not os.environ.get('EMMAKEN_NO_SDK') From 13f35d0bc636c39003876b6af180db726529fe37 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 17 Apr 2013 17:41:52 +0700 Subject: [PATCH 422/544] Remove flags for disabling ms-compatibility. With the use of -target rather than -triple, these are no longer needed. --- tools/shared.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tools/shared.py b/tools/shared.py index 2eca57420cfa8..80f44328f7858 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -399,13 +399,9 @@ def clean_temp(): except: COMPILER_OPTS = [] # Force a simple, standard target as much as possible: target 32-bit linux, and disable various flags that hint at other platforms -# -fno-ms-compatibility is passed, since on Windows, Clang enables a 'MS compatibility mode' by default, that disables char16_t and char32_t -# to be MSVC header -compatible. This would cause build errors in libcxx file __config. -# -fno-delayed-template-parsing is needed on Windows due to http://llvm.org/PR15651 COMPILER_OPTS = COMPILER_OPTS + ['-m32', '-U__i386__', '-U__x86_64__', '-U__i386', '-U__x86_64', '-Ui386', '-Ux86_64', '-U__SSE__', '-U__SSE2__', '-U__MMX__', '-UX87_DOUBLE_ROUNDING', '-UHAVE_GCC_ASM_FOR_X87', '-DEMSCRIPTEN', '-U__STRICT_ANSI__', '-U__CYGWIN__', - '-D__STDC__', '-target', 'i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno', - '-fno-ms-compatibility', '-fno-delayed-template-parsing'] + '-D__STDC__', '-target', 'i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno'] USE_EMSDK = not os.environ.get('EMMAKEN_NO_SDK') From 2d90a3963ef641d576103eeb885fe1617f04b5e0 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 17 Apr 2013 17:44:54 +0700 Subject: [PATCH 423/544] __STDC__ is already defined by clang. --- tools/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index 80f44328f7858..4d12e33a3e70f 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -401,7 +401,7 @@ def clean_temp(): # Force a simple, standard target as much as possible: target 32-bit linux, and disable various flags that hint at other platforms COMPILER_OPTS = COMPILER_OPTS + ['-m32', '-U__i386__', '-U__x86_64__', '-U__i386', '-U__x86_64', '-Ui386', '-Ux86_64', '-U__SSE__', '-U__SSE2__', '-U__MMX__', '-UX87_DOUBLE_ROUNDING', '-UHAVE_GCC_ASM_FOR_X87', '-DEMSCRIPTEN', '-U__STRICT_ANSI__', '-U__CYGWIN__', - '-D__STDC__', '-target', 'i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno'] + '-target', 'i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno'] USE_EMSDK = not os.environ.get('EMMAKEN_NO_SDK') From 054ea0065886ebc8bff8132c5d81182f847bbb8e Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 17 Apr 2013 17:51:21 +0700 Subject: [PATCH 424/544] Remove unnecessary x86_64 and x87 undefines. These aren't defined for our target in the first place, so we don't need to undefine them. --- tools/shared.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/shared.py b/tools/shared.py index 4d12e33a3e70f..f59ac9c5f55d6 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -399,8 +399,9 @@ def clean_temp(): except: COMPILER_OPTS = [] # Force a simple, standard target as much as possible: target 32-bit linux, and disable various flags that hint at other platforms -COMPILER_OPTS = COMPILER_OPTS + ['-m32', '-U__i386__', '-U__x86_64__', '-U__i386', '-U__x86_64', '-Ui386', '-Ux86_64', '-U__SSE__', '-U__SSE2__', '-U__MMX__', - '-UX87_DOUBLE_ROUNDING', '-UHAVE_GCC_ASM_FOR_X87', '-DEMSCRIPTEN', '-U__STRICT_ANSI__', '-U__CYGWIN__', +COMPILER_OPTS = COMPILER_OPTS + ['-m32', '-U__i386__', '-U__i386', '-Ui386', + '-U__SSE__', '-U__SSE_MATH__', '-U__SSE2__', '-U__SSE2_MATH__', '-U__MMX__', + '-DEMSCRIPTEN', '-U__STRICT_ANSI__', '-U__CYGWIN__', '-target', 'i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno'] USE_EMSDK = not os.environ.get('EMMAKEN_NO_SDK') From 0d1d8a114cc4e73438c04bf4070f30852b1a1961 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 17 Apr 2013 17:53:04 +0700 Subject: [PATCH 425/544] Remove unnecessary undefine of __CYGWIN__. --- tools/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index f59ac9c5f55d6..a53c0a7b26fd0 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -401,7 +401,7 @@ def clean_temp(): # Force a simple, standard target as much as possible: target 32-bit linux, and disable various flags that hint at other platforms COMPILER_OPTS = COMPILER_OPTS + ['-m32', '-U__i386__', '-U__i386', '-Ui386', '-U__SSE__', '-U__SSE_MATH__', '-U__SSE2__', '-U__SSE2_MATH__', '-U__MMX__', - '-DEMSCRIPTEN', '-U__STRICT_ANSI__', '-U__CYGWIN__', + '-DEMSCRIPTEN', '-U__STRICT_ANSI__', '-target', 'i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno'] USE_EMSDK = not os.environ.get('EMMAKEN_NO_SDK') From 4496bd1f5f644c37e0600f3bb1c756d8ff307b7f Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 17 Apr 2013 18:00:39 +0700 Subject: [PATCH 426/544] Use a generic constraint for test_inlinejs. This being generic lets it work with multiple target triples rather than being x86-specific. This works under both the current target triple and le32-unknown-nacl. --- tests/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runner.py b/tests/runner.py index db5ba10893e37..bda17fe768b32 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -3541,7 +3541,7 @@ def test_inlinejs(self): double get() { double ret = 0; - __asm __volatile__("12/3.3":"=a"(ret)); + __asm __volatile__("12/3.3":"=r"(ret)); return ret; } From d66573c7e8becabf5acfb72cd3e65fedf1b56b3b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 17 Apr 2013 11:06:49 -0700 Subject: [PATCH 427/544] remove eliminated variable definitions only if variable was successfully removed (it might not be if it is in a switch) in asm --- tools/eliminator/asm-eliminator-test-output.js | 15 +++++++++++++++ tools/eliminator/asm-eliminator-test.js | 15 +++++++++++++++ tools/js-optimizer.js | 13 +++++++------ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/tools/eliminator/asm-eliminator-test-output.js b/tools/eliminator/asm-eliminator-test-output.js index 4cf15c62d6de2..e477c32031b53 100644 --- a/tools/eliminator/asm-eliminator-test-output.js +++ b/tools/eliminator/asm-eliminator-test-output.js @@ -108,4 +108,19 @@ function label() { i(); } } +function switchy() { + var no = 0, yes = 0; + while (1) switch (label | 0) { + case x: + no = 100; + break; + case y: + yes = 111; + yes = yes * 2; + print(yes); + yes--; + print(yes / 2); + continue; + } +} diff --git a/tools/eliminator/asm-eliminator-test.js b/tools/eliminator/asm-eliminator-test.js index d2c0507caa448..acc07edb77b62 100644 --- a/tools/eliminator/asm-eliminator-test.js +++ b/tools/eliminator/asm-eliminator-test.js @@ -141,5 +141,20 @@ function label() { i(); } } +function switchy() { + var no = 0, yes = 0; + while (1) switch (label | 0) { + case x: + no = 100; // eliminatable in theory, but eliminator does not look into switch. must leave def above as well. + break; + case y: + yes = 111; + yes = yes*2; + print(yes); + yes--; + print(yes/2); + continue; + } +} // EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label"] diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 5ede0ce8d0b87..598287db14310 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -1765,6 +1765,7 @@ function eliminate(ast, memSafe) { var values = {}; var locals = {}; var varsToRemove = {}; // variables being removed, that we can eliminate all 'var x;' of (this refers to 'var' nodes we should remove) + // 1 means we should remove it, 2 means we successfully removed it var varsToTryToRemove = {}; // variables that have 0 uses, but have side effects - when we scan we can try to remove them // add arguments as locals if (func[2]) { @@ -1822,7 +1823,7 @@ function eliminate(ast, memSafe) { }); } if (!hasSideEffects) { - varsToRemove[name] = 1; // remove it normally + varsToRemove[name] = !definitions[name] ? 2 : 1; // remove it normally sideEffectFree[name] = true; } else { varsToTryToRemove[name] = 1; // try to remove it later during scanning @@ -1979,7 +1980,7 @@ function eliminate(ast, memSafe) { for (var i = 0; i < value.length; i++) { node[i] = value[i]; } - varsToRemove[name] = 1; + varsToRemove[name] = 2; } } else { if (allowTracking) track(name, node[3], node); @@ -2019,7 +2020,7 @@ function eliminate(ast, memSafe) { for (var i = 0; i < value.length; i++) { node[i] = value[i]; } - varsToRemove[name] = 1; + varsToRemove[name] = 2; } } } @@ -2123,7 +2124,7 @@ function eliminate(ast, memSafe) { function doEliminate(name, node) { //printErr('elim!!!!! ' + name); // yes, eliminate! - varsToRemove[name] = 1; // both assign and var definitions can have other vars we must clean up + varsToRemove[name] = 2; // both assign and var definitions can have other vars we must clean up var info = tracked[name]; delete tracked[name]; var defNode = info.defNode; @@ -2181,7 +2182,7 @@ function eliminate(ast, memSafe) { //printErr('cleaning up ' + JSON.stringify(varsToRemove)); traverse(func, function(node, type) { if (type === 'var') { - node[1] = node[1].filter(function(pair) { return !(pair[0] in varsToRemove) }); + node[1] = node[1].filter(function(pair) { return !varsToRemove[pair[0]] }); if (node[1].length == 0) { // wipe out an empty |var;| node[0] = 'toplevel'; @@ -2192,7 +2193,7 @@ function eliminate(ast, memSafe) { if (asm) { for (var v in varsToRemove) { - delete asmData.vars[v]; + if (varsToRemove[v] == 2) delete asmData.vars[v]; } denormalizeAsm(func, asmData); } From 2be92943d135dd4beb12c394c921eaaa26f98cc5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 17 Apr 2013 11:08:51 -0700 Subject: [PATCH 428/544] enable asm in -O1 and prepare to add testing --- emcc | 2 +- tests/runner.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/emcc b/emcc index 7edc71e4c6809..e25d9d917943c 100755 --- a/emcc +++ b/emcc @@ -1002,7 +1002,7 @@ try: # Apply effects from settings if shared.Settings.ASM_JS: - assert opt_level == 2, 'asm.js requires -O2' + assert opt_level >= 1, 'asm.js requires -O1 or above' if closure: print >> sys.stderr, 'emcc: warning: disabling closure because it is not compatible with asm.js code generation' diff --git a/tests/runner.py b/tests/runner.py index db5ba10893e37..8786d4f608949 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -9001,6 +9001,7 @@ def setUp(self): exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "-s", "JS_CHUNK_SIZE=1024"])') # asm.js + #exec('asm1 = make_run("asm1", compiler=CLANG, emcc_args=["-O1", "-s", "ASM_JS=1"])') exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1"])') exec('asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1"])') From 5891371e0c573f4c3a28c0ac56943674a969b2be Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 17 Apr 2013 11:46:03 -0700 Subject: [PATCH 429/544] fix test/cases/legalizer_ta2.ll for asm1 --- tests/cases/legalizer_ta2.ll | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cases/legalizer_ta2.ll b/tests/cases/legalizer_ta2.ll index 7e17c707246e1..89ebcef6056d6 100644 --- a/tests/cases/legalizer_ta2.ll +++ b/tests/cases/legalizer_ta2.ll @@ -188,4 +188,5 @@ done: declare i32 @puts(i8*) declare i32 @__gxx_personality_v0(...) +declare void @__cxa_throw(i32, i32, i32) ; for asm1, where exceptions are enabled but this test needs a throw to bring in lib stuff From 00acb94c2b3c9e9b12be5930b3c897412fbc4573 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 17 Apr 2013 12:11:20 -0700 Subject: [PATCH 430/544] emit return in unreachable in asm mode --- src/jsifier.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 926be71aa69bd..856e880c4af6a 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1458,11 +1458,12 @@ function JSify(data, functionsOnly, givenFunctions) { }); makeFuncLineActor('unreachable', function(item) { + var ret = ''; + if (ASM_JS && item.funcData.returnType != 'void') ret = 'return ' + asmCoercion('0', item.funcData.returnType) + ';'; if (ASSERTIONS) { - return ASM_JS ? 'abort()' : 'throw "Reached an unreachable!"'; - } else { - return ';'; + ret = (ASM_JS ? 'abort()' : 'throw "Reached an unreachable!"') + ';' + ret; } + return ret || ';'; }); // Final combiner From 2ff1887ef99474695f2156d79d61201888c8dcbb Mon Sep 17 00:00:00 2001 From: "Michael J. Bishop" Date: Wed, 17 Apr 2013 15:52:38 -0400 Subject: [PATCH 431/544] Added test for passing two separate arrays of attributes, each with different stride values but both tightly packed. The test case test both passing explicit and implicit stride (0 means "tightly packed"). --- tests/gl_stride.c | 152 ++++++++++++++++++++++++++++++++++++++++++++ tests/gl_stride.png | Bin 0 -> 345620 bytes tests/runner.py | 3 + 3 files changed, 155 insertions(+) create mode 100644 tests/gl_stride.c create mode 100644 tests/gl_stride.png diff --git a/tests/gl_stride.c b/tests/gl_stride.c new file mode 100644 index 0000000000000..c254ad5a83015 --- /dev/null +++ b/tests/gl_stride.c @@ -0,0 +1,152 @@ +/******************************************************************* + * * + * Using SDL With OpenGL * + * * + * Tutorial by Kyle Foley (sdw) * + * * + * http://gpwiki.org/index.php/SDL:Tutorials:Using_SDL_with_OpenGL * + * * + *******************************************************************/ + +/* +THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION +AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN. + +THE ORIGINAL AUTHOR IS KYLE FOLEY. + +THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY +OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF +MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE, +ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE +RESULTING FROM THE USE, MODIFICATION, OR +REDISTRIBUTION OF THIS SOFTWARE. +*/ + +#if !EMSCRIPTEN +#define USE_GLEW 0 +#endif + +#if USE_GLEW +#include "GL/glew.h" +#endif + +#include "SDL/SDL.h" +#include "SDL/SDL_image.h" +#if !USE_GLEW +#include "SDL/SDL_opengl.h" +#endif + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + SDL_Surface *screen; + + // Slightly different SDL initialization + if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) { + printf("Unable to initialize SDL: %s\n", SDL_GetError()); + return 1; + } + + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new* + + screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL ); // *changed* + if ( !screen ) { + printf("Unable to set video mode: %s\n", SDL_GetError()); + return 1; + } + + // Set the OpenGL state after creating the context with SDL_SetVideoMode + + glClearColor( 0, 0, 0, 0 ); + +#if !EMSCRIPTEN + glEnable( GL_TEXTURE_2D ); // Need this to display a texture XXX unnecessary in OpenGL ES 2.0/WebGL +#endif + + glViewport( 0, 0, 640, 480 ); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Clear the screen before drawing + glClear( GL_COLOR_BUFFER_BIT ); + + typedef struct Vertex { + GLfloat x; + GLfloat y; + } Vertex; + + typedef struct Color { + GLubyte r; + GLubyte g; + GLubyte b; + GLubyte a; + } Color; + + Vertex vertices[3] = { + {-1.0, 0.0}, + { 0.0, 1.0}, + { 1.0, 0.0} + }; + + Color colors[3] = { + {0xFF, 0x00, 0x00, 0xFF}, + {0x00, 0xFF, 0x00, 0xFF}, + {0x00, 0x00, 0xFF, 0xFF} + }; + + Vertex vertices2[3] = { + {-1.0, 0.0}, + { 1.0, 0.0}, + { 0.0, -1.0} + }; + + Color colors2[3] = { + {0xFF, 0x00, 0x00, 0xFF}, + {0x00, 0x00, 0xFF, 0xFF}, + {0x00, 0xFF, 0x00, 0xFF} + }; + + // DRAW + + // Clear the screen before drawing + glClear( GL_COLOR_BUFFER_BIT ); + + // This test ensures that we can use two separate arrays in memory for different + // attributes, and that they each can have different stride. + // The first test shows implicit striding (the zero indicates tightly packed) + // The second test shows explicit striding where the stride is passed in + // even though it also is tightly packed + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + // TEST 1 + + glVertexPointer(2, GL_FLOAT, 0, vertices); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + + // TEST 2 + + glVertexPointer(2, GL_FLOAT, 8, vertices2); + glColorPointer(4, GL_UNSIGNED_BYTE, 4, colors2); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + + SDL_GL_SwapBuffers(); + +#if !EMSCRIPTEN + // Wait for 3 seconds to give us a chance to see the image + SDL_Delay(3000); +#endif + + SDL_Quit(); + + return 0; +} diff --git a/tests/gl_stride.png b/tests/gl_stride.png new file mode 100644 index 0000000000000000000000000000000000000000..db1bc7512bed205d3f9be4f795a2dda6fc6c4275 GIT binary patch literal 345620 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

    QRJBdj3!{!cl+M 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 z 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%0DO?2MI~{+8*NEuzQ1_N2ciSbv77^*>AehGl;> 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 Q|#?&)%{3TNw2b0t* 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 Date: Wed, 17 Apr 2013 14:23:31 -0700 Subject: [PATCH 432/544] do not emit landingpad call to cxa_find_matching_catch if exceptions are disabled --- src/jsifier.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/jsifier.js b/src/jsifier.js index 856e880c4af6a..8281f8957b0c7 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1210,6 +1210,11 @@ function JSify(data, functionsOnly, givenFunctions) { } }); makeFuncLineActor('landingpad', function(item) { + if (DISABLE_EXCEPTION_CATCHING) { + item.assignTo = null; + if (ASSERTIONS) warnOnce('landingpad, but exceptions are disabled!'); + return ';' + } var catchTypeArray = item.catchables.map(finalizeLLVMParameter).map(function(element) { return asmCoercion(element, 'i32') }).join(','); var ret = asmCoercion('___cxa_find_matching_catch(-1, -1' + (catchTypeArray.length > 0 ? ',' + catchTypeArray : '') +')', 'i32'); if (USE_TYPED_ARRAYS == 2) { From 823cd26725e2108141c3fec7b76c47288c6fd532 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 17 Apr 2013 14:23:49 -0700 Subject: [PATCH 433/544] enable testing for asm -O1 --- tests/runner.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 8786d4f608949..c2d70c22b5f29 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -455,7 +455,7 @@ def setup_runtimelink_test(self): if len(sys.argv) == 2 and 'ALL.' in sys.argv[1]: ignore, test = sys.argv[1].split('.') print 'Running all test modes on test "%s"' % test - sys.argv = [sys.argv[0], 'default.'+test, 'o1.'+test, 'o2.'+test, 'asm2.'+test, 'asm2g.'+test, 's_0_0.'+test, 's_0_1.'+test, 's_1_0.'+test, 's_1_1.'+test] + sys.argv = [sys.argv[0], 'default.'+test, 'o1.'+test, 'o2.'+test, 'asm1.'+test, 'asm2.'+test, 'asm2g.'+test, 's_0_0.'+test, 's_0_1.'+test, 's_1_0.'+test, 's_1_1.'+test] class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline ## Does a complete test - builds, runs, checks output, etc. @@ -3709,6 +3709,7 @@ def test_cxx03_do_run(self): def test_bigswitch(self): if Settings.RELOOP: return self.skip('TODO: switch in relooper, issue #781') + if Settings.ASM_JS: return self.skip('TODO: switch too large for asm') src = open(path_from_root('tests', 'bigswitch.cpp')).read() self.do_run(src, '''34962: GL_ARRAY_BUFFER (0x8892) @@ -9001,7 +9002,7 @@ def setUp(self): exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "-s", "JS_CHUNK_SIZE=1024"])') # asm.js - #exec('asm1 = make_run("asm1", compiler=CLANG, emcc_args=["-O1", "-s", "ASM_JS=1"])') + exec('asm1 = make_run("asm1", compiler=CLANG, emcc_args=["-O1", "-s", "ASM_JS=1"])') exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1"])') exec('asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1"])') From 5d82a4c77304f6fcd164d73fbad6c0f3c9a43daf Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 17 Apr 2013 20:10:46 -0700 Subject: [PATCH 434/544] emit landingpad variable assignment to avoid errors, even when exceptions are disabled --- src/jsifier.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 8281f8957b0c7..a4dd797bd26a8 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1210,10 +1210,11 @@ function JSify(data, functionsOnly, givenFunctions) { } }); makeFuncLineActor('landingpad', function(item) { - if (DISABLE_EXCEPTION_CATCHING) { + if (DISABLE_EXCEPTION_CATCHING && USE_TYPED_ARRAYS == 2) { + ret = makeVarDef(item.assignTo) + '$0 = 0; ' + item.assignTo + '$1 = 0;'; item.assignTo = null; if (ASSERTIONS) warnOnce('landingpad, but exceptions are disabled!'); - return ';' + return ret; } var catchTypeArray = item.catchables.map(finalizeLLVMParameter).map(function(element) { return asmCoercion(element, 'i32') }).join(','); var ret = asmCoercion('___cxa_find_matching_catch(-1, -1' + (catchTypeArray.length > 0 ? ',' + catchTypeArray : '') +')', 'i32'); From 040eb9db4222bf3b3eff2ba0ca72e83830f76d47 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 17 Apr 2013 21:08:28 -0700 Subject: [PATCH 435/544] when we have multiple strides, restride --- src/library_gl.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/library_gl.js b/src/library_gl.js index 0912b5dab037f..b91d782c47c9a 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -2282,14 +2282,14 @@ var LibraryGL = { } attributes.sort(function(x, y) { return !x ? (!y ? 0 : 1) : (!y ? -1 : (x.pointer - y.pointer)) }); start = GL.currArrayBuffer ? 0 : attributes[0].pointer; + var multiStrides = false; for (var i = 0; i < attributes.length; i++) { var attribute = attributes[i]; if (!attribute) break; -#if ASSERTIONS - assert(stride == 0 || stride == attribute.stride); // must all be in the same buffer -#endif + if (stride != 0 && stride != attribute.stride) multiStrides = true; if (attribute.stride) stride = attribute.stride; } + if (multiStrides) stride = 0; // we will need to restride var bytes = 0; // total size in bytes if (!stride && !beginEnd) { // beginEnd can not have stride in the attributes, that is fine. otherwise, @@ -2297,7 +2297,7 @@ var LibraryGL = { // our emulation code simple, we perform unpacking/restriding here. this adds overhead, so // it is a good idea to not hit this! #if ASSERTIONS - Runtime.warnOnce('Unpacking/restriding attributes, this is not fast'); + Runtime.warnOnce('Unpacking/restriding attributes, this is slow and dangerous'); #endif if (!GL.immediate.restrideBuffer) GL.immediate.restrideBuffer = _malloc(GL.MAX_TEMP_BUFFER_SIZE); start = GL.immediate.restrideBuffer; From f554c2fac03138bf6d3c25180b6dc6771fb80166 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 8 Apr 2013 12:19:26 -0700 Subject: [PATCH 436/544] Generalize class property access. --- src/embind/embind.js | 25 +++++++++++++++---------- system/include/emscripten/bind.h | 25 +++++++++++++++++++++++-- tests/embind/embind.test.js | 10 ++++++++++ tests/embind/embind_test.cpp | 1 + 4 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index ee717f4be2409..03af701008783 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1154,42 +1154,47 @@ function __embind_register_class_class_function( } function __embind_register_class_property( - rawClassType, + classType, fieldName, - rawFieldType, + getterReturnType, getter, + getterContext, + setterArgumentType, setter, - context + setterContext ) { fieldName = Pointer_stringify(fieldName); getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; - whenDependentTypesAreResolved([], [rawClassType], function(classType) { + + whenDependentTypesAreResolved([], [classType], function(classType) { classType = classType[0]; var humanName = classType.name + '.' + fieldName; Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, { get: function() { - throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [rawFieldType]); + throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [getterReturnType, setterArgumentType]); }, set: function() { - throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [rawFieldType]); + throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [getterReturnType, setterArgumentType]); }, enumerable: true, configurable: true }); - whenDependentTypesAreResolved([], [rawFieldType], function(fieldType) { - fieldType = fieldType[0]; + whenDependentTypesAreResolved([], [getterReturnType, setterArgumentType], function(types) { + var getterReturnType = types[0]; + var setterArgumentType = types[1]; + Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, { get: function() { var ptr = validateThis(this, classType, humanName + ' getter'); - return fieldType.fromWireType(getter(context, ptr)); + return getterReturnType.fromWireType(getter(getterContext, ptr)); }, set: function(v) { var ptr = validateThis(this, classType, humanName + ' setter'); var destructors = []; - setter(context, ptr, fieldType.toWireType(destructors, v)); + setter(setterContext, ptr, setterArgumentType.toWireType(destructors, v)); runDestructors(destructors); }, enumerable: true diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 57e44c0c2b06e..d70aec91101e3 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -136,10 +136,12 @@ namespace emscripten { void _embind_register_class_property( TYPEID classType, const char* fieldName, - TYPEID fieldType, + TYPEID getterReturnType, GenericFunction getter, + void* getterContext, + TYPEID setterArgumentType, GenericFunction setter, - void* context); + void* setterContext); void _embind_register_class_class_function( TYPEID classType, @@ -980,11 +982,30 @@ namespace emscripten { fieldName, TypeID::get(), reinterpret_cast(&MemberAccess::template getWire), + getContext(field), + TypeID::get(), reinterpret_cast(&MemberAccess::template setWire), getContext(field)); return *this; } + template + class_& property(const char* fieldName, Getter getter, Setter setter) { + using namespace internal; + typedef GetterPolicy GP; + typedef SetterPolicy SP; + _embind_register_class_property( + TypeID::get(), + fieldName, + TypeID::get(), + reinterpret_cast(&GP::template get), + GP::getContext(getter), + TypeID::get(), + reinterpret_cast(&SP::template set), + SP::getContext(setter)); + return *this; + } + template class_& class_function(const char* methodName, ReturnType (*classMethod)(Args...), Policies...) { using namespace internal; diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 290fed7238c22..82dbeb25f4110 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -837,6 +837,16 @@ module({ assert.equal(0, cm.count_emval_handles()); }); + test("class properties can be methods", function() { + var a = {}; + var b = {foo: 'foo'}; + var c = new cm.ValHolder(a); + assert.equal(a, c.val); + c.val = b; + assert.equal(b, c.val); + c.delete(); + }); + test("class instance $$ property is non-enumerable", function() { var c = new cm.ValHolder(undefined); assert.deepEqual([], Object.keys(c)); diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 1384406a00008..f3e2cbeee6b67 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1527,6 +1527,7 @@ EMSCRIPTEN_BINDINGS(tests) { .function("getConstVal", &ValHolder::getConstVal) .function("getValConstRef", &ValHolder::getValConstRef) .function("setVal", &ValHolder::setVal) + .property("val", &ValHolder::getVal, &ValHolder::setVal) .class_function("makeConst", &ValHolder::makeConst, allow_raw_pointer()) .class_function("makeValHolder", &ValHolder::makeValHolder) .class_function("some_class_method", &ValHolder::some_class_method) From 927c8a5e44da6c5cc539fa7d4e0a2168dafa3d36 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 8 Apr 2013 13:58:34 -0700 Subject: [PATCH 437/544] Kill validateThis for methods --- src/embind/embind.js | 8 ++++++-- tests/embind/embind.test.js | 8 ++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 03af701008783..b8bd5fcfb9a63 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -640,9 +640,15 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { return 0; } } + if (!(handle instanceof this.registeredClass.constructor)) { throwBindingError('Expected null or instance of ' + this.name + ', got ' + _embind_repr(handle)); } + + if (!handle.$$.ptr) { + throwBindingError('Cannot pass deleted object'); + } + // TODO: this is not strictly true // We could support BY_EMVAL conversions from raw pointers to smart pointers // because the smart pointer can hold a reference to the handle @@ -1079,8 +1085,6 @@ function __embind_register_class_function( throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-2)); } - validateThis(this, classType, humanName); - var destructors = []; var args = new Array(argCount + 1); args[0] = context; diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 82dbeb25f4110..8155fd1116677 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -143,7 +143,7 @@ module({ var e = assert.throws(cm.BindingError, function() { cm.Derived.prototype.setMember.call(a, "foo"); }); - assert.equal('Derived.setMember incompatible with "this" of type HasTwoBases', e.message); + assert.equal('Expected null or instance of Derived*, got [object Object]', e.message); a.delete(); }); @@ -153,7 +153,7 @@ module({ }); if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! // got Error: expected: Derived.setMember with invalid "this": undefined, actual: Derived.setMember incompatible with "this" of type Object - assert.equal('Derived.setMember with invalid "this": undefined', e.message); + assert.equal('Expected null or instance of Derived*, got undefined', e.message); } var e = assert.throws(cm.BindingError, function() { @@ -161,14 +161,14 @@ module({ }); if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! // TODO got 'Derived.setMember incompatible with "this" of type Object' - assert.equal('Derived.setMember with invalid "this": this', e.message); + assert.equal('Expected null or instance of Derived*, got this', e.message); } var e = assert.throws(cm.BindingError, function() { cm.Derived.prototype.setMember.call({}, "foo"); }); if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! - assert.equal('Derived.setMember incompatible with "this" of type Object', e.message); + assert.equal('Expected null or instance of Derived*, got [object Object]', e.message); } }); From 17639c372a5f41177177c21c56731b103ad738ad Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 9 Apr 2013 18:01:15 -0700 Subject: [PATCH 438/544] allow optional implementation of non-abstract virtual methods --- src/embind/emval.js | 5 +++++ system/include/emscripten/bind.h | 15 ++++++++++++++- system/include/emscripten/val.h | 7 +++++++ tests/embind/embind.test.js | 22 ++++++++++++++++++++++ tests/embind/embind_test.cpp | 14 ++++++++++++++ 5 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index 45030b99c633d..037ce47d6f032 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -194,3 +194,8 @@ function __emval_call_void_method(handle, name, argCount, argTypes) { var obj = _emval_handle_array[handle].value; obj[name].apply(obj, args); } + +function __emval_has_function(handle, name) { + name = Pointer_stringify(name); + return _emval_handle_array[handle].value[name] instanceof Function; +} diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index d70aec91101e3..07955d75b3a94 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -713,7 +713,7 @@ namespace emscripten { template class wrapper : public T { public: - wrapper(const val& wrapped) + explicit wrapper(const val& wrapped) : wrapped(wrapped) {} @@ -722,7 +722,20 @@ namespace emscripten { return Caller::call(wrapped, name, args...); } + template + ReturnType optional_call(const char* name, Default def, Args... args) const { + if (has_function(name)) { + return Caller::call(wrapped, name); + } else { + return def(); + } + } + private: + bool has_function(const char* name) const { + return wrapped.has_function(name); + } + // this class only exists because you can't partially specialize function templates template struct Caller { diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 91f775a709fc2..c27a0fdb65e09 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -48,6 +48,9 @@ namespace emscripten { unsigned argCount, internal::TYPEID argTypes[] /*, ...*/); + bool _emval_has_function( + EM_VAL value, + const char* methodName); } } @@ -222,6 +225,10 @@ namespace emscripten { toWireType(args)...); } + bool has_function(const char* name) const { + return _emval_has_function(handle, name); + } + template T as() const { using namespace internal; diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 8155fd1116677..4a8665f44a038 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -1464,6 +1464,28 @@ module({ assert.equal(expected, cm.callAbstractMethod(impl)); impl.delete(); }); + + test("can implement optional methods in JavaScript", function() { + var expected = "my JS string"; + function MyImplementation() { + this.rv = expected; + } + MyImplementation.prototype.optionalMethod = function() { + return this.rv; + }; + + var impl = cm.AbstractClass.implement(new MyImplementation); + assert.equal(expected, impl.optionalMethod(expected)); + assert.equal(expected, cm.callOptionalMethod(impl, expected)); + impl.delete(); + }); + + test("if not implemented then optional method runs default", function() { + var impl = cm.AbstractClass.implement({}); + assert.equal("optionalfoo", impl.optionalMethod("foo")); + assert.equal("optionalfoo", cm.callOptionalMethod(impl, "foo")); + impl.delete(); + }); }); BaseFixture.extend("registration order", function() { diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index f3e2cbeee6b67..39de38528f967 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1074,6 +1074,9 @@ class AbstractClass { public: virtual ~AbstractClass() {} virtual std::string abstractMethod() const = 0; + virtual std::string optionalMethod(std::string s) const { + return "optional" + s; + } }; class AbstractClassWrapper : public wrapper { @@ -1083,6 +1086,11 @@ class AbstractClassWrapper : public wrapper { std::string abstractMethod() const { return call("abstractMethod"); } + std::string optionalMethod(std::string s) const { + return optional_call("optionalMethod", [&] { + return AbstractClass::optionalMethod(s); + }, s); + } }; class ConcreteClass : public AbstractClass { @@ -1099,6 +1107,10 @@ std::string callAbstractMethod(AbstractClass& ac) { return ac.abstractMethod(); } +std::string callOptionalMethod(AbstractClass& ac, std::string s) { + return ac.optionalMethod(s); +} + class HasExternalConstructor { public: HasExternalConstructor(const std::string& str) @@ -1859,10 +1871,12 @@ EMSCRIPTEN_BINDINGS(tests) { .smart_ptr>() .allow_subclass() .function("abstractMethod", &AbstractClass::abstractMethod) + .function("optionalMethod", &AbstractClass::optionalMethod) ; function("getAbstractClass", &getAbstractClass); function("callAbstractMethod", &callAbstractMethod); + function("callOptionalMethod", &callOptionalMethod); class_("HasExternalConstructor") .constructor(&createHasExternalConstructor) From bdeab9a67107aaacc97bc043b8a753e0c58d7e7d Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 9 Apr 2013 18:37:29 -0700 Subject: [PATCH 439/544] fix a bug in optional argument lists --- system/include/emscripten/bind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 07955d75b3a94..73a8d4da218a3 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -725,7 +725,7 @@ namespace emscripten { template ReturnType optional_call(const char* name, Default def, Args... args) const { if (has_function(name)) { - return Caller::call(wrapped, name); + return Caller::call(wrapped, name, args...); } else { return def(); } From de80f9c04100e57f74f62352981548cd3e322579 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Tue, 9 Apr 2013 12:49:32 -0700 Subject: [PATCH 440/544] Support for intrusive pointers. This dependency on Northstar must be removed before pusing embind to GitHub. --- src/embind/embind.js | 2 +- system/include/emscripten/bind.h | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index b8bd5fcfb9a63..4225060135adf 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -672,7 +672,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { break; case 1: // INTRUSIVE - throwBindingError('INTRUSIVE sharing policy not yet supported'); + ptr = handle.$$.smartPtr; break; case 2: // BY_EMVAL diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 73a8d4da218a3..3901ce5086815 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -9,6 +9,7 @@ #include #include #include +#include "northstar/Pointer.h" namespace emscripten { enum class sharing_policy { @@ -705,6 +706,24 @@ namespace emscripten { }; }; + template + struct smart_ptr_trait> { + typedef northstar::IntrusivePointer PointerType; + typedef typename PointerType::element_type element_type; + + static element_type* get(const PointerType& ptr) { + return ptr.get(); + } + + static northstar::IntrusivePointer* share(PointeeType* p, internal::EM_VAL v) { + return new northstar::IntrusivePointer(p); + } + + static sharing_policy get_sharing_policy() { + return sharing_policy::INTRUSIVE; + } + }; + //////////////////////////////////////////////////////////////////////////////// // CLASSES //////////////////////////////////////////////////////////////////////////////// From ebb2069d804f49b457f6a4349a3136703db60190 Mon Sep 17 00:00:00 2001 From: Bill Welden Date: Wed, 10 Apr 2013 14:09:40 -0700 Subject: [PATCH 441/544] Removed dependency on Northstar. --- system/include/emscripten/bind.h | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 3901ce5086815..73a8d4da218a3 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -9,7 +9,6 @@ #include #include #include -#include "northstar/Pointer.h" namespace emscripten { enum class sharing_policy { @@ -706,24 +705,6 @@ namespace emscripten { }; }; - template - struct smart_ptr_trait> { - typedef northstar::IntrusivePointer PointerType; - typedef typename PointerType::element_type element_type; - - static element_type* get(const PointerType& ptr) { - return ptr.get(); - } - - static northstar::IntrusivePointer* share(PointeeType* p, internal::EM_VAL v) { - return new northstar::IntrusivePointer(p); - } - - static sharing_policy get_sharing_policy() { - return sharing_policy::INTRUSIVE; - } - }; - //////////////////////////////////////////////////////////////////////////////// // CLASSES //////////////////////////////////////////////////////////////////////////////// From bcf017994524b515274344dcf667dc03b8153448 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 10 Apr 2013 23:10:26 -0700 Subject: [PATCH 442/544] verify non-ascii data can be passed through std::string --- tests/embind/embind.test.js | 8 ++++++++ tests/embind/embind_test.cpp | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 4a8665f44a038..07f093ea351c4 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -388,6 +388,14 @@ module({ }); }); + BaseFixture.extend("string", function() { + var expected = ''; + for (var i = 0; i < 128; ++i) { + expected += String.fromCharCode(128 + i); + } + assert.equal(expected, cm.get_non_ascii_string()); + }); + BaseFixture.extend("embind", function() { test("value creation", function() { assert.equal(15, cm.emval_test_new_integer()); diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 39de38528f967..6a3d5dba583c2 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -79,6 +79,15 @@ unsigned emval_test_sum(val v) { return rv; } +std::string get_non_ascii_string() { + char c[128 + 1]; + c[128] = 0; + for (int i = 0; i < 128; ++i) { + c[i] = 128 + i; + } + return c; +} + std::string emval_test_take_and_return_const_char_star(const char* str) { return str; } @@ -1493,6 +1502,7 @@ EMSCRIPTEN_BINDINGS(tests) { function("const_ref_adder", &const_ref_adder); function("emval_test_sum", &emval_test_sum); + function("get_non_ascii_string", &get_non_ascii_string); //function("emval_test_take_and_return_const_char_star", &emval_test_take_and_return_const_char_star); function("emval_test_take_and_return_std_string", &emval_test_take_and_return_std_string); function("emval_test_take_and_return_std_string_const_ref", &emval_test_take_and_return_std_string_const_ref); From 6a4574cfe44b75f8cfaa916a08b402f99baf6cc7 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 10 Apr 2013 23:59:51 -0700 Subject: [PATCH 443/544] Add support for returning std::wstring --- src/embind/embind.js | 31 ++++++++++++++++++++++++++++--- system/include/emscripten/bind.h | 7 ++++++- system/include/emscripten/wire.h | 20 ++++++++++++++++++++ system/lib/embind/bind.cpp | 21 ++++++++++++++++++++- tests/embind/embind.test.js | 20 +++++++++++++++----- tests/embind/embind_test.cpp | 10 ++++++++++ 6 files changed, 99 insertions(+), 10 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 4225060135adf..576a519e49aee 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -317,12 +317,12 @@ function __embind_register_float(rawType, name) { }); } -function __embind_register_cstring(rawType, name) { +function __embind_register_std_string(rawType, name) { name = Pointer_stringify(name); registerType(rawType, { name: name, fromWireType: function(value) { - var length = HEAP32[value >> 2]; + var length = HEAPU32[value >> 2]; var a = new Array(length); for (var i = 0; i < length; ++i) { a[i] = String.fromCharCode(HEAPU8[value + 4 + i]); @@ -334,7 +334,7 @@ function __embind_register_cstring(rawType, name) { // assumes 4-byte alignment var length = value.length; var ptr = _malloc(4 + length); - HEAP32[ptr >> 2] = length; + HEAPU32[ptr >> 2] = length; for (var i = 0; i < length; ++i) { HEAPU8[ptr + 4 + i] = value.charCodeAt(i); } @@ -344,6 +344,31 @@ function __embind_register_cstring(rawType, name) { }); } +function __embind_register_std_wstring(rawType, charSize, name) { + name = Pointer_stringify(name); + var HEAP, shift; + if (charSize == 2) { + HEAP = HEAPU16; + shift = 1; + } else if (charSize == 4) { + HEAP = HEAPU32; + shift = 2; + } + registerType(rawType, { + name: name, + fromWireType: function(value) { + var length = HEAPU32[value >> 2]; + var a = new Array(length); + var start = (value + 4) >> shift; + for (var i = 0; i < length; ++i) { + a[i] = String.fromCharCode(HEAP[start + i]); + } + _free(value); + return a.join(''); + }, + }); +} + function __embind_register_emval(rawType, name) { name = Pointer_stringify(name); registerType(rawType, { diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 73a8d4da218a3..9b6e69c98b21e 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -47,10 +47,15 @@ namespace emscripten { TYPEID floatType, const char* name); - void _embind_register_cstring( + void _embind_register_std_string( TYPEID stringType, const char* name); + void _embind_register_std_wstring( + TYPEID stringType, + size_t charSize, + const char* name); + void _embind_register_emval( TYPEID emvalType, const char* name); diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 64114491ab1b5..0e8334e86c1c4 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -181,6 +181,26 @@ namespace emscripten { } }; + template<> + struct BindingType { + typedef struct { + size_t length; + wchar_t data[1]; // trailing data + }* WireType; + static WireType toWireType(const std::wstring& v) { + WireType wt = (WireType)malloc(sizeof(size_t) + v.length() * sizeof(wchar_t)); + wt->length = v.length(); + wmemcpy(wt->data, v.data(), v.length()); + return wt; + } + static std::wstring fromWireType(WireType v) { + return std::wstring(v->data, v->length); + } + static void destroy(WireType v) { + free(v); + } + }; + template struct BindingType : public BindingType { }; diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index deb55138ff2f2..6cacf1e2e928e 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -44,6 +44,24 @@ namespace emscripten { } } +// TODO: fix in library.js or a proper emscripten libc +extern "C" wchar_t *wmemset(wchar_t *dest, wchar_t c, size_t count) { + wchar_t *o = dest; + while (count--) { + *o++ = c; + } + return dest; +} + +// TODO: fix in library.js or a proper emscripten libc +extern "C" wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, size_t count) { + wchar_t *o = dest; + while (count--) { + *dest++ = *src++; + } + return dest; +} + EMSCRIPTEN_BINDINGS(native_and_builtin_types) { using namespace emscripten::internal; @@ -64,6 +82,7 @@ EMSCRIPTEN_BINDINGS(native_and_builtin_types) { _embind_register_float(TypeID::get(), "float"); _embind_register_float(TypeID::get(), "double"); - _embind_register_cstring(TypeID::get(), "std::string"); + _embind_register_std_string(TypeID::get(), "std::string"); + _embind_register_std_wstring(TypeID::get(), sizeof(wchar_t), "std::wstring"); _embind_register_emval(TypeID::get(), "emscripten::val"); } diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 07f093ea351c4..872ee398d70bd 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -389,11 +389,21 @@ module({ }); BaseFixture.extend("string", function() { - var expected = ''; - for (var i = 0; i < 128; ++i) { - expected += String.fromCharCode(128 + i); - } - assert.equal(expected, cm.get_non_ascii_string()); + test("non-ascii strings", function() { + var expected = ''; + for (var i = 0; i < 128; ++i) { + expected += String.fromCharCode(128 + i); + } + assert.equal(expected, cm.get_non_ascii_string()); + }); + + test("non-ascii wstrings", function() { + var expected = String.fromCharCode(10) + + String.fromCharCode(1234) + + String.fromCharCode(2345) + + String.fromCharCode(65535); + assert.equal(expected, cm.get_non_ascii_wstring()); + }); }); BaseFixture.extend("embind", function() { diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 6a3d5dba583c2..f274fbf5558d5 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -88,6 +88,15 @@ std::string get_non_ascii_string() { return c; } +std::wstring get_non_ascii_wstring() { + std::wstring ws(4, 0); + ws[0] = 10; + ws[1] = 1234; + ws[2] = 2345; + ws[3] = 65535; + return ws; +} + std::string emval_test_take_and_return_const_char_star(const char* str) { return str; } @@ -1503,6 +1512,7 @@ EMSCRIPTEN_BINDINGS(tests) { function("emval_test_sum", &emval_test_sum); function("get_non_ascii_string", &get_non_ascii_string); + function("get_non_ascii_wstring", &get_non_ascii_wstring); //function("emval_test_take_and_return_const_char_star", &emval_test_take_and_return_const_char_star); function("emval_test_take_and_return_std_string", &emval_test_take_and_return_std_string); function("emval_test_take_and_return_std_string_const_ref", &emval_test_take_and_return_std_string_const_ref); From 53c228a260b7a5e90e430860e130ed6006bd328a Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 11 Apr 2013 00:07:53 -0700 Subject: [PATCH 444/544] Allow passing JavaScript strings to std::wstring --- src/embind/embind.js | 12 ++++++++++++ tests/embind/embind.test.js | 8 ++++++++ tests/embind/embind_test.cpp | 5 +++++ 3 files changed, 25 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index 576a519e49aee..f66b04958940d 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -366,6 +366,18 @@ function __embind_register_std_wstring(rawType, charSize, name) { _free(value); return a.join(''); }, + toWireType: function(destructors, value) { + // assumes 4-byte alignment + var length = value.length; + var ptr = _malloc(4 + length * charSize); + HEAPU32[ptr >> 2] = length; + var start = (ptr + 4) >> shift; + for (var i = 0; i < length; ++i) { + HEAP[start + i] = value.charCodeAt(i); + } + destructors.push(_free, ptr); + return ptr; + }, }); } diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 872ee398d70bd..6f63d543d3fdb 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -404,6 +404,14 @@ module({ String.fromCharCode(65535); assert.equal(expected, cm.get_non_ascii_wstring()); }); + + test("passing unicode string into C++", function() { + var expected = String.fromCharCode(10) + + String.fromCharCode(1234) + + String.fromCharCode(2345) + + String.fromCharCode(65535); + assert.equal(expected, cm.take_and_return_std_wstring(expected)); + }); }); BaseFixture.extend("embind", function() { diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index f274fbf5558d5..86d850e06e37d 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -109,6 +109,10 @@ std::string emval_test_take_and_return_std_string_const_ref(const std::string& s return str; } +std::wstring take_and_return_std_wstring(std::wstring str) { + return str; +} + std::function emval_test_get_function_ptr() { return emval_test_take_and_return_std_string; } @@ -1516,6 +1520,7 @@ EMSCRIPTEN_BINDINGS(tests) { //function("emval_test_take_and_return_const_char_star", &emval_test_take_and_return_const_char_star); function("emval_test_take_and_return_std_string", &emval_test_take_and_return_std_string); function("emval_test_take_and_return_std_string_const_ref", &emval_test_take_and_return_std_string_const_ref); + function("take_and_return_std_wstring", &take_and_return_std_wstring); //function("emval_test_take_and_return_CustomStruct", &emval_test_take_and_return_CustomStruct); From 6ca9bffb114f206c13d9954be32d6b8034ce5eef Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 11 Apr 2013 00:14:23 -0700 Subject: [PATCH 445/544] assert if, when trying to convert JS string to std::string, the JS string has code units that do not fit in 8 bits --- src/embind/embind.js | 7 ++++++- tests/embind/embind.test.js | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index f66b04958940d..f9b15fa39dcb4 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -336,7 +336,12 @@ function __embind_register_std_string(rawType, name) { var ptr = _malloc(4 + length); HEAPU32[ptr >> 2] = length; for (var i = 0; i < length; ++i) { - HEAPU8[ptr + 4 + i] = value.charCodeAt(i); + var charCode = value.charCodeAt(i); + if (charCode > 255) { + _free(ptr); + throwBindingError('String has UTF-16 code units that do not fit in 8 bits'); + } + HEAPU8[ptr + 4 + i] = charCode; } destructors.push(_free, ptr); return ptr; diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 6f63d543d3fdb..fec7145ae9510 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -397,6 +397,12 @@ module({ assert.equal(expected, cm.get_non_ascii_string()); }); + test("passing non-8-bit strings from JS to std::string throws", function() { + assert.throws(cm.BindingError, function() { + cm.emval_test_take_and_return_std_string("\u1234"); + }); + }); + test("non-ascii wstrings", function() { var expected = String.fromCharCode(10) + String.fromCharCode(1234) + From e9cd9155f8617581a8e96187eef6a5869cf9eb5f Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 11 Apr 2013 00:16:04 -0700 Subject: [PATCH 446/544] jshint --- src/embind/embind.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index f9b15fa39dcb4..81af76db079a0 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1,6 +1,6 @@ /*global Module*/ /*global _malloc, _free, _memcpy*/ -/*global FUNCTION_TABLE, HEAP32, HEAPU8*/ +/*global FUNCTION_TABLE, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32*/ /*global Pointer_stringify*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ /*global ___getTypeName*/ @@ -352,10 +352,10 @@ function __embind_register_std_string(rawType, name) { function __embind_register_std_wstring(rawType, charSize, name) { name = Pointer_stringify(name); var HEAP, shift; - if (charSize == 2) { + if (charSize === 2) { HEAP = HEAPU16; shift = 1; - } else if (charSize == 4) { + } else if (charSize === 4) { HEAP = HEAPU32; shift = 2; } From a9539326b89fec17dfe7fb4315eb5d256a1afcf6 Mon Sep 17 00:00:00 2001 From: jinsuck Date: Fri, 12 Apr 2013 13:00:26 -0700 Subject: [PATCH 447/544] Replace Pointer_stringify() with something simpler and faster. The "String.fromCharCode" can be a performance bottleneck if called a lot, like 50,000 times per second. Depending on application it can be necessary. A better solution is not converting from HEAP at all, but it requires more work. --- src/embind/embind.js | 61 ++++++++++++++++++++++++++++---------------- src/embind/emval.js | 14 +++++----- 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 81af76db079a0..9afbf2fb5a6dd 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1,7 +1,7 @@ /*global Module*/ /*global _malloc, _free, _memcpy*/ /*global FUNCTION_TABLE, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32*/ -/*global Pointer_stringify*/ +/*global readLatin1String*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ /*global ___getTypeName*/ @@ -223,9 +223,26 @@ function whenDependentTypesAreResolved(myTypes, dependentTypes, getTypeConverter } } +var __charCodes = []; + +function readLatin1String(ptr) { + if (__charCodes.length === 0) { + for (var charCodeI = 0; charCodeI < 127; charCodeI++) { + __charCodes.push(String.fromCharCode(charCodeI)); + } + } + + var ret = ""; + var c = ptr; + while (HEAPU8[c]) { + ret += __charCodes[HEAPU8[c++]]; + } + return ret; +} + function getTypeName(type) { var ptr = ___getTypeName(type); - var rv = Pointer_stringify(ptr); + var rv = readLatin1String(ptr); _free(ptr); return rv; } @@ -247,7 +264,7 @@ function requireRegisteredType(rawType, humanName) { } function __embind_register_void(rawType, name) { - name = Pointer_stringify(name); + name = readLatin1String(name); registerType(rawType, { name: name, fromWireType: function() { @@ -257,7 +274,7 @@ function __embind_register_void(rawType, name) { } function __embind_register_bool(rawType, name, trueValue, falseValue) { - name = Pointer_stringify(name); + name = readLatin1String(name); registerType(rawType, { name: name, fromWireType: function(wt) { @@ -274,7 +291,7 @@ function __embind_register_bool(rawType, name, trueValue, falseValue) { // When converting a number from JS to C++ side, the valid range of the number is // [minRange, maxRange], inclusive. function __embind_register_integer(primitiveType, name, minRange, maxRange) { - name = Pointer_stringify(name); + name = readLatin1String(name); if (maxRange === -1) { // LLVM doesn't have signed and unsigned 32-bit types, so u32 literals come out as 'i32 -1'. Always treat those as max u32. maxRange = 4294967295; } @@ -300,7 +317,7 @@ function __embind_register_integer(primitiveType, name, minRange, maxRange) { } function __embind_register_float(rawType, name) { - name = Pointer_stringify(name); + name = readLatin1String(name); registerType(rawType, { name: name, fromWireType: function(value) { @@ -318,7 +335,7 @@ function __embind_register_float(rawType, name) { } function __embind_register_std_string(rawType, name) { - name = Pointer_stringify(name); + name = readLatin1String(name); registerType(rawType, { name: name, fromWireType: function(value) { @@ -350,7 +367,7 @@ function __embind_register_std_string(rawType, name) { } function __embind_register_std_wstring(rawType, charSize, name) { - name = Pointer_stringify(name); + name = readLatin1String(name); var HEAP, shift; if (charSize === 2) { HEAP = HEAPU16; @@ -387,7 +404,7 @@ function __embind_register_std_wstring(rawType, charSize, name) { } function __embind_register_emval(rawType, name) { - name = Pointer_stringify(name); + name = readLatin1String(name); registerType(rawType, { name: name, fromWireType: function(handle) { @@ -432,7 +449,7 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, fn) { var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - name = Pointer_stringify(name); + name = readLatin1String(name); rawInvoker = FUNCTION_TABLE[rawInvoker]; exposePublicSymbol(name, function() { @@ -449,7 +466,7 @@ var tupleRegistrations = {}; function __embind_register_tuple(rawType, name, rawConstructor, rawDestructor) { tupleRegistrations[rawType] = { - name: Pointer_stringify(name), + name: readLatin1String(name), rawConstructor: FUNCTION_TABLE[rawConstructor], rawDestructor: FUNCTION_TABLE[rawDestructor], elements: [], @@ -538,7 +555,7 @@ function __embind_register_struct( rawDestructor ) { structRegistrations[rawType] = { - name: Pointer_stringify(name), + name: readLatin1String(name), rawConstructor: FUNCTION_TABLE[rawConstructor], rawDestructor: FUNCTION_TABLE[rawDestructor], fields: [], @@ -556,7 +573,7 @@ function __embind_register_struct_field( setterContext ) { structRegistrations[structType].fields.push({ - fieldName: Pointer_stringify(fieldName), + fieldName: readLatin1String(fieldName), getterReturnType: getterReturnType, getter: FUNCTION_TABLE[getter], getterContext: getterContext, @@ -913,7 +930,7 @@ function __embind_register_class( name, rawDestructor ) { - name = Pointer_stringify(name); + name = readLatin1String(name); rawDestructor = FUNCTION_TABLE[rawDestructor]; getActualType = FUNCTION_TABLE[getActualType]; upcast = FUNCTION_TABLE[upcast]; @@ -1097,7 +1114,7 @@ function __embind_register_class_function( context ) { var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - methodName = Pointer_stringify(methodName); + methodName = readLatin1String(methodName); rawInvoker = FUNCTION_TABLE[rawInvoker]; whenDependentTypesAreResolved([], [rawClassType], function(classType) { @@ -1163,7 +1180,7 @@ function __embind_register_class_class_function( fn ) { var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - methodName = Pointer_stringify(methodName); + methodName = readLatin1String(methodName); rawInvoker = FUNCTION_TABLE[rawInvoker]; whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; @@ -1209,7 +1226,7 @@ function __embind_register_class_property( setter, setterContext ) { - fieldName = Pointer_stringify(fieldName); + fieldName = readLatin1String(fieldName); getter = FUNCTION_TABLE[getter]; setter = FUNCTION_TABLE[setter]; @@ -1274,7 +1291,7 @@ function __embind_register_smart_ptr( rawShare, rawDestructor ) { - name = Pointer_stringify(name); + name = readLatin1String(name); rawGetPointee = FUNCTION_TABLE[rawGetPointee]; rawConstructor = FUNCTION_TABLE[rawConstructor]; rawShare = FUNCTION_TABLE[rawShare]; @@ -1304,7 +1321,7 @@ function __embind_register_enum( rawType, name ) { - name = Pointer_stringify(name); + name = readLatin1String(name); function constructor() { } @@ -1329,7 +1346,7 @@ function __embind_register_enum_value( enumValue ) { var enumType = requireRegisteredType(rawEnumType, 'enum'); - name = Pointer_stringify(name); + name = readLatin1String(name); var Enum = enumType.constructor; @@ -1347,7 +1364,7 @@ function __embind_register_interface( rawConstructor, rawDestructor ) { - name = Pointer_stringify(name); + name = readLatin1String(name); rawConstructor = FUNCTION_TABLE[rawConstructor]; rawDestructor = FUNCTION_TABLE[rawDestructor]; @@ -1365,7 +1382,7 @@ function __embind_register_interface( } function __embind_register_constant(name, type, value) { - name = Pointer_stringify(name); + name = readLatin1String(name); whenDependentTypesAreResolved([], [type], function(type) { type = type[0]; Module[name] = type.fromWireType(value); diff --git a/src/embind/emval.js b/src/embind/emval.js index 037ce47d6f032..c4f06503fe358 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -1,6 +1,6 @@ /*global Module*/ /*global HEAP32*/ -/*global Pointer_stringify, writeStringToMemory*/ +/*global readLatin1String, writeStringToMemory*/ /*global requireRegisteredType*/ var _emval_handle_array = []; @@ -74,7 +74,7 @@ function __emval_null() { } function __emval_new_cstring(v) { - return __emval_register(Pointer_stringify(v)); + return __emval_register(readLatin1String(v)); } function __emval_take_value(type, v) { @@ -127,12 +127,12 @@ function __emval_new(handle, argCount, argTypes) { var global = (function(){return Function;})()('return this')(); function __emval_get_global(name) { - name = Pointer_stringify(name); + name = readLatin1String(name); return __emval_register(global[name]); } function __emval_get_module_property(name) { - name = Pointer_stringify(name); + name = readLatin1String(name); return __emval_register(Module[name]); } @@ -173,7 +173,7 @@ function __emval_call(handle, argCount, argTypes) { } function __emval_call_method(handle, name, argCount, argTypes) { - name = Pointer_stringify(name); + name = readLatin1String(name); var args = parseParameters( argCount, @@ -185,7 +185,7 @@ function __emval_call_method(handle, name, argCount, argTypes) { } function __emval_call_void_method(handle, name, argCount, argTypes) { - name = Pointer_stringify(name); + name = readLatin1String(name); var args = parseParameters( argCount, @@ -196,6 +196,6 @@ function __emval_call_void_method(handle, name, argCount, argTypes) { } function __emval_has_function(handle, name) { - name = Pointer_stringify(name); + name = readLatin1String(name); return _emval_handle_array[handle].value[name] instanceof Function; } From 181e6abb2f3abb9c3dc07d769adb84f6bc5982bc Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 15 Apr 2013 17:40:16 -0700 Subject: [PATCH 448/544] cannot pass non-strings to std::string arguments :) --- src/embind/embind.js | 4 ++++ tests/embind/embind.test.js | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index 9afbf2fb5a6dd..5fc8c9485264b 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -348,6 +348,10 @@ function __embind_register_std_string(rawType, name) { return a.join(''); }, toWireType: function(destructors, value) { + if (typeof value !== "string") { + throwBindingError('Cannot pass non-string to std::string'); + } + // assumes 4-byte alignment var length = value.length; var ptr = _malloc(4 + length); diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index fec7145ae9510..6473573a03a5e 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -403,6 +403,12 @@ module({ }); }); + test("can't pass integers as strings", function() { + var e = assert.throws(cm.BindingError, function() { + cm.emval_test_take_and_return_std_string(10); + }); + }); + test("non-ascii wstrings", function() { var expected = String.fromCharCode(10) + String.fromCharCode(1234) + From e53dd06bf9ca763a65f8bc77dd3ae980843e8652 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 15 Apr 2013 21:15:13 -0700 Subject: [PATCH 449/544] allow passing Int8Array and Uint8Array directly to std::string --- src/embind/embind.js | 17 +++++++++++++++-- tests/embind/embind.test.js | 10 ++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 5fc8c9485264b..078b5c1c7a677 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -348,7 +348,20 @@ function __embind_register_std_string(rawType, name) { return a.join(''); }, toWireType: function(destructors, value) { - if (typeof value !== "string") { + function getTAElement(ta, index) { + return ta[index]; + } + function getStringElement(string, index) { + return string.charCodeAt(index); + } + var getElement; + if (value instanceof Uint8Array) { + getElement = getTAElement; + } else if (value instanceof Int8Array) { + getElement = getTAElement; + } else if (typeof value === 'string') { + getElement = getStringElement; + } else { throwBindingError('Cannot pass non-string to std::string'); } @@ -357,7 +370,7 @@ function __embind_register_std_string(rawType, name) { var ptr = _malloc(4 + length); HEAPU32[ptr >> 2] = length; for (var i = 0; i < length; ++i) { - var charCode = value.charCodeAt(i); + var charCode = getElement(value, i); if (charCode > 255) { _free(ptr); throwBindingError('String has UTF-16 code units that do not fit in 8 bits'); diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 6473573a03a5e..821355d2c41cb 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -409,6 +409,16 @@ module({ }); }); + test("can pass Uint8Array to std::string", function() { + var e = cm.emval_test_take_and_return_std_string(new Uint8Array([65, 66, 67, 68])); + assert.equal('ABCD', e); + }); + + test("can pass Int8Array to std::string", function() { + var e = cm.emval_test_take_and_return_std_string(new Int8Array([65, 66, 67, 68])); + assert.equal('ABCD', e); + }); + test("non-ascii wstrings", function() { var expected = String.fromCharCode(10) + String.fromCharCode(1234) + From d2e6efdf4821ff1e9f16fc4884d398619c0d7a06 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 15 Apr 2013 21:29:01 -0700 Subject: [PATCH 450/544] can pass ArrayBuffer to std::string --- src/embind/embind.js | 4 ++++ tests/embind/embind.test.js | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index 078b5c1c7a677..bd13087d10c53 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -348,6 +348,10 @@ function __embind_register_std_string(rawType, name) { return a.join(''); }, toWireType: function(destructors, value) { + if (value instanceof ArrayBuffer) { + value = new Uint8Array(value); + } + function getTAElement(ta, index) { return ta[index]; } diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 821355d2c41cb..82029de4a16ac 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -419,6 +419,11 @@ module({ assert.equal('ABCD', e); }); + test("can pass ArrayBuffer to std::string", function() { + var e = cm.emval_test_take_and_return_std_string((new Int8Array([65, 66, 67, 68])).buffer); + assert.equal('ABCD', e); + }); + test("non-ascii wstrings", function() { var expected = String.fromCharCode(10) + String.fromCharCode(1234) + From 426cbf616c7a4465e707d6f5cd0d11ab9ce27905 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Mon, 15 Apr 2013 22:26:21 -0700 Subject: [PATCH 451/544] Support returning movable types --- system/include/emscripten/wire.h | 14 +++++++++++--- tests/embind/embind_test.cpp | 11 +++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index 0e8334e86c1c4..6fb15fc73762f 100755 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -205,6 +205,10 @@ namespace emscripten { struct BindingType : public BindingType { }; + template + struct BindingType : public BindingType { + }; + template struct BindingType : public BindingType { }; @@ -236,10 +240,14 @@ namespace emscripten { typedef typename std::remove_reference::type ActualT; typedef ActualT* WireType; - static WireType toWireType(T v) { + static WireType toWireType(const T& v) { return new T(v); } + static WireType toWireType(T&& v) { + return new T(std::forward(v)); + } + static ActualT& fromWireType(WireType p) { return *p; } @@ -282,8 +290,8 @@ namespace emscripten { {}; template - auto toWireType(const T& v) -> typename BindingType::WireType { - return BindingType::toWireType(v); + auto toWireType(T&& v) -> typename BindingType::WireType { + return BindingType::toWireType(std::forward(v)); } template diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 86d850e06e37d..ce13311274125 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -2088,15 +2088,26 @@ class Noncopyable { public: Noncopyable() {} + Noncopyable(Noncopyable&& other) { + other.valid = false; + } std::string method() const { return "foo"; } + + bool valid = true; }; +Noncopyable getNoncopyable() { + return Noncopyable(); +} + EMSCRIPTEN_BINDINGS(noncopyable) { class_("Noncopyable") .constructor<>() .function("method", &Noncopyable::method) ; + + function("getNoncopyable", &getNoncopyable); } From c2bc8d4f1ed4fe5e7477e4dc5d3f32ca5f1e6a56 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 16 Apr 2013 01:17:56 -0700 Subject: [PATCH 452/544] implement perfect forwarding in embind --- system/include/emscripten/bind.h | 16 ++++++++-------- system/include/emscripten/val.h | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 9b6e69c98b21e..b17488b93bd8d 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -723,14 +723,14 @@ namespace emscripten { {} template - ReturnType call(const char* name, Args... args) const { - return Caller::call(wrapped, name, args...); + ReturnType call(const char* name, Args&&... args) const { + return Caller::call(wrapped, name, std::forward(args)...); } template - ReturnType optional_call(const char* name, Default def, Args... args) const { + ReturnType optional_call(const char* name, Default def, Args&&... args) const { if (has_function(name)) { - return Caller::call(wrapped, name, args...); + return Caller::call(wrapped, name, std::forward(args)...); } else { return def(); } @@ -744,15 +744,15 @@ namespace emscripten { // this class only exists because you can't partially specialize function templates template struct Caller { - static ReturnType call(const val& v, const char* name, Args... args) { - return v.call(name, args...).template as(); + static ReturnType call(const val& v, const char* name, Args&&... args) { + return v.call(name, std::forward(args)...).template as(); } }; template struct Caller { - static void call(const val& v, const char* name, Args... args) { - v.call_void(name, args...); + static void call(const val& v, const char* name, Args&&... args) { + v.call_void(name, std::forward(args)...); } }; diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index c27a0fdb65e09..d32c9650aedfb 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -135,7 +135,7 @@ namespace emscripten { } template - val new_(Args... args) const { + val new_(Args&&... args) const { using namespace internal; WithPolicies<>::ArgTypeList argList; @@ -152,7 +152,7 @@ namespace emscripten { handle, argList.count, argList.types, - toWireType(args)...)); + toWireType(std::forward(args))...)); } template @@ -166,7 +166,7 @@ namespace emscripten { } template - val operator()(Args... args) { + val operator()(Args&&... args) { using namespace internal; WithPolicies<>::ArgTypeList argList; @@ -181,11 +181,11 @@ namespace emscripten { handle, argList.count, argList.types, - toWireType(args)...)); + toWireType(std::forward(args))...)); } template - val call(const char* name, Args... args) const { + val call(const char* name, Args&&... args) const { using namespace internal; WithPolicies<>::ArgTypeList argList; @@ -202,11 +202,11 @@ namespace emscripten { name, argList.count, argList.types, - toWireType(args)...)); + toWireType(std::forward(args))...)); } template - void call_void(const char* name, Args... args) const { + void call_void(const char* name, Args&&... args) const { using namespace internal; WithPolicies<>::ArgTypeList argList; @@ -222,7 +222,7 @@ namespace emscripten { name, argList.count, argList.types, - toWireType(args)...); + toWireType(std::forward(args))...); } bool has_function(const char* name) const { From d990cb17d8c43913a733c28601f4319fce90c27a Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 16 Apr 2013 02:13:41 -0700 Subject: [PATCH 453/544] Finally! JSInterface is dead --- src/embind/embind.js | 23 ---------- system/include/emscripten/bind.h | 74 -------------------------------- system/lib/embind/bind.cpp | 8 ---- tests/embind/embind.test.js | 18 -------- tests/embind/embind_test.cpp | 22 ---------- 5 files changed, 145 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index bd13087d10c53..440fa267c6e1f 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1379,29 +1379,6 @@ function __embind_register_enum_value( Enum[name] = Value; } -function __embind_register_interface( - rawType, - name, - rawConstructor, - rawDestructor -) { - name = readLatin1String(name); - rawConstructor = FUNCTION_TABLE[rawConstructor]; - rawDestructor = FUNCTION_TABLE[rawDestructor]; - - registerType(rawType, { - name: name, - rawConstructor: rawConstructor, - rawDestructor: rawDestructor, - toWireType: function(destructors, o) { - var handle = __emval_register(o); - var ptr = this.rawConstructor(handle); - destructors.push(this.rawDestructor, ptr); - return ptr; - }, - }); -} - function __embind_register_constant(name, type, value) { name = readLatin1String(name); whenDependentTypesAreResolved([], [type], function(type) { diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index b17488b93bd8d..894586a60f01f 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -1249,80 +1249,6 @@ namespace emscripten { typename std::aligned_storage::type data; }; } - - //////////////////////////////////////////////////////////////////////////////// - // NEW INTERFACE - //////////////////////////////////////////////////////////////////////////////// - - class JSInterface { - public: - JSInterface(internal::EM_VAL handle) { - initialize(handle); - } - - JSInterface(const JSInterface& obj) - : jsobj(obj.jsobj) - {} - - template - ReturnType call(const char* name, Args... args) { - assertInitialized(); - return Caller::call(*jsobj, name, args...); - } - - static std::shared_ptr cloneToSharedPtr(const JSInterface& i) { - return std::make_shared(i); - } - - private: - void initialize(internal::EM_VAL handle) { - if (jsobj) { - internal::_embind_fatal_error( - "Cannot initialize interface wrapper twice", - "JSInterface"); - } - jsobj = val::take_ownership(handle); - } - - // this class only exists because you can't partially specialize function templates - template - struct Caller { - static ReturnType call(val& v, const char* name, Args... args) { - return v.call(name, args...).template as(); - } - }; - - template - struct Caller { - static void call(val& v, const char* name, Args... args) { - v.call_void(name, args...); - } - }; - - void assertInitialized() { - if (!jsobj) { - internal::_embind_fatal_error( - "Cannot invoke call on uninitialized Javascript interface wrapper.", "JSInterface"); - } - } - - internal::optional jsobj; - }; - - namespace internal { - extern JSInterface* create_js_interface(EM_VAL e); - } - - class register_js_interface { - public: - register_js_interface() { - _embind_register_interface( - internal::TypeID::get(), - "JSInterface", - reinterpret_cast(&internal::create_js_interface), - reinterpret_cast(&internal::raw_destructor)); - } - }; } namespace emscripten { diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 6cacf1e2e928e..35d99dad1807e 100755 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -36,14 +36,6 @@ extern "C" { } } -namespace emscripten { - namespace internal { - JSInterface* create_js_interface(EM_VAL e) { - return new JSInterface(e); - } - } -} - // TODO: fix in library.js or a proper emscripten libc extern "C" wchar_t *wmemset(wchar_t *dest, wchar_t c, size_t count) { wchar_t *o = dest; diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 82029de4a16ac..5af15be935f90 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -1478,24 +1478,6 @@ module({ }); }); - BaseFixture.extend("JavaScript interface", function() { - this.setUp(function() { - this.testobj = { - "method1": function() { return 111; }, - "method2": function() { return 222; } - }; - }); - - test("pass js object to c++ and call its method", function() { - var obj = new cm.JSInterfaceHolder(this.testobj); - assert.equal(111, obj.callMethod("method1")); - assert.equal(222, obj.callMethod("method2")); - assert.equal(111, obj.callMethodUsingSharedPtr("method1")); - assert.equal(222, obj.callMethodUsingSharedPtr("method2")); - obj.delete(); - }); - }); - BaseFixture.extend("abstract methods", function() { test("can call abstract methods", function() { var obj = cm.getAbstractClass(); diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index ce13311274125..5733c08f71110 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1065,20 +1065,6 @@ std::vector> emval_test_return_shared_ptr_vector() return sharedStrVector; } -class JSInterfaceHolder { -public: - JSInterfaceHolder(JSInterface &jsobj) : jsobj_(jsobj) { - ptr_ = JSInterface::cloneToSharedPtr(jsobj_); - } - - int callMethod(std::string method) { return jsobj_.call(method.c_str()); } - int callMethodUsingSharedPtr(std::string method) { return ptr_->call(method.c_str()); } - -private: - JSInterface jsobj_; - std::shared_ptr ptr_; -}; - void test_string_with_vec(const std::string& p1, std::vector& v1) { // THIS DOES NOT WORK -- need to get as val and then call vecFromJSArray printf("%s\n", p1.c_str()); @@ -1488,8 +1474,6 @@ EMSCRIPTEN_BINDINGS(constants) { } EMSCRIPTEN_BINDINGS(tests) { - register_js_interface(); - register_vector("IntegerVector"); register_vector("CharVector"); register_vector("VectorUnsigned"); @@ -1883,12 +1867,6 @@ EMSCRIPTEN_BINDINGS(tests) { register_map("StringIntMap"); function("embind_test_get_string_int_map", embind_test_get_string_int_map); - class_("JSInterfaceHolder") - .constructor() - .function("callMethod", &JSInterfaceHolder::callMethod) - .function("callMethodUsingSharedPtr", &JSInterfaceHolder::callMethodUsingSharedPtr) - ; - function("embind_test_new_Object", &embind_test_new_Object); function("embind_test_new_factory", &embind_test_new_factory); From 775f840e378eba5a9a8053857113a40efb980fb7 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 16 Apr 2013 14:25:01 -0700 Subject: [PATCH 454/544] Add perfect forwarding throughout emscripten::val. This shaves 50 KB off the non-minified JS in Northstar. --- src/embind/emval.js | 28 ++++++++++++++++++++++------ system/include/emscripten/bind.h | 10 +++++----- system/include/emscripten/val.h | 21 +++++++++++++++++---- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index c4f06503fe358..68b613f3e0e61 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -1,9 +1,9 @@ /*global Module*/ /*global HEAP32*/ /*global readLatin1String, writeStringToMemory*/ -/*global requireRegisteredType*/ +/*global requireRegisteredType, throwBindingError*/ -var _emval_handle_array = []; +var _emval_handle_array = [{}]; // reserve zero var _emval_free_list = []; // Public JS API @@ -11,7 +11,7 @@ var _emval_free_list = []; /** @expose */ Module.count_emval_handles = function() { var count = 0; - for (var i = 0; i < _emval_handle_array.length; ++i) { + for (var i = 1; i < _emval_handle_array.length; ++i) { if (_emval_handle_array[i] !== undefined) { ++count; } @@ -21,7 +21,7 @@ Module.count_emval_handles = function() { /** @expose */ Module.get_first_emval = function() { - for (var i = 0; i < _emval_handle_array.length; ++i) { + for (var i = 1; i < _emval_handle_array.length; ++i) { if (_emval_handle_array[i] !== undefined) { return _emval_handle_array[i]; } @@ -31,6 +31,12 @@ Module.get_first_emval = function() { // Private C++ API +function requireHandle(handle) { + if (!handle) { + throwBindingError('Cannot use deleted val. handle = ' + handle); + } +} + function __emval_register(value) { var handle = _emval_free_list.length ? _emval_free_list.pop() : @@ -41,11 +47,13 @@ function __emval_register(value) { } function __emval_incref(handle) { - _emval_handle_array[handle].refcount += 1; + if (handle) { + _emval_handle_array[handle].refcount += 1; + } } function __emval_decref(handle) { - if (0 === --_emval_handle_array[handle].refcount) { + if (handle && 0 === --_emval_handle_array[handle].refcount) { delete _emval_handle_array[handle]; _emval_free_list.push(handle); @@ -86,6 +94,8 @@ function __emval_take_value(type, v) { var __newers = {}; // arity -> function function __emval_new(handle, argCount, argTypes) { + requireHandle(handle); + var args = parseParameters( argCount, argTypes, @@ -137,14 +147,17 @@ function __emval_get_module_property(name) { } function __emval_get_property(handle, key) { + requireHandle(handle); return __emval_register(_emval_handle_array[handle].value[_emval_handle_array[key].value]); } function __emval_set_property(handle, key, value) { + requireHandle(handle); _emval_handle_array[handle].value[_emval_handle_array[key].value] = _emval_handle_array[value].value; } function __emval_as(handle, returnType) { + requireHandle(handle); returnType = requireRegisteredType(returnType, 'emval::as'); var destructors = []; // caller owns destructing @@ -163,6 +176,7 @@ function parseParameters(argCount, argTypes, argWireTypes) { } function __emval_call(handle, argCount, argTypes) { + requireHandle(handle); var fn = _emval_handle_array[handle].value; var args = parseParameters( argCount, @@ -173,6 +187,7 @@ function __emval_call(handle, argCount, argTypes) { } function __emval_call_method(handle, name, argCount, argTypes) { + requireHandle(handle); name = readLatin1String(name); var args = parseParameters( @@ -185,6 +200,7 @@ function __emval_call_method(handle, name, argCount, argTypes) { } function __emval_call_void_method(handle, name, argCount, argTypes) { + requireHandle(handle); name = readLatin1String(name); var args = parseParameters( diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 894586a60f01f..a388603191ae9 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -284,8 +284,8 @@ namespace emscripten { } template - WrapperType wrapped_new(Args... args) { - return WrapperType(new ClassType(args...)); + WrapperType wrapped_new(Args&&... args) { + return WrapperType(new ClassType(std::forward(args)...)); } template @@ -718,8 +718,8 @@ namespace emscripten { template class wrapper : public T { public: - explicit wrapper(const val& wrapped) - : wrapped(wrapped) + explicit wrapper(val&& wrapped) + : wrapped(std::forward(wrapped)) {} template @@ -760,7 +760,7 @@ namespace emscripten { }; #define EMSCRIPTEN_WRAPPER(T) \ - T(const ::emscripten::val& v): wrapper(v) {} + T(::emscripten::val&& v): wrapper(std::forward<::emscripten::val>(v)) {} namespace internal { struct NoBaseClass { diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index d32c9650aedfb..1fccd4345175b 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -101,18 +101,24 @@ namespace emscripten { } template - explicit val(const T& value) { + explicit val(T&& value) { typedef internal::BindingType BT; auto taker = reinterpret_cast(&internal::_emval_take_value); - handle = taker(internal::TypeID::get(), BT::toWireType(value)); + handle = taker(internal::TypeID::get(), BT::toWireType(std::forward(value))); } val() = delete; - val(const char* v) + explicit val(const char* v) : handle(internal::_emval_new_cstring(v)) {} + val(val&& v) + : handle(v.handle) + { + v.handle = 0; + } + val(const val& v) : handle(v.handle) { @@ -123,6 +129,13 @@ namespace emscripten { internal::_emval_decref(handle); } + val& operator=(val&& v) { + internal::_emval_decref(handle); + handle = v.handle; + v.handle = 0; + return *this; + } + val& operator=(const val& v) { internal::_emval_incref(v.handle); internal::_emval_decref(handle); @@ -260,7 +273,7 @@ namespace emscripten { template<> struct BindingType { typedef internal::EM_VAL WireType; - static WireType toWireType(val v) { + static WireType toWireType(const val& v) { _emval_incref(v.handle); return v.handle; } From e5c04828c4c2eaec83cf25b83067064db2270c2e Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 16 Apr 2013 17:53:38 -0700 Subject: [PATCH 455/544] fix readLatin1String to actually cover the range of latin-1 characters and add support for interned string symbols to emscripten::val --- src/embind/embind.js | 28 ++++++++++++++-------------- src/embind/emval.js | 27 +++++++++++++++++++++------ system/include/emscripten/val.h | 21 +++++++++++++++++++++ tests/embind/embind_test.cpp | 4 +++- 4 files changed, 59 insertions(+), 21 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 440fa267c6e1f..753d40a49a9f2 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -223,21 +223,21 @@ function whenDependentTypesAreResolved(myTypes, dependentTypes, getTypeConverter } } -var __charCodes = []; +var __charCodes = (function() { + var codes = new Array(256); + for (var i = 0; i < 256; ++i) { + codes[i] = String.fromCharCode(i); + } + return codes; +})(); function readLatin1String(ptr) { - if (__charCodes.length === 0) { - for (var charCodeI = 0; charCodeI < 127; charCodeI++) { - __charCodes.push(String.fromCharCode(charCodeI)); + var ret = ""; + var c = ptr; + while (HEAPU8[c]) { + ret += __charCodes[HEAPU8[c++]]; } - } - - var ret = ""; - var c = ptr; - while (HEAPU8[c]) { - ret += __charCodes[HEAPU8[c++]]; - } - return ret; + return ret; } function getTypeName(type) { @@ -1143,8 +1143,8 @@ function __embind_register_class_function( var humanName = classType.name + '.' + methodName; var unboundTypesHandler = function() { - throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); - }; + throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); + }; var proto = classType.registeredClass.instancePrototype; var method = proto[methodName]; diff --git a/src/embind/emval.js b/src/embind/emval.js index 68b613f3e0e61..c02ffa927f38a 100755 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -31,6 +31,21 @@ Module.get_first_emval = function() { // Private C++ API +var _emval_symbols = {}; // address -> string + +function __emval_register_symbol(address) { + _emval_symbols[address] = readLatin1String(address); +} + +function getStringOrSymbol(address) { + var symbol = _emval_symbols[address]; + if (symbol === undefined) { + return readLatin1String(address); + } else { + return symbol; + } +} + function requireHandle(handle) { if (!handle) { throwBindingError('Cannot use deleted val. handle = ' + handle); @@ -82,7 +97,7 @@ function __emval_null() { } function __emval_new_cstring(v) { - return __emval_register(readLatin1String(v)); + return __emval_register(getStringOrSymbol(v)); } function __emval_take_value(type, v) { @@ -137,12 +152,12 @@ function __emval_new(handle, argCount, argTypes) { var global = (function(){return Function;})()('return this')(); function __emval_get_global(name) { - name = readLatin1String(name); + name = getStringOrSymbol(name); return __emval_register(global[name]); } function __emval_get_module_property(name) { - name = readLatin1String(name); + name = getStringOrSymbol(name); return __emval_register(Module[name]); } @@ -188,7 +203,7 @@ function __emval_call(handle, argCount, argTypes) { function __emval_call_method(handle, name, argCount, argTypes) { requireHandle(handle); - name = readLatin1String(name); + name = getStringOrSymbol(name); var args = parseParameters( argCount, @@ -201,7 +216,7 @@ function __emval_call_method(handle, name, argCount, argTypes) { function __emval_call_void_method(handle, name, argCount, argTypes) { requireHandle(handle); - name = readLatin1String(name); + name = getStringOrSymbol(name); var args = parseParameters( argCount, @@ -212,6 +227,6 @@ function __emval_call_void_method(handle, name, argCount, argTypes) { } function __emval_has_function(handle, name) { - name = readLatin1String(name); + name = getStringOrSymbol(name); return _emval_handle_array[handle].value[name] instanceof Function; } diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 1fccd4345175b..42d8d375361ce 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -8,6 +8,8 @@ namespace emscripten { namespace internal { // Implemented in JavaScript. Don't call these directly. extern "C" { + void _emval_register_symbol(const char*); + typedef struct _EM_VAL* EM_VAL; void _emval_incref(EM_VAL value); @@ -54,6 +56,25 @@ namespace emscripten { } } + class symbol { + public: + symbol() = delete; + + // I so wish I could require the argument to be a string literal + symbol(const char* address) + : address(address) + { + internal::_emval_register_symbol(address); + } + + operator const char*() const { + return address; + } + + private: + const char* address; + }; + class val { public: // missing operators: diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 5733c08f71110..9bab2872d1143 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1087,6 +1087,8 @@ class AbstractClass { } }; +symbol optionalMethodSymbol = "optionalMethod"; + class AbstractClassWrapper : public wrapper { public: EMSCRIPTEN_WRAPPER(AbstractClassWrapper); @@ -1095,7 +1097,7 @@ class AbstractClassWrapper : public wrapper { return call("abstractMethod"); } std::string optionalMethod(std::string s) const { - return optional_call("optionalMethod", [&] { + return optional_call(optionalMethodSymbol, [&] { return AbstractClass::optionalMethod(s); }, s); } From a76d9ceaee0a83c0af562753ad5efd01858c1c8b Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 16 Apr 2013 18:46:47 -0700 Subject: [PATCH 456/544] switch to EMSCRIPTEN_SYMBOL which improves code size a bit by storing the pointer to the string literal as a constant as opposed to a global variable. --- system/include/emscripten/val.h | 22 +++++++--------------- tests/embind/embind_test.cpp | 4 ++-- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 42d8d375361ce..09cad80e1daeb 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -56,25 +56,17 @@ namespace emscripten { } } - class symbol { - public: - symbol() = delete; - - // I so wish I could require the argument to be a string literal - symbol(const char* address) - : address(address) - { + template + struct symbol_registrar { + symbol_registrar() { internal::_emval_register_symbol(address); } - - operator const char*() const { - return address; - } - - private: - const char* address; }; +#define EMSCRIPTEN_SYMBOL(name) \ + static const char name##_symbol[] = #name; \ + static const symbol_registrar name##_registrar + class val { public: // missing operators: diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 9bab2872d1143..04771dbe2d1ad 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1087,7 +1087,7 @@ class AbstractClass { } }; -symbol optionalMethodSymbol = "optionalMethod"; +EMSCRIPTEN_SYMBOL(optionalMethod); class AbstractClassWrapper : public wrapper { public: @@ -1097,7 +1097,7 @@ class AbstractClassWrapper : public wrapper { return call("abstractMethod"); } std::string optionalMethod(std::string s) const { - return optional_call(optionalMethodSymbol, [&] { + return optional_call(optionalMethod_symbol, [&] { return AbstractClass::optionalMethod(s); }, s); } From 75881fce897a3c5849c139866fe46d39d6b05bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 11 Apr 2013 14:07:23 +0300 Subject: [PATCH 457/544] Added benchmark for embind code. --- tests/embind/embind.benchmark.js | 153 ++++++++++++++++++++++++ tests/embind/embind_benchmark.cpp | 186 ++++++++++++++++++++++++++++++ tests/embind/shell.html | 94 +++++++++++++++ 3 files changed, 433 insertions(+) create mode 100644 tests/embind/embind.benchmark.js create mode 100644 tests/embind/embind_benchmark.cpp create mode 100644 tests/embind/shell.html diff --git a/tests/embind/embind.benchmark.js b/tests/embind/embind.benchmark.js new file mode 100644 index 0000000000000..7b08be5d9298a --- /dev/null +++ b/tests/embind/embind.benchmark.js @@ -0,0 +1,153 @@ +function _increment_counter_benchmark_js(N) { + var ctr = _get_counter(); + var a = _emscripten_get_now(); + for(i = 0; i < N; ++i) { + _increment_counter(); + _increment_counter(); + _increment_counter(); + _increment_counter(); + _increment_counter(); + _increment_counter(); + _increment_counter(); + _increment_counter(); + _increment_counter(); + _increment_counter(); + } + var b = _emscripten_get_now(); + var ctr2 = _get_counter(); + Module.print("JS increment_counter " + N + " iters: " + (b-a)*1000 + " msecs. result: " + (ctr2-ctr)); +} + +function _returns_input_benchmark_js() { + var a = _emscripten_get_now(); + var t = 0; + for(i = 0; i < 100000; ++i) { + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + t += _returns_input(i); + } + var b = _emscripten_get_now(); + Module.print("JS returns_input 100000 iters: " + (b-a)*1000 + " msecs. result: " + t); +} + +function _sum_int_benchmark_js() { + var a = _emscripten_get_now(); + var r = 0; + for(i = 0; i < 100000; ++i) { + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); + } + var b = _emscripten_get_now(); + Module.print("JS sum_int 100000 iters: " + (b-a)*1000 + " msecs. result: " + r); +} + +function _sum_float_benchmark_js() { + var a = _emscripten_get_now(); + var r = 0; + for(i = 0; i < 100000; ++i) { + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); + } + var b = _emscripten_get_now(); + Module.print("JS sum_float 100000 iters: " + (b-a)*1000 + " msecs. result: " + r); +} + +function _increment_counter_benchmark_embind_js(N) { + var ctr = _get_counter(); + var a = _emscripten_get_now(); + for(i = 0; i < N; ++i) { + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + Module['increment_counter'](); + } + var b = _emscripten_get_now(); + var ctr2 = _get_counter(); + Module.print("JS embind increment_counter " + N + " iters: " + (b-a)*1000 + " msecs. result: " + (ctr2-ctr)); +} + +function _returns_input_benchmark_embind_js() { + var a = _emscripten_get_now(); + var t = 0; + for(i = 0; i < 100000; ++i) { + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + t += Module['returns_input'](i); + } + var b = _emscripten_get_now(); + Module.print("JS embind returns_input 100000 iters: " + (b-a)*1000 + " msecs. result: " + t); +} + +function _sum_int_benchmark_embind_js() { + var a = _emscripten_get_now(); + var r = 0; + for(i = 0; i < 100000; ++i) { + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); + } + var b = _emscripten_get_now(); + Module.print("JS embind sum_int 100000 iters: " + (b-a)*1000 + " msecs. result: " + r); +} + +function _sum_float_benchmark_embind_js() { + var a = _emscripten_get_now(); + var r = 0; + for(i = 0; i < 100000; ++i) { + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); + } + var b = _emscripten_get_now(); + Module.print("JS embind sum_float 100000 iters: " + (b-a)*1000 + " msecs. result: " + r); +} diff --git a/tests/embind/embind_benchmark.cpp b/tests/embind/embind_benchmark.cpp new file mode 100644 index 0000000000000..c9391a2975a1c --- /dev/null +++ b/tests/embind/embind_benchmark.cpp @@ -0,0 +1,186 @@ +#include +#include +#include + +int counter = 0; + +extern "C" +{ + +int __attribute__((noinline)) get_counter() +{ + return counter; +} + +void __attribute__((noinline)) increment_counter() +{ + ++counter; +} + +int __attribute__((noinline)) sum_int(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int v9) +{ + return v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9; +} + +float __attribute__((noinline)) sum_float(float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8, float v9) +{ + return v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9; +} + +int __attribute__((noinline)) returns_input(int i) +{ + return i; +} + +extern void increment_counter_benchmark_js(int N); +extern void returns_input_benchmark_js(); +extern void sum_int_benchmark_js(); +extern void sum_float_benchmark_js(); + +extern void increment_counter_benchmark_embind_js(int N); +extern void returns_input_benchmark_embind_js(); +extern void sum_int_benchmark_embind_js(); +extern void sum_float_benchmark_embind_js(); + +} + +EMSCRIPTEN_BINDINGS(benchmark) +{ + using namespace emscripten; + + function("get_counter", &get_counter); + function("increment_counter", &increment_counter); + function("returns_input", &returns_input); + function("sum_int", &sum_int); + function("sum_float", &sum_float); +} + +void __attribute__((noinline)) emscripten_get_now_benchmark(int N) +{ + volatile float t = emscripten_get_now(); + for(int i = 0; i < N; ++i) + { + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + emscripten_get_now(); + } + volatile float t2 = emscripten_get_now(); + printf("C++ emscripten_get_now %d iters: %f msecs.\n", N, 1000.f*(t2-t)); +} + +void __attribute__((noinline)) increment_counter_benchmark(int N) +{ + volatile float t = emscripten_get_now(); + for(int i = 0; i < N; ++i) + { + increment_counter(); + increment_counter(); + increment_counter(); + increment_counter(); + increment_counter(); + increment_counter(); + increment_counter(); + increment_counter(); + increment_counter(); + increment_counter(); + } + volatile float t2 = emscripten_get_now(); + printf("C++ increment_counter %d iters: %f msecs.\n", N, 1000.f*(t2-t)); +} + +void __attribute__((noinline)) returns_input_benchmark() +{ + volatile int r = 0; + volatile float t = emscripten_get_now(); + for(int i = 0; i < 100000; ++i) + { + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + r += returns_input(i); + } + volatile float t2 = emscripten_get_now(); + printf("C++ returns_input 100000 iters: %f msecs.\n", 1000.f*(t2-t)); +} + +void __attribute__((noinline)) sum_int_benchmark() +{ + volatile float t = emscripten_get_now(); + volatile int r = 0; + for(int i = 0; i < 100000; ++i) + { + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + r += sum_int(i,2,3,4,5,6,7,8,9); + } + volatile float t2 = emscripten_get_now(); + printf("C++ sum_int 100000 iters: %f msecs.\n", 1000.f*(t2-t)); +} + +void __attribute__((noinline)) sum_float_benchmark() +{ + volatile float f = 0.f; + volatile float t = emscripten_get_now(); + for(int i = 0; i < 100000; ++i) + { + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); + } + volatile float t2 = emscripten_get_now(); + printf("C++ sum_float 100000 iters: %f msecs.\n", 1000.f*(t2-t)); +} + +int main() +{ + for(int i = 1000; i <= 100000; i *= 10) + emscripten_get_now_benchmark(i); + + printf("\n"); + for(int i = 1000; i <= 100000; i *= 10) + { + increment_counter_benchmark(i); + increment_counter_benchmark_js(i); + increment_counter_benchmark_embind_js(i); + printf("\n"); + } + + returns_input_benchmark(); + returns_input_benchmark_js(); + returns_input_benchmark_embind_js(); + printf("\n"); + sum_int_benchmark(); + sum_int_benchmark_js(); + sum_int_benchmark_embind_js(); + printf("\n"); + sum_float_benchmark(); + sum_float_benchmark_js(); + sum_float_benchmark_embind_js(); +} diff --git a/tests/embind/shell.html b/tests/embind/shell.html new file mode 100644 index 0000000000000..6664ec78415d6 --- /dev/null +++ b/tests/embind/shell.html @@ -0,0 +1,94 @@ + + + + + + Emscripten-Generated Code + + + +
    Downloading...
    +
    + +
    + + + +
    + +
    + + + + From 9a310fb5b6043e93bc37ebb894b8487fc9fd7ef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 11 Apr 2013 14:08:46 +0300 Subject: [PATCH 458/544] Optimize embind makeInvoker to not call function.apply or do for() loops. Instead, manually craft invoker functions for each function. --- src/embind/embind.js | 71 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 753d40a49a9f2..00d56bc8c8cd6 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -447,25 +447,66 @@ function runDestructors(destructors) { } } +// Function implementation of operator new, per +// http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf +// 13.2.2 +// ES3 +function new_(constructor, argumentList) { + if (!(constructor instanceof Function)) { + throw new TypeError('new_ called with constructor type ' + typeof(constructor) + " which is not a function"); + } + + /* + * Previously, the following line was just: + + function dummy() {}; + + * Unfortunately, Chrome was preserving 'dummy' as the object's name, even though at creation, the 'dummy' has the + * correct constructor name. Thus, objects created with IMVU.new would show up in the debugger as 'dummy', which + * isn't very helpful. Using IMVU.createNamedFunction addresses the issue. Doublely-unfortunately, there's no way + * to write a test for this behavior. -NRD 2013.02.22 + */ + var dummy = createNamedFunction(constructor.name, function(){}); + dummy.prototype = constructor.prototype; + var obj = new dummy; + + var r = constructor.apply(obj, argumentList); + return (r instanceof Object) ? r : obj; +}; + function makeInvoker(name, argCount, argTypes, invoker, fn) { if (!FUNCTION_TABLE[fn]) { throwBindingError('function '+name+' is not defined'); } - return createNamedFunction(makeLegalFunctionName(name), function() { - if (arguments.length !== argCount - 1) { - throwBindingError('function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + (argCount - 1)); - } - var destructors = []; - var args = new Array(argCount); - args[0] = fn; - for (var i = 1; i < argCount; ++i) { - args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]); - } - var rv = invoker.apply(null, args); - rv = argTypes[0].fromWireType(rv); - runDestructors(destructors); - return rv; - }); + // Functions with signature "void function()" do not need an invoker that marshalls between wire types. + if (argCount == 1 && argTypes[0].name == "void") { + return FUNCTION_TABLE[fn]; + } + + var invokerFnBody = + "return function "+makeLegalFunctionName(name)+"() { " + + "var destructors = [];"; + + var argsList = ""; + var args1 = ["invoker", "fn", "runDestructors", "retType" ]; + var args2 = [invoker, fn, runDestructors, argTypes[0] ]; + + for(i = 0; i < argCount-1; ++i) { + invokerFnBody += "var arg"+i+" = argType"+i+".toWireType(destructors, arguments["+i+"]);"; + argsList += ", arg"+i; + args1.push("argType"+i); + args2.push(argTypes[i+1]); + } + + invokerFnBody += + "var rv = invoker(fn"+argsList+");" + + "runDestructors(destructors);" + + "return retType.fromWireType(rv);" + + "}"; + + args1.push(invokerFnBody); + + return new_(Function, args1).apply(null, args2); } function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, fn) { From d9886ee985f8c2f5fd3f3ac8d88867d3895e3366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 11 Apr 2013 14:31:36 +0300 Subject: [PATCH 459/544] Added synthetic benchmark for comparing class member function call in C++ and embind. --- tests/embind/embind.benchmark.js | 20 ++++++++++ tests/embind/embind_benchmark.cpp | 61 +++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/tests/embind/embind.benchmark.js b/tests/embind/embind.benchmark.js index 7b08be5d9298a..035f91ff372ce 100644 --- a/tests/embind/embind.benchmark.js +++ b/tests/embind/embind.benchmark.js @@ -18,6 +18,26 @@ function _increment_counter_benchmark_js(N) { Module.print("JS increment_counter " + N + " iters: " + (b-a)*1000 + " msecs. result: " + (ctr2-ctr)); } +function _increment_class_counter_benchmark_embind_js(N) { + var foo = new Module.Foo(); + var a = _emscripten_get_now(); + for(i = 0; i < N; ++i) { + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + } + var b = _emscripten_get_now(); + Module.print("JS increment_class_counter_embind " + N + " iters: " + (b-a)*1000 + " msecs. result: " + foo.class_counter_val()); + foo.delete(); +} + function _returns_input_benchmark_js() { var a = _emscripten_get_now(); var t = 0; diff --git a/tests/embind/embind_benchmark.cpp b/tests/embind/embind_benchmark.cpp index c9391a2975a1c..6bf71d5628a53 100644 --- a/tests/embind/embind_benchmark.cpp +++ b/tests/embind/embind_benchmark.cpp @@ -42,8 +42,35 @@ extern void returns_input_benchmark_embind_js(); extern void sum_int_benchmark_embind_js(); extern void sum_float_benchmark_embind_js(); +extern void increment_class_counter_benchmark_embind_js(int N); } +class Foo +{ +public: + Foo() + :class_counter(0) + { + } + + void __attribute__((noinline)) incr_global_counter() + { + ++counter; + } + + void __attribute__((noinline)) incr_class_counter() + { + ++class_counter; + } + + int class_counter_val() const + { + return class_counter; + } + + int class_counter; +}; + EMSCRIPTEN_BINDINGS(benchmark) { using namespace emscripten; @@ -53,6 +80,12 @@ EMSCRIPTEN_BINDINGS(benchmark) function("returns_input", &returns_input); function("sum_int", &sum_int); function("sum_float", &sum_float); + + class_("Foo") + .constructor<>() + .function("incr_global_counter", &Foo::incr_global_counter) + .function("incr_class_counter", &Foo::incr_class_counter) + .function("class_counter_val", &Foo::class_counter_val); } void __attribute__((noinline)) emscripten_get_now_benchmark(int N) @@ -95,6 +128,27 @@ void __attribute__((noinline)) increment_counter_benchmark(int N) printf("C++ increment_counter %d iters: %f msecs.\n", N, 1000.f*(t2-t)); } +void __attribute__((noinline)) increment_class_counter_benchmark(int N) +{ + Foo foo; + volatile float t = emscripten_get_now(); + for(int i = 0; i < N; ++i) + { + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + foo.incr_class_counter(); + } + volatile float t2 = emscripten_get_now(); + printf("C++ increment_class_counter %d iters: %f msecs. result: %d\n", N, 1000.f*(t2-t), foo.class_counter); +} + void __attribute__((noinline)) returns_input_benchmark() { volatile int r = 0; @@ -172,6 +226,13 @@ int main() printf("\n"); } + for(int i = 1000; i <= 100000; i *= 10) + { + increment_class_counter_benchmark(i); + increment_class_counter_benchmark_embind_js(i); + printf("\n"); + } + returns_input_benchmark(); returns_input_benchmark_js(); returns_input_benchmark_embind_js(); From c643f6469fc2db1a4aa49e404e7ccf5d412d2838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 11 Apr 2013 14:51:54 +0300 Subject: [PATCH 460/544] Restore missing argument count check into the embind invoker function generated with makeInvoker. --- src/embind/embind.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 00d56bc8c8cd6..7d186ba59f29e 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -478,18 +478,23 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { if (!FUNCTION_TABLE[fn]) { throwBindingError('function '+name+' is not defined'); } + // Functions with signature "void function()" do not need an invoker that marshalls between wire types. - if (argCount == 1 && argTypes[0].name == "void") { - return FUNCTION_TABLE[fn]; - } +// TODO: This omits argument count check - enable only at -O3 or similar. +// if (ENABLE_UNSAFE_OPTS && argCount == 1 && argTypes[0].name == "void") { +// return FUNCTION_TABLE[fn]; +// } var invokerFnBody = "return function "+makeLegalFunctionName(name)+"() { " + + "if (arguments.length !== "+(argCount - 1)+") {" + + "throwBindingError('function "+name+" called with ' + arguments.length + ' arguments, expected "+(argCount - 1)+" args!');" + + "}" + "var destructors = [];"; var argsList = ""; - var args1 = ["invoker", "fn", "runDestructors", "retType" ]; - var args2 = [invoker, fn, runDestructors, argTypes[0] ]; + var args1 = ["throwBindingError", "invoker", "fn", "runDestructors", "retType" ]; + var args2 = [throwBindingError, invoker, fn, runDestructors, argTypes[0] ]; for(i = 0; i < argCount-1; ++i) { invokerFnBody += "var arg"+i+" = argType"+i+".toWireType(destructors, arguments["+i+"]);"; From 3d451192df36f938ae563214ebf3cd9b71713f54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 11 Apr 2013 14:58:19 +0300 Subject: [PATCH 461/544] Rename test for consistency. --- tests/embind/embind.benchmark.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/embind/embind.benchmark.js b/tests/embind/embind.benchmark.js index 035f91ff372ce..de1cdd2c14dd1 100644 --- a/tests/embind/embind.benchmark.js +++ b/tests/embind/embind.benchmark.js @@ -34,7 +34,7 @@ function _increment_class_counter_benchmark_embind_js(N) { foo.incr_class_counter(); } var b = _emscripten_get_now(); - Module.print("JS increment_class_counter_embind " + N + " iters: " + (b-a)*1000 + " msecs. result: " + foo.class_counter_val()); + Module.print("JS embind increment_class_counter " + N + " iters: " + (b-a)*1000 + " msecs. result: " + foo.class_counter_val()); foo.delete(); } From c7cfcda3ad9a8a21438b32ca9fe79baeb4bdfeda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 11 Apr 2013 16:24:21 +0300 Subject: [PATCH 462/544] Add a more concrete realworld benchmark with GameObject/Transform/Vector3 position/rotation object hierarchy with shared_ptrs and benchmark moving objects from JS side using embind. --- tests/embind/embind.benchmark.js | 28 +++++++++ tests/embind/embind_benchmark.cpp | 97 +++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/tests/embind/embind.benchmark.js b/tests/embind/embind.benchmark.js index de1cdd2c14dd1..959358b661d06 100644 --- a/tests/embind/embind.benchmark.js +++ b/tests/embind/embind.benchmark.js @@ -171,3 +171,31 @@ function _sum_float_benchmark_embind_js() { var b = _emscripten_get_now(); Module.print("JS embind sum_float 100000 iters: " + (b-a)*1000 + " msecs. result: " + r); } + +function _move_gameobjects_benchmark_embind_js() { + var N = 100000; + var objects = []; + for(i = 0; i < N; ++i) { + objects.push(Module['create_game_object']()); + } + + var a = _emscripten_get_now(); + for(i = 0; i < N; ++i) { + var t = objects[i].GetTransform(); + var pos = Module.add(t.GetPosition(), [2, 0, 1]); + var rot = Module.add(t.GetRotation(), [0.1, 0.2, 0.3]); + t.SetPosition(pos); + t.SetRotation(rot); + t.delete(); + } + var b = _emscripten_get_now(); + + var accum = [0,0,0]; + for(i = 0; i < N; ++i) { + var t = objects[i].GetTransform(); + accum = Module.add(Module.add(accum, t.GetPosition()), t.GetRotation()); + t.delete(); + } + + Module.print("JS embind move_gameobjects " + N + " iters: " + 1000*(b-a) + " msecs. Result: " + (accum[0] + accum[1] + accum[2])); +} diff --git a/tests/embind/embind_benchmark.cpp b/tests/embind/embind_benchmark.cpp index 6bf71d5628a53..91efa4afd306a 100644 --- a/tests/embind/embind_benchmark.cpp +++ b/tests/embind/embind_benchmark.cpp @@ -1,6 +1,7 @@ #include #include #include +#include int counter = 0; @@ -43,6 +44,54 @@ extern void sum_int_benchmark_embind_js(); extern void sum_float_benchmark_embind_js(); extern void increment_class_counter_benchmark_embind_js(int N); +extern void move_gameobjects_benchmark_embind_js(); +} + +class Vec3 +{ +public: + Vec3():x(0),y(0),z(0) {} + Vec3(float x_, float y_, float z_):x(x_),y(y_),z(z_) {} + float x,y,z; +}; + +Vec3 add(const Vec3 &lhs, const Vec3 &rhs) { return Vec3(lhs.x+rhs.x, lhs.y+rhs.y, lhs.z+rhs.z); } + +class Transform +{ +public: + Transform():scale(1) {} + + Vec3 pos; + Vec3 rot; + float scale; + + Vec3 GetPosition() { return pos; } + Vec3 GetRotation() { return rot; } + float GetScale() { return scale; } + + void SetPosition(const Vec3 &pos_) { pos = pos_; } + void SetRotation(const Vec3 &rot_) { rot = rot_; } + void SetScale(float scale_) { scale = scale_; } +}; +typedef std::shared_ptr TransformPtr; + +class GameObject +{ +public: + GameObject() + { + transform = std::make_shared(); + } + std::shared_ptr transform; + + TransformPtr GetTransform() { return transform; } +}; +typedef std::shared_ptr GameObjectPtr; + +GameObjectPtr create_game_object() +{ + return std::make_shared(); } class Foo @@ -75,6 +124,27 @@ EMSCRIPTEN_BINDINGS(benchmark) { using namespace emscripten; + class_("GameObject") + .smart_ptr() + .function("GetTransform", &GameObject::GetTransform); + + class_("Transform") + .smart_ptr() + .function("GetPosition", &Transform::GetPosition) + .function("GetRotation", &Transform::GetRotation) + .function("GetScale", &Transform::GetScale) + .function("SetPosition", &Transform::SetPosition) + .function("SetRotation", &Transform::SetRotation) + .function("SetScale", &Transform::SetScale); + + value_tuple("Vec3") + .element(&Vec3::x) + .element(&Vec3::y) + .element(&Vec3::z); + + function("create_game_object", &create_game_object); + function("add", &add); + function("get_counter", &get_counter); function("increment_counter", &increment_counter); function("returns_input", &returns_input); @@ -212,6 +282,30 @@ void __attribute__((noinline)) sum_float_benchmark() printf("C++ sum_float 100000 iters: %f msecs.\n", 1000.f*(t2-t)); } +void __attribute__((noinline)) move_gameobjects_benchmark() +{ + const int N = 100000; + GameObjectPtr objects[N]; + for(int i = 0; i < N; ++i) + objects[i] = create_game_object(); + + volatile float t = emscripten_get_now(); + for(int i = 0; i < N; ++i) + { + TransformPtr t = objects[i]->GetTransform(); + Vec3 pos = add(t->GetPosition(), Vec3(2.f, 0.f, 1.f)); + Vec3 rot = add(t->GetRotation(), Vec3(0.1f, 0.2f, 0.3f)); + t->SetPosition(pos); + t->SetRotation(rot); + } + volatile float t2 = emscripten_get_now(); + + Vec3 accum; + for(int i = 0; i < N; ++i) + accum = add(add(accum, objects[i]->GetTransform()->GetPosition()), objects[i]->GetTransform()->GetRotation()); + printf("C++ move_gameobjects %d iters: %f msecs. Result: %f\n", N, 1000.f*(t2-t), accum.x+accum.y+accum.z); +} + int main() { for(int i = 1000; i <= 100000; i *= 10) @@ -244,4 +338,7 @@ int main() sum_float_benchmark(); sum_float_benchmark_js(); sum_float_benchmark_embind_js(); + printf("\n"); + move_gameobjects_benchmark(); + move_gameobjects_benchmark_embind_js(); } From 001ef88766b1baaa81e7975309afcb7640cd5175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 11 Apr 2013 16:29:52 +0300 Subject: [PATCH 463/544] Remove clang inlining to level the profiling comparison against 'dynamic' runtime dispatch between JS and JS embind. --- tests/embind/embind_benchmark.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/embind/embind_benchmark.cpp b/tests/embind/embind_benchmark.cpp index 91efa4afd306a..4a4726860867f 100644 --- a/tests/embind/embind_benchmark.cpp +++ b/tests/embind/embind_benchmark.cpp @@ -66,13 +66,13 @@ class Transform Vec3 rot; float scale; - Vec3 GetPosition() { return pos; } - Vec3 GetRotation() { return rot; } - float GetScale() { return scale; } + Vec3 __attribute__((noinline)) GetPosition() const { return pos; } + Vec3 __attribute__((noinline)) GetRotation() const { return rot; } + float __attribute__((noinline)) GetScale() const { return scale; } - void SetPosition(const Vec3 &pos_) { pos = pos_; } - void SetRotation(const Vec3 &rot_) { rot = rot_; } - void SetScale(float scale_) { scale = scale_; } + void __attribute__((noinline)) SetPosition(const Vec3 &pos_) { pos = pos_; } + void __attribute__((noinline)) SetRotation(const Vec3 &rot_) { rot = rot_; } + void __attribute__((noinline)) SetScale(float scale_) { scale = scale_; } }; typedef std::shared_ptr TransformPtr; @@ -85,7 +85,7 @@ class GameObject } std::shared_ptr transform; - TransformPtr GetTransform() { return transform; } + TransformPtr __attribute__((noinline)) GetTransform() const { return transform; } }; typedef std::shared_ptr GameObjectPtr; From 1312d4cf6dbfa74ef1026a0da45971b99a661709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 11 Apr 2013 20:50:41 +0300 Subject: [PATCH 464/544] Optimize the generation of class member function invoker in embind. --- src/embind/embind.js | 48 +++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 7d186ba59f29e..7adfffb67cecc 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -493,8 +493,8 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) { "var destructors = [];"; var argsList = ""; - var args1 = ["throwBindingError", "invoker", "fn", "runDestructors", "retType" ]; - var args2 = [throwBindingError, invoker, fn, runDestructors, argTypes[0] ]; + var args1 = ["throwBindingError", "invoker", "fn", "runDestructors", "retType"]; + var args2 = [throwBindingError, invoker, fn, runDestructors, argTypes[0]]; for(i = 0; i < argCount-1; ++i) { invokerFnBody += "var arg"+i+" = argType"+i+".toWireType(destructors, arguments["+i+"]);"; @@ -1206,23 +1206,35 @@ function __embind_register_class_function( } whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { - var memberFunction = createNamedFunction(makeLegalFunctionName(humanName), function() { - if (arguments.length !== argCount - 2) { - throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-2)); - } + var invokerFnBody = + "return function "+makeLegalFunctionName(humanName)+"() { " + + "if (arguments.length !== "+(argCount - 2)+") {" + + "throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount - 2)+" args!');" + + "}" + + "validateThis(this, classType, '"+humanName+"');" + + "var destructors = [];"; + + var argsList = ""; + var args1 = ["throwBindingError", "validateThis", "classType", "invoker", "fn", "runDestructors", "retType", "classParam"]; + var args2 = [throwBindingError, validateThis, classType, rawInvoker, context, runDestructors, argTypes[0], argTypes[1]]; + + for(i = 0; i < argCount-2; ++i) { + invokerFnBody += "var arg"+i+" = argType"+i+".toWireType(destructors, arguments["+i+"]);"; + argsList += ", arg"+i; + args1.push("argType"+i); + args2.push(argTypes[i+2]); + } - var destructors = []; - var args = new Array(argCount + 1); - args[0] = context; - args[1] = argTypes[1].toWireType(destructors, this); - for (var i = 2; i < argCount; ++i) { - args[i] = argTypes[i].toWireType(destructors, arguments[i - 2]); - } - var rv = rawInvoker.apply(null, args); - rv = argTypes[0].fromWireType(rv); - runDestructors(destructors); - return rv; - }); + invokerFnBody += + "var thisWired = classParam.toWireType(destructors, this);" + + "var rv = invoker(fn, thisWired"+argsList+");" + + "runDestructors(destructors);" + + "return retType.fromWireType(rv);" + + "}"; + + args1.push(invokerFnBody); + + var memberFunction = new_(Function, args1).apply(null, args2); // Replace the initial unbound-handler-stub function with the appropriate member function, now that all types // are resolved. If multiple overloads are registered for this function, the function goes into an overload table. From 0ee5e6e9a0c6478f20c4dbb45714d4b66640cea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 15 Apr 2013 12:53:03 +0300 Subject: [PATCH 465/544] Separate RegisteredPointer toWireType implementations between const-, nonconst-, and smartptr implementations. --- src/embind/embind.js | 139 ++++++++++++++++++++++++++++++------------- 1 file changed, 96 insertions(+), 43 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 7adfffb67cecc..51834de9c01c1 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -711,37 +711,7 @@ function __embind_finalize_struct(structType) { }); } -function RegisteredPointer( - name, - registeredClass, - isReference, - isConst, - - // smart pointer properties - isSmartPointer, - pointeeType, - sharingPolicy, - rawGetPointee, - rawConstructor, - rawShare, - rawDestructor -) { - this.name = name; - this.registeredClass = registeredClass; - this.isReference = isReference; - this.isConst = isConst; - - // smart pointer properties - this.isSmartPointer = isSmartPointer; - this.pointeeType = pointeeType; - this.sharingPolicy = sharingPolicy; - this.rawGetPointee = rawGetPointee; - this.rawConstructor = rawConstructor; - this.rawShare = rawShare; - this.rawDestructor = rawDestructor; -} - -RegisteredPointer.prototype.toWireType = function(destructors, handle) { +genericPointerToWireType = function(destructors, handle) { var self = this; function throwCannotConvert() { var name; @@ -786,6 +756,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { } var handleClass = handle.$$.ptrType.registeredClass; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); + if (this.isSmartPointer) { switch (this.sharingPolicy) { case 0: // NONE @@ -823,6 +794,79 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) { return ptr; }; +nonConstNoSmartPtrRawPointerToWireType = function(destructors, handle) { + if (handle === null) { + if (this.isReference) { + throwBindingError('null is not a valid ' + this.name); + } + return 0; + } +// if (!(handle instanceof this.registeredClass.constructor)) { +// throwBindingError('Expected null or instance of ' + this.name + ', got ' + _embind_repr(handle)); +// } + if (handle.$$.ptrType.isConst) { + throwBindingError('Cannot convert argument of type ' + handle.$$.ptrType.name + ' to parameter type ' + this.name); + } + var handleClass = handle.$$.ptrType.registeredClass; + var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); + return ptr; +}; + +constNoSmartPtrRawPointerToWireType = function(destructors, handle) { + if (handle === null) { + if (this.isReference) { + throwBindingError('null is not a valid ' + this.name); + } + return 0; + } +// if (!(handle instanceof this.registeredClass.constructor)) { +// throwBindingError('Expected null or instance of ' + this.name + ', got ' + _embind_repr(handle)); +// } + var handleClass = handle.$$.ptrType.registeredClass; + var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); + return ptr; +}; + +function RegisteredPointer( + name, + registeredClass, + isReference, + isConst, + + // smart pointer properties + isSmartPointer, + pointeeType, + sharingPolicy, + rawGetPointee, + rawConstructor, + rawShare, + rawDestructor +) { + this.name = name; + this.registeredClass = registeredClass; + this.isReference = isReference; + this.isConst = isConst; + + // smart pointer properties + this.isSmartPointer = isSmartPointer; + this.pointeeType = pointeeType; + this.sharingPolicy = sharingPolicy; + this.rawGetPointee = rawGetPointee; + this.rawConstructor = rawConstructor; + this.rawShare = rawShare; + this.rawDestructor = rawDestructor; + + if (!isSmartPointer && registeredClass.baseClass === undefined) { + if (isConst) { + this.toWireType = constNoInheritanceNoSmartPtrRawPointerToWireType; + } else { + this.toWireType = nonConstNoInheritanceNoSmartPtrRawPointerToWireType; + } + } else { + this.toWireType = genericPointerToWireType; + } +} + RegisteredPointer.prototype.getPointee = function(ptr) { if (this.rawGetPointee) { ptr = this.rawGetPointee(ptr); @@ -1207,30 +1251,39 @@ function __embind_register_class_function( whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { var invokerFnBody = - "return function "+makeLegalFunctionName(humanName)+"() { " + - "if (arguments.length !== "+(argCount - 2)+") {" + - "throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount - 2)+" args!');" + - "}" + - "validateThis(this, classType, '"+humanName+"');" + - "var destructors = [];"; + "return function "+makeLegalFunctionName(humanName)+"() {\n" + + "if (arguments.length !== "+(argCount - 2)+") {\n" + + "throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount - 2)+" args!');\n" + + "}\n" + + "validateThis(this, classType, '"+humanName+"');\n" + + "var destructors = [];\n"; var argsList = ""; var args1 = ["throwBindingError", "validateThis", "classType", "invoker", "fn", "runDestructors", "retType", "classParam"]; var args2 = [throwBindingError, validateThis, classType, rawInvoker, context, runDestructors, argTypes[0], argTypes[1]]; for(i = 0; i < argCount-2; ++i) { - invokerFnBody += "var arg"+i+" = argType"+i+".toWireType(destructors, arguments["+i+"]);"; + invokerFnBody += "var arg"+i+" = argType"+i+".toWireType(destructors, arguments["+i+"]);\n"; argsList += ", arg"+i; args1.push("argType"+i); args2.push(argTypes[i+2]); } invokerFnBody += - "var thisWired = classParam.toWireType(destructors, this);" + - "var rv = invoker(fn, thisWired"+argsList+");" + - "runDestructors(destructors);" + - "return retType.fromWireType(rv);" + - "}"; + "var thisWired = classParam.toWireType(destructors, this);\n" + + if (argTypes[0].name !== "void") { + invokerFnBody += + "var rv = invoker(fn, thisWired"+argsList+");\n" + + "runDestructors(destructors);\n" + + "return retType.fromWireType(rv);\n" + + "}\n"; + } else { + invokerFnBody += + "invoker(fn, thisWired"+argsList+");\n" + + "runDestructors(destructors);\n" + + "}\n"; + } args1.push(invokerFnBody); From 1c4257be3e20aa0cf9f504d0a2c994d840621e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 15 Apr 2013 17:24:10 +0300 Subject: [PATCH 466/544] Optimize embind by avoiding to generate an array for destructors to run after toWireType. Instead, directly generate dtor calls whenever possible. --- src/embind/embind.js | 102 +++++++++++++++++++++++++++++++------------ 1 file changed, 75 insertions(+), 27 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 51834de9c01c1..4aa8038d34616 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -285,6 +285,7 @@ function __embind_register_bool(rawType, name, trueValue, falseValue) { toWireType: function(destructors, o) { return o ? trueValue : falseValue; }, + destructorFunction: null, // This type does not need a destructor }); } @@ -313,6 +314,7 @@ function __embind_register_integer(primitiveType, name, minRange, maxRange) { } return value | 0; }, + destructorFunction: null, // This type does not need a destructor }); } @@ -331,6 +333,7 @@ function __embind_register_float(rawType, name) { } return value; }, + destructorFunction: null, // This type does not need a destructor }); } @@ -418,9 +421,12 @@ function __embind_register_std_wstring(rawType, charSize, name) { for (var i = 0; i < length; ++i) { HEAP[start + i] = value.charCodeAt(i); } - destructors.push(_free, ptr); + if (destructors !== null) { + destructors.push(_free, ptr); + } return ptr; }, + destructorFunction: _free, }); } @@ -436,6 +442,7 @@ function __embind_register_emval(rawType, name) { toWireType: function(destructors, value) { return __emval_register(value); }, + destructorFunction: null, // This type does not need a destructor }); } @@ -606,9 +613,12 @@ function __embind_finalize_tuple(rawTupleType) { for (var i = 0; i < elementsLength; ++i) { elements[i].write(ptr, o[i]); } - destructors.push(rawDestructor, ptr); + if (destructors !== null) { + destructors.push(rawDestructor, ptr); + } return ptr; }, + destructorFunction: rawDestructor, }]; }); } @@ -704,9 +714,12 @@ function __embind_finalize_struct(structType) { for (fieldName in fields) { fields[fieldName].write(ptr, o[fieldName]); } - destructors.push(rawDestructor, ptr); + if (destructors !== null) { + destructors.push(rawDestructor, ptr); + } return ptr; }, + destructorFunction: rawDestructor, }]; }); } @@ -801,9 +814,9 @@ nonConstNoSmartPtrRawPointerToWireType = function(destructors, handle) { } return 0; } -// if (!(handle instanceof this.registeredClass.constructor)) { -// throwBindingError('Expected null or instance of ' + this.name + ', got ' + _embind_repr(handle)); -// } + if (!(handle instanceof this.registeredClass.constructor)) { + throwBindingError('Expected null or instance of ' + this.name + ', got ' + _embind_repr(handle)); + } if (handle.$$.ptrType.isConst) { throwBindingError('Cannot convert argument of type ' + handle.$$.ptrType.name + ' to parameter type ' + this.name); } @@ -819,9 +832,9 @@ constNoSmartPtrRawPointerToWireType = function(destructors, handle) { } return 0; } -// if (!(handle instanceof this.registeredClass.constructor)) { -// throwBindingError('Expected null or instance of ' + this.name + ', got ' + _embind_repr(handle)); -// } + if (!(handle instanceof this.registeredClass.constructor)) { + throwBindingError('Expected null or instance of ' + this.name + ', got ' + _embind_repr(handle)); + } var handleClass = handle.$$.ptrType.registeredClass; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); return ptr; @@ -858,9 +871,11 @@ function RegisteredPointer( if (!isSmartPointer && registeredClass.baseClass === undefined) { if (isConst) { - this.toWireType = constNoInheritanceNoSmartPtrRawPointerToWireType; + this.toWireType = constNoSmartPtrRawPointerToWireType; + this.destructorFunction = null; } else { - this.toWireType = nonConstNoInheritanceNoSmartPtrRawPointerToWireType; + this.toWireType = nonConstNoSmartPtrRawPointerToWireType; + this.destructorFunction = null; } } else { this.toWireType = genericPointerToWireType; @@ -1250,44 +1265,76 @@ function __embind_register_class_function( } whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { + + var argsList = ""; + for(i = 0; i < argCount-2; ++i) { + argsList += (i!=0?", ":"")+"arg"+i; + } + var invokerFnBody = - "return function "+makeLegalFunctionName(humanName)+"() {\n" + + "return function "+makeLegalFunctionName(humanName)+"("+argsList+") {\n" + "if (arguments.length !== "+(argCount - 2)+") {\n" + "throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount - 2)+" args!');\n" + "}\n" + - "validateThis(this, classType, '"+humanName+"');\n" + - "var destructors = [];\n"; + "validateThis(this, classType, '"+humanName+"');\n"; - var argsList = ""; + // Determine if we need to use a dynamic stack to store the destructors for the function parameters. + // TODO: Remove this completely once all function invokers are being dynamically generated. + var needsDestructorStack = false; + + for(i = 1; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. + if (argTypes[i].destructorFunction === undefined) { // The type does not define a destructor function - must use dynamic stack + needsDestructorStack = true; + break; + } + } + + if (needsDestructorStack) { + invokerFnBody += + "var destructors = [];\n"; + } + + var dtorStack = needsDestructorStack ? "destructors" : "null"; var args1 = ["throwBindingError", "validateThis", "classType", "invoker", "fn", "runDestructors", "retType", "classParam"]; var args2 = [throwBindingError, validateThis, classType, rawInvoker, context, runDestructors, argTypes[0], argTypes[1]]; for(i = 0; i < argCount-2; ++i) { - invokerFnBody += "var arg"+i+" = argType"+i+".toWireType(destructors, arguments["+i+"]);\n"; + invokerFnBody += "var arg"+i+" = argType"+i+".toWireType("+dtorStack+", arg"+i+"); // "+argTypes[i+2].name+"\n"; argsList += ", arg"+i; args1.push("argType"+i); args2.push(argTypes[i+2]); } invokerFnBody += - "var thisWired = classParam.toWireType(destructors, this);\n" + "var thisWired = classParam.toWireType("+dtorStack+", this);\n" - if (argTypes[0].name !== "void") { - invokerFnBody += - "var rv = invoker(fn, thisWired"+argsList+");\n" + - "runDestructors(destructors);\n" + - "return retType.fromWireType(rv);\n" + - "}\n"; + var returns = (argTypes[0].name !== "void"); + + invokerFnBody += + (returns?"var rv = ":"") + "invoker(fn, thisWired"+(argCount-2>0?", ":"")+argsList+");\n"; + + if (needsDestructorStack) { + invokerFnBody += "runDestructors(destructors);\n"; } else { - invokerFnBody += - "invoker(fn, thisWired"+argsList+");\n" + - "runDestructors(destructors);\n" + - "}\n"; + for(i = 1; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. + var paramName = (i == 1 ? "thisWired" : ("argType"+(i-2))); + if (argTypes[i].destructorFunction !== null) { + invokerFnBody += paramName+"_dtor("+paramName+"); // "+argTypes[i].name+"\n"; + args1.push(paramName+"_dtor"); + args2.push(argTypes[i].destructorFunction); + } + } + } + + if (returns) { + invokerFnBody += "return retType.fromWireType(rv);\n"; } + invokerFnBody += "}\n"; args1.push(invokerFnBody); var memberFunction = new_(Function, args1).apply(null, args2); + //Module.print(memberFunction); // Replace the initial unbound-handler-stub function with the appropriate member function, now that all types // are resolved. If multiple overloads are registered for this function, the function goes into an overload table. @@ -1468,6 +1515,7 @@ function __embind_register_enum( toWireType: function(destructors, c) { return c.value; }, + destructorFunction: null, }); exposePublicSymbol(name, constructor); } From 477cde821da19c3a04450cf9072068b87295ec99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 15 Apr 2013 17:36:32 +0300 Subject: [PATCH 467/544] Implement high-resolution timing in emscripten_get_now() when run in node. Return timing ticks consistently as seconds in all methods. --- src/library_browser.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/library_browser.js b/src/library_browser.js index c1add7406b81a..6922c42f18597 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -704,8 +704,12 @@ mergeInto(LibraryManager.library, { }, emscripten_get_now: function() { - if (window['performance'] && window['performance']['now']) { - return window['performance']['now'](); + if (ENVIRONMENT_IS_NODE) { + var t = process['hrtime'](); + return t[0] + t[1] / 1e9; + } + else if (window['performance'] && window['performance']['now']) { + return window['performance']['now']() / 1000.0; } else { return Date.now(); } From 51c2826d68883d2324c728558aa10a8ffc299d1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 15 Apr 2013 17:48:15 +0300 Subject: [PATCH 468/544] Remove validateThis since it was also deleted in imvu/emscripten upstream. --- src/embind/embind.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 4aa8038d34616..4cc111a32a51c 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1275,8 +1275,8 @@ function __embind_register_class_function( "return function "+makeLegalFunctionName(humanName)+"("+argsList+") {\n" + "if (arguments.length !== "+(argCount - 2)+") {\n" + "throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount - 2)+" args!');\n" + - "}\n" + - "validateThis(this, classType, '"+humanName+"');\n"; + "}\n";// + + //"validateThis(this, classType, '"+humanName+"');\n"; // Determine if we need to use a dynamic stack to store the destructors for the function parameters. // TODO: Remove this completely once all function invokers are being dynamically generated. From a0406a1cb9d0de51c923fca1c1e2e637dd3bd57a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 15 Apr 2013 21:13:42 +0300 Subject: [PATCH 469/544] Embind: Merge makeInvoker and class member function invoker generator functions into one to remove code duplication. --- src/embind/embind.js | 187 +++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 95 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 4cc111a32a51c..0af19bb1192c8 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -481,44 +481,107 @@ function new_(constructor, argumentList) { return (r instanceof Object) ? r : obj; }; -function makeInvoker(name, argCount, argTypes, invoker, fn) { - if (!FUNCTION_TABLE[fn]) { - throwBindingError('function '+name+' is not defined'); +// The path to interop from JS code to C++ code: +// (hand-written JS code) -> (autogenerated JS invoker) -> (template-generated C++ invoker) -> (target C++ function) +// craftInvokerFunction generates the JS invoker function for each function exposed to JS through embind. +function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc) { + // humanName: a human-readable string name for the function to be generated. + // argTypes: An array that contains the embind type objects for all types in the function signature. + // argTypes[0] is the type object for the function return value. + // argTypes[1] is the type object for function this object/class type, or null if not crafting an invoker for a class method. + // argTypes[2...] are the actual function parameters. + // classType: The embind type object for the class to be bound, or null if this is not a method of a class. + // cppInvokerFunc: JS Function object to the C++-side function that interops into C++ code. + // cppTargetFunc: Function pointer (an integer to FUNCTION_TABLE) to the target C++ function the cppInvokerFunc will end up calling. + var argCount = argTypes.length; + + if (argCount < 2) { + throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!"); + } + + var isClassMethodFunc = (argTypes[1] !== null && classType !== null); + + if (!isClassMethodFunc && !FUNCTION_TABLE[cppTargetFunc]) { + throwBindingError('Global function '+humanName+' is not defined!'); } - // Functions with signature "void function()" do not need an invoker that marshalls between wire types. + // Free functions with signature "void function()" do not need an invoker that marshalls between wire types. // TODO: This omits argument count check - enable only at -O3 or similar. -// if (ENABLE_UNSAFE_OPTS && argCount == 1 && argTypes[0].name == "void") { +// if (ENABLE_UNSAFE_OPTS && argCount == 2 && argTypes[0].name == "void" && !isClassMethodFunc) { // return FUNCTION_TABLE[fn]; // } - var invokerFnBody = - "return function "+makeLegalFunctionName(name)+"() { " + - "if (arguments.length !== "+(argCount - 1)+") {" + - "throwBindingError('function "+name+" called with ' + arguments.length + ' arguments, expected "+(argCount - 1)+" args!');" + - "}" + - "var destructors = [];"; - var argsList = ""; - var args1 = ["throwBindingError", "invoker", "fn", "runDestructors", "retType"]; - var args2 = [throwBindingError, invoker, fn, runDestructors, argTypes[0]]; + for(i = 0; i < argCount-2; ++i) { + argsList += (i!=0?", ":"")+"arg"+i; + } + + var invokerFnBody = + "return function "+makeLegalFunctionName(humanName)+"("+argsList+") {\n" + + "if (arguments.length !== "+(argCount - 2)+") {\n" + + "throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount - 2)+" args!');\n" + + "}\n";// + + //"validateThis(this, classType, '"+humanName+"');\n"; + + // Determine if we need to use a dynamic stack to store the destructors for the function parameters. + // TODO: Remove this completely once all function invokers are being dynamically generated. + var needsDestructorStack = false; + + for(i = 1; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. + if (argTypes[i] !== null && argTypes[i].destructorFunction === undefined) { // The type does not define a destructor function - must use dynamic stack + needsDestructorStack = true; + break; + } + } + + if (needsDestructorStack) { + invokerFnBody += + "var destructors = [];\n"; + } - for(i = 0; i < argCount-1; ++i) { - invokerFnBody += "var arg"+i+" = argType"+i+".toWireType(destructors, arguments["+i+"]);"; - argsList += ", arg"+i; + var dtorStack = needsDestructorStack ? "destructors" : "null"; + var args1 = ["throwBindingError", "validateThis", "classType", "invoker", "fn", "runDestructors", "retType", "classParam"]; + var args2 = [throwBindingError, validateThis, classType, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]]; + + for(i = 0; i < argCount-2; ++i) { + invokerFnBody += "var arg"+i+" = argType"+i+".toWireType("+dtorStack+", arg"+i+"); // "+argTypes[i+2].name+"\n"; + // argsList += ", arg"+i; args1.push("argType"+i); - args2.push(argTypes[i+1]); + args2.push(argTypes[i+2]); + } + + if (isClassMethodFunc) { + invokerFnBody += "var thisWired = classParam.toWireType("+dtorStack+", this);\n" + argsList = "thisWired" + (argsList.length > 0 ? ", " : "") + argsList; } - invokerFnBody += - "var rv = invoker(fn"+argsList+");" + - "runDestructors(destructors);" + - "return retType.fromWireType(rv);" + - "}"; + var returns = (argTypes[0].name !== "void"); + + invokerFnBody += + (returns?"var rv = ":"") + "invoker(fn"+(argsList.length>0?", ":"")+argsList+");\n"; + + if (needsDestructorStack) { + invokerFnBody += "runDestructors(destructors);\n"; + } else { + for(i = isClassMethodFunc?1:2; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. Also skip class type if not a method. + var paramName = (i == 1 ? "thisWired" : ("argType"+(i-2))); + if (argTypes[i].destructorFunction !== null) { + invokerFnBody += paramName+"_dtor("+paramName+"); // "+argTypes[i].name+"\n"; + args1.push(paramName+"_dtor"); + args2.push(argTypes[i].destructorFunction); + } + } + } + + if (returns) { + invokerFnBody += "return retType.fromWireType(rv);\n"; + } + invokerFnBody += "}\n"; args1.push(invokerFnBody); - return new_(Function, args1).apply(null, args2); + var invokerFunction = new_(Function, args1).apply(null, args2); + return invokerFunction; } function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, fn) { @@ -531,7 +594,8 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, }, argCount - 1); whenDependentTypesAreResolved([], argTypes, function(argTypes) { - replacePublicSymbol(name, makeInvoker(name, argCount, argTypes, rawInvoker, fn), argCount - 1); + var invokerArgsArray = [argTypes[0] /* return value */, null /* no class 'this'*/].concat(argTypes.slice(1) /* actual params */); + replacePublicSymbol(name, craftInvokerFunction(name, invokerArgsArray, null /* no class 'this'*/, rawInvoker, fn), argCount - 1); return []; }); } @@ -1266,75 +1330,7 @@ function __embind_register_class_function( whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { - var argsList = ""; - for(i = 0; i < argCount-2; ++i) { - argsList += (i!=0?", ":"")+"arg"+i; - } - - var invokerFnBody = - "return function "+makeLegalFunctionName(humanName)+"("+argsList+") {\n" + - "if (arguments.length !== "+(argCount - 2)+") {\n" + - "throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount - 2)+" args!');\n" + - "}\n";// + - //"validateThis(this, classType, '"+humanName+"');\n"; - - // Determine if we need to use a dynamic stack to store the destructors for the function parameters. - // TODO: Remove this completely once all function invokers are being dynamically generated. - var needsDestructorStack = false; - - for(i = 1; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. - if (argTypes[i].destructorFunction === undefined) { // The type does not define a destructor function - must use dynamic stack - needsDestructorStack = true; - break; - } - } - - if (needsDestructorStack) { - invokerFnBody += - "var destructors = [];\n"; - } - - var dtorStack = needsDestructorStack ? "destructors" : "null"; - var args1 = ["throwBindingError", "validateThis", "classType", "invoker", "fn", "runDestructors", "retType", "classParam"]; - var args2 = [throwBindingError, validateThis, classType, rawInvoker, context, runDestructors, argTypes[0], argTypes[1]]; - - for(i = 0; i < argCount-2; ++i) { - invokerFnBody += "var arg"+i+" = argType"+i+".toWireType("+dtorStack+", arg"+i+"); // "+argTypes[i+2].name+"\n"; - argsList += ", arg"+i; - args1.push("argType"+i); - args2.push(argTypes[i+2]); - } - - invokerFnBody += - "var thisWired = classParam.toWireType("+dtorStack+", this);\n" - - var returns = (argTypes[0].name !== "void"); - - invokerFnBody += - (returns?"var rv = ":"") + "invoker(fn, thisWired"+(argCount-2>0?", ":"")+argsList+");\n"; - - if (needsDestructorStack) { - invokerFnBody += "runDestructors(destructors);\n"; - } else { - for(i = 1; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. - var paramName = (i == 1 ? "thisWired" : ("argType"+(i-2))); - if (argTypes[i].destructorFunction !== null) { - invokerFnBody += paramName+"_dtor("+paramName+"); // "+argTypes[i].name+"\n"; - args1.push(paramName+"_dtor"); - args2.push(argTypes[i].destructorFunction); - } - } - } - - if (returns) { - invokerFnBody += "return retType.fromWireType(rv);\n"; - } - invokerFnBody += "}\n"; - - args1.push(invokerFnBody); - - var memberFunction = new_(Function, args1).apply(null, args2); - //Module.print(memberFunction); + var memberFunction = craftInvokerFunction(humanName, argTypes, classType, rawInvoker, context); // Replace the initial unbound-handler-stub function with the appropriate member function, now that all types // are resolved. If multiple overloads are registered for this function, the function goes into an overload table. @@ -1383,7 +1379,8 @@ function __embind_register_class_class_function( whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { // Replace the initial unbound-types-handler stub with the proper function. If multiple overloads are registered, // the function handlers go into an overload table. - var func = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn); + var invokerArgsArray = [argTypes[0] /* return value */, null /* no class 'this'*/].concat(argTypes.slice(1) /* actual params */); + var func = craftInvokerFunction(humanName, invokerArgsArray, null /* no class 'this'*/, rawInvoker, fn); if (undefined === proto[methodName].overloadTable) { proto[methodName] = func; } else { From 63df46540d7ba78dca88fd83ec0def3bd203b638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 16 Apr 2013 12:09:44 +0300 Subject: [PATCH 470/544] Clean up jslint diagnostics. --- src/embind/embind.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 0af19bb1192c8..bf493bf997538 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -479,7 +479,7 @@ function new_(constructor, argumentList) { var r = constructor.apply(obj, argumentList); return (r instanceof Object) ? r : obj; -}; +} // The path to interop from JS code to C++ code: // (hand-written JS code) -> (autogenerated JS invoker) -> (template-generated C++ invoker) -> (target C++ function) @@ -512,8 +512,8 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp // } var argsList = ""; - for(i = 0; i < argCount-2; ++i) { - argsList += (i!=0?", ":"")+"arg"+i; + for(var i = 0; i < argCount-2; ++i) { + argsList += (i!==0?", ":"")+"arg"+i; } var invokerFnBody = @@ -527,7 +527,7 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp // TODO: Remove this completely once all function invokers are being dynamically generated. var needsDestructorStack = false; - for(i = 1; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. + for(var i = 1; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. if (argTypes[i] !== null && argTypes[i].destructorFunction === undefined) { // The type does not define a destructor function - must use dynamic stack needsDestructorStack = true; break; @@ -543,7 +543,7 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp var args1 = ["throwBindingError", "validateThis", "classType", "invoker", "fn", "runDestructors", "retType", "classParam"]; var args2 = [throwBindingError, validateThis, classType, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]]; - for(i = 0; i < argCount-2; ++i) { + for(var i = 0; i < argCount-2; ++i) { invokerFnBody += "var arg"+i+" = argType"+i+".toWireType("+dtorStack+", arg"+i+"); // "+argTypes[i+2].name+"\n"; // argsList += ", arg"+i; args1.push("argType"+i); @@ -551,7 +551,7 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp } if (isClassMethodFunc) { - invokerFnBody += "var thisWired = classParam.toWireType("+dtorStack+", this);\n" + invokerFnBody += "var thisWired = classParam.toWireType("+dtorStack+", this);\n"; argsList = "thisWired" + (argsList.length > 0 ? ", " : "") + argsList; } @@ -563,8 +563,8 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp if (needsDestructorStack) { invokerFnBody += "runDestructors(destructors);\n"; } else { - for(i = isClassMethodFunc?1:2; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. Also skip class type if not a method. - var paramName = (i == 1 ? "thisWired" : ("argType"+(i-2))); + for(var i = isClassMethodFunc?1:2; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. Also skip class type if not a method. + var paramName = (i === 1 ? "thisWired" : ("argType"+(i-2))); if (argTypes[i].destructorFunction !== null) { invokerFnBody += paramName+"_dtor("+paramName+"); // "+argTypes[i].name+"\n"; args1.push(paramName+"_dtor"); @@ -788,7 +788,7 @@ function __embind_finalize_struct(structType) { }); } -genericPointerToWireType = function(destructors, handle) { +var genericPointerToWireType = function(destructors, handle) { var self = this; function throwCannotConvert() { var name; @@ -871,7 +871,7 @@ genericPointerToWireType = function(destructors, handle) { return ptr; }; -nonConstNoSmartPtrRawPointerToWireType = function(destructors, handle) { +var nonConstNoSmartPtrRawPointerToWireType = function(destructors, handle) { if (handle === null) { if (this.isReference) { throwBindingError('null is not a valid ' + this.name); @@ -889,7 +889,7 @@ nonConstNoSmartPtrRawPointerToWireType = function(destructors, handle) { return ptr; }; -constNoSmartPtrRawPointerToWireType = function(destructors, handle) { +var constNoSmartPtrRawPointerToWireType = function(destructors, handle) { if (handle === null) { if (this.isReference) { throwBindingError('null is not a valid ' + this.name); From 8892232a7174008595c82fda7a64e5995cc4e3e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 16 Apr 2013 17:33:52 +0300 Subject: [PATCH 471/544] Fix test runner - preserve validateThis and convert class this to wire type before parameters to catch invalid this type before invalid parameters. --- src/embind/embind.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index bf493bf997538..5ae258cdb1299 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -520,8 +520,11 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp "return function "+makeLegalFunctionName(humanName)+"("+argsList+") {\n" + "if (arguments.length !== "+(argCount - 2)+") {\n" + "throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount - 2)+" args!');\n" + - "}\n";// + - //"validateThis(this, classType, '"+humanName+"');\n"; + "}\n"; + + if (isClassMethodFunc) { + invokerFnBody += "validateThis(this, classType, '"+humanName+"');\n"; + } // Determine if we need to use a dynamic stack to store the destructors for the function parameters. // TODO: Remove this completely once all function invokers are being dynamically generated. @@ -543,6 +546,10 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp var args1 = ["throwBindingError", "validateThis", "classType", "invoker", "fn", "runDestructors", "retType", "classParam"]; var args2 = [throwBindingError, validateThis, classType, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]]; + if (isClassMethodFunc) { + invokerFnBody += "var thisWired = classParam.toWireType("+dtorStack+", this);\n"; + } + for(var i = 0; i < argCount-2; ++i) { invokerFnBody += "var arg"+i+" = argType"+i+".toWireType("+dtorStack+", arg"+i+"); // "+argTypes[i+2].name+"\n"; // argsList += ", arg"+i; @@ -551,7 +558,6 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp } if (isClassMethodFunc) { - invokerFnBody += "var thisWired = classParam.toWireType("+dtorStack+", this);\n"; argsList = "thisWired" + (argsList.length > 0 ? ", " : "") + argsList; } @@ -932,7 +938,7 @@ function RegisteredPointer( this.rawConstructor = rawConstructor; this.rawShare = rawShare; this.rawDestructor = rawDestructor; - +/* if (!isSmartPointer && registeredClass.baseClass === undefined) { if (isConst) { this.toWireType = constNoSmartPtrRawPointerToWireType; @@ -941,9 +947,9 @@ function RegisteredPointer( this.toWireType = nonConstNoSmartPtrRawPointerToWireType; this.destructorFunction = null; } - } else { + } else {*/ this.toWireType = genericPointerToWireType; - } + //} } RegisteredPointer.prototype.getPointee = function(ptr) { From f10fe0cc393eaf1a457872487eac31a128b496e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 16 Apr 2013 18:27:18 +0300 Subject: [PATCH 472/544] Merge Chad's validateThis removal commit to new optimized invoker function. --- src/embind/embind.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 5ae258cdb1299..0a40c36d34be4 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -522,10 +522,6 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp "throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount - 2)+" args!');\n" + "}\n"; - if (isClassMethodFunc) { - invokerFnBody += "validateThis(this, classType, '"+humanName+"');\n"; - } - // Determine if we need to use a dynamic stack to store the destructors for the function parameters. // TODO: Remove this completely once all function invokers are being dynamically generated. var needsDestructorStack = false; @@ -543,8 +539,8 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp } var dtorStack = needsDestructorStack ? "destructors" : "null"; - var args1 = ["throwBindingError", "validateThis", "classType", "invoker", "fn", "runDestructors", "retType", "classParam"]; - var args2 = [throwBindingError, validateThis, classType, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]]; + var args1 = ["throwBindingError", "classType", "invoker", "fn", "runDestructors", "retType", "classParam"]; + var args2 = [throwBindingError, classType, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]]; if (isClassMethodFunc) { invokerFnBody += "var thisWired = classParam.toWireType("+dtorStack+", this);\n"; @@ -887,6 +883,9 @@ var nonConstNoSmartPtrRawPointerToWireType = function(destructors, handle) { if (!(handle instanceof this.registeredClass.constructor)) { throwBindingError('Expected null or instance of ' + this.name + ', got ' + _embind_repr(handle)); } + if (!handle.$$.ptr) { + throwBindingError('Cannot pass deleted object'); + } if (handle.$$.ptrType.isConst) { throwBindingError('Cannot convert argument of type ' + handle.$$.ptrType.name + ' to parameter type ' + this.name); } @@ -905,6 +904,9 @@ var constNoSmartPtrRawPointerToWireType = function(destructors, handle) { if (!(handle instanceof this.registeredClass.constructor)) { throwBindingError('Expected null or instance of ' + this.name + ', got ' + _embind_repr(handle)); } + if (!handle.$$.ptr) { + throwBindingError('Cannot pass deleted object'); + } var handleClass = handle.$$.ptrType.registeredClass; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); return ptr; From 2afab7b6f9f890e2ba55e6273cb46db0f52c74d2 Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Tue, 16 Apr 2013 21:12:39 +0300 Subject: [PATCH 473/544] Fix use of destructors in crafted destructors. --- src/embind/embind.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 0a40c36d34be4..2a484deaf11b6 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -384,9 +384,12 @@ function __embind_register_std_string(rawType, name) { } HEAPU8[ptr + 4 + i] = charCode; } - destructors.push(_free, ptr); + if (destructors !== null) { + destructors.push(_free, ptr); + } return ptr; }, + destructorFunction: function(ptr) { _free(ptr); }, }); } @@ -426,7 +429,7 @@ function __embind_register_std_wstring(rawType, charSize, name) { } return ptr; }, - destructorFunction: _free, + destructorFunction: function(ptr) { _free(ptr); }, }); } @@ -512,8 +515,10 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp // } var argsList = ""; + var argsListWired = ""; for(var i = 0; i < argCount-2; ++i) { argsList += (i!==0?", ":"")+"arg"+i; + argsListWired += (i!==0?", ":"")+"arg"+i+"Wired"; } var invokerFnBody = @@ -547,26 +552,25 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp } for(var i = 0; i < argCount-2; ++i) { - invokerFnBody += "var arg"+i+" = argType"+i+".toWireType("+dtorStack+", arg"+i+"); // "+argTypes[i+2].name+"\n"; - // argsList += ", arg"+i; + invokerFnBody += "var arg"+i+"Wired = argType"+i+".toWireType("+dtorStack+", arg"+i+"); // "+argTypes[i+2].name+"\n"; args1.push("argType"+i); args2.push(argTypes[i+2]); } if (isClassMethodFunc) { - argsList = "thisWired" + (argsList.length > 0 ? ", " : "") + argsList; + argsListWired = "thisWired" + (argsListWired.length > 0 ? ", " : "") + argsListWired; } var returns = (argTypes[0].name !== "void"); invokerFnBody += - (returns?"var rv = ":"") + "invoker(fn"+(argsList.length>0?", ":"")+argsList+");\n"; + (returns?"var rv = ":"") + "invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n"; if (needsDestructorStack) { invokerFnBody += "runDestructors(destructors);\n"; } else { for(var i = isClassMethodFunc?1:2; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. Also skip class type if not a method. - var paramName = (i === 1 ? "thisWired" : ("argType"+(i-2))); + var paramName = (i === 1 ? "thisWired" : ("arg"+(i-2)+"Wired")); if (argTypes[i].destructorFunction !== null) { invokerFnBody += paramName+"_dtor("+paramName+"); // "+argTypes[i].name+"\n"; args1.push(paramName+"_dtor"); From 3734028036e309fa13c8b4b9956666285ebaf94d Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Tue, 16 Apr 2013 21:14:58 +0300 Subject: [PATCH 474/544] Match embind tests to reported exception. --- tests/embind/embind.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 5af15be935f90..ff20791df4195 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -153,7 +153,7 @@ module({ }); if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! // got Error: expected: Derived.setMember with invalid "this": undefined, actual: Derived.setMember incompatible with "this" of type Object - assert.equal('Expected null or instance of Derived*, got undefined', e.message); + assert.equal('Expected null or instance of Derived*, got [object global]', e.message); } var e = assert.throws(cm.BindingError, function() { From 496b38f13f74e04af233d5ad7307be4f099b07e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 16 Apr 2013 22:03:13 +0300 Subject: [PATCH 475/544] Add a new unit test that explicitly checks for the case when two different classes happen to have member functions with the same name and signature - a reason why the 'instanceof' check exists in embind.js. --- tests/embind/embind.test.js | 11 +++++++++++ tests/embind/embind_test.cpp | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index ff20791df4195..0763f09a228be 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -147,6 +147,17 @@ module({ a.delete(); }); + test("calling method on unrelated class throws error (2)", function() { + // Base1 and Base2 both have the method 'getField()' exposed - make sure + // that calling the Base2 function with a 'this' instance of Base1 doesn't accidentally work! + var a = new cm.Base1; + var e = assert.throws(cm.BindingError, function() { + cm.Base2.prototype.getField.call(a); + }); + assert.equal('Expected null or instance of Base2 const*, got [object Object]', e.message); + a.delete(); + }); + test("calling method with invalid this throws error", function() { var e = assert.throws(cm.BindingError, function() { cm.Derived.prototype.setMember.call(undefined, "foo"); diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 04771dbe2d1ad..0439c8329638b 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1814,6 +1814,11 @@ EMSCRIPTEN_BINDINGS(tests) { function("embind_attempt_to_modify_smart_pointer_when_passed_by_value", embind_attempt_to_modify_smart_pointer_when_passed_by_value); function("embind_save_smart_base_pointer", embind_save_smart_base_pointer); + class_("Base1") + .constructor() + .function("getField", &Base1::getField) + ; + class_("Base2") .function("getField", &Base2::getField) .property("field", &Base2::field2) From 11bcd19a9ceae940277ec9ef72bea663f2f50ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 16 Apr 2013 22:39:50 +0300 Subject: [PATCH 476/544] Removed embind class member this pointer 'instanceof' check when serializing this to wire type, since instanceof was profiled to be slow. Instead, the correct instanceof enforcement is done in the upcastPointer function. --- src/embind/embind.js | 27 +++++++++++---------------- tests/embind/embind.test.js | 4 ++-- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 2a484deaf11b6..b41137e761593 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -820,12 +820,8 @@ var genericPointerToWireType = function(destructors, handle) { } } - if (!(handle instanceof this.registeredClass.constructor)) { - throwBindingError('Expected null or instance of ' + this.name + ', got ' + _embind_repr(handle)); - } - - if (!handle.$$.ptr) { - throwBindingError('Cannot pass deleted object'); + if (!handle.$$ || !handle.$$.ptr) { + throwBindingError('Cannot pass deleted or null object'); } // TODO: this is not strictly true @@ -884,11 +880,9 @@ var nonConstNoSmartPtrRawPointerToWireType = function(destructors, handle) { } return 0; } - if (!(handle instanceof this.registeredClass.constructor)) { - throwBindingError('Expected null or instance of ' + this.name + ', got ' + _embind_repr(handle)); - } - if (!handle.$$.ptr) { - throwBindingError('Cannot pass deleted object'); + + if (!handle.$$ || !handle.$$.ptr) { + throwBindingError('Cannot pass deleted or null object'); } if (handle.$$.ptrType.isConst) { throwBindingError('Cannot convert argument of type ' + handle.$$.ptrType.name + ' to parameter type ' + this.name); @@ -905,11 +899,9 @@ var constNoSmartPtrRawPointerToWireType = function(destructors, handle) { } return 0; } - if (!(handle instanceof this.registeredClass.constructor)) { - throwBindingError('Expected null or instance of ' + this.name + ', got ' + _embind_repr(handle)); - } - if (!handle.$$.ptr) { - throwBindingError('Cannot pass deleted object'); + + if (!handle.$$ || !handle.$$.ptr) { + throwBindingError('Cannot pass deleted or null object'); } var handleClass = handle.$$.ptrType.registeredClass; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); @@ -1283,6 +1275,9 @@ function downcastPointer(ptr, ptrClass, desiredClass) { function upcastPointer(ptr, ptrClass, desiredClass) { while (ptrClass !== desiredClass) { + if (!ptrClass.upcast) { + throwBindingError("Expected null or instance of " + desiredClass.name + ", got an instance of " + ptrClass.name); + } ptr = ptrClass.upcast(ptr); ptrClass = ptrClass.baseClass; } diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 0763f09a228be..efb5ae847bb2c 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -143,7 +143,7 @@ module({ var e = assert.throws(cm.BindingError, function() { cm.Derived.prototype.setMember.call(a, "foo"); }); - assert.equal('Expected null or instance of Derived*, got [object Object]', e.message); + assert.equal('Expected null or instance of Derived, got an instance of Base2', e.message); a.delete(); }); @@ -154,7 +154,7 @@ module({ var e = assert.throws(cm.BindingError, function() { cm.Base2.prototype.getField.call(a); }); - assert.equal('Expected null or instance of Base2 const*, got [object Object]', e.message); + assert.equal('Expected null or instance of Base2, got an instance of Base1', e.message); a.delete(); }); From ccb6ee201fbbc0add5b07808b9308ee9c9e28764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 16 Apr 2013 23:02:00 +0300 Subject: [PATCH 477/544] Restore previously temporarily disabled specific non-smartptr wiretype converters. --- src/embind/embind.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index b41137e761593..42aff0c45d883 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -936,7 +936,7 @@ function RegisteredPointer( this.rawConstructor = rawConstructor; this.rawShare = rawShare; this.rawDestructor = rawDestructor; -/* + if (!isSmartPointer && registeredClass.baseClass === undefined) { if (isConst) { this.toWireType = constNoSmartPtrRawPointerToWireType; @@ -945,9 +945,9 @@ function RegisteredPointer( this.toWireType = nonConstNoSmartPtrRawPointerToWireType; this.destructorFunction = null; } - } else {*/ + } else { this.toWireType = genericPointerToWireType; - //} + } } RegisteredPointer.prototype.getPointee = function(ptr) { From f3c28a7b9aac81b67619378c67f72e8cbc0254b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 16 Apr 2013 23:02:29 +0300 Subject: [PATCH 478/544] Do slightly fewer iterations of GameObject benchmark to make the test run a bit quicker. --- tests/embind/embind.benchmark.js | 2 +- tests/embind/embind_benchmark.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/embind/embind.benchmark.js b/tests/embind/embind.benchmark.js index 959358b661d06..f0f6e078e36c2 100644 --- a/tests/embind/embind.benchmark.js +++ b/tests/embind/embind.benchmark.js @@ -173,7 +173,7 @@ function _sum_float_benchmark_embind_js() { } function _move_gameobjects_benchmark_embind_js() { - var N = 100000; + var N = 10000; var objects = []; for(i = 0; i < N; ++i) { objects.push(Module['create_game_object']()); diff --git a/tests/embind/embind_benchmark.cpp b/tests/embind/embind_benchmark.cpp index 4a4726860867f..8ce33bc8729c6 100644 --- a/tests/embind/embind_benchmark.cpp +++ b/tests/embind/embind_benchmark.cpp @@ -284,7 +284,7 @@ void __attribute__((noinline)) sum_float_benchmark() void __attribute__((noinline)) move_gameobjects_benchmark() { - const int N = 100000; + const int N = 10000; GameObjectPtr objects[N]; for(int i = 0; i < N; ++i) objects[i] = create_game_object(); From 94f9f007a444181386ee7fe2b4cb01be93ebe48f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 17 Apr 2013 07:54:00 +0300 Subject: [PATCH 479/544] Improve error messages from embind pointer marshalling and remove TODOs in embind test code. --- src/embind/embind.js | 21 +++++++++++++++------ tests/embind/embind.test.js | 37 +++++++++++++++++++++---------------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 42aff0c45d883..205d7fdc2b257 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -820,8 +820,11 @@ var genericPointerToWireType = function(destructors, handle) { } } - if (!handle.$$ || !handle.$$.ptr) { - throwBindingError('Cannot pass deleted or null object'); + if (!handle.$$) { + throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); + } + if (!handle.$$.ptr) { + throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); } // TODO: this is not strictly true @@ -881,8 +884,11 @@ var nonConstNoSmartPtrRawPointerToWireType = function(destructors, handle) { return 0; } - if (!handle.$$ || !handle.$$.ptr) { - throwBindingError('Cannot pass deleted or null object'); + if (!handle.$$) { + throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); + } + if (!handle.$$.ptr) { + throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); } if (handle.$$.ptrType.isConst) { throwBindingError('Cannot convert argument of type ' + handle.$$.ptrType.name + ' to parameter type ' + this.name); @@ -900,8 +906,11 @@ var constNoSmartPtrRawPointerToWireType = function(destructors, handle) { return 0; } - if (!handle.$$ || !handle.$$.ptr) { - throwBindingError('Cannot pass deleted or null object'); + if (!handle.$$) { + throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); + } + if (!handle.$$.ptr) { + throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); } var handleClass = handle.$$.ptrType.registeredClass; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index efb5ae847bb2c..4ad854f47f214 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -145,42 +145,47 @@ module({ }); assert.equal('Expected null or instance of Derived, got an instance of Base2', e.message); a.delete(); - }); - test("calling method on unrelated class throws error (2)", function() { // Base1 and Base2 both have the method 'getField()' exposed - make sure // that calling the Base2 function with a 'this' instance of Base1 doesn't accidentally work! - var a = new cm.Base1; + var b = new cm.Base1; var e = assert.throws(cm.BindingError, function() { - cm.Base2.prototype.getField.call(a); + cm.Base2.prototype.getField.call(b); }); assert.equal('Expected null or instance of Base2, got an instance of Base1', e.message); - a.delete(); + b.delete(); }); test("calling method with invalid this throws error", function() { var e = assert.throws(cm.BindingError, function() { cm.Derived.prototype.setMember.call(undefined, "foo"); }); - if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! - // got Error: expected: Derived.setMember with invalid "this": undefined, actual: Derived.setMember incompatible with "this" of type Object - assert.equal('Expected null or instance of Derived*, got [object global]', e.message); - } + assert.equal('Cannot pass "[object global]" as a Derived*', e.message); + + var e = assert.throws(cm.BindingError, function() { + cm.Derived.prototype.setMember.call(true, "foo"); + }); + assert.equal('Cannot pass "true" as a Derived*', e.message); + + var e = assert.throws(cm.BindingError, function() { + cm.Derived.prototype.setMember.call(null, "foo"); + }); + assert.equal('Cannot pass "[object global]" as a Derived*', e.message); + + var e = assert.throws(cm.BindingError, function() { + cm.Derived.prototype.setMember.call(42, "foo"); + }); + assert.equal('Cannot pass "42" as a Derived*', e.message); var e = assert.throws(cm.BindingError, function() { cm.Derived.prototype.setMember.call("this", "foo"); }); - if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! - // TODO got 'Derived.setMember incompatible with "this" of type Object' - assert.equal('Expected null or instance of Derived*, got this', e.message); - } + assert.equal('Cannot pass "this" as a Derived*', e.message); var e = assert.throws(cm.BindingError, function() { cm.Derived.prototype.setMember.call({}, "foo"); }); - if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! - assert.equal('Expected null or instance of Derived*, got [object Object]', e.message); - } + assert.equal('Cannot pass "[object Object]" as a Derived*', e.message); }); test("setting and getting property on unrelated class throws error", function() { From d2cab99a79f7d7718e257f1a41ea3354b6c68fa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 17 Apr 2013 08:01:11 +0300 Subject: [PATCH 480/544] Comment on pointer marshalling functions. --- src/embind/embind.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 205d7fdc2b257..3b6910a88a308 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -876,7 +876,9 @@ var genericPointerToWireType = function(destructors, handle) { return ptr; }; -var nonConstNoSmartPtrRawPointerToWireType = function(destructors, handle) { +// If we know a pointer type is not going to have SmartPtr logic in it, we can +// special-case optimize it a bit (compare to genericPointerToWireType) +var constNoSmartPtrRawPointerToWireType = function(destructors, handle) { if (handle === null) { if (this.isReference) { throwBindingError('null is not a valid ' + this.name); @@ -890,15 +892,14 @@ var nonConstNoSmartPtrRawPointerToWireType = function(destructors, handle) { if (!handle.$$.ptr) { throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); } - if (handle.$$.ptrType.isConst) { - throwBindingError('Cannot convert argument of type ' + handle.$$.ptrType.name + ' to parameter type ' + this.name); - } var handleClass = handle.$$.ptrType.registeredClass; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); return ptr; }; -var constNoSmartPtrRawPointerToWireType = function(destructors, handle) { +// An optimized version for non-const method accesses - there we must additionally restrict that +// the pointer is not a const-pointer. +var nonConstNoSmartPtrRawPointerToWireType = function(destructors, handle) { if (handle === null) { if (this.isReference) { throwBindingError('null is not a valid ' + this.name); @@ -912,6 +913,9 @@ var constNoSmartPtrRawPointerToWireType = function(destructors, handle) { if (!handle.$$.ptr) { throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); } + if (handle.$$.ptrType.isConst) { + throwBindingError('Cannot convert argument of type ' + handle.$$.ptrType.name + ' to parameter type ' + this.name); + } var handleClass = handle.$$.ptrType.registeredClass; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); return ptr; From 905bbbf350aa1dc475873db681d952b085fd940d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 17 Apr 2013 08:25:16 +0300 Subject: [PATCH 481/544] Minor optimizations and notes in genericPointerToWireType. --- src/embind/embind.js | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 3b6910a88a308..c26a463e7ed5f 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -795,17 +795,6 @@ function __embind_finalize_struct(structType) { } var genericPointerToWireType = function(destructors, handle) { - var self = this; - function throwCannotConvert() { - var name; - if (handle.$$.smartPtrType) { - name = handle.$$.smartPtrType.name; - } else { - name = handle.$$.ptrType.name; - } - throwBindingError('Cannot convert argument of type ' + name + ' to parameter type ' + self.name); - } - if (handle === null) { if (this.isReference) { throwBindingError('null is not a valid ' + this.name); @@ -826,27 +815,27 @@ var genericPointerToWireType = function(destructors, handle) { if (!handle.$$.ptr) { throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); } - - // TODO: this is not strictly true - // We could support BY_EMVAL conversions from raw pointers to smart pointers - // because the smart pointer can hold a reference to the handle - if (this.isSmartPointer && undefined === handle.$$.smartPtr) { - throwBindingError('Passing raw pointer to smart pointer is illegal'); - } if (!this.isConst && handle.$$.ptrType.isConst) { - throwCannotConvert(); + throwBindingError('Cannot convert argument of type ' + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + ' to parameter type ' + this.name); } var handleClass = handle.$$.ptrType.registeredClass; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); if (this.isSmartPointer) { + // TODO: this is not strictly true + // We could support BY_EMVAL conversions from raw pointers to smart pointers + // because the smart pointer can hold a reference to the handle + if (undefined === handle.$$.smartPtr) { + throwBindingError('Passing raw pointer to smart pointer is illegal'); + } + switch (this.sharingPolicy) { case 0: // NONE // no upcasting if (handle.$$.smartPtrType === this) { ptr = handle.$$.smartPtr; } else { - throwCannotConvert(); + throwBindingError('Cannot convert argument of type ' + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + ' to parameter type ' + this.name); } break; @@ -960,6 +949,10 @@ function RegisteredPointer( } } else { this.toWireType = genericPointerToWireType; + // Here we must leave this.destructorFunction undefined, since whether genericPointerToWireType returns + // a pointer that needs to be freed up is runtime-dependent, and cannot be evaluated at registration time. + // TODO: Create an alternative mechanism that allows removing the use of var destructors = []; array in + // craftInvokerFunction altogether. } } From f25a4c9d196b5436bf526308cb9d771f3610dd81 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 17 Apr 2013 16:56:41 -0700 Subject: [PATCH 482/544] Add support for read-only properties. --- src/embind/embind.js | 44 +++++++++++++++++++++----------- system/include/emscripten/bind.h | 34 +++++++++++++++++++++++- tests/embind/embind.test.js | 21 +++++++++++++++ tests/embind/embind_test.cpp | 18 +++++++++++-- 4 files changed, 99 insertions(+), 18 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index c26a463e7ed5f..1b8b2456f7dba 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1417,40 +1417,54 @@ function __embind_register_class_property( ) { fieldName = readLatin1String(fieldName); getter = FUNCTION_TABLE[getter]; - setter = FUNCTION_TABLE[setter]; whenDependentTypesAreResolved([], [classType], function(classType) { classType = classType[0]; var humanName = classType.name + '.' + fieldName; - - Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, { + var desc = { get: function() { throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [getterReturnType, setterArgumentType]); }, - set: function() { - throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [getterReturnType, setterArgumentType]); - }, enumerable: true, configurable: true - }); + }; + if (setter) { + desc.set = function() { + throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [getterReturnType, setterArgumentType]); + }; + } else { + desc.set = function(v) { + throwBindingError(humanName + ' is a read-only property'); + }; + } - whenDependentTypesAreResolved([], [getterReturnType, setterArgumentType], function(types) { - var getterReturnType = types[0]; - var setterArgumentType = types[1]; + Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, desc); - Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, { + whenDependentTypesAreResolved( + [], + (setter ? [getterReturnType, setterArgumentType] : [getterReturnType]), + function(types) { + var getterReturnType = types[0]; + var desc = { get: function() { var ptr = validateThis(this, classType, humanName + ' getter'); return getterReturnType.fromWireType(getter(getterContext, ptr)); }, - set: function(v) { + enumerable: true + }; + + if (setter) { + setter = FUNCTION_TABLE[setter]; + var setterArgumentType = types[1]; + desc.set = function(v) { var ptr = validateThis(this, classType, humanName + ' setter'); var destructors = []; setter(setterContext, ptr, setterArgumentType.toWireType(destructors, v)); runDestructors(destructors); - }, - enumerable: true - }); + }; + } + + Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, desc); return []; }); diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index a388603191ae9..0bb212902d8a6 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -991,7 +991,23 @@ namespace emscripten { return *this; } - template + template::value>::type> + class_& property(const char* fieldName, const FieldType ClassType::*field) { + using namespace internal; + + _embind_register_class_property( + TypeID::get(), + fieldName, + TypeID::get(), + reinterpret_cast(&MemberAccess::template getWire), + getContext(field), + 0, + 0, + 0); + return *this; + } + + template::value>::type> class_& property(const char* fieldName, FieldType ClassType::*field) { using namespace internal; @@ -1007,6 +1023,22 @@ namespace emscripten { return *this; } + template + class_& property(const char* fieldName, Getter getter) { + using namespace internal; + typedef GetterPolicy GP; + _embind_register_class_property( + TypeID::get(), + fieldName, + TypeID::get(), + reinterpret_cast(&GP::template get), + GP::getContext(getter), + 0, + 0, + 0); + return *this; + } + template class_& property(const char* fieldName, Getter getter, Setter setter) { using namespace internal; diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 4ad854f47f214..8ef46ad8f9c72 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -916,6 +916,27 @@ module({ c.delete(); }); + test("class properties can be read-only", function() { + var a = {}; + var h = new cm.ValHolder(a); + assert.equal(a, h.val_readonly); + var e = assert.throws(cm.BindingError, function() { + h.val_readonly = 10; + }); + assert.equal('ValHolder.val_readonly is a read-only property', e.message); + h.delete(); + }); + + test("read-only member field", function() { + var a = new cm.HasReadOnlyProperty(10); + assert.equal(10, a.i); + var e = assert.throws(cm.BindingError, function() { + a.i = 20; + }); + assert.equal('HasReadOnlyProperty.i is a read-only property', e.message); + a.delete(); + }); + test("class instance $$ property is non-enumerable", function() { var c = new cm.ValHolder(undefined); assert.deepEqual([], Object.keys(c)); diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 0439c8329638b..7cde8e7f56e48 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -673,8 +673,6 @@ class PolyDerivedFourTimesNotBound: public PolyDerivedThrice { std::string name_; }; -// todo: does it need to be polymorphic? -// todo: virtual diamond pattern class PolyDiamondBase { public: PolyDiamondBase(): @@ -1551,6 +1549,7 @@ EMSCRIPTEN_BINDINGS(tests) { .function("getValConstRef", &ValHolder::getValConstRef) .function("setVal", &ValHolder::setVal) .property("val", &ValHolder::getVal, &ValHolder::setVal) + .property("val_readonly", &ValHolder::getVal) .class_function("makeConst", &ValHolder::makeConst, allow_raw_pointer()) .class_function("makeValHolder", &ValHolder::makeValHolder) .class_function("some_class_method", &ValHolder::some_class_method) @@ -2096,3 +2095,18 @@ EMSCRIPTEN_BINDINGS(noncopyable) { function("getNoncopyable", &getNoncopyable); } + +struct HasReadOnlyProperty { + HasReadOnlyProperty(int i) + : i(i) + {} + + const int i; +}; + +EMSCRIPTEN_BINDINGS(read_only_properties) { + class_("HasReadOnlyProperty") + .constructor() + .property("i", &HasReadOnlyProperty::i) + ; +} From b4cc2e135b1d611fa54c28bf05aada1657c97b30 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 17 Apr 2013 17:28:27 -0700 Subject: [PATCH 483/544] calloperator wasn't pulling its own weight. We probably should have a higher-level register_function though... --- system/include/emscripten/bind.h | 5 ----- tests/embind/embind_test.cpp | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 0bb212902d8a6..cd35a2383c9e5 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -1070,11 +1070,6 @@ namespace emscripten { reinterpret_cast(classMethod)); return *this; } - - template - class_& calloperator(const char* methodName, Policies... policies) { - return function(methodName, &ClassType::operator(), policies...); - } }; //////////////////////////////////////////////////////////////////////////////// diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 7cde8e7f56e48..e969f9d84c070 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1573,7 +1573,7 @@ EMSCRIPTEN_BINDINGS(tests) { class_>("StringFunctorString") .constructor<>() - .calloperator("opcall") + .function("opcall", &std::function::operator()) ; function("emval_test_get_function_ptr", &emval_test_get_function_ptr); From a02d08a15f853665cee193c7f21e84f48bee8845 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 17 Apr 2013 17:51:24 -0700 Subject: [PATCH 484/544] Make select_overload work for member functions --- system/include/emscripten/bind.h | 12 ++++++++++++ tests/embind/embind_test.cpp | 24 +++++++++++++----------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index cd35a2383c9e5..4d2f4ac801e91 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -229,6 +229,18 @@ namespace emscripten { return fn; } + namespace internal { + template + struct MemberFunctionType { + typedef Signature (ClassType::*type); + }; + } + + template + typename internal::MemberFunctionType::type select_overload(Signature (ClassType::*fn)) { + return fn; + } + namespace internal { template struct Invoker { diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index e969f9d84c070..f2359955bc6e4 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1925,8 +1925,8 @@ EMSCRIPTEN_BINDINGS(tests) { function("long_to_string", &long_to_string); function("unsigned_long_to_string", &unsigned_long_to_string); - function("overloaded_function", (int(*)(int))&overloaded_function); - function("overloaded_function", (int(*)(int, int))&overloaded_function); + function("overloaded_function", select_overload(&overloaded_function)); + function("overloaded_function", select_overload(&overloaded_function)); class_("MultipleCtors") .constructor() @@ -1936,19 +1936,21 @@ EMSCRIPTEN_BINDINGS(tests) { class_("MultipleOverloads") .constructor<>() - .function("Func", (int(MultipleOverloads::*)(int))&MultipleOverloads::Func) - .function("Func", (int(MultipleOverloads::*)(int,int))&MultipleOverloads::Func) + .function("Func", select_overload(&MultipleOverloads::Func)) + .function("Func", select_overload(&MultipleOverloads::Func)) .function("WhichFuncCalled", &MultipleOverloads::WhichFuncCalled) - .class_function("StaticFunc", (int(*)(int))&MultipleOverloads::StaticFunc) - .class_function("StaticFunc", (int(*)(int,int))&MultipleOverloads::StaticFunc) - .class_function("WhichStaticFuncCalled", &MultipleOverloads::WhichStaticFuncCalled); + .class_function("StaticFunc", select_overload(&MultipleOverloads::StaticFunc)) + .class_function("StaticFunc", select_overload(&MultipleOverloads::StaticFunc)) + .class_function("WhichStaticFuncCalled", &MultipleOverloads::WhichStaticFuncCalled) + ; class_ >("MultipleOverloadsDerived") .constructor<>() - .function("Func", (int(MultipleOverloadsDerived::*)(int,int,int))&MultipleOverloadsDerived::Func) - .function("Func", (int(MultipleOverloadsDerived::*)(int,int,int,int))&MultipleOverloadsDerived::Func) - .class_function("StaticFunc", (int(*)(int,int,int))&MultipleOverloadsDerived::StaticFunc) - .class_function("StaticFunc", (int(*)(int,int,int,int))&MultipleOverloadsDerived::StaticFunc); + .function("Func", select_overload(&MultipleOverloadsDerived::Func)) + .function("Func", select_overload(&MultipleOverloadsDerived::Func)) + .class_function("StaticFunc", select_overload(&MultipleOverloadsDerived::StaticFunc)) + .class_function("StaticFunc", select_overload(&MultipleOverloadsDerived::StaticFunc)) + ; } // tests for out-of-order registration From 4a6460b255e78529201efe786b57911e76631e19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Apr 2013 11:53:29 +0300 Subject: [PATCH 485/544] Fix embind to work with --closure 1. The symbols fromWireType and toWireType cannot be minified, since they are referred from inside craftInvokerFunction code, which refers to these functions by strings. Also, consistently use 12292 instead of '12292' to have no closure mismatches. --- src/embind/embind.js | 68 ++++++++++++++++---------------- tests/embind/embind.benchmark.js | 44 ++++++++++----------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 1b8b2456f7dba..8bbff9e45c91d 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -267,7 +267,7 @@ function __embind_register_void(rawType, name) { name = readLatin1String(name); registerType(rawType, { name: name, - fromWireType: function() { + 'fromWireType': function() { return undefined; }, }); @@ -277,12 +277,12 @@ function __embind_register_bool(rawType, name, trueValue, falseValue) { name = readLatin1String(name); registerType(rawType, { name: name, - fromWireType: function(wt) { + 'fromWireType': function(wt) { // ambiguous emscripten ABI: sometimes return values are // true or false, and sometimes integers (0 or 1) return !!wt; }, - toWireType: function(destructors, o) { + 'toWireType': function(destructors, o) { return o ? trueValue : falseValue; }, destructorFunction: null, // This type does not need a destructor @@ -300,10 +300,10 @@ function __embind_register_integer(primitiveType, name, minRange, maxRange) { name: name, minRange: minRange, maxRange: maxRange, - fromWireType: function(value) { + 'fromWireType': function(value) { return value; }, - toWireType: function(destructors, value) { + 'toWireType': function(destructors, value) { // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: we could // avoid the following two if()s and assume value is of proper type. if (typeof value !== "number") { @@ -322,10 +322,10 @@ function __embind_register_float(rawType, name) { name = readLatin1String(name); registerType(rawType, { name: name, - fromWireType: function(value) { + 'fromWireType': function(value) { return value; }, - toWireType: function(destructors, value) { + 'toWireType': function(destructors, value) { // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: we could // avoid the following if() and assume value is of proper type. if (typeof value !== "number") { @@ -341,7 +341,7 @@ function __embind_register_std_string(rawType, name) { name = readLatin1String(name); registerType(rawType, { name: name, - fromWireType: function(value) { + 'fromWireType': function(value) { var length = HEAPU32[value >> 2]; var a = new Array(length); for (var i = 0; i < length; ++i) { @@ -350,7 +350,7 @@ function __embind_register_std_string(rawType, name) { _free(value); return a.join(''); }, - toWireType: function(destructors, value) { + 'toWireType': function(destructors, value) { if (value instanceof ArrayBuffer) { value = new Uint8Array(value); } @@ -405,7 +405,7 @@ function __embind_register_std_wstring(rawType, charSize, name) { } registerType(rawType, { name: name, - fromWireType: function(value) { + 'fromWireType': function(value) { var length = HEAPU32[value >> 2]; var a = new Array(length); var start = (value + 4) >> shift; @@ -415,7 +415,7 @@ function __embind_register_std_wstring(rawType, charSize, name) { _free(value); return a.join(''); }, - toWireType: function(destructors, value) { + 'toWireType': function(destructors, value) { // assumes 4-byte alignment var length = value.length; var ptr = _malloc(4 + length * charSize); @@ -437,12 +437,12 @@ function __embind_register_emval(rawType, name) { name = readLatin1String(name); registerType(rawType, { name: name, - fromWireType: function(handle) { + 'fromWireType': function(handle) { var rv = _emval_handle_array[handle].value; __emval_decref(handle); return rv; }, - toWireType: function(destructors, value) { + 'toWireType': function(destructors, value) { return __emval_register(value); }, destructorFunction: null, // This type does not need a destructor @@ -656,18 +656,18 @@ function __embind_finalize_tuple(rawTupleType) { var setter = elt.setter; var setterContext = elt.setterContext; elt.read = function(ptr) { - return getterReturnType.fromWireType(getter(getterContext, ptr)); + return getterReturnType['fromWireType'](getter(getterContext, ptr)); }; elt.write = function(ptr, o) { var destructors = []; - setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o)); + setter(setterContext, ptr, setterArgumentType['toWireType'](destructors, o)); runDestructors(destructors); }; }); return [{ name: reg.name, - fromWireType: function(ptr) { + 'fromWireType': function(ptr) { var rv = new Array(elementsLength); for (var i = 0; i < elementsLength; ++i) { rv[i] = elements[i].read(ptr); @@ -675,7 +675,7 @@ function __embind_finalize_tuple(rawTupleType) { rawDestructor(ptr); return rv; }, - toWireType: function(destructors, o) { + 'toWireType': function(destructors, o) { if (elementsLength !== o.length) { throw new TypeError("Incorrect number of tuple elements"); } @@ -751,12 +751,12 @@ function __embind_finalize_struct(structType) { var setterContext = field.setterContext; fields[fieldName] = { read: function(ptr) { - return getterReturnType.fromWireType( + return getterReturnType['fromWireType']( getter(getterContext, ptr)); }, write: function(ptr, o) { var destructors = []; - setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o)); + setter(setterContext, ptr, setterArgumentType['toWireType'](destructors, o)); runDestructors(destructors); } }; @@ -764,7 +764,7 @@ function __embind_finalize_struct(structType) { return [{ name: reg.name, - fromWireType: function(ptr) { + 'fromWireType': function(ptr) { var rv = {}; for (var i in fields) { rv[i] = fields[i].read(ptr); @@ -772,7 +772,7 @@ function __embind_finalize_struct(structType) { rawDestructor(ptr); return rv; }, - toWireType: function(destructors, o) { + 'toWireType': function(destructors, o) { // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: // assume all fields are present without checking. for (var fieldName in fields) { @@ -941,14 +941,14 @@ function RegisteredPointer( if (!isSmartPointer && registeredClass.baseClass === undefined) { if (isConst) { - this.toWireType = constNoSmartPtrRawPointerToWireType; + this['toWireType'] = constNoSmartPtrRawPointerToWireType; this.destructorFunction = null; } else { - this.toWireType = nonConstNoSmartPtrRawPointerToWireType; + this['toWireType'] = nonConstNoSmartPtrRawPointerToWireType; this.destructorFunction = null; } } else { - this.toWireType = genericPointerToWireType; + this['toWireType'] = genericPointerToWireType; // Here we must leave this.destructorFunction undefined, since whether genericPointerToWireType returns // a pointer that needs to be freed up is runtime-dependent, and cannot be evaluated at registration time. // TODO: Create an alternative mechanism that allows removing the use of var destructors = []; array in @@ -969,7 +969,7 @@ RegisteredPointer.prototype.destructor = function(ptr) { } }; -RegisteredPointer.prototype.fromWireType = function(ptr) { +RegisteredPointer.prototype['fromWireType'] = function(ptr) { // ptr is a raw pointer (or a raw smartpointer) // rawPointer is a maybe-null raw pointer @@ -1040,7 +1040,7 @@ function makeClassHandle(prototype, record) { } record.count = { value: 1 }; return Object.create(prototype, { - '$$': { + $$: { value: record, }, }); @@ -1060,7 +1060,7 @@ ClassHandle.prototype.clone = function() { } var clone = Object.create(Object.getPrototypeOf(this), { - '$$': { + $$: { value: shallowCopy(this.$$), } }); @@ -1253,13 +1253,13 @@ function __embind_register_class_constructor( var args = new Array(argCount); args[0] = rawConstructor; for (var i = 1; i < argCount; ++i) { - args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]); + args[i] = argTypes[i]['toWireType'](destructors, arguments[i - 1]); } var ptr = invoker.apply(null, args); runDestructors(destructors); - return argTypes[0].fromWireType(ptr); + return argTypes[0]['fromWireType'](ptr); }; return []; }); @@ -1448,7 +1448,7 @@ function __embind_register_class_property( var desc = { get: function() { var ptr = validateThis(this, classType, humanName + ' getter'); - return getterReturnType.fromWireType(getter(getterContext, ptr)); + return getterReturnType['fromWireType'](getter(getterContext, ptr)); }, enumerable: true }; @@ -1459,7 +1459,7 @@ function __embind_register_class_property( desc.set = function(v) { var ptr = validateThis(this, classType, humanName + ' setter'); var destructors = []; - setter(setterContext, ptr, setterArgumentType.toWireType(destructors, v)); + setter(setterContext, ptr, setterArgumentType['toWireType'](destructors, v)); runDestructors(destructors); }; } @@ -1533,10 +1533,10 @@ function __embind_register_enum( registerType(rawType, { name: name, constructor: constructor, - fromWireType: function(c) { + 'fromWireType': function(c) { return this.constructor.values[c]; }, - toWireType: function(destructors, c) { + 'toWireType': function(destructors, c) { return c.value; }, destructorFunction: null, @@ -1566,7 +1566,7 @@ function __embind_register_constant(name, type, value) { name = readLatin1String(name); whenDependentTypesAreResolved([], [type], function(type) { type = type[0]; - Module[name] = type.fromWireType(value); + Module[name] = type['fromWireType'](value); return []; }); } diff --git a/tests/embind/embind.benchmark.js b/tests/embind/embind.benchmark.js index f0f6e078e36c2..2d1cd3cfe73f8 100644 --- a/tests/embind/embind.benchmark.js +++ b/tests/embind/embind.benchmark.js @@ -19,23 +19,23 @@ function _increment_counter_benchmark_js(N) { } function _increment_class_counter_benchmark_embind_js(N) { - var foo = new Module.Foo(); + var foo = new Module['Foo'](); var a = _emscripten_get_now(); for(i = 0; i < N; ++i) { - foo.incr_class_counter(); - foo.incr_class_counter(); - foo.incr_class_counter(); - foo.incr_class_counter(); - foo.incr_class_counter(); - foo.incr_class_counter(); - foo.incr_class_counter(); - foo.incr_class_counter(); - foo.incr_class_counter(); - foo.incr_class_counter(); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); + foo['incr_class_counter'](); } var b = _emscripten_get_now(); - Module.print("JS embind increment_class_counter " + N + " iters: " + (b-a)*1000 + " msecs. result: " + foo.class_counter_val()); - foo.delete(); + Module.print("JS embind increment_class_counter " + N + " iters: " + (b-a)*1000 + " msecs. result: " + foo['class_counter_val']()); + foo['delete'](); } function _returns_input_benchmark_js() { @@ -181,20 +181,20 @@ function _move_gameobjects_benchmark_embind_js() { var a = _emscripten_get_now(); for(i = 0; i < N; ++i) { - var t = objects[i].GetTransform(); - var pos = Module.add(t.GetPosition(), [2, 0, 1]); - var rot = Module.add(t.GetRotation(), [0.1, 0.2, 0.3]); - t.SetPosition(pos); - t.SetRotation(rot); - t.delete(); + var t = objects[i]['GetTransform'](); + var pos = Module['add'](t['GetPosition'](), [2, 0, 1]); + var rot = Module['add'](t['GetRotation'](), [0.1, 0.2, 0.3]); + t['SetPosition'](pos); + t['SetRotation'](rot); + t['delete'](); } var b = _emscripten_get_now(); var accum = [0,0,0]; for(i = 0; i < N; ++i) { - var t = objects[i].GetTransform(); - accum = Module.add(Module.add(accum, t.GetPosition()), t.GetRotation()); - t.delete(); + var t = objects[i]['GetTransform'](); + accum = Module['add'](Module['add'](accum, t['GetPosition']()), t['GetRotation']()); + t['delete'](); } Module.print("JS embind move_gameobjects " + N + " iters: " + 1000*(b-a) + " msecs. Result: " + (accum[0] + accum[1] + accum[2])); From d8a9592f22453faa7577e9c0bf8ab3446da89241 Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Thu, 18 Apr 2013 13:13:30 +0300 Subject: [PATCH 486/544] Suppress jslint false positives. --- src/embind/embind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 8bbff9e45c91d..988526b4853bd 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -4,7 +4,7 @@ /*global readLatin1String*/ /*global __emval_register, _emval_handle_array, __emval_decref*/ /*global ___getTypeName*/ - +/*jslint sub:true*/ /* The symbols 'fromWireType' and 'toWireType' must be accessed via array notation to be closure-safe since craftInvokerFunction crafts functions as strings that can't be closured. */ var InternalError = Module.InternalError = extendError(Error, 'InternalError'); var BindingError = Module.BindingError = extendError(Error, 'BindingError'); var UnboundTypeError = Module.UnboundTypeError = extendError(BindingError, 'UnboundTypeError'); From d1a4bcfa384c2d309a589b6d8cdfa0398e2a48f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Apr 2013 20:42:51 +0300 Subject: [PATCH 487/544] Make all paths of emscripten_get_now() return msecs. --- src/library_browser.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/library_browser.js b/src/library_browser.js index 6922c42f18597..85eb93f7fc6a3 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -706,10 +706,10 @@ mergeInto(LibraryManager.library, { emscripten_get_now: function() { if (ENVIRONMENT_IS_NODE) { var t = process['hrtime'](); - return t[0] + t[1] / 1e9; + return t[0] * 1e3 + t[1] / 1e6; } else if (window['performance'] && window['performance']['now']) { - return window['performance']['now']() / 1000.0; + return window['performance']['now'](); } else { return Date.now(); } From 52ffac8de7b9cdf3643871985e1c864238d355b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Apr 2013 20:33:59 +0300 Subject: [PATCH 488/544] Make embind benchmarks read emscripten_get_now() in msecs. --- tests/embind/embind.benchmark.js | 20 ++++++++++---------- tests/embind/embind_benchmark.cpp | 14 +++++++------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/embind/embind.benchmark.js b/tests/embind/embind.benchmark.js index 2d1cd3cfe73f8..4ce9355c9ec6c 100644 --- a/tests/embind/embind.benchmark.js +++ b/tests/embind/embind.benchmark.js @@ -15,7 +15,7 @@ function _increment_counter_benchmark_js(N) { } var b = _emscripten_get_now(); var ctr2 = _get_counter(); - Module.print("JS increment_counter " + N + " iters: " + (b-a)*1000 + " msecs. result: " + (ctr2-ctr)); + Module.print("JS increment_counter " + N + " iters: " + (b-a) + " msecs. result: " + (ctr2-ctr)); } function _increment_class_counter_benchmark_embind_js(N) { @@ -34,7 +34,7 @@ function _increment_class_counter_benchmark_embind_js(N) { foo['incr_class_counter'](); } var b = _emscripten_get_now(); - Module.print("JS embind increment_class_counter " + N + " iters: " + (b-a)*1000 + " msecs. result: " + foo['class_counter_val']()); + Module.print("JS embind increment_class_counter " + N + " iters: " + (b-a) + " msecs. result: " + foo['class_counter_val']()); foo['delete'](); } @@ -54,7 +54,7 @@ function _returns_input_benchmark_js() { t += _returns_input(i); } var b = _emscripten_get_now(); - Module.print("JS returns_input 100000 iters: " + (b-a)*1000 + " msecs. result: " + t); + Module.print("JS returns_input 100000 iters: " + (b-a) + " msecs. result: " + t); } function _sum_int_benchmark_js() { @@ -73,7 +73,7 @@ function _sum_int_benchmark_js() { r += _sum_int(i, 2, 3, 4, 5, 6, 7, 8, 9); } var b = _emscripten_get_now(); - Module.print("JS sum_int 100000 iters: " + (b-a)*1000 + " msecs. result: " + r); + Module.print("JS sum_int 100000 iters: " + (b-a) + " msecs. result: " + r); } function _sum_float_benchmark_js() { @@ -92,7 +92,7 @@ function _sum_float_benchmark_js() { r += _sum_float(i, 2, 3, 4, 5, 6, 7, 8, 9); } var b = _emscripten_get_now(); - Module.print("JS sum_float 100000 iters: " + (b-a)*1000 + " msecs. result: " + r); + Module.print("JS sum_float 100000 iters: " + (b-a) + " msecs. result: " + r); } function _increment_counter_benchmark_embind_js(N) { @@ -112,7 +112,7 @@ function _increment_counter_benchmark_embind_js(N) { } var b = _emscripten_get_now(); var ctr2 = _get_counter(); - Module.print("JS embind increment_counter " + N + " iters: " + (b-a)*1000 + " msecs. result: " + (ctr2-ctr)); + Module.print("JS embind increment_counter " + N + " iters: " + (b-a) + " msecs. result: " + (ctr2-ctr)); } function _returns_input_benchmark_embind_js() { @@ -131,7 +131,7 @@ function _returns_input_benchmark_embind_js() { t += Module['returns_input'](i); } var b = _emscripten_get_now(); - Module.print("JS embind returns_input 100000 iters: " + (b-a)*1000 + " msecs. result: " + t); + Module.print("JS embind returns_input 100000 iters: " + (b-a) + " msecs. result: " + t); } function _sum_int_benchmark_embind_js() { @@ -150,7 +150,7 @@ function _sum_int_benchmark_embind_js() { r += Module['sum_int'](i, 2, 3, 4, 5, 6, 7, 8, 9); } var b = _emscripten_get_now(); - Module.print("JS embind sum_int 100000 iters: " + (b-a)*1000 + " msecs. result: " + r); + Module.print("JS embind sum_int 100000 iters: " + (b-a) + " msecs. result: " + r); } function _sum_float_benchmark_embind_js() { @@ -169,7 +169,7 @@ function _sum_float_benchmark_embind_js() { r += Module['sum_float'](i, 2, 3, 4, 5, 6, 7, 8, 9); } var b = _emscripten_get_now(); - Module.print("JS embind sum_float 100000 iters: " + (b-a)*1000 + " msecs. result: " + r); + Module.print("JS embind sum_float 100000 iters: " + (b-a) + " msecs. result: " + r); } function _move_gameobjects_benchmark_embind_js() { @@ -197,5 +197,5 @@ function _move_gameobjects_benchmark_embind_js() { t['delete'](); } - Module.print("JS embind move_gameobjects " + N + " iters: " + 1000*(b-a) + " msecs. Result: " + (accum[0] + accum[1] + accum[2])); + Module.print("JS embind move_gameobjects " + N + " iters: " + (b-a) + " msecs. Result: " + (accum[0] + accum[1] + accum[2])); } diff --git a/tests/embind/embind_benchmark.cpp b/tests/embind/embind_benchmark.cpp index 8ce33bc8729c6..80abc7e72d26e 100644 --- a/tests/embind/embind_benchmark.cpp +++ b/tests/embind/embind_benchmark.cpp @@ -175,7 +175,7 @@ void __attribute__((noinline)) emscripten_get_now_benchmark(int N) emscripten_get_now(); } volatile float t2 = emscripten_get_now(); - printf("C++ emscripten_get_now %d iters: %f msecs.\n", N, 1000.f*(t2-t)); + printf("C++ emscripten_get_now %d iters: %f msecs.\n", N, (t2-t)); } void __attribute__((noinline)) increment_counter_benchmark(int N) @@ -195,7 +195,7 @@ void __attribute__((noinline)) increment_counter_benchmark(int N) increment_counter(); } volatile float t2 = emscripten_get_now(); - printf("C++ increment_counter %d iters: %f msecs.\n", N, 1000.f*(t2-t)); + printf("C++ increment_counter %d iters: %f msecs.\n", N, (t2-t)); } void __attribute__((noinline)) increment_class_counter_benchmark(int N) @@ -216,7 +216,7 @@ void __attribute__((noinline)) increment_class_counter_benchmark(int N) foo.incr_class_counter(); } volatile float t2 = emscripten_get_now(); - printf("C++ increment_class_counter %d iters: %f msecs. result: %d\n", N, 1000.f*(t2-t), foo.class_counter); + printf("C++ increment_class_counter %d iters: %f msecs. result: %d\n", N, (t2-t), foo.class_counter); } void __attribute__((noinline)) returns_input_benchmark() @@ -237,7 +237,7 @@ void __attribute__((noinline)) returns_input_benchmark() r += returns_input(i); } volatile float t2 = emscripten_get_now(); - printf("C++ returns_input 100000 iters: %f msecs.\n", 1000.f*(t2-t)); + printf("C++ returns_input 100000 iters: %f msecs.\n", (t2-t)); } void __attribute__((noinline)) sum_int_benchmark() @@ -258,7 +258,7 @@ void __attribute__((noinline)) sum_int_benchmark() r += sum_int(i,2,3,4,5,6,7,8,9); } volatile float t2 = emscripten_get_now(); - printf("C++ sum_int 100000 iters: %f msecs.\n", 1000.f*(t2-t)); + printf("C++ sum_int 100000 iters: %f msecs.\n", (t2-t)); } void __attribute__((noinline)) sum_float_benchmark() @@ -279,7 +279,7 @@ void __attribute__((noinline)) sum_float_benchmark() f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); } volatile float t2 = emscripten_get_now(); - printf("C++ sum_float 100000 iters: %f msecs.\n", 1000.f*(t2-t)); + printf("C++ sum_float 100000 iters: %f msecs.\n", (t2-t)); } void __attribute__((noinline)) move_gameobjects_benchmark() @@ -303,7 +303,7 @@ void __attribute__((noinline)) move_gameobjects_benchmark() Vec3 accum; for(int i = 0; i < N; ++i) accum = add(add(accum, objects[i]->GetTransform()->GetPosition()), objects[i]->GetTransform()->GetRotation()); - printf("C++ move_gameobjects %d iters: %f msecs. Result: %f\n", N, 1000.f*(t2-t), accum.x+accum.y+accum.z); + printf("C++ move_gameobjects %d iters: %f msecs. Result: %f\n", N, (t2-t), accum.x+accum.y+accum.z); } int main() From d45afdc6f7ffae61c5c9137761529da2841af20d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 18 Apr 2013 11:31:41 -0700 Subject: [PATCH 489/544] be more flexible in check for keeping std* as low values; cttz/ctlz can add 512 bytes to initial allocations --- src/library.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library.js b/src/library.js index 11f30a1cdb782..ee01abcda1676 100644 --- a/src/library.js +++ b/src/library.js @@ -573,7 +573,7 @@ LibraryManager.library = { eof: false, ungotten: [] }; - assert(Math.max(_stdin, _stdout, _stderr) < 128); // make sure these are low, we flatten arrays with these + assert(Math.max(_stdin, _stdout, _stderr) < 1024); // make sure these are low, we flatten arrays with these {{{ makeSetValue(makeGlobalUse('_stdin'), 0, 1, 'void*') }}}; {{{ makeSetValue(makeGlobalUse('_stdout'), 0, 2, 'void*') }}}; {{{ makeSetValue(makeGlobalUse('_stderr'), 0, 3, 'void*') }}}; From d9173c5dfb0c58a7d5be96f1e4615cefd77f6f43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Apr 2013 21:32:50 +0300 Subject: [PATCH 490/544] Restore -O2 test on other.test_embind - works ok. --- tests/runner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 7619e85fb9ab7..b3d995bffbabe 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -10243,8 +10243,8 @@ def test_embind(self): for args, fail in [ ([], True), # without --bind, we fail (['--bind'], False), - (['--bind', '-O1'], False) - # XXX TODO (['--bind', '-O2'], False) + (['--bind', '-O1'], False), + (['--bind', '-O2'], False) ]: print args, fail self.clear() From c25999057ddc122981d00dae8b52df5985b8dc5c Mon Sep 17 00:00:00 2001 From: Arlo Breault Date: Thu, 18 Apr 2013 14:11:23 -0700 Subject: [PATCH 491/544] Just return op not supported. See #1060 --- src/library.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/library.js b/src/library.js index 2e24a462ef2c3..c8205d2b5a555 100644 --- a/src/library.js +++ b/src/library.js @@ -7395,17 +7395,12 @@ LibraryManager.library = { } }, - socketpair__deps: ['__setErrNo', '$ERRNO_CODES', 'pipe'], + socketpair__deps: ['__setErrNo', '$ERRNO_CODES'], socketpair: function(domain, type, protocol, sv) { // int socketpair(int domain, int type, int protocol, int sv[2]); - // http://sources.iwp9.org/files/plan9/sys/src/ape/lib/bsd/socketpair.c - switch (domain) { - case {{{ cDefine('PF_UNIX') }}}: - return _pipe(sv); - default: - ___setErrNo(ERRNO_CODES.EOPNOTSUPP); - return -1; - } + // http://pubs.opengroup.org/onlinepubs/009695399/functions/socketpair.html + ___setErrNo(ERRNO_CODES.EOPNOTSUPP); + return -1; }, // pty.h From c0074e01ac06a66faf3e9d91f1cecb4ff02c7ee9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 18 Apr 2013 20:20:55 -0700 Subject: [PATCH 492/544] setjmp support for asm.js --- emscripten.py | 8 ++- src/analyzer.js | 16 ++--- src/jsifier.js | 44 ++++++++++---- src/library.js | 60 +++++++++++++++++++ src/preamble.js | 2 + src/settings.js | 1 + ...{longjmp_tiny_noasm.ll => longjmp_tiny.ll} | 0 ...ongjmp_tiny_noasm.txt => longjmp_tiny.txt} | 0 8 files changed, 110 insertions(+), 21 deletions(-) rename tests/cases/{longjmp_tiny_noasm.ll => longjmp_tiny.ll} (100%) rename tests/cases/{longjmp_tiny_noasm.txt => longjmp_tiny.txt} (100%) diff --git a/emscripten.py b/emscripten.py index 6e5f1e7cccca8..0fa6ac30d6495 100755 --- a/emscripten.py +++ b/emscripten.py @@ -426,7 +426,7 @@ def asm_coerce(value, sig): try { %sModule.dynCall_%s(%s); } catch(e) { - asm.setThrew(1); + asm.setThrew(1, 0); } } ''' % (sig, args, 'return ' if sig[0] != 'v' else '', sig, args) @@ -489,6 +489,8 @@ def math_fix(g): var HEAPF64 = new global.Float64Array(buffer); ''' % (asm_setup,) + '\n' + asm_global_vars + ''' var __THREW__ = 0; + var threwValue = 0; + var setjmpId = 0; var undef = 0; var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0; ''' + ''.join([''' @@ -509,9 +511,11 @@ def math_fix(g): top = top|0; STACKTOP = top; } - function setThrew(threw) { + function setThrew(threw, value) { threw = threw|0; + value = value|0; __THREW__ = threw; + threwValue = value; } ''' + ''.join([''' function setTempRet%d(value) { diff --git a/src/analyzer.js b/src/analyzer.js index df5a435e52254..3278139b2ffe0 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -1389,21 +1389,21 @@ function analyzer(data, sidePass) { var line = label.lines[j]; if ((line.intertype == 'call' || line.intertype == 'invoke') && line.ident == setjmp) { // Add a new label - var oldIdent = label.ident; - var newIdent = func.labelIdCounter++; + var oldLabel = label.ident; + var newLabel = func.labelIdCounter++; if (!func.setjmpTable) func.setjmpTable = []; - func.setjmpTable.push([oldIdent, newIdent, line.assignTo]); + func.setjmpTable.push({ oldLabel: oldLabel, newLabel: newLabel, assignTo: line.assignTo }); func.labels.splice(i+1, 0, { intertype: 'label', - ident: newIdent, + ident: newLabel, lineNum: label.lineNum + 0.5, lines: label.lines.slice(j+1) }); - func.labelsDict[newIdent] = func.labels[i+1]; + func.labelsDict[newLabel] = func.labels[i+1]; label.lines = label.lines.slice(0, j+1); label.lines.push({ intertype: 'branch', - label: toNiceIdent(newIdent), + label: toNiceIdent(newLabel), lineNum: line.lineNum + 0.01, // XXX legalizing might confuse this }); // Correct phis @@ -1412,8 +1412,8 @@ function analyzer(data, sidePass) { if (phi.intertype == 'phi') { for (var i = 0; i < phi.params.length; i++) { var sourceLabelId = getActualLabelId(phi.params[i].label); - if (sourceLabelId == oldIdent) { - phi.params[i].label = newIdent; + if (sourceLabelId == oldLabel) { + phi.params[i].label = newLabel; } } } diff --git a/src/jsifier.js b/src/jsifier.js index a4dd797bd26a8..7086922cf225c 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -701,18 +701,22 @@ function JSify(data, functionsOnly, givenFunctions) { ret += indent + 'label = ' + getLabelId(block.entries[0]) + '; ' + (SHOW_LABELS ? '/* ' + getOriginalLabelId(block.entries[0]) + ' */' : '') + '\n'; } // otherwise, should have been set before! if (func.setjmpTable) { - assert(!ASM_JS, 'asm.js mode does not support setjmp yet'); - var setjmpTable = {}; - ret += indent + 'var mySetjmpIds = {};\n'; - ret += indent + 'var setjmpTable = {'; - func.setjmpTable.forEach(function(triple) { // original label, label we created for right after the setjmp, variable setjmp result goes into - ret += '"' + getLabelId(triple[0]) + '": ' + 'function(value) { label = ' + getLabelId(triple[1]) + '; ' + triple[2] + ' = value },'; - }); - ret += 'dummy: 0'; - ret += '};\n'; + if (!ASM_JS) { + var setjmpTable = {}; + ret += indent + 'var mySetjmpIds = {};\n'; + ret += indent + 'var setjmpTable = {'; + func.setjmpTable.forEach(function(triple) { // original label, label we created for right after the setjmp, variable setjmp result goes into + ret += '"' + getLabelId(triple.oldLabel) + '": ' + 'function(value) { label = ' + getLabelId(triple.newLabel) + '; ' + triple.assignTo + ' = value },'; + }); + ret += 'dummy: 0'; + ret += '};\n'; + } else { + ret += 'var setjmpLabel = 0;\n'; + ret += 'var setjmpTable = ' + RuntimeGenerator.stackAlloc(4 * (MAX_SETJMPS + 1) * 2) + ';\n'; + } } ret += indent + 'while(1) '; - if (func.setjmpTable) { + if (func.setjmpTable && !ASM_JS) { ret += 'try { '; } ret += 'switch(' + asmCoercion('label', 'i32') + ') {\n'; @@ -720,9 +724,19 @@ function JSify(data, functionsOnly, givenFunctions) { return indent + ' case ' + getLabelId(label.ident) + ': ' + (SHOW_LABELS ? '// ' + getOriginalLabelId(label.ident) : '') + '\n' + getLabelLines(label, indent + ' '); }).join('\n') + '\n'; + if (func.setjmpTable && ASM_JS) { + // emit a label in which we write to the proper local variable, before jumping to the actual label + ret += ' case -1111: '; + ret += func.setjmpTable.map(function(triple) { // original label, label we created for right after the setjmp, variable setjmp result goes into + return 'if ((setjmpLabel|0) == ' + getLabelId(triple.oldLabel) + ') { ' + triple.assignTo + ' = threwValue; label = ' + triple.newLabel + ' }\n'; + }).join(' else '); + if (ASSERTIONS) ret += 'else abort(-3);\n'; + ret += '__THREW__ = threwValue = 0;\n'; + ret += 'break;\n'; + } if (ASSERTIONS) ret += indent + ' default: assert(0' + (ASM_JS ? '' : ', "bad label: " + label') + ');\n'; ret += indent + '}\n'; - if (func.setjmpTable) { + if (func.setjmpTable && !ASM_JS) { ret += ' } catch(e) { if (!e.longjmp || !(e.id in mySetjmpIds)) throw(e); setjmpTable[setjmpLabels[e.id]](e.value) }'; } } else { @@ -1301,6 +1315,8 @@ function JSify(data, functionsOnly, givenFunctions) { // We cannot compile assembly. See comment in intertyper.js:'Call' assert(ident != 'asm', 'Inline assembly cannot be compiled to JavaScript!'); + if (ASM_JS && funcData.setjmpTable) forceByPointer = true; // in asm.js mode, we must do an invoke for each call + ident = Variables.resolveAliasToIdent(ident); var shortident = ident.slice(1); var simpleIdent = shortident; @@ -1455,6 +1471,12 @@ function JSify(data, functionsOnly, givenFunctions) { ret += '; return 0'; // special case: abort() can happen without return, breaking the return type of asm functions. ensure a return } } + + if (ASM_JS && funcData.setjmpTable) { + // check if a longjmp was done + ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) > 0)) { setjmpLabel = _testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable); if ((setjmpLabel|0) > 0) { label = -1111; break } } __THREW__ = threwValue = 0;\n'; + } + return ret; } makeFuncLineActor('getelementptr', function(item) { return finalizeLLVMFunctionCall(item) }); diff --git a/src/library.js b/src/library.js index ee01abcda1676..95aa2ede661f3 100644 --- a/src/library.js +++ b/src/library.js @@ -6217,13 +6217,73 @@ LibraryManager.library = { // related functionality so the slowdown is more limited. // ========================================================================== + saveSetjmp__asm: true, + saveSetjmp__sig: 'iii', + saveSetjmp: function(env, label, table) { + // Not particularly fast: slow table lookup of setjmpId to label. But setjmp + // prevents relooping anyhow, so slowness is to be expected. And typical case + // is 1 setjmp per invocation, or less. + env = env|0; + label = label|0; + table = table|0; + var i = 0; +#if ASSERTIONS + if ((label|0) == 0) abort(121); +#endif + setjmpId = (setjmpId+1)|0; + {{{ makeSetValueAsm('env', '0', 'setjmpId', 'i32') }}}; + while ((i|0) < {{{ MAX_SETJMPS }}}) { + if ({{{ makeGetValueAsm('table', 'i*4', 'i32') }}} == 0) { + {{{ makeSetValueAsm('table', 'i*4', 'setjmpId', 'i32') }}}; + {{{ makeSetValueAsm('table', 'i*4+4', 'label', 'i32') }}}; + // prepare next slot + {{{ makeSetValueAsm('table', 'i*4+8', '0', 'i32') }}}; + return 0; + } + i = (i+2)|0; + } + abort(987); // if you hit this, adjust MAX_SETJMPS + return 0; + }, + + testSetjmp__asm: true, + testSetjmp__sig: 'iii', + testSetjmp: function(id, table) { + id = id|0; + table = table|0; + var i = 0, curr = 0; + while ((i|0) < {{{ MAX_SETJMPS }}}) { + curr = {{{ makeGetValueAsm('table', 'i', 'i32') }}}; + if ((curr|0) == 0) break; + if ((curr|0) == (id|0)) { + return {{{ makeGetValueAsm('table', 'i+1', 'i32') }}}; + } + i = (i+2)|0; + } + return 0; + }, + +#if ASM_JS + setjmp__deps: ['saveSetjmp', 'testSetjmp'], +#endif setjmp__inline: function(env) { // Save the label +#if ASM_JS + return '_saveSetjmp(' + env + ', label, setjmpTable)'; +#else return '(tempInt = setjmpId++, mySetjmpIds[tempInt] = 1, setjmpLabels[tempInt] = label,' + makeSetValue(env, '0', 'tempInt', 'i32', undefined, undefined, undefined, undefined, ',') + ', 0)'; +#endif }, +#if ASM_JS + longjmp__deps: ['saveSetjmp', 'testSetjmp'], +#endif longjmp: function(env, value) { +#if ASM_JS + asm.setThrew(env, value || 1); +#else throw { longjmp: true, id: {{{ makeGetValue('env', '0', 'i32') }}}, value: value || 1 }; +#endif }, // ========================================================================== diff --git a/src/preamble.js b/src/preamble.js index 592363f91966c..17b74cd9ecbe9 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -217,8 +217,10 @@ var START_TIME = Date.now(); //======================================== var __THREW__ = 0; // Used in checking for thrown exceptions. +#if ASM_JS == 0 var setjmpId = 1; // Used in setjmp/longjmp var setjmpLabels = {}; +#endif var ABORT = false; diff --git a/src/settings.js b/src/settings.js index 8f31c2d896bfd..db24cca4f8d4c 100644 --- a/src/settings.js +++ b/src/settings.js @@ -55,6 +55,7 @@ var ALLOW_MEMORY_GROWTH = 0; // If false, we abort with an error if we try to al // that case we must be careful about optimizations, in particular the // eliminator). Note that memory growth is only supported with typed // arrays. +var MAX_SETJMPS = 10; // size of setjmp table allocated in each function invocation (that has setjmp) // Code embetterments var MICRO_OPTS = 1; // Various micro-optimizations, like nativizing variables diff --git a/tests/cases/longjmp_tiny_noasm.ll b/tests/cases/longjmp_tiny.ll similarity index 100% rename from tests/cases/longjmp_tiny_noasm.ll rename to tests/cases/longjmp_tiny.ll diff --git a/tests/cases/longjmp_tiny_noasm.txt b/tests/cases/longjmp_tiny.txt similarity index 100% rename from tests/cases/longjmp_tiny_noasm.txt rename to tests/cases/longjmp_tiny.txt From 544b922fd0059996989cc8aa12237d97bf5125bb Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 18 Apr 2013 21:04:54 -0700 Subject: [PATCH 493/544] throw in longjmp, do not overwrite previous throw data in setThrew, and enable test_longjmp in asm --- emscripten.py | 6 ++++-- src/library.js | 1 + tests/runner.py | 2 -- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/emscripten.py b/emscripten.py index 0fa6ac30d6495..6d384a964809c 100755 --- a/emscripten.py +++ b/emscripten.py @@ -514,8 +514,10 @@ def math_fix(g): function setThrew(threw, value) { threw = threw|0; value = value|0; - __THREW__ = threw; - threwValue = value; + if ((__THREW__|0) == 0) { + __THREW__ = threw; + threwValue = value; + } } ''' + ''.join([''' function setTempRet%d(value) { diff --git a/src/library.js b/src/library.js index 95aa2ede661f3..f9ed3ee636e51 100644 --- a/src/library.js +++ b/src/library.js @@ -6281,6 +6281,7 @@ LibraryManager.library = { longjmp: function(env, value) { #if ASM_JS asm.setThrew(env, value || 1); + throw 'longjmp'; #else throw { longjmp: true, id: {{{ makeGetValue('env', '0', 'i32') }}}, value: value || 1 }; #endif diff --git a/tests/runner.py b/tests/runner.py index b3d995bffbabe..f6614048fcbb0 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -2310,8 +2310,6 @@ def test_assert(self): self.do_run(src, 'Assertion failed: 1 == false') def test_longjmp(self): - if Settings.ASM_JS: return self.skip('asm does not support longjmp') - src = r''' #include #include From 93e4ae68d6263556f6bd2dfd4ffc9f1377ada7ce Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 18 Apr 2013 21:07:16 -0700 Subject: [PATCH 494/544] enable test_longjmp4 in asm --- tests/runner.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index f6614048fcbb0..fd8fce20f6dda 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -2443,8 +2443,6 @@ def test_longjmp3(self): ''') def test_longjmp4(self): - if Settings.ASM_JS: return self.skip('asm does not support longjmp') - src = r''' #include #include From 5bdc1a5bab4a14a9970fb53be603989a57a3a67b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 18 Apr 2013 21:39:22 -0700 Subject: [PATCH 495/544] exit to caller when setjmp encounters an id that is not ours; enable test_longjmp2 and 3 in asm --- src/jsifier.js | 5 +++-- src/library.js | 4 ++-- tests/runner.py | 4 ---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 7086922cf225c..ea1289c606fd7 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1473,8 +1473,9 @@ function JSify(data, functionsOnly, givenFunctions) { } if (ASM_JS && funcData.setjmpTable) { - // check if a longjmp was done - ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) > 0)) { setjmpLabel = _testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable); if ((setjmpLabel|0) > 0) { label = -1111; break } } __THREW__ = threwValue = 0;\n'; + // check if a longjmp was done. If a setjmp happened, check if ours. If ours, go to -111 to handle it. + // otherwise, just return - the call to us must also have been an invoke, so the setjmp propagates that way + ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) > 0)) { setjmpLabel = _testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable); if ((setjmpLabel|0) > 0) { label = -1111; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;\n'; } return ret; diff --git a/src/library.js b/src/library.js index f9ed3ee636e51..2663512d88263 100644 --- a/src/library.js +++ b/src/library.js @@ -6253,10 +6253,10 @@ LibraryManager.library = { table = table|0; var i = 0, curr = 0; while ((i|0) < {{{ MAX_SETJMPS }}}) { - curr = {{{ makeGetValueAsm('table', 'i', 'i32') }}}; + curr = {{{ makeGetValueAsm('table', 'i*4', 'i32') }}}; if ((curr|0) == 0) break; if ((curr|0) == (id|0)) { - return {{{ makeGetValueAsm('table', 'i+1', 'i32') }}}; + return {{{ makeGetValueAsm('table', 'i*4+4', 'i32') }}}; } i = (i+2)|0; } diff --git a/tests/runner.py b/tests/runner.py index fd8fce20f6dda..60b670f7d2cf4 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -2341,8 +2341,6 @@ def test_longjmp(self): self.do_run(src, 'second\nmain: 1\n') def test_longjmp2(self): - if Settings.ASM_JS: return self.skip('asm does not support longjmp') - src = r''' #include #include @@ -2389,8 +2387,6 @@ def test_longjmp2(self): ''') def test_longjmp3(self): - if Settings.ASM_JS: return self.skip('asm does not support longjmp') - src = r''' #include #include From 67f9270a2022a70c0e4ed19b2b6c4a86ae658fcc Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 18 Apr 2013 21:41:28 -0700 Subject: [PATCH 496/544] enable tests/cases/*longjmp* for asm --- .../{longjmp_tiny_noasm_invoke.ll => longjmp_tiny_invoke.ll} | 0 .../{longjmp_tiny_noasm_invoke.txt => longjmp_tiny_invoke.txt} | 0 tests/cases/{longjmp_tiny_phi_noasm.ll => longjmp_tiny_phi.ll} | 0 tests/cases/{longjmp_tiny_phi_noasm.txt => longjmp_tiny_phi.txt} | 0 tests/cases/{longjmp_tiny_phi2_noasm.ll => longjmp_tiny_phi2.ll} | 0 .../cases/{longjmp_tiny_phi2_noasm.txt => longjmp_tiny_phi2.txt} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename tests/cases/{longjmp_tiny_noasm_invoke.ll => longjmp_tiny_invoke.ll} (100%) rename tests/cases/{longjmp_tiny_noasm_invoke.txt => longjmp_tiny_invoke.txt} (100%) rename tests/cases/{longjmp_tiny_phi_noasm.ll => longjmp_tiny_phi.ll} (100%) rename tests/cases/{longjmp_tiny_phi_noasm.txt => longjmp_tiny_phi.txt} (100%) rename tests/cases/{longjmp_tiny_phi2_noasm.ll => longjmp_tiny_phi2.ll} (100%) rename tests/cases/{longjmp_tiny_phi2_noasm.txt => longjmp_tiny_phi2.txt} (100%) diff --git a/tests/cases/longjmp_tiny_noasm_invoke.ll b/tests/cases/longjmp_tiny_invoke.ll similarity index 100% rename from tests/cases/longjmp_tiny_noasm_invoke.ll rename to tests/cases/longjmp_tiny_invoke.ll diff --git a/tests/cases/longjmp_tiny_noasm_invoke.txt b/tests/cases/longjmp_tiny_invoke.txt similarity index 100% rename from tests/cases/longjmp_tiny_noasm_invoke.txt rename to tests/cases/longjmp_tiny_invoke.txt diff --git a/tests/cases/longjmp_tiny_phi_noasm.ll b/tests/cases/longjmp_tiny_phi.ll similarity index 100% rename from tests/cases/longjmp_tiny_phi_noasm.ll rename to tests/cases/longjmp_tiny_phi.ll diff --git a/tests/cases/longjmp_tiny_phi_noasm.txt b/tests/cases/longjmp_tiny_phi.txt similarity index 100% rename from tests/cases/longjmp_tiny_phi_noasm.txt rename to tests/cases/longjmp_tiny_phi.txt diff --git a/tests/cases/longjmp_tiny_phi2_noasm.ll b/tests/cases/longjmp_tiny_phi2.ll similarity index 100% rename from tests/cases/longjmp_tiny_phi2_noasm.ll rename to tests/cases/longjmp_tiny_phi2.ll diff --git a/tests/cases/longjmp_tiny_phi2_noasm.txt b/tests/cases/longjmp_tiny_phi2.txt similarity index 100% rename from tests/cases/longjmp_tiny_phi2_noasm.txt rename to tests/cases/longjmp_tiny_phi2.txt From d1806a5165e6599cc9a0ad741f1cc4fd866e3054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Apr 2013 09:36:14 +0300 Subject: [PATCH 497/544] Improve error reporting in build_library. --- tools/shared.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/shared.py b/tools/shared.py index d5a37c038aa03..d1049842f026c 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -732,13 +732,13 @@ def open_make_err(i, mode='r'): basename = os.path.basename(f) cache[cache_name].append((basename, open(f, 'rb').read())) break - except: + except Exception, e: if i > 0: # Due to the ugly hack above our best guess is to output the first run with open_make_err(0) as ferr: for line in ferr: sys.stderr.write(line) - raise Exception('could not build library ' + name) + raise Exception('could not build library ' + name + ' due to exception ' + str(e)) if old_dir: os.chdir(old_dir) return generated_libs From 5986269bda083c99b3c684048e5d0834918a1a2d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 18 Apr 2013 13:22:41 -0700 Subject: [PATCH 498/544] always hardcode arguments in benchmarks --- tests/runner.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 60b670f7d2cf4..aa2e1dc1989c9 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -12099,8 +12099,7 @@ def do_benchmark(self, name, src, args=[], expected_output='FAIL', emcc_args=[], '-o', final_filename] + shared_args + emcc_args, stdout=PIPE, stderr=self.stderr_redirect).communicate() assert os.path.exists(final_filename), 'Failed to compile file: ' + output[0] - if self.save_JS: - self.hardcode_arguments(final_filename, args) + self.hardcode_arguments(final_filename, args) # Run JS global total_times, tests_done From 95e3ccbcb7bd802e1b4287d3fc964deda75dd73c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 10:07:30 -0700 Subject: [PATCH 499/544] properly clear __THREW__ in asm exceptions --- src/jsifier.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jsifier.js b/src/jsifier.js index ea1289c606fd7..a01b2655225e3 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1200,7 +1200,7 @@ function JSify(data, functionsOnly, givenFunctions) { } item.reloopingJS = ret; // everything but the actual branching (which the relooper will do for us) item.toLabelJS = getPhiSetsForLabel(phiSets, item.toLabel); - item.unwindLabelJS = getPhiSetsForLabel(phiSets, item.unwindLabel); + item.unwindLabelJS = (ASM_JS ? '__THREW__ = 0;' : '') + getPhiSetsForLabel(phiSets, item.unwindLabel); ret += 'if (!__THREW__) { ' + item.toLabelJS + makeBranch(item.toLabel, item.currLabelId) + ' } else { ' + item.unwindLabelJS + makeBranch(item.unwindLabel, item.currLabelId) + ' }'; return ret; From 8dc4fc973b3a938dadad13273196cd857b90030e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 10:40:11 -0700 Subject: [PATCH 500/544] enable ASM_JS=1 in -O1+, and start to update testing --- emcc | 2 +- tests/runner.py | 12 +++++++----- tools/shared.py | 1 + 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/emcc b/emcc index e25d9d917943c..147776aede2a3 100755 --- a/emcc +++ b/emcc @@ -163,7 +163,7 @@ Most normal gcc/g++ options will work, for example: Options that are modified or new in %s include: -O0 No optimizations (default) - -O1 Simple optimizations, including LLVM -O1 + -O1 Simple optimizations, including asm.js, LLVM -O1 optimizations, and no runtime assertions or C++ exception catching (to re-enable C++ exception catching, use diff --git a/tests/runner.py b/tests/runner.py index aa2e1dc1989c9..86f1fab932cad 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -7394,6 +7394,8 @@ def test_lua(self): extra_emscripten_args=['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/langinfo.h,libc/time.h']) def get_freetype(self): + Settings.DEAD_FUNCTIONS += ['_inflateEnd', '_inflate', '_inflateReset', '_inflateInit2_'] + return self.get_library('freetype', os.path.join('objs', '.libs', 'libfreetype.a')) @@ -8988,15 +8990,15 @@ def setUp(self): exec('default = make_run("default", compiler=CLANG, emcc_args=[])') # Make one run with -O1, with safe heap - exec('o1 = make_run("o1", compiler=CLANG, emcc_args=["-O1", "-s", "SAFE_HEAP=1"])') + exec('o1 = make_run("o1", compiler=CLANG, emcc_args=["-O1", "-s", "ASM_JS=0", "-s", "SAFE_HEAP=1"])') # Make one run with -O2, but without closure (we enable closure in specific tests, otherwise on everything it is too slow) - exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "-s", "JS_CHUNK_SIZE=1024"])') + exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=0", "-s", "JS_CHUNK_SIZE=1024"])') # asm.js - exec('asm1 = make_run("asm1", compiler=CLANG, emcc_args=["-O1", "-s", "ASM_JS=1"])') - exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1"])') - exec('asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1"])') + exec('asm1 = make_run("asm1", compiler=CLANG, emcc_args=["-O1"])') + exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2"])') + exec('asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1"])') # Make custom runs with various options for compiler, quantum, embetter, typed_arrays, llvm_opts in [ diff --git a/tools/shared.py b/tools/shared.py index eedb2e8b9ed6c..d2891943f9c4e 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -564,6 +564,7 @@ def serialize(self): @classmethod def apply_opt_level(self, opt_level, noisy=False): if opt_level >= 1: + Settings.ASM_JS = 1 Settings.ASSERTIONS = 0 Settings.DISABLE_EXCEPTION_CATCHING = 1 Settings.EMIT_GENERATED_FUNCTIONS = 1 From f173cd3457a8ed0689662afd7008b6c906a983c2 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 10:47:36 -0700 Subject: [PATCH 501/544] disable asm.js when using embind --- emcc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/emcc b/emcc index 147776aede2a3..aaaab53ea72f7 100755 --- a/emcc +++ b/emcc @@ -1004,6 +1004,10 @@ try: if shared.Settings.ASM_JS: assert opt_level >= 1, 'asm.js requires -O1 or above' + if bind: + shared.Settings.ASM_JS = 0 + print >> sys.stderr, 'emcc: warning: disabling asm.js because it is not compatible with embind yet' + if closure: print >> sys.stderr, 'emcc: warning: disabling closure because it is not compatible with asm.js code generation' closure = False From 1d1924ccc9d32513c2b0fa7f10444371472ebc89 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 11:09:22 -0700 Subject: [PATCH 502/544] update tests --- emcc | 1 - tests/runner.py | 27 ++++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/emcc b/emcc index aaaab53ea72f7..5d22129a28d5e 100755 --- a/emcc +++ b/emcc @@ -1007,7 +1007,6 @@ try: if bind: shared.Settings.ASM_JS = 0 print >> sys.stderr, 'emcc: warning: disabling asm.js because it is not compatible with embind yet' - if closure: print >> sys.stderr, 'emcc: warning: disabling closure because it is not compatible with asm.js code generation' closure = False diff --git a/tests/runner.py b/tests/runner.py index 86f1fab932cad..924e53d2bc92d 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -9135,19 +9135,19 @@ def test_emcc(self): (['-o', 'something.js'], 0, None, 0, 1), (['-o', 'something.js', '-O0'], 0, None, 0, 0), (['-o', 'something.js', '-O1'], 1, None, 0, 0), - (['-o', 'something.js', '-O1', '--closure', '1'], 1, None, 1, 0), + (['-o', 'something.js', '-O1', '-g'], 1, None, 0, 0), + (['-o', 'something.js', '-O1', '--closure', '1'], 1, None, 0, 0), # no closure when asm.js is on + (['-o', 'something.js', '-O1', '--closure', '1', '-s', 'ASM_JS=0'], 1, None, 1, 0), (['-o', 'something.js', '-O2'], 2, None, 0, 1), - (['-o', 'something.js', '-O2', '--closure', '0'], 2, None, 0, 0), (['-o', 'something.js', '-O2', '-g'], 2, None, 0, 0), (['-o', 'something.js', '-Os'], 2, None, 0, 1), - (['-o', 'something.js', '-O3'], 3, None, 1, 1), - (['-o', 'something.js', '-O3', '--closure', '0'], 3, None, 0, 0), + (['-o', 'something.js', '-O3', '-s', 'ASM_JS=0'], 3, None, 1, 1), # and, test compiling to bitcode first (['-o', 'something.bc'], 0, [], 0, 0), (['-o', 'something.bc'], 0, ['-O0'], 0, 0), (['-o', 'something.bc'], 1, ['-O1'], 0, 0), (['-o', 'something.bc'], 2, ['-O2'], 0, 0), - (['-o', 'something.bc'], 3, ['-O3'], 1, 0), + (['-o', 'something.bc'], 3, ['-O3', '-s', 'ASM_JS=0'], 1, 0), (['-O1', '-o', 'something.bc'], 0, [], 0, 0), # -Ox is ignored and warned about ]: print params, opt_level, bc_params, closure, has_malloc @@ -9178,23 +9178,23 @@ def test_emcc(self): # closure has not been run, we can do some additional checks. TODO: figure out how to do these even with closure assert 'Module._main = ' not in generated, 'closure compiler should not have been run' if keep_debug: - assert ('(label)' in generated) == (opt_level <= 1), 'relooping should be in opt >= 2' + assert ('(label)' in generated or '(label | 0)' in generated) == (opt_level <= 1), 'relooping should be in opt >= 2' assert ('assert(STACKTOP < STACK_MAX' in generated) == (opt_level == 0), 'assertions should be in opt == 0' - assert 'var $i;' in generated or 'var $i_0' in generated or 'var $storemerge3;' in generated or 'var $storemerge4;' in generated or 'var $i_04;' in generated, 'micro opts should always be on' - if opt_level >= 2: + assert 'var $i;' in generated or 'var $i_0' in generated or 'var $storemerge3;' in generated or 'var $storemerge4;' in generated or 'var $i_04;' in generated or 'var $original = 0' in generated, 'micro opts should always be on' + if opt_level >= 2 and '-g' in params: assert re.search('HEAP8\[\$?\w+ ?\+ ?\(+\$?\w+ ?', generated) or re.search('HEAP8\[HEAP32\[', generated), 'eliminator should create compound expressions, and fewer one-time vars' # also in -O1, but easier to test in -O2 assert ('_puts(' in generated) == (opt_level >= 1), 'with opt >= 1, llvm opts are run and they should optimize printf to puts' if opt_level <= 1 or '-g' in params: assert 'function _main() {' in generated, 'Should be unminified, including whitespace' - elif opt_level >= 2: assert 'function _main(){' in generated, 'Should be whitespace-minified' + elif opt_level >= 2: assert ('function _main(){' in generated or '"use asm";var a=' in generated), 'Should be whitespace-minified' # emcc -s RELOOP=1 src.cpp ==> should pass -s to emscripten.py. --typed-arrays is a convenient alias for -s USE_TYPED_ARRAYS for params, test, text in [ - (['-s', 'ASM_JS=1', '-O2'], lambda generated: 'var b=0' in generated and not 'function _main' in generated, 'registerize/minify is run by default in -O2'), - (['-s', 'ASM_JS=1', '-O2', '--minify', '0'], lambda generated: 'var b = 0' in generated and not 'function _main' in generated, 'minify is cancelled, but not registerize'), - (['-s', 'ASM_JS=1', '-O2', '-g'], lambda generated: 'var b=0' not in generated and 'var b = 0' not in generated and 'function _main' in generated, 'registerize/minify is cancelled by -g'), + (['-O2'], lambda generated: 'var b=0' in generated and not 'function _main' in generated, 'registerize/minify is run by default in -O2'), + (['-O2', '--minify', '0'], lambda generated: 'var b = 0' in generated and not 'function _main' in generated, 'minify is cancelled, but not registerize'), + (['-O2', '-g'], lambda generated: 'var b=0' not in generated and 'var b = 0' not in generated and 'function _main' in generated, 'registerize/minify is cancelled by -g'), (['-s', 'INLINING_LIMIT=0'], lambda generated: 'function _dump' in generated, 'no inlining without opts'), (['-O3', '-s', 'INLINING_LIMIT=0', '--closure', '0'], lambda generated: 'function _dump' not in generated, 'lto/inlining'), - (['-Os', '--llvm-lto', '1'], lambda generated: 'function _dump' in generated, '-Os disables inlining'), + (['-Os', '--llvm-lto', '1', '-s', 'ASM_JS=0'], lambda generated: 'function _dump' in generated, '-Os disables inlining'), (['-s', 'USE_TYPED_ARRAYS=0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'), (['-s', 'USE_TYPED_ARRAYS=1'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'), ([], lambda generated: 'Module["_dump"]' not in generated, 'dump is not exported by default'), @@ -9204,6 +9204,7 @@ def test_emcc(self): (['--typed-arrays', '2'], lambda generated: 'new Uint16Array' in generated and 'new Uint32Array' in generated, 'typed arrays 2 selected'), (['--llvm-opts', '1'], lambda generated: '_puts(' in generated, 'llvm opts requested'), ]: + print params, text self.clear() output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world_loop.cpp'), '-o', 'a.out.js'] + params, stdout=PIPE, stderr=PIPE).communicate() assert len(output[0]) == 0, output[0] From 87c1af8ca6842681fbba7e45b520eae8fd12926f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 11:14:24 -0700 Subject: [PATCH 503/544] use power of two heap in relooper --- tools/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index d2891943f9c4e..6b5ad835a8f05 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -1163,7 +1163,7 @@ def make(opt_level): Building.emcc(os.path.join('relooper', 'Relooper.cpp'), ['-I' + os.path.join('relooper'), '--post-js', os.path.join('relooper', 'emscripten', 'glue.js'), '--memory-init-file', '0', - '-s', 'TOTAL_MEMORY=52428800', + '-s', 'TOTAL_MEMORY=67108864', '-s', 'EXPORTED_FUNCTIONS=["_rl_set_output_buffer","_rl_make_output_buffer","_rl_new_block","_rl_delete_block","_rl_block_add_branch_to","_rl_new_relooper","_rl_delete_relooper","_rl_relooper_add_block","_rl_relooper_calculate","_rl_relooper_render", "_rl_set_asm_js_mode"]', '-s', 'DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=["memcpy", "memset", "malloc", "free", "puts"]', '-s', 'RELOOPER="' + relooper + '"', From 5d4bbcfac43472bd5cf63f810f25d91ae15d00f2 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 11:14:34 -0700 Subject: [PATCH 504/544] update test_closure_compiler --- tests/runner.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 924e53d2bc92d..624cf70dccdfd 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -12524,13 +12524,13 @@ def test_closure_compiler(self): f = open(CONFIG_FILE, 'a') f.write('CLOSURE_COMPILER = "/tmp/nowhere/nothingtoseehere/kjadsfkjwelkjsdfkqgas/nonexistent.txt"\n') f.close() - output = self.check_working([EMCC, '-O2', '--closure', '1', 'tests/hello_world.cpp'], CLOSURE_FATAL) + output = self.check_working([EMCC, '-O2', '-s', 'ASM_JS=0', '--closure', '1', 'tests/hello_world.cpp'], CLOSURE_FATAL) # With a working path, all is well restore() try_delete('a.out.js') - output = self.check_working([EMCC, '-O2', '--closure', '1', 'tests/hello_world.cpp'], '') - assert os.path.exists('a.out.js') + output = self.check_working([EMCC, '-O2', '-s', 'ASM_JS=0', '--closure', '1', 'tests/hello_world.cpp'], '') + assert os.path.exists('a.out.js'), output def test_llvm(self): LLVM_WARNING = 'warning: LLVM version appears incorrect' From e21902e6aa7241eb5854e0037051f1032c9377dd Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 11:19:12 -0700 Subject: [PATCH 505/544] update test_relooper --- tests/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runner.py b/tests/runner.py index 624cf70dccdfd..af36a8f318fa0 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -12789,7 +12789,7 @@ def test_relooper(self): print >> sys.stderr, phase, i opt = min(i, 2) try_delete('a.out.js') - output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_loop.cpp'), '-O' + str(opt)], + output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_loop.cpp'), '-O' + str(opt), '-g'], stdout=PIPE, stderr=PIPE).communicate() self.assertContained('hello, world!', run_js('a.out.js')) output = '\n'.join(output) From 1d128c1bccf76703941262712f309a565ca01fcf Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 11:21:45 -0700 Subject: [PATCH 506/544] update test_jcache --- tests/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runner.py b/tests/runner.py index af36a8f318fa0..8114338fcd0bc 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -12841,7 +12841,7 @@ def test_jcache(self): (['--jcache'], 'hello_malloc.cpp', False, True, False, True, False, True, []), ([], 'hello_malloc.cpp', False, False, False, False, False, False, []), # new, huge file - ([], 'hello_libcxx.cpp', False, False, False, False, False, False, ('3 chunks',)), + ([], 'hello_libcxx.cpp', False, False, False, False, False, False, ('4 chunks',)), (['--jcache'], 'hello_libcxx.cpp', True, False, True, False, True, False, []), (['--jcache'], 'hello_libcxx.cpp', False, True, False, True, False, True, []), ([], 'hello_libcxx.cpp', False, False, False, False, False, False, []), From 797935a8e8a99c3e5b885d42eeea40c42efedd5f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 11:34:13 -0700 Subject: [PATCH 507/544] update browser.test_runtimelink --- tests/runner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 8114338fcd0bc..d754e056b6a43 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -11732,10 +11732,10 @@ def test_runtimelink(self): main, supp = self.setup_runtimelink_test() open(self.in_dir('supp.cpp'), 'w').write(supp) - Popen([PYTHON, EMCC, self.in_dir('supp.cpp'), '-o', 'supp.js', '-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-s', 'BUILD_AS_SHARED_LIB=2', '-O2']).communicate() + Popen([PYTHON, EMCC, self.in_dir('supp.cpp'), '-o', 'supp.js', '-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-s', 'BUILD_AS_SHARED_LIB=2', '-O2', '-s', 'ASM_JS=0']).communicate() shutil.move(self.in_dir('supp.js'), self.in_dir('supp.so')) - self.btest(main, args=['-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-s', 'RUNTIME_LINKED_LIBS=["supp.so"]', '-DBROWSER=1', '-O2'], expected='76') + self.btest(main, args=['-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-s', 'RUNTIME_LINKED_LIBS=["supp.so"]', '-DBROWSER=1', '-O2', '-s', 'ASM_JS=0'], expected='76') def test_pre_run_deps(self): # Adding a dependency in preRun will delay run From 2e49ab9e7cad988adfc0f3c57185ceefa8dcad6d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 11:39:56 -0700 Subject: [PATCH 508/544] fix test_websockets_gethostbyname --- tests/websockets_gethostbyname.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/websockets_gethostbyname.c b/tests/websockets_gethostbyname.c index cba2c6352c347..1580d9a7654f8 100644 --- a/tests/websockets_gethostbyname.c +++ b/tests/websockets_gethostbyname.c @@ -44,7 +44,7 @@ unsigned int get_all_buf(int sock, char* output, unsigned int maxsize) int done = 0; -void iter(void *arg) { +void iter() { /* perform read write operations ... */ static char out[1024*2]; static int pos = 0; @@ -124,7 +124,7 @@ int main(void) #if EMSCRIPTEN emscripten_set_main_loop(iter, 0, 0); #else - while (!done) iter(NULL); + while (!done) iter(); #endif return EXIT_SUCCESS; From ba7a643dcb47b572d7509753e7c3a84625e5ca54 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 11:48:01 -0700 Subject: [PATCH 509/544] fix test_asm_pgo --- tests/runner.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index d754e056b6a43..59b1647f7d5f6 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -8072,11 +8072,13 @@ def test_asm_pgo(self): self.do_run(src, output) shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('normal.js')) - self.emcc_args = map(lambda x: 'ASM_JS=0' if x == 'ASM_JS=1' else x, self.emcc_args) + self.emcc_args.append('-s') + self.emcc_args.append('ASM_JS=0') Settings.PGO = 1 self.do_run(src, output) Settings.PGO = 0 - self.emcc_args = map(lambda x: 'ASM_JS=1' if x == 'ASM_JS=0' else x, self.emcc_args) + self.emcc_args.append('-s') + self.emcc_args.append('ASM_JS=1') shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgo.js')) pgo_output = run_js(self.in_dir('pgo.js')).split('\n')[1] From b047e22b770a01b828e143a83cc5144227d7f70d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 13:55:46 -0700 Subject: [PATCH 510/544] hide embind test output unless an error occurred --- tests/runner.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 59b1647f7d5f6..d7a7003fd557e 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -10250,8 +10250,7 @@ def test_embind(self): assert os.path.exists(self.in_dir('a.out.js')) == (not fail) if not fail: output = run_js(self.in_dir('a.out.js'), stdout=PIPE, stderr=PIPE, full_output=True) - print >> sys.stderr, output - assert "FAIL" not in output + assert "FAIL" not in output, output def test_llvm_nativizer(self): try: From aafdc909660b82b600f6fce2cfda7f0703919b38 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 13:50:52 -0700 Subject: [PATCH 511/544] enable freetype in asm (except for -O1 which hits a js engine bug) --- tests/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runner.py b/tests/runner.py index d7a7003fd557e..868ef9557e500 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -7402,7 +7402,7 @@ def get_freetype(self): def test_freetype(self): if self.emcc_args is None: return self.skip('requires emcc') if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: Figure out and try to fix') - if Settings.ASM_JS: return self.skip('asm does not support longjmp') + if Settings.ASM_JS and '-O2' not in self.emcc_args: return self.skip('mozilla bug 863867') if Settings.CORRECT_SIGNS == 0: Settings.CORRECT_SIGNS = 1 # Not sure why, but needed From 9d883b2df98dd4d5776e798f8b8f1bb4273d705a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 15:13:50 -0700 Subject: [PATCH 512/544] clean up benchmark args --- tests/runner.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 868ef9557e500..532f15a6130eb 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -12097,9 +12097,9 @@ def do_benchmark(self, name, src, args=[], expected_output='FAIL', emcc_args=[], try_delete(final_filename) output = Popen([PYTHON, EMCC, filename, #'-O3', - '-O2', '-s', 'INLINING_LIMIT=0', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0',# '-s', 'EXPLICIT_ZEXT=1', - '-s', 'ASM_JS=1', '-s', 'USE_MATH_IMUL=1', '--llvm-lto', '1', '--memory-init-file', '0', - '-s', 'TOTAL_MEMORY=128*1024*1024', '-s', 'FAST_MEMORY=10*1024*1024', + '-O2', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0', + '--llvm-lto', '1', '--memory-init-file', '0', + '-s', 'TOTAL_MEMORY=128*1024*1024', '-o', final_filename] + shared_args + emcc_args, stdout=PIPE, stderr=self.stderr_redirect).communicate() assert os.path.exists(final_filename), 'Failed to compile file: ' + output[0] From 6943061f656d69a9115b3d368b0d2b8c27011d08 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 15:17:44 -0700 Subject: [PATCH 513/544] add sig for glUniformMatrix2fv --- src/library_gl.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/library_gl.js b/src/library_gl.js index b91d782c47c9a..8923435f19544 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -901,6 +901,7 @@ var LibraryGL = { Module.ctx.uniform4fv(location, view); }, + glUniformMatrix2fv__sig: 'viiii', glUniformMatrix2fv: function(location, count, transpose, value) { location = GL.uniforms[location]; var view; From 9e666300844804758187b15845c32fd24d7fb830 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 15:55:38 -0700 Subject: [PATCH 514/544] add testing for gl in asm2g --- tests/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runner.py b/tests/runner.py index 532f15a6130eb..6b71193936c68 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -11600,7 +11600,7 @@ def test_cubegeom_pre3(self): self.btest('cubegeom_pre3.c', expected=['-1472804742', '-1626058463', '-2046234971']) def test_cubegeom(self): - self.btest('cubegeom.c', expected=['188641320', '1522377227', '-1054007155', '-1111866053']) + self.btest('cubegeom.c', args=['-O2', '-g'], expected=['188641320', '1522377227', '-1054007155', '-1111866053']) def test_cubegeom_color(self): self.btest('cubegeom_color.c', expected=['588472350', '-687660609', '-818120875']) From 9089dc78a6c7fd21be5fc115451996018779dd40 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 16:28:43 -0700 Subject: [PATCH 515/544] add erf dep and testing --- src/library.js | 1 + tests/runner.py | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/library.js b/src/library.js index 1ba4f2fa1c6e3..939da8b1e733f 100644 --- a/src/library.js +++ b/src/library.js @@ -5439,6 +5439,7 @@ LibraryManager.library = { return (ONE_SQRTPI * Math.exp(- x * x) * q2); }, erfcf: 'erfcf', + erf__deps: ['erfc'], erf: function (x) { var MATH_TOLERANCE = 1E-12; var TWO_SQRTPI = 1.128379167095512574; diff --git a/tests/runner.py b/tests/runner.py index 6b71193936c68..c0e16632f8613 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -3056,11 +3056,12 @@ def test_mathfuncptr(self): main(void) { float (*fn)(float) = &sqrtf; float (*fn2)(float) = &fabsf; - printf("fn2(-5) = %d, fn(10) = %f\\n", (int)fn2(-5), fn(10)); + float (*fn3)(float) = &erff; + printf("fn2(-5) = %d, fn(10) = %.2f, erf(10) = %.2f\\n", (int)fn2(-5), fn(10), fn3(10)); return 0; } ''' - self.do_run(src, 'fn2(-5) = 5, fn(10) = 3.16') + self.do_run(src, 'fn2(-5) = 5, fn(10) = 3.16, erf(10) = 1.00') def test_funcptrfunc(self): src = r''' From 31872fbd01ca23962d954ca40232c7b8bfde58fe Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Apr 2013 20:30:03 -0700 Subject: [PATCH 516/544] support for Runtime.addFunction in asm.js --- emscripten.py | 25 +++++++++++++++++++++++-- src/modules.js | 2 +- src/preamble.js | 9 +++++++++ src/runtime.js | 25 +++++++++++++++++++++---- src/settings.js | 3 +++ tests/runner.py | 18 ++++++++++++------ 6 files changed, 69 insertions(+), 13 deletions(-) diff --git a/emscripten.py b/emscripten.py index 6d384a964809c..649b3c0bce476 100755 --- a/emscripten.py +++ b/emscripten.py @@ -303,6 +303,7 @@ def load_from_cache(chunk): # calculations on merged forwarded data forwarded_json['Functions']['indexedFunctions'] = {} i = 2 + if settings['ASM_JS']: i += 2*settings['RESERVED_FUNCTION_POINTERS'] for indexed in indexed_functions: #print >> sys.stderr, 'indaxx', indexed, i forwarded_json['Functions']['indexedFunctions'][indexed] = i # make sure not to modify this python object later - we use it in indexize @@ -379,7 +380,16 @@ def make_table(sig, raw): params = ','.join(['p%d' % p for p in range(len(sig)-1)]) coercions = ';'.join(['p%d = %sp%d%s' % (p, '+' if sig[p+1] != 'i' else '', p, '' if sig[p+1] != 'i' else '|0') for p in range(len(sig)-1)]) + ';' ret = '' if sig[0] == 'v' else ('return %s0' % ('+' if sig[0] != 'i' else '')) - return ('function %s(%s) { %s abort(%d); %s }' % (bad, params, coercions, i, ret), raw.replace('[0,', '[' + bad + ',').replace(',0,', ',' + bad + ',').replace(',0,', ',' + bad + ',').replace(',0]', ',' + bad + ']').replace(',0]', ',' + bad + ']').replace(',0\n', ',' + bad + '\n')) + start = raw.index('[') + end = raw.rindex(']') + body = raw[start+1:end].split(',') + for j in range(settings['RESERVED_FUNCTION_POINTERS']): + body[2 + 2*j] = 'jsCall_%s_%s' % (sig, j) + def fix_item(item): + newline = '\n' in item + return (bad if item.replace('\n', '') == '0' else item) + ('\n' if newline else '') + body = ','.join(map(fix_item, body)) + return ('function %s(%s) { %s abort(%d); %s }' % (bad, params, coercions, i, ret), raw[:start+1] + body + raw[end:]) infos = [make_table(sig, raw) for sig, raw in last_forwarded_json['Functions']['tables'].iteritems()] function_tables_defs = '\n'.join([info[0] for info in infos]) + '\n// EMSCRIPTEN_END_FUNCS\n' + '\n'.join([info[1] for info in infos]) @@ -389,6 +399,7 @@ def make_table(sig, raw): math_envs = ['Math.min'] # TODO: move min to maths asm_setup += '\n'.join(['var %s = %s;' % (f.replace('.', '_'), f) for f in math_envs]) basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat', 'copyTempDouble', 'copyTempFloat'] + [m.replace('.', '_') for m in math_envs] + if settings['RESERVED_FUNCTION_POINTERS'] > 0: basic_funcs.append('jsCall') if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE', 'SAFE_HEAP_CLEAR'] if settings['CHECK_HEAP_ALIGN']: basic_funcs += ['CHECK_ALIGN_2', 'CHECK_ALIGN_4', 'CHECK_ALIGN_8'] basic_vars = ['STACKTOP', 'STACK_MAX', 'tempDoublePtr', 'ABORT'] @@ -404,7 +415,7 @@ def make_table(sig, raw): def asm_coerce(value, sig): if sig == 'v': return value return ('+' if sig != 'i' else '') + value + ('|0' if sig == 'i' else '') - + function_tables = ['dynCall_' + table for table in last_forwarded_json['Functions']['tables']] function_tables_impls = [] for sig in last_forwarded_json['Functions']['tables'].iterkeys(): @@ -419,6 +430,16 @@ def asm_coerce(value, sig): %s; } ''' % (sig, ',' if len(sig) > 1 else '', args, arg_coercions, ret)) + + for i in range(settings['RESERVED_FUNCTION_POINTERS']): + jsret = ('return ' if sig[0] != 'v' else '') + asm_coerce('jsCall(%d%s%s)' % (i, ',' if coerced_args else '', coerced_args), sig[0]) + function_tables_impls.append(''' + function jsCall_%s_%s(%s) { + %s + %s; + } + +''' % (sig, i, args, arg_coercions, jsret)) args = ','.join(['a' + str(i) for i in range(1, len(sig))]) args = 'index' + (',' if args else '') + args asm_setup += ''' diff --git a/src/modules.js b/src/modules.js index 5b5f79477a2cc..7a7698462233b 100644 --- a/src/modules.js +++ b/src/modules.js @@ -234,7 +234,7 @@ var Functions = { unimplementedFunctions: {}, // library etc. functions that we need to index, maps id to signature indexedFunctions: {}, - nextIndex: 2, // Start at a non-0 (even, see below) value + nextIndex: (ASM_JS ? 2*RESERVED_FUNCTION_POINTERS : 0) + 2, // Start at a non-0 (even, see below) value blockAddresses: {}, // maps functions to a map of block labels to label ids diff --git a/src/preamble.js b/src/preamble.js index 17b74cd9ecbe9..92305ca0db48b 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -6,6 +6,15 @@ {{RUNTIME}} +#if ASM_JS +#if RESERVED_FUNCTION_POINTERS +function jsCall() { + var args = Array.prototype.slice.call(arguments); + return Runtime.functionPointers[args[0]].apply(null, args.slice(1)); +} +#endif +#endif + #if BENCHMARK Module.realPrint = Module.print; Module.print = Module.printErr = function(){}; diff --git a/src/runtime.js b/src/runtime.js index 2a26db28e4073..5b9a8134b4e6a 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -305,18 +305,35 @@ var Runtime = { } }, - addFunction: function(func, sig) { - //assert(sig); // TODO: support asm - var table = FUNCTION_TABLE; // TODO: support asm +#if ASM_JS + functionPointers: new Array(RESERVED_FUNCTION_POINTERS), +#endif + + addFunction: function(func) { +#if ASM_JS + for (var i = 0; i < Runtime.functionPointers.length; i++) { + if (!Runtime.functionPointers[i]) { + Runtime.functionPointers[i] = func; + return 2 + 2*i; + } + } + throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.'; +#else + var table = FUNCTION_TABLE; var ret = table.length; table.push(func); table.push(0); return ret; +#endif }, removeFunction: function(index) { - var table = FUNCTION_TABLE; // TODO: support asm +#if ASM_JS + Runtime.functionPointers[(index-2)/2] = null; +#else + var table = FUNCTION_TABLE; table[index] = null; +#endif }, warnOnce: function(text) { diff --git a/src/settings.js b/src/settings.js index db24cca4f8d4c..7cd0c02e26c45 100644 --- a/src/settings.js +++ b/src/settings.js @@ -131,6 +131,9 @@ var CHECK_HEAP_ALIGN = 0; // Check heap accesses for alignment, but don't do as var SAFE_DYNCALLS = 0; // Show stack traces on missing function pointer/virtual method calls +var RESERVED_FUNCTION_POINTERS = 0; // In asm.js mode, we cannot simply add function pointers to + // function tables, so we reserve some slots for them. + var ASM_HEAP_LOG = 0; // Simple heap logging, like SAFE_HEAP_LOG but cheaper, and in asm.js var CORRUPTION_CHECK = 0; // When enabled, will emit a buffer area at the beginning and diff --git a/tests/runner.py b/tests/runner.py index c0e16632f8613..99f24fc951b76 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -8106,9 +8106,9 @@ def test_asm_pgo(self): def test_add_function(self): if self.emcc_args is None: return self.skip('requires emcc') - if Settings.ASM_JS: return self.skip('needs a singleton function table') Settings.INVOKE_RUN = 0 + Settings.RESERVED_FUNCTION_POINTERS = 1 src = r''' #include @@ -8117,21 +8117,27 @@ def test_add_function(self): int main(int argc, char **argv) { int fp = atoi(argv[1]); printf("fp: %d\n", fp); - void (*f)() = reinterpret_cast(fp); - f(); + void (*f)(int) = reinterpret_cast(fp); + f(7); return 0; } ''' open(os.path.join(self.get_dir(), 'post.js'), 'w').write(''' - var newFuncPtr = Runtime.addFunction(function() { - Module.print('Hello from JS!'); + var newFuncPtr = Runtime.addFunction(function(num) { + Module.print('Hello ' + num + ' from JS!'); }); Module.callMain([newFuncPtr.toString()]); ''') self.emcc_args += ['--post-js', 'post.js'] - self.do_run(src, '''Hello from JS!''') + self.do_run(src, '''Hello 7 from JS!''') + + if Settings.ASM_JS: + Settings.RESERVED_FUNCTION_POINTERS = 0 + self.do_run(src, '''Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.''') + generated = open('src.cpp.o.js').read() + assert 'jsCall' not in generated def test_scriptaclass(self): if self.emcc_args is None: return self.skip('requires emcc') From 6f8af49c568abfb3b4203f1d3dc95e12fe573986 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 20 Apr 2013 16:02:42 -0700 Subject: [PATCH 517/544] optimize HEAPU?8[..] << 24 >> 24 and similar --- tools/js-optimizer.js | 36 ++++++++++++++++++----- tools/test-js-optimizer-asm-pre-output.js | 20 +++++++++++++ tools/test-js-optimizer-asm-pre.js | 23 ++++++++++++++- 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 598287db14310..5601f65c42977 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -452,7 +452,16 @@ function simplifyExpressionsPre(ast) { }, null, []); } - // &-related optimizations + // & and heap-related optimizations + + var heapBits, heapUnsigned; + function parseHeap(name) { + if (name.substr(0, 4) != 'HEAP') return false; + heapUnsigned = name[4] == 'U'; + heapBits = parseInt(name.substr(heapUnsigned ? 5 : 4)); + return true; + } + traverseGenerated(ast, function(node, type) { if (type == 'binary' && node[1] == '&' && node[3][0] == 'num') { if (node[2][0] == 'num') return ['num', node[2][1] & node[3][1]]; @@ -465,12 +474,10 @@ function simplifyExpressionsPre(ast) { } else if (input[0] == 'sub' && input[1][0] == 'name') { // HEAP8[..] & 255 => HEAPU8[..] var name = input[1][1]; - if (name.substr(0, 4) == 'HEAP') { - var unsigned = name[4] == 'U'; - var bits = parseInt(name.substr(unsigned ? 5 : 4)); - if (amount == Math.pow(2, bits)-1) { - if (!unsigned) { - input[1][1] = 'HEAPU' + bits; // make unsigned + if (parseHeap(name)) { + if (amount == Math.pow(2, heapBits)-1) { + if (!heapUnsigned) { + input[1][1] = 'HEAPU' + heapBits; // make unsigned } if (asm) { // we cannot return HEAPU8 without a coercion, but at least we do HEAP8 & 255 => HEAPU8 | 0 @@ -482,6 +489,21 @@ function simplifyExpressionsPre(ast) { } } } + } else if (type == 'binary' && node[1] == '>>' && node[3][0] == 'num' && + node[2][0] == 'binary' && node[2][1] == '<<' && node[2][3][0] == 'num' && + node[2][2][0] == 'sub' && node[2][2][1][0] == 'name') { + // collapse HEAPU?8[..] << 24 >> 24 etc. into HEAP8[..] | 0 + var amount = node[3][1]; + var name = node[2][2][1][1]; + if (amount == node[2][3][1] && parseHeap(name)) { + if (heapBits == 32 - amount) { + node[2][2][1][1] = 'HEAP' + heapBits; + node[1] = '|'; + node[2] = node[2][2]; + node[3][1] = 0; + return node; + } + } } }); diff --git a/tools/test-js-optimizer-asm-pre-output.js b/tools/test-js-optimizer-asm-pre-output.js index 53619c84ba6e4..72608aa8ba005 100644 --- a/tools/test-js-optimizer-asm-pre-output.js +++ b/tools/test-js-optimizer-asm-pre-output.js @@ -73,4 +73,24 @@ function retf() { } return +0; } +function i32_8() { + if ((HEAP8[$4 & 16777215] | 0) == 0) { + print(5); + } + if ((HEAP8[$5 & 16777215] | 0) == 0) { + print(5); + } + if ((HEAP8[$6 & 16777215] | 0) == 0) { + print(5); + } + if ((HEAP8[$7 & 16777215] | 0) == 0) { + print(5); + } + if (HEAPU8[$8 & 16777215] << 24 >> 16 == 0) { + print(5); + } + if (HEAPU8[$9 & 16777215] << 16 >> 16 == 0) { + print(5); + } +} diff --git a/tools/test-js-optimizer-asm-pre.js b/tools/test-js-optimizer-asm-pre.js index 0fb7050f96589..f2ffaef453977 100644 --- a/tools/test-js-optimizer-asm-pre.js +++ b/tools/test-js-optimizer-asm-pre.js @@ -74,4 +74,25 @@ function retf() { } // missing final return, need it as a float } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a", "b", "rett", "ret2t", "retf"] +function i32_8() { + if (((HEAP8[$4 & 16777215] | 0) << 24 >> 24) == 0) { + print(5); + } + if ((HEAP8[$5 & 16777215] << 24 >> 24) == 0) { + print(5); + } + if (((HEAPU8[$6 & 16777215] | 0) << 24 >> 24) == 0) { + print(5); + } + if ((HEAPU8[$7 & 16777215] << 24 >> 24) == 0) { + print(5); + } + // non-valid + if ((HEAPU8[$8 & 16777215] << 24 >> 16) == 0) { + print(5); + } + if ((HEAPU8[$9 & 16777215] << 16 >> 16) == 0) { + print(5); + } +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a", "b", "rett", "ret2t", "retf", "i32_8"] From fe8c5821fce322bee6d334aa191baf3f3187d527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sun, 21 Apr 2013 09:11:57 +0300 Subject: [PATCH 518/544] Add new passgameobject_ptr embind benchmark to test smartptr routing in and out of functions. --- tests/embind/embind.benchmark.js | 23 +++++++++++++++++++++++ tests/embind/embind_benchmark.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/tests/embind/embind.benchmark.js b/tests/embind/embind.benchmark.js index 4ce9355c9ec6c..fcbd64ef052a8 100644 --- a/tests/embind/embind.benchmark.js +++ b/tests/embind/embind.benchmark.js @@ -195,7 +195,30 @@ function _move_gameobjects_benchmark_embind_js() { var t = objects[i]['GetTransform'](); accum = Module['add'](Module['add'](accum, t['GetPosition']()), t['GetRotation']()); t['delete'](); + objects[i]['delete'](); } Module.print("JS embind move_gameobjects " + N + " iters: " + (b-a) + " msecs. Result: " + (accum[0] + accum[1] + accum[2])); } + +function _pass_gameobject_ptr_benchmark_embind_js() { + var N = 100000; + var objects = []; + for(i = 0; i < N; ++i) { + objects.push(Module['create_game_object']()); + } + + var a = _emscripten_get_now(); + for(i = 0; i < N; ++i) { + var t = Module['pass_gameobject_ptr'](objects[i]); + t['delete'](); + } + var b = _emscripten_get_now(); + + for(i = 0; i < N; ++i) { + objects[i]['delete'](); + } + + Module.print("JS embind pass_gameobject_ptr " + N + " iters: " + (b-a) + " msecs."); +} + diff --git a/tests/embind/embind_benchmark.cpp b/tests/embind/embind_benchmark.cpp index 80abc7e72d26e..cdfe998c9b839 100644 --- a/tests/embind/embind_benchmark.cpp +++ b/tests/embind/embind_benchmark.cpp @@ -45,6 +45,9 @@ extern void sum_float_benchmark_embind_js(); extern void increment_class_counter_benchmark_embind_js(int N); extern void move_gameobjects_benchmark_embind_js(); + +extern void pass_gameobject_ptr_benchmark(); +extern void pass_gameobject_ptr_benchmark_embind_js(); } class Vec3 @@ -94,6 +97,11 @@ GameObjectPtr create_game_object() return std::make_shared(); } +GameObjectPtr __attribute__((noinline)) pass_gameobject_ptr(GameObjectPtr p) +{ + return p; +} + class Foo { public: @@ -143,6 +151,7 @@ EMSCRIPTEN_BINDINGS(benchmark) .element(&Vec3::z); function("create_game_object", &create_game_object); + function("pass_gameobject_ptr", &pass_gameobject_ptr); function("add", &add); function("get_counter", &get_counter); @@ -306,6 +315,23 @@ void __attribute__((noinline)) move_gameobjects_benchmark() printf("C++ move_gameobjects %d iters: %f msecs. Result: %f\n", N, (t2-t), accum.x+accum.y+accum.z); } +void __attribute__((noinline)) pass_gameobject_ptr_benchmark() +{ + const int N = 100000; + GameObjectPtr objects[N]; + for(int i = 0; i < N; ++i) + objects[i] = create_game_object(); + + volatile float t = emscripten_get_now(); + for(int i = 0; i < N; ++i) + { + objects[i] = pass_gameobject_ptr(objects[i]); + } + volatile float t2 = emscripten_get_now(); + + printf("C++ pass_gameobject_ptr %d iters: %f msecs.\n", N, (t2-t)); +} + int main() { for(int i = 1000; i <= 100000; i *= 10) @@ -341,4 +367,7 @@ int main() printf("\n"); move_gameobjects_benchmark(); move_gameobjects_benchmark_embind_js(); + printf("\n"); + pass_gameobject_ptr_benchmark(); + pass_gameobject_ptr_benchmark_embind_js(); } From 41e2d50e93ce7c2e33e969583ea409c7532859ed Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 14 Apr 2013 23:34:11 +0700 Subject: [PATCH 519/544] Remove unused file. --- system/lib/libc/musl/memcpy.c | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 system/lib/libc/musl/memcpy.c diff --git a/system/lib/libc/musl/memcpy.c b/system/lib/libc/musl/memcpy.c deleted file mode 100644 index 8e98302f3d3f0..0000000000000 --- a/system/lib/libc/musl/memcpy.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include - -#define SS (sizeof(size_t)) -#define ALIGN (sizeof(size_t)-1) -#define ONES ((size_t)-1/UCHAR_MAX) - -void *memcpy(void *restrict dest, const void *restrict src, size_t n) -{ - unsigned char *d = dest; - const unsigned char *s = src; - - if (((uintptr_t)d & ALIGN) != ((uintptr_t)s & ALIGN)) - goto misaligned; - - for (; ((uintptr_t)d & ALIGN) && n; n--) *d++ = *s++; - if (n) { - size_t *wd = (void *)d; - const size_t *ws = (const void *)s; - - for (; n>=SS; n-=SS) *wd++ = *ws++; - d = (void *)wd; - s = (const void *)ws; -misaligned: - for (; n; n--) *d++ = *s++; - } - return dest; -} From 58175e72768f0697e83b91f752c9be533f613c25 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 21 Apr 2013 13:39:34 +0700 Subject: [PATCH 520/544] Let libc.symbols use same symbol format as libcxx. This is just the output of 'llvm-nm -extern-only -defined-only'. --- emcc | 3 +- system/lib/libc.symbols | 162 ++++++++++++++++++++-------------------- 2 files changed, 83 insertions(+), 82 deletions(-) diff --git a/emcc b/emcc index 5d22129a28d5e..fb063799e938a 100755 --- a/emcc +++ b/emcc @@ -1150,7 +1150,8 @@ try: # so all is well anyhow too. # XXX We also need to add libc symbols that use malloc, for example strdup. It's very rare to use just them and not # a normal malloc symbol (like free, after calling strdup), so we haven't hit this yet, but it is possible. - libc_symbols = open(shared.path_from_root('system', 'lib', 'libc.symbols')).read().split('\n') + libc_symbols = map(lambda line: line.strip().split(' ')[1], open(shared.path_from_root('system', 'lib', 'libc.symbols')).readlines()) + libc_symbols = set(libc_symbols) # libcxx def create_libcxx(): diff --git a/system/lib/libc.symbols b/system/lib/libc.symbols index 96e995cf10cd4..1b126abfe6025 100644 --- a/system/lib/libc.symbols +++ b/system/lib/libc.symbols @@ -1,81 +1,81 @@ -_ZNKSt20bad_array_new_length4whatEv -_ZNKSt9bad_alloc4whatEv -_ZNSt20bad_array_new_lengthC1Ev -_ZNSt20bad_array_new_lengthC2Ev -_ZNSt20bad_array_new_lengthD0Ev -_ZNSt20bad_array_new_lengthD1Ev -_ZNSt20bad_array_new_lengthD2Ev -_ZNSt9bad_allocC1Ev -_ZNSt9bad_allocC2Ev -_ZNSt9bad_allocD0Ev -_ZNSt9bad_allocD1Ev -_ZNSt9bad_allocD2Ev -_ZSt15get_new_handlerv -_ZSt15set_new_handlerPFvvE -_ZSt17__throw_bad_allocv -_ZSt7nothrow -_ZTISt20bad_array_new_length -_ZTISt9bad_alloc -_ZTSSt20bad_array_new_length -_ZTSSt9bad_alloc -_ZTVSt20bad_array_new_length -_ZTVSt9bad_alloc -_ZdaPv -_ZdaPvRKSt9nothrow_t -_ZdlPv -_ZdlPvRKSt9nothrow_t -_Znaj -_ZnajRKSt9nothrow_t -_Znwj -_ZnwjRKSt9nothrow_t -_err -_errx -_verr -_verrx -_vwarn -_vwarnx -_warn -_warnx -atof -bulk_free -calloc -err -errx -free -getopt -getopt_long -getopt_long_only -independent_calloc -independent_comalloc -mallinfo -malloc -malloc_footprint -malloc_footprint_limit -malloc_max_footprint -malloc_set_footprint_limit -malloc_stats -malloc_trim -malloc_usable_size -mallopt -memalign -optarg -opterr -optind -optopt -optreset -posix_memalign -pvalloc -realloc -realloc_in_place -strtod -strtod_l -strtof -strtold -strtold_l -valloc -verr -verrx -vwarn -vwarnx -warn1 -warnx + T _ZNKSt20bad_array_new_length4whatEv + T _ZNKSt9bad_alloc4whatEv + T _ZNSt20bad_array_new_lengthC1Ev + T _ZNSt20bad_array_new_lengthC2Ev + T _ZNSt20bad_array_new_lengthD0Ev + ? _ZNSt20bad_array_new_lengthD1Ev + T _ZNSt20bad_array_new_lengthD2Ev + T _ZNSt9bad_allocC1Ev + T _ZNSt9bad_allocC2Ev + T _ZNSt9bad_allocD0Ev + T _ZNSt9bad_allocD1Ev + T _ZNSt9bad_allocD2Ev + T _ZSt15get_new_handlerv + T _ZSt15set_new_handlerPFvvE + T _ZSt17__throw_bad_allocv + D _ZSt7nothrow + D _ZTISt20bad_array_new_length + D _ZTISt9bad_alloc + D _ZTSSt20bad_array_new_length + D _ZTSSt9bad_alloc + D _ZTVSt20bad_array_new_length + D _ZTVSt9bad_alloc + W _ZdaPv + W _ZdaPvRKSt9nothrow_t + W _ZdlPv + W _ZdlPvRKSt9nothrow_t + W _Znaj + W _ZnajRKSt9nothrow_t + W _Znwj + W _ZnwjRKSt9nothrow_t + T _err + T _errx + T _verr + T _verrx + T _vwarn + T _vwarnx + T _warn + T _warnx + T atof + W bulk_free + W calloc + W err + W errx + W free + T getopt + T getopt_long + T getopt_long_only + W independent_calloc + W independent_comalloc + W mallinfo + W malloc + W malloc_footprint + W malloc_footprint_limit + W malloc_max_footprint + W malloc_set_footprint_limit + W malloc_stats + W malloc_trim + T malloc_usable_size + W mallopt + W memalign + C optarg + D opterr + D optind + D optopt + C optreset + W posix_memalign + W pvalloc + W realloc + W realloc_in_place + T strtod + T strtod_l + T strtof + T strtold + T strtold_l + W valloc + W verr + W verrx + W vwarn + W vwarnx + W warn1 + W warnx From b9090fa1f2ba90a5745981d1a4d4108915ddd6e9 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 15 Apr 2013 01:19:23 +0700 Subject: [PATCH 521/544] Add musl wchar function implementations. --- emcc | 39 ++++++- src/library.js | 7 -- system/lib/libc/musl/src/internal/libc.c | 22 ++++ system/lib/libc/musl/src/internal/libc.h | 71 ++++++++++++ system/lib/libc/musl/src/string/wcpcpy.c | 6 + system/lib/libc/musl/src/string/wcpncpy.c | 6 + system/lib/libc/musl/src/string/wcscasecmp.c | 7 ++ .../lib/libc/musl/src/string/wcscasecmp_l.c | 6 + system/lib/libc/musl/src/string/wcscat.c | 7 ++ system/lib/libc/musl/src/string/wcschr.c | 8 ++ system/lib/libc/musl/src/string/wcscmp.c | 7 ++ system/lib/libc/musl/src/string/wcscpy.c | 8 ++ system/lib/libc/musl/src/string/wcscspn.c | 10 ++ system/lib/libc/musl/src/string/wcsdup.c | 11 ++ system/lib/libc/musl/src/string/wcslen.c | 8 ++ system/lib/libc/musl/src/string/wcsncasecmp.c | 9 ++ .../lib/libc/musl/src/string/wcsncasecmp_l.c | 6 + system/lib/libc/musl/src/string/wcsncat.c | 10 ++ system/lib/libc/musl/src/string/wcsncmp.c | 7 ++ system/lib/libc/musl/src/string/wcsncpy.c | 9 ++ system/lib/libc/musl/src/string/wcsnlen.c | 8 ++ system/lib/libc/musl/src/string/wcspbrk.c | 7 ++ system/lib/libc/musl/src/string/wcsrchr.c | 8 ++ system/lib/libc/musl/src/string/wcsspn.c | 8 ++ system/lib/libc/musl/src/string/wcsstr.c | 108 ++++++++++++++++++ system/lib/libc/musl/src/string/wcstok.c | 12 ++ system/lib/libc/musl/src/string/wcswcs.c | 6 + system/lib/libc/musl/src/string/wmemchr.c | 8 ++ system/lib/libc/musl/src/string/wmemcmp.c | 8 ++ system/lib/libc/musl/src/string/wmemcpy.c | 9 ++ system/lib/libc/musl/src/string/wmemmove.c | 12 ++ system/lib/libc/musl/src/string/wmemset.c | 9 ++ 32 files changed, 459 insertions(+), 8 deletions(-) create mode 100644 system/lib/libc/musl/src/internal/libc.c create mode 100644 system/lib/libc/musl/src/internal/libc.h create mode 100644 system/lib/libc/musl/src/string/wcpcpy.c create mode 100644 system/lib/libc/musl/src/string/wcpncpy.c create mode 100644 system/lib/libc/musl/src/string/wcscasecmp.c create mode 100644 system/lib/libc/musl/src/string/wcscasecmp_l.c create mode 100644 system/lib/libc/musl/src/string/wcscat.c create mode 100644 system/lib/libc/musl/src/string/wcschr.c create mode 100644 system/lib/libc/musl/src/string/wcscmp.c create mode 100644 system/lib/libc/musl/src/string/wcscpy.c create mode 100644 system/lib/libc/musl/src/string/wcscspn.c create mode 100644 system/lib/libc/musl/src/string/wcsdup.c create mode 100644 system/lib/libc/musl/src/string/wcslen.c create mode 100644 system/lib/libc/musl/src/string/wcsncasecmp.c create mode 100644 system/lib/libc/musl/src/string/wcsncasecmp_l.c create mode 100644 system/lib/libc/musl/src/string/wcsncat.c create mode 100644 system/lib/libc/musl/src/string/wcsncmp.c create mode 100644 system/lib/libc/musl/src/string/wcsncpy.c create mode 100644 system/lib/libc/musl/src/string/wcsnlen.c create mode 100644 system/lib/libc/musl/src/string/wcspbrk.c create mode 100644 system/lib/libc/musl/src/string/wcsrchr.c create mode 100644 system/lib/libc/musl/src/string/wcsspn.c create mode 100644 system/lib/libc/musl/src/string/wcsstr.c create mode 100644 system/lib/libc/musl/src/string/wcstok.c create mode 100644 system/lib/libc/musl/src/string/wcswcs.c create mode 100644 system/lib/libc/musl/src/string/wmemchr.c create mode 100644 system/lib/libc/musl/src/string/wmemcmp.c create mode 100644 system/lib/libc/musl/src/string/wmemcpy.c create mode 100644 system/lib/libc/musl/src/string/wmemmove.c create mode 100644 system/lib/libc/musl/src/string/wmemset.c diff --git a/emcc b/emcc index fb063799e938a..8c21562b18f84 100755 --- a/emcc +++ b/emcc @@ -1127,11 +1127,48 @@ try: os.path.join('libc', 'stdlib', 'strtod.c'), ]; + musl_files = [ + ['string', [ + 'wcpcpy.c', + 'wcpncpy.c', + 'wcscasecmp.c', + # 'wcscasecmp_l.c', # XXX: alltypes.h issue + 'wcscat.c', + 'wcschr.c', + 'wcscmp.c', + 'wcscpy.c', + 'wcscspn.c', + 'wcsdup.c', + 'wcslen.c', + 'wcsncasecmp.c', + # 'wcsncasecmp_l.c', # XXX: alltypes.h issue + 'wcsncat.c', + 'wcsncmp.c', + 'wcsncpy.c', + 'wcsnlen.c', + 'wcspbrk.c', + 'wcsrchr.c', + 'wcsspn.c', + 'wcsstr.c', + 'wcstok.c', + 'wcswcs.c', + 'wmemchr.c', + 'wmemcmp.c', + 'wmemcpy.c', + 'wmemmove.c', + 'wmemset.c', + ]] + ] + + for directory, sources in musl_files: + libc_files += [os.path.join('libc', 'musl', 'src', directory, source) for source in sources] + prev_cxx = os.environ.get('EMMAKEN_CXX') if prev_cxx: os.environ['EMMAKEN_CXX'] = '' + musl_internal_includes = shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'internal') for src in libc_files: o = in_temp(os.path.basename(src) + '.o') - execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o], stdout=stdout, stderr=stderr) + execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o, '-I', musl_internal_includes], stdout=stdout, stderr=stderr) o_s.append(o) if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx diff --git a/src/library.js b/src/library.js index 939da8b1e733f..bb4d710be75db 100644 --- a/src/library.js +++ b/src/library.js @@ -4243,8 +4243,6 @@ LibraryManager.library = { return ret|0; }, - wmemcpy: function() { throw 'wmemcpy not implemented' }, - llvm_memcpy_i32: 'memcpy', llvm_memcpy_i64: 'memcpy', llvm_memcpy_p0i8_p0i8_i32: 'memcpy', @@ -4274,8 +4272,6 @@ LibraryManager.library = { llvm_memmove_p0i8_p0i8_i32: 'memmove', llvm_memmove_p0i8_p0i8_i64: 'memmove', - wmemmove: function() { throw 'wmemmove not implemented' }, - memset__inline: function(ptr, value, num, align) { return makeSetValues(ptr, 0, value, 'null', num, align); }, @@ -4316,8 +4312,6 @@ LibraryManager.library = { llvm_memset_p0i8_i32: 'memset', llvm_memset_p0i8_i64: 'memset', - wmemset: function() { throw 'wmemset not implemented' }, - strlen__sig: 'ii', strlen__asm: true, strlen: function(ptr) { @@ -4335,7 +4329,6 @@ LibraryManager.library = { return 1; }, - wcslen: function() { throw 'wcslen not implemented' }, mbrlen: function() { throw 'mbrlen not implemented' }, mbsrtowcs: function() { throw 'mbsrtowcs not implemented' }, wcsnrtombs: function() { throw 'wcsnrtombs not implemented' }, diff --git a/system/lib/libc/musl/src/internal/libc.c b/system/lib/libc/musl/src/internal/libc.c new file mode 100644 index 0000000000000..942f6b4484368 --- /dev/null +++ b/system/lib/libc/musl/src/internal/libc.c @@ -0,0 +1,22 @@ +#include "libc.h" + +#ifdef USE_LIBC_ACCESSOR +struct __libc *__libc_loc() +{ + static struct __libc __libc; + return &__libc; +} +#else +struct __libc __libc; +#endif + +#ifdef BROKEN_VISIBILITY +__asm__(".hidden __libc"); +#endif + +size_t __hwcap; +size_t __sysinfo; +char *__progname=0, *__progname_full=0; + +weak_alias(__progname, program_invocation_short_name); +weak_alias(__progname_full, program_invocation_name); diff --git a/system/lib/libc/musl/src/internal/libc.h b/system/lib/libc/musl/src/internal/libc.h new file mode 100644 index 0000000000000..c9416f075b417 --- /dev/null +++ b/system/lib/libc/musl/src/internal/libc.h @@ -0,0 +1,71 @@ +#ifndef LIBC_H +#define LIBC_H + +#include +#include + +struct __libc { + void *main_thread; + int threaded; + int secure; + size_t *auxv; + int (*atexit)(void (*)(void)); + void (*fini)(void); + void (*ldso_fini)(void); + volatile int threads_minus_1; + int canceldisable; + FILE *ofl_head; + int ofl_lock[2]; + size_t tls_size; +}; + +extern size_t __hwcap; + +#if !defined(__PIC__) || (100*__GNUC__+__GNUC_MINOR__ >= 303 && !defined(__PCC__)) + +#ifdef __PIC__ +#if __GNUC__ < 4 +#define BROKEN_VISIBILITY 1 +#endif +#define ATTR_LIBC_VISIBILITY __attribute__((visibility("hidden"))) +#else +#define ATTR_LIBC_VISIBILITY +#endif + +extern struct __libc __libc ATTR_LIBC_VISIBILITY; +#define libc __libc + +#else + +#define USE_LIBC_ACCESSOR +#define ATTR_LIBC_VISIBILITY +extern struct __libc *__libc_loc(void) __attribute__((const)); +#define libc (*__libc_loc()) + +#endif + + +/* Designed to avoid any overhead in non-threaded processes */ +void __lock(volatile int *) ATTR_LIBC_VISIBILITY; +void __unlock(volatile int *) ATTR_LIBC_VISIBILITY; +int __lockfile(FILE *) ATTR_LIBC_VISIBILITY; +void __unlockfile(FILE *) ATTR_LIBC_VISIBILITY; +#define LOCK(x) (libc.threads_minus_1 ? (__lock(x),1) : ((void)(x),1)) +#define UNLOCK(x) (libc.threads_minus_1 ? (__unlock(x),1) : ((void)(x),1)) + +void __synccall(void (*)(void *), void *); +int __setxid(int, int, int, int); + +extern char **__environ; + +#undef weak_alias +#define weak_alias(old, new) \ + extern __typeof(old) new __attribute__((weak, alias(#old))) + +#undef LFS64_2 +#define LFS64_2(x, y) weak_alias(x, y) + +#undef LFS64 +#define LFS64(x) LFS64_2(x, x##64) + +#endif diff --git a/system/lib/libc/musl/src/string/wcpcpy.c b/system/lib/libc/musl/src/string/wcpcpy.c new file mode 100644 index 0000000000000..ef401343323b4 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcpcpy.c @@ -0,0 +1,6 @@ +#include + +wchar_t *wcpcpy(wchar_t *restrict d, const wchar_t *restrict s) +{ + return wcscpy(d, s) + wcslen(s); +} diff --git a/system/lib/libc/musl/src/string/wcpncpy.c b/system/lib/libc/musl/src/string/wcpncpy.c new file mode 100644 index 0000000000000..b667f6d6a8dbb --- /dev/null +++ b/system/lib/libc/musl/src/string/wcpncpy.c @@ -0,0 +1,6 @@ +#include + +wchar_t *wcpncpy(wchar_t *restrict d, const wchar_t *restrict s, size_t n) +{ + return wcsncpy(d, s, n) + wcsnlen(s, n); +} diff --git a/system/lib/libc/musl/src/string/wcscasecmp.c b/system/lib/libc/musl/src/string/wcscasecmp.c new file mode 100644 index 0000000000000..3edeec7d3dd63 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcscasecmp.c @@ -0,0 +1,7 @@ +#include +#include + +int wcscasecmp(const wchar_t *l, const wchar_t *r) +{ + return wcsncasecmp(l, r, -1); +} diff --git a/system/lib/libc/musl/src/string/wcscasecmp_l.c b/system/lib/libc/musl/src/string/wcscasecmp_l.c new file mode 100644 index 0000000000000..065dd0aad757d --- /dev/null +++ b/system/lib/libc/musl/src/string/wcscasecmp_l.c @@ -0,0 +1,6 @@ +#include + +int wcscasecmp_l(const wchar_t *l, const wchar_t *r, locale_t locale) +{ + return wcscasecmp(l, r); +} diff --git a/system/lib/libc/musl/src/string/wcscat.c b/system/lib/libc/musl/src/string/wcscat.c new file mode 100644 index 0000000000000..d4f00ebdfe0bc --- /dev/null +++ b/system/lib/libc/musl/src/string/wcscat.c @@ -0,0 +1,7 @@ +#include + +wchar_t *wcscat(wchar_t *restrict dest, const wchar_t *restrict src) +{ + wcscpy(dest + wcslen(dest), src); + return dest; +} diff --git a/system/lib/libc/musl/src/string/wcschr.c b/system/lib/libc/musl/src/string/wcschr.c new file mode 100644 index 0000000000000..8dfc2f318316f --- /dev/null +++ b/system/lib/libc/musl/src/string/wcschr.c @@ -0,0 +1,8 @@ +#include + +wchar_t *wcschr(const wchar_t *s, wchar_t c) +{ + if (!c) return (wchar_t *)s + wcslen(s); + for (; *s && *s != c; s++); + return *s ? (wchar_t *)s : 0; +} diff --git a/system/lib/libc/musl/src/string/wcscmp.c b/system/lib/libc/musl/src/string/wcscmp.c new file mode 100644 index 0000000000000..26eeee7045612 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcscmp.c @@ -0,0 +1,7 @@ +#include + +int wcscmp(const wchar_t *l, const wchar_t *r) +{ + for (; *l==*r && *l && *r; l++, r++); + return *l - *r; +} diff --git a/system/lib/libc/musl/src/string/wcscpy.c b/system/lib/libc/musl/src/string/wcscpy.c new file mode 100644 index 0000000000000..625bf53d08768 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcscpy.c @@ -0,0 +1,8 @@ +#include + +wchar_t *wcscpy(wchar_t *restrict d, const wchar_t *restrict s) +{ + wchar_t *a = d; + while ((*d++ = *s++)); + return a; +} diff --git a/system/lib/libc/musl/src/string/wcscspn.c b/system/lib/libc/musl/src/string/wcscspn.c new file mode 100644 index 0000000000000..c4e52722e11d8 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcscspn.c @@ -0,0 +1,10 @@ +#include + +size_t wcscspn(const wchar_t *s, const wchar_t *c) +{ + const wchar_t *a; + if (!c[0]) return wcslen(s); + if (!c[1]) return (s=wcschr(a=s, *c)) ? s-a : wcslen(a); + for (a=s; *s && !wcschr(c, *s); s++); + return s-a; +} diff --git a/system/lib/libc/musl/src/string/wcsdup.c b/system/lib/libc/musl/src/string/wcsdup.c new file mode 100644 index 0000000000000..dd49c1b6297f6 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcsdup.c @@ -0,0 +1,11 @@ +#include +#include +#include "libc.h" + +wchar_t *wcsdup(const wchar_t *s) +{ + size_t l = wcslen(s); + wchar_t *d = malloc((l+1)*sizeof(wchar_t)); + if (!d) return NULL; + return wmemcpy(d, s, l+1); +} diff --git a/system/lib/libc/musl/src/string/wcslen.c b/system/lib/libc/musl/src/string/wcslen.c new file mode 100644 index 0000000000000..1b7b66550c618 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcslen.c @@ -0,0 +1,8 @@ +#include + +size_t wcslen(const wchar_t *s) +{ + const wchar_t *a; + for (a=s; *s; s++); + return s-a; +} diff --git a/system/lib/libc/musl/src/string/wcsncasecmp.c b/system/lib/libc/musl/src/string/wcsncasecmp.c new file mode 100644 index 0000000000000..8fefe799c4370 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcsncasecmp.c @@ -0,0 +1,9 @@ +#include +#include + +int wcsncasecmp(const wchar_t *l, const wchar_t *r, size_t n) +{ + if (!n--) return 0; + for (; *l && *r && n && (*l == *r || towlower(*l) == towlower(*r)); l++, r++, n--); + return towlower(*l) - towlower(*r); +} diff --git a/system/lib/libc/musl/src/string/wcsncasecmp_l.c b/system/lib/libc/musl/src/string/wcsncasecmp_l.c new file mode 100644 index 0000000000000..63872481927b4 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcsncasecmp_l.c @@ -0,0 +1,6 @@ +#include + +int wcsncasecmp_l(const wchar_t *l, const wchar_t *r, size_t n, locale_t locale) +{ + return wcsncasecmp(l, r, n); +} diff --git a/system/lib/libc/musl/src/string/wcsncat.c b/system/lib/libc/musl/src/string/wcsncat.c new file mode 100644 index 0000000000000..8563f1a2a701c --- /dev/null +++ b/system/lib/libc/musl/src/string/wcsncat.c @@ -0,0 +1,10 @@ +#include + +wchar_t *wcsncat(wchar_t *restrict d, const wchar_t *restrict s, size_t n) +{ + wchar_t *a = d; + d += wcslen(d); + while (n && *s) n--, *d++ = *s++; + *d++ = 0; + return a; +} diff --git a/system/lib/libc/musl/src/string/wcsncmp.c b/system/lib/libc/musl/src/string/wcsncmp.c new file mode 100644 index 0000000000000..4ab32a924c465 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcsncmp.c @@ -0,0 +1,7 @@ +#include + +int wcsncmp(const wchar_t *l, const wchar_t *r, size_t n) +{ + for (; n && *l==*r && *l && *r; n--, l++, r++); + return n ? *l - *r : 0; +} diff --git a/system/lib/libc/musl/src/string/wcsncpy.c b/system/lib/libc/musl/src/string/wcsncpy.c new file mode 100644 index 0000000000000..4bede04d251e0 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcsncpy.c @@ -0,0 +1,9 @@ +#include + +wchar_t *wcsncpy(wchar_t *restrict d, const wchar_t *restrict s, size_t n) +{ + wchar_t *a = d; + while (n && *s) n--, *d++ = *s++; + wmemset(d, 0, n); + return a; +} diff --git a/system/lib/libc/musl/src/string/wcsnlen.c b/system/lib/libc/musl/src/string/wcsnlen.c new file mode 100644 index 0000000000000..a7763373147b4 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcsnlen.c @@ -0,0 +1,8 @@ +#include + +size_t wcsnlen(const wchar_t *s, size_t n) +{ + const wchar_t *z = wmemchr(s, 0, n); + if (z) n = z-s; + return n; +} diff --git a/system/lib/libc/musl/src/string/wcspbrk.c b/system/lib/libc/musl/src/string/wcspbrk.c new file mode 100644 index 0000000000000..0c72c197b33b5 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcspbrk.c @@ -0,0 +1,7 @@ +#include + +wchar_t *wcspbrk(const wchar_t *s, const wchar_t *b) +{ + s += wcscspn(s, b); + return *s ? (wchar_t *)s : NULL; +} diff --git a/system/lib/libc/musl/src/string/wcsrchr.c b/system/lib/libc/musl/src/string/wcsrchr.c new file mode 100644 index 0000000000000..8961b9e2f8eee --- /dev/null +++ b/system/lib/libc/musl/src/string/wcsrchr.c @@ -0,0 +1,8 @@ +#include + +wchar_t *wcsrchr(const wchar_t *s, wchar_t c) +{ + const wchar_t *p; + for (p=s+wcslen(s); p>=s && *p!=c; p--); + return p>=s ? (wchar_t *)p : 0; +} diff --git a/system/lib/libc/musl/src/string/wcsspn.c b/system/lib/libc/musl/src/string/wcsspn.c new file mode 100644 index 0000000000000..4320d8f6b7dc7 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcsspn.c @@ -0,0 +1,8 @@ +#include + +size_t wcsspn(const wchar_t *s, const wchar_t *c) +{ + const wchar_t *a; + for (a=s; *s && wcschr(c, *s); s++); + return s-a; +} diff --git a/system/lib/libc/musl/src/string/wcsstr.c b/system/lib/libc/musl/src/string/wcsstr.c new file mode 100644 index 0000000000000..037d096578e1c --- /dev/null +++ b/system/lib/libc/musl/src/string/wcsstr.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include + +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)<(b)?(a):(b)) + +static wchar_t *twoway_wcsstr(const wchar_t *h, const wchar_t *n) +{ + const wchar_t *z; + size_t l, ip, jp, k, p, ms, p0, mem, mem0; + + /* Computing length of needle */ + for (l=0; n[l] && h[l]; l++); + if (n[l]) return 0; /* hit the end of h */ + + /* Compute maximal suffix */ + ip = -1; jp = 0; k = p = 1; + while (jp+k n[jp+k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + ms = ip; + p0 = p; + + /* And with the opposite comparison */ + ip = -1; jp = 0; k = p = 1; + while (jp+k ms+1) ms = ip; + else p = p0; + + /* Periodic needle? */ + if (wmemcmp(n, n+p, ms+1)) { + mem0 = 0; + p = MAX(ms, l-ms-1) + 1; + } else mem0 = l-p; + mem = 0; + + /* Initialize incremental end-of-haystack pointer */ + z = h; + + /* Search loop */ + for (;;) { + /* Update incremental end-of-haystack pointer */ + if (z-h < l) { + /* Fast estimate for MIN(l,63) */ + size_t grow = l | 63; + const wchar_t *z2 = wmemchr(z, 0, grow); + if (z2) { + z = z2; + if (z-h < l) return 0; + } else z += grow; + } + + /* Compare right half */ + for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++); + if (n[k]) { + h += k-ms; + mem = 0; + continue; + } + /* Compare left half */ + for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--); + if (k == mem) return (wchar_t *)h; + h += p; + mem = mem0; + } +} + +wchar_t *wcsstr(const wchar_t *restrict h, const wchar_t *restrict n) +{ + /* Return immediately on empty needle or haystack */ + if (!n[0]) return (wchar_t *)h; + if (!h[0]) return 0; + + /* Use faster algorithms for short needles */ + h = wcschr(h, *n); + if (!h || !n[1]) return (wchar_t *)h; + if (!h[1]) return 0; + + return twoway_wcsstr(h, n); +} diff --git a/system/lib/libc/musl/src/string/wcstok.c b/system/lib/libc/musl/src/string/wcstok.c new file mode 100644 index 0000000000000..ecc8033190c78 --- /dev/null +++ b/system/lib/libc/musl/src/string/wcstok.c @@ -0,0 +1,12 @@ +#include + +wchar_t *wcstok(wchar_t *restrict s, const wchar_t *restrict sep, wchar_t **restrict p) +{ + if (!s && !(s = *p)) return NULL; + s += wcsspn(s, sep); + if (!*s) return *p = 0; + *p = s + wcscspn(s, sep); + if (**p) *(*p)++ = 0; + else *p = 0; + return s; +} diff --git a/system/lib/libc/musl/src/string/wcswcs.c b/system/lib/libc/musl/src/string/wcswcs.c new file mode 100644 index 0000000000000..9cfe4ac40b43c --- /dev/null +++ b/system/lib/libc/musl/src/string/wcswcs.c @@ -0,0 +1,6 @@ +#include + +wchar_t *wcswcs(const wchar_t *haystack, const wchar_t *needle) +{ + return wcsstr(haystack, needle); +} diff --git a/system/lib/libc/musl/src/string/wmemchr.c b/system/lib/libc/musl/src/string/wmemchr.c new file mode 100644 index 0000000000000..37d69629eea37 --- /dev/null +++ b/system/lib/libc/musl/src/string/wmemchr.c @@ -0,0 +1,8 @@ +#include +#include + +wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t n) +{ + for (; n && *s != c; n--, s++); + return n ? (wchar_t *)s : 0; +} diff --git a/system/lib/libc/musl/src/string/wmemcmp.c b/system/lib/libc/musl/src/string/wmemcmp.c new file mode 100644 index 0000000000000..6788a383fcb25 --- /dev/null +++ b/system/lib/libc/musl/src/string/wmemcmp.c @@ -0,0 +1,8 @@ +#include +#include + +int wmemcmp(const wchar_t *l, const wchar_t *r, size_t n) +{ + for (; n && *l==*r; n--, l++, r++); + return n ? *l-*r : 0; +} diff --git a/system/lib/libc/musl/src/string/wmemcpy.c b/system/lib/libc/musl/src/string/wmemcpy.c new file mode 100644 index 0000000000000..55a8e1d8caec2 --- /dev/null +++ b/system/lib/libc/musl/src/string/wmemcpy.c @@ -0,0 +1,9 @@ +#include +#include + +wchar_t *wmemcpy(wchar_t *restrict d, const wchar_t *restrict s, size_t n) +{ + wchar_t *a = d; + while (n--) *d++ = *s++; + return a; +} diff --git a/system/lib/libc/musl/src/string/wmemmove.c b/system/lib/libc/musl/src/string/wmemmove.c new file mode 100644 index 0000000000000..cde4feec920d2 --- /dev/null +++ b/system/lib/libc/musl/src/string/wmemmove.c @@ -0,0 +1,12 @@ +#include +#include + +wchar_t *wmemmove(wchar_t *d, const wchar_t *s, size_t n) +{ + wchar_t *d0 = d; + if ((size_t)(d-s) < n) + while (n--) d[n] = s[n]; + else + while (n--) *d++ = *s++; + return d0; +} diff --git a/system/lib/libc/musl/src/string/wmemset.c b/system/lib/libc/musl/src/string/wmemset.c new file mode 100644 index 0000000000000..1a2a8618d1b03 --- /dev/null +++ b/system/lib/libc/musl/src/string/wmemset.c @@ -0,0 +1,9 @@ +#include +#include + +wchar_t *wmemset(wchar_t *d, wchar_t c, size_t n) +{ + wchar_t *ret = d; + while (n--) *d++ = c; + return ret; +} From 7cacf252e7f99fc2c98b969f8076011cfb6854d1 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 15 Apr 2013 23:03:13 +0700 Subject: [PATCH 522/544] Add musl multibyte function implementations. --- emcc | 17 +++ src/library.js | 37 ------- system/lib/libc/musl/src/multibyte/btowc.c | 7 ++ system/lib/libc/musl/src/multibyte/internal.c | 38 +++++++ system/lib/libc/musl/src/multibyte/internal.h | 22 ++++ system/lib/libc/musl/src/multibyte/mblen.c | 17 +++ system/lib/libc/musl/src/multibyte/mbrlen.c | 18 ++++ system/lib/libc/musl/src/multibyte/mbrtowc.c | 57 ++++++++++ system/lib/libc/musl/src/multibyte/mbsinit.c | 17 +++ .../lib/libc/musl/src/multibyte/mbsnrtowcs.c | 65 ++++++++++++ .../lib/libc/musl/src/multibyte/mbsrtowcs.c | 100 ++++++++++++++++++ system/lib/libc/musl/src/multibyte/mbstowcs.c | 7 ++ system/lib/libc/musl/src/multibyte/mbtowc.c | 53 ++++++++++ system/lib/libc/musl/src/multibyte/wcrtomb.c | 38 +++++++ .../lib/libc/musl/src/multibyte/wcsnrtombs.c | 52 +++++++++ .../lib/libc/musl/src/multibyte/wcsrtombs.c | 58 ++++++++++ system/lib/libc/musl/src/multibyte/wcstombs.c | 7 ++ system/lib/libc/musl/src/multibyte/wctob.c | 8 ++ system/lib/libc/musl/src/multibyte/wctomb.c | 18 ++++ 19 files changed, 599 insertions(+), 37 deletions(-) create mode 100644 system/lib/libc/musl/src/multibyte/btowc.c create mode 100644 system/lib/libc/musl/src/multibyte/internal.c create mode 100644 system/lib/libc/musl/src/multibyte/internal.h create mode 100644 system/lib/libc/musl/src/multibyte/mblen.c create mode 100644 system/lib/libc/musl/src/multibyte/mbrlen.c create mode 100644 system/lib/libc/musl/src/multibyte/mbrtowc.c create mode 100644 system/lib/libc/musl/src/multibyte/mbsinit.c create mode 100644 system/lib/libc/musl/src/multibyte/mbsnrtowcs.c create mode 100644 system/lib/libc/musl/src/multibyte/mbsrtowcs.c create mode 100644 system/lib/libc/musl/src/multibyte/mbstowcs.c create mode 100644 system/lib/libc/musl/src/multibyte/mbtowc.c create mode 100644 system/lib/libc/musl/src/multibyte/wcrtomb.c create mode 100644 system/lib/libc/musl/src/multibyte/wcsnrtombs.c create mode 100644 system/lib/libc/musl/src/multibyte/wcsrtombs.c create mode 100644 system/lib/libc/musl/src/multibyte/wcstombs.c create mode 100644 system/lib/libc/musl/src/multibyte/wctob.c create mode 100644 system/lib/libc/musl/src/multibyte/wctomb.c diff --git a/emcc b/emcc index 8c21562b18f84..ce5b499e3a6ef 100755 --- a/emcc +++ b/emcc @@ -1128,6 +1128,23 @@ try: ]; musl_files = [ + ['multibyte', [ + 'btowc.c', + 'mblen.c', + 'mbrlen.c', + 'mbrtowc.c', + 'mbsinit.c', + 'mbsnrtowcs.c', + 'mbsrtowcs.c', + 'mbstowcs.c', + 'mbtowc.c', + 'wcrtomb.c', + 'wcsnrtombs.c', + 'wcsrtombs.c', + 'wcstombs.c', + 'wctob.c', + 'wctomb.c', + ]], ['string', [ 'wcpcpy.c', 'wcpncpy.c', diff --git a/src/library.js b/src/library.js index bb4d710be75db..dfaff1fb26865 100644 --- a/src/library.js +++ b/src/library.js @@ -4168,32 +4168,6 @@ LibraryManager.library = { } }, - mbtowc: function(pwc, pmb, maxx) { - // XXX doesn't really handle multibyte at all - if (!pmb) return 0; - maxx = Math.min({{{ cDefine('_NL_CTYPE_MB_CUR_MAX') }}}, maxx); - var i; - for (i = 0; i < maxx; i++) { - var curr = {{{ makeGetValue('pmb', 0, 'i8') }}}; - if (pwc) { - {{{ makeSetValue('pwc', '0', 'curr', 'i8') }}}; - {{{ makeSetValue('pwc', '1', '0', 'i8') }}}; - pwc += 2; - } - pmb++; - if (!curr) break; - } - return i; - }, - - wcrtomb: function(s, wc, ps) { - // XXX doesn't really handle multibyte at all - if (s) { - {{{ makeSetValue('s', '0', 'wc', 'i8') }}}; - } - return 1; - }, - arc4random: 'rand', // ========================================================================== @@ -4324,17 +4298,6 @@ LibraryManager.library = { return (curr - ptr)|0; }, - // TODO: Implement when we have real unicode support. - mblen: function() { - return 1; - }, - - mbrlen: function() { throw 'mbrlen not implemented' }, - mbsrtowcs: function() { throw 'mbsrtowcs not implemented' }, - wcsnrtombs: function() { throw 'wcsnrtombs not implemented' }, - mbsnrtowcs: function() { throw 'mbsnrtowcs not implemented' }, - mbrtowc: function() { throw 'mbrtowc not implemented' }, - strspn: function(pstr, pset) { var str = pstr, set, strcurr, setcurr; while (1) { diff --git a/system/lib/libc/musl/src/multibyte/btowc.c b/system/lib/libc/musl/src/multibyte/btowc.c new file mode 100644 index 0000000000000..9d2c3b16eb77a --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/btowc.c @@ -0,0 +1,7 @@ +#include +#include + +wint_t btowc(int c) +{ + return c<128U ? c : EOF; +} diff --git a/system/lib/libc/musl/src/multibyte/internal.c b/system/lib/libc/musl/src/multibyte/internal.c new file mode 100644 index 0000000000000..ab22806ecb387 --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/internal.c @@ -0,0 +1,38 @@ +/* + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include + +#include "internal.h" + +#define C(x) ( x<2 ? -1 : ( R(0x80,0xc0) | x ) ) +#define D(x) C((x+16)) +#define E(x) ( ( x==0 ? R(0xa0,0xc0) : \ + x==0xd ? R(0x80,0xa0) : \ + R(0x80,0xc0) ) \ + | ( R(0x80,0xc0) >> 6 ) \ + | x ) +#define F(x) ( ( x>=5 ? 0 : \ + x==0 ? R(0x90,0xc0) : \ + x==4 ? R(0x80,0xa0) : \ + R(0x80,0xc0) ) \ + | ( R(0x80,0xc0) >> 6 ) \ + | ( R(0x80,0xc0) >> 12 ) \ + | x ) + +const uint32_t bittab[] = { + C(0x2),C(0x3),C(0x4),C(0x5),C(0x6),C(0x7), + C(0x8),C(0x9),C(0xa),C(0xb),C(0xc),C(0xd),C(0xe),C(0xf), + D(0x0),D(0x1),D(0x2),D(0x3),D(0x4),D(0x5),D(0x6),D(0x7), + D(0x8),D(0x9),D(0xa),D(0xb),D(0xc),D(0xd),D(0xe),D(0xf), + E(0x0),E(0x1),E(0x2),E(0x3),E(0x4),E(0x5),E(0x6),E(0x7), + E(0x8),E(0x9),E(0xa),E(0xb),E(0xc),E(0xd),E(0xe),E(0xf), + F(0x0),F(0x1),F(0x2),F(0x3),F(0x4) +}; + +#ifdef BROKEN_VISIBILITY +__asm__(".hidden __fsmu8"); +#endif diff --git a/system/lib/libc/musl/src/multibyte/internal.h b/system/lib/libc/musl/src/multibyte/internal.h new file mode 100644 index 0000000000000..25ba240e06269 --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/internal.h @@ -0,0 +1,22 @@ +/* + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#define bittab __fsmu8 + +#include "libc.h" + +extern const uint32_t bittab[] ATTR_LIBC_VISIBILITY; + +/* Upper 6 state bits are a negative integer offset to bound-check next byte */ +/* equivalent to: ( (b-0x80) | (b+offset) ) & ~0x3f */ +#define OOB(c,b) (((((b)>>3)-0x10)|(((b)>>3)+((int32_t)(c)>>26))) & ~7) + +/* Interval [a,b). Either a must be 80 or b must be c0, lower 3 bits clear. */ +#define R(a,b) ((uint32_t)((a==0x80 ? 0x40-b : -a) << 23)) +#define FAILSTATE R(0x80,0x80) + +#define SA 0xc2u +#define SB 0xf4u diff --git a/system/lib/libc/musl/src/multibyte/mblen.c b/system/lib/libc/musl/src/multibyte/mblen.c new file mode 100644 index 0000000000000..26d356494a61d --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/mblen.c @@ -0,0 +1,17 @@ +/* + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include +#include +#include +#include + +#include "internal.h" + +int mblen(const char *s, size_t n) +{ + return mbtowc(0, s, n); +} diff --git a/system/lib/libc/musl/src/multibyte/mbrlen.c b/system/lib/libc/musl/src/multibyte/mbrlen.c new file mode 100644 index 0000000000000..c9714ef82244a --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/mbrlen.c @@ -0,0 +1,18 @@ +/* + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include +#include +#include +#include + +#include "internal.h" + +size_t mbrlen(const char *restrict s, size_t n, mbstate_t *restrict st) +{ + static unsigned internal; + return mbrtowc(0, s, n, st ? st : (mbstate_t *)&internal); +} diff --git a/system/lib/libc/musl/src/multibyte/mbrtowc.c b/system/lib/libc/musl/src/multibyte/mbrtowc.c new file mode 100644 index 0000000000000..db80366141151 --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/mbrtowc.c @@ -0,0 +1,57 @@ +/* + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include +#include +#include +#include + +#include "internal.h" + +size_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate_t *restrict st) +{ + static unsigned internal_state; + unsigned c; + const unsigned char *s = (const void *)src; + const unsigned N = n; + + if (!st) st = (void *)&internal_state; + c = *(unsigned *)st; + + if (!s) { + if (c) goto ilseq; + return 0; + } else if (!wc) wc = (void *)&wc; + + if (!n) return -2; + if (!c) { + if (*s < 0x80) return !!(*wc = *s); + if (*s-SA > SB-SA) goto ilseq; + c = bittab[*s++-SA]; n--; + } + + if (n) { + if (OOB(c,*s)) goto ilseq; +loop: + c = c<<6 | *s++-0x80; n--; + if (!(c&(1U<<31))) { + *(unsigned *)st = 0; + *wc = c; + return N-n; + } + if (n) { + if (*s-0x80u >= 0x40) goto ilseq; + goto loop; + } + } + + *(unsigned *)st = c; + return -2; +ilseq: + *(unsigned *)st = 0; + errno = EILSEQ; + return -1; +} diff --git a/system/lib/libc/musl/src/multibyte/mbsinit.c b/system/lib/libc/musl/src/multibyte/mbsinit.c new file mode 100644 index 0000000000000..c0e7e494232a9 --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/mbsinit.c @@ -0,0 +1,17 @@ +/* + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include +#include +#include +#include + +#include "internal.h" + +int mbsinit(const mbstate_t *st) +{ + return !st || !*(unsigned *)st; +} diff --git a/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c b/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c new file mode 100644 index 0000000000000..33457f95bdccd --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c @@ -0,0 +1,65 @@ +/* + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include +#include +#include +#include +#include + +#include "internal.h" + +size_t mbsnrtowcs(wchar_t *restrict wcs, const char **restrict src, size_t n, size_t wn, mbstate_t *restrict st) +{ + size_t l, cnt=0, n2; + wchar_t *ws, wbuf[256]; + const char *s = *src; + + if (!wcs) ws = wbuf, wn = sizeof wbuf / sizeof *wbuf; + else ws = wcs; + + /* making sure output buffer size is at most n/4 will ensure + * that mbsrtowcs never reads more than n input bytes. thus + * we can use mbsrtowcs as long as it's practical.. */ + + while ( s && wn && ( (n2=n/4)>=wn || n2>32 ) ) { + if (n2>=wn) n2=wn; + n -= n2; + l = mbsrtowcs(ws, &s, n2, st); + if (!(l+1)) { + cnt = l; + wn = 0; + break; + } + if (ws != wbuf) { + ws += l; + wn -= l; + } + cnt += l; + } + if (s) while (wn && n) { + l = mbrtowc(ws, s, n, st); + if (l+2<=2) { + if (!(l+1)) { + cnt = l; + break; + } + if (!l) { + s = 0; + break; + } + /* have to roll back partial character */ + *(unsigned *)st = 0; + break; + } + s += l; n -= l; + /* safe - this loop runs fewer than sizeof(wbuf)/8 times */ + ws++; wn--; + cnt++; + } + if (wcs) *src = s; + return cnt; +} diff --git a/system/lib/libc/musl/src/multibyte/mbsrtowcs.c b/system/lib/libc/musl/src/multibyte/mbsrtowcs.c new file mode 100644 index 0000000000000..75a493c4f5f38 --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/mbsrtowcs.c @@ -0,0 +1,100 @@ +/* + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include +#include +#include +#include + +#include "internal.h" + +size_t mbsrtowcs(wchar_t *restrict ws, const char **restrict src, size_t wn, mbstate_t *restrict st) +{ + const unsigned char *s = (const void *)*src; + size_t wn0 = wn; + unsigned c = 0; + + if (st && (c = *(unsigned *)st)) { + if (ws) { + *(unsigned *)st = 0; + goto resume; + } else { + goto resume0; + } + } + + if (!ws) for (;;) { + if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) { + while (!(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) { + s += 4; + wn -= 4; + } + } + if (*s-1u < 0x7f) { + s++; + wn--; + continue; + } + if (*s-SA > SB-SA) break; + c = bittab[*s++-SA]; +resume0: + if (OOB(c,*s)) { s--; break; } + s++; + if (c&(1U<<25)) { + if (*s-0x80u >= 0x40) { s-=2; break; } + s++; + if (c&(1U<<19)) { + if (*s-0x80u >= 0x40) { s-=3; break; } + s++; + } + } + wn--; + c = 0; + } else for (;;) { + if (!wn) return wn0; + if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) { + while (wn>=4 && !(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) { + *ws++ = *s++; + *ws++ = *s++; + *ws++ = *s++; + *ws++ = *s++; + wn -= 4; + } + } + if (*s-1u < 0x7f) { + *ws++ = *s++; + wn--; + continue; + } + if (*s-SA > SB-SA) break; + c = bittab[*s++-SA]; +resume: + if (OOB(c,*s)) { s--; break; } + c = (c<<6) | *s++-0x80; + if (c&(1U<<31)) { + if (*s-0x80u >= 0x40) { s-=2; break; } + c = (c<<6) | *s++-0x80; + if (c&(1U<<31)) { + if (*s-0x80u >= 0x40) { s-=3; break; } + c = (c<<6) | *s++-0x80; + } + } + *ws++ = c; + wn--; + c = 0; + } + + if (!c && !*s) { + if (ws) { + *ws = 0; + *src = 0; + } + return wn0-wn; + } + errno = EILSEQ; + if (ws) *src = (const void *)s; + return -1; +} diff --git a/system/lib/libc/musl/src/multibyte/mbstowcs.c b/system/lib/libc/musl/src/multibyte/mbstowcs.c new file mode 100644 index 0000000000000..dc0d459480e26 --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/mbstowcs.c @@ -0,0 +1,7 @@ +#include +#include + +size_t mbstowcs(wchar_t *restrict ws, const char *restrict s, size_t wn) +{ + return mbsrtowcs(ws, (void*)&s, wn, 0); +} diff --git a/system/lib/libc/musl/src/multibyte/mbtowc.c b/system/lib/libc/musl/src/multibyte/mbtowc.c new file mode 100644 index 0000000000000..ec9e54ad07b4a --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/mbtowc.c @@ -0,0 +1,53 @@ +/* + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include +#include +#include +#include + +#include "internal.h" +#include +int mbtowc(wchar_t *restrict wc, const char *restrict src, size_t n) +{ + unsigned c; + const unsigned char *s = (const void *)src; + + if (!s) return 0; + if (!n) goto ilseq; + if (!wc) wc = (void *)&wc; + + if (*s < 0x80) return !!(*wc = *s); + if (*s-SA > SB-SA) goto ilseq; + c = bittab[*s++-SA]; + + /* Avoid excessive checks against n: If shifting the state n-1 + * times does not clear the high bit, then the value of n is + * insufficient to read a character */ + if (n<4 && ((c<<(6*n-6)) & (1U<<31))) goto ilseq; + + if (OOB(c,*s)) goto ilseq; + c = c<<6 | *s++-0x80; + if (!(c&(1U<<31))) { + *wc = c; + return 2; + } + + if (*s-0x80u >= 0x40) goto ilseq; + c = c<<6 | *s++-0x80; + if (!(c&(1U<<31))) { + *wc = c; + return 3; + } + + if (*s-0x80u >= 0x40) goto ilseq; + *wc = c<<6 | *s++-0x80; + return 4; + +ilseq: + errno = EILSEQ; + return -1; +} diff --git a/system/lib/libc/musl/src/multibyte/wcrtomb.c b/system/lib/libc/musl/src/multibyte/wcrtomb.c new file mode 100644 index 0000000000000..250649f55b4fb --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/wcrtomb.c @@ -0,0 +1,38 @@ +/* + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include +#include +#include +#include + +#include "internal.h" + +size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict st) +{ + if (!s) return 1; + if ((unsigned)wc < 0x80) { + *s = wc; + return 1; + } else if ((unsigned)wc < 0x800) { + *s++ = 0xc0 | (wc>>6); + *s = 0x80 | (wc&0x3f); + return 2; + } else if ((unsigned)wc < 0xd800 || (unsigned)wc-0xe000 < 0x2000) { + *s++ = 0xe0 | (wc>>12); + *s++ = 0x80 | ((wc>>6)&0x3f); + *s = 0x80 | (wc&0x3f); + return 3; + } else if ((unsigned)wc-0x10000 < 0x100000) { + *s++ = 0xf0 | (wc>>18); + *s++ = 0x80 | ((wc>>12)&0x3f); + *s++ = 0x80 | ((wc>>6)&0x3f); + *s = 0x80 | (wc&0x3f); + return 4; + } + errno = EILSEQ; + return -1; +} diff --git a/system/lib/libc/musl/src/multibyte/wcsnrtombs.c b/system/lib/libc/musl/src/multibyte/wcsnrtombs.c new file mode 100644 index 0000000000000..a2e308b3be62e --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/wcsnrtombs.c @@ -0,0 +1,52 @@ +/* + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include +#include +#include +#include + +#include "internal.h" + +size_t wcsnrtombs(char *restrict dst, const wchar_t **restrict wcs, size_t wn, size_t n, mbstate_t *restrict st) +{ + size_t l, cnt=0, n2; + char *s, buf[256]; + const wchar_t *ws = *wcs; + + if (!dst) s = buf, n = sizeof buf; + else s = dst; + + while ( ws && n && ( (n2=wn)>=n || n2>32 ) ) { + if (n2>=n) n2=n; + wn -= n2; + l = wcsrtombs(s, &ws, n2, 0); + if (!(l+1)) { + cnt = l; + n = 0; + break; + } + if (s != buf) { + s += l; + n -= l; + } + cnt += l; + } + if (ws) while (n && wn) { + l = wcrtomb(s, *ws, 0); + if ((l+1)<=1) { + if (!l) ws = 0; + else cnt = l; + break; + } + ws++; wn--; + /* safe - this loop runs fewer than sizeof(buf) times */ + s+=l; n-=l; + cnt++; + } + if (dst) *wcs = ws; + return cnt; +} diff --git a/system/lib/libc/musl/src/multibyte/wcsrtombs.c b/system/lib/libc/musl/src/multibyte/wcsrtombs.c new file mode 100644 index 0000000000000..d48a65e74aacc --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/wcsrtombs.c @@ -0,0 +1,58 @@ +/* + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include +#include +#include +#include + +#include "internal.h" + +size_t wcsrtombs(char *restrict s, const wchar_t **restrict ws, size_t n, mbstate_t *restrict st) +{ + const wchar_t *ws2; + char buf[4]; + size_t N = n, l; + if (!s) { + for (n=0, ws2=*ws; *ws2; ws2++) { + if (*ws2 >= 0x80u) { + l = wcrtomb(buf, *ws2, 0); + if (!(l+1)) return -1; + n += l; + } else n++; + } + return n; + } + while (n>=4 && **ws) { + if (**ws >= 0x80u) { + l = wcrtomb(s, **ws, 0); + if (!(l+1)) return -1; + s += l; + n -= l; + } else { + *s++ = **ws; + n--; + } + (*ws)++; + } + while (n && **ws) { + if (**ws >= 0x80u) { + l = wcrtomb(buf, **ws, 0); + if (!(l+1)) return -1; + if (l>n) return N-n; + wcrtomb(s, **ws, 0); + s += l; + n -= l; + } else { + *s++ = **ws; + n--; + } + (*ws)++; + } + if (n) *s = 0; + *ws = 0; + return N-n; +} diff --git a/system/lib/libc/musl/src/multibyte/wcstombs.c b/system/lib/libc/musl/src/multibyte/wcstombs.c new file mode 100644 index 0000000000000..ab152874db940 --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/wcstombs.c @@ -0,0 +1,7 @@ +#include +#include + +size_t wcstombs(char *restrict s, const wchar_t *restrict ws, size_t n) +{ + return wcsrtombs(s, &(const wchar_t *){ws}, n, 0); +} diff --git a/system/lib/libc/musl/src/multibyte/wctob.c b/system/lib/libc/musl/src/multibyte/wctob.c new file mode 100644 index 0000000000000..d6353ee179357 --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/wctob.c @@ -0,0 +1,8 @@ +#include +#include + +int wctob(wint_t c) +{ + if (c < 128U) return c; + return EOF; +} diff --git a/system/lib/libc/musl/src/multibyte/wctomb.c b/system/lib/libc/musl/src/multibyte/wctomb.c new file mode 100644 index 0000000000000..6910ef37f5041 --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/wctomb.c @@ -0,0 +1,18 @@ +/* + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include +#include +#include +#include + +#include "internal.h" + +int wctomb(char *s, wchar_t wc) +{ + if (!s) return 0; + return wcrtomb(s, wc, 0); +} From 654b36699e487b3d12a1827603f5f97414ee8d13 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 22 Apr 2013 17:38:22 +0700 Subject: [PATCH 523/544] Move wchar,mb stuff to libcextra. --- emcc | 66 ++++++++++++++++++++++++++---------- system/lib/libcextra.symbols | 48 ++++++++++++++++++++++++++ tests/runner.py | 16 +++++++++ 3 files changed, 112 insertions(+), 18 deletions(-) create mode 100644 system/lib/libcextra.symbols diff --git a/emcc b/emcc index ce5b499e3a6ef..9eafd685858aa 100755 --- a/emcc +++ b/emcc @@ -1127,6 +1127,44 @@ try: os.path.join('libc', 'stdlib', 'strtod.c'), ]; + musl_files = [] + + for directory, sources in musl_files: + libc_files += [os.path.join('libc', 'musl', 'src', directory, source) for source in sources] + + prev_cxx = os.environ.get('EMMAKEN_CXX') + if prev_cxx: os.environ['EMMAKEN_CXX'] = '' + musl_internal_includes = shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'internal') + for src in libc_files: + o = in_temp(os.path.basename(src) + '.o') + execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o, '-I', musl_internal_includes], stdout=stdout, stderr=stderr) + o_s.append(o) + if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx + + shared.Building.link(o_s, in_temp('libc.bc')) + return in_temp('libc.bc') + + def fix_libc(need): + # libc needs some sign correction. # If we are in mode 0, switch to 2. We will add our lines + try: + if shared.Settings.CORRECT_SIGNS == 0: raise Exception('we need to change to 2') + except: # we fail if equal to 0 - so we need to switch to 2 - or if CORRECT_SIGNS is not even in Settings + shared.Settings.CORRECT_SIGNS = 2 + if shared.Settings.CORRECT_SIGNS == 2: + shared.Settings.CORRECT_SIGNS_LINES = [shared.path_from_root('src', 'dlmalloc.c') + ':' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]] + # If we are in mode 1, we are correcting everything anyhow. If we are in mode 3, we will be corrected + # so all is well anyhow too. + # XXX We also need to add libc symbols that use malloc, for example strdup. It's very rare to use just them and not + # a normal malloc symbol (like free, after calling strdup), so we haven't hit this yet, but it is possible. + libc_symbols = map(lambda line: line.strip().split(' ')[1], open(shared.path_from_root('system', 'lib', 'libc.symbols')).readlines()) + libc_symbols = set(libc_symbols) + + # libcextra + def create_libcextra(): + if DEBUG: print >> sys.stderr, 'emcc: building libcextra for cache' + o_s = [] + libcextra_files = [] + musl_files = [ ['multibyte', [ 'btowc.c', @@ -1177,35 +1215,26 @@ try: ]] ] + libcextra_files = [] for directory, sources in musl_files: - libc_files += [os.path.join('libc', 'musl', 'src', directory, source) for source in sources] + libcextra_files += [os.path.join('libc', 'musl', 'src', directory, source) for source in sources] prev_cxx = os.environ.get('EMMAKEN_CXX') if prev_cxx: os.environ['EMMAKEN_CXX'] = '' musl_internal_includes = shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'internal') - for src in libc_files: + for src in libcextra_files: o = in_temp(os.path.basename(src) + '.o') execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o, '-I', musl_internal_includes], stdout=stdout, stderr=stderr) o_s.append(o) if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx - shared.Building.link(o_s, in_temp('libc.bc')) - return in_temp('libc.bc') + shared.Building.link(o_s, in_temp('libcextra.bc')) + return in_temp('libcextra.bc') - def fix_libc(need): - # libc needs some sign correction. # If we are in mode 0, switch to 2. We will add our lines - try: - if shared.Settings.CORRECT_SIGNS == 0: raise Exception('we need to change to 2') - except: # we fail if equal to 0 - so we need to switch to 2 - or if CORRECT_SIGNS is not even in Settings - shared.Settings.CORRECT_SIGNS = 2 - if shared.Settings.CORRECT_SIGNS == 2: - shared.Settings.CORRECT_SIGNS_LINES = [shared.path_from_root('src', 'dlmalloc.c') + ':' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]] - # If we are in mode 1, we are correcting everything anyhow. If we are in mode 3, we will be corrected - # so all is well anyhow too. - # XXX We also need to add libc symbols that use malloc, for example strdup. It's very rare to use just them and not - # a normal malloc symbol (like free, after calling strdup), so we haven't hit this yet, but it is possible. - libc_symbols = map(lambda line: line.strip().split(' ')[1], open(shared.path_from_root('system', 'lib', 'libc.symbols')).readlines()) - libc_symbols = set(libc_symbols) + def fix_libcextra(need): + pass + libcextra_symbols = map(lambda line: line.strip().split(' ')[1], open(shared.path_from_root('system', 'lib', 'libcextra.symbols')).readlines()) + libcextra_symbols = set(libcextra_symbols) # libcxx def create_libcxx(): @@ -1279,6 +1308,7 @@ try: force = os.environ.get('EMCC_FORCE_STDLIBS') has = need = None for name, create, fix, library_symbols in [('libcxx', create_libcxx, fix_libcxx, libcxx_symbols), + ('libcextra', create_libcextra, fix_libcextra, libcextra_symbols), ('libcxxabi', create_libcxxabi, fix_libcxxabi, libcxxabi_symbols), ('libc', create_libc, fix_libc, libc_symbols)]: if not force: diff --git a/system/lib/libcextra.symbols b/system/lib/libcextra.symbols new file mode 100644 index 0000000000000..97805c96bd710 --- /dev/null +++ b/system/lib/libcextra.symbols @@ -0,0 +1,48 @@ + U __errno + U __fsmu8 + T btowc + U malloc + T mblen + T mbrlen + d mbrlen.internal + T mbrtowc + d mbrtowc.internal_state + T mbsinit + T mbsnrtowcs + T mbsrtowcs + T mbstowcs + T mbtowc + U towlower + t twoway_wcsstr + T wcpcpy + T wcpncpy + T wcrtomb + T wcscasecmp + T wcscat + T wcschr + T wcscmp + T wcscpy + T wcscspn + T wcsdup + T wcslen + T wcsncasecmp + T wcsncat + T wcsncmp + T wcsncpy + T wcsnlen + T wcsnrtombs + T wcspbrk + T wcsrchr + T wcsrtombs + T wcsspn + T wcsstr + T wcstok + T wcstombs + T wcswcs + T wctob + T wctomb + T wmemchr + T wmemcmp + T wmemcpy + T wmemmove + T wmemset diff --git a/tests/runner.py b/tests/runner.py index 99f24fc951b76..00426b0c8612b 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -2309,6 +2309,22 @@ def test_assert(self): ''' self.do_run(src, 'Assertion failed: 1 == false') + def test_libcextra(self): + src = r''' + #include + #include + + int main() + { + const wchar_t* wstr = L"Hello"; + + printf("wcslen: %d\n", wcslen(wstr)); + + return 0; + } + ''' + self.do_run(src, 'wcslen: 5') + def test_longjmp(self): src = r''' #include From f636c9bfc6c11c9e53825a27b56beb7731f7b3d5 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 15 Apr 2013 22:32:39 +0700 Subject: [PATCH 524/544] Bump version. --- tools/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index 6b5ad835a8f05..9010b6e237fff 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -199,7 +199,7 @@ def check_node_version(): # we re-check sanity when the settings are changed) # We also re-check sanity and clear the cache when the version changes -EMSCRIPTEN_VERSION = '1.3.6' +EMSCRIPTEN_VERSION = '1.3.7' def check_sanity(force=False): try: From b80d879b78243e1dddb5abffad60294e6b47d1bc Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 22 Apr 2013 09:31:22 -0700 Subject: [PATCH 525/544] fix argument hardcoding --- tests/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runner.py b/tests/runner.py index 99f24fc951b76..811d32a5b3e54 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -138,7 +138,7 @@ def hardcode_arguments(self, filename, args): # Hardcode in the arguments, so js is portable without manual commandlinearguments if not args: return js = open(filename).read() - open(filename, 'w').write(js.replace('var ret = run();', 'var ret = run(%s);' % str(args))) + open(filename, 'w').write(js.replace('run();', 'run(%s);' % str(args))) def prep_ll_run(self, filename, ll_file, force_recompile=False, build_ll_hook=None): if ll_file.endswith(('.bc', '.o')): From 9a37f4ce7d3a36d106a04f2555f02e2e38e25ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 22 Apr 2013 20:43:46 +0300 Subject: [PATCH 526/544] In test_time, be more relaxed about the time wait condition - thread scheduling/system contention may interfere with the wait and produce a longer wait than 2 seconds. --- tests/time/src.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/time/src.c b/tests/time/src.c index aaf2878f569bc..d33885fedb624 100644 --- a/tests/time/src.c +++ b/tests/time/src.c @@ -96,7 +96,8 @@ int main() { clock_t start = clock(); printf("clock(start): %d\n", start >= 0); while (clock() - start < 2 * CLOCKS_PER_SEC); // Poor man's sleep(). - printf("clock(end): %d\n", time(NULL) - start_t == 2); + clock_t diff = time(NULL) - start_t; + printf("clock(end): %d\n", diff >= 2 && diff < 30); // Verify that ctime_r(x, buf) is equivalent to asctime_r(localtime(x), buf). time_t t7 = time(0); From b3dc9ab122e62f9ec2aa0c31e8a0d477851018a5 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 23 Apr 2013 02:25:34 +0700 Subject: [PATCH 527/544] Add a readme giving the date / revision of these sources. --- system/lib/libc/musl/readme.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 system/lib/libc/musl/readme.txt diff --git a/system/lib/libc/musl/readme.txt b/system/lib/libc/musl/readme.txt new file mode 100644 index 0000000000000..0df3429d84eea --- /dev/null +++ b/system/lib/libc/musl/readme.txt @@ -0,0 +1 @@ +These sources were downloaded from the musl-0.9.10 release on April 14, 2003. From 247ae2e571575d3f37933de0d76f8cdedc600f2b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 22 Apr 2013 13:08:40 -0700 Subject: [PATCH 528/544] show clear error message instead of 987 when too many setjmp calls --- src/library.js | 6 ++++-- src/parseTools.js | 10 ++++++++++ src/settings.js | 2 +- tests/runner.py | 16 ++++++++++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/library.js b/src/library.js index 939da8b1e733f..91270c384f55a 100644 --- a/src/library.js +++ b/src/library.js @@ -6220,6 +6220,7 @@ LibraryManager.library = { saveSetjmp__asm: true, saveSetjmp__sig: 'iii', + saveSetjmp__deps: ['putchar'], saveSetjmp: function(env, label, table) { // Not particularly fast: slow table lookup of setjmpId to label. But setjmp // prevents relooping anyhow, so slowness is to be expected. And typical case @@ -6233,7 +6234,7 @@ LibraryManager.library = { #endif setjmpId = (setjmpId+1)|0; {{{ makeSetValueAsm('env', '0', 'setjmpId', 'i32') }}}; - while ((i|0) < {{{ MAX_SETJMPS }}}) { + while ((i|0) < {{{ 2*MAX_SETJMPS }}}) { if ({{{ makeGetValueAsm('table', 'i*4', 'i32') }}} == 0) { {{{ makeSetValueAsm('table', 'i*4', 'setjmpId', 'i32') }}}; {{{ makeSetValueAsm('table', 'i*4+4', 'label', 'i32') }}}; @@ -6243,7 +6244,8 @@ LibraryManager.library = { } i = (i+2)|0; } - abort(987); // if you hit this, adjust MAX_SETJMPS + {{{ makePrintChars('too many setjmps in a function call, build with a higher value for MAX_SETJMPS') }}}; + abort(0); return 0; }, diff --git a/src/parseTools.js b/src/parseTools.js index 2eb456f1ede10..fe21dfd5c70b5 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -2363,3 +2363,13 @@ function getTypeFromHeap(suffix) { } } +// Generates code that prints without printf(), but just putchar (so can be directly inline) +function makePrintChars(s) { + var ret = ''; + for (var i = 0; i < s.length; i++) { + ret += '_putchar(' + s.charCodeAt(i) + ');'; + } + ret += '_putchar(10);'; + return ret; +} + diff --git a/src/settings.js b/src/settings.js index 7cd0c02e26c45..d30db173a700d 100644 --- a/src/settings.js +++ b/src/settings.js @@ -55,7 +55,7 @@ var ALLOW_MEMORY_GROWTH = 0; // If false, we abort with an error if we try to al // that case we must be careful about optimizations, in particular the // eliminator). Note that memory growth is only supported with typed // arrays. -var MAX_SETJMPS = 10; // size of setjmp table allocated in each function invocation (that has setjmp) +var MAX_SETJMPS = 20; // size of setjmp table allocated in each function invocation (that has setjmp) // Code embetterments var MICRO_OPTS = 1; // Various micro-optimizations, like nativizing variables diff --git a/tests/runner.py b/tests/runner.py index 811d32a5b3e54..2e01226f558c8 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -2489,6 +2489,22 @@ def test_longjmp4(self): Exception execution path of first function! 1 ''') + def test_setjmp_many(self): + src = r''' + #include + #include + + int main(int argc) { + jmp_buf buf; + for (int i = 0; i < NUM; i++) printf("%d\n", setjmp(buf)); + if (argc-- == 1131) longjmp(buf, 11); + return 0; + } + ''' + for num in [Settings.MAX_SETJMPS, Settings.MAX_SETJMPS+1]: + print num + self.do_run(src.replace('NUM', str(num)), '0\n' * num if num <= Settings.MAX_SETJMPS or not Settings.ASM_JS else 'build with a higher value for MAX_SETJMPS') + def test_exceptions(self): if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1") if self.emcc_args is None: return self.skip('need emcc to add in libcxx properly') From f6f4ccf638f3e97bf370a4005cb783d8c7208b34 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 22 Apr 2013 13:26:52 -0700 Subject: [PATCH 529/544] not using Changelong anymore --- ChangeLog | 137 ------------------------------------------------------ 1 file changed, 137 deletions(-) delete mode 100644 ChangeLog diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index b60921cd21245..0000000000000 --- a/ChangeLog +++ /dev/null @@ -1,137 +0,0 @@ -2011-??-??: Version 2.0 - - * Bundled headers - * TODO: try to not need all the -h in tests/runner.py, and for user scripts too - -2011-07-31: Version 1.5 - - * eSpeak text-to-speech demo - * Filesystem emulation API - * Parse metadata type info for easier interaction with llvm structures - * Bindings generator improvements - * Many library improvements and fixes - * Various bug fixes - -2011-07-10: Version 1.4 - - * Compiling and loading of dynamic libraries - * Automatic bindings generation using CppHeaderParser - * Much improved emscripten.py - * Many library improvements and fixes - * Various bug fixes - -2011-06-22: Version 1.3 - - * Optional typed arrays with single shared buffer (TA2) - * Optional support for nonportable optimizations with TA2 - * Relooper optimizations - * Reading from stdin on the web opens window.prompt - * Various bug fixes - -2011-05-29: Version 1.2 - - * Doom demo - * Major SDL improvements: color palettes, input events, audio - * Various improvements for CHECK_* and CORRECT_*, and new AUTO_OPTIMIZE - * Experimental work towards supporting OpenGL in WebGL - * Various bug fixes - -2011-05-01: Version 1.1 - - * Much improved Bullet demo (llvm opts, quantum = 1, CubicVR.js) - * QUANTUM == 1 a.k.a memory compression option - * Dead function elimination tool - * Various performance improvements in generated code - * Various bug fixes - -2011-04-09: Version 1.0 - - * Poppler test and web demo - * Optimize compiler memory usage very significantly - * Support for LLVM 2.9 - * Better interaction with closure compiler - * Finish docs/paper.pdf - * Many bug fixes - -2011-03-05: Version 0.9 - - * OpenJPEG test and web demo - * Line number debugging info and autodebugger tool - * CORRECT_ROUNDINGS option - * Line-specific CORRECT_* options - * 20% faster compilation - * Generate strict mode JavaScript - * Many bug fixes, additional tests and library implementations - -2011-02-06: Version 0.8 - - * Freetype web demo (2011-02-08, right after 0.8) - * Freetype and zlib tests (including the entire build procedure) - * File emulation - * CHECK_OVERFLOWS & CORRECT_OVERFLOWS options to handle numerical size issues - * CHECK_SIGNS option to find whether GUARD_SIGNS is necessary - * Improvements to usage of llvm optimizations, and testing - * Many bug fixes, additional tests and library implementations - -2010-12-18: Version 0.7 - - * Python web demo - * Support for essentially all LLVM optimizations - * Proper support for C bitfields - * Many bug fixes, additional tests and library implementations - -2010-11-25: Version 0.6 - - * Web demos: Lua and Bullet/WebGL - * SAFE_HEAP checks for invalid reads/writes, nonportable .ll - * Basic C++ exceptions support (|catch(...)|) - * Optimize compilation of very large projects (memory and speed) - * Support for frontend-optimized .ll input, plus tests - * Integration (combining scripts with compiled C++) tools and tests - * Many bug fixes, additional tests and library implementations - -2010-11-02: Version 0.5 - - * Much faster compilation, in particular of large projects - * Bullet physics library test - * GCC name demangling test - * Module-ization of generated code (optional) - * Name demangler and namespace generator tools - * Many code cleanups, bug fixes, additional tests and library implementations - -2010-10-17: Version 0.4 - - * Much faster optimized code, now 10X the speed of our unoptimized code - * Support for the recently-released LLVM 2.8 - * Support for typed arrays - * Integration with the Closure Compiler - * Benchmarking framework in test runner - * Many code cleanups, bug fixes, and additional tests - -2010-10-05: Version 0.3 - - * Much faster compilation (but still slow with relooper) - * Clang support - * Optional memory alignment that precisely matches C/C++ - * Proper memory management, including stack and (optional) dlmalloc - * Rewritten relooper; no emulated blocks in any test - * Initial support for SDL - * Raytracing test + web demo - * Many code cleanups, bug fixes, additional tests and library implementations - -2010-09-11: Version 0.2 - - * sauer (cubescript) test passes (without RELOOPing), + web demo - * ES_SIZEOF - safe&portable sizeof replacement - * emscripten.py tool for easy compiling - * Better debugging support, using SAFE_HEAP and LABEL_DEBUG, using internal preprocessor - * Compiler can now run all tests in both SpiderMonkey and V8 - * Various compiler optimizations (still barely scratched the surface though) - * Many code cleanups, bug fixes, additional tests and library implementations - -2010-08-28: Version 0.1 - - * All tests pass, including fannkuch and fasta, but constglobalstructs - * Relooping of Fannkuch is complete, fasta has one left - * Emscriptened Fannkuch is 19X slower than gcc -O0, 37X than gcc -O2 - From 29a9d8b2c5d5032ef6c980b5256982f66ac23d5b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 22 Apr 2013 17:59:13 -0700 Subject: [PATCH 530/544] big function finder tool --- tools/find_bigfuncs.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tools/find_bigfuncs.py diff --git a/tools/find_bigfuncs.py b/tools/find_bigfuncs.py new file mode 100644 index 0000000000000..ebff8b6ea942f --- /dev/null +++ b/tools/find_bigfuncs.py @@ -0,0 +1,23 @@ +''' +Simple tool to find big functions in an .ll file. Anything over i64 is of interest. +''' + +import os, sys, re + +filename = sys.argv[1] +i = 0 +maxx = -1 +maxxest = '?' +start = -1 +curr = '?' +for line in open(filename): + i += 1 + if line.startswith('function '): + start = i + curr = line + elif line.startswith('}'): + size = i - start + if size > maxx: + maxx = size + maxxest = curr +print maxx, 'lines in', maxxest From 40edec0ec80f07b5ce2e351e67137f7908a0ea1e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 22 Apr 2013 20:38:00 -0700 Subject: [PATCH 531/544] use invoke when doing a setjmp-guarding call via a function pointer --- src/jsifier.js | 11 ++++++----- tests/runner.py | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index a01b2655225e3..3d2d022b8406d 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1448,20 +1448,21 @@ function JSify(data, functionsOnly, givenFunctions) { var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs); if (ASM_JS) { assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out) - if (!byPointerForced) { + if (!byPointerForced && !funcData.setjmpTable) { + // normal asm function pointer call callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py } else { - // This is a forced call, through an invoke_*. + // This is a call through an invoke_*, either a forced one, or a setjmp-required one // note: no need to update argsTypes at this point - Functions.unimplementedFunctions[callIdent] = sig; - args.unshift(byPointerForced ? Functions.getIndex(callIdent) : callIdent); + if (byPointerForced) Functions.unimplementedFunctions[callIdent] = sig; + args.unshift(byPointerForced ? Functions.getIndex(callIdent) : asmCoercion(callIdent, 'i32')); callIdent = 'invoke_' + sig; } } else if (SAFE_DYNCALLS) { assert(!ASM_JS, 'cannot emit safe dyncalls in asm'); callIdent = '(tempInt=' + callIdent + ',tempInt < 0 || tempInt >= FUNCTION_TABLE.length-1 || !FUNCTION_TABLE[tempInt] ? abort("dyncall error: ' + sig + ' " + FUNCTION_TABLE_NAMES[tempInt]) : tempInt)'; } - if (!byPointerForced) callIdent = Functions.getTable(sig) + '[' + callIdent + ']'; + if (!ASM_JS || (!byPointerForced && !funcData.setjmpTable)) callIdent = Functions.getTable(sig) + '[' + callIdent + ']'; } var ret = callIdent + '(' + args.join(', ') + ')'; diff --git a/tests/runner.py b/tests/runner.py index 2e01226f558c8..33a2ef67931c9 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -2489,6 +2489,41 @@ def test_longjmp4(self): Exception execution path of first function! 1 ''') + def test_longjmp_funcptr(self): + src = r''' + #include + #include + + static jmp_buf buf; + + void (*fp)() = NULL; + + void second(void) { + printf("second\n"); // prints + longjmp(buf,1); // jumps back to where setjmp was called - making setjmp now return 1 + } + + void first(void) { + fp(); + printf("first\n"); // does not print + } + + int main(int argc, char **argv) { + fp = argc == 200 ? NULL : second; + + volatile int x = 0; + if ( ! setjmp(buf) ) { + x++; + first(); // when executed, setjmp returns 0 + } else { // when longjmp jumps back, setjmp returns 1 + printf("main: %d\n", x); // prints + } + + return 0; + } + ''' + self.do_run(src, 'second\nmain: 1\n') + def test_setjmp_many(self): src = r''' #include From 02194bcc84104fad8f0d0ff6d5ff6f4312dd8d5e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 22 Apr 2013 20:52:07 -0700 Subject: [PATCH 532/544] make sure to coerce arguments to invoke due to setjmp --- src/jsifier.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jsifier.js b/src/jsifier.js index 3d2d022b8406d..9678a56d6adbb 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1370,7 +1370,7 @@ function JSify(data, functionsOnly, givenFunctions) { args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) }); if (ASM_JS) { - if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced) { + if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced || funcData.setjmpTable) { args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) }); } else { args = args.map(function(arg, i) { return asmEnsureFloat(arg, argsTypes[i]) }); From 029c076151fb9cb47c54af53c52870ef0b620c5c Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 23 Apr 2013 10:47:20 +0700 Subject: [PATCH 533/544] Clean up libc / libcxx build infrastructure. This creates a couple of additional methods to reduce copy/paste and make things a bit easier to follow. --- emcc | 104 ++++++++++++++++++++++++----------------------------------- 1 file changed, 42 insertions(+), 62 deletions(-) diff --git a/emcc b/emcc index 9eafd685858aa..fed7e9979077e 100755 --- a/emcc +++ b/emcc @@ -1108,10 +1108,45 @@ try: # Note that we assume a single symbol is enough to know if we have/do not have dlmalloc etc. If you # include just a few symbols but want the rest, this will not work. + def read_symbols(path, exclude=None): + symbols = map(lambda line: line.strip().split(' ')[1], open(path).readlines()) + if exclude: + symbols = filter(lambda symbol: symbol not in exclude, symbols) + return set(symbols) + + # XXX We also need to add libc symbols that use malloc, for example strdup. It's very rare to use just them and not + # a normal malloc symbol (like free, after calling strdup), so we haven't hit this yet, but it is possible. + libc_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libc.symbols')) + libcextra_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libcextra.symbols')) + libcxx_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libcxx', 'symbols'), exclude=libc_symbols) + libcxxabi_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libcxxabi', 'symbols'), exclude=libc_symbols) + + def build_libc(lib_filename, files): + o_s = [] + prev_cxx = os.environ.get('EMMAKEN_CXX') + if prev_cxx: os.environ['EMMAKEN_CXX'] = '' + musl_internal_includes = shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'internal') + for src in files: + o = in_temp(os.path.basename(src) + '.o') + execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o, '-I', musl_internal_includes], stdout=stdout, stderr=stderr) + o_s.append(o) + if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx + shared.Building.link(o_s, in_temp(lib_filename)) + return in_temp(lib_filename) + + def build_libcxx(src_dirname, lib_filename, files): + o_s = [] + for src in files: + o = in_temp(src + '.o') + srcfile = shared.path_from_root(src_dirname, src) + execute([shared.PYTHON, shared.EMXX, srcfile, '-o', o, '-std=c++11'], stdout=stdout, stderr=stderr) + o_s.append(o) + shared.Building.link(o_s, in_temp(lib_filename)) + return in_temp(lib_filename) + # libc def create_libc(): if DEBUG: print >> sys.stderr, 'emcc: building libc for cache' - o_s = [] libc_files = [ 'dlmalloc.c', os.path.join('libcxx', 'new.cpp'), @@ -1126,23 +1161,7 @@ try: os.path.join('libc', 'gen', 'vwarnx.c'), os.path.join('libc', 'stdlib', 'strtod.c'), ]; - - musl_files = [] - - for directory, sources in musl_files: - libc_files += [os.path.join('libc', 'musl', 'src', directory, source) for source in sources] - - prev_cxx = os.environ.get('EMMAKEN_CXX') - if prev_cxx: os.environ['EMMAKEN_CXX'] = '' - musl_internal_includes = shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'internal') - for src in libc_files: - o = in_temp(os.path.basename(src) + '.o') - execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o, '-I', musl_internal_includes], stdout=stdout, stderr=stderr) - o_s.append(o) - if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx - - shared.Building.link(o_s, in_temp('libc.bc')) - return in_temp('libc.bc') + return build_libc('libc.bc', libc_files) def fix_libc(need): # libc needs some sign correction. # If we are in mode 0, switch to 2. We will add our lines @@ -1154,17 +1173,10 @@ try: shared.Settings.CORRECT_SIGNS_LINES = [shared.path_from_root('src', 'dlmalloc.c') + ':' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]] # If we are in mode 1, we are correcting everything anyhow. If we are in mode 3, we will be corrected # so all is well anyhow too. - # XXX We also need to add libc symbols that use malloc, for example strdup. It's very rare to use just them and not - # a normal malloc symbol (like free, after calling strdup), so we haven't hit this yet, but it is possible. - libc_symbols = map(lambda line: line.strip().split(' ')[1], open(shared.path_from_root('system', 'lib', 'libc.symbols')).readlines()) - libc_symbols = set(libc_symbols) # libcextra def create_libcextra(): if DEBUG: print >> sys.stderr, 'emcc: building libcextra for cache' - o_s = [] - libcextra_files = [] - musl_files = [ ['multibyte', [ 'btowc.c', @@ -1214,32 +1226,17 @@ try: 'wmemset.c', ]] ] - libcextra_files = [] for directory, sources in musl_files: libcextra_files += [os.path.join('libc', 'musl', 'src', directory, source) for source in sources] - - prev_cxx = os.environ.get('EMMAKEN_CXX') - if prev_cxx: os.environ['EMMAKEN_CXX'] = '' - musl_internal_includes = shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'internal') - for src in libcextra_files: - o = in_temp(os.path.basename(src) + '.o') - execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o, '-I', musl_internal_includes], stdout=stdout, stderr=stderr) - o_s.append(o) - if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx - - shared.Building.link(o_s, in_temp('libcextra.bc')) - return in_temp('libcextra.bc') + return build_libc('libcextra.bc', libcextra_files) def fix_libcextra(need): pass - libcextra_symbols = map(lambda line: line.strip().split(' ')[1], open(shared.path_from_root('system', 'lib', 'libcextra.symbols')).readlines()) - libcextra_symbols = set(libcextra_symbols) # libcxx def create_libcxx(): if DEBUG: print >> sys.stderr, 'emcc: building libcxx for cache' - os = [] libcxx_files = [ 'algorithm.cpp', 'condition_variable.cpp', @@ -1264,44 +1261,27 @@ try: 'regex.cpp', 'strstream.cpp' ] - for src in libcxx_files: - o = in_temp(src + '.o') - srcfile = shared.path_from_root('system', 'lib', 'libcxx', src) - execute([shared.PYTHON, shared.EMXX, srcfile, '-o', o, '-std=c++11'], stdout=stdout, stderr=stderr) - os.append(o) - shared.Building.link(os, in_temp('libcxx.bc')) - return in_temp('libcxx.bc') + return build_libcxx(os.path.join('system', 'lib', 'libcxx'), 'libcxx.bc', libcxx_files) + def fix_libcxx(need): assert shared.Settings.QUANTUM_SIZE == 4, 'We do not support libc++ with QUANTUM_SIZE == 1' # libcxx might need corrections, so turn them all on. TODO: check which are actually needed shared.Settings.CORRECT_SIGNS = shared.Settings.CORRECT_OVERFLOWS = shared.Settings.CORRECT_ROUNDINGS = 1 #print >> sys.stderr, 'emcc: info: using libcxx turns on CORRECT_* options' - libcxx_symbols = map(lambda line: line.strip().split(' ')[1], open(shared.path_from_root('system', 'lib', 'libcxx', 'symbols')).readlines()) - libcxx_symbols = filter(lambda symbol: symbol not in libc_symbols, libcxx_symbols) - libcxx_symbols = set(libcxx_symbols) # libcxxabi - just for dynamic_cast for now def create_libcxxabi(): if DEBUG: print >> sys.stderr, 'emcc: building libcxxabi for cache' - os = [] libcxxabi_files = [ 'typeinfo.cpp', 'private_typeinfo.cpp' ] - for src in libcxxabi_files: - o = in_temp(src + '.o') - srcfile = shared.path_from_root('system', 'lib', 'libcxxabi', 'src', src) - execute([shared.PYTHON, shared.EMXX, srcfile, '-o', o, '-std=c++11'], stdout=stdout, stderr=stderr) - os.append(o) - shared.Building.link(os, in_temp('libcxxabi.bc')) - return in_temp('libcxxabi.bc') + return build_libcxx(os.path.join('system', 'lib', 'libcxxabi', 'src'), 'libcxxabi.bc', libcxxabi_files) + def fix_libcxxabi(need): assert shared.Settings.QUANTUM_SIZE == 4, 'We do not support libc++abi with QUANTUM_SIZE == 1' #print >> sys.stderr, 'emcc: info: using libcxxabi, this may need CORRECT_* options' #shared.Settings.CORRECT_SIGNS = shared.Settings.CORRECT_OVERFLOWS = shared.Settings.CORRECT_ROUNDINGS = 1 - libcxxabi_symbols = map(lambda line: line.strip().split(' ')[1], open(shared.path_from_root('system', 'lib', 'libcxxabi', 'symbols')).readlines()) - libcxxabi_symbols = filter(lambda symbol: symbol not in libc_symbols, libcxxabi_symbols) - libcxxabi_symbols = set(libcxxabi_symbols) # If we have libcxx, we must force inclusion of libc, since libcxx uses new internally. Note: this is kind of hacky # Settings this in the environment will avoid checking dependencies and make building big projects a little faster From 443c7789afe003e4563dec22c0278650de40aee8 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 23 Apr 2013 11:10:49 +0700 Subject: [PATCH 534/544] Better guessing for LLVM_ROOT. On OS X, there is a system-wide clang that is the wrong version, so the guessing goes wrong. Looking for llvm-dis is less likely to go wrong and is also required by the build process. --- tools/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index 6b5ad835a8f05..748b509ca4056 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -111,7 +111,7 @@ def path_from_root(*pathelems): config_file = config_file.replace('{{{ EMSCRIPTEN_ROOT }}}', __rootpath__) llvm_root = '/usr/bin' try: - llvm_root = os.path.dirname(Popen(['which', 'clang'], stdout=PIPE).communicate()[0].replace('\n', '')) + llvm_root = os.path.dirname(Popen(['which', 'llvm-dis'], stdout=PIPE).communicate()[0].replace('\n', '')) except: pass config_file = config_file.replace('{{{ LLVM_ROOT }}}', llvm_root) From 23ed21d54e73db3597b64b6b06ab09194717c1c4 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 23 Apr 2013 10:54:59 -0700 Subject: [PATCH 535/544] clear errors on calling dead functions --- src/compiler.js | 2 ++ src/jsifier.js | 4 ++++ src/parseTools.js | 9 +++++---- tests/runner.py | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/compiler.js b/src/compiler.js index 9c19aeb0f80dc..d74ff7cbb2c10 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -168,6 +168,8 @@ if (SAFE_HEAP >= 2) { EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS); EXPORTED_GLOBALS = set(EXPORTED_GLOBALS); EXCEPTION_CATCHING_WHITELIST = set(EXCEPTION_CATCHING_WHITELIST); + +if (DEAD_FUNCTIONS.length && ASSERTIONS) DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push('putchar'); // for debug output DEAD_FUNCTIONS = numberedSet(DEAD_FUNCTIONS); RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG; diff --git a/src/jsifier.js b/src/jsifier.js index 9678a56d6adbb..6d8def393dabd 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1441,6 +1441,10 @@ function JSify(data, functionsOnly, givenFunctions) { if (callIdent in DEAD_FUNCTIONS) { var ret = 'abort(' + DEAD_FUNCTIONS[callIdent] + ')'; if (ASM_JS) ret = asmCoercion(ret, returnType); + if (ASSERTIONS) { + assert(DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.indexOf('putchar') >= 0, 'need putchar for DEAD_FUNCTIONS + ASSERTIONS output'); + ret = '(' + makePrintChars('dead:' + callIdent, ',') + ',' + ret + ')'; + } return ret; } diff --git a/src/parseTools.js b/src/parseTools.js index fe21dfd5c70b5..8347a929ed3c4 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -2363,13 +2363,14 @@ function getTypeFromHeap(suffix) { } } -// Generates code that prints without printf(), but just putchar (so can be directly inline) -function makePrintChars(s) { +// Generates code that prints without printf(), but just putchar (so can be directly inline in asm.js) +function makePrintChars(s, sep) { + sep = sep || ';'; var ret = ''; for (var i = 0; i < s.length; i++) { - ret += '_putchar(' + s.charCodeAt(i) + ');'; + ret += '_putchar(' + s.charCodeAt(i) + ')' + sep; } - ret += '_putchar(10);'; + ret += '_putchar(10)'; return ret; } diff --git a/tests/runner.py b/tests/runner.py index 33a2ef67931c9..bd6fd83870878 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -8070,7 +8070,7 @@ def test(expected, args=[], no_build=False): Settings.DEAD_FUNCTIONS = [] # Run the same code with argc that uses the dead function, see abort - test(('abort', 'is not a function'), args=['a', 'b'], no_build=True) + test(('dead:_unused' if Settings.ASSERTIONS else 'abort', 'is not a function'), args=['a', 'b'], no_build=True) # Normal stuff run_all('normal', r''' From 27601a8a9f19446c84f1904e460375a29564b192 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 23 Apr 2013 11:16:11 -0700 Subject: [PATCH 536/544] add test for repeated longjmp to a single setjmp --- tests/runner.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/runner.py b/tests/runner.py index bd6fd83870878..76dde5582f736 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -2524,6 +2524,34 @@ def test_longjmp_funcptr(self): ''' self.do_run(src, 'second\nmain: 1\n') + def test_longjmp_repeat(self): + Settings.MAX_SETJMPS = 1 + + src = r''' + #include + #include + + static jmp_buf buf; + + int main() { + volatile int x = 0; + printf("setjmp:%d\n", setjmp(buf)); + x++; + printf("x:%d\n", x); + if (x < 4) longjmp(buf, x*2); + return 0; + } + ''' + self.do_run(src, '''setjmp:0 +x:1 +setjmp:2 +x:2 +setjmp:4 +x:3 +setjmp:6 +x:4 +''') + def test_setjmp_many(self): src = r''' #include From fb9103426684a1fa70736febe147df49aedc91a5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 23 Apr 2013 14:09:08 -0700 Subject: [PATCH 537/544] add a define of __EMSCRIPTEN__ --- tools/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index 748b509ca4056..51447c05d5bc4 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -401,7 +401,7 @@ def clean_temp(): # Force a simple, standard target as much as possible: target 32-bit linux, and disable various flags that hint at other platforms COMPILER_OPTS = COMPILER_OPTS + ['-m32', '-U__i386__', '-U__i386', '-Ui386', '-U__SSE__', '-U__SSE_MATH__', '-U__SSE2__', '-U__SSE2_MATH__', '-U__MMX__', - '-DEMSCRIPTEN', '-U__STRICT_ANSI__', + '-DEMSCRIPTEN', '-D__EMSCRIPTEN__', '-U__STRICT_ANSI__', '-target', 'i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno'] USE_EMSDK = not os.environ.get('EMMAKEN_NO_SDK') From a5e96a395fcd69e44b7df074151e5c9783c1ded6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 23 Apr 2013 14:56:14 -0700 Subject: [PATCH 538/544] fix memory corruption in setjmp/asm.js; fixes #1087 --- src/jsifier.js | 1 + tests/runner.py | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/jsifier.js b/src/jsifier.js index 6d8def393dabd..cd18f74d43359 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -713,6 +713,7 @@ function JSify(data, functionsOnly, givenFunctions) { } else { ret += 'var setjmpLabel = 0;\n'; ret += 'var setjmpTable = ' + RuntimeGenerator.stackAlloc(4 * (MAX_SETJMPS + 1) * 2) + ';\n'; + ret += makeSetValue('setjmpTable', '0', '0', 'i32') + ';'; // initialize first entry to 0 } } ret += indent + 'while(1) '; diff --git a/tests/runner.py b/tests/runner.py index 76dde5582f736..ea0609bcb215b 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -2550,6 +2550,66 @@ def test_longjmp_repeat(self): x:3 setjmp:6 x:4 +''') + + def test_longjmp_stacked(self): + src = r''' + #include + #include + #include + #include + + int bottom, top; + + int run(int y) { + // confuse stack + char *s = (char*)alloca(100); + memset(s, 1, 100); + s[y] = y; + s[y/2] = y*2; + volatile int x = s[y]; + top = (int)alloca(4); + if (x <= 2) return x; + jmp_buf buf; + printf("setjmp of %d\n", x); + if (setjmp(buf) == 0) { + printf("going\n"); + x += run(x/2); + longjmp(buf, 1); + } + printf("back\n"); + return x/2; + } + + int main(int argc, char **argv) { + int sum = 0; + for (int i = 0; i < argc*2; i++) { + bottom = (int)alloca(4); + sum += run(10); + // scorch the earth + if (bottom < top) { + memset((void*)bottom, 1, top - bottom); + } else { + memset((void*)top, 1, bottom - top); + } + } + printf("%d\n", sum); + return sum; + } + ''' + self.do_run(src, '''setjmp of 10 +going +setjmp of 5 +going +back +back +setjmp of 10 +going +setjmp of 5 +going +back +back +12 ''') def test_setjmp_many(self): From b49c89fd54b60b03e437367c30bf92daf4b14d6a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 23 Apr 2013 17:00:53 -0700 Subject: [PATCH 539/544] remove UNRESOLVED_AS_DEAD since it doesn't work --- src/jsifier.js | 2 +- src/settings.js | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index cd18f74d43359..fb761b18c3818 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -487,7 +487,7 @@ function JSify(data, functionsOnly, givenFunctions) { } else if (LibraryManager.library.hasOwnProperty(shortident)) { item.JS = addFromLibrary(shortident); } else if (!LibraryManager.library.hasOwnProperty(shortident + '__inline')) { - if (!(item.ident in DEAD_FUNCTIONS) && !UNRESOLVED_AS_DEAD) { + if (!(item.ident in DEAD_FUNCTIONS)) { item.JS = 'var ' + item.ident + '; // stub for ' + item.ident; if (ASM_JS) { error('Unresolved symbol: ' + item.ident + ', this must be corrected for asm.js validation to succeed. Consider adding it to DEAD_FUNCTIONS.'); diff --git a/src/settings.js b/src/settings.js index d30db173a700d..8c7d1f838b7c6 100644 --- a/src/settings.js +++ b/src/settings.js @@ -351,10 +351,6 @@ var DEAD_FUNCTIONS = []; // Functions on this list are not converted to JS, and // If a dead function is actually called, you will get a runtime // error. // TODO: options to lazily load such functions -var UNRESOLVED_AS_DEAD = 0; // Handle all unresolved functions as if they were in the - // list of dead functions. This is a quick way to turn - // all unresolved references into runtime aborts (and not - // get compile-time warnings or errors on them). var EXPLICIT_ZEXT = 0; // If 1, generate an explicit conversion of zext i1 to i32, using ?: From 4d74114a45901d8b694e1f543b0b8ff6daf10acb Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 23 Apr 2013 18:18:40 -0700 Subject: [PATCH 540/544] emit coercion on i64 math call return values --- src/fastLong.js | 17 +++++++++-------- src/parseTools.js | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/fastLong.js b/src/fastLong.js index 95f398db216bf..d1ce5d39e8e72 100644 --- a/src/fastLong.js +++ b/src/fastLong.js @@ -22,13 +22,13 @@ function ___divdi3($a$0, $a$1, $b$0, $b$1) { $1$1 = (($a$1 | 0) < 0 ? -1 : 0) >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1; $2$0 = $b$1 >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; $2$1 = (($b$1 | 0) < 0 ? -1 : 0) >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; - $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1); + $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1) | 0; $4$1 = tempRet0; - $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1); + $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1) | 0; $7$0 = $2$0 ^ $1$0; $7$1 = $2$1 ^ $1$1; $8$0 = ___udivmoddi4($4$0, $4$1, $6$0, tempRet0, 0) | 0; - $10$0 = _i64Subtract($8$0 ^ $7$0, tempRet0 ^ $7$1, $7$0, $7$1); + $10$0 = _i64Subtract($8$0 ^ $7$0, tempRet0 ^ $7$1, $7$0, $7$1) | 0; return (tempRet0 = tempRet0, $10$0) | 0; } function ___remdi3($a$0, $a$1, $b$0, $b$1) { @@ -44,11 +44,11 @@ function ___remdi3($a$0, $a$1, $b$0, $b$1) { $1$1 = (($a$1 | 0) < 0 ? -1 : 0) >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1; $2$0 = $b$1 >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; $2$1 = (($b$1 | 0) < 0 ? -1 : 0) >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; - $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1); + $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1) | 0; $4$1 = tempRet0; - $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1); + $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1) | 0; ___udivmoddi4($4$0, $4$1, $6$0, tempRet0, $rem); - $10$0 = _i64Subtract(HEAP32[$rem >> 2] ^ $1$0, HEAP32[$rem + 4 >> 2] ^ $1$1, $1$0, $1$1); + $10$0 = _i64Subtract(HEAP32[$rem >> 2] ^ $1$0, HEAP32[$rem + 4 >> 2] ^ $1$1, $1$0, $1$1) | 0; $10$1 = tempRet0; STACKTOP = __stackBase__; return (tempRet0 = $10$1, $10$0) | 0; @@ -245,7 +245,7 @@ function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) { } else { $d_sroa_0_0_insert_insert99$0 = 0 | $b$0 & -1; $d_sroa_0_0_insert_insert99$1 = $d_sroa_1_4_extract_shift$0 | $b$1 & 0; - $137$0 = _i64Add($d_sroa_0_0_insert_insert99$0, $d_sroa_0_0_insert_insert99$1, -1, -1); + $137$0 = _i64Add($d_sroa_0_0_insert_insert99$0, $d_sroa_0_0_insert_insert99$1, -1, -1) | 0; $137$1 = tempRet0; $q_sroa_1_1198 = $q_sroa_1_1_ph; $q_sroa_0_1199 = $q_sroa_0_1_ph; @@ -262,7 +262,7 @@ function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) { $150$1 = tempRet0; $151$0 = $150$1 >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1; $152 = $151$0 & 1; - $154$0 = _i64Subtract($r_sroa_0_0_insert_insert42$0, $r_sroa_0_0_insert_insert42$1, $151$0 & $d_sroa_0_0_insert_insert99$0, ((($150$1 | 0) < 0 ? -1 : 0) >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1) & $d_sroa_0_0_insert_insert99$1); + $154$0 = _i64Subtract($r_sroa_0_0_insert_insert42$0, $r_sroa_0_0_insert_insert42$1, $151$0 & $d_sroa_0_0_insert_insert99$0, ((($150$1 | 0) < 0 ? -1 : 0) >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1) & $d_sroa_0_0_insert_insert99$1) | 0; $r_sroa_0_0_extract_trunc = $154$0; $r_sroa_1_4_extract_trunc = tempRet0; $155 = $sr_1202 - 1 | 0; @@ -296,3 +296,4 @@ function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) { return (tempRet0 = $_0$1, $_0$0) | 0; } // ======================================================================= + diff --git a/src/parseTools.js b/src/parseTools.js index 8347a929ed3c4..f4ce12d52bfd4 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -2000,7 +2000,7 @@ function processMathop(item) { } function preciseCall(name) { Types.preciseI64MathUsed = true; - return finish([name + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + ')', 'tempRet0']); + return finish([asmCoercion(name + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + ')', 'i32'), 'tempRet0']); } function i64PreciseLib(type) { return preciseCall('_i64' + type[0].toUpperCase() + type.substr(1)); From 7bba036d79ee219f46402cd914504adf5a199230 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 23 Apr 2013 18:22:27 -0700 Subject: [PATCH 541/544] coerce output of bitshift* --- src/analyzer.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/analyzer.js b/src/analyzer.js index 3278139b2ffe0..7fbdf24dea7f1 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -660,10 +660,12 @@ function analyzer(data, sidePass) { assert(PRECISE_I64_MATH, 'Must have precise i64 math for non-constant 64-bit shifts'); Types.preciseI64MathUsed = 1; value.intertype = 'value'; - value.ident = 'var ' + value.assignTo + '$0 = _bitshift64' + value.op[0].toUpperCase() + value.op.substr(1) + '(' + - asmCoercion(sourceElements[0].ident, 'i32') + ',' + - asmCoercion(sourceElements[1].ident, 'i32') + ',' + - asmCoercion(value.params[1].ident + '$0', 'i32') + ');' + + value.ident = 'var ' + value.assignTo + '$0 = ' + + asmCoercion('_bitshift64' + value.op[0].toUpperCase() + value.op.substr(1) + '(' + + asmCoercion(sourceElements[0].ident, 'i32') + ',' + + asmCoercion(sourceElements[1].ident, 'i32') + ',' + + asmCoercion(value.params[1].ident + '$0', 'i32') + ')', 'i32' + ) + ';' + 'var ' + value.assignTo + '$1 = tempRet0;'; value.assignTo = null; i++; From 5b300b8e00e089ad9c5eba04738632b39f9002a0 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 23 Apr 2013 18:26:32 -0700 Subject: [PATCH 542/544] properly coerce setjmp helpers --- src/jsifier.js | 2 +- src/library.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index fb761b18c3818..30a06d760e24e 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1481,7 +1481,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (ASM_JS && funcData.setjmpTable) { // check if a longjmp was done. If a setjmp happened, check if ours. If ours, go to -111 to handle it. // otherwise, just return - the call to us must also have been an invoke, so the setjmp propagates that way - ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) > 0)) { setjmpLabel = _testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable); if ((setjmpLabel|0) > 0) { label = -1111; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;\n'; + ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) > 0)) { setjmpLabel = ' + asmCoercion('_testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable)', 'i32') + '; if ((setjmpLabel|0) > 0) { label = -1111; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;\n'; } return ret; diff --git a/src/library.js b/src/library.js index 91270c384f55a..daba06111fa03 100644 --- a/src/library.js +++ b/src/library.js @@ -6272,7 +6272,7 @@ LibraryManager.library = { setjmp__inline: function(env) { // Save the label #if ASM_JS - return '_saveSetjmp(' + env + ', label, setjmpTable)'; + return '_saveSetjmp(' + env + ', label, setjmpTable)|0'; #else return '(tempInt = setjmpId++, mySetjmpIds[tempInt] = 1, setjmpLabels[tempInt] = label,' + makeSetValue(env, '0', 'tempInt', 'i32', undefined, undefined, undefined, undefined, ',') + ', 0)'; #endif From 57331dbc8dbc8b88c29f1067a32d5631fda0bcc3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 23 Apr 2013 18:28:26 -0700 Subject: [PATCH 543/544] add missing coercion in strcat --- src/library.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library.js b/src/library.js index daba06111fa03..7fbe335dade27 100644 --- a/src/library.js +++ b/src/library.js @@ -4437,7 +4437,7 @@ LibraryManager.library = { strcat: function(pdest, psrc) { pdest = pdest|0; psrc = psrc|0; var i = 0; - pdest = (pdest + _strlen(pdest))|0; + pdest = (pdest + (_strlen(pdest)|0))|0; do { {{{ makeCopyValues('pdest+i', 'psrc+i', 1, 'i8', null, 1) }}}; i = (i+1)|0; From 430dcb4c1533a7c2e9486a2bcbb4e0bda3025c0c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 23 Apr 2013 18:40:59 -0700 Subject: [PATCH 544/544] add coercion in strncasecmp --- src/library.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/library.js b/src/library.js index 7fbe335dade27..04878ffc9bf78 100644 --- a/src/library.js +++ b/src/library.js @@ -4501,8 +4501,8 @@ LibraryManager.library = { px = px|0; py = py|0; n = n|0; var i = 0, x = 0, y = 0; while ((i>>>0) < (n>>>0)) { - x = _tolower({{{ makeGetValueAsm('px', 'i', 'i8', 0, 1) }}}); - y = _tolower({{{ makeGetValueAsm('py', 'i', 'i8', 0, 1) }}}); + x = _tolower({{{ makeGetValueAsm('px', 'i', 'i8', 0, 1) }}})|0; + y = _tolower({{{ makeGetValueAsm('py', 'i', 'i8', 0, 1) }}})|0; if (((x|0) == (y|0)) & ((x|0) == 0)) return 0; if ((x|0) == 0) return -1; if ((y|0) == 0) return 1;