2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* collada.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
2014-02-10 02:10:30 +01:00
# include "collada.h"
2017-01-16 08:04:19 +01:00
2017-08-27 21:07:15 +02:00
# include <stdio.h>
2014-02-10 02:10:30 +01:00
//#define DEBUG_DEFAULT_ANIMATION
//#define DEBUG_COLLADA
# ifdef DEBUG_COLLADA
# define COLLADA_PRINT(m_what) print_line(m_what)
# else
# define COLLADA_PRINT(m_what)
# endif
# define COLLADA_IMPORT_SCALE_SCENE
/* HELPERS */
2023-05-11 12:32:23 +02:00
String Collada : : Effect : : get_texture_path ( const String & p_source , Collada & p_state ) const {
2019-06-26 15:08:25 +02:00
const String & image = p_source ;
2023-05-11 12:32:23 +02:00
ERR_FAIL_COND_V ( ! p_state . state . image_map . has ( image ) , " " ) ;
return p_state . state . image_map [ image ] . path ;
2014-02-10 02:10:30 +01:00
}
2020-10-17 07:08:21 +02:00
Transform3D Collada : : get_root_transform ( ) const {
Transform3D unit_scale_transform ;
2014-02-10 02:10:30 +01:00
# ifndef COLLADA_IMPORT_SCALE_SCENE
unit_scale_transform . scale ( Vector3 ( state . unit_scale , state . unit_scale , state . unit_scale ) ) ;
# endif
return unit_scale_transform ;
}
2023-05-11 12:32:23 +02:00
void Collada : : Vertex : : fix_unit_scale ( const Collada & p_state ) {
2014-02-10 02:10:30 +01:00
# ifdef COLLADA_IMPORT_SCALE_SCENE
2023-05-11 12:32:23 +02:00
vertex * = p_state . state . unit_scale ;
2014-02-10 02:10:30 +01:00
# endif
}
static String _uri_to_id ( const String & p_uri ) {
2020-05-14 16:41:43 +02:00
if ( p_uri . begins_with ( " # " ) ) {
2014-02-10 02:10:30 +01:00
return p_uri . substr ( 1 , p_uri . size ( ) - 1 ) ;
2020-05-14 16:41:43 +02:00
} else {
2014-02-10 02:10:30 +01:00
return p_uri ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
/** HELPER FUNCTIONS **/
2020-10-17 07:08:21 +02:00
Transform3D Collada : : fix_transform ( const Transform3D & p_transform ) {
Transform3D tr = p_transform ;
2014-02-10 02:10:30 +01:00
# ifndef NO_UP_AXIS_SWAP
if ( state . up_axis ! = Vector3 : : AXIS_Y ) {
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < 3 ; i + + ) {
2014-02-10 02:10:30 +01:00
SWAP ( tr . basis [ 1 ] [ i ] , tr . basis [ state . up_axis ] [ i ] ) ;
2020-05-14 16:41:43 +02:00
}
for ( int i = 0 ; i < 3 ; i + + ) {
2014-02-10 02:10:30 +01:00
SWAP ( tr . basis [ i ] [ 1 ] , tr . basis [ i ] [ state . up_axis ] ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
SWAP ( tr . origin [ 1 ] , tr . origin [ state . up_axis ] ) ;
tr . basis [ state . up_axis ] [ 0 ] = - tr . basis [ state . up_axis ] [ 0 ] ;
tr . basis [ state . up_axis ] [ 1 ] = - tr . basis [ state . up_axis ] [ 1 ] ;
tr . basis [ 0 ] [ state . up_axis ] = - tr . basis [ 0 ] [ state . up_axis ] ;
tr . basis [ 1 ] [ state . up_axis ] = - tr . basis [ 1 ] [ state . up_axis ] ;
tr . origin [ state . up_axis ] = - tr . origin [ state . up_axis ] ;
}
# endif
2017-01-14 12:26:56 +01:00
//tr.scale(Vector3(state.unit_scale.unit_scale.unit_scale));
2014-02-10 02:10:30 +01:00
return tr ;
//return state.matrix_fix * p_transform;
}
2023-05-11 12:32:23 +02:00
static Transform3D _read_transform_from_array ( const Vector < float > & p_array , int p_ofs = 0 ) {
2020-10-17 07:08:21 +02:00
Transform3D tr ;
2014-02-10 02:10:30 +01:00
// i wonder why collada matrices are transposed, given that's opposed to opengl..
2023-05-11 12:32:23 +02:00
tr . basis . rows [ 0 ] [ 0 ] = p_array [ 0 + p_ofs ] ;
tr . basis . rows [ 0 ] [ 1 ] = p_array [ 1 + p_ofs ] ;
tr . basis . rows [ 0 ] [ 2 ] = p_array [ 2 + p_ofs ] ;
tr . basis . rows [ 1 ] [ 0 ] = p_array [ 4 + p_ofs ] ;
tr . basis . rows [ 1 ] [ 1 ] = p_array [ 5 + p_ofs ] ;
tr . basis . rows [ 1 ] [ 2 ] = p_array [ 6 + p_ofs ] ;
tr . basis . rows [ 2 ] [ 0 ] = p_array [ 8 + p_ofs ] ;
tr . basis . rows [ 2 ] [ 1 ] = p_array [ 9 + p_ofs ] ;
tr . basis . rows [ 2 ] [ 2 ] = p_array [ 10 + p_ofs ] ;
tr . origin . x = p_array [ 3 + p_ofs ] ;
tr . origin . y = p_array [ 7 + p_ofs ] ;
tr . origin . z = p_array [ 11 + p_ofs ] ;
2014-02-10 02:10:30 +01:00
return tr ;
}
/* STRUCTURES */
2023-05-11 12:32:23 +02:00
Transform3D Collada : : Node : : compute_transform ( const Collada & p_state ) const {
2020-10-17 07:08:21 +02:00
Transform3D xform ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < xform_list . size ( ) ; i + + ) {
2020-10-17 07:08:21 +02:00
Transform3D xform_step ;
2014-02-10 02:10:30 +01:00
const XForm & xf = xform_list [ i ] ;
switch ( xf . op ) {
case XForm : : OP_ROTATE : {
if ( xf . data . size ( ) > = 4 ) {
2022-08-13 17:45:42 +02:00
xform_step . rotate ( Vector3 ( xf . data [ 0 ] , xf . data [ 1 ] , xf . data [ 2 ] ) , Math : : deg_to_rad ( xf . data [ 3 ] ) ) ;
2014-02-10 02:10:30 +01:00
}
} break ;
case XForm : : OP_SCALE : {
if ( xf . data . size ( ) > = 3 ) {
xform_step . scale ( Vector3 ( xf . data [ 0 ] , xf . data [ 1 ] , xf . data [ 2 ] ) ) ;
}
} break ;
case XForm : : OP_TRANSLATE : {
if ( xf . data . size ( ) > = 3 ) {
xform_step . origin = Vector3 ( xf . data [ 0 ] , xf . data [ 1 ] , xf . data [ 2 ] ) ;
}
} break ;
case XForm : : OP_MATRIX : {
if ( xf . data . size ( ) > = 16 ) {
xform_step = _read_transform_from_array ( xf . data , 0 ) ;
}
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2014-02-10 02:10:30 +01:00
}
xform = xform * xform_step ;
}
# ifdef COLLADA_IMPORT_SCALE_SCENE
2023-05-11 12:32:23 +02:00
xform . origin * = p_state . state . unit_scale ;
2014-02-10 02:10:30 +01:00
# endif
return xform ;
}
2020-10-17 07:08:21 +02:00
Transform3D Collada : : Node : : get_transform ( ) const {
2014-02-10 02:10:30 +01:00
return default_transform ;
}
2020-10-17 07:08:21 +02:00
Transform3D Collada : : Node : : get_global_transform ( ) const {
2020-05-14 16:41:43 +02:00
if ( parent ) {
2014-02-10 02:10:30 +01:00
return parent - > get_global_transform ( ) * default_transform ;
2020-05-14 16:41:43 +02:00
} else {
2014-02-10 02:10:30 +01:00
return default_transform ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2018-07-25 03:11:03 +02:00
Vector < float > Collada : : AnimationTrack : : get_value_at_time ( float p_time ) const {
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND_V ( keys . size ( ) = = 0 , Vector < float > ( ) ) ;
int i = 0 ;
for ( i = 0 ; i < keys . size ( ) ; i + + ) {
2020-05-14 16:41:43 +02:00
if ( keys [ i ] . time > p_time ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2020-05-14 16:41:43 +02:00
if ( i = = 0 ) {
2014-02-10 02:10:30 +01:00
return keys [ 0 ] . data ;
2020-05-14 16:41:43 +02:00
}
if ( i = = keys . size ( ) ) {
2014-02-10 02:10:30 +01:00
return keys [ keys . size ( ) - 1 ] . data ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
switch ( keys [ i ] . interp_type ) {
case INTERP_BEZIER : //wait for bezier
case INTERP_LINEAR : {
float c = ( p_time - keys [ i - 1 ] . time ) / ( keys [ i ] . time - keys [ i - 1 ] . time ) ;
if ( keys [ i ] . data . size ( ) = = 16 ) {
//interpolate a matrix
2020-10-17 07:08:21 +02:00
Transform3D src = _read_transform_from_array ( keys [ i - 1 ] . data ) ;
Transform3D dst = _read_transform_from_array ( keys [ i ] . data ) ;
2014-02-10 02:10:30 +01:00
2020-10-17 07:08:21 +02:00
Transform3D interp = c < 0.001 ? src : src . interpolate_with ( dst , c ) ;
2014-02-10 02:10:30 +01:00
Vector < float > ret ;
ret . resize ( 16 ) ;
2020-10-17 07:08:21 +02:00
Transform3D tr ;
2014-02-10 02:10:30 +01:00
// i wonder why collada matrices are transposed, given that's opposed to opengl..
2022-04-25 00:07:35 +02:00
ret . write [ 0 ] = interp . basis . rows [ 0 ] [ 0 ] ;
ret . write [ 1 ] = interp . basis . rows [ 0 ] [ 1 ] ;
ret . write [ 2 ] = interp . basis . rows [ 0 ] [ 2 ] ;
ret . write [ 4 ] = interp . basis . rows [ 1 ] [ 0 ] ;
ret . write [ 5 ] = interp . basis . rows [ 1 ] [ 1 ] ;
ret . write [ 6 ] = interp . basis . rows [ 1 ] [ 2 ] ;
ret . write [ 8 ] = interp . basis . rows [ 2 ] [ 0 ] ;
ret . write [ 9 ] = interp . basis . rows [ 2 ] [ 1 ] ;
ret . write [ 10 ] = interp . basis . rows [ 2 ] [ 2 ] ;
2018-07-25 03:11:03 +02:00
ret . write [ 3 ] = interp . origin . x ;
ret . write [ 7 ] = interp . origin . y ;
ret . write [ 11 ] = interp . origin . z ;
ret . write [ 12 ] = 0 ;
ret . write [ 13 ] = 0 ;
ret . write [ 14 ] = 0 ;
ret . write [ 15 ] = 1 ;
2014-02-10 02:10:30 +01:00
return ret ;
} else {
Vector < float > dest ;
dest . resize ( keys [ i ] . data . size ( ) ) ;
for ( int j = 0 ; j < dest . size ( ) ; j + + ) {
2018-07-25 03:11:03 +02:00
dest . write [ j ] = keys [ i ] . data [ j ] * c + keys [ i - 1 ] . data [ j ] * ( 1.0 - c ) ;
2014-02-10 02:10:30 +01:00
}
return dest ;
//interpolate one by one
}
} break ;
}
ERR_FAIL_V ( Vector < float > ( ) ) ;
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_asset ( XMLParser & p_parser ) {
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String name = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( name = = " up_axis " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
if ( p_parser . get_node_data ( ) = = " X_UP " ) {
2014-02-10 02:10:30 +01:00
state . up_axis = Vector3 : : AXIS_X ;
2020-05-14 16:41:43 +02:00
}
2023-05-11 12:32:23 +02:00
if ( p_parser . get_node_data ( ) = = " Y_UP " ) {
2014-02-10 02:10:30 +01:00
state . up_axis = Vector3 : : AXIS_Y ;
2020-05-14 16:41:43 +02:00
}
2023-05-11 12:32:23 +02:00
if ( p_parser . get_node_data ( ) = = " Z_UP " ) {
2014-02-10 02:10:30 +01:00
state . up_axis = Vector3 : : AXIS_Z ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
COLLADA_PRINT ( " up axis: " + p_parser . get_node_data ( ) ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " unit " ) {
2023-05-11 12:32:23 +02:00
state . unit_scale = p_parser . get_named_attribute_value ( " meter " ) . to_float ( ) ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " unit scale: " + rtos ( state . unit_scale ) ) ;
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " asset " ) {
2014-02-10 02:10:30 +01:00
break ; //end of <asset>
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_image ( XMLParser & p_parser ) {
String id = p_parser . get_named_attribute_value ( " id " ) ;
2014-02-10 02:10:30 +01:00
if ( ! ( state . import_flags & IMPORT_FLAG_SCENE ) ) {
2023-05-11 12:32:23 +02:00
if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return ;
}
Image image ;
if ( state . version < State : : Version ( 1 , 4 , 0 ) ) {
/* <1.4 */
2023-05-11 12:32:23 +02:00
String path = p_parser . get_named_attribute_value ( " source " ) . strip_edges ( ) ;
2022-02-03 17:03:38 +01:00
if ( ! path . contains ( " :// " ) & & path . is_relative_path ( ) ) {
2014-02-10 02:10:30 +01:00
// path is relative to file being loaded, so convert to a resource path
2022-08-30 02:34:01 +02:00
image . path = ProjectSettings : : get_singleton ( ) - > localize_path ( state . local_path . get_base_dir ( ) . path_join ( path . uri_decode ( ) ) ) ;
2014-02-10 02:10:30 +01:00
}
} else {
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String name = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( name = = " init_from " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
String path = p_parser . get_node_data ( ) . strip_edges ( ) . uri_decode ( ) ;
2014-02-10 02:10:30 +01:00
2022-02-03 17:03:38 +01:00
if ( ! path . contains ( " :// " ) & & path . is_relative_path ( ) ) {
2014-02-10 02:10:30 +01:00
// path is relative to file being loaded, so convert to a resource path
2022-08-30 02:34:01 +02:00
path = ProjectSettings : : get_singleton ( ) - > localize_path ( state . local_path . get_base_dir ( ) . path_join ( path ) ) ;
2014-02-10 02:10:30 +01:00
2014-03-14 02:57:24 +01:00
} else if ( path . find ( " file:/// " ) = = 0 ) {
path = path . replace_first ( " file:/// " , " " ) ;
2017-07-19 22:00:46 +02:00
path = ProjectSettings : : get_singleton ( ) - > localize_path ( path ) ;
2014-02-10 02:10:30 +01:00
}
image . path = path ;
2017-02-23 09:28:09 +01:00
} else if ( name = = " data " ) {
2014-02-10 02:10:30 +01:00
ERR_PRINT ( " COLLADA Embedded image data not supported! " ) ;
2023-05-11 12:32:23 +02:00
} else if ( name = = " extra " & & ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " image " ) {
2014-02-10 02:10:30 +01:00
break ; //end of <asset>
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
state . image_map [ id ] = image ;
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_material ( XMLParser & p_parser ) {
2014-02-10 02:10:30 +01:00
if ( ! ( state . import_flags & IMPORT_FLAG_SCENE ) ) {
2023-05-11 12:32:23 +02:00
if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return ;
}
Material material ;
2023-05-11 12:32:23 +02:00
String id = p_parser . get_named_attribute_value ( " id " ) ;
if ( p_parser . has_attribute ( " name " ) ) {
material . name = p_parser . get_named_attribute_value ( " name " ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
if ( state . version < State : : Version ( 1 , 4 , 0 ) ) {
/* <1.4 */
ERR_PRINT ( " Collada Materials < 1.4 are not supported (yet) " ) ;
} else {
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT & & p_parser . get_node_name ( ) = = " instance_effect " ) {
material . instance_effect = _uri_to_id ( p_parser . get_named_attribute_value ( " url " ) ) ;
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " material " ) {
2014-02-10 02:10:30 +01:00
break ; //end of <asset>
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
state . material_map [ id ] = material ;
}
//! reads floats from inside of xml element until end of xml element
2023-05-11 12:32:23 +02:00
Vector < float > Collada : : _read_float_array ( XMLParser & p_parser ) {
if ( p_parser . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return Vector < float > ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
Vector < String > splitters ;
splitters . push_back ( " " ) ;
splitters . push_back ( " \n " ) ;
splitters . push_back ( " \r " ) ;
splitters . push_back ( " \t " ) ;
Vector < float > array ;
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
2014-02-10 02:10:30 +01:00
// TODO: check for comments inside the element
// and ignore them.
2023-05-11 12:32:23 +02:00
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_TEXT ) {
2014-02-10 02:10:30 +01:00
// parse float data
2023-05-11 12:32:23 +02:00
String str = p_parser . get_node_data ( ) ;
2014-02-10 02:10:30 +01:00
array = str . split_floats_mk ( splitters , false ) ;
//array=str.split_floats(" ",false);
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END ) {
2014-02-10 02:10:30 +01:00
break ; // end parsing text
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
return array ;
}
2023-05-11 12:32:23 +02:00
Vector < String > Collada : : _read_string_array ( XMLParser & p_parser ) {
if ( p_parser . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return Vector < String > ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
Vector < String > array ;
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
2014-02-10 02:10:30 +01:00
// TODO: check for comments inside the element
// and ignore them.
2023-05-11 12:32:23 +02:00
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_TEXT ) {
2014-02-10 02:10:30 +01:00
// parse String data
2023-05-11 12:32:23 +02:00
String str = p_parser . get_node_data ( ) ;
2014-10-10 00:44:27 +02:00
array = str . split_spaces ( ) ;
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END ) {
2014-02-10 02:10:30 +01:00
break ; // end parsing text
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
return array ;
}
2023-05-11 12:32:23 +02:00
Transform3D Collada : : _read_transform ( XMLParser & p_parser ) {
if ( p_parser . is_empty ( ) ) {
2020-10-17 07:08:21 +02:00
return Transform3D ( ) ;
2022-01-27 17:34:33 +01:00
}
2014-02-10 02:10:30 +01:00
2016-11-29 23:55:12 +01:00
Vector < String > array ;
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
2014-02-10 02:10:30 +01:00
// TODO: check for comments inside the element
// and ignore them.
2023-05-11 12:32:23 +02:00
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_TEXT ) {
2014-02-10 02:10:30 +01:00
// parse float data
2023-05-11 12:32:23 +02:00
String str = p_parser . get_node_data ( ) ;
2016-11-29 23:55:12 +01:00
array = str . split_spaces ( ) ;
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END ) {
2014-02-10 02:10:30 +01:00
break ; // end parsing text
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2020-10-17 07:08:21 +02:00
ERR_FAIL_COND_V ( array . size ( ) ! = 16 , Transform3D ( ) ) ;
2016-11-29 23:55:12 +01:00
Vector < float > farr ;
farr . resize ( 16 ) ;
for ( int i = 0 ; i < 16 ; i + + ) {
2020-07-24 20:07:57 +02:00
farr . write [ i ] = array [ i ] . to_float ( ) ;
2016-11-29 23:55:12 +01:00
}
return _read_transform_from_array ( farr ) ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
String Collada : : _read_empty_draw_type ( XMLParser & p_parser ) {
2016-06-05 20:59:21 +02:00
String empty_draw_type = " " ;
2017-03-05 16:44:50 +01:00
2023-05-11 12:32:23 +02:00
if ( p_parser . is_empty ( ) ) {
2016-06-05 20:59:21 +02:00
return empty_draw_type ;
2020-05-14 16:41:43 +02:00
}
2017-03-05 16:44:50 +01:00
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_TEXT ) {
empty_draw_type = p_parser . get_node_data ( ) ;
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END ) {
2016-06-05 20:59:21 +02:00
break ; // end parsing text
2020-05-14 16:41:43 +02:00
}
2016-06-05 20:59:21 +02:00
}
return empty_draw_type ;
}
2023-05-11 12:32:23 +02:00
Variant Collada : : _parse_param ( XMLParser & p_parser ) {
if ( p_parser . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return Variant ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
String from = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
Variant data ;
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
if ( p_parser . get_node_name ( ) = = " float " ) {
p_parser . read ( ) ;
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_TEXT ) {
data = p_parser . get_node_data ( ) . to_float ( ) ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " float2 " ) {
Vector < float > v2 = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
if ( v2 . size ( ) > = 2 ) {
data = Vector2 ( v2 [ 0 ] , v2 [ 1 ] ) ;
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " float3 " ) {
Vector < float > v3 = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
if ( v3 . size ( ) > = 3 ) {
data = Vector3 ( v3 [ 0 ] , v3 [ 1 ] , v3 [ 2 ] ) ;
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " float4 " ) {
Vector < float > v4 = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
if ( v4 . size ( ) > = 4 ) {
data = Color ( v4 [ 0 ] , v4 [ 1 ] , v4 [ 2 ] , v4 [ 3 ] ) ;
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " sampler2D " ) {
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
if ( p_parser . get_node_name ( ) = = " source " ) {
p_parser . read ( ) ;
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_TEXT ) {
data = p_parser . get_node_data ( ) ;
2014-02-10 02:10:30 +01:00
}
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " sampler2D " ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " surface " ) {
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
if ( p_parser . get_node_name ( ) = = " init_from " ) {
p_parser . read ( ) ;
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_TEXT ) {
data = p_parser . get_node_data ( ) ;
2014-02-10 02:10:30 +01:00
}
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " surface " ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = from ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
COLLADA_PRINT ( " newparam ending " + p_parser . get_node_name ( ) ) ;
2014-02-10 02:10:30 +01:00
return data ;
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_effect_material ( XMLParser & p_parser , Effect & p_effect , String & p_id ) {
2014-02-10 02:10:30 +01:00
if ( ! ( state . import_flags & IMPORT_FLAG_SCENE ) ) {
2023-05-11 12:32:23 +02:00
if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return ;
}
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
2014-02-10 02:10:30 +01:00
// first come the tags we descend, but ignore the top-levels
2023-05-11 12:32:23 +02:00
COLLADA_PRINT ( " node name: " + p_parser . get_node_name ( ) ) ;
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
if ( ! p_parser . is_empty ( ) & &
( p_parser . get_node_name ( ) = = " profile_COMMON " | |
p_parser . get_node_name ( ) = = " technique " | |
p_parser . get_node_name ( ) = = " extra " ) ) {
_parse_effect_material ( p_parser , p_effect , p_id ) ; // try again
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " newparam " ) {
String name = p_parser . get_named_attribute_value ( " sid " ) ;
Variant value = _parse_param ( p_parser ) ;
p_effect . params [ name ] = value ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " param: " + name + " value: " + String ( value ) ) ;
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " constant " | |
p_parser . get_node_name ( ) = = " lambert " | |
p_parser . get_node_name ( ) = = " phong " | |
p_parser . get_node_name ( ) = = " blinn " ) {
COLLADA_PRINT ( " shade model: " + p_parser . get_node_name ( ) ) ;
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String what = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( what = = " emission " | |
what = = " diffuse " | |
what = = " specular " | |
what = = " reflective " ) {
// color or texture types
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
if ( p_parser . get_node_name ( ) = = " color " ) {
Vector < float > colorarr = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " colorarr size: " + rtos ( colorarr . size ( ) ) ) ;
if ( colorarr . size ( ) > = 3 ) {
Fix misc. source comment typos
Found using `codespell -q 3 -S ./thirdparty,*.po -L ang,ba,cas,dof,doubleclick,fave,hist,leapyear,lod,nd,numer,ois,paket,seeked,sinc,switchs,te,uint -D ~/Projects/codespell/codespell_lib/data/dictionary.txt `
2019-09-19 20:36:39 +02:00
// alpha strangely not alright? maybe it needs to be multiplied by value as a channel intensity
2014-02-10 02:10:30 +01:00
Color color ( colorarr [ 0 ] , colorarr [ 1 ] , colorarr [ 2 ] , 1.0 ) ;
2020-05-14 16:41:43 +02:00
if ( what = = " diffuse " ) {
2023-05-11 12:32:23 +02:00
p_effect . diffuse . color = color ;
2020-05-14 16:41:43 +02:00
}
if ( what = = " specular " ) {
2023-05-11 12:32:23 +02:00
p_effect . specular . color = color ;
2020-05-14 16:41:43 +02:00
}
if ( what = = " emission " ) {
2023-05-11 12:32:23 +02:00
p_effect . emission . color = color ;
2020-05-14 16:41:43 +02:00
}
2017-03-05 16:44:50 +01:00
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( what + " color: " + color ) ;
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " texture " ) {
String sampler = p_parser . get_named_attribute_value ( " texture " ) ;
if ( ! p_effect . params . has ( sampler ) ) {
ERR_PRINT ( String ( " Couldn't find sampler: " + sampler + " in material: " + p_id ) . utf8 ( ) . get_data ( ) ) ;
2014-02-10 02:10:30 +01:00
} else {
2023-05-11 12:32:23 +02:00
String surface = p_effect . params [ sampler ] ;
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
if ( ! p_effect . params . has ( surface ) ) {
ERR_PRINT ( String ( " Couldn't find surface: " + surface + " in material: " + p_id ) . utf8 ( ) . get_data ( ) ) ;
2014-02-10 02:10:30 +01:00
} else {
2023-05-11 12:32:23 +02:00
String uri = p_effect . params [ surface ] ;
2014-02-10 02:10:30 +01:00
if ( what = = " diffuse " ) {
2023-05-11 12:32:23 +02:00
p_effect . diffuse . texture = uri ;
2014-02-10 02:10:30 +01:00
} else if ( what = = " specular " ) {
2023-05-11 12:32:23 +02:00
p_effect . specular . texture = uri ;
2014-02-10 02:10:30 +01:00
} else if ( what = = " emission " ) {
2023-05-11 12:32:23 +02:00
p_effect . emission . texture = uri ;
2014-02-10 02:10:30 +01:00
} else if ( what = = " bump " ) {
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " bumptype " ) & & p_parser . get_named_attribute_value ( " bumptype " ) ! = " NORMALMAP " ) {
2019-06-11 14:49:34 +02:00
WARN_PRINT ( " 'bump' texture type is not NORMALMAP, only NORMALMAP is supported. " ) ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
p_effect . bump . texture = uri ;
2014-02-10 02:10:30 +01:00
}
COLLADA_PRINT ( what + " texture: " + uri ) ;
}
}
2023-05-11 12:32:23 +02:00
} else if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = what ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
} else if ( what = = " shininess " ) {
2023-05-11 12:32:23 +02:00
p_effect . shininess = _parse_param ( p_parser ) ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & &
( p_parser . get_node_name ( ) = = " constant " | |
p_parser . get_node_name ( ) = = " lambert " | |
p_parser . get_node_name ( ) = = " phong " | |
p_parser . get_node_name ( ) = = " blinn " ) ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " double_sided " | | p_parser . get_node_name ( ) = = " show_double_sided " ) { // colladamax / google earth
2014-02-10 02:10:30 +01:00
// 3DS Max / Google Earth double sided extension
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
p_effect . found_double_sided = true ;
p_effect . double_sided = p_parser . get_node_data ( ) . to_int ( ) ;
COLLADA_PRINT ( " double sided: " + itos ( p_parser . get_node_data ( ) . to_int ( ) ) ) ;
} else if ( p_parser . get_node_name ( ) = = " unshaded " ) {
p_parser . read ( ) ;
p_effect . unshaded = p_parser . get_node_data ( ) . to_int ( ) ;
} else if ( p_parser . get_node_name ( ) = = " bump " ) {
2014-02-10 02:10:30 +01:00
// color or texture types
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
if ( p_parser . get_node_name ( ) = = " texture " ) {
String sampler = p_parser . get_named_attribute_value ( " texture " ) ;
if ( ! p_effect . params . has ( sampler ) ) {
ERR_PRINT ( String ( " Couldn't find sampler: " + sampler + " in material: " + p_id ) . utf8 ( ) . get_data ( ) ) ;
2014-02-10 02:10:30 +01:00
} else {
2023-05-11 12:32:23 +02:00
String surface = p_effect . params [ sampler ] ;
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
if ( ! p_effect . params . has ( surface ) ) {
ERR_PRINT ( String ( " Couldn't find surface: " + surface + " in material: " + p_id ) . utf8 ( ) . get_data ( ) ) ;
2014-02-10 02:10:30 +01:00
} else {
2023-05-11 12:32:23 +02:00
String uri = p_effect . params [ surface ] ;
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " bumptype " ) & & p_parser . get_named_attribute_value ( " bumptype " ) ! = " NORMALMAP " ) {
2019-06-11 14:49:34 +02:00
WARN_PRINT ( " 'bump' texture type is not NORMALMAP, only NORMALMAP is supported. " ) ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
p_effect . bump . texture = uri ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " bump: " + uri ) ;
}
}
2023-05-11 12:32:23 +02:00
} else if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " bump " ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & &
( p_parser . get_node_name ( ) = = " effect " | |
p_parser . get_node_name ( ) = = " profile_COMMON " | |
p_parser . get_node_name ( ) = = " technique " | |
p_parser . get_node_name ( ) = = " extra " ) ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_effect ( XMLParser & p_parser ) {
2014-02-10 02:10:30 +01:00
if ( ! ( state . import_flags & IMPORT_FLAG_SCENE ) ) {
2023-05-11 12:32:23 +02:00
if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return ;
}
2023-05-11 12:32:23 +02:00
String id = p_parser . get_named_attribute_value ( " id " ) ;
2014-02-10 02:10:30 +01:00
Effect effect ;
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " name " ) ) {
effect . name = p_parser . get_named_attribute_value ( " name " ) ;
2020-05-14 16:41:43 +02:00
}
2023-05-11 12:32:23 +02:00
_parse_effect_material ( p_parser , effect , id ) ;
2014-06-28 14:50:20 +02:00
2014-02-10 02:10:30 +01:00
state . effect_map [ id ] = effect ;
COLLADA_PRINT ( " Effect ID: " + id ) ;
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_camera ( XMLParser & p_parser ) {
2014-02-10 02:10:30 +01:00
if ( ! ( state . import_flags & IMPORT_FLAG_SCENE ) ) {
2023-05-11 12:32:23 +02:00
if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return ;
}
2023-05-11 12:32:23 +02:00
String id = p_parser . get_named_attribute_value ( " id " ) ;
2014-02-10 02:10:30 +01:00
state . camera_data_map [ id ] = CameraData ( ) ;
CameraData & camera = state . camera_data_map [ id ] ;
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String name = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( name = = " perspective " ) {
camera . mode = CameraData : : MODE_PERSPECTIVE ;
2015-03-03 18:39:13 +01:00
} else if ( name = = " orthographic " ) {
2014-02-10 02:10:30 +01:00
camera . mode = CameraData : : MODE_ORTHOGONAL ;
} else if ( name = = " xfov " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
camera . perspective . x_fov = p_parser . get_node_data ( ) . to_float ( ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " yfov " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
camera . perspective . y_fov = p_parser . get_node_data ( ) . to_float ( ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " xmag " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
camera . orthogonal . x_mag = p_parser . get_node_data ( ) . to_float ( ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " ymag " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
camera . orthogonal . y_mag = p_parser . get_node_data ( ) . to_float ( ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " aspect_ratio " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
camera . aspect = p_parser . get_node_data ( ) . to_float ( ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " znear " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
camera . z_near = p_parser . get_node_data ( ) . to_float ( ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " zfar " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
camera . z_far = p_parser . get_node_data ( ) . to_float ( ) ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " camera " ) {
2014-02-10 02:10:30 +01:00
break ; //end of <asset>
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
COLLADA_PRINT ( " Camera ID: " + id ) ;
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_light ( XMLParser & p_parser ) {
2014-02-10 02:10:30 +01:00
if ( ! ( state . import_flags & IMPORT_FLAG_SCENE ) ) {
2023-05-11 12:32:23 +02:00
if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return ;
}
2023-05-11 12:32:23 +02:00
String id = p_parser . get_named_attribute_value ( " id " ) ;
2014-02-10 02:10:30 +01:00
state . light_data_map [ id ] = LightData ( ) ;
LightData & light = state . light_data_map [ id ] ;
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String name = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( name = = " ambient " ) {
light . mode = LightData : : MODE_AMBIENT ;
} else if ( name = = " directional " ) {
light . mode = LightData : : MODE_DIRECTIONAL ;
} else if ( name = = " point " ) {
light . mode = LightData : : MODE_OMNI ;
} else if ( name = = " spot " ) {
light . mode = LightData : : MODE_SPOT ;
} else if ( name = = " color " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
Vector < float > colorarr = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " colorarr size: " + rtos ( colorarr . size ( ) ) ) ;
if ( colorarr . size ( ) > = 4 ) {
Fix misc. source comment typos
Found using `codespell -q 3 -S ./thirdparty,*.po -L ang,ba,cas,dof,doubleclick,fave,hist,leapyear,lod,nd,numer,ois,paket,seeked,sinc,switchs,te,uint -D ~/Projects/codespell/codespell_lib/data/dictionary.txt `
2019-09-19 20:36:39 +02:00
// alpha strangely not alright? maybe it needs to be multiplied by value as a channel intensity
2014-02-10 02:10:30 +01:00
Color color ( colorarr [ 0 ] , colorarr [ 1 ] , colorarr [ 2 ] , 1.0 ) ;
light . color = color ;
}
} else if ( name = = " constant_attenuation " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
light . constant_att = p_parser . get_node_data ( ) . to_float ( ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " linear_attenuation " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
light . linear_att = p_parser . get_node_data ( ) . to_float ( ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " quadratic_attenuation " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
light . quad_att = p_parser . get_node_data ( ) . to_float ( ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " falloff_angle " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
light . spot_angle = p_parser . get_node_data ( ) . to_float ( ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " falloff_exponent " ) {
2023-05-11 12:32:23 +02:00
p_parser . read ( ) ;
light . spot_exp = p_parser . get_node_data ( ) . to_float ( ) ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " light " ) {
2014-02-10 02:10:30 +01:00
break ; //end of <asset>
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
COLLADA_PRINT ( " Light ID: " + id ) ;
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_curve_geometry ( XMLParser & p_parser , String p_id , String p_name ) {
2014-02-10 02:10:30 +01:00
if ( ! ( state . import_flags & IMPORT_FLAG_SCENE ) ) {
2023-05-11 12:32:23 +02:00
if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return ;
}
//load everything into a pre dictionary
state . curve_data_map [ p_id ] = CurveData ( ) ;
CurveData & curvedata = state . curve_data_map [ p_id ] ;
curvedata . name = p_name ;
2023-05-11 12:32:23 +02:00
String closed = p_parser . get_named_attribute_value_safe ( " closed " ) . to_lower ( ) ;
2022-10-24 16:33:03 +02:00
curvedata . closed = closed = = " true " | | closed = = " 1 " ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " curve name: " + p_name ) ;
String current_source ;
2018-01-18 21:37:17 +01:00
// handles geometry node and the curve children in this loop
2014-02-10 02:10:30 +01:00
// read sources with arrays and accessor for each curve
2023-05-11 12:32:23 +02:00
if ( p_parser . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
}
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String section = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( section = = " source " ) {
2023-05-11 12:32:23 +02:00
String id = p_parser . get_named_attribute_value ( " id " ) ;
2014-02-10 02:10:30 +01:00
curvedata . sources [ id ] = CurveData : : Source ( ) ;
current_source = id ;
COLLADA_PRINT ( " source data: " + id ) ;
2015-05-01 15:44:08 +02:00
} else if ( section = = " float_array " | | section = = " array " ) {
2014-02-10 02:10:30 +01:00
// create a new array and read it.
if ( curvedata . sources . has ( current_source ) ) {
2023-05-11 12:32:23 +02:00
curvedata . sources [ current_source ] . array = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " section: " + current_source + " read " + itos ( curvedata . sources [ current_source ] . array . size ( ) ) + " values. " ) ;
}
} else if ( section = = " Name_array " ) {
// create a new array and read it.
if ( curvedata . sources . has ( current_source ) ) {
2023-05-11 12:32:23 +02:00
curvedata . sources [ current_source ] . sarray = _read_string_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " section: " + current_source + " read " + itos ( curvedata . sources [ current_source ] . array . size ( ) ) + " values. " ) ;
}
} else if ( section = = " technique_common " ) {
//skip it
} else if ( section = = " accessor " ) { // child of source (below a technique tag)
if ( curvedata . sources . has ( current_source ) ) {
2023-05-11 12:32:23 +02:00
curvedata . sources [ current_source ] . stride = p_parser . get_named_attribute_value ( " stride " ) . to_int ( ) ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " section: " + current_source + " stride " + itos ( curvedata . sources [ current_source ] . stride ) ) ;
}
} else if ( section = = " control_vertices " ) {
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
if ( p_parser . get_node_name ( ) = = " input " ) {
String semantic = p_parser . get_named_attribute_value ( " semantic " ) ;
String source = _uri_to_id ( p_parser . get_named_attribute_value ( " source " ) ) ;
2014-02-10 02:10:30 +01:00
curvedata . control_vertices [ semantic ] = source ;
COLLADA_PRINT ( section + " input semantic: " + semantic + " source: " + source ) ;
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = section ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " spline " ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_mesh_geometry ( XMLParser & p_parser , String p_id , String p_name ) {
2014-02-10 02:10:30 +01:00
if ( ! ( state . import_flags & IMPORT_FLAG_SCENE ) ) {
2023-05-11 12:32:23 +02:00
if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return ;
}
//load everything into a pre dictionary
state . mesh_data_map [ p_id ] = MeshData ( ) ;
MeshData & meshdata = state . mesh_data_map [ p_id ] ;
meshdata . name = p_name ;
COLLADA_PRINT ( " mesh name: " + p_name ) ;
String current_source ;
2018-01-18 21:37:17 +01:00
// handles geometry node and the mesh children in this loop
2014-02-10 02:10:30 +01:00
// read sources with arrays and accessor for each mesh
2023-05-11 12:32:23 +02:00
if ( p_parser . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
}
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String section = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( section = = " source " ) {
2023-05-11 12:32:23 +02:00
String id = p_parser . get_named_attribute_value ( " id " ) ;
2014-02-10 02:10:30 +01:00
meshdata . sources [ id ] = MeshData : : Source ( ) ;
current_source = id ;
COLLADA_PRINT ( " source data: " + id ) ;
2017-02-23 09:28:09 +01:00
} else if ( section = = " float_array " | | section = = " array " ) {
2014-02-10 02:10:30 +01:00
// create a new array and read it.
if ( meshdata . sources . has ( current_source ) ) {
2023-05-11 12:32:23 +02:00
meshdata . sources [ current_source ] . array = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " section: " + current_source + " read " + itos ( meshdata . sources [ current_source ] . array . size ( ) ) + " values. " ) ;
}
} else if ( section = = " technique_common " ) {
//skip it
} else if ( section = = " accessor " ) { // child of source (below a technique tag)
if ( meshdata . sources . has ( current_source ) ) {
2023-05-11 12:32:23 +02:00
meshdata . sources [ current_source ] . stride = p_parser . get_named_attribute_value ( " stride " ) . to_int ( ) ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " section: " + current_source + " stride " + itos ( meshdata . sources [ current_source ] . stride ) ) ;
}
} else if ( section = = " vertices " ) {
MeshData : : Vertices vert ;
2023-05-11 12:32:23 +02:00
String id = p_parser . get_named_attribute_value ( " id " ) ;
2021-05-08 17:33:22 +02:00
int last_ref = 0 ;
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
if ( p_parser . get_node_name ( ) = = " input " ) {
String semantic = p_parser . get_named_attribute_value ( " semantic " ) ;
String source = _uri_to_id ( p_parser . get_named_attribute_value ( " source " ) ) ;
2014-02-10 02:10:30 +01:00
2021-05-08 17:33:22 +02:00
if ( semantic = = " TEXCOORD " ) {
semantic = " TEXCOORD " + itos ( last_ref + + ) ;
}
2014-02-10 02:10:30 +01:00
vert . sources [ semantic ] = source ;
COLLADA_PRINT ( section + " input semantic: " + semantic + " source: " + source ) ;
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = section ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
meshdata . vertices [ id ] = vert ;
} else if ( section = = " triangles " | | section = = " polylist " | | section = = " polygons " ) {
bool polygons = ( section = = " polygons " ) ;
if ( polygons ) {
WARN_PRINT ( " Primitive type \" polygons \" is not well supported (concave shapes may fail). To ensure that the geometry is properly imported, please re-export using \" triangles \" or \" polylist \" . " ) ;
}
MeshData : : Primitives prim ;
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " material " ) ) {
prim . material = p_parser . get_named_attribute_value ( " material " ) ;
2020-05-14 16:41:43 +02:00
}
2023-05-11 12:32:23 +02:00
prim . count = p_parser . get_named_attribute_value ( " count " ) . to_int ( ) ;
2014-02-10 02:10:30 +01:00
prim . vertex_size = 0 ;
int last_ref = 0 ;
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
if ( p_parser . get_node_name ( ) = = " input " ) {
String semantic = p_parser . get_named_attribute_value ( " semantic " ) ;
String source = _uri_to_id ( p_parser . get_named_attribute_value ( " source " ) ) ;
2014-02-10 02:10:30 +01:00
if ( semantic = = " TEXCOORD " ) {
semantic = " TEXCOORD " + itos ( last_ref + + ) ;
}
2023-05-11 12:32:23 +02:00
int offset = p_parser . get_named_attribute_value ( " offset " ) . to_int ( ) ;
2014-02-10 02:10:30 +01:00
MeshData : : Primitives : : SourceRef sref ;
sref . source = source ;
sref . offset = offset ;
prim . sources [ semantic ] = sref ;
prim . vertex_size = MAX ( prim . vertex_size , offset + 1 ) ;
COLLADA_PRINT ( section + " input semantic: " + semantic + " source: " + source + " offset: " + itos ( offset ) ) ;
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " p " ) { //indices
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
Vector < float > values = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
if ( polygons ) {
2019-06-26 15:08:25 +02:00
ERR_CONTINUE ( prim . vertex_size = = 0 ) ;
2014-02-10 02:10:30 +01:00
prim . polygons . push_back ( values . size ( ) / prim . vertex_size ) ;
int from = prim . indices . size ( ) ;
prim . indices . resize ( from + values . size ( ) ) ;
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < values . size ( ) ; i + + ) {
2018-07-25 03:11:03 +02:00
prim . indices . write [ from + i ] = values [ i ] ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
} else if ( prim . vertex_size > 0 ) {
prim . indices = values ;
}
COLLADA_PRINT ( " read " + itos ( values . size ( ) ) + " index values " ) ;
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " vcount " ) { // primitive
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
Vector < float > values = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
prim . polygons = values ;
COLLADA_PRINT ( " read " + itos ( values . size ( ) ) + " polygon values " ) ;
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = section ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
meshdata . primitives . push_back ( prim ) ;
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " double_sided " ) {
p_parser . read ( ) ;
2014-02-10 02:10:30 +01:00
meshdata . found_double_sided = true ;
2023-05-11 12:32:23 +02:00
meshdata . double_sided = p_parser . get_node_data ( ) . to_int ( ) ;
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " polygons " ) {
2014-02-10 02:10:30 +01:00
ERR_PRINT ( " Primitive type \" polygons \" not supported, re-export using \" polylist \" or \" triangles \" . " ) ;
2023-05-11 12:32:23 +02:00
} else if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " mesh " ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_skin_controller ( XMLParser & p_parser , String p_id ) {
2014-02-10 02:10:30 +01:00
state . skin_controller_data_map [ p_id ] = SkinControllerData ( ) ;
SkinControllerData & skindata = state . skin_controller_data_map [ p_id ] ;
2023-05-11 12:32:23 +02:00
skindata . base = _uri_to_id ( p_parser . get_named_attribute_value ( " source " ) ) ;
2014-02-10 02:10:30 +01:00
String current_source ;
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String section = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( section = = " bind_shape_matrix " ) {
2023-05-11 12:32:23 +02:00
skindata . bind_shape = _read_transform ( p_parser ) ;
2014-02-10 02:10:30 +01:00
# ifdef COLLADA_IMPORT_SCALE_SCENE
skindata . bind_shape . origin * = state . unit_scale ;
# endif
COLLADA_PRINT ( " skeleton bind shape transform: " + skindata . bind_shape ) ;
} else if ( section = = " source " ) {
2023-05-11 12:32:23 +02:00
String id = p_parser . get_named_attribute_value ( " id " ) ;
2014-02-10 02:10:30 +01:00
skindata . sources [ id ] = SkinControllerData : : Source ( ) ;
current_source = id ;
COLLADA_PRINT ( " source data: " + id ) ;
} else if ( section = = " float_array " | | section = = " array " ) {
// create a new array and read it.
if ( skindata . sources . has ( current_source ) ) {
2023-05-11 12:32:23 +02:00
skindata . sources [ current_source ] . array = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " section: " + current_source + " read " + itos ( skindata . sources [ current_source ] . array . size ( ) ) + " values. " ) ;
}
} else if ( section = = " Name_array " | | section = = " IDREF_array " ) {
// create a new array and read it.
2020-05-14 16:41:43 +02:00
if ( section = = " IDREF_array " ) {
2014-02-10 02:10:30 +01:00
skindata . use_idrefs = true ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
if ( skindata . sources . has ( current_source ) ) {
2023-05-11 12:32:23 +02:00
skindata . sources [ current_source ] . sarray = _read_string_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
if ( section = = " IDREF_array " ) {
Vector < String > sa = skindata . sources [ current_source ] . sarray ;
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < sa . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
state . idref_joints . insert ( sa [ i ] ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
COLLADA_PRINT ( " section: " + current_source + " read " + itos ( skindata . sources [ current_source ] . array . size ( ) ) + " values. " ) ;
}
} else if ( section = = " technique_common " ) {
//skip it
} else if ( section = = " accessor " ) { // child of source (below a technique tag)
if ( skindata . sources . has ( current_source ) ) {
int stride = 1 ;
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " stride " ) ) {
stride = p_parser . get_named_attribute_value ( " stride " ) . to_int ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
skindata . sources [ current_source ] . stride = stride ;
COLLADA_PRINT ( " section: " + current_source + " stride " + itos ( skindata . sources [ current_source ] . stride ) ) ;
}
} else if ( section = = " joints " ) {
SkinControllerData : : Joints joint ;
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
if ( p_parser . get_node_name ( ) = = " input " ) {
String semantic = p_parser . get_named_attribute_value ( " semantic " ) ;
String source = _uri_to_id ( p_parser . get_named_attribute_value ( " source " ) ) ;
2014-02-10 02:10:30 +01:00
joint . sources [ semantic ] = source ;
COLLADA_PRINT ( section + " input semantic: " + semantic + " source: " + source ) ;
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = section ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
skindata . joints = joint ;
} else if ( section = = " vertex_weights " ) {
SkinControllerData : : Weights weights ;
2023-05-11 12:32:23 +02:00
weights . count = p_parser . get_named_attribute_value ( " count " ) . to_int ( ) ;
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
if ( p_parser . get_node_name ( ) = = " input " ) {
String semantic = p_parser . get_named_attribute_value ( " semantic " ) ;
String source = _uri_to_id ( p_parser . get_named_attribute_value ( " source " ) ) ;
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
int offset = p_parser . get_named_attribute_value ( " offset " ) . to_int ( ) ;
2014-02-10 02:10:30 +01:00
SkinControllerData : : Weights : : SourceRef sref ;
sref . source = source ;
sref . offset = offset ;
weights . sources [ semantic ] = sref ;
COLLADA_PRINT ( section + " input semantic: " + semantic + " source: " + source + " offset: " + itos ( offset ) ) ;
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " v " ) { //indices
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
Vector < float > values = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
weights . indices = values ;
COLLADA_PRINT ( " read " + itos ( values . size ( ) ) + " index values " ) ;
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " vcount " ) { // weightsitive
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
Vector < float > values = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
weights . sets = values ;
COLLADA_PRINT ( " read " + itos ( values . size ( ) ) + " polygon values " ) ;
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = section ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
skindata . weights = weights ;
2017-01-14 12:26:56 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " skin " ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
/* STORE REST MATRICES */
2020-10-17 07:08:21 +02:00
Vector < Transform3D > rests ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! skindata . joints . sources . has ( " JOINT " ) ) ;
ERR_FAIL_COND ( ! skindata . joints . sources . has ( " INV_BIND_MATRIX " ) ) ;
String joint_arr = skindata . joints . sources [ " JOINT " ] ;
String ibm = skindata . joints . sources [ " INV_BIND_MATRIX " ] ;
ERR_FAIL_COND ( ! skindata . sources . has ( joint_arr ) ) ;
ERR_FAIL_COND ( ! skindata . sources . has ( ibm ) ) ;
SkinControllerData : : Source & joint_source = skindata . sources [ joint_arr ] ;
SkinControllerData : : Source & ibm_source = skindata . sources [ ibm ] ;
ERR_FAIL_COND ( joint_source . sarray . size ( ) ! = ibm_source . array . size ( ) / 16 ) ;
for ( int i = 0 ; i < joint_source . sarray . size ( ) ; i + + ) {
String name = joint_source . sarray [ i ] ;
2020-10-17 07:08:21 +02:00
Transform3D xform = _read_transform_from_array ( ibm_source . array , i * 16 ) ; //<- this is a mistake, it must be applied to vertices
2014-02-10 02:10:30 +01:00
xform . affine_invert ( ) ; // inverse for rest, because it's an inverse
# ifdef COLLADA_IMPORT_SCALE_SCENE
xform . origin * = state . unit_scale ;
# endif
skindata . bone_rest_map [ name ] = xform ;
}
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_morph_controller ( XMLParser & p_parser , String p_id ) {
2014-02-10 02:10:30 +01:00
state . morph_controller_data_map [ p_id ] = MorphControllerData ( ) ;
MorphControllerData & morphdata = state . morph_controller_data_map [ p_id ] ;
2023-05-11 12:32:23 +02:00
morphdata . mesh = _uri_to_id ( p_parser . get_named_attribute_value ( " source " ) ) ;
morphdata . mode = p_parser . get_named_attribute_value ( " method " ) ;
2014-02-10 02:10:30 +01:00
String current_source ;
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String section = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( section = = " source " ) {
2023-05-11 12:32:23 +02:00
String id = p_parser . get_named_attribute_value ( " id " ) ;
2014-02-10 02:10:30 +01:00
morphdata . sources [ id ] = MorphControllerData : : Source ( ) ;
current_source = id ;
COLLADA_PRINT ( " source data: " + id ) ;
} else if ( section = = " float_array " | | section = = " array " ) {
// create a new array and read it.
if ( morphdata . sources . has ( current_source ) ) {
2023-05-11 12:32:23 +02:00
morphdata . sources [ current_source ] . array = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " section: " + current_source + " read " + itos ( morphdata . sources [ current_source ] . array . size ( ) ) + " values. " ) ;
}
} else if ( section = = " Name_array " | | section = = " IDREF_array " ) {
// create a new array and read it.
if ( morphdata . sources . has ( current_source ) ) {
2023-05-11 12:32:23 +02:00
morphdata . sources [ current_source ] . sarray = _read_string_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " section: " + current_source + " read " + itos ( morphdata . sources [ current_source ] . array . size ( ) ) + " values. " ) ;
}
} else if ( section = = " technique_common " ) {
//skip it
} else if ( section = = " accessor " ) { // child of source (below a technique tag)
if ( morphdata . sources . has ( current_source ) ) {
int stride = 1 ;
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " stride " ) ) {
stride = p_parser . get_named_attribute_value ( " stride " ) . to_int ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
morphdata . sources [ current_source ] . stride = stride ;
COLLADA_PRINT ( " section: " + current_source + " stride " + itos ( morphdata . sources [ current_source ] . stride ) ) ;
}
} else if ( section = = " targets " ) {
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
if ( p_parser . get_node_name ( ) = = " input " ) {
String semantic = p_parser . get_named_attribute_value ( " semantic " ) ;
String source = _uri_to_id ( p_parser . get_named_attribute_value ( " source " ) ) ;
2014-02-10 02:10:30 +01:00
morphdata . targets [ semantic ] = source ;
COLLADA_PRINT ( section + " input semantic: " + semantic + " source: " + source ) ;
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = section ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " morph " ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
if ( morphdata . targets . has ( " MORPH_WEIGHT " ) ) {
state . morph_name_map [ morphdata . targets [ " MORPH_WEIGHT " ] ] = p_id ;
}
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_controller ( XMLParser & p_parser ) {
String id = p_parser . get_named_attribute_value ( " id " ) ;
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
if ( p_parser . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
}
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String section = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( section = = " skin " ) {
2023-05-11 12:32:23 +02:00
_parse_skin_controller ( p_parser , id ) ;
2014-02-10 02:10:30 +01:00
} else if ( section = = " morph " ) {
2023-05-11 12:32:23 +02:00
_parse_morph_controller ( p_parser , id ) ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " controller " ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2023-05-11 12:32:23 +02:00
Collada : : Node * Collada : : _parse_visual_instance_geometry ( XMLParser & p_parser ) {
String type = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
NodeGeometry * geom = memnew ( NodeGeometry ) ;
geom - > controller = type = = " instance_controller " ;
2023-05-11 12:32:23 +02:00
geom - > source = _uri_to_id ( p_parser . get_named_attribute_value_safe ( " url " ) ) ;
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
if ( p_parser . is_empty ( ) ) { //nothing else to parse...
2014-02-10 02:10:30 +01:00
return geom ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
// try to find also many materials and skeletons!
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
if ( p_parser . get_node_name ( ) = = " instance_material " ) {
String symbol = p_parser . get_named_attribute_value ( " symbol " ) ;
String target = _uri_to_id ( p_parser . get_named_attribute_value ( " target " ) ) ;
2014-02-10 02:10:30 +01:00
NodeGeometry : : Material mat ;
mat . target = target ;
geom - > material_map [ symbol ] = mat ;
COLLADA_PRINT ( " uses material: ' " + target + " ' on primitive' " + symbol + " ' " ) ;
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_name ( ) = = " skeleton " ) {
p_parser . read ( ) ;
String uri = _uri_to_id ( p_parser . get_node_data ( ) ) ;
2021-12-09 10:42:46 +01:00
if ( ! uri . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
geom - > skeletons . push_back ( uri ) ;
}
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = type ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
if ( geom - > controller ) {
2020-12-15 13:04:21 +01:00
if ( geom - > skeletons . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
//XSI style
if ( state . skin_controller_data_map . has ( geom - > source ) ) {
SkinControllerData * skin = & state . skin_controller_data_map [ geom - > source ] ;
//case where skeletons reference bones with IDREF (XSI)
ERR_FAIL_COND_V ( ! skin - > joints . sources . has ( " JOINT " ) , geom ) ;
String joint_arr = skin - > joints . sources [ " JOINT " ] ;
ERR_FAIL_COND_V ( ! skin - > sources . has ( joint_arr ) , geom ) ;
Collada : : SkinControllerData : : Source & joint_source = skin - > sources [ joint_arr ] ;
geom - > skeletons = joint_source . sarray ; //quite crazy, but should work.
}
}
}
return geom ;
}
2023-05-11 12:32:23 +02:00
Collada : : Node * Collada : : _parse_visual_instance_camera ( XMLParser & p_parser ) {
2014-02-10 02:10:30 +01:00
NodeCamera * cam = memnew ( NodeCamera ) ;
2023-05-11 12:32:23 +02:00
cam - > camera = _uri_to_id ( p_parser . get_named_attribute_value_safe ( " url " ) ) ;
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( state . up_axis = = Vector3 : : AXIS_Z ) { //collada weirdness
2016-10-18 22:50:21 +02:00
cam - > post_transform . basis . rotate ( Vector3 ( 1 , 0 , 0 ) , - Math_PI * 0.5 ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
if ( p_parser . is_empty ( ) ) { //nothing else to parse...
2014-02-10 02:10:30 +01:00
return cam ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " instance_camera " ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
return cam ;
}
2023-05-11 12:32:23 +02:00
Collada : : Node * Collada : : _parse_visual_instance_light ( XMLParser & p_parser ) {
2014-02-10 02:10:30 +01:00
NodeLight * cam = memnew ( NodeLight ) ;
2023-05-11 12:32:23 +02:00
cam - > light = _uri_to_id ( p_parser . get_named_attribute_value_safe ( " url " ) ) ;
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( state . up_axis = = Vector3 : : AXIS_Z ) { //collada weirdness
2016-10-18 22:50:21 +02:00
cam - > post_transform . basis . rotate ( Vector3 ( 1 , 0 , 0 ) , - Math_PI * 0.5 ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
if ( p_parser . is_empty ( ) ) { //nothing else to parse...
2014-02-10 02:10:30 +01:00
return cam ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " instance_light " ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
return cam ;
}
2023-05-11 12:32:23 +02:00
Collada : : Node * Collada : : _parse_visual_node_instance_data ( XMLParser & p_parser ) {
String instance_type = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( instance_type = = " instance_geometry " | | instance_type = = " instance_controller " ) {
2023-05-11 12:32:23 +02:00
return _parse_visual_instance_geometry ( p_parser ) ;
2014-02-10 02:10:30 +01:00
} else if ( instance_type = = " instance_camera " ) {
2023-05-11 12:32:23 +02:00
return _parse_visual_instance_camera ( p_parser ) ;
2014-02-10 02:10:30 +01:00
} else if ( instance_type = = " instance_light " ) {
2023-05-11 12:32:23 +02:00
return _parse_visual_instance_light ( p_parser ) ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
if ( p_parser . is_empty ( ) ) { //nothing else to parse...
2020-04-02 01:20:12 +02:00
return nullptr ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = instance_type ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2020-04-02 01:20:12 +02:00
return nullptr ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
Collada : : Node * Collada : : _parse_visual_scene_node ( XMLParser & p_parser ) {
2014-02-10 02:10:30 +01:00
String name ;
2023-05-11 12:32:23 +02:00
String id = p_parser . get_named_attribute_value_safe ( " id " ) ;
2014-02-10 02:10:30 +01:00
bool found_name = false ;
2021-12-09 10:42:46 +01:00
if ( id . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
id = " %NODEID% " + itos ( Math : : rand ( ) ) ;
} else {
found_name = true ;
}
Vector < Node : : XForm > xform_list ;
Vector < Node * > children ;
2017-03-05 16:44:50 +01:00
2016-06-05 20:59:21 +02:00
String empty_draw_type = " " ;
2014-02-10 02:10:30 +01:00
2020-04-02 01:20:12 +02:00
Node * node = nullptr ;
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
name = p_parser . has_attribute ( " name " ) ? p_parser . get_named_attribute_value_safe ( " name " ) : p_parser . get_named_attribute_value_safe ( " id " ) ;
2021-12-09 10:42:46 +01:00
if ( name . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
name = id ;
} else {
found_name = true ;
}
2023-05-11 12:32:23 +02:00
if ( ( p_parser . has_attribute ( " type " ) & & p_parser . get_named_attribute_value ( " type " ) = = " JOINT " ) | | state . idref_joints . has ( name ) ) {
2014-02-10 02:10:30 +01:00
// handle a bone
NodeJoint * joint = memnew ( NodeJoint ) ;
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " sid " ) ) { //bones may not have sid
joint - > sid = p_parser . get_named_attribute_value ( " sid " ) ;
2017-01-14 12:26:56 +01:00
//state.bone_map[joint->sid]=joint;
2015-12-12 18:55:16 +01:00
} else if ( state . idref_joints . has ( name ) ) {
2014-02-10 02:10:30 +01:00
joint - > sid = name ; //kind of a cheat but..
2023-05-11 12:32:23 +02:00
} else if ( p_parser . has_attribute ( " name " ) ) {
joint - > sid = p_parser . get_named_attribute_value_safe ( " name " ) ;
2015-12-12 18:55:16 +01:00
}
2021-12-09 10:42:46 +01:00
if ( ! joint - > sid . is_empty ( ) ) {
2014-09-15 16:33:30 +02:00
state . sid_to_node_map [ joint - > sid ] = id ;
}
2014-02-10 02:10:30 +01:00
node = joint ;
}
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String section = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( section = = " translate " ) {
Node : : XForm xf ;
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " sid " ) ) {
xf . id = p_parser . get_named_attribute_value ( " sid " ) ;
2014-02-10 02:10:30 +01:00
}
xf . op = Node : : XForm : : OP_TRANSLATE ;
2023-05-11 12:32:23 +02:00
Vector < float > xlt = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
xf . data = xlt ;
xform_list . push_back ( xf ) ;
} else if ( section = = " rotate " ) {
Node : : XForm xf ;
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " sid " ) ) {
xf . id = p_parser . get_named_attribute_value ( " sid " ) ;
2014-02-10 02:10:30 +01:00
}
xf . op = Node : : XForm : : OP_ROTATE ;
2023-05-11 12:32:23 +02:00
Vector < float > rot = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
xf . data = rot ;
xform_list . push_back ( xf ) ;
} else if ( section = = " scale " ) {
Node : : XForm xf ;
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " sid " ) ) {
xf . id = p_parser . get_named_attribute_value ( " sid " ) ;
2014-02-10 02:10:30 +01:00
}
xf . op = Node : : XForm : : OP_SCALE ;
2023-05-11 12:32:23 +02:00
Vector < float > scale = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
xf . data = scale ;
xform_list . push_back ( xf ) ;
} else if ( section = = " matrix " ) {
Node : : XForm xf ;
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " sid " ) ) {
xf . id = p_parser . get_named_attribute_value ( " sid " ) ;
2014-02-10 02:10:30 +01:00
}
xf . op = Node : : XForm : : OP_MATRIX ;
2023-05-11 12:32:23 +02:00
Vector < float > matrix = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
xf . data = matrix ;
String mtx ;
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < matrix . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
mtx + = " " + rtos ( matrix [ i ] ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
xform_list . push_back ( xf ) ;
} else if ( section = = " visibility " ) {
Node : : XForm xf ;
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " sid " ) ) {
xf . id = p_parser . get_named_attribute_value ( " sid " ) ;
2014-02-10 02:10:30 +01:00
}
xf . op = Node : : XForm : : OP_VISIBILITY ;
2023-05-11 12:32:23 +02:00
Vector < float > visible = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
xf . data = visible ;
xform_list . push_back ( xf ) ;
2016-06-05 20:59:21 +02:00
} else if ( section = = " empty_draw_type " ) {
2023-05-11 12:32:23 +02:00
empty_draw_type = _read_empty_draw_type ( p_parser ) ;
2016-06-05 20:59:21 +02:00
} else if ( section = = " technique " | | section = = " extra " ) {
2014-02-10 02:10:30 +01:00
} else if ( section ! = " node " ) {
//usually what defines the type of node
if ( section . begins_with ( " instance_ " ) ) {
if ( ! node ) {
2023-05-11 12:32:23 +02:00
node = _parse_visual_node_instance_data ( p_parser ) ;
2014-02-10 02:10:30 +01:00
} else {
ERR_PRINT ( " Multiple instance_* not supported. " ) ;
}
}
2019-08-07 12:54:30 +02:00
} else {
2014-02-10 02:10:30 +01:00
/* Found a child node!! what to do..*/
2023-05-11 12:32:23 +02:00
Node * child = _parse_visual_scene_node ( p_parser ) ;
2014-02-10 02:10:30 +01:00
children . push_back ( child ) ;
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " node " ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
if ( ! node ) {
node = memnew ( Node ) ; //generic node, nothing of relevance found
}
node - > noname = ! found_name ;
node - > xform_list = xform_list ;
node - > children = children ;
for ( int i = 0 ; i < children . size ( ) ; i + + ) {
node - > children [ i ] - > parent = node ;
}
node - > name = name ;
node - > id = id ;
2016-06-05 20:59:21 +02:00
node - > empty_draw_type = empty_draw_type ;
2014-02-10 02:10:30 +01:00
if ( node - > children . size ( ) = = 1 ) {
if ( node - > children [ 0 ] - > noname & & ! node - > noname ) {
node - > children [ 0 ] - > name = node - > name ;
node - > name = node - > name + " -base " ;
}
}
node - > default_transform = node - > compute_transform ( * this ) ;
state . scene_map [ id ] = node ;
return node ;
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_visual_scene ( XMLParser & p_parser ) {
String id = p_parser . get_named_attribute_value ( " id " ) ;
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
if ( p_parser . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
}
state . visual_scene_map [ id ] = VisualScene ( ) ;
VisualScene & vscene = state . visual_scene_map [ id ] ;
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " name " ) ) {
vscene . name = p_parser . get_named_attribute_value ( " name " ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String section = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( section = = " node " ) {
2023-05-11 12:32:23 +02:00
vscene . root_nodes . push_back ( _parse_visual_scene_node ( p_parser ) ) ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " visual_scene " ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
COLLADA_PRINT ( " Scene ID: " + id ) ;
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_animation ( XMLParser & p_parser ) {
2014-02-10 02:10:30 +01:00
if ( ! ( state . import_flags & IMPORT_FLAG_ANIMATION ) ) {
2023-05-11 12:32:23 +02:00
if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return ;
}
2022-05-13 15:04:37 +02:00
HashMap < String , Vector < float > > float_sources ;
HashMap < String , Vector < String > > string_sources ;
HashMap < String , int > source_strides ;
HashMap < String , HashMap < String , String > > samplers ;
HashMap < String , Vector < String > > source_param_names ;
HashMap < String , Vector < String > > source_param_types ;
2014-02-10 02:10:30 +01:00
String id = " " ;
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " id " ) ) {
id = p_parser . get_named_attribute_value ( " id " ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
String current_source ;
String current_sampler ;
Vector < String > channel_sources ;
Vector < String > channel_targets ;
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String name = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( name = = " source " ) {
2023-05-11 12:32:23 +02:00
current_source = p_parser . get_named_attribute_value ( " id " ) ;
2014-02-10 02:10:30 +01:00
source_param_names [ current_source ] = Vector < String > ( ) ;
source_param_types [ current_source ] = Vector < String > ( ) ;
} else if ( name = = " float_array " ) {
2021-12-09 10:42:46 +01:00
if ( ! current_source . is_empty ( ) ) {
2023-05-11 12:32:23 +02:00
float_sources [ current_source ] = _read_float_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
}
} else if ( name = = " Name_array " ) {
2021-12-09 10:42:46 +01:00
if ( ! current_source . is_empty ( ) ) {
2023-05-11 12:32:23 +02:00
string_sources [ current_source ] = _read_string_array ( p_parser ) ;
2014-02-10 02:10:30 +01:00
}
} else if ( name = = " accessor " ) {
2023-05-11 12:32:23 +02:00
if ( ! current_source . is_empty ( ) & & p_parser . has_attribute ( " stride " ) ) {
source_strides [ current_source ] = p_parser . get_named_attribute_value ( " stride " ) . to_int ( ) ;
2014-02-10 02:10:30 +01:00
}
} else if ( name = = " sampler " ) {
2023-05-11 12:32:23 +02:00
current_sampler = p_parser . get_named_attribute_value ( " id " ) ;
2022-05-13 15:04:37 +02:00
samplers [ current_sampler ] = HashMap < String , String > ( ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " param " ) {
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " name " ) ) {
source_param_names [ current_source ] . push_back ( p_parser . get_named_attribute_value ( " name " ) ) ;
2020-05-14 16:41:43 +02:00
} else {
2014-02-10 02:10:30 +01:00
source_param_names [ current_source ] . push_back ( " " ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " type " ) ) {
source_param_types [ current_source ] . push_back ( p_parser . get_named_attribute_value ( " type " ) ) ;
2020-05-14 16:41:43 +02:00
} else {
2014-02-10 02:10:30 +01:00
source_param_types [ current_source ] . push_back ( " " ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
} else if ( name = = " input " ) {
2021-12-09 10:42:46 +01:00
if ( ! current_sampler . is_empty ( ) ) {
2023-05-11 12:32:23 +02:00
samplers [ current_sampler ] [ p_parser . get_named_attribute_value ( " semantic " ) ] = p_parser . get_named_attribute_value ( " source " ) ;
2014-02-10 02:10:30 +01:00
}
} else if ( name = = " channel " ) {
2023-05-11 12:32:23 +02:00
channel_sources . push_back ( p_parser . get_named_attribute_value ( " source " ) ) ;
channel_targets . push_back ( p_parser . get_named_attribute_value ( " target " ) ) ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " animation " ) {
2014-02-10 02:10:30 +01:00
break ; //end of <asset>
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
for ( int i = 0 ; i < channel_sources . size ( ) ; i + + ) {
String source = _uri_to_id ( channel_sources [ i ] ) ;
String target = channel_targets [ i ] ;
ERR_CONTINUE ( ! samplers . has ( source ) ) ;
2022-05-13 15:04:37 +02:00
HashMap < String , String > & sampler = samplers [ source ] ;
2014-02-10 02:10:30 +01:00
ERR_CONTINUE ( ! sampler . has ( " INPUT " ) ) ; //no input semantic? wtf?
String input_id = _uri_to_id ( sampler [ " INPUT " ] ) ;
COLLADA_PRINT ( " input id is " + input_id ) ;
ERR_CONTINUE ( ! float_sources . has ( input_id ) ) ;
ERR_CONTINUE ( ! sampler . has ( " OUTPUT " ) ) ;
String output_id = _uri_to_id ( sampler [ " OUTPUT " ] ) ;
ERR_CONTINUE ( ! float_sources . has ( output_id ) ) ;
ERR_CONTINUE ( ! source_param_names . has ( output_id ) ) ;
Vector < String > & names = source_param_names [ output_id ] ;
for ( int l = 0 ; l < names . size ( ) ; l + + ) {
String name = names [ l ] ;
Vector < float > & time_keys = float_sources [ input_id ] ;
int key_count = time_keys . size ( ) ;
AnimationTrack track ; //begin crating track
track . id = id ;
track . keys . resize ( key_count ) ;
for ( int j = 0 ; j < key_count ; j + + ) {
2018-07-25 03:11:03 +02:00
track . keys . write [ j ] . time = time_keys [ j ] ;
2014-02-10 02:10:30 +01:00
state . animation_length = MAX ( state . animation_length , time_keys [ j ] ) ;
}
//now read actual values
int stride = 1 ;
2020-05-14 16:41:43 +02:00
if ( source_strides . has ( output_id ) ) {
2014-02-10 02:10:30 +01:00
stride = source_strides [ output_id ] ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
int output_len = stride / names . size ( ) ;
ERR_CONTINUE ( output_len = = 0 ) ;
ERR_CONTINUE ( ! float_sources . has ( output_id ) ) ;
Vector < float > & output = float_sources [ output_id ] ;
2019-08-15 04:57:49 +02:00
ERR_CONTINUE_MSG ( ( output . size ( ) / stride ) ! = key_count , " Wrong number of keys in output. " ) ;
2014-02-10 02:10:30 +01:00
for ( int j = 0 ; j < key_count ; j + + ) {
2018-07-25 03:11:03 +02:00
track . keys . write [ j ] . data . resize ( output_len ) ;
2020-05-14 16:41:43 +02:00
for ( int k = 0 ; k < output_len ; k + + ) {
2018-07-25 03:11:03 +02:00
track . keys . write [ j ] . data . write [ k ] = output [ l + j * stride + k ] ; //super weird but should work:
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
if ( sampler . has ( " INTERPOLATION " ) ) {
String interp_id = _uri_to_id ( sampler [ " INTERPOLATION " ] ) ;
ERR_CONTINUE ( ! string_sources . has ( interp_id ) ) ;
Vector < String > & interps = string_sources [ interp_id ] ;
ERR_CONTINUE ( interps . size ( ) ! = key_count ) ;
for ( int j = 0 ; j < key_count ; j + + ) {
2020-05-14 16:41:43 +02:00
if ( interps [ j ] = = " BEZIER " ) {
2018-07-25 03:11:03 +02:00
track . keys . write [ j ] . interp_type = AnimationTrack : : INTERP_BEZIER ;
2020-05-14 16:41:43 +02:00
} else {
2018-07-25 03:11:03 +02:00
track . keys . write [ j ] . interp_type = AnimationTrack : : INTERP_LINEAR ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
if ( sampler . has ( " IN_TANGENT " ) & & sampler . has ( " OUT_TANGENT " ) ) {
//bezier control points..
String intangent_id = _uri_to_id ( sampler [ " IN_TANGENT " ] ) ;
ERR_CONTINUE ( ! float_sources . has ( intangent_id ) ) ;
Vector < float > & intangents = float_sources [ intangent_id ] ;
ERR_CONTINUE ( intangents . size ( ) ! = key_count * 2 * names . size ( ) ) ;
String outangent_id = _uri_to_id ( sampler [ " OUT_TANGENT " ] ) ;
ERR_CONTINUE ( ! float_sources . has ( outangent_id ) ) ;
Vector < float > & outangents = float_sources [ outangent_id ] ;
ERR_CONTINUE ( outangents . size ( ) ! = key_count * 2 * names . size ( ) ) ;
for ( int j = 0 ; j < key_count ; j + + ) {
2018-07-25 03:11:03 +02:00
track . keys . write [ j ] . in_tangent = Vector2 ( intangents [ j * 2 * names . size ( ) + 0 + l * 2 ] , intangents [ j * 2 * names . size ( ) + 1 + l * 2 ] ) ;
track . keys . write [ j ] . out_tangent = Vector2 ( outangents [ j * 2 * names . size ( ) + 0 + l * 2 ] , outangents [ j * 2 * names . size ( ) + 1 + l * 2 ] ) ;
2014-02-10 02:10:30 +01:00
}
}
2022-02-03 17:03:38 +01:00
if ( target . contains ( " / " ) ) { //transform component
2015-06-29 05:29:49 +02:00
track . target = target . get_slicec ( ' / ' , 0 ) ;
track . param = target . get_slicec ( ' / ' , 1 ) ;
2022-02-03 17:03:38 +01:00
if ( track . param . contains ( " . " ) ) {
2014-02-10 02:10:30 +01:00
track . component = track . param . get_slice ( " . " , 1 ) . to_upper ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
track . param = track . param . get_slice ( " . " , 0 ) ;
2021-12-09 10:42:46 +01:00
if ( names . size ( ) > 1 & & track . component . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
//this is a guess because the collada spec is ambiguous here...
//i suppose if you have many names (outputs) you can't use a component and i should abide to that.
track . component = name ;
}
} else {
track . target = target ;
}
state . animation_tracks . push_back ( track ) ;
2020-05-14 16:41:43 +02:00
if ( ! state . referenced_tracks . has ( target ) ) {
2014-02-10 02:10:30 +01:00
state . referenced_tracks [ target ] = Vector < int > ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
state . referenced_tracks [ target ] . push_back ( state . animation_tracks . size ( ) - 1 ) ;
2021-12-09 10:42:46 +01:00
if ( ! id . is_empty ( ) ) {
2020-05-14 16:41:43 +02:00
if ( ! state . by_id_tracks . has ( id ) ) {
2014-02-10 02:10:30 +01:00
state . by_id_tracks [ id ] = Vector < int > ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
state . by_id_tracks [ id ] . push_back ( state . animation_tracks . size ( ) - 1 ) ;
}
COLLADA_PRINT ( " loaded animation with " + itos ( key_count ) + " keys " ) ;
}
}
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_animation_clip ( XMLParser & p_parser ) {
2014-02-10 02:10:30 +01:00
if ( ! ( state . import_flags & IMPORT_FLAG_ANIMATION ) ) {
2023-05-11 12:32:23 +02:00
if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return ;
}
AnimationClip clip ;
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " name " ) ) {
clip . name = p_parser . get_named_attribute_value ( " name " ) ;
} else if ( p_parser . has_attribute ( " id " ) ) {
clip . name = p_parser . get_named_attribute_value ( " id " ) ;
2020-05-14 16:41:43 +02:00
}
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " start " ) ) {
clip . begin = p_parser . get_named_attribute_value ( " start " ) . to_float ( ) ;
2020-05-14 16:41:43 +02:00
}
2023-05-11 12:32:23 +02:00
if ( p_parser . has_attribute ( " end " ) ) {
clip . end = p_parser . get_named_attribute_value ( " end " ) . to_float ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String name = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( name = = " instance_animation " ) {
2023-05-11 12:32:23 +02:00
String url = _uri_to_id ( p_parser . get_named_attribute_value ( " url " ) ) ;
2014-02-10 02:10:30 +01:00
clip . tracks . push_back ( url ) ;
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " animation_clip " ) {
2014-02-10 02:10:30 +01:00
break ; //end of <asset>
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
state . animation_clips . push_back ( clip ) ;
}
2017-10-21 19:31:23 +02:00
2023-05-11 12:32:23 +02:00
void Collada : : _parse_scene ( XMLParser & p_parser ) {
if ( p_parser . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
}
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String name = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
if ( name = = " instance_visual_scene " ) {
2023-05-11 12:32:23 +02:00
state . root_visual_scene = _uri_to_id ( p_parser . get_named_attribute_value ( " url " ) ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " instance_physics_scene " ) {
2023-05-11 12:32:23 +02:00
state . root_physics_scene = _uri_to_id ( p_parser . get_named_attribute_value ( " url " ) ) ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " scene " ) {
2014-02-10 02:10:30 +01:00
break ; //end of <asset>
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2023-05-11 12:32:23 +02:00
void Collada : : _parse_library ( XMLParser & p_parser ) {
if ( p_parser . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
}
2023-05-11 12:32:23 +02:00
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
String name = p_parser . get_node_name ( ) ;
2014-02-10 02:10:30 +01:00
COLLADA_PRINT ( " library name is: " + name ) ;
if ( name = = " image " ) {
2023-05-11 12:32:23 +02:00
_parse_image ( p_parser ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " material " ) {
2023-05-11 12:32:23 +02:00
_parse_material ( p_parser ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " effect " ) {
2023-05-11 12:32:23 +02:00
_parse_effect ( p_parser ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " camera " ) {
2023-05-11 12:32:23 +02:00
_parse_camera ( p_parser ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " light " ) {
2023-05-11 12:32:23 +02:00
_parse_light ( p_parser ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " geometry " ) {
2023-05-11 12:32:23 +02:00
String id = p_parser . get_named_attribute_value ( " id " ) ;
String name2 = p_parser . get_named_attribute_value_safe ( " name " ) ;
while ( p_parser . read ( ) = = OK ) {
if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
if ( p_parser . get_node_name ( ) = = " mesh " ) {
2021-12-09 10:42:46 +01:00
state . mesh_name_map [ id ] = ( ! name2 . is_empty ( ) ) ? name2 : id ;
2023-05-11 12:32:23 +02:00
_parse_mesh_geometry ( p_parser , id , name2 ) ;
} else if ( p_parser . get_node_name ( ) = = " spline " ) {
2021-12-09 10:42:46 +01:00
state . mesh_name_map [ id ] = ( ! name2 . is_empty ( ) ) ? name2 : id ;
2023-05-11 12:32:23 +02:00
_parse_curve_geometry ( p_parser , id , name2 ) ;
} else if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) = = " geometry " ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
} else if ( name = = " controller " ) {
2023-05-11 12:32:23 +02:00
_parse_controller ( p_parser ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " animation " ) {
2023-05-11 12:32:23 +02:00
_parse_animation ( p_parser ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " animation_clip " ) {
2023-05-11 12:32:23 +02:00
_parse_animation_clip ( p_parser ) ;
2014-02-10 02:10:30 +01:00
} else if ( name = = " visual_scene " ) {
COLLADA_PRINT ( " visual scene " ) ;
2023-05-11 12:32:23 +02:00
_parse_visual_scene ( p_parser ) ;
} else if ( ! p_parser . is_empty ( ) ) {
p_parser . skip_section ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-05-11 12:32:23 +02:00
} else if ( p_parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT_END & & p_parser . get_node_name ( ) . begins_with ( " library_ " ) ) {
2014-02-10 02:10:30 +01:00
break ; //end of <asset>
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
void Collada : : _joint_set_owner ( Collada : : Node * p_node , NodeSkeleton * p_owner ) {
if ( p_node - > type = = Node : : TYPE_JOINT ) {
NodeJoint * nj = static_cast < NodeJoint * > ( p_node ) ;
nj - > owner = p_owner ;
for ( int i = 0 ; i < nj - > children . size ( ) ; i + + ) {
2018-07-25 03:11:03 +02:00
_joint_set_owner ( nj - > children . write [ i ] , p_owner ) ;
2014-02-10 02:10:30 +01:00
}
}
}
2014-12-02 18:02:41 +01:00
void Collada : : _create_skeletons ( Collada : : Node * * p_node , NodeSkeleton * p_skeleton ) {
2014-02-10 02:10:30 +01:00
Node * node = * p_node ;
if ( node - > type = = Node : : TYPE_JOINT ) {
2014-12-02 18:02:41 +01:00
if ( ! p_skeleton ) {
// ohohohoohoo it's a joint node, time to work!
NodeSkeleton * sk = memnew ( NodeSkeleton ) ;
* p_node = sk ;
sk - > children . push_back ( node ) ;
sk - > parent = node - > parent ;
node - > parent = sk ;
p_skeleton = sk ;
}
2014-02-10 02:10:30 +01:00
2014-12-02 18:02:41 +01:00
NodeJoint * nj = static_cast < NodeJoint * > ( node ) ;
nj - > owner = p_skeleton ;
2014-02-10 02:10:30 +01:00
} else {
2020-04-02 01:20:12 +02:00
p_skeleton = nullptr ;
2014-12-02 18:02:41 +01:00
}
2014-02-10 02:10:30 +01:00
2014-12-02 18:02:41 +01:00
for ( int i = 0 ; i < node - > children . size ( ) ; i + + ) {
2018-07-25 03:11:03 +02:00
_create_skeletons ( & node - > children . write [ i ] , p_skeleton ) ;
2014-02-10 02:10:30 +01:00
}
}
bool Collada : : _remove_node ( Node * p_parent , Node * p_node ) {
for ( int i = 0 ; i < p_parent - > children . size ( ) ; i + + ) {
if ( p_parent - > children [ i ] = = p_node ) {
2021-07-04 00:17:03 +02:00
p_parent - > children . remove_at ( i ) ;
2014-02-10 02:10:30 +01:00
return true ;
}
2020-05-14 16:41:43 +02:00
if ( _remove_node ( p_parent - > children [ i ] , p_node ) ) {
2014-02-10 02:10:30 +01:00
return true ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
return false ;
}
void Collada : : _remove_node ( VisualScene * p_vscene , Node * p_node ) {
for ( int i = 0 ; i < p_vscene - > root_nodes . size ( ) ; i + + ) {
if ( p_vscene - > root_nodes [ i ] = = p_node ) {
2021-07-04 00:17:03 +02:00
p_vscene - > root_nodes . remove_at ( i ) ;
2014-02-10 02:10:30 +01:00
return ;
}
2020-05-14 16:41:43 +02:00
if ( _remove_node ( p_vscene - > root_nodes [ i ] , p_node ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
ERR_PRINT ( " ERROR: Not found node to remove? " ) ;
}
void Collada : : _merge_skeletons ( VisualScene * p_vscene , Node * p_node ) {
if ( p_node - > type = = Node : : TYPE_GEOMETRY ) {
NodeGeometry * gnode = static_cast < NodeGeometry * > ( p_node ) ;
if ( gnode - > controller ) {
// recount skeletons used
2022-05-19 17:00:06 +02:00
HashSet < NodeSkeleton * > skeletons ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < gnode - > skeletons . size ( ) ; i + + ) {
String nodeid = gnode - > skeletons [ i ] ;
ERR_CONTINUE ( ! state . scene_map . has ( nodeid ) ) ; //weird, it should have it...
2020-03-11 21:01:02 +01:00
NodeJoint * nj = dynamic_cast < NodeJoint * > ( state . scene_map [ nodeid ] ) ;
2017-08-08 13:14:51 +02:00
ERR_CONTINUE ( ! nj ) ; //broken collada
2014-02-10 02:10:30 +01:00
ERR_CONTINUE ( ! nj - > owner ) ; //weird, node should have a skeleton owner
skeletons . insert ( nj - > owner ) ;
}
if ( skeletons . size ( ) > 1 ) {
//do the merger!!
2022-05-19 17:00:06 +02:00
HashSet < NodeSkeleton * > : : Iterator E = skeletons . begin ( ) ;
NodeSkeleton * base = * E ;
2014-02-10 02:10:30 +01:00
2022-05-19 17:00:06 +02:00
for ( + + E ; E ; + + E ) {
NodeSkeleton * merged = * E ;
2014-02-10 02:10:30 +01:00
_remove_node ( p_vscene , merged ) ;
for ( int i = 0 ; i < merged - > children . size ( ) ; i + + ) {
_joint_set_owner ( merged - > children [ i ] , base ) ;
base - > children . push_back ( merged - > children [ i ] ) ;
merged - > children [ i ] - > parent = base ;
}
merged - > children . clear ( ) ; //take children from it
memdelete ( merged ) ;
}
}
}
}
for ( int i = 0 ; i < p_node - > children . size ( ) ; i + + ) {
_merge_skeletons ( p_vscene , p_node - > children [ i ] ) ;
}
2014-09-15 16:33:30 +02:00
}
void Collada : : _merge_skeletons2 ( VisualScene * p_vscene ) {
2021-08-09 22:13:42 +02:00
for ( KeyValue < String , SkinControllerData > & E : state . skin_controller_data_map ) {
SkinControllerData & cd = E . value ;
2014-09-15 16:33:30 +02:00
2020-04-02 01:20:12 +02:00
NodeSkeleton * skeleton = nullptr ;
2014-09-15 16:33:30 +02:00
2021-08-09 22:13:42 +02:00
for ( const KeyValue < String , Transform3D > & F : cd . bone_rest_map ) {
2014-09-15 16:33:30 +02:00
String name ;
2021-08-09 22:13:42 +02:00
if ( ! state . sid_to_node_map . has ( F . key ) ) {
2014-09-15 16:33:30 +02:00
continue ;
}
2021-08-09 22:13:42 +02:00
name = state . sid_to_node_map [ F . key ] ;
2014-09-15 16:33:30 +02:00
ERR_CONTINUE ( ! state . scene_map . has ( name ) ) ;
Node * node = state . scene_map [ name ] ;
ERR_CONTINUE ( node - > type ! = Node : : TYPE_JOINT ) ;
2019-04-08 11:03:37 +02:00
2020-04-02 01:20:12 +02:00
NodeSkeleton * sk = nullptr ;
2014-09-15 16:33:30 +02:00
while ( node & & ! sk ) {
if ( node - > type = = Node : : TYPE_SKELETON ) {
sk = static_cast < NodeSkeleton * > ( node ) ;
}
node = node - > parent ;
}
2018-04-21 16:35:23 +02:00
ERR_CONTINUE ( ! sk ) ;
2014-09-15 16:33:30 +02:00
if ( ! skeleton ) {
skeleton = sk ;
continue ;
}
if ( skeleton ! = sk ) {
//whoa.. wtf, merge.
_remove_node ( p_vscene , sk ) ;
for ( int i = 0 ; i < sk - > children . size ( ) ; i + + ) {
_joint_set_owner ( sk - > children [ i ] , skeleton ) ;
skeleton - > children . push_back ( sk - > children [ i ] ) ;
sk - > children [ i ] - > parent = skeleton ;
}
sk - > children . clear ( ) ; //take children from it
memdelete ( sk ) ;
}
}
}
2014-02-10 02:10:30 +01:00
}
bool Collada : : _optimize_skeletons ( VisualScene * p_vscene , Node * p_node ) {
Node * node = p_node ;
if ( node - > type = = Node : : TYPE_SKELETON & & node - > parent & & node - > parent - > type = = Node : : TYPE_NODE & & node - > parent - > children . size ( ) = = 1 ) {
//replace parent by this...
Node * parent = node - > parent ;
Fix misc. source comment typos
Found using `codespell -q 3 -S ./thirdparty,*.po -L ang,ba,cas,dof,doubleclick,fave,hist,leapyear,lod,nd,numer,ois,paket,seeked,sinc,switchs,te,uint -D ~/Projects/codespell/codespell_lib/data/dictionary.txt `
2019-09-19 20:36:39 +02:00
//i wonder if this is alright.. i think it is since created skeleton (first joint) is already animated by bone..
2014-02-10 02:10:30 +01:00
node - > id = parent - > id ;
node - > name = parent - > name ;
node - > xform_list = parent - > xform_list ;
node - > default_transform = parent - > default_transform ;
state . scene_map [ node - > id ] = node ;
node - > parent = parent - > parent ;
if ( parent - > parent ) {
Node * gp = parent - > parent ;
bool found = false ;
for ( int i = 0 ; i < gp - > children . size ( ) ; i + + ) {
if ( gp - > children [ i ] = = parent ) {
2018-07-25 03:11:03 +02:00
gp - > children . write [ i ] = node ;
2014-02-10 02:10:30 +01:00
found = true ;
break ;
}
}
if ( ! found ) {
ERR_PRINT ( " BUG " ) ;
}
} else {
bool found = false ;
for ( int i = 0 ; i < p_vscene - > root_nodes . size ( ) ; i + + ) {
if ( p_vscene - > root_nodes [ i ] = = parent ) {
2018-07-25 03:11:03 +02:00
p_vscene - > root_nodes . write [ i ] = node ;
2014-02-10 02:10:30 +01:00
found = true ;
break ;
}
}
if ( ! found ) {
ERR_PRINT ( " BUG " ) ;
}
}
parent - > children . clear ( ) ;
memdelete ( parent ) ;
return true ;
}
for ( int i = 0 ; i < node - > children . size ( ) ; i + + ) {
2020-05-14 16:41:43 +02:00
if ( _optimize_skeletons ( p_vscene , node - > children [ i ] ) ) {
2014-02-10 02:10:30 +01:00
return false ; //stop processing, go up
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
return false ;
}
bool Collada : : _move_geometry_to_skeletons ( VisualScene * p_vscene , Node * p_node , List < Node * > * p_mgeom ) {
2019-02-13 09:23:29 +01:00
// Bind Shape Matrix scales the bones and makes them gigantic, so the matrix then shrinks the model?
// Solution: apply the Bind Shape Matrix to the VERTICES, and if the object comes scaled, it seems to be left alone!
2014-02-10 02:10:30 +01:00
if ( p_node - > type = = Node : : TYPE_GEOMETRY ) {
NodeGeometry * ng = static_cast < NodeGeometry * > ( p_node ) ;
2020-05-14 16:41:43 +02:00
if ( ng - > ignore_anim ) {
2014-02-10 02:10:30 +01:00
return false ; //already made child of skeleton and processeg
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
if ( ng - > controller & & ng - > skeletons . size ( ) ) {
String nodeid = ng - > skeletons [ 0 ] ;
ERR_FAIL_COND_V ( ! state . scene_map . has ( nodeid ) , false ) ; //weird, it should have it...
2020-03-11 21:01:02 +01:00
NodeJoint * nj = dynamic_cast < NodeJoint * > ( state . scene_map [ nodeid ] ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL_V ( nj , false ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND_V ( ! nj - > owner , false ) ; //weird, node should have a skeleton owner
NodeSkeleton * sk = nj - > owner ;
Node * p = sk - > parent ;
bool node_is_parent_of_skeleton = false ;
while ( p ) {
if ( p = = p_node ) {
node_is_parent_of_skeleton = true ;
break ;
}
p = p - > parent ; // try again
}
ERR_FAIL_COND_V ( node_is_parent_of_skeleton , false ) ;
//this should be correct
ERR_FAIL_COND_V ( ! state . skin_controller_data_map . has ( ng - > source ) , false ) ;
SkinControllerData & skin = state . skin_controller_data_map [ ng - > source ] ;
2020-10-17 07:08:21 +02:00
Transform3D skel_inv = sk - > get_global_transform ( ) . affine_inverse ( ) ;
2014-02-10 02:10:30 +01:00
p_node - > default_transform = skel_inv * ( skin . bind_shape /* p_node->get_global_transform()*/ ) ; // i honestly have no idea what to do with a previous model xform.. most exporters ignore it
//make rests relative to the skeleton (they seem to be always relative to world)
2021-08-09 22:13:42 +02:00
for ( KeyValue < String , Transform3D > & E : skin . bone_rest_map ) {
E . value = skel_inv * E . value ; //make the bone rest local to the skeleton
state . bone_rest_map [ E . key ] = E . value ; // make it remember where the bone is globally, now that it's relative
2014-02-10 02:10:30 +01:00
}
//but most exporters seem to work only if i do this..
//p_node->default_transform = p_node->get_global_transform();
2020-10-17 07:08:21 +02:00
//p_node->default_transform=Transform3D(); //this seems to be correct, because bind shape makes the object local to the skeleton
2014-02-10 02:10:30 +01:00
p_node - > ignore_anim = true ; // collada may animate this later, if it does, then this is not supported (redo your original asset and don't animate the base mesh)
p_node - > parent = sk ;
2017-03-24 21:45:31 +01:00
//sk->children.push_back(0,p_node); //avoid INFINITE loop
2014-02-10 02:10:30 +01:00
p_mgeom - > push_back ( p_node ) ;
return true ;
}
}
for ( int i = 0 ; i < p_node - > children . size ( ) ; i + + ) {
if ( _move_geometry_to_skeletons ( p_vscene , p_node - > children [ i ] , p_mgeom ) ) {
2021-07-04 00:17:03 +02:00
p_node - > children . remove_at ( i ) ;
2014-02-10 02:10:30 +01:00
i - - ;
}
}
return false ;
}
void Collada : : _find_morph_nodes ( VisualScene * p_vscene , Node * p_node ) {
if ( p_node - > type = = Node : : TYPE_GEOMETRY ) {
NodeGeometry * nj = static_cast < NodeGeometry * > ( p_node ) ;
if ( nj - > controller ) {
String base = nj - > source ;
2021-12-09 10:42:46 +01:00
while ( ! base . is_empty ( ) & & ! state . mesh_data_map . has ( base ) ) {
2014-02-10 02:10:30 +01:00
if ( state . skin_controller_data_map . has ( base ) ) {
SkinControllerData & sk = state . skin_controller_data_map [ base ] ;
base = sk . base ;
} else if ( state . morph_controller_data_map . has ( base ) ) {
state . morph_ownership_map [ base ] = nj - > id ;
break ;
} else {
2019-08-15 04:57:49 +02:00
ERR_FAIL_MSG ( " Invalid scene. " ) ;
2014-02-10 02:10:30 +01:00
}
}
}
}
for ( int i = 0 ; i < p_node - > children . size ( ) ; i + + ) {
_find_morph_nodes ( p_vscene , p_node - > children [ i ] ) ;
}
}
void Collada : : _optimize ( ) {
2021-08-09 22:13:42 +02:00
for ( KeyValue < String , VisualScene > & E : state . visual_scene_map ) {
VisualScene & vs = E . value ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < vs . root_nodes . size ( ) ; i + + ) {
2018-07-25 03:11:03 +02:00
_create_skeletons ( & vs . root_nodes . write [ i ] ) ;
2014-02-10 02:10:30 +01:00
}
2017-08-27 21:07:15 +02:00
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < vs . root_nodes . size ( ) ; i + + ) {
_merge_skeletons ( & vs , vs . root_nodes [ i ] ) ;
}
2014-09-15 16:33:30 +02:00
_merge_skeletons2 ( & vs ) ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < vs . root_nodes . size ( ) ; i + + ) {
_optimize_skeletons ( & vs , vs . root_nodes [ i ] ) ;
}
for ( int i = 0 ; i < vs . root_nodes . size ( ) ; i + + ) {
List < Node * > mgeom ;
if ( _move_geometry_to_skeletons ( & vs , vs . root_nodes [ i ] , & mgeom ) ) {
2021-07-04 00:17:03 +02:00
vs . root_nodes . remove_at ( i ) ;
2014-02-10 02:10:30 +01:00
i - - ;
}
2020-12-15 13:04:21 +01:00
while ( ! mgeom . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
Node * n = mgeom . front ( ) - > get ( ) ;
n - > parent - > children . push_back ( n ) ;
mgeom . pop_front ( ) ;
}
}
2017-08-27 21:07:15 +02:00
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < vs . root_nodes . size ( ) ; i + + ) {
_find_morph_nodes ( & vs , vs . root_nodes [ i ] ) ;
}
}
}
int Collada : : get_uv_channel ( String p_name ) {
if ( ! channel_map . has ( p_name ) ) {
ERR_FAIL_COND_V ( channel_map . size ( ) = = 2 , 0 ) ;
channel_map [ p_name ] = channel_map . size ( ) ;
}
return channel_map [ p_name ] ;
}
Error Collada : : load ( const String & p_path , int p_flags ) {
Ref < XMLParser > parserr = memnew ( XMLParser ) ;
XMLParser & parser = * parserr . ptr ( ) ;
Error err = parser . open ( p_path ) ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err , err , " Cannot open Collada file ' " + p_path + " '. " ) ;
2014-02-10 02:10:30 +01:00
2017-07-19 22:00:46 +02:00
state . local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
2014-02-10 02:10:30 +01:00
state . import_flags = p_flags ;
/* Skip headers */
while ( ( err = parser . read ( ) ) = = OK ) {
if ( parser . get_node_type ( ) = = XMLParser : : NODE_ELEMENT ) {
if ( parser . get_node_name ( ) = = " COLLADA " ) {
break ;
2020-05-14 16:41:43 +02:00
} else if ( ! parser . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
parser . skip_section ( ) ; // unknown section, likely headers
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , ERR_FILE_CORRUPT , " Corrupted Collada file ' " + p_path + " '. " ) ;
2014-02-10 02:10:30 +01:00
/* Start loading Collada */
{
//version
2022-11-28 10:00:48 +01:00
String version = parser . get_named_attribute_value ( " version " ) ;
2014-02-10 02:10:30 +01:00
state . version . major = version . get_slice ( " . " , 0 ) . to_int ( ) ;
state . version . minor = version . get_slice ( " . " , 1 ) . to_int ( ) ;
state . version . rev = version . get_slice ( " . " , 2 ) . to_int ( ) ;
COLLADA_PRINT ( " Collada VERSION: " + version ) ;
}
while ( ( err = parser . read ( ) ) = = OK ) {
/* Read all the main sections.. */
2020-05-14 16:41:43 +02:00
if ( parser . get_node_type ( ) ! = XMLParser : : NODE_ELEMENT ) {
2014-02-10 02:10:30 +01:00
continue ; //no idea what this may be, but skipping anyway
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
String section = parser . get_node_name ( ) ;
COLLADA_PRINT ( " section: " + section ) ;
if ( section = = " asset " ) {
_parse_asset ( parser ) ;
} else if ( section . begins_with ( " library_ " ) ) {
_parse_library ( parser ) ;
} else if ( section = = " scene " ) {
_parse_scene ( parser ) ;
} else if ( ! parser . is_empty ( ) ) {
parser . skip_section ( ) ; // unknown section, likely headers
}
}
_optimize ( ) ;
return OK ;
}
Collada : : Collada ( ) {
}