From 4144a222d39c6d0f05fc0013585b6c138887889a Mon Sep 17 00:00:00 2001 From: Marc-Antoine Lortie Date: Mon, 16 Dec 2019 11:31:41 -0500 Subject: [PATCH] Added HL1 MDL loader tests. Added new unit test source files. Added MDL samples for tests. Updated CMakeLists file to include the new unit tests. --- test/CMakeLists.txt | 5 + test/models/MDL/MDL (HL1)/alpha_test.mdl | Bin 0 -> 264280 bytes test/models/MDL/MDL (HL1)/blend_additive.mdl | Bin 0 -> 4032 bytes test/models/MDL/MDL (HL1)/chrome_sphere.mdl | Bin 0 -> 18680 bytes .../MDL/MDL (HL1)/duplicate_bodyparts.mdl | Bin 0 -> 7652 bytes .../duplicate_sequence_groups.mdl | Bin 0 -> 7644 bytes .../duplicate_sequence_groups01.mdl | Bin 0 -> 92 bytes .../duplicate_sequence_groups02.mdl | Bin 0 -> 92 bytes .../duplicate_sequence_groups03.mdl | Bin 0 -> 92 bytes .../duplicate_sequence_groups04.mdl | Bin 0 -> 92 bytes .../duplicate_sequence_groups05.mdl | Bin 0 -> 92 bytes .../duplicate_sequence_groups06.mdl | Bin 0 -> 92 bytes .../duplicate_sequence_groups07.mdl | Bin 0 -> 92 bytes .../duplicate_sequence_groups08.mdl | Bin 0 -> 92 bytes .../duplicate_sequence_groups09.mdl | Bin 0 -> 92 bytes .../MDL/MDL (HL1)/duplicate_sequences.mdl | Bin 0 -> 6852 bytes .../MDL/MDL (HL1)/duplicate_submodels.mdl | Bin 0 -> 3672 bytes test/models/MDL/MDL (HL1)/man.mdl | Bin 0 -> 9732 bytes test/models/MDL/MDL (HL1)/man01.mdl | Bin 0 -> 76 bytes test/models/MDL/MDL (HL1)/manT.mdl | Bin 0 -> 9104 bytes .../MDL/MDL (HL1)/sequence_transitions.mdl | Bin 0 -> 6484 bytes .../MDL/MDL (HL1)/unnamed_bodyparts.mdl | Bin 0 -> 7652 bytes test/models/MDL/MDL (HL1)/unnamed_bones.mdl | Bin 0 -> 9124 bytes .../unnamed_sequence_groups.mdl | Bin 0 -> 7644 bytes .../unnamed_sequence_groups01.mdl | Bin 0 -> 92 bytes .../unnamed_sequence_groups02.mdl | Bin 0 -> 92 bytes .../unnamed_sequence_groups03.mdl | Bin 0 -> 92 bytes .../unnamed_sequence_groups04.mdl | Bin 0 -> 92 bytes .../unnamed_sequence_groups05.mdl | Bin 0 -> 92 bytes .../unnamed_sequence_groups06.mdl | Bin 0 -> 92 bytes .../unnamed_sequence_groups07.mdl | Bin 0 -> 92 bytes .../unnamed_sequence_groups08.mdl | Bin 0 -> 92 bytes .../unnamed_sequence_groups09.mdl | Bin 0 -> 92 bytes .../MDL/MDL (HL1)/unnamed_sequences.mdl | Bin 0 -> 6852 bytes test/unit/ImportExport/MDL/MDLHL1TestFiles.h | 59 +++ .../MDL/utMDLImporter_HL1_ImportSettings.cpp | 244 ++++++++++ .../MDL/utMDLImporter_HL1_Materials.cpp | 136 ++++++ .../MDL/utMDLImporter_HL1_Nodes.cpp | 458 ++++++++++++++++++ test/unit/ImportExport/utMDLImporter.cpp | 71 +++ 39 files changed, 973 insertions(+) create mode 100644 test/models/MDL/MDL (HL1)/alpha_test.mdl create mode 100644 test/models/MDL/MDL (HL1)/blend_additive.mdl create mode 100644 test/models/MDL/MDL (HL1)/chrome_sphere.mdl create mode 100644 test/models/MDL/MDL (HL1)/duplicate_bodyparts.mdl create mode 100644 test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups.mdl create mode 100644 test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups01.mdl create mode 100644 test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups02.mdl create mode 100644 test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups03.mdl create mode 100644 test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups04.mdl create mode 100644 test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups05.mdl create mode 100644 test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups06.mdl create mode 100644 test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups07.mdl create mode 100644 test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups08.mdl create mode 100644 test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups09.mdl create mode 100644 test/models/MDL/MDL (HL1)/duplicate_sequences.mdl create mode 100644 test/models/MDL/MDL (HL1)/duplicate_submodels.mdl create mode 100644 test/models/MDL/MDL (HL1)/man.mdl create mode 100644 test/models/MDL/MDL (HL1)/man01.mdl create mode 100644 test/models/MDL/MDL (HL1)/manT.mdl create mode 100644 test/models/MDL/MDL (HL1)/sequence_transitions.mdl create mode 100644 test/models/MDL/MDL (HL1)/unnamed_bodyparts.mdl create mode 100644 test/models/MDL/MDL (HL1)/unnamed_bones.mdl create mode 100644 test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups.mdl create mode 100644 test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups01.mdl create mode 100644 test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups02.mdl create mode 100644 test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups03.mdl create mode 100644 test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups04.mdl create mode 100644 test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups05.mdl create mode 100644 test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups06.mdl create mode 100644 test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups07.mdl create mode 100644 test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups08.mdl create mode 100644 test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups09.mdl create mode 100644 test/models/MDL/MDL (HL1)/unnamed_sequences.mdl create mode 100644 test/unit/ImportExport/MDL/MDLHL1TestFiles.h create mode 100644 test/unit/ImportExport/MDL/utMDLImporter_HL1_ImportSettings.cpp create mode 100644 test/unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp create mode 100644 test/unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp create mode 100644 test/unit/ImportExport/utMDLImporter.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 23caae88c..2429ab25d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -128,6 +128,11 @@ SET( IMPORTERS unit/ImportExport/utOFFImportExport.cpp unit/ImportExport/utNFFImportExport.cpp unit/ImportExport/utXGLImportExport.cpp + unit/ImportExport/utMDLImporter.cpp + unit/ImportExport/MDL/MDLHL1TestFiles.h + unit/ImportExport/MDL/utMDLImporter_HL1_ImportSettings.cpp + unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp + unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp ) SET( MATERIAL diff --git a/test/models/MDL/MDL (HL1)/alpha_test.mdl b/test/models/MDL/MDL (HL1)/alpha_test.mdl new file mode 100644 index 0000000000000000000000000000000000000000..81b7f48e9c62865ae3a3a8dfa3d0cc065f24f2d7 GIT binary patch literal 264280 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 literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/blend_additive.mdl b/test/models/MDL/MDL (HL1)/blend_additive.mdl new file mode 100644 index 0000000000000000000000000000000000000000..21f947d83cdcd6bddda66dce3df55a1874c4691b GIT binary patch literal 4032 zcmeHJzl)q@5Pr^!7C{MuL=cN9M650#g5s|o4~qmW1OtKuZ!Yeh9PZwQ+{V@^Erk37 z7E_4$2c)p_rc}|!DqxE7KS&`eq&T11+vN_j5fg-f-0;oLeDltacb<8_m%Z@zdlydw zSX(>C=cC=pmF@9pxG~usj>dcEE{{h$!;Q`1aC^G_>1b^-9Mg3v<(Z}C`!cT3`}cXo zuwO_mTb<73bB_Rg@YE^bTXO5YeuH|;FWNv_#2>yL{r39$?#}4Qa<_IsYHQ17bUfnb znI8sx_nB?QU&EXyPhNO=&aWK#KaQ2vgU_~yu+|h<+ynFa8DYJwl=Sgr}td{uNL;E*M{4>51ws- z*G*zIy}G@*^YM7J_u%Pfk$s$Q5ctO^&r@C`x9wfZFUia3590kZv44Zu_j>DFThH&) zzQ3@yeu*<7@3&9u=YM;3(6PtuJX(VfKL6&W_F3rN=dF3|#rbIY7i|j++Iw}jQ{e2( z`b3*Z&+xt19-Udw;uK}Ctx_JYExz}S$>wxK9LH;yCs#W3Uy{)8S@P55{zmW0_u~B} zJf83MzO1;@J12C4z(YoW2hnHjGvR!5PtvXY`p4TUFo6p~kb)9GAqrKP!WE%NMJZqq zgBr}>hA^a|49q7Eb(k|T!jX<*t$+kHU;z(AAOjUZLK2#=geM}AiAta#1ua;?3sJ~I z6#$jqj#?Md=uj;vcPXMOYN9S0qA6OU^re|(s;(NUsai~6D%Msrb<;3S(=ug~;_Yg# z?i#M?TCVI|qT?;pLnAapE0l0Zc2Z0A)JVD(F~k8auv zPSixYwu!rVh^Kgoqr2%1S#O7xS%mqV_=@!|&D_nyJk86PlF@Xetts5oz1%qo31>e> zQ+R}Dc!hI3lFlZLe(8~(>6OlzNjW<=2A4;9mRC9YT(CV(n@*e|$HmF?6h#^flg=2D zDOtkda1ITSX_twHhe-6i#TqrUt{s+XSw=9}H(O*ky`k_-XXQQ_5{<7#?=m7YvVz4~ zhbb9NN80k>&h3b=-2H%u<$!;PT2LPTHTva*P7rv=2=GAiJ0kl`P*O|M$sKGbcd+w< M<6TzyzrBP11|x`|=Kufz literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/chrome_sphere.mdl b/test/models/MDL/MDL (HL1)/chrome_sphere.mdl new file mode 100644 index 0000000000000000000000000000000000000000..d69d700700a4089c4d7a529686b85d09088fef58 GIT binary patch literal 18680 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

x!GJ>YHm%p zH&+(dzWA@_yU(APiZ8BwwkHv1;F-ICcn#jOQSva_3Z&S*KY^W;mP+c;?MA&jgoH;XM6Gy;yHNoy@+@L-m_8iIdGG28F2%i zd@aPg@Pn3TX_f0mTz1dfzvm5S?r!JIZCB4#;--yL_n(xD9j5oXN&1K`R;>)f@H{#r zo-5V9KJ9vbI3u37t9^Xh^?Y?kJde+a=hN!>IBnhT9fRjHysY2|ZcW`>-57YBj@1K&?QnK&?QnK&?QnK&?QnK&?QnK&`<4PXWBbS;wst3|D3WdlcXQ z`b3zN$(WoemhB~x;xP%28mVlmdqk7%3>_e z5-f!UeUXN#h>5sJh!g;*ux3_OOvP0~rKq4tw(P1VX5uDcQcO@edyZEZb8(k&DK3zM zBSAI9LOdiwN(eOKB4E-YR>X@$ky39Jmy)n6*8#CoZQN0Y|a*Jg^jYBoRH>p zzzh=L8T4h%S*n_;xmu_d1tdnJBXVhO7G}i^E5UB4N0D-Kw{R4P`P4oF)tRyN-@fPf%350=!7-Ia$#k16`4~D&QJ49vMR*i&EioTYn&M{$sY2ap(zj>yISA5YxBGqZhc OmVNwSkpZ#$)5TwiM@2RO literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups.mdl b/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups.mdl new file mode 100644 index 0000000000000000000000000000000000000000..d815641dcc4c482b4cee3a4087ac6c2063ec2ae5 GIT binary patch literal 7644 zcmeHLJ#QRk5S|deKZNKg08N?7&WB?=Lc#+=LXn^fRTSyQ_%4a1^9TOur%XXfK{-W) zQc%)oO5hhzqX>XwW+xe0x0D-5T`n9qb+NH_trz5KjK3UBLc7 zY9IYvz;b+}9#iM{uMy>`U*0DA;GJro>-X#V!?&=2jrUip$^Sh6+1~D8f;4BRutalg zv$H#XfA`l7tZjr{u#c%ecHX3#jIjC!7WZ?xbOXmNV;-8OCg!QIW{;n6hwpRaG#@ANP7mEPjLY69*& zw+Xm>Wof5BY}q&kJ;T$xGIf?{CePJ*c$!bFnLO9#;Aup2j(Aq);OSj%FwKnT`W!qB zmUG0jItNd0j{2<4!_#~d%*@;RJUq>gX(rE&^YI)VY;W$~o7F?M6t0G{$IIgcy>Hd$ zAKu?QK$m|oxH~w=uKsZOpK_$XAJBtmf1?=h<4CNJ@jD#TmOW{WjYll2zV%t$(7Qew z^{zkFe$sE+MXI{L)e+N26-b{@R`@G?q##YhrEhlH9%c2lFCGM^^F5s36=`j~e}{D$ z=rYh{pvyp)fi44G2D%J%8R#<5WuVKz|1SghgtO6MqrtE;3)qwR@wXFUQYK?^reG>e zB*a1@q(Ua-LLpQHAGpLyqNGZu zNstCvkOxIj38F$=ND65oE98ZuP$@(toN`2yL_D`jA%RL}5f)`J7H0{T!h&l7!&JmX zTqHya9H_7+sw$@9Dxp$T5F}e(swQUQCSg)c5IKA9R~K_}mvAXANC!tc)esBukO(Ou z$PpI-lNPZeUL=Z?B9z&MJJU>$c?NBT3|V7NZe=qzXA8E%Mj1^C(v$;ckiefIzpSZJ z)lALRLaiuVVmB@XmgZ(*R?JWdc0)W0$j#ltt+=5)9EKnj*M)glgq1MVjEf<1#pYsO zEQ*z4l=lU~L$z@cYKU^7GFe6D%!P7#bdKOCjN+gUnIM&<@k|dgk@aTHtf?lqYlKEo zBm;3HL`0K<+#(Fjd1tU^e$`W@dxS@Ekb?&1+ OVo=0+7#NxV*8>1xz7j+L literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups02.mdl b/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups02.mdl new file mode 100644 index 0000000000000000000000000000000000000000..27a830ea99db9c011b66bfa5d8139f8efa7465d5 GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wj!7vk$jMAjEJ=+oPAx1=%}Y*=PcO1+ OVo=0+7#NxV*8>1x@e)M< literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups03.mdl b/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups03.mdl new file mode 100644 index 0000000000000000000000000000000000000000..bb972422f745b494084b6ca4d1eb13fae7216957 GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wj!7vk$jMAjEJ=+oPAx1=%}Y*=PcO1+ OVo=0+7#NxV*8>1yBoamd literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups04.mdl b/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups04.mdl new file mode 100644 index 0000000000000000000000000000000000000000..54473290fd5b8aa10f6fdcedef35e721655a81ce GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wj!7vk$jMAjEJ=+oPAx1=%}Y*=PcO1+ OVo=0+7#NxV*8>1yR}x16 literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups05.mdl b/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups05.mdl new file mode 100644 index 0000000000000000000000000000000000000000..594465528b3cdc4f26ef4cf0b97e8d6fd3202236 GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wj!7vk$jMAjEJ=+oPAx1=%}Y*=PcO1+ OVo=0+7#NxV*8>1yiV{cw literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups06.mdl b/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups06.mdl new file mode 100644 index 0000000000000000000000000000000000000000..aaf090ace3096395de1421b99c66b14c9e295e58 GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wj!7vk$jMAjEJ=+oPAx1=%}Y*=PcO1+ OVo=0+7#NxV*8>1yy%I?P literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups07.mdl b/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups07.mdl new file mode 100644 index 0000000000000000000000000000000000000000..cd10b665aa43b8a322c796afbc8eecc7fefb759e GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wj!7vk$jMAjEJ=+oPAx1=%}Y*=PcO1+ OVo=0+7#NxV*8>1y@DfS@ literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups08.mdl b/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups08.mdl new file mode 100644 index 0000000000000000000000000000000000000000..e37672707c6e8e7338ba36d00fe7c5744258940a GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wj!7vk$jMAjEJ=+oPAx1=%}Y*=PcO1+ OVo=0+7#NxV*8>1zBN9sh literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups09.mdl b/test/models/MDL/MDL (HL1)/duplicate_sequence_groups/duplicate_sequence_groups09.mdl new file mode 100644 index 0000000000000000000000000000000000000000..1ca742eba9f078f35a405f023db11b526e5c4b1f GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wj!7vk$jMAjEJ=+oPAx1=%}Y*=PcO1+ OVo=0+7#NxV*8>1zRuW7A literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/duplicate_sequences.mdl b/test/models/MDL/MDL (HL1)/duplicate_sequences.mdl new file mode 100644 index 0000000000000000000000000000000000000000..923e3d76b533f29a5e5841aecb01a120a46ec172 GIT binary patch literal 6852 zcmeHLzi*sn40cEdsE|-s2IPUEQ^Jp`MM5H`VrV6hkmyt)ozvV`h;)~P>txmtLB?P;%0#44;)ZeqVpD?Z=Pb%lGE4fAP(Y z^F*|^wvL~z-TvNoujzLByWOUDu--k~>uqms4w}wE^TT1Yv(+4|^}9XnKPivjJ!v`n zdIc`eCvM$ZKuW&_{T#YX@4q?LKf`zqz{^&HCi5ThyyVD#yqf;5=T~=knyF=WHiVS5 z^gKE4@${YFHn6slZN)yN$>?9Weq}N~neKm^R#u01UiW&t+iN->PEpLxe*L^`FSy0L zcwe1ttogr-J^Jh7w~ub#d-w}tY+$}|^WMcv6>olDtT;SX3h${8M-P^VcTk{b7JiPZ8#M}8`4$K#(<>7s>DBjofd8-fLto(=b`|+&T)UrH& zA1{b^if!I(d3c{Jh_`cP9?m1%^6>t-0N!qMd-Je2I0CmcJ=ovg-1+WRf9p?AU!~P} ziucp_K6CK>=00vS`_1iUe{_3UKWmPPXSi$ByYCwG*BE8{5_*7fQtDkdu^nkF$M3_J z?S^;a!%G$G{v=M#OIGQPk-j|2^xkMr^ch{o>?>TxKvQq+R)25u;LJ+kQOB?DPbKs2 zIIXQ^pk<(Cpk<(Cpk<(Cpk<(Cpk<(Cpk?6y#{m9?v(d1TGOWx3@<;si`!iuuCS!7@ zU`i$uVj&SyAro?;5K19ZVkJ>hB~x;xP)a4lVS8YL5-#ZiIyfq*hFFM)L`a5! zBThjkO|cYDiIhyCVi(~|iyreT+L8>cF;{M7Gd5=nwq&EKrT}TdL1rXDJOjV1g;Lc_ z&DBCJ6(Qk`jj)xtS(v36I>BzJM`3bvw{S~0w1>k`q+(x~hecS1p=X?i$`#IOo)&4D zMs+Sw9=eT9=povL&Quqfiwot7=p4b3jOL&ZMUYCR@uCMzRKHn^HPy=P8ljO2GEg^4 zL^TD-Ey9qwP6m7Nt6nJGBRtZP9C;8D-q;9R4F7)S{=m$JI4nbaVNnWt{ME%jL=@rl literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/duplicate_submodels.mdl b/test/models/MDL/MDL (HL1)/duplicate_submodels.mdl new file mode 100644 index 0000000000000000000000000000000000000000..232f5d7e5deb34e5a16321254a2a1fb35622a1ff GIT binary patch literal 3672 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

yFxa4Cg>D&o?du!$pM{- zo)0<=Js+0phZU$&w zy&U+>1g)#*#5o}cw5}eEL!&5By-8vcW>S=>9{u}4>*{4E){m~9UO&2edj06?>Gh+l zr`M0Jo?bt?dV2ln>gn~PtEbnGu3mOx{pjlH^`on&*N?8AUO&2edj06?>Gh+lr`M0J zo?bt?dV2ln>hYAT>diYX{&O@@Z=TXr{&n65Vcq2+!>+`dp-vWtwGEz?RSmT+b+V+6 zuC|uo$Y435S0t_RZ~b~jx)N)bBWW1Xk}j+ywU)G1T1%7G^!ld`PqupfyRaJ7depkq zNs>DH9ik3Tw%Ud(v8J^ybsSPhzX#MA1|9t#xUeeKy435DI>V%newV0&i%#NQQvXrH NwXJojQve;d{{WG)SsVZW literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/man01.mdl b/test/models/MDL/MDL (HL1)/man01.mdl new file mode 100644 index 0000000000000000000000000000000000000000..40de728547d287a2a278befc14eef66cd0645ea5 GIT binary patch literal 76 lcmeZt2@d39U|`72Pf5)wj>%2TGceT4P00ZYkpz5zssY5*2XFuY literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/manT.mdl b/test/models/MDL/MDL (HL1)/manT.mdl new file mode 100644 index 0000000000000000000000000000000000000000..e1dd7c548cf0d365db1b73d7654daa97a4371f58 GIT binary patch literal 9104 zcmeHLv5H+s3_XeCB5tykD+dJb19pBugfs>l2a*)7q7B}{@WO7EgvH${`~mw3DuTa5 zwaY-d6#9fM(rxi_^oV0{wRi&$vLl$Q`v%RCbToIwyhmSu``sN}U(WAeALFVBw`KU3 z#`(vA?Yr!NjS55M^Fr;{tLdEe}wCQM^uc#HSte}H%J={vj!*T9?D zcJX}%e1CFsbo$lt^Orw7JKAiH&prh9-+b=^kB`s(!TaXd)0557b?^>8SD^SvHN1sS z^!$0rVqh__HwN@EayPhB)Gx9mf7a_a7j6gx4QVJt8{ja9JHkOnI?B-w1T5fz2r!U= z3UoktMmP}^Fp?;uC&*vLjTx&gRNI3DA~ zbC!C;6{VTGd6?5Y&C9&aWvgjPxYIq|%e@5~jl(gO?zb{z~EC%+*fWAqcAsXB%X}y(X^`BV%hdSJKj(7cU`_I!Qi-EE9{0wR!E|smp6rkMLpZF-&G*&}ud&>L z&!0=bek~xS--P}Hx=bf;EVNuCdW2E78b2-P@7HEX>%UknJ}*FB!t*bW#?7jIeLjPf zt@I{Y-T(CM-wv_1xoyWjqvaUAd*j-2eEMSlCED4W{jlxzpg(+NeMF~U6o!_&nisEo zHG$Op)nZTny8O+PTMr-qf*6OGAKrR+`AWsx#5?FIj-JbE-ZB>6kDfo>G}#{BX@NN- zFXP?C^BS!b-jCbGM!h|}Kb`|`^|9?`!7IF1HsWlJ+r#_l9C+({S)-N0`$@alsJDmr z?$yb`^mx!4fA??i>lY9z-aEMK3glD7 zO^mWVgT4U!y41UQX=^o>i}&}-cEdaT@%$bB;WAFeE!kV1_N((uA1sXYIn|l}syA&= z!f^lF(f#Fv|EvTabsph$|NG;f+Jc<#LHEZ z1SpwBSd_(BoF!P21$$wJsECQUNQfi?sIZn*RZPWILM2sDBwKA&6Eks>Fi8_s&R+iN zVlM6yF6ja~I4Y=yScr#2NQQtTPC+J3u@p~Nk_@adS8io9HfIaA zWTUF40BONNW+Xv81HY_=Qq@e&)j};5A>oaUu$8!3n57vy!EUHWVRCb~a7#C|hr>{$ zVqchtMOcQRXPk!070zj%7HOGAbuLgIx{XcfA=-t`R2P|x3+0OF9Kn%{=AaKnkV>WT zq6bV=zgdel)ynM}p^*wQP&Z0MH3i5m!jQR627B?VUMSroJkpUIc@Prb*a%z9{yud- SF|!#C%M3qQl!9LTbny=~RmT(n literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/unnamed_bodyparts.mdl b/test/models/MDL/MDL (HL1)/unnamed_bodyparts.mdl new file mode 100644 index 0000000000000000000000000000000000000000..bd73348695bdce4715100181a0d43b7492ace186 GIT binary patch literal 7652 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 literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups.mdl b/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups.mdl new file mode 100644 index 0000000000000000000000000000000000000000..1dff3a15a198a696eedc58a93531a4ea653bf7fa GIT binary patch literal 7644 zcmeHLJ#So95S6*~fCf``ux8`*wHZ?%vMf?lk=Ihe+}t;~e(?Im*$g z1)|0`Mq}yx;WeUq>DRZ3K6qz1ul4(*`GdExK%DF!uExLX_0M;%Fp~dMvIm5A* zq285ApfO*Z-j^F%hI+3|!N<_z^u96{@nlx-->Xkn(FVDf=*5>xzSv};LA}5yBN#BBD=Mb-{w>xz&^pjM z&^pjM&^pjM&^pjM&^pjM&^qw{a{yoAY;f6NFs#f1@i>0^{YaRU$(Woen39QvSV)9a z$b?)dgi`PYmsm-ZRLPWFDU?zP`PfK|)R36mD2x(ZPV6L3>SRvt6i(?xK^!DO8e~Bp z6hRq8Nt`4}nq*0y6iJyxBwTVti$uJ(N|Hb&vj~f_7>lz6OS0fzzz7vF5f=%OL;@Ao zLRH07TqRUe1x2#et!iQ>ZW1PGg38%zzq*)dK8eGyMoCMG*64POrv^Vpgf#5 zZo(PjxNtIcip=GOa%FUm;7G>d;2g>zm7?*o2Ts&^vzBYB#qAoQkqR?VH%de`CCDwp uz+CSP_VQP~RJuoaq=OthNQvFJ5m+4medPYY%#QJ9ImSOMYQQ-B*Tp{)o_=Zo literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups01.mdl b/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups01.mdl new file mode 100644 index 0000000000000000000000000000000000000000..f2989f5ea076beaa2b53460a9cdebf5bc251e39f GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wjw#K{OUzA8i7!qqEKSWzPK{45$}cS_HZau7P00Z&!wF(g MWOx`Dng7=V063u$aR2}S literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups02.mdl b/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups02.mdl new file mode 100644 index 0000000000000000000000000000000000000000..378b748b16faf0632454fd585837ca22d1587c23 GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wjw#K{OUzA8i7!qqEKSWzPK{45$}cS_HZao5P00Z&!wF(g MWOx`Dng7=V065kWasU7T literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups03.mdl b/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups03.mdl new file mode 100644 index 0000000000000000000000000000000000000000..2fb0ace12f36784ab8ee2ccce7c53f11c51f0859 GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wjw#K{OUzA8i7!qqEKSWzPK{45$}cS_HZa!9P00Z&!wF(g MWOx`Dng7=V067a0a{vGU literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups04.mdl b/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups04.mdl new file mode 100644 index 0000000000000000000000000000000000000000..cfef3a95e94c4e94db4220e674f8f7eff6913363 GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wjw#K{OUzA8i7!qqEKSWzPK{45$}cS_HZal4P00Z&!wF(g MWOx`Dng7=V069PrbN~PV literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups05.mdl b/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups05.mdl new file mode 100644 index 0000000000000000000000000000000000000000..6d636fb8bd143ce290c5f4d9f1aeb247d000a745 GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wjw#K{OUzA8i7!qqEKSWzPK{45$}cS_HZax8P00Z&!wF(g MWOx`Dng7=V06BFLbpQYW literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups06.mdl b/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups06.mdl new file mode 100644 index 0000000000000000000000000000000000000000..4b1a691ded82042b8e0c5805f9196dc2908a0df4 GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wjw#K{OUzA8i7!qqEKSWzPK{45$}cS_HZar6P00Z&!wF(g MWOx`Dng7=V06D4=b^rhX literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups07.mdl b/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups07.mdl new file mode 100644 index 0000000000000000000000000000000000000000..a778283f9ece392ec4df914f01234ecf951ff169 GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wjw#K{OUzA8i7!qqEKSWzPK{45$}cS_HZa%AP00Z&!wF(g MWOx`Dng7=V06E_gcK`qY literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups08.mdl b/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups08.mdl new file mode 100644 index 0000000000000000000000000000000000000000..f398522f5ecca70a8a1168d80c8c9edd69eddcb1 GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wjw#K{OUzA8i7!qqEKSWzPK{45$}cS_Hn7mkP00Z&!wF(g MWOx`Dng7=V06G*AcmMzZ literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups09.mdl b/test/models/MDL/MDL (HL1)/unnamed_sequence_groups/unnamed_sequence_groups09.mdl new file mode 100644 index 0000000000000000000000000000000000000000..da668949402cd744858b3407daafaf334bc658ff GIT binary patch literal 92 zcmeZt2@d39U|`72Pf5)wjw#K{OUzA8i7!qqEKSWzPK{45$}cS_Hn7yoP00Z&!wF(g MWOx`Dng7=V06Iw#c>n+a literal 0 HcmV?d00001 diff --git a/test/models/MDL/MDL (HL1)/unnamed_sequences.mdl b/test/models/MDL/MDL (HL1)/unnamed_sequences.mdl new file mode 100644 index 0000000000000000000000000000000000000000..8ed0646f0866eed4a2036c4b89f07b8153da0c4a GIT binary patch literal 6852 zcmeHLF>hQ&5FTR+K#>qF1)72)l`W8!AR*xaQ4k3vq)FIp51w~Gv9pk&bz)VUtaz0 z9U|J=+Q!e#z44vfqh@$xyfkH_cz5OT`(4{vEgRVI zqTMvC1*G)b&@Z6N^x<0z{TqyL0(jYKP&@wx&r4qJU#ynD>-iUZlV)k@&SsFZmOf5i z-SPC@KXVhbPL__U*gz(Mc}r!#gd|9XTCu$Gu}%AKtqw z;637ZrvtP#tPk(~74V*fa%o>5-Uln-J>vJ3zXVIHHCrFv`T%z2{Jy`BSHOG3@5kLr z7nb$$`(y>YC!t*0*N6A-74Qz5TZ6;VbO~=wv+4fr!Q_Y0sb}+PsjIXaPjNmi?lT8J z4)$?<*>7$&`}6zD_E~dOJi}e1&c3gpzr`rq*U(dp|4W^9t?i}8a&aEMZa18X4|gio z{Wea`OE&3^xxO^d^uc^i^ch{k?3=-~0ZpT=@5guA2WM7-9hWic{#0_@9jCYT4D<~2 z4D<~24D<~24D<~24D<~24D<|~KL+qGoXv;Lm0@KTkZ1AhU(ba}nT*Mqf+?9uh=oK* zg-pnWLMVkuiIqf2l}yQ%LMfFHkB!7g4S~sx!YGl;iJinroy^Id!YQ37h=U|ZgDl8{ zA}E6>iIXHrlPt-TA}N!IgbR*nB@wT!k|aRMEW)BJ#^Nl&k}U9r8KNR4;vylE2%y4R zR#h<-R|%C=L6L0bswQUQCSj5$sGPm_tBbj~OSq&9=-{ZJ8e$=EqctWXiGA%#$36T&DfkR*piK^ngXN+2bqxs@eKU37D`n!HCGF@RD{HC zIKo!qW?`0Q=mfi=9)-!x-NG&1&>jv$kqW;s4~wu2L(e!3l`A%>QT=8u)>JFEYlKEB$UxmF5!DnRw+KV# sdNbIIU-d%i9^sLW +#include +#include +#include +#include + +using namespace Assimp; + +class utMDLImporter_HL1_ImportSettings : public ::testing::Test { + +public: + // Test various import settings scenarios. + + void importSettings() { + + /* Verify that animations are *NOT* imported when + 'Read animations' is disabled. */ + load_with_import_setting_bool( + MDL_HL1_FILE_MAN, + AI_CONFIG_IMPORT_MDL_HL1_READ_ANIMATIONS, + false, // Set config value to false. + [&](const aiScene *scene) { + EXPECT_EQ(0, scene->mNumAnimations); + EXPECT_EQ(nullptr, scene->mRootNode->FindNode(AI_MDL_HL1_NODE_SEQUENCE_INFOS)); + EXPECT_EQ(nullptr, scene->mRootNode->FindNode(AI_MDL_HL1_NODE_SEQUENCE_GROUPS)); + EXPECT_EQ(nullptr, scene->mRootNode->FindNode(AI_MDL_HL1_NODE_SEQUENCE_TRANSITION_GRAPH)); + + expect_global_info_eq(scene, { + { 0, "NumSequences" }, + { 0, "NumTransitionNodes" } + }); + }); + + /* Verify that blend controllers info is *NOT* imported when + 'Read blend controllers' is disabled. */ + load_with_import_setting_bool( + MDL_HL1_FILE_MAN, + AI_CONFIG_IMPORT_MDL_HL1_READ_BLEND_CONTROLLERS, + false, // Set config value to false. + [&](const aiScene *scene) { + EXPECT_NE(0, scene->mNumAnimations); + + const aiNode *sequence_infos = scene->mRootNode->FindNode(AI_MDL_HL1_NODE_SEQUENCE_INFOS); + EXPECT_NE(nullptr, sequence_infos); + + for (unsigned int i = 0; i < sequence_infos->mNumChildren; ++i) + EXPECT_EQ(nullptr, sequence_infos->mChildren[i]->FindNode(AI_MDL_HL1_NODE_BLEND_CONTROLLERS)); + + expect_global_info_eq(scene, 0, "NumBlendControllers"); + }); + + /* Verify that animation events are *NOT* imported when + 'Read animation events' is disabled. */ + load_with_import_setting_bool( + MDL_HL1_FILE_MAN, + AI_CONFIG_IMPORT_MDL_HL1_READ_ANIMATION_EVENTS, + false, // Set config value to false. + [&](const aiScene *scene) { + EXPECT_NE(0, scene->mNumAnimations); + + const aiNode *sequence_infos = scene->mRootNode->FindNode(AI_MDL_HL1_NODE_SEQUENCE_INFOS); + EXPECT_NE(nullptr, sequence_infos); + + for (unsigned int i = 0; i < sequence_infos->mNumChildren; ++i) + EXPECT_EQ(nullptr, sequence_infos->mChildren[i]->FindNode(AI_MDL_HL1_NODE_ANIMATION_EVENTS)); + }); + + /* Verify that sequence transitions info is read when + 'Read sequence transitions' is enabled. */ + load_with_import_setting_bool( + ASSIMP_TEST_MDL_HL1_MODELS_DIR "sequence_transitions.mdl", + AI_CONFIG_IMPORT_MDL_HL1_READ_SEQUENCE_TRANSITIONS, + true, // Set config value to true. + [&](const aiScene *scene) { + EXPECT_NE(nullptr, scene->mRootNode->FindNode(AI_MDL_HL1_NODE_SEQUENCE_TRANSITION_GRAPH)); + expect_global_info_eq(scene, 4, "NumTransitionNodes"); + }); + + /* Verify that sequence transitions info is *NOT* read when + 'Read sequence transitions' is disabled. */ + load_with_import_setting_bool( + ASSIMP_TEST_MDL_HL1_MODELS_DIR "sequence_transitions.mdl", + AI_CONFIG_IMPORT_MDL_HL1_READ_SEQUENCE_TRANSITIONS, + false, // Set config value to false. + [&](const aiScene *scene) { + EXPECT_EQ(nullptr, scene->mRootNode->FindNode(AI_MDL_HL1_NODE_SEQUENCE_TRANSITION_GRAPH)); + expect_global_info_eq(scene, 0, "NumTransitionNodes"); + }); + + /* Verify that bone controllers info is *NOT* read when + 'Read bone controllers' is disabled. */ + load_with_import_setting_bool( + MDL_HL1_FILE_MAN, + AI_CONFIG_IMPORT_MDL_HL1_READ_BONE_CONTROLLERS, + false, // Set config value to false. + [&](const aiScene *scene) { + EXPECT_EQ(nullptr, scene->mRootNode->FindNode(AI_MDL_HL1_NODE_BONE_CONTROLLERS)); + expect_global_info_eq(scene, 0, "NumBoneControllers"); + }); + + /* Verify that attachments info is *NOT* read when + 'Read attachments' is disabled. */ + load_with_import_setting_bool( + MDL_HL1_FILE_MAN, + AI_CONFIG_IMPORT_MDL_HL1_READ_ATTACHMENTS, + false, // Set config value to false. + [&](const aiScene *scene) { + EXPECT_EQ(nullptr, scene->mRootNode->FindNode(AI_MDL_HL1_NODE_ATTACHMENTS)); + expect_global_info_eq(scene, 0, "NumAttachments"); + }); + + /* Verify that hitboxes info is *NOT* read when + 'Read hitboxes' is disabled. */ + load_with_import_setting_bool( + MDL_HL1_FILE_MAN, + AI_CONFIG_IMPORT_MDL_HL1_READ_HITBOXES, + false, // Set config value to false. + [&](const aiScene *scene) { + EXPECT_EQ(nullptr, scene->mRootNode->FindNode(AI_MDL_HL1_NODE_HITBOXES)); + expect_global_info_eq(scene, 0, "NumHitboxes"); + }); + + /* Verify that misc global info is *NOT* read when + 'Read misc global info' is disabled. */ + load_with_import_setting_bool( + MDL_HL1_FILE_MAN, + AI_CONFIG_IMPORT_MDL_HL1_READ_MISC_GLOBAL_INFO, + false, // Set config value to false. + [&](const aiScene *scene) { + aiNode *global_info = get_global_info(scene); + EXPECT_NE(nullptr, global_info); + aiVector3D temp; + EXPECT_FALSE(global_info->mMetaData->Get("EyePosition", temp)); + }); + } + +private: + void load_with_import_setting_bool( + const char *file_path, + const char *setting_key, + bool setting_value, + std::function &&func) { + Assimp::Importer importer; + importer.SetPropertyBool(setting_key, setting_value); + const aiScene *scene = importer.ReadFile(file_path, aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + func(scene); + } + + void load_with_import_setting_string( + const char *file_path, + const char *setting_key, + const char *setting_value, + std::function &&func) { + Assimp::Importer importer; + importer.SetPropertyString(setting_key, setting_value); + const aiScene *scene = importer.ReadFile(file_path, aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + func(scene); + } + + inline static aiNode *get_global_info(const aiScene *scene) { + return scene->mRootNode->FindNode(AI_MDL_HL1_NODE_GLOBAL_INFO); + } + + template + static void expect_global_info_eq( + const aiScene *scene, + T expected_value, + const char *key_name) { + aiNode *global_info = get_global_info(scene); + EXPECT_NE(nullptr, global_info); + T temp; + EXPECT_TRUE(global_info->mMetaData->Get(key_name, temp)); + EXPECT_EQ(expected_value, temp); + } + + template + static void expect_global_info_eq(const aiScene *scene, + std::initializer_list> p_kv) { + aiNode *global_info = get_global_info(scene); + EXPECT_NE(nullptr, global_info); + for (auto it = p_kv.begin(); it != p_kv.end(); ++it) { + T temp; + EXPECT_TRUE(global_info->mMetaData->Get(it->second, temp)); + EXPECT_EQ(it->first, temp); + } + } +}; + +TEST_F(utMDLImporter_HL1_ImportSettings, importSettings) { + importSettings(); +} diff --git a/test/unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp b/test/unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp new file mode 100644 index 000000000..df008e115 --- /dev/null +++ b/test/unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp @@ -0,0 +1,136 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +/** @file utMDLImporter_HL1_Materials.cpp + * @brief Half-Life 1 MDL loader materials tests. + */ + +#include "UnitTestPCH.h" +#include "AbstractImportExportBase.h" +#include +#include +#include +#include "MDLHL1TestFiles.h" +#include "MDL/HalfLife/HL1ImportDefinitions.h" + +using namespace Assimp; + +class utMDLImporter_HL1_Materials : public ::testing::Test { + +public: + /* Given an MDL model with a texture flagged as flatshade, + verify that the imported model has a flat shading model. */ + void flatShadeTexture() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "chrome_sphere.mdl", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + EXPECT_NE(nullptr, scene->mMaterials); + + aiShadingMode shading_mode; + scene->mMaterials[0]->Get(AI_MATKEY_SHADING_MODEL, shading_mode); + EXPECT_EQ(aiShadingMode_Flat, shading_mode); + } + + /* Given an MDL model with a chrome texture, verify that + the imported model has a chrome material. */ + void chromeTexture() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "chrome_sphere.mdl", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + EXPECT_NE(nullptr, scene->mMaterials); + + int chrome; + scene->mMaterials[0]->Get(AI_MDL_HL1_MATKEY_CHROME(aiTextureType_DIFFUSE, 0), chrome); + EXPECT_EQ(1, chrome); + } + + /* Given an MDL model with an additive texture, verify that + the imported model has an additive material. */ + void additiveBlendTexture() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "blend_additive.mdl", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + EXPECT_NE(nullptr, scene->mMaterials); + + aiBlendMode blend_mode; + scene->mMaterials[0]->Get(AI_MATKEY_BLEND_FUNC, blend_mode); + EXPECT_EQ(aiBlendMode_Additive, blend_mode); + } + + /* Given an MDL model with a color masked texture, verify that + the imported model has a color masked material. Ensure too + that the transparency color is the correct one. */ + void textureWithColorMask() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "alpha_test.mdl", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + EXPECT_NE(nullptr, scene->mMaterials); + + int texture_flags; + scene->mMaterials[0]->Get(AI_MATKEY_TEXFLAGS_DIFFUSE(0), texture_flags); + EXPECT_EQ(aiTextureFlags_UseAlpha, texture_flags); + + // The model has only one texture, a 256 color bitmap with + // a palette. Pure blue is the last color in the palette, + // and should be the transparency color. + aiColor3D transparency_color; + scene->mMaterials[0]->Get(AI_MATKEY_COLOR_TRANSPARENT, transparency_color); + EXPECT_EQ(aiColor3D(0, 0, 255), transparency_color); + } +}; + +TEST_F(utMDLImporter_HL1_Materials, flatShadeTexture) { + flatShadeTexture(); +} + +TEST_F(utMDLImporter_HL1_Materials, chromeTexture) { + chromeTexture(); +} + +TEST_F(utMDLImporter_HL1_Materials, additiveBlendTexture) { + additiveBlendTexture(); +} + +TEST_F(utMDLImporter_HL1_Materials, textureWithColorMask) { + textureWithColorMask(); +} diff --git a/test/unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp b/test/unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp new file mode 100644 index 000000000..efb1f8a06 --- /dev/null +++ b/test/unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp @@ -0,0 +1,458 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +/** @file utMDLImporter_HL1_Nodes.cpp + * @brief Half-Life 1 MDL loader nodes tests. + */ + +#include "UnitTestPCH.h" +#include "AbstractImportExportBase.h" +#include +#include +#include +#include "MDLHL1TestFiles.h" +#include "MDL/HalfLife/HL1ImportDefinitions.h" + +using namespace Assimp; + +class utMDLImporter_HL1_Nodes : public ::testing::Test { + +public: + /** + * @note The following tests require a basic understanding + * of the SMD format. For more information about SMD format, + * please refer to the SMD importer or go to VDC + * (Valve Developer Community). + */ + + /* Given a model with bones that have empty names, + verify that all the bones of the imported model + have unique and no empty names. + + "" <----+---- empty names + "" <----+ + "" <----+ + "Bone_3" | + "" <----+ + "Bone_2" | + "Bone_5" | + "" <----+ + "" <----+ + */ + void emptyBonesNames() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "unnamed_bones.mdl", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + + const std::vector expected_bones_names = { + "Bone", + "Bone_0", + "Bone_1", + "Bone_3", + "Bone_4", + "Bone_2", + "Bone_5", + "Bone_6", + "Bone_7" + }; + + expect_named_children(scene, AI_MDL_HL1_NODE_BONES, expected_bones_names); + } + + /* Given a model with bodyparts that have empty names, + verify that the imported model contains bodyparts with + unique and no empty names. + + $body "" <----+---- empty names + $body "Bodypart_1" | + $body "Bodypart_5" | + $body "Bodypart_6" | + $body "" <----+ + $body "Bodypart_2" | + $body "" <----+ + $body "Bodypart_3" | + $body "" <----+ + */ + void emptyBodypartsNames() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "unnamed_bodyparts.mdl", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + + const std::vector expected_bodyparts_names = { + "Bodypart", + "Bodypart_1", + "Bodypart_5", + "Bodypart_6", + "Bodypart_0", + "Bodypart_2", + "Bodypart_4", + "Bodypart_3", + "Bodypart_7" + }; + + expect_named_children(scene, AI_MDL_HL1_NODE_BODYPARTS, expected_bodyparts_names); + } + + /* Given a model with bodyparts that have duplicate names, + verify that the imported model contains bodyparts with + unique and no duplicate names. + + $body "Bodypart" <-----+ + $body "Bodypart_1" <--+ | + $body "Bodypart_2" | | + $body "Bodypart1" | | + $body "Bodypart" ---|--+ + $body "Bodypart_1" ---+ | + $body "Bodypart2" | + $body "Bodypart" ------+ + $body "Bodypart_4" + */ + void duplicateBodypartsNames() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "duplicate_bodyparts.mdl", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + + const std::vector expected_bodyparts_names = { + "Bodypart", + "Bodypart_1", + "Bodypart_2", + "Bodypart1", + "Bodypart_0", + "Bodypart_1_0", + "Bodypart2", + "Bodypart_3", + "Bodypart_4" + }; + + expect_named_children(scene, AI_MDL_HL1_NODE_BODYPARTS, expected_bodyparts_names); + } + + /* Given a model with several bodyparts that contains multiple + sub models with the same file name, verify for each bodypart + sub model of the imported model that they have a unique name. + + $bodygroup "first_bodypart" + { + studio "triangle" <------+ duplicate file names. + studio "triangle" -------+ + } | + | + $bodygroup "second_bodypart" | + { | + studio "triangle" -------+ same as first bodypart, but with same file. + studio "triangle" -------+ + } + + $bodygroup "last_bodypart" + { + studio "triangle2" <------+ duplicate names. + studio "triangle2" -------+ + } + */ + void duplicateSubModelsNames() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "duplicate_submodels.mdl", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + + const std::vector> expected_bodypart_sub_models_names = { + { + "triangle", + "triangle_0", + }, + { + "triangle_1", + "triangle_2", + }, + { + "triangle2", + "triangle2_0", + } + }; + + const aiNode *bodyparts_node = scene->mRootNode->FindNode(AI_MDL_HL1_NODE_BODYPARTS); + EXPECT_NE(nullptr, bodyparts_node); + EXPECT_EQ(3, bodyparts_node->mNumChildren); + for (unsigned int i = 0; i < bodyparts_node->mNumChildren; ++i) { + expect_named_children(bodyparts_node->mChildren[i], + expected_bodypart_sub_models_names[i]); + } + } + + /* Given a model with sequences that have duplicate names, verify + that each sequence from the imported model has a unique + name. + + $sequence "idle_1" <-------+ + $sequence "idle" <----+ | + $sequence "idle_2" | | + $sequence "idle" -----+ | + $sequence "idle_0" | | + $sequence "idle_1" -----|--+ + $sequence "idle_3" | + $sequence "idle" -----+ + $sequence "idle_7" + */ + void duplicateSequenceNames() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "duplicate_sequences.mdl", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + + const std::vector expected_sequence_names = { + "idle_1", + "idle", + "idle_2", + "idle_4", + "idle_0", + "idle_1_0", + "idle_3", + "idle_5", + "idle_7" + }; + + expect_named_children(scene, AI_MDL_HL1_NODE_SEQUENCE_INFOS, expected_sequence_names); + } + + /* Given a model with sequences that have empty names, verify + that each sequence from the imported model has a unique + name. + + $sequence "" <----+---- empty names + $sequence "Sequence_1" | + $sequence "" <----+ + $sequence "Sequence_4" | + $sequence "" <----+ + $sequence "Sequence_8" | + $sequence "" <----+ + $sequence "Sequence_2" | + $sequence "" <----+ + */ + void emptySequenceNames() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "unnamed_sequences.mdl", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + + const std::vector expected_sequence_names = { + "Sequence", + "Sequence_1", + "Sequence_0", + "Sequence_4", + "Sequence_3", + "Sequence_8", + "Sequence_5", + "Sequence_2", + "Sequence_6" + }; + + expect_named_children(scene, AI_MDL_HL1_NODE_SEQUENCE_INFOS, expected_sequence_names); + } + + /* Given a model with sequence groups that have duplicate names, + verify that each sequence group from the imported model has + a unique name. + + "default" + $sequencegroup "SequenceGroup" <----+ + $sequencegroup "SequenceGroup_1" | + $sequencegroup "SequenceGroup_5" <----|--+ + $sequencegroup "SequenceGroup" -----+ | + $sequencegroup "SequenceGroup_0" | | + $sequencegroup "SequenceGroup" -----+ | + $sequencegroup "SequenceGroup_5" --------+ + $sequencegroup "SequenceGroup_6" + $sequencegroup "SequenceGroup_2" + */ + void duplicateSequenceGroupNames() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "duplicate_sequence_groups/duplicate_sequence_groups.mdl", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + + const std::vector expected_sequence_names = { + "default", + "SequenceGroup", + "SequenceGroup_1", + "SequenceGroup_5", + "SequenceGroup_3", + "SequenceGroup_0", + "SequenceGroup_4", + "SequenceGroup_5_0", + "SequenceGroup_6", + "SequenceGroup_2" + }; + + expect_named_children(scene, AI_MDL_HL1_NODE_SEQUENCE_GROUPS, expected_sequence_names); + } + + /* Given a model with sequence groups that have empty names, + verify that each sequence group from the imported model has + a unique name. + + "default" + $sequencegroup "" <----+---- empty names + $sequencegroup "SequenceGroup_2" | + $sequencegroup "SequenceGroup_6" | + $sequencegroup "" <----+ + $sequencegroup "" <----+ + $sequencegroup "SequenceGroup_1" | + $sequencegroup "SequenceGroup_5" | + $sequencegroup "" <----+ + $sequencegroup "SequenceGroup_4" + */ + void emptySequenceGroupNames() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "unnamed_sequence_groups/unnamed_sequence_groups.mdl", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + + const std::vector expected_sequence_names = { + "default", + "SequenceGroup", + "SequenceGroup_2", + "SequenceGroup_6", + "SequenceGroup_0", + "SequenceGroup_3", + "SequenceGroup_1", + "SequenceGroup_5", + "SequenceGroup_7", + "SequenceGroup_4" + }; + + expect_named_children(scene, AI_MDL_HL1_NODE_SEQUENCE_GROUPS, expected_sequence_names); + } + + /* Verify that mOffsetMatrix applies the correct + inverse bind pose transform. */ + void offsetMatrixUnappliesTransformations() { + + const float TOLERANCE = 0.01f; + + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(MDL_HL1_FILE_MAN, aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + + aiNode *scene_bones_node = scene->mRootNode->FindNode(AI_MDL_HL1_NODE_BONES); + + const aiMatrix4x4 identity_matrix; + + for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { + aiMesh *scene_mesh = scene->mMeshes[i]; + for (unsigned int j = 0; j < scene_mesh->mNumBones; ++j) { + aiBone *scene_mesh_bone = scene_mesh->mBones[j]; + + // Store local node transforms. + aiNode *n = scene_bones_node->FindNode(scene_mesh_bone->mName); + std::vector bone_matrices = { n->mTransformation }; + while (n->mParent != scene->mRootNode) { + n = n->mParent; + bone_matrices.push_back(n->mTransformation); + } + + // Compute absolute node transform. + aiMatrix4x4 transform; + for (auto it = bone_matrices.rbegin(); it != bone_matrices.rend(); ++it) + transform *= *it; + + // Unapply the transformation using the offset matrix. + aiMatrix4x4 unapplied_transform = scene_mesh_bone->mOffsetMatrix * transform; + + // Ensure that we have, approximatively, the identity matrix. + expect_equal_matrices(identity_matrix, unapplied_transform, TOLERANCE); + } + } + } + +private: + void expect_named_children(const aiNode *parent_node, const std::vector &expected_names) { + EXPECT_NE(nullptr, parent_node); + EXPECT_EQ(expected_names.size(), parent_node->mNumChildren); + + for (unsigned int i = 0; i < parent_node->mNumChildren; ++i) + EXPECT_EQ(expected_names[i], parent_node->mChildren[i]->mName.C_Str()); + } + + void expect_named_children(const aiScene *scene, const char *node_name, const std::vector &expected_names) { + const aiNode *node = scene->mRootNode->FindNode(node_name); + expect_named_children(scene->mRootNode->FindNode(node_name), expected_names); + } + + void expect_equal_matrices(const aiMatrix4x4 &expected, const aiMatrix4x4 &actual, float abs_error) { + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) + EXPECT_NEAR(expected[i][j], actual[i][j], abs_error); + } + } +}; + +TEST_F(utMDLImporter_HL1_Nodes, emptyBonesNames) { + emptyBonesNames(); +} + +TEST_F(utMDLImporter_HL1_Nodes, emptyBodypartsNames) { + emptyBodypartsNames(); +} + +TEST_F(utMDLImporter_HL1_Nodes, duplicateBodypartsNames) { + duplicateBodypartsNames(); +} + +TEST_F(utMDLImporter_HL1_Nodes, duplicateSubModelsNames) { + duplicateSubModelsNames(); +} + +TEST_F(utMDLImporter_HL1_Nodes, emptySequenceNames) { + emptySequenceNames(); +} + +TEST_F(utMDLImporter_HL1_Nodes, duplicateSequenceNames) { + duplicateSequenceNames(); +} + +TEST_F(utMDLImporter_HL1_Nodes, emptySequenceGroupNames) { + emptySequenceGroupNames(); +} + +TEST_F(utMDLImporter_HL1_Nodes, duplicateSequenceGroupNames) { + duplicateSequenceGroupNames(); +} + +TEST_F(utMDLImporter_HL1_Nodes, offsetMatrixUnappliesTransformations) { + offsetMatrixUnappliesTransformations(); +} diff --git a/test/unit/ImportExport/utMDLImporter.cpp b/test/unit/ImportExport/utMDLImporter.cpp new file mode 100644 index 000000000..4c7149f54 --- /dev/null +++ b/test/unit/ImportExport/utMDLImporter.cpp @@ -0,0 +1,71 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +#include "UnitTestPCH.h" + +#include "AbstractImportExportBase.h" +#include +#include +#include + +#include "MDL/MDLHL1TestFiles.h" + +using namespace Assimp; + +class utMDLImporter : public AbstractImportExportBase { +public: + virtual bool importerTest() { + + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(MDL_HL1_FILE_MAN, 0); + EXPECT_NE(nullptr, scene); + + // Add further MDL tests... + + return true; + } +}; + +TEST_F(utMDLImporter, importMDLFromFileTest) { + EXPECT_TRUE(importerTest()); +}