/** @brief OpenSimの OAR用ツール @file OARTool.cpp @author Fumi.Iseki @date 2014 10/5 */ #include "OARTool.h" using namespace jbxl; /////////////////////////////////////////////////////////////////////////////////////// // OARTool Class // void OARTool::init(void) { pathOAR = init_Buffer(); // OAR directory pathDAE = init_Buffer(); // Output directory for DAE pathSTL = init_Buffer(); // Output directory for STL pathTEX = init_Buffer(); // Texture directory pathPTM = init_Buffer(); // Fhantom directory pathAST = init_Buffer(); // Adding assets directory regionName = init_Buffer(); isMegaRegion = false; // majorVersion = 0; // OAR format major version minorVersion = 0; // OAR format minor version xsize = 256; // ysize = 256; // waterHeight = 20.0; // shift.set(0.0, 0.0, 0.0); objectsNum = 0; settingsFiles = NULL; // Files list in settings terrainsFiles = NULL; // Files list in terrains landdataFiles = NULL; // Files list in landata assetsFiles = NULL; // Files list in assets objectsFiles = NULL; // Files list in objects forUnity3D = true; // for Unity3D forUnity5 = false; // for Unity3D v5.x forUnity4 = false; // for Unity3D v4.x terrainNum = 0; terrain = NULL; // pointer to TerrainSetteings treeTool.init(); // for BREP SetVertexTolerance(1.0e-8f); SetAbsVertexTolerance(1.0e-6f); } // void OARTool::free(void) { if (terrain!=NULL) { for (int i=0; i"); if (ismega!=NULL) if (!strcmp(ismega, "TRUE")) isMegaRegion = true; majorVersion = get_xml_int_attr_bystr(arc_xml, "", "major_version"); minorVersion = get_xml_int_attr_bystr(arc_xml, "", "minor_version"); char* xysize = get_xml_str_content_bystr(arc_xml, ""); if (xysize!=NULL) { char* xstrsz = awk(xysize, ',', 1); char* ystrsz = awk(xysize, ',', 2); xsize = atoi(xstrsz); ysize = atoi(ystrsz); ::free(xstrsz); ::free(ystrsz); } del_xml(&arc_xml); } else { DEBUG_MODE PRINT_MESG("OARTool::GetDatanInfo: WARNING: not found archive file! [%sarchive.xml]\n", pathOAR.buf); return false; } // Settings Files Buffer set_path = dup_Buffer(pathOAR); #ifdef WIN32 cat_s2Buffer("settings\\", &set_path); #else cat_s2Buffer("settings/", &set_path); #endif settingsFiles = get_dir_files((char*)set_path.buf); free_Buffer(&set_path); // int snum = 0; tList* lp = settingsFiles; while (lp!=NULL) { if (ex_strncaservscmp((char*)lp->ldat.val.buf, ".xml" , 4)) { Buffer name = make_Buffer_bystr(get_file_name((char*)lp->ldat.val.buf)); del_file_extension_Buffer(&name); lp->ldat.key = name; if (snum==0) regionName = dup_Buffer(name); lp = lp->next; snum++; } else { if (lp==settingsFiles) settingsFiles = lp->next; lp = del_tList_node(&lp); } } if (snum==0) { DEBUG_MODE PRINT_MESG("OARTool::SetupPathInfo: WARNING: not found settings file! [%ssettings/]\n", pathOAR.buf); return false; } // Terrain R32 Files Buffer trn_path = dup_Buffer(pathOAR); #ifdef WIN32 cat_s2Buffer("terrains\\", &trn_path); #else cat_s2Buffer("terrains/", &trn_path); #endif terrainsFiles = get_dir_files((char*)trn_path.buf); free_Buffer(&trn_path); // int tnum = 0; lp = terrainsFiles; while (lp!=NULL) { if (ex_strncaservscmp((char*)lp->ldat.val.buf, ".r32" , 4)) { Buffer name = make_Buffer_bystr(get_file_name((char*)lp->ldat.val.buf)); del_file_extension_Buffer(&name); lp->ldat.key = name; lp = lp->next; tnum++; } else { if (lp==terrainsFiles) terrainsFiles = lp->next; lp = del_tList_node(&lp); } } if (tnum==0) { DEBUG_MODE PRINT_MESG("OARTool::SetupPathInfo: WARNING: not found terrains file! [%sterrains/]\n", pathOAR.buf); return false; } terrainNum = tnum; // number of terrains // Landdata Files Buffer lnd_path = dup_Buffer(pathOAR); #ifdef WIN32 cat_s2Buffer("landdata\\", &lnd_path); #else cat_s2Buffer("landdata/", &lnd_path); #endif landdataFiles = get_dir_files((char*)lnd_path.buf); free_Buffer(&lnd_path); /* if (landdataFiles!=NULL) { tXML* land_xml = xml_parse_file((char*)landdataFiles->ldat.val.buf); if (land_xml!=NULL) { char* name = get_xml_str_content_bystr(land_xml, ""); // パーセル名 regionName = make_Buffer_bystr(name); del_xml(&land_xml); } }*/ // Objects Files Buffer obj_path = dup_Buffer(pathOAR); #ifdef WIN32 cat_s2Buffer("objects\\", &obj_path); #else cat_s2Buffer("objects/", &obj_path); #endif objectsFiles = get_dir_files_rcsv((char*)obj_path.buf); free_Buffer(&obj_path); objectsNum = 0; lp = objectsFiles; while (lp!=NULL) { if (ex_strncaservscmp((char*)lp->ldat.val.buf, ".xml" , 4)) { objectsNum++; lp = lp->next; } else { if (lp==objectsFiles) objectsFiles = lp->next; lp = del_tList_node(&lp); } } // Assets Files tList* extn = add_tList_node_str(NULL, "txt", NULL); // #ifdef WIN32 // Windowsの場合は : で区切れない if (pathAST.buf[strlen((char*)pathAST.buf)-1]!='\\') cat_s2Buffer("\\", &pathAST); assetsFiles = add_resource_list((char*)pathAST.buf, 36, assetsFiles, extn); #else Buffer* dirs = awk_Buffer_dim(pathAST, ':'); if (dirs!=NULL) { int num = dirs->state; for (int i=0; ildat.key.buf, xsize, ysize); terrain[count].ReadSettings((char*)lps->ldat.val.buf); terrain[count].ReadHeightData((char*)lpt->ldat.val.buf); lps = lps->next; lpt = lpt->next; count++; } } else { while (countldat.key.buf, xsize, ysize); terrain[count].ReadHeightData((char*)lpt->ldat.val.buf); lpt = lpt->next; count++; } } if (count>0) waterHeight = terrain[0].water_height(); } int OARTool::GenerateTerrainDae(void) { if (terrainNum==0) return 0; PRINT_MESG("GenerateTerrainDae: generating terrain dae file\n"); int num = 0; while (num=startnum && num<=stopnum) { GenerateDae((char*)lp->ldat.val.buf, num, useBrep, phantom, command); if (counter!=NULL) { if (counter->cancel) break; counter->StepIt(); } cnt++; } lp = lp->next; } if (counter!=NULL && counter->cancel) cnt = -1; return cnt; } int OARTool::GenerateSelectedDae(int objnum, int* objlist, bool useBrep, bool phantom, char* command) { tList* lp = objectsFiles; CVCounter* counter = GetUsableGlobalCounter(); int num = 0; int cnt = 0; while (lp!=NULL) { if (num==objlist[cnt]) { GenerateDae((char*)lp->ldat.val.buf, num+1, useBrep, phantom, command); if (counter!=NULL) { if (counter->cancel) break; counter->StepIt(); } cnt++; if (cnt==objnum) break; } num++; lp = lp->next; } if (counter!=NULL && counter->cancel) cnt = -1; return cnt; } /** Tree, Grass, Prim(Sculpt, Meshを含む) のXMLデータ(オブジェクト1個分) を Collada形式で書きだす. 出力先は outPathで指定されたディレクトリ. @param fname オブジェクト名(xmlファイル名) @param useBrep 頂点の配置にBREPを使用するか? 使用すると処理時間はかかるが,データサイズが小さくなる. @param num 表示用の処理番号. @paeam phantom オブジェクト中に1個でもファントムがある場合,全体をファントムとするか? @param command JPEG2000(テクスチャ)の内部処理が失敗した場合の外部コマンド. @param outPath 大域変数.データの出力先. */ void OARTool::GenerateDae(const char* fname, int num, bool useBrep, bool phantom, char* command) { PRINT_MESG("[%d/%d] GenerateDae: converting %s\n", num, objectsNum, fname); int shno = 0; PrimBaseShape* shapes; tXML* sxml = xml_parse_file(fname); if (sxml!=NULL) { shapes = CreatePrimBaseShapesFromXML(sxml, assetsFiles, &shno); // Shapeデータ.shnoはデータの数 del_xml(&sxml); if (shapes==NULL || shno<=0) { PRINT_MESG("OARTool::GenerateDae: WARNING: not found shape data in %s (skip)\n", fname); return; } } else { PRINT_MESG("OARTool::GenerateDae: WARNING: XML File %s Read Error.(skip)\n", fname); return; } ColladaXML* dae = new ColladaXML(); dae->forUnity5 = forUnity5; dae->forUnity3D = forUnity3D; dae->forUnity3D = forUnity3D; dae->setBlankTexture(PRIM_OS_BLANK_TEXTURE); bool phantom_out, collider; if (phantom) phantom_out = false; else phantom_out = true; int count = 0; for (int s=0; snodelist; while (node!=NULL) { if (node->material_param.enable) { // convert texture char* addname = node->material_param.getAdditionalName(); ConvertTexture(node->material_param.getTextureName(), addname, MTRL_IMAGE_TYPE, NULL, command); node->material_param.setupFullName(MTRL_IMAGE_TYPE); } node = node->next; } dae->addObject(data, collider); freeMeshObjectData(data); // count++; } } // // Grass else if (shapes[s].PCode==PRIM_PCODE_GRASS){ // shapes[s].affineTrans.addShift(-xsize/2.0f, -ysize/2.0f, -waterHeight); MeshObjectData* data = treeTool.GenerateGrass(shapes[s], terrain, forUnity3D); // 1個の Terrainのみサポート.範囲チェックあり shapes[s].affineTrans.addShift(shift.x, shift.y, shift.z); // if (data!=NULL) { collider = false; if (phantom) phantom_out = true; // MeshObjectNode* node = data->nodelist; while (node!=NULL) { if (node->material_param.enable) { // convert texture char* addname = node->material_param.getAdditionalName(); ConvertTexture(node->material_param.getTextureName(), addname, MTRL_IMAGE_TYPE, NULL, command); node->material_param.setupFullName(MTRL_IMAGE_TYPE); } node = node->next; } dae->addObject(data, collider); freeMeshObjectData(data); // count++; } } // // Prim (Sculpt, Meshを含む) else if (shapes[s].PCode==PRIM_PCODE_PRIM) { // shapes[s].affineTrans.addShift(-xsize/2.0f+shift.x, -ysize/2.0f+shift.y, -waterHeight+shift.z); MeshObjectData* data = MeshObjectDataFromPrimShape(shapes[s], assetsFiles, useBrep, forUnity3D); // if (data!=NULL) { if (strstr((const char*)shapes[s].ObjFlags.buf, OART_FLAGS_PHANTOM)!=NULL) { // Phantom collider = false; if (phantom) phantom_out = true; } else { collider = true; if (!phantom) phantom_out = false; } // MeshObjectNode* node = data->nodelist; while (node!=NULL) { if (node->material_param.enable) { // MeshObjectDataFromPrimShape へ移動 //node->material_param.setAlphaChannel(CheckAlphaChannel(node->material_param.getTextureName())); //if (node->material_param.isSetAlpha()) node->material_param.setTransparent(MTRL_DEFAULT_ALPHA); //if (unity3D) { // char* paramsname = GetBase64ParamsString(node->material_param, 'O'); // O: Object // if (paramsname!=NULL) { // node->material_param.setAdditionalName(paramsname); // ::free(paramsname); // } //} // convert texture char* addname = node->material_param.getAdditionalName(); ConvertTexture(node->material_param.getTextureName(), addname, MTRL_IMAGE_TYPE, NULL, command); ConvertTexture(node->material_param.getBumpMapName(), addname, MTRL_IMAGE_TYPE, NULL, command); ConvertTexture(node->material_param.getSpecMapName(), addname, MTRL_IMAGE_TYPE, NULL, command); node->material_param.setupFullName(MTRL_IMAGE_TYPE); } node = node->next; } dae->addObject(data, collider); freeMeshObjectData(data); // count++; } } } // Output file if (count>0) { if (count==1 && forUnity4) dae->addCenterObject(); // for Unity4.x // Buffer out_path = dup_Buffer(pathDAE); if (phantom_out) cat_s2Buffer(OART_DEFAULT_PTM_DIR, &out_path); dae->outputFile(fname, (char*)out_path.buf, XML_INDENT_FORMAT); // fnameの拡張子は自動的に変換される free_Buffer(&out_path); } freeColladaXML(dae); for (int s=0; s vp = JPEG2KImage2MSGraph(jpg); DEBUG_MODE PRINT_MESG("OARTool::ConvertTexture: texture = %s [size = (%4d,%4d,%2d), mode = %d]\n", texture, jpg.ws, jpg.hs, jpg.col, jpg.cmode); // if (vp.zs>0) { TGAImage tga = MSGraph2TGAImage(vp); int err = writeTGAFile((char*)outpath.buf, tga); if (!err) converted = true; else PRINT_MESG("OARTool::ConvertTexture: ERROR: write error (%d).\n", err); tga.free(); } else { PRINT_MESG("OARTool::ConvertTexture: ERROR: color num of %s is %d\n", texture, vp.zs); } vp.free(); jpg.free(); } else { if (jpg.state==JBXL_GRAPH_IVDDATA_ERROR) { DEBUG_MODE PRINT_MESG("OARTool::ConvertTexture: ERROR: texture %s is invalid.\n", texture); } else { DEBUG_MODE PRINT_MESG("OARTool::ConvertTexture: ERROR: texture %s convert error (%d).\n", texture, jpg.state); } } // // Retry convert using external command if (!converted) { DEBUG_MODE PRINT_MESG("OARTool::ConvertTexture: RETRY: convert %s to %s\n", path, (char*)outpath.buf); // char command[LMESG]; memset(command, 0, LMESG); if (comformat!=NULL) { snprintf(command, LMESG-1, comformat, path, (char*)outpath.buf); } else { snprintf(command, LMESG-1, OART_JP2_DECOMP_COM, path, (char*)outpath.buf); } // int err = 0; #ifdef WIN32 STARTUPINFOA sinfo; // コマンドの実行 PROCESS_INFORMATION pinfo; memset(&sinfo, 0, sizeof(STARTUPINFO)); sinfo.cb = sizeof(STARTUPINFO); sinfo.wShowWindow = SW_HIDE; CreateProcessA(NULL, (LPSTR)command, NULL, NULL, FALSE, CREATE_NO_WINDOW ,NULL, NULL, &sinfo, &pinfo); CloseHandle(pinfo.hThread); DWORD ret = WaitForSingleObject(pinfo.hProcess, INFINITE); CloseHandle(pinfo.hProcess); if (ret!=WAIT_OBJECT_0) err = 1; #else int ret = system(command); err = WEXITSTATUS(ret); #endif if (err!=0) { make_dummy = false; PRINT_MESG("OARTool::ConvertTexture: ERROR: texture %s convert error (%d).\n", texture, err); } else { DEBUG_MODE PRINT_MESG("OARTool::ConvertTexture: SUCCESS: texture %s is converted.\n", texture); } } } else { make_dummy = false; PRINT_MESG("OARTool::ConvertTexture: ERROR: texture %s is lost!\n", texture); } } free_Buffer(&outpath); // // if (make_dummy) MakeDummyTexture(texture, add_name, ext_name, dist); return; } /** テスト中! @param texture コンバート元データのUUID. @param add_fname コンバート先ファイル名の追加文字列. @param ext_fname コンバート先ファイル名の拡張子. @param dist コンバート先のパス. */ void OARTool::MakeDummyTexture(const char* texture, const char* add_name, const char* ext_name, const char* dist) { if (texture==NULL) return; Buffer outpath; if (dist==NULL) outpath = make_Buffer_bystr((char*)pathTEX.buf); else outpath = make_Buffer_bystr(dist); cat_s2Buffer(texture, &outpath); if (add_name!=NULL) { cat_s2Buffer("_", &outpath); cat_s2Buffer(add_name, &outpath); } if (ext_name!=NULL) { if (ext_name[0]!='.') cat_s2Buffer(".", &outpath); cat_s2Buffer(ext_name, &outpath); } #ifndef WIN32 rewrite_sBuffer_str(&outpath, " ", "\\ "); rewrite_sBuffer_str(&outpath, ";", "\\;"); #endif if (!file_exist((char*)outpath.buf)) { // Buffer inppath = dup_Buffer(pathAST); cat_s2Buffer("dummy.tga", &inppath); int ret = copy_file((char*)inppath.buf, (char*)outpath.buf); //PRINT_MESG("====> %d %s\n", ret, inppath.buf); free_Buffer(&inppath); } free_Buffer(&outpath); return; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // for STL // int OARTool::GenerateTerrainSTL(bool binfile) { if (terrainNum==0) return 0; PRINT_MESG("GenerateTerrainSTL: generating terrain stl file\n"); int num = 0; while (num=startnum && num<=stopnum) { GenerateSTL((char*)lp->ldat.val.buf, num, binfile); if (counter!=NULL) { if (counter->cancel) break; counter->StepIt(); } cnt++; } lp = lp->next; } if (counter!=NULL && counter->cancel) cnt = -1; return cnt; } int OARTool::GenerateSelectedSTL(int objnum, int* objlist, bool binfile) { tList* lp = objectsFiles; CVCounter* counter = GetUsableGlobalCounter(); int num = 0; int cnt = 0; while (lp!=NULL) { if (num==objlist[cnt]) { GenerateSTL((char*)lp->ldat.val.buf, num+1, binfile); if (counter!=NULL) { if (counter->cancel) break; counter->StepIt(); } cnt++; if (cnt==objnum) break; } num++; lp = lp->next; } if (counter!=NULL && counter->cancel) cnt = -1; return cnt; } /** Tree, Grass, Prim(Sculpt, Meshを含む) のXMLデータ(ファイル1個分) を STL形式で書きだす. 頂点の配置には BREPが使用される. @param fname オブジェクト名 @param num 表示用の処理番号. @param binfile データをバイナリ形式で出力するか? */ void OARTool::GenerateSTL(const char* fname, int num, bool binfile) { PRINT_MESG("[%d/%d] GenerateSTL: converting %s\n", num, objectsNum, fname); BrepSolidList* slist = GenerateSolidList(fname); // Output file if (slist!=NULL) { Buffer out_path = dup_Buffer(pathSTL); slist->outputFile(fname, (char*)out_path.buf, binfile); // fnameの拡張子は自動的に変換される free_Buffer(&out_path); freeBrepSolidList(slist); } return; } BrepSolidList* OARTool::GenerateSolidList(const char* fname) { int shno = 0; PrimBaseShape* shapes; tXML* sxml = xml_parse_file(fname); if (sxml!=NULL) { shapes = CreatePrimBaseShapesFromXML(sxml, assetsFiles, &shno); // Shapeデータ.shnoはデータの数 del_xml(&sxml); if (shapes==NULL || shno<=0) { PRINT_MESG("OARTool::GenerateBrepSolidList: WARNING: not found shape data in %s (skip)\n", fname); return NULL; } } else { PRINT_MESG("OARTool::GenerateBrepSolidList: WARNING: XML File %s Read Error.(skip)\n", fname); return NULL; } BrepSolidList* slist = new BrepSolidList(); int count = 0; for (int s=0; saddObject(data); freeMeshObjectData(data); // count++; } } // // Grass else if (shapes[s].PCode==PRIM_PCODE_GRASS){ // shapes[s].affineTrans.addShift(-xsize/2.0f, -ysize/2.0f, -waterHeight); MeshObjectData* data = treeTool.GenerateGrass(shapes[s], terrain, forUnity3D); // 1個の Terrainのみサポート.範囲チェックあり shapes[s].affineTrans.addShift(shift.x, shift.y, shift.z); // if (data!=NULL) { slist->addObject(data); freeMeshObjectData(data); // count++; } } // // Prim (Sculpt, Meshを含む) else if (shapes[s].PCode==PRIM_PCODE_PRIM) { // shapes[s].affineTrans.addShift(-xsize/2.0f+shift.x, -ysize/2.0f+shift.y, -waterHeight+shift.z); MeshObjectData* data = MeshObjectDataFromPrimShape(shapes[s], assetsFiles, false, forUnity3D); // if (data!=NULL) { slist->addObject(data); freeMeshObjectData(data); // count++; } } } for (int s=0; s