Import PSK PSA.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. namespace PSK_PSA{ // so local structures are unique
  5. /******************************************************************************/
  6. #pragma pack(push, 4) // PSK/PSA require 4 byte packing
  7. /******************************************************************************/
  8. struct VChunkHeader
  9. {
  10. Char8 ChunkID[20]; // String ID of up to 19 chars (usually zero-terminated)
  11. Int TypeFlag; // Flags/reserved
  12. Int DataSize; // Size per struct following
  13. Int DataCount; // Number of structs
  14. };
  15. struct VJointPos // A bone: an orientation, and a position, all relative to their parent.
  16. {
  17. Quaternion Orientation;
  18. Vec Position;
  19. Flt Length; // For collision testing / debugging drawing. (unused)
  20. Flt XSize;
  21. Flt YSize;
  22. Flt ZSize;
  23. };
  24. struct VBone // Raw data bone
  25. {
  26. Char8 Name[64]; //
  27. UInt Flags; // Reserved
  28. Int NumChildren; // Children (not used)
  29. Int ParentIndex; // 0/null if this is the root bone
  30. VJointPos BonePos; // Reference position
  31. };
  32. struct AnimInfoBinary
  33. {
  34. Char8 Name [64]; // Animation's name
  35. Char8 Group[64]; // Animation's group name
  36. Int TotalBones; // TotalBones * NumRawFrames is number of animation keys to digest.
  37. Int RootInclude; // 0 none 1 included (unused)
  38. Int KeyCompressionStyle; // Reserved: variants in tradeoffs for compression.
  39. Int KeyQuotum; // Max key quotum for compression
  40. Flt KeyReduction; // desired
  41. Flt TrackTime; // explicit - can be overridden by the animation rate
  42. Flt AnimRate; // frames per second.
  43. Int StartBone; // - Reserved: for partial animations (unused)
  44. Int FirstRawFrame; //
  45. Int NumRawFrames; // NumRawFrames and AnimRate dictate tracktime...
  46. };
  47. struct VQuatAnimKey // An animation key.
  48. {
  49. Vec Position; // Relative to parent.
  50. Quaternion Orientation; // Relative to parent.
  51. Flt Time; // The duration until the next key (end key wraps to first...)
  52. };
  53. struct VPoint // Points: regular FVectors
  54. {
  55. Vec Point;
  56. };
  57. struct VVertex // Vertex with texturing info, akin to Hoppe's 'Wedge' concept - import only.
  58. {
  59. UShort PointIndex; // Index into the 3d point table.
  60. Flt U, V; // Texture U, V coordinates.
  61. Byte MatIndex; // At runtime, this one will be implied by the face that's pointing to us.
  62. Byte Reserved; // Top secret.
  63. };
  64. struct VTriangle // Textured triangle.
  65. {
  66. UShort WedgeIndex[3]; // Point to three vertices in the vertex list.
  67. Byte MatIndex; // Materials can be anything.
  68. Byte AuxMatIndex; // Second material (unused).
  69. UInt SmoothingGroups; // 32-bit flag for smoothing groups.
  70. };
  71. struct VMaterial // Raw data material
  72. {
  73. Char8 MaterialName[64];
  74. Int TextureIndex; // Texture index ('multiskin index')
  75. UInt PolyFlags; // ALL poly's with THIS material will have this flag.
  76. Int AuxMaterial; // Reserved: index into another material, eg. detailtexture/shininess/whatever.
  77. UInt AuxFlags; // Reserved: auxiliary flags
  78. Int LodBias; // Material-specific lod bias (unused)
  79. Int LodStyle; // Material-specific lod style (unused)
  80. };
  81. struct VRawBoneInfluence // Raw data bone influence. Just weight, vertex, and Bone, sorted later.
  82. {
  83. Flt Weight;
  84. Int PointIndex;
  85. Int BoneIndex;
  86. };
  87. /******************************************************************************/
  88. static void CreateSkeleton(Skeleton &skeleton, Memc<VBone> &bones)
  89. {
  90. skeleton.bones.setNum(bones.elms());
  91. FREPA(bones)
  92. {
  93. SkelBone &sbon=skeleton.bones[i];
  94. VBone &ubon=bones[i];
  95. sbon.parent=((i && InRange(ubon.ParentIndex, skeleton.bones)) ? ubon.ParentIndex : 0xFF);
  96. if(!i)ubon.BonePos.Orientation.w*=-1; Matrix3 orient=ubon.BonePos.Orientation;
  97. if(!i)ubon.BonePos.Orientation.w*=-1;
  98. sbon.pos =ubon.BonePos.Position;
  99. sbon.dir =orient.z;
  100. sbon.perp=orient.y;
  101. if(InRange(sbon.parent, skeleton.bones))sbon*=(Matrix)skeleton.bones[sbon.parent];
  102. Set(sbon.name, ubon.Name); REP(Length(sbon.name))if(sbon.name[i]==' ')sbon.name[i]=0;else break; // remove useless spaces
  103. }
  104. FREPA(bones)skeleton.bones[i].dir=skeleton.bones[i].cross(); // do this at the end, because sbon transformation by matrix relies on original value
  105. skeleton.setBoneLengths();
  106. }
  107. /******************************************************************************/
  108. #pragma pack(pop)
  109. /******************************************************************************/
  110. } // namespace PSK_PSA
  111. /******************************************************************************/
  112. Bool ImportPSK(C Str &name, Mesh *mesh, Skeleton *skeleton, MemPtr<XMaterial> materials, MemPtr<Int> part_material_index)
  113. {
  114. if(mesh )mesh ->del();
  115. if(skeleton)skeleton->del();
  116. materials .clear();
  117. part_material_index.clear();
  118. using namespace PSK_PSA;
  119. File f; if(f.readTry(name))
  120. {
  121. VChunkHeader general_header; f>> general_header;
  122. VChunkHeader points_header; f>> points_header; Memc<VPoint > points; if( points_header.DataCount<0 || points_header.DataCount && SIZE(VPoint )!= points_header.DataSize)return false; points.setNum( points_header.DataCount); f.getN( points.data(), points.elms());
  123. VChunkHeader vertexs_header; f>> vertexs_header; Memc<VVertex > vertexs; if( vertexs_header.DataCount<0 || vertexs_header.DataCount && SIZE(VVertex )!= vertexs_header.DataSize)return false; vertexs.setNum( vertexs_header.DataCount); f.getN(vertexs.data(), vertexs.elms());
  124. VChunkHeader faces_header; f>> faces_header; Memc<VTriangle > faces; if( faces_header.DataCount<0 || faces_header.DataCount && SIZE(VTriangle )!= faces_header.DataSize)return false; faces.setNum( faces_header.DataCount); f.getN( faces.data(), faces.elms());
  125. VChunkHeader materials_header; f>>materials_header; Memc<VMaterial > mtrls; if(materials_header.DataCount<0 || materials_header.DataCount && SIZE(VMaterial )!=materials_header.DataSize)return false; mtrls.setNum(materials_header.DataCount); f.getN( mtrls.data(), mtrls.elms());
  126. VChunkHeader bones_header; f>> bones_header; Memc<VBone > bones; if( bones_header.DataCount<0 || bones_header.DataCount && SIZE(VBone )!= bones_header.DataSize)return false; bones.setNum( bones_header.DataCount); f.getN( bones.data(), bones.elms());
  127. VChunkHeader skins_header; f>> skins_header; Memc<VRawBoneInfluence> skins; if( skins_header.DataCount<0 || skins_header.DataCount && SIZE(VRawBoneInfluence)!= skins_header.DataSize)return false; skins.setNum( skins_header.DataCount); f.getN( skins.data(), skins.elms());
  128. if(!f.ok())return false;
  129. // skeleton
  130. MemtN<Byte, 256> old_to_new;
  131. Skeleton temp, *skel=(skeleton ? skeleton : mesh ? &temp : null); // if skel not specified, but we want mesh, then we have to process it
  132. if(skel){CreateSkeleton(*skel, bones); skel->sortBones(old_to_new); if(VIRTUAL_ROOT_BONE)REPAO(old_to_new)++;} // 'sortBones' must be called before 'SetSkin'
  133. // mesh
  134. if(mesh)
  135. {
  136. // skinning
  137. Memc< Memc<IndexWeight> > vtx_skin; if(skins.elms())
  138. {
  139. vtx_skin.setNum(points.elms());
  140. REPA(skins)
  141. {
  142. C VRawBoneInfluence &skin=skins[i];
  143. if(InRange(skin.PointIndex, vtx_skin) && InRange(skin.BoneIndex, old_to_new))vtx_skin[skin.PointIndex].New().set(old_to_new[skin.BoneIndex], skin.Weight);
  144. }
  145. }
  146. MeshBase base(faces.elms()*3, 0, faces.elms(), 0, VTX_TEX0|(skins.elms() ? VTX_SKIN : 0)|TRI_ID);
  147. FREPA(faces)
  148. {
  149. C VTriangle &vtri =faces[i]; REPA(vtri.WedgeIndex)if(!InRange(vtri.WedgeIndex[i], vertexs))return false;
  150. C VVertex &vvtx0=vertexs[vtri.WedgeIndex[0]],
  151. &vvtx1=vertexs[vtri.WedgeIndex[1]],
  152. &vvtx2=vertexs[vtri.WedgeIndex[2]];
  153. if(!InRange(vvtx0.PointIndex, points)
  154. || !InRange(vvtx1.PointIndex, points)
  155. || !InRange(vvtx2.PointIndex, points))return false;
  156. Int a=i*3, b=a+1, c=b+1;
  157. base.vtx.pos(a)=points[vvtx0.PointIndex].Point;
  158. base.vtx.pos(b)=points[vvtx1.PointIndex].Point;
  159. base.vtx.pos(c)=points[vvtx2.PointIndex].Point;
  160. base.vtx.tex0(a).set(vvtx0.U, vvtx0.V);
  161. base.vtx.tex0(b).set(vvtx1.U, vvtx1.V);
  162. base.vtx.tex0(c).set(vvtx2.U, vvtx2.V);
  163. if(skins.elms())
  164. {
  165. SetSkin(vtx_skin[vvtx0.PointIndex], base.vtx.matrix(a), base.vtx.blend(a), skel);
  166. SetSkin(vtx_skin[vvtx1.PointIndex], base.vtx.matrix(b), base.vtx.blend(b), skel);
  167. SetSkin(vtx_skin[vvtx2.PointIndex], base.vtx.matrix(c), base.vtx.blend(c), skel);
  168. }
  169. base.tri.id (i)=vtri.MatIndex;
  170. base.tri.ind(i).set(c, b, a); // face indexes need to be reversed
  171. }
  172. base.weldVtx(VTX_ALL, EPSD, EPS_COL_COS, -1).setVtxDup().setNormals().copyId(*mesh); // use small epsilon in case mesh is scaled down
  173. // material indexes
  174. if(part_material_index)FREPA(*mesh)part_material_index.add(i);
  175. }
  176. // materials
  177. if(materials)
  178. {
  179. FREPA(mtrls)
  180. {
  181. XMaterial &xm=materials.New();
  182. xm.name=mtrls[i].MaterialName;
  183. }
  184. FileText f; if(f.read(GetPath(name)+"\\X_ModelInfo_"+GetBaseNoExt(name)+".LOG"))for(; !f.end(); )
  185. {
  186. if(Starts(f.getLine(), "= materials ="))
  187. {
  188. Int index=-1;
  189. for(Str line; !f.end(); )
  190. {
  191. f.getLine(line);
  192. Int pos=TextPosI(line, "* Index:"); if(pos>=0)index++;
  193. pos=TextPosI(line, "Original Bitmap:"); if(pos>=0 && InRange(index, materials))
  194. {
  195. Str tex=SkipStart(line()+pos, "Original Bitmap:");
  196. pos=TextPosI(tex, "Path:"); if(pos>=0)tex.clip(pos);
  197. materials[index].color_map=tex.removeOuterWhiteChars();
  198. materials[index].fixPath(GetPath(name));
  199. }
  200. }
  201. }
  202. }
  203. }
  204. // remove nub bones
  205. //if(skel)RemoveNubBones(mesh, *skel, null);
  206. // finalize
  207. if(skel ) skel->rightToLeft().setBoneTypes(); // 'setBoneTypes' must be called after 'sortBones' and 'rightToLeft' and before 'Mesh.skeleton'
  208. if(mesh ){mesh->rightToLeft().skeleton(skel).skeleton(null).setBox(); CleanMesh(*mesh);}
  209. if(skeleton){skel->setBoneShapes(); if(skeleton!=skel)Swap(*skeleton, *skel);}
  210. return true;
  211. }
  212. return false;
  213. }
  214. Bool ImportPSA(C Str &name, Skeleton *skeleton, MemPtr<XAnimation> animations)
  215. {
  216. if(skeleton)skeleton->del();
  217. animations.clear();
  218. using namespace PSK_PSA;
  219. File f; if(f.readTry(name))
  220. {
  221. VChunkHeader general_header; f>> general_header;
  222. VChunkHeader bones_header; f>> bones_header; Memc<VBone > bones; if( bones_header.DataCount<0 || bones_header.DataCount && SIZE(VBone )!= bones_header.DataSize)return false; bones.setNum( bones_header.DataCount); f.getN(bones.data(), bones.elms());
  223. VChunkHeader anim_header; f>> anim_header; Memc<AnimInfoBinary> anims; if( anim_header.DataCount<0 || anim_header.DataCount && SIZE(AnimInfoBinary)!= anim_header.DataSize)return false; anims.setNum( anim_header.DataCount); f.getN(anims.data(), anims.elms());
  224. VChunkHeader raw_keys_header; f>>raw_keys_header; Memc<VQuatAnimKey > keys ; if(raw_keys_header.DataCount<0 || raw_keys_header.DataCount && SIZE(VQuatAnimKey )!=raw_keys_header.DataSize)return false; keys.setNum(raw_keys_header.DataCount); f.getN( keys.data(), keys.elms());
  225. if(!f.ok())return false;
  226. // create skeleton
  227. Skeleton temp, *skel=(skeleton ? skeleton : animations ? &temp : null); // if skel not specified, but we want animations, then we have to process it
  228. if(skel)
  229. {
  230. CreateSkeleton(*skel, bones);
  231. // create animations
  232. if(animations)FREPA(anims)
  233. {
  234. C AnimInfoBinary &anim=anims[i];
  235. if(anim.TotalBones==skel->bones.elms()
  236. && anim.FirstRawFrame>=0 // can be zero
  237. && anim.NumRawFrames>0 // if zero then ignore
  238. && (anim.FirstRawFrame+anim.NumRawFrames)*anim.TotalBones<=keys.elms()) // frames are in range
  239. {
  240. XAnimation &xanimation=animations.New();
  241. Animation & animation=xanimation.anim;
  242. xanimation.fps =anim.AnimRate;
  243. xanimation.name=anim.Name;
  244. animation.bones.setNum(skel->bones.elms());
  245. FREPA(skel->bones)
  246. {
  247. Flt time=0;
  248. VBone &ubon= bones[i];
  249. SkelBone &sbon=skel ->bones[i];
  250. AnimBone &abon=animation.bones[i]; abon.set(sbon.name);
  251. Bool parent =(sbon.parent!=0xFF);
  252. Matrix3 parent_matrix , parent_matrix_inv,
  253. parent_matrix_temp, parent_matrix_temp_inv; // this is skel.bone(sbon.parent) before changing the xz
  254. if(parent)
  255. {
  256. parent_matrix =skel->bones[sbon.parent];
  257. parent_matrix_temp=Orient(-skel->bones[sbon.parent].cross(), skel->bones[sbon.parent].perp);
  258. parent_matrix .inverse(parent_matrix_inv , true);
  259. parent_matrix_temp.inverse(parent_matrix_temp_inv, true);
  260. }
  261. abon.poss.setNumZero(anim.NumRawFrames);
  262. abon.orns.setNumZero(anim.NumRawFrames);
  263. FREPD(k, anim.NumRawFrames)
  264. {
  265. VQuatAnimKey &key=keys[(k+anim.FirstRawFrame)*anim.TotalBones + i];
  266. AnimKeys::Pos &pos=abon.poss[k]; pos.time=time;
  267. AnimKeys::Orn &orn=abon.orns[k]; orn.time=time;
  268. animation.length(Max(animation.length(), time), false);
  269. // orientation
  270. {
  271. // set rotation
  272. orn.orn=sbon;
  273. // animate
  274. {
  275. if(!i){ubon.BonePos.Orientation.w*=-1; key.Orientation.w*=-1;}
  276. if(parent)orn.orn*=parent_matrix_temp_inv ; // transform bone from global space to local space relative to parent
  277. orn.orn*=GetTransform((Matrix3)ubon.BonePos.Orientation, (Matrix3)key.Orientation); // perform transformation from source to target matrix, looks like 'frame' is the target matrix
  278. if(parent)orn.orn*=parent_matrix_temp ; // transform bone from local space to global space
  279. if(!i){ubon.BonePos.Orientation.w*=-1; key.Orientation.w*=-1;}
  280. }
  281. //
  282. if(parent)orn.orn*=parent_matrix_inv;
  283. }
  284. // position
  285. {
  286. pos.pos=key.Position-ubon.BonePos.Position;
  287. if(parent)
  288. {
  289. pos.pos*=parent_matrix_temp;
  290. pos.pos*=parent_matrix_inv ;
  291. }
  292. }
  293. time+=key.Time;
  294. }
  295. }
  296. // rescale in time
  297. if(xanimation.fps>0)animation.length(animation.length()/xanimation.fps, true);
  298. // override length
  299. if(anim.TrackTime>0)animation.length((xanimation.fps>0) ? anim.TrackTime/xanimation.fps : anim.TrackTime, false);
  300. // process
  301. animation.setTangents().removeUnused().rightToLeft(*skel).setRootMatrix();
  302. }else
  303. {
  304. // invalid data
  305. }
  306. }
  307. // remove nub bones
  308. //Memt<Animation*> anims; REPA(animations)anims.add(&animations[i].anim); RemoveNubBones(null, *skel, anims);
  309. skel->sortBones().rightToLeft().setBoneTypes();
  310. REPAO(animations).anim.setBoneTypeIndexesFromSkeleton(*skel);
  311. if(skeleton){skel->setBoneShapes(); if(skeleton!=skel)Swap(*skeleton, *skel);}
  312. }
  313. return true;
  314. }
  315. return false;
  316. }
  317. /******************************************************************************/
  318. }
  319. /******************************************************************************/