#include "resource_importer_obj.h" #include "io/resource_saver.h" #include "scene/resources/mesh.h" #include "scene/resources/surface_tool.h" #include "scene/resources/surface_tool.h" #include "os/file_access.h" String ResourceImporterOBJ::get_importer_name() const { return "obj_mesh"; } String ResourceImporterOBJ::get_visible_name() const{ return "OBJ As Mesh"; } void ResourceImporterOBJ::get_recognized_extensions(List *p_extensions) const{ p_extensions->push_back("obj"); } String ResourceImporterOBJ::get_save_extension() const { return "msh"; } String ResourceImporterOBJ::get_resource_type() const{ return "Mesh"; } bool ResourceImporterOBJ::get_option_visibility(const String& p_option,const Map& p_options) const { return true; } int ResourceImporterOBJ::get_preset_count() const { return 0; } String ResourceImporterOBJ::get_preset_name(int p_idx) const { return String(); } void ResourceImporterOBJ::get_import_options(List *r_options,int p_preset) const { r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"generate/tangents"),true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"generate/normals"),true)); //not for nowp //r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"import/materials"))); //r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"import/textures"))); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"force/flip_faces"),false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"force/smooth_shading"),true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"force/weld_vertices"),true)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL,"force/weld_tolerance",PROPERTY_HINT_RANGE,"0.00001,16,0.00001"),0.0001)); //r_options->push_back(PropertyInfo(Variant::INT,"compress/bitrate",PROPERTY_HINT_ENUM,"64,96,128,192")); } Error ResourceImporterOBJ::import(const String& p_source_file, const String& p_save_path, const Map& p_options, List* r_platform_variants, List *r_gen_files) { FileAccessRef f = FileAccess::open(p_source_file,FileAccess::READ); ERR_FAIL_COND_V(!f,ERR_CANT_OPEN); Ref mesh = Ref( memnew( Mesh ) ); Map > name_map; bool generate_normals=p_options["generate/normals"]; bool generate_tangents=p_options["generate/tangents"]; bool flip_faces=p_options["force/flip_faces"]; bool force_smooth=p_options["force/smooth_shading"]; bool weld_vertices=p_options["force/weld_vertices"]; float weld_tolerance=p_options["force/weld_tolerance"]; Vector vertices; Vector normals; Vector uvs; String name; Ref surf_tool = memnew( SurfaceTool) ; surf_tool->begin(Mesh::PRIMITIVE_TRIANGLES); if (force_smooth) surf_tool->add_smooth_group(true); int has_index_data=false; while(true) { String l = f->get_line().strip_edges(); if (l.begins_with("v ")) { //vertex Vector v = l.split(" ",false); ERR_FAIL_COND_V(v.size()<4,ERR_INVALID_DATA); Vector3 vtx; vtx.x=v[1].to_float(); vtx.y=v[2].to_float(); vtx.z=v[3].to_float(); vertices.push_back(vtx); } else if (l.begins_with("vt ")) { //uv Vector v = l.split(" ",false); ERR_FAIL_COND_V(v.size()<3,ERR_INVALID_DATA); Vector2 uv; uv.x=v[1].to_float(); uv.y=1.0-v[2].to_float(); uvs.push_back(uv); } else if (l.begins_with("vn ")) { //normal Vector v = l.split(" ",false); ERR_FAIL_COND_V(v.size()<4,ERR_INVALID_DATA); Vector3 nrm; nrm.x=v[1].to_float(); nrm.y=v[2].to_float(); nrm.z=v[3].to_float(); normals.push_back(nrm); } if (l.begins_with("f ")) { //vertex has_index_data=true; Vector v = l.split(" ",false); ERR_FAIL_COND_V(v.size()<4,ERR_INVALID_DATA); //not very fast, could be sped up Vector face[3]; face[0] = v[1].split("/"); face[1] = v[2].split("/"); ERR_FAIL_COND_V(face[0].size()==0,ERR_PARSE_ERROR); ERR_FAIL_COND_V(face[0].size()!=face[1].size(),ERR_PARSE_ERROR); for(int i=2;iadd_normal(normals[norm]); } if (face[idx].size()>=2 && face[idx][1]!=String()) { int uv = face[idx][1].to_int()-1; ERR_FAIL_INDEX_V(uv,uvs.size(),ERR_PARSE_ERROR); surf_tool->add_uv(uvs[uv]); } int vtx = face[idx][0].to_int()-1; ERR_FAIL_INDEX_V(vtx,vertices.size(),ERR_PARSE_ERROR); Vector3 vertex = vertices[vtx]; if (weld_vertices) vertex=vertex.snapped(weld_tolerance); surf_tool->add_vertex(vertex); } face[1]=face[2]; } } else if (l.begins_with("s ") && !force_smooth) { //smoothing String what = l.substr(2,l.length()).strip_edges(); if (what=="off") surf_tool->add_smooth_group(false); else surf_tool->add_smooth_group(true); } else if (l.begins_with("o ") || f->eof_reached()) { //new surface or done if (has_index_data) { //new object/surface if (generate_normals || force_smooth) surf_tool->generate_normals(); if (uvs.size() && (normals.size() || generate_normals) && generate_tangents) surf_tool->generate_tangents(); surf_tool->index(); mesh = surf_tool->commit(mesh); if (name=="") name=vformat(TTR("Surface %d"),mesh->get_surface_count()-1); mesh->surface_set_name(mesh->get_surface_count()-1,name); name=""; surf_tool->clear(); surf_tool->begin(Mesh::PRIMITIVE_TRIANGLES); if (force_smooth) surf_tool->add_smooth_group(true); has_index_data=false; if (f->eof_reached()) break; } if (l.begins_with("o ")) //name name=l.substr(2,l.length()).strip_edges(); } } /* TODO, check existing materials and merge? //re-apply materials if exist for(int i=0;iget_surface_count();i++) { String n = mesh->surface_get_name(i); if (name_map.has(n)) mesh->surface_set_material(i,name_map[n]); } */ Error err = ResourceSaver::save(p_save_path+".msh",mesh); return err; } ResourceImporterOBJ::ResourceImporterOBJ() { }