//**************************************************************************** // saveXsiFile //**************************************************************************** static bool saveXsiFile( const FgString &fname, const FffMultiObjectC &model, const vector<FffMultiObjectC> *morphTargets, const string &appName) { size_t numTargets=0; if (morphTargets) { numTargets = morphTargets->size(); } FgPath path(fname); path.ext = "xsi"; FgOfstream ofs(path.str()); if (!ofs) { return false; } // // Get object's bounding box (for camera and lighting info) // FgVect3F centroid(0.0f,0.0f,0.0f); FgVect3F lowBound(0.0f,0.0f,0.0f); FgVect3F hiBound(0.0f,0.0f,0.0f); unsigned long numTotalVtx=0; for (unsigned long yy=0; yy<model.numObjs(); ++yy) { // Get aliase names for all the lists. const vector<FgVect3F> &vtxList = model.getPtList(yy); // Calculate the info for (unsigned long pt=0; pt<vtxList.size(); ++pt) { centroid += vtxList[pt]; ++numTotalVtx; if (yy==0 && pt==0) { lowBound = vtxList[pt]; hiBound = vtxList[pt]; } else { if (lowBound[0] > vtxList[pt][0]) lowBound[0]=vtxList[pt][0]; if (lowBound[1] > vtxList[pt][1]) lowBound[1]=vtxList[pt][1]; if (lowBound[2] > vtxList[pt][2]) lowBound[2]=vtxList[pt][2]; if (hiBound[0] < vtxList[pt][0]) hiBound[0]=vtxList[pt][0]; if (hiBound[1] < vtxList[pt][1]) hiBound[1]=vtxList[pt][1]; if (hiBound[2] < vtxList[pt][2]) hiBound[2]=vtxList[pt][2]; } } } centroid /= float(numTotalVtx); FgVect3F camPos = centroid; float zdiff = hiBound[2] - lowBound[2]; camPos[2] += zdiff*2.0f; float camNearPlane = 0.1f; float camFarPlane = zdiff*5.0f; // // Write (version 3.0) file header // ofs << "xsi 0300txt 0032\n\n" << flush; // // Output some standard info // ofs << "\n"; ofs << "SI_FileInfo\n"; ofs << "{\n"; ofs << " \"\",\n"; ofs << " \"" << appName << "\",\n"; ofs << "}\n"; ofs << "\n"; ofs << "SI_Scene scene1\n"; ofs << "{ \n"; ofs << " \"FRAMES\",\n"; ofs << " 1.000000,\n"; if (numTargets) ofs << " " << numTargets+1 << ".000000,\n"; else ofs << " 100.000000,\n"; ofs << " 30.0,\n"; ofs << "}\n"; ofs << "\n"; ofs << "SI_CoordinateSystem coord1\n"; ofs << "{\n"; ofs << " 1;\n"; ofs << " 0;\n"; ofs << " 1;\n"; ofs << " 0;\n"; ofs << " 2;\n"; ofs << " 5;\n"; ofs << "}\n"; ofs << "\n"; ofs << "SI_Angle\n"; ofs << "{\n"; ofs << " 0;\n"; ofs << "}\n"; ofs << "\n"; ofs << "SI_Camera camera1\n"; ofs << "{\n"; // Position ofs << " " << floatToString(camPos[0]) << "; " << floatToString(camPos[1]) << "; " << floatToString(camPos[2]) << ";;\n"; // Point of interest (camera direction) ofs << " " << floatToString(centroid[0]) << "; " << floatToString(centroid[1]) << "; " << floatToString(centroid[2]) << ";;\n"; // Roll ofs << " 0.0;\n"; // Field of view ofs << " 55.0;\n"; // Near plane units ofs << " " << floatToString(camNearPlane) << ";\n"; // Far plane units ofs << " " << floatToString(camFarPlane) << ";\n"; ofs << "}\n"; ofs << "\n" << flush; ofs << "SI_Ambience\n"; ofs << "{\n"; ofs << " 0.2; 0.2; 0.2;;\n"; ofs << "}\n"; ofs << "\n" << flush; ofs << "SI_Light light1\n"; ofs << "{\n"; // Type ofs << " 0;\n"; // Colour of light ofs << " 1.0; 1.0; 1.0;;\n"; // Position of light (above the camera) ofs << " " << floatToString(camPos[0]) << "; " << floatToString(hiBound[1]) << "; " << floatToString(camPos[2]) << ";;\n"; ofs << "}\n"; ofs << "\n" << flush; // // Now output the material list. // ofs << "SI_MaterialLibrary MATLIB-scene1\n"; ofs << "{\n"; ofs << " " << model.numObjs() << ",\n"; unsigned long xx; for (xx=0; xx<model.numObjs(); ++xx) { string objName = model.getModelName(xx); ofs << "\n"; ofs << " SI_Material " << objName << "\n"; ofs << " {\n"; ofs << " 0.7, 0.7, 0.7, 1.0,\n"; // Diffuse colour ofs << " 50.0,\n"; // Specular decay ofs << " 1.0, 1.0, 1.0,\n"; // Specular colour ofs << " 0.0, 0.0, 0.0,\n"; // Emissive colour ofs << " 2,\n"; // Shading type (2=phong) ofs << " 0.3, 0.3, 0.3,\n"; // Ambient colour // Now output texture image info. string txtFname = model.getTextureFilename(xx); unsigned long imgWd=0, imgHgt=0; if (txtFname != "" && txtFname.length() > 0) { // Get the image size by loading the image FgImgRgbaUb tmpImg; fgLoadImgAnyFormat(path.dir()+txtFname,tmpImg); { imgWd = tmpImg.width(); imgHgt = tmpImg.height(); } } if (imgWd != 0 && imgHgt != 0) { string objTexName = objName + string(".Material.") + objName + string(".texture.map"); ofs << " SI_Texture2D " << objTexName << "\n"; ofs << " {\n"; ofs << " \"" << txtFname << "\";\n"; ofs << " 3;\n"; // UV map (unwrapped) ofs << " " << imgWd << ";" << imgHgt << ";\n"; ofs << " 0;" << imgWd-1 << ";0;" << imgHgt-1 << ";\n"; ofs << " 0;\n"; // No UV swap ofs << " 1;1;\n"; ofs << " 0;0;\n"; ofs << " 1.0;1.0;\n"; // UV scale ofs << " 0.0;0.0;\n"; // UV offset ofs << " 1.0,0.0,0.0,0.0,\n"; // Project matrix ofs << " 0.0,1.0,0.0,0.0,\n"; ofs << " 0.0,0.0,1.0,0.0,\n"; ofs << " 0.0,0.0,0.0,1.0;;\n"; ofs << " 3;\n"; // No mask blending ofs << " 1.0;\n"; // Blending value ofs << " 0.0;\n"; // Texture ambient ofs << " 0.0;\n"; // Texture diffuse ofs << " 0.0;\n"; // Texture specular ofs << " 0.0;\n"; // Texture transparency ofs << " 0.0;\n"; // Texture reflectivity ofs << " 0.0;\n"; // Texture roughness ofs << " }\n"; } ofs << " }\n" << flush; } ofs << "}\n"; ofs << "\n" << flush; // // Now we output the models // for (xx=0; xx<model.numObjs(); ++xx) { string objName = model.getModelName(xx); // Get aliase names for all the lists. const vector<FgVect3F> &vtxList = model.getPtList(xx); const vector<FgVect3UI> &triList = model.getTriList(xx); const vector<FgVect4UI> &quadList = model.getQuadList(xx); const vector<FgVect2F> &txtList = model.getTextCoord(xx); const vector<FgVect3UI> &txtTriList = model.getTexTriList(xx); const vector<FgVect4UI> &txtQuadList = model.getTexQuadList(xx); bool perFacet = false; bool perVertex = false; if (vtxList.size() == txtList.size() && txtTriList.size() == 0 && txtQuadList.size() == 0) perVertex = true; else if (txtList.size() > 0 && txtTriList.size() == triList.size() && txtQuadList.size() == quadList.size()) perFacet = true; // Create a new list for vertex normals vector<FgVect3F> normList; normList.resize(vtxList.size()); // Output the current model ofs << "SI_Model MDL-" << objName << endl; ofs << "{\n"; ofs << " SI_Transform SRT-" << objName << endl; ofs << " {\n"; ofs << " 1.0, 1.0, 1.0, \n"; ofs << " 0.0, 0.0, 0.0, \n"; ofs << " 0.0, 0.0, 0.0, \n"; ofs << " }\n"; ofs << "\n"; ofs << " SI_GlobalMaterial\n"; ofs << " {\n"; ofs << " \"" << objName << "\",\n"; ofs << " \"BRANCH\",\n"; ofs << " }\n"; ofs << "\n"; ofs << " SI_Visibility\n"; ofs << " {\n"; ofs << " 1, \n"; ofs << " }\n"; ofs << "\n"; ofs << " SI_Mesh MSH-" << objName << endl; ofs << " {\n"; // Coordinates (position, normal, and UV) ofs << " SI_Shape SHP-" << objName << "-ORG\n"; ofs << " {\n"; if (perVertex || perFacet) ofs << " 3,\n"; else ofs << " 2,\n"; ofs << " \"ORDERED\",\n"; ofs << "\n"; ofs << " " << vtxList.size() << ",\n"; ofs << " \"POSITION\",\n"; unsigned long pt; for (pt=0; pt<vtxList.size(); ++pt) { ofs << " " << floatToString(vtxList[pt][0]) << ", " << floatToString(vtxList[pt][1]) << ", " << floatToString(vtxList[pt][2]) << ",\n"; // Initialize the normal list to zero. normList[pt] = FgVect3F(0); } ofs << "\n"; // Calculate the normal first for (unsigned long tt=0; tt<triList.size(); ++tt) { FgVect3F norm = calTriNormals(vtxList,triList,tt); normList[ triList[tt][0] ] += norm; normList[ triList[tt][1] ] += norm; normList[ triList[tt][2] ] += norm; } for (unsigned long qq=0; qq<quadList.size(); ++qq) { FgVect3F norm = calQuadNormals(vtxList,quadList,qq); normList[ quadList[qq][0] ] += norm; normList[ quadList[qq][1] ] += norm; normList[ quadList[qq][2] ] += norm; normList[ quadList[qq][3] ] += norm; } ofs << " " << normList.size() << ",\n"; ofs << " \"NORMAL\",\n"; for (pt=0; pt<normList.size(); ++pt) { float ln = normList[pt].length(); if (ln > 0.0f) normList[pt] /= ln; ofs << " " << floatToString(normList[pt][0]) << ", " << floatToString(normList[pt][1]) << ", " << floatToString(normList[pt][2]) << ",\n"; } if (perVertex || perFacet) { ofs << "\n"; ofs << " " << txtList.size() << ",\n"; ofs << " \"TEX_COORD_UV\",\n"; for (pt=0; pt<txtList.size(); ++pt) { ofs << " " << floatToString(txtList[pt][0]) << ", " << floatToString(txtList[pt][1]) << ", \n"; } } ofs << " }\n" << flush; // // Facets // if (triList.size()) { ofs << "\n"; ofs << " SI_TriangleList " << objName << "\n"; ofs << " {\n"; ofs << " " << triList.size() << ",\n"; if (perVertex || perFacet) ofs << " \"NORMAL|TEX_COORD_UV\",\n"; else ofs << " \"NORMAL\",\n"; ofs << " \"" << objName << "\",\n"; // Triangle vertex id. ofs << "\n"; unsigned long tri; for (tri=0; tri<triList.size(); ++tri) { ofs << " " << triList[tri][0] << ", " << triList[tri][1] << ", " << triList[tri][2] << ", \n"; } // Triangle's normal id. ofs << "\n"; for (tri=0; tri<triList.size(); ++tri) { ofs << " " << triList[tri][0] << ", " << triList[tri][1] << ", " << triList[tri][2] << ", \n"; } // Triangle's texture coordinate id. if (perVertex) { ofs << "\n"; for (tri=0; tri<triList.size(); ++tri) { ofs << " " << triList[tri][0] << ", " << triList[tri][1] << ", " << triList[tri][2] << ", \n"; } } else if (perFacet) { ofs << "\n"; for (tri=0; tri<txtTriList.size(); ++tri) { ofs << " " << txtTriList[tri][0] << ", " << txtTriList[tri][1] << ", " << txtTriList[tri][2] << ", \n"; } } ofs << " }\n" << flush; } if (quadList.size()) { ofs << "\n"; ofs << " SI_PolygonList " << objName << "\n"; ofs << " {\n"; ofs << " " << quadList.size() << ",\n"; if (perVertex || perFacet) ofs << " \"NORMAL|TEX_COORD_UV\",\n"; else ofs << " \"NORMAL\",\n"; ofs << " \"" << objName << "\",\n"; ofs << " " << 4*quadList.size() << ",\n"; unsigned long qu; for (qu=0; qu<quadList.size(); ++qu) { ofs << " 4,\n"; } // Quad's vertex id. ofs << "\n"; for (qu=0; qu<quadList.size(); ++qu) { ofs << " " << quadList[qu][0] << ", " << quadList[qu][1] << ", " << quadList[qu][2] << ", " << quadList[qu][3] << ", \n"; } // Quad's normal id. ofs << "\n"; for (qu=0; qu<quadList.size(); ++qu) { ofs << " " << quadList[qu][0] << ", " << quadList[qu][1] << ", " << quadList[qu][2] << ", " << quadList[qu][3] << ", \n"; } // Quad's texture coordinate id. if (perVertex) { ofs << "\n"; for (qu=0; qu<quadList.size(); ++qu) { ofs << " " << quadList[qu][0] << ", " << quadList[qu][1] << ", " << quadList[qu][2] << ", " << quadList[qu][3] << ", \n"; } } else if (perFacet) { ofs << "\n"; for (qu=0; qu<txtQuadList.size(); ++qu) { ofs << " " << txtQuadList[qu][0] << ", " << txtQuadList[qu][1] << ", " << txtQuadList[qu][2] << ", " << txtQuadList[qu][3] << ", \n"; } } ofs << " }\n" << flush; } // Output morph targets as animations if (morphTargets) { size_t numMorphs = morphTargets->size(); if (numMorphs) { ofs << "\n"; ofs << " SI_ShapeAnimation SHPANIM-" << objName << endl; ofs << " {\n"; ofs << " \"LINEAR\",\n"; ofs << " " << numMorphs+1 << ",\n"; for (unsigned long mm=0; mm<numMorphs+1; ++mm) { const vector<FgVect3F> *mvtxList = &vtxList; if (mm > 0) mvtxList = &((*morphTargets)[mm-1].getPtList(xx)); normList.resize( mvtxList->size() ); ofs << "\n"; ofs << " SI_Shape SHP-" << objName << "-" << mm << "\n"; ofs << " {\n"; if (perVertex || perFacet) ofs << " 3,\n"; else ofs << " 2,\n"; ofs << " \"INDEXED\",\n"; // New vertex list. ofs << "\n"; ofs << " " << mvtxList->size() << ",\n"; ofs << " \"POSITION\",\n"; for (pt=0; pt<mvtxList->size(); ++pt) { ofs << " " << pt << ", " << floatToString((*mvtxList)[pt][0]) << ", " << floatToString((*mvtxList)[pt][1]) << ", " << floatToString((*mvtxList)[pt][2]) << ",\n"; // Initialize the normal list to zero. normList[pt] = FgVect3F(0.0f); } // New normal list. size_t tt; for (tt=0; tt<triList.size(); ++tt) { FgVect3F norm=calTriNormals(*mvtxList,triList,ulong(tt)); normList[ triList[tt][0] ] += norm; normList[ triList[tt][1] ] += norm; normList[ triList[tt][2] ] += norm; } size_t qq; for (qq=0; qq<quadList.size(); ++qq) { FgVect3F norm=calQuadNormals(*mvtxList,quadList,ulong(qq)); normList[ quadList[qq][0] ] += norm; normList[ quadList[qq][1] ] += norm; normList[ quadList[qq][2] ] += norm; normList[ quadList[qq][3] ] += norm; } ofs << "\n"; ofs << " " << normList.size() << ",\n"; ofs << " \"NORMAL\",\n"; for (pt=0; pt<normList.size(); ++pt) { float ln = normList[pt].length(); if (ln > 0.0f) normList[pt] /= ln; ofs << " " << pt << ", " << floatToString(normList[pt][0]) << ", " << floatToString(normList[pt][1]) << ", " << floatToString(normList[pt][2]) << ",\n"; } // Texture UV if (perVertex || perFacet) { ofs << "\n"; ofs << " " << txtList.size() << ",\n"; ofs << " \"TEX_COORD_UV\",\n"; for (pt=0; pt<txtList.size(); ++pt) { ofs << " " << pt << ", " << floatToString(txtList[pt][0]) << ", " << floatToString(txtList[pt][1]) << ", \n"; } } ofs << " }\n" << flush; } ofs << "\n"; ofs << " SI_FCurve " << objName << "-SHPANIM-1\n"; ofs << " {\n"; ofs << " \"" << objName << "\",\n"; ofs << " \"SHPANIM-1\",\n"; ofs << " \"LINEAR\",\n"; ofs << " 1,1,\n"; ofs << " " << numMorphs+1 << ",\n"; size_t mm; for (mm=0; mm<numMorphs+1; ++mm) { ofs << " " << mm+1 << ", " << mm << ".0,\n"; } ofs << " }\n"; ofs << " }\n" << flush; } } // End of SI_Mesh ofs << " }\n"; // End of SI_Model ofs << "}\n"; // End of current model ofs << "\n" << flush; } // // Done. // if (ofs.fail()) { ofs.close(); return false; } else { ofs.close(); return true; } }
//**************************************************************************** // Local fffWriteMdataChunk_local //**************************************************************************** static bool fffWriteMdataChunk_local( FILE *fptr, long &chunkSize, const FffMultiObjectC &model) { long chunkStartPos = ftell(fptr); unsigned short id = MDATA; chunkSize = 6; if (!fffWriteChunkHeader_local(fptr,id,chunkSize)) return false; // Build Texture info map<string,string> textureInfoMap; // Key = fname, map = mapName vector< string > mapNameList; for (unsigned long objId=0; objId < model.numObjs(); ++objId) { string textureFile = model.getTextureFilename(objId); if (textureFile != "") { // Make the filename in DOS 8.3 format FgPath upath(textureFile); string path=upath.dir().m_str, root=upath.base.m_str, suff=upath.ext.m_str; if (root.length() > 8) { textureFile = path + root.substr(0,8) + "." + suff; } if (textureInfoMap.find(textureFile) == textureInfoMap.end()) { textureInfoMap[textureFile] = fffMdlNameTo3dsName(model.getModelName(objId), mapNameList); } } } for (map<string,string>::const_iterator itr = textureInfoMap.begin(); itr != textureInfoMap.end(); ++itr) { long matEntryChunkStartPos = ftell(fptr); id = MAT_ENTRY; long matEntryChunkSize=6; if (!fffWriteChunkHeader_local(fptr,id,matEntryChunkSize)) return false; id = MAT_NAME; long mapNameChunkSize = 6 + long(itr->second.length()) + 1; if (!fffWriteChunkHeader_local(fptr,id,mapNameChunkSize)) return false; if (!fffWrite3dsString_local(fptr,itr->second)) return false; matEntryChunkSize += mapNameChunkSize; long colourChunkSize = 6 + 3; id = MAT_AMBIENT; long mapAmbientColourChunkSize = 6 + colourChunkSize; if (!fffWriteChunkHeader_local(fptr,id,mapAmbientColourChunkSize)) return false; id = COLOUR_RGB_BYTE; if (!fffWriteChunkHeader_local(fptr,id,colourChunkSize)) return false; char red=(char)0; char green=(char)0; char blue=(char)0; if (fwrite(&red,1,1,fptr) != 1) return false; if (fwrite(&green,1,1,fptr) != 1) return false; if (fwrite(&blue,1,1,fptr) != 1) return false; matEntryChunkSize += mapAmbientColourChunkSize; id = MAT_DIFFUSE; long mapDiffuseColourChunkSize = 6 + colourChunkSize; if (!fffWriteChunkHeader_local(fptr,id,mapDiffuseColourChunkSize)) return false; id = COLOUR_RGB_BYTE; if (!fffWriteChunkHeader_local(fptr,id,colourChunkSize)) return false; red=(char)255; green=(char)255; blue=(char)255; if (fwrite(&red,1,1,fptr) != 1) return false; if (fwrite(&green,1,1,fptr) != 1) return false; if (fwrite(&blue,1,1,fptr) != 1) return false; matEntryChunkSize += mapDiffuseColourChunkSize; id = MAT_SPECULAR; long mapSpecularColourChunkSize = 6 + colourChunkSize; if (!fffWriteChunkHeader_local(fptr,id,mapSpecularColourChunkSize)) return false; id = COLOUR_RGB_BYTE; if (!fffWriteChunkHeader_local(fptr,id,colourChunkSize)) return false; red=(char)0; green=(char)0; blue=(char)0; if (fwrite(&red,1,1,fptr) != 1) return false; if (fwrite(&green,1,1,fptr) != 1) return false; if (fwrite(&blue,1,1,fptr) != 1) return false; matEntryChunkSize += mapSpecularColourChunkSize; id = MAT_TEXMAP; long mapFilenameChunkSize = 6 + long(itr->first.length()) + 1; long textMapChunkSize = 6 + mapFilenameChunkSize; if (!fffWriteChunkHeader_local(fptr,id,textMapChunkSize)) return false; id = MAT_MAP_FNAME; if (!fffWriteChunkHeader_local(fptr,id,mapFilenameChunkSize)) return false; if (!fffWrite3dsString_local(fptr,itr->first)) return false; matEntryChunkSize += textMapChunkSize; if (!fffUpdateChunkSizeInfo_local(fptr,matEntryChunkSize, matEntryChunkStartPos)) return false; chunkSize += matEntryChunkSize; } vector< string > objNameList; ulong objId; for (objId=0; objId<model.numObjs(); ++objId) { long objChunkStartPos = ftell(fptr); id = OBJECT; long objChunkSize = 6; if (!fffWriteChunkHeader_local(fptr,id,objChunkSize)) return false; string objName = fffMdlNameTo3dsName(model.getModelName(objId), objNameList); if (!fffWrite3dsString_local(fptr,objName)) return false; objChunkSize += long(objName.length())+1; long triObjChunkSize; if (!fffWriteTriObjectChunk_local(fptr,triObjChunkSize, textureInfoMap,objId,model)) return false; objChunkSize += triObjChunkSize; if (!fffUpdateChunkSizeInfo_local(fptr,objChunkSize,objChunkStartPos)) return false; chunkSize += objChunkSize; } if (!fffUpdateChunkSizeInfo_local(fptr,chunkSize,chunkStartPos)) return false; return true; }