home *** CD-ROM | disk | FTP | other *** search
- #include "xentax.h"
- #include "x_lwo.h"
- #include "x_smc.h"
-
- struct SMCJointInfo {
- uint32 listindex;
- std::string name;
- };
-
- class SMCJointVisitor : public JOINTVISITOR {
- private :
- std::map<uint32, SMCJointInfo> indexmap;
- std::deque<lwVertex3D> pnts;
- std::deque<lwSkelegon> pols;
- private :
- SMCJointVisitor(const SMCJointVisitor&);
- void operator =(const SMCJointVisitor&);
- public :
- SMCJointVisitor() {}
- ~SMCJointVisitor() {}
- public :
- uint32 joints(void)const
- {
- return pnts.size();
- }
- uint32 bones(void)const
- {
- return pols.size();
- }
- boost::shared_array<lwVertex3D> createJoints(void)const
- {
- boost::shared_array<lwVertex3D> data(new lwVertex3D[pnts.size()]);
- for(size_t i = 0; i < pnts.size(); i++) {
- data[i].x = pnts[i].x;
- data[i].y = pnts[i].y;
- data[i].z = pnts[i].z;
- }
- return data;
- }
- boost::shared_array<lwSkelegon> createBones(void)const
- {
- boost::shared_array<lwSkelegon> data(new lwSkelegon[pols.size()]);
- for(size_t i = 0; i < pols.size(); i++) {
- data[i].a = pols[i].a;
- data[i].b = pols[i].b;
- data[i].name = pols[i].name;
- }
- return data;
- }
- return_type operator ()(argument1 joint, argument2 index)
- {
- // joint must be valid
- if(index == INVALID_JOINT) return false;
-
- // initialize position
- lwVertex3D pos;
- pos.x = joint.rel_x;
- pos.y = joint.rel_y;
- pos.z = joint.rel_z;
-
- // save bone
- if(joint.parent != INVALID_JOINT)
- {
- // get parent information
- std::map<uint32, SMCJointInfo>::iterator iter = indexmap.find(joint.parent);
- if(iter == indexmap.end()) return false;
- SMCJointInfo parent_info = iter->second;
-
- // convert to absolute position
- pos.x += pnts[parent_info.listindex].x;
- pos.y += pnts[parent_info.listindex].y;
- pos.z += pnts[parent_info.listindex].z;
-
- // save bone
- lwSkelegon bone;
- bone.a = parent_info.listindex;
- bone.b = pnts.size();
- bone.name += parent_info.name;
- bone.name += "_";
- bone.name += joint.name;
- pols.push_back(bone);
- }
-
- // save point information
- SMCJointInfo info;
- info.listindex = pnts.size();
- info.name = joint.name;
- indexmap.insert(std::map<uint32, SMCJointInfo>::value_type(index, info));
-
- // save point
- pnts.push_back(pos);
- return true;
- }
- };
-
- template<class T>
- bool SaveTriangleList(const SMC_INDEX_BUFFER& ib, boost::shared_array<lwTriangle>& facedata)
- {
- // validate
- if(ib.elem < 3) return error("Index buffer is not a triangle list.");
- if(ib.elem % 3) return error("Index buffer is not a triangle list.");
- if(ib.type != FACE_TYPE_TRIANGLES) return error("Index buffer is not a triangle list.");
-
- // pointer to data
- const T* data = reinterpret_cast<const T*>(ib.data.get());
- if(!data) return error("Invalid data pointer.");
-
- // transfer data
- uint32 n_triangles = ib.elem/3;
- uint32 index = 0;
- for(uint32 i = 0; i < n_triangles; i++) {
- facedata[i].a = data[index++];
- facedata[i].b = data[index++];
- facedata[i].c = data[index++];
- }
-
- return true;
- }
-
- template<class T>
- bool SaveTriangleStrip(const SMC_INDEX_BUFFER& ib, boost::shared_array<lwTriangle>& facedata)
- {
- // validate
- if(ib.elem < 3) return error("Index buffer is not a triangle strip.");
- if(ib.type != FACE_TYPE_TRISTRIP) return error("Index buffer is not a triangle strip.");
-
- // pointer to data
- const T* data = reinterpret_cast<const T*>(ib.data.get());
- if(!data) return error("Invalid data pointer.");
-
- // first triangle
- uint32 a = facedata[0].a = data[0];
- uint32 b = facedata[0].b = data[1];
- uint32 c = facedata[0].c = data[2];
-
- // other triangles
- uint32 n_triangles = ib.elem - 2;
- for(size_t i = 1; i < n_triangles; i++)
- {
- // next triangle
- a = b;
- b = c;
- c = data[i];
-
- // winding
- if(!(a == b || a == c || b == c)) {
- if(i % 2) {
- facedata[i].a = a;
- facedata[i].b = c;
- facedata[i].c = b;
- }
- else {
- facedata[i].a = a;
- facedata[i].b = b;
- facedata[i].c = c;
- }
- }
- }
-
- return true;
- }
-
- bool SaveLWO(const char* path, const char* name, const SIMPLEMODELCONTAINER& data)
- {
- // validate
- using namespace std;
- if(!path || !strlen(path)) return error("SaveLWO: A path must be specified.");
- if(!name || !strlen(name)) return error("SaveLWO: A name must be specified.");
-
- // data
- boost::shared_array<lwVertex3D> vd; // PNTS data
- boost::shared_array<lwVertex2D> ud; // TXUV data
- boost::shared_array<lwTriangle> fd; // POLS data
-
- // save LAYR
- lwFileSaver saver;
- saver.insertLayr(0, nullptr);
-
- // save CLIP
- for(size_t i = 0; i < data.textures.size(); i++)
- saver.insertClip((i + 1), data.textures[i].filename.c_str());
-
- // save PNTS
- if(data.vbuffer.elem) {
- // save xyz
- if(data.vbuffer.flags & VERTEX_POSITION) {
- vd.reset(new lwVertex3D[data.vbuffer.elem]);
- for(uint32 i = 0; i < data.vbuffer.elem; i++) {
- vd[i].x = data.vbuffer.data[i].vx;
- vd[i].y = data.vbuffer.data[i].vy;
- vd[i].z = data.vbuffer.data[i].vz;
- }
- saver.insertPnts(0, 0, vd, data.vbuffer.elem);
- }
- // save uv
- if(data.vbuffer.flags & VERTEX_UV) {
- ud.reset(new lwVertex2D[data.vbuffer.elem]);
- for(uint32 i = 0; i < data.vbuffer.elem; i++) {
- ud[i].x = data.vbuffer.data[i].tu;
- ud[i].y = data.vbuffer.data[i].tv;
- }
- }
- // save weights
- if(data.vbuffer.flags & VERTEX_WEIGHTS)
- {
- if(data.vbuffer.flags & VERTEX_BONEIDX)
- {
- // TODO:
- }
- else if(data.vbuffer.flags & VERTEX_WMAPIDX)
- {
- // construct WGHT maps
- typedef map<uint32, deque<lwRefVertex1D>> wmap_type;
- wmap_type wmap;
- for(uint32 i = 0; i < data.vbuffer.elem; i++) {
- for(uint32 j = 0; j < 8; j++) {
- if(data.vbuffer.data[i].mi[j] != INVALID_VERTEX_WMAP_INDEX) {
- wmap_type::iterator iter = wmap.find(data.vbuffer.data[i].mi[j]);
- if(iter == wmap.end()) iter = wmap.insert(wmap_type::value_type(data.vbuffer.data[i].mi[j], deque<lwRefVertex1D>())).first;
- lwRefVertex1D item;
- item.reference = i;
- item.x = data.vbuffer.data[i].wv[j]/65535.0f;
- iter->second.push_back(item);
- }
- }
- }
-
- // save WGHT maps
- for(wmap_type::iterator iter = wmap.begin(); iter != wmap.end(); iter++) {
- if(iter->second.size()) {
- boost::shared_array<lwRefVertex1D> wset(new lwRefVertex1D[iter->second.size()]);
- uint32 index = 0;
- for(size_t i = 0; i < iter->second.size(); i++) {
- wset[index].reference = iter->second[i].reference;
- wset[index].x = iter->second[i].x;
- index++;
- }
- stringstream ss;
- ss << "wmap_" << setfill('0') << setw(3) << iter->first;
- saver.insertWght(0, 0, ss.str().c_str(), wset, iter->second.size());
- }
- }
- }
- }
- }
-
- // save POLS
- for(uint32 i = 0; i < data.ibuffer.size(); i++)
- {
- const SMC_INDEX_BUFFER& ib = data.ibuffer[i];
- if(ib.type == FACE_TYPE_TRIANGLES) {
- uint32 n_triangles = ib.elem/3;
- fd.reset(new lwTriangle[n_triangles]);
- if(ib.format == FACE_FORMAT_UINT_08) SaveTriangleList<uint08>(ib, fd);
- else if(ib.format == FACE_FORMAT_UINT_16) SaveTriangleList<uint16>(ib, fd);
- else if(ib.format == FACE_FORMAT_UINT_32) SaveTriangleList<uint32>(ib, fd);
- saver.insertPols(0, 0, ib.name.c_str(), fd, n_triangles);
- }
- else if(ib.type == FACE_TYPE_TRISTRIP) {
- uint32 n_triangles = ib.elem - 2;
- fd.reset(new lwTriangle[n_triangles]);
- if(ib.format == FACE_FORMAT_UINT_08) SaveTriangleStrip<uint08>(ib, fd);
- else if(ib.format == FACE_FORMAT_UINT_16) SaveTriangleStrip<uint16>(ib, fd);
- else if(ib.format == FACE_FORMAT_UINT_32) SaveTriangleStrip<uint32>(ib, fd);
- saver.insertPols(0, 0, ib.name.c_str(), fd, n_triangles);
- }
-
- // save TXUV
- if(data.vbuffer.flags & VERTEX_UV)
- {
- // construct TXUV map
- map<uint32, lwVertex2D> uvmap;
- uint32 n_triangles = ib.elem/3;
- for(uint32 j = 0; j < n_triangles; j++) {
- uint32 ref_a = fd[j].a;
- uint32 ref_b = fd[j].b;
- uint32 ref_c = fd[j].c;
- lwVertex2D val_a = ud[ref_a];
- lwVertex2D val_b = ud[ref_b];
- lwVertex2D val_c = ud[ref_c];
- uvmap.insert(map<uint32, lwVertex2D>::value_type(ref_a, val_a));
- uvmap.insert(map<uint32, lwVertex2D>::value_type(ref_b, val_b));
- uvmap.insert(map<uint32, lwVertex2D>::value_type(ref_c, val_c));
- }
-
- // save TXUV map
- boost::shared_array<lwRefVertex2D> uvset(new lwRefVertex2D[uvmap.size()]);
- uint32 index = 0;
- for(map<uint32, lwVertex2D>::iterator iter = uvmap.begin(); iter != uvmap.end(); iter++) {
- uvset[index].reference = iter->first;
- uvset[index].x = iter->second.x;
- uvset[index].y = iter->second.y;
- index++;
- }
- saver.insertTxuv(0, 0, ib.name.c_str(), uvset, uvmap.size());
-
- // enable texture mapping
- if(ib.material != INVALID_MATERIAL)
- {
- // enable material
- const SMC_MATERIAL& material = data.materials[ib.material];
- if(material.basemap != INVALID_TEXTURE_INDEX) {
- saver.enableSurfColrImag(ib.name.c_str());
- saver.setSurfColrVmap(ib.name.c_str(), ib.name.c_str());
- saver.setSurfColrImag(ib.name.c_str(), material.basemap + 1);
- }
- if(material.specmap != INVALID_TEXTURE_INDEX) {
- saver.enableSurfSpecImag(ib.name.c_str());
- saver.setSurfSpecVmap(ib.name.c_str(), ib.name.c_str());
- saver.setSurfSpecImag(ib.name.c_str(), material.specmap + 1);
- }
- if(material.tranmap != INVALID_TEXTURE_INDEX) {
- saver.enableSurfTranImag(ib.name.c_str());
- saver.setSurfTranVmap(ib.name.c_str(), ib.name.c_str());
- saver.setSurfTranImag(ib.name.c_str(), material.tranmap + 1);
- saver.setSurfTranNega(ib.name.c_str(), 1); // TODO: remove
- }
- }
- }
- }
-
- // save SKEL
- for(size_t i = 0; i < data.skeletons.size(); i++)
- {
- // skeleton identifier
- const SKELETON& item = data.skeletons[i];
-
- // traverse joints
- SMCJointVisitor jv;
- item.traverse(jv);
- if(jv.joints() != item.joints()) return error("Invalid skeleton.");
-
- // insert skeleton
- saver.insertJnts(0, i, jv.createJoints(), jv.joints());
- saver.insertSkel(0, 0, item.get_identifier(), jv.createBones(), jv.bones());
- }
-
- // save file
- std::stringstream ss;
- ss << path << name << ".lwo";
- return saver.save(ss.str().c_str());
- }