Import 3DS.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. #define CHUNK3DS_MAIN3DS 0x4D4D
  6. #define CHUNK3DS_EDIT3DS 0x3D3D
  7. #define CHUNK3DS_EDIT_OBJECT 0x4000
  8. #define CHUNK3DS_OBJ_TRIMESH 0x4100
  9. #define CHUNK3DS_TRI_VERTEXLIST 0x4110
  10. #define CHUNK3DS_TRI_FACELIST 0x4120
  11. #define CHUNK3DS_TRI_MTRLLIST 0x4130
  12. #define CHUNK3DS_TRI_TEXCOORD 0x4140
  13. #define CHUNK3DS_TRI_SMOOTH_GROUPS 0x4150
  14. #define CHUNK3DS_TRI_MATRIX 0x4160
  15. #define CHUNK3DS_MTRL 0xAFFF
  16. #define CHUNK3DS_MTRL_NAME 0xA000
  17. #define CHUNK3DS_MTRL_COLOR 0xA020
  18. #define CHUNK3DS_MTRL_COLOR_MAP 0xA200
  19. #define CHUNK3DS_MTRL_SPEC_MAP 0xA204
  20. #define CHUNK3DS_MTRL_ALPHA_MAP 0xA210
  21. #define CHUNK3DS_MTRL_REFL_MAP 0xA220
  22. #define CHUNK3DS_MTRL_BUMP_MAP 0xA230
  23. #define CHUNK3DS_MTRL_TEX_NAME 0xA300
  24. #define CHUNK3DS_MTRL_2_SIDED 0xA081
  25. #define CHUNK3DS_KFDATA 0xB000
  26. #define CHUNK3DS_OBJECT_NODE_TAG 0xB002
  27. #define CHUNK3DS_NODE_HEADER 0xB010
  28. #define CHUNK3DS_PIVOT 0xB013
  29. #define CHUNK3DS_SCALE 0x0100
  30. #define CHUNK3DS_COLOR_RGB_BYTE 0x0011
  31. /******************************************************************************/
  32. Bool Import3DS(C Str &name, Mesh *mesh, MemPtr<XMaterial> materials, MemPtr<Int> part_material_index)
  33. {
  34. if(mesh)mesh->del();
  35. materials .clear();
  36. part_material_index.clear();
  37. #pragma pack(push, 1)
  38. struct Chunk
  39. {
  40. U16 id;
  41. U32 length;
  42. };
  43. #pragma pack(pop)
  44. struct Mesh : MeshBase
  45. {
  46. Memc<UInt> tri_smooth_groups;
  47. Matrix matrix;
  48. Str8 name;
  49. Mesh() {matrix.identity();}
  50. };
  51. struct Node
  52. {
  53. Str8 name;
  54. Vec pivot;
  55. Node() {pivot.zero();}
  56. };
  57. File f; if(f.readTry(name))
  58. {
  59. UInt last_tex=0;
  60. Str8 last_name;
  61. Memc<Mesh> meshes;
  62. Memc<Node> nodes;
  63. Flt scale=1;
  64. for(; !f.end(); )
  65. {
  66. Chunk chunk; f.get(&chunk, SIZE(chunk)); Long end=f.pos()+Unaligned(chunk.length)-SIZE(chunk);
  67. switch(Unaligned(chunk.id))
  68. {
  69. case CHUNK3DS_MAIN3DS :
  70. case CHUNK3DS_EDIT3DS :
  71. case CHUNK3DS_MTRL :
  72. case CHUNK3DS_KFDATA :
  73. case CHUNK3DS_OBJECT_NODE_TAG:
  74. case CHUNK3DS_MTRL_COLOR : break;
  75. case CHUNK3DS_SCALE: f>>scale; break;
  76. case CHUNK3DS_MTRL_COLOR_MAP:
  77. case CHUNK3DS_MTRL_SPEC_MAP :
  78. case CHUNK3DS_MTRL_ALPHA_MAP:
  79. case CHUNK3DS_MTRL_REFL_MAP :
  80. case CHUNK3DS_MTRL_BUMP_MAP : last_tex=Unaligned(chunk.id); break;
  81. case CHUNK3DS_EDIT_OBJECT:
  82. {
  83. last_name.clear(); for(Char8 c; c=f.getByte(); )last_name+=c;
  84. }break;
  85. case CHUNK3DS_OBJ_TRIMESH:
  86. {
  87. Mesh &mesh=meshes.New();
  88. mesh.name=last_name;
  89. }break;
  90. case CHUNK3DS_NODE_HEADER:
  91. {
  92. Node &node=nodes.New(); for(Char8 c; c=f.getByte(); )node.name+=c;
  93. }goto skip;
  94. case CHUNK3DS_PIVOT: if(Node *node=nodes.addrLast())
  95. {
  96. f>>node->pivot;
  97. }goto skip;
  98. case CHUNK3DS_TRI_VERTEXLIST: if(Mesh *mesh=meshes.addrLast())if(!mesh->vtxs())
  99. {
  100. mesh->vtx._elms=f.getUShort(); mesh->include(VTX_POS); f.getN(mesh->vtx.pos(), mesh->vtxs());
  101. }goto skip;
  102. case CHUNK3DS_TRI_TEXCOORD: if(Mesh *mesh=meshes.addrLast())if(!mesh->vtx.tex0())
  103. {
  104. Int vtxs=f.getUShort(); if(vtxs==mesh->vtxs()){mesh->include(VTX_TEX0); f.getN(mesh->vtx.tex0(), mesh->vtxs());}
  105. }goto skip;
  106. case CHUNK3DS_TRI_FACELIST:
  107. {
  108. Int tris=f.getUShort(); end=f.pos()+tris*4*2;
  109. if(Mesh *mesh=meshes.addrLast())if(!mesh->tris())
  110. {
  111. mesh->tri._elms=tris; mesh->include(TRI_IND); FREPA(mesh->tri)
  112. {
  113. U16 ind[4]; f>>ind; mesh->tri.ind(i).set(ind[0], ind[1], ind[2]);
  114. }
  115. }
  116. }goto skip;
  117. case CHUNK3DS_TRI_MTRLLIST: if(Mesh *mesh=meshes.addrLast())
  118. {
  119. Str material_name ; for(Char8 c; c=f.getByte(); )material_name+=c;
  120. Int material_index=-1; if(materials){REPA(materials)if(Equal(materials[i].name, material_name)){material_index=i; break;} if(material_index<0){material_index=materials.elms(); materials.New().name=material_name;}}
  121. Int tris =f.getUShort();
  122. if(!mesh->tri.id()){mesh->include(TRI_ID); REPA(mesh->tri)mesh->tri.id(i)=-1;}
  123. REP(tris)
  124. {
  125. Int tri=f.getUShort(); if(InRange(tri, mesh->tri))mesh->tri.id(tri)=material_index;
  126. }
  127. }goto skip;
  128. case CHUNK3DS_TRI_SMOOTH_GROUPS: if(Mesh *mesh=meshes.addrLast()) // a list of UInt's for each triangle, smooth group is a 32-bit UInt value, each bit specifies a smoothing group, if 2 tris share a smoothing group, then the vertex normals should be smoothened
  129. {
  130. if(!mesh->tri_smooth_groups.elms())
  131. {
  132. mesh->tri_smooth_groups.setNum(mesh->tris());
  133. f.getN(mesh->tri_smooth_groups.data(), mesh->tri_smooth_groups.elms());
  134. }
  135. }goto skip;
  136. case CHUNK3DS_TRI_MATRIX: if(Mesh *mesh=meshes.addrLast())
  137. {
  138. f>>mesh->matrix.x;
  139. f>>mesh->matrix.y;
  140. f>>mesh->matrix.z;
  141. f>>mesh->matrix.pos;
  142. }goto skip;
  143. case CHUNK3DS_MTRL_NAME:
  144. {
  145. Str material_name ; for(Char8 c; c=f.getByte(); )material_name+=c;
  146. Int material_index=-1; if(materials){REPA(materials)if(Equal(materials[i].name, material_name)){material_index=i; break;} if(material_index<0){material_index=materials.elms(); materials.New().name=material_name;}}
  147. }break;
  148. // not confirmed:
  149. /*case CHUNK3DS_MTRL_2_SIDED: if(materials.notNull() && materials.elms())materials.last().cull=false; break;
  150. */
  151. case CHUNK3DS_MTRL_TEX_NAME:
  152. {
  153. Str tex_name; for(Char8 c; c=f.getByte(); )tex_name+=c;
  154. if(materials.elms())switch(last_tex)
  155. {
  156. case CHUNK3DS_MTRL_COLOR_MAP: materials.last().color_map =tex_name; break;
  157. case CHUNK3DS_MTRL_SPEC_MAP : materials.last().specular_map =tex_name; break;
  158. case CHUNK3DS_MTRL_ALPHA_MAP: materials.last().alpha_map =tex_name; break;
  159. case CHUNK3DS_MTRL_REFL_MAP : materials.last().reflection_map=tex_name; break;
  160. case CHUNK3DS_MTRL_BUMP_MAP : materials.last().bump_map =tex_name; break;
  161. }
  162. }break;
  163. case CHUNK3DS_COLOR_RGB_BYTE:
  164. {
  165. Color c; f>>c.r>>c.g>>c.b; c.a=255;
  166. if(materials.elms())materials.last().color=c.asVec4();
  167. }break;
  168. default: skip: f.pos(end); break;
  169. }
  170. if(!f.ok())return false;
  171. }
  172. // update materials
  173. REPAO(materials).fixPath(GetPath(name));
  174. // create mesh
  175. if(mesh)
  176. {
  177. // process smoothing groups
  178. REPA(meshes)
  179. {
  180. Mesh &mesh=meshes[i];
  181. if(mesh.matrix.mirrored()) // flip X coordinate of vertices if mesh matrix has negative determinant
  182. {
  183. Matrix mirrored=mesh.matrix; mirrored.x.chs(); Matrix m=~mesh.matrix*mirrored;
  184. mesh.transform(m).reverse();
  185. }
  186. if(mesh.tri_smooth_groups.elms())
  187. {
  188. mesh.explodeVtxs(); // explode so each face has its unique vertexes, this is needed because in 3DS, 2 faces sharing the exact same vertex, can have different smoothing groups
  189. if(C VecI *tri=mesh.tri.ind())
  190. {
  191. mesh.include(VTX_MATERIAL); // for simplification, we're applying smoothing groups onto vertexes, no need to initially clear the vtx material because we've used 'explodeVtxs', making all tris have their own unique vertexes
  192. REPA(mesh.tri) // iterate all faces
  193. {
  194. UInt group=mesh.tri_smooth_groups[i]; // get smoothing groups of that face
  195. C VecI &t=tri[i]; REPA(t)mesh.vtx.material(t.c[i]).u=group; // apply smoothing groups onto triangle vertexes
  196. }
  197. mesh.setVtxDupEx(0, EPSD, EPS_COL_COS, true); // generate vertex duplicates based on smoothing groups, use small epsilon in case mesh is scaled down
  198. mesh.exclude(VTX_MATERIAL); // remove no longer needed vertex material
  199. }
  200. }
  201. mesh.setNormals();
  202. if(mesh.vtx.dup())
  203. {
  204. mesh.exclude(VTX_DUP);
  205. mesh.weldVtx(VTX_ALL, EPSD, EPS_COL_COS, -1); // use small epsilon in case mesh is scaled down, having duplicates means that we called explode vertexes, which now we need to weld, do not remove degenerate faces because they're not needed because we're doing this only because of 'explodeVtxs'
  206. }
  207. }
  208. Memc<MeshPart> parts; // parts after splitting materials
  209. FREPA(nodes) // iterate all nodes
  210. {
  211. Node &node=nodes[i]; REPA(meshes) // find mesh for this node
  212. {
  213. C Mesh &mesh=meshes[i]; if(Equal(mesh.name, node.name, true)) // if they have the same name
  214. {
  215. Matrix m=~mesh.matrix;
  216. m.moveBack(node.pivot);
  217. m*=mesh.matrix;
  218. Int max_id=mesh.maxId();
  219. if( max_id<0) // if mesh doesn't have ID at all
  220. { // copy the complete mesh
  221. MeshPart &part=parts.New();
  222. Set(part.name, mesh.name);
  223. part.base.create(mesh);
  224. part.base.transform(m);
  225. if(part_material_index)part_material_index.add(-1); // set material as -1
  226. }else // if it has ID's
  227. for(Int i=-1; i<=max_id; i++)if(mesh.hasId(i)) // iterate through all id's and copy only those which have faces
  228. {
  229. MeshPart &part=parts.New();
  230. Set(part.name, mesh.name);
  231. mesh.copyId(part.base, i);
  232. part.base.transform(m);
  233. if(part_material_index)part_material_index.add(i); // set i-th material
  234. }
  235. break;
  236. }
  237. }
  238. }
  239. mesh->create (parts.elms()); REPA(*mesh)Swap(mesh->parts[i], parts[i]);
  240. mesh->exclude(FACE_ID).rightToLeft().texScale(Vec2(1, -1)).setBox();
  241. CleanMesh(*mesh);
  242. }
  243. return true;
  244. }
  245. return false;
  246. }
  247. /******************************************************************************/
  248. }
  249. /******************************************************************************/