From 6df9737f9cbaf410853514463ef59e215fc698ba Mon Sep 17 00:00:00 2001 From: Travis Bradshaw Date: Tue, 31 Jan 2012 15:48:05 -0600 Subject: [PATCH] The source release of the qutils. --- qutils/BIN/BSPINFO.EXE | Bin 0 -> 54784 bytes qutils/BIN/LIGHT.EXE | Bin 0 -> 84992 bytes qutils/BIN/MODELGEN.EXE | Bin 0 -> 89600 bytes qutils/BIN/QBSP.EXE | Bin 0 -> 128512 bytes qutils/BIN/QCC.EXE | Bin 0 -> 72192 bytes qutils/BIN/QFILES.EXE | Bin 0 -> 54272 bytes qutils/BIN/QLUMPY.EXE | Bin 0 -> 55808 bytes qutils/BIN/SPRGEN.EXE | Bin 0 -> 48640 bytes qutils/BIN/TEXMAKE.EXE | Bin 0 -> 55296 bytes qutils/BIN/VIS.EXE | Bin 0 -> 81408 bytes qutils/BSPINFO/BSPINFO.C | 25 + qutils/BSPINFO/BSPINFO.MAK | 234 +++++++ qutils/BSPINFO/BSPINFO.MDP | Bin 0 -> 35840 bytes qutils/BSPINFO/BSPINFO.NCB | Bin 0 -> 74752 bytes qutils/COMMON/BSPFILE.C | 375 +++++++++++ qutils/COMMON/BSPFILE.H | 251 +++++++ qutils/COMMON/CMDLIB.C | 867 ++++++++++++++++++++++++ qutils/COMMON/CMDLIB.H | 97 +++ qutils/COMMON/LBMLIB.C | 508 ++++++++++++++ qutils/COMMON/LBMLIB.H | 42 ++ qutils/COMMON/MATHLIB.C | 109 +++ qutils/COMMON/MATHLIB.H | 48 ++ qutils/COMMON/POLYLIB.C | 400 +++++++++++ qutils/COMMON/POLYLIB.H | 22 + qutils/COMMON/SCRIPLIB.C | 185 ++++++ qutils/COMMON/SCRIPLIB.H | 21 + qutils/COMMON/THREADS.C | 239 +++++++ qutils/COMMON/THREADS.H | 8 + qutils/COMMON/TRILIB.C | 170 +++++ qutils/COMMON/TRILIB.H | 11 + qutils/COMMON/WADLIB.C | 328 +++++++++ qutils/COMMON/WADLIB.H | 53 ++ qutils/INSTALL.BAT | 43 ++ qutils/LIGHT/ENTITIES.C | 278 ++++++++ qutils/LIGHT/ENTITIES.H | 33 + qutils/LIGHT/LIGHT.C | 146 ++++ qutils/LIGHT/LIGHT.H | 38 ++ qutils/LIGHT/LIGHT.MAK | 407 ++++++++++++ qutils/LIGHT/LIGHT.MDP | Bin 0 -> 37376 bytes qutils/LIGHT/LIGHT.NCB | Bin 0 -> 99328 bytes qutils/LIGHT/LTFACE.C | 588 +++++++++++++++++ qutils/LIGHT/THREADS.C | 66 ++ qutils/LIGHT/THREADS.H | 17 + qutils/LIGHT/TRACE.C | 197 ++++++ qutils/MODELGEN/ANORMS.H | 162 +++++ qutils/MODELGEN/MODELGEN.C | 1212 ++++++++++++++++++++++++++++++++++ qutils/MODELGEN/MODELGEN.H | 113 ++++ qutils/MODELGEN/MODELGEN.MAK | 294 +++++++++ qutils/MODELGEN/MODELGEN.MDP | Bin 0 -> 36352 bytes qutils/MODELGEN/MODELGEN.NCB | Bin 0 -> 91136 bytes qutils/QBSP/BRUSH.C | 870 ++++++++++++++++++++++++ qutils/QBSP/BSP5.H | 297 +++++++++ qutils/QBSP/CSG4.C | 464 +++++++++++++ qutils/QBSP/MAKEFILE | 65 ++ qutils/QBSP/MAP.C | 579 ++++++++++++++++ qutils/QBSP/MAP.H | 50 ++ qutils/QBSP/MERGE.C | 277 ++++++++ qutils/QBSP/NODRAW.C | 54 ++ qutils/QBSP/OUTSIDE.C | 252 +++++++ qutils/QBSP/PORTALS.C | 576 ++++++++++++++++ qutils/QBSP/QBSP.C | 1030 +++++++++++++++++++++++++++++ qutils/QBSP/QBSP.MAK | 527 +++++++++++++++ qutils/QBSP/QBSP.MDP | Bin 0 -> 38400 bytes qutils/QBSP/QBSP.NCB | Bin 0 -> 123904 bytes qutils/QBSP/REGION.C | 511 ++++++++++++++ qutils/QBSP/SOLIDBSP.C | 754 +++++++++++++++++++++ qutils/QBSP/SURFACES.C | 512 ++++++++++++++ qutils/QBSP/TJUNC.C | 506 ++++++++++++++ qutils/QBSP/WRITEBSP.C | 523 +++++++++++++++ qutils/QCC/MAKEFILE | 42 ++ qutils/QCC/PR_COMP.C | 936 ++++++++++++++++++++++++++ qutils/QCC/PR_COMP.H | 161 +++++ qutils/QCC/PR_LEX.C | 677 +++++++++++++++++++ qutils/QCC/QCC | Bin 0 -> 146232 bytes qutils/QCC/QCC.C | 808 +++++++++++++++++++++++ qutils/QCC/QCC.H | 436 ++++++++++++ qutils/QCC/QCC.MAK | 249 +++++++ qutils/QCC/QCC.MDP | Bin 0 -> 36352 bytes qutils/QCC/QCC.NCB | Bin 0 -> 99328 bytes qutils/QCC/QCC.PDB | Bin 0 -> 164864 bytes qutils/QCC/VC40.PDB | Bin 0 -> 45056 bytes qutils/QFILES/QFILES.C | 251 +++++++ qutils/QFILES/QFILES.MAK | 221 +++++++ qutils/QFILES/QFILES.MDP | Bin 0 -> 36352 bytes qutils/QFILES/QFILES.NCB | Bin 0 -> 58368 bytes qutils/QLUMPY/QLUMPY.C | 301 +++++++++ qutils/QLUMPY/QLUMPY.H | 16 + qutils/QLUMPY/QLUMPY.MAK | 324 +++++++++ qutils/QLUMPY/QLUMPY.MDP | Bin 0 -> 36352 bytes qutils/QLUMPY/QLUMPY.NCB | Bin 0 -> 107520 bytes qutils/QLUMPY/QUAKEGRB.C | 523 +++++++++++++++ qutils/README.TXT | 148 +++++ qutils/SPRGEN/SPRGEN.C | 526 +++++++++++++++ qutils/SPRGEN/SPRGEN.MAK | 300 +++++++++ qutils/SPRGEN/SPRGEN.MDP | Bin 0 -> 36352 bytes qutils/SPRGEN/SPRGEN.NCB | Bin 0 -> 82944 bytes qutils/SPRGEN/SPRITEGN.H | 88 +++ qutils/SPRGEN/S_BUBBLE.SPR | Bin 0 -> 588 bytes qutils/SPRGEN/S_EXPLOD.SPR | Bin 0 -> 18972 bytes qutils/SPRGEN/S_LIGHT.SPR | Bin 0 -> 1080 bytes qutils/TEXMAKE/TEXMAKE.C | 222 +++++++ qutils/TEXMAKE/TEXMAKE.MAK | 269 ++++++++ qutils/TEXMAKE/TEXMAKE.MDP | Bin 0 -> 35840 bytes qutils/TEXMAKE/TEXMAKE.NCB | Bin 0 -> 58368 bytes qutils/VIS/FLOW.C | 475 +++++++++++++ qutils/VIS/SOUNDPVS.C | 146 ++++ qutils/VIS/VIS.C | 963 +++++++++++++++++++++++++++ qutils/VIS/VIS.H | 125 ++++ qutils/VIS/VIS.MAK | 288 ++++++++ qutils/VIS/VIS.MDP | Bin 0 -> 35840 bytes qutils/VIS/VIS.NCB | Bin 0 -> 74752 bytes 111 files changed, 23929 insertions(+) create mode 100644 qutils/BIN/BSPINFO.EXE create mode 100644 qutils/BIN/LIGHT.EXE create mode 100644 qutils/BIN/MODELGEN.EXE create mode 100644 qutils/BIN/QBSP.EXE create mode 100644 qutils/BIN/QCC.EXE create mode 100644 qutils/BIN/QFILES.EXE create mode 100644 qutils/BIN/QLUMPY.EXE create mode 100644 qutils/BIN/SPRGEN.EXE create mode 100644 qutils/BIN/TEXMAKE.EXE create mode 100644 qutils/BIN/VIS.EXE create mode 100644 qutils/BSPINFO/BSPINFO.C create mode 100644 qutils/BSPINFO/BSPINFO.MAK create mode 100644 qutils/BSPINFO/BSPINFO.MDP create mode 100644 qutils/BSPINFO/BSPINFO.NCB create mode 100644 qutils/COMMON/BSPFILE.C create mode 100644 qutils/COMMON/BSPFILE.H create mode 100644 qutils/COMMON/CMDLIB.C create mode 100644 qutils/COMMON/CMDLIB.H create mode 100644 qutils/COMMON/LBMLIB.C create mode 100644 qutils/COMMON/LBMLIB.H create mode 100644 qutils/COMMON/MATHLIB.C create mode 100644 qutils/COMMON/MATHLIB.H create mode 100644 qutils/COMMON/POLYLIB.C create mode 100644 qutils/COMMON/POLYLIB.H create mode 100644 qutils/COMMON/SCRIPLIB.C create mode 100644 qutils/COMMON/SCRIPLIB.H create mode 100644 qutils/COMMON/THREADS.C create mode 100644 qutils/COMMON/THREADS.H create mode 100644 qutils/COMMON/TRILIB.C create mode 100644 qutils/COMMON/TRILIB.H create mode 100644 qutils/COMMON/WADLIB.C create mode 100644 qutils/COMMON/WADLIB.H create mode 100644 qutils/INSTALL.BAT create mode 100644 qutils/LIGHT/ENTITIES.C create mode 100644 qutils/LIGHT/ENTITIES.H create mode 100644 qutils/LIGHT/LIGHT.C create mode 100644 qutils/LIGHT/LIGHT.H create mode 100644 qutils/LIGHT/LIGHT.MAK create mode 100644 qutils/LIGHT/LIGHT.MDP create mode 100644 qutils/LIGHT/LIGHT.NCB create mode 100644 qutils/LIGHT/LTFACE.C create mode 100644 qutils/LIGHT/THREADS.C create mode 100644 qutils/LIGHT/THREADS.H create mode 100644 qutils/LIGHT/TRACE.C create mode 100644 qutils/MODELGEN/ANORMS.H create mode 100644 qutils/MODELGEN/MODELGEN.C create mode 100644 qutils/MODELGEN/MODELGEN.H create mode 100644 qutils/MODELGEN/MODELGEN.MAK create mode 100644 qutils/MODELGEN/MODELGEN.MDP create mode 100644 qutils/MODELGEN/MODELGEN.NCB create mode 100644 qutils/QBSP/BRUSH.C create mode 100644 qutils/QBSP/BSP5.H create mode 100644 qutils/QBSP/CSG4.C create mode 100644 qutils/QBSP/MAKEFILE create mode 100644 qutils/QBSP/MAP.C create mode 100644 qutils/QBSP/MAP.H create mode 100644 qutils/QBSP/MERGE.C create mode 100644 qutils/QBSP/NODRAW.C create mode 100644 qutils/QBSP/OUTSIDE.C create mode 100644 qutils/QBSP/PORTALS.C create mode 100644 qutils/QBSP/QBSP.C create mode 100644 qutils/QBSP/QBSP.MAK create mode 100644 qutils/QBSP/QBSP.MDP create mode 100644 qutils/QBSP/QBSP.NCB create mode 100644 qutils/QBSP/REGION.C create mode 100644 qutils/QBSP/SOLIDBSP.C create mode 100644 qutils/QBSP/SURFACES.C create mode 100644 qutils/QBSP/TJUNC.C create mode 100644 qutils/QBSP/WRITEBSP.C create mode 100644 qutils/QCC/MAKEFILE create mode 100644 qutils/QCC/PR_COMP.C create mode 100644 qutils/QCC/PR_COMP.H create mode 100644 qutils/QCC/PR_LEX.C create mode 100644 qutils/QCC/QCC create mode 100644 qutils/QCC/QCC.C create mode 100644 qutils/QCC/QCC.H create mode 100644 qutils/QCC/QCC.MAK create mode 100644 qutils/QCC/QCC.MDP create mode 100644 qutils/QCC/QCC.NCB create mode 100644 qutils/QCC/QCC.PDB create mode 100644 qutils/QCC/VC40.PDB create mode 100644 qutils/QFILES/QFILES.C create mode 100644 qutils/QFILES/QFILES.MAK create mode 100644 qutils/QFILES/QFILES.MDP create mode 100644 qutils/QFILES/QFILES.NCB create mode 100644 qutils/QLUMPY/QLUMPY.C create mode 100644 qutils/QLUMPY/QLUMPY.H create mode 100644 qutils/QLUMPY/QLUMPY.MAK create mode 100644 qutils/QLUMPY/QLUMPY.MDP create mode 100644 qutils/QLUMPY/QLUMPY.NCB create mode 100644 qutils/QLUMPY/QUAKEGRB.C create mode 100644 qutils/README.TXT create mode 100644 qutils/SPRGEN/SPRGEN.C create mode 100644 qutils/SPRGEN/SPRGEN.MAK create mode 100644 qutils/SPRGEN/SPRGEN.MDP create mode 100644 qutils/SPRGEN/SPRGEN.NCB create mode 100644 qutils/SPRGEN/SPRITEGN.H create mode 100644 qutils/SPRGEN/S_BUBBLE.SPR create mode 100644 qutils/SPRGEN/S_EXPLOD.SPR create mode 100644 qutils/SPRGEN/S_LIGHT.SPR create mode 100644 qutils/TEXMAKE/TEXMAKE.C create mode 100644 qutils/TEXMAKE/TEXMAKE.MAK create mode 100644 qutils/TEXMAKE/TEXMAKE.MDP create mode 100644 qutils/TEXMAKE/TEXMAKE.NCB create mode 100644 qutils/VIS/FLOW.C create mode 100644 qutils/VIS/SOUNDPVS.C create mode 100644 qutils/VIS/VIS.C create mode 100644 qutils/VIS/VIS.H create mode 100644 qutils/VIS/VIS.MAK create mode 100644 qutils/VIS/VIS.MDP create mode 100644 qutils/VIS/VIS.NCB diff --git a/qutils/BIN/BSPINFO.EXE b/qutils/BIN/BSPINFO.EXE new file mode 100644 index 0000000000000000000000000000000000000000..bc95fc9a42e252a58f1a48d9ab62ee9252995787 GIT binary patch literal 54784 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 X6VL=S0Zl*?&;&FAO+XX)zaj7+Hl{{O literal 0 HcmV?d00001 diff --git a/qutils/BIN/LIGHT.EXE b/qutils/BIN/LIGHT.EXE new file mode 100644 index 0000000000000000000000000000000000000000..d2ed09505dce1df0fb84a62f355a18408805020f GIT binary patch literal 84992 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℞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 literal 0 HcmV?d00001 diff --git a/qutils/BIN/MODELGEN.EXE b/qutils/BIN/MODELGEN.EXE new file mode 100644 index 0000000000000000000000000000000000000000..825b9c6027ad82172a675907ad50944ff90ab28b GIT binary patch literal 89600 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 >}LC~+Ky2$Q#&uz^x|u4H=uc$HB$VA7xHePt8# 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

FWv6m04F~W{R~9vW>)yk!^Eg9lF={qOHMpm~eWX zRr`Gu#s?3HCa7N{hB&X(_fRJxl?nG=3dPj&F7lF+QZs! zwa2t4wO;LN)VHf%tG8f_CTJ~GMv>dj4YdL0-Sre>7ti!Exw7@d!O02|>Sf8?PW;5r9 z)_Us~)^DwUTDf}uocUM9X~ig|T3MuYDj!6R!ZgvETQ%=%zR(nC=V_nPzM_3kyG{F- z_EU_9bo7~3#s`f(OhZlc!9#p(Itc#ZBshq!=3W^2Bh3!;QnSar1#8D1OE=&!)wt*{6SY<| zRx?FYtl6PCs`-(P<}uoA?c>^?wWqWlbp6n4wt#}euyWSvKiB`H{|g*aZ-Wved6nUQ z!()bL3@;eoG<<3J%W%!m-WYA{Y3z?a|A?`pX{5u6JCse}Hab}%{t2?PXg<0TlofLdztUg|!pdYSR>&^OPeL8rJY5D?vvHr0BTfI16 z%gt)67iM#!IoUiG{6MBT2dl@l|6(40*8DtXfY-q(ZpE5dk5zHEd9S(D>Y{T12*LGm z*2;Hk_G-S=e5*OBIfdEkZ;ezNsg2dfYZJ7?wQ8*y{Bg7{Ru`ws)aB@qAovSXAV`5A z1%ea^QXoiyAO(UH2vQ(OfglBf6bMovNP!>)f)of+AV`5A1%ea^QXoiyAO(UH2vQ(O zfglBf6bMovNP!>)f)of+AV`5A1%ea^QXoiyAO(UH2vQ(OfglBf6bMovNP!>)f)of+ zAV`5A1%ea^QXoiyAO(UH2vQ(OfglBf6bMovNP!>)f)of+AV`5A1%ea^QXoiyAO(UH L2vXqxLkj#a|9zmX literal 0 HcmV?d00001 diff --git a/qutils/BIN/QBSP.EXE b/qutils/BIN/QBSP.EXE new file mode 100644 index 0000000000000000000000000000000000000000..8eaf56a5ed6c0caa21a85cb433c46d1efb63d4a8 GIT binary patch literal 128512 zcmeFae|S{YwLd&bW|9#n%!q>>bRwf2+gyp7n%E{LXae~qB2EZQup(fkbd0D-XB2Bl zNKevwJdCw1R=w9>X|(mW-u|@rf}%+b5U^;it?i6}Vr$z?gDnb`sK|UjpS8~<0l9s@ zeV+H9_j%qZbI$&~_S$Q&z4lsb?{mfH?{VZg91bV`Wik%OMm+gfBftOrXC0C!Pk(x{ z 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≀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 aVibr`AVz^01!5G4Q6NTv7zJ)hf&T*^@0#xb literal 0 HcmV?d00001 diff --git a/qutils/BIN/QCC.EXE b/qutils/BIN/QCC.EXE new file mode 100644 index 0000000000000000000000000000000000000000..9f208f9a2839d75d78be879eda0c656991583651 GIT binary patch literal 72192 zcmeFaeSA~Ll{bDRUE9LQNPr9qF`y8UkQj&)!3JYHk-^wNc#$!dNy1xN;;LTSWXZii z69aOtom!r#A=`Gh-L}uxCGBRL?ryqiw`+RyLL+!Ns?rI;&Dl8!!P~w@$bL<6+-fu zsn3p)elzOjYuZf9UcP2^@aqq_@85FY*S6gA4fj{?`Q|t8Q`}#<*S$skru*yPbeFBH za)0B#P4~{u$;tK@Mf(>?(lS$q^gp-Ez9msxpESla+61cp8;~h(0S@5DfzMHT^@(S* zpqn5>KmX^rCiy~qaYV{TnfY(>hkz*0EzJ;5SN`sEORMcyPWnsG9+dm^UqG0x+`C;t z`rCv=bP=yfCh&}ZZb{lWd&{PKlzSxU_XIeK4|taThh9?ud=SWNfhHB4o+?RwNSlLC zqA~GE|9q0vKKttev61QmjZ!9lPvMjH&qsJ$?%jOfS0$q*{Nef0o z{{OfCuSuZc6lq~Zdm z;~)DXzx}iS96FYNj&*eOo7qt0x!nsENN0Y|4r%XM&OE`s;An)zI@b*yvz*wlKFmwG zo61c8*Jgr7?HMS#TiQdl?4@qI=V?fBPaj_QoTRU(3rnT8pH3;2!d9(4PwTLhgr=5C zTRx?-v{S`I;#}*3QmJXs-uN@*_r_T!leFPXmL`O4=nRIz&snME3ORak8)kN1$4`;k`ylU%tI2VmY)4VYUY6cwFJ^1&|{F`qWqlb z@G_6f+gtR~&eiA&%cNSCrFC2V3-#Y3M{T%b7>Kp3;=EsfLIBPSz(v3QT>-c#0GIsw z!vb&#fTGDHkosS@(oaX9#UG@?1NyrlA6?Mf8_-t^N(z9@a!6F5qyTi(p(Cx8hzt+N zxD90jBV6$gtLXFVHzi*CSj8#7?oPa(Vif~^eQe@&fK{CJ>*mDkSypkeDF!N?!7HU+kZhfamsgs3S*7%z zsFaF9rS!uqrIH~3RHcWZVc^uqD<#cCr9M8{Xl;H zAmIgclPEHvZ|5p2`-7WEftR8k*lN$}NWI4yUhQ$Q91r?_cbUgYQ$6ZhMq@ayMPHGu z1jG5_qTwwc)k$?I`VlW5`=PhCx?+Do|EJkpWC4AL$bcbGJ5WsHOWUX8OC`3)JCbsz}QLy8Q7DX+LcMnsugCaHn!MNC+#X>c^;o$d@|7v zRrt`nN2){NyCxG(%;N4<^O-@HWZSX*+lWN++2a&5^iczT6Dl}PGD`~GqaosE>^ zdY;4De+-HC-?eM{R2V}K6mblFX?ma5FXrn`>!E zvhQ#A>scd;*emdWBBxMJjwtG%k|>#kQp`*F^ddKqjM^R$C^0vYV&A{Q?61`SHBrcJ zqNkE$*n%5r_T&Y+1# zJmmpN!spCW-u4Z996;IgC=AW+jEl%(#p`9oA3^&Y)@IRwQUFVHj8>Sby2<#vnvB8; zWcvkwMfA3c!I@jQ-1bwCZ_tKKSGTVp>PZ&M$LmuxBvku@J?|r19kK!HM!zuDC5LX{ zZNz%&@`8^7rAja75F4At&EC`Y#wPF;sh0QGBY7_k2ke$JzfiVdDZ-@1Fi-h>@bna@ zCv;>EkYWqy$xl!7=;?lXnoUm|@l>Usgwp`CBU@x;i>>VI));!Pk<&^~K904|!1{)@ z>9oD+A$0hln0v{`Sw}Ek$lb669Wloc7xB!pVIQFnkI$s=bd)$sas|d;$GCynI;KxuQrapCizs3(wKrlP3El4?eT; zS&EMXpVjyr!>1RYKjLG8K)Ufe8oy8+Z@jRCOwXN5pLLL}t9Tr&i%n{X(j4Amoj+Qg zlzmtk*Rt3&{|=KnMr$`~QFHcT^`y5wmT`5v))PmU9H(`9DnvQEI$|;vBHq+7f#5J& zQQtC+bJg*YIS@QafDX=#l{Lm`N{!6H0*Q?Bx6ku#U8~(DDH&RqHFnAvI(h$WIOV_+ zkJMei2L)o%cd;LPJb`hf>APfLOe_CP~Z*+=+mR zFxZA%XP(ga8qJ;k)87E_Gs>V(|1=(lGPs4q;Yq;#`Zd4<>BO%e;|*nnk~;kQSyTk0ooX-YQoh1zr%D9_8#x0Tr*j6d#)4l+braF&}|t4wfaU;UO1I zcFHpCA)BO@*X8N|Lvso(zS+^eSrR-X?Ps3i%dPMN2fM??Okp$2p;@suydsl5;DUi- zWpg4=qZHFzg2ytw$7{oZOe&EbRLyYfh+a*$Y|{CXX@UfIx?q-kib`7Ff#MZr+M7<| zrDWi9pQJ8h<&M4WaOW_&iA+FlXty}#kHrvm97B}fG{4dqqB_jk$43lN_NE`B9KGl& zu+l}9HFysHGZkmzs4`T#o(9f z;QZoM@Jo>Y4ZqxXykIYP8~<eBf=?3gjtLw{*2a94``m7r zAh3pB|A|4F1_Hg|0_9U5WEJGdd7y4guo0Mk z{Xh8JW5c}XK$3mm;xU!gdNUS6v1N5*00}A_?U5^?RbtAEO|Q!#v`rjsLlSMQC@lx2 zP2!6)n%14#c1K*f3RZPtrZNryOxufz;NOWUnPpamE!DvpF`uMG^RzBmUvUn$Ft>DV z!7{=u5v-9k$QN|E1R%)*LaXHk%0hyB#fw(&aaece1f7JiNWh4OI{0BMHTm!wM{G^S zr+reT{?;&xhC38iQQJ>xcBr(i3+K`k+7nZCa6un)2M6ED8B-H{o=E5%PcSRZ9ckqSg02sdSS{$IG4DyJLY=ICfFEi~ zD;uSqGpiHoU_NX=1=JfsEUkBPvS zOp&Bh(!TU0?_ltCV&vR7K^dwK9wopJIA^42lc9r{>N(*9qBZhGA`z?aM-!$qk5N!N zF@xkaw#=%;}p)*_B58q2d7UB>0t-xRJKrUTbwQgcPU?nJ%zrXQiJXeDI9Nc-s9 z-nbQzUX*ZxynW@?9{h+&+0HWk`X2=kWdCVhc~~l_z5QiW#!j206mpx%dpIH=Y{QbG z7H-gfmv%1mfl0O9(i92){b3*NXoazd!=J;;$rSQn*}|!v0cweEYCbH0SEJWr&B`Xg zH|${6(EQnW$WzB*l?jo_%oQ8;9CE~CW^XUM1WN)rfL92kgq1s?mwC)ln62hC^(uZ= z?n25{N(Ebi4wDCOa6X&ZVw!Kp42VTkOQ~u80-6Ck%vz^8yM2TKqddW~{6U>s?C-`> z8(CxjNS!20okC<%J$_qZw&H+*1e#r-aiQ=IUG0x$f=8#nI-vjTbD>c>=&}(IOjg>$ z)e@wMl@j&VgNdfB*3Sy_H~~n`e;6Et1!qB06|al0vYw{}m4|@0C4fp*&`p3@NkA@n z(t~SBOI?Bz8hfFCzZ8}^8xT33!q|$2fY)6h$If!H2|4JZBHtDW)b;)asw-4W6+o^C zkz&5GMA0jaqI-mD`_qxc^0Q6?p%_#2Mp2EPhlb^)@L?xd01GC6IJo*_pVaUPS>PRU zOSr@bsJ=?%;K&%EHsp7~yaK|og=}jg*Gc5&r^sypx#<+@{{^87rhW^j2Dlc?JSkql zz;}ep3$o#J&0_`@7wyC1B~iaYYCw<~lu!H8X#K^Rln`x1)%Qha=<|4eZwAOBqkY5r zJ$)DvLAjN1{vm;5Z`_|0v`qj(+h-T3OqmS}+RlvO90>jr!mSa)yPlOzz-Hb|rNnHUW&`P%uPWut2<^=E-4*7uHZX3?iGfWnKUt>X$8UBu+R zmPlA5x`cL6)}k^39$-mOMKC02^mG<3cI^5O-nv9Wa1FAAOJ)6iK{(jY&}*sV@L{N4 zKt=2APoSt1^eQyAfc|>|s{DzMK{Vg!-y7i8349K=1jBrc(@y!YMX}bi8a7}Ft+HOA zuco-Yu@QW+l`;nVHGks(u8w9EPSEQp>QQWw`)q6n3R0homB2n+4Ohj4!dtnSwZt;Dr^}6s%TbNS0UN@}*ZUC`}|V(pko&B)j5dUCxU zUL+QgFlE<-g9s9!((>EGv-nbSxs9)y!m|iUu^E+m2dr%%uSKU8X^UjB#{loqF}|K+ zJLHtH4IaX(6kca6Iu|*_;&Y~0b7pG87JJhpB(pNl8t4OT$sd5pN_{D;0KAjr>r7RZ zL0XXOO*H*1^8_QS$*OZy26qE@l|JQ4xOZNT+stu4gNg8^a%TY-<;8N~K;Yg9z6928 z%dj`KfworK3TDe4VVTEpuz-!3IpN>A0^yHeR>5}a*GDjPT!HX=uY~*4%W(zag;&B= zfJ@_rF(vz=Nd`E{NiYo-`mLlmC1lM?tOo|Xg#t`6u!n4Vkq&k&fo4x%C}blUVmhBQ!n}6< zHe*g0=+5BO0Ij=%J12Os16!GpbaGB?KrFkp=V7S5>zE3V(>Dr0SB}XZ|7@J!h zu$5Xw<2RStuSVjo4`LOClgW=lyd5Im-h`72Jug8kr3pXCeGU|o@PqsZ`8AS$koPlT zeDEQEv5+n;dj5q5CO$oXz>DP3QEAHutVae=IHIFYp>167ap_BWub1@&aBR@_$#Pre zo<=zT^k2WtnchPTcW014kpAfp($~GHTucIzvIKLcpDdC#cxJ#wQ+q4zNhw$P_}-K@ zoW0AdpClUjT1ZlENVSgsJSl*HtH0AqC?j^9)?vp90}THpO+Wt7N~DG6WmE5w)X{Cw z61YkT$a3gA&It|Yd=HB;G-YO-LsJr{63Ezv801CS_rZTj8Jl_`ki2sc$P(i1fUI4B z4IPvTa%%#zRxST?xyC1OzNuzCmkp|7ZtcP}JWr!%XK-K`1$_)t2Svv+kfhj}|4-_{L7u2I;7Vdmc8=kGa)5US5AYtka6F6}xS&_g4BLC&okYAE(D6PVqLH~*M z7j+*Rqu~+}yG7>}hUQ&QD{d0uS!fqHUoVPF)$v#9y@%+1kmxO?r@MB(r44UTjwcy8 zWbhy;By~s?4*CTc3k1GmWV04SjPOi*_t8UI+~3eKPI2VUc$L3e{~x}*rsY;1`=$&Y zn@+38gT=&1zF>qVzvzhksXY#oX0lmY7D>eqsbkm0Gj@}Iz%-ef2YHKks8CLVtrIZO zepP|zXhCeWSAllPy=%I5DO=6Z&FCoZrLKh&RrX)l0S)gkZg9CzLtlR9?-<);3kTel-zl1;%aYb-c9P80<(Vw zisIHP$@_j7W%N%pgLVq>Z3MzZ;T#9(YS2#&@iXqbvO;Xot7sq?1W+h)5F=U`W+7(yl-|M|#TzLnP58)lf;-+R zFCSQpFU}@Cf~#_pU^5<6{RS3888$mp*%x>tbVsU~5m z=onyiABlbc4*=PV;YvF53%F1o1fu?ZyrBS*{yj>kkq2AyUlX852}Cb+2F)U0cmx!_(I(rN4zyik*P+kZwh7xFP$&D=wS zVpM-Kp^#`PWEw4+85yOhHatzu=+7nh!SMBXDk760G3vRr;aRFz%oHt4OrdiH_0vP= z3U|3vdXmx+{b>{;v;?IZoKFs}PO>3F+gwE##;(iOF>#vNRm9V)PlIuUHPq zRjhL_38}?3|0?vRUifv^nC9P^+L-Dc>DL+0yUD6x8&z{Rnjd87-vtX;aKc)aMPYy2 zE|+3~BI^NU7HTc#a#NrN1AiZte*sC*yvvmvaYMIn$q61Ml%6Z2qz2S>#BU`BRJ|V> z(?%fDlB(8=kX)dNqMU3s)yi#bOrcf1nXRxDF1D#RVCM|WIrSQEZ`0wO6C*pF5x57M)Ku!*Mr65mY7V)yj(i9? zgc7LAEeIC1dD}((PhkaYqmHJ(ingMqHI&Nc*G;_T5K@EzaE{S+XPi%VZF?g_9?|98 z1Qy*_&DuwkcWkRjNz0(D7a-RN?V;y!I{Qju&)hpWuh3VFH-vs zb1#y0A75$Z<3+fc9)~m_K1gO1-ykI}()i|Xoik5iAkPEOZV16aW0rnbGTV-z4^`<) z5&$I|NO_P-JXWpmfiPK*z8Q&Zm>X94?c7{84gws5rn^%cb>vD&j;xdvUfbw_N5HNB ziBnHxJ|#R&VF3`0P%kPs8sW&1V8KO@6hL!PI(ohpEF#W8fy%%(7QtY*3NsMl1*b9E z0U_0;F<&Ahc3z$#H7xVU;9Uj=rZ0|I!GhSwT@TX(oO0T^hZMhdZijM*cJ2nHTst>IDb>zhuM}(N<}0@fe9FIo5T_90 zRfOmyL^~m76JiF@csyCC@9yRtD!(hEfoj3{L-D2<)NB-|>8vSTVBhzxxP9MUan`j0 zljO{zcTslyo_ebme{h#Y`vgWdy zk=KdhKORLQhQDM3pfm0#c@&mVM9B92=B z2T>jCPS!;g8u6w9{i|YqfPEh`MRfm$s{kUa?l9mzby7`0|A_#n_O}tPfPpQz8Cn(4 z?-M2u8wQV)TW7>+htBY)`2)e#q7X z9DWGQ5vVg&>NG0BHGr_2oS;H=T16k=6k@mBmnyP^QbY?_0ILOWx?+wJcPCk+0UIlF9T83`cj#d*i}Cx>#{=?in^ zlcaN-AV^TfPXZD94uqfcgrYaaJ4_@gzPsny!B*Jksc)()A&n7>LV&h?N^F<#b!4Q!Ie63v$FEd}%I^5c@zdq(2eD()OMI7lXDS3oQ9!x$&0T48Q zXLg&RiE*vdUEXkh80cGG6@z4g8T{%DT`yD;goF_e+CLf8q<05?z7Tt$@R6f$Z%4Ox z!I7S=T{2;2yJS{tp%-`wSJ>3?SnulJ0O#=LQ!lmjV80jfb2WM!9}sao%JyVP!5DK9 z=rJdB&+(*Hu?-%O)hu`dB}g*BDjZdQeWIH;q7Tv78xW2S4In-?bZ5{M0Iv=C6AT`- zQ%fvFGzG5?d|cWlkK>~bNXP=H18=UW>`C4ZNE|FXD2Eh# z(Tfj^4q=Ddw6L`3#Vwy>GMgdHXR3nA45=|eQHn!@HcBD?KdQ6UXs*oU&ht3+L@c{24^^>(eq^}}I~*hcDR+@5k^o61%+wAIeC1nXE#77cCt z6f=J7GDsWkO*TKa8L5z@?1@8Rk7<|swq}sM7{$@;jD5roigX0@$vg`UR^yxEianqo z0c~g&0N&^LBp;R|L9H=KR>pJRIl3{`xF{cOR}-khmeL2;;WX6_D;x6C(dQGEmk=tV z+RprTXCN?UYld(?{d~jv{Pq#zG2~;I;EEY0_}Ds}7i>Wc&ab(KT4Up}1j-3Q z%qY?555^^q-ZDUZEeC$UR)>5=hEU=$sO2!D?-xC0Kz8|osne1r^dDw<2YD43R? zzK+XSyCf+Ek%ex*{t;>#-Hz#Xp}T~*$C1W`9stHw#gAeuZ($yeV7|aJSyAIcr(T9C zaNhhbnLTJ_TPV84im_TdDzUGiUOE01XM#&=KiEr<*vtTAKC=?`k#hkF6_Q$oFB_(2 z8(C5q;dlA<&3u9QH`q(p^3bb4YcI{AowtO&M6HsrmqsTlFzltLxZ5ddFL8Y$J%SA0 zBDJ#pDjTx?<@>|8w4eDU>m=O~Jy(1qJ_`&;=rDcIOjKkO2TG`=$~2&ctY*z&lXk#i)B-Fy0H18VwJ;-?St{+yXr&(n{kCQNnIi|%RcYR% zHhO~|BxpvwCAP$}O0hox)o`dz?LsN7C-1^~GU{eg%!t-#!vz{~b`)qOq>-kbIoLQ( zoL7k1g)(wgyi@Blp{r&Y`C4A}9&b6;O1e5&<~M~DXPX&K-Hh(iRp!Z-n%8pu2r21FsQ+W@-8X;K&v`ih1?g6QAO15kZxfMF;Xe{MLK(9iCI3^C(^E3lq_T)V^O$UlgRJYRyluLK_nOK4AG z{X+&5+!ioSxID>WW&K~s(*b$D19`HAw&{F@;AK^E({Xq`NStpZ#90Kh)0r;Lg+iRp z{(nYhF43<-RAa036*89&?F{cmk`VLf5cB6rF@Hw#2>96@j!J!(SUZu3w{sCYi@F{t z2ZDnO>HDx;p7PM!Wxz z$|IW>9!19W@mM!IsKsZgSwlVCAI!f}+9LD?+3c9TTlp*=&(+hXa52MT)U89L+EJJz zN;AAXo5EN|f|pYc_)5a}>hatGWWqdnsO9yB_u@$E&>i7iAFQBoPBFgs%)wX3dsfSf z;hcGR)PDnWzkAU|Dn)O`VoN`BGqw?PPobDS4wy)~HVY=`{XhkEqqGu&Ah3j6-65T4F`$KZR}9!Jxd6|=EZ!isLVC|8BM)AZ>&P- zF^ZbS<1B4OQPoaNgp{#b-xqLY#72>uVLxy2a(Gu*w?X&_<{s2ML% z{aTmYa7lvj>VM6mqz7gZ^d#Cq*z25^hVh2XFi4Q;E}T8&fsf@F4xjaWE{|te(UgW$ zND;_5#neoSdb@<19BBH~k0WRk6o#>cFbc$hk8JOR!EF23`g0eRlMcc1+T~mc|YT#p|Dm-ehnELPFzjFUV{%h?o!f)upjp~h&M$aa&;@AHL`iIGE9%P7l zG(v8|p&soO+L)QsPi{X9N^`(x#2Jb#t2_!$=JbD#DnL1R;P&fyp(1Zc7Fi*RbQ?u> z8`z|c{md*wl-0+GNf>-XVpvZ@O`xZY|R<$QO{ZwW8e20d4yli0yU3% zHUk3ttK}*v1Xc27#3z6V41)**t;N;YYj64hqZK&f23W%ZQm?4?iaYkY_KG9+DriI3 zi*<9}7Ha3_+P{4oMho%g*~EG418+lJ1;A1>1@=&v18)gw+8b45(60pu@+5nCtzZAV zfZnXMQ(}+QA|0GAMq5e!cZ!!~^b(4?wO4$|LCTv)t?aT#wj=TZ*m*R#_CJW1k(Co> z{5iDLE*!;Jixq7`Pqsh;C;@S$vLMjjIE38j-J@E6g|1Jf({WjEoTN_GH}%@TBY_+^ zStMLDVQ)MGd}6@q*XIZZ2>N?KEyLPDbJ2zR*ZW_^Te8keAd)MQG9Ph@7zMpUT_jIs zVxkWF{&^jrn4pxd{_i6vfl;#rFo!h&*7_u<<2$5mn1~e7Cy{T(`@f1*2#DYA5&KrM z)@Ia-ZakB7>PBfwMs3&{Gl$986H>kbIfuGJNZSu`aP1IU4hZn<9rx*+m(D))N4#(pu> z<;E{b#E0KRUS)!QID`0arvi}qhbY7oE7PALDDECXbYA{tS;p)Cgv1f}PF({C$bh<0 zrw3Jl7ph6Q2`b`|cFm~I!h>6SU@ACqLtY*X8^@@anL{Ta4rlIlDjN_|-?Djkf&UDC*^d@G}J{$t9KvM1anJK9xcs?wG%^C;~MUmq%51TAlE$$j4 zkcpm|lCmxgvRL;IfiM$f6_5bnif}`lJyol)+B!5F@>)|sX&i^rHhVnPlva#1B2>Fj zhj8iR3V1OH`nQ;om`w? z$Ot2#2m*AESOs5n=-+~_Lrp1eor)*q*i6*tlF;+1ZzZy`=p8V)azeLbhp2+TsAot{ zz+H?ZQ0)jeGE|7VG329Ub)iShiscP;QM-%R{8-LV7j+ONhf+!V=20pHGAF+~A8$il zv;&D+-D(~vN(|}L#u(G<+<($zSd;OEAG+|<7FcED$_@9|j%wV_gY+&&k@ zu$S(DPyayd>XD>jZ?k5VeoWv9a_o(dpW|0ne3`qi3%vgOfv|hiTAyUS+b0#_(}>TD z_`HQr9^k|H+==IV@Y#%yf=@j@`vI3SGE5obpE<*lks(KxNb>>z5T6)61Nd+}`7i!6 zA=RA1uF91QZyc{aTfcGgL;qz$h$1h6O^n7i2$+pSptu)t3EulGI^U<(D!@mP2 zoDHwu)BR5)ZLrg8n0AXg~>s32B|4F`I^nU881{Cog<3}BuB zei+}6RlPltH4|BZRZ0vu+0jVg#T}%hW;8PUp+{fL;KKtu+H`zJ^2m@(J~)r}uvjNy zYx{oN`tV};?yxny82|IaesY>ecgwZt7x>J@rvjfl@u|b-A$)e@^K*Q@xEBPB`ZNDb zBj9F>JmNhgGxeIqAFZ@MgSBP6a4zjh@ATu)5`Lf6Bya@Bt}?mFZ&PquR>svsgt4nX zHdCxY=d{J9VPyT{k9<)l@`dHS;(^I~k=e`!yzSU6&c(V8OJJ<^!kOXnyzX*x^&`HC zd!^Ao5i9DF;m6A*4+i-&?2nu#k#>&U({vGlb~IhIqj?q6G2rL5l;z7$VuSQ~Wbh8+ zilR9v2`eOb(Z|>-@ zI8yQ(`9sk`yVi>I2uy}F-~&@yvMP!ZG2Ug#DPP!ZS;(Ro>^=D%C1mE-zkyNRQzzy3 z&EBcZ6ewK*okECJkc8U(H6X!VGVq zj!P0LypHae;gx|rXkKzdH-8LT@#v703i`=VuT42#sQ<0ou!p=a!WDwsgt>$$!LJvg zvp^e@Zk$vimzLPpCC`bFOlaPu%LFZQiu&?Mrs;5Cf!}Pz}@xrO5J%aXN%k*<9TI9Gyzox{}ZVd zTE|&gC#{0LbP=sWb3qSx2;txYcY8sn$NBY1+{GgVMBW>gwIQ^rK>mV76JD;gqEpNp zPA=_K8L2qm;L!K;SqCv-a9Cy6U9HDsyf;N2;l}b@Vy8QUICX={qOPsey@#L8#$)pe zoYAm$mk(1%Y7TtSN|+gxsi!B(>2`(_i*evU--BeCOd`;V;%ZeJ{Hr)P(zQ@- zP{u^cF~6DGZ~#6Iubw}S!!&WGD>JH-HBROsKVi&PW?T<_hwO{x;zXkAz@s&m%>gpL zL*?2fOa0@m)EXdHLe(@eYX{0kI;e0Sft+FF#T0I@-ag)@82!Lr4!nS9H@=?~8;ch? zQtm_&K(Ij(gM}foyBvL(t(#D%71d6U($0c1+g#duEqPdk^?WZrq1e*zlp{AWUYj@@FfL-IxC?9==(U(My`7G zICuMTGLm29j~uMt4=Vs6qkPi1^EtAl^&@X__NlE+<=O>* z{S?E8>8jNGKH_O&&ghn}LJ7F&Bstgonstq|eTax4+L|s(GvPk4=|t@aYlrU3aAAA| zA5sXvh{UTX#V?iIj$e7F$zS?=yuX9?c?a8)?`-za9e0is`aAfh3ouOF1*yVwryX!b zQ69gaMt_2o3Ju6pMax^GK?fuk&vil>c#LXt#z)dHw4f%Q>!7qA#8srHolHy9anve3 z?MPZ09~Tk^8Om%+OM|B;Jzx9{Ofn7}=XGL@5r2(*^{I^BUQTw)ORx1cVQ@gZ#NR^e z>#xEY3d~6hH8?Qe;p0C~NaakyMlhaK2P1yLz7O#Vt?wC4eXlZy>s@&v-&EQOuV`i+ z_A&b406~Mr#@Y9cVY#$R%r}vjYJE^S^;pZ8pKdpoO3j(&EtxIHnkTdzDsMclo=Mxh zMzv%wgyu_%o#W0kE13)Ms(#8k7f{6aJW6x4n2YaKvWpiPi36;2X=r|dnn~Zv`Ia22 zhN7I7wpbVVnzI`ZtAmMNeBxuUEWhI-RVYoWLL!y#XW6iy%qLgBG7UnWq-IkRNikG1k9r@?35u7M%)o9vEhsU5;65Zx zpGC$BrXrjX9qO?hY#Q8U_8x{?q6r<4L`j>KPPoFD1I|n7MpS|wUL+uvxZG6ZXIUb@ zK8w~VMlqrgONZs4UoQb&AO&OY?byVNEH`y6l4dmx?i?GbG_{zqul!=mWZo!~1fiy@ zj}N_VIc9m2O)dl7ZS)nMREz77YY}0Uz#&?@EQcT@H-f^tOp8hp`v*^m;$s`+JHC}M z)Z1m6RjOUsR6l;-Ch*6iKODLwnfMQT8wuG+powl|f^?@TeXD{i;Yj(-q#`E7>$ zG9kZ&=%R(Qib1Qo)RIBJaKO;b-m#)|`L)kLjd1*s{00Iz5N$a~OFaL`g8aG_cqFt7 z+HJGc%*aEgF3T)n!|^n(&Qw#O>u58S(Nz&Ih?y4c3T1du~!gQaONold*aVG{4#O&h6F&01Dc&|k<6Ck ztd)KN-au5ohfBhT*eQBg47G6WA;y^rLaD?YA+(`ps3($FP^Hi1xo}+%&sHkKFG zC1wBD&gNVn&$*bFpbcNF_Y`&SaO0A78;dTa(-p&A3ojv@zgk~T+A6Miphb_{Pe2-t zwFCU33j$J*gAER>B#I)C_b}g06oC;&k2OdE4Zq_1L;P|jx*S7a=p$J&vjwy+(U*4;UGeQRGnWa;@gUi65KELgC!C-!f4+dZ6yzt%Cw2W zi&pH^XlN5h*xW|eN)*`va`@{m1s9`$O>x>2mW)UPq_`Pwf4tv@bD7HQB8;NSjL4j= z%=QeNuUMpG#D7MX)Nw%*x+N=n#;W^}JHGlEYb?6yu?#8-dQa;CZ~G<$EaG3ow`8ga zH_27n*eY9LrB%%kY*$r2w;DPh%Qha^ax1Q&#HqUQ-`noIyHn;j(F=LNp5ZPh53UiW zRUxJmR}KCJ(A9TeN0sKWp24WhcR(!%#B*Q9F>$ z1T86{(zfNM&-B-#P#(9{@&>|3-Zmn|)}$iEFe-HMNU>$9NHNGCFdiwEN$qdMh+(Jv z-I>G?%uO{5hr7TU4KJBIs4iJkf-vJZJ>F#Z(LWb&VnmMMdI)&wyBD1VBT@{vfbrmt z3`8Gbc;QnrMRgz@$rNn@8xa8=C)x6WO<}GA&<7}IdV^}GJiI*%YN{JP-b_9BQn~%n z|3v)y6<9#z8AdF=Z=l<|!&rHi|&tkYmJV>|$DdDwF^l+YO)uP-wSmwD( zR+a!|2JOGnVS}RKU9?B%A|_^l8<)SjsuJ!hAt-wj1>RNZQ{Uzk1oR2wAxYs5LE*c{ z1ch`@G@Uy9+=MYH+ z0s+Ount|+EK4>yLPKlEq9{8N_7pRD9>}^}3IFSUWq#1~i9cjc& zEIyr-+;rI9*az(ahS}cqrg&PcT;1Z!D9%=#&E^G5Py%6-Dt48*GP2PZ(P-Gof`P}J zSD_VpxYJNwCfriEd`Qh(mvZQ(xu3{E;lMQgjnrz;5%ude+>S~4_y`G%x=;apkj_Zi zRdS1Uumeuf8%WV-4$1I`uEr{vRg8X zC)pcG!;5niYk6~4|6V*p40%h6UfG%#Sz)5%Fr&3Db5~Y&|4%6GQy_g059M_fY(W>6 zPxQl)1VNAw5gnGvlPckOF<4KzJe?rVDXA3E04ggXyumV;yjYoxUCr_2n$60N-PV>|*v+R{+21{WTj6pH)xA9638NK|CX3UeUO{_u5BuGn}~5J3eb zA0NrW+-%K9Vc28l_s@zU(E%$U@x%?GKNt8$l1~k0cp`nHLAerwZl zd*e+6J)fc4yL~hy3R4G~s+~8fR$dWa*xcP1P9SYZIES9J?XnfB26S8mfp<$z2;YVL zd&e}!eZGh@^PGQ%uJ}N+qOhK%Ss+4xK#2TI8o@_8@-adCw70y?le#Xf!38g zo(5_p(9)9crh%FWbZbc@4fHU9JSC5%fgT~y*ph!F5DwK*jWj#9(u2Rw8b6NFH_YjZ zISg6QpX4F9;h7C{DL@*K14g?!7*D86KWimkV5Hz8&k0(mt+g5N5!n}!n<%BIbK8f^ zoZrEx_iH=J|0AP5QM&t0F&xgK^4P)94tU+xkGN9@bFu^A5~ZY4{~3xv?yv;|V>WWX|Axq& z`rCbJf8dW5!Eu(1H;2tY#YpPUTB$0(zV&sUx0}oe!*6K>kiu5O5mOm@wQn&D^#CTz z+!GQfbUxn6WB$m3cUAMQ-VKsr zbeZW#84V1VhBP^B4&63QDUZ|cRYuDM{C%&M3FTyK4r;AvUsPBA5y79;oLb-qtaup#Au71Rye*1SCk`)hPCxGpn>IaqTtkQC`W4%qRNJF zvq6`c{v?Vzlz8|!e+YNdUc!~4n3JIFxVM@*2N@=0k13_qdYlJ;^A4`uLdggLNJB%% z9bKiLKg#=qw-?^vGRhnkGlLv804d@Hxn}htSacIoyrz@OVxb~T#*29OJ|})Y%a1Lp z*0+EdOv1+BCmCB6&n-r6slvHr&ajuslk{`;auxqmVFC%g%D9G9PEK6L_(1a!UxVWB zAL*~6C1^m?3uiqs3eL2oi`f;0foj(`pfwT|x}uo7v69CmbqKhHGwh8&!i&~kfG{aX zNn18n1AoGxfV-08xywK)hFp6Sg{AKQDcT&D!T5lF=BZyomz*a1BlNc`aH4L~yfV)u zWoF9?QzP#E!115sUdoDmRPzF({xzOlUb#^!AnsEzRvn zwYCry3jkhkDth~Y0fUHFecG_R<=I5FG#T%C66g>wMoyXi*mo3fknOWi<2UlC?+AXN zC(Oi_z?bZ8$4SMz!%K0wiVH2YhorxkFtL$K#ZZKO*o0eK!=)TWD|sGJc**r6s43MX z!WQBCR>qROJA-2ai?{UfB^8~HKoE=+pT3$m%oihpeh$0{DH-=`Z$hLfR{j*p-#DLEK@ zW@{xOyqeVM!HeKbpNcQ&SnHEH{IWlCu0wA5?I5jC(-igeQw}XAp+rPyh2ii zV-*{sjC>8}DD#$qLgzukFcv-brhfyPIJ<&{&xYg+A{-4G?2StRZ8%Sa*c-RwInwC) z4PLnM;b*hR>c9Z|2I!u!?<|%5JWm(bEd9Lp=TAg_#Q_O8<{88K(#{ocy>2A9&cdS> zH{0s@rAgKLwO!OQwtYQRGKLi6L~iZRM;Ksq^{(;P6$y!qyOk{Qho$(4x&L((kY@S) z^&IRu&zG_cv16Qw1P`f7f)2MyqCXV%D`YzJ1TBXAdH{wJh$kIrI6w^)f&oCCp+&?qjO2+s(^?gNh^i#AM7I{5D4Zy{T%Hmv+*z+$|Dcc z2vBtNfou2JX6xMi@cZf*4itOYXq*aEK3)85tIemytq=5 zp!&K5)j34B--McrU58{ePDWPBS0g0ybAfZCPLF^PqtaG#Ark4vMD`^^n%CZ}%@ zq}{Dz!o3a&@7u`iyx@@r9Sl9Wh(~fgfNT2jhk%l?9DK{6rRA25@mN!_^ zuZ6su+Aoi^@ucWYxi$n|P4a{di6~m^NzfQ(oNiY0Ya8I=iA!5WxDS#jv4TS!5TDa3>rC)PxGN1$6gU5%$P`*m^J}V1P7f89 zY-;`hXD^l|qw)7_K`D6%9NyzYpRyi2+3@>Xtdt!h-Gba41UuG$toPWTj`fT_tezb@ z!v=;n!7XzLDbAq}EyuQuDFWU$>z1q{;BGaoKyYT)`nx+F$sGf7^f`^{c!9h+IK5C= zr}ucw&#R+tEee3MURK>9ROfsgUk;-#8|oT^x~yBR`Jnx3EX43@#jkDXZN&G#Eu~iu zjt=hY z^o%r%(lC>SUWeZ4qQ64;fT$j*Tgiu!*Gy?^hAW^p;!d((o>Q!e#SsV+P@G&vf^wlfO#-<6q_Z*O$Tv4P&A5<(#ABvRZDR; z4KL#rM|@~o4*LKv)4X7uHL>zEYitY-08t)FMYOj5Z|Bgr5ok56UXxBgHOH5l2~7c) zH~N^T8cNB%<{t8z`*5yd)N+{}5L#n-zzH9W71AG)5 z!3svB@pY!IGS5W(u_XPWe!{?20J!299?ePW^r{;DLufqcgk01KHTrP$%Z1Qtv_^l0 zdz`Q#&hd_30S{%ud+IdKKEN0z=a?(B%qkta^uSHzI(3{r|jQ%vBpF~0} z#Es>Qd}1?V-sxU646ew=@0Z0U-%uQTn!n=HNGb@dmL?!?`(P)|H@A^e4tC0lMLT32 z?6lIaJlN@=U-Mw6n|@6ce4demLpL};S<7B*cu&Gm)o@NiPg2I=7Yh|-EPer19I^2^ zr2a8m4)xy{@}cV`^5Id*1}63FQG|jgLO~7+MyDq^ed~(P54AX)2#Sd+xfT-=k!iN! zUB(ZHHsi-Z+?Z|dp-v(bPi9Uh>O*ZHhto;5+VM_Q*kU=MBXZ0dI)Xpljq8j!I#M`! z$f0CWnuXHLR4A4-c;udF90C89FxSLH#y2Y+HLQz{0LFia=)+%6wRCn2XRu+`^+RuG zJ_Tjd&y6%mIbQo<=(VQ2HU*P0bSGM&#VtF=M&vdPK_cUDhZzCtKjRZGr3)-B2;&Q@ zGB_%n-0{V_e?66I6!i_@2$#1LiH@{7Bl7QF`@qkvRh9aJTy7(;*nV}S_;(m?oi!}0 z&ZK>Uz_aU(q;Kg|X?k^-ujnip4V&Bng-{xIWQVjIb)n+tXu*_Tdw%D&QDQcq=I^|S z?P<;ld2K1S4vOq(GAYw5C=ovVb{+Q|&q{y;oNeNmGz4rdE z-7ir6L&tACgac_#_9pIl$z$_Tn)BLManCSqE(7nA(eJh(A^hOQ@Ld;S=D1$_V7c1! zEOb?3uYeT?!kFPW&Od~uWg#q^U77e(rfJ1bjh zMR?vXxXXbeeoYJ6eKIZ|sjwDBcV0#LyuDb@i3&x5zd(USzu&bYKZa!5`NCaAx)T_9 zq#~;;IX+@L6BVq|7oh?p8KHIFULUgD%nP-OZSK{DQ+M4$)%p4T(ZF>A5pz1(E+H_3 z43fyeHaIO)xgy7=ST;D>O1hHCQQ5G`<3wxYPNp8gjko>RQ*T^pd+h_-%tPFQNjnzD zaEanZpTJ)l84a(icFw2fVmza>l%%%YYlT=x7jDyatC^G%o+Mh+@IR402OWq#AVmaC zd7P$HL>Et=kxIYFX&IRg{RMxt>c!pyO?-T}RR0HPC`v5=)U6%JL!{JW;D?Aw8v&^N zKa>CFFXbl>_~rTOFctVhr-aaIsv{4Y*w<|gmOuf{gpF@mCt>p-V^Q;zn58STpnS1< zx+@c_o%)Gz;LfcdyCQU3p*jjF^q>q~$_&lFS+%ZYDC=>|f=03D3=$}Lmg1WJE@^Q*I8Z%vcwgc97KfYjTbZ6A# zVKqMXeL1V>XMZl`3Fi<(I9I`UN`fT6s#@mH4AipEYHAxk9N1M|+wrkXK?I@NhWDiq zqEm5YOWZE88TQ|Gp-YS@iIZtNvlc7+;@Ay1BXn4u0RQng8u-`M(jS$nz%>!X98gTf z-rks8yDz@0N71FNHr8e7C>pjujNMLYi0_!G ztJpE^eG7M-$35R~`!SAV4dCk(KJVaj2%lP(SsTu3DK|G)nBh^RYr=L5nDI87;ZnEe ztVEi2&bIYh_SVqbC^-K`*1=vp^925|NnfItCaMK_02QU-`3uXZmU9M48#qZA9x=fs z2=o8MCw&K>W_-5evk@QsVIDI?YHlevHCLD}8ig?oh60{|w3J(#D=djO*1lpTQ8@j} z^l2aC7V0FGRORk7PbBiu`fqg=zdi#4sD$pY*;DL|*J5{k9PNwG?@FxJcA6D%eF&Sn^5zDxNN{Vk2P5DrimDzY-A6Q-LyOZ#Ezl+uL7Ar4Wt%H{mHk zaN<^{v2`#CS`hiMu7^f2x*_VYh|6oieI>O_7BTn;)j}g(^}yIrtYA?&_Gz5W>*93F z)9)aCyynIJGf4|)Hwx*cu}gnmm)QNDU^kRv_g|1AnB0x01bO%^AeyOG`~iW`g#y(^ zHDPAOvvT%Jt5!ZcJre zM+ITX6t}p5su`Gv;sR1iX%q|6e=DBSw1<~GEm86aUCBx2vET{i&BPD#7N}N;iX=ab zg6xmJ%b|t#$7s81FE5Znl@l3obog??T;hBEf3|({{%?EV0vA=a#eIN55mAuPP^nG| zMn2EHALpDIkcVP`2#98uBFqRnGQ`X%7AgjoI8v0B*0s`1v$C?TrIjhB`M8;3+11j@ z)UIRn@KsWpeE)UM433(0@BO~t_xODrShF8%?|t@J`?dDkYwumJ*n)DXuS#y3+nNJT zWKJlR&BiUGV814@*Z(}RREqkKnoaT5$P?qzLJ5*6>mwv&JA+)&Z8U6-lgQQF{R-+e zcaQ>P*ZdleD{`UMiP6lCI>a({Tx2bMD^;l2>9Lq4=Y>`&E~UojWl=joDlsI@kSeac zu$d*T$VO(N&c#p=a=K1qI37#95O@#)8eHD@Kt+tPh?mIB3O@gJ2)aEuaHNF-)=F4$ z$c17+ReY69pxJZ?hK7o#Ic;w1I%pHA2qV;!bm?h2iHIz!(`Wn@v#`Mv)Rxm zlwr`Hf_F9FY=dn76C3vV?rx5zAOeC26huG}0qtOAr`rSI3P~rHS&d218duN@pb{ zPXe()s0{<5A<{uUiW8M29_2;Hq{wQl*twi5tFdDGu+0}O$X%&Egw2?!(EJ5N6-kwq zqDji8_=T!aCn!4j)mUBT(GW2d?39Kf+W6`kM4@R_lZ8$@_Q}X$kzv|@5kHF5J%N!w z0|)(kUwVz=`YxcMoCI+5d-klTmWbu*5lQtib#;>7wCe_7ih+?mgCtKI zI;EG85QDX)P4OEg8>!9VZBh}CLL2P#tXKyNO^9~j9bMMLu>%s+kjA<9je9g9yQQjSED4B?A9-GMI zLm|G*^NxB&O1oZBT^~_huhL?iJgrqe8RLz^**(rHm77;*7 z6hP43_;Vh2H$Bs;<}%Ff%N8mQU2y_8R`w92pf< zbv5c*aU1O)gBH3r9!oCnp(PVx`1Z4sj#XJnK0G`kZDP%9J+P8Ofr4X7QelBd2?uj! zqU=~X5atSUAc&&1Now5DH6nS_vC~i-C-Lb_lcOzMNWbHAK zbxJT0uK+>gF?sHVr)Ob&9Mbok8~_!s*;ZPkhb{yIey)V6CUv9&?^9suz(RXkq+<(t z?<}03NT>S5;*jjY@A;E+g;5G~4q-RBB=ip@HCEcn04XpO*r5BEE2q;e&f>ABrNG-q z&I;~(k$2pq3o4hoprGD|X!W4`<@oZ_hO{h79TPg)0`IZS(yL|dvbo!dY?n7_T;Z0} zA$Crx_fp8VN?srd45jUP^_p=0Oof6!?Uc7Iq0pl0lx-&`%2Ci1T#zk5DqG;`nB(b+ z`>4U2f~2SfvGwV=+9b$>9kQ$1JVRP>)j+xe^Yolio~T@}=L!sVwLv6^YamD#R4$`@ zn)vejFh*hh94BbBct$AZp1?;`droit=@!WQVBPv7ru=niK3Q-vop(;arc}?+Fo*$m z+*3D{B&fdp;#LRbVV|dE>&c*+qd{A-ss2RJ))TkXWruC`26cWPo9R3q$c7|31b#AP zE0Rc@9b?;)okUwN<7Hu`Z{yoe`B+l)KhrR9vf$35JRLj*ih{Zz+POE1G_<^W>BAIR zDL9W3Rs^C25Y&NJWr!KeH{U@==MkStJa-(KkgL)bFkkRFa&X8_mekA+W8Amd zYJQ5s%W!aVhpi{0JO{TPjiN7V#@H3r`O~@rMO_Cd5PbeidZ%i4H`_?me<=k8dANSE z)y)o#qXYq%eM;~u=2PVULWPxk`+^csVoTSnt29*_X&2e=K82)KPmYJC3-_!(d! zMlcnXBZu;j#>m(bz(t}WrP?49nu9|CT^)7|3m(+0z%OfqAczA~nZ&qnhaoWTK9V;n zqf6b}j$t7|JBBH^9m7JU9=c|GB1A;Lw$6#1cLs@L!9NK`wQVO3TXWMAJ zlH?w|Vm^AAx9O*TjG~R4!8XsG*t$GUu^^+v{1M1YNQaZf!N@0aX7Z)iC}j${xgEOl zh`*730uu@M?|(-0(35mVs6QtGF)Jx1{ain0Gbps896{cppZbxPvl(Q=S^KuSI~5CZ zJIo&?XOqTRkT+?oH#Ty^DX5a*Ca18-4Ndi$3eOJO9;V5O+_0}+vkqsHA60}j*-&?S z)hn9nV;ZGsN9iCaA>_=Ipt(Pui%z)#lc!!=FGV3#kH{@MNE(7k8MX(bwxKQ7q6xdjE!?;5!&M%1b2`Vx6|D-XT zRP*m9BFfc2l)7!I`BH}{%P%3kJOK5V-L0gqcHT29Vhn_tXI^y&B@f7oI{&%n(miLN z|AWg5kOK5Ir2Z^%jLnlB4lOWruo{~uHypw^oM!hvj98m`D~vd)?Mlsd?oqT|T3D%9 zbR#obZiLd#DBIlM&>m}8YDD7iTOuFoA=$QAW<=dxH#@9uwxZ4~eL&ncYVWt%Fj&s2j0MjsmTB-G-dJpP+tt=P=!0j80<#sbeJ%X zn(81gT1#pu@yH#E4v2l1s#HkpMiQY7fFJy^*=_bv6heHxT@eF$nDpThH%Rg@{piTo zc8$UYq+IWJE&lPW69q;N6tOisgKL_DG1X6W@4&W$_+Weli~fcUt$NHh*B&2z$wEi( zL^HDoZNUqx=Yf3gUZ|ls>C^-r0~@0DKpm0;%{k&T)5t%1rjn|@Bn`KnKV%DnUE-;2 z^X&04uApIZGHN74Dcs>cfqRxvSl9~?T8+jUw2?R!n-MRYZbl}0w7S*m-PEk%=+)|` zji0@!9pBvA>c&kssqr^URBi4?#?3fQ3QewAf!`h!D!O$}MStJmM%j$QzSp}G=%Xe` z8andm2inV2ryjotI+j=)4!MRt2e~l@1=~8KnCl841xWXeG0@OSN2h|U{&lMI*iXOy z@i%VFmf`3mF@G$a)$#mSTh>H@pRS6B9v7yo?ob;E?tx6L*_rRzvGr0&%@LeC?NZWC zpO}Yib4^TjMK3h^2w#_g{(yRgQDL5aD1xrJdER4EM-qlTft#f2>KhVi7Va5DJ9{wd z_N@`e!iIUC*M%++FKF9`=?mh@Mc)>KjEwMH3Yb;ld_V?QZ@V;}S%JEw8T^OSW1)gk zEyRlM$h?9a@0XyD%uGeqe4wCcZY=3iqu7RUFtHacC~!#|q*vt0$74AsU8~TS`47c{ zp4jp2N?))|{YiZFf+mztgh(|83Ngp#G>3}}J_si&e^@=gC$^RKZoDgjd_w6*W+-us zCNZ+4bajOXag^IeiKHh4%7#_M%sol=LG&{ZyTM^NzaOy6vwdEW=Nk{M%u(b(p95up zZXg7!(JM%+9d!n*U+xOhY9}=yoXCZ{kyaz=n(cHENC#RspR=vT>)S{|b1^Ly!f13F zxDrF8{TYxwNIS)`%+(4_J_tb$NLx0{qrI6+q-G;+Au-C~M(4GKLJ1C@f_WM4K*&P{ zLYGfn5fJWD#$Ih9d<;_eiIX zBw@ahipnC4F7UnpKbm5An{{n+99f(r#jlj(L!?0QQSq4O&3>s4yN%L7Bf#}~v#AeB zg}M+OkxS{(jco9dGZ^fSL)jbhKxD(1(U85!8Kdv3!M%iXAZ*EqL}aNirTb8#(5+-% z-mshrJ{OlpMb4uknE%qIYHRZ6uqFUA#8@iw9nbSrZJd~Bsp=#Yp%!_ zDASfIQO}>>KS(w5np6WLT#+h>nMvh4x?oBt%-u-f1%gqX4fr4giVJDX@qVya)z*6x*&p)C|i(&-~n5~ zNvMa(8su#`)IpDeGc^~^R4M|hTF5n>nS!Cp0VJmg55_Joih@B$ldLNJ*95qxNp9};sF$1w^EFk9{g|x=(LC5e&(~ zF4R#pcT|A9=1fYoE@pG{a4C_GwLbGE5_;BW1ohpTgI#M?sDgRk z?N3UH`Mb5ieQ8$|8}9!$WeuJ!`N=dIEkp?if$hU%M znmj_fG8+5vnrfe-y>G5t7K{o?MxQ(&azo436Jb~oe!p`Ie+j3KCrkHIV~)!I({%&l zCkG`X1^2dQA7ybKJsk=PC2z1DeYesKhvqlX%^2fNK@P?x<#;_%;u(h>SDm0>N4xgM zjl1GTHuOgdsGNl@h%)SRbqfE)6_V6^HsF{ce2?P%Rw6Zyi9 z((I6?np3Un_n|KLA`=ue*X6~z$q1*aJ?@Hs5y}UQ>joH1t1H<35k84h9I$m;ee$I? z+wX0*i#}Uhky1&9HBV|F|1rLdM9LZA{Tcc5eDp;=ddd0d>dQy-M|3=Um-?BPn#1a6 z{@xr?Ka*Y@;Y+{gf^JkE#q)0*=6l7D&7pNSq8Uiv>k0CGv8P+xH-Cfhn%ZAnw~=}% zzBrmp`sC)FbvIIP_GFTiPkw+%CFcbyrSEcEKNyZRe8c&j4$!6R2V4M$v`^lFTQNUX70vyqq$h=M8p zZ502OVTOaQGdVbq1U(Q`t#Nr%ceyVzY;%2q6RHljN_Rd|A^7T(Z?c?x{_~Lw(jtC8 z^Xf1|N1O)T*o>xsF|a}*JVc^7zQ;2&a%SRTuvK`Y?twmA-?LYrE1=bBuY71MPaoOJH2}?pLo8W|8D4{f*NpZOC z#bvj-SVy_F4BixO28D6jO6^wX;9`^%f-(uZQZ|2NesU(8moY9aTymGWrB`r>$cLeVm6_anN(QJx@MMJ$zJX#Epu5bnA;MxgOxTm;P*C0 zav*Qh9i_!En8En$1ZU#yWOtV#lciJga)sYdiOynW@&`m? zI)OZ$5}Z8YJ5i=4v^kkhh+JAWxy`53bZe2i%|+qujzV8>|NDKlfC(ScpQW0^PPUd= zD^Qrl?4+6Oy+uU>*BPr+l9mJDtEi+>rkS|6W(8Jbs~#$ zbV5)z2D9|N?4S~>y_(h=WtgPS=r*!3Tu(eQ880am0^Y; zUxR#sTn=`Uvz#ro+u2E=oYjtsFQpD&+06=*@lqsWrjMlX?oxX(TgVpKt%YT5dEr#4 zKzz~2DIjeM&kE&*MN=u;Qq*hXqVX59t_mx@S9)iWqkLvSZ2I_s_u3tfscdN(-i!ja zSu0Rc1HVm50dHo7whzW@$(JHJB}%o?hthGCSlJ?X#g*w09VN;VjWFU2&Bz~_3wsp+ z_T=nThUo`8c~-%bJo>?7*vR~m@MZ+Em@y{hC+DY;Te6s$l;q4z1Gy!O?AH6;dfBb> zyLGZ#>vwBqx5n?*$ZoaYt(M&?zgs1{m43HUc5{9=XJ#_evq$EWTe6T_vLojV1I&c< z>=emN%g&d~JfDAo9}n|ZKyF(8=-h0?l`T^IJdi9cM@j;8knNeEo6k;3`t6jg-%d&U z?Z}PKE+-@VPe`X^e0C`rpFPiK7Wl(4BElu7rsk&Q@@kMFsTU1E#(uYlt;po|E&m{HcAc)Qwj@H3JX&TOLz(^B5dC1 zp^_(=hL*`LCV%$D9MkOd#K{6rG7 z6aZn&7W^%=035~hgB||G5-#bQybx}D0FKh~!&vy|1mOJXkx97W0XTmgGE?C%NVw{2-bXl1 z0L~we(j?r#0Ng3ik-(3O55VOhJb@n<7l3PkKLO!l;U5)%BR@Y7E-V1Y0Y^Z1!Z883 zz`PKy4g4_*hiAO20(!R>*6 zql}Yy`5e5j-1pAw;W*&0ha(zX4@YTV4@d939b5Ah4bf?aKo>{@Q;&la-Y=%diWt0{!szA zD1;{*nS=`qz;RdMm_Na_d@Hq;wmvd2%~Jt5%AX(Sh5zvY9OZ$4@Q2~Q|2num@ZTPQ z^QTGiHo<@Wb#QCp|NM1u%izEGI=F@Kue}bg3jVI^;Oy`(z7B3Y{PVAa%Y=XGb#Maw zH37Ilnhk`1{8c!j2>}cLI0@HC1=Ut>DSj;cW3GdXf`6EVW3Gv(fd9qglJ_+@yrTVS zr$9Re{x76JMpjl@YKAzgiurC?v57=KPO>>! zQDn1{$4C#MGk~l$B0Mc6jC zGzkxIOP?mcV_IR^%)pnBfQjTig>7OBXknL4EpyB$W2YC|-BzFcBJrBMkjUfKtMVs{ zK@gOIP=K<;l-d}^?kFm>!(Qxw9Ir&qD-U;t)#a`zgDeR4`vG?YBw-tCBf_xL+)fue z$%?#zo|7Or!*dsaWNH!_92LdnI}~mbFhJ^Yxug-UFCf7=;XW8-&h(j;Wag7hE|9Jj z5K$G`Q6iGq#R2ggN(K3?a6sB~W&QCaXlE!j+@8H2S>x5hnV-SsB--96ra2MuP-78J1K3{kVUwi7mh!>1_ zG)DiYPY5D#|3y3n;^q7o@j?-={J)6T0r47q@iv0?|L)Tf0oVN(?+eUl;xGUH`>6c< zK(zJS{U+tz@F)2{^%r=`%b&%c_!s!4e}QlM3p~yO{nPg+{RN)d1l8{-lnDpO0h9w8 z0P6t$KGW(fDn!pxRD$MQW}RV&*dB62XKAsOz1QtEvUl?m;IdTCBd4h8w`Z)}Vaz{u)WR?agJNiS!k;e@3Wtfza zSvi?$W7+&WbJBofNaD?w%IgS)z7baz-}~1su+HK8R!MA6k(gVfhO$LmZPKco9TQKK zht0kH(Ge@AzP@nlEBp3-^V4Z%bX2fYmD}gd+{HuBSNwC5aZzl|{eK^~^1V-&ZEHRI z)v-zODH>K06!Wj*ov!Co=jBgXb;p~D^Ey5LE?{krwwIvkk(i|z4( z_33wQxbKCYOAHTveg4vkrw?q}xqbMzV;?Mep)x6~Fg7@`uVK&bA3lHhf4A4mtL+a}9nbt=e4l|K z!o-N=xL1F8X5xm&eRi z*j&SkgN6d51W>oJ2ICI@aa#>2uvESg-DBn z@;V5uO_2YLN#G>_G@@ceMoY34mfGDF)E2n+CQ=Z|45H4=|3GW?>W9Xnz#xBwr!ehL zI|cp|3b>b|ZwC0EQ+Hq-$&|tG_rJ`{N|KVgx*jJoWsIA#hDxFXT-f%eLVF6!xblF8v>iwfLcMgZ(Je~FC$?^@io zKEt7#@@Idw%(Z`4hM&t^{tIIMy}!T|9$+s21w()Q-}&>$XNe&HpFdRRY1Tw$hTU$R zT!;ngnV9rDt@paEWkoa|r1}@OrFDNywp=rrbf40PYS<*Zm+~ZUL+oe3aA=&U{mC1nm4&{QSZ%2G7 z@7Bsvr^^XCw9#1lt~Q>V_yU9_9=fo&xPp439BTz;_fArwD7KcBO65TBww5{ElS^be zQU2P}q=~nqqOhVAWOkPYl(t0IB8V*@bdb9_kV1MFQH8WEiYiLWiE&S>v=)(U0J564 zf=#ZNj8B0aBY=0Na=QG@EO;7!uBl9+&M`#R>hLF$L0UrPY9Mei&NR#5U)x))+$;@IvC7=Y52`~WS0AYZ0ie%;pU=Lso zU@@Q?-~to_@&UsE20$Vp77zwF7n02E2Q&hf0VwQ3m@cvdG64dB1F(Py0EIafESra6 z?gFd@ECo~p2v2L@^iZ4c0U-X2fab7dDgd#7P(T*|&Br?dXnq|5fC`~xk{`K=(Ii}F zfFDQcQd}}40hBJWkL1@45bXobg|7xsp6B|^2VfGu20-{)0HyON;C8?>KKBZkl)vWz^u8AW z6mA26^0ya2_yYjK$ATzCpa1j$-5V)BJvYHliPrQy9AJMWz}^sG$G5bF ze=NYhD8NqTPvuCoSqNx<{xb>$1=Ce7s2?EY#0O?RaH}u+>aS(XidC{X_t_&C$(A&` zS~Axl{MMCUtYl^MHNSH&$zDl5^UZ%Ve6lb6TL}O0bH|_S#eDmm_c@XVU-`79KYN7~ zV-zajs4wpMf@LOrG35)@m4V@!`{}{2j{M3n%Gq+v3O5uhA?lDiL>6rV6(~P*WL}=^ zLrx|yBYRkY6FN0n$r;&~eR6f2O5Y`Xkj!EP3^cF@OJwlA$_etU%DOrZ% z>8=}(^xCc;PfPL2G3RBcmsUV%WWRExkX}IPYp$FA1VOKGHd z7#HD*p-k4y1=rwoNJAhE$Ctwz0*f z5d(wZ$SWs(&mV^Mb2?5bVG66FZ^82Y0Qr~(m0%If0T`;N7 zUIvruS0zjuUov4*UmOQB8fHu9Wab8#dtlO-wiqT&i0m+X!PLO)4fA3+#&4M4!<-58 zFwFa4?tw{-bQjE4m~>YcJz1rYCORG984F6CRCQ7Y3}AD84I#4>io+F@3`4rTe(yBm zxo!;)&yk62Vu2U@6qlG|x4epErkHrp@dsh+HI0ij9wY%;(Uz-W&c)o5zK3YR0_Fgc zola|ov=l?K94nUSB!MJxTx5~tstLv6(t5_kBUsD8^*C2Q`Qwm22F@TLa`N)8K2APTP0Il^555^8c>tnIbX)@SO~8J@SwJ@=$N{ne(A}1?v(V{EhW7b%YmTGbjeNsTc8`HFxnl;C1;(~;vURAV5{Ej0 zJZjb8Vu=Yv3d+8tvXisP%*alc+|Xc@%sk0oddZ*tEDugW^D9ZmE3# z(2avYN5Vx-|wDro`VT@ z*Zq2E@=K4moV{(!bGz>TvbrpD_urPV3xabeZclLIdzp{+eB|3BcENJ57=B=7IsLR) z#uf8lkE~x(7G3kRW!t9%tv!#9y>Y|7)0U>lzO}=84_o`e3qM+tR=-the=YPq{e#UG zwYX{Mecyhzc*{ReSl<8r_q~O+-Dd20`M70B=3U=pZQs23@qg{MJhnZLcc*?7v-zpl zEMHB2XR$Hum78Dxc(EnE?~bFJ-r<#np8G6?qwm~0`}Mr4=yxYr4*WQzzQg9n=5@c2 zYKgb3I%!;W+jn!;^ta4fyW;q!;;QtfFGrh;?(eXtZ~ly$)<@@xkN#%rd0$aNin4L7 zaBJN@!vn*XY-D~vz#pDJHmvvS-eV804&isyrVZ`*){}1ip}{8gy>XxPJ*4_EqhXwJ z^+TH*$9%Esfz{8wsXAKnMzT&pRmjm`&i~Vz#D+~0eb;Q06zjQ0>Tic7hoX31Q-Dr4=4l71}p?D z1-uH_4A>8tk9enGMtsULeE(wmbv7R&dcZ`GD~#O7;nRn986` z@K-)oB^fKIQr=S_z@`<~ok6)S`{=S67)6;yL0QCU4ux1S-!TRPx)fTebq8gpWEGa@ zNqdYCe`v5DmG5W^&rA;tHHOYEBgq_P9Q!+hN0(tu6`x<6R#{{%C)NcR+U~`ir0;_Q zk=riOBpZvSc!!4}+NNFRHs!ZFlbI$8e=P#@*guXjhWX@=V<3-936qjTgkv5fdvZz+ zF3%y`$h0i7cL+v#1kk&NNw>S5CG=TC-Lz-MNjnT=T9RinbE8}$v>%H~4Byi0N*}ye zO+Hky#$j4PZzrjkR9AkY@=q(nemR+PaoF!S4eC7BHtOGWr4Ld&CC6!F%nKl=qp3(T zGhQm`T&rBC{i_U@`68*&w*UO^r$7|?${@(gxEQVZ;*t4vdtC_T#6%9oXID&J9VQEpf6R{m4zRfeiMtD;p} zm06XlxL02m)mN(Hsxzt8y>_=4$WMPSRFu>$R)2Yqf7`Khhr8ChP9d-KBd-w@UZA z?jO3(br*HP`i}Y-eJ}kj`hj|bewaQ}f2Y1gKTSVd|2O?|{RaJZ{cim~^*`y)>4OZ> zhTaC&Fvy@Y2!>=swjtker@>~h8_EqXL#3h0P;IC+%r`t`c;4`$;XT9qhK~*38#)^M z7)9e~;}qi(<67ez#tp{9#`DH#(;!otX@Y5*X^!bZ(`wUZ(b4Tgp*OeE1y{|@VSxlVap*;Um~rB)@WvQ*<#52)%?kE)(hy{vju^{(o?s<(Q8T2!Z~t?DXu zoqCb_DfP4JFV)|ue^8%Qch*E|ZqoGCa2lN^MU$bKsHxLDrdg_4p?N{GPP0X`OY^bj zpyn%-ZnLIE^SdTk+g00Lo2Jdu=4r=iAJ;yuU8DV2dq(@KHb~c5r`3tN6x|5jJYBtR zscwtzsP3fhwC;i~K|e^Z)|>Qh{Ve@_{cHM9^q=d$(KqXFGz>(EPB6?g)EU+p4j7`0 zeT^n#p|Q;Pfbm)5>&ADDpBR5IhMM}AvP>nW8q+hTw@rIZUz;wP#_-d4C;t||h5wBI zhJRGpD8!3KafCQQtP&TBPm6DeTf`mW0r9xlES{B0q=z}qoM2X&MRTUP&|G4!FwZeB zHLo(iVSdNF4W+ZseAL`xZZ&tX^tNa$$(G@k9Lprjy_WkdHI@d;QJ+6s6%zeiVQW}&Kly%C-(B?KO_bQJm zyP&1bP}QTA?NuF89aEiFY19HrX1uyWJzxEddcFD|I34^O^-t4( z`6sl#?v_N0%JR5nxn-^81Ir%EG0S;sdr8DM;SLe>t)sXCu9%z3m2a6Nl)dIA&H`O96)38_MckS*j1uM3-mt-@a6Q=yNj7cJs&agglYlj2sfpP4gv!MEb0z?D?P$m8tX{rG}`O109Y%u^OB-O6V%D(qKwR$0)h7igDj zzt^7CM(Dcf5~UVBT$iVF=v=zly7{^nb+78y>)z2t>s9&@`g`;*=wH{L)?d&MF}`Aa z+qeTI|4)>vg3snh^Fxr^5}~sgE&fwT)&i1xFuMt*%usQ!iIPuU?~Gt3IMWuJ)?GSD#X!Q@5xusu_(!6Q+sKL}_9)v6?sy zt68mmOZy#qpdWP+`Y4PlvHCbYtB=Q*;PtYr{-k*}$@kQSNt!05`EI5!upj6|RP zvNQ&NtQ@KushX;Cs?Mnt>O0kwK!pbN)9TggSJetlv}TA#)J)P=YL9Ar>sXye=SB-| z(FN%j=~v*Jw&;)RFX^ica}75cYm9Zq0~q7JGhRfS>w+G0kZGuC6k6R(w76$XFPIul zA7HfWz~9PGpOX&L;?gorbLpYJUiz`9jH<$BptI#5T<|cy6Sgd>!HR>g01p2$F zs@GJD(F#KGJuJokLYx=h^^-F>=+sAYR} zpGc!eCw(`RsZP(M#~Q1DK>xV@S$zF^eE%-}QT<7Mm?6RtWr#7v8Z;P9($QayGK@lB z}djDGJ~ zel>c&H~7D!XWJw+3fqOAVy2iQ=7Y}|j}gsa&c#^uFY^!PewK-rDsT;-Sq@v6BJqGljULZdODG?Fycnp(|#%|cCsrb)9O<#Jea zL=&&oY0cWZFv85%)@Yy5zN6iz^=e~u{dJ>s6Lqt6PwC#(HR+ml=XH#}i@u*;iE-p1 zj34iTXS*3=#&|=KVJb$921AQMfqv{^<6?~HtI$WhW!!AsX8h3Dgc0I4Xb!m8iH2fB ziNweHdDw-9rG{mO<=|x37}gs$Vq9o6Y&SF+_8SgjbT|UO_7p~l7L2)J#t37SF~%5+ zu_Dnp(8yr~PBNw%hZ{4EImYp*{l&%-qup3(tTI*`YmM_k|D_n2mm8lqt~0JTZZvK( zHX8S!6!serqTleMEKV8E8Cy^yVWtRElqtrWNm0dz|>4L4<)#+t^PCYp*t zL6@l#y=Jwk*3@8HY+4G6E;p^kxW3-B(X`35%d`j7-ETUGvh|w2N6&N4#PA9}jE~@> z_&A>BAa6j4C-JHLa6X?O%a2FjRLqz2F20hl;;Z?E=!F-fT`c3*pk1uv*Yg{} z7wqEqfHT<7AK{PlUjBRj6nF$iPzYf{gb*vl39Jw=BnlddbElCqN5~h(3gd-|f?X&V zTtcN#CCnEV3JtLE~B}Rq$;6NM1#o}`Dd2x-nR$M1;5*x+s;x2KIcu+hn z9syVC70-b;xhOJbg*giRNi2F5);thnwFbP3U>*)GHOHK99&0WJuWC1!n_cE=b1mi+ z3(XDab(Wi-H?J|T4VYcXGYjSv*00bP4A*9AbF}%|vFKeVYKyfcTD!I!yke!c3Ujks z?R@P*ZG(2PcByt5M*HW%#jn+_({9q9(+<=X>z3*EV=Rr)r|PTpwfZL1ZK~7M$5I`p zx=VAf2E$@-?dt>T=W&AwRC0e3|!Maz*VmWv0sJP^u<8t_#m;6gUy zjg8vv+FjZ`+9vIO@UVxqM=%n2!GD}WURtylwTw=o3)4mDqA)hZ>f$gC#)B&vsN*mm z8gzm#37qb5j2bz*eBD^xc=S%ix_EIQ%197XQ9}9XIg3#`F3b#SQ8J6gWhfV!rZhi8 z#@e5D3ba$8odWF?Xs19s1==alPJwm`v{Rs+0__xNr$9Re+9}XZfp!YCQ=pv!?G$LI OKsyE6De!-g0{;Uh;?vjw literal 0 HcmV?d00001 diff --git a/qutils/BIN/QFILES.EXE b/qutils/BIN/QFILES.EXE new file mode 100644 index 0000000000000000000000000000000000000000..66ee526bd1b621a771d579a4428fc461a9b75f14 GIT binary patch literal 54272 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


_GQFlWwZa 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
(AR;1)tKG}-|$0iIG16cQA{A!0I4RB zYJgNDPcLTdV?fA}FJKv!h^mkj4;f48vvpyD*+2c=)&I*aR?p9Q5m zaLvW;niIHh2OM3G;QCMVx(aa;eagpbe$6NQX2XYlzUohww{1h7bp6b{IKJ__R>n*c z)^jZoV^P8&VcT{s=%#DFdHuh{2m9yDozH`%unxJ%MX{s>KT})rGou+lK3tdLx(wIl zxMt$IB3b9V@-%+RuBVEqLyd<}Y1~@Zb}4ER)nC^J8~RpqFU?IhSZ5nDe!XoloR_0g zG4Z(qw`xhfm;x90}XV#^((Pk|9-^Gtlb zoG4Ip1uHy^^gHP%8%cip{4pfY8KQ4irYXrvd4N*V&zGk(AiLWK0rC|6#FvkeX=!6$ z2bnj^u@$*Jje<-vZi2nRKHcMd;smw=wDswB_}<1VHn3#eJshtHIiENfuXq&S*nUU0 z9cY6tHZ?9Eh`Y&L97Gs3L)*t4maY#zDPAxMo!8X9vo1hQcJ5A+HiAwO$8(|gfNr}I z8Uh+KIf4K0_P#tWs;dA0f@nylNMwp+V}ep5-r4s%?1};+Ah@Ojb4NypnQ<0GA5##_ z1zUVk&bep1 z=X}mNpYu8Ejc72r!>y@cErPfR$LZ+u(W`^f=>gW6YHx2ufacw|1@>D^>He?Fko;EM zeh9adKZHV&9~Z`LRy5!UN=5{&h2AzX{sqi8aknU>&kWzCX~&<6xOyC`r3f^cZfwWm zV6Eud-*;(_Gbpv{1n!b61oNW>wb-PpKuEQau(N~dgxA1eScVR)8-gH|OA=}8(!~c_ zWD_j1>-Jx1TACbK*9*?G#Jie<*vuJ84XEaw8Q;sZk{bH=Hz+5m_4VW1m+7^>;N30Q z{`wQ1EBgA9AZx>YNw-_{JXKcT0^P%mku7#(Gb%+=OduSLaA>rok1|!wj*3M5 zRTp~V2ZqlP57*?zV0b}-qWvOa!Wd50^Xk?w6q1rxH}il{0Wb%(0z+x6 zpmaV?x5++qC%iaSE*$#+kwdY3npfu$gNxgE%6Agk?u@kWdKTj$aRY?*yEF}1o86C! zZNB)R(V9s@YG~k$10n75>Sp0&3aXMgmackaHPU$3(UAM{aY$agBD49~kQ`xV9YU~p zHsr8>GMC23n4itBJAyVgG(M|NkM|A5iNV&`kYNIeh7N5$Jxl9VLK0*0tyP&JIF*Gi zR$;Bm4#D6CU(4GLt)o?511(bE#R3~H{}#L$cm!tBL*)+QcAVxHiy-*y-cUxN51DxFRCV(MBP45_Bk%k4WZh z(XfezBt2mV`xq=xC!)Ng=GcR9SU}8pn+JvQg?doCb$bWm!W^{cpM`n^22YzEqmY82 zjum?XE9wIwI>q>Q;~IddKx9IK{zKAo(gJI_Ju2+Bi9Ssh#!T+D4KFO42J-nLP^mGA z7;&kg!HS?AQ0StkDX0B<3fYHEkP<5sR)eiqk6Qy^78a(g)9g{<-he)0G!G&gilM*n zdtnwE`zUeHA8aXL6SXX>7B4H|kcbWqJ~=kn(+i0g`y|BIi7$6)Xz;b6;_D(%wZ1)R zU2xkASZI9^{yUJbu!bq_C;WqdN+wNFjfkd9jTBZW#n}PSUZgtp;2qFWbhP4DDom%+ zGsftF*85S+GxH!-rTWLzFck1ekamKZ^%{CoVrQ zxau&9plxPYPgZ%(8}$Yz zBXBV|G^W8D=sSQTIFzHFH9O`c+-@@6YBJsQo0WSQ}BAO9J`K=1@=eVkUQ=ZSjzoPOtZx7nuha88IPFb$sGm}0~5j=8-RWzWZWSSmE?wH|s zZHUeSBd(=8f%5Zms)P*^b6N&t^JqmW_Sov*X{f3W!EWkVxc#?BAI(nh<=6y6M8v+b zGm^lXpoFJS-}R_D?fopGIucV})%A)^B!8gmrSLr{{G)v|N4=M`a_XGuma$a2GpLS- z3A$#7_gLrZilYs~XhQ`R0@8yi%q+jE8q|jNRRkiY`x4u&35u$}QiVZrD?Ep!wp$() z<+(y%2;3=oa^DWT^q%@(M**4{nGzGvyaJW5au<8qZk1;Yn6P~a+h+A=HrQD8xp(Iw+BRnz6- zqSYlx%c9EhIWnA%Tpyp$TXKthscu`2*$bzBW=AStkYRQwxZD}$3H^MIem;AGZ*> z8c^uXbe1IZg^h9C)Bpb{z{bYk3D~Qd`Hn3Utx|X-I!UzJ7Q*B@oswd+V}itLv-2K_ z%^`7_#|jS&6K(U`y3B=Rc?&ths$hZ_9%EoCbQeAj@rsG|M0+TDkJIO{^cKz09>f!E zi^D%-w~a3HN_z37Ubk7|_dKq^<7za=!A#+!<^C5UQZg4iExg?mBAA7^$!tR?a!1;Q zB*$5Vy5)0>bvVa6B!$jmWXFQsd6-^^SB!&UdQn3BYMhwYJI)}6n;*?Pc(u(-?-RV_+q{B~lKd3Vb%ZMPimvHU(M{IiR|RCQ1s~%J|o_c8~hr6;EzB{|-t;3(5`S}-VSZJU}mi^cV*$We|y1y*YKHIV4Z|@CV{_&9|I~uN>JX;Wz zq>uy!gnwt*<6V(FEqBc8{XdAA)_T!T=MVn6cGsLQa#Zf_?K`lozAE|6x+w4c)L|PZ zuIjW{GyT-n+uy(Z)s{Uw`<@^CbkVBP_+WF#z?g2D+I<(le&)iu>wRb1UI=-k=ZC)z z{k-4CiO-E07m*br*M&WC>-aaHY`gJF{e+hWSLr{BShLbTebTw~UBe%XZDAPICL!|e zi*s-Nc;LW^C*HdMJyuNzT%xR8a2b_=n;(=Y?Dt1J@8eSe`_4ctu<+e;d zzUudlFHGOGc;xq!uRgNJ@YRv-msRsyz0)DzT2k^*sv*9TFulK&N_k{~HXMMQl zjpV_6-&UnPimE%F37)E19`n>E!;hQlyWF^5b@Zi=*1Y(UuV3y^^_UJ5e+fAh@!k^) zbaA)ZU9_LbIPm7jRd3b3yl+nTN%z?;!&A~CPqjRN-L3vitfkcuXcif^_^tY(|t=jP#7SZs;oOL@lMj^dy*y}^}}24v)9r6j?} z|BUiI4}JkODoNLPCf<)mJJ+M}f)QQWUCM>)I!KXD*Bmw}jIaNw0%6hI%U`*ZpL^;a z1^yEX#4rxV$Jp_ETnHB9@Y(G!R_=*syZ|YZ%NVrKtb|;l!U~NE_Cf?Dl7yzK{+7*{_oM^Y3o|<;a;ms`~woWw4;r$N@ zR;$fn^G?Vxdq@zv<2TFgEaW{Tz`@S{aJT3FDcPAR>2evxM`~U<){p)IqO17N_rxbW zU`(^y`O#*`Q;-@Z9)6sUcNFrlPqw-FLa)<30ezlV!WX-|6PQ$=qtI(}Is_|QvCGaE zBQLy=5A=g}XW>`~XC>&X%msEtLj9KmoukAHA=d76j7GfKJS0VTAuq9j02BfNoHmOP z3EX^kujt$C9!<$$lAXn7$hACmmGqqGc8=vC1lwHv9og7!bBqOnvJqu3r^7A^%M#B7 zkC!h-m^4R;*>1BSd%PfHBCU{qkp??&^-7Q*3twVGu7&6&caywma8^lgY zTJHgnUL9Vy(@uRhL{X69P8z5i7sc_vvLoT(PwBy1d_+OYR~jfMft(-`o#YDdT^5vP zUtv*WQkk@3N*V8#P~H(&o4EmOxf&Of{9M%jfOw^m(B*Mv{ig z=yv;DsFD(EV_hx8XaVVOjLV<2re`5-h`AZ*nE{QZD^zqm6x+O1%@Idqa)~6&-UH|h zfQ3LMPz2-x8XyV?1#Z^HGj+gD;2mHIFb^mLT!0101(E>;5Cwz+mp;L{8(@6k0e(STKM%K=pBKU04=#- zo`Pu&UdA zD*=jUKJYm3ivM{TbV}a}fZn$XAb%SHO5djdxqk(adq)t3=<}Z_Ny}$D{n0$1kzQc zs4pPosHqdCcJ&8ec}g@adtKDam!7^!rufNag1#F5YnC5dE)kvo^k05kw2JrZAN-sC z6a4-+!2iM5&b=1FoPVwEwPF7_{>jUP5Cc&G2OfL!n1mU5Y|Js)pZy;>dh+yjhLKJd zQ|9(Lyf$?A0+W=Wji3VMrVq%;5pC#^$w|xX)9jH+9*~icmU+h}TgA%M4}|m*#g1m3 z5Oo+3BF5XC=u2&08+!DKLKiGV%TPGgKMd#bTK-8mC53Zgd@U)lxxGF}LwEHa!V4&V z#XpRHq|<@E*V`L%0yK%2YfKcc=qisA8o8eSCPM-%l~5CYx6fDFq?ykN*ELUHpMCMQ2759tbfPIH+5;Qx87c zZ7!CeLoK#B?xr&<NLZ5T(^LT-W*FvZIwHiA0H; zm`sforL1UAEJ=jCB-#?fM12XFVMja@1iiT`bBQuQR!(kn zYbGoC?&s$bZZ$yT@Eq_y za0Ivvgu*X%^m0T>G72$R2`~ltqrx~T-R$uu zV6alcXE|Lyd^C}u&4U88J_}|;|j`{cCCUg9fHcjTN9qpRTQGX9>G?zX1e1}G} zWXsl0qB&^WzRu4m$h_=g?Wdi$AIXfDTzcgLSI^aN?Rwc3e`v(5=<^ZJ4Cqu}5kKy^ zuNEb>Z8_)hb+5!<-}Y+q#qzMZo4YH ztU5o!xNC&I>XijU8%C_Wv`kW+`}%CP`S7i(p;bqtN6fr_eDs@(u3hP|?X|rlPLw&) z_r0`OGAl59)Xr!h^2;2kJ>XxfzF`_?4Ebugi~g>ehFbKe2FzLP2&?$jwBtxD-|5@I z4{tpDi|J6iZk2sH_gTAZ)la7Ql^bmKbuB+uKV5H<8@D7*JpaYQZC`$G+J5WSr{>D` z<7?NPGxbg%b|z!z)`g3{+hViuE|~Vvjbu}l>GccR*L(ahW%U!Lr`9ezx5Y9k z_0WkyT;bnZ)ppArU(qnX+&KStU8jkK(Mi(kwT7-U4{N6OS-gq4^_Bjc8H0m6zgu_q z>6Ir+?0_JQo%qV?@pWiL%0 zvN1F^I_+F9m1027+n0+awVfER()z-FKp_zw6DAobsnhXTw{*czwWn4EyVkiin{ zn5<&9H=CDhnjuSIm=k25iWz2FCd$N=7wkSIyJR=Ipxg;ASe&6}>X(G>A3dTFZ>pQ; z8D^;vuedatj_x~wQ3t?x9`B}^85*4?*_|G~FIG-5v34y0vxYR`lSLvD?`D|a$wqWd z!XmGiVZISk1V8k0rUS*6`Go)Qtn#1Z$z}OW&D9!}0*KI5CVVxCu7$l@I z36qsxq_PEtg3wZ!;GaBVN(0g%oB72Y_dgB;`0k2Bo^2RVua zqF7Q&3waj_Merohe2-sbYxYDR<;lF;&RyA@cuc2aJIKIz&G6*COQ)?fig(F&HT@YDO$2zc*0%VX=&f=3)h8BJQ?9I(zy<(Q6Yh zXOiSBcA4FLQ%OB?w+%vEqMFu>N_m(Gq=8KW^Rwt;8DJHPi5V``oorrgIgNAF|60mw z&Jq7h%%K>61Yj(|hOrX1A6vkVW1nYNvv0Fo*gCeAG)5XLO_ruf?b0&obm?sAE7DEU zkEM0e%hK!8+tN0&_A;f+Buka`mkp6UDVr*rD_bagQFd7NmF&FirmU@;m8Z#b8E}Iw$!)!s3w`S#RIy;PA2HJ#5drGsV zdD7w1QBtdPjMOFdN+(DsODm*bN>584k@c2&WD8`Wa)Ufc-cMdAA19wCUnk!sKPT_3 zSfXC8-lDEiA5~veUr}FEx6nMQiPFSrG@2orCp8w$7|nLgx0>HIZMFGYvv!$wjrNpo zgx;nv(O2nZ27{rmVW45SVT{3Rm}yvISYg;~IAFM7xX)N(oMBvH{K@#M@gVml7i?N% zT5n=laelCb4VPY!w^BT!a49Y+|E|2Iys2bVL8@R?8&#+(T-8w(sgkIoR0dVNDp}Q6 zm98pNRjOvFW~=6@7OI|CEm6IyTA^C4TB~|T^}cG8YKy8`)lt(+Gh9=mnW5RJsnOij z1Zul$by}Bpymqm6m-e8xPTQc3)IF{ns+*@v^a?}1;fP_XaXL4fTL2n^ zu<_!2-YRxI`x*NU`y0zhJ4p{nFG%OhK9JSRF3Vae9#D)_tWtce_*wCQvV$^Kxj|X0 z?5TQ26{#_4R%>gt0lJ5EL-bCR@Fx96gWc%DcjZcrlZ<7?N>F9C@wD-rvCjCT@sjcH z#%so#MurRGg1I)FjLYDHOkGg!pO_9&TEGJjL36NPb|yQIeVtv)*06io6YM#5uJldm zR_PDYXxVz%Hd&5*n0$=fDW4+0jH6zi72Omo6z?lqE5nqL%6Qb=Jmr(h_m$g~r<50! zt3bESs#?`i)d|&Q)h$(+x~uvLb(%U)?NEf_SF68N|Dt9!{WMcF`!#i%*4mZY z4cZ^H*R?H&!=6SFW3(Td7;4Td&)zyR2)eZ>NtyetYXR`fU9WeW`wuzD!?kL#~E9#ogu-Oa&$f z+VwuuSrbjf*P)DCfbVr>Ikqob#Fnxzu-j4hzC-P6E$u9gmZnOFNj=i3;CqXt%cL8m zwbI|DH>BaR9HiX z{+d48AT>l8`ygKSaR7I=Y>ZjFJ;E&I%m#SBybk?ii(`?dg(Nt@8YC37twOJ^c!P?>4 zZQ5{Mg08>rY26&%3%cdH7`;qCMPH}CtnXroGxRs)f%7ai{A^flTx)#C_`Y$I@v8B* zF^D66`UuyZi{s>+o{Q(Qx#66bJI`I=ensFt(9$+eJ(qVwjV4Hmv5CnrWmA{uUM+6QwM51n&&hxgLva_L+am&*+X z{YP;Yu86a9E|f$mH%Z7NF*gO0m#ZAEv?%RLFIsPIh((IVU*2R0p zc0)4pCYs50D&2Lr?N7TuQ*2ke-AcFJ72hDqz=U@Jt4)knMAzPQu%bv31i8QObIzTY zptbw|@9*<}`TYO+nf3@Xn_jtelwQqj&Tax!Lzv0~?f75&SH@%fB zYrOY-YtuL8|y;wrZN153({h&a6ScF3U_QiLvMc6#1aC0iXfH@!;puEf^c}|9}0z zjRMMPv8JxRwo%ajZjvA- zW$3NHD~&{ko(r-|n3q-bb=eUfBZ3I+%#N_|h}ha39Z}~XBGQec&0rs~&AEEuY>OxG zS&O@UxXIP7H#u7`+-eep7F+9QeW*wC#M+wrx^PK1TJ%?}OxXW3t0i*L8O*5|{wWq-_dm*s%J z+fqQJCp62}`U;zBz!Gl%fzCX&$>%BhNZsu7`VT0*md@KQ6`l73(s1W(deM;MS>5sM z2bK?G%jO9IfA-i z2JwOb9|DR8fG55^{y|i|_z9(A?f#%3$T|IzuQ)kQ$6eEB3c`=xvAJGl;LHvaC*5*Kd%3Rbtrw_1 z+oo{3x)&OBWuZ-f&_N<_jwb**IvzQ6N!MAr&SgFyTDHS>7f-J2^=9=?pV7WQ&d+M! z*RB_cj3vB%AI^^Yjwie6H)ls}Kom&oC6a;+!~)dBg5$e)0qZYq;*v2mRQ55BfjwAMl@uVjw9)hiMM^yE`Ae_p=2;1&Me$4-Mxu<1IO<;tU>+*ebLc zn$Ic7(_`hqDoX{4A7sk4?8kkv$MSlC*uijc5$(2*-xBJ@~{Vaeg5t; z;43+Z-3b2|2Q2uqiLu=7d?OLx&(2usM4&O1y+7yN@H zDeo{BB~y~paxNhGe2|mF(w%BA=;c#-EL2Bt%k!KbftV{uV+5DT05rAekbf|m&uRm# zJMT2{09LVOK2PVJ=AuK16%eL`Uh>h9<#B*EX7LbsSaVXA9;nCGTXGpspgSNUFsh0T&+@27s6D(e3D7bC}u&Z|98Bh(S~Q>YUAnIZvrPPKwYQ>DAGsLAJI<82oOIG%;r zawieuQ9pQwA>F&&_VoaZ?g7Rec zcaI&bm&$KhMwZKm!Am}L0kAx4C)P}?l~|d)ymdx-V6Q@mS(13s%71h3rhKoy@9zd? zgStL&F=4R=n85a1ZCgk!poGuH)*#wvY69gAi-hJ%0;(jq<<1LgrIo#p+5C^DBynTbg101U-0Dxqk9b*N4&VgsOk zed}HV94BEr*l5yLV;%`+P%7-`LxQ7y1SAPR4M4n`&g0#wy<5JjMl0lLdCXr!oFn7V zzf*=M(;38chFfd25mqIm$KPfkI?8(0WnF3yH9@*p4Q(W#kEMY=%S4I|Sln8(hs|?- z#3BEAP<_@CK&Eyc8jm~6ot0~;a^AUR601@8ULs#*E+b!b8nwwTx@EFN*ND+Iw&)sr z8u{Z)9x&NKvkN8?{KJmj4^hTYl~y&AQMcovmH1XJIk&vWTBOE5%;bdjI+_ARESt6q z%q(5MhaPHfh*S7^MljS`%2WDmRb?~e_ma7~>)cC7ROUHHX=S$|`-mvvWmEx$HIiMo zifGWXX;gbDSNm7!YRUW>B@wLCu4a0ht;Ov^GN9sCD!)zqm^`0RM8 zuL)ly==-i_5j9Ys)o({4qh3N%U2|EG!>{Hr@Y+`C-vMmtbHZvx*3q}2Ej*<{V z+7^z9T6Hm`z0X)jyj^~m)Pih&A^BV%(*A+7#g0M{YL6ELY7`pnA?+88Z6K4M7b1di z_Fpj6*rh3bRyR_VTpvV>dXZrx-jXgJ8cK(5XKy~DJpMKqELzh=Aw4Ipb@i;?vF#;* z75f2|3Ej!5TPeP%yALfa2xG{=hwoL4D>RAAG&P?vuGU_=hA~7)FCc_4S`xXVmOB28 zk<;6`n$0Go3&rR{TOF$H?zr6^>Zr+2fmpyuU>`#r(vR$2R0PJbzu{%5XIK?@HdG`O zCfutvGx8^(B-GhW~C>8W7)JYQ=cdqZVvTvl1X9=FIg&6K_f}B#}4)=o5djJ*v)8CCu1e6Mi zqbaz=ij;a=7G{BPJoNX7*R6z9q%=>S);>HI+!hW_X9%;50MYz%7KrZ@$oL~sB zeZgo#!RkolRzaHDXbo@L7lg|AA%kPbNIR`6a*H6pUmtcNLi;LO7)`bzr8KFDqCTZN zCsZHas3F?T>S9+CIqW;UhVtx~%92&&D-|@J2-3AgbJQF|NB9Q-71BnpWUY&l%LxVZ zHa1S!)WqeeGK`@~to7OJ!_=GiJc;Zz+Bnwcwy}e6s`bXDc3puRIuo_R1jF%Ta3~GSiIpx(+)L|MUTS&W#g^8fpuZd#i zZ0=@P`wS$E{Kr`SXTKo-pqJs5%75_!b)8Ip;!LW7GX#P->l#hfT9iR?1`<+!_%~GM zewIgMwf=(i&#*SlO8uc(?yLpq; zY1=_Mlt&s^)J-*p9?Z%QY5M?z5GIPBL6|dCU8ikKWvu5kCxmMl8-vGfb@fHv>IKp` zVwG23ij>|UIRbHMe57=aG;aw$<&U7Bxc-lFJy=z&S3k|lrVN?e4>V7Vl;_Qn#x2F; z2KmDcaTv|TgqWAslMHcjxPchH!SNqG4Lv7qcpho6^klf}FyhfbSphZv6U4c&LA=)4 zgDn0*%Q2WgPT6`!ojvE>o&A#Ibs&Ui%T607WtdC{(Yl zpjf8XL)kR(zP|xFO{PYK-_s_^lp3Uz(>B;mAhKwZgLMoj)}6J&qR6L_`~97Zgheox z?e82yiQeH8kzO-C-az$FIvdm;^$;y4{fl~tG{~QsV6jPFd*3yedO@pR%AlT8_alWx zOV1u);qWHSH=UpqWI06TTv+4qH9gXtAJ&NVkBqX}w7QSmJZy2OnzYzr3)>Pwp~I&A zoF_=PP&&Sl$3OC?;+OFF&3`IB%;T3`7O$M1%dA4a8cdvgbzr|>J=ue5adTI%(jI|) zKs8Fy9<)Leu3EWjxi$hZi@>=ce87ZWy&tf(k4IS56m%XDkxmtT@t;T@gAgK8hO~`n zJ&QpWfUiWLI&qcu3=&ak_^epEY{7CVP!U?N+$+uP(cH7hmKp+q+_Rwk2|b#V%*2(x zX%yz=vEiqv`1@G#u5|IRGzA?GZNjvGaX8jaI;$padbPAYbdCJtM#S(A*biwi^mB71Pn%4U1!sYWrj<%9<~fj%ec8Jq^$yF8+K46D$cD|A+3T1k_C$eR^lbZ>}w4>=$!>t zvB1eJCB3u25DUBnN!hT2-dW%(7C6KL=^cSXexMX4mlCZN%do(oY=oHJcLO4et=t-d(*w>;Cm7-*Sccfw|mHp%r+|~VrEf~8{&W+8dWwpXo?xjk%P`!7^(HWlAxgb+K=Hud>9IM5DT99gpju-uZ6^M2a7Su_0XG_ z-X_tTKyM_E+$W1LwW{=$637Onf+z#hd>>z!C>09LcObI3`&|aUkZ?>l$w#E)D+OE7!*2Ud5a|1Pt+r9?%RqS5kS^4tCgQaeorV>$&ij!1b;W|u|Xit zNj!#ZK+*9i4WPsp=+B?(dP=aNjaeUi_z6%R(Ip}6TYP|}p}!Q8WHpjR$wcp47d1oj zD|_e0|NVxbum{%xT(9El!X=nQvnYxd8WfE2q;?P5N+_%N&A}j6$s1{W$^m?=M-qW2 zqf6)S-yak@r=TXPSgo8S^O>b8c?5lTdX;)XxiDL@Di?}mD+};{pfFIT=KMynM*E5Z z$HAd67zD*sieifvwa3>nw!$v$~rE`V}PaG zp*)0Y&%-t08M;Z9-<^;5Xr9QfGhi@5rcab;pQX1zQ~#?9_SiUp?txHG{;lZNv-Gp9 zTYCpKvtNZ|p%{(R90=1(J-YBs*oXB%6n{PBOGG-)Eo z>?Xi)S-S7LKFJnpEZtkY0|(yfAL#DSx1q?vCZ9<4A2{$hl{qwu@xdruIbE!rycJz+ z1=97OQT7(caUIF&AI-e7(BH8D9{f8N0;u+Z?!j^&UcA~9fQd3tZaO26vTLn8%AOT9 zaA0ii^+s;Wo62?@!q_*;L6~;40VX@_+N?AK2Qt`9Ksd@Ed=6&g!^_n^#7M}Z?OD+S z2N_OTQ1+*iLC!L~jO;sEcnS{$0=p+tX`wT5LL=PNdkh7rpQpwUd^6YjNp2p=M;W!Eb!b;5G$ih#u@O0Wk85|Q7bBN)1cnppV z5AB~*(e{B%^uS?;V-}Q1Dp?vwo;}RMGvyMFt5az+I3A*Knm=(uFzAOfI9@|B)W5w0 zN5KXF1Z=tnX* zHdD+IhU3vOI5Ir64XJ4RKqh+N=;csKQ_0eF%6J$8aib21gbiN~eW* zLP9D-3m}l8g&;#B6dFOKquORc+i9two8*7{A)9sqf-D<%1iG~MNfKt^{%7ic@G=;z{{Ma%jDDE${tNYQ zX0R@+|J`F?q5cfk=jy-UGCWxQXOGGIx%!hJ|6KjgL$-~ne-@j#*u1NFO*}+_2BYX~ z&O(7T)o9--^MqVMc!q9{b_EJhk2YR8>4@yIV-OS^ZTBLGl7S6$VgtR!(YBU{&0%4V zw&nOVVixe2VrUiZf5G1|7CYLn=kJDI(0wa3`jXanNl7T`-?|>~Q!#njF^-Opp^%^# z7E+2#jC!c3UwJoIIV2VxQu|xq6(WK#{tz^3H_|$xxwRQFbsuY9BzkOgT*8h@HlrSN|U$1)W%}flVI^PEVpdt#S(5Wf?bckHXpt12>Nt4|6$LT+Xo1dhJCdRA78HRwdAu zu+Ms794xMbO~SbV_9I|HELBkfz_e)lVw3n_hz`@#Jdtee}PoU(4ju#ke zy>a9bL+}z*t})7Cp`4hw!(OXY1dj$`u7#L($}Z)?d|HpW6YDW?uNsFD!4@~Xj!QC= zdQ*+IDxU#NUN)&WVeu^2$k+Lb|3v5UF0vd9SB6Xx$+e66bq7#QRQmFSjY{~1pM70w!F1UbIhb7Jy|7So-L1O7D|y}3S;7d&Ptz^%(yTl z-Zj35@K4wF@Zql2fQp8pHB&Ghkv=>6Fy{~D(#iX+wEPsuDzcS%^TF2Rtkb5kEHGTi zliPL4QK!A>BN!BLilwIpQ1c@?+?3!epcl-YxG=+fzyn5cf}}3CKdnd)!03mq3h+a^ zWP=lp#SILd-hC%)V>)Tbkt;A4Y+GhDe(j9{7U;CuQ@nX8HX_CTLJU9GakmRW_s z{`;|@2TT_Q1N*n08?MUtO2K3W%OYSAayQS>`WZ3z)`_4TI6e;?|1t$g7WJFtG44dM zZq+$lnJ0>pX;IN1e^k%XxCa|EHU3f5SbF&kpnMszVGGV8~}&TcI6+i=rfX9;a# zkwOFt*~>%7+DPIL)VYa;WLCDh5HsSj)-&k~$opVXcRpycgu7%)EbK;6qhg_fpPyBp#&U9pjfhgt5yV!zh}7 zhuO`zO`3z-WT84NQW<)|o1jq=7H_Q7upqslA0h4Cjy76}2v$%s$HOY#)yLq+4Uef4 z@=fX^%nd!z(_&V!>=QUoa}!ZLhPZhQITGT;!fBKOZ7fGKjP-_$za~2xo;sH;lYid* zz84+bs2~k%sdsLF$NDjZ@;Ekb1C=-`X`JuV&O9WBHn|!3CUbFn5Bz#v;)8kacHlvZSPh!IgfjMQZ{te;*o`R zVk>E!y3kERlP_PGwU<1nNx|?J{UN=Q zcwLQXnv5+q&gA+sOlP;20+w4)k4Sd)2(~z$7=ap6bg)`oNRrc49n$`Si8^xJnhzHs zX?2l?RVZiDTcZ^-RYIiDIwW>3hob51Fd5jkf8c1}03x8eg3FUUXvuGa* zqMc|^)w069UlcwzEYn7SM)U+};AVuOi_z1APuu?qdOAVRH$hKzp?wyOzLH<95!+9| zONq$&T8f+jj25nJaxUcLbPZ9rWfc87NHwuWn}Z<$yoDa!z8z7V%;!Mnb7?YvO!TM= zskb|;wOg;H5}z2kFrUq!75_f0m)J!7DL_g$>S6az3>R}- zu%x~z3Wh>mPdlOiM!%uy1)m@jj4t~-f7AMojwpBHThBW-%fV=V z6JE8a;1k!k=psSUcEO=byYEIAYYNT)%#Q6C!ZgclOd)@bq`+>RQbA$Z)YhnLKO1EN zQ~S&7k!#y^xP=kY^%#=w_yKOAu1DCtgYMc(*p-4N32FBsQSvM5qSLCN3eiRH;Vq;t zdJq0i7!5J>#no?U?7NY}2Xdgct}Z&WVbcymbNyZFf3Axw72SYqmaN*p0b!zENYn5J zE(ue;^@5iWk1vCQTwd5}usU8r!}!($wSeYNY|ZqxnP_M>&*^*(%cXA^GpjY3nH2<8 zg3YX!WoA}Z~*1aoH5xfkh@GF^|og$2O^l?AA2 zt#dgc#-zZ0L(EWZs9A*1R2R?3ljzZnr`T)?&3_BuWEy`Hh`qVlC%lCbb3l6&_qR_D z?=`Vug?42DGuppsBR?YTDbN-zo6lmo2(iV(rI>2#1sA~t%;zpGOA+NoRJ~p>N^$+r zQ?ldiS#etX2V>$s!3uaP-xa_9D*t{ zc0xXzHMpW!425FkW+po>6;mi`-ly z=g?jHv@@TIAua#5PTPWDM_$_jc{n9N2L4EWa(RJ=ji#&~{Onb4FuT zruvYY%kyiqX{Ka=;Xo`smVMZ-_*H^~VOY5pP7kr=ro;SL;#Kz%RM9GB5=9-|-Z z6{xNU`&_iyDbmHuW^V$n@@*C?JrhDnB4`qlfo%GPKn!GL^gC0hR*9B

DRDv4BF_ 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 AMgRZ+ literal 0 HcmV?d00001 diff --git a/qutils/BIN/TEXMAKE.EXE b/qutils/BIN/TEXMAKE.EXE new file mode 100644 index 0000000000000000000000000000000000000000..98094adc847e507ecf24ed26d603a49bf1dd9e4b GIT binary patch literal 55296 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.(i>6AmRP&f-m1Z+)QM5K!Tc|Z_E3}7Ddr+q7{CZdi=}1|r>|I%* ze5!mQN==|lQC29ss(PvnDv4T;JaW|q>KE1Tskf?ks`nv%ullt5syae*i{??yvzj%U zHV#m5q~4L>cUt+2l@n zgM69%W%*iAc&GfR{Dk~r#cPT!ik}sIQNy+>3sm>0W~eGv3sh%SK2=Y3AN5P>chsFU ziJBBmx@NSdP;;;59nCh)w`f%_YL94-X}jod(e*=XQtC(OOZDsY@9G~mJYm>rxX)-e zDovkLJDAFG%V4}JZ3T8>*?Rdq@{RJ%@+SFq;IIcJ{ki;*{A>9!U~@&zDTIn>MXVxS zk);@+$Wi1e#wjK!CMl*WN)=@atD*{ZVYZ@LQKLAlJf&2rGE}uHw`!|;vSyCvcI`0j zKeP+APw1Z0{iajtN9z~ppVP0_Z`NlUCK*03^fInBeP*IX{$s#LEg36$MDmK{q|_%J zA{!wa9+G>4B1w^~ND0ZU9=+RA#WKZm#Z!uB(Z?NCY*4l;|5SETT~no~Me0;_fAv7M zSS?qpQSRyLr_?Ldo764nslHR|HA7LK=4#fXM>?qKppDn|*P67GwB_2TwR^P(wNbjx zx>TJ?H(6)XJ*InEw?TJ8cTKlfe@L$|j5hpgC@|h_e8srdxXHN3c*uCvc-DB;m}t7) zG{7{{RA{o9W|@|m9yc|azBHX7de>kr8-^Ht&I0jnu}9oVGF#Fp*(~`|;*s1eyG-Zj%?i!inpVwcnxmS_Xe(XO52c|jsL&TdkcN-7`@yu-te;FEkl!Guiv!ru(|@V|TK~QNxWQxi1!KT@!$@PbvBp?$Tx?uw z{LL6;N-scD7jO)7&GkVC-uRNPe}l^7+9CI6JXEjb|h9yr8Flcj3u2x+%?dZoWhyUWsKnZRt4%q+Vf{p8K^RQVveNj@C7O=3Odqw;6ba`&TG{9GYW zc2;I%WVl;dqVy=wDov_2s<%|%s7|RmtGi?DoPx2kOk+ha=G4qan{Cy6s_|;hY2vgu zY5QqMX^XY9wJ&KmX^(3qx^&dMx#(xs>ps>U)E(3Ps*BQh)o1Fb>)mKSpXsmZ`xx|w zOv7D8dQ%2vrU^f^pypCaI>XN>ydx z3#w2DXRE5g9W<%7qbBZA?NueHlhn!hLXmoaW{9Q|-}kC!oo1irOU>PSyIyGMVlbf9 z6rsgGZrFf2_LTw1H1TUsoh8W_eV;~cxFCr|ISj+-^#yv&pQY!e*Q9-917vcUQ8rW7 zD0>F=A{ONVu}mTCj|fGw(Rs#eu*)u*cc zsxMWCQTpGjepLO8I&fC?hw4xCOcClRb&NVrorpToL)}Z=8(hNx^z>j*i?TnV+GF4KFR%Mk`Nu20QswFj&derHq zl4X+RlBXokN>+d~XlrkqB~6m;lAV%0lD%kqha_K1j!90S@A*Y?T5?`;QF28x4mG+| zZpC<1Ew7g^l`lulehGE^9gGXxF(!PD@!*8~7x{Vg$wG_$17pqIsr7-+GI3!W0NoAWVTU1;P{vQy@%% zFa^RC2vZ3!W0NoAWVTU1;P{vQy@%%Fa^RC2vZ3!W0NoAWVTU1;P{vQy@%%Fa^RC2vZ3!W0NoAWVTU1;P{v sQy@%%Fa^RC2vZ3!W0NoAWVTU1;P~gUrd4j1JWlk3;+NC literal 0 HcmV?d00001 diff --git a/qutils/BSPINFO/BSPINFO.C b/qutils/BSPINFO/BSPINFO.C new file mode 100644 index 0000000..08e46df --- /dev/null +++ b/qutils/BSPINFO/BSPINFO.C @@ -0,0 +1,25 @@ + +#include "cmdlib.h" +#include "mathlib.h" +#include "bspfile.h" + +void main (int argc, char **argv) +{ + int i; + char source[1024]; + + if (argc == 1) + Error ("usage: bspinfo bspfile [bspfiles]"); + + for (i=1 ; iB&Y$2pzac5ov)U2D2$!h}`0A~acC>wL&o@15d#2@UrK^)Y&?PL9!SQ-igZYA)tQXt?r&KQ%^ex^uk`)Unr%E zsr0!E@xqPdHxE8Mt&)PyM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOhQ-Kp*tu3eW&V zVIK^_ei+*JJ)#b5oIn(MAfnV|gVz5P4LTD6B0vO)01+SpM1Tko0U|&IhyW2F0z_bk z5I6t_;Sjt6hhYRp;RuZFkbY4&HbNkZtG_*{D3|_5D{jNI7X_POH%)tbiluqQuSzd} z-Inj+5iA!5UloytLB8}s}3qqU}@8B z2-obCe~a?bS;x_uEGc~3a03_I;D!q0JJdLmwS?v&Sz9=DjApLE9nEg5e2*$4p^CX| z8k|*{>=t)~^6|rCg`CY-G~Hth-1V(CxF1nrtmPpW1{>U?Gt{3@XSk&^x6GYIOWafb ze@4-vmZ;=u`VvdkxW1&Mzo7I$OM2Zlp0xZGWk+(h$E(~yKHY-<4OI>*m9=;NUE0q( zXo%y)jc()gFRBc;!dh#cjKJ!#bUu$}I4U?sUj`Y&vKqQ;>Y z5g-Cvm%xLb**)^_`#!hDxIVY6zOVe6i0V=1Sw0uAhnVO2wkW-MzBrRLVSrThqshbq|8d@uaq`=$|i z5k^H<3fR;e;fHp>u3vGRuE*;$SaIs26P7S--QltTR8VlnJ=1c_p-Xj+>ygL_)c?ZQ zmUv5LDje9dj!evo)L_rhKxd0sW+_!*bZr_1X%HmQ*KGiWyn$I%Z)MUg6SE0FubWMG zo|#QSk#hH3YKdgh8L@V|OI9i8m@(t+7)5BJ;H#W^1d(l-RZZ@OX|;w}kW_{&_3oNm zPik*sX5llc`wqpR8lt*}mC6Hxqu6y0J$3kuSoC~Vl!^e?)Sa!FNweElSVR8gV z|G-G8lw824;vl3x)toB#ayXU4%Y*TbDTV)2C6&dA(IG#+{uJwCG2YeU@s#Ug(qr&O z1i#LaO7jNCI&E8T$})TnpBhdW=Ri2CYY{lmsVBn?Rrbo_d^f(1M!$;{{Oc)1>zY@S z507=6L{(ST(b+(>|JSYh21e4?ZW6(c-08@PjSN1h(iJ<;T%lCG@OSEa1q{vOK=%xHZ3B$ z@yjDHB>&S29=B=#4|fP@|Bv?n)J8Y$|F!m(Y5$M*|DLf!Nc(^5Z*A`89aP%?dwIXa r(Vd6@5g-CYfCvx)BJf-UK7bG5BlsAuz$_#o1?lIqCgtr-APWBhe$26( literal 0 HcmV?d00001 diff --git a/qutils/BSPINFO/BSPINFO.NCB b/qutils/BSPINFO/BSPINFO.NCB new file mode 100644 index 0000000000000000000000000000000000000000..112a95e29fb0dae0ae66e201e39b0f2d4bcd971b GIT binary patch literal 74752 zcmeI53vgW3dB=~02(kgQ81oE-YuR99uw?`o2iYK5l5K(fz%s@JCt|g`k~WsKVzn}M zCZr0XCC~>XlO|~(ouui54t>x#a-9nSYJ8=6t( zk#uQj=DBImKz=y4pSm-Jk&(ja4%d!-H@Y%!Wt%e>?HC!)=63DKk7kA^vbi1Od&YN^ z_KfAms~S)<<9I1us>)YQUw3hTS2Jqq%m`Lhv%9bOHE3SbySaPg+D*~Y=*sSm=e0yz zx_Y|Wd%KdaO0#?P%99@@PiL-wV$h^`w@$_B9V=aO{Ly%(4`dGh3Va(u81qu*Ch%kM z7vYY;J&8LKcOvdxxGQj&t1&+$-?8}0qp|1)+$`K|;*Y|g!@E2e|6Xui|8Aw>T8KXm zKR`@@d3X=vo_@I1yaH{^Bds>!Ip@EO{{Ro9@zGXG_ml8{hX=73zlWSF@dfLhzuoym z_+R0H?#90c|Ks?RCZX;W&A}v$tJVFEHr1B z(@kXN^W^85J15AW&fD6tMGs=JWdWjcGNP@h#GCM(S4u z7Yk?pufAEZ+@;6s1!LBdP)GXBR8VjB?zK4O?*Uhtg-QqiBXITK9^VD7etfn||0MWq zVl2MbL|Jh4<9jKr`fnqw@nVvA)prp;DYMF)LqqDwe;4?1l;0@4(L~<>KY{#%F8@OC zlexbytouhryJ`(Ffa#~m*mdjEiM z7w%tO`Vg7cf#2ou9pG4kG*38u0(=Abs}BD#_~qaWTzkF%eg)UN9iRUwBJE1tZkPTr zkyn9#(Bc0Kel;!rO?*feX{_JD{fszVW61k)pK;gQNPHjZTa`}xHK(`+*XMA(J89BC z?aH49-jDl$E8j?b7W`7-yg#oH9>A^S;uqt*e>M5u1MdA-Xm35Z_y2+PS=6EQTky3$ z*1Nfyd_Md>7ak$~LpYUD9-sc1MBeJK>Q&x{aK266_iggNZper9Z-deokasCA8NLwwt2ou;eU;Jo{VeX6xLUaKC)1Pn>#zB{T=P1duBZCs54bqd z=yKw`&m{u{3IqzgNecV{eb?N>Or*7w#{XM|)8A@r7W{?q1`}xwCMXE6kNJPff1}GE z&lg(F9*1kJ7ko)L{jt_w0yjUfV@W;b-F(1~H4Wfy{I|A+-$l>Am+zi`a~V!;a^t^Q zMp$*)@gHAfpZa_|{^P$Fm!dv5{%fqY>pnOBo5kSAB#@ zJ#{AdR-7H*xxV-h+i-S#XB^S9-A;YgW2YZ0HO~C1$8n8!np^lb2v3gJhsrqpHSR(5 zlOG^ZAW-1orNB$-pJ|@@f34s>uJJ+epDx|=)*4{8Du1UFVz_qWs+98ta4~ z>GEs*7XFOV>5s+FjXAeA5Pkv$0tJ2z6!82!&A$Q!3IqzgvncQpZddDlhGf9W|9~@n zw|J3XrL$zR@F%PV>sZg9LI#F%v(4d;5hiG^clh&!XH(w~9DXJF#Y0%^aIL40#(l@( z=a7C3tL&?oTu^T$-nrI{w+iQaS__K@d@_s$rEA}kcA2wXey#Vkue(<1b4;Z9h4TD8 z^N$Aj6>|t{y?>vpubJ=(xa~@(KAORtWVQLOt3LuiiS}RXaP3KI&3PCZ)t(l@ihEw= z;g6_oT2p?}<=6WARLXx`>EzeFEAD8elV5Fp59yt*zDK~d#{Wx~U$lvEJ?{P%6P}Oz zEr*{?xQX&j4nG5Y0dBRszV2-y_j9+qU-1skApb_y4?T!x|H7DWx%|5JBHW|!*2WL^=&t1CsA4_n*?{KZJ)uvCl`#Fi{c@EcmTG!)N^emTxzvA+%t;?wI!!BLC z96ghpUHKC!uQ}+gxW6RstGIu{X-(XRKZGmcl&&?he7W-zaar2_XT%i;kl$At^9=buFL~J zTR3!E3N9W`+U1{5Sl`nf!l9?$7rmo@=J17t_5P0tr@Y=rUGr3M+MUw3z6f^$IK^$> zl*G9#>F_)8SCeNQP7Fom-;NVs$;T_tw~5o9i+thN<3EAB3HM_c=hNh0NL`=6SAEHP zR8D1-rh4v4gp+BDi4PDc@OD$cjo0QyE~M_tjo0R7!kQD<@%b1wq6r^v9;^FP-s>ay z4nAga_H6mM7~fJq23P;^HKkM0ryTCa@08{P`VQ^*z1XB4BHYOLcfaxz{+z?@cusx) z0j^I#eX7zsEZ%DVMfv%_?{VpNyyts=6r3bK-lrZUtp4ae*S;6PkK&3YcfD?l8?)2l z;$Iwvv-1J?%MTD%|MiDT=YIA$+|CbZ-_zilQ~bUwKjd&XUr7A`9J0mp1={xu!WskZ ze1YJ<5k8jo{kAK=-QsTkK>hy?uKA6fKal^Q32V;a<`1dw5!U?1&KF4k4q^3qSy!L> z%j2p428VBUxSdZ>|8wA)BiQ)__)iFH&Sd8k;Lj3Pe{AOyZ6>ApiTZpupGf_bu;xE@ zKEd_BMflxZ&(0?({}lMCrr}jPp8)?pxaL1@K9Tx4Veypge1h~J5mx{1<`bzW2uIZC z<`1dwg3rg<`2+c%A>4%fTiqYe=N5~%#`B3rllnHeXrMkeIX_VN&CCl9WIo{Y`uPA& zIq2X>+oC$Y{lgeH59b>`g0Ezj{gw{8#)bw33Iqzgr4$I?|65AVP+6eBAw>bE@|N#% zNHsb%Hc%i?;4Ptm#{Vvy)=%R1#jAcBus@Tgq0J>sMZV3U^Y5J7qQ&)HZ}WBDSoQEA z-dMr6xzvQwn*3md6oZW9KDB2OOV!JVu`>l9jc(*MTWlIr(d5T@-`b+dM)7KkThUTpk19aXqPFsYch3X zYE8w>)vUKh?Rd*YEXHB?c%`D!&g>arGc^z*s zsaf>|_6N5ABGdC^)&54x7Fe{uVsASAwi`_2vF0{Dnfe=Qwes%!dGDc12W=7`b(y`Q zxMXh(_Cqf!C)ExNX}#n6aB+Eb9o;Y9Ingya)pT!Q6oE5^;%3K*sL9!HuP;y z7sqoxS2kTrlWn|I9L=Q1bD5DbpE7=KIn-hw(P*5{XQRl(Sh1W3%K;@r+;HK#T+wtD zi-mGp&LYbq{!GVEF0+#sjQD~XMHty^7|x9ja;s~*d%Ac9225{yAh&5OH+p3;U&`5N zC>p;Z$}Zy-8wR;KyMXQ^iK>7&=$R3nZg85M>WQ^^%T-s5yifM_LYk>kCk{1 z>0LRS)|nefPYjp3c9(LaAKNnpTD%wZZTPo(qR8QPcVN*2`DyB0f zB_|7KbK@nRbvbPfl_l}13hYB%pWE#zGDOhEZJa2RmZxEQ@}<&nu6L-Qr!(~%4VyLj z!8kh3(o+~6w4|~r7K;W$sk5u6m(PAzeq5j1 zc>Y6tvktL$mdL!VySIBycTe}$t0*v>9~>%86)B_Dg?hTzt>4fn?rMO$O?VaeikXnLx>a(H4W~!3E|abB zD>85HY2Vo8a_`C&X|3{ChboF}>)Nu_l^BKaWKVb%IX6Oemy?REA)6|{B0B`J7Ef%` z2htf;o$xC1u5It|RcD6tW3B}?f)%AYdb&3!8kNfq>KX~JB6nBkI)9CkbaChSMA5aT z0-K;;8XV1KBl~G5UZV}|TQ2LpVoRc>s=-}sDyXh;>QSqJzi#h!=`p4RwjcDvR8%Tt z^W!_s5S=akYBu)!N=r;fVQfzik38-`6mVUz?a*`;`_ik|^_5jG+Mjt+`SKqu098K$JO=3+c@r6J*?pv0h&rw-?vEpI&ju4D$l0v$b8K4dlo8_FVLcMHC%>=?d9C zLIHhC^8Lp|*nPE%)%z=7pMre#Lin-|A-IOMp$EwUNFr8SM|ymcnUG$PcoMQ*AelSKQVMRtNyk#Q1Y|2jvTu{%l8uw> zjpT(TOrZ6qWGX#;J<)c_Y)a-%y10@zkq)Z#G$orNc@)WHO72FwMw0)Kj;DALlI@iZ z1<5c<#!j*|lDV+5eC|S$pYb5wTIugfuT%1%gCyJz-sLh#7De(RNs#PD5~Q0comdZ& zpOOsBm#Ie}{U*tmNYB>G^GQB139_>w*;9dZBqj5j1j$s@0_nm^7FKdN%{a-!3S?(O zaXj`B$+SwQN46oPJ1hGX(%F?9mTW&r-cd57)gU=353+gTfvT-t2+4^}2eQdhBvGnxD`uH?=4(eJ+ zy7b>Ao9sdIcOE>ySF&$!6e{Ka<8NXvqE}qjg6J+hCUvX*-bstpB#}wqi|DF;E7r3e{)nd#4MsVC{c^$8tigvHcJC z{VRj!C(7@;@0#{MNcY{A`cw5S-8l6r>f?m3!x8lM!0ebz_gc39v4ODK)JH><{|cP+ zi*9iEHgL)7-r?{o2_Hkc<|4|kT>;74KIYQj2QK;9?>PJ_!jgye_CzEPEPG+zo`|^9 z(s9u|P4#K~mAtCPec@-}=Hphl`j!x0fV1{R@Y`@_;+%ak(@t1rG~ZPDOK|7llJ-TG zaeZ%JWGQLQ;NHH-rQp)Z@%Ba56F!f0YhQ%$THFQTn!~C73vnxPnga>%!08?}PZX|u zSw;S&eUXcaOWGG{2T$4;=>qrmMb0CvXXx#Vv=G)a_Vz{2C#+}a?TcJM_;Q@JFM_YO z>6vOiruHnx=^1+aBC84O8F~96s|a6BdtZXyyf>*G;BtE%{(i!8nh)vS)E>0{|l#Z z()QL&?2>5>kStSelg!ttcwJL@HD{cz?aHGyh2~TWA8d9_^vpCL)_retbkw>{acXbU zCRwm`!V4APkfngt|Eu%*fAQLlSKR6UwN~l>wN~l>#p}d63TW&q>;DnfSf}w=Yb@2L z{+xM2tp7*E*@QLzYJIBm8sF51iXWr=^KoVUKOz=@Ym5@lL+J}~O*pIn=fY>wziZ7a zeI)6^NWahO|Iztt?w~%~;(W`Rj|f-aCEkJM84#)TH=_TiazXzOVg@**C}8#fXz`0U zK8slY5C3J{VSGPU|BvuXIIa0>>i;p6|CqFQk>Be75f)G2T{x@%NBZ-Gk09Ohl)xVX zFYEs?LHeA-oj(7*_5Y}NpZb5){~-01_5Z+M06&WB*VO-`L(yFLD4eqgP^tgNx4nln z^=HmLKQjGNQ~!_j1JeKF{xsi}KA^KFP^te% zeLo@nM4Z+C1AmsV`eUpAH>*njk96^#PQlgG|0De=(q#X@>i>a%AN(|&)&B#p(EkJf z5oxEB-|GL(Hv889BmXnxSO0JI|L||IxYPe5{oCLgGt|Ea{Xd8>4Ga>`dlu>2XJmaU z%SRxbS6c8J;!DbYC(~fTQ>s}QfRQZ|819dOC^^moPLDEZ_F9!$|2oyLtDNybr+2N%E3@&gx`=t=Tx{bBim;J*NGqP*h=Mopy2zK-Pw zlHL!#2xs|$;3I_3!dZSG_J6dOCi^&+A6RdqHt=TBEkBU-)4*H69X~L-pRjmnmLJ$; zqTeBW0oQl@!04~Ze<5)m*IwLv!5x1v`XRV@m==e=p9fzJ?)Zh#?}A^Fz{S^V2eH30$4`t(;OoI3Ctn@sBm4>BOL2~$7~M^{hZb0VBIg~fCf_FF z96vFd58eyz_=(Z&;Nl1R^9F7OzmoEfpBUWU}?}2B)RZktb zc$wnQS$-mTBkdieyyYiyf3J}*PrBnLMw$zK5c*nvBF{r}p`AF(KjeAoT^hz&{$X8g zk4n$j@(-!+dcp-c#?uBTfk4*!TWlYdqe=FIYm}1voq2 z)5o?E7Ju@<_W#^?zc=QOYJOnHck0vF`uhDpH=c8Y8k;Y`Rqp>Wep0sXUcdiWJ|D>K z|CPsU%U?wldq4YsQ|AlR-v3+W$7?%x*}(m~@!GcS!1w=FRqg+k$7{F$*Seqmzp3*F z#1HuZ?XlxGQ%B83G=HeM{|CM1la|3%?*F;*davLATjj^=w`l)w|K}4N3gdM3T%&qC z4*P$+SOEeBehn0mT(8FN753V7uX+6Z82?|%BrCls#=qh1|7)!WydarerE7hq5!&1T z*IJj6<^^m2pD{=MEAYS8{yzcj?XmKB&3fS{P#{p?*Fpi$zt>zWK%hXNz&ncqAK`YV z_V23Y|647OQt2$gfmW-}!}8ME|6d*3{|A4JRPhX)JVEq4VXe<=+W#lNc+c8Tck%^M zZ2#Zc6DD2r2l4Zr{6KUL;bU=5ejw7?T|7}|FE~1r@Nqb64;cQ1__xYq?f=8S&|dxV zaJ=thveE#qwe$(xkKOMFSKC#_?(f6ThzN`4YxnbYzl2YwytV%i-U6;TYtNVRYMbUX zUu08*DN&@oZt)9h+W#kAZG8`}(*FPI+V=mce=&Kr2CZrTpZ1kvfn=E% z;;g-1uD6Wv8MNQ-*HfS7Y@(TTWkiqD2`|Fg{d#cmK6FjHUk^RcC9G#69Vy+P=7USP zUZws2*4X|(>9y_um+kjP3n;HPS^NK7Pw$H4n=9@A$M)H!^Azm=L!h?-to$F(>u_7Q zv;Pmh#lPY?$MSzX^N28BEdNJmp!cI}|DUkFPw@z)*T?>keYf;|Tlqh5y-TmR|L^4g zNLz~2c^g*#j|=Htmpy6eLDkV7y)Sx4t^6P9dbjls)|CIF>(Ks8S^kgwRAJw5EB{AW z@0;Ft@lS&MA4CZ7j-)_M`~Q3_FGCHM?eX}`_x=*$!}%Vq{2$?uIozGsGmZQo{Wsq} z<4dLef4*2O&n`fjJJ<`8cFaA5L(oLBH2%Bs(kZmim){!+NL{|_#HxA1-2|8IEJ z%K!1ao+Yp5KXyI=eIFq#eW;rD|GECRNH5#}C;wC6W%)nq`#!klM3wS?oEJ&otoP$b zq^Wj~up1p);QJqob24)*^K=&=R+{|7`a zGRp>@*o+@bSs|S&g0b$KIHlH#<(Yc@E@f@r~xA zX8ji^B396}(DTw#wr^tl|B~+)?nKHhkf?{*iXo9enoxzx_8qS`N7mI{W{&U6B7^v;TkZ zB~98MJm~EI+jjBF9&Gmiw;$UKy;_ZI(Tk54e^uf>Pr;;VXmbfuk#BS8s2{Ji&#|69 z;$Z40&UEdXO`j_J8QLe0ceCDJg6!{niN&s67t*eS>3j*_uD6#uq4q$5LyrQlz3|!# z;sM;M%`YrvTZ89Iqbs{Np4Sp>>B4qyi5>llx>>KqUbCK*i^vxOZW zEDViic1(;hR%LfsOZEO}I`1>1+gI-DW2^=_YfR^;O&!D5KALSWW`^>+a-8NiwkJN^ z%AZg*ZaTJf^mUKsOQ!0Co+VMHnAw#cp2*oOoXWyUL*r|7x|NQ&itKT0D!k3+sVrSx z*;G}#@2wo%C=FchI9 zLnOK;bxWCG7rRNO876CR!lj}h(;pJ;6G(+ZN7P7^Qy>-gXK0t$?jHP68DbX+Hc_`g ztUw+0A*en=CXS7NWd>QM5Io4tP7-AHQD#%UIJV3b$aIs;9LW^5#K3iAh|D4B$QzkK zklMFQoCu_LAhXIcJtLDmN%$pYlOPdPZ6|n;i6MVvhmPPFp^j>hm|+qm_FW5PwpvGb z=x7y*LduMiOausIo<(p^ReNNzNyp_RL1v0%8ebq0N`a2`ka~&-iHhoI8y)8(vlvfM zuRnH3W-Vk|TIv}xc_ol(ADM6Zva8odx@RY|77~@$QAYa%nW(yjOj13OxqhkS$|TT* zj&3sf=RwDrNMuuH{{%XINFX&0nL?@s5;2tta)C_ZehOb=vO1=v8e|S?Um$grvUq+~ zMwyE8AXcbE`)2~zP^ZkHOO?4AWS&VX5mNJ!sHsdK>DVNh9g(R?iPuUUr5a>rT_E#m zdnhMU>mIJBKCwh^!q-tiQVEior|IDHBuFjOgUqQ5bVQZRv3wf;t~kn?n;3Lqc{(cQ zU+`ttM5@`7Iz&ctK1ewDZ$i#>T9S07`+e1i8(GEXf&W|Dhq^|7zqmFv4qOagaQSM@Dc<{hfY8_xeKL~J1C zN7+E?%=J$UR#0bOi^cuEIMc4=_w_vXb;Z}MWvgD0{atYC&62M9nK;H`Q+zVpE8TCw zO?+6Av0H&Jeb~KZke>M>9CHF|$4>J}+4+?I*bnig2R4U%bMd$0t8SHHtT*2Tmu|N} zbAcyunlJnw@zU>V!Iy5i>eiS)oBEi0nj3JM7u*Xjd4aoeiTM&(fIxvjfp;1Oq~rM@ z?&*hHO#>au_HJ1sHs-lUWbqO`VEn`AfTBlRt-kK|wpDg9_A+=6=_~OC>z%*d`9t^* zXhA}~J@}2MuQHS5`z-P5f9}M;hWW-<@b92cdH{bI{4xAfNPo`xL$pWN8S2ERo|Cw~ z@;^qr@_*&kR{Fbkvj+JwtW_dodWmVn681{0UtdH|dJdKama)`Xjheadnode[j] = LittleLong (d->headnode[j]); + + d->visleafs = LittleLong (d->visleafs); + d->firstface = LittleLong (d->firstface); + d->numfaces = LittleLong (d->numfaces); + + for (j=0 ; j<3 ; j++) + { + d->mins[j] = LittleFloat(d->mins[j]); + d->maxs[j] = LittleFloat(d->maxs[j]); + d->origin[j] = LittleFloat(d->origin[j]); + } + } + +// +// vertexes +// + for (i=0 ; inummiptex; + else + c = LittleLong(mtl->nummiptex); + mtl->nummiptex = LittleLong (mtl->nummiptex); + for (i=0 ; idataofs[i] = LittleLong(mtl->dataofs[i]); + } + +// +// marksurfaces +// + for (i=0 ; ilumps[lump].filelen; + ofs = header->lumps[lump].fileofs; + + if (length % size) + Error ("LoadBSPFile: odd lump size"); + + memcpy (dest, (byte *)header + ofs, length); + + return length / size; +} + +/* +============= +LoadBSPFile +============= +*/ +void LoadBSPFile (char *filename) +{ + int i; + +// +// load the file header +// + LoadFile (filename, (void **)&header); + +// swap the header + for (i=0 ; i< sizeof(dheader_t)/4 ; i++) + ((int *)header)[i] = LittleLong ( ((int *)header)[i]); + + if (header->version != BSPVERSION) + Error ("%s is version %i, not %i", filename, i, BSPVERSION); + + nummodels = CopyLump (LUMP_MODELS, dmodels, sizeof(dmodel_t)); + numvertexes = CopyLump (LUMP_VERTEXES, dvertexes, sizeof(dvertex_t)); + numplanes = CopyLump (LUMP_PLANES, dplanes, sizeof(dplane_t)); + numleafs = CopyLump (LUMP_LEAFS, dleafs, sizeof(dleaf_t)); + numnodes = CopyLump (LUMP_NODES, dnodes, sizeof(dnode_t)); + numtexinfo = CopyLump (LUMP_TEXINFO, texinfo, sizeof(texinfo_t)); + numclipnodes = CopyLump (LUMP_CLIPNODES, dclipnodes, sizeof(dclipnode_t)); + numfaces = CopyLump (LUMP_FACES, dfaces, sizeof(dface_t)); + nummarksurfaces = CopyLump (LUMP_MARKSURFACES, dmarksurfaces, sizeof(dmarksurfaces[0])); + numsurfedges = CopyLump (LUMP_SURFEDGES, dsurfedges, sizeof(dsurfedges[0])); + numedges = CopyLump (LUMP_EDGES, dedges, sizeof(dedge_t)); + + texdatasize = CopyLump (LUMP_TEXTURES, dtexdata, 1); + visdatasize = CopyLump (LUMP_VISIBILITY, dvisdata, 1); + lightdatasize = CopyLump (LUMP_LIGHTING, dlightdata, 1); + entdatasize = CopyLump (LUMP_ENTITIES, dentdata, 1); + + free (header); // everything has been copied out + +// +// swap everything +// + SwapBSPFile (false); +} + +//============================================================================ + +FILE *wadfile; +dheader_t outheader; + +void AddLump (int lumpnum, void *data, int len) +{ + lump_t *lump; + + lump = &header->lumps[lumpnum]; + + lump->fileofs = LittleLong( ftell(wadfile) ); + lump->filelen = LittleLong(len); + SafeWrite (wadfile, data, (len+3)&~3); +} + +/* +============= +WriteBSPFile + +Swaps the bsp file in place, so it should not be referenced again +============= +*/ +void WriteBSPFile (char *filename) +{ + header = &outheader; + memset (header, 0, sizeof(dheader_t)); + + SwapBSPFile (true); + + header->version = LittleLong (BSPVERSION); + + wadfile = SafeOpenWrite (filename); + SafeWrite (wadfile, header, sizeof(dheader_t)); // overwritten later + + AddLump (LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t)); + AddLump (LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t)); + AddLump (LUMP_VERTEXES, dvertexes, numvertexes*sizeof(dvertex_t)); + AddLump (LUMP_NODES, dnodes, numnodes*sizeof(dnode_t)); + AddLump (LUMP_TEXINFO, texinfo, numtexinfo*sizeof(texinfo_t)); + AddLump (LUMP_FACES, dfaces, numfaces*sizeof(dface_t)); + AddLump (LUMP_CLIPNODES, dclipnodes, numclipnodes*sizeof(dclipnode_t)); + AddLump (LUMP_MARKSURFACES, dmarksurfaces, nummarksurfaces*sizeof(dmarksurfaces[0])); + AddLump (LUMP_SURFEDGES, dsurfedges, numsurfedges*sizeof(dsurfedges[0])); + AddLump (LUMP_EDGES, dedges, numedges*sizeof(dedge_t)); + AddLump (LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t)); + + AddLump (LUMP_LIGHTING, dlightdata, lightdatasize); + AddLump (LUMP_VISIBILITY, dvisdata, visdatasize); + AddLump (LUMP_ENTITIES, dentdata, entdatasize); + AddLump (LUMP_TEXTURES, dtexdata, texdatasize); + + fseek (wadfile, 0, SEEK_SET); + SafeWrite (wadfile, header, sizeof(dheader_t)); + fclose (wadfile); +} + +//============================================================================ + +/* +============= +PrintBSPFileSizes + +Dumps info about current file +============= +*/ +void PrintBSPFileSizes (void) +{ + printf ("%5i planes %6i\n" + ,numplanes, (int)(numplanes*sizeof(dplane_t))); + printf ("%5i vertexes %6i\n" + ,numvertexes, (int)(numvertexes*sizeof(dvertex_t))); + printf ("%5i nodes %6i\n" + ,numnodes, (int)(numnodes*sizeof(dnode_t))); + printf ("%5i texinfo %6i\n" + ,numtexinfo, (int)(numtexinfo*sizeof(texinfo_t))); + printf ("%5i faces %6i\n" + ,numfaces, (int)(numfaces*sizeof(dface_t))); + printf ("%5i clipnodes %6i\n" + ,numclipnodes, (int)(numclipnodes*sizeof(dclipnode_t))); + printf ("%5i leafs %6i\n" + ,numleafs, (int)(numleafs*sizeof(dleaf_t))); + printf ("%5i marksurfaces %6i\n" + ,nummarksurfaces, (int)(nummarksurfaces*sizeof(dmarksurfaces[0]))); + printf ("%5i surfedges %6i\n" + ,numsurfedges, (int)(numsurfedges*sizeof(dmarksurfaces[0]))); + printf ("%5i edges %6i\n" + ,numedges, (int)(numedges*sizeof(dedge_t))); + if (!texdatasize) + printf (" 0 textures 0\n"); + else + printf ("%5i textures %6i\n",((dmiptexlump_t*)dtexdata)->nummiptex, texdatasize); + printf (" lightdata %6i\n", lightdatasize); + printf (" visdata %6i\n", visdatasize); + printf (" entdata %6i\n", entdatasize); +} + + diff --git a/qutils/COMMON/BSPFILE.H b/qutils/COMMON/BSPFILE.H new file mode 100644 index 0000000..28d4c53 --- /dev/null +++ b/qutils/COMMON/BSPFILE.H @@ -0,0 +1,251 @@ + + +// upper design bounds + +#define MAX_MAP_HULLS 4 + +#define MAX_MAP_MODELS 256 +#define MAX_MAP_BRUSHES 4096 +#define MAX_MAP_ENTITIES 1024 +#define MAX_MAP_ENTSTRING 65536 + +#define MAX_MAP_PLANES 8192 +#define MAX_MAP_NODES 32767 // because negative shorts are contents +#define MAX_MAP_CLIPNODES 32767 // +#define MAX_MAP_LEAFS 32767 // +#define MAX_MAP_VERTS 65535 +#define MAX_MAP_FACES 65535 +#define MAX_MAP_MARKSURFACES 65535 +#define MAX_MAP_TEXINFO 4096 +#define MAX_MAP_EDGES 256000 +#define MAX_MAP_SURFEDGES 512000 +#define MAX_MAP_MIPTEX 0x200000 +#define MAX_MAP_LIGHTING 0x100000 +#define MAX_MAP_VISIBILITY 0x100000 + +// key / value pair sizes + +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +//============================================================================= + + +#define BSPVERSION 29 + +typedef struct +{ + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_TEXTURES 2 +#define LUMP_VERTEXES 3 +#define LUMP_VISIBILITY 4 +#define LUMP_NODES 5 +#define LUMP_TEXINFO 6 +#define LUMP_FACES 7 +#define LUMP_LIGHTING 8 +#define LUMP_CLIPNODES 9 +#define LUMP_LEAFS 10 +#define LUMP_MARKSURFACES 11 +#define LUMP_EDGES 12 +#define LUMP_SURFEDGES 13 +#define LUMP_MODELS 14 + +#define HEADER_LUMPS 15 + +typedef struct +{ + float mins[3], maxs[3]; + float origin[3]; + int headnode[MAX_MAP_HULLS]; + int visleafs; // not including the solid leaf 0 + int firstface, numfaces; +} dmodel_t; + +typedef struct +{ + int version; + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + int nummiptex; + int dataofs[4]; // [nummiptex] +} dmiptexlump_t; + +#define MIPLEVELS 4 +typedef struct miptex_s +{ + char name[16]; + unsigned width, height; + unsigned offsets[MIPLEVELS]; // four mip maps stored +} miptex_t; + + +typedef struct +{ + float point[3]; +} dvertex_t; + + +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +// 3-5 are non-axial planes snapped to the nearest +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +typedef struct +{ + float normal[3]; + float dist; + int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate +} dplane_t; + + + +#define CONTENTS_EMPTY -1 +#define CONTENTS_SOLID -2 +#define CONTENTS_WATER -3 +#define CONTENTS_SLIME -4 +#define CONTENTS_LAVA -5 +#define CONTENTS_SKY -6 + +// !!! if this is changed, it must be changed in asm_i386.h too !!! +typedef struct +{ + int planenum; + short children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for sphere culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides +} dnode_t; + +typedef struct +{ + int planenum; + short children[2]; // negative numbers are contents +} dclipnode_t; + + +typedef struct texinfo_s +{ + float vecs[2][4]; // [s/t][xyz offset] + int miptex; + int flags; +} texinfo_t; +#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision + +// note that edge 0 is never used, because negative edge nums are used for +// counterclockwise use of the edge in a face +typedef struct +{ + unsigned short v[2]; // vertex numbers +} dedge_t; + +#define MAXLIGHTMAPS 4 +typedef struct +{ + short planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + + + +#define AMBIENT_WATER 0 +#define AMBIENT_SKY 1 +#define AMBIENT_SLIME 2 +#define AMBIENT_LAVA 3 + +#define NUM_AMBIENTS 4 // automatic ambient sounds + +// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas +// all other leafs need visibility info +typedef struct +{ + int contents; + int visofs; // -1 = no visibility info + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstmarksurface; + unsigned short nummarksurfaces; + + byte ambient_level[NUM_AMBIENTS]; +} dleaf_t; + +//============================================================================ + +#ifndef QUAKE_GAME + +// the utilities get to be lazy and just use large static arrays + +extern int nummodels; +extern dmodel_t dmodels[MAX_MAP_MODELS]; + +extern int visdatasize; +extern byte dvisdata[MAX_MAP_VISIBILITY]; + +extern int lightdatasize; +extern byte dlightdata[MAX_MAP_LIGHTING]; + +extern int texdatasize; +extern byte dtexdata[MAX_MAP_MIPTEX]; // (dmiptexlump_t) + +extern int entdatasize; +extern char dentdata[MAX_MAP_ENTSTRING]; + +extern int numleafs; +extern dleaf_t dleafs[MAX_MAP_LEAFS]; + +extern int numplanes; +extern dplane_t dplanes[MAX_MAP_PLANES]; + +extern int numvertexes; +extern dvertex_t dvertexes[MAX_MAP_VERTS]; + +extern int numnodes; +extern dnode_t dnodes[MAX_MAP_NODES]; + +extern int numtexinfo; +extern texinfo_t texinfo[MAX_MAP_TEXINFO]; + +extern int numfaces; +extern dface_t dfaces[MAX_MAP_FACES]; + +extern int numclipnodes; +extern dclipnode_t dclipnodes[MAX_MAP_CLIPNODES]; + +extern int numedges; +extern dedge_t dedges[MAX_MAP_EDGES]; + +extern int nummarksurfaces; +extern unsigned short dmarksurfaces[MAX_MAP_MARKSURFACES]; + +extern int numsurfedges; +extern int dsurfedges[MAX_MAP_SURFEDGES]; + + + +void LoadBSPFile (char *filename); +void WriteBSPFile (char *filename); +void PrintBSPFileSizes (void); + +#endif diff --git a/qutils/COMMON/CMDLIB.C b/qutils/COMMON/CMDLIB.C new file mode 100644 index 0000000..af7ee52 --- /dev/null +++ b/qutils/COMMON/CMDLIB.C @@ -0,0 +1,867 @@ +// cmdlib.c + +#include "cmdlib.h" +#include +#include + +#ifdef WIN32 +#include +#endif + +#ifdef NeXT +#include +#endif + +#define PATHSEPERATOR '/' + +// set these before calling CheckParm +int myargc; +char **myargv; + +char com_token[1024]; +qboolean com_eof; + +qboolean archive; +char archivedir[1024]; + + +/* +================= +Error + +For abnormal program terminations +================= +*/ +void Error (char *error, ...) +{ + va_list argptr; + + printf ("************ ERROR ************\n"); + + va_start (argptr,error); + vprintf (error,argptr); + va_end (argptr); + printf ("\n"); + exit (1); +} + + +/* + +qdir will hold the path up to the quake directory, including the slash + + f:\quake\ + /raid/quake/ + +gamedir will hold qdir + the game directory (id1, id2, etc) + + */ + +char qdir[1024]; +char gamedir[1024]; + +void SetQdirFromPath (char *path) +{ + char temp[1024]; + char *c; + + if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':')) + { // path is partial + Q_getwd (temp); + strcat (temp, path); + path = temp; + } + + // search for "quake" in path + + for (c=path ; *c ; c++) + if (!Q_strncasecmp (c, "quake", 5)) + { + strncpy (qdir, path, c+6-path); + printf ("qdir: %s\n", qdir); + c += 6; + while (*c) + { + if (*c == '/' || *c == '\\') + { + strncpy (gamedir, path, c+1-path); + printf ("gamedir: %s\n", gamedir); + return; + } + c++; + } + Error ("No gamedir in %s", path); + return; + } + Error ("SeetQdirFromPath: no 'quake' in %s", path); +} + +char *ExpandPath (char *path) +{ + static char full[1024]; + if (!qdir) + Error ("ExpandPath called without qdir set"); + if (path[0] == '/' || path[0] == '\\' || path[1] == ':') + return path; + sprintf (full, "%s%s", qdir, path); + return full; +} + +char *ExpandPathAndArchive (char *path) +{ + char *expanded; + char archivename[1024]; + + expanded = ExpandPath (path); + + if (archive) + { + sprintf (archivename, "%s/%s", archivedir, path); + CopyFile (expanded, archivename); + } + return expanded; +} + + +char *copystring(char *s) +{ + char *b; + b = malloc(strlen(s)+1); + strcpy (b, s); + return b; +} + + + +/* +================ +I_FloatTime +================ +*/ +double I_FloatTime (void) +{ + time_t t; + + time (&t); + + return t; +#if 0 +// more precise, less portable + struct timeval tp; + struct timezone tzp; + static int secbase; + + gettimeofday(&tp, &tzp); + + if (!secbase) + { + secbase = tp.tv_sec; + return tp.tv_usec/1000000.0; + } + + return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; +#endif +} + +void Q_getwd (char *out) +{ +#ifdef WIN32 + _getcwd (out, 256); + strcat (out, "\\"); +#else + getwd (out); +#endif +} + + +void Q_mkdir (char *path) +{ +#ifdef WIN32 + if (_mkdir (path) != -1) + return; +#else + if (mkdir (path, 0777) != -1) + return; +#endif + if (errno != EEXIST) + Error ("mkdir %s: %s",path, strerror(errno)); +} + +/* +============ +FileTime + +returns -1 if not present +============ +*/ +int FileTime (char *path) +{ + struct stat buf; + + if (stat (path,&buf) == -1) + return -1; + + return buf.st_mtime; +} + + + +/* +============== +COM_Parse + +Parse a token out of a string +============== +*/ +char *COM_Parse (char *data) +{ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if (!data) + return NULL; + +// skip whitespace +skipwhite: + while ( (c = *data) <= ' ') + { + if (c == 0) + { + com_eof = true; + return NULL; // end of file; + } + data++; + } + +// skip // comments + if (c=='/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + +// handle quoted strings specially + if (c == '\"') + { + data++; + do + { + c = *data++; + if (c=='\"') + { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } while (1); + } + +// parse single characters + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + { + com_token[len] = c; + len++; + com_token[len] = 0; + return data+1; + } + +// parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + break; + } while (c>32); + + com_token[len] = 0; + return data; +} + + +int Q_strncasecmp (char *s1, char *s2, int n) +{ + int c1, c2; + + while (1) + { + c1 = *s1++; + c2 = *s2++; + + if (!n--) + return 0; // strings are equal until end point + + if (c1 != c2) + { + if (c1 >= 'a' && c1 <= 'z') + c1 -= ('a' - 'A'); + if (c2 >= 'a' && c2 <= 'z') + c2 -= ('a' - 'A'); + if (c1 != c2) + return -1; // strings not equal + } + if (!c1) + return 0; // strings are equal + } + + return -1; +} + +int Q_strcasecmp (char *s1, char *s2) +{ + return Q_strncasecmp (s1, s2, 99999); +} + + +char *strupr (char *start) +{ + char *in; + in = start; + while (*in) + { + *in = toupper(*in); + in++; + } + return start; +} + +char *strlower (char *start) +{ + char *in; + in = start; + while (*in) + { + *in = tolower(*in); + in++; + } + return start; +} + + +/* +============================================================================= + + MISC FUNCTIONS + +============================================================================= +*/ + + +/* +================= +CheckParm + +Checks for the given parameter in the program's command line arguments +Returns the argument number (1 to argc-1) or 0 if not present +================= +*/ +int CheckParm (char *check) +{ + int i; + + for (i = 1;i 0 && path[length] != PATHSEPERATOR) + length--; + path[length] = 0; +} + +void StripExtension (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != '.') + { + length--; + if (path[length] == '/') + return; // no extension + } + if (length) + path[length] = 0; +} + + +/* +==================== +Extract file parts +==================== +*/ +void ExtractFilePath (char *path, char *dest) +{ + char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != PATHSEPERATOR) + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void ExtractFileBase (char *path, char *dest) +{ + char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != PATHSEPERATOR) + src--; + + while (*src && *src != '.') + { + *dest++ = *src++; + } + *dest = 0; +} + +void ExtractFileExtension (char *path, char *dest) +{ + char *src; + + src = path + strlen(path) - 1; + +// +// back up until a . or the start +// + while (src != path && *(src-1) != '.') + src--; + if (src == path) + { + *dest = 0; // no extension + return; + } + + strcpy (dest,src); +} + + +/* +============== +ParseNum / ParseHex +============== +*/ +int ParseHex (char *hex) +{ + char *str; + int num; + + num = 0; + str = hex; + + while (*str) + { + num <<= 4; + if (*str >= '0' && *str <= '9') + num += *str-'0'; + else if (*str >= 'a' && *str <= 'f') + num += 10 + *str-'a'; + else if (*str >= 'A' && *str <= 'F') + num += 10 + *str-'A'; + else + Error ("Bad hex number: %s",hex); + str++; + } + + return num; +} + + +int ParseNum (char *str) +{ + if (str[0] == '$') + return ParseHex (str+1); + if (str[0] == '0' && str[1] == 'x') + return ParseHex (str+2); + return atol (str); +} + + + +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short BigShort (short l) +{ + return l; +} + + +int LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int BigLong (int l) +{ + return l; +} + + +float LittleFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float BigFloat (float l) +{ + return l; +} + + +#else + + +short BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short LittleShort (short l) +{ + return l; +} + + +int BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int LittleLong (int l) +{ + return l; +} + +float BigFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float LittleFloat (float l) +{ + return l; +} + + +#endif + + +//======================================================= + + +// FIXME: byte swap? + +// this is a 16 bit, non-reflected CRC using the polynomial 0x1021 +// and the initial and final xor values shown below... in other words, the +// CCITT standard CRC used by XMODEM + +#define CRC_INIT_VALUE 0xffff +#define CRC_XOR_VALUE 0x0000 + +static unsigned short crctable[256] = +{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +void CRC_Init(unsigned short *crcvalue) +{ + *crcvalue = CRC_INIT_VALUE; +} + +void CRC_ProcessByte(unsigned short *crcvalue, byte data) +{ + *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data]; +} + +unsigned short CRC_Value(unsigned short crcvalue) +{ + return crcvalue ^ CRC_XOR_VALUE; +} +//============================================================================= + +/* +============ +CreatePath +============ +*/ +void CreatePath (char *path) +{ + char *ofs, c; + + for (ofs = path+1 ; *ofs ; ofs++) + { + c = *ofs; + if (c == '/' || c == '\\') + { // create the directory + *ofs = 0; + Q_mkdir (path); + *ofs = c; + } + } +} + + +/* +============ +CopyFile + + Used to archive source files +============ +*/ +void CopyFile (char *from, char *to) +{ + void *buffer; + int length; + + length = LoadFile (from, &buffer); + CreatePath (to); + SaveFile (to, buffer, length); + free (buffer); +} diff --git a/qutils/COMMON/CMDLIB.H b/qutils/COMMON/CMDLIB.H new file mode 100644 index 0000000..b556288 --- /dev/null +++ b/qutils/COMMON/CMDLIB.H @@ -0,0 +1,97 @@ +// cmdlib.h + +#ifndef __CMDLIB__ +#define __CMDLIB__ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ +typedef enum {false, true} qboolean; +typedef unsigned char byte; +#endif + +// the dec offsetof macro doesn't work very well... +#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier) + + +// set these before calling CheckParm +extern int myargc; +extern char **myargv; + +char *strupr (char *in); +char *strlower (char *in); +int Q_strncasecmp (char *s1, char *s2, int n); +int Q_strcasecmp (char *s1, char *s2); +void Q_getwd (char *out); + +int filelength (FILE *f); +int FileTime (char *path); + +void Q_mkdir (char *path); + +extern char qdir[1024]; +extern char gamedir[1024]; +void SetQdirFromPath (char *path); +char *ExpandPath (char *path); +char *ExpandPathAndArchive (char *path); + + +double I_FloatTime (void); + +void Error (char *error, ...); +int CheckParm (char *check); + +FILE *SafeOpenWrite (char *filename); +FILE *SafeOpenRead (char *filename); +void SafeRead (FILE *f, void *buffer, int count); +void SafeWrite (FILE *f, void *buffer, int count); + +int LoadFile (char *filename, void **bufferptr); +void SaveFile (char *filename, void *buffer, int count); + +void DefaultExtension (char *path, char *extension); +void DefaultPath (char *path, char *basepath); +void StripFilename (char *path); +void StripExtension (char *path); + +void ExtractFilePath (char *path, char *dest); +void ExtractFileBase (char *path, char *dest); +void ExtractFileExtension (char *path, char *dest); + +int ParseNum (char *str); + +short BigShort (short l); +short LittleShort (short l); +int BigLong (int l); +int LittleLong (int l); +float BigFloat (float l); +float LittleFloat (float l); + + +char *COM_Parse (char *data); + +extern char com_token[1024]; +extern qboolean com_eof; + +char *copystring(char *s); + + +void CRC_Init(unsigned short *crcvalue); +void CRC_ProcessByte(unsigned short *crcvalue, byte data); +unsigned short CRC_Value(unsigned short crcvalue); + +void CreatePath (char *path); +void CopyFile (char *from, char *to); + +extern qboolean archive; +extern char archivedir[1024]; + + +#endif diff --git a/qutils/COMMON/LBMLIB.C b/qutils/COMMON/LBMLIB.C new file mode 100644 index 0000000..c64f44e --- /dev/null +++ b/qutils/COMMON/LBMLIB.C @@ -0,0 +1,508 @@ +// lbmlib.c + +#include "cmdlib.h" +#include "lbmlib.h" + + + +/* +============================================================================ + + LBM STUFF + +============================================================================ +*/ + + +#define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24)) +#define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24)) +#define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24)) +#define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24)) +#define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24)) +#define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24)) + + +bmhd_t bmhd; + +int Align (int l) +{ + if (l&1) + return l+1; + return l; +} + + + +/* +================ += += LBMRLEdecompress += += Source must be evenly aligned! += +================ +*/ + +byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth) +{ + int count; + byte b,rept; + + count = 0; + + do + { + rept = *source++; + + if (rept > 0x80) + { + rept = (rept^0xff)+2; + b = *source++; + memset(unpacked,b,rept); + unpacked += rept; + } + else if (rept < 0x80) + { + rept++; + memcpy(unpacked,source,rept); + unpacked += rept; + source += rept; + } + else + rept = 0; // rept of 0x80 is NOP + + count += rept; + + } while (countbpwidth) + Error ("Decompression exceeded width!\n"); + + + return source; +} + + +#define BPLANESIZE 128 +byte bitplanes[9][BPLANESIZE]; // max size 1024 by 9 bit planes + + +/* +================= += += MungeBitPlanes8 += += This destroys the bit plane data! += +================= +*/ + +void MungeBitPlanes8 (int width, byte *dest) +{ + *dest=width; // shut up the compiler warning + Error ("MungeBitPlanes8 not rewritten!"); +#if 0 +asm les di,[dest] +asm mov si,-1 +asm mov cx,[width] +mungebyte: +asm inc si +asm mov dx,8 +mungebit: +asm shl [BYTE PTR bitplanes + BPLANESIZE*7 +si],1 +asm rcl al,1 +asm shl [BYTE PTR bitplanes + BPLANESIZE*6 +si],1 +asm rcl al,1 +asm shl [BYTE PTR bitplanes + BPLANESIZE*5 +si],1 +asm rcl al,1 +asm shl [BYTE PTR bitplanes + BPLANESIZE*4 +si],1 +asm rcl al,1 +asm shl [BYTE PTR bitplanes + BPLANESIZE*3 +si],1 +asm rcl al,1 +asm shl [BYTE PTR bitplanes + BPLANESIZE*2 +si],1 +asm rcl al,1 +asm shl [BYTE PTR bitplanes + BPLANESIZE*1 +si],1 +asm rcl al,1 +asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1 +asm rcl al,1 +asm stosb +asm dec cx +asm jz done +asm dec dx +asm jnz mungebit +asm jmp mungebyte + +done: +#endif +} + + +void MungeBitPlanes4 (int width, byte *dest) +{ + *dest=width; // shut up the compiler warning + Error ("MungeBitPlanes4 not rewritten!"); +#if 0 + +asm les di,[dest] +asm mov si,-1 +asm mov cx,[width] +mungebyte: +asm inc si +asm mov dx,8 +mungebit: +asm xor al,al +asm shl [BYTE PTR bitplanes + BPLANESIZE*3 +si],1 +asm rcl al,1 +asm shl [BYTE PTR bitplanes + BPLANESIZE*2 +si],1 +asm rcl al,1 +asm shl [BYTE PTR bitplanes + BPLANESIZE*1 +si],1 +asm rcl al,1 +asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1 +asm rcl al,1 +asm stosb +asm dec cx +asm jz done +asm dec dx +asm jnz mungebit +asm jmp mungebyte + +done: +#endif +} + + +void MungeBitPlanes2 (int width, byte *dest) +{ + *dest=width; // shut up the compiler warning + Error ("MungeBitPlanes2 not rewritten!"); +#if 0 +asm les di,[dest] +asm mov si,-1 +asm mov cx,[width] +mungebyte: +asm inc si +asm mov dx,8 +mungebit: +asm xor al,al +asm shl [BYTE PTR bitplanes + BPLANESIZE*1 +si],1 +asm rcl al,1 +asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1 +asm rcl al,1 +asm stosb +asm dec cx +asm jz done +asm dec dx +asm jnz mungebit +asm jmp mungebyte + +done: +#endif +} + + +void MungeBitPlanes1 (int width, byte *dest) +{ + *dest=width; // shut up the compiler warning + Error ("MungeBitPlanes1 not rewritten!"); +#if 0 +asm les di,[dest] +asm mov si,-1 +asm mov cx,[width] +mungebyte: +asm inc si +asm mov dx,8 +mungebit: +asm xor al,al +asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1 +asm rcl al,1 +asm stosb +asm dec cx +asm jz done +asm dec dx +asm jnz mungebit +asm jmp mungebyte + +done: +#endif +} + + +/* +================= += += LoadLBM += +================= +*/ + +void LoadLBM (char *filename, byte **picture, byte **palette) +{ + byte *LBMbuffer, *picbuffer, *cmapbuffer; + int y,p,planes; + byte *LBM_P, *LBMEND_P; + byte *pic_p; + byte *body_p; + unsigned rowsize; + + int formtype,formlength; + int chunktype,chunklength; + void (*mungecall) (int, byte *); + +// qiet compiler warnings + picbuffer = NULL; + cmapbuffer = NULL; + mungecall = NULL; + +// +// load the LBM +// + LoadFile (filename, (void **)&LBMbuffer); + +// +// parse the LBM header +// + LBM_P = LBMbuffer; + if ( *(int *)LBMbuffer != LittleLong(FORMID) ) + Error ("No FORM ID at start of file!\n"); + + LBM_P += 4; + formlength = BigLong( *(int *)LBM_P ); + LBM_P += 4; + LBMEND_P = LBM_P + Align(formlength); + + formtype = LittleLong(*(int *)LBM_P); + + if (formtype != ILBMID && formtype != PBMID) + Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff + ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff); + + LBM_P += 4; + +// +// parse chunks +// + + while (LBM_P < LBMEND_P) + { + chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24); + LBM_P += 4; + chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24); + LBM_P += 4; + + switch ( chunktype ) + { + case BMHDID: + memcpy (&bmhd,LBM_P,sizeof(bmhd)); + bmhd.w = BigShort(bmhd.w); + bmhd.h = BigShort(bmhd.h); + bmhd.x = BigShort(bmhd.x); + bmhd.y = BigShort(bmhd.y); + bmhd.pageWidth = BigShort(bmhd.pageWidth); + bmhd.pageHeight = BigShort(bmhd.pageHeight); + break; + + case CMAPID: + cmapbuffer = malloc (768); + memset (cmapbuffer, 0, 768); + memcpy (cmapbuffer, LBM_P, chunklength); + break; + + case BODYID: + body_p = LBM_P; + + pic_p = picbuffer = malloc (bmhd.w*bmhd.h); + if (formtype == PBMID) + { + // + // unpack PBM + // + for (y=0 ; y EQUAL_EPSILON) + return false; + + return true; +} + +vec_t Q_rint (vec_t in) +{ + return floor (in + 0.5); +} + +void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc) +{ + vc[0] = va[0] + scale*vb[0]; + vc[1] = va[1] + scale*vb[1]; + vc[2] = va[2] + scale*vb[2]; +} + +void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +vec_t _DotProduct (vec3_t v1, vec3_t v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]-vb[0]; + out[1] = va[1]-vb[1]; + out[2] = va[2]-vb[2]; +} + +void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]+vb[0]; + out[1] = va[1]+vb[1]; + out[2] = va[2]+vb[2]; +} + +void _VectorCopy (vec3_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +vec_t VectorNormalize (vec3_t v) +{ + int i; + double length; + + length = 0; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = sqrt (length); + if (length == 0) + return 0; + + for (i=0 ; i< 3 ; i++) + v[i] /= length; + + return length; +} + +void VectorInverse (vec3_t v) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +void VectorScale (vec3_t v, vec_t scale, vec3_t out) +{ + out[0] = v[0] * scale; + out[1] = v[1] * scale; + out[2] = v[2] * scale; +} + diff --git a/qutils/COMMON/MATHLIB.H b/qutils/COMMON/MATHLIB.H new file mode 100644 index 0000000..d4311dc --- /dev/null +++ b/qutils/COMMON/MATHLIB.H @@ -0,0 +1,48 @@ +#ifndef __MATHLIB__ +#define __MATHLIB__ + +// mathlib.h + +#include + +#ifdef DOUBLEVEC_T +typedef double vec_t; +#else +typedef float vec_t; +#endif +typedef vec_t vec3_t[3]; + +#define SIDE_FRONT 0 +#define SIDE_ON 2 +#define SIDE_BACK 1 +#define SIDE_CROSS -2 + +#define Q_PI 3.14159265358979323846 + +extern vec3_t vec3_origin; + +#define EQUAL_EPSILON 0.001 + +qboolean VectorCompare (vec3_t v1, vec3_t v2); + +#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) +#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} +#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} +#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} + +vec_t Q_rint (vec_t in); +vec_t _DotProduct (vec3_t v1, vec3_t v2); +void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out); +void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out); +void _VectorCopy (vec3_t in, vec3_t out); + +double VectorLength(vec3_t v); + +void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc); + +void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); +vec_t VectorNormalize (vec3_t v); +void VectorInverse (vec3_t v); +void VectorScale (vec3_t v, vec_t scale, vec3_t out); + +#endif diff --git a/qutils/COMMON/POLYLIB.C b/qutils/COMMON/POLYLIB.C new file mode 100644 index 0000000..a45293a --- /dev/null +++ b/qutils/COMMON/POLYLIB.C @@ -0,0 +1,400 @@ + +#include "cmdlib.h" +#include "mathlib.h" +#include "polylib.h" + +#define BOGUS_RANGE 8192 + +/* +============= +AllocWinding +============= +*/ +winding_t *AllocWinding (int points) +{ + winding_t *w; + int s; + + s = sizeof(vec_t)*3*points + sizeof(int); + w = malloc (s); + memset (w, 0, s); + return w; +} + +/* +============ +RemoveColinearPoints +============ +*/ +int c_removed; + +void RemoveColinearPoints (winding_t *w) +{ + int i, j, k; + vec3_t v1, v2; + int nump; + vec3_t p[MAX_POINTS_ON_WINDING]; + + nump = 0; + for (i=0 ; inumpoints ; i++) + { + j = (i+1)%w->numpoints; + k = (i+w->numpoints-1)%w->numpoints; + VectorSubtract (w->p[j], w->p[i], v1); + VectorSubtract (w->p[i], w->p[k], v2); + VectorNormalize(v1); + VectorNormalize(v2); + if (DotProduct(v1, v2) < 0.999) + { + VectorCopy (w->p[i], p[nump]); + nump++; + } + } + + if (nump == w->numpoints) + return; + + c_removed += w->numpoints - nump; + w->numpoints = nump; + memcpy (w->p, p, nump*sizeof(p[0])); +} + +/* +============ +WindingPlane +============ +*/ +void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist) +{ + vec3_t v1, v2; + + VectorSubtract (w->p[1], w->p[0], v1); + VectorSubtract (w->p[2], w->p[0], v2); + CrossProduct (v1, v2, normal); + VectorNormalize (normal); + *dist = DotProduct (w->p[0], normal); + +} + +/* +============= +WindingArea +============= +*/ +vec_t WindingArea (winding_t *w) +{ + int i; + vec3_t d1, d2, cross; + vec_t total; + + total = 0; + for (i=2 ; inumpoints ; i++) + { + VectorSubtract (w->p[i-1], w->p[0], d1); + VectorSubtract (w->p[i], w->p[0], d2); + CrossProduct (d1, d2, cross); + total += 0.5 * VectorLength ( cross ); + } + return total; +} + +/* +============= +WindingCenter +============= +*/ +void WindingCenter (winding_t *w, vec3_t center) +{ + int i; + vec3_t d1, d2, cross; + float scale; + + VectorCopy (vec3_origin, center); + for (i=0 ; inumpoints ; i++) + VectorAdd (w->p[i], center, center); + + scale = 1.0/w->numpoints; + VectorScale (center, scale, center); +} + +/* +================= +BaseWindingForPlane +================= +*/ +winding_t *BaseWindingForPlane (vec3_t normal, float dist) +{ + int i, x; + vec_t max, v; + vec3_t org, vright, vup; + winding_t *w; + +// find the major axis + + max = -BOGUS_RANGE; + x = -1; + for (i=0 ; i<3; i++) + { + v = fabs(normal[i]); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) + Error ("BaseWindingForPlane: no axis found"); + + VectorCopy (vec3_origin, vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + v = DotProduct (vup, normal); + VectorMA (vup, -v, normal, vup); + VectorNormalize (vup); + + VectorScale (normal, dist, org); + + CrossProduct (vup, normal, vright); + + VectorScale (vup, 8192, vup); + VectorScale (vright, 8192, vright); + +// project a really big axis aligned box onto the plane + w = AllocWinding (4); + + VectorSubtract (org, vright, w->p[0]); + VectorAdd (w->p[0], vup, w->p[0]); + + VectorAdd (org, vright, w->p[1]); + VectorAdd (w->p[1], vup, w->p[1]); + + VectorAdd (org, vright, w->p[2]); + VectorSubtract (w->p[2], vup, w->p[2]); + + VectorSubtract (org, vright, w->p[3]); + VectorSubtract (w->p[3], vup, w->p[3]); + + w->numpoints = 4; + + return w; +} + +/* +================== +CopyWinding +================== +*/ +winding_t *CopyWinding (winding_t *w) +{ + int size; + winding_t *c; + + size = (int)((winding_t *)0)->p[w->numpoints]; + c = malloc (size); + memcpy (c, w, size); + return c; +} + + +/* +============= +ClipWinding +============= +*/ +void ClipWinding (winding_t *in, vec3_t normal, vec_t dist, + winding_t **front, winding_t **back) +{ + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + vec_t dot; + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *f, *b; + int maxpts; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->p[i], normal); + dot -= dist; + dists[i] = dot; + if (dot > ON_EPSILON) + sides[i] = SIDE_FRONT; + else if (dot < -ON_EPSILON) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + *front = *back = NULL; + + if (!counts[0]) + { + *back = CopyWinding (in); + return; + } + if (!counts[1]) + { + *front = CopyWinding (in); + return; + } + + maxpts = in->numpoints+4; // can't use counts[0]+2 because + // of fp grouping errors + + *front = f = AllocWinding (maxpts); + *back = b = AllocWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + if (sides[i] == SIDE_BACK) + { + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->p[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (normal[j] == 1) + mid[j] = dist; + else if (normal[j] == -1) + mid[j] = -dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (mid, b->p[b->numpoints]); + b->numpoints++; + } + + if (f->numpoints > maxpts || b->numpoints > maxpts) + Error ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING) + Error ("ClipWinding: MAX_POINTS_ON_WINDING"); +} + +/* +================= +ChopWinding + +Returns the fragment of in that is on the front side +of the cliping plane. The original is freed. +================= +*/ +winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist) +{ + winding_t *f, *b; + + ClipWinding (in, normal, dist, &f, &b); + free (in); + if (b) + free (b); + return f; +} + +/* +================= +CheckWinding + +================= +*/ +void CheckWinding (winding_t *w) +{ + int i, j; + vec_t *p1, *p2; + vec_t d, edgedist; + vec3_t dir, edgenormal, facenormal; + vec_t area; + vec_t facedist; + + if (w->numpoints < 3) + Error ("CheckFace: %i points",w->numpoints); + + area = WindingArea(w); + if (area < 1) + Error ("CheckFace: %f area", area); + + WindingPlane (w, facenormal, &facedist); + + for (i=0 ; inumpoints ; i++) + { + p1 = w->p[i]; + + for (j=0 ; j<3 ; j++) + if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE) + Error ("CheckFace: BUGUS_RANGE: %f",p1[j]); + + j = i+1 == w->numpoints ? 0 : i+1; + + // check the point is on the face plane + d = DotProduct (p1, facenormal) - facedist; + if (d < -ON_EPSILON || d > ON_EPSILON) + Error ("CheckFace: point off plane"); + + // check the edge isn't degenerate + p2 = w->p[j]; + VectorSubtract (p2, p1, dir); + + if (VectorLength (dir) < ON_EPSILON) + Error ("CheckFace: degenerate edge"); + + CrossProduct (facenormal, dir, edgenormal); + VectorNormalize (edgenormal); + edgedist = DotProduct (p1, edgenormal); + edgedist += ON_EPSILON; + + // all other points must be on front side + for (j=0 ; jnumpoints ; j++) + { + if (j == i) + continue; + d = DotProduct (w->p[j], edgenormal); + if (d > edgedist) + Error ("CheckFace: non-convex"); + } + } +} + diff --git a/qutils/COMMON/POLYLIB.H b/qutils/COMMON/POLYLIB.H new file mode 100644 index 0000000..7f0794d --- /dev/null +++ b/qutils/COMMON/POLYLIB.H @@ -0,0 +1,22 @@ + +typedef struct +{ + int numpoints; + vec3_t p[4]; // variable sized +} winding_t; + +#define MAX_POINTS_ON_WINDING 64 + +#define ON_EPSILON 0.1 + +winding_t *AllocWinding (int points); +vec_t WindingArea (winding_t *w); +void WindingCenter (winding_t *w, vec3_t center); +void ClipWinding (winding_t *in, vec3_t normal, vec_t dist, + winding_t **front, winding_t **back); +winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist); +winding_t *CopyWinding (winding_t *w); +winding_t *BaseWindingForPlane (vec3_t normal, float dist); +void CheckWinding (winding_t *w); +void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist); +void RemoveColinearPoints (winding_t *w); diff --git a/qutils/COMMON/SCRIPLIB.C b/qutils/COMMON/SCRIPLIB.C new file mode 100644 index 0000000..6f158f6 --- /dev/null +++ b/qutils/COMMON/SCRIPLIB.C @@ -0,0 +1,185 @@ +// scriplib.c + +#include "cmdlib.h" +#include "scriplib.h" + +/* +============================================================================= + + PARSING STUFF + +============================================================================= +*/ + +char token[MAXTOKEN]; +char *scriptbuffer,*script_p,*scriptend_p; +int grabbed; +int scriptline; +qboolean endofscript; +qboolean tokenready; // only true if UnGetToken was just called + +/* +============== += += LoadScriptFile += +============== +*/ + +void LoadScriptFile (char *filename) +{ + int size; + + size = LoadFile (filename, (void **)&scriptbuffer); + + script_p = scriptbuffer; + scriptend_p = script_p + size; + scriptline = 1; + endofscript = false; + tokenready = false; +} + + +/* +============== += += UnGetToken += += Signals that the current token was not used, and should be reported += for the next GetToken. Note that + +GetToken (true); +UnGetToken (); +GetToken (false); + += could cross a line boundary. += +============== +*/ + +void UnGetToken (void) +{ + tokenready = true; +} + + +/* +============== +GetToken +============== +*/ +qboolean GetToken (qboolean crossline) +{ + char *token_p; + + if (tokenready) // is a token allready waiting? + { + tokenready = false; + return true; + } + + if (script_p >= scriptend_p) + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + endofscript = true; + return false; + } + +// +// skip space +// +skipspace: + while (*script_p <= 32) + { + if (script_p >= scriptend_p) + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + endofscript = true; + return true; + } + if (*script_p++ == '\n') + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + scriptline++; + } + } + + if (script_p >= scriptend_p) + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + endofscript = true; + return true; + } + + if (*script_p == ';' || *script_p == '#') // semicolon is comment field + { // also make # a comment field + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + while (*script_p++ != '\n') + if (script_p >= scriptend_p) + { + endofscript = true; + return false; + } + goto skipspace; + } + +// +// copy token +// + token_p = token; + + while ( *script_p > 32 && *script_p != ';') + { + *token_p++ = *script_p++; + if (script_p == scriptend_p) + break; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i\n",scriptline); + } + + *token_p = 0; + return true; +} + + +/* +============== += += TokenAvailable += += Returns true if there is another token on the line += +============== +*/ + +qboolean TokenAvailable (void) +{ + char *search_p; + + search_p = script_p; + + if (search_p >= scriptend_p) + return false; + + while ( *search_p <= 32) + { + if (*search_p == '\n') + return false; + search_p++; + if (search_p == scriptend_p) + return false; + + } + + if (*search_p == ';') + return false; + + return true; +} + + diff --git a/qutils/COMMON/SCRIPLIB.H b/qutils/COMMON/SCRIPLIB.H new file mode 100644 index 0000000..95673f3 --- /dev/null +++ b/qutils/COMMON/SCRIPLIB.H @@ -0,0 +1,21 @@ +// scriplib.h + +#ifndef __CMDLIB__ +#include "cmdlib.h" +#endif + +#define MAXTOKEN 128 + +extern char token[MAXTOKEN]; +extern char *scriptbuffer,*script_p,*scriptend_p; +extern int grabbed; +extern int scriptline; +extern qboolean endofscript; + + +void LoadScriptFile (char *filename); +qboolean GetToken (qboolean crossline); +void UnGetToken (void); +qboolean TokenAvailable (void); + + diff --git a/qutils/COMMON/THREADS.C b/qutils/COMMON/THREADS.C new file mode 100644 index 0000000..6545b50 --- /dev/null +++ b/qutils/COMMON/THREADS.C @@ -0,0 +1,239 @@ + +#include "cmdlib.h" +#include "threads.h" + +#define MAX_THREADS 64 + +int dispatch; +int workcount; +int oldf; +qboolean pacifier; + +/* +============= +GetThreadWork + +============= +*/ +int GetThreadWork (void) +{ + int r; + int f; + + ThreadLock (); + + if (dispatch == workcount) + { + ThreadUnlock (); + return -1; + } + + f = 10*dispatch / workcount; + if (f != oldf) + { + oldf = f; + if (pacifier) + printf ("%i...", f); + } + + r = dispatch; + dispatch++; + ThreadUnlock (); + + return r; +} + + + +/* +=================================================================== + +WIN32 + +=================================================================== +*/ +#ifdef WIN32 + +#define USED + +#include + +int numthreads = 1; +CRITICAL_SECTION crit; + +void ThreadLock (void) +{ + EnterCriticalSection (&crit); +} + +void ThreadUnlock (void) +{ + LeaveCriticalSection (&crit); +} + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int threadid[MAX_THREADS]; + HANDLE threadhandle[MAX_THREADS]; + int i; + + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + + // + // run threads in parallel + // + InitializeCriticalSection (&crit); + for (i=0 ; i + +pthread_mutex_t *my_mutex; + +void ThreadLock (void) +{ + if (my_mutex) + pthread_mutex_lock (my_mutex); +} + +void ThreadUnlock (void) +{ + if (my_mutex) + pthread_mutex_unlock (my_mutex); +} + + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int i; + pthread_t work_threads[MAX_THREADS]; + pthread_addr_t status; + pthread_attr_t attrib; + pthread_mutexattr_t mattrib; + + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + + if (!my_mutex) + { + my_mutex = malloc (sizeof(*my_mutex)); + if (pthread_mutexattr_create (&mattrib) == -1) + Error ("pthread_mutex_attr_create failed"); + if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1) + Error ("pthread_mutexattr_setkind_np failed"); + if (pthread_mutex_init (my_mutex, mattrib) == -1) + Error ("pthread_mutex_init failed"); + } + + if (pthread_attr_create (&attrib) == -1) + Error ("pthread_attr_create failed"); + if (pthread_attr_setstacksize (&attrib, 0x100000) == -1) + Error ("pthread_attr_setstacksize failed"); + + for (i=0 ; i +#include "cmdlib.h" +#include "mathlib.h" +#include "trilib.h" + +// on disk representation of a face + + +#define FLOAT_START 99999.0 +#define FLOAT_END -FLOAT_START +#define MAGIC 123322 + +//#define NOISY 1 + +typedef struct { + float v[3]; +} vector; + +typedef struct +{ + vector n; /* normal */ + vector p; /* point */ + vector c; /* color */ + float u; /* u */ + float v; /* v */ +} aliaspoint_t; + +typedef struct { + aliaspoint_t pt[3]; +} tf_triangle; + + +void ByteSwapTri (tf_triangle *tri) +{ + int i; + + for (i=0 ; iverts[j][k] = tri.pt[j].p.v[k]; + } + } + + ptri++; + + if ((ptri - *pptri) >= MAXTRIANGLES) + Error ("Error: too many triangles; increase MAXTRIANGLES\n"); + } + } + + *numtriangles = ptri - *pptri; + + fclose (input); +} + diff --git a/qutils/COMMON/TRILIB.H b/qutils/COMMON/TRILIB.H new file mode 100644 index 0000000..84e02f0 --- /dev/null +++ b/qutils/COMMON/TRILIB.H @@ -0,0 +1,11 @@ +// +// trilib.h: header file for loading triangles from an Alias triangle file +// +#define MAXTRIANGLES 2048 + +typedef struct { + vec3_t verts[3]; +} triangle_t; + +void LoadTriangleList (char *filename, triangle_t **pptri, int *numtriangles); + diff --git a/qutils/COMMON/WADLIB.C b/qutils/COMMON/WADLIB.C new file mode 100644 index 0000000..63e4339 --- /dev/null +++ b/qutils/COMMON/WADLIB.C @@ -0,0 +1,328 @@ +// wad2lib.c + +#include +#include +#include +#include +#include +#include +#include +//#include +#include + +#ifdef NeXT +#include +#endif +#include "cmdlib.h" +#include "wadlib.h" + +/* +============================================================================ + + WAD READING + +============================================================================ +*/ + + +lumpinfo_t *lumpinfo; // location of each lump on disk +int numlumps; + +wadinfo_t header; +FILE *wadhandle; + + +/* +==================== +W_OpenWad +==================== +*/ +void W_OpenWad (char *filename) +{ + lumpinfo_t *lump_p; + unsigned i; + int length; + +// +// open the file and add to directory +// + wadhandle = SafeOpenRead (filename); + SafeRead (wadhandle, &header, sizeof(header)); + + if (strncmp(header.identification,"WAD2",4)) + Error ("Wad file %s doesn't have WAD2 id\n",filename); + + header.numlumps = LittleLong(header.numlumps); + header.infotableofs = LittleLong(header.infotableofs); + + numlumps = header.numlumps; + + length = numlumps*sizeof(lumpinfo_t); + lumpinfo = malloc (length); + lump_p = lumpinfo; + + fseek (wadhandle, header.infotableofs, SEEK_SET); + SafeRead (wadhandle, lumpinfo, length); + +// +// Fill in lumpinfo +// + + for (i=0 ; ifilepos = LittleLong(lump_p->filepos); + lump_p->size = LittleLong(lump_p->size); + } +} + + + +void CleanupName (char *in, char *out) +{ + int i; + + for (i=0 ; iname ) ; i++ ) + { + if (!in[i]) + break; + + out[i] = toupper(in[i]); + } + + for ( ; iname ); i++ ) + out[i] = 0; +} + + +/* +==================== +W_CheckNumForName + +Returns -1 if name not found +==================== +*/ +int W_CheckNumForName (char *name) +{ + char cleanname[16]; + int v1,v2, v3, v4; + int i; + lumpinfo_t *lump_p; + + CleanupName (name, cleanname); + +// make the name into four integers for easy compares + + v1 = *(int *)cleanname; + v2 = *(int *)&cleanname[4]; + v3 = *(int *)&cleanname[8]; + v4 = *(int *)&cleanname[12]; + +// find it + + lump_p = lumpinfo; + for (i=0 ; iname == v1 + && *(int *)&lump_p->name[4] == v2 + && *(int *)&lump_p->name[8] == v3 + && *(int *)&lump_p->name[12] == v4) + return i; + } + + return -1; +} + + +/* +==================== +W_GetNumForName + +Calls W_CheckNumForName, but bombs out if not found +==================== +*/ +int W_GetNumForName (char *name) +{ + int i; + + i = W_CheckNumForName (name); + if (i != -1) + return i; + + Error ("W_GetNumForName: %s not found!",name); + return -1; +} + + +/* +==================== +W_LumpLength + +Returns the buffer size needed to load the given lump +==================== +*/ +int W_LumpLength (int lump) +{ + if (lump >= numlumps) + Error ("W_LumpLength: %i >= numlumps",lump); + return lumpinfo[lump].size; +} + + +/* +==================== +W_ReadLumpNum + +Loads the lump into the given buffer, which must be >= W_LumpLength() +==================== +*/ +void W_ReadLumpNum (int lump, void *dest) +{ + lumpinfo_t *l; + + if (lump >= numlumps) + Error ("W_ReadLump: %i >= numlumps",lump); + l = lumpinfo+lump; + + fseek (wadhandle, l->filepos, SEEK_SET); + SafeRead (wadhandle, dest, l->size); +} + + + +/* +==================== +W_LoadLumpNum +==================== +*/ +void *W_LoadLumpNum (int lump) +{ + void *buf; + + if ((unsigned)lump >= numlumps) + Error ("W_CacheLumpNum: %i >= numlumps",lump); + + buf = malloc (W_LumpLength (lump)); + W_ReadLumpNum (lump, buf); + + return buf; +} + + +/* +==================== +W_LoadLumpName +==================== +*/ +void *W_LoadLumpName (char *name) +{ + return W_LoadLumpNum (W_GetNumForName(name)); +} + + +/* +=============================================================================== + + WAD CREATION + +=============================================================================== +*/ + +FILE *outwad; + +lumpinfo_t outinfo[4096]; +int outlumps; + +short (*wadshort) (short l); +int (*wadlong) (int l); + +/* +=============== +NewWad +=============== +*/ + +void NewWad (char *pathname, qboolean bigendien) +{ + outwad = SafeOpenWrite (pathname); + fseek (outwad, sizeof(wadinfo_t), SEEK_SET); + memset (outinfo, 0, sizeof(outinfo)); + + if (bigendien) + { + wadshort = BigShort; + wadlong = BigLong; + } + else + { + wadshort = LittleShort; + wadlong = LittleLong; + } + + outlumps = 0; +} + + +/* +=============== +AddLump +=============== +*/ + +void AddLump (char *name, void *buffer, int length, int type, int compress) +{ + lumpinfo_t *info; + int ofs; + + info = &outinfo[outlumps]; + outlumps++; + + memset (info,0,sizeof(info)); + + strcpy (info->name, name); + strupr (info->name); + + ofs = ftell(outwad); + info->filepos = wadlong(ofs); + info->size = info->disksize = wadlong(length); + info->type = type; + info->compression = compress; + +// FIXME: do compression + + SafeWrite (outwad, buffer, length); +} + + +/* +=============== +WriteWad +=============== +*/ + +void WriteWad (void) +{ + wadinfo_t header; + int ofs; + +// write the lumpingo + ofs = ftell(outwad); + + SafeWrite (outwad, outinfo, outlumps*sizeof(lumpinfo_t) ); + +// write the header + +// a program will be able to tell the ednieness of a wad by the id + header.identification[0] = 'W'; + header.identification[1] = 'A'; + header.identification[2] = 'D'; + header.identification[3] = '2'; + + header.numlumps = wadlong(outlumps); + header.infotableofs = wadlong(ofs); + + fseek (outwad, 0, SEEK_SET); + SafeWrite (outwad, &header, sizeof(header)); + fclose (outwad); +} + + diff --git a/qutils/COMMON/WADLIB.H b/qutils/COMMON/WADLIB.H new file mode 100644 index 0000000..d9fecf8 --- /dev/null +++ b/qutils/COMMON/WADLIB.H @@ -0,0 +1,53 @@ +// wadlib.h + +// +// wad reading +// + +#define CMP_NONE 0 +#define CMP_LZSS 1 + +#define TYP_NONE 0 +#define TYP_LABEL 1 +#define TYP_LUMPY 64 // 64 + grab command number + +typedef struct +{ + char identification[4]; // should be WAD2 or 2DAW + int numlumps; + int infotableofs; +} wadinfo_t; + + +typedef struct +{ + int filepos; + int disksize; + int size; // uncompressed + char type; + char compression; + char pad1, pad2; + char name[16]; // must be null terminated +} lumpinfo_t; + +extern lumpinfo_t *lumpinfo; // location of each lump on disk +extern int numlumps; +extern wadinfo_t header; + +void W_OpenWad (char *filename); +int W_CheckNumForName (char *name); +int W_GetNumForName (char *name); +int W_LumpLength (int lump); +void W_ReadLumpNum (int lump, void *dest); +void *W_LoadLumpNum (int lump); +void *W_LoadLumpName (char *name); + +void CleanupName (char *in, char *out); + +// +// wad creation +// +void NewWad (char *pathname, qboolean bigendien); +void AddLump (char *name, void *buffer, int length, int type, int compress); +void WriteWad (void); + diff --git a/qutils/INSTALL.BAT b/qutils/INSTALL.BAT new file mode 100644 index 0000000..93463a8 --- /dev/null +++ b/qutils/INSTALL.BAT @@ -0,0 +1,43 @@ +cd qlumpy +nmake /f "qlumpy.mak" CFG="qlumpy - Win32 Release" +copy release\qlumpy.exe \quake\bin_nt + +cd ..\texmake +nmake /f "texmake.mak" CFG="texmake - Win32 Release" +copy release\texmake.exe \quake\bin_nt + +cd ..\modelgen +nmake /f "modelgen.mak" CFG="modelgen - Win32 Release" +copy release\modelgen.exe \quake\bin_nt + +cd ..\sprgen +nmake /f "sprgen.mak" CFG="sprgen - Win32 Release" +copy release\sprgen.exe \quake\bin_nt + + +cd ..\qbsp +nmake /f "qbsp.mak" CFG="qbsp - Win32 Release" +copy release\qbsp.exe \quake\bin_nt + +cd ..\light +nmake /f "light.mak" CFG="light - Win32 Release" +copy release\light.exe \quake\bin_nt + +cd ..\vis +nmake /f "vis.mak" CFG="vis - Win32 Release" +copy release\vis.exe \quake\bin_nt + +cd ..\bspinfo +nmake /f "bspinfo.mak" CFG="bspinfo - Win32 Release" +copy release\bspinfo.exe \quake\bin_nt + + +cd ..\qcc +nmake /f "qcc.mak" CFG="qcc - Win32 Release" +copy release\qcc.exe \quake\bin_nt + +cd ..\qfiles +nmake /f "qfiles.mak" CFG="qfiles - Win32 Release" +copy release\qfiles.exe \quake\bin_nt + +cd .. diff --git a/qutils/LIGHT/ENTITIES.C b/qutils/LIGHT/ENTITIES.C new file mode 100644 index 0000000..185198f --- /dev/null +++ b/qutils/LIGHT/ENTITIES.C @@ -0,0 +1,278 @@ +// entities.c + +#include "light.h" + +entity_t entities[MAX_MAP_ENTITIES]; +int num_entities; + +/* +============================================================================== + +ENTITY FILE PARSING + +If a light has a targetname, generate a unique style in the 32-63 range +============================================================================== +*/ + +int numlighttargets; +char lighttargets[32][64]; + +int LightStyleForTargetname (char *targetname, qboolean alloc) +{ + int i; + + for (i=0 ; ikey, key); + strcpy (epair->value, com_token); + epair->next = entity->epairs; + entity->epairs = epair; + + if (!strcmp(key, "classname")) + strcpy (entity->classname, com_token); + else if (!strcmp(key, "target")) + strcpy (entity->target, com_token); + else if (!strcmp(key, "targetname")) + strcpy (entity->targetname, com_token); + else if (!strcmp(key, "origin")) + { + // scan into doubles, then assign + // which makes it vec_t size independent + if (sscanf(com_token, "%lf %lf %lf", + &vec[0], &vec[1], &vec[2]) != 3) + Error ("LoadEntities: not 3 values for origin"); + for (i=0 ; i<3 ; i++) + entity->origin[i] = vec[i]; + } + else if (!strncmp(key, "light", 5) || !strcmp (key, "_light") ) + { + entity->light = atof(com_token); + } + else if (!strcmp(key, "style")) + { + entity->style = atof(com_token); + if ((unsigned)entity->style > 254) + Error ("Bad light style %i (must be 0-254)", entity->style); + } + else if (!strcmp(key, "angle")) + { + entity->angle = atof(com_token); + } + + } + + // all fields have been parsed + if (!strncmp (entity->classname, "light", 5) && !entity->light) + entity->light = DEFAULTLIGHTLEVEL; + + if (!strcmp (entity->classname, "light")) + { + if (entity->targetname[0] && !entity->style) + { + char s[16]; + + entity->style = LightStyleForTargetname (entity->targetname, true); + sprintf (s,"%i", entity->style); + SetKeyValue (entity, "style", s); + } + } + } + + printf ("%d entities read\n", num_entities); + + MatchTargets (); +} + +char *ValueForKey (entity_t *ent, char *key) +{ + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + return ep->value; + return ""; +} + +void SetKeyValue (entity_t *ent, char *key, char *value) +{ + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + { + strcpy (ep->value, value); + return; + } + ep = malloc (sizeof(*ep)); + ep->next = ent->epairs; + ent->epairs = ep; + strcpy (ep->key, key); + strcpy (ep->value, value); +} + +float FloatForKey (entity_t *ent, char *key) +{ + char *k; + + k = ValueForKey (ent, key); + return atof(k); +} + +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec) +{ + char *k; + + k = ValueForKey (ent, key); + sscanf (k, "%lf %lf %lf", &vec[0], &vec[1], &vec[2]); +} + + + +/* +================ +WriteEntitiesToString +================ +*/ +void WriteEntitiesToString (void) +{ + char *buf, *end; + epair_t *ep; + char line[128]; + int i; + + buf = dentdata; + end = buf; + *end = 0; + + printf ("%i switchable light styles\n", numlighttargets); + + for (i=0 ; inext) + { + sprintf (line, "\"%s\" \"%s\"\n", ep->key, ep->value); + strcat (end, line); + end += strlen(line); + } + strcat (end,"}\n"); + end += 2; + + if (end > buf + MAX_MAP_ENTSTRING) + Error ("Entity text too long"); + } + entdatasize = end - buf + 1; +} + diff --git a/qutils/LIGHT/ENTITIES.H b/qutils/LIGHT/ENTITIES.H new file mode 100644 index 0000000..2ef2e68 --- /dev/null +++ b/qutils/LIGHT/ENTITIES.H @@ -0,0 +1,33 @@ + +#define DEFAULTLIGHTLEVEL 300 + +typedef struct epair_s +{ + struct epair_s *next; + char key[MAX_KEY]; + char value[MAX_VALUE]; +} epair_t; + +typedef struct entity_s +{ + char classname[64]; + vec3_t origin; + float angle; + int light; + int style; + char target[32]; + char targetname[32]; + struct epair_s *epairs; + struct entity_s *targetent; +} entity_t; + +extern entity_t entities[MAX_MAP_ENTITIES]; +extern int num_entities; + +char *ValueForKey (entity_t *ent, char *key); +void SetKeyValue (entity_t *ent, char *key, char *value); +float FloatForKey (entity_t *ent, char *key); +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec); + +void LoadEntities (void); +void WriteEntitiesToString (void); diff --git a/qutils/LIGHT/LIGHT.C b/qutils/LIGHT/LIGHT.C new file mode 100644 index 0000000..52abcd4 --- /dev/null +++ b/qutils/LIGHT/LIGHT.C @@ -0,0 +1,146 @@ +// lighting.c + +#include "light.h" + +/* + +NOTES +----- + +*/ + +float scaledist = 1.0; +float scalecos = 0.5; +float rangescale = 0.5; + +byte *filebase, *file_p, *file_end; + +dmodel_t *bspmodel; +int bspfileface; // next surface to dispatch + +vec3_t bsp_origin; + +qboolean extrasamples; + +float minlights[MAX_MAP_FACES]; + + +byte *GetFileSpace (int size) +{ + byte *buf; + + LOCK; + file_p = (byte *)(((long)file_p + 3)&~3); + buf = file_p; + file_p += size; + UNLOCK; + if (file_p > file_end) + Error ("GetFileSpace: overrun"); + return buf; +} + + +void LightThread (void *junk) +{ + int i; + + while (1) + { + LOCK; + i = bspfileface++; + UNLOCK; + if (i >= numfaces) + return; + + LightFace (i); + } +} + +/* +============= +LightWorld +============= +*/ +void LightWorld (void) +{ + filebase = file_p = dlightdata; + file_end = filebase + MAX_MAP_LIGHTING; + + RunThreadsOn (LightThread); + + lightdatasize = file_p - filebase; + + printf ("lightdatasize: %i\n", lightdatasize); +} + + +/* +======== +main + +light modelfile +======== +*/ +int main (int argc, char **argv) +{ + int i; + double start, end; + char source[1024]; + + printf ("----- LightFaces ----\n"); + + for (i=1 ; i#*2{( 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 literal 0 HcmV?d00001 diff --git a/qutils/LIGHT/LIGHT.NCB b/qutils/LIGHT/LIGHT.NCB new file mode 100644 index 0000000000000000000000000000000000000000..e07f5afa2c6568d7ee015913c0cd0e85e075a5b6 GIT binary patch literal 99328 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 literal 0 HcmV?d00001 diff --git a/qutils/LIGHT/LTFACE.C b/qutils/LIGHT/LTFACE.C new file mode 100644 index 0000000..0b22931 --- /dev/null +++ b/qutils/LIGHT/LTFACE.C @@ -0,0 +1,588 @@ + +#include "light.h" + +/* +============ +CastRay + +Returns the distance between the points, or -1 if blocked +============= +*/ +vec_t CastRay (vec3_t p1, vec3_t p2) +{ + int i; + vec_t t; + qboolean trace; + + trace = TestLine (p1, p2); + + if (!trace) + return -1; // ray was blocked + + t = 0; + for (i=0 ; i< 3 ; i++) + t += (p2[i]-p1[i]) * (p2[i]-p1[i]); + + if (t == 0) + t = 1; // don't blow up... + return sqrt(t); +} + +/* +=============================================================================== + +SAMPLE POINT DETERMINATION + +void SetupBlock (dface_t *f) Returns with surfpt[] set + +This is a little tricky because the lightmap covers more area than the face. +If done in the straightforward fashion, some of the +sample points will be inside walls or on the other side of walls, causing +false shadows and light bleeds. + +To solve this, I only consider a sample point valid if a line can be drawn +between it and the exact midpoint of the face. If invalid, it is adjusted +towards the center until it is valid. + +(this doesn't completely work) + +=============================================================================== +*/ + +#define SINGLEMAP (18*18*4) + +typedef struct +{ + vec_t lightmaps[MAXLIGHTMAPS][SINGLEMAP]; + int numlightstyles; + vec_t *light; + vec_t facedist; + vec3_t facenormal; + + int numsurfpt; + vec3_t surfpt[SINGLEMAP]; + + vec3_t texorg; + vec3_t worldtotex[2]; // s = (world - texorg) . worldtotex[0] + vec3_t textoworld[2]; // world = texorg + s * textoworld[0] + + vec_t exactmins[2], exactmaxs[2]; + + int texmins[2], texsize[2]; + int lightstyles[256]; + int surfnum; + dface_t *face; +} lightinfo_t; + + +/* +================ +CalcFaceVectors + +Fills in texorg, worldtotex. and textoworld +================ +*/ +void CalcFaceVectors (lightinfo_t *l) +{ + texinfo_t *tex; + int i, j; + vec3_t texnormal; + float distscale; + vec_t dist, len; + + tex = &texinfo[l->face->texinfo]; + +// convert from float to vec_t + for (i=0 ; i<2 ; i++) + for (j=0 ; j<3 ; j++) + l->worldtotex[i][j] = tex->vecs[i][j]; + +// calculate a normal to the texture axis. points can be moved along this +// without changing their S/T + texnormal[0] = tex->vecs[1][1]*tex->vecs[0][2] + - tex->vecs[1][2]*tex->vecs[0][1]; + texnormal[1] = tex->vecs[1][2]*tex->vecs[0][0] + - tex->vecs[1][0]*tex->vecs[0][2]; + texnormal[2] = tex->vecs[1][0]*tex->vecs[0][1] + - tex->vecs[1][1]*tex->vecs[0][0]; + VectorNormalize (texnormal); + +// flip it towards plane normal + distscale = DotProduct (texnormal, l->facenormal); + if (!distscale) + Error ("Texture axis perpendicular to face"); + if (distscale < 0) + { + distscale = -distscale; + VectorSubtract (vec3_origin, texnormal, texnormal); + } + +// distscale is the ratio of the distance along the texture normal to +// the distance along the plane normal + distscale = 1/distscale; + + for (i=0 ; i<2 ; i++) + { + len = VectorLength (l->worldtotex[i]); + dist = DotProduct (l->worldtotex[i], l->facenormal); + dist *= distscale; + VectorMA (l->worldtotex[i], -dist, texnormal, l->textoworld[i]); + VectorScale (l->textoworld[i], (1/len)*(1/len), l->textoworld[i]); + } + + +// calculate texorg on the texture plane + for (i=0 ; i<3 ; i++) + l->texorg[i] = -tex->vecs[0][3]* l->textoworld[0][i] - tex->vecs[1][3] * l->textoworld[1][i]; + +// project back to the face plane + dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1; + dist *= distscale; + VectorMA (l->texorg, -dist, texnormal, l->texorg); + +} + +/* +================ +CalcFaceExtents + +Fills in s->texmins[] and s->texsize[] +also sets exactmins[] and exactmaxs[] +================ +*/ +void CalcFaceExtents (lightinfo_t *l) +{ + dface_t *s; + vec_t mins[2], maxs[2], val; + int i,j, e; + dvertex_t *v; + texinfo_t *tex; + + s = l->face; + + mins[0] = mins[1] = 999999; + maxs[0] = maxs[1] = -99999; + + tex = &texinfo[s->texinfo]; + + for (i=0 ; inumedges ; i++) + { + e = dsurfedges[s->firstedge+i]; + if (e >= 0) + v = dvertexes + dedges[e].v[0]; + else + v = dvertexes + dedges[-e].v[1]; + + for (j=0 ; j<2 ; j++) + { + val = v->point[0] * tex->vecs[j][0] + + v->point[1] * tex->vecs[j][1] + + v->point[2] * tex->vecs[j][2] + + tex->vecs[j][3]; + if (val < mins[j]) + mins[j] = val; + if (val > maxs[j]) + maxs[j] = val; + } + } + + for (i=0 ; i<2 ; i++) + { + l->exactmins[i] = mins[i]; + l->exactmaxs[i] = maxs[i]; + + mins[i] = floor(mins[i]/16); + maxs[i] = ceil(maxs[i]/16); + + l->texmins[i] = mins[i]; + l->texsize[i] = maxs[i] - mins[i]; + if (l->texsize[i] > 17) + Error ("Bad surface extents"); + } +} + +/* +================= +CalcPoints + +For each texture aligned grid point, back project onto the plane +to get the world xyz value of the sample point +================= +*/ +int c_bad; +void CalcPoints (lightinfo_t *l) +{ + int i; + int s, t, j; + int w, h, step; + vec_t starts, startt, us, ut; + vec_t *surf; + vec_t mids, midt; + vec3_t facemid, move; + +// +// fill in surforg +// the points are biased towards the center of the surface +// to help avoid edge cases just inside walls +// + surf = l->surfpt[0]; + mids = (l->exactmaxs[0] + l->exactmins[0])/2; + midt = (l->exactmaxs[1] + l->exactmins[1])/2; + + for (j=0 ; j<3 ; j++) + facemid[j] = l->texorg[j] + l->textoworld[0][j]*mids + l->textoworld[1][j]*midt; + + if (extrasamples) + { // extra filtering + h = (l->texsize[1]+1)*2; + w = (l->texsize[0]+1)*2; + starts = (l->texmins[0]-0.5)*16; + startt = (l->texmins[1]-0.5)*16; + step = 8; + } + else + { + h = l->texsize[1]+1; + w = l->texsize[0]+1; + starts = l->texmins[0]*16; + startt = l->texmins[1]*16; + step = 16; + } + + l->numsurfpt = w * h; + for (t=0 ; ttexorg[j] + l->textoworld[0][j]*us + + l->textoworld[1][j]*ut; + + if (CastRay (facemid, surf) != -1) + break; // got it + if (i & 1) + { + if (us > mids) + { + us -= 8; + if (us < mids) + us = mids; + } + else + { + us += 8; + if (us > mids) + us = mids; + } + } + else + { + if (ut > midt) + { + ut -= 8; + if (ut < midt) + ut = midt; + } + else + { + ut += 8; + if (ut > midt) + ut = midt; + } + } + + // move surf 8 pixels towards the center + VectorSubtract (facemid, surf, move); + VectorNormalize (move); + VectorMA (surf, 8, move, surf); + } + if (i == 2) + c_bad++; + } + } + +} + + +/* +=============================================================================== + +FACE LIGHTING + +=============================================================================== +*/ + +int c_culldistplane, c_proper; + +/* +================ +SingleLightFace +================ +*/ +void SingleLightFace (entity_t *light, lightinfo_t *l) +{ + vec_t dist; + vec3_t incoming; + vec_t angle; + vec_t add; + vec_t *surf; + qboolean hit; + int mapnum; + int size; + int c, i; + vec3_t rel; + vec3_t spotvec; + vec_t falloff; + vec_t *lightsamp; + + VectorSubtract (light->origin, bsp_origin, rel); + dist = scaledist * (DotProduct (rel, l->facenormal) - l->facedist); + +// don't bother with lights behind the surface + if (dist <= 0) + return; + +// don't bother with light too far away + if (dist > light->light) + { + c_culldistplane++; + return; + } + + if (light->targetent) + { + VectorSubtract (light->targetent->origin, light->origin, spotvec); + VectorNormalize (spotvec); + if (!light->angle) + falloff = -cos(20*Q_PI/180); + else + falloff = -cos(light->angle/2*Q_PI/180); + } + else + falloff = 0; // shut up compiler warnings + + mapnum = 0; + for (mapnum=0 ; mapnumnumlightstyles ; mapnum++) + if (l->lightstyles[mapnum] == light->style) + break; + lightsamp = l->lightmaps[mapnum]; + if (mapnum == l->numlightstyles) + { // init a new light map + if (mapnum == MAXLIGHTMAPS) + { + printf ("WARNING: Too many light styles on a face\n"); + return; + } + size = (l->texsize[1]+1)*(l->texsize[0]+1); + for (i=0 ; isurfpt[0]; + for (c=0 ; cnumsurfpt ; c++, surf+=3) + { + dist = CastRay(light->origin, surf)*scaledist; + if (dist < 0) + continue; // light doesn't reach + + VectorSubtract (light->origin, surf, incoming); + VectorNormalize (incoming); + angle = DotProduct (incoming, l->facenormal); + if (light->targetent) + { // spotlight cutoff + if (DotProduct (spotvec, incoming) > falloff) + continue; + } + + angle = (1.0-scalecos) + scalecos*angle; + add = light->light - dist; + add *= angle; + if (add < 0) + continue; + lightsamp[c] += add; + if (lightsamp[c] > 1) // ignore real tiny lights + hit = true; + } + + if (mapnum == l->numlightstyles && hit) + { + l->lightstyles[mapnum] = light->style; + l->numlightstyles++; // the style has some real data now + } +} + +/* +============ +FixMinlight +============ +*/ +void FixMinlight (lightinfo_t *l) +{ + int i, j; + float minlight; + + minlight = minlights[l->surfnum]; + +// if minlight is set, there must be a style 0 light map + if (!minlight) + return; + + for (i=0 ; i< l->numlightstyles ; i++) + { + if (l->lightstyles[i] == 0) + break; + } + if (i == l->numlightstyles) + { + if (l->numlightstyles == MAXLIGHTMAPS) + return; // oh well.. + for (j=0 ; jnumsurfpt ; j++) + l->lightmaps[i][j] = minlight; + l->lightstyles[i] = 0; + l->numlightstyles++; + } + else + { + for (j=0 ; jnumsurfpt ; j++) + if ( l->lightmaps[i][j] < minlight) + l->lightmaps[i][j] = minlight; + } +} + + +/* +============ +LightFace +============ +*/ +void LightFace (int surfnum) +{ + dface_t *f; + lightinfo_t l; + int s, t; + int i,j,c; + vec_t total; + int size; + int lightmapwidth, lightmapsize; + byte *out; + vec_t *light; + int w, h; + + f = dfaces + surfnum; + +// +// some surfaces don't need lightmaps +// + f->lightofs = -1; + for (j=0 ; jstyles[j] = 255; + + if ( texinfo[f->texinfo].flags & TEX_SPECIAL) + { // non-lit texture + return; + } + + memset (&l, 0, sizeof(l)); + l.surfnum = surfnum; + l.face = f; + +// +// rotate plane +// + VectorCopy (dplanes[f->planenum].normal, l.facenormal); + l.facedist = dplanes[f->planenum].dist; + if (f->side) + { + VectorSubtract (vec3_origin, l.facenormal, l.facenormal); + l.facedist = -l.facedist; + } + + + + CalcFaceVectors (&l); + CalcFaceExtents (&l); + CalcPoints (&l); + + lightmapwidth = l.texsize[0]+1; + + size = lightmapwidth*(l.texsize[1]+1); + if (size > SINGLEMAP) + Error ("Bad lightmap size"); + + for (i=0 ; istyles[i] = l.lightstyles[i]; + + lightmapsize = size*l.numlightstyles; + + out = GetFileSpace (lightmapsize); + f->lightofs = out - filebase; + +// extra filtering + h = (l.texsize[1]+1)*2; + w = (l.texsize[0]+1)*2; + + for (i=0 ; i< l.numlightstyles ; i++) + { + if (l.lightstyles[i] == 0xff) + Error ("Wrote empty lightmap"); + light = l.lightmaps[i]; + c = 0; + for (t=0 ; t<=l.texsize[1] ; t++) + for (s=0 ; s<=l.texsize[0] ; s++, c++) + { + if (extrasamples) + { // filtered sample + total = light[t*2*w+s*2] + light[t*2*w+s*2+1] + + light[(t*2+1)*w+s*2] + light[(t*2+1)*w+s*2+1]; + total *= 0.25; + } + else + total = light[c]; + total *= rangescale; // scale before clamping + if (total > 255) + total = 255; + if (total < 0) + Error ("light < 0"); + *out++ = total; + } + } + + +} + diff --git a/qutils/LIGHT/THREADS.C b/qutils/LIGHT/THREADS.C new file mode 100644 index 0000000..522d6d9 --- /dev/null +++ b/qutils/LIGHT/THREADS.C @@ -0,0 +1,66 @@ + +#include "cmdlib.h" +#include "threads.h" + +#ifdef __alpha +int numthreads = 4; +pthread_mutex_t *my_mutex; +#else +int numthreads = 1; +#endif + +void InitThreads (void) +{ +#ifdef __alpha + pthread_mutexattr_t mattrib; + + my_mutex = malloc (sizeof(*my_mutex)); + if (pthread_mutexattr_create (&mattrib) == -1) + Error ("pthread_mutex_attr_create failed"); + if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1) + Error ("pthread_mutexattr_setkind_np failed"); + if (pthread_mutex_init (my_mutex, mattrib) == -1) + Error ("pthread_mutex_init failed"); +#endif +} + +/* +=============== +RunThreadsOn +=============== +*/ +void RunThreadsOn ( threadfunc_t func ) +{ +#ifdef __alpha + pthread_t work_threads[256]; + pthread_addr_t status; + pthread_attr_t attrib; + int i; + + if (numthreads == 1) + { + func (NULL); + return; + } + + if (pthread_attr_create (&attrib) == -1) + Error ("pthread_attr_create failed"); + if (pthread_attr_setstacksize (&attrib, 0x100000) == -1) + Error ("pthread_attr_setstacksize failed"); + + for (i=0 ; i +extern pthread_mutex_t *my_mutex; +#define LOCK pthread_mutex_lock (my_mutex) +#define UNLOCK pthread_mutex_unlock (my_mutex) +#else +#define LOCK +#define UNLOCK +#endif + +extern int numthreads; + +typedef void (threadfunc_t) (void *); + +void InitThreads (void); +void RunThreadsOn ( threadfunc_t func ); diff --git a/qutils/LIGHT/TRACE.C b/qutils/LIGHT/TRACE.C new file mode 100644 index 0000000..ded4924 --- /dev/null +++ b/qutils/LIGHT/TRACE.C @@ -0,0 +1,197 @@ +// trace.c + +#include "light.h" + +typedef struct tnode_s +{ + int type; + vec3_t normal; + float dist; + int children[2]; + int pad; +} tnode_t; + +tnode_t *tnodes, *tnode_p; + +/* +============== +MakeTnode + +Converts the disk node structure into the efficient tracing structure +============== +*/ +void MakeTnode (int nodenum) +{ + tnode_t *t; + dplane_t *plane; + int i; + dnode_t *node; + + t = tnode_p++; + + node = dnodes + nodenum; + plane = dplanes + node->planenum; + + t->type = plane->type; + VectorCopy (plane->normal, t->normal); + t->dist = plane->dist; + + for (i=0 ; i<2 ; i++) + { + if (node->children[i] < 0) + t->children[i] = dleafs[-node->children[i] - 1].contents; + else + { + t->children[i] = tnode_p - tnodes; + MakeTnode (node->children[i]); + } + } + +} + + +/* +============= +MakeTnodes + +Loads the node structure out of a .bsp file to be used for light occlusion +============= +*/ +void MakeTnodes (dmodel_t *bm) +{ + tnode_p = tnodes = malloc(numnodes * sizeof(tnode_t)); + + MakeTnode (0); +} + + + +/* +============================================================================== + +LINE TRACING + +The major lighting operation is a point to point visibility test, performed +by recursive subdivision of the line by the BSP tree. + +============================================================================== +*/ + +typedef struct +{ + vec3_t backpt; + int side; + int node; +} tracestack_t; + + +/* +============== +TestLine +============== +*/ +qboolean TestLine (vec3_t start, vec3_t stop) +{ + int node; + float front, back; + tracestack_t *tstack_p; + int side; + float frontx,fronty, frontz, backx, backy, backz; + tracestack_t tracestack[64]; + tnode_t *tnode; + + frontx = start[0]; + fronty = start[1]; + frontz = start[2]; + backx = stop[0]; + backy = stop[1]; + backz = stop[2]; + + tstack_p = tracestack; + node = 0; + + while (1) + { + while (node < 0 && node != CONTENTS_SOLID) + { + // pop up the stack for a back side + tstack_p--; + if (tstack_p < tracestack) + return true; + node = tstack_p->node; + + // set the hit point for this plane + + frontx = backx; + fronty = backy; + frontz = backz; + + // go down the back side + + backx = tstack_p->backpt[0]; + backy = tstack_p->backpt[1]; + backz = tstack_p->backpt[2]; + + node = tnodes[tstack_p->node].children[!tstack_p->side]; + } + + if (node == CONTENTS_SOLID) + return false; // DONE! + + tnode = &tnodes[node]; + + switch (tnode->type) + { + case PLANE_X: + front = frontx - tnode->dist; + back = backx - tnode->dist; + break; + case PLANE_Y: + front = fronty - tnode->dist; + back = backy - tnode->dist; + break; + case PLANE_Z: + front = frontz - tnode->dist; + back = backz - tnode->dist; + break; + default: + front = (frontx*tnode->normal[0] + fronty*tnode->normal[1] + frontz*tnode->normal[2]) - tnode->dist; + back = (backx*tnode->normal[0] + backy*tnode->normal[1] + backz*tnode->normal[2]) - tnode->dist; + break; + } + + if (front > -ON_EPSILON && back > -ON_EPSILON) +// if (front > 0 && back > 0) + { + node = tnode->children[0]; + continue; + } + + if (front < ON_EPSILON && back < ON_EPSILON) +// if (front <= 0 && back <= 0) + { + node = tnode->children[1]; + continue; + } + + side = front < 0; + + front = front / (front-back); + + tstack_p->node = node; + tstack_p->side = side; + tstack_p->backpt[0] = backx; + tstack_p->backpt[1] = backy; + tstack_p->backpt[2] = backz; + + tstack_p++; + + backx = frontx + front*(backx-frontx); + backy = fronty + front*(backy-fronty); + backz = frontz + front*(backz-frontz); + + node = tnode->children[side]; + } +} + + diff --git a/qutils/MODELGEN/ANORMS.H b/qutils/MODELGEN/ANORMS.H new file mode 100644 index 0000000..adc6908 --- /dev/null +++ b/qutils/MODELGEN/ANORMS.H @@ -0,0 +1,162 @@ +{-0.525731, 0.000000, 0.850651}, +{-0.442863, 0.238856, 0.864188}, +{-0.295242, 0.000000, 0.955423}, +{-0.309017, 0.500000, 0.809017}, +{-0.162460, 0.262866, 0.951056}, +{0.000000, 0.000000, 1.000000}, +{0.000000, 0.850651, 0.525731}, +{-0.147621, 0.716567, 0.681718}, +{0.147621, 0.716567, 0.681718}, +{0.000000, 0.525731, 0.850651}, +{0.309017, 0.500000, 0.809017}, +{0.525731, 0.000000, 0.850651}, +{0.295242, 0.000000, 0.955423}, +{0.442863, 0.238856, 0.864188}, +{0.162460, 0.262866, 0.951056}, +{-0.681718, 0.147621, 0.716567}, +{-0.809017, 0.309017, 0.500000}, +{-0.587785, 0.425325, 0.688191}, +{-0.850651, 0.525731, 0.000000}, +{-0.864188, 0.442863, 0.238856}, +{-0.716567, 0.681718, 0.147621}, +{-0.688191, 0.587785, 0.425325}, +{-0.500000, 0.809017, 0.309017}, +{-0.238856, 0.864188, 0.442863}, +{-0.425325, 0.688191, 0.587785}, +{-0.716567, 0.681718, -0.147621}, +{-0.500000, 0.809017, -0.309017}, +{-0.525731, 0.850651, 0.000000}, +{0.000000, 0.850651, -0.525731}, +{-0.238856, 0.864188, -0.442863}, +{0.000000, 0.955423, -0.295242}, +{-0.262866, 0.951056, -0.162460}, +{0.000000, 1.000000, 0.000000}, +{0.000000, 0.955423, 0.295242}, +{-0.262866, 0.951056, 0.162460}, +{0.238856, 0.864188, 0.442863}, +{0.262866, 0.951056, 0.162460}, +{0.500000, 0.809017, 0.309017}, +{0.238856, 0.864188, -0.442863}, +{0.262866, 0.951056, -0.162460}, +{0.500000, 0.809017, -0.309017}, +{0.850651, 0.525731, 0.000000}, +{0.716567, 0.681718, 0.147621}, +{0.716567, 0.681718, -0.147621}, +{0.525731, 0.850651, 0.000000}, +{0.425325, 0.688191, 0.587785}, +{0.864188, 0.442863, 0.238856}, +{0.688191, 0.587785, 0.425325}, +{0.809017, 0.309017, 0.500000}, +{0.681718, 0.147621, 0.716567}, +{0.587785, 0.425325, 0.688191}, +{0.955423, 0.295242, 0.000000}, +{1.000000, 0.000000, 0.000000}, +{0.951056, 0.162460, 0.262866}, +{0.850651, -0.525731, 0.000000}, +{0.955423, -0.295242, 0.000000}, +{0.864188, -0.442863, 0.238856}, +{0.951056, -0.162460, 0.262866}, +{0.809017, -0.309017, 0.500000}, +{0.681718, -0.147621, 0.716567}, +{0.850651, 0.000000, 0.525731}, +{0.864188, 0.442863, -0.238856}, +{0.809017, 0.309017, -0.500000}, +{0.951056, 0.162460, -0.262866}, +{0.525731, 0.000000, -0.850651}, +{0.681718, 0.147621, -0.716567}, +{0.681718, -0.147621, -0.716567}, +{0.850651, 0.000000, -0.525731}, +{0.809017, -0.309017, -0.500000}, +{0.864188, -0.442863, -0.238856}, +{0.951056, -0.162460, -0.262866}, +{0.147621, 0.716567, -0.681718}, +{0.309017, 0.500000, -0.809017}, +{0.425325, 0.688191, -0.587785}, +{0.442863, 0.238856, -0.864188}, +{0.587785, 0.425325, -0.688191}, +{0.688191, 0.587785, -0.425325}, +{-0.147621, 0.716567, -0.681718}, +{-0.309017, 0.500000, -0.809017}, +{0.000000, 0.525731, -0.850651}, +{-0.525731, 0.000000, -0.850651}, +{-0.442863, 0.238856, -0.864188}, +{-0.295242, 0.000000, -0.955423}, +{-0.162460, 0.262866, -0.951056}, +{0.000000, 0.000000, -1.000000}, +{0.295242, 0.000000, -0.955423}, +{0.162460, 0.262866, -0.951056}, +{-0.442863, -0.238856, -0.864188}, +{-0.309017, -0.500000, -0.809017}, +{-0.162460, -0.262866, -0.951056}, +{0.000000, -0.850651, -0.525731}, +{-0.147621, -0.716567, -0.681718}, +{0.147621, -0.716567, -0.681718}, +{0.000000, -0.525731, -0.850651}, +{0.309017, -0.500000, -0.809017}, +{0.442863, -0.238856, -0.864188}, +{0.162460, -0.262866, -0.951056}, +{0.238856, -0.864188, -0.442863}, +{0.500000, -0.809017, -0.309017}, +{0.425325, -0.688191, -0.587785}, +{0.716567, -0.681718, -0.147621}, +{0.688191, -0.587785, -0.425325}, +{0.587785, -0.425325, -0.688191}, +{0.000000, -0.955423, -0.295242}, +{0.000000, -1.000000, 0.000000}, +{0.262866, -0.951056, -0.162460}, +{0.000000, -0.850651, 0.525731}, +{0.000000, -0.955423, 0.295242}, +{0.238856, -0.864188, 0.442863}, +{0.262866, -0.951056, 0.162460}, +{0.500000, -0.809017, 0.309017}, +{0.716567, -0.681718, 0.147621}, +{0.525731, -0.850651, 0.000000}, +{-0.238856, -0.864188, -0.442863}, +{-0.500000, -0.809017, -0.309017}, +{-0.262866, -0.951056, -0.162460}, +{-0.850651, -0.525731, 0.000000}, +{-0.716567, -0.681718, -0.147621}, +{-0.716567, -0.681718, 0.147621}, +{-0.525731, -0.850651, 0.000000}, +{-0.500000, -0.809017, 0.309017}, +{-0.238856, -0.864188, 0.442863}, +{-0.262866, -0.951056, 0.162460}, +{-0.864188, -0.442863, 0.238856}, +{-0.809017, -0.309017, 0.500000}, +{-0.688191, -0.587785, 0.425325}, +{-0.681718, -0.147621, 0.716567}, +{-0.442863, -0.238856, 0.864188}, +{-0.587785, -0.425325, 0.688191}, +{-0.309017, -0.500000, 0.809017}, +{-0.147621, -0.716567, 0.681718}, +{-0.425325, -0.688191, 0.587785}, +{-0.162460, -0.262866, 0.951056}, +{0.442863, -0.238856, 0.864188}, +{0.162460, -0.262866, 0.951056}, +{0.309017, -0.500000, 0.809017}, +{0.147621, -0.716567, 0.681718}, +{0.000000, -0.525731, 0.850651}, +{0.425325, -0.688191, 0.587785}, +{0.587785, -0.425325, 0.688191}, +{0.688191, -0.587785, 0.425325}, +{-0.955423, 0.295242, 0.000000}, +{-0.951056, 0.162460, 0.262866}, +{-1.000000, 0.000000, 0.000000}, +{-0.850651, 0.000000, 0.525731}, +{-0.955423, -0.295242, 0.000000}, +{-0.951056, -0.162460, 0.262866}, +{-0.864188, 0.442863, -0.238856}, +{-0.951056, 0.162460, -0.262866}, +{-0.809017, 0.309017, -0.500000}, +{-0.864188, -0.442863, -0.238856}, +{-0.951056, -0.162460, -0.262866}, +{-0.809017, -0.309017, -0.500000}, +{-0.681718, 0.147621, -0.716567}, +{-0.681718, -0.147621, -0.716567}, +{-0.850651, 0.000000, -0.525731}, +{-0.688191, 0.587785, -0.425325}, +{-0.587785, 0.425325, -0.688191}, +{-0.425325, 0.688191, -0.587785}, +{-0.425325, -0.688191, -0.587785}, +{-0.587785, -0.425325, -0.688191}, +{-0.688191, -0.587785, -0.425325}, diff --git a/qutils/MODELGEN/MODELGEN.C b/qutils/MODELGEN/MODELGEN.C new file mode 100644 index 0000000..2d1b478 --- /dev/null +++ b/qutils/MODELGEN/MODELGEN.C @@ -0,0 +1,1212 @@ +// +// modelgen.c: generates a .mdl file from a base triangle file (.tri), a +// texture containing front and back skins (.lbm), and a series of frame +// triangle files (.tri). Result is stored in +// /raid/quake/models/.mdl. +// + +#define INCLUDELIBS + +#include + +#include "modelgen.h" + +#define MAXVERTS 2048 +#define MAXFRAMES 256 +#define MAXSKINS 100 + + +typedef struct { + aliasframetype_t type; // single frame or group of frames + void *pdata; // either a daliasframe_t or group info + float interval; // only used for frames in groups + int numgroupframes; // only used by group headers + char name[16]; +} aliaspackage_t; + +typedef struct { + aliasskintype_t type; // single skin or group of skiins + void *pdata; // either a daliasskinframe_t or group info + float interval; // only used for skins in groups + int numgroupskins; // only used by group headers +} aliasskinpackage_t; + +typedef struct { + int numnormals; + float normals[20][3]; +} vertexnormals; + + +typedef struct { + vec3_t v; + int lightnormalindex; +} trivert_t; + +//============================================================================ + +trivert_t verts[MAXFRAMES][MAXVERTS]; +mdl_t model; + +char file1[1024]; +char skinname[1024]; +char qbasename[1024]; +float scale, scale_up = 1.0; +vec3_t mins, maxs; +vec3_t framesmins, framesmaxs; +vec3_t adjust; + +aliaspackage_t frames[MAXFRAMES]; + +aliasskinpackage_t skins[MAXSKINS]; + +// +// base frame info +// +vec3_t baseverts[MAXVERTS]; +stvert_t stverts[MAXVERTS]; +dtriangle_t triangles[MAXTRIANGLES]; +int degenerate[MAXTRIANGLES]; + + +char cdpartial[256]; +char cddir[256]; + +int framecount, skincount; +qboolean cdset; +int degeneratetris; +int firstframe = 1; +float totsize, averagesize; + +vertexnormals vnorms[MAXVERTS]; + +#define NUMVERTEXNORMALS 162 + +float avertexnormals[NUMVERTEXNORMALS][3] = { +#include "anorms.h" +}; + +trivertx_t tarray[MAXVERTS]; + +char outname[1024]; + + +void ClearModel (void) +{ + memset (&model, 0, sizeof(model)); + model.synctype = ST_RAND; // default + framecount = skincount = 0; + + scale = 0; + scale_up = 1.0; + + VectorCopy (vec3_origin, adjust); + VectorCopy (vec3_origin, mins); + VectorCopy (vec3_origin, maxs); + VectorCopy (vec3_origin, framesmins); + VectorCopy (vec3_origin, framesmaxs); + + degeneratetris = 0; + cdset = false; + firstframe = 1; + totsize = 0.0; +} + + +/* +============ +WriteFrame +============ +*/ +void WriteFrame (FILE *modelouthandle, int framenum) +{ + int j, k; + trivert_t *pframe; + daliasframe_t aframe; + float v; + + pframe = verts[framenum]; + + strcpy (aframe.name, frames[framenum].name); + + for (j=0 ; j<3 ; j++) + { + aframe.bboxmin.v[j] = 255; + aframe.bboxmax.v[j] = 0; + } + + for (j=0 ; j NUMVERTEXNORMALS) + Error ("invalid lightnormalindex %d\n", + tarray[j].lightnormalindex); + + for (k=0 ; k<3 ; k++) + { + // scale to byte values & min/max check + v = (pframe[j].v[k] - model.scale_origin[k]) / model.scale[k]; + + tarray[j].v[k] = v; + + if (tarray[j].v[k] < aframe.bboxmin.v[k]) + { + aframe.bboxmin.v[k] = tarray[j].v[k]; + } + if (tarray[j].v[k] > aframe.bboxmax.v[k]) + { + aframe.bboxmax.v[k] = tarray[j].v[k]; + } + + + } + } + + SafeWrite (modelouthandle, &aframe, sizeof (aframe)); + + SafeWrite (modelouthandle, &tarray[0], + model.numverts * sizeof(tarray[0])); +} + + +/* +============ +WriteGroupBBox +============ +*/ +void WriteGroupBBox (FILE *modelouthandle, int numframes, int curframe) +{ + int i, j, k; + daliasgroup_t dagroup; + trivert_t *pframe; + + + dagroup.numframes = LittleLong (numframes); + + for (i=0 ; i<3 ; i++) + { + dagroup.bboxmin.v[i] = 255; + dagroup.bboxmax.v[i] = 0; + } + + for (i=0 ; i dagroup.bboxmax.v[k]) + dagroup.bboxmax.v[k] = tarray[j].v[k]; + } + } + + curframe++; + } + + SafeWrite (modelouthandle, &dagroup, sizeof(dagroup)); +} + + +/* +============ +WriteModel +============ +*/ +void WriteModelFile (FILE *modelouthandle) +{ + int i, curframe, curskin; + float dist[3]; + mdl_t modeltemp; + +// Calculate the bounding box for this model + for (i=0 ; i<3 ; i++) + { + printf ("framesmins[%d]: %f, framesmaxs[%d]: %f\n", + i, framesmins[i], i, framesmaxs[i]); + if (fabs (framesmins[i]) > fabs (framesmaxs[i])) + dist[i] = framesmins[i]; + else + dist[i] = framesmaxs[i]; + + model.scale[i] = (framesmaxs[i] - framesmins[i]) / 255.9; + model.scale_origin[i] = framesmins[i]; + } + + model.boundingradius = sqrt(dist[0] * dist[0] + + dist[1] * dist[1] + + dist[2] * dist[2]); + +// +// write out the model header +// + modeltemp.ident = LittleLong (IDPOLYHEADER); + modeltemp.version = LittleLong (ALIAS_VERSION); + modeltemp.boundingradius = LittleFloat (model.boundingradius); + + for (i=0 ; i<3 ; i++) + { + modeltemp.scale[i] = LittleFloat (model.scale[i]); + modeltemp.scale_origin[i] = LittleFloat (model.scale_origin[i]); + modeltemp.eyeposition[i] = LittleFloat (model.eyeposition[i] + + adjust[i]); + } + + modeltemp.flags = LittleLong (model.flags); + modeltemp.numskins = LittleLong (model.numskins); + modeltemp.skinwidth = LittleLong (model.skinwidth); + modeltemp.skinheight = LittleLong (model.skinheight); + modeltemp.numverts = LittleLong (model.numverts); + modeltemp.numtris = LittleLong (model.numtris - degeneratetris); + modeltemp.numframes = LittleLong (model.numframes); + modeltemp.synctype = LittleFloat (model.synctype); + averagesize = totsize / model.numtris; + modeltemp.size = LittleFloat (averagesize); + + SafeWrite (modelouthandle, &modeltemp, sizeof(model)); + +// +// write out the skins +// + curskin = 0; + + for (i=0 ; i maxs[j]) + maxs[j] = v; + } + } + + for (i=0 ; i<3 ; i++) + { + mins[i] = floor(mins[i]); + maxs[i] = ceil(maxs[i]); + } + + width = maxs[0] - mins[0]; + height = maxs[2] - mins[2]; + + printf ("width: %i height: %i\n",width, height); + + scale = 8; + if (width*scale >= 150) + scale = 150.0 / width; + if (height*scale >= 190) + scale = 190.0 / height; + iwidth = ceil(width*scale) + 4; + iheight = ceil(height*scale) + 4; + + printf ("scale: %f\n",scale); + printf ("iwidth: %i iheight: %i\n",iwidth, iheight); + +// +// determine which side of each triangle to map the texture to +// + for (i=0 ; i 0) + { + basex = iwidth + 2; + triangles[i].facesfront = 0; + } + else + { + basex = 2; + triangles[i].facesfront = 1; + } + basey = 2; + + for (j=0 ; j<3 ; j++) + { + float *pbasevert; + stvert_t *pstvert; + + pbasevert = baseverts[triangles[i].vertindex[j]]; + pstvert = &stverts[triangles[i].vertindex[j]]; + + if (triangles[i].facesfront) + { + pstvert->onseam |= 1; + } + else + { + pstvert->onseam |= 2; + } + + if ((triangles[i].facesfront) || ((pstvert->onseam & 1) == 0)) + { + // we want the front s value for seam vertices + pstvert->s = Q_rint((pbasevert[0] - mins[0]) * scale + basex); + pstvert->t = Q_rint((maxs[2] - pbasevert[2]) * scale + basey); + } + } + } + +// make the width a multiple of 4; some hardware requires this, and it ensures +// dword alignment for each scan + skinwidth = iwidth*2; + model.skinwidth = (skinwidth + 3) & ~3; + model.skinheight = iheight; + + printf ("skin width: %i (unpadded width %i) skin height: %i\n", + model.skinwidth, skinwidth, model.skinheight); +} + + +/* +================= +Cmd_Base +================= +*/ +void Cmd_Base (void) +{ + triangle_t *ptri; + int i, j, k; + int time1; + + GetToken (false); + strcpy (qbasename, token); + + sprintf (file1, "%s/%s.tri", cdpartial, token); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s.tri", cddir, token); + time1 = FileTime (file1); + if (time1 == -1) + Error ("%s doesn't exist", file1); + +// +// load the base triangles +// + LoadTriangleList (file1, &ptri, &model.numtris); + printf("NUMBER OF TRIANGLES (including degenerate triangles): %d\n", + model.numtris); + +// +// run through all the base triangles, storing each unique vertex in the +// base vertex list and setting the indirect triangles to point to the base +// vertices +// + for (i=0 ; i MAXSKINS) + Error ("Too many skins; increase MAXSKINS"); +} + + +/* +=============== +GrabFrame +=============== +*/ +void GrabFrame (char *frame, int isgroup) +{ + triangle_t *ptri; + int i, j; + trivert_t *ptrivert; + int numtris; + int time1; + + sprintf (file1, "%s/%s.tri", cdpartial, frame); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s.tri",cddir, frame); + time1 = FileTime (file1); + if (time1 == -1) + Error ("%s does not exist",file1); + + printf ("grabbing %s\n", file1); + frames[framecount].interval = 0.1; + strcpy (frames[framecount].name, frame); + +// +// load the frame +// + LoadTriangleList (file1, &ptri, &numtris); + + if (numtris != model.numtris) + Error ("number of triangles doesn't match\n"); + +// set the intervals + if (isgroup && TokenAvailable ()) + { + GetToken (false); + frames[framecount].interval = atof (token); + if (frames[framecount].interval <= 0.0) + Error ("Non-positive interval %s %f", token, + frames[framecount].interval); + } + else + { + frames[framecount].interval = 0.1; + } + +// +// allocate storage for the frame's vertices +// + ptrivert = verts[framecount]; + + frames[framecount].pdata = ptrivert; + frames[framecount].type = ALIAS_SINGLE; + + for (i=0 ; i framesmaxs[k]) + framesmaxs[k] = ptrivert[vertindex].v[k]; + } + + VectorCopy (normal, + vnorms[vertindex]. + normals[vnorms[vertindex].numnormals]); + + vnorms[vertindex].numnormals++; + } + } + +// +// calculate the vertex normals, match them to the template list, and store the +// index of the best match +// + for (i=0 ; i 0) + { + for (j=0 ; j<3 ; j++) + { + int k; + + v[j] = 0; + + for (k=0 ; k maxdot) + { + maxdot = dot; + maxdotindex = j; + } + } + + ptrivert[i].lightnormalindex = maxdotindex; + } + + framecount++; + + if (framecount >= MAXFRAMES) + Error ("Too many frames; increase MAXFRAMES"); + + free (ptri); + firstframe = 0; +} + +/* +=============== +Cmd_Frame +=============== +*/ +void Cmd_Frame (int isgroup) +{ + while (TokenAvailable()) + { + GetToken (false); + GrabFrame (token, isgroup); + + if (!isgroup) + model.numframes++; + } +} + +/* +=============== +Cmd_SkinGroupStart +=============== +*/ +void Cmd_SkinGroupStart (void) +{ + int groupskin; + + groupskin = skincount++; + if (skincount >= MAXFRAMES) + Error ("Too many skins; increase MAXSKINS"); + + skins[groupskin].type = ALIAS_SKIN_GROUP; + skins[groupskin].numgroupskins = 0; + + while (1) + { + GetToken (true); + if (endofscript) + Error ("End of file during group"); + + if (!strcmp (token, "$skin")) + { + Cmd_Skin (); + skins[groupskin].numgroupskins++; + } + else if (!strcmp (token, "$skingroupend")) + { + break; + } + else + { + Error ("$skin or $skingroupend expected\n"); + } + + } + + if (skins[groupskin].numgroupskins == 0) + Error ("Empty group\n"); +} + + +/* +=============== +Cmd_FrameGroupStart +=============== +*/ +void Cmd_FrameGroupStart (void) +{ + int groupframe; + + groupframe = framecount++; + if (framecount >= MAXFRAMES) + Error ("Too many frames; increase MAXFRAMES"); + + frames[groupframe].type = ALIAS_GROUP; + frames[groupframe].numgroupframes = 0; + + while (1) + { + GetToken (true); + if (endofscript) + Error ("End of file during group"); + + if (!strcmp (token, "$frame")) + { + Cmd_Frame (1); + } + else if (!strcmp (token, "$framegroupend")) + { + break; + } + else + { + Error ("$frame or $framegroupend expected\n"); + } + + } + + frames[groupframe].numgroupframes += framecount - groupframe - 1; + + if (frames[groupframe].numgroupframes == 0) + Error ("Empty group\n"); +} + + +/* +================= +Cmd_Origin +================= +*/ +void Cmd_Origin (void) +{ + +// rotate points into frame of reference so model points down the positive x +// axis + GetToken (false); + adjust[1] = -atof (token); + + GetToken (false); + adjust[0] = atof (token); + + GetToken (false); + adjust[2] = -atof (token); +} + + +/* +================= +Cmd_Eyeposition +================= +*/ +void Cmd_Eyeposition (void) +{ + +// rotate points into frame of reference so model points down the positive x +// axis + GetToken (false); + model.eyeposition[1] = atof (token); + + GetToken (false); + model.eyeposition[0] = -atof (token); + + GetToken (false); + model.eyeposition[2] = atof (token); +} + + +/* +================= +Cmd_ScaleUp +================= +*/ +void Cmd_ScaleUp (void) +{ + + GetToken (false); + scale_up = atof (token); +} + +/* +================= +Cmd_Flags +================= +*/ +void Cmd_Flags (void) +{ + GetToken (false); + model.flags = atoi (token); +} + + +/* +================= +Cmd_Modelname +================= +*/ +void Cmd_Modelname (void) +{ + WriteModel (); + GetToken (false); + strcpy (outname, token); +} + + +/* +=============== +ParseScript +=============== +*/ +void ParseScript (void) +{ + while (1) + { + do + { // look for a line starting with a $ command + GetToken (true); + if (endofscript) + return; + if (token[0] == '$') + break; + while (TokenAvailable()) + GetToken (false); + } while (1); + + if (!strcmp (token, "$modelname")) + { + Cmd_Modelname (); + } + else if (!strcmp (token, "$base")) + { + Cmd_Base (); + } + else if (!strcmp (token, "$cd")) + { + if (cdset) + Error ("Two $cd in one model"); + cdset = true; + GetToken (false); + strcpy (cdpartial, token); + strcpy (cddir, ExpandPath(token)); + } + else if (!strcmp (token, "$sync")) + { + model.synctype = ST_SYNC; + } + else if (!strcmp (token, "$origin")) + { + Cmd_Origin (); + } + else if (!strcmp (token, "$eyeposition")) + { + Cmd_Eyeposition (); + } + else if (!strcmp (token, "$scale")) + { + Cmd_ScaleUp (); + } + else if (!strcmp (token, "$flags")) + { + Cmd_Flags (); + } + else if (!strcmp (token, "$frame")) + { + Cmd_Frame (0); + } + else if (!strcmp (token, "$skin")) + { + Cmd_Skin (); + model.numskins++; + } + else if (!strcmp (token, "$framegroupstart")) + { + Cmd_FrameGroupStart (); + model.numframes++; + } + else if (!strcmp (token, "$skingroupstart")) + { + Cmd_SkinGroupStart (); + model.numskins++; + } + else + { + Error ("bad command %s\n", token); + } + + } +} + +/* +============== +main +============== +*/ +int main (int argc, char **argv) +{ + int i; + char path[1024]; + + if (argc != 2 && argc != 4) + Error ("usage: modelgen [-archive directory] file.qc"); + + if (!strcmp(argv[1], "-archive")) + { + archive = true; + strcpy (archivedir, argv[2]); + printf ("Archiving source to: %s\n", archivedir); + i = 3; + } + else + i = 1; + +// +// load the script +// + strcpy (path, argv[i]); + DefaultExtension (path, ".qc"); + SetQdirFromPath (path); + LoadScriptFile (path); + +// +// parse it +// + memset (&model, 0, sizeof(model)); + + for (i=0 ; i<3 ; i++) + { + framesmins[i] = 9999999; + framesmaxs[i] = -9999999; + } + + + ClearModel (); + strcpy (outname, argv[1]); + + ParseScript (); + WriteModel (); + + return 0; +} + diff --git a/qutils/MODELGEN/MODELGEN.H b/qutils/MODELGEN/MODELGEN.H new file mode 100644 index 0000000..386245e --- /dev/null +++ b/qutils/MODELGEN/MODELGEN.H @@ -0,0 +1,113 @@ +// +// modelgen.h: header file for model generation program +// + +// ********************************************************* +// * This file must be identical in the modelgen directory * +// * and in the Quake directory, because it's used to * +// * pass data from one to the other via model files. * +// ********************************************************* + +#ifdef INCLUDELIBS + +#include +#include +#include +#include + +#include "cmdlib.h" +#include "scriplib.h" +#include "mathlib.h" +#include "trilib.h" +#include "lbmlib.h" + +#endif + +#define ALIAS_VERSION 6 + +#define ALIAS_ONSEAM 0x0020 + +// must match definition in spritegn.h +#ifndef SYNCTYPE_T +#define SYNCTYPE_T +typedef enum {ST_SYNC=0, ST_RAND } synctype_t; +#endif + +typedef enum { ALIAS_SINGLE=0, ALIAS_GROUP } aliasframetype_t; + +typedef enum { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP } aliasskintype_t; + +typedef struct { + int ident; + int version; + vec3_t scale; + vec3_t scale_origin; + float boundingradius; + vec3_t eyeposition; + int numskins; + int skinwidth; + int skinheight; + int numverts; + int numtris; + int numframes; + synctype_t synctype; + int flags; + float size; +} mdl_t; + +// TODO: could be shorts + +typedef struct { + int onseam; + int s; + int t; +} stvert_t; + +typedef struct dtriangle_s { + int facesfront; + int vertindex[3]; +} dtriangle_t; + +#define DT_FACES_FRONT 0x0010 + + +typedef struct { + byte v[3]; + byte lightnormalindex; +} trivertx_t; + +typedef struct { + trivertx_t bboxmin; // lightnormal isn't used + trivertx_t bboxmax; // lightnormal isn't used + char name[16]; // frame name from grabbing +} daliasframe_t; + +typedef struct { + int numframes; + trivertx_t bboxmin; // lightnormal isn't used + trivertx_t bboxmax; // lightnormal isn't used +} daliasgroup_t; + +typedef struct { + int numskins; +} daliasskingroup_t; + +typedef struct { + float interval; +} daliasinterval_t; + +typedef struct { + float interval; +} daliasskininterval_t; + +typedef struct { + aliasframetype_t type; +} daliasframetype_t; + +typedef struct { + aliasskintype_t type; +} daliasskintype_t; + +#define IDPOLYHEADER (('O'<<24)+('P'<<16)+('D'<<8)+'I') + // little-endian "IDPO" + diff --git a/qutils/MODELGEN/MODELGEN.MAK b/qutils/MODELGEN/MODELGEN.MAK new file mode 100644 index 0000000..9b79469 --- /dev/null +++ b/qutils/MODELGEN/MODELGEN.MAK @@ -0,0 +1,294 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=modelgen - Win32 Debug +!MESSAGE No configuration specified. Defaulting to modelgen - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "modelgen - Win32 Release" && "$(CFG)" !=\ + "modelgen - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "modelgen.mak" CFG="modelgen - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "modelgen - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "modelgen - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "modelgen - Win32 Debug" +RSC=rc.exe +CPP=cl.exe + +!IF "$(CFG)" == "modelgen - 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 "" +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "$(OUTDIR)\modelgen.exe" + +CLEAN : + -@erase ".\Release\modelgen.exe" + -@erase ".\Release\mathlib.obj" + -@erase ".\Release\cmdlib.obj" + -@erase ".\Release\lbmlib.obj" + -@erase ".\Release\trilib.obj" + -@erase ".\Release\scriplib.obj" + -@erase ".\Release\modelgen.obj" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /ML /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/modelgen.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Release/ +CPP_SBRS= +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/modelgen.bsc" +BSC32_SBRS= +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 /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 /nologo /subsystem:console /machine:I386 +LINK32_FLAGS=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 /incremental:no\ + /pdb:"$(OUTDIR)/modelgen.pdb" /machine:I386 /out:"$(OUTDIR)/modelgen.exe" +LINK32_OBJS= \ + "$(INTDIR)/mathlib.obj" \ + "$(INTDIR)/cmdlib.obj" \ + "$(INTDIR)/lbmlib.obj" \ + "$(INTDIR)/trilib.obj" \ + "$(INTDIR)/scriplib.obj" \ + "$(INTDIR)/modelgen.obj" + +"$(OUTDIR)\modelgen.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "modelgen - 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 Target_Dir "" +OUTDIR=.\Debug +INTDIR=.\Debug + +ALL : "$(OUTDIR)\modelgen.exe" + +CLEAN : + -@erase ".\Debug\vc40.pdb" + -@erase ".\Debug\vc40.idb" + -@erase ".\Debug\modelgen.exe" + -@erase ".\Debug\trilib.obj" + -@erase ".\Debug\mathlib.obj" + -@erase ".\Debug\lbmlib.obj" + -@erase ".\Debug\modelgen.obj" + -@erase ".\Debug\scriplib.obj" + -@erase ".\Debug\cmdlib.obj" + -@erase ".\Debug\modelgen.ilk" + -@erase ".\Debug\modelgen.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MLd /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/modelgen.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Debug/ +CPP_SBRS= +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/modelgen.bsc" +BSC32_SBRS= +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 /subsystem:console /debug /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 /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=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 /incremental:yes\ + /pdb:"$(OUTDIR)/modelgen.pdb" /debug /machine:I386\ + /out:"$(OUTDIR)/modelgen.exe" +LINK32_OBJS= \ + "$(INTDIR)/trilib.obj" \ + "$(INTDIR)/mathlib.obj" \ + "$(INTDIR)/lbmlib.obj" \ + "$(INTDIR)/modelgen.obj" \ + "$(INTDIR)/scriplib.obj" \ + "$(INTDIR)/cmdlib.obj" + +"$(OUTDIR)\modelgen.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Target + +# Name "modelgen - Win32 Release" +# Name "modelgen - Win32 Debug" + +!IF "$(CFG)" == "modelgen - Win32 Release" + +!ELSEIF "$(CFG)" == "modelgen - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\modelgen.c +DEP_CPP_MODEL=\ + {$(INCLUDE)}"\sys\STAT.H"\ + ".\modelgen.h"\ + ".\anorms.h"\ + {$(INCLUDE)}"\sys\TYPES.H"\ + ".\..\common\cmdlib.h"\ + ".\..\common\scriplib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\trilib.h"\ + ".\..\common\lbmlib.h"\ + + +"$(INTDIR)\modelgen.obj" : $(SOURCE) $(DEP_CPP_MODEL) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\cmdlib.c +DEP_CPP_CMDLI=\ + ".\..\common\cmdlib.h"\ + {$(INCLUDE)}"\sys\TYPES.H"\ + {$(INCLUDE)}"\sys\STAT.H"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\trilib.c +DEP_CPP_TRILI=\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\trilib.h"\ + + +"$(INTDIR)\trilib.obj" : $(SOURCE) $(DEP_CPP_TRILI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\scriplib.c +DEP_CPP_SCRIP=\ + ".\..\common\cmdlib.h"\ + ".\..\common\scriplib.h"\ + + +"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\mathlib.c +DEP_CPP_MATHL=\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + + +"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\lbmlib.c +DEP_CPP_LBMLI=\ + ".\..\common\cmdlib.h"\ + ".\..\common\lbmlib.h"\ + + +"$(INTDIR)\lbmlib.obj" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +# End Target +# End Project +################################################################################ diff --git a/qutils/MODELGEN/MODELGEN.MDP b/qutils/MODELGEN/MODELGEN.MDP new file mode 100644 index 0000000000000000000000000000000000000000..00dfd2596b1324a74c823193c48199b2e2d7140a GIT binary patch literal 36352 zcmeI5TXWM!6o8K)2~N0$76PME?Ep&wsvjTsj4P5&>Y5g-C>LExoL z$|eP8(hoP`myd6@#hhpoYbVeRJ$M2XgI?%^t*{NYuU(ZSUw8t&uo=X^e*Y2$I{yn{ z&<7D90z`la5CI}U1c(3;AOb{y2oQmGB0%SV?X;TDK9`+%^1BOOf|p@8?12H;`|Ku2 zJTx1W=v>isV2!q2muu-X5L3TUF=zY}GSNcW73#%Vpb|)yleQ6cgIXPgr8) ztk4}O+d4N(++wHL4Z|89VrgEimV~KaYvT%jKmNTYn?;*&xNcA`_oi&ib8PceO4JIW z7}jo=wc`#~=Vc3OKird6J=I&PaF#b*)ig?0nOmOF6R&Q7C;elZ#$A`aZ`h{l8MY-G zd$4hP)?!!H5@#95u^rihgL%?BWwSgl+s=}#J&3h0XHAorRFh>b*K?{`t-YhzzHiF5 zG@OB9Rn?-2W*0SHsTDfr8?hE}s5(m8k@}v05c*dgRK#`SdZTsv3q^JW!>ZRFSK!J1bS{T# zxGK0t_kE9H6DpdE@M>=P>E67dIks!x_E_q~iPh^Ye6$N+JvUTOn>!;5L$WX|3nKuB z5X>PZpSzM1T67TsB0vO)01+SpM1Tko0U|&I)|CLA|E(+D4R8E6WsLGaH~cEC-vIZ+ zEAT2DfP-)d27$q0h_7E~WO;)T=!3Bz<&eZ7ow(@ym(G9vLuNYvwdnje*c0fT2oM1x zKm>>Y5g-CYfCvzQb|66KzwNM!&p(IP;3yn}nES^Y&388V8 zOtZMJ85F0|nepqBLHSl{da5v;%iy<(O8go(x$5$y%oj~mv^i|~5UozwQ7hJH47=Ww zG}-CJk<%AhQfF~#6&nsmV_H#)Ocq@&F0}ui=Z?kA;h_X(tFo%gov>Kajj(jjurL|Z zHhl@qZq?0F*rMtSYDJ2HA_@!Dkbl-}t7d0t>MXeHkiAL;Ji|&%^ z@$x93lkGtNj(j9HK;@Bm3wqmMF+)3Qkgsmo{Sn2G)bs_8oLlvF%#C8`7){h`QWKcmT_bR?<(&@7nl++bv4O^5!#-+u$p$)y8tSa2Ev2dwci1bBk(?Tc~l5HW<9owD0a)T(> z_*bpx{I8S)*1@~j7w94aM1TkofmH+?B0vO)01+Sp?MEO1NjME>UwSNKN^2O*waeE4Iqa0{JO4 z#MLb1C!a91yxfn6`Fzn!+u95-V|2meE7nAmqUPre{o(-DiPs~Xm@Og%>o~KcX#axW z$I7SZQCw?@zCQcx0^0x&!r4*$m*T%gwlNYHDE`~%S!q$&4L2)_|N5bRv110oW{Usf z)AXX~m)0oCO!40!9$gbJr1&pBXt7lYy`!V-6#td~Nu*CAKm>?DQvwwKZHlHN8ZN;* X@Ge}2F&Kvwq#@H0v!+P~1bX2g#c^I; literal 0 HcmV?d00001 diff --git a/qutils/MODELGEN/MODELGEN.NCB b/qutils/MODELGEN/MODELGEN.NCB new file mode 100644 index 0000000000000000000000000000000000000000..aa8fab12c1d4df9eb09f5d092cc44686e52bc319 GIT binary patch literal 91136 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 W0x1Pj3ZxWBDUebirNE1T0{} literal 0 HcmV?d00001 diff --git a/qutils/QBSP/BRUSH.C b/qutils/QBSP/BRUSH.C new file mode 100644 index 0000000..1a3b3ab --- /dev/null +++ b/qutils/QBSP/BRUSH.C @@ -0,0 +1,870 @@ +// brush.c + +#include "bsp5.h" + +int numbrushplanes; +plane_t planes[MAX_MAP_PLANES]; + +int numbrushfaces; +mface_t faces[128]; // beveled clipping hull can generate many extra + + +/* +================= +CheckFace + +Note: this will not catch 0 area polygons +================= +*/ +void CheckFace (face_t *f) +{ + int i, j; + vec_t *p1, *p2; + vec_t d, edgedist; + vec3_t dir, edgenormal, facenormal; + + if (f->numpoints < 3) + Error ("CheckFace: %i points",f->numpoints); + + VectorCopy (planes[f->planenum].normal, facenormal); + if (f->planeside) + { + VectorSubtract (vec3_origin, facenormal, facenormal); + } + + for (i=0 ; inumpoints ; i++) + { + p1 = f->pts[i]; + + for (j=0 ; j<3 ; j++) + if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE) + Error ("CheckFace: BUGUS_RANGE: %f",p1[j]); + + j = i+1 == f->numpoints ? 0 : i+1; + + // check the point is on the face plane + d = DotProduct (p1, planes[f->planenum].normal) - planes[f->planenum].dist; + if (d < -ON_EPSILON || d > ON_EPSILON) + Error ("CheckFace: point off plane"); + + // check the edge isn't degenerate + p2 = f->pts[j]; + VectorSubtract (p2, p1, dir); + + if (VectorLength (dir) < ON_EPSILON) + Error ("CheckFace: degenerate edge"); + + CrossProduct (facenormal, dir, edgenormal); + VectorNormalize (edgenormal); + edgedist = DotProduct (p1, edgenormal); + edgedist += ON_EPSILON; + + // all other points must be on front side + for (j=0 ; jnumpoints ; j++) + { + if (j == i) + continue; + d = DotProduct (f->pts[j], edgenormal); + if (d > edgedist) + Error ("CheckFace: non-convex"); + } + } +} + + +//=========================================================================== + +/* +================= +ClearBounds +================= +*/ +void ClearBounds (brushset_t *bs) +{ + int i, j; + + for (j=0 ; jmins[i] = 99999; + bs->maxs[i] = -99999; + } +} + +/* +================= +AddToBounds +================= +*/ +void AddToBounds (brushset_t *bs, vec3_t v) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if (v[i] < bs->mins[i]) + bs->mins[i] = v[i]; + if (v[i] > bs->maxs[i]) + bs->maxs[i] = v[i]; + } +} + +//=========================================================================== + +int PlaneTypeForNormal (vec3_t normal) +{ + float ax, ay, az; + +// NOTE: should these have an epsilon around 1.0? + if (normal[0] == 1.0) + return PLANE_X; + if (normal[1] == 1.0) + return PLANE_Y; + if (normal[2] == 1.0) + return PLANE_Z; + if (normal[0] == -1.0 || + normal[1] == -1.0 || + normal[2] == -1.0) + Error ("PlaneTypeForNormal: not a canonical vector"); + + ax = fabs(normal[0]); + ay = fabs(normal[1]); + az = fabs(normal[2]); + + if (ax >= ay && ax >= az) + return PLANE_ANYX; + if (ay >= ax && ay >= az) + return PLANE_ANYY; + return PLANE_ANYZ; +} + +#define DISTEPSILON 0.01 +#define ANGLEEPSILON 0.00001 + +void NormalizePlane (plane_t *dp) +{ + vec_t ax, ay, az; + + if (dp->normal[0] == -1.0) + { + dp->normal[0] = 1.0; + dp->dist = -dp->dist; + } + if (dp->normal[1] == -1.0) + { + dp->normal[1] = 1.0; + dp->dist = -dp->dist; + } + if (dp->normal[2] == -1.0) + { + dp->normal[2] = 1.0; + dp->dist = -dp->dist; + } + + if (dp->normal[0] == 1.0) + { + dp->type = PLANE_X; + return; + } + if (dp->normal[1] == 1.0) + { + dp->type = PLANE_Y; + return; + } + if (dp->normal[2] == 1.0) + { + dp->type = PLANE_Z; + return; + } + + ax = fabs(dp->normal[0]); + ay = fabs(dp->normal[1]); + az = fabs(dp->normal[2]); + + if (ax >= ay && ax >= az) + dp->type = PLANE_ANYX; + else if (ay >= ax && ay >= az) + dp->type = PLANE_ANYY; + else + dp->type = PLANE_ANYZ; + if (dp->normal[dp->type-PLANE_ANYX] < 0) + { + VectorSubtract (vec3_origin, dp->normal, dp->normal); + dp->dist = -dp->dist; + } + +} + +/* +=============== +FindPlane + +Returns a global plane number and the side that will be the front +=============== +*/ +int FindPlane (plane_t *dplane, int *side) +{ + int i; + plane_t *dp, pl; + vec_t dot; + + dot = VectorLength(dplane->normal); + if (dot < 1.0 - ANGLEEPSILON || dot > 1.0 + ANGLEEPSILON) + Error ("FindPlane: normalization error"); + + pl = *dplane; + NormalizePlane (&pl); + if (DotProduct(pl.normal, dplane->normal) > 0) + *side = 0; + else + *side = 1; + + dp = planes; + for (i=0 ; inormal, pl.normal); + if (dot > 1.0 - ANGLEEPSILON + && fabs(dp->dist - pl.dist) < DISTEPSILON ) + { // regular match + return i; + } + } + + if (numbrushplanes == MAX_MAP_PLANES) + Error ("numbrushplanes == MAX_MAP_PLANES"); + + planes[numbrushplanes] = pl; + + numbrushplanes++; + + return numbrushplanes-1; +} + + +/* +=============== +FindPlane_old + +Returns a global plane number and the side that will be the front +=============== +*/ +int FindPlane_old (plane_t *dplane, int *side) +{ + int i; + plane_t *dp; + vec_t dot, ax, ay, az; + + dot = VectorLength(dplane->normal); + if (dot < 1.0 - ANGLEEPSILON || dot > 1.0 + ANGLEEPSILON) + Error ("FindPlane: normalization error"); + + dp = planes; + + for (i=0 ; inormal, dp->normal); + if (dot > 1.0 - ANGLEEPSILON + && fabs(dplane->dist - dp->dist) < DISTEPSILON ) + { // regular match + *side = 0; + return i; + } + if (dot < -1.0+ANGLEEPSILON + && fabs(dplane->dist + dp->dist) < DISTEPSILON ) + { // inverse of vector + *side = 1; + return i; + } + } + +// allocate a new plane, flipping normal to a consistant direction +// if needed + *dp = *dplane; + + if (numbrushplanes == MAX_MAP_PLANES) + Error ("numbrushplanes == MAX_MAP_PLANES"); + numbrushplanes++; + + *side = 0; + +// NOTE: should these have an epsilon around 1.0? + if (dplane->normal[0] == 1.0) + dp->type = PLANE_X; + else if (dplane->normal[1] == 1.0) + dp->type = PLANE_Y; + else if (dplane->normal[2] == 1.0) + dp->type = PLANE_Z; + else if (dplane->normal[0] == -1.0) + { + dp->type = PLANE_X; + dp->normal[0] = 1.0; + dp->dist = -dp->dist; + *side = 1; + } + else if (dplane->normal[1] == -1.0) + { + dp->type = PLANE_Y; + dp->normal[1] = 1.0; + dp->dist = -dp->dist; + *side = 1; + } + else if (dplane->normal[2] == -1.0) + { + dp->type = PLANE_Z; + dp->normal[2] = 1.0; + dp->dist = -dp->dist; + *side = 1; + } + else + { + ax = fabs(dplane->normal[0]); + ay = fabs(dplane->normal[1]); + az = fabs(dplane->normal[2]); + + if (ax >= ay && ax >= az) + dp->type = PLANE_ANYX; + else if (ay >= ax && ay >= az) + dp->type = PLANE_ANYY; + else + dp->type = PLANE_ANYZ; + if (dplane->normal[dp->type-PLANE_ANYX] < 0) + { + VectorSubtract (vec3_origin, dp->normal, dp->normal); + dp->dist = -dp->dist; + *side = 1; + } + } + + return i; +} + + + +/* +============================================================================= + + TURN BRUSHES INTO GROUPS OF FACES + +============================================================================= +*/ + +vec3_t brush_mins, brush_maxs; +face_t *brush_faces; + +/* +================= +CreateBrushFaces +================= +*/ +#define ZERO_EPSILON 0.001 +void CreateBrushFaces (void) +{ + int i,j, k; + vec_t r; + face_t *f; + winding_t *w; + plane_t plane; + mface_t *mf; + + brush_mins[0] = brush_mins[1] = brush_mins[2] = 99999; + brush_maxs[0] = brush_maxs[1] = brush_maxs[2] = -99999; + + brush_faces = NULL; + + for (i=0 ; iplane); + + for (j=0 ; jnumpoints = w->numpoints; + if (f->numpoints > MAXEDGES) + Error ("f->numpoints > MAXEDGES"); + + for (j=0 ; jnumpoints ; j++) + { + for (k=0 ; k<3 ; k++) + { + r = Q_rint (w->points[j][k]); + if ( fabs(w->points[j][k] - r) < ZERO_EPSILON) + f->pts[j][k] = r; + else + f->pts[j][k] = w->points[j][k]; + + if (f->pts[j][k] < brush_mins[k]) + brush_mins[k] = f->pts[j][k]; + if (f->pts[j][k] > brush_maxs[k]) + brush_maxs[k] = f->pts[j][k]; + } + + } + FreeWinding (w); + f->texturenum = mf->texinfo; + f->planenum = FindPlane (&mf->plane, &f->planeside); + f->next = brush_faces; + brush_faces = f; + CheckFace (f); + } +} + + + +/* +============================================================================== + +BEVELED CLIPPING HULL GENERATION + +This is done by brute force, and could easily get a lot faster if anyone cares. +============================================================================== +*/ + +vec3_t hull_size[3][2] = { +{ {0, 0, 0}, {0, 0, 0} }, +{ {-16,-16,-32}, {16,16,24} }, +{ {-32,-32,-64}, {32,32,24} } + +}; + +#define MAX_HULL_POINTS 32 +#define MAX_HULL_EDGES 64 + +int num_hull_points; +vec3_t hull_points[MAX_HULL_POINTS]; +vec3_t hull_corners[MAX_HULL_POINTS*8]; +int num_hull_edges; +int hull_edges[MAX_HULL_EDGES][2]; + +/* +============ +AddBrushPlane +============= +*/ +void AddBrushPlane (plane_t *plane) +{ + int i; + plane_t *pl; + float l; + + if (numbrushfaces == MAX_FACES) + Error ("AddBrushPlane: numbrushfaces == MAX_FACES"); + l = VectorLength (plane->normal); + if (l < 0.999 || l > 1.001) + Error ("AddBrushPlane: bad normal"); + + for (i=0 ; inormal, plane->normal) + && fabs(pl->dist - plane->dist) < ON_EPSILON ) + return; + } + faces[i].plane = *plane; + faces[i].texinfo = faces[0].texinfo; + numbrushfaces++; +} + + +/* +============ +TestAddPlane + +Adds the given plane to the brush description if all of the original brush +vertexes can be put on the front side +============= +*/ +void TestAddPlane (plane_t *plane) +{ + int i, c; + vec_t d; + vec_t *corner; + plane_t flip; + vec3_t inv; + int counts[3]; + plane_t *pl; + +// see if the plane has allready been added + for (i=0 ; inormal, pl->normal) && fabs(plane->dist - pl->dist) < ON_EPSILON) + return; + VectorSubtract (vec3_origin, plane->normal, inv); + if (VectorCompare (inv, pl->normal) && fabs(plane->dist + pl->dist) < ON_EPSILON) + return; + } + +// check all the corner points + counts[0] = counts[1] = counts[2] = 0; + c = num_hull_points * 8; + + corner = hull_corners[0]; + for (i=0 ; inormal) - plane->dist; + if (d < -ON_EPSILON) + { + if (counts[0]) + return; + counts[1]++; + } + else if (d > ON_EPSILON) + { + if (counts[1]) + return; + counts[0]++; + } + else + counts[2]++; + } + +// the plane is a seperator + + if (counts[0]) + { + VectorSubtract (vec3_origin, plane->normal, flip.normal); + flip.dist = -plane->dist; + plane = &flip; + } + + AddBrushPlane (plane); +} + +/* +============ +AddHullPoint + +Doesn't add if duplicated +============= +*/ +int AddHullPoint (vec3_t p, int hullnum) +{ + int i; + vec_t *c; + int x,y,z; + + for (i=0 ; i 1+ANGLEEPSILON) + continue; + plane.dist = DotProduct (planeorg, plane.normal); + TestAddPlane (&plane); + } + } + + +} + +/* +============ +ExpandBrush +============= +*/ +void ExpandBrush (int hullnum) +{ + int i, x, s; + vec3_t corner; + face_t *f; + plane_t plane, *p; + + num_hull_points = 0; + num_hull_edges = 0; + +// create all the hull points + for (f=brush_faces ; f ; f=f->next) + for (i=0 ; inumpoints ; i++) + AddHullPoint (f->pts[i], hullnum); + +// expand all of the planes + for (i=0 ; inormal[x] > 0) + corner[x] = hull_size[hullnum][1][x]; + else if (p->normal[x] < 0) + corner[x] = hull_size[hullnum][0][x]; + } + p->dist += DotProduct (corner, p->normal); + } + +// add any axis planes not contained in the brush to bevel off corners + for (x=0 ; x<3 ; x++) + for (s=-1 ; s<=1 ; s+=2) + { + // add the plane + VectorCopy (vec3_origin, plane.normal); + plane.normal[x] = s; + if (s == -1) + plane.dist = -brush_mins[x] + -hull_size[hullnum][0][x]; + else + plane.dist = brush_maxs[x] + hull_size[hullnum][1][x]; + AddBrushPlane (&plane); + } + +// add all of the edge bevels + for (f=brush_faces ; f ; f=f->next) + for (i=0 ; inumpoints ; i++) + AddHullEdge (f->pts[i], f->pts[(i+1)%f->numpoints], hullnum); +} + +//============================================================================ + + +/* +=============== +LoadBrush + +Converts a mapbrush to a bsp brush +=============== +*/ +brush_t *LoadBrush (mbrush_t *mb, int hullnum) +{ + brush_t *b; + int contents; + char *name; + mface_t *f; + +// +// check texture name for attributes +// + name = miptex[texinfo[mb->faces->texinfo].miptex]; + + if (!Q_strcasecmp(name, "clip") && hullnum == 0) + return NULL; // "clip" brushes don't show up in the draw hull + + if (name[0] == '*' && worldmodel) // entities never use water merging + { + if (!Q_strncasecmp(name+1,"lava",4)) + contents = CONTENTS_LAVA; + else if (!Q_strncasecmp(name+1,"slime",5)) + contents = CONTENTS_SLIME; + else + contents = CONTENTS_WATER; + } + else if (!Q_strncasecmp (name, "sky",3) && worldmodel && hullnum == 0) + contents = CONTENTS_SKY; + else + contents = CONTENTS_SOLID; + + if (hullnum && contents != CONTENTS_SOLID && contents != CONTENTS_SKY) + return NULL; // water brushes don't show up in clipping hulls + +// no seperate textures on clip hull + +// +// create the faces +// + brush_faces = NULL; + + numbrushfaces = 0; + for (f=mb->faces ; f ; f=f->next) + { + faces[numbrushfaces] = *f; + if (hullnum) + faces[numbrushfaces].texinfo = 0; + numbrushfaces++; + } + + CreateBrushFaces (); + + if (!brush_faces) + { + printf ("WARNING: couldn't create brush faces\n"); + return NULL; + } + + if (hullnum) + { + ExpandBrush (hullnum); + CreateBrushFaces (); + } + +// +// create the brush +// + b = AllocBrush (); + + b->contents = contents; + b->faces = brush_faces; + VectorCopy (brush_mins, b->mins); + VectorCopy (brush_maxs, b->maxs); + + return b; +} + +//============================================================================= + + +/* +============ +Brush_DrawAll + +============ +*/ +void Brush_DrawAll (brushset_t *bs) +{ + brush_t *b; + face_t *f; + + for (b=bs->brushes ; b ; b=b->next) + for (f=b->faces ; f ; f=f->next) + Draw_DrawFace (f); +} + + +/* +============ +Brush_LoadEntity +============ +*/ +brushset_t *Brush_LoadEntity (entity_t *ent, int hullnum) +{ + brush_t *b, *next, *water, *other; + mbrush_t *mbr; + int numbrushes; + brushset_t *bset; + + bset = malloc (sizeof(brushset_t)); + memset (bset, 0, sizeof(brushset_t)); + ClearBounds (bset); + + numbrushes = 0; + other = water = NULL; + + qprintf ("--- Brush_LoadEntity ---\n"); + + for (mbr = ent->brushes ; mbr ; mbr=mbr->next) + { + b = LoadBrush (mbr, hullnum); + if (!b) + continue; + + numbrushes++; + + if (b->contents != CONTENTS_SOLID) + { + b->next = water; + water = b; + } + else + { + b->next = other; + other = b; + } + + AddToBounds (bset, b->mins); + AddToBounds (bset, b->maxs); + } + +// add all of the water textures at the start + for (b=water ; b ; b=next) + { + next = b->next; + b->next = other; + other = b; + } + + bset->brushes = other; + + brushset = bset; + Brush_DrawAll (bset); + + qprintf ("%i brushes read\n",numbrushes); + + return bset; +} + + diff --git a/qutils/QBSP/BSP5.H b/qutils/QBSP/BSP5.H new file mode 100644 index 0000000..81093c1 --- /dev/null +++ b/qutils/QBSP/BSP5.H @@ -0,0 +1,297 @@ + +// bsp5.h + +#include "cmdlib.h" +#include "mathlib.h" +#include "bspfile.h" + +typedef struct +{ + vec3_t normal; + vec_t dist; + int type; +} plane_t; + + +#include "map.h" + +#define MAX_THREADS 4 + +#define ON_EPSILON 0.05 +#define BOGUS_RANGE 18000 + +// the exact bounding box of the brushes is expanded some for the headnode +// volume. is this still needed? +#define SIDESPACE 24 + +//============================================================================ + + +typedef struct +{ + int numpoints; + vec3_t points[8]; // variable sized +} winding_t; + +#define MAX_POINTS_ON_WINDING 64 + +winding_t *BaseWindingForPlane (plane_t *p); +void CheckWinding (winding_t *w); +winding_t *NewWinding (int points); +void FreeWinding (winding_t *w); +winding_t *CopyWinding (winding_t *w); +winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon); +void DivideWinding (winding_t *in, plane_t *split, winding_t **front, winding_t **back); + +//============================================================================ + +#define MAXEDGES 32 +#define MAXPOINTS 28 // don't let a base face get past this + // because it can be split more later + +typedef struct visfacet_s +{ + struct visfacet_s *next; + + int planenum; + int planeside; // which side is the front of the face + int texturenum; + int contents[2]; // 0 = front side + + struct visfacet_s *original; // face on node + int outputnumber; // only valid for original faces after + // write surfaces + int numpoints; + vec3_t pts[MAXEDGES]; // FIXME: change to use winding_t + int edges[MAXEDGES]; +} face_t; + + +typedef struct surface_s +{ + struct surface_s *next; + struct surface_s *original; // before BSP cuts it up + int planenum; + int outputplanenum; // only valid after WriteSurfacePlanes + vec3_t mins, maxs; + qboolean onnode; // true if surface has already been used + // as a splitting node + face_t *faces; // links to all the faces on either side of the surf +} surface_t; + + +// +// there is a node_t structure for every node and leaf in the bsp tree +// +#define PLANENUM_LEAF -1 + +typedef struct node_s +{ + vec3_t mins,maxs; // bounding volume, not just points inside + +// information for decision nodes + int planenum; // -1 = leaf node + int outputplanenum; // only valid after WriteNodePlanes + int firstface; // decision node only + int numfaces; // decision node only + struct node_s *children[2]; // only valid for decision nodes + face_t *faces; // decision nodes only, list for both sides + +// information for leafs + int contents; // leaf nodes (0 for decision nodes) + face_t **markfaces; // leaf nodes only, point to node faces + struct portal_s *portals; + int visleafnum; // -1 = solid + int valid; // for flood filling + int occupied; // light number in leaf for outside filling +} node_t; + +//============================================================================= + +// brush.c + +#define NUM_HULLS 2 // normal and +16 + +#define NUM_CONTENTS 2 // solid and water + +typedef struct brush_s +{ + struct brush_s *next; + vec3_t mins, maxs; + face_t *faces; + int contents; +} brush_t; + +typedef struct +{ + vec3_t mins, maxs; + brush_t *brushes; // NULL terminated list +} brushset_t; + +extern int numbrushplanes; +extern plane_t planes[MAX_MAP_PLANES]; + +brushset_t *Brush_LoadEntity (entity_t *ent, int hullnum); +int PlaneTypeForNormal (vec3_t normal); +int FindPlane (plane_t *dplane, int *side); + +//============================================================================= + +// csg4.c + +// build surfaces is also used by GatherNodeFaces +extern face_t *validfaces[MAX_MAP_PLANES]; +surface_t *BuildSurfaces (void); + +face_t *NewFaceFromFace (face_t *in); +surface_t *CSGFaces (brushset_t *bs); +void SplitFace (face_t *in, plane_t *split, face_t **front, face_t **back); + +//============================================================================= + +// solidbsp.c + +void DivideFacet (face_t *in, plane_t *split, face_t **front, face_t **back); +void CalcSurfaceInfo (surface_t *surf); +void SubdivideFace (face_t *f, face_t **prevptr); +node_t *SolidBSP (surface_t *surfhead, qboolean midsplit); + +//============================================================================= + +// merge.c + +void MergePlaneFaces (surface_t *plane); +face_t *MergeFaceToList (face_t *face, face_t *list); +face_t *FreeMergeListScraps (face_t *merged); +void MergeAll (surface_t *surfhead); + +//============================================================================= + +// surfaces.c + +extern int c_cornerverts; +extern int c_tryedges; +extern face_t *edgefaces[MAX_MAP_EDGES][2]; + +extern int firstmodeledge; +extern int firstmodelface; + +void SubdivideFaces (surface_t *surfhead); + +surface_t *GatherNodeFaces (node_t *headnode); + +void MakeFaceEdges (node_t *headnode); + +//============================================================================= + +// portals.c + +typedef struct portal_s +{ + int planenum; + node_t *nodes[2]; // [0] = front side of planenum + struct portal_s *next[2]; + winding_t *winding; +} portal_t; + +extern node_t outside_node; // portals outside the world face this + +void PortalizeWorld (node_t *headnode); +void WritePortalfile (node_t *headnode); +void FreeAllPortals (node_t *node); + +//============================================================================= + +// region.c + +void GrowNodeRegions (node_t *headnode); + +//============================================================================= + +// tjunc.c + +void tjunc (node_t *headnode); + +//============================================================================= + +// writebsp.c + +void WriteNodePlanes (node_t *headnode); +void WriteClipNodes (node_t *headnode); +void WriteDrawNodes (node_t *headnode); + +void BumpModel (int hullnum); +int FindFinalPlane (dplane_t *p); + +void BeginBSPFile (void); +void FinishBSPFile (void); + +//============================================================================= + +// draw.c + +void Draw_ClearBounds (void); +void Draw_AddToBounds (vec3_t v); +void Draw_DrawFace (face_t *f); +void Draw_ClearWindow (void); +void Draw_SetRed (void); +void Draw_SetGrey (void); +void Draw_SetBlack (void); +void DrawPoint (vec3_t v); + +void Draw_SetColor (int c); +void SetColor (int c); +void DrawPortal (portal_t *p); +void DrawLeaf (node_t *l, int color); +void DrawBrush (brush_t *b); + +void DrawWinding (winding_t *w); +void DrawTri (vec3_t p1, vec3_t p2, vec3_t p3); + +//============================================================================= + +// outside.c + +qboolean FillOutside (node_t *node); + +//============================================================================= + +extern qboolean drawflag; +extern qboolean nofill; +extern qboolean notjunc; +extern qboolean noclip; +extern qboolean verbose; + +extern int subdivide_size; + +extern int hullnum; + +extern brushset_t *brushset; + +void qprintf (char *fmt, ...); // only prints if verbose + +extern int valid; + +extern char portfilename[1024]; +extern char bspfilename[1024]; +extern char pointfilename[1024]; + +extern qboolean worldmodel; + + +// misc functions + +face_t *AllocFace (void); +void FreeFace (face_t *f); + +struct portal_s *AllocPortal (void); +void FreePortal (struct portal_s *p); + +surface_t *AllocSurface (void); +void FreeSurface (surface_t *s); + +node_t *AllocNode (void); +struct brush_s *AllocBrush (void); + +//============================================================================= + diff --git a/qutils/QBSP/CSG4.C b/qutils/QBSP/CSG4.C new file mode 100644 index 0000000..97646de --- /dev/null +++ b/qutils/QBSP/CSG4.C @@ -0,0 +1,464 @@ +// csg4.c + +#include "bsp5.h" + +/* + +NOTES +----- +Brushes that touch still need to be split at the cut point to make a tjunction + +*/ + +face_t *validfaces[MAX_MAP_PLANES]; + + +face_t *inside, *outside; +int brushfaces; +int csgfaces; +int csgmergefaces; + +void DrawList (face_t *list) +{ + for ( ; list ; list=list->next) + Draw_DrawFace (list); +} + + +/* +================== +NewFaceFromFace + +Duplicates the non point information of a face, used by SplitFace and +MergeFace. +================== +*/ +face_t *NewFaceFromFace (face_t *in) +{ + face_t *newf; + + newf = AllocFace (); + + newf->planenum = in->planenum; + newf->texturenum = in->texturenum; + newf->planeside = in->planeside; + newf->original = in->original; + newf->contents[0] = in->contents[0]; + newf->contents[1] = in->contents[1]; + + return newf; +} + + +/* +================== +SplitFace + +================== +*/ +void SplitFace (face_t *in, plane_t *split, face_t **front, face_t **back) +{ + vec_t dists[MAXEDGES+1]; + int sides[MAXEDGES+1]; + int counts[3]; + vec_t dot; + int i, j; + face_t *newf, *new2; + vec_t *p1, *p2; + vec3_t mid; + + if (in->numpoints < 0) + Error ("SplitFace: freed face"); + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->pts[i], split->normal); + dot -= split->dist; + dists[i] = dot; + if (dot > ON_EPSILON) + sides[i] = SIDE_FRONT; + else if (dot < -ON_EPSILON) + sides[i] = SIDE_BACK; + else + sides[i] = SIDE_ON; + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (!counts[0]) + { + *front = NULL; + *back = in; + return; + } + if (!counts[1]) + { + *front = in; + *back = NULL; + return; + } + + *back = newf = NewFaceFromFace (in); + *front = new2 = NewFaceFromFace (in); + +// distribute the points and generate splits + + for (i=0 ; inumpoints ; i++) + { + if (newf->numpoints > MAXEDGES || new2->numpoints > MAXEDGES) + Error ("SplitFace: numpoints > MAXEDGES"); + + p1 = in->pts[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, newf->pts[newf->numpoints]); + newf->numpoints++; + VectorCopy (p1, new2->pts[new2->numpoints]); + new2->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, new2->pts[new2->numpoints]); + new2->numpoints++; + } + else + { + VectorCopy (p1, newf->pts[newf->numpoints]); + newf->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->pts[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (split->normal[j] == 1) + mid[j] = split->dist; + else if (split->normal[j] == -1) + mid[j] = -split->dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, newf->pts[newf->numpoints]); + newf->numpoints++; + VectorCopy (mid, new2->pts[new2->numpoints]); + new2->numpoints++; + } + + if (newf->numpoints > MAXEDGES || new2->numpoints > MAXEDGES) + Error ("SplitFace: numpoints > MAXEDGES"); + +#if 0 +CheckFace (newf); +CheckFace (new2); +#endif + +// free the original face now that is is represented by the fragments + FreeFace (in); +} + +/* +================= +ClipInside + +Clips all of the faces in the inside list, possibly moving them to the +outside list or spliting it into a piece in each list. + +Faces exactly on the plane will stay inside unless overdrawn by later brush + +frontside is the side of the plane that holds the outside list +================= +*/ +void ClipInside (int splitplane, int frontside, qboolean precedence) +{ + face_t *f, *next; + face_t *frags[2]; + face_t *insidelist; + plane_t *split; + + split = &planes[splitplane]; + + insidelist = NULL; + for (f=inside ; f ; f=next) + { + next = f->next; + + if (f->planenum == splitplane) + { // exactly on, handle special + if ( frontside != f->planeside || precedence ) + { // allways clip off opposite faceing + frags[frontside] = NULL; + frags[!frontside] = f; + } + else + { // leave it on the outside + frags[frontside] = f; + frags[!frontside] = NULL; + } + } + else + { // proper split + SplitFace (f, split, &frags[0], &frags[1]); + } + + if (frags[frontside]) + { + frags[frontside]->next = outside; + outside = frags[frontside]; + } + if (frags[!frontside]) + { + frags[!frontside]->next = insidelist; + insidelist = frags[!frontside]; + } + } + + inside = insidelist; +} + + +/* +================== +SaveOutside + +Saves all of the faces in the outside list to the bsp plane list +================== +*/ +void SaveOutside (qboolean mirror) +{ + face_t *f , *next, *newf; + int i; + int planenum; + + for (f=outside ; f ; f=next) + { + next = f->next; + csgfaces++; + Draw_DrawFace (f); + planenum = f->planenum; + + if (mirror) + { + newf = NewFaceFromFace (f); + + newf->numpoints = f->numpoints; + newf->planeside = f->planeside ^ 1; // reverse side + newf->contents[0] = f->contents[1]; + newf->contents[1] = f->contents[0]; + + for (i=0 ; inumpoints ; i++) // add points backwards + { + VectorCopy (f->pts[f->numpoints-1-i], newf->pts[i]); + } + } + else + newf = NULL; + + validfaces[planenum] = MergeFaceToList(f, validfaces[planenum]); + if (newf) + validfaces[planenum] = MergeFaceToList(newf, validfaces[planenum]); + + validfaces[planenum] = FreeMergeListScraps (validfaces[planenum]); + } +} + +/* +================== +FreeInside + +Free all the faces that got clipped out +================== +*/ +void FreeInside (int contents) +{ + face_t *f, *next; + + for (f=inside ; f ; f=next) + { + next = f->next; + + if (contents != CONTENTS_SOLID) + { + f->contents[0] = contents; + f->next = outside; + outside = f; + } + else + FreeFace (f); + } +} + + +//========================================================================== + +/* +================== +BuildSurfaces + +Returns a chain of all the external surfaces with one or more visible +faces. +================== +*/ +surface_t *BuildSurfaces (void) +{ + face_t **f; + face_t *count; + int i; + surface_t *s; + surface_t *surfhead; + + surfhead = NULL; + + f = validfaces; + for (i=0 ; iplanenum = i; + s->next = surfhead; + surfhead = s; + s->faces = *f; + for (count = s->faces ; count ; count=count->next) + csgmergefaces++; + CalcSurfaceInfo (s); // bounding box and flags + } + + return surfhead; +} + +//========================================================================== + +/* +================== +CopyFacesToOutside +================== +*/ +void CopyFacesToOutside (brush_t *b) +{ + face_t *f, *newf; + + outside = NULL; + + for (f=b->faces ; f ; f=f->next) + { + brushfaces++; +#if 0 +{ + int i; + + for (i=0 ; inumpoints ; i++) + printf ("(%f,%f,%f) ",f->pts[i][0], f->pts[i][1], f->pts[i][2]); + printf ("\n"); +} +#endif + newf = AllocFace (); + *newf = *f; + newf->next = outside; + newf->contents[0] = CONTENTS_EMPTY; + newf->contents[1] = b->contents; + outside = newf; + } +} + + +/* +================== +CSGFaces + +Returns a list of surfaces containing aall of the faces +================== +*/ +surface_t *CSGFaces (brushset_t *bs) +{ + brush_t *b1, *b2; + int i; + qboolean overwrite; + face_t *f; + surface_t *surfhead; + + qprintf ("---- CSGFaces ----\n"); + + memset (validfaces, 0, sizeof(validfaces)); + + csgfaces = brushfaces = csgmergefaces = 0; + + Draw_ClearWindow (); + +// +// do the solid faces +// + for (b1=bs->brushes ; b1 ; b1 = b1->next) + { + // set outside to a copy of the brush's faces + CopyFacesToOutside (b1); + + overwrite = false; + + for (b2=bs->brushes ; b2 ; b2 = b2->next) + { + // see if b2 needs to clip a chunk out of b1 + + if (b1==b2) + { + overwrite = true; // later brushes now overwrite + continue; + } + + // check bounding box first + for (i=0 ; i<3 ; i++) + if (b1->mins[i] > b2->maxs[i] || b1->maxs[i] < b2->mins[i]) + break; + if (i<3) + continue; + + // divide faces by the planes of the new brush + + inside = outside; + outside = NULL; + + for (f=b2->faces ; f ; f=f->next) + ClipInside (f->planenum, f->planeside, overwrite); + + // these faces are continued in another brush, so get rid of them + if (b1->contents == CONTENTS_SOLID && b2->contents <= CONTENTS_WATER) + FreeInside (b2->contents); + else + FreeInside (CONTENTS_SOLID); + } + + // all of the faces left in outside are real surface faces + if (b1->contents != CONTENTS_SOLID) + SaveOutside (true); // mirror faces for inside view + else + SaveOutside (false); + } + +#if 0 + if (!csgfaces) + Error ("No faces"); +#endif + + surfhead = BuildSurfaces (); + + qprintf ("%5i brushfaces\n", brushfaces); + qprintf ("%5i csgfaces\n", csgfaces); + qprintf ("%5i mergedfaces\n", csgmergefaces); + + return surfhead; +} + + diff --git a/qutils/QBSP/MAKEFILE b/qutils/QBSP/MAKEFILE new file mode 100644 index 0000000..5e6318a --- /dev/null +++ b/qutils/QBSP/MAKEFILE @@ -0,0 +1,65 @@ + +EXES = qbsp light vis bspinfo entmap visx +NTEXES = qbsp.exe light.exe vis.exe bspinfo.exe entmap.exe visx.exe + +#============================================================================== + +EXT= .o + +all: $(EXES) + +clean: + rm *.o *.obj $(EXES) $(NTEXES) + +next: + make "CFLAGS = -g -Wall -I.." + +nextinstall: + make "CFLAGS = -O4 -g -Wall -I.. -arch i386 -arch hppa" + cp $(EXES) /LocalApps + +alpha: + make "CFLAGS = -g -I.." "LDFLAGS = -lm" + +alphainstall: + make "CFLAGS = -O4 -I.." "LDFLAGS = -lm" + cp $(EXES) /LocalApps + +nt: + nmake /nologo "CFLAGS = -nologo -Zi -DWIN32 -I.." "LDFLAGS = " "EXT = .obj" + +ntinstall: + nmake /nologo "CFLAGS = -nologo -Ox -G5 -DWIN32 -I.." "LDFLAGS = " "EXT = .obj" + cp $(NTEXES) f:\nt\id + +#============================================================================== + + +QBSPFILES = region$(EXT) map$(EXT) brush$(EXT) cmdlib$(EXT) csg4$(EXT) surfaces$(EXT) mathlib$(EXT)\ + merge$(EXT) outside$(EXT) portals$(EXT) qbsp$(EXT) solidbsp$(EXT) tjunc$(EXT)\ + writebsp$(EXT) bspfile$(EXT) nodraw$(EXT) +qbsp : $(QBSPFILES) + $(CC) $(CFLAGS) -o qbsp $(QBSPFILES) + +light : threads$(EXT) bspfile$(EXT) cmdlib$(EXT) light$(EXT) ltface$(EXT) mathlib$(EXT) trace$(EXT) entities$(EXT) + $(CC) $(CFLAGS) -o light threads$(EXT) bspfile$(EXT) cmdlib$(EXT) light$(EXT) ltface$(EXT) mathlib$(EXT) trace$(EXT) entities$(EXT) + +vis : vis$(EXT) flow$(EXT) cmdlib$(EXT) mathlib$(EXT) bspfile$(EXT) soundpvs$(EXT) + $(CC) $(CFLAGS) -o vis vis$(EXT) flow$(EXT) cmdlib$(EXT) mathlib$(EXT) bspfile$(EXT) soundpvs$(EXT) + +visx : visx$(EXT) flowx$(EXT) cmdlib$(EXT) mathlib$(EXT) bspfile$(EXT) soundpvs$(EXT) + $(CC) $(CFLAGS) -o visx visx$(EXT) flowx$(EXT) cmdlib$(EXT) mathlib$(EXT) bspfile$(EXT) soundpvs$(EXT) + +bspinfo : bspinfo$(EXT) bspfile$(EXT) cmdlib$(EXT) + $(CC) $(CFLAGS) -o bspinfo bspinfo$(EXT) bspfile$(EXT) cmdlib$(EXT) + +entmap : entmap$(EXT) cmdlib$(EXT) + $(CC) $(CFLAGS) -o entmap entmap$(EXT) cmdlib$(EXT) + + +cmdlib$(EXT) : ../cmdlib.c + $(CC) $(CFLAGS) -c -o cmdlib$(EXT) ../cmdlib.c +mathlib$(EXT) : ../mathlib.c + $(CC) $(CFLAGS) -c -o mathlib$(EXT) ../mathlib.c + + diff --git a/qutils/QBSP/MAP.C b/qutils/QBSP/MAP.C new file mode 100644 index 0000000..0aaa2f4 --- /dev/null +++ b/qutils/QBSP/MAP.C @@ -0,0 +1,579 @@ +// map.c + +#include "bsp5.h" + +int nummapbrushes; +mbrush_t mapbrushes[MAX_MAP_BRUSHES]; + +int num_entities; +entity_t entities[MAX_MAP_ENTITIES]; + +int nummiptex; +char miptex[MAX_MAP_TEXINFO][16]; + +//============================================================================ + +/* +=============== +FindMiptex + +=============== +*/ +int FindMiptex (char *name) +{ + int i; + + for (i=0 ; imiptex][0] == '*' + || !Q_strncasecmp (miptex[t->miptex], "sky",3) ) + t->flags |= TEX_SPECIAL; + + + tex = texinfo; + for (i=0 ; imiptex != tex->miptex) + continue; + if (t->flags != tex->flags) + continue; + + for (j=0 ; j<8 ; j++) + if (t->vecs[0][j] != tex->vecs[0][j]) + break; + if (j != 8) + continue; + + return i; + } + +// allocate a new texture + if (numtexinfo == MAX_MAP_TEXINFO) + Error ("numtexinfo == MAX_MAP_TEXINFO"); + texinfo[i] = *t; + numtexinfo++; + + return i; +} + + +//============================================================================ + +#define MAXTOKEN 128 + +char token[MAXTOKEN]; +qboolean unget; +char *script_p; +int scriptline; + +void StartTokenParsing (char *data) +{ + scriptline = 1; + script_p = data; + unget = false; +} + +qboolean GetToken (qboolean crossline) +{ + char *token_p; + + if (unget) // is a token allready waiting? + return true; + +// +// skip space +// +skipspace: + while (*script_p <= 32) + { + if (!*script_p) + { + if (!crossline) + Error ("Line %i is incomplete",scriptline); + return false; + } + if (*script_p++ == '\n') + { + if (!crossline) + Error ("Line %i is incomplete",scriptline); + scriptline++; + } + } + + if (script_p[0] == '/' && script_p[1] == '/') // comment field + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + while (*script_p++ != '\n') + if (!*script_p) + { + if (!crossline) + Error ("Line %i is incomplete",scriptline); + return false; + } + goto skipspace; + } + +// +// copy token +// + token_p = token; + + if (*script_p == '"') + { + script_p++; + while ( *script_p != '"' ) + { + if (!*script_p) + Error ("EOF inside quoted token"); + *token_p++ = *script_p++; + if (token_p > &token[MAXTOKEN-1]) + Error ("Token too large on line %i",scriptline); + } + script_p++; + } + else while ( *script_p > 32 ) + { + *token_p++ = *script_p++; + if (token_p > &token[MAXTOKEN-1]) + Error ("Token too large on line %i",scriptline); + } + + *token_p = 0; + + return true; +} + +void UngetToken () +{ + unget = true; +} + + +//============================================================================ + +entity_t *mapent; + +/* +================= +ParseEpair +================= +*/ +void ParseEpair (void) +{ + epair_t *e; + + e = malloc (sizeof(epair_t)); + memset (e, 0, sizeof(epair_t)); + e->next = mapent->epairs; + mapent->epairs = e; + + if (strlen(token) >= MAX_KEY-1) + Error ("ParseEpar: token too long"); + e->key = copystring(token); + GetToken (false); + if (strlen(token) >= MAX_VALUE-1) + Error ("ParseEpar: token too long"); + e->value = copystring(token); +} + +//============================================================================ + + +/* +================== +textureAxisFromPlane +================== +*/ +vec3_t baseaxis[18] = +{ +{0,0,1}, {1,0,0}, {0,-1,0}, // floor +{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling +{1,0,0}, {0,1,0}, {0,0,-1}, // west wall +{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall +{0,1,0}, {1,0,0}, {0,0,-1}, // south wall +{0,-1,0}, {1,0,0}, {0,0,-1} // north wall +}; + +void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv) +{ + int bestaxis; + float dot,best; + int i; + + best = 0; + bestaxis = 0; + + for (i=0 ; i<6 ; i++) + { + dot = DotProduct (pln->normal, baseaxis[i*3]); + if (dot > best) + { + best = dot; + bestaxis = i; + } + } + + VectorCopy (baseaxis[bestaxis*3+1], xv); + VectorCopy (baseaxis[bestaxis*3+2], yv); +} + + +//============================================================================= + + +/* +================= +ParseBrush +================= +*/ +void ParseBrush (void) +{ + mbrush_t *b; + mface_t *f, *f2; + vec3_t planepts[3]; + vec3_t t1, t2, t3; + int i,j; + texinfo_t tx; + vec_t d; + float shift[2], rotate, scale[2]; + + b = &mapbrushes[nummapbrushes]; + nummapbrushes++; + b->next = mapent->brushes; + mapent->brushes = b; + + do + { + if (!GetToken (true)) + break; + if (!strcmp (token, "}") ) + break; + + // read the three point plane definition + for (i=0 ; i<3 ; i++) + { + if (i != 0) + GetToken (true); + if (strcmp (token, "(") ) + Error ("parsing brush"); + + for (j=0 ; j<3 ; j++) + { + GetToken (false); + planepts[i][j] = atoi(token); + } + + GetToken (false); + if (strcmp (token, ")") ) + Error ("parsing brush"); + + } + + // read the texturedef + memset (&tx, 0, sizeof(tx)); + GetToken (false); + tx.miptex = FindMiptex (token); + GetToken (false); + shift[0] = atoi(token); + GetToken (false); + shift[1] = atoi(token); + GetToken (false); + rotate = atoi(token); + GetToken (false); + scale[0] = atof(token); + GetToken (false); + scale[1] = atof(token); + + // if the three points are all on a previous plane, it is a + // duplicate plane + for (f2 = b->faces ; f2 ; f2=f2->next) + { + for (i=0 ; i<3 ; i++) + { + d = DotProduct(planepts[i],f2->plane.normal) - f2->plane.dist; + if (d < -ON_EPSILON || d > ON_EPSILON) + break; + } + if (i==3) + break; + } + if (f2) + { + printf ("WARNING: brush with duplicate plane\n"); + continue; + } + + f = malloc(sizeof(mface_t)); + f->next = b->faces; + b->faces = f; + + // convert to a vector / dist plane + for (j=0 ; j<3 ; j++) + { + t1[j] = planepts[0][j] - planepts[1][j]; + t2[j] = planepts[2][j] - planepts[1][j]; + t3[j] = planepts[1][j]; + } + + CrossProduct(t1,t2, f->plane.normal); + if (VectorCompare (f->plane.normal, vec3_origin)) + { + printf ("WARNING: brush plane with no normal\n"); + b->faces = f->next; + free (f); + break; + } + VectorNormalize (f->plane.normal); + f->plane.dist = DotProduct (t3, f->plane.normal); + + // + // fake proper texture vectors from QuakeEd style + // + { + vec3_t vecs[2]; + int sv, tv; + float ang, sinv, cosv; + float ns, nt; + + TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]); + + if (!scale[0]) + scale[0] = 1; + if (!scale[1]) + scale[1] = 1; + + + // rotate axis + if (rotate == 0) + { sinv = 0 ; cosv = 1; } + else if (rotate == 90) + { sinv = 1 ; cosv = 0; } + else if (rotate == 180) + { sinv = 0 ; cosv = -1; } + else if (rotate == 270) + { sinv = -1 ; cosv = 0; } + else + { + ang = rotate / 180 * Q_PI; + sinv = sin(ang); + cosv = cos(ang); + } + + if (vecs[0][0]) + sv = 0; + else if (vecs[0][1]) + sv = 1; + else + sv = 2; + + if (vecs[1][0]) + tv = 0; + else if (vecs[1][1]) + tv = 1; + else + tv = 2; + + for (i=0 ; i<2 ; i++) + { + ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; + nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; + vecs[i][sv] = ns; + vecs[i][tv] = nt; + } + + for (i=0 ; i<2 ; i++) + for (j=0 ; j<3 ; j++) + tx.vecs[i][j] = vecs[i][j] / scale[i]; + + tx.vecs[0][3] = shift[0]; + tx.vecs[1][3] = shift[1]; + } + + // unique the texinfo + f->texinfo = FindTexinfo (&tx); + } while (1); +} + +/* +================ +ParseEntity +================ +*/ +qboolean ParseEntity (void) +{ + if (!GetToken (true)) + return false; + + if (strcmp (token, "{") ) + Error ("ParseEntity: { not found"); + + if (num_entities == MAX_MAP_ENTITIES) + Error ("num_entities == MAX_MAP_ENTITIES"); + + mapent = &entities[num_entities]; + num_entities++; + + do + { + if (!GetToken (true)) + Error ("ParseEntity: EOF without closing brace"); + if (!strcmp (token, "}") ) + break; + if (!strcmp (token, "{") ) + ParseBrush (); + else + ParseEpair (); + } while (1); + + GetVectorForKey (mapent, "origin", mapent->origin); + return true; +} + +/* +================ +LoadMapFile +================ +*/ +void LoadMapFile (char *filename) +{ + char *buf; + + LoadFile (filename, (void **)&buf); + + StartTokenParsing (buf); + + num_entities = 0; + + while (ParseEntity ()) + { + } + + free (buf); + + qprintf ("--- LoadMapFile ---\n"); + qprintf ("%s\n", filename); + qprintf ("%5i brushes\n", nummapbrushes); + qprintf ("%5i entities\n", num_entities); + qprintf ("%5i miptex\n", nummiptex); + qprintf ("%5i texinfo\n", numtexinfo); +} + +void PrintEntity (entity_t *ent) +{ + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) + printf ("%20s : %s\n", ep->key, ep->value); +} + + +char *ValueForKey (entity_t *ent, char *key) +{ + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + return ep->value; + return ""; +} + +void SetKeyValue (entity_t *ent, char *key, char *value) +{ + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + { + free (ep->value); + ep->value = copystring(value); + return; + } + ep = malloc (sizeof(*ep)); + ep->next = ent->epairs; + ent->epairs = ep; + ep->key = copystring(key); + ep->value = copystring(value); +} + +float FloatForKey (entity_t *ent, char *key) +{ + char *k; + + k = ValueForKey (ent, key); + return atof(k); +} + +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec) +{ + char *k; + double v1, v2, v3; + + k = ValueForKey (ent, key); + v1 = v2 = v3 = 0; +// scanf into doubles, then assign, so it is vec_t size independent + sscanf (k, "%lf %lf %lf", &v1, &v2, &v3); + vec[0] = v1; + vec[1] = v2; + vec[2] = v3; +} + + +void WriteEntitiesToString (void) +{ + char *buf, *end; + epair_t *ep; + char line[128]; + int i; + + buf = dentdata; + end = buf; + *end = 0; + + for (i=0 ; inext) + { + sprintf (line, "\"%s\" \"%s\"\n", ep->key, ep->value); + strcat (end, line); + end += strlen(line); + } + strcat (end,"}\n"); + end += 2; + + if (end > buf + MAX_MAP_ENTSTRING) + Error ("Entity text too long"); + } + entdatasize = end - buf + 1; +} + diff --git a/qutils/QBSP/MAP.H b/qutils/QBSP/MAP.H new file mode 100644 index 0000000..ce1224c --- /dev/null +++ b/qutils/QBSP/MAP.H @@ -0,0 +1,50 @@ + + +#define MAX_FACES 16 +typedef struct mface_s +{ + struct mface_s *next; + plane_t plane; + int texinfo; +} mface_t; + +typedef struct mbrush_s +{ + struct mbrush_s *next; + mface_t *faces; +} mbrush_t; + +typedef struct epair_s +{ + struct epair_s *next; + char *key; + char *value; +} epair_t; + +typedef struct +{ + vec3_t origin; + mbrush_t *brushes; + epair_t *epairs; +} entity_t; + +extern int nummapbrushes; +extern mbrush_t mapbrushes[MAX_MAP_BRUSHES]; + +extern int num_entities; +extern entity_t entities[MAX_MAP_ENTITIES]; + +extern int nummiptex; +extern char miptex[MAX_MAP_TEXINFO][16]; + +void LoadMapFile (char *filename); + +int FindMiptex (char *name); + +void PrintEntity (entity_t *ent); +char *ValueForKey (entity_t *ent, char *key); +void SetKeyValue (entity_t *ent, char *key, char *value); +float FloatForKey (entity_t *ent, char *key); +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec); + +void WriteEntitiesToString (void); diff --git a/qutils/QBSP/MERGE.C b/qutils/QBSP/MERGE.C new file mode 100644 index 0000000..54e3298 --- /dev/null +++ b/qutils/QBSP/MERGE.C @@ -0,0 +1,277 @@ +// merge.c + +#include "bsp5.h" + + +#define CONTINUOUS_EPSILON 0.001 + +/* +================ +CheckColinear + +================ +*/ +void CheckColinear (face_t *f) +{ + int i, j; + vec3_t v1, v2; + + for (i=0 ; inumpoints ;i++) + { +// skip the point if the vector from the previous point is the same +// as the vector to the next point + j = (i - 1 < 0) ? f->numpoints - 1 : i - 1; + VectorSubtract (f->pts[i], f->pts[j], v1); + VectorNormalize (v1); + + j = (i + 1 == f->numpoints) ? 0 : i + 1; + VectorSubtract (f->pts[j], f->pts[i], v2); + VectorNormalize (v2); + + if (VectorCompare (v1, v2)) + Error ("Colinear edge"); + } + +} + + +/* +============= +TryMerge + +If two polygons share a common edge and the edges that meet at the +common points are both inside the other polygons, merge them + +Returns NULL if the faces couldn't be merged, or the new face. +The originals will NOT be freed. +============= +*/ +face_t *TryMerge (face_t *f1, face_t *f2) +{ + vec_t *p1, *p2, *p3, *p4, *back; + face_t *newf; + int i, j, k, l; + vec3_t normal, delta, planenormal; + vec_t dot; + plane_t *plane; + qboolean keep1, keep2; + + if (f1->numpoints == -1 || f2->numpoints == -1) + return NULL; + if (f1->planeside != f2->planeside) + return NULL; + if (f1->texturenum != f2->texturenum) + return NULL; + if (f1->contents[0] != f2->contents[0]) + return NULL; + if (f1->contents[1] != f2->contents[1]) + return NULL; + +// +// find a common edge +// + p1 = p2 = NULL; // stop compiler warning + j = 0; // + + for (i=0 ; inumpoints ; i++) + { + p1 = f1->pts[i]; + p2 = f1->pts[(i+1)%f1->numpoints]; + for (j=0 ; jnumpoints ; j++) + { + p3 = f2->pts[j]; + p4 = f2->pts[(j+1)%f2->numpoints]; + for (k=0 ; k<3 ; k++) + { + if (fabs(p1[k] - p4[k]) > EQUAL_EPSILON) + break; + if (fabs(p2[k] - p3[k]) > EQUAL_EPSILON) + break; + } + if (k==3) + break; + } + if (j < f2->numpoints) + break; + } + + if (i == f1->numpoints) + return NULL; // no matching edges + +// +// check slope of connected lines +// if the slopes are colinear, the point can be removed +// + plane = &planes[f1->planenum]; + VectorCopy (plane->normal, planenormal); + if (f1->planeside) + VectorSubtract (vec3_origin, planenormal, planenormal); + + back = f1->pts[(i+f1->numpoints-1)%f1->numpoints]; + VectorSubtract (p1, back, delta); + CrossProduct (planenormal, delta, normal); + VectorNormalize (normal); + + back = f2->pts[(j+2)%f2->numpoints]; + VectorSubtract (back, p1, delta); + dot = DotProduct (delta, normal); + if (dot > CONTINUOUS_EPSILON) + return NULL; // not a convex polygon + keep1 = dot < -CONTINUOUS_EPSILON; + + back = f1->pts[(i+2)%f1->numpoints]; + VectorSubtract (back, p2, delta); + CrossProduct (planenormal, delta, normal); + VectorNormalize (normal); + + back = f2->pts[(j+f2->numpoints-1)%f2->numpoints]; + VectorSubtract (back, p2, delta); + dot = DotProduct (delta, normal); + if (dot > CONTINUOUS_EPSILON) + return NULL; // not a convex polygon + keep2 = dot < -CONTINUOUS_EPSILON; + +// +// build the new polygon +// + if (f1->numpoints + f2->numpoints > MAXEDGES) + { +// Error ("TryMerge: too many edges!"); + return NULL; + } + + newf = NewFaceFromFace (f1); + +// copy first polygon + for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints) + { + if (k==(i+1)%f1->numpoints && !keep2) + continue; + + VectorCopy (f1->pts[k], newf->pts[newf->numpoints]); + newf->numpoints++; + } + +// copy second polygon + for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints) + { + if (l==(j+1)%f2->numpoints && !keep1) + continue; + VectorCopy (f2->pts[l], newf->pts[newf->numpoints]); + newf->numpoints++; + } + + return newf; +} + + +/* +=============== +MergeFaceToList +=============== +*/ +qboolean mergedebug; +face_t *MergeFaceToList (face_t *face, face_t *list) +{ + face_t *newf, *f; + + for (f=list ; f ; f=f->next) + { +//CheckColinear (f); +if (mergedebug) +{ +Draw_ClearWindow (); +Draw_DrawFace (face); +Draw_DrawFace (f); +Draw_SetBlack (); +} + newf = TryMerge (face, f); + if (!newf) + continue; + FreeFace (face); + f->numpoints = -1; // merged out + return MergeFaceToList (newf, list); + } + +// didn't merge, so add at start + face->next = list; + return face; +} + + +/* +=============== +FreeMergeListScraps +=============== +*/ +face_t *FreeMergeListScraps (face_t *merged) +{ + face_t *head, *next; + + head = NULL; + for ( ; merged ; merged = next) + { + next = merged->next; + if (merged->numpoints == -1) + FreeFace (merged); + else + { + merged->next = head; + head = merged; + } + } + + return head; +} + + +/* +=============== +MergePlaneFaces +=============== +*/ +void MergePlaneFaces (surface_t *plane) +{ + face_t *f1, *next; + face_t *merged; + + merged = NULL; + + for (f1 = plane->faces ; f1 ; f1 = next) + { + next = f1->next; + merged = MergeFaceToList (f1, merged); + } + +// chain all of the non-empty faces to the plane + plane->faces = FreeMergeListScraps (merged); +} + + +/* +============ +MergeAll +============ +*/ +void MergeAll (surface_t *surfhead) +{ + surface_t *surf; + int mergefaces; + face_t *f; + + printf ("---- MergeAll ----\n"); + + mergefaces = 0; + for (surf = surfhead ; surf ; surf=surf->next) + { + MergePlaneFaces (surf); +Draw_ClearWindow (); + for (f=surf->faces ; f ; f=f->next) + { +Draw_DrawFace (f); + mergefaces++; + } + } + + printf ("%i mergefaces\n", mergefaces); +} diff --git a/qutils/QBSP/NODRAW.C b/qutils/QBSP/NODRAW.C new file mode 100644 index 0000000..7fd8de9 --- /dev/null +++ b/qutils/QBSP/NODRAW.C @@ -0,0 +1,54 @@ + +#include "bsp5.h" + +void Draw_ClearBounds (void) +{ +} + +void Draw_AddToBounds (vec3_t v) +{ +} + +void Draw_DrawFace (face_t *f) +{ +} + +void Draw_ClearWindow (void) +{ +} + +void Draw_SetRed (void) +{ +} + +void Draw_SetGrey (void) +{ +} + +void Draw_SetBlack (void) +{ +} + +void DrawPoint (vec3_t v) +{ +} + +void DrawLeaf (node_t *l, int color) +{ +} + +void DrawBrush (brush_t *b) +{ +} + +void DrawWinding (winding_t *w) +{ +} + +void DrawTri (vec3_t p1, vec3_t p2, vec3_t p3) +{ +} + +void DrawPortal (portal_t *portal) +{ +} diff --git a/qutils/QBSP/OUTSIDE.C b/qutils/QBSP/OUTSIDE.C new file mode 100644 index 0000000..31eb662 --- /dev/null +++ b/qutils/QBSP/OUTSIDE.C @@ -0,0 +1,252 @@ + +#include "bsp5.h" + +int outleafs; + +/* +=========== +PointInLeaf +=========== +*/ +node_t *PointInLeaf (node_t *node, vec3_t point) +{ + vec_t d; + + if (node->contents) + return node; + + d = DotProduct (planes[node->planenum].normal, point) - planes[node->planenum]. dist; + + if (d > 0) + return PointInLeaf (node->children[0], point); + + return PointInLeaf (node->children[1], point); +} + +/* +=========== +PlaceOccupant +=========== +*/ +qboolean PlaceOccupant (int num, vec3_t point, node_t *headnode) +{ + node_t *n; + + n = PointInLeaf (headnode, point); + if (n->contents == CONTENTS_SOLID) + return false; + n->occupied = num; + return true; +} + + +/* +============== +MarkLeakTrail +============== +*/ +portal_t *prevleaknode; +FILE *leakfile; +void MarkLeakTrail (portal_t *n2) +{ + int i, j; + vec3_t p1, p2, dir; + float len; + portal_t *n1; + + if (hullnum) + return; + + n1 = prevleaknode; + prevleaknode = n2; + + if (!n1) + return; + + VectorCopy (n2->winding->points[0], p1); + for (i=1 ; i< n2->winding->numpoints ; i++) + { + for (j=0 ; j<3 ; j++) + p1[j] = (p1[j] + n2->winding->points[i][j]) / 2; + } + + VectorCopy (n1->winding->points[0], p2); + for (i=1 ; i< n1->winding->numpoints ; i++) + { + for (j=0 ; j<3 ; j++) + p2[j] = (p2[j] + n1->winding->points[i][j]) / 2; + } + + VectorSubtract (p2, p1, dir); + len = VectorLength (dir); + VectorNormalize (dir); + + while (len > 2) + { + fprintf (leakfile,"%f %f %f\n", p1[0], p1[1], p1[2]); + for (i=0 ; i<3 ; i++) + p1[i] += dir[i]*2; + len -= 2; + } +} + +/* +================== +RecursiveFillOutside + +If fill is false, just check, don't fill +Returns true if an occupied leaf is reached +================== +*/ +int hit_occupied; +int backdraw; +qboolean RecursiveFillOutside (node_t *l, qboolean fill) +{ + portal_t *p; + int s; + + if (l->contents == CONTENTS_SOLID || l->contents == CONTENTS_SKY) + return false; + + if (l->valid == valid) + return false; + + if (l->occupied) + return true; + + l->valid = valid; + +// fill it and it's neighbors + if (fill) + l->contents = CONTENTS_SOLID; + outleafs++; + + for (p=l->portals ; p ; ) + { + s = (p->nodes[0] == l); + + if (RecursiveFillOutside (p->nodes[s], fill) ) + { // leaked, so stop filling + if (backdraw-- > 0) + { + MarkLeakTrail (p); + DrawLeaf (l, 2); + } + return true; + } + p = p->next[!s]; + } + + return false; +} + +/* +================== +ClearOutFaces + +================== +*/ +void ClearOutFaces (node_t *node) +{ + face_t **fp; + + if (node->planenum != -1) + { + ClearOutFaces (node->children[0]); + ClearOutFaces (node->children[1]); + return; + } + if (node->contents != CONTENTS_SOLID) + return; + + for (fp=node->markfaces ; *fp ; fp++) + { + // mark all the original faces that are removed + (*fp)->numpoints = 0; + } + node->faces = NULL; +} + + +//============================================================================= + +/* +=========== +FillOutside + +=========== +*/ +qboolean FillOutside (node_t *node) +{ + int s; + vec_t *v; + int i; + qboolean inside; + + qprintf ("----- FillOutside ----\n"); + + if (nofill) + { + printf ("skipped\n"); + return false; + } + + inside = false; + for (i=1 ; inodes[1] == &outside_node); + +// first check to see if an occupied leaf is hit + outleafs = 0; + valid++; + + prevleaknode = NULL; + + if (!hullnum) + { + leakfile = fopen (pointfilename, "w"); + if (!leakfile) + Error ("Couldn't open %s\n", pointfilename); + } + + if (RecursiveFillOutside (outside_node.portals->nodes[s], false)) + { + v = entities[hit_occupied].origin; + qprintf ("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + qprintf ("reached occupant at: (%4.0f,%4.0f,%4.0f)\n" + , v[0], v[1], v[2]); + qprintf ("no filling performed\n"); + if (!hullnum) + fclose (leakfile); + qprintf ("leak file written to %s\n", pointfilename); + qprintf ("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + return false; + } + if (!hullnum) + fclose (leakfile); + +// now go back and fill things in + valid++; + RecursiveFillOutside (outside_node.portals->nodes[s], true); + +// remove faces from filled in leafs + ClearOutFaces (node); + + qprintf ("%4i outleafs\n", outleafs); + return true; +} + + diff --git a/qutils/QBSP/PORTALS.C b/qutils/QBSP/PORTALS.C new file mode 100644 index 0000000..1286cbb --- /dev/null +++ b/qutils/QBSP/PORTALS.C @@ -0,0 +1,576 @@ + +#include "bsp5.h" + + +node_t outside_node; // portals outside the world face this + +//============================================================================= + +/* +============= +AddPortalToNodes +============= +*/ +void AddPortalToNodes (portal_t *p, node_t *front, node_t *back) +{ + if (p->nodes[0] || p->nodes[1]) + Error ("AddPortalToNode: allready included"); + + p->nodes[0] = front; + p->next[0] = front->portals; + front->portals = p; + + p->nodes[1] = back; + p->next[1] = back->portals; + back->portals = p; +} + + +/* +============= +RemovePortalFromNode +============= +*/ +void RemovePortalFromNode (portal_t *portal, node_t *l) +{ + portal_t **pp, *t; + +// remove reference to the current portal + pp = &l->portals; + while (1) + { + t = *pp; + if (!t) + Error ("RemovePortalFromNode: portal not in leaf"); + + if ( t == portal ) + break; + + if (t->nodes[0] == l) + pp = &t->next[0]; + else if (t->nodes[1] == l) + pp = &t->next[1]; + else + Error ("RemovePortalFromNode: portal not bounding leaf"); + } + + if (portal->nodes[0] == l) + { + *pp = portal->next[0]; + portal->nodes[0] = NULL; + } + else if (portal->nodes[1] == l) + { + *pp = portal->next[1]; + portal->nodes[1] = NULL; + } +} + +//============================================================================ + +void PrintPortal (portal_t *p) +{ + int i; + winding_t *w; + + w = p->winding; + for (i=0 ; inumpoints ; i++) + printf ("(%5.0f,%5.0f,%5.0f)\n",w->points[i][0] + , w->points[i][1], w->points[i][2]); +} + +/* +================ +MakeHeadnodePortals + +The created portals will face the global outside_node +================ +*/ +void MakeHeadnodePortals (node_t *node) +{ + vec3_t bounds[2]; + int i, j, n; + portal_t *p, *portals[6]; + plane_t bplanes[6], *pl; + int side; + + Draw_ClearWindow (); + +// pad with some space so there will never be null volume leafs + for (i=0 ; i<3 ; i++) + { + bounds[0][i] = brushset->mins[i] - SIDESPACE; + bounds[1][i] = brushset->maxs[i] + SIDESPACE; + } + + outside_node.contents = CONTENTS_SOLID; + outside_node.portals = NULL; + + for (i=0 ; i<3 ; i++) + for (j=0 ; j<2 ; j++) + { + n = j*3 + i; + + p = AllocPortal (); + portals[n] = p; + + pl = &bplanes[n]; + memset (pl, 0, sizeof(*pl)); + if (j) + { + pl->normal[i] = -1; + pl->dist = -bounds[j][i]; + } + else + { + pl->normal[i] = 1; + pl->dist = bounds[j][i]; + } + p->planenum = FindPlane (pl, &side); + + p->winding = BaseWindingForPlane (pl); + if (side) + AddPortalToNodes (p, &outside_node, node); + else + AddPortalToNodes (p, node, &outside_node); + } + +// clip the basewindings by all the other planes + for (i=0 ; i<6 ; i++) + { + for (j=0 ; j<6 ; j++) + { + if (j == i) + continue; + portals[i]->winding = ClipWinding (portals[i]->winding, &bplanes[j], true); + } + } +} + +//============================================================================ + +void CheckWindingInNode (winding_t *w, node_t *node) +{ + int i, j; + + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + if (w->points[i][j] < node->mins[j] - 1 + || w->points[i][j] > node->maxs[j] + 1) + { + printf ("WARNING: CheckWindingInNode: outside\n"); + return; + } + } +} + +void CheckWindingArea (winding_t *w) +{ + int i; + float total, add; + vec3_t v1, v2, cross; + + total = 0; + for (i=1 ; inumpoints ; i++) + { + VectorSubtract (w->points[i], w->points[0], v1); + VectorSubtract (w->points[i+1], w->points[0], v2); + CrossProduct (v1, v2, cross); + add = VectorLength (cross); + total += add*0.5; + } + if (total < 16) + printf ("WARNING: winding area %f\n", total); +} + + +void PlaneFromWinding (winding_t *w, plane_t *plane) +{ + vec3_t v1, v2; + +// calc plane + VectorSubtract (w->points[2], w->points[1], v1); + VectorSubtract (w->points[0], w->points[1], v2); + CrossProduct (v2, v1, plane->normal); + VectorNormalize (plane->normal); + plane->dist = DotProduct (w->points[0], plane->normal); +} + +void CheckLeafPortalConsistancy (node_t *node) +{ + int side, side2; + portal_t *p, *p2; + plane_t plane, plane2; + int i; + winding_t *w; + float dist; + + side = side2 = 0; // quiet compiler warning + + for (p = node->portals ; p ; p = p->next[side]) + { + if (p->nodes[0] == node) + side = 0; + else if (p->nodes[1] == node) + side = 1; + else + Error ("CutNodePortals_r: mislinked portal"); + CheckWindingInNode (p->winding, node); + CheckWindingArea (p->winding); + + // check that the side orders are correct + plane = planes[p->planenum]; + PlaneFromWinding (p->winding, &plane2); + + for (p2 = node->portals ; p2 ; p2 = p2->next[side2]) + { + if (p2->nodes[0] == node) + side2 = 0; + else if (p2->nodes[1] == node) + side2 = 1; + else + Error ("CutNodePortals_r: mislinked portal"); + w = p2->winding; + for (i=0 ; inumpoints ; i++) + { + dist = DotProduct (w->points[i], plane.normal) - plane.dist; + if ( (side == 0 && dist < -1) || (side == 1 && dist > 1) ) + { + printf ("WARNING: portal siding direction is wrong\n"); + return; + } + } + + } + } +} + + +/* +================ +CutNodePortals_r + +================ +*/ +void CutNodePortals_r (node_t *node) +{ + plane_t *plane, clipplane; + node_t *f, *b, *other_node; + portal_t *p, *new_portal, *next_portal; + winding_t *w, *frontwinding, *backwinding; + int side; + +// CheckLeafPortalConsistancy (node); + +// +// seperate the portals on node into it's children +// + if (node->contents) + { + return; // at a leaf, no more dividing + } + + plane = &planes[node->planenum]; + + f = node->children[0]; + b = node->children[1]; + +// +// create the new portal by taking the full plane winding for the cutting plane +// and clipping it by all of the planes from the other portals +// + new_portal = AllocPortal (); + new_portal->planenum = node->planenum; + + w = BaseWindingForPlane (&planes[node->planenum]); + side = 0; // shut up compiler warning + for (p = node->portals ; p ; p = p->next[side]) + { + clipplane = planes[p->planenum]; + if (p->nodes[0] == node) + side = 0; + else if (p->nodes[1] == node) + { + clipplane.dist = -clipplane.dist; + VectorSubtract (vec3_origin, clipplane.normal, clipplane.normal); + side = 1; + } + else + Error ("CutNodePortals_r: mislinked portal"); + + w = ClipWinding (w, &clipplane, true); + if (!w) + { + printf ("WARNING: CutNodePortals_r:new portal was clipped away\n"); + break; + } + } + + if (w) + { + // if the plane was not clipped on all sides, there was an error + new_portal->winding = w; + AddPortalToNodes (new_portal, f, b); + } + +// +// partition the portals +// + for (p = node->portals ; p ; p = next_portal) + { + if (p->nodes[0] == node) + side = 0; + else if (p->nodes[1] == node) + side = 1; + else + Error ("CutNodePortals_r: mislinked portal"); + next_portal = p->next[side]; + + other_node = p->nodes[!side]; + RemovePortalFromNode (p, p->nodes[0]); + RemovePortalFromNode (p, p->nodes[1]); + +// +// cut the portal into two portals, one on each side of the cut plane +// + DivideWinding (p->winding, plane, &frontwinding, &backwinding); + + if (!frontwinding) + { + if (side == 0) + AddPortalToNodes (p, b, other_node); + else + AddPortalToNodes (p, other_node, b); + continue; + } + if (!backwinding) + { + if (side == 0) + AddPortalToNodes (p, f, other_node); + else + AddPortalToNodes (p, other_node, f); + continue; + } + + // the winding is split + new_portal = AllocPortal (); + *new_portal = *p; + new_portal->winding = backwinding; + FreeWinding (p->winding); + p->winding = frontwinding; + + if (side == 0) + { + AddPortalToNodes (p, f, other_node); + AddPortalToNodes (new_portal, b, other_node); + } + else + { + AddPortalToNodes (p, other_node, f); + AddPortalToNodes (new_portal, other_node, b); + } + } + +DrawLeaf (f,1); +DrawLeaf (b,2); + + CutNodePortals_r (f); + CutNodePortals_r (b); + +} + + +/* +================== +PortalizeWorld + +Builds the exact polyhedrons for the nodes and leafs +================== +*/ +void PortalizeWorld (node_t *headnode) +{ + qprintf ("----- portalize ----\n"); + + MakeHeadnodePortals (headnode); + CutNodePortals_r (headnode); +} + + +/* +================== +FreeAllPortals + +================== +*/ +void FreeAllPortals (node_t *node) +{ + portal_t *p, *nextp; + + if (!node->contents) + { + FreeAllPortals (node->children[0]); + FreeAllPortals (node->children[1]); + } + + for (p=node->portals ; p ; p=nextp) + { + if (p->nodes[0] == node) + nextp = p->next[0]; + else + nextp = p->next[1]; + RemovePortalFromNode (p, p->nodes[0]); + RemovePortalFromNode (p, p->nodes[1]); + FreeWinding (p->winding); + FreePortal (p); + } +} + +/* +============================================================================== + +PORTAL FILE GENERATION + +============================================================================== +*/ + +#define PORTALFILE "PRT1" + +FILE *pf; +int num_visleafs; // leafs the player can be in +int num_visportals; + +void WriteFloat (FILE *f, vec_t v) +{ + if ( fabs(v - Q_rint(v)) < 0.001 ) + fprintf (f,"%i ",(int)Q_rint(v)); + else + fprintf (f,"%f ",v); +} + +void WritePortalFile_r (node_t *node) +{ + int i; + portal_t *p; + winding_t *w; + plane_t *pl, plane2; + + if (!node->contents) + { + WritePortalFile_r (node->children[0]); + WritePortalFile_r (node->children[1]); + return; + } + + if (node->contents == CONTENTS_SOLID) + return; + + for (p = node->portals ; p ; ) + { + w = p->winding; + if (w && p->nodes[0] == node + && p->nodes[0]->contents == p->nodes[1]->contents) + { + // write out to the file + + // sometimes planes get turned around when they are very near + // the changeover point between different axis. interpret the + // plane the same way vis will, and flip the side orders if needed + pl = &planes[p->planenum]; + PlaneFromWinding (w, &plane2); + if ( DotProduct (pl->normal, plane2.normal) < 0.99 ) + { // backwards... + fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->visleafnum, p->nodes[0]->visleafnum); + } + else + fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[0]->visleafnum, p->nodes[1]->visleafnum); + for (i=0 ; inumpoints ; i++) + { + fprintf (pf,"("); + WriteFloat (pf, w->points[i][0]); + WriteFloat (pf, w->points[i][1]); + WriteFloat (pf, w->points[i][2]); + fprintf (pf,") "); + } + fprintf (pf,"\n"); + } + + if (p->nodes[0] == node) + p = p->next[0]; + else + p = p->next[1]; + } + +} + +/* +================ +NumberLeafs_r +================ +*/ +void NumberLeafs_r (node_t *node) +{ + portal_t *p; + + if (!node->contents) + { // decision node + node->visleafnum = -99; + NumberLeafs_r (node->children[0]); + NumberLeafs_r (node->children[1]); + return; + } + + Draw_ClearWindow (); + DrawLeaf (node, 1); + + if (node->contents == CONTENTS_SOLID) + { // solid block, viewpoint never inside + node->visleafnum = -1; + return; + } + + node->visleafnum = num_visleafs++; + + for (p = node->portals ; p ; ) + { + if (p->nodes[0] == node) // only write out from first leaf + { + if (p->nodes[0]->contents == p->nodes[1]->contents) + num_visportals++; + p = p->next[0]; + } + else + p = p->next[1]; + } + +} + + +/* +================ +WritePortalfile +================ +*/ +void WritePortalfile (node_t *headnode) +{ +// set the visleafnum field in every leaf and count the total number of portals + num_visleafs = 0; + num_visportals = 0; + NumberLeafs_r (headnode); + +// write the file + printf ("writing %s\n", portfilename); + pf = fopen (portfilename, "w"); + if (!pf) + Error ("Error opening %s", portfilename); + + fprintf (pf, "%s\n", PORTALFILE); + fprintf (pf, "%i\n", num_visleafs); + fprintf (pf, "%i\n", num_visportals); + + WritePortalFile_r (headnode); + + fclose (pf); +} + + diff --git a/qutils/QBSP/QBSP.C b/qutils/QBSP/QBSP.C new file mode 100644 index 0000000..064fb3a --- /dev/null +++ b/qutils/QBSP/QBSP.C @@ -0,0 +1,1030 @@ +// bsp5.c + +#include "bsp5.h" + +// +// command line flags +// +qboolean drawflag; +qboolean nofill; +qboolean notjunc; +qboolean noclip; +qboolean onlyents; +qboolean verbose = true; +qboolean allverbose; +qboolean usehulls; + +int subdivide_size = 240; + +brushset_t *brushset; + +int valid; + +char bspfilename[1024]; +char pointfilename[1024]; +char portfilename[1024]; +char hullfilename[1024]; + +char *argv0; // changed after fork(); + +qboolean worldmodel; + +int hullnum; + +//=========================================================================== + +void qprintf (char *fmt, ...) +{ + va_list argptr; + + if (!verbose) + return; + + va_start (argptr, fmt); + vprintf (fmt,argptr); + va_end (argptr); +} + +/* +================= +BaseWindingForPlane +================= +*/ +winding_t *BaseWindingForPlane (plane_t *p) +{ + int i, x; + vec_t max, v; + vec3_t org, vright, vup; + winding_t *w; + +// find the major axis + + max = -BOGUS_RANGE; + x = -1; + for (i=0 ; i<3; i++) + { + v = fabs(p->normal[i]); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) + Error ("BaseWindingForPlane: no axis found"); + + VectorCopy (vec3_origin, vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + v = DotProduct (vup, p->normal); + VectorMA (vup, -v, p->normal, vup); + VectorNormalize (vup); + + VectorScale (p->normal, p->dist, org); + + CrossProduct (vup, p->normal, vright); + + VectorScale (vup, 8192, vup); + VectorScale (vright, 8192, vright); + +// project a really big axis aligned box onto the plane + w = NewWinding (4); + + VectorSubtract (org, vright, w->points[0]); + VectorAdd (w->points[0], vup, w->points[0]); + + VectorAdd (org, vright, w->points[1]); + VectorAdd (w->points[1], vup, w->points[1]); + + VectorAdd (org, vright, w->points[2]); + VectorSubtract (w->points[2], vup, w->points[2]); + + VectorSubtract (org, vright, w->points[3]); + VectorSubtract (w->points[3], vup, w->points[3]); + + w->numpoints = 4; + + return w; +} + + + +/* +================== +CopyWinding +================== +*/ +winding_t *CopyWinding (winding_t *w) +{ + int size; + winding_t *c; + + size = (int)((winding_t *)0)->points[w->numpoints]; + c = malloc (size); + memcpy (c, w, size); + return c; +} + + + +/* +================== +CheckWinding + +Check for possible errors +================== +*/ +void CheckWinding (winding_t *w) +{ +} + + +/* +================== +ClipWinding + +Clips the winding to the plane, returning the new winding on the positive side +Frees the input winding. +If keepon is true, an exactly on-plane winding will be saved, otherwise +it will be clipped away. +================== +*/ +winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon) +{ + vec_t dists[MAX_POINTS_ON_WINDING]; + int sides[MAX_POINTS_ON_WINDING]; + int counts[3]; + vec_t dot; + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *neww; + int maxpts; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->points[i], split->normal); + dot -= split->dist; + dists[i] = dot; + if (dot > ON_EPSILON) + sides[i] = SIDE_FRONT; + else if (dot < -ON_EPSILON) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (keepon && !counts[0] && !counts[1]) + return in; + + if (!counts[0]) + { + FreeWinding (in); + return NULL; + } + if (!counts[1]) + return in; + + maxpts = in->numpoints+4; // can't use counts[0]+2 because + // of fp grouping errors + neww = NewWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->points[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->points[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (split->normal[j] == 1) + mid[j] = split->dist; + else if (split->normal[j] == -1) + mid[j] = -split->dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (neww->numpoints > maxpts) + Error ("ClipWinding: points exceeded estimate"); + +// free the original winding + FreeWinding (in); + + return neww; +} + + +/* +================== +DivideWinding + +Divides a winding by a plane, producing one or two windings. The +original winding is not damaged or freed. If only on one side, the +returned winding will be the input winding. If on both sides, two +new windings will be created. +================== +*/ +void DivideWinding (winding_t *in, plane_t *split, winding_t **front, winding_t **back) +{ + vec_t dists[MAX_POINTS_ON_WINDING]; + int sides[MAX_POINTS_ON_WINDING]; + int counts[3]; + vec_t dot; + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *f, *b; + int maxpts; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->points[i], split->normal); + dot -= split->dist; + dists[i] = dot; + if (dot > ON_EPSILON) + sides[i] = SIDE_FRONT; + else if (dot < -ON_EPSILON) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + *front = *back = NULL; + + if (!counts[0]) + { + *back = in; + return; + } + if (!counts[1]) + { + *front = in; + return; + } + + maxpts = in->numpoints+4; // can't use counts[0]+2 because + // of fp grouping errors + + *front = f = NewWinding (maxpts); + *back = b = NewWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->points[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->points[f->numpoints]); + f->numpoints++; + VectorCopy (p1, b->points[b->numpoints]); + b->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->points[f->numpoints]); + f->numpoints++; + } + if (sides[i] == SIDE_BACK) + { + VectorCopy (p1, b->points[b->numpoints]); + b->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->points[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (split->normal[j] == 1) + mid[j] = split->dist; + else if (split->normal[j] == -1) + mid[j] = -split->dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->points[f->numpoints]); + f->numpoints++; + VectorCopy (mid, b->points[b->numpoints]); + b->numpoints++; + } + + if (f->numpoints > maxpts || b->numpoints > maxpts) + Error ("ClipWinding: points exceeded estimate"); +} + + +//=========================================================================== + +int c_activefaces, c_peakfaces; +int c_activesurfaces, c_peaksurfaces; +int c_activewindings, c_peakwindings; +int c_activeportals, c_peakportals; + +void PrintMemory (void) +{ + printf ("faces : %6i (%6i)\n", c_activefaces, c_peakfaces); + printf ("surfaces: %6i (%6i)\n", c_activesurfaces, c_peaksurfaces); + printf ("windings: %6i (%6i)\n", c_activewindings, c_peakwindings); + printf ("portals : %6i (%6i)\n", c_activeportals, c_peakportals); +} + +/* +================== +NewWinding +================== +*/ +winding_t *NewWinding (int points) +{ + winding_t *w; + int size; + + if (points > MAX_POINTS_ON_WINDING) + Error ("NewWinding: %i points", points); + + c_activewindings++; + if (c_activewindings > c_peakwindings) + c_peakwindings = c_activewindings; + + size = (int)((winding_t *)0)->points[points]; + w = malloc (size); + memset (w, 0, size); + + return w; +} + + +void FreeWinding (winding_t *w) +{ + c_activewindings--; + free (w); +} + + + +/* +=========== +AllocFace +=========== +*/ +face_t *AllocFace (void) +{ + face_t *f; + + c_activefaces++; + if (c_activefaces > c_peakfaces) + c_peakfaces = c_activefaces; + + f = malloc (sizeof(face_t)); + memset (f, 0, sizeof(face_t)); + f->planenum = -1; + + return f; +} + + +void FreeFace (face_t *f) +{ + c_activefaces--; +// memset (f,0xff,sizeof(face_t)); + free (f); +} + + +/* +=========== +AllocSurface +=========== +*/ +surface_t *AllocSurface (void) +{ + surface_t *s; + + s = malloc (sizeof(surface_t)); + memset (s, 0, sizeof(surface_t)); + + c_activesurfaces++; + if (c_activesurfaces > c_peaksurfaces) + c_peaksurfaces = c_activesurfaces; + + return s; +} + +void FreeSurface (surface_t *s) +{ + c_activesurfaces--; + free (s); +} + +/* +=========== +AllocPortal +=========== +*/ +portal_t *AllocPortal (void) +{ + portal_t *p; + + c_activeportals++; + if (c_activeportals > c_peakportals) + c_peakportals = c_activeportals; + + p = malloc (sizeof(portal_t)); + memset (p, 0, sizeof(portal_t)); + + return p; +} + +void FreePortal (portal_t *p) +{ + c_activeportals--; + free (p); +} + + +/* +=========== +AllocNode +=========== +*/ +node_t *AllocNode (void) +{ + node_t *n; + + n = malloc (sizeof(node_t)); + memset (n, 0, sizeof(node_t)); + + return n; +} + +/* +=========== +AllocBrush +=========== +*/ +brush_t *AllocBrush (void) +{ + brush_t *b; + + b = malloc (sizeof(brush_t)); + memset (b, 0, sizeof(brush_t)); + + return b; +} + +//=========================================================================== + +/* +=============== +ProcessEntity +=============== +*/ +void ProcessEntity (int entnum) +{ + entity_t *ent; + char mod[80]; + surface_t *surfs; + node_t *nodes; + brushset_t *bs; + + + ent = &entities[entnum]; + if (!ent->brushes) + return; // non-bmodel entity + + if (entnum > 0) + { + worldmodel = false; + if (entnum == 1) + qprintf ("--- Internal Entities ---\n"); + sprintf (mod, "*%i", nummodels); + if (verbose) + PrintEntity (ent); + + if (hullnum == 0) + printf ("MODEL: %s\n", mod); + SetKeyValue (ent, "model", mod); + } + else + worldmodel = true; + + +// +// take the brush_ts and clip off all overlapping and contained faces, +// leaving a perfect skin of the model with no hidden faces +// + bs = Brush_LoadEntity (ent, hullnum); + + if (!bs->brushes) + { + PrintEntity (ent); + Error ("Entity with no valid brushes"); + } + + brushset = bs; + surfs = CSGFaces (bs); + + if (hullnum != 0) + { + nodes = SolidBSP (surfs, true); + if (entnum == 0 && !nofill) // assume non-world bmodels are simple + { + PortalizeWorld (nodes); + if (FillOutside (nodes)) + { + surfs = GatherNodeFaces (nodes); + nodes = SolidBSP (surfs, false); // make a really good tree + } + FreeAllPortals (nodes); + } + WriteNodePlanes (nodes); + WriteClipNodes (nodes); + BumpModel (hullnum); + } + else + { + // + // SolidBSP generates a node tree + // + // if not the world, make a good tree first + // the world is just going to make a bad tree + // because the outside filling will force a regeneration later + nodes = SolidBSP (surfs, entnum == 0); + + // + // build all the portals in the bsp tree + // some portals are solid polygons, and some are paths to other leafs + // + if (entnum == 0 && !nofill) // assume non-world bmodels are simple + { + PortalizeWorld (nodes); + + if (FillOutside (nodes)) + { + FreeAllPortals (nodes); + + // get the remaining faces together into surfaces again + surfs = GatherNodeFaces (nodes); + + // merge polygons + MergeAll (surfs); + + // make a really good tree + nodes = SolidBSP (surfs, false); + + // make the real portals for vis tracing + PortalizeWorld (nodes); + + // save portal file for vis tracing + WritePortalfile (nodes); + + // fix tjunctions + tjunc (nodes); + } + FreeAllPortals (nodes); + } + + WriteNodePlanes (nodes); + MakeFaceEdges (nodes); + WriteDrawNodes (nodes); + } +} + +/* +================= +UpdateEntLump + +================= +*/ +void UpdateEntLump (void) +{ + int m, entnum; + char mod[80]; + + m = 1; + for (entnum = 1 ; entnum < num_entities ; entnum++) + { + if (!entities[entnum].brushes) + continue; + sprintf (mod, "*%i", m); + SetKeyValue (&entities[entnum], "model", mod); + m++; + } + + printf ("Updating entities lump...\n"); + LoadBSPFile (bspfilename); + WriteEntitiesToString(); + WriteBSPFile (bspfilename); +} + +/* +================= +WriteClipHull + +Write the clipping hull out to a text file so the parent process can get it +================= +*/ +void WriteClipHull (void) +{ + FILE *f; + int i; + dplane_t *p; + dclipnode_t *d; + + hullfilename[strlen(hullfilename)-1] = '0' + hullnum; + + qprintf ("---- WriteClipHull ----\n"); + qprintf ("Writing %s\n", hullfilename); + + f = fopen (hullfilename, "w"); + if (!f) + Error ("Couldn't open %s", hullfilename); + + fprintf (f, "%i\n", nummodels); + + for (i=0 ; iplanenum]; + // the node number is only written out for human readability + fprintf (f, "%5i : %f %f %f %f : %5i %5i\n", i, p->normal[0], p->normal[1], p->normal[2], p->dist, d->children[0], d->children[1]); + } + + fclose (f); +} + +/* +================= +ReadClipHull + +Read the files written out by the child processes +================= +*/ +void ReadClipHull (int hullnum) +{ + FILE *f; + int i, j, n; + int firstclipnode; + dplane_t p; + dclipnode_t *d; + int c1, c2; + float f1, f2, f3, f4; + int junk; + vec3_t norm; + + hullfilename[strlen(hullfilename)-1] = '0' + hullnum; + + f = fopen (hullfilename, "r"); + if (!f) + Error ("Couldn't open %s", hullfilename); + + if (fscanf (f,"%i\n", &n) != 1) + Error ("Error parsing %s", hullfilename); + + if (n != nummodels) + Error ("ReadClipHull: hull had %i models, base had %i", n, nummodels); + + for (i=0 ; ichildren[0] = c1 >= 0 ? c1 + firstclipnode : c1; + d->children[1] = c2 >= 0 ? c2 + firstclipnode : c2; + d->planenum = FindFinalPlane (&p); + } + +} + +/* +================= +CreateSingleHull + +================= +*/ +void CreateSingleHull (void) +{ + int entnum; + +// for each entity in the map file that has geometry + for (entnum = 0 ; entnum < num_entities ; entnum++) + { + ProcessEntity (entnum); + if (!allverbose) + verbose = false; // don't print rest of entities + } + + if (hullnum) + WriteClipHull (); +} + +/* +================= +CreateHulls + +================= +*/ +void CreateHulls (void) +{ +// commanded to create a single hull only + if (hullnum) + { + CreateSingleHull (); + exit (0); + } + +// commanded to use the allready existing hulls 1 and 2 + if (usehulls) + { + CreateSingleHull (); + return; + } + +// commanded to ignore the hulls altogether + if (noclip) + { + CreateSingleHull (); + return; + } + + +// create all the hulls + +#ifdef __alpha + printf ("forking hull processes...\n"); +// fork a process for each clipping hull + fflush (stdout); + if (!fork ()) + { + hullnum = 1; + verbose = false; + drawflag = false; + sprintf (argv0, "HUL%i", hullnum); + } + else if (!fork ()) + { + hullnum = 2; + verbose = false; + drawflag = false; + sprintf (argv0, "HUL%i", hullnum); + } + CreateSingleHull (); + + if (hullnum) + exit (0); + + wait (NULL); // wait for clip hull process to finish + wait (NULL); // wait for clip hull process to finish + +#else +// create the hulls sequentially + printf ("building hulls sequentially...\n"); + + hullnum = 1; + CreateSingleHull (); + + nummodels = 0; + numplanes = 0; + numclipnodes = 0; + hullnum = 2; + CreateSingleHull (); + + nummodels = 0; + numplanes = 0; + numclipnodes = 0; + hullnum = 0; + CreateSingleHull (); +#endif + +} + +/* +================= +ProcessFile + +================= +*/ +void ProcessFile (char *sourcebase, char *bspfilename1) +{ +// create filenames + strcpy (bspfilename, bspfilename1); + StripExtension (bspfilename); + strcat (bspfilename, ".bsp"); + + strcpy (hullfilename, bspfilename1); + StripExtension (hullfilename); + strcat (hullfilename, ".h0"); + + strcpy (portfilename, bspfilename1); + StripExtension (portfilename); + strcat (portfilename, ".prt"); + + strcpy (pointfilename, bspfilename1); + StripExtension (pointfilename); + strcat (pointfilename, ".pts"); + + if (!onlyents) + { + remove (bspfilename); + if (!usehulls) + { + hullfilename[strlen(hullfilename)-1] = '1'; + remove (hullfilename); + hullfilename[strlen(hullfilename)-1] = '2'; + remove (hullfilename); + } + remove (portfilename); + remove (pointfilename); + } + +// load brushes and entities + LoadMapFile (sourcebase); + if (onlyents) + { + UpdateEntLump (); + return; + } + +// init the tables to be shared by all models + BeginBSPFile (); + +// the clipping hulls will be written out to text files by forked processes + CreateHulls (); + + ReadClipHull (1); + ReadClipHull (2); + + WriteEntitiesToString(); + FinishBSPFile (); +} + + +/* +================== +main + +================== +*/ +int main (int argc, char **argv) +{ + int i; + double start, end; + char sourcename[1024]; + char destname[1024]; + +// malloc_debug (15); + +// +// check command line flags +// + for (i=1 ; i"); + + SetQdirFromPath (argv[i]); + +// +// let forked processes change name for ps status +// + argv0 = argv[0]; + + +// +// create destination name if not specified +// + strcpy (sourcename, argv[i]); + DefaultExtension (sourcename, ".map"); + + if (i != argc - 2) + { + strcpy (destname, argv[i]); + StripExtension (destname); + strcat (destname, ".bsp"); + printf ("outputfile: %s\n", destname); + } + else + strcpy (destname, argv[i+1]); + +// +// do it! +// + start = I_FloatTime (); + ProcessFile (sourcename, destname); + end = I_FloatTime (); + printf ("%5.1f seconds elapsed\n", end-start); + + return 0; +} diff --git a/qutils/QBSP/QBSP.MAK b/qutils/QBSP/QBSP.MAK new file mode 100644 index 0000000..ac0e9ae --- /dev/null +++ b/qutils/QBSP/QBSP.MAK @@ -0,0 +1,527 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=qbsp - Win32 Debug +!MESSAGE No configuration specified. Defaulting to qbsp - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "qbsp - Win32 Release" && "$(CFG)" != "qbsp - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "qbsp.mak" CFG="qbsp - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qbsp - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "qbsp - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "qbsp - Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "qbsp - 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 "" +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "$(OUTDIR)\qbsp.exe" + +CLEAN : + -@erase ".\Release\qbsp.exe" + -@erase ".\Release\mathlib.obj" + -@erase ".\Release\solidbsp.obj" + -@erase ".\Release\portals.obj" + -@erase ".\Release\surfaces.obj" + -@erase ".\Release\nodraw.obj" + -@erase ".\Release\cmdlib.obj" + -@erase ".\Release\csg4.obj" + -@erase ".\Release\brush.obj" + -@erase ".\Release\merge.obj" + -@erase ".\Release\map.obj" + -@erase ".\Release\region.obj" + -@erase ".\Release\bspfile.obj" + -@erase ".\Release\writebsp.obj" + -@erase ".\Release\outside.obj" + -@erase ".\Release\qbsp.obj" + -@erase ".\Release\tjunc.obj" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /ML /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/qbsp.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Release/ +CPP_SBRS= +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qbsp.bsc" +BSC32_SBRS= +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 /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 /nologo /subsystem:console /machine:I386 +LINK32_FLAGS=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 /incremental:no\ + /pdb:"$(OUTDIR)/qbsp.pdb" /machine:I386 /out:"$(OUTDIR)/qbsp.exe" +LINK32_OBJS= \ + ".\Release\mathlib.obj" \ + ".\Release\solidbsp.obj" \ + ".\Release\portals.obj" \ + ".\Release\surfaces.obj" \ + ".\Release\nodraw.obj" \ + ".\Release\cmdlib.obj" \ + ".\Release\csg4.obj" \ + ".\Release\brush.obj" \ + ".\Release\merge.obj" \ + ".\Release\map.obj" \ + ".\Release\region.obj" \ + ".\Release\bspfile.obj" \ + ".\Release\writebsp.obj" \ + ".\Release\outside.obj" \ + ".\Release\qbsp.obj" \ + ".\Release\tjunc.obj" + +"$(OUTDIR)\qbsp.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "qbsp - 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 Target_Dir "" +OUTDIR=.\Debug +INTDIR=.\Debug + +ALL : "$(OUTDIR)\qbsp.exe" + +CLEAN : + -@erase ".\Debug\vc40.pdb" + -@erase ".\Debug\vc40.idb" + -@erase ".\Debug\qbsp.exe" + -@erase ".\Debug\region.obj" + -@erase ".\Debug\mathlib.obj" + -@erase ".\Debug\csg4.obj" + -@erase ".\Debug\portals.obj" + -@erase ".\Debug\surfaces.obj" + -@erase ".\Debug\tjunc.obj" + -@erase ".\Debug\nodraw.obj" + -@erase ".\Debug\outside.obj" + -@erase ".\Debug\map.obj" + -@erase ".\Debug\bspfile.obj" + -@erase ".\Debug\solidbsp.obj" + -@erase ".\Debug\brush.obj" + -@erase ".\Debug\merge.obj" + -@erase ".\Debug\qbsp.obj" + -@erase ".\Debug\cmdlib.obj" + -@erase ".\Debug\writebsp.obj" + -@erase ".\Debug\qbsp.ilk" + -@erase ".\Debug\qbsp.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MLd /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/qbsp.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Debug/ +CPP_SBRS= +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qbsp.bsc" +BSC32_SBRS= +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 /subsystem:console /debug /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 /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=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 /incremental:yes\ + /pdb:"$(OUTDIR)/qbsp.pdb" /debug /machine:I386 /out:"$(OUTDIR)/qbsp.exe" +LINK32_OBJS= \ + ".\Debug\region.obj" \ + ".\Debug\mathlib.obj" \ + ".\Debug\csg4.obj" \ + ".\Debug\portals.obj" \ + ".\Debug\surfaces.obj" \ + ".\Debug\tjunc.obj" \ + ".\Debug\nodraw.obj" \ + ".\Debug\outside.obj" \ + ".\Debug\map.obj" \ + ".\Debug\bspfile.obj" \ + ".\Debug\solidbsp.obj" \ + ".\Debug\brush.obj" \ + ".\Debug\merge.obj" \ + ".\Debug\qbsp.obj" \ + ".\Debug\cmdlib.obj" \ + ".\Debug\writebsp.obj" + +"$(OUTDIR)\qbsp.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Target + +# Name "qbsp - Win32 Release" +# Name "qbsp - Win32 Debug" + +!IF "$(CFG)" == "qbsp - Win32 Release" + +!ELSEIF "$(CFG)" == "qbsp - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\writebsp.c +DEP_CPP_WRITE=\ + ".\bsp5.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + ".\map.h"\ + + +"$(INTDIR)\writebsp.obj" : $(SOURCE) $(DEP_CPP_WRITE) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\tjunc.c +DEP_CPP_TJUNC=\ + ".\bsp5.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + ".\map.h"\ + + +"$(INTDIR)\tjunc.obj" : $(SOURCE) $(DEP_CPP_TJUNC) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\surfaces.c +DEP_CPP_SURFA=\ + ".\bsp5.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + ".\map.h"\ + + +"$(INTDIR)\surfaces.obj" : $(SOURCE) $(DEP_CPP_SURFA) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\solidbsp.c +DEP_CPP_SOLID=\ + ".\bsp5.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + ".\map.h"\ + + +"$(INTDIR)\solidbsp.obj" : $(SOURCE) $(DEP_CPP_SOLID) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\region.c +DEP_CPP_REGIO=\ + ".\bsp5.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + ".\map.h"\ + + +"$(INTDIR)\region.obj" : $(SOURCE) $(DEP_CPP_REGIO) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qbsp.c +DEP_CPP_QBSP_=\ + ".\bsp5.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + ".\map.h"\ + + +"$(INTDIR)\qbsp.obj" : $(SOURCE) $(DEP_CPP_QBSP_) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\portals.c +DEP_CPP_PORTA=\ + ".\bsp5.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + ".\map.h"\ + + +"$(INTDIR)\portals.obj" : $(SOURCE) $(DEP_CPP_PORTA) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\outside.c +DEP_CPP_OUTSI=\ + ".\bsp5.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + ".\map.h"\ + + +"$(INTDIR)\outside.obj" : $(SOURCE) $(DEP_CPP_OUTSI) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\nodraw.c +DEP_CPP_NODRA=\ + ".\bsp5.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + ".\map.h"\ + + +"$(INTDIR)\nodraw.obj" : $(SOURCE) $(DEP_CPP_NODRA) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\merge.c +DEP_CPP_MERGE=\ + ".\bsp5.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + ".\map.h"\ + + +"$(INTDIR)\merge.obj" : $(SOURCE) $(DEP_CPP_MERGE) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\map.c +DEP_CPP_MAP_C=\ + ".\bsp5.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + ".\map.h"\ + + +"$(INTDIR)\map.obj" : $(SOURCE) $(DEP_CPP_MAP_C) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\csg4.c +DEP_CPP_CSG4_=\ + ".\bsp5.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + ".\map.h"\ + + +"$(INTDIR)\csg4.obj" : $(SOURCE) $(DEP_CPP_CSG4_) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\brush.c +DEP_CPP_BRUSH=\ + ".\bsp5.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + ".\map.h"\ + + +"$(INTDIR)\brush.obj" : $(SOURCE) $(DEP_CPP_BRUSH) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\bspfile.c +DEP_CPP_BSPFI=\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + + +"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\cmdlib.c +DEP_CPP_CMDLI=\ + ".\..\common\cmdlib.h"\ + {$(INCLUDE)}"\sys\TYPES.H"\ + {$(INCLUDE)}"\sys\STAT.H"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\mathlib.c +DEP_CPP_MATHL=\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + + +"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\mathlib.h + +!IF "$(CFG)" == "qbsp - Win32 Release" + +!ELSEIF "$(CFG)" == "qbsp - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\cmdlib.h + +!IF "$(CFG)" == "qbsp - Win32 Release" + +!ELSEIF "$(CFG)" == "qbsp - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\bspfile.h + +!IF "$(CFG)" == "qbsp - Win32 Release" + +!ELSEIF "$(CFG)" == "qbsp - Win32 Debug" + +!ENDIF + +# End Source File +# End Target +# End Project +################################################################################ diff --git a/qutils/QBSP/QBSP.MDP b/qutils/QBSP/QBSP.MDP new file mode 100644 index 0000000000000000000000000000000000000000..4cdb63187bc8be1c67fc80a67c63d36d7aae8b15 GIT binary patch literal 38400 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 M+MyEe3j_w>e;HwAcmMzZ literal 0 HcmV?d00001 diff --git a/qutils/QBSP/QBSP.NCB b/qutils/QBSP/QBSP.NCB new file mode 100644 index 0000000000000000000000000000000000000000..3c66e828e17648dae4b564db41c921074edfc085 GIT binary patch literal 123904 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 F{tw}e6_Wq} literal 0 HcmV?d00001 diff --git a/qutils/QBSP/REGION.C b/qutils/QBSP/REGION.C new file mode 100644 index 0000000..8f28c78 --- /dev/null +++ b/qutils/QBSP/REGION.C @@ -0,0 +1,511 @@ +// region.h + +#include "bsp5.h" + +/* + +input +----- +vertexes +edges +faces + +output +------ +smaller set of vertexes +smaller set of edges +regions +? triangulated regions +face to region mapping numbers + +*/ + +#define MAX_EDGES_IN_REGION 32 + +int firstedge; + +vec3_t region_mins, region_maxs; + +void AddPointToRegion (vec3_t p) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if (p[i] < region_mins[i]) + region_mins[i] = p[i]; + if (p[i] > region_maxs[i]) + region_maxs[i] = p[i]; + } +} + +void ClearRegionSize (void) +{ + region_mins[0] = region_mins[1] = region_mins[2] = 9999; + region_maxs[0] = region_maxs[1] = region_maxs[2] = -9999; +} + +void AddFaceToRegionSize (face_t *f) +{ + int i; + + for (i=0 ; inumpoints ; i++) + AddPointToRegion (f->pts[i]); +} + +/* +============== +CanJoinFaces +============== +*/ +qboolean CanJoinFaces (face_t *f, face_t *f2) +{ + vec3_t oldmins, oldmaxs; + int i; + + if (f2->planenum != f->planenum + || f2->planeside != f->planeside + || f2->texturenum != f->texturenum) + return false; + if (f2->outputnumber != -1) + return false; + if (f2->contents[0] != f->contents[0]) + { // does this ever happen? theyy shouldn't share. + printf ("CanJoinFaces: edge with different contents"); + return false; + } + +// check size constraints + if ( ! (texinfo[f->texturenum].flags & TEX_SPECIAL) ) + { + VectorCopy (region_mins, oldmins); + VectorCopy (region_maxs, oldmaxs); + AddFaceToRegionSize (f2); + for (i=0 ; i<3 ; i++) + { + if (region_maxs[i] - region_mins[i] > 240) + { + VectorCopy (oldmins, region_mins); + VectorCopy (oldmaxs, region_maxs); + return false; + } + } + } + else + { + if (numsurfedges - firstedge + f2->numpoints > MAX_EDGES_IN_REGION) + return false; // a huge water or sky polygon + } + +// check edge count constraints + return true; +} + + +/* +============== +RecursiveGrowRegion +============== +*/ +void RecursiveGrowRegion (dface_t *r, face_t *f) +{ + int e; + face_t *f2; + int i; + + if (f->outputnumber == numfaces) + return; + + if (f->outputnumber != -1) + Error ("RecursiveGrowRegion: region collision"); + f->outputnumber = numfaces; + +// add edges + for (i=0 ; inumpoints ; i++) + { + e = f->edges[i]; + if (!edgefaces[abs(e)][0]) + continue; // edge has allready been removed + if (e > 0) + f2 = edgefaces[e][1]; + else + f2 = edgefaces[-e][0]; + if (f2 && f2->outputnumber == numfaces) + { + edgefaces[abs(e)][0] = NULL; + edgefaces[abs(e)][1] = NULL; + continue; // allready merged + } + if (f2 && CanJoinFaces (f, f2)) + { // remove the edge and merge the faces + edgefaces[abs(e)][0] = NULL; + edgefaces[abs(e)][1] = NULL; + RecursiveGrowRegion (r, f2); + } + else + { + // emit a surfedge + if (numsurfedges == MAX_MAP_SURFEDGES) + Error ("numsurfedges == MAX_MAP_SURFEDGES"); + dsurfedges[numsurfedges] = e; + numsurfedges++; + } + } + +} + +void PrintDface (int f) +{ // for debugging + dface_t *df; + dedge_t *e; + int i, n; + + df = &dfaces[f]; + for (i=0 ; inumedges ; i++) + { + n = dsurfedges[df->firstedge+i]; + e = &dedges[abs(n)]; + if (n < 0) + printf ("%5i = %5i : %5i\n", n, e->v[1], e->v[0]); + else + printf ("%5i = %5i : %5i\n", n, e->v[0], e->v[1]); + } +} + +void FindVertexUse (int v) +{ // for debugging + int i, j, n; + dface_t *df; + dedge_t *e; + + for (i=firstmodelface ; inumedges ; j++) + { + n = dsurfedges[df->firstedge+j]; + e = &dedges[abs(n)]; + if (e->v[0] == v || e->v[1] == v) + { + printf ("on face %i\n", i); + break; + } + } + } +} + +void FindEdgeUse (int v) +{ // for debugging + int i, j, n; + dface_t *df; + + for (i=firstmodelface ; inumedges ; j++) + { + n = dsurfedges[df->firstedge+j]; + if (n == v || -n == v) + { + printf ("on face %i\n", i); + break; + } + } + } +} + +/* +================ +HealEdges + +Extends e1 so that it goes all the way to e2, and removes all references +to e2 +================ +*/ +int edgemapping[MAX_MAP_EDGES]; +void HealEdges (int e1, int e2) +{ + int i, j, n, saved; + dface_t *df; + dedge_t *ed, *ed2; + vec3_t v1, v2; + dface_t *found[2]; + int foundj[2]; + +return; + e1 = edgemapping[e1]; + e2 = edgemapping[e2]; + +// extend e1 to e2 + ed = &dedges[e1]; + ed2 = &dedges[e2]; + VectorSubtract (dvertexes[ed->v[1]].point, dvertexes[ed->v[0]].point, v1); + VectorNormalize (v1); + + if (ed->v[0] == ed2->v[0]) + ed->v[0] = ed2->v[1]; + else if (ed->v[0] == ed2->v[1]) + ed->v[0] = ed2->v[0]; + else if (ed->v[1] == ed2->v[0]) + ed->v[1] = ed2->v[1]; + else if (ed->v[1] == ed2->v[1]) + ed->v[1] = ed2->v[0]; + else + Error ("HealEdges: edges don't meet"); + + VectorSubtract (dvertexes[ed->v[1]].point, dvertexes[ed->v[0]].point, v2); + VectorNormalize (v2); + + if (!VectorCompare (v1, v2)) + Error ("HealEdges: edges not colinear"); + + edgemapping[e2] = e1; + saved = 0; + +// remove all uses of e2 + for (i=firstmodelface ; inumedges ; j++) + { + n = dsurfedges[df->firstedge+j]; + if (n == e2 || n == -e2) + { + found[saved] = df; + foundj[saved] = j; + saved++; + break; + } + } + } + + if (saved != 2) + printf ("WARNING: didn't find both faces for a saved edge\n"); + else + { + for (i=0 ; i<2 ; i++) + { // remove this edge + df = found[i]; + j = foundj[i]; + for (j++ ; jnumedges ; j++) + dsurfedges[df->firstedge+j-1] = + dsurfedges[df->firstedge+j]; + dsurfedges[df->firstedge+j-1] = 0; + df->numedges--; + } + + + edgefaces[e2][0] = edgefaces[e2][1] = NULL; + } +} + +typedef struct +{ + int numedges; + int edges[2]; +} checkpoint_t; + +checkpoint_t checkpoints[MAX_MAP_VERTS]; + +/* +============== +RemoveColinearEdges +============== +*/ +void RemoveColinearEdges (void) +{ + int i,j, v; + int c0, c1, c2, c3; + checkpoint_t *cp; + +// no edges remapped yet + for (i=0 ; inumedges<2) + cp->edges[cp->numedges] = i; + cp->numedges++; + } + } + +// if a vertex only has two edges and they are colinear, it can be removed + c0 = c1 = c2 = c3 = 0; + + for (i=0 ; inumedges) + { + case 0: + c0++; + break; + case 1: + c1++; + break; + case 2: + c2++; + HealEdges (cp->edges[0], cp->edges[1]); + break; + default: + c3++; + break; + } + } + +// qprintf ("%5i c0\n", c0); +// qprintf ("%5i c1\n", c1); +// qprintf ("%5i c2\n", c2); +// qprintf ("%5i c3+\n", c3); + qprintf ("%5i deges removed by tjunction healing\n", c2); +} + +/* +============== +CountRealNumbers +============== +*/ +void CountRealNumbers (void) +{ + int i; + int c; + + qprintf ("%5i regions\n", numfaces-firstmodelface); + + c = 0; + for (i=firstmodelface ; iplanenum == PLANENUM_LEAF) + return; + + node->firstface = numfaces; + + for (f=node->faces ; f ; f=f->next) + { +// if (f->outputnumber != -1) +// continue; // allready grown into an earlier region + + // emit a region + + if (numfaces == MAX_MAP_FACES) + Error ("MAX_MAP_FACES"); + f->outputnumber = numfaces; + r = &dfaces[numfaces]; + + r->planenum = node->outputplanenum; + r->side = f->planeside; + r->texinfo = f->texturenum; + for (i=0 ; istyles[i] = 255; + r->lightofs = -1; + + // add the face and mergable neighbors to it + +#if 0 + ClearRegionSize (); + AddFaceToRegionSize (f); + RecursiveGrowRegion (r, f); +#endif + r->firstedge = firstedge = numsurfedges; + for (i=0 ; inumpoints ; i++) + { + if (numsurfedges == MAX_MAP_SURFEDGES) + Error ("numsurfedges == MAX_MAP_SURFEDGES"); + dsurfedges[numsurfedges] = f->edges[i]; + numsurfedges++; + } + + r->numedges = numsurfedges - r->firstedge; + + numfaces++; + } + + node->numfaces = numfaces - node->firstface; + + GrowNodeRegion_r (node->children[0]); + GrowNodeRegion_r (node->children[1]); +} + + +/* +============== +GrowNodeRegions +============== +*/ +void GrowNodeRegions (node_t *headnode) +{ + qprintf ("---- GrowRegions ----\n"); + + GrowNodeRegion_r (headnode); + +//RemoveColinearEdges (); + CountRealNumbers (); +} + +/* +=============================================================================== + +Turn the faces on a plane into optimal non-convex regions +The edges may still be split later as a result of tjunctions + +typedef struct +{ + vec3_t dir; + vec3_t origin; + vec3_t p[2]; +} +for all faces + for all edges + for all edges so far + if overlap + split + + +=============================================================================== +*/ + + + + + + + + + + + + + diff --git a/qutils/QBSP/SOLIDBSP.C b/qutils/QBSP/SOLIDBSP.C new file mode 100644 index 0000000..dae404b --- /dev/null +++ b/qutils/QBSP/SOLIDBSP.C @@ -0,0 +1,754 @@ +// solidbsp.c + +#include "bsp5.h" + +int leaffaces; +int nodefaces; +int splitnodes; + +int c_solid, c_empty, c_water; + +qboolean usemidsplit; + +//============================================================================ + +/* +================== +FaceSide + +For BSP hueristic +================== +*/ +int FaceSide (face_t *in, plane_t *split) +{ + int frontcount, backcount; + vec_t dot; + int i; + vec_t *p; + + + frontcount = backcount = 0; + +// axial planes are fast + if (split->type < 3) + for (i=0, p = in->pts[0]+split->type ; inumpoints ; i++, p+=3) + { + if (*p > split->dist + ON_EPSILON) + { + if (backcount) + return SIDE_ON; + frontcount = 1; + } + else if (*p < split->dist - ON_EPSILON) + { + if (frontcount) + return SIDE_ON; + backcount = 1; + } + } + else +// sloping planes take longer + for (i=0, p = in->pts[0] ; inumpoints ; i++, p+=3) + { + dot = DotProduct (p, split->normal); + dot -= split->dist; + if (dot > ON_EPSILON) + { + if (backcount) + return SIDE_ON; + frontcount = 1; + } + else if (dot < -ON_EPSILON) + { + if (frontcount) + return SIDE_ON; + backcount = 1; + } + } + + if (!frontcount) + return SIDE_BACK; + if (!backcount) + return SIDE_FRONT; + + return SIDE_ON; +} + +/* +================== +ChooseMidPlaneFromList + +The clipping hull BSP doesn't worry about avoiding splits +================== +*/ +surface_t *ChooseMidPlaneFromList (surface_t *surfaces, vec3_t mins, vec3_t maxs) +{ + int j,l; + surface_t *p, *bestsurface; + vec_t bestvalue, value, dist; + plane_t *plane; + +// +// pick the plane that splits the least +// + bestvalue = 6*8192*8192; + bestsurface = NULL; + + for (p=surfaces ; p ; p=p->next) + { + if (p->onnode) + continue; + + plane = &planes[p->planenum]; + + // check for axis aligned surfaces + l = plane->type; + if (l > PLANE_Z) + continue; + + // + // calculate the split metric along axis l, smaller values are better + // + value = 0; + + dist = plane->dist * plane->normal[l]; + for (j=0 ; j<3 ; j++) + { + if (j == l) + { + value += (maxs[l]-dist)*(maxs[l]-dist); + value += (dist-mins[l])*(dist-mins[l]); + } + else + value += 2*(maxs[j]-mins[j])*(maxs[j]-mins[j]); + } + + if (value > bestvalue) + continue; + + // + // currently the best! + // + bestvalue = value; + bestsurface = p; + } + + if (!bestsurface) + { + for (p=surfaces ; p ; p=p->next) + if (!p->onnode) + return p; // first valid surface + Error ("ChooseMidPlaneFromList: no valid planes"); + } + + return bestsurface; +} + + + +/* +================== +ChoosePlaneFromList + +The real BSP hueristic +================== +*/ +surface_t *ChoosePlaneFromList (surface_t *surfaces, vec3_t mins, vec3_t maxs, qboolean usefloors) +{ + int j,k,l; + surface_t *p, *p2, *bestsurface; + vec_t bestvalue, bestdistribution, value, dist; + plane_t *plane; + face_t *f; + +// +// pick the plane that splits the least +// + bestvalue = 99999; + bestsurface = NULL; + bestdistribution = 9e30; + + for (p=surfaces ; p ; p=p->next) + { + if (p->onnode) + continue; + + plane = &planes[p->planenum]; + k = 0; + + if (!usefloors && plane->normal[2] == 1) + continue; + + for (p2=surfaces ; p2 ; p2=p2->next) + { + if (p2 == p) + continue; + if (p2->onnode) + continue; + + for (f=p2->faces ; f ; f=f->next) + { + if (FaceSide (f, plane) == SIDE_ON) + { + k++; + if (k >= bestvalue) + break; + } + + } + if (k > bestvalue) + break; + } + + if (k > bestvalue) + continue; + + // if equal numbers, axial planes win, then decide on spatial subdivision + + if (k < bestvalue || (k == bestvalue && plane->type < PLANE_ANYX) ) + { + // check for axis aligned surfaces + l = plane->type; + + if (l <= PLANE_Z) + { // axial aligned + // + // calculate the split metric along axis l + // + value = 0; + + for (j=0 ; j<3 ; j++) + { + if (j == l) + { + dist = plane->dist * plane->normal[l]; + value += (maxs[l]-dist)*(maxs[l]-dist); + value += (dist-mins[l])*(dist-mins[l]); + } + else + value += 2*(maxs[j]-mins[j])*(maxs[j]-mins[j]); + } + + if (value > bestdistribution && k == bestvalue) + continue; + bestdistribution = value; + } + // + // currently the best! + // + bestvalue = k; + bestsurface = p; + } + + } + + + return bestsurface; +} + + +/* +================== +SelectPartition + +Selects a surface from a linked list of surfaces to split the group on +returns NULL if the surface list can not be divided any more (a leaf) +================== +*/ +surface_t *SelectPartition (surface_t *surfaces) +{ + int i,j; + vec3_t mins, maxs; + surface_t *p, *bestsurface; + +// +// count onnode surfaces +// + i = 0; + bestsurface = NULL; + for (p=surfaces ; p ; p=p->next) + if (!p->onnode) + { + i++; + bestsurface = p; + } + + if (i==0) + return NULL; + + if (i==1) + return bestsurface; // this is a final split + +// +// calculate a bounding box of the entire surfaceset +// + for (i=0 ; i<3 ; i++) + { + mins[i] = 99999; + maxs[i] = -99999; + } + + for (p=surfaces ; p ; p=p->next) + for (j=0 ; j<3 ; j++) + { + if (p->mins[j] < mins[j]) + mins[j] = p->mins[j]; + if (p->maxs[j] > maxs[j]) + maxs[j] = p->maxs[j]; + } + + if (usemidsplit) // do fast way for clipping hull + return ChooseMidPlaneFromList (surfaces, mins, maxs); + +// do slow way to save poly splits for drawing hull +#if 0 + bestsurface = ChoosePlaneFromList (surfaces, mins, maxs, false); + if (bestsurface) + return bestsurface; +#endif + return ChoosePlaneFromList (surfaces, mins, maxs, true); +} + +//============================================================================ + +/* +================= +CalcSurfaceInfo + +Calculates the bounding box +================= +*/ +void CalcSurfaceInfo (surface_t *surf) +{ + int i,j; + face_t *f; + + if (!surf->faces) + Error ("CalcSurfaceInfo: surface without a face"); + +// +// calculate a bounding box +// + for (i=0 ; i<3 ; i++) + { + surf->mins[i] = 99999; + surf->maxs[i] = -99999; + } + + for (f=surf->faces ; f ; f=f->next) + { +if (f->contents[0] >= 0 || f->contents[1] >= 0) +Error ("Bad contents"); + for (i=0 ; inumpoints ; i++) + for (j=0 ; j<3 ; j++) + { + if (f->pts[i][j] < surf->mins[j]) + surf->mins[j] = f->pts[i][j]; + if (f->pts[i][j] > surf->maxs[j]) + surf->maxs[j] = f->pts[i][j]; + } + } +} + + + +/* +================== +DividePlane +================== +*/ +void DividePlane (surface_t *in, plane_t *split, surface_t **front, surface_t **back) +{ + face_t *facet, *next; + face_t *frontlist, *backlist; + face_t *frontfrag, *backfrag; + surface_t *news; + plane_t *inplane; + + inplane = &planes[in->planenum]; + +// parallel case is easy + if (VectorCompare (inplane->normal, split->normal)) + { +// check for exactly on node + if (inplane->dist == split->dist) + { // divide the facets to the front and back sides + news = AllocSurface (); + *news = *in; + + facet=in->faces; + in->faces = NULL; + news->faces = NULL; + in->onnode = news->onnode = true; + + for ( ; facet ; facet=next) + { + next = facet->next; + if (facet->planeside == 1) + { + facet->next = news->faces; + news->faces = facet; + } + else + { + facet->next = in->faces; + in->faces = facet; + } + } + + if (in->faces) + *front = in; + else + *front = NULL; + if (news->faces) + *back = news; + else + *back = NULL; + return; + } + + if (inplane->dist > split->dist) + { + *front = in; + *back = NULL; + } + else + { + *front = NULL; + *back = in; + } + return; + } + +// do a real split. may still end up entirely on one side +// OPTIMIZE: use bounding box for fast test + frontlist = NULL; + backlist = NULL; + + for (facet = in->faces ; facet ; facet = next) + { + next = facet->next; + SplitFace (facet, split, &frontfrag, &backfrag); + if (frontfrag) + { + frontfrag->next = frontlist; + frontlist = frontfrag; + } + if (backfrag) + { + backfrag->next = backlist; + backlist = backfrag; + } + } + +// if nothing actually got split, just move the in plane + + if (frontlist == NULL) + { + *front = NULL; + *back = in; + in->faces = backlist; + return; + } + + if (backlist == NULL) + { + *front = in; + *back = NULL; + in->faces = frontlist; + return; + } + + +// stuff got split, so allocate one new plane and reuse in + news = AllocSurface (); + *news = *in; + news->faces = backlist; + *back = news; + + in->faces = frontlist; + *front = in; + +// recalc bboxes and flags + CalcSurfaceInfo (news); + CalcSurfaceInfo (in); +} + +/* +================== +DivideNodeBounds +================== +*/ +void DivideNodeBounds (node_t *node, plane_t *split) +{ + VectorCopy (node->mins, node->children[0]->mins); + VectorCopy (node->mins, node->children[1]->mins); + VectorCopy (node->maxs, node->children[0]->maxs); + VectorCopy (node->maxs, node->children[1]->maxs); + +// OPTIMIZE: sloping cuts can give a better bbox than this... + if (split->type > 2) + return; + + node->children[0]->mins[split->type] = + node->children[1]->maxs[split->type] = split->dist; +} + +/* +================== +LinkConvexFaces + +Determines the contents of the leaf and creates the final list of +original faces that have some fragment inside this leaf +================== +*/ +void LinkConvexFaces (surface_t *planelist, node_t *leafnode) +{ + face_t *f, *next; + surface_t *surf, *pnext; + int i, count; + + leafnode->faces = NULL; + leafnode->contents = 0; + leafnode->planenum = -1; + + count = 0; + for ( surf = planelist ; surf ; surf = surf->next) + { + for (f = surf->faces ; f ; f=f->next) + { + count++; + if (!leafnode->contents) + leafnode->contents = f->contents[0]; + else if (leafnode->contents != f->contents[0]) + Error ("Mixed face contents in leafnode"); + } + } + + if (!leafnode->contents) + leafnode->contents = CONTENTS_SOLID; + + switch (leafnode->contents) + { + case CONTENTS_EMPTY: + c_empty++; + break; + case CONTENTS_SOLID: + c_solid++; + break; + case CONTENTS_WATER: + case CONTENTS_SLIME: + case CONTENTS_LAVA: + case CONTENTS_SKY: + c_water++; + break; + default: + Error ("LinkConvexFaces: bad contents number"); + } + +// +// write the list of faces, and free the originals +// + leaffaces += count; + leafnode->markfaces = malloc(sizeof(face_t *)*(count+1)); + i = 0; + for ( surf = planelist ; surf ; surf = pnext) + { + pnext = surf->next; + for (f = surf->faces ; f ; f=next) + { + next = f->next; + leafnode->markfaces[i] = f->original; + i++; + FreeFace (f); + } + FreeSurface (surf); + } + leafnode->markfaces[i] = NULL; // sentinal +} + + +/* +================== +LinkNodeFaces + +Returns a duplicated list of all faces on surface +================== +*/ +face_t *LinkNodeFaces (surface_t *surface) +{ + face_t *f, *new, **prevptr; + face_t *list; + + list = NULL; + + +// subdivide + prevptr = &surface->faces; + while (1) + { + f = *prevptr; + if (!f) + break; + SubdivideFace (f, prevptr); + f = *prevptr; + prevptr = &f->next; + } + +// copy + for (f=surface->faces ; f ; f=f->next) + { + nodefaces++; + new = AllocFace (); + *new = *f; + f->original = new; + new->next = list; + list = new; + } + + return list; +} + + +/* +================== +PartitionSurfaces +================== +*/ +void PartitionSurfaces (surface_t *surfaces, node_t *node) +{ + surface_t *split, *p, *next; + surface_t *frontlist, *backlist; + surface_t *frontfrag, *backfrag; + plane_t *splitplane; + + split = SelectPartition (surfaces); + if (!split) + { // this is a leaf node + node->planenum = PLANENUM_LEAF; + LinkConvexFaces (surfaces, node); + return; + } + + splitnodes++; + node->faces = LinkNodeFaces (split); + node->children[0] = AllocNode (); + node->children[1] = AllocNode (); + node->planenum = split->planenum; + + splitplane = &planes[split->planenum]; + + DivideNodeBounds (node, splitplane); + + +// +// multiple surfaces, so split all the polysurfaces into front and back lists +// + frontlist = NULL; + backlist = NULL; + + for (p=surfaces ; p ; p=next) + { + next = p->next; + DividePlane (p, splitplane, &frontfrag, &backfrag); + if (frontfrag && backfrag) + { + // the plane was split, which may expose oportunities to merge + // adjacent faces into a single face +// MergePlaneFaces (frontfrag); +// MergePlaneFaces (backfrag); + } + + if (frontfrag) + { + if (!frontfrag->faces) + Error ("surface with no faces"); + frontfrag->next = frontlist; + frontlist = frontfrag; + } + if (backfrag) + { + if (!backfrag->faces) + Error ("surface with no faces"); + backfrag->next = backlist; + backlist = backfrag; + } + } + + PartitionSurfaces (frontlist, node->children[0]); + PartitionSurfaces (backlist, node->children[1]); +} + +/* +================== +DrawSurface +================== +*/ +void DrawSurface (surface_t *surf) +{ + face_t *f; + + for (f=surf->faces ; f ; f=f->next) + Draw_DrawFace (f); +} + +/* +================== +DrawSurfaceList +================== +*/ +void DrawSurfaceList (surface_t *surf) +{ + Draw_ClearWindow (); + while (surf) + { + DrawSurface (surf); + surf = surf->next; + } +} + +/* +================== +SolidBSP +================== +*/ +node_t *SolidBSP (surface_t *surfhead, qboolean midsplit) +{ + int i; + node_t *headnode; + + qprintf ("----- SolidBSP -----\n"); + + headnode = AllocNode (); + usemidsplit = midsplit; + +// +// calculate a bounding box for the entire model +// + for (i=0 ; i<3 ; i++) + { + headnode->mins[i] = brushset->mins[i] - SIDESPACE; + headnode->maxs[i] = brushset->maxs[i] + SIDESPACE; + } + +// +// recursively partition everything +// + Draw_ClearWindow (); + splitnodes = 0; + leaffaces = 0; + nodefaces = 0; + c_solid = c_empty = c_water = 0; + + PartitionSurfaces (surfhead, headnode); + + qprintf ("%5i split nodes\n", splitnodes); + qprintf ("%5i solid leafs\n", c_solid); + qprintf ("%5i empty leafs\n", c_empty); + qprintf ("%5i water leafs\n", c_water); + qprintf ("%5i leaffaces\n",leaffaces); + qprintf ("%5i nodefaces\n", nodefaces); + + return headnode; +} + diff --git a/qutils/QBSP/SURFACES.C b/qutils/QBSP/SURFACES.C new file mode 100644 index 0000000..082493b --- /dev/null +++ b/qutils/QBSP/SURFACES.C @@ -0,0 +1,512 @@ +// divide.h + +#include "bsp5.h" + + +surface_t newcopy_t; + +/* +a surface has all of the faces that could be drawn on a given plane + +the outside filling stage can remove some of them so a better bsp can be generated + +*/ + +int subdivides; + + +/* +=============== +SubdivideFace + +If the face is >256 in either texture direction, carve a valid sized +piece off and insert the remainder in the next link +=============== +*/ +void SubdivideFace (face_t *f, face_t **prevptr) +{ + float mins, maxs; + vec_t v; + int axis, i; + plane_t plane; + face_t *front, *back, *next; + texinfo_t *tex; + +// special (non-surface cached) faces don't need subdivision + tex = &texinfo[f->texturenum]; + + if ( tex->flags & TEX_SPECIAL) + return; + + + for (axis = 0 ; axis < 2 ; axis++) + { + while (1) + { + mins = 9999; + maxs = -9999; + + for (i=0 ; inumpoints ; i++) + { + v = DotProduct (f->pts[i], tex->vecs[axis]); + if (v < mins) + mins = v; + if (v > maxs) + maxs = v; + } + + if (maxs - mins <= subdivide_size) + break; + + // split it + subdivides++; + + VectorCopy (tex->vecs[axis], plane.normal); + v = VectorLength (plane.normal); + VectorNormalize (plane.normal); + plane.dist = (mins + subdivide_size - 16)/v; + next = f->next; + SplitFace (f, &plane, &front, &back); + if (!front || !back) + Error ("SubdivideFace: didn't split the polygon"); + *prevptr = back; + back->next = front; + front->next = next; + f = back; + } + } +} + + +/* +================ +SubdivideFaces +================ +*/ +void SubdivideFaces (surface_t *surfhead) +{ + surface_t *surf; + face_t *f , **prevptr; + + qprintf ("--- SubdivideFaces ---\n"); + + subdivides = 0; + + for (surf = surfhead ; surf ; surf=surf->next) + { + prevptr = &surf->faces; + while (1) + { + f = *prevptr; + if (!f) + break; + SubdivideFace (f, prevptr); + f = *prevptr; + prevptr = &f->next; + } + } + + qprintf ("%i faces added by subdivision\n", subdivides); + +} + + +/* +============================================================================= + +GatherNodeFaces + +Frees the current node tree and returns a new chain of the surfaces that +have inside faces. +============================================================================= +*/ + +void GatherNodeFaces_r (node_t *node) +{ + face_t *f, *next; + + if (node->planenum != PLANENUM_LEAF) + { +// +// decision node +// + for (f=node->faces ; f ; f=next) + { + next = f->next; + if (!f->numpoints) + { // face was removed outside + FreeFace (f); + } + else + { + f->next = validfaces[f->planenum]; + validfaces[f->planenum] = f; + } + } + + GatherNodeFaces_r (node->children[0]); + GatherNodeFaces_r (node->children[1]); + + free (node); + } + else + { +// +// leaf node +// + free (node); + } +} + +/* +================ +GatherNodeFaces + +================ +*/ +surface_t *GatherNodeFaces (node_t *headnode) +{ + memset (validfaces, 0, sizeof(validfaces)); + GatherNodeFaces_r (headnode); + return BuildSurfaces (); +} + +//=========================================================================== + +typedef struct hashvert_s +{ + struct hashvert_s *next; + vec3_t point; + int num; + int numplanes; // for corner determination + int planenums[2]; + int numedges; +} hashvert_t; + +#define POINT_EPSILON 0.01 + +int c_cornerverts; + +hashvert_t hvertex[MAX_MAP_VERTS]; +hashvert_t *hvert_p; + +face_t *edgefaces[MAX_MAP_EDGES][2]; +int firstmodeledge = 1; +int firstmodelface; + +//============================================================================ + +#define NUM_HASH 4096 + +hashvert_t *hashverts[NUM_HASH]; + +static vec3_t hash_min, hash_scale; + +static void InitHash (void) +{ + vec3_t size; + vec_t volume; + vec_t scale; + int newsize[2]; + int i; + + memset (hashverts, 0, sizeof(hashverts)); + + for (i=0 ; i<3 ; i++) + { + hash_min[i] = -8000; + size[i] = 16000; + } + + volume = size[0]*size[1]; + + scale = sqrt(volume / NUM_HASH); + + newsize[0] = size[0] / scale; + newsize[1] = size[1] / scale; + + hash_scale[0] = newsize[0] / size[0]; + hash_scale[1] = newsize[1] / size[1]; + hash_scale[2] = newsize[1]; + + hvert_p = hvertex; +} + +static unsigned HashVec (vec3_t vec) +{ + unsigned h; + + h = hash_scale[0] * (vec[0] - hash_min[0]) * hash_scale[2] + + hash_scale[1] * (vec[1] - hash_min[1]); + if ( h >= NUM_HASH) + return NUM_HASH - 1; + return h; +} + + +/* +============= +GetVertex +============= +*/ +int GetVertex (vec3_t in, int planenum) +{ + int h; + int i; + hashvert_t *hv; + vec3_t vert; + + for (i=0 ; i<3 ; i++) + { + if ( fabs(in[i] - Q_rint(in[i])) < 0.001) + vert[i] = Q_rint(in[i]); + else + vert[i] = in[i]; + } + + h = HashVec (vert); + + for (hv=hashverts[h] ; hv ; hv=hv->next) + { + if ( fabs(hv->point[0]-vert[0])point[1]-vert[1])point[2]-vert[2])numedges++; + if (hv->numplanes == 3) + return hv->num; // allready known to be a corner + for (i=0 ; inumplanes ; i++) + if (hv->planenums[i] == planenum) + return hv->num; // allready know this plane + if (hv->numplanes == 2) + c_cornerverts++; + else + hv->planenums[hv->numplanes] = planenum; + hv->numplanes++; + return hv->num; + } + } + + hv = hvert_p; + hv->numedges = 1; + hv->numplanes = 1; + hv->planenums[0] = planenum; + hv->next = hashverts[h]; + hashverts[h] = hv; + VectorCopy (vert, hv->point); + hv->num = numvertexes; + if (hv->num==MAX_MAP_VERTS) + Error ("GetVertex: MAX_MAP_VERTS"); + hvert_p++; + +// emit a vertex + if (numvertexes == MAX_MAP_VERTS) + Error ("numvertexes == MAX_MAP_VERTS"); + + dvertexes[numvertexes].point[0] = vert[0]; + dvertexes[numvertexes].point[1] = vert[1]; + dvertexes[numvertexes].point[2] = vert[2]; + numvertexes++; + + return hv->num; +} + +//=========================================================================== + + +/* +================== +GetEdge + +Don't allow four way edges +================== +*/ +int c_tryedges; + +int GetEdge (vec3_t p1, vec3_t p2, face_t *f) +{ + int v1, v2; + dedge_t *edge; + int i; + + if (!f->contents[0]) + Error ("GetEdge: 0 contents"); + + c_tryedges++; + v1 = GetVertex (p1, f->planenum); + v2 = GetVertex (p2, f->planenum); + for (i=firstmodeledge ; i < numedges ; i++) + { + edge = &dedges[i]; + if (v1 == edge->v[1] && v2 == edge->v[0] + && !edgefaces[i][1] + && edgefaces[i][0]->contents[0] == f->contents[0]) + { + edgefaces[i][1] = f; + return -i; + } + } + +// emit an edge + if (numedges == MAX_MAP_EDGES) + Error ("numedges == MAX_MAP_EDGES"); + edge = &dedges[numedges]; + numedges++; + edge->v[0] = v1; + edge->v[1] = v2; + edgefaces[i][0] = f; + + return i; +} + + +/* +================== +FindFaceEdges +================== +*/ +void FindFaceEdges (face_t *face) +{ + int i; + + face->outputnumber = -1; + if (face->numpoints > MAXEDGES) + Error ("WriteFace: %i points", face->numpoints); + + for (i=0; inumpoints ; i++) + face->edges[i] = GetEdge + (face->pts[i], face->pts[(i+1)%face->numpoints], face); +} + +/* +============= +CheckVertexes +// debugging +============= +*/ +void CheckVertexes (void) +{ + int cb, c0, c1, c2, c3; + hashvert_t *hv; + + cb = c0 = c1 = c2 = c3 = 0; + for (hv=hvertex ; hv!=hvert_p ; hv++) + { + if (hv->numedges < 0 || hv->numedges & 1) + cb++; + else if (!hv->numedges) + c0++; + else if (hv->numedges == 2) + c1++; + else if (hv->numedges == 4) + c2++; + else + c3++; + } + + qprintf ("%5i bad edge points\n", cb); + qprintf ("%5i 0 edge points\n", c0); + qprintf ("%5i 2 edge points\n", c1); + qprintf ("%5i 4 edge points\n", c2); + qprintf ("%5i 6+ edge points\n", c3); +} + +/* +============= +CheckEdges +// debugging +============= +*/ +void CheckEdges (void) +{ + dedge_t *edge; + int i; + dvertex_t *d1, *d2; + face_t *f1, *f2; + int c_nonconvex; + int c_multitexture; + + c_nonconvex = c_multitexture = 0; + +// CheckVertexes (); + + for (i=1 ; i < numedges ; i++) + { + edge = &dedges[i]; + if (!edgefaces[i][1]) + { + d1 = &dvertexes[edge->v[0]]; + d2 = &dvertexes[edge->v[1]]; + qprintf ("unshared edge at: (%8.2f, %8.2f, %8.2f) (%8.2f, %8.2f, %8.2f)\n",d1->point[0], d1->point[1], d1->point[2], d2->point[0], d2->point[1], d2->point[2]); + } + else + { + f1 = edgefaces[i][0]; + f2 = edgefaces[i][1]; + if (f1->planeside != f2->planeside) + continue; + if (f1->planenum != f2->planenum) + continue; + + // on the same plane, might be discardable + if (f1->texturenum == f2->texturenum) + { + hvertex[edge->v[0]].numedges-=2; + hvertex[edge->v[1]].numedges-=2; + c_nonconvex++; + } + else + c_multitexture++; + } + } + +// qprintf ("%5i edges\n", i); +// qprintf ("%5i c_nonconvex\n", c_nonconvex); +// qprintf ("%5i c_multitexture\n", c_multitexture); + +// CheckVertexes (); +} + + +/* +================ +MakeFaceEdges_r +================ +*/ +void MakeFaceEdges_r (node_t *node) +{ + face_t *f; + + if (node->planenum == PLANENUM_LEAF) + return; + + for (f=node->faces ; f ; f=f->next) + FindFaceEdges (f); + + MakeFaceEdges_r (node->children[0]); + MakeFaceEdges_r (node->children[1]); +} + +/* +================ +MakeFaceEdges +================ +*/ +void MakeFaceEdges (node_t *headnode) +{ + qprintf ("----- MakeFaceEdges -----\n"); + + InitHash (); + c_tryedges = 0; + c_cornerverts = 0; + + MakeFaceEdges_r (headnode); + +// CheckEdges (); + + GrowNodeRegions (headnode); + + firstmodeledge = numedges; + firstmodelface = numfaces; +} + diff --git a/qutils/QBSP/TJUNC.C b/qutils/QBSP/TJUNC.C new file mode 100644 index 0000000..35d34e4 --- /dev/null +++ b/qutils/QBSP/TJUNC.C @@ -0,0 +1,506 @@ +// tjunc.c + +#include "bsp5.h" + + +typedef struct wvert_s +{ + vec_t t; + struct wvert_s *prev, *next; +} wvert_t; + +typedef struct wedge_s +{ + struct wedge_s *next; + vec3_t dir; + vec3_t origin; + wvert_t head; +} wedge_t; + +int numwedges, numwverts; +int tjuncs; +int tjuncfaces; + +#define MAXWVERTS 0x20000 +#define MAXWEDGES 0x10000 + + +wvert_t wverts[MAXWVERTS]; +wedge_t wedges[MAXWEDGES]; + + +void PrintFace (face_t *f) +{ + int i; + + for (i=0 ; inumpoints ; i++) + printf ("(%5.2f, %5.2f, %5.2f)\n", f->pts[i][0], f->pts[i][1], f->pts[i][2]); +} + +//============================================================================ + +#define NUM_HASH 1024 + +wedge_t *wedge_hash[NUM_HASH]; + +static vec3_t hash_min, hash_scale; + +static void InitHash (vec3_t mins, vec3_t maxs) +{ + vec3_t size; + vec_t volume; + vec_t scale; + int newsize[2]; + + VectorCopy (mins, hash_min); + VectorSubtract (maxs, mins, size); + memset (wedge_hash, 0, sizeof(wedge_hash)); + + volume = size[0]*size[1]; + + scale = sqrt(volume / NUM_HASH); + + newsize[0] = size[0] / scale; + newsize[1] = size[1] / scale; + + hash_scale[0] = newsize[0] / size[0]; + hash_scale[1] = newsize[1] / size[1]; + hash_scale[2] = newsize[1]; +} + +static unsigned HashVec (vec3_t vec) +{ + unsigned h; + + h = hash_scale[0] * (vec[0] - hash_min[0]) * hash_scale[2] + + hash_scale[1] * (vec[1] - hash_min[1]); + if ( h >= NUM_HASH) + return NUM_HASH - 1; + return h; +} + +//============================================================================ + +void CanonicalVector (vec3_t vec) +{ + VectorNormalize (vec); + if (vec[0] > EQUAL_EPSILON) + return; + else if (vec[0] < -EQUAL_EPSILON) + { + VectorSubtract (vec3_origin, vec, vec); + return; + } + else + vec[0] = 0; + + if (vec[1] > EQUAL_EPSILON) + return; + else if (vec[1] < -EQUAL_EPSILON) + { + VectorSubtract (vec3_origin, vec, vec); + return; + } + else + vec[1] = 0; + + if (vec[2] > EQUAL_EPSILON) + return; + else if (vec[2] < -EQUAL_EPSILON) + { + VectorSubtract (vec3_origin, vec, vec); + return; + } + else + vec[2] = 0; + Error ("CanonicalVector: degenerate"); +} + +wedge_t *FindEdge (vec3_t p1, vec3_t p2, vec_t *t1, vec_t *t2) +{ + vec3_t origin; + vec3_t dir; + wedge_t *w; + vec_t temp; + int h; + + VectorSubtract (p2, p1, dir); + CanonicalVector (dir); + + *t1 = DotProduct (p1, dir); + *t2 = DotProduct (p2, dir); + + VectorMA (p1, -*t1, dir, origin); + + if (*t1 > *t2) + { + temp = *t1; + *t1 = *t2; + *t2 = temp; + } + + h = HashVec (origin); + + for (w = wedge_hash[h] ; w ; w=w->next) + { + temp = w->origin[0] - origin[0]; + if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON) + continue; + temp = w->origin[1] - origin[1]; + if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON) + continue; + temp = w->origin[2] - origin[2]; + if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON) + continue; + + temp = w->dir[0] - dir[0]; + if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON) + continue; + temp = w->dir[1] - dir[1]; + if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON) + continue; + temp = w->dir[2] - dir[2]; + if (temp < -EQUAL_EPSILON || temp > EQUAL_EPSILON) + continue; + + return w; + } + + if (numwedges == MAXWEDGES) + Error ("FindEdge: numwedges == MAXWEDGES"); + w = &wedges[numwedges]; + numwedges++; + + w->next = wedge_hash[h]; + wedge_hash[h] = w; + + VectorCopy (origin, w->origin); + VectorCopy (dir, w->dir); + w->head.next = w->head.prev = &w->head; + w->head.t = 99999; + return w; +} + + +/* +=============== +AddVert + +=============== +*/ +#define T_EPSILON 0.01 + +void AddVert (wedge_t *w, vec_t t) +{ + wvert_t *v, *newv; + + v = w->head.next; + do + { + if (fabs(v->t - t) < T_EPSILON) + return; + if (v->t > t) + break; + v = v->next; + } while (1); + +// insert a new wvert before v + if (numwverts == MAXWVERTS) + Error ("AddVert: numwverts == MAXWVERTS"); + + newv = &wverts[numwverts]; + numwverts++; + + newv->t = t; + newv->next = v; + newv->prev = v->prev; + v->prev->next = newv; + v->prev = newv; +} + + +/* +=============== +AddEdge + +=============== +*/ +void AddEdge (vec3_t p1, vec3_t p2) +{ + wedge_t *w; + vec_t t1, t2; + + w = FindEdge(p1, p2, &t1, &t2); + AddVert (w, t1); + AddVert (w, t2); +} + +/* +=============== +AddFaceEdges + +=============== +*/ +void AddFaceEdges (face_t *f) +{ + int i, j; + + for (i=0 ; i < f->numpoints ; i++) + { + j = (i+1)%f->numpoints; + AddEdge (f->pts[i], f->pts[j]); + } +} + + +//============================================================================ + +// a specially allocated face that can hold hundreds of edges if needed +byte superfacebuf[8192]; +face_t *superface = (face_t *)superfacebuf; + +void FixFaceEdges (face_t *f); + +face_t *newlist; + +void SplitFaceForTjunc (face_t *f, face_t *original) +{ + int i; + face_t *new, *chain; + vec3_t dir, test; + vec_t v; + int firstcorner, lastcorner; + + chain = NULL; + do + { + if (f->numpoints <= MAXPOINTS) + { // the face is now small enough without more cutting + // so copy it back to the original + *original = *f; + original->original = chain; + original->next = newlist; + newlist = original; + return; + } + + tjuncfaces++; + +restart: + // find the last corner + VectorSubtract (f->pts[f->numpoints-1], f->pts[0], dir); + VectorNormalize (dir); + for (lastcorner=f->numpoints-1 ; lastcorner > 0 ; lastcorner--) + { + VectorSubtract (f->pts[lastcorner-1], f->pts[lastcorner], test); + VectorNormalize (test); + v = DotProduct (test, dir); + if (v < 0.9999 || v > 1.00001) + { + break; + } + } + + // find the first corner + VectorSubtract (f->pts[1], f->pts[0], dir); + VectorNormalize (dir); + for (firstcorner=1 ; firstcorner < f->numpoints-1 ; firstcorner++) + { + VectorSubtract (f->pts[firstcorner+1], f->pts[firstcorner], test); + VectorNormalize (test); + v = DotProduct (test, dir); + if (v < 0.9999 || v > 1.00001) + { + break; + } + } + + if (firstcorner+2 >= MAXPOINTS) + { + // rotate the point winding + VectorCopy (f->pts[0], test); + for (i=1 ; inumpoints ; i++) + { + VectorCopy (f->pts[i], f->pts[i-1]); + } + VectorCopy (test, f->pts[f->numpoints-1]); + goto restart; + } + + + // cut off as big a piece as possible, less than MAXPOINTS, and not + // past lastcorner + + new = NewFaceFromFace (f); + if (f->original) + Error ("SplitFaceForTjunc: f->original"); + + new->original = chain; + chain = new; + new->next = newlist; + newlist = new; + if (f->numpoints - firstcorner <= MAXPOINTS) + new->numpoints = firstcorner+2; + else if (lastcorner+2 < MAXPOINTS && + f->numpoints - lastcorner <= MAXPOINTS) + new->numpoints = lastcorner+2; + else + new->numpoints = MAXPOINTS; + + for (i=0 ; inumpoints ; i++) + { + VectorCopy (f->pts[i], new->pts[i]); + } + + + for (i=new->numpoints-1 ; inumpoints ; i++) + { + VectorCopy (f->pts[i], f->pts[i-(new->numpoints-2)]); + } + f->numpoints -= (new->numpoints-2); + } while (1); + +} + + +/* +=============== +FixFaceEdges + +=============== +*/ +void FixFaceEdges (face_t *f) +{ + int i, j, k; + wedge_t *w; + wvert_t *v; + vec_t t1, t2; + + *superface = *f; + +restart: + for (i=0 ; i < superface->numpoints ; i++) + { + j = (i+1)%superface->numpoints; + + w = FindEdge (superface->pts[i], superface->pts[j], &t1, &t2); + + for (v=w->head.next ; v->t < t1 + T_EPSILON ; v = v->next) + { + } + + if (v->t < t2-T_EPSILON) + { + tjuncs++; + // insert a new vertex here + for (k = superface->numpoints ; k> j ; k--) + { + VectorCopy (superface->pts[k-1], superface->pts[k]); + } + VectorMA (w->origin, v->t, w->dir, superface->pts[j]); + superface->numpoints++; + goto restart; + } + } + + + if (superface->numpoints <= MAXPOINTS) + { + *f = *superface; + f->next = newlist; + newlist = f; + return; + } + +// the face needs to be split into multiple faces because of too many edges + + SplitFaceForTjunc (superface, f); + +} + + +//============================================================================ + +void tjunc_find_r (node_t *node) +{ + face_t *f; + + if (node->planenum == PLANENUM_LEAF) + return; + + for (f=node->faces ; f ; f=f->next) + AddFaceEdges (f); + + tjunc_find_r (node->children[0]); + tjunc_find_r (node->children[1]); +} + +void tjunc_fix_r (node_t *node) +{ + face_t *f, *next; + + if (node->planenum == PLANENUM_LEAF) + return; + + newlist = NULL; + + for (f=node->faces ; f ; f=next) + { + next = f->next; + FixFaceEdges (f); + } + + node->faces = newlist; + + tjunc_fix_r (node->children[0]); + tjunc_fix_r (node->children[1]); +} + +/* +=========== +tjunc + +=========== +*/ +void tjunc (node_t *headnode) +{ + vec3_t maxs, mins; + int i; + + qprintf ("---- tjunc ----\n"); + + if (notjunc) + return; + +// +// identify all points on common edges +// + +// origin points won't allways be inside the map, so extend the hash area + for (i=0 ; i<3 ; i++) + { + if ( fabs(brushset->maxs[i]) > fabs(brushset->mins[i]) ) + maxs[i] = fabs(brushset->maxs[i]); + else + maxs[i] = fabs(brushset->mins[i]); + } + VectorSubtract (vec3_origin, maxs, mins); + + InitHash (mins, maxs); + + numwedges = numwverts = 0; + + tjunc_find_r (headnode); + + qprintf ("%i world edges %i edge points\n", numwedges, numwverts); + +// +// add extra vertexes on edges where needed +// + tjuncs = tjuncfaces = 0; + + tjunc_fix_r (headnode); + + qprintf ("%i edges added by tjunctions\n", tjuncs); + qprintf ("%i faces added by tjunctions\n", tjuncfaces); +} diff --git a/qutils/QBSP/WRITEBSP.C b/qutils/QBSP/WRITEBSP.C new file mode 100644 index 0000000..0d06232 --- /dev/null +++ b/qutils/QBSP/WRITEBSP.C @@ -0,0 +1,523 @@ + +#include "bsp5.h" + + +int headclipnode; +int firstface; + +//=========================================================================== + +/* +================== +FindFinalPlane + +Used to find plane index numbers for clip nodes read from child processes +================== +*/ +int FindFinalPlane (dplane_t *p) +{ + int i; + dplane_t *dplane; + + for (i=0, dplane = dplanes ; itype != dplane->type) + continue; + if (p->dist != dplane->dist) + continue; + if (p->normal[0] != dplane->normal[0]) + continue; + if (p->normal[1] != dplane->normal[1]) + continue; + if (p->normal[2] != dplane->normal[2]) + continue; + return i; + } + +// +// new plane +// + if (numplanes == MAX_MAP_PLANES) + Error ("numplanes == MAX_MAP_PLANES"); + dplane = &dplanes[numplanes]; + *dplane = *p; + numplanes++; + + return numplanes - 1; +} + + + +int planemapping[MAX_MAP_PLANES]; + +void WriteNodePlanes_r (node_t *node) +{ + plane_t *plane; + dplane_t *dplane; + + if (node->planenum == -1) + return; + if (planemapping[node->planenum] == -1) + { // a new plane + planemapping[node->planenum] = numplanes; + + if (numplanes == MAX_MAP_PLANES) + Error ("numplanes == MAX_MAP_PLANES"); + plane = &planes[node->planenum]; + dplane = &dplanes[numplanes]; + dplane->normal[0] = plane->normal[0]; + dplane->normal[1] = plane->normal[1]; + dplane->normal[2] = plane->normal[2]; + dplane->dist = plane->dist; + dplane->type = plane->type; + + numplanes++; + } + + node->outputplanenum = planemapping[node->planenum]; + + WriteNodePlanes_r (node->children[0]); + WriteNodePlanes_r (node->children[1]); +} + +/* +================== +WriteNodePlanes + +================== +*/ +void WriteNodePlanes (node_t *nodes) +{ + memset (planemapping,-1, sizeof(planemapping)); + WriteNodePlanes_r (nodes); +} + +//=========================================================================== + +/* +================== +WriteClipNodes_r + +================== +*/ +int WriteClipNodes_r (node_t *node) +{ + int i, c; + dclipnode_t *cn; + int num; + +// FIXME: free more stuff? + if (node->planenum == -1) + { + num = node->contents; + free (node); + return num; + } + +// emit a clipnode + c = numclipnodes; + cn = &dclipnodes[numclipnodes]; + numclipnodes++; + cn->planenum = node->outputplanenum; + for (i=0 ; i<2 ; i++) + cn->children[i] = WriteClipNodes_r(node->children[i]); + + free (node); + return c; +} + +/* +================== +WriteClipNodes + +Called after the clipping hull is completed. Generates a disk format +representation and frees the original memory. +================== +*/ +void WriteClipNodes (node_t *nodes) +{ + headclipnode = numclipnodes; + WriteClipNodes_r (nodes); +} + +//=========================================================================== + +/* +================== +WriteLeaf +================== +*/ +void WriteLeaf (node_t *node) +{ + face_t **fp, *f; + dleaf_t *leaf_p; + +// emit a leaf + leaf_p = &dleafs[numleafs]; + numleafs++; + + leaf_p->contents = node->contents; + +// +// write bounding box info +// + VectorCopy (node->mins, leaf_p->mins); + VectorCopy (node->maxs, leaf_p->maxs); + + leaf_p->visofs = -1; // no vis info yet + +// +// write the marksurfaces +// + leaf_p->firstmarksurface = nummarksurfaces; + + for (fp=node->markfaces ; *fp ; fp++) + { + // emit a marksurface + if (nummarksurfaces == MAX_MAP_MARKSURFACES) + Error ("nummarksurfaces == MAX_MAP_MARKSURFACES"); + f = *fp; + do + { + dmarksurfaces[nummarksurfaces] = f->outputnumber; + nummarksurfaces++; + f=f->original; // grab tjunction split faces + } while (f); + } + + leaf_p->nummarksurfaces = nummarksurfaces - leaf_p->firstmarksurface; +} + + +/* +================== +WriteDrawNodes_r +================== +*/ +void WriteDrawNodes_r (node_t *node) +{ + dnode_t *n; + int i; + +// emit a node + if (numnodes == MAX_MAP_NODES) + Error ("numnodes == MAX_MAP_NODES"); + n = &dnodes[numnodes]; + numnodes++; + + VectorCopy (node->mins, n->mins); + VectorCopy (node->maxs, n->maxs); + + n->planenum = node->outputplanenum; + n->firstface = node->firstface; + n->numfaces = node->numfaces; + +// +// recursively output the other nodes +// + + for (i=0 ; i<2 ; i++) + { + if (node->children[i]->planenum == -1) + { + if (node->children[i]->contents == CONTENTS_SOLID) + n->children[i] = -1; + else + { + n->children[i] = -(numleafs + 1); + WriteLeaf (node->children[i]); + } + } + else + { + n->children[i] = numnodes; + WriteDrawNodes_r (node->children[i]); + } + } +} + +/* +================== +WriteDrawNodes +================== +*/ +void WriteDrawNodes (node_t *headnode) +{ + int i; + int start; + dmodel_t *bm; + +#if 0 + if (headnode->contents < 0) + Error ("FinishBSPModel: empty model"); +#endif + +// emit a model + if (nummodels == MAX_MAP_MODELS) + Error ("nummodels == MAX_MAP_MODELS"); + bm = &dmodels[nummodels]; + nummodels++; + + bm->headnode[0] = numnodes; + bm->firstface = firstface; + bm->numfaces = numfaces - firstface; + firstface = numfaces; + + start = numleafs; + + if (headnode->contents < 0) + WriteLeaf (headnode); + else + WriteDrawNodes_r (headnode); + bm->visleafs = numleafs - start; + + for (i=0 ; i<3 ; i++) + { + bm->mins[i] = headnode->mins[i] + SIDESPACE + 1; // remove the padding + bm->maxs[i] = headnode->maxs[i] - SIDESPACE - 1; + } +// FIXME: are all the children decendant of padded nodes? +} + + +/* +================== +BumpModel + +Used by the clipping hull processes that only need to store headclipnode +================== +*/ +void BumpModel (int hullnum) +{ + dmodel_t *bm; + +// emit a model + if (nummodels == MAX_MAP_MODELS) + Error ("nummodels == MAX_MAP_MODELS"); + bm = &dmodels[nummodels]; + nummodels++; + + bm->headnode[hullnum] = headclipnode; +} + +//============================================================================= + +typedef struct +{ + char identification[4]; // should be WAD2 + int numlumps; + int infotableofs; +} wadinfo_t; + + +typedef struct +{ + int filepos; + int disksize; + int size; // uncompressed + char type; + char compression; + char pad1, pad2; + char name[16]; // must be null terminated +} lumpinfo_t; + +FILE *texfile; +wadinfo_t wadinfo; +lumpinfo_t *lumpinfo; + +void CleanupName (char *in, char *out) +{ + int i; + + for (i=0 ; i< 16 ; i++ ) + { + if (!in[i]) + break; + + out[i] = toupper(in[i]); + } + + for ( ; i< 16 ; i++ ) + out[i] = 0; +} + + +/* +================= +TEX_InitFromWad +================= +*/ +void TEX_InitFromWad (char *path) +{ + int i; + + texfile = SafeOpenRead (path); + SafeRead (texfile, &wadinfo, sizeof(wadinfo)); + if (strncmp (wadinfo.identification, "WAD2", 4)) + Error ("TEX_InitFromWad: %s isn't a wadfile",path); + wadinfo.numlumps = LittleLong(wadinfo.numlumps); + wadinfo.infotableofs = LittleLong(wadinfo.infotableofs); + fseek (texfile, wadinfo.infotableofs, SEEK_SET); + lumpinfo = malloc(wadinfo.numlumps*sizeof(lumpinfo_t)); + SafeRead (texfile, lumpinfo, wadinfo.numlumps*sizeof(lumpinfo_t)); + + for (i=0 ; idataofs[nummiptex]; + l->nummiptex = nummiptex; + for (i=0 ; idataofs[i] = data - (byte *)l; + len = LoadLump (miptex[i], data); + if (data + len - dtexdata >= MAX_MAP_MIPTEX) + Error ("Textures exceeded MAX_MAP_MIPTEX"); + if (!len) + l->dataofs[i] = -1; // didn't find the texture + data += len; + } + + texdatasize = data - dtexdata; +} + +//=========================================================================== + + +/* +================== +BeginBSPFile +================== +*/ +void BeginBSPFile (void) +{ +// edge 0 is not used, because 0 can't be negated + numedges = 1; + +// leaf 0 is common solid with no faces + numleafs = 1; + dleafs[0].contents = CONTENTS_SOLID; + + firstface = 0; +} + + +/* +================== +FinishBSPFile +================== +*/ +void FinishBSPFile (void) +{ + printf ("--- FinishBSPFile ---\n"); + printf ("WriteBSPFile: %s\n", bspfilename); + + WriteMiptex (); + + PrintBSPFileSizes (); + WriteBSPFile (bspfilename); +} + diff --git a/qutils/QCC/MAKEFILE b/qutils/QCC/MAKEFILE new file mode 100644 index 0000000..c07c8e5 --- /dev/null +++ b/qutils/QCC/MAKEFILE @@ -0,0 +1,42 @@ + +EXES = qcc +NTEXES = qcc.exe + +#============================================================================== + +EXT= .o + +all: $(EXES) + +clean: + rm *.o *.obj $(EXES) $(NTEXES) + +next: + make "CFLAGS = -g -Wall -I.." + +nextinstall: + make "CFLAGS = -O4 -g -Wall -I.. -arch i386 -arch hppa" + cp $(EXES) /LocalApps + +alpha: + make "CFLAGS = -g -I.." "LDFLAGS = -lm" + +alphainstall: + make "CFLAGS = -O4 -I.." "LDFLAGS = -lm" + cp $(EXES) /LocalApps + +nt: + nmake /nologo "CFLAGS = -nologo -Zi -DWIN32 -I.." "LDFLAGS = " "EXT = .obj" + +ntinstall: + nmake /nologo "CFLAGS = -nologo -Ox -G5 -DWIN32 -I.." "LDFLAGS = " "EXT = .obj" + cp $(NTEXES) f:\nt\id + +#============================================================================== + +QCCFILES = qcc$(EXT) pr_lex$(EXT) pr_comp$(EXT) cmdlib$(EXT) +qcc : $(QCCFILES) + $(CC) $(CFLAGS) -o qcc $(QCCFILES) + +cmdlib$(EXT) : ../cmdlib.c + $(CC) $(CFLAGS) -c -o cmdlib$(EXT) ../cmdlib.c diff --git a/qutils/QCC/PR_COMP.C b/qutils/QCC/PR_COMP.C new file mode 100644 index 0000000..7c49599 --- /dev/null +++ b/qutils/QCC/PR_COMP.C @@ -0,0 +1,936 @@ + +#include "qcc.h" + + +pr_info_t pr; +def_t *pr_global_defs[MAX_REGS]; // to find def for a global variable +int pr_edict_size; + +//======================================== + +def_t *pr_scope; // the function being parsed, or NULL +qboolean pr_dumpasm; +string_t s_file; // filename for function definition + +int locals_end; // for tracking local variables vs temps + +jmp_buf pr_parse_abort; // longjump with this on parse error + +void PR_ParseDefs (void); + +//======================================== + + +opcode_t pr_opcodes[] = +{ + {"", "DONE", -1, false, &def_entity, &def_field, &def_void}, + + {"*", "MUL_F", 2, false, &def_float, &def_float, &def_float}, + {"*", "MUL_V", 2, false, &def_vector, &def_vector, &def_float}, + {"*", "MUL_FV", 2, false, &def_float, &def_vector, &def_vector}, + {"*", "MUL_VF", 2, false, &def_vector, &def_float, &def_vector}, + + {"/", "DIV", 2, false, &def_float, &def_float, &def_float}, + + {"+", "ADD_F", 3, false, &def_float, &def_float, &def_float}, + {"+", "ADD_V", 3, false, &def_vector, &def_vector, &def_vector}, + + {"-", "SUB_F", 3, false, &def_float, &def_float, &def_float}, + {"-", "SUB_V", 3, false, &def_vector, &def_vector, &def_vector}, + + {"==", "EQ_F", 4, false, &def_float, &def_float, &def_float}, + {"==", "EQ_V", 4, false, &def_vector, &def_vector, &def_float}, + {"==", "EQ_S", 4, false, &def_string, &def_string, &def_float}, + {"==", "EQ_E", 4, false, &def_entity, &def_entity, &def_float}, + {"==", "EQ_FNC", 4, false, &def_function, &def_function, &def_float}, + + {"!=", "NE_F", 4, false, &def_float, &def_float, &def_float}, + {"!=", "NE_V", 4, false, &def_vector, &def_vector, &def_float}, + {"!=", "NE_S", 4, false, &def_string, &def_string, &def_float}, + {"!=", "NE_E", 4, false, &def_entity, &def_entity, &def_float}, + {"!=", "NE_FNC", 4, false, &def_function, &def_function, &def_float}, + + {"<=", "LE", 4, false, &def_float, &def_float, &def_float}, + {">=", "GE", 4, false, &def_float, &def_float, &def_float}, + {"<", "LT", 4, false, &def_float, &def_float, &def_float}, + {">", "GT", 4, false, &def_float, &def_float, &def_float}, + + {".", "INDIRECT", 1, false, &def_entity, &def_field, &def_float}, + {".", "INDIRECT", 1, false, &def_entity, &def_field, &def_vector}, + {".", "INDIRECT", 1, false, &def_entity, &def_field, &def_string}, + {".", "INDIRECT", 1, false, &def_entity, &def_field, &def_entity}, + {".", "INDIRECT", 1, false, &def_entity, &def_field, &def_field}, + {".", "INDIRECT", 1, false, &def_entity, &def_field, &def_function}, + + {".", "ADDRESS", 1, false, &def_entity, &def_field, &def_pointer}, + + {"=", "STORE_F", 5, true, &def_float, &def_float, &def_float}, + {"=", "STORE_V", 5, true, &def_vector, &def_vector, &def_vector}, + {"=", "STORE_S", 5, true, &def_string, &def_string, &def_string}, + {"=", "STORE_ENT", 5, true, &def_entity, &def_entity, &def_entity}, + {"=", "STORE_FLD", 5, true, &def_field, &def_field, &def_field}, + {"=", "STORE_FNC", 5, true, &def_function, &def_function, &def_function}, + + {"=", "STOREP_F", 5, true, &def_pointer, &def_float, &def_float}, + {"=", "STOREP_V", 5, true, &def_pointer, &def_vector, &def_vector}, + {"=", "STOREP_S", 5, true, &def_pointer, &def_string, &def_string}, + {"=", "STOREP_ENT", 5, true, &def_pointer, &def_entity, &def_entity}, + {"=", "STOREP_FLD", 5, true, &def_pointer, &def_field, &def_field}, + {"=", "STOREP_FNC", 5, true, &def_pointer, &def_function, &def_function}, + + {"", "RETURN", -1, false, &def_void, &def_void, &def_void}, + + {"!", "NOT_F", -1, false, &def_float, &def_void, &def_float}, + {"!", "NOT_V", -1, false, &def_vector, &def_void, &def_float}, + {"!", "NOT_S", -1, false, &def_vector, &def_void, &def_float}, + {"!", "NOT_ENT", -1, false, &def_entity, &def_void, &def_float}, + {"!", "NOT_FNC", -1, false, &def_function, &def_void, &def_float}, + + {"", "IF", -1, false, &def_float, &def_float, &def_void}, + {"", "IFNOT", -1, false, &def_float, &def_float, &def_void}, + +// calls returns REG_RETURN + {"", "CALL0", -1, false, &def_function, &def_void, &def_void}, + {"", "CALL1", -1, false, &def_function, &def_void, &def_void}, + {"", "CALL2", -1, false, &def_function, &def_void, &def_void}, + {"", "CALL3", -1, false, &def_function, &def_void, &def_void}, + {"", "CALL4", -1, false, &def_function, &def_void, &def_void}, + {"", "CALL5", -1, false, &def_function, &def_void, &def_void}, + {"", "CALL6", -1, false, &def_function, &def_void, &def_void}, + {"", "CALL7", -1, false, &def_function, &def_void, &def_void}, + {"", "CALL8", -1, false, &def_function, &def_void, &def_void}, + + {"", "STATE", -1, false, &def_float, &def_float, &def_void}, + + {"", "GOTO", -1, false, &def_float, &def_void, &def_void}, + + {"&&", "AND", 6, false, &def_float, &def_float, &def_float}, + {"||", "OR", 6, false, &def_float, &def_float, &def_float}, + + {"&", "BITAND", 2, false, &def_float, &def_float, &def_float}, + {"|", "BITOR", 2, false, &def_float, &def_float, &def_float}, + + {NULL} +}; + +#define TOP_PRIORITY 6 +#define NOT_PRIORITY 4 + +def_t *PR_Expression (int priority); + +def_t junkdef; + +//=========================================================================== + + +/* +============ +PR_Statement + +Emits a primitive statement, returning the var it places it's value in +============ +*/ +def_t *PR_Statement ( opcode_t *op, def_t *var_a, def_t *var_b) +{ + dstatement_t *statement; + def_t *var_c; + + statement = &statements[numstatements]; + numstatements++; + + statement_linenums[statement-statements] = pr_source_line; + statement->op = op - pr_opcodes; + statement->a = var_a ? var_a->ofs : 0; + statement->b = var_b ? var_b->ofs : 0; + if (op->type_c == &def_void || op->right_associative) + { + var_c = NULL; + statement->c = 0; // ifs, gotos, and assignments + // don't need vars allocated + } + else + { // allocate result space + var_c = malloc (sizeof(def_t)); + memset (var_c, 0, sizeof(def_t)); + var_c->ofs = numpr_globals; + var_c->type = op->type_c->type; + + statement->c = numpr_globals; + numpr_globals += type_size[op->type_c->type->type]; + } + + if (op->right_associative) + return var_a; + return var_c; +} + +/* +============ +PR_ParseImmediate + +Looks for a preexisting constant +============ +*/ +def_t *PR_ParseImmediate (void) +{ + def_t *cn; + +// check for a constant with the same value + for (cn=pr.def_head.next ; cn ; cn=cn->next) + { + if (!cn->initialized) + continue; + if (cn->type != pr_immediate_type) + continue; + if (pr_immediate_type == &type_string) + { + if (!strcmp(G_STRING(cn->ofs), pr_immediate_string) ) + { + PR_Lex (); + return cn; + } + } + else if (pr_immediate_type == &type_float) + { + if ( G_FLOAT(cn->ofs) == pr_immediate._float ) + { + PR_Lex (); + return cn; + } + } + else if (pr_immediate_type == &type_vector) + { + if ( ( G_FLOAT(cn->ofs) == pr_immediate.vector[0] ) + && ( G_FLOAT(cn->ofs+1) == pr_immediate.vector[1] ) + && ( G_FLOAT(cn->ofs+2) == pr_immediate.vector[2] ) ) + { + PR_Lex (); + return cn; + } + } + else + PR_ParseError ("weird immediate type"); + } + +// allocate a new one + cn = malloc (sizeof(def_t)); + cn->next = NULL; + + pr.def_tail->next = cn; + pr.def_tail = cn; + + cn->search_next = pr.search; + pr.search = cn; + + cn->type = pr_immediate_type; + cn->name = "IMMEDIATE"; + cn->initialized = 1; + cn->scope = NULL; // always share immediates + +// copy the immediate to the global area + cn->ofs = numpr_globals; + pr_global_defs[cn->ofs] = cn; + numpr_globals += type_size[pr_immediate_type->type]; + if (pr_immediate_type == &type_string) + pr_immediate.string = CopyString (pr_immediate_string); + + memcpy (pr_globals + cn->ofs, &pr_immediate, 4*type_size[pr_immediate_type->type]); + + PR_Lex (); + + return cn; +} + + +void PrecacheSound (def_t *e, int ch) +{ + char *n; + int i; + + if (!e->ofs) + return; + n = G_STRING(e->ofs); + for (i=0 ; i= '1' && ch <= '9') + precache_sounds_block[i] = ch - '0'; + else + precache_sounds_block[i] = 1; + numsounds++; +} + +void PrecacheModel (def_t *e, int ch) +{ + char *n; + int i; + + if (!e->ofs) + return; + n = G_STRING(e->ofs); + for (i=0 ; i= '1' && ch <= '9') + precache_models_block[i] = ch - '0'; + else + precache_models_block[i] = 1; + nummodels++; +} + +void PrecacheFile (def_t *e, int ch) +{ + char *n; + int i; + + if (!e->ofs) + return; + n = G_STRING(e->ofs); + for (i=0 ; i= '1' && ch <= '9') + precache_files_block[i] = ch - '0'; + else + precache_files_block[i] = 1; + numfiles++; +} + +/* +============ +PR_ParseFunctionCall +============ +*/ +def_t *PR_ParseFunctionCall (def_t *func) +{ + def_t *e; + int arg; + type_t *t; + + t = func->type; + + if (t->type != ev_function) + PR_ParseError ("not a function"); + +// copy the arguments to the global parameter variables + arg = 0; + if (!PR_Check(")")) + { + do + { + if (t->num_parms != -1 && arg >= t->num_parms) + PR_ParseError ("too many parameters"); + e = PR_Expression (TOP_PRIORITY); + + if (arg == 0 && func->name) + { + // save information for model and sound caching + if (!strncmp(func->name,"precache_sound", 14)) + PrecacheSound (e, func->name[14]); + else if (!strncmp(func->name,"precache_model", 14)) + PrecacheModel (e, func->name[14]); + else if (!strncmp(func->name,"precache_file", 13)) + PrecacheFile (e, func->name[13]); + } + + if (t->num_parms != -1 && ( e->type != t->parm_types[arg] ) ) + PR_ParseError ("type mismatch on parm %i", arg); + // a vector copy will copy everything + def_parms[arg].type = t->parm_types[arg]; + PR_Statement (&pr_opcodes[OP_STORE_V], e, &def_parms[arg]); + arg++; + } while (PR_Check (",")); + + if (t->num_parms != -1 && arg != t->num_parms) + PR_ParseError ("too few parameters"); + PR_Expect (")"); + } + if (arg >8) + PR_ParseError ("More than eight parameters"); + + + PR_Statement (&pr_opcodes[OP_CALL0+arg], func, 0); + + def_ret.type = t->aux_type; + return &def_ret; +} + +/* +============ +PR_ParseValue + +Returns the global ofs for the current token +============ +*/ +def_t *PR_ParseValue (void) +{ + def_t *d; + char *name; + +// if the token is an immediate, allocate a constant for it + if (pr_token_type == tt_immediate) + return PR_ParseImmediate (); + + name = PR_ParseName (); + +// look through the defs + d = PR_GetDef (NULL, name, pr_scope, false); + if (!d) + PR_ParseError ("Unknown value \"%s\"", name); + return d; +} + + +/* +============ +PR_Term +============ +*/ +def_t *PR_Term (void) +{ + def_t *e, *e2; + etype_t t; + + if (PR_Check ("!")) + { + e = PR_Expression (NOT_PRIORITY); + t = e->type->type; + if (t == ev_float) + e2 = PR_Statement (&pr_opcodes[OP_NOT_F], e, 0); + else if (t == ev_string) + e2 = PR_Statement (&pr_opcodes[OP_NOT_S], e, 0); + else if (t == ev_entity) + e2 = PR_Statement (&pr_opcodes[OP_NOT_ENT], e, 0); + else if (t == ev_vector) + e2 = PR_Statement (&pr_opcodes[OP_NOT_V], e, 0); + else if (t == ev_function) + e2 = PR_Statement (&pr_opcodes[OP_NOT_FNC], e, 0); + else + { + e2 = NULL; // shut up compiler warning; + PR_ParseError ("type mismatch for !"); + } + return e2; + } + + if (PR_Check ("(")) + { + e = PR_Expression (TOP_PRIORITY); + PR_Expect (")"); + return e; + } + + return PR_ParseValue (); +} + +/* +============== +PR_Expression +============== +*/ + +def_t *PR_Expression (int priority) +{ + opcode_t *op, *oldop; + def_t *e, *e2; + etype_t type_a, type_b, type_c; + + if (priority == 0) + return PR_Term (); + + e = PR_Expression (priority-1); + + while (1) + { + if (priority == 1 && PR_Check ("(") ) + return PR_ParseFunctionCall (e); + + for (op=pr_opcodes ; op->name ; op++) + { + if (op->priority != priority) + continue; + if (!PR_Check (op->name)) + continue; + if ( op->right_associative ) + { + // if last statement is an indirect, change it to an address of + if ( (unsigned)(statements[numstatements-1].op - OP_LOAD_F) < 6 ) + { + statements[numstatements-1].op = OP_ADDRESS; + def_pointer.type->aux_type = e->type; + e->type = def_pointer.type; + } + e2 = PR_Expression (priority); + } + else + e2 = PR_Expression (priority-1); + + // type check + type_a = e->type->type; + type_b = e2->type->type; + + if (op->name[0] == '.')// field access gets type from field + { + if (e2->type->aux_type) + type_c = e2->type->aux_type->type; + else + type_c = -1; // not a field + } + else + type_c = ev_void; + + oldop = op; + while (type_a != op->type_a->type->type + || type_b != op->type_b->type->type + || (type_c != ev_void && type_c != op->type_c->type->type) ) + { + op++; + if (!op->name || strcmp (op->name , oldop->name)) + PR_ParseError ("type mismatch for %s", oldop->name); + } + + if (type_a == ev_pointer && type_b != e->type->aux_type->type) + PR_ParseError ("type mismatch for %s", op->name); + + + if (op->right_associative) + e = PR_Statement (op, e2, e); + else + e = PR_Statement (op, e, e2); + + if (type_c != ev_void) // field access gets type from field + e->type = e2->type->aux_type; + + break; + } + if (!op->name) + break; // next token isn't at this priority level + } + + return e; +} + + +/* +============ +PR_ParseStatement + +============ +*/ +void PR_ParseStatement (void) +{ + def_t *e; + dstatement_t *patch1, *patch2; + + if (PR_Check ("{")) + { + do + { + PR_ParseStatement (); + } while (!PR_Check ("}")); + return; + } + + if (PR_Check("return")) + { + if (PR_Check (";")) + { + PR_Statement (&pr_opcodes[OP_RETURN], 0, 0); + return; + } + e = PR_Expression (TOP_PRIORITY); + PR_Expect (";"); + PR_Statement (&pr_opcodes[OP_RETURN], e, 0); + return; + } + + if (PR_Check("while")) + { + PR_Expect ("("); + patch2 = &statements[numstatements]; + e = PR_Expression (TOP_PRIORITY); + PR_Expect (")"); + patch1 = &statements[numstatements]; + PR_Statement (&pr_opcodes[OP_IFNOT], e, 0); + PR_ParseStatement (); + junkdef.ofs = patch2 - &statements[numstatements]; + PR_Statement (&pr_opcodes[OP_GOTO], &junkdef, 0); + patch1->b = &statements[numstatements] - patch1; + return; + } + + if (PR_Check("do")) + { + patch1 = &statements[numstatements]; + PR_ParseStatement (); + PR_Expect ("while"); + PR_Expect ("("); + e = PR_Expression (TOP_PRIORITY); + PR_Expect (")"); + PR_Expect (";"); + junkdef.ofs = patch1 - &statements[numstatements]; + PR_Statement (&pr_opcodes[OP_IF], e, &junkdef); + return; + } + + if (PR_Check("local")) + { + PR_ParseDefs (); + locals_end = numpr_globals; + return; + } + + if (PR_Check("if")) + { + PR_Expect ("("); + e = PR_Expression (TOP_PRIORITY); + PR_Expect (")"); + + patch1 = &statements[numstatements]; + PR_Statement (&pr_opcodes[OP_IFNOT], e, 0); + + PR_ParseStatement (); + + if (PR_Check ("else")) + { + patch2 = &statements[numstatements]; + PR_Statement (&pr_opcodes[OP_GOTO], 0, 0); + patch1->b = &statements[numstatements] - patch1; + PR_ParseStatement (); + patch2->a = &statements[numstatements] - patch2; + } + else + patch1->b = &statements[numstatements] - patch1; + + return; + } + + PR_Expression (TOP_PRIORITY); + PR_Expect (";"); +} + + +/* +============== +PR_ParseState + +States are special functions made for convenience. They automatically +set frame, nextthink (implicitly), and think (allowing forward definitions). + +// void() name = [framenum, nextthink] {code} +// expands to: +// function void name () +// { +// self.frame=framenum; +// self.nextthink = time + 0.1; +// self.think = nextthink +// +// }; +============== +*/ +void PR_ParseState (void) +{ + char *name; + def_t *s1, *def; + + if (pr_token_type != tt_immediate || pr_immediate_type != &type_float) + PR_ParseError ("state frame must be a number"); + s1 = PR_ParseImmediate (); + + PR_Expect (","); + + name = PR_ParseName (); + def = PR_GetDef (&type_function, name,0, true); + + PR_Expect ("]"); + + PR_Statement (&pr_opcodes[OP_STATE], s1, def); +} + +/* +============ +PR_ParseImmediateStatements + +Parse a function body +============ +*/ +function_t *PR_ParseImmediateStatements (type_t *type) +{ + int i; + function_t *f; + def_t *defs[MAX_PARMS]; + + f = malloc (sizeof(function_t)); + +// +// check for builtin function definition #1, #2, etc +// + if (PR_Check ("#")) + { + if (pr_token_type != tt_immediate + || pr_immediate_type != &type_float + || pr_immediate._float != (int)pr_immediate._float) + PR_ParseError ("Bad builtin immediate"); + f->builtin = (int)pr_immediate._float; + PR_Lex (); + return f; + } + + f->builtin = 0; +// +// define the parms +// + for (i=0 ; inum_parms ; i++) + { + defs[i] = PR_GetDef (type->parm_types[i], pr_parm_names[i], pr_scope, true); + f->parm_ofs[i] = defs[i]->ofs; + if (i > 0 && f->parm_ofs[i] < f->parm_ofs[i-1]) + Error ("bad parm order"); + } + + f->code = numstatements; + +// +// check for a state opcode +// + if (PR_Check ("[")) + PR_ParseState (); + +// +// parse regular statements +// + PR_Expect ("{"); + + while (!PR_Check("}")) + PR_ParseStatement (); + +// emit an end of statements opcode + PR_Statement (pr_opcodes, 0,0); + + + return f; +} + +/* +============ +PR_GetDef + +If type is NULL, it will match any type +If allocate is true, a new def will be allocated if it can't be found +============ +*/ +def_t *PR_GetDef (type_t *type, char *name, def_t *scope, qboolean allocate) +{ + def_t *def, **old; + char element[MAX_NAME]; + +// see if the name is already in use + old = &pr.search; + for (def = *old ; def ; old=&def->search_next,def = *old) + if (!strcmp(def->name,name) ) + { + if ( def->scope && def->scope != scope) + continue; // in a different function + + if (type && def->type != type) + PR_ParseError ("Type mismatch on redeclaration of %s",name); + + // move to head of list to find fast next time + *old = def->search_next; + def->search_next = pr.search; + pr.search = def; + return def; + } + + if (!allocate) + return NULL; + +// allocate a new def + def = malloc (sizeof(def_t)); + memset (def, 0, sizeof(*def)); + def->next = NULL; + pr.def_tail->next = def; + pr.def_tail = def; + + def->search_next = pr.search; + pr.search = def; + + def->name = malloc (strlen(name)+1); + strcpy (def->name, name); + def->type = type; + + def->scope = scope; + + def->ofs = numpr_globals; + pr_global_defs[numpr_globals] = def; + +// +// make automatic defs for the vectors elements +// .origin can be accessed as .origin_x, .origin_y, and .origin_z +// + if (type->type == ev_vector) + { + sprintf (element, "%s_x",name); + PR_GetDef (&type_float, element, scope, true); + + sprintf (element, "%s_y",name); + PR_GetDef (&type_float, element, scope, true); + + sprintf (element, "%s_z",name); + PR_GetDef (&type_float, element, scope, true); + } + else + numpr_globals += type_size[type->type]; + + if (type->type == ev_field) + { + *(int *)&pr_globals[def->ofs] = pr.size_fields; + + if (type->aux_type->type == ev_vector) + { + sprintf (element, "%s_x",name); + PR_GetDef (&type_floatfield, element, scope, true); + + sprintf (element, "%s_y",name); + PR_GetDef (&type_floatfield, element, scope, true); + + sprintf (element, "%s_z",name); + PR_GetDef (&type_floatfield, element, scope, true); + } + else + pr.size_fields += type_size[type->aux_type->type]; + } + +// if (pr_dumpasm) +// PR_PrintOfs (def->ofs); + + return def; +} + +/* +================ +PR_ParseDefs + +Called at the outer layer and when a local statement is hit +================ +*/ +void PR_ParseDefs (void) +{ + char *name; + type_t *type; + def_t *def; + function_t *f; + dfunction_t *df; + int i; + int locals_start; + + type = PR_ParseType (); + + if (pr_scope && (type->type == ev_field || type->type == ev_function) ) + PR_ParseError ("Fields and functions must be global"); + + do + { + name = PR_ParseName (); + + def = PR_GetDef (type, name, pr_scope, true); + +// check for an initialization + if ( PR_Check ("=") ) + { + if (def->initialized) + PR_ParseError ("%s redeclared", name); + + if (type->type == ev_function) + { + locals_start = locals_end = numpr_globals; + pr_scope = def; + f = PR_ParseImmediateStatements (type); + pr_scope = NULL; + def->initialized = 1; + G_FUNCTION(def->ofs) = numfunctions; + f->def = def; +// if (pr_dumpasm) +// PR_PrintFunction (def); + + // fill in the dfunction + df = &functions[numfunctions]; + numfunctions++; + if (f->builtin) + df->first_statement = -f->builtin; + else + df->first_statement = f->code; + df->s_name = CopyString (f->def->name); + df->s_file = s_file; + df->numparms = f->def->type->num_parms; + df->locals = locals_end - locals_start; + df->parm_start = locals_start; + for (i=0 ; inumparms ; i++) + df->parm_size[i] = type_size[f->def->type->parm_types[i]->type]; + + continue; + } + else if (pr_immediate_type != type) + PR_ParseError ("wrong immediate type for %s", name); + + def->initialized = 1; + memcpy (pr_globals + def->ofs, &pr_immediate, 4*type_size[pr_immediate_type->type]); + PR_Lex (); + } + + } while (PR_Check (",")); + + PR_Expect (";"); +} + +/* +============ +PR_CompileFile + +compiles the 0 terminated text, adding defintions to the pr structure +============ +*/ +qboolean PR_CompileFile (char *string, char *filename) +{ + if (!pr.memory) + Error ("PR_CompileFile: Didn't clear"); + + PR_ClearGrabMacros (); // clear the frame macros + + pr_file_p = string; + s_file = CopyString (filename); + + pr_source_line = 0; + + PR_NewLine (); + + PR_Lex (); // read first token + + while (pr_token_type != tt_eof) + { + if (setjmp(pr_parse_abort)) + { + if (++pr_error_count > MAX_ERRORS) + return false; + PR_SkipToSemicolon (); + if (pr_token_type == tt_eof) + return false; + } + + pr_scope = NULL; // outside all functions + + PR_ParseDefs (); + } + + return (pr_error_count == 0); +} + diff --git a/qutils/QCC/PR_COMP.H b/qutils/QCC/PR_COMP.H new file mode 100644 index 0000000..c31947c --- /dev/null +++ b/qutils/QCC/PR_COMP.H @@ -0,0 +1,161 @@ + +// this file is shared by quake and qcc + +typedef int func_t; +typedef int string_t; + +typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer} etype_t; + + +#define OFS_NULL 0 +#define OFS_RETURN 1 +#define OFS_PARM0 4 // leave 3 ofs for each parm to hold vectors +#define OFS_PARM1 7 +#define OFS_PARM2 10 +#define OFS_PARM3 13 +#define OFS_PARM4 16 +#define OFS_PARM5 19 +#define OFS_PARM6 22 +#define OFS_PARM7 25 +#define RESERVED_OFS 28 + + +enum { + OP_DONE, + OP_MUL_F, + OP_MUL_V, + OP_MUL_FV, + OP_MUL_VF, + OP_DIV_F, + OP_ADD_F, + OP_ADD_V, + OP_SUB_F, + OP_SUB_V, + + OP_EQ_F, + OP_EQ_V, + OP_EQ_S, + OP_EQ_E, + OP_EQ_FNC, + + OP_NE_F, + OP_NE_V, + OP_NE_S, + OP_NE_E, + OP_NE_FNC, + + OP_LE, + OP_GE, + OP_LT, + OP_GT, + + OP_LOAD_F, + OP_LOAD_V, + OP_LOAD_S, + OP_LOAD_ENT, + OP_LOAD_FLD, + OP_LOAD_FNC, + + OP_ADDRESS, + + OP_STORE_F, + OP_STORE_V, + OP_STORE_S, + OP_STORE_ENT, + OP_STORE_FLD, + OP_STORE_FNC, + + OP_STOREP_F, + OP_STOREP_V, + OP_STOREP_S, + OP_STOREP_ENT, + OP_STOREP_FLD, + OP_STOREP_FNC, + + OP_RETURN, + OP_NOT_F, + OP_NOT_V, + OP_NOT_S, + OP_NOT_ENT, + OP_NOT_FNC, + OP_IF, + OP_IFNOT, + OP_CALL0, + OP_CALL1, + OP_CALL2, + OP_CALL3, + OP_CALL4, + OP_CALL5, + OP_CALL6, + OP_CALL7, + OP_CALL8, + OP_STATE, + OP_GOTO, + OP_AND, + OP_OR, + + OP_BITAND, + OP_BITOR +}; + + +typedef struct statement_s +{ + unsigned short op; + short a,b,c; +} dstatement_t; + +typedef struct +{ + unsigned short type; // if DEF_SAVEGLOBGAL bit is set + // the variable needs to be saved in savegames + unsigned short ofs; + int s_name; +} ddef_t; +#define DEF_SAVEGLOBGAL (1<<15) + +#define MAX_PARMS 8 + +typedef struct +{ + int first_statement; // negative numbers are builtins + int parm_start; + int locals; // total ints of parms + locals + + int profile; // runtime + + int s_name; + int s_file; // source file defined in + + int numparms; + byte parm_size[MAX_PARMS]; +} dfunction_t; + + +#define PROG_VERSION 6 +typedef struct +{ + int version; + int crc; // check of header file + + int ofs_statements; + int numstatements; // statement 0 is an error + + int ofs_globaldefs; + int numglobaldefs; + + int ofs_fielddefs; + int numfielddefs; + + int ofs_functions; + int numfunctions; // function 0 is an empty + + int ofs_strings; + int numstrings; // first string is a null string + + int ofs_globals; + int numglobals; + + int entityfields; +} dprograms_t; + diff --git a/qutils/QCC/PR_LEX.C b/qutils/QCC/PR_LEX.C new file mode 100644 index 0000000..10983bb --- /dev/null +++ b/qutils/QCC/PR_LEX.C @@ -0,0 +1,677 @@ + +#include "qcc.h" + +int pr_source_line; + +char *pr_file_p; +char *pr_line_start; // start of current source line + +int pr_bracelevel; + +char pr_token[2048]; +token_type_t pr_token_type; +type_t *pr_immediate_type; +eval_t pr_immediate; + +char pr_immediate_string[2048]; + +int pr_error_count; + +char *pr_punctuation[] = +// longer symbols must be before a shorter partial match +{"&&", "||", "<=", ">=","==", "!=", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", ".", "<", ">" , "#" , "&" , "|" , NULL}; + +// simple types. function types are dynamically allocated +type_t type_void = {ev_void, &def_void}; +type_t type_string = {ev_string, &def_string}; +type_t type_float = {ev_float, &def_float}; +type_t type_vector = {ev_vector, &def_vector}; +type_t type_entity = {ev_entity, &def_entity}; +type_t type_field = {ev_field, &def_field}; +type_t type_function = {ev_function, &def_function,NULL,&type_void}; +// type_function is a void() function used for state defs +type_t type_pointer = {ev_pointer, &def_pointer}; + +type_t type_floatfield = {ev_field, &def_field, NULL, &type_float}; + +int type_size[8] = {1,1,1,3,1,1,1,1}; + +def_t def_void = {&type_void, "temp"}; +def_t def_string = {&type_string, "temp"}; +def_t def_float = {&type_float, "temp"}; +def_t def_vector = {&type_vector, "temp"}; +def_t def_entity = {&type_entity, "temp"}; +def_t def_field = {&type_field, "temp"}; +def_t def_function = {&type_function, "temp"}; +def_t def_pointer = {&type_pointer, "temp"}; + +def_t def_ret, def_parms[MAX_PARMS]; + +def_t *def_for_type[8] = {&def_void, &def_string, &def_float, &def_vector, &def_entity, &def_field, &def_function, &def_pointer}; + +void PR_LexWhitespace (void); + + +/* +============== +PR_PrintNextLine +============== +*/ +void PR_PrintNextLine (void) +{ + char *t; + + printf ("%3i:",pr_source_line); + for (t=pr_line_start ; *t && *t != '\n' ; t++) + printf ("%c",*t); + printf ("\n"); +} + +/* +============== +PR_NewLine + +Call at start of file and when *pr_file_p == '\n' +============== +*/ +void PR_NewLine (void) +{ + qboolean m; + + if (*pr_file_p == '\n') + { + pr_file_p++; + m = true; + } + else + m = false; + + pr_source_line++; + pr_line_start = pr_file_p; + +// if (pr_dumpasm) +// PR_PrintNextLine (); + if (m) + pr_file_p--; +} + +/* +============== +PR_LexString + +Parses a quoted string +============== +*/ +void PR_LexString (void) +{ + int c; + int len; + + len = 0; + pr_file_p++; + do + { + c = *pr_file_p++; + if (!c) + PR_ParseError ("EOF inside quote"); + if (c=='\n') + PR_ParseError ("newline inside quote"); + if (c=='\\') + { // escape char + c = *pr_file_p++; + if (!c) + PR_ParseError ("EOF inside quote"); + if (c == 'n') + c = '\n'; + else if (c == '"') + c = '"'; + else + PR_ParseError ("Unknown escape char"); + } + else if (c=='\"') + { + pr_token[len] = 0; + pr_token_type = tt_immediate; + pr_immediate_type = &type_string; + strcpy (pr_immediate_string, pr_token); + return; + } + pr_token[len] = c; + len++; + } while (1); +} + +/* +============== +PR_LexNumber +============== +*/ +float PR_LexNumber (void) +{ + int c; + int len; + + len = 0; + c = *pr_file_p; + do + { + pr_token[len] = c; + len++; + pr_file_p++; + c = *pr_file_p; + } while ((c >= '0' && c<= '9') || c == '.'); + pr_token[len] = 0; + return atof (pr_token); +} + +/* +============== +PR_LexVector + +Parses a single quoted vector +============== +*/ +void PR_LexVector (void) +{ + int i; + + pr_file_p++; + pr_token_type = tt_immediate; + pr_immediate_type = &type_vector; + for (i=0 ; i<3 ; i++) + { + pr_immediate.vector[i] = PR_LexNumber (); + PR_LexWhitespace (); + } + if (*pr_file_p != '\'') + PR_ParseError ("Bad vector"); + pr_file_p++; +} + +/* +============== +PR_LexName + +Parses an identifier +============== +*/ +void PR_LexName (void) +{ + int c; + int len; + + len = 0; + c = *pr_file_p; + do + { + pr_token[len] = c; + len++; + pr_file_p++; + c = *pr_file_p; + } while ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' + || (c >= '0' && c <= '9')); + pr_token[len] = 0; + pr_token_type = tt_name; +} + +/* +============== +PR_LexPunctuation +============== +*/ +void PR_LexPunctuation (void) +{ + int i; + int len; + char *p; + + pr_token_type = tt_punct; + + for (i=0 ; (p = pr_punctuation[i]) != NULL ; i++) + { + len = strlen(p); + if (!strncmp(p, pr_file_p, len) ) + { + strcpy (pr_token, p); + if (p[0] == '{') + pr_bracelevel++; + else if (p[0] == '}') + pr_bracelevel--; + pr_file_p += len; + return; + } + } + + PR_ParseError ("Unknown punctuation"); +} + + +/* +============== +PR_LexWhitespace +============== +*/ +void PR_LexWhitespace (void) +{ + int c; + + while (1) + { + // skip whitespace + while ( (c = *pr_file_p) <= ' ') + { + if (c=='\n') + PR_NewLine (); + if (c == 0) + return; // end of file + pr_file_p++; + } + + // skip // comments + if (c=='/' && pr_file_p[1] == '/') + { + while (*pr_file_p && *pr_file_p != '\n') + pr_file_p++; + PR_NewLine(); + pr_file_p++; + continue; + } + + // skip /* */ comments + if (c=='/' && pr_file_p[1] == '*') + { + do + { + pr_file_p++; + if (pr_file_p[0]=='\n') + PR_NewLine(); + if (pr_file_p[1] == 0) + return; + } while (pr_file_p[-1] != '*' || pr_file_p[0] != '/'); + pr_file_p++; + continue; + } + + break; // a real character has been found + } +} + +//============================================================================ + +#define MAX_FRAMES 256 + +char pr_framemacros[MAX_FRAMES][16]; +int pr_nummacros; + +void PR_ClearGrabMacros (void) +{ + pr_nummacros = 0; +} + +void PR_FindMacro (void) +{ + int i; + + for (i=0 ; i ' ' && c != ',' && c != ';') + { + pr_token[i] = c; + i++; + pr_file_p++; + } + pr_token[i] = 0; + return true; +} + +void PR_ParseFrame (void) +{ + while (PR_SimpleGetToken ()) + { + strcpy (pr_framemacros[pr_nummacros], pr_token); + pr_nummacros++; + } +} + +/* +============== +PR_LexGrab + +Deals with counting sequence numbers and replacing frame macros +============== +*/ +void PR_LexGrab (void) +{ + pr_file_p++; // skip the $ + if (!PR_SimpleGetToken ()) + PR_ParseError ("hanging $"); + +// check for $frame + if (!strcmp (pr_token, "frame")) + { + PR_ParseFrame (); + PR_Lex (); + } +// ignore other known $commands + else if (!strcmp (pr_token, "cd") + || !strcmp (pr_token, "origin") + || !strcmp (pr_token, "base") + || !strcmp (pr_token, "flags") + || !strcmp (pr_token, "scale") + || !strcmp (pr_token, "skin") ) + { // skip to end of line + while (PR_SimpleGetToken ()) + ; + PR_Lex (); + } +// look for a frame name macro + else + PR_FindMacro (); +} + +//============================================================================ + +/* +============== +PR_Lex + +Sets pr_token, pr_token_type, and possibly pr_immediate and pr_immediate_type +============== +*/ +void PR_Lex (void) +{ + int c; + + pr_token[0] = 0; + + if (!pr_file_p) + { + pr_token_type = tt_eof; + return; + } + + PR_LexWhitespace (); + + c = *pr_file_p; + + if (!c) + { + pr_token_type = tt_eof; + return; + } + +// handle quoted strings as a unit + if (c == '\"') + { + PR_LexString (); + return; + } + +// handle quoted vectors as a unit + if (c == '\'') + { + PR_LexVector (); + return; + } + +// if the first character is a valid identifier, parse until a non-id +// character is reached + if ( (c >= '0' && c <= '9') || ( c=='-' && pr_file_p[1]>='0' && pr_file_p[1] <='9') ) + { + pr_token_type = tt_immediate; + pr_immediate_type = &type_float; + pr_immediate._float = PR_LexNumber (); + return; + } + + if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' ) + { + PR_LexName (); + return; + } + + if (c == '$') + { + PR_LexGrab (); + return; + } + +// parse symbol strings until a non-symbol is found + PR_LexPunctuation (); +} + +//============================================================================= + +/* +============ +PR_ParseError + +Aborts the current file load +============ +*/ +void PR_ParseError (char *error, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,error); + vsprintf (string,error,argptr); + va_end (argptr); + + printf ("%s:%i:%s\n", strings + s_file, pr_source_line, string); + + longjmp (pr_parse_abort, 1); +} + + +/* +============= +PR_Expect + +Issues an error if the current token isn't equal to string +Gets the next token +============= +*/ +void PR_Expect (char *string) +{ + if (strcmp (string, pr_token)) + PR_ParseError ("expected %s, found %s",string, pr_token); + PR_Lex (); +} + + +/* +============= +PR_Check + +Returns true and gets the next token if the current token equals string +Returns false and does nothing otherwise +============= +*/ +qboolean PR_Check (char *string) +{ + if (strcmp (string, pr_token)) + return false; + + PR_Lex (); + return true; +} + +/* +============ +PR_ParseName + +Checks to see if the current token is a valid name +============ +*/ +char *PR_ParseName (void) +{ + static char ident[MAX_NAME]; + + if (pr_token_type != tt_name) + PR_ParseError ("not a name"); + if (strlen(pr_token) >= MAX_NAME-1) + PR_ParseError ("name too long"); + strcpy (ident, pr_token); + PR_Lex (); + + return ident; +} + +/* +============ +PR_FindType + +Returns a preexisting complex type that matches the parm, or allocates +a new one and copies it out. +============ +*/ +type_t *PR_FindType (type_t *type) +{ + def_t *def; + type_t *check; + int i; + + for (check = pr.types ; check ; check = check->next) + { + if (check->type != type->type + || check->aux_type != type->aux_type + || check->num_parms != type->num_parms) + continue; + + for (i=0 ; i< type->num_parms ; i++) + if (check->parm_types[i] != type->parm_types[i]) + break; + + if (i == type->num_parms) + return check; + } + +// allocate a new one + check = malloc (sizeof (*check)); + *check = *type; + check->next = pr.types; + pr.types = check; + +// allocate a generic def for the type, so fields can reference it + def = malloc (sizeof(def_t)); + def->name = "COMPLEX TYPE"; + def->type = check; + check->def = def; + return check; +} + + +/* +============ +PR_SkipToSemicolon + +For error recovery, also pops out of nested braces +============ +*/ +void PR_SkipToSemicolon (void) +{ + do + { + if (!pr_bracelevel && PR_Check (";")) + return; + PR_Lex (); + } while (pr_token[0]); // eof will return a null token +} + + +/* +============ +PR_ParseType + +Parses a variable type, including field and functions types +============ +*/ +char pr_parm_names[MAX_PARMS][MAX_NAME]; + +type_t *PR_ParseType (void) +{ + type_t new; + type_t *type; + char *name; + + if (PR_Check (".")) + { + memset (&new, 0, sizeof(new)); + new.type = ev_field; + new.aux_type = PR_ParseType (); + return PR_FindType (&new); + } + + if (!strcmp (pr_token, "float") ) + type = &type_float; + else if (!strcmp (pr_token, "vector") ) + type = &type_vector; + else if (!strcmp (pr_token, "float") ) + type = &type_float; + else if (!strcmp (pr_token, "entity") ) + type = &type_entity; + else if (!strcmp (pr_token, "string") ) + type = &type_string; + else if (!strcmp (pr_token, "void") ) + type = &type_void; + else + { + PR_ParseError ("\"%s\" is not a type", pr_token); + type = &type_float; // shut up compiler warning + } + PR_Lex (); + + if (!PR_Check ("(")) + return type; + +// function type + memset (&new, 0, sizeof(new)); + new.type = ev_function; + new.aux_type = type; // return type + new.num_parms = 0; + if (!PR_Check (")")) + { + if (PR_Check ("...")) + new.num_parms = -1; // variable args + else + do + { + type = PR_ParseType (); + name = PR_ParseName (); + strcpy (pr_parm_names[new.num_parms], name); + new.parm_types[new.num_parms] = type; + new.num_parms++; + } while (PR_Check (",")); + + PR_Expect (")"); + } + + return PR_FindType (&new); +} + diff --git a/qutils/QCC/QCC b/qutils/QCC/QCC new file mode 100644 index 0000000000000000000000000000000000000000..ceb89d25a275a925a2be9a3b223d9a218df5b1bd GIT binary patch literal 146232 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 literal 0 HcmV?d00001 diff --git a/qutils/QCC/QCC.C b/qutils/QCC/QCC.C new file mode 100644 index 0000000..319330d --- /dev/null +++ b/qutils/QCC/QCC.C @@ -0,0 +1,808 @@ + +#include "qcc.h" + +char sourcedir[1024]; +char destfile[1024]; + +float pr_globals[MAX_REGS]; +int numpr_globals; + +char strings[MAX_STRINGS]; +int strofs; + +dstatement_t statements[MAX_STATEMENTS]; +int numstatements; +int statement_linenums[MAX_STATEMENTS]; + +dfunction_t functions[MAX_FUNCTIONS]; +int numfunctions; + +ddef_t globals[MAX_GLOBALS]; +int numglobaldefs; + +ddef_t fields[MAX_FIELDS]; +int numfielddefs; + +char precache_sounds[MAX_SOUNDS][MAX_DATA_PATH]; +int precache_sounds_block[MAX_SOUNDS]; +int numsounds; + +char precache_models[MAX_MODELS][MAX_DATA_PATH]; +int precache_models_block[MAX_SOUNDS]; +int nummodels; + +char precache_files[MAX_FILES][MAX_DATA_PATH]; +int precache_files_block[MAX_SOUNDS]; +int numfiles; + +/* +============ +WriteFiles + + Generates files.dat, which contains all of the + data files actually used by the game, to be + processed by qfiles.exe +============ +*/ +void WriteFiles (void) +{ + FILE *f; + int i; + char filename[1024]; + + sprintf (filename, "%sfiles.dat", sourcedir); + f = fopen (filename, "w"); + if (!f) + Error ("Couldn't open %s", filename); + + fprintf (f, "%i\n", numsounds); + for (i=0 ; is_file, strings + d->s_name, d->first_statement, d->parm_start); + for (j=0 ; jnumparms ; j++) + printf ("%i ",d->parm_size[j]); + printf (")\n"); + } +} + +void PrintFields (void) +{ + int i; + ddef_t *d; + + for (i=0 ; iofs, d->type, strings + d->s_name); + } +} + +void PrintGlobals (void) +{ + int i; + ddef_t *d; + + for (i=0 ; iofs, d->type, strings + d->s_name); + } +} + + +void InitData (void) +{ + int i; + + numstatements = 1; + strofs = 1; + numfunctions = 1; + numglobaldefs = 1; + numfielddefs = 1; + + def_ret.ofs = OFS_RETURN; + for (i=0 ; inext) + { + if (def->type->type == ev_function) + { +// df = &functions[numfunctions]; +// numfunctions++; + + } + else if (def->type->type == ev_field) + { + dd = &fields[numfielddefs]; + numfielddefs++; + dd->type = def->type->aux_type->type; + dd->s_name = CopyString (def->name); + dd->ofs = G_INT(def->ofs); + } + dd = &globals[numglobaldefs]; + numglobaldefs++; + dd->type = def->type->type; + if ( !def->initialized + && def->type->type != ev_function + && def->type->type != ev_field + && def->scope == NULL) + dd->type |= DEF_SAVEGLOBGAL; + dd->s_name = CopyString (def->name); + dd->ofs = def->ofs; + } + +//PrintStrings (); +//PrintFunctions (); +//PrintFields (); +//PrintGlobals (); +strofs = (strofs+3)&~3; + + printf ("%6i strofs\n", strofs); + printf ("%6i numstatements\n", numstatements); + printf ("%6i numfunctions\n", numfunctions); + printf ("%6i numglobaldefs\n", numglobaldefs); + printf ("%6i numfielddefs\n", numfielddefs); + printf ("%6i numpr_globals\n", numpr_globals); + + h = SafeOpenWrite (destfile); + SafeWrite (h, &progs, sizeof(progs)); + + progs.ofs_strings = ftell (h); + progs.numstrings = strofs; + SafeWrite (h, strings, strofs); + + progs.ofs_statements = ftell (h); + progs.numstatements = numstatements; + for (i=0 ; i 60) + { + *s++ = '.'; + *s++ = '.'; + *s++ = '.'; + break; + } + } + *s++ = '"'; + *s++ = 0; + return buf; +} + + + +def_t *PR_DefForFieldOfs (gofs_t ofs) +{ + def_t *d; + + for (d=pr.def_head.next ; d ; d=d->next) + { + if (d->type->type != ev_field) + continue; + if (*((int *)&pr_globals[d->ofs]) == ofs) + return d; + } + Error ("PR_DefForFieldOfs: couldn't find %i",ofs); + return NULL; +} + +/* +============ +PR_ValueString + +Returns a string describing *data in a type specific manner +============= +*/ +char *PR_ValueString (etype_t type, void *val) +{ + static char line[256]; + def_t *def; + dfunction_t *f; + + switch (type) + { + case ev_string: + sprintf (line, "%s", PR_String(strings + *(int *)val)); + break; + case ev_entity: + sprintf (line, "entity %i", *(int *)val); + break; + case ev_function: + f = functions + *(int *)val; + if (!f) + sprintf (line, "undefined function"); + else + sprintf (line, "%s()", strings + f->s_name); + break; + case ev_field: + def = PR_DefForFieldOfs ( *(int *)val ); + sprintf (line, ".%s", def->name); + break; + case ev_void: + sprintf (line, "void"); + break; + case ev_float: + sprintf (line, "%5.1f", *(float *)val); + break; + case ev_vector: + sprintf (line, "'%5.1f %5.1f %5.1f'", ((float *)val)[0], ((float *)val)[1], ((float *)val)[2]); + break; + case ev_pointer: + sprintf (line, "pointer"); + break; + default: + sprintf (line, "bad type %i", type); + break; + } + + return line; +} + +/* +============ +PR_GlobalString + +Returns a string with a description and the contents of a global, +padded to 20 field width +============ +*/ +char *PR_GlobalStringNoContents (gofs_t ofs) +{ + int i; + def_t *def; + void *val; + static char line[128]; + + val = (void *)&pr_globals[ofs]; + def = pr_global_defs[ofs]; + if (!def) +// Error ("PR_GlobalString: no def for %i", ofs); + sprintf (line,"%i(???)", ofs); + else + sprintf (line,"%i(%s)", ofs, def->name); + + i = strlen(line); + for ( ; i<16 ; i++) + strcat (line," "); + strcat (line," "); + + return line; +} + +char *PR_GlobalString (gofs_t ofs) +{ + char *s; + int i; + def_t *def; + void *val; + static char line[128]; + + val = (void *)&pr_globals[ofs]; + def = pr_global_defs[ofs]; + if (!def) + return PR_GlobalStringNoContents(ofs); + if (def->initialized && def->type->type != ev_function) + { + s = PR_ValueString (def->type->type, &pr_globals[ofs]); + sprintf (line,"%i(%s)", ofs, s); + } + else + sprintf (line,"%i(%s)", ofs, def->name); + + i = strlen(line); + for ( ; i<16 ; i++) + strcat (line," "); + strcat (line," "); + + return line; +} + +/* +============ +PR_PrintOfs +============ +*/ +void PR_PrintOfs (gofs_t ofs) +{ + printf ("%s\n",PR_GlobalString(ofs)); +} + +/* +================= +PR_PrintStatement +================= +*/ +void PR_PrintStatement (dstatement_t *s) +{ + int i; + + printf ("%4i : %4i : %s ", (int)(s - statements), statement_linenums[s-statements], pr_opcodes[s->op].opname); + i = strlen(pr_opcodes[s->op].opname); + for ( ; i<10 ; i++) + printf (" "); + + if (s->op == OP_IF || s->op == OP_IFNOT) + printf ("%sbranch %i",PR_GlobalString(s->a),s->b); + else if (s->op == OP_GOTO) + { + printf ("branch %i",s->a); + } + else if ( (unsigned)(s->op - OP_STORE_F) < 6) + { + printf ("%s",PR_GlobalString(s->a)); + printf ("%s", PR_GlobalStringNoContents(s->b)); + } + else + { + if (s->a) + printf ("%s",PR_GlobalString(s->a)); + if (s->b) + printf ("%s",PR_GlobalString(s->b)); + if (s->c) + printf ("%s", PR_GlobalStringNoContents(s->c)); + } + printf ("\n"); +} + + +/* +============ +PR_PrintDefs +============ +*/ +void PR_PrintDefs (void) +{ + def_t *d; + + for (d=pr.def_head.next ; d ; d=d->next) + PR_PrintOfs (d->ofs); +} + + +/* +============== +PR_BeginCompilation + +called before compiling a batch of files, clears the pr struct +============== +*/ +void PR_BeginCompilation (void *memory, int memsize) +{ + int i; + + pr.memory = memory; + pr.max_memory = memsize; + + numpr_globals = RESERVED_OFS; + pr.def_tail = &pr.def_head; + + for (i=0 ; inext) + { + if (d->type->type == ev_function && !d->scope)// function parms are ok + { +// f = G_FUNCTION(d->ofs); +// if (!f || (!f->code && !f->builtin) ) + if (!d->initialized) + { + printf ("function %s was not defined\n",d->name); + errors = true; + } + } + } + + return !errors; +} + +//============================================================================= + +/* +============ +PR_WriteProgdefs + +Writes the global and entity structures out +Returns a crc of the header, to be stored in the progs file for comparison +at load time. +============ +*/ +int PR_WriteProgdefs (char *filename) +{ + def_t *d; + FILE *f; + unsigned short crc; + int c; + + printf ("writing %s\n", filename); + f = fopen (filename, "w"); + +// print global vars until the first field is defined + fprintf (f,"\n/* file generated by qcc, do not modify */\n\ntypedef struct\n{\tint\tpad[%i];\n", RESERVED_OFS); + for (d=pr.def_head.next ; d ; d=d->next) + { + if (!strcmp (d->name, "end_sys_globals")) + break; + + switch (d->type->type) + { + case ev_float: + fprintf (f, "\tfloat\t%s;\n",d->name); + break; + case ev_vector: + fprintf (f, "\tvec3_t\t%s;\n",d->name); + d=d->next->next->next; // skip the elements + break; + case ev_string: + fprintf (f,"\tstring_t\t%s;\n",d->name); + break; + case ev_function: + fprintf (f,"\tfunc_t\t%s;\n",d->name); + break; + case ev_entity: + fprintf (f,"\tint\t%s;\n",d->name); + break; + default: + fprintf (f,"\tint\t%s;\n",d->name); + break; + } + } + fprintf (f,"} globalvars_t;\n\n"); + +// print all fields + fprintf (f,"typedef struct\n{\n"); + for (d=pr.def_head.next ; d ; d=d->next) + { + if (!strcmp (d->name, "end_sys_fields")) + break; + + if (d->type->type != ev_field) + continue; + + switch (d->type->aux_type->type) + { + case ev_float: + fprintf (f,"\tfloat\t%s;\n",d->name); + break; + case ev_vector: + fprintf (f,"\tvec3_t\t%s;\n",d->name); + d=d->next->next->next; // skip the elements + break; + case ev_string: + fprintf (f,"\tstring_t\t%s;\n",d->name); + break; + case ev_function: + fprintf (f,"\tfunc_t\t%s;\n",d->name); + break; + case ev_entity: + fprintf (f,"\tint\t%s;\n",d->name); + break; + default: + fprintf (f,"\tint\t%s;\n",d->name); + break; + } + } + fprintf (f,"} entvars_t;\n\n"); + + fclose (f); + +// do a crc of the file + CRC_Init (&crc); + f = fopen (filename, "r+"); + while ((c = fgetc(f)) != EOF) + CRC_ProcessByte (&crc, (byte)c); + + fprintf (f,"#define PROGHEADER_CRC %i\n", crc); + fclose (f); + + return crc; +} + + +void PrintFunction (char *name) +{ + int i; + dstatement_t *ds; + dfunction_t *df; + + for (i=0 ; ifirst_statement; + while (1) + { + PR_PrintStatement (ds); + if (!ds->op) + break; + ds++; + } +} + + +//============================================================================ + +/* +============ +main +============ +*/ +void main (int argc, char **argv) +{ + char *src; + char *src2; + char filename[1024]; + int p, crc; + double start, stop; + + start = I_FloatTime (); + + myargc = argc; + myargv = argv; + + if ( CheckParm ("-?") || CheckParm ("-help")) + { + printf ("qcc looks for progs.src in the current directory.\n"); + printf ("to look in a different directory: qcc -src \n"); + printf ("to build a clean data tree: qcc -copy \n"); + printf ("to build a clean pak file: qcc -pak \n"); + printf ("to bsp all bmodels: qcc -bspmodels \n"); + return; + } + + p = CheckParm ("-src"); + if (p && p < argc-1 ) + { + strcpy (sourcedir, argv[p+1]); + strcat (sourcedir, "/"); + printf ("Source directory: %s\n", sourcedir); + } + else + strcpy (sourcedir, ""); + + InitData (); + + sprintf (filename, "%sprogs.src", sourcedir); + LoadFile (filename, (void *)&src); + + src = COM_Parse (src); + if (!src) + Error ("No destination filename. qcc -help for info.\n"); + strcpy (destfile, com_token); + printf ("outputfile: %s\n", destfile); + + pr_dumpasm = false; + + PR_BeginCompilation (malloc (0x100000), 0x100000); + +// compile all the files + do + { + src = COM_Parse(src); + if (!src) + break; + sprintf (filename, "%s%s", sourcedir, com_token); + printf ("compiling %s\n", filename); + LoadFile (filename, (void *)&src2); + + if (!PR_CompileFile (src2, filename) ) + exit (1); + + } while (1); + + if (!PR_FinishCompilation ()) + Error ("compilation errors"); + + p = CheckParm ("-asm"); + if (p) + { + for (p++ ; p +#include + +#include "pr_comp.h" + +/* + +TODO: + +"stopped at 10 errors" + +other pointer types for models and clients? + +compact string heap? + +allways initialize all variables to something safe + +the def->type->type arrangement is really silly. + +return type checking + +parm count type checking + +immediate overflow checking + +pass the first two parms in call->b and call->c + +*/ + +/* + +comments +-------- +// comments discard text until the end of line +/ * * / comments discard all enclosed text (spaced out on this line because this documentation is in a regular C comment block, and typing them in normally causes a parse error) + +code structure +-------------- +A definition is: + [ = ] {, [ = ] }; + + +types +----- +simple types: void, float, vector, string, or entity + float width, height; + string name; + entity self, other; + +vector types: + vector org; // also creates org_x, org_y, and org_z float defs + + +A function type is specified as: simpletype ( type name {,type name} ) +The names are ignored except when the function is initialized. + void() think; + entity() FindTarget; + void(vector destination, float speed, void() callback) SUB_CalcMove; + void(...) dprint; // variable argument builtin + +A field type is specified as: .type + .vector origin; + .string netname; + .void() think, touch, use; + + +names +----- +Names are a maximum of 64 characters, must begin with A-Z,a-z, or _, and can continue with those characters or 0-9. + +There are two levels of scoping: global, and function. The parameter list of a function and any vars declared inside a function with the "local" statement are only visible within that function, + + +immediates +---------- +Float immediates must begin with 0-9 or minus sign. .5 is illegal. + +A parsing ambiguity is present with negative constants. "a-5" will be parsed as "a", then "-5", causing an error. Seperate the - from the digits with a space "a - 5" to get the proper behavior. + 12 + 1.6 + 0.5 + -100 + +Vector immediates are three float immediates enclosed in single quotes. + '0 0 0' + '20.5 -10 0.00001' + +String immediates are characters enclosed in double quotes. The string cannot contain explicit newlines, but the escape character \n can embed one. The \" escape can be used to include a quote in the string. + "maps/jrwiz1.bsp" + "sound/nin/pain.wav" + "ouch!\n" + +Code immediates are statements enclosed in {} braces. +statement: + { } + ; + local [ = ] {, [ = ] }; + return ; + if ( ) [ else ]; + while ( ) ; + do while ( ); + ( ); + +expression: + combiations of names and these operators with standard C precedence: + "&&", "||", "<=", ">=","==", "!=", "!", "*", "/", "-", "+", "=", ".", "<", ">", "&", "|" + Parenthesis can be used to alter order of operation. + The & and | operations perform integral bit ops on floats + +A built in function immediate is a number sign followed by an integer. + #1 + #12 + + +compilation +----------- +Source files are processed sequentially without dumping any state, so if a defs file is the first one processed, the definitions will be available to all other files. + +The language is strongly typed and there are no casts. + +Anything that is initialized is assumed to be constant, and will have immediates folded into it. If you change the value, your program will malfunction. All uninitialized globals will be saved to savegame files. + +Functions cannot have more than eight parameters. + +Error recovery during compilation is minimal. It will skip to the next global definition, so you will never see more than one error at a time in a given function. All compilation aborts after ten error messages. + +Names can be defined multiple times until they are defined with an initialization, allowing functions to be prototyped before their definition. + +void() MyFunction; // the prototype + +void() MyFunction = // the initialization +{ + dprint ("we're here\n"); +}; + + +entities and fields +------------------- + + +execution +--------- +Code execution is initiated by C code in quake from two main places: the timed think routines for periodic control, and the touch function when two objects impact each other. + +There are three global variables that are set before beginning code execution: + entity world; // the server's world object, which holds all global + // state for the server, like the deathmatch flags + // and the body ques. + entity self; // the entity the function is executing for + entity other; // the other object in an impact, not used for thinks + float time; // the current game time. Note that because the + // entities in the world are simulated sequentially, + // time is NOT strictly increasing. An impact late + // in one entity's time slice may set time higher + // than the think function of the next entity. + // The difference is limited to 0.1 seconds. +Execution is also caused by a few uncommon events, like the addition of a new client to an existing server. + +There is a runnaway counter that stops a program if 100000 statements are executed, assuming it is in an infinite loop. + +It is acceptable to change the system set global variables. This is usually done to pose as another entity by changing self and calling a function. + +The interpretation is fairly efficient, but it is still over an order of magnitude slower than compiled C code. All time consuming operations should be made into built in functions. + +A profile counter is kept for each function, and incremented for each interpreted instruction inside that function. The "profile" console command in Quake will dump out the top 10 functions, then clear all the counters. The "profile all" command will dump sorted stats for every function that has been executed. + + +afunc ( 4, bfunc(1,2,3)); +will fail because there is a shared parameter marshaling area, which will cause the 1 from bfunc to overwrite the 4 allready placed in parm0. When a function is called, it copies the parms from the globals into it's privately scoped variables, so there is no collision when calling another function. + +total = factorial(3) + factorial(4); +Will fail because the return value from functions is held in a single global area. If this really gets on your nerves, tell me and I can work around it at a slight performance and space penalty by allocating a new register for the function call and copying it out. + + +built in functions +------------------ +void(string text) dprint; +Prints the string to the server console. + +void(entity client, string text) cprint; +Prints a message to a specific client. + +void(string text) bprint; +Broadcast prints a message to all clients on the current server. + +entity() spawn; +Returns a totally empty entity. You can manually set everything up, or just set the origin and call one of the existing entity setup functions. + +entity(entity start, .string field, string match) find; +Searches the server entity list beginning at start, looking for an entity that has entity.field = match. To start at the beginning of the list, pass world. World is returned when the end of the list is reached. + + + + +gotchas +------- + +The && and || operators DO NOT EARLY OUT like C! + +Don't confuse single quoted vectors with double quoted strings + +The function declaration syntax takes a little getting used to. + +Don't forget the ; after the trailing brace of a function initialization. + +Don't forget the "local" before defining local variables. + +There are no ++ / -- operators, or operate/assign operators. + +*/ + +//============================================================================= + +// offsets are allways multiplied by 4 before using +typedef int gofs_t; // offset in global data block +typedef struct function_s function_t; + +#define MAX_PARMS 8 + +typedef struct type_s +{ + etype_t type; + struct def_s *def; // a def that points to this type + struct type_s *next; +// function types are more complex + struct type_s *aux_type; // return type or field type + int num_parms; // -1 = variable args + struct type_s *parm_types[MAX_PARMS]; // only [num_parms] allocated +} type_t; + +typedef struct def_s +{ + type_t *type; + char *name; + struct def_s *next; + struct def_s *search_next; // for finding faster + gofs_t ofs; + struct def_s *scope; // function the var was defined in, or NULL + int initialized; // 1 when a declaration included "= immediate" +} def_t; + +//============================================================================ + +// pr_loc.h -- program local defs + +#define MAX_ERRORS 10 + +#define MAX_NAME 64 // chars long + +#define MAX_REGS 16384 + +//============================================================================= + +typedef union eval_s +{ + string_t string; + float _float; + float vector[3]; + func_t function; + int _int; + union eval_s *ptr; +} eval_t; + +extern int type_size[8]; +extern def_t *def_for_type[8]; + +extern type_t type_void, type_string, type_float, type_vector, type_entity, type_field, type_function, type_pointer, type_floatfield; + +extern def_t def_void, def_string, def_float, def_vector, def_entity, def_field, def_function, def_pointer; + +struct function_s +{ + int builtin; // if non 0, call an internal function + int code; // first statement + char *file; // source file with definition + int file_line; + struct def_s *def; + int parm_ofs[MAX_PARMS]; // allways contiguous, right? +}; + + +// +// output generated by prog parsing +// +typedef struct +{ + char *memory; + int max_memory; + int current_memory; + type_t *types; + + def_t def_head; // unused head of linked list + def_t *def_tail; // add new defs after this and move it + def_t *search; // search chain through defs + + int size_fields; +} pr_info_t; + +extern pr_info_t pr; + +typedef struct +{ + char *name; + char *opname; + float priority; + qboolean right_associative; + def_t *type_a, *type_b, *type_c; +} opcode_t; + +//============================================================================ + + +extern opcode_t pr_opcodes[99]; // sized by initialization + +extern qboolean pr_dumpasm; + +extern def_t *pr_global_defs[MAX_REGS]; // to find def for a global variable + +typedef enum { +tt_eof, // end of file reached +tt_name, // an alphanumeric name token +tt_punct, // code punctuation +tt_immediate, // string, float, vector +} token_type_t; + +extern char pr_token[2048]; +extern token_type_t pr_token_type; +extern type_t *pr_immediate_type; +extern eval_t pr_immediate; + +void PR_PrintStatement (dstatement_t *s); + +void PR_Lex (void); +// reads the next token into pr_token and classifies its type + +type_t *PR_ParseType (void); +char *PR_ParseName (void); + +qboolean PR_Check (char *string); +void PR_Expect (char *string); +void PR_ParseError (char *error, ...); + + +extern jmp_buf pr_parse_abort; // longjump with this on parse error +extern int pr_source_line; +extern char *pr_file_p; + +void *PR_Malloc (int size); + + +#define OFS_NULL 0 +#define OFS_RETURN 1 +#define OFS_PARM0 4 // leave 3 ofs for each parm to hold vectors +#define OFS_PARM1 7 +#define OFS_PARM2 10 +#define OFS_PARM3 13 +#define OFS_PARM4 16 +#define RESERVED_OFS 28 + + +extern def_t *pr_scope; +extern int pr_error_count; + +void PR_NewLine (void); +def_t *PR_GetDef (type_t *type, char *name, def_t *scope, qboolean allocate); + +void PR_PrintDefs (void); + +void PR_SkipToSemicolon (void); + +extern char pr_parm_names[MAX_PARMS][MAX_NAME]; +extern qboolean pr_trace; + +#define G_FLOAT(o) (pr_globals[o]) +#define G_INT(o) (*(int *)&pr_globals[o]) +#define G_VECTOR(o) (&pr_globals[o]) +#define G_STRING(o) (strings + *(string_t *)&pr_globals[o]) +#define G_FUNCTION(o) (*(func_t *)&pr_globals[o]) + +char *PR_ValueString (etype_t type, void *val); + +void PR_ClearGrabMacros (void); + +qboolean PR_CompileFile (char *string, char *filename); + +extern qboolean pr_dumpasm; + +extern string_t s_file; // filename for function definition + +extern def_t def_ret, def_parms[MAX_PARMS]; + +//============================================================================= + +#define MAX_STRINGS 500000 +#define MAX_GLOBALS 16384 +#define MAX_FIELDS 1024 +#define MAX_STATEMENTS 65536 +#define MAX_FUNCTIONS 8192 + +#define MAX_SOUNDS 1024 +#define MAX_MODELS 1024 +#define MAX_FILES 1024 +#define MAX_DATA_PATH 64 + +extern char strings[MAX_STRINGS]; +extern int strofs; + +extern dstatement_t statements[MAX_STATEMENTS]; +extern int numstatements; +extern int statement_linenums[MAX_STATEMENTS]; + +extern dfunction_t functions[MAX_FUNCTIONS]; +extern int numfunctions; + +extern float pr_globals[MAX_REGS]; +extern int numpr_globals; + +extern char pr_immediate_string[2048]; + +extern char precache_sounds[MAX_SOUNDS][MAX_DATA_PATH]; +extern int precache_sounds_block[MAX_SOUNDS]; +extern int numsounds; + +extern char precache_models[MAX_MODELS][MAX_DATA_PATH]; +extern int precache_models_block[MAX_SOUNDS]; +extern int nummodels; + +extern char precache_files[MAX_FILES][MAX_DATA_PATH]; +extern int precache_files_block[MAX_SOUNDS]; +extern int numfiles; + +int CopyString (char *str); + + diff --git a/qutils/QCC/QCC.MAK b/qutils/QCC/QCC.MAK new file mode 100644 index 0000000..e408f6a --- /dev/null +++ b/qutils/QCC/QCC.MAK @@ -0,0 +1,249 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=qcc - Win32 Debug +!MESSAGE No configuration specified. Defaulting to qcc - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "qcc - Win32 Release" && "$(CFG)" != "qcc - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "qcc.mak" CFG="qcc - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qcc - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "qcc - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "qcc - Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "qcc - 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 "" +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "$(OUTDIR)\qcc.exe" + +CLEAN : + -@erase ".\Release\qcc.exe" + -@erase ".\Release\qcc.obj" + -@erase ".\Release\pr_comp.obj" + -@erase ".\Release\pr_lex.obj" + -@erase ".\Release\cmdlib.obj" + -@erase ".\Release\vc40.pdb" + -@erase ".\Release\qcc.map" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /GX /Zi /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /ML /GX /Zi /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/qcc.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Release/ +CPP_SBRS= +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qcc.bsc" +BSC32_SBRS= +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 /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 /nologo /subsystem:console /profile /map /machine:I386 +LINK32_FLAGS=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 /profile /map:"$(INTDIR)/qcc.map"\ + /machine:I386 /out:"$(OUTDIR)/qcc.exe" +LINK32_OBJS= \ + "$(INTDIR)/qcc.obj" \ + "$(INTDIR)/pr_comp.obj" \ + "$(INTDIR)/pr_lex.obj" \ + "$(INTDIR)/cmdlib.obj" + +"$(OUTDIR)\qcc.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "qcc - 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 Target_Dir "" +OUTDIR=.\Debug +INTDIR=.\Debug + +ALL : "$(OUTDIR)\qcc.exe" + +CLEAN : + -@erase ".\Debug\vc40.pdb" + -@erase ".\Debug\vc40.idb" + -@erase ".\Debug\qcc.exe" + -@erase ".\Debug\pr_lex.obj" + -@erase ".\Debug\qcc.obj" + -@erase ".\Debug\cmdlib.obj" + -@erase ".\Debug\pr_comp.obj" + -@erase ".\Debug\qcc.map" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MLd /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/qcc.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Debug/ +CPP_SBRS= +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qcc.bsc" +BSC32_SBRS= +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 /subsystem:console /debug /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 /nologo /subsystem:console /profile /map /debug /machine:I386 +LINK32_FLAGS=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 /profile /map:"$(INTDIR)/qcc.map"\ + /debug /machine:I386 /out:"$(OUTDIR)/qcc.exe" +LINK32_OBJS= \ + "$(INTDIR)/pr_lex.obj" \ + "$(INTDIR)/qcc.obj" \ + "$(INTDIR)/cmdlib.obj" \ + "$(INTDIR)/pr_comp.obj" + +"$(OUTDIR)\qcc.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Target + +# Name "qcc - Win32 Release" +# Name "qcc - Win32 Debug" + +!IF "$(CFG)" == "qcc - Win32 Release" + +!ELSEIF "$(CFG)" == "qcc - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\pr_comp.c +DEP_CPP_PR_CO=\ + ".\qcc.h"\ + ".\..\common\cmdlib.h"\ + ".\pr_comp.h"\ + + +"$(INTDIR)\pr_comp.obj" : $(SOURCE) $(DEP_CPP_PR_CO) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qcc.c +DEP_CPP_QCC_C=\ + ".\qcc.h"\ + ".\..\common\cmdlib.h"\ + ".\pr_comp.h"\ + + +"$(INTDIR)\qcc.obj" : $(SOURCE) $(DEP_CPP_QCC_C) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\pr_lex.c +DEP_CPP_PR_LE=\ + ".\qcc.h"\ + ".\..\common\cmdlib.h"\ + ".\pr_comp.h"\ + + +"$(INTDIR)\pr_lex.obj" : $(SOURCE) $(DEP_CPP_PR_LE) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\cmdlib.c +DEP_CPP_CMDLI=\ + ".\..\common\cmdlib.h"\ + {$(INCLUDE)}"\sys\TYPES.H"\ + {$(INCLUDE)}"\sys\STAT.H"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +# End Target +# End Project +################################################################################ diff --git a/qutils/QCC/QCC.MDP b/qutils/QCC/QCC.MDP new file mode 100644 index 0000000000000000000000000000000000000000..7ba57155b624bf8fbb8f4eec8c7f0c1790a4c34b GIT binary patch literal 36352 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 Bl0E}jpF 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 literal 0 HcmV?d00001 diff --git a/qutils/QFILES/QFILES.C b/qutils/QFILES/QFILES.C new file mode 100644 index 0000000..cb732f0 --- /dev/null +++ b/qutils/QFILES/QFILES.C @@ -0,0 +1,251 @@ + +#include "cmdlib.h" + +#define MAX_SOUNDS 1024 +#define MAX_MODELS 1024 +#define MAX_FILES 1024 + +#define MAX_DATA_PATH 64 + + +char precache_sounds[MAX_SOUNDS][MAX_DATA_PATH]; +int precache_sounds_block[MAX_SOUNDS]; +int numsounds; + +char precache_models[MAX_MODELS][MAX_DATA_PATH]; +int precache_models_block[MAX_SOUNDS]; +int nummodels; + +char precache_files[MAX_FILES][MAX_DATA_PATH]; +int precache_files_block[MAX_SOUNDS]; +int numfiles; + + +typedef struct +{ + char name[56]; + int filepos, filelen; +} packfile_t; + +typedef struct +{ + char id[4]; + int dirofs; + int dirlen; +} packheader_t; + +packfile_t pfiles[4096], *pf; +FILE *packhandle; +int packbytes; + + +/* +=========== +PackFile + +Copy a file into the pak file +=========== +*/ +void PackFile (char *src, char *name) +{ + FILE *in; + int remaining, count; + char buf[4096]; + + if ( (byte *)pf - (byte *)pfiles > sizeof(pfiles) ) + Error ("Too many files in pak file"); + + in = SafeOpenRead (src); + remaining = filelength (in); + + pf->filepos = LittleLong (ftell (packhandle)); + pf->filelen = LittleLong (remaining); + strcpy (pf->name, name); + printf ("%64s : %7i\n", pf->name, remaining); + + packbytes += remaining; + + while (remaining) + { + if (remaining < sizeof(buf)) + count = remaining; + else + count = sizeof(buf); + SafeRead (in, buf, count); + SafeWrite (packhandle, buf, count); + remaining -= count; + } + + fclose (in); + pf++; +} + + +/* +=========== +CopyQFiles +=========== +*/ +void CopyQFiles (int blocknum) +{ + int i, p; + char srcfile[1024]; + char destfile[1024]; + char name[1024]; + packheader_t header; + int dirlen; + unsigned short crc; + + // create a pak file + pf = pfiles; + + sprintf (destfile, "%spak%i.pak", gamedir, blocknum); + packhandle = SafeOpenWrite (destfile); + SafeWrite (packhandle, &header, sizeof(header)); + + blocknum++; + + for (i=0 ; i : build a .pak file\n"); + printf ("qfiles -bspmodels : regenerates all brush models\n"); + exit (1); + } + + SetQdirFromPath (""); + + ReadFiles (); + + if (!strcmp (argv[1], "-pak")) + { + CopyQFiles (atoi(argv[2])); + } + else if (!strcmp (argv[1], "-bspmodels")) + { + BspModels (); + } + else + Error ("unknown command: %s", argv[1]); + + return 0; +} + diff --git a/qutils/QFILES/QFILES.MAK b/qutils/QFILES/QFILES.MAK new file mode 100644 index 0000000..f9f4a4f --- /dev/null +++ b/qutils/QFILES/QFILES.MAK @@ -0,0 +1,221 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=qfiles - Win32 Debug +!MESSAGE No configuration specified. Defaulting to qfiles - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "qfiles - Win32 Release" && "$(CFG)" != "qfiles - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "qfiles.mak" CFG="qfiles - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qfiles - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "qfiles - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +RSC=rc.exe +CPP=cl.exe + +!IF "$(CFG)" == "qfiles - 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 "" +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "$(OUTDIR)\qfiles.exe" + +CLEAN : + -@erase ".\Release\qfiles.exe" + -@erase ".\Release\qfiles.obj" + -@erase ".\Release\cmdlib.obj" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W1 /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /ML /W1 /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/qfiles.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Release/ +CPP_SBRS= +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qfiles.bsc" +BSC32_SBRS= +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 /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 /nologo /subsystem:console /machine:I386 +LINK32_FLAGS=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 /incremental:no\ + /pdb:"$(OUTDIR)/qfiles.pdb" /machine:I386 /out:"$(OUTDIR)/qfiles.exe" +LINK32_OBJS= \ + "$(INTDIR)/qfiles.obj" \ + "$(INTDIR)/cmdlib.obj" + +"$(OUTDIR)\qfiles.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "qfiles - 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 Target_Dir "" +OUTDIR=.\Debug +INTDIR=.\Debug + +ALL : "$(OUTDIR)\qfiles.exe" + +CLEAN : + -@erase ".\Debug\qfiles.exe" + -@erase ".\Debug\qfiles.obj" + -@erase ".\Debug\cmdlib.obj" + -@erase ".\Debug\qfiles.ilk" + -@erase ".\Debug\qfiles.pdb" + -@erase ".\Debug\vc40.pdb" + -@erase ".\Debug\vc40.idb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W1 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MLd /W1 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG"\ + /D "_CONSOLE" /Fp"$(INTDIR)/qfiles.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Debug/ +CPP_SBRS= +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qfiles.bsc" +BSC32_SBRS= +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 /subsystem:console /debug /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 /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=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 /incremental:yes\ + /pdb:"$(OUTDIR)/qfiles.pdb" /debug /machine:I386 /out:"$(OUTDIR)/qfiles.exe" +LINK32_OBJS= \ + "$(INTDIR)/qfiles.obj" \ + "$(INTDIR)/cmdlib.obj" + +"$(OUTDIR)\qfiles.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Target + +# Name "qfiles - Win32 Release" +# Name "qfiles - Win32 Debug" + +!IF "$(CFG)" == "qfiles - Win32 Release" + +!ELSEIF "$(CFG)" == "qfiles - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\qfiles.c +DEP_CPP_QFILE=\ + ".\..\common\cmdlib.h"\ + + +"$(INTDIR)\qfiles.obj" : $(SOURCE) $(DEP_CPP_QFILE) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\cmdlib.c +DEP_CPP_CMDLI=\ + ".\..\common\cmdlib.h"\ + {$(INCLUDE)}"\sys\types.h"\ + {$(INCLUDE)}"\sys\stat.h"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\cmdlib.h + +!IF "$(CFG)" == "qfiles - Win32 Release" + +!ELSEIF "$(CFG)" == "qfiles - Win32 Debug" + +!ENDIF + +# End Source File +# End Target +# End Project +################################################################################ diff --git a/qutils/QFILES/QFILES.MDP b/qutils/QFILES/QFILES.MDP new file mode 100644 index 0000000000000000000000000000000000000000..52b2e99bbf4fc798e329729291c0bc2afdbc6e4e GIT binary patch literal 36352 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 MAXLUMP) + Error ("Lump size exceeded %d, memory corrupted!",MAXLUMP); + +// +// write the grabbed lump to the wadfile +// + AddLump (lumpname,lumpbuffer,size,type, compression); +} + +/* +=========== +WriteFile + +Save as a seperate file instead of as a wadfile lump +=========== +*/ +void WriteFile (void) +{ + char filename[1024]; + char *exp; + + sprintf (filename,"%s/%s.lmp", destfile, lumpname); + exp = ExpandPath(filename); + printf ("saved %s\n", exp); + SaveFile (exp, lumpbuffer, lump_p-lumpbuffer); +} + +/* +================ +ParseScript +================ +*/ +void ParseScript (void) +{ + int cmd; + int size; + + do + { + // + // get a command / lump name + // + GetToken (true); + if (endofscript) + break; + if (!Q_strcasecmp (token,"$LOAD")) + { + GetToken (false); + LoadScreen (token); + continue; + } + + if (!Q_strcasecmp (token,"$DEST")) + { + GetToken (false); + strcpy (destfile, ExpandPath(token)); + continue; + } + + if (!Q_strcasecmp (token,"$SINGLEDEST")) + { + GetToken (false); + strcpy (destfile, token); + savesingle = true; + continue; + } + + + // + // new lump + // + if (strlen(token) >= sizeof(lumpname) ) + Error ("\"%s\" is too long to be a lump name",token); + memset (lumpname,0,sizeof(lumpname)); + strcpy (lumpname, token); + for (size=0 ; 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 d3319 || yh>199) + Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,xh,yh); + + transcolor = 255; + + +// +// fill in header +// + header = (qpic_t *)lump_p; + width = xh-xl+1; + header->width = LittleLong(width); + header->height = LittleLong(yh-yl+1); + +// +// start grabbing posts +// + lump_p = (byte *)header->data; + + for (y=yl ; y<= yh ; y++) + for (x=xl ; x<=xh ; x++) + *lump_p++ = SCRN(x,y); +} + +/* +============================================================================= + +COLORMAP GRABBING + +============================================================================= +*/ + +/* +=============== +BestColor +=============== +*/ +byte BestColor (int r, int g, int b, int start, int stop) +{ + int i; + int dr, dg, db; + int bestdistortion, distortion; + int bestcolor; + byte *pal; + +// +// let any color go to 0 as a last resort +// + bestdistortion = ( (int)r*r + (int)g*g + (int)b*b )*2; + bestcolor = 0; + + pal = lbmpalette + start*3; + for (i=start ; i<= stop ; i++) + { + dr = r - (int)pal[0]; + dg = g - (int)pal[1]; + db = b - (int)pal[2]; + pal += 3; + distortion = dr*dr + dg*dg + db*db; + if (distortion < bestdistortion) + { + if (!distortion) + return i; // perfect match + + bestdistortion = distortion; + bestcolor = i; + } + } + + return bestcolor; +} + + +/* +============== +GrabColormap + +filename COLORMAP levels fullbrights +the first map is an identiy 0-255 +the final map is all black except for the fullbrights +the remaining maps are evenly spread +fullbright colors start at the top of the palette. +============== +*/ +void GrabColormap (void) +{ + int levels, brights; + int l, c; + float frac, red, green, blue; + + GetToken (false); + levels = atoi (token); + GetToken (false); + brights = atoi (token); + +// identity lump + for (l=0 ; l<256 ; l++) + *lump_p++ = l; + +// shaded levels + for (l=1;l= 240) + { +return pix; + if (!fullbright) + { + fullbright = true; + r = 0; + g = 0; + b = 0; + } + } + else + { + if (fullbright) + continue; + } + + r += lbmpalette[pix*3]; + g += lbmpalette[pix*3+1]; + b += lbmpalette[pix*3+2]; + vis++; + } + + if (fullbright == 2) + return 255; + + r /= vis; + g /= vis; + b /= vis; + + if (!fullbright) + { + r += d_red; + g += d_green; + b += d_blue; + } + +// +// find the best color +// + bestdistortion = r*r + g*g + b*b; + bestcolor = 0; + if (fullbright) + { + i = 240; + e = 255; + } + else + { + i = 0; + e = 240; + } + + for ( ; i< e ; i++) + { + pix = i; //pixdata[i]; + + pal = lbmpalette + pix*3; + + dr = r - (int)pal[0]; + dg = g - (int)pal[1]; + db = b - (int)pal[2]; + + distortion = dr*dr + dg*dg + db*db; + if (distortion < bestdistortion) + { + if (!distortion) + { + d_red = d_green = d_blue = 0; // no distortion yet + return pix; // perfect match + } + + bestdistortion = distortion; + bestcolor = pix; + } + } + + if (!fullbright) + { // error diffusion + pal = lbmpalette + bestcolor*3; + d_red = r - (int)pal[0]; + d_green = g - (int)pal[1]; + d_blue = b - (int)pal[2]; + } + + return bestcolor; +} + + +/* +============== +GrabMip + +filename MIP x y width height +must be multiples of sixteen +============== +*/ +void GrabMip (void) +{ + int x,y,xl,yl,xh,yh,w,h; + byte *screen_p, *source; + int linedelta; + miptex_t *qtex; + int miplevel, mipstep; + int xx, yy, pix; + int count; + + GetToken (false); + xl = atoi (token); + GetToken (false); + yl = atoi (token); + GetToken (false); + w = atoi (token); + GetToken (false); + h = atoi (token); + + if ( (w & 15) || (h & 15) ) + Error ("line %i: miptex sizes must be multiples of 16", scriptline); + + xh = xl+w; + yh = yl+h; + + qtex = (miptex_t *)lump_p; + qtex->width = LittleLong(w); + qtex->height = LittleLong(h); + strcpy (qtex->name, lumpname); + + lump_p = (byte *)&qtex->offsets[4]; + + screen_p = byteimage + yl*byteimagewidth + xl; + linedelta = byteimagewidth - w; + + source = lump_p; + qtex->offsets[0] = LittleLong(lump_p - (byte *)qtex); + + for (y=yl ; yoffsets[miplevel] = LittleLong(lump_p - (byte *)qtex); + + mipstep = 1<.spr. +// + +#define INCLUDELIBS + + +#ifdef NeXT +#include +#endif + +#include "spritegn.h" + +#define MAX_BUFFER_SIZE 0x100000 +#define MAX_FRAMES 1000 + +dsprite_t sprite; +byte *byteimage, *lbmpalette; +int byteimagewidth, byteimageheight; +byte *lumpbuffer, *plump; +char spritedir[1024]; +char spriteoutname[1024]; +int framesmaxs[2]; +int framecount; + +typedef struct { + spriteframetype_t type; // single frame or group of frames + void *pdata; // either a dspriteframe_t or group info + float interval; // only used for frames in groups + int numgroupframes; // only used by group headers +} spritepackage_t; + +spritepackage_t frames[MAX_FRAMES]; + +void FinishSprite (void); +void Cmd_Spritename (void); + + +/* +============ +WriteFrame +============ +*/ +void WriteFrame (FILE *spriteouthandle, int framenum) +{ + dspriteframe_t *pframe; + dspriteframe_t frametemp; + + pframe = (dspriteframe_t *)frames[framenum].pdata; + frametemp.origin[0] = LittleLong (pframe->origin[0]); + frametemp.origin[1] = LittleLong (pframe->origin[1]); + frametemp.width = LittleLong (pframe->width); + frametemp.height = LittleLong (pframe->height); + + SafeWrite (spriteouthandle, &frametemp, sizeof (frametemp)); + SafeWrite (spriteouthandle, + (byte *)(pframe + 1), + pframe->height * pframe->width); +} + + +/* +============ +WriteSprite +============ +*/ +void WriteSprite (FILE *spriteouthandle) +{ + int i, groupframe, curframe; + dsprite_t spritetemp; + + sprite.boundingradius = sqrt (((framesmaxs[0] >> 1) * + (framesmaxs[0] >> 1)) + + ((framesmaxs[1] >> 1) * + (framesmaxs[1] >> 1))); + +// +// write out the sprite header +// + spritetemp.type = LittleLong (sprite.type); + spritetemp.boundingradius = LittleFloat (sprite.boundingradius); + spritetemp.width = LittleLong (framesmaxs[0]); + spritetemp.height = LittleLong (framesmaxs[1]); + spritetemp.numframes = LittleLong (sprite.numframes); + spritetemp.beamlength = LittleFloat (sprite.beamlength); + spritetemp.synctype = LittleFloat (sprite.synctype); + spritetemp.version = LittleLong (SPRITE_VERSION); + spritetemp.ident = LittleLong (IDSPRITEHEADER); + + SafeWrite (spriteouthandle, &spritetemp, sizeof(spritetemp)); + +// +// write out the frames +// + curframe = 0; + + for (i=0 ; i 255) || (h > 255)) + Error ("Sprite has a dimension longer than 255"); + + xh = xl+w; + yh = yl+h; + + pframe = (dspriteframe_t *)plump; + frames[framecount].pdata = pframe; + frames[framecount].type = SPR_SINGLE; + + if (TokenAvailable ()) + { + GetToken (false); + frames[framecount].interval = atof (token); + if (frames[framecount].interval <= 0.0) + Error ("Non-positive interval"); + } + else + { + frames[framecount].interval = 0.1; + } + + if (TokenAvailable ()) + { + GetToken (false); + pframe->origin[0] = -atoi (token); + GetToken (false); + pframe->origin[1] = atoi (token); + } + else + { + pframe->origin[0] = -(w >> 1); + pframe->origin[1] = h >> 1; + } + + pframe->width = w; + pframe->height = h; + + if (w > framesmaxs[0]) + framesmaxs[0] = w; + + if (h > framesmaxs[1]) + framesmaxs[1] = h; + + plump = (byte *)(pframe + 1); + + screen_p = byteimage + yl*byteimagewidth + xl; + linedelta = byteimagewidth - w; + + source = plump; + + for (y=yl ; y= MAX_FRAMES) + Error ("Too many frames; increase MAX_FRAMES\n"); +} + + +/* +=============== +Cmd_GroupStart +=============== +*/ +void Cmd_GroupStart (void) +{ + int groupframe; + + groupframe = framecount++; + + frames[groupframe].type = SPR_GROUP; + frames[groupframe].numgroupframes = 0; + + while (1) + { + GetToken (true); + if (endofscript) + Error ("End of file during group"); + + if (!strcmp (token, "$frame")) + { + Cmd_Frame (); + frames[groupframe].numgroupframes++; + } + else if (!strcmp (token, "$load")) + { + Cmd_Load (); + } + else if (!strcmp (token, "$groupend")) + { + break; + } + else + { + Error ("$frame, $load, or $groupend expected\n"); + } + + } + + if (frames[groupframe].numgroupframes == 0) + Error ("Empty group\n"); +} + + +/* +=============== +ParseScript +=============== +*/ +void ParseScript (void) +{ + while (1) + { + GetToken (true); + if (endofscript) + break; + + if (!strcmp (token, "$load")) + { + Cmd_Load (); + } + if (!strcmp (token, "$spritename")) + { + Cmd_Spritename (); + } + else if (!strcmp (token, "$type")) + { + Cmd_Type (); + } + else if (!strcmp (token, "$beamlength")) + { + Cmd_Beamlength (); + } + else if (!strcmp (token, "$sync")) + { + sprite.synctype = ST_SYNC; + } + else if (!strcmp (token, "$frame")) + { + Cmd_Frame (); + sprite.numframes++; + } + else if (!strcmp (token, "$load")) + { + Cmd_Load (); + } + else if (!strcmp (token, "$groupstart")) + { + Cmd_GroupStart (); + sprite.numframes++; + } + } +} + +/* +============== +Cmd_Spritename +============== +*/ +void Cmd_Spritename (void) +{ + if (sprite.numframes) + FinishSprite (); + + GetToken (false); + sprintf (spriteoutname, "%s%s.spr", spritedir, token); + memset (&sprite, 0, sizeof(sprite)); + framecount = 0; + + framesmaxs[0] = -9999999; + framesmaxs[1] = -9999999; + + lumpbuffer = malloc (MAX_BUFFER_SIZE * 2); // *2 for padding + if (!lumpbuffer) + Error ("Couldn't get buffer memory"); + + plump = lumpbuffer; + sprite.synctype = ST_RAND; // default +} + +/* +============== +FinishSprite +============== +*/ +void FinishSprite (void) +{ + FILE *spriteouthandle; + + if (sprite.numframes == 0) + Error ("no frames\n"); + + if (!strlen(spriteoutname)) + Error ("Didn't name sprite file"); + + if ((plump - lumpbuffer) > MAX_BUFFER_SIZE) + Error ("Sprite package too big; increase MAX_BUFFER_SIZE"); + + spriteouthandle = SafeOpenWrite (spriteoutname); + printf ("saving in %s\n", spriteoutname); + WriteSprite (spriteouthandle); + fclose (spriteouthandle); + + printf ("spritegen: successful\n"); + printf ("%d frame(s)\n", sprite.numframes); + printf ("%d ungrouped frame(s), including group headers\n", framecount); + + spriteoutname[0] = 0; // clear for a new sprite +} + +/* +============== +main + +============== +*/ +int main (int argc, char **argv) +{ + int i; + + if (argc != 2 && argc != 4) + Error ("usage: spritegen [-archive directory] file.qc"); + + if (!strcmp(argv[1], "-archive")) + { + archive = true; + strcpy (archivedir, argv[2]); + printf ("Archiving source to: %s\n", archivedir); + i = 3; + } + else + i = 1; + + SetQdirFromPath (argv[i]); + ExtractFilePath (argv[i], spritedir); // chop the filename + +// +// load the script +// + LoadScriptFile (argv[i]); + + ParseScript (); + FinishSprite (); + + return 0; +} + diff --git a/qutils/SPRGEN/SPRGEN.MAK b/qutils/SPRGEN/SPRGEN.MAK new file mode 100644 index 0000000..c7982f3 --- /dev/null +++ b/qutils/SPRGEN/SPRGEN.MAK @@ -0,0 +1,300 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=sprgen - Win32 Debug +!MESSAGE No configuration specified. Defaulting to sprgen - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "sprgen - Win32 Release" && "$(CFG)" != "sprgen - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "sprgen.mak" CFG="sprgen - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "sprgen - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "sprgen - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "sprgen - Win32 Debug" +RSC=rc.exe +CPP=cl.exe + +!IF "$(CFG)" == "sprgen - 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 "" +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "$(OUTDIR)\sprgen.exe" + +CLEAN : + -@erase ".\Release\sprgen.exe" + -@erase ".\Release\scriplib.obj" + -@erase ".\Release\sprgen.obj" + -@erase ".\Release\cmdlib.obj" + -@erase ".\Release\lbmlib.obj" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /ML /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/sprgen.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Release/ +CPP_SBRS= +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/sprgen.bsc" +BSC32_SBRS= +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 /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 /nologo /subsystem:console /machine:I386 +LINK32_FLAGS=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 /incremental:no\ + /pdb:"$(OUTDIR)/sprgen.pdb" /machine:I386 /out:"$(OUTDIR)/sprgen.exe" +LINK32_OBJS= \ + ".\Release\scriplib.obj" \ + ".\Release\sprgen.obj" \ + ".\Release\cmdlib.obj" \ + ".\Release\lbmlib.obj" + +"$(OUTDIR)\sprgen.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "sprgen - 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 Target_Dir "" +OUTDIR=.\Debug +INTDIR=.\Debug + +ALL : "$(OUTDIR)\sprgen.exe" + +CLEAN : + -@erase ".\Debug\vc40.pdb" + -@erase ".\Debug\vc40.idb" + -@erase ".\Debug\sprgen.exe" + -@erase ".\Debug\cmdlib.obj" + -@erase ".\Debug\scriplib.obj" + -@erase ".\Debug\lbmlib.obj" + -@erase ".\Debug\sprgen.obj" + -@erase ".\Debug\sprgen.ilk" + -@erase ".\Debug\sprgen.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MLd /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/sprgen.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Debug/ +CPP_SBRS= +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/sprgen.bsc" +BSC32_SBRS= +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 /subsystem:console /debug /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 /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=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 /incremental:yes\ + /pdb:"$(OUTDIR)/sprgen.pdb" /debug /machine:I386 /out:"$(OUTDIR)/sprgen.exe" +LINK32_OBJS= \ + ".\Debug\cmdlib.obj" \ + ".\Debug\scriplib.obj" \ + ".\Debug\lbmlib.obj" \ + ".\Debug\sprgen.obj" + +"$(OUTDIR)\sprgen.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Target + +# Name "sprgen - Win32 Release" +# Name "sprgen - Win32 Debug" + +!IF "$(CFG)" == "sprgen - Win32 Release" + +!ELSEIF "$(CFG)" == "sprgen - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\sprgen.c + +!IF "$(CFG)" == "sprgen - Win32 Release" + +DEP_CPP_SPRGE=\ + ".\spritegn.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\scriplib.h"\ + ".\..\common\lbmlib.h"\ + + +"$(INTDIR)\sprgen.obj" : $(SOURCE) $(DEP_CPP_SPRGE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "sprgen - Win32 Debug" + +DEP_CPP_SPRGE=\ + ".\spritegn.h"\ + ".\..\common\cmdlib.h"\ + + +"$(INTDIR)\sprgen.obj" : $(SOURCE) $(DEP_CPP_SPRGE) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\cmdlib.c +DEP_CPP_CMDLI=\ + ".\..\common\cmdlib.h"\ + {$(INCLUDE)}"\sys\TYPES.H"\ + {$(INCLUDE)}"\sys\STAT.H"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\scriplib.c +DEP_CPP_SCRIP=\ + ".\..\common\cmdlib.h"\ + ".\..\common\scriplib.h"\ + + +"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\lbmlib.c +DEP_CPP_LBMLI=\ + ".\..\common\cmdlib.h"\ + ".\..\common\lbmlib.h"\ + + +"$(INTDIR)\lbmlib.obj" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\scriplib.h + +!IF "$(CFG)" == "sprgen - Win32 Release" + +!ELSEIF "$(CFG)" == "sprgen - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\lbmlib.h + +!IF "$(CFG)" == "sprgen - Win32 Release" + +!ELSEIF "$(CFG)" == "sprgen - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\cmdlib.h + +!IF "$(CFG)" == "sprgen - Win32 Release" + +!ELSEIF "$(CFG)" == "sprgen - Win32 Debug" + +!ENDIF + +# End Source File +# End Target +# End Project +################################################################################ diff --git a/qutils/SPRGEN/SPRGEN.MDP b/qutils/SPRGEN/SPRGEN.MDP new file mode 100644 index 0000000000000000000000000000000000000000..900e8ac6806f6ee039bb61ee85057b026ed9f63f GIT binary patch literal 36352 zcmeI5-EY%Y6u?i`5848yjJCkG(n~fzHfU1%!Jr!(ZIX6DNn17LQ=O1wUlLQt4z^R8 zu}Qpa(xiQVJ?)QS(%$w@@UWNdagUQ2JJjXNX1tL;h6lncV(x4*|AOb{y2oM1xKm>>Y5g-CY zfCvx)B0vOQ5CZ$42lm6uZ~%It5BlNY3oppty0M{m(-GG==qp>`V$r#8yE6n`X@K)J7v4T%_aZf>yM9&3FThD zjt#M^x;Z++l00822+O~HC_aPDyNvg!N{grw{@MnSi=7F}bZyHRN{Ct^)Pc2oW$l#B zm1Wt2+V}gCimSNQGG|%cQ4GCcmbmE(J+Zd|Jm{HJRqi z1xGVcM$8rLs>YJKQ??wvzWobq@0+x3rOKwPim5rC39fNXcH>Kw=$|$$#YM8F zWtXrwb7gKTW=-TP6zL5_^c7v>EMH|exNS)rU#|(IO}?tAE?eME#i)V%1_ciK7Scgy zy=&BW^;?wb_GRW)xP8m8?n?XLVbgxUDd#HcGD{S>x-472$JTv*>t$10ulWPE^`}jj z7r2dl!aDyWiu6d4#w-6M^yh6<#QVgxu>14~MY{cNHEK^q;KAW!CWC5tSMVNvOk%duN7y~$hV2(txnM)a= zMH>+y0z`la5CI}U1c(3;AOb{y2oM1xKm@`G9EMlmRd@{s;0O!?gQE})7o^%3kU$qq z{w#+jR@uZx>%X-Ai%Z0zOQ^K|OY6V>EJ2?{fCvx)B0vO)01+SpM1Tko0V1%y2)qHu z;5eLslkg_I1*hQj_Ubu7b_3R;AewpLad_M|Uvu;JCQ;qxr6v8c3-4Fk0aiUmy%N_TY=lPWF4lfWcb%_sydingMZrI=IXhO}cDJP^T>QgMTm zN=4T^E0&g5r2rPya&S`Xty9T6RmbI}3C#U;&EN)fY24TL+qik@xA&J+=Q%k~)L^en?r1?f7M;mPf5{_!? zWiJ)DxfLT{3M8IrrP!<|fsLl^K|*p7`WrlXA(cr@=2D(7S8C|98Q+cPMxNlpvrS!i zf#Y3wc&HQ0HoQ?Gt}AV#XAahSWJRS?gY*8qEuGiI3B&W-Ync!m&&$PaKzlAV^!>qDh&PEhQ97?pm-Cl!Jo50=68P55Hi>iV@gXFDb?t2zAIAv$;rDt?!%Jku!61JG&OI z&!=*+51LD~=N2ayHxp><=uKX_x|7HL1n>Y5g-CYfCvx)B0vP58v-$i!!VqI5g3Ir7>Bd)Hk^a=Fahs8H+`gz zJSzg-;!QW={XcEc8Uc6RWfF0GK?!*AQVeKbOsK$ufMy2Eq9_8I*F=2~!_u%U1Da(a z69hCrPFzRJRor{)j`Cv70)FxhLysT#;Nm@Bb(5C5$V+8>84rhAo`MJ~)crd{ulOt0 ziPr!qF05j5SmIceA+dT2QZ9h?wHP zB5i3ihVskZJhJ`2#l9*2EC2eTBM~41M1Tko0V42p1TMgP@IG9GNtnVllO&{`&KzlP ID*~PHFKMVft^fc4 literal 0 HcmV?d00001 diff --git a/qutils/SPRGEN/SPRGEN.NCB b/qutils/SPRGEN/SPRGEN.NCB new file mode 100644 index 0000000000000000000000000000000000000000..cf2cd4f4bcb59ab3b9998e95374d183f2017e675 GIT binary patch literal 82944 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 Ufmi~u1Y!xq5{M=6s+Pe22hY~&YXATM literal 0 HcmV?d00001 diff --git a/qutils/SPRGEN/SPRITEGN.H b/qutils/SPRGEN/SPRITEGN.H new file mode 100644 index 0000000..6427d60 --- /dev/null +++ b/qutils/SPRGEN/SPRITEGN.H @@ -0,0 +1,88 @@ +// +// spritegn.h: header file for sprite generation program +// + +// ********************************************************** +// * This file must be identical in the spritegen directory * +// * and in the Quake directory, because it's used to * +// * pass data from one to the other via .spr files. * +// ********************************************************** + +//------------------------------------------------------- +// This program generates .spr sprite package files. +// The format of the files is as follows: +// +// dsprite_t file header structure +// +// +// dspriteframe_t frame header structure +// sprite bitmap +// +// dspriteframe_t frame header structure +// sprite bitmap +// +//------------------------------------------------------- + +#ifdef INCLUDELIBS + +#include +#include +#include +#include + +#include "cmdlib.h" +#include "scriplib.h" +#include "lbmlib.h" + +#endif + +#define SPRITE_VERSION 1 + +// must match definition in modelgen.h +#ifndef SYNCTYPE_T +#define SYNCTYPE_T +typedef enum {ST_SYNC=0, ST_RAND } synctype_t; +#endif + +// TODO: shorten these? +typedef struct { + int ident; + int version; + int type; + float boundingradius; + int width; + int height; + int numframes; + float beamlength; + synctype_t synctype; +} dsprite_t; + +#define SPR_VP_PARALLEL_UPRIGHT 0 +#define SPR_FACING_UPRIGHT 1 +#define SPR_VP_PARALLEL 2 +#define SPR_ORIENTED 3 +#define SPR_VP_PARALLEL_ORIENTED 4 + +typedef struct { + int origin[2]; + int width; + int height; +} dspriteframe_t; + +typedef struct { + int numframes; +} dspritegroup_t; + +typedef struct { + float interval; +} dspriteinterval_t; + +typedef enum { SPR_SINGLE=0, SPR_GROUP } spriteframetype_t; + +typedef struct { + spriteframetype_t type; +} dspriteframetype_t; + +#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I') + // little-endian "IDSP" + diff --git a/qutils/SPRGEN/S_BUBBLE.SPR b/qutils/SPRGEN/S_BUBBLE.SPR new file mode 100644 index 0000000000000000000000000000000000000000..b9b0e8bccc261df7063f85ef799aec9b4d441cda GIT binary patch literal 588 zcmeZt2@YUnU|?VZ;?FFmjsid$gh6}|0Lg*CkN^Mwa{y_WJdjHZprNUOY^;{9o({5r xrk=i@CXxaTZGAmt`TrVPC|o3^RA$mKOwe4ese$T64Lx-f6&mWOd=yEVasXQy@E8C9 literal 0 HcmV?d00001 diff --git a/qutils/SPRGEN/S_EXPLOD.SPR b/qutils/SPRGEN/S_EXPLOD.SPR new file mode 100644 index 0000000000000000000000000000000000000000..c69a18d55095b8b141102564b51351704f53130d GIT binary patch literal 18972 zcmeI2%aYr;6^5NGvWt41s+l}T)@l+2C~2IEovEV9rYfcg$-HRRwp-+@aAuyS7k-B< z@&w{m67wH`QcG>|BG*(>l@KkFl!%Z2!NCD|K(#R5{PlOQUcLG~-hW^GdHfgb>HP=1 zsn9tp|Ej9$JM53=@o^}F2L=!PuXtdLh8W+{7=Yn7a0WNczzA+8h0nz&=l(|S-Y)ic zD4#z5<0g_P`@`W5ub+SY^#)sI24;^!ns-0{Z1xj1lj5K`0-^e;UpqyqdPQBwNJGW+$giUIaZK2l!>&*t4REAtTIPb8_hbEy-DHPRg40l z@&_!${_Za8LiG7xMk6$l2r&D*(J1N1Rm{)wyeM{1EB3i3dJm}a$4#E)e^pqQxr(tvd8bAuhZ{HEGeZ4kUKg30IFpgVwoKFkDGThQT0wSOzV?a zuF}IH-uO`@c#k{}S}K7;Hnc{zM=xZjoJ=4)S_)-sD5HH*=ZVBw7N2&2j>-@LQ|`Rm z?I5`KUc0-zBLQRi2w57XdOOV#zc2o|&*K&=E0Zg(PM%4Rl2g1p1cP{ldMYDTLMj&q zci8XTHa(Tz>m-&qb)>h4L-M-0M~Y)5@_)_g%b>xz-RRW(B56Jn`Xc+i+bEd7s0znW zI*hk+O{1RoY^U~%atu=GgK|yN5`pb@Cqp%-O(g1YxA!RGu9S#^>#V%+%zl?&H#Ex$ zBbHtlm(aTDRmYgwvpY{#p2?4$lY<9t^uVyDxY1$1U3HH60IGA7#H|aqR z^}(TW3QN;8*Eg&t&X&@JPD1qwO7X-q&q=7}lw|x>GaYbI1R%@eI8D;BtT|+H`&~g7 zxZ29VanQ@EMR5Y_bSZFGq(Zk=#g$(<7LD`0h?+-M0>gr!Kz)Tab2Hba2#XLV0LdS9 z0eIBYl9wHbAm)zuK&o>ROjY}cB{Qjzsk>dCUviTlnAE{cafx=8R0jp#(8P}R_;l$~ zW>aWVVA3d1its5!$%`7i%2iUrNCa4-`Wy``OT4uN>A+ZxU+PtI6-6#_@XB^eSSJGX>nH`6P?a7tISOAAeDPbp-T16QP;P`o0&MD2I;>dUdX71By z$hLYI)Ip;A{3-_kSJf~P8J!RGl=fDuRPN@Rv(u4rT&oo$5HHyko8%SGa zaj7i@m(+HG^NG^~7P|~ud2OJk)fl4A$9p?hjl%{$p%FkJjoU0g)6%-c%)q_`?yN%ACeR$x=Kze7H8bSs2MWKeobDY7-=-3NnErLu9^o

&F!g~eM%1Jcb~Oua)iiA4 zb0f)61`bU_&65;3b&T1G`~%HAzxK0?N3$RTN12*I9Ev9?V6;x~u4LctgK{c3ax27% zQlkiJ2!kfBLf9yB6UVhIB3y+TEQXP2@5|;<6RYnGOoBdX#h*WKup>jU@cL|D=V+BsquxTVd} zNY%{s8X*sC-nil=M3=?FUClRYI7S~LG`Q8oBZd89!7#s}L;+i3cXq1%aKTm&pFe+! zWW`V#{CM>euIq+ZPYho+dtg{oH2Y>abKwD--!dA3(gPj5z}*5G3^N@v`f$Q5%m5cA zw0tne55pM~W>3;!%mT+n_!NfjB(#LtN769y&pigV!PLQYKAYO%o4<8~hQ+M+ zmTA1VC$5(!56)Cf?YD2c+Gto-GS`!<$)X1ldM5T9Ww2G3*Y6MMY1#k(UO=muCQD9WT zB4NAUChr>7lH_88qu8^Vi)0MhcMa~!b-7L=&Kv(_hlz>c_Vfvvdx|u==GJR;iEG=O zHGsyL;W4G_`B*6=F|80#;2Pw|9vs7s25vlNoC`Q5MnaXUTwkFn67nexj7E-z!xXKX zQ|HxkP)s~`itcF~#A963oQ5G1&Gkf6d}u<9^E8!M%Ydu%dZ0hK(wo^q zV-MQ1sl>w2jkhHQ*-5eV+^4DCh*dV$u#|oIiCW%KxTu&}$6h-(#RHt#6Z+kaQY3g3 zp72k(PGh7g&4md$oeFz0bEeKFMSmm4;+@*Zt7Z&|kFcmi;e>ATWjlExN}#`ywvJDqqHQW!#oHBO^8LEliIAGU)678*rg>vXU7{5>Z%y z#JejUJzfGKBp!H*` zl0Ipe7C&;9<%ReerrteEBUeyEt;N!SwO=~ql%N7NW-L5m!qgs9hSmc{>jB4GqW@SAOxvkU4eW*E2!<7U zr0wvirENq9RAZI5Sptd47bGhuL%I%- zd|7;qH3`a15m09s$etkHrE-3rK&(mFEmne8dgRHQ!~m)k(YO^O6(Y|qAC3nP3?3Lf RFnD0_z~F(w1OIgo{2QzO4bT7p literal 0 HcmV?d00001 diff --git a/qutils/SPRGEN/S_LIGHT.SPR b/qutils/SPRGEN/S_LIGHT.SPR new file mode 100644 index 0000000000000000000000000000000000000000..90b482030f42bbdd6ab1413fa3d721d02674fe28 GIT binary patch literal 1080 zcmd6lT~5O=495rJ032agLE?osBrcF9j^m{JI34#w;sE96u3NUTJtE;Ms@ngD9ouiO zAMX#V)#{P+{q*^==IzJ-c^uzg(=9*0Si}p5FhsF&+p3urEh<74Jwq5$lG4Ujt5XUNr06A( zJY@xIa9|YGa~$_1TCBElv)$lg#Wcm!B|UrAGQ+!>P^?I=km8YpZ??Prfl#aV3TcgG z>_^}|gt<=Z`Vc7(J=stCX8i(OPec#p9qrq>p8O>6+b#81&)*w>LC$Uf!LMglO=9oQ z+yEym{R39%@@b+%GN_`Yy)%3!2d9IcLYYm0k#X<#3Z|$Em@E{y^!Hw|!CvG5r_Ui|lY~BX| literal 0 HcmV?d00001 diff --git a/qutils/TEXMAKE/TEXMAKE.C b/qutils/TEXMAKE/TEXMAKE.C new file mode 100644 index 0000000..4a10cf9 --- /dev/null +++ b/qutils/TEXMAKE/TEXMAKE.C @@ -0,0 +1,222 @@ +#include "cmdlib.h" +#include "mathlib.h" +#include "lbmlib.h" +#include "trilib.h" + + +triangle_t *faces; +int numfaces; + +byte pic[64000]; +byte *palette; + +int width, height; +int iwidth, iheight; + +float scale; + +char texname[20]; + + +/* +================ +BoundFaces +================ +*/ +vec3_t mins, maxs; + +void BoundFaces (void) +{ + int i,j,k; + triangle_t *pol; + float v; + + for (i=0 ; iverts[j][k]; + if (vmaxs[k]) + maxs[k] = v; + } + } + + for (i=0 ; i<3 ; i++) + { + mins[i] = floor(mins[i]); + maxs[i] = ceil(maxs[i]); + } + + width = maxs[0] - mins[0]; + height = maxs[2] - mins[2]; + + printf ("width: %i height: %i\n",width, height); + + scale = 8; + if (width*scale >= 150) + scale = 150.0 / width; + if (height*scale >= 190) + scale = 190.0 / height; + iwidth = ceil(width*scale) + 4; + iheight = ceil(height*scale) + 4; + + printf ("scale: %f\n",scale); + printf ("iwidth: %i iheight: %i\n",iwidth, iheight); +} + + +/* +============ +DrawLine + +Draw a fat line +============ +*/ +void DrawLine (int x1, int y1, int x2, int y2) +{ + int dx, dy; + int adx, ady; + int count; + float xfrac, yfrac, xstep, ystep; + unsigned sx, sy; + float u, v; + + dx = x2 - x1; + dy = y2 - y1; + adx = abs(dx); + ady = abs(dy); + + count = adx > ady ? adx : ady; + count ++; + + if (count > 300) + return; // don't ever hang up on bad data + + xfrac = x1; + yfrac = y1; + + xstep = (float)dx / count; + ystep = (float)dy / count; + + do + { + for (u=-0.1 ; u<=0.9 ; u+=0.999) + for (v=-0.1 ; v<=0.9 ; v+=0.999) + { + sx = xfrac+u; + sy = yfrac+v; + if (sx < 320 && sy < 200) + pic[sy*320+sx] = 255; + } + + xfrac += xstep; + yfrac += ystep; + count--; + } while (count > 0); +} + + +/* +============ +AddFace +============ +*/ +void AddFace (triangle_t *f) +{ + vec3_t v1, v2, normal; + int basex, basey; + int i, j; + int coords[3][2]; + +// +// determine which side to map the teture to +// + VectorSubtract (f->verts[0], f->verts[1], v1); + VectorSubtract (f->verts[2], f->verts[1], v2); + CrossProduct (v1, v2, normal); + + if (normal[1] > 0) + basex = iwidth + 2; + else + basex = 2; + basey = 2; + + for (i=0 ; i<3 ; i++) + { + coords[i][0] = Q_rint((f->verts[i][0] - mins[0])*scale + basex); + coords[i][1] = Q_rint( (maxs[2] - f->verts[i][2])*scale + basey); + } + +// +// draw lines +// + for (i=0 ; i<3 ; i++) + { + j = (i+1)%3; + DrawLine (coords[i][0], coords[i][1], + coords[j][0], coords[j][1]); + } +} + + +/* +============ +CalcPalette +============ +*/ +void CalcPalette (void) +{ + byte *picture; + LoadLBM (ExpandPath("id1/gfx/gamepal.lbm"), &picture, &palette); +} + + + +/* +============ +main +============ +*/ +void main (int argc, char **argv) +{ + int i; + char filename[1024]; + + if (argc == 1) + Error ("texmake polfile[.idpol]\nGenerates polfile.lbm and polfile_t.idpol\n"); + +// +// read the polfile +// + strcpy (filename, argv[1]); + DefaultExtension (filename, ".tri"); + SetQdirFromPath (filename); + LoadTriangleList (filename, &faces, &numfaces); + printf ("numfaces: %i\n",numfaces); + +// +// generate the texture coordinates +// + BoundFaces (); + +// +// generate the lbm +// + for (i=0 ; iHJO!@v84h$y_{2AfE3^N=UZXA1sGlv3Y%3De6xULe)43lZ&rBXFCpmL_ncrM)NTpMwF&!jrHA1dA>HCsAn~0`d>uQtP-( zo;DC@hmEi~U&u_PGlz~O^RJD*_uUKoWKhtZ2oM1xKm>>Y5g-CYfCvx)B0vO)01;Rh z1df5yra_p7-q^`m?$pLM3hrkF_WVG{L4>I@U!{7XKU_bL^uFGCCY*Y0N+mb?DU|;IaS!_xzah7!)+mRCN%u;;9 zW_ez*okjU{7e0L?XPUgEnk;9zo>S8r?LCF^9TT>tp$CRlQ;Q~=UC?;7QE9Jl#G1pd z>MUcpRogWh<=0W(JK{L%A{(`9mhSo{xXyLijrUPw`8#Bt(!)HwZ(DqDhXHP;?hU}pIcsNfjA?MDn7Q_)-6^yLlB zv0eMB$I=H5+&#`BM#YX!=Q-8W%7WXt?U6{mKIeCdQcp^z#S1>OUyM2w}?I48b^Q0c#172&%;cFPd z^Pd3U{&EpwCslvE*0OzSYwgFpk@-$|6dr@eVHfnn6To0MBrqE2Y7GLLVB{<5DXsqk z(E2X`t^aCeTK|=^0^NxK5g-CYfCvx)B0vO)01;R}1nB%{FqW-){&NpJg{vO>U_bsc z{24d^&#s@)CQtsAK-^#d6YKwd)7kU+kyo;8fSt=t3=Og~+41a1A=@raYR;uB+q6qI zOXbH|>eP9bnjB=Q97`mVGn!qg*j9q2GA!ZO46+lM?C9B3LH=@ja-uLfp2gBwHF1WU zTy=TM;|mph2|==|l~Hg3jgHxMAwJOvnAaKbMuCUhdgc5*FaZvvlL2HeNL@PHMh)7X~#BssDe4Q z=7oh?&Cq=-wqDev0%o;pSg3c{trgux*W;C8Jd5h05tcG6&Eeu`tZEKhh`Fj4hwCh) zTlf&MR8*~OSbR7)bo?kw*){KOMZUljY)bkP1D2-#J_1F7ohgIaD$ymG%$^#jVi`)&vv5A-;jJlv08IyNvKY$U5 zJK4SAAc{HBuy9WFox;gd>1&pRlbVo4*Xoi1fpeaMyR7Lc$9|J*UbOZ~_QmeHat%K~ zynp7`j@?(~t6U6yaHeAG+;s5^?s_vtoMMys1rs%X6C3pY72Vph)n)B_wJ*$e#(D~c z(KGm$q6^Z~s#D@#4yU*9aaXco%E9-{q{r~Ic7wcs`DHX>n!0NWim0+HvPykQy5}18 zDe9hU)TgY78XI(8Rq$st=?t%OJUMS^i{gh7D$dqU$RZZDSXN+bqnJ2wyNXUM zbafS#jnfyVvW4W!D>u|xm>!v4O(7OKyGkn^v7XH7b1mz5;C}EKe8K3G2oM1xKm>>Y z5g-CYfCvx)B0vO)01+Sp_Z@*Gr0|D0hhPwf;4r>p`Y0TO<8T6o@4KE-hyH&8-QpcA zcwMIbKinat{lB{w-)a9(Y!gQBM$`UZiuV7)ok80Fqy4{@-3Dt}$7%oX|Nkc`StJ5P qfCvzQH6cLf{{zgedj9`;cmZC7m*6Cfz$m04vnEkTjocpu;_wepb>Q*< literal 0 HcmV?d00001 diff --git a/qutils/TEXMAKE/TEXMAKE.NCB b/qutils/TEXMAKE/TEXMAKE.NCB new file mode 100644 index 0000000000000000000000000000000000000000..fbbe7a0810a57b1ba41b0435978032e9433acc5d GIT binary patch literal 58368 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 literal 0 HcmV?d00001 diff --git a/qutils/VIS/FLOW.C b/qutils/VIS/FLOW.C new file mode 100644 index 0000000..4e81b53 --- /dev/null +++ b/qutils/VIS/FLOW.C @@ -0,0 +1,475 @@ +#include "vis.h" + +int c_chains; +int c_portalskip, c_leafskip; +int c_vistest, c_mighttest; + +int active; + +void CheckStack (leaf_t *leaf, threaddata_t *thread) +{ + pstack_t *p; + + for (p=thread->pstack_head.next ; p ; p=p->next) + if (p->leaf == leaf) + Error ("CheckStack: leaf recursion"); +} + + +/* +============== +ClipToSeperators + +Source, pass, and target are an ordering of portals. + +Generates seperating planes canidates by taking two points from source and one +point from pass, and clips target by them. + +If target is totally clipped away, that portal can not be seen through. + +Normal clip keeps target on the same side as pass, which is correct if the +order goes source, pass, target. If the order goes pass, source, target then +flipclip should be set. +============== +*/ +winding_t *ClipToSeperators (winding_t *source, winding_t *pass, winding_t *target, qboolean flipclip) +{ + int i, j, k, l; + plane_t plane; + vec3_t v1, v2; + float d; + vec_t length; + int counts[3]; + qboolean fliptest; + +// check all combinations + for (i=0 ; inumpoints ; i++) + { + l = (i+1)%source->numpoints; + VectorSubtract (source->points[l] , source->points[i], v1); + + // fing a vertex of pass that makes a plane that puts all of the + // vertexes of pass on the front side and all of the vertexes of + // source on the back side + for (j=0 ; jnumpoints ; j++) + { + VectorSubtract (pass->points[j], source->points[i], v2); + + plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1]; + plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2]; + plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0]; + + // if points don't make a valid plane, skip it + + length = plane.normal[0] * plane.normal[0] + + plane.normal[1] * plane.normal[1] + + plane.normal[2] * plane.normal[2]; + + if (length < ON_EPSILON) + continue; + + length = 1/sqrt(length); + + plane.normal[0] *= length; + plane.normal[1] *= length; + plane.normal[2] *= length; + + plane.dist = DotProduct (pass->points[j], plane.normal); + + // + // find out which side of the generated seperating plane has the + // source portal + // + fliptest = false; + for (k=0 ; knumpoints ; k++) + { + if (k == i || k == l) + continue; + d = DotProduct (source->points[k], plane.normal) - plane.dist; + if (d < -ON_EPSILON) + { // source is on the negative side, so we want all + // pass and target on the positive side + fliptest = false; + break; + } + else if (d > ON_EPSILON) + { // source is on the positive side, so we want all + // pass and target on the negative side + fliptest = true; + break; + } + } + if (k == source->numpoints) + continue; // planar with source portal + + // + // flip the normal if the source portal is backwards + // + if (fliptest) + { + VectorSubtract (vec3_origin, plane.normal, plane.normal); + plane.dist = -plane.dist; + } + + // + // if all of the pass portal points are now on the positive side, + // this is the seperating plane + // + counts[0] = counts[1] = counts[2] = 0; + for (k=0 ; knumpoints ; k++) + { + if (k==j) + continue; + d = DotProduct (pass->points[k], plane.normal) - plane.dist; + if (d < -ON_EPSILON) + break; + else if (d > ON_EPSILON) + counts[0]++; + else + counts[2]++; + } + if (k != pass->numpoints) + continue; // points on negative side, not a seperating plane + + if (!counts[0]) + { + continue; // planar with seperating plane + } + + // + // flip the normal if we want the back side + // + if (flipclip) + { + VectorSubtract (vec3_origin, plane.normal, plane.normal); + plane.dist = -plane.dist; + } + + // + // clip target by the seperating plane + // + target = ClipWinding (target, &plane, false); + if (!target) + return NULL; // target is not visible + } + } + + return target; +} + + + +/* +================== +RecursiveLeafFlow + +Flood fill through the leafs +If src_portal is NULL, this is the originating leaf +================== +*/ +void RecursiveLeafFlow (int leafnum, threaddata_t *thread, pstack_t *prevstack) +{ + pstack_t stack; + portal_t *p; + plane_t backplane; + winding_t *source, *target; + leaf_t *leaf; + int i, j; + long *test, *might, *vis; + qboolean more; + + c_chains++; + + leaf = &leafs[leafnum]; + CheckStack (leaf, thread); + +// mark the leaf as visible + if (! (thread->leafvis[leafnum>>3] & (1<<(leafnum&7)) ) ) + { + thread->leafvis[leafnum>>3] |= 1<<(leafnum&7); + thread->base->numcansee++; + } + + prevstack->next = &stack; + stack.next = NULL; + stack.leaf = leaf; + stack.portal = NULL; + stack.mightsee = malloc(bitbytes); + might = (long *)stack.mightsee; + vis = (long *)thread->leafvis; + +// check all portals for flowing into other leafs + for (i=0 ; inumportals ; i++) + { + p = leaf->portals[i]; + + if ( ! (prevstack->mightsee[p->leaf>>3] & (1<<(p->leaf&7)) ) ) + { + c_leafskip++; + continue; // can't possibly see it + } + + // if the portal can't see anything we haven't allready seen, skip it + if (p->status == stat_done) + { + c_vistest++; + test = (long *)p->visbits; + } + else + { + c_mighttest++; + test = (long *)p->mightsee; + } + more = false; + for (j=0 ; jmightsee)[j] & test[j]; + if (might[j] & ~vis[j]) + more = true; + } + + if (!more) + { // can't see anything new + c_portalskip++; + continue; + } + +// get plane of portal, point normal into the neighbor leaf + stack.portalplane = p->plane; + VectorSubtract (vec3_origin, p->plane.normal, backplane.normal); + backplane.dist = -p->plane.dist; + + if (VectorCompare (prevstack->portalplane.normal, backplane.normal) ) + continue; // can't go out a coplanar face + + c_portalcheck++; + + stack.portal = p; + stack.next = NULL; + + target = ClipWinding (p->winding, &thread->pstack_head.portalplane, false); + if (!target) + continue; + + if (!prevstack->pass) + { // the second leaf can only be blocked if coplanar + + stack.source = prevstack->source; + stack.pass = target; + RecursiveLeafFlow (p->leaf, thread, &stack); + FreeWinding (target); + continue; + } + + target = ClipWinding (target, &prevstack->portalplane, false); + if (!target) + continue; + + source = CopyWinding (prevstack->source); + + source = ClipWinding (source, &backplane, false); + if (!source) + { + FreeWinding (target); + continue; + } + + c_portaltest++; + + if (testlevel > 0) + { + target = ClipToSeperators (source, prevstack->pass, target, false); + if (!target) + { + FreeWinding (source); + continue; + } + } + + if (testlevel > 1) + { + target = ClipToSeperators (prevstack->pass, source, target, true); + if (!target) + { + FreeWinding (source); + continue; + } + } + + if (testlevel > 2) + { + source = ClipToSeperators (target, prevstack->pass, source, false); + if (!source) + { + FreeWinding (target); + continue; + } + } + + if (testlevel > 3) + { + source = ClipToSeperators (prevstack->pass, target, source, true); + if (!source) + { + FreeWinding (target); + continue; + } + } + + stack.source = source; + stack.pass = target; + + c_portalpass++; + + // flow through it for real + RecursiveLeafFlow (p->leaf, thread, &stack); + + FreeWinding (source); + FreeWinding (target); + } + + free (stack.mightsee); +} + + +/* +=============== +PortalFlow + +=============== +*/ +void PortalFlow (portal_t *p) +{ + threaddata_t data; + + if (p->status != stat_working) + Error ("PortalFlow: reflowed"); + p->status = stat_working; + + p->visbits = malloc (bitbytes); + memset (p->visbits, 0, bitbytes); + + memset (&data, 0, sizeof(data)); + data.leafvis = p->visbits; + data.base = p; + + data.pstack_head.portal = p; + data.pstack_head.source = p->winding; + data.pstack_head.portalplane = p->plane; + data.pstack_head.mightsee = p->mightsee; + + RecursiveLeafFlow (p->leaf, &data, &data.pstack_head); + + p->status = stat_done; +} + + +/* +=============================================================================== + +This is a rough first-order aproximation that is used to trivially reject some +of the final calculations. + +=============================================================================== +*/ + +byte portalsee[MAX_PORTALS]; +int c_leafsee, c_portalsee; + +void SimpleFlood (portal_t *srcportal, int leafnum) +{ + int i; + leaf_t *leaf; + portal_t *p; + + if (srcportal->mightsee[leafnum>>3] & (1<<(leafnum&7)) ) + return; + srcportal->mightsee[leafnum>>3] |= (1<<(leafnum&7)); + c_leafsee++; + + leaf = &leafs[leafnum]; + + for (i=0 ; inumportals ; i++) + { + p = leaf->portals[i]; + if ( !portalsee[ p - portals ] ) + continue; + SimpleFlood (srcportal, p->leaf); + } +} + + +/* +============== +BasePortalVis +============== +*/ +void BasePortalVis (void) +{ + int i, j, k; + portal_t *tp, *p; + float d; + winding_t *w; + + for (i=0, p = portals ; imightsee = malloc (bitbytes); + memset (p->mightsee, 0, bitbytes); + + c_portalsee = 0; + memset (portalsee, 0, numportals*2); + + for (j=0, tp = portals ; jwinding; + for (k=0 ; knumpoints ; k++) + { + d = DotProduct (w->points[k], p->plane.normal) + - p->plane.dist; + if (d > ON_EPSILON) + break; + } + if (k == w->numpoints) + continue; // no points on front + + + w = p->winding; + for (k=0 ; knumpoints ; k++) + { + d = DotProduct (w->points[k], tp->plane.normal) + - tp->plane.dist; + if (d < -ON_EPSILON) + break; + } + if (k == w->numpoints) + continue; // no points on front + + portalsee[j] = 1; + c_portalsee++; + + } + + c_leafsee = 0; + SimpleFlood (p, p->leaf); + p->nummightsee = c_leafsee; +// printf ("portal:%4i c_leafsee:%4i \n", i, c_leafsee); + + } + +} + + + + + + + + + + + + + + diff --git a/qutils/VIS/SOUNDPVS.C b/qutils/VIS/SOUNDPVS.C new file mode 100644 index 0000000..ee351e9 --- /dev/null +++ b/qutils/VIS/SOUNDPVS.C @@ -0,0 +1,146 @@ + +#include "vis.h" + +/* + +Some textures (sky, water, slime, lava) are considered ambien sound emiters. +Find an aproximate distance to the nearest emiter of each class for each leaf. + +*/ + + +/* +==================== +SurfaceBBox + +==================== +*/ +void SurfaceBBox (dface_t *s, vec3_t mins, vec3_t maxs) +{ + int i, j; + int e; + int vi; + float *v; + + mins[0] = mins[1] = 999999; + maxs[0] = maxs[1] = -99999; + + for (i=0 ; inumedges ; i++) + { + e = dsurfedges[s->firstedge+i]; + if (e >= 0) + vi = dedges[e].v[0]; + else + vi = dedges[-e].v[1]; + v = dvertexes[vi].point; + + for (j=0 ; j<3 ; j++) + { + if (v[j] < mins[j]) + mins[j] = v[j]; + if (v[j] > maxs[j]) + maxs[j] = v[j]; + } + } +} + + +/* +==================== +CalcAmbientSounds + +==================== +*/ +void CalcAmbientSounds (void) +{ + int i, j, k, l; + dleaf_t *leaf, *hit; + byte *vis; + dface_t *surf; + vec3_t mins, maxs; + float d, maxd; + int ambient_type; + texinfo_t *info; + miptex_t *miptex; + int ofs; + float dists[NUM_AMBIENTS]; + float vol; + + for (i=0 ; i< portalleafs ; i++) + { + leaf = &dleafs[i+1]; + + // + // clear ambients + // + for (j=0 ; j>3] & (1<<(j&7))) ) + continue; + + // + // check this leaf for sound textures + // + hit = &dleafs[j+1]; + + for (k=0 ; k< hit->nummarksurfaces ; k++) + { + surf = &dfaces[dmarksurfaces[hit->firstmarksurface + k]]; + info = &texinfo[surf->texinfo]; + ofs = ((dmiptexlump_t *)dtexdata)->dataofs[info->miptex]; + miptex = (miptex_t *)(&dtexdata[ofs]); + + if ( !Q_strncasecmp (miptex->name, "*water", 6) ) + ambient_type = AMBIENT_WATER; + else if ( !Q_strncasecmp (miptex->name, "sky", 3) ) + ambient_type = AMBIENT_SKY; + else if ( !Q_strncasecmp (miptex->name, "*slime", 6) ) + ambient_type = AMBIENT_WATER; // AMBIENT_SLIME; + else if ( !Q_strncasecmp (miptex->name, "*lava", 6) ) + ambient_type = AMBIENT_LAVA; + else if ( !Q_strncasecmp (miptex->name, "*04water", 8) ) + ambient_type = AMBIENT_WATER; + else + continue; + + // find distance from source leaf to polygon + SurfaceBBox (surf, mins, maxs); + maxd = 0; + for (l=0 ; l<3 ; l++) + { + if (mins[l] > leaf->maxs[l]) + d = mins[l] - leaf->maxs[l]; + else if (maxs[l] < leaf->mins[l]) + d = leaf->mins[l] - mins[l]; + else + d = 0; + if (d > maxd) + maxd = d; + } + + maxd = 0.25; + if (maxd < dists[ambient_type]) + dists[ambient_type] = maxd; + } + } + + for (j=0 ; jambient_level[j] = vol*255; + } + } +} + diff --git a/qutils/VIS/VIS.C b/qutils/VIS/VIS.C new file mode 100644 index 0000000..f0a9a20 --- /dev/null +++ b/qutils/VIS/VIS.C @@ -0,0 +1,963 @@ +// vis.c + +#include "vis.h" + +#define MAX_THREADS 4 + +int numportals; +int portalleafs; + +portal_t *portals; +leaf_t *leafs; + +int c_portaltest, c_portalpass, c_portalcheck; + + +qboolean showgetleaf = true; + +int leafon; // the next leaf to be given to a thread to process + +#ifdef __alpha +pthread_mutex_t *my_mutex; +#endif + +byte *vismap, *vismap_p, *vismap_end; // past visfile +int originalvismapsize; + +byte *uncompressed; // [bitbytes*portalleafs] + +int bitbytes; // (portalleafs+63)>>3 +int bitlongs; + +#ifdef __alpha +int numthreads = 4; +#else +int numthreads = 1; +#endif + +qboolean fastvis; +qboolean verbose; +int testlevel = 2; + +#if 0 +void NormalizePlane (plane_t *dp) +{ + vec_t ax, ay, az; + + if (dp->normal[0] == -1.0) + { + dp->normal[0] = 1.0; + dp->dist = -dp->dist; + return; + } + if (dp->normal[1] == -1.0) + { + dp->normal[1] = 1.0; + dp->dist = -dp->dist; + return; + } + if (dp->normal[2] == -1.0) + { + dp->normal[2] = 1.0; + dp->dist = -dp->dist; + return; + } + + ax = fabs(dp->normal[0]); + ay = fabs(dp->normal[1]); + az = fabs(dp->normal[2]); + + if (ax >= ay && ax >= az) + { + if (dp->normal[0] < 0) + { + VectorSubtract (vec3_origin, dp->normal, dp->normal); + dp->dist = -dp->dist; + } + return; + } + + if (ay >= ax && ay >= az) + { + if (dp->normal[1] < 0) + { + VectorSubtract (vec3_origin, dp->normal, dp->normal); + dp->dist = -dp->dist; + } + return; + } + + if (dp->normal[2] < 0) + { + VectorSubtract (vec3_origin, dp->normal, dp->normal); + dp->dist = -dp->dist; + } +} +#endif + +void PlaneFromWinding (winding_t *w, plane_t *plane) +{ + vec3_t v1, v2; + +// calc plane + VectorSubtract (w->points[2], w->points[1], v1); + VectorSubtract (w->points[0], w->points[1], v2); + CrossProduct (v2, v1, plane->normal); + VectorNormalize (plane->normal); + plane->dist = DotProduct (w->points[0], plane->normal); +} + +//============================================================================= + +/* +================== +NewWinding +================== +*/ +winding_t *NewWinding (int points) +{ + winding_t *w; + int size; + + if (points > MAX_POINTS_ON_WINDING) + Error ("NewWinding: %i points", points); + + size = (int)((winding_t *)0)->points[points]; + w = malloc (size); + memset (w, 0, size); + + return w; +} + + +void FreeWinding (winding_t *w) +{ + if (!w->original) + free (w); +} + + +void pw(winding_t *w) +{ + int i; + for (i=0 ; inumpoints ; i++) + printf ("(%5.1f, %5.1f, %5.1f)\n",w->points[i][0], w->points[i][1],w->points[i][2]); +} + +void prl(leaf_t *l) +{ + int i; + portal_t *p; + plane_t pl; + + for (i=0 ; inumportals ; i++) + { + p = l->portals[i]; + pl = p->plane; + printf ("portal %4i to leaf %4i : %7.1f : (%4.1f, %4.1f, %4.1f)\n",(int)(p-portals),p->leaf,pl.dist, pl.normal[0], pl.normal[1], pl.normal[2]); + } +} + +/* +================== +CopyWinding +================== +*/ +winding_t *CopyWinding (winding_t *w) +{ + int size; + winding_t *c; + + size = (int)((winding_t *)0)->points[w->numpoints]; + c = malloc (size); + memcpy (c, w, size); + c->original = false; + return c; +} + + +/* +================== +ClipWinding + +Clips the winding to the plane, returning the new winding on the positive side +Frees the input winding. +If keepon is true, an exactly on-plane winding will be saved, otherwise +it will be clipped away. +================== +*/ +winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon) +{ + vec_t dists[MAX_POINTS_ON_WINDING]; + int sides[MAX_POINTS_ON_WINDING]; + int counts[3]; + vec_t dot; + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *neww; + int maxpts; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->points[i], split->normal); + dot -= split->dist; + dists[i] = dot; + if (dot > ON_EPSILON) + sides[i] = SIDE_FRONT; + else if (dot < -ON_EPSILON) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (keepon && !counts[0] && !counts[1]) + return in; + + if (!counts[0]) + { + FreeWinding (in); + return NULL; + } + if (!counts[1]) + return in; + + maxpts = in->numpoints+4; // can't use counts[0]+2 because + // of fp grouping errors + neww = NewWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->points[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->points[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (split->normal[j] == 1) + mid[j] = split->dist; + else if (split->normal[j] == -1) + mid[j] = -split->dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (neww->numpoints > maxpts) + Error ("ClipWinding: points exceeded estimate"); + +// free the original winding + FreeWinding (in); + + return neww; +} + + +//============================================================================= + +/* +============= +GetNextPortal + +Returns the next portal for a thread to work on +Returns the portals from the least complex, so the later ones can reuse +the earlier information. +============= +*/ +portal_t *GetNextPortal (void) +{ + int j; + portal_t *p, *tp; + int min; + + LOCK; + + min = 99999; + p = NULL; + + for (j=0, tp = portals ; jnummightsee < min && tp->status == stat_none) + { + min = tp->nummightsee; + p = tp; + } + } + + + if (p) + p->status = stat_working; + + UNLOCK; + + return p; +} + +/* +============== +LeafThread +============== +*/ +#ifdef __alpha +pthread_addr_t LeafThread (pthread_addr_t thread) +#else +void *LeafThread (int thread) +#endif +{ + portal_t *p; + +//printf ("Begining LeafThread: %i\n",(int)thread); + do + { + p = GetNextPortal (); + if (!p) + break; + + PortalFlow (p); + + if (verbose) + printf ("portal:%4i mightsee:%4i cansee:%4i\n", (int)(p - portals), p->nummightsee, p->numcansee); + } while (1); + +//printf ("Completed LeafThread: %i\n",(int)thread); + + return NULL; +} + +/* +=============== +CompressRow + +=============== +*/ +int CompressRow (byte *vis, byte *dest) +{ + int j; + int rep; + int visrow; + byte *dest_p; + + dest_p = dest; + visrow = (portalleafs + 7)>>3; + + for (j=0 ; jnumportals ; i++) + { + p = leaf->portals[i]; + if (p->status != stat_done) + Error ("portal not done"); + for (j=0 ; jvisbits[j]; + } + + if (outbuffer[leafnum>>3] & (1<<(leafnum&7))) + Error ("Leaf portals saw into leaf"); + + outbuffer[leafnum>>3] |= (1<<(leafnum&7)); + + numvis = 0; + for (i=0 ; i>3] & (1<<(i&3))) + numvis++; + +// +// compress the bit string +// + if (verbose) + printf ("leaf %4i : %4i visible\n", leafnum, numvis); + totalvis += numvis; + +#if 0 + i = (portalleafs+7)>>3; + memcpy (compressed, outbuffer, i); +#else + i = CompressRow (outbuffer, compressed); +#endif + + dest = vismap_p; + vismap_p += i; + + if (vismap_p > vismap_end) + Error ("Vismap expansion overflow"); + + dleafs[leafnum+1].visofs = dest-vismap; // leaf 0 is a common solid + + memcpy (dest, compressed, i); +} + + +/* +================== +CalcPortalVis +================== +*/ +void CalcPortalVis (void) +{ + int i; + +// fastvis just uses mightsee for a very loose bound + if (fastvis) + { + for (i=0 ; idist - p2->dist) > 0.01) + return false; + + for (i=0 ; i<3 ; i++) + if ( fabs(p1->normal[i] - p2->normal[i] ) > 0.001) + return false; + + return true; +} + +sep_t *Findpassages (winding_t *source, winding_t *pass) +{ + int i, j, k, l; + plane_t plane; + vec3_t v1, v2; + float d; + double length; + int counts[3]; + qboolean fliptest; + sep_t *sep, *list; + + list = NULL; + +// check all combinations + for (i=0 ; inumpoints ; i++) + { + l = (i+1)%source->numpoints; + VectorSubtract (source->points[l] , source->points[i], v1); + + // fing a vertex of pass that makes a plane that puts all of the + // vertexes of pass on the front side and all of the vertexes of + // source on the back side + for (j=0 ; jnumpoints ; j++) + { + VectorSubtract (pass->points[j], source->points[i], v2); + + plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1]; + plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2]; + plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0]; + + // if points don't make a valid plane, skip it + + length = plane.normal[0] * plane.normal[0] + + plane.normal[1] * plane.normal[1] + + plane.normal[2] * plane.normal[2]; + + if (length < ON_EPSILON) + continue; + + length = 1/sqrt(length); + + plane.normal[0] *= length; + plane.normal[1] *= length; + plane.normal[2] *= length; + + plane.dist = DotProduct (pass->points[j], plane.normal); + + // + // find out which side of the generated seperating plane has the + // source portal + // + fliptest = false; + for (k=0 ; knumpoints ; k++) + { + if (k == i || k == l) + continue; + d = DotProduct (source->points[k], plane.normal) - plane.dist; + if (d < -ON_EPSILON) + { // source is on the negative side, so we want all + // pass and target on the positive side + fliptest = false; + break; + } + else if (d > ON_EPSILON) + { // source is on the positive side, so we want all + // pass and target on the negative side + fliptest = true; + break; + } + } + if (k == source->numpoints) + continue; // planar with source portal + + // + // flip the normal if the source portal is backwards + // + if (fliptest) + { + VectorSubtract (vec3_origin, plane.normal, plane.normal); + plane.dist = -plane.dist; + } + + // + // if all of the pass portal points are now on the positive side, + // this is the seperating plane + // + counts[0] = counts[1] = counts[2] = 0; + for (k=0 ; knumpoints ; k++) + { + if (k==j) + continue; + d = DotProduct (pass->points[k], plane.normal) - plane.dist; + if (d < -ON_EPSILON) + break; + else if (d > ON_EPSILON) + counts[0]++; + else + counts[2]++; + } + if (k != pass->numpoints) + continue; // points on negative side, not a seperating plane + + if (!counts[0]) + continue; // planar with pass portal + + // + // save this out + // + count_sep++; + + sep = malloc(sizeof(*sep)); + sep->next = list; + list = sep; + sep->plane = plane; + } + } + + return list; +} + + + +/* +============ +CalcPassages +============ +*/ +void CalcPassages (void) +{ + int i, j, k; + int count, count2; + leaf_t *l; + portal_t *p1, *p2; + sep_t *sep; + passage_t *passages; + + printf ("building passages...\n"); + + count = count2 = 0; + for (i=0 ; inumportals ; j++) + { + p1 = l->portals[j]; + for (k=0 ; knumportals ; k++) + { + if (k==j) + continue; + + count++; + p2 = l->portals[k]; + + // definately can't see into a coplanar portal + if (PlaneCompare (&p1->plane, &p2->plane) ) + continue; + + count2++; + + sep = Findpassages (p1->winding, p2->winding); + if (!sep) + { +// Error ("No seperating planes found in portal pair"); + count_sep++; + sep = malloc(sizeof(*sep)); + sep->next = NULL; + sep->plane = p1->plane; + } + passages = malloc(sizeof(*passages)); + passages->planes = sep; + passages->from = p1->leaf; + passages->to = p2->leaf; + passages->next = l->passages; + l->passages = passages; + } + } + } + + printf ("numpassages: %i (%i)\n", count2, count); + printf ("total passages: %i\n", count_sep); +} + +//============================================================================= + +/* +============ +LoadPortals +============ +*/ +void LoadPortals (char *name) +{ + int i, j; + portal_t *p; + leaf_t *l; + char magic[80]; + FILE *f; + int numpoints; + winding_t *w; + int leafnums[2]; + plane_t plane; + + if (!strcmp(name,"-")) + f = stdin; + else + { + f = fopen(name, "r"); + if (!f) + { + printf ("LoadPortals: couldn't read %s\n",name); + printf ("No vising performed.\n"); + exit (1); + } + } + + if (fscanf (f,"%79s\n%i\n%i\n",magic, &portalleafs, &numportals) != 3) + Error ("LoadPortals: failed to read header"); + if (strcmp(magic,PORTALFILE)) + Error ("LoadPortals: not a portal file"); + + printf ("%4i portalleafs\n", portalleafs); + printf ("%4i numportals\n", numportals); + + bitbytes = ((portalleafs+63)&~63)>>3; + bitlongs = bitbytes/sizeof(long); + +// each file portal is split into two memory portals + portals = malloc(2*numportals*sizeof(portal_t)); + memset (portals, 0, 2*numportals*sizeof(portal_t)); + + leafs = malloc(portalleafs*sizeof(leaf_t)); + memset (leafs, 0, portalleafs*sizeof(leaf_t)); + + originalvismapsize = portalleafs*((portalleafs+7)/8); + + vismap = vismap_p = dvisdata; + vismap_end = vismap + MAX_MAP_VISIBILITY; + + for (i=0, p=portals ; i MAX_POINTS_ON_WINDING) + Error ("LoadPortals: portal %i has too many points", i); + if ( (unsigned)leafnums[0] > portalleafs + || (unsigned)leafnums[1] > portalleafs) + Error ("LoadPortals: reading portal %i", i); + + w = p->winding = NewWinding (numpoints); + w->original = true; + w->numpoints = numpoints; + + for (j=0 ; jpoints[j][k] = v[k]; + } + fscanf (f, "\n"); + + // calc plane + PlaneFromWinding (w, &plane); + + // create forward portal + l = &leafs[leafnums[0]]; + if (l->numportals == MAX_PORTALS_ON_LEAF) + Error ("Leaf with too many portals"); + l->portals[l->numportals] = p; + l->numportals++; + + p->winding = w; + VectorSubtract (vec3_origin, plane.normal, p->plane.normal); + p->plane.dist = -plane.dist; + p->leaf = leafnums[1]; + p++; + + // create backwards portal + l = &leafs[leafnums[1]]; + if (l->numportals == MAX_PORTALS_ON_LEAF) + Error ("Leaf with too many portals"); + l->portals[l->numportals] = p; + l->numportals++; + + p->winding = w; + p->plane = plane; + p->leaf = leafnums[0]; + p++; + + } + + fclose (f); +} + + +/* +=========== +main +=========== +*/ +int main (int argc, char **argv) +{ + char portalfile[1024]; + char source[1024]; + int i; + double start, end; + + printf ("---- vis ----\n"); + + for (i=1 ; i +extern pthread_mutex_t *my_mutex; +#define LOCK pthread_mutex_lock (my_mutex) +#define UNLOCK pthread_mutex_unlock (my_mutex) +#else +#define LOCK +#define UNLOCK +#endif + + +extern int numportals; +extern int portalleafs; + +extern portal_t *portals; +extern leaf_t *leafs; + +extern int c_portaltest, c_portalpass, c_portalcheck; +extern int c_portalskip, c_leafskip; +extern int c_vistest, c_mighttest; +extern int c_chains; + +extern byte *vismap, *vismap_p, *vismap_end; // past visfile + +extern qboolean showgetleaf; +extern int testlevel; + +extern byte *uncompressed; +extern int bitbytes; +extern int bitlongs; + + +void LeafFlow (int leafnum); +void BasePortalVis (void); + +void PortalFlow (portal_t *p); + +void CalcAmbientSounds (void); diff --git a/qutils/VIS/VIS.MAK b/qutils/VIS/VIS.MAK new file mode 100644 index 0000000..62736f8 --- /dev/null +++ b/qutils/VIS/VIS.MAK @@ -0,0 +1,288 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=vis - Win32 Debug +!MESSAGE No configuration specified. Defaulting to vis - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "vis - Win32 Release" && "$(CFG)" != "vis - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "vis.mak" CFG="vis - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "vis - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "vis - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "vis - Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "vis - 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 "" +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "$(OUTDIR)\vis.exe" + +CLEAN : + -@erase ".\Release\vis.exe" + -@erase ".\Release\soundpvs.obj" + -@erase ".\Release\vis.obj" + -@erase ".\Release\bspfile.obj" + -@erase ".\Release\flow.obj" + -@erase ".\Release\cmdlib.obj" + -@erase ".\Release\mathlib.obj" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /ML /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/vis.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Release/ +CPP_SBRS= +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/vis.bsc" +BSC32_SBRS= +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 /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 /nologo /subsystem:console /machine:I386 +LINK32_FLAGS=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 /incremental:no\ + /pdb:"$(OUTDIR)/vis.pdb" /machine:I386 /out:"$(OUTDIR)/vis.exe" +LINK32_OBJS= \ + "$(INTDIR)/soundpvs.obj" \ + "$(INTDIR)/vis.obj" \ + "$(INTDIR)/bspfile.obj" \ + "$(INTDIR)/flow.obj" \ + "$(INTDIR)/cmdlib.obj" \ + "$(INTDIR)/mathlib.obj" + +"$(OUTDIR)\vis.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "vis - 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 Target_Dir "" +OUTDIR=.\Debug +INTDIR=.\Debug + +ALL : "$(OUTDIR)\vis.exe" + +CLEAN : + -@erase ".\Debug\vc40.pdb" + -@erase ".\Debug\vc40.idb" + -@erase ".\Debug\vis.exe" + -@erase ".\Debug\mathlib.obj" + -@erase ".\Debug\vis.obj" + -@erase ".\Debug\cmdlib.obj" + -@erase ".\Debug\flow.obj" + -@erase ".\Debug\bspfile.obj" + -@erase ".\Debug\soundpvs.obj" + -@erase ".\Debug\vis.ilk" + -@erase ".\Debug\vis.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MLd /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/vis.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Debug/ +CPP_SBRS= +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/vis.bsc" +BSC32_SBRS= +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 /subsystem:console /debug /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 /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=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 /incremental:yes\ + /pdb:"$(OUTDIR)/vis.pdb" /debug /machine:I386 /out:"$(OUTDIR)/vis.exe" +LINK32_OBJS= \ + "$(INTDIR)/mathlib.obj" \ + "$(INTDIR)/vis.obj" \ + "$(INTDIR)/cmdlib.obj" \ + "$(INTDIR)/flow.obj" \ + "$(INTDIR)/bspfile.obj" \ + "$(INTDIR)/soundpvs.obj" + +"$(OUTDIR)\vis.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Target + +# Name "vis - Win32 Release" +# Name "vis - Win32 Debug" + +!IF "$(CFG)" == "vis - Win32 Release" + +!ELSEIF "$(CFG)" == "vis - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\vis.c +DEP_CPP_VIS_C=\ + ".\vis.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + + +"$(INTDIR)\vis.obj" : $(SOURCE) $(DEP_CPP_VIS_C) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\soundpvs.c +DEP_CPP_SOUND=\ + ".\vis.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + + +"$(INTDIR)\soundpvs.obj" : $(SOURCE) $(DEP_CPP_SOUND) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\flow.c +DEP_CPP_FLOW_=\ + ".\vis.h"\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + + +"$(INTDIR)\flow.obj" : $(SOURCE) $(DEP_CPP_FLOW_) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\cmdlib.c +DEP_CPP_CMDLI=\ + ".\..\common\cmdlib.h"\ + {$(INCLUDE)}"\sys\TYPES.H"\ + {$(INCLUDE)}"\sys\STAT.H"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\bspfile.c +DEP_CPP_BSPFI=\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + ".\..\common\bspfile.h"\ + + +"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\mathlib.c +DEP_CPP_MATHL=\ + ".\..\common\cmdlib.h"\ + ".\..\common\mathlib.h"\ + + +"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +# End Target +# End Project +################################################################################ diff --git a/qutils/VIS/VIS.MDP b/qutils/VIS/VIS.MDP new file mode 100644 index 0000000000000000000000000000000000000000..52df1133c152d59344104c12c81f774dde1445e6 GIT binary patch literal 35840 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 literal 0 HcmV?d00001 diff --git a/qutils/VIS/VIS.NCB b/qutils/VIS/VIS.NCB new file mode 100644 index 0000000000000000000000000000000000000000..09e69a67819d90c8b2a706bda8da1d4eb1336605 GIT binary patch literal 74752 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 aW7+kx5KB3yVU5P!DTT!@rocW*f&T~8Eou}1 literal 0 HcmV?d00001