Import MS3D.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. namespace MS3D{ // so that local structures are unique
  5. /******************************************************************************
  6. AngleQuaternion (x, y, z) works the same like Quaternion.set(-x,-y,-z)
  7. R_ConcatTransforms(a, b, c) works the same like c=b*a
  8. performed modifications on ms3d source files:
  9. removed #include <vector>
  10. std::vector -> std__vector
  11. msModel::Load(const char *filename) -> Load(C Str &filename);
  12. msModel::SetupJoints() -> SetupJoints(bool set_tangents);
  13. fopen(filename, "rb") ->
  14. #if WINDOWS
  15. FILE *fp = _wfopen(filename, L"rb");
  16. #else
  17. FILE *fp = fopen(UnixPathUTF8(filename), "r");
  18. #endif
  19. renamed *.cpp -> *.cpp.h so by default they will not be added to compilation
  20. /******************************************************************************/
  21. #define USE_MS3D_ANIMATION_METHODS 0
  22. #pragma warning(push)
  23. #pragma warning(disable:4996) // '_wfopen': This function or variable may be unsafe. Consider using _wfopen_s instead
  24. #pragma warning(disable:4267) // 64bit - conversion from 'size_t' to 'Int', possible loss of data
  25. #include "../../../../ThirdPartyLibs/MilkShape3D/mathlib.cpp.h"
  26. #include "../../../../ThirdPartyLibs/MilkShape3D/msModel.cpp.h"
  27. #pragma warning(pop)
  28. /******************************************************************************/
  29. static void ToMatrix(Matrix3 &m, float a[3][4])
  30. {
  31. m.x.set(a[0][0], a[1][0], a[2][0]);
  32. m.y.set(a[0][1], a[1][1], a[2][1]);
  33. m.z.set(a[0][2], a[1][2], a[2][2]);
  34. }
  35. static void ToMatrix(Matrix &m, float a[3][4])
  36. {
  37. m.x .set(a[0][0], a[1][0], a[2][0]);
  38. m.y .set(a[0][1], a[1][1], a[2][1]);
  39. m.z .set(a[0][2], a[1][2], a[2][2]);
  40. m.pos.set(a[0][3], a[1][3], a[2][3]);
  41. }
  42. static void FromMatrix(Matrix &m, float a[3][4])
  43. {
  44. a[0][0]=m.x .x; a[1][0]=m.x .y; a[2][0]=m.x .z;
  45. a[0][1]=m.y .x; a[1][1]=m.y .y; a[2][1]=m.y .z;
  46. a[0][2]=m.z .x; a[1][2]=m.z .y; a[2][2]=m.z .z;
  47. a[0][3]=m.pos.x; a[1][3]=m.pos.y; a[2][3]=m.pos.z;
  48. }
  49. static void SetSkin(VecB4 &matrix, VecB4 &blend, msModel &ms3d, ms3d_vertex_t &vertex, MemtN<Byte, 256> &old_to_new, Skeleton *skeleton)
  50. {
  51. int indices[4], weights[4]; ms3d.FillJointIndicesAndWeights(&vertex, indices, weights);
  52. MemtN<IndexWeight, 256> skin; // div by 100 not needed because weight is normalized in 'SetSkin'
  53. if(weights[0]>0 && InRange(indices[0], old_to_new))skin.New().set(old_to_new[indices[0]], weights[0]/* /100.0f */);
  54. if(weights[1]>0 && InRange(indices[1], old_to_new))skin.New().set(old_to_new[indices[1]], weights[1]/* /100.0f */);
  55. if(weights[2]>0 && InRange(indices[2], old_to_new))skin.New().set(old_to_new[indices[2]], weights[2]/* /100.0f */);
  56. if(weights[3]>0 && InRange(indices[3], old_to_new))skin.New().set(old_to_new[indices[3]], weights[3]/* /100.0f */);
  57. SetSkin(skin, matrix, blend, skeleton);
  58. }
  59. static void CreateSkeleton(Skeleton &skeleton, msModel &ms3d, Int bones, XAnimation *animation)
  60. {
  61. ms3d.SetupJoints(USE_MS3D_ANIMATION_METHODS);
  62. skeleton.bones.setNum(bones);
  63. FREP(bones)
  64. {
  65. ms3d_joint_t &joint=*ms3d.GetJoint(i);
  66. SkelBone &sbon =skeleton.bones[i];
  67. Set(sbon.name, joint.name);
  68. sbon.parent=(InRange(joint.parentIndex, bones) ? joint.parentIndex : 0xFF);
  69. Matrix m; ToMatrix(m, joint.matGlobalSkeleton);
  70. sbon.perp=m.y ;
  71. sbon.dir =m.x ;
  72. sbon.pos =m.pos;
  73. }
  74. skeleton.setBoneLengths();
  75. // animation
  76. if(animation)
  77. {
  78. animation->fps=ms3d.GetAnimationFps();
  79. Animation &anim=animation->anim;
  80. anim.length(ms3d.GetTotalFrames(), false);
  81. anim.bones.setNum(bones);
  82. FREPA(anim.bones)
  83. {
  84. C SkelBone &sbon =skeleton.bones[i];
  85. AnimBone &abon =anim .bones[i];
  86. Bool parent =(sbon.parent!=0xFF);
  87. Matrix3 parent_matrix_inv; if(parent)skeleton.bones[sbon.parent].inverse(parent_matrix_inv);
  88. ms3d_joint_t &joint = *ms3d.GetJoint( i) ,
  89. *joint_parent=(parent ? ms3d.GetJoint(joint.parentIndex) : null);
  90. abon.set(sbon.name);
  91. abon.orns.setNumZero(joint.rotationKeys.size());
  92. abon.poss.setNumZero(joint.positionKeys.size());
  93. // setup rotations
  94. FREPA(abon.orns)
  95. {
  96. AnimKeys::Orn &orn =abon .orns [i];
  97. C ms3d_keyframe_t &frame=joint.rotationKeys[i];
  98. orn.time=frame.time;
  99. Orient sbon_src =sbon ; // src in global space
  100. if(parent)sbon_src*=parent_matrix_inv; // src in parent space
  101. #if USE_MS3D_ANIMATION_METHODS
  102. // calculating animations through ms3d functions (very slow, because all bones need to be calculated)
  103. // from available global matrixes for each bone we calculate as follow:
  104. // target orientation in parent space = joint.matGlobal / jointParent.matGlobal
  105. //if(orn.time>40)continue; // calculating animations for all bones and frames is very slow, so for tests limit to only few frames
  106. ms3d.SetFrame(frame.time);
  107. // opis : R_ConcatTransforms(parentJoint->matGlobal, joint->matLocal, joint->matGlobal);
  108. // czyli: joint->matGlobal = joint->matLocal * parentJoint->matGlobal;
  109. Matrix3 m; ToMatrix(m, joint.matGlobal);
  110. orn.orn.perp=m.y;
  111. orn.orn.dir =m.x; // dest in global space
  112. if(parent)
  113. {
  114. Orient parent_dest; ToMatrix(m, joint_parent->matGlobal);
  115. parent_dest.perp=m.y;
  116. parent_dest.dir =m.x; // parent_dest in global space
  117. orn.orn/=Matrix3(parent_dest); // dest in parent space
  118. }
  119. #else
  120. // code from ms3d classes
  121. {
  122. vec4_t quat ; AngleQuaternion(frame.key, quat); // calculate the quaternion basing on the angles
  123. float matAnimate[3][4]; QuaternionMatrix(quat, matAnimate); // calculate the transformation matrix basing on the quaternion
  124. //matAnimate[0][3]=pos[0];
  125. //matAnimate[1][3]=pos[1]; we don't care about positions
  126. //matAnimate[2][3]=pos[2];
  127. // animate the local joint matrix using: matLocal = matLocalSkeleton * matAnimate
  128. R_ConcatTransforms(joint.matLocalSkeleton, matAnimate, joint.matLocal); // set target matrix
  129. }
  130. Matrix3 m; ToMatrix(m, joint.matLocal); // convert the matrix to easier form
  131. if(parent)
  132. {
  133. // formula discovered by trial and error (observing what should we receive when using USE_MS3D_ANIMATION_METHODS - orn.orn / parent_dest, according to what we have in joint.matLocal)
  134. orn.orn.perp.x=-m.y.z;
  135. orn.orn.perp.y= m.y.y;
  136. orn.orn.perp.z= m.y.x;
  137. orn.orn.dir.x=-m.x.z;
  138. orn.orn.dir.y= m.x.y;
  139. orn.orn.dir.z= m.x.x;
  140. }else
  141. {
  142. orn.orn.perp=m.y;
  143. orn.orn.dir =m.x; // dest in global space
  144. }
  145. #endif
  146. }
  147. // setup positions
  148. FREPA(abon.poss)
  149. {
  150. AnimKeys::Pos &pos =abon .poss [i];
  151. C ms3d_keyframe_t &frame=joint.positionKeys[i];
  152. pos.time=frame.time;
  153. // code from ms3d classes
  154. {
  155. float matAnimate[3][4]; // we don't care about orientations
  156. matAnimate[0][3]=frame.key[0];
  157. matAnimate[1][3]=frame.key[1];
  158. matAnimate[2][3]=frame.key[2];
  159. // animate the local joint matrix using: matLocal = matLocalSkeleton * matAnimate
  160. R_ConcatTransforms(joint.matLocalSkeleton, matAnimate, joint.matLocal); // set target matrix
  161. }
  162. Matrix M_l ; ToMatrix(M_l , joint.matLocal );
  163. Matrix M_ls; ToMatrix(M_ls, joint.matLocalSkeleton);
  164. pos.pos=M_l.pos-M_ls.pos;
  165. if(parent)
  166. {
  167. Matrix3 p_gs; ToMatrix(p_gs, joint_parent->matGlobalSkeleton);
  168. pos.pos*=p_gs;
  169. pos.pos*=parent_matrix_inv;
  170. }
  171. }
  172. }
  173. // rescale in time
  174. if(Flt fps=ms3d.GetAnimationFps())anim.length(anim.length()/fps, true);
  175. // process
  176. anim.setTangents().removeUnused().setRootMatrix();
  177. }
  178. }
  179. /******************************************************************************/
  180. } // namespace MS3D
  181. /******************************************************************************/
  182. Bool ImportMS3D(C Str &name, Mesh *mesh, Skeleton *skeleton, XAnimation *animation, MemPtr<XMaterial> materials, MemPtr<Int> part_material_index)
  183. {
  184. if(mesh )mesh ->del();
  185. if(skeleton )skeleton ->del();
  186. if(animation)animation->del();
  187. materials .clear();
  188. part_material_index.clear();
  189. #if !WEB // MilkShape can load only from a stdio file
  190. using namespace MS3D;
  191. msModel ms3d; if(ms3d.Load(name))
  192. {
  193. Int material_num=ms3d.GetNumMaterials(),
  194. vtxs =ms3d.GetNumVertices (),
  195. tris =ms3d.GetNumTriangles(),
  196. bones =ms3d.GetNumJoints ();
  197. // materials
  198. if(materials)FREP(material_num)
  199. {
  200. XMaterial &xm =materials.New();
  201. C ms3d_material_t &mat=*ms3d.GetMaterial(i);
  202. xm.ambient .set(mat.emissive[0], mat.emissive[1], mat.emissive[2]);
  203. xm.color .set(mat.diffuse [0], mat.diffuse [1], mat.diffuse [2], mat.transparency);
  204. xm.specular.set(mat.specular[0], mat.specular[1], mat.specular[2]);
  205. xm.name =mat.name ;
  206. xm.color_map=mat.texture ;
  207. xm.alpha_map=mat.alphamap;
  208. xm.fixPath(GetPath(name));
  209. }
  210. // skeleton
  211. MemtN<Byte, 256> old_to_new;
  212. Skeleton temp, *skel=(skeleton ? skeleton : (mesh || animation) ? &temp : null); // if skel not specified, but we want mesh or animation, then we have to process it
  213. if(skel){CreateSkeleton(*skel, ms3d, bones, animation); skel->sortBones(old_to_new); if(VIRTUAL_ROOT_BONE)REPAO(old_to_new)++;} // 'sortBones' must be called before 'SetSkin'
  214. // mesh
  215. if(mesh)
  216. {
  217. mesh->create(ms3d.GetNumGroups()); FREPA(*mesh)
  218. {
  219. ms3d_group_t &group=*ms3d. GetGroup(i);
  220. MeshPart &part = mesh->parts[i];
  221. MeshBase &base = part. base;
  222. if(part_material_index)part_material_index.add(InRange(group.materialIndex, material_num) ? group.materialIndex : -1);
  223. Set(part.name, group.name);
  224. base.create(group.triangleIndices.size()*3, 0, group.triangleIndices.size(), 0, VTX_POS|VTX_NRM|VTX_TEX0|TRI_IND|(bones ? VTX_SKIN : 0));
  225. FREPA(base.tri)
  226. {
  227. Int t=group.triangleIndices[i]; if(!InRange(t, tris))goto invalid;
  228. ms3d_triangle_t &triangle=*ms3d.GetTriangle(t); REPA(triangle.vertexIndices)if(!InRange(triangle.vertexIndices[i], vtxs))goto invalid;
  229. ms3d_vertex_t &vertex0 =*ms3d.GetVertex (triangle.vertexIndices[0]);
  230. ms3d_vertex_t &vertex1 =*ms3d.GetVertex (triangle.vertexIndices[1]);
  231. ms3d_vertex_t &vertex2 =*ms3d.GetVertex (triangle.vertexIndices[2]);
  232. Int v=i*3;
  233. base.vtx.pos(v+0).set(vertex0.vertex[0], vertex0.vertex[1], vertex0.vertex[2]);
  234. base.vtx.pos(v+1).set(vertex1.vertex[0], vertex1.vertex[1], vertex1.vertex[2]);
  235. base.vtx.pos(v+2).set(vertex2.vertex[0], vertex2.vertex[1], vertex2.vertex[2]);
  236. base.vtx.nrm(v+0).set(triangle.vertexNormals[0][0], triangle.vertexNormals[0][1], triangle.vertexNormals[0][2]);
  237. base.vtx.nrm(v+1).set(triangle.vertexNormals[1][0], triangle.vertexNormals[1][1], triangle.vertexNormals[1][2]);
  238. base.vtx.nrm(v+2).set(triangle.vertexNormals[2][0], triangle.vertexNormals[2][1], triangle.vertexNormals[2][2]);
  239. base.vtx.tex0(v+0).set(triangle.s[0], triangle.t[0]);
  240. base.vtx.tex0(v+1).set(triangle.s[1], triangle.t[1]);
  241. base.vtx.tex0(v+2).set(triangle.s[2], triangle.t[2]);
  242. if(base.vtx.matrix() && base.vtx.blend())
  243. {
  244. SetSkin(base.vtx.matrix(v+0), base.vtx.blend(v+0), ms3d, vertex0, old_to_new, skel);
  245. SetSkin(base.vtx.matrix(v+1), base.vtx.blend(v+1), ms3d, vertex1, old_to_new, skel);
  246. SetSkin(base.vtx.matrix(v+2), base.vtx.blend(v+2), ms3d, vertex2, old_to_new, skel);
  247. }
  248. base.tri.ind(i).set(v+0, v+1, v+2);
  249. }
  250. base.weldVtx(VTX_ALL, EPSD, EPS_COL_COS, -1); // use small epsilon in case mesh is scaled down
  251. }
  252. mesh->setBox();
  253. }
  254. // remove nub bones
  255. //if(skel){Animation* anim=(animation ? &animation->anim : null); RemoveNubBones(mesh, *skel, anim);}
  256. // finalize
  257. if(skel ) skel ->mirrorX().setBoneTypes();
  258. if(animation) animation->anim.mirrorX().setBoneTypeIndexesFromSkeleton(*skel);
  259. if(mesh ){mesh ->mirrorX().skeleton(skel).skeleton(null); CleanMesh(*mesh);}
  260. if(skeleton ){skel ->setBoneShapes(); if(skeleton!=skel)Swap(*skeleton, *skel);}
  261. return true;
  262. }
  263. #endif
  264. invalid:
  265. if(mesh)mesh->del();
  266. return false;
  267. }
  268. /******************************************************************************/
  269. }
  270. /******************************************************************************/