2023-01-10 15:26:54 +01:00
/**************************************************************************/
/* resource_importer_obj.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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-05 00:50:27 +01:00
2017-02-03 04:08:50 +01:00
# include "resource_importer_obj.h"
2018-09-11 18:13:45 +02:00
# include "core/io/resource_saver.h"
# include "core/os/file_access.h"
2017-07-18 02:05:38 +02:00
# include "scene/3d/mesh_instance.h"
# include "scene/3d/spatial.h"
2017-02-03 04:08:50 +01:00
# include "scene/resources/mesh.h"
# include "scene/resources/surface_tool.h"
2017-07-18 02:05:38 +02:00
uint32_t EditorOBJImporter : : get_import_flags ( ) const {
return IMPORT_SCENE ;
2017-02-03 04:08:50 +01:00
}
2021-05-04 14:20:36 +02:00
static Error _parse_material_library ( const String & p_path , Map < String , Ref < SpatialMaterial > > & material_map , List < String > * r_missing_deps ) {
2017-07-18 02:05:38 +02:00
FileAccessRef f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
2019-08-15 04:57:49 +02: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 04:08:50 +01:00
2017-07-18 02:05:38 +02:00
Ref < SpatialMaterial > current ;
String current_name ;
String base_path = p_path . get_base_dir ( ) ;
while ( true ) {
String l = f - > get_line ( ) . strip_edges ( ) ;
2017-02-03 04:08:50 +01:00
2017-07-18 02:05:38 +02:00
if ( l . begins_with ( " newmtl " ) ) {
//vertex
2017-02-03 04:08:50 +01:00
2017-07-18 02:05:38 +02:00
current_name = l . replace ( " newmtl " , " " ) . strip_edges ( ) ;
current . instance ( ) ;
2017-11-25 16:32:02 +01:00
current - > set_name ( current_name ) ;
2017-07-18 02:05:38 +02:00
material_map [ current_name ] = current ;
} else if ( l . begins_with ( " Ka " ) ) {
//uv
2021-06-18 13:26:58 +02:00
WARN_PRINT ( " OBJ: Ambient light for material ' " + current_name + " ' is ignored in PBR " ) ;
2017-02-03 04:08:50 +01:00
2017-07-18 02:05:38 +02: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 ) {
current - > set_feature ( SpatialMaterial : : FEATURE_TRANSPARENT , true ) ;
}
} 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 ) {
current - > set_feature ( SpatialMaterial : : FEATURE_TRANSPARENT , true ) ;
}
} else if ( l . begins_with ( " map_Ka " ) ) {
//uv
2021-06-18 13:26:58 +02:00
WARN_PRINT ( " OBJ: Ambient light texture for material ' " + current_name + " ' is ignored in PBR " ) ;
2017-07-18 02:05:38 +02: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 04:23:40 +02:00
String path ;
if ( p . is_abs_path ( ) ) {
path = p ;
} else {
path = base_path . plus_file ( p ) ;
}
2017-07-18 02:05:38 +02:00
Ref < Texture > texture = ResourceLoader : : load ( path ) ;
if ( texture . is_valid ( ) ) {
current - > set_texture ( SpatialMaterial : : TEXTURE_ALBEDO , texture ) ;
2017-09-30 01:38:27 +02:00
} else if ( r_missing_deps ) {
2017-07-18 02:05:38 +02: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 04:23:40 +02:00
String path ;
if ( p . is_abs_path ( ) ) {
path = p ;
} else {
path = base_path . plus_file ( p ) ;
}
2017-07-18 02:05:38 +02:00
Ref < Texture > texture = ResourceLoader : : load ( path ) ;
if ( texture . is_valid ( ) ) {
current - > set_texture ( SpatialMaterial : : TEXTURE_METALLIC , texture ) ;
2017-09-30 01:38:27 +02:00
} else if ( r_missing_deps ) {
2017-07-18 02:05:38 +02: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 04:23:40 +02:00
String path ;
if ( p . is_abs_path ( ) ) {
path = p ;
} else {
path = base_path . plus_file ( p ) ;
}
2017-07-18 02:05:38 +02:00
Ref < Texture > texture = ResourceLoader : : load ( path ) ;
if ( texture . is_valid ( ) ) {
current - > set_texture ( SpatialMaterial : : TEXTURE_ROUGHNESS , texture ) ;
2017-09-30 01:38:27 +02:00
} else if ( r_missing_deps ) {
2017-07-18 02:05:38 +02: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 04:08:50 +01:00
2017-07-18 02:05:38 +02:00
Ref < Texture > texture = ResourceLoader : : load ( path ) ;
if ( texture . is_valid ( ) ) {
current - > set_feature ( SpatialMaterial : : FEATURE_NORMAL_MAPPING , true ) ;
current - > set_texture ( SpatialMaterial : : TEXTURE_NORMAL , texture ) ;
2017-09-30 01:38:27 +02:00
} else if ( r_missing_deps ) {
2017-07-18 02:05:38 +02:00
r_missing_deps - > push_back ( path ) ;
}
} else if ( f - > eof_reached ( ) ) {
break ;
}
}
return OK ;
2017-02-03 04:08:50 +01:00
}
2021-05-10 22:51:11 +02:00
static Error _parse_obj ( const String & p_path , List < Ref < Mesh > > & r_meshes , bool p_single_mesh , bool p_generate_tangents , int p_compress_flags , Vector3 p_scale_mesh , Vector3 p_offset_mesh , List < String > * r_missing_deps ) {
2017-07-18 02:05:38 +02:00
FileAccessRef f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
2019-08-15 04:57:49 +02: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 02:05:38 +02:00
Ref < ArrayMesh > mesh ;
mesh . instance ( ) ;
2017-02-03 04:08:50 +01:00
2017-09-30 01:38:27 +02:00
bool generate_tangents = p_generate_tangents ;
2018-02-12 11:36:40 +01:00
Vector3 scale_mesh = p_scale_mesh ;
2020-01-11 09:21:38 +01:00
Vector3 offset_mesh = p_offset_mesh ;
2018-07-01 00:58:37 +02:00
2017-02-03 04:08:50 +01:00
Vector < Vector3 > vertices ;
Vector < Vector3 > normals ;
Vector < Vector2 > uvs ;
2023-05-02 12:03:01 +02:00
Vector < Color > colors ;
2017-02-03 04:08:50 +01:00
String name ;
2021-05-04 14:20:36 +02:00
Map < String , Map < String , Ref < SpatialMaterial > > > material_map ;
2017-07-18 02:05:38 +02:00
2017-03-05 16:44:50 +01:00
Ref < SurfaceTool > surf_tool = memnew ( SurfaceTool ) ;
2017-02-03 04:08:50 +01:00
surf_tool - > begin ( Mesh : : PRIMITIVE_TRIANGLES ) ;
2017-07-18 02:05:38 +02:00
String current_material_library ;
String current_material ;
String current_group ;
2017-02-03 04:08:50 +01:00
2017-03-05 16:44:50 +01:00
while ( true ) {
2017-02-03 04:08:50 +01:00
String l = f - > get_line ( ) . strip_edges ( ) ;
2018-07-30 02:37:55 +02:00
while ( l . length ( ) & & l [ l . length ( ) - 1 ] = = ' \\ ' ) {
String add = f - > get_line ( ) . strip_edges ( ) ;
l + = add ;
if ( add = = String ( ) ) {
break ;
}
}
2017-02-03 04:08:50 +01:00
if ( l . begins_with ( " v " ) ) {
//vertex
2017-03-05 16:44:50 +01:00
Vector < String > v = l . split ( " " , false ) ;
2017-09-30 01:38:27 +02:00
ERR_FAIL_COND_V ( v . size ( ) < 4 , ERR_FILE_CORRUPT ) ;
2017-02-03 04:08:50 +01:00
Vector3 vtx ;
2020-01-11 09:21:38 +01: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 04:08:50 +01:00
vertices . push_back ( vtx ) ;
2023-05-02 12:03:01 +02:00
//vertex colors
if ( v . size ( ) > = 7 ) {
while ( colors . size ( ) < vertices . size ( ) - 1 ) {
colors . push_back ( Color ( 1.0 , 1.0 , 1.0 ) ) ;
}
Color c ;
c . r = v [ 4 ] . to_float ( ) ;
c . g = v [ 5 ] . to_float ( ) ;
c . b = v [ 6 ] . to_float ( ) ;
colors . push_back ( c ) ;
} else if ( ! colors . empty ( ) ) {
colors . push_back ( Color ( 1.0 , 1.0 , 1.0 ) ) ;
}
2017-03-05 16:44:50 +01:00
} else if ( l . begins_with ( " vt " ) ) {
2017-02-03 04:08:50 +01:00
//uv
2017-03-05 16:44:50 +01:00
Vector < String > v = l . split ( " " , false ) ;
2017-09-30 01:38:27 +02:00
ERR_FAIL_COND_V ( v . size ( ) < 3 , ERR_FILE_CORRUPT ) ;
2017-02-03 04:08:50 +01:00
Vector2 uv ;
2017-03-05 16:44:50 +01:00
uv . x = v [ 1 ] . to_float ( ) ;
uv . y = 1.0 - v [ 2 ] . to_float ( ) ;
2017-02-03 04:08:50 +01:00
uvs . push_back ( uv ) ;
} else if ( l . begins_with ( " vn " ) ) {
//normal
2017-03-05 16:44:50 +01:00
Vector < String > v = l . split ( " " , false ) ;
2017-09-30 01:38:27 +02:00
ERR_FAIL_COND_V ( v . size ( ) < 4 , ERR_FILE_CORRUPT ) ;
2017-02-03 04:08:50 +01:00
Vector3 nrm ;
2017-03-05 16:44:50 +01:00
nrm . x = v [ 1 ] . to_float ( ) ;
nrm . y = v [ 2 ] . to_float ( ) ;
nrm . z = v [ 3 ] . to_float ( ) ;
2017-02-03 04:08:50 +01:00
normals . push_back ( nrm ) ;
2017-02-23 09:28:09 +01:00
} else if ( l . begins_with ( " f " ) ) {
2017-03-05 16:44:50 +01:00
//vertex
2017-02-03 04:08:50 +01:00
2017-03-05 16:44:50 +01:00
Vector < String > v = l . split ( " " , false ) ;
2017-09-30 01:38:27 +02:00
ERR_FAIL_COND_V ( v . size ( ) < 4 , ERR_FILE_CORRUPT ) ;
2017-02-03 04:08:50 +01:00
//not very fast, could be sped up
Vector < String > face [ 3 ] ;
face [ 0 ] = v [ 1 ] . split ( " / " ) ;
face [ 1 ] = v [ 2 ] . split ( " / " ) ;
2017-09-30 01:38:27 +02:00
ERR_FAIL_COND_V ( face [ 0 ] . size ( ) = = 0 , ERR_FILE_CORRUPT ) ;
2018-07-30 02:37:55 +02:00
2017-09-30 01:38:27 +02:00
ERR_FAIL_COND_V ( face [ 0 ] . size ( ) ! = face [ 1 ] . size ( ) , ERR_FILE_CORRUPT ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 2 ; i < v . size ( ) - 1 ; i + + ) {
face [ 2 ] = v [ i + 1 ] . split ( " / " ) ;
2018-07-30 02:37:55 +02:00
2017-09-30 01:38:27 +02:00
ERR_FAIL_COND_V ( face [ 0 ] . size ( ) ! = face [ 2 ] . size ( ) , ERR_FILE_CORRUPT ) ;
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < 3 ; j + + ) {
int idx = j ;
2017-02-03 04:08:50 +01:00
2019-06-20 16:59:48 +02:00
if ( idx < 2 ) {
2017-03-05 16:44:50 +01:00
idx = 1 ^ idx ;
2017-02-03 04:08:50 +01:00
}
2017-03-05 16:44:50 +01:00
if ( face [ idx ] . size ( ) = = 3 ) {
int norm = face [ idx ] [ 2 ] . to_int ( ) - 1 ;
2021-05-05 12:44:11 +02:00
if ( norm < 0 ) {
2017-04-27 10:24:09 +02:00
norm + = normals . size ( ) + 1 ;
2021-05-05 12:44:11 +02:00
}
2017-09-30 01:38:27 +02:00
ERR_FAIL_INDEX_V ( norm , normals . size ( ) , ERR_FILE_CORRUPT ) ;
2017-02-03 04:08:50 +01:00
surf_tool - > add_normal ( normals [ norm ] ) ;
}
2017-03-05 16:44:50 +01:00
if ( face [ idx ] . size ( ) > = 2 & & face [ idx ] [ 1 ] ! = String ( ) ) {
int uv = face [ idx ] [ 1 ] . to_int ( ) - 1 ;
2021-05-05 12:44:11 +02:00
if ( uv < 0 ) {
2017-04-27 10:24:09 +02:00
uv + = uvs . size ( ) + 1 ;
2021-05-05 12:44:11 +02:00
}
2017-09-30 01:38:27 +02:00
ERR_FAIL_INDEX_V ( uv , uvs . size ( ) , ERR_FILE_CORRUPT ) ;
2017-02-03 04:08:50 +01:00
surf_tool - > add_uv ( uvs [ uv ] ) ;
}
2017-03-05 16:44:50 +01:00
int vtx = face [ idx ] [ 0 ] . to_int ( ) - 1 ;
2021-05-05 12:44:11 +02:00
if ( vtx < 0 ) {
2017-04-27 10:24:09 +02:00
vtx + = vertices . size ( ) + 1 ;
2021-05-05 12:44:11 +02:00
}
2017-09-30 01:38:27 +02:00
ERR_FAIL_INDEX_V ( vtx , vertices . size ( ) , ERR_FILE_CORRUPT ) ;
2017-02-03 04:08:50 +01:00
Vector3 vertex = vertices [ vtx ] ;
2023-05-02 12:03:01 +02:00
if ( ! colors . empty ( ) ) {
surf_tool - > add_color ( colors [ vtx ] ) ;
}
2017-07-18 02:05:38 +02:00
//if (weld_vertices)
// vertex.snap(Vector3(weld_tolerance, weld_tolerance, weld_tolerance));
2017-02-03 04:08:50 +01:00
surf_tool - > add_vertex ( vertex ) ;
}
2017-03-05 16:44:50 +01:00
face [ 1 ] = face [ 2 ] ;
2017-02-03 04:08:50 +01:00
}
2017-07-18 02:05:38 +02:00
} else if ( l . begins_with ( " s " ) ) { //smoothing
2017-03-05 16:44:50 +01:00
String what = l . substr ( 2 , l . length ( ) ) . strip_edges ( ) ;
2021-05-05 12:44:11 +02:00
if ( what = = " off " ) {
2017-02-03 04:08:50 +01:00
surf_tool - > add_smooth_group ( false ) ;
2021-05-05 12:44:11 +02:00
} else {
2017-02-03 04:08:50 +01:00
surf_tool - > add_smooth_group ( true ) ;
2021-05-05 12:44:11 +02:00
}
2017-07-29 05:03:54 +02: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 02:05:38 +02:00
if ( surf_tool - > get_vertex_array ( ) . size ( ) ) {
//another group going on, commit it
if ( normals . size ( ) = = 0 ) {
2017-02-03 04:08:50 +01:00
surf_tool - > generate_normals ( ) ;
2017-07-18 02:05:38 +02:00
}
if ( generate_tangents & & uvs . size ( ) ) {
2017-02-03 04:08:50 +01:00
surf_tool - > generate_tangents ( ) ;
2017-07-18 02:05:38 +02:00
}
2017-02-03 04:08:50 +01:00
surf_tool - > index ( ) ;
2017-07-18 02:05:38 +02:00
2018-08-24 09:35:07 +02: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 02:05:38 +02:00
if ( material_map . has ( current_material_library ) & & material_map [ current_material_library ] . has ( current_material ) ) {
2023-05-02 12:03:01 +02:00
Ref < SpatialMaterial > & material = material_map [ current_material_library ] [ current_material ] ;
if ( ! colors . empty ( ) ) {
material - > set_flag ( SpatialMaterial : : FLAG_SRGB_VERTEX_COLOR , true ) ;
}
surf_tool - > set_material ( material ) ;
2017-07-18 02:05:38 +02:00
}
2021-05-10 22:51:11 +02:00
mesh = surf_tool - > commit ( mesh , p_compress_flags ) ;
2017-07-18 02:05:38 +02: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 09:35:07 +02:00
print_verbose ( " OBJ: Added surface : " + mesh - > surface_get_name ( mesh - > get_surface_count ( ) - 1 ) ) ;
2017-02-03 04:08:50 +01:00
surf_tool - > clear ( ) ;
surf_tool - > begin ( Mesh : : PRIMITIVE_TRIANGLES ) ;
2017-07-18 02:05:38 +02:00
}
if ( l . begins_with ( " o " ) | | f - > eof_reached ( ) ) {
2017-09-30 01:38:27 +02:00
if ( ! p_single_mesh ) {
mesh - > set_name ( name ) ;
r_meshes . push_back ( mesh ) ;
mesh . instance ( ) ;
current_group = " " ;
current_material = " " ;
}
2017-02-03 04:08:50 +01:00
}
2017-07-18 02:05:38 +02:00
if ( f - > eof_reached ( ) ) {
break ;
}
if ( l . begins_with ( " o " ) ) {
2017-03-05 16:44:50 +01:00
name = l . substr ( 2 , l . length ( ) ) . strip_edges ( ) ;
2017-07-18 02:05:38 +02: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 ) ) {
2021-05-04 14:20:36 +02:00
Map < String , Ref < SpatialMaterial > > lib ;
2021-11-07 03:12:36 +01:00
String lib_path = current_material_library ;
if ( lib_path . is_rel_path ( ) ) {
lib_path = p_path . get_base_dir ( ) . plus_file ( current_material_library ) ;
2017-07-18 23:21:51 +02:00
}
2021-11-07 03:12:36 +01:00
Error err = _parse_material_library ( lib_path , lib , r_missing_deps ) ;
2017-07-18 02:05:38 +02:00
if ( err = = OK ) {
material_map [ current_material_library ] = lib ;
}
}
2017-02-03 04:08:50 +01:00
}
}
2017-09-30 01:38:27 +02:00
if ( p_single_mesh ) {
r_meshes . push_back ( mesh ) ;
}
return OK ;
}
2021-05-10 22:51:11 +02:00
Node * EditorOBJImporter : : import_scene ( const String & p_path , uint32_t p_flags , int p_bake_fps , uint32_t p_compress_flags , List < String > * r_missing_deps , Error * r_err ) {
2021-05-04 14:20:36 +02:00
List < Ref < Mesh > > meshes ;
2017-09-30 01:38:27 +02:00
2021-05-10 22:51:11 +02:00
Error err = _parse_obj ( p_path , meshes , false , p_flags & IMPORT_GENERATE_TANGENT_ARRAYS , p_compress_flags , Vector3 ( 1 , 1 , 1 ) , Vector3 ( 0 , 0 , 0 ) , r_missing_deps ) ;
2017-09-30 01:38:27 +02:00
if ( err ! = OK ) {
if ( r_err ) {
* r_err = err ;
}
2021-05-04 16:00:45 +02:00
return nullptr ;
2017-09-30 01:38:27 +02:00
}
Spatial * scene = memnew ( Spatial ) ;
2021-05-04 14:20:36 +02:00
for ( List < Ref < Mesh > > : : Element * E = meshes . front ( ) ; E ; E = E - > next ( ) ) {
2017-09-30 01:38:27 +02:00
MeshInstance * mi = memnew ( MeshInstance ) ;
2017-11-19 20:51:05 +01:00
mi - > set_mesh ( E - > get ( ) ) ;
2017-09-30 01:38:27 +02:00
mi - > set_name ( E - > get ( ) - > get_name ( ) ) ;
scene - > add_child ( mi ) ;
mi - > set_owner ( scene ) ;
}
2017-02-03 04:08:50 +01:00
2017-09-30 01:38:27 +02:00
if ( r_err ) {
* r_err = OK ;
2017-02-03 04:08:50 +01:00
}
2017-07-18 02:05:38 +02:00
return scene ;
2017-02-03 04:08:50 +01:00
}
2017-12-07 19:44:20 +01:00
Ref < Animation > EditorOBJImporter : : import_animation ( const String & p_path , uint32_t p_flags , int p_bake_fps ) {
2017-07-18 02:05:38 +02:00
return Ref < Animation > ( ) ;
}
2017-09-30 01:38:27 +02:00
void EditorOBJImporter : : get_extensions ( List < String > * r_extensions ) const {
r_extensions - > push_back ( " obj " ) ;
}
2017-07-18 02:05:38 +02:00
EditorOBJImporter : : EditorOBJImporter ( ) {
2017-02-03 04:08:50 +01:00
}
2017-09-30 01:38:27 +02: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 11:36:40 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : VECTOR3 , " scale_mesh " ) , Vector3 ( 1 , 1 , 1 ) ) ) ;
2020-01-11 09:21:38 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : VECTOR3 , " offset_mesh " ) , Vector3 ( 0 , 0 , 0 ) ) ) ;
2021-05-10 22:51:11 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " octahedral_compression " ) , true ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " optimize_mesh_flags " , PROPERTY_HINT_FLAGS , " Vertex,Normal,Tangent,Color,TexUV,TexUV2,Bones,Weights,Index " ) , VS : : ARRAY_COMPRESS_DEFAULT > > VS : : ARRAY_COMPRESS_BASE ) ) ;
2017-09-30 01:38:27 +02:00
}
bool ResourceImporterOBJ : : get_option_visibility ( const String & p_option , const Map < StringName , Variant > & p_options ) const {
return true ;
}
2019-02-26 22:43:37 +01: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 ) {
2021-05-04 14:20:36 +02:00
List < Ref < Mesh > > meshes ;
2017-09-30 01:38:27 +02:00
2021-05-10 22:51:11 +02:00
uint32_t compress_flags = int ( p_options [ " optimize_mesh_flags " ] ) < < VS : : ARRAY_COMPRESS_BASE ;
if ( bool ( p_options [ " octahedral_compression " ] ) ) {
compress_flags | = VS : : ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION ;
}
Error err = _parse_obj ( p_source_file , meshes , true , p_options [ " generate_tangents " ] , compress_flags , p_options [ " scale_mesh " ] , p_options [ " offset_mesh " ] , nullptr ) ;
2017-09-30 01:38:27 +02: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 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Cannot save Mesh to file ' " + save_path + " '. " ) ;
2017-09-30 01:38:27 +02:00
r_gen_files - > push_back ( save_path ) ;
return OK ;
}
ResourceImporterOBJ : : ResourceImporterOBJ ( ) {
}