2017-03-05 14:47:28 +00:00
/*************************************************************************/
/* resource_importer_obj.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:16:55 +00:00
/* https://godotengine.org */
2017-03-05 14:47:28 +00:00
/*************************************************************************/
2020-01-01 10:16:22 +00:00
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
2017-03-05 14:47:28 +00:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2018-01-04 23:50:27 +00:00
2017-02-03 03:08:50 +00:00
# include "resource_importer_obj.h"
2018-09-11 16:13:45 +00:00
# include "core/io/resource_saver.h"
# include "core/os/file_access.h"
2020-03-26 21:49:16 +00:00
# include "scene/3d/mesh_instance_3d.h"
# include "scene/3d/node_3d.h"
2017-02-03 03:08:50 +00:00
# include "scene/resources/mesh.h"
# include "scene/resources/surface_tool.h"
2017-07-18 00:05:38 +00:00
uint32_t EditorOBJImporter : : get_import_flags ( ) const {
2017-02-03 03:08:50 +00:00
2017-07-18 00:05:38 +00:00
return IMPORT_SCENE ;
2017-02-03 03:08:50 +00:00
}
2020-03-17 06:33:00 +00:00
static Error _parse_material_library ( const String & p_path , Map < String , Ref < StandardMaterial3D > > & material_map , List < String > * r_missing_deps ) {
2017-02-03 03:08:50 +00:00
2017-07-18 00:05:38 +00:00
FileAccessRef f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
2019-08-15 02:57:49 +00:00
ERR_FAIL_COND_V_MSG ( ! f , ERR_CANT_OPEN , vformat ( " Couldn't open MTL file '%s', it may not exist or not be readable. " , p_path ) ) ;
2017-02-03 03:08:50 +00:00
2019-09-15 04:01:52 +00:00
Ref < StandardMaterial3D > current ;
2017-07-18 00:05:38 +00:00
String current_name ;
String base_path = p_path . get_base_dir ( ) ;
while ( true ) {
2017-02-03 03:08:50 +00:00
2017-07-18 00:05:38 +00:00
String l = f - > get_line ( ) . strip_edges ( ) ;
2017-02-03 03:08:50 +00:00
2017-07-18 00:05:38 +00:00
if ( l . begins_with ( " newmtl " ) ) {
//vertex
2017-02-03 03:08:50 +00:00
2017-07-18 00:05:38 +00:00
current_name = l . replace ( " newmtl " , " " ) . strip_edges ( ) ;
current . instance ( ) ;
2017-11-25 15:32:02 +00:00
current - > set_name ( current_name ) ;
2017-07-18 00:05:38 +00:00
material_map [ current_name ] = current ;
} else if ( l . begins_with ( " Ka " ) ) {
//uv
2019-11-07 08:44:15 +00:00
WARN_PRINT ( " OBJ: Ambient light for material ' " + current_name + " ' is ignored in PBR " ) ;
2017-02-03 03:08:50 +00:00
2017-07-18 00:05:38 +00:00
} else if ( l . begins_with ( " Kd " ) ) {
//normal
ERR_FAIL_COND_V ( current . is_null ( ) , ERR_FILE_CORRUPT ) ;
Vector < String > v = l . split ( " " , false ) ;
ERR_FAIL_COND_V ( v . size ( ) < 4 , ERR_INVALID_DATA ) ;
Color c = current - > get_albedo ( ) ;
c . r = v [ 1 ] . to_float ( ) ;
c . g = v [ 2 ] . to_float ( ) ;
c . b = v [ 3 ] . to_float ( ) ;
current - > set_albedo ( c ) ;
} else if ( l . begins_with ( " Ks " ) ) {
//normal
ERR_FAIL_COND_V ( current . is_null ( ) , ERR_FILE_CORRUPT ) ;
Vector < String > v = l . split ( " " , false ) ;
ERR_FAIL_COND_V ( v . size ( ) < 4 , ERR_INVALID_DATA ) ;
float r = v [ 1 ] . to_float ( ) ;
float g = v [ 2 ] . to_float ( ) ;
float b = v [ 3 ] . to_float ( ) ;
float metalness = MAX ( r , MAX ( g , b ) ) ;
current - > set_metallic ( metalness ) ;
} else if ( l . begins_with ( " Ns " ) ) {
//normal
ERR_FAIL_COND_V ( current . is_null ( ) , ERR_FILE_CORRUPT ) ;
Vector < String > v = l . split ( " " , false ) ;
ERR_FAIL_COND_V ( v . size ( ) ! = 2 , ERR_INVALID_DATA ) ;
float s = v [ 1 ] . to_float ( ) ;
current - > set_metallic ( ( 1000.0 - s ) / 1000.0 ) ;
} else if ( l . begins_with ( " d " ) ) {
//normal
ERR_FAIL_COND_V ( current . is_null ( ) , ERR_FILE_CORRUPT ) ;
Vector < String > v = l . split ( " " , false ) ;
ERR_FAIL_COND_V ( v . size ( ) ! = 2 , ERR_INVALID_DATA ) ;
float d = v [ 1 ] . to_float ( ) ;
Color c = current - > get_albedo ( ) ;
c . a = d ;
current - > set_albedo ( c ) ;
if ( c . a < 0.99 ) {
2019-09-15 04:01:52 +00:00
current - > set_transparency ( StandardMaterial3D : : TRANSPARENCY_ALPHA ) ;
2017-07-18 00:05:38 +00:00
}
} else if ( l . begins_with ( " Tr " ) ) {
//normal
ERR_FAIL_COND_V ( current . is_null ( ) , ERR_FILE_CORRUPT ) ;
Vector < String > v = l . split ( " " , false ) ;
ERR_FAIL_COND_V ( v . size ( ) ! = 2 , ERR_INVALID_DATA ) ;
float d = v [ 1 ] . to_float ( ) ;
Color c = current - > get_albedo ( ) ;
c . a = 1.0 - d ;
current - > set_albedo ( c ) ;
if ( c . a < 0.99 ) {
2019-09-15 04:01:52 +00:00
current - > set_transparency ( StandardMaterial3D : : TRANSPARENCY_ALPHA ) ;
2017-07-18 00:05:38 +00:00
}
} else if ( l . begins_with ( " map_Ka " ) ) {
//uv
2019-11-07 08:44:15 +00:00
WARN_PRINT ( " OBJ: Ambient light texture for material ' " + current_name + " ' is ignored in PBR " ) ;
2017-07-18 00:05:38 +00:00
} else if ( l . begins_with ( " map_Kd " ) ) {
//normal
ERR_FAIL_COND_V ( current . is_null ( ) , ERR_FILE_CORRUPT ) ;
String p = l . replace ( " map_Kd " , " " ) . replace ( " \\ " , " / " ) . strip_edges ( ) ;
2018-09-17 02:23:40 +00:00
String path ;
if ( p . is_abs_path ( ) ) {
path = p ;
} else {
path = base_path . plus_file ( p ) ;
}
2017-07-18 00:05:38 +00:00
2019-06-11 18:43:37 +00:00
Ref < Texture2D > texture = ResourceLoader : : load ( path ) ;
2017-07-18 00:05:38 +00:00
if ( texture . is_valid ( ) ) {
2019-09-15 04:01:52 +00:00
current - > set_texture ( StandardMaterial3D : : TEXTURE_ALBEDO , texture ) ;
2017-09-29 23:38:27 +00:00
} else if ( r_missing_deps ) {
2017-07-18 00:05:38 +00:00
r_missing_deps - > push_back ( path ) ;
}
} else if ( l . begins_with ( " map_Ks " ) ) {
//normal
ERR_FAIL_COND_V ( current . is_null ( ) , ERR_FILE_CORRUPT ) ;
String p = l . replace ( " map_Ks " , " " ) . replace ( " \\ " , " / " ) . strip_edges ( ) ;
2018-09-17 02:23:40 +00:00
String path ;
if ( p . is_abs_path ( ) ) {
path = p ;
} else {
path = base_path . plus_file ( p ) ;
}
2017-07-18 00:05:38 +00:00
2019-06-11 18:43:37 +00:00
Ref < Texture2D > texture = ResourceLoader : : load ( path ) ;
2017-07-18 00:05:38 +00:00
if ( texture . is_valid ( ) ) {
2019-09-15 04:01:52 +00:00
current - > set_texture ( StandardMaterial3D : : TEXTURE_METALLIC , texture ) ;
2017-09-29 23:38:27 +00:00
} else if ( r_missing_deps ) {
2017-07-18 00:05:38 +00:00
r_missing_deps - > push_back ( path ) ;
}
} else if ( l . begins_with ( " map_Ns " ) ) {
//normal
ERR_FAIL_COND_V ( current . is_null ( ) , ERR_FILE_CORRUPT ) ;
String p = l . replace ( " map_Ns " , " " ) . replace ( " \\ " , " / " ) . strip_edges ( ) ;
2018-09-17 02:23:40 +00:00
String path ;
if ( p . is_abs_path ( ) ) {
path = p ;
} else {
path = base_path . plus_file ( p ) ;
}
2017-07-18 00:05:38 +00:00
2019-06-11 18:43:37 +00:00
Ref < Texture2D > texture = ResourceLoader : : load ( path ) ;
2017-07-18 00:05:38 +00:00
if ( texture . is_valid ( ) ) {
2019-09-15 04:01:52 +00:00
current - > set_texture ( StandardMaterial3D : : TEXTURE_ROUGHNESS , texture ) ;
2017-09-29 23:38:27 +00:00
} else if ( r_missing_deps ) {
2017-07-18 00:05:38 +00:00
r_missing_deps - > push_back ( path ) ;
}
} else if ( l . begins_with ( " map_bump " ) ) {
//normal
ERR_FAIL_COND_V ( current . is_null ( ) , ERR_FILE_CORRUPT ) ;
String p = l . replace ( " map_bump " , " " ) . replace ( " \\ " , " / " ) . strip_edges ( ) ;
String path = base_path . plus_file ( p ) ;
2017-02-03 03:08:50 +00:00
2019-06-11 18:43:37 +00:00
Ref < Texture2D > texture = ResourceLoader : : load ( path ) ;
2017-07-18 00:05:38 +00:00
if ( texture . is_valid ( ) ) {
2019-09-15 04:01:52 +00:00
current - > set_feature ( StandardMaterial3D : : FEATURE_NORMAL_MAPPING , true ) ;
current - > set_texture ( StandardMaterial3D : : TEXTURE_NORMAL , texture ) ;
2017-09-29 23:38:27 +00:00
} else if ( r_missing_deps ) {
2017-07-18 00:05:38 +00:00
r_missing_deps - > push_back ( path ) ;
}
} else if ( f - > eof_reached ( ) ) {
break ;
}
}
return OK ;
2017-02-03 03:08:50 +00:00
}
2020-03-17 06:33:00 +00:00
static Error _parse_obj ( const String & p_path , List < Ref < Mesh > > & r_meshes , bool p_single_mesh , bool p_generate_tangents , bool p_optimize , Vector3 p_scale_mesh , Vector3 p_offset_mesh , List < String > * r_missing_deps ) {
2017-02-03 03:08:50 +00:00
2017-07-18 00:05:38 +00:00
FileAccessRef f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
2019-08-15 02:57:49 +00:00
ERR_FAIL_COND_V_MSG ( ! f , ERR_CANT_OPEN , vformat ( " Couldn't open OBJ file '%s', it may not exist or not be readable. " , p_path ) ) ;
2017-07-18 00:05:38 +00:00
Ref < ArrayMesh > mesh ;
mesh . instance ( ) ;
2017-02-03 03:08:50 +00:00
2017-09-29 23:38:27 +00:00
bool generate_tangents = p_generate_tangents ;
2018-02-12 10:36:40 +00:00
Vector3 scale_mesh = p_scale_mesh ;
2020-01-11 08:21:38 +00:00
Vector3 offset_mesh = p_offset_mesh ;
2018-06-30 22:58:37 +00:00
int mesh_flags = p_optimize ? Mesh : : ARRAY_COMPRESS_DEFAULT : 0 ;
2017-02-03 03:08:50 +00:00
Vector < Vector3 > vertices ;
Vector < Vector3 > normals ;
Vector < Vector2 > uvs ;
String name ;
2020-03-17 06:33:00 +00:00
Map < String , Map < String , Ref < StandardMaterial3D > > > material_map ;
2017-07-18 00:05:38 +00:00
2017-03-05 15:44:50 +00:00
Ref < SurfaceTool > surf_tool = memnew ( SurfaceTool ) ;
2017-02-03 03:08:50 +00:00
surf_tool - > begin ( Mesh : : PRIMITIVE_TRIANGLES ) ;
2017-07-18 00:05:38 +00:00
String current_material_library ;
String current_material ;
String current_group ;
2017-02-03 03:08:50 +00:00
2017-03-05 15:44:50 +00:00
while ( true ) {
2017-02-03 03:08:50 +00:00
String l = f - > get_line ( ) . strip_edges ( ) ;
2018-07-30 00:37:55 +00:00
while ( l . length ( ) & & l [ l . length ( ) - 1 ] = = ' \\ ' ) {
String add = f - > get_line ( ) . strip_edges ( ) ;
l + = add ;
if ( add = = String ( ) ) {
break ;
}
}
2017-02-03 03:08:50 +00:00
if ( l . begins_with ( " v " ) ) {
//vertex
2017-03-05 15:44:50 +00:00
Vector < String > v = l . split ( " " , false ) ;
2017-09-29 23:38:27 +00:00
ERR_FAIL_COND_V ( v . size ( ) < 4 , ERR_FILE_CORRUPT ) ;
2017-02-03 03:08:50 +00:00
Vector3 vtx ;
2020-01-11 08:21:38 +00:00
vtx . x = v [ 1 ] . to_float ( ) * scale_mesh . x + offset_mesh . x ;
vtx . y = v [ 2 ] . to_float ( ) * scale_mesh . y + offset_mesh . y ;
vtx . z = v [ 3 ] . to_float ( ) * scale_mesh . z + offset_mesh . z ;
2017-02-03 03:08:50 +00:00
vertices . push_back ( vtx ) ;
2017-03-05 15:44:50 +00:00
} else if ( l . begins_with ( " vt " ) ) {
2017-02-03 03:08:50 +00:00
//uv
2017-03-05 15:44:50 +00:00
Vector < String > v = l . split ( " " , false ) ;
2017-09-29 23:38:27 +00:00
ERR_FAIL_COND_V ( v . size ( ) < 3 , ERR_FILE_CORRUPT ) ;
2017-02-03 03:08:50 +00:00
Vector2 uv ;
2017-03-05 15:44:50 +00:00
uv . x = v [ 1 ] . to_float ( ) ;
uv . y = 1.0 - v [ 2 ] . to_float ( ) ;
2017-02-03 03:08:50 +00:00
uvs . push_back ( uv ) ;
} else if ( l . begins_with ( " vn " ) ) {
//normal
2017-03-05 15:44:50 +00:00
Vector < String > v = l . split ( " " , false ) ;
2017-09-29 23:38:27 +00:00
ERR_FAIL_COND_V ( v . size ( ) < 4 , ERR_FILE_CORRUPT ) ;
2017-02-03 03:08:50 +00:00
Vector3 nrm ;
2017-03-05 15:44:50 +00:00
nrm . x = v [ 1 ] . to_float ( ) ;
nrm . y = v [ 2 ] . to_float ( ) ;
nrm . z = v [ 3 ] . to_float ( ) ;
2017-02-03 03:08:50 +00:00
normals . push_back ( nrm ) ;
2017-02-23 08:28:09 +00:00
} else if ( l . begins_with ( " f " ) ) {
2017-03-05 15:44:50 +00:00
//vertex
2017-02-03 03:08:50 +00:00
2017-03-05 15:44:50 +00:00
Vector < String > v = l . split ( " " , false ) ;
2017-09-29 23:38:27 +00:00
ERR_FAIL_COND_V ( v . size ( ) < 4 , ERR_FILE_CORRUPT ) ;
2017-02-03 03:08:50 +00:00
//not very fast, could be sped up
Vector < String > face [ 3 ] ;
face [ 0 ] = v [ 1 ] . split ( " / " ) ;
face [ 1 ] = v [ 2 ] . split ( " / " ) ;
2017-09-29 23:38:27 +00:00
ERR_FAIL_COND_V ( face [ 0 ] . size ( ) = = 0 , ERR_FILE_CORRUPT ) ;
2018-07-30 00:37:55 +00:00
2017-09-29 23:38:27 +00:00
ERR_FAIL_COND_V ( face [ 0 ] . size ( ) ! = face [ 1 ] . size ( ) , ERR_FILE_CORRUPT ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 2 ; i < v . size ( ) - 1 ; i + + ) {
2017-02-03 03:08:50 +00:00
2017-03-05 15:44:50 +00:00
face [ 2 ] = v [ i + 1 ] . split ( " / " ) ;
2018-07-30 00:37:55 +00:00
2017-09-29 23:38:27 +00:00
ERR_FAIL_COND_V ( face [ 0 ] . size ( ) ! = face [ 2 ] . size ( ) , ERR_FILE_CORRUPT ) ;
2017-03-05 15:44:50 +00:00
for ( int j = 0 ; j < 3 ; j + + ) {
2017-02-03 03:08:50 +00:00
2017-03-05 15:44:50 +00:00
int idx = j ;
2017-02-03 03:08:50 +00:00
2019-06-20 14:59:48 +00:00
if ( idx < 2 ) {
2017-03-05 15:44:50 +00:00
idx = 1 ^ idx ;
2017-02-03 03:08:50 +00:00
}
2017-03-05 15:44:50 +00:00
if ( face [ idx ] . size ( ) = = 3 ) {
int norm = face [ idx ] [ 2 ] . to_int ( ) - 1 ;
2017-04-27 08:24:09 +00:00
if ( norm < 0 )
norm + = normals . size ( ) + 1 ;
2017-09-29 23:38:27 +00:00
ERR_FAIL_INDEX_V ( norm , normals . size ( ) , ERR_FILE_CORRUPT ) ;
2017-02-03 03:08:50 +00:00
surf_tool - > add_normal ( normals [ norm ] ) ;
}
2017-03-05 15:44:50 +00:00
if ( face [ idx ] . size ( ) > = 2 & & face [ idx ] [ 1 ] ! = String ( ) ) {
int uv = face [ idx ] [ 1 ] . to_int ( ) - 1 ;
2017-04-27 08:24:09 +00:00
if ( uv < 0 )
uv + = uvs . size ( ) + 1 ;
2017-09-29 23:38:27 +00:00
ERR_FAIL_INDEX_V ( uv , uvs . size ( ) , ERR_FILE_CORRUPT ) ;
2017-02-03 03:08:50 +00:00
surf_tool - > add_uv ( uvs [ uv ] ) ;
}
2017-03-05 15:44:50 +00:00
int vtx = face [ idx ] [ 0 ] . to_int ( ) - 1 ;
2017-04-27 08:24:09 +00:00
if ( vtx < 0 )
vtx + = vertices . size ( ) + 1 ;
2017-09-29 23:38:27 +00:00
ERR_FAIL_INDEX_V ( vtx , vertices . size ( ) , ERR_FILE_CORRUPT ) ;
2017-02-03 03:08:50 +00:00
Vector3 vertex = vertices [ vtx ] ;
2017-07-18 00:05:38 +00:00
//if (weld_vertices)
// vertex.snap(Vector3(weld_tolerance, weld_tolerance, weld_tolerance));
2017-02-03 03:08:50 +00:00
surf_tool - > add_vertex ( vertex ) ;
}
2017-03-05 15:44:50 +00:00
face [ 1 ] = face [ 2 ] ;
2017-02-03 03:08:50 +00:00
}
2017-07-18 00:05:38 +00:00
} else if ( l . begins_with ( " s " ) ) { //smoothing
2017-03-05 15:44:50 +00:00
String what = l . substr ( 2 , l . length ( ) ) . strip_edges ( ) ;
if ( what = = " off " )
2017-02-03 03:08:50 +00:00
surf_tool - > add_smooth_group ( false ) ;
else
surf_tool - > add_smooth_group ( true ) ;
2017-07-29 03:03:54 +00:00
} else if ( /*l.begins_with("g ") | | */ l . begins_with ( " usemtl " ) | | ( l . begins_with ( " o " ) | | f - > eof_reached ( ) ) ) { //commit group to mesh
//groups are too annoying
2017-07-18 00:05:38 +00:00
if ( surf_tool - > get_vertex_array ( ) . size ( ) ) {
//another group going on, commit it
if ( normals . size ( ) = = 0 ) {
2017-02-03 03:08:50 +00:00
surf_tool - > generate_normals ( ) ;
2017-07-18 00:05:38 +00:00
}
if ( generate_tangents & & uvs . size ( ) ) {
2017-02-03 03:08:50 +00:00
surf_tool - > generate_tangents ( ) ;
2017-07-18 00:05:38 +00:00
}
2017-02-03 03:08:50 +00:00
surf_tool - > index ( ) ;
2017-07-18 00:05:38 +00:00
2018-08-24 07:35:07 +00:00
print_verbose ( " OBJ: Current material library " + current_material_library + " has " + itos ( material_map . has ( current_material_library ) ) ) ;
print_verbose ( " OBJ: Current material " + current_material + " has " + itos ( material_map . has ( current_material_library ) & & material_map [ current_material_library ] . has ( current_material ) ) ) ;
2017-07-18 00:05:38 +00:00
if ( material_map . has ( current_material_library ) & & material_map [ current_material_library ] . has ( current_material ) ) {
surf_tool - > set_material ( material_map [ current_material_library ] [ current_material ] ) ;
}
2018-06-30 22:58:37 +00:00
mesh = surf_tool - > commit ( mesh , mesh_flags ) ;
2017-07-18 00:05:38 +00:00
if ( current_material ! = String ( ) ) {
mesh - > surface_set_name ( mesh - > get_surface_count ( ) - 1 , current_material . get_basename ( ) ) ;
} else if ( current_group ! = String ( ) ) {
mesh - > surface_set_name ( mesh - > get_surface_count ( ) - 1 , current_group ) ;
}
2018-08-24 07:35:07 +00:00
print_verbose ( " OBJ: Added surface : " + mesh - > surface_get_name ( mesh - > get_surface_count ( ) - 1 ) ) ;
2017-02-03 03:08:50 +00:00
surf_tool - > clear ( ) ;
surf_tool - > begin ( Mesh : : PRIMITIVE_TRIANGLES ) ;
2017-07-18 00:05:38 +00:00
}
if ( l . begins_with ( " o " ) | | f - > eof_reached ( ) ) {
2017-09-29 23:38:27 +00:00
if ( ! p_single_mesh ) {
mesh - > set_name ( name ) ;
r_meshes . push_back ( mesh ) ;
mesh . instance ( ) ;
current_group = " " ;
current_material = " " ;
}
2017-02-03 03:08:50 +00:00
}
2017-07-18 00:05:38 +00:00
if ( f - > eof_reached ( ) ) {
break ;
}
if ( l . begins_with ( " o " ) ) {
2017-03-05 15:44:50 +00:00
name = l . substr ( 2 , l . length ( ) ) . strip_edges ( ) ;
2017-07-18 00:05:38 +00:00
}
if ( l . begins_with ( " usemtl " ) ) {
current_material = l . replace ( " usemtl " , " " ) . strip_edges ( ) ;
}
if ( l . begins_with ( " g " ) ) {
current_group = l . substr ( 2 , l . length ( ) ) . strip_edges ( ) ;
}
} else if ( l . begins_with ( " mtllib " ) ) { //parse material
current_material_library = l . replace ( " mtllib " , " " ) . strip_edges ( ) ;
if ( ! material_map . has ( current_material_library ) ) {
2020-03-17 06:33:00 +00:00
Map < String , Ref < StandardMaterial3D > > lib ;
2017-07-18 00:05:38 +00:00
Error err = _parse_material_library ( current_material_library , lib , r_missing_deps ) ;
2017-07-18 21:21:51 +00:00
if ( err = = ERR_CANT_OPEN ) {
String dir = p_path . get_base_dir ( ) ;
err = _parse_material_library ( dir . plus_file ( current_material_library ) , lib , r_missing_deps ) ;
}
2017-07-18 00:05:38 +00:00
if ( err = = OK ) {
material_map [ current_material_library ] = lib ;
}
}
2017-02-03 03:08:50 +00:00
}
}
2017-09-29 23:38:27 +00:00
if ( p_single_mesh ) {
r_meshes . push_back ( mesh ) ;
}
return OK ;
}
Node * EditorOBJImporter : : import_scene ( const String & p_path , uint32_t p_flags , int p_bake_fps , List < String > * r_missing_deps , Error * r_err ) {
2020-03-17 06:33:00 +00:00
List < Ref < Mesh > > meshes ;
2017-09-29 23:38:27 +00:00
2020-01-11 08:21:38 +00:00
Error err = _parse_obj ( p_path , meshes , false , p_flags & IMPORT_GENERATE_TANGENT_ARRAYS , p_flags & IMPORT_USE_COMPRESSION , Vector3 ( 1 , 1 , 1 ) , Vector3 ( 0 , 0 , 0 ) , r_missing_deps ) ;
2017-09-29 23:38:27 +00:00
if ( err ! = OK ) {
if ( r_err ) {
* r_err = err ;
}
2020-04-01 23:20:12 +00:00
return nullptr ;
2017-09-29 23:38:27 +00:00
}
2020-03-26 21:49:16 +00:00
Node3D * scene = memnew ( Node3D ) ;
2017-09-29 23:38:27 +00:00
2020-03-17 06:33:00 +00:00
for ( List < Ref < Mesh > > : : Element * E = meshes . front ( ) ; E ; E = E - > next ( ) ) {
2017-09-29 23:38:27 +00:00
2020-03-26 21:49:16 +00:00
MeshInstance3D * mi = memnew ( MeshInstance3D ) ;
2017-11-19 19:51:05 +00:00
mi - > set_mesh ( E - > get ( ) ) ;
2017-09-29 23:38:27 +00:00
mi - > set_name ( E - > get ( ) - > get_name ( ) ) ;
scene - > add_child ( mi ) ;
mi - > set_owner ( scene ) ;
}
2017-02-03 03:08:50 +00:00
2017-09-29 23:38:27 +00:00
if ( r_err ) {
* r_err = OK ;
2017-02-03 03:08:50 +00:00
}
2017-07-18 00:05:38 +00:00
return scene ;
2017-02-03 03:08:50 +00:00
}
2017-12-07 18:44:20 +00:00
Ref < Animation > EditorOBJImporter : : import_animation ( const String & p_path , uint32_t p_flags , int p_bake_fps ) {
2017-02-03 03:08:50 +00:00
2017-07-18 00:05:38 +00:00
return Ref < Animation > ( ) ;
}
2017-09-29 23:38:27 +00:00
void EditorOBJImporter : : get_extensions ( List < String > * r_extensions ) const {
r_extensions - > push_back ( " obj " ) ;
}
2017-07-18 00:05:38 +00:00
EditorOBJImporter : : EditorOBJImporter ( ) {
2017-02-03 03:08:50 +00:00
}
2017-09-29 23:38:27 +00:00
////////////////////////////////////////////////////
String ResourceImporterOBJ : : get_importer_name ( ) const {
return " wavefront_obj " ;
}
String ResourceImporterOBJ : : get_visible_name ( ) const {
return " OBJ As Mesh " ;
}
void ResourceImporterOBJ : : get_recognized_extensions ( List < String > * p_extensions ) const {
p_extensions - > push_back ( " obj " ) ;
}
String ResourceImporterOBJ : : get_save_extension ( ) const {
return " mesh " ;
}
String ResourceImporterOBJ : : get_resource_type ( ) const {
return " Mesh " ;
}
int ResourceImporterOBJ : : get_preset_count ( ) const {
return 0 ;
}
String ResourceImporterOBJ : : get_preset_name ( int p_idx ) const {
return " " ;
}
void ResourceImporterOBJ : : get_import_options ( List < ImportOption > * r_options , int p_preset ) const {
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " generate_tangents " ) , true ) ) ;
2018-02-12 10:36:40 +00:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : VECTOR3 , " scale_mesh " ) , Vector3 ( 1 , 1 , 1 ) ) ) ;
2020-01-11 08:21:38 +00:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : VECTOR3 , " offset_mesh " ) , Vector3 ( 0 , 0 , 0 ) ) ) ;
2018-06-30 22:58:37 +00:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " optimize_mesh " ) , true ) ) ;
2017-09-29 23:38:27 +00:00
}
bool ResourceImporterOBJ : : get_option_visibility ( const String & p_option , const Map < StringName , Variant > & p_options ) const {
return true ;
}
2019-02-26 21:43:37 +00:00
Error ResourceImporterOBJ : : import ( const String & p_source_file , const String & p_save_path , const Map < StringName , Variant > & p_options , List < String > * r_platform_variants , List < String > * r_gen_files , Variant * r_metadata ) {
2017-09-29 23:38:27 +00:00
2020-03-17 06:33:00 +00:00
List < Ref < Mesh > > meshes ;
2017-09-29 23:38:27 +00:00
2020-04-01 23:20:12 +00:00
Error err = _parse_obj ( p_source_file , meshes , true , p_options [ " generate_tangents " ] , p_options [ " optimize_mesh " ] , p_options [ " scale_mesh " ] , p_options [ " offset_mesh " ] , nullptr ) ;
2017-09-29 23:38:27 +00:00
ERR_FAIL_COND_V ( err ! = OK , err ) ;
ERR_FAIL_COND_V ( meshes . size ( ) ! = 1 , ERR_BUG ) ;
String save_path = p_save_path + " .mesh " ;
err = ResourceSaver : : save ( save_path , meshes . front ( ) - > get ( ) ) ;
2019-09-25 08:28:50 +00:00
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Cannot save Mesh to file ' " + save_path + " '. " ) ;
2017-09-29 23:38:27 +00:00
r_gen_files - > push_back ( save_path ) ;
return OK ;
}
ResourceImporterOBJ : : ResourceImporterOBJ ( ) {
}