- Timestamp:
- 01/26/16 18:59:46 (9 years ago)
- Location:
- trunk
- Files:
-
- 25 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/nv/core/resource.hh
r484 r485 18 18 #include <nv/stl/hash_store.hh> 19 19 #include <nv/stl/vector.hh> 20 21 #include <nv/core/logging.hh> 20 22 21 23 … … 77 79 { 78 80 public: 79 resource() : m_id( 0), m_handler( nullptr ) {}81 resource() : m_id(), m_handler( nullptr ) {} 80 82 resource_id id() const { return m_id; } 81 83 constexpr bool is_valid() const { return m_id && m_handler; } … … 214 216 if ( m->second->exists( id ) || m->second->load_resource( id ) ) 215 217 return m->second->create< T >( id ); 216 //NV_ASSERT( false, "resource_manager.get failed!" );218 NV_ASSERT( false, "resource_manager.get failed!" ); 217 219 return resource< T >(); 218 220 } … … 227 229 return m->second->create< T >( id ); 228 230 } 229 //NV_ASSERT( false, "resource_manager.get failed!" );231 NV_ASSERT( false, "resource_manager.get failed!" ); 230 232 return resource< T >(); 231 233 } -
trunk/nv/core/transform.hh
r482 r485 106 106 template <> struct type_to_enum< transform > { static const datatype type = TRANSFORM; }; 107 107 108 template<>109 inline transform interpolate( const transform& a, const transform& b, float value )110 {111 return transform(112 math::mix ( a.get_position(), b.get_position(), value ),113 math::slerp( a.get_orientation(), b.get_orientation(), value )114 );115 }116 108 } 117 109 -
trunk/nv/engine/animation.hh
r484 r485 18 18 #include <nv/interface/mesh_data.hh> 19 19 #include <nv/gfx/skeleton_instance.hh> 20 #include <nv/gfx/poses.hh> 20 21 21 22 namespace nv … … 25 26 } 26 27 27 NV_RTTI_DECLARE_NAME ( nv::mesh_nodes_data, "nv::mesh_nodes_data")28 NV_RTTI_DECLARE_NAME ( nv::animator_bind_data, "nv::animator_bind_data" )29 NV_RTTI_DECLARE_NAME ( nv::animator_data, "nv::animator_data")28 NV_RTTI_DECLARE_NAME ( nv::mesh_nodes_data, "nv::mesh_nodes_data" ) 29 NV_RTTI_DECLARE_NAME ( nv::animator_bind_data, "nv::animator_bind_data" ) 30 NV_RTTI_DECLARE_NAME ( nv::animator_data, "nv::animator_data" ) 30 31 31 32 namespace nv 32 33 { 33 34 34 classanimator_clip_data35 struct animator_clip_data 35 36 { 36 public: 37 animator_clip_data( resource< mesh_nodes_data > data, frame_range frange ) 38 : m_data( data ) 39 , m_range( frange ) 40 { 41 } 42 // uint32 get_start_frame() const { return m_range.start; } 43 // uint32 get_end_frame() const { return m_range.end; } 44 // uint32 get_frame_count() const { return m_range.duration(); } 45 // bool is_looping() const { return m_range.is_looping; } 46 resource< mesh_nodes_data > get_data() const { return m_data; } 47 const frame_range& get_range() const { return m_range; } 48 protected: 49 resource< mesh_nodes_data > m_data; 50 frame_range m_range; 37 uint32 id; 38 frame_range range; 51 39 }; 52 40 … … 54 42 { 55 43 public: 56 animator_data() {} 44 animator_data( pose_data_set* data ) : m_data( data ) {} 45 // 46 pose_data_set* get_pose_data() { return m_data; } 47 const pose_data_set* get_pose_data() const { return m_data; } 48 57 49 const animator_clip_data* get_clip( shash64 name ) const 58 50 { … … 70 62 } 71 63 protected: 64 pose_data_set* m_data; 72 65 hash_store< shash64, animator_clip_data > m_clip_data; 73 66 }; … … 77 70 { 78 71 public: 79 animator_bind_data( const data_node_list& bones )72 animator_bind_data( const data_node_list& pose_frame, const data_node_list& bones ) 80 73 : m_bone_list( bones.get_name() ) 81 74 { 82 // TODO: m_bone_list.clone 83 for ( auto bone : bones ) 84 { 85 m_bone_list.append( bone ); 86 } 87 m_bone_transforms.prepare( m_bone_list ); 75 m_bone_list.assign( bones ); 76 m_bone_transforms.prepare( bones ); 77 m_pose_binding.prepare( pose_frame, bones ); 88 78 } 89 void add_binding( shash64 id, const mesh_nodes_data* nodes ) 79 const bone_transforms& get_bone_transforms() const { return m_bone_transforms; } 80 const skeleton_binding& get_pose_binding() const 90 81 { 91 m_bind_data[id].prepare( nodes, m_bone_list );82 return m_pose_binding; 92 83 } 84 const data_node_list& get_bone_list() const { return m_bone_list; } 93 85 94 bool has_binding( shash64 id ) const { return m_bind_data.find( id ) != m_bind_data.end(); }95 const bone_transforms& get_bone_transforms() const { return m_bone_transforms; }96 const skeleton_binding& get_binding( shash64 id ) const97 {98 return m_bind_data.at( id );99 }100 86 protected: 101 hash_store< shash64, skeleton_binding > m_bind_data;87 skeleton_binding m_pose_binding; 102 88 bone_transforms m_bone_transforms; 103 89 data_node_list m_bone_list; … … 132 118 } 133 119 120 sint16 get_bone_index( shash64 bone_name ) const 121 { 122 if ( is_valid() ) 123 { 124 auto data = m_bind_data.lock(); 125 sint16 id = data->get_bone_list().resolve( bone_name ); 126 return id; 127 } 128 return -1; 129 } 130 131 const mat4& get_bone_matrix( shash64 bone_name ) const 132 { 133 if ( is_valid() ) 134 { 135 auto data = m_bind_data.lock(); 136 sint16 id = data->get_bone_list().resolve( bone_name ); 137 if ( id >= 0 ) 138 { 139 return data->get_bone_list()[id].transform; 140 } 141 } 142 return mat4(); 143 } 144 145 134 146 void update( shash64 clip, uint32 time ) 135 147 { … … 139 151 auto bind_data = m_bind_data.lock(); 140 152 const animator_clip_data* clip_data = data->get_clip( clip ); 141 if ( clip_data ) 153 154 if ( data->get_pose_data() ) 142 155 { 143 if ( auto nodes = clip_data->get_data().lock())156 if ( clip_data ) 144 157 { 145 float fframe = clip_data->get_range().frame_from_ms_fps( time, nodes->get_fps() ); 146 m_transforms.animate( &*nodes, bind_data->get_binding( clip ), fframe ); 158 auto pose_data = data->get_pose_data(); 159 float fframe = clip_data->range.frame_from_ms_fps( time, 30 ); 160 161 unsigned v1 = unsigned( fframe ); 162 unsigned v2 = v1 + 1; 163 if ( v2 >= clip_data->range.end ) v2 = clip_data->range.start; 164 165 unsigned iv1 = v1 + clip_data->id; 166 unsigned iv2 = v2 + clip_data->id; 167 168 m_transforms.interpolate_slerp( pose_data->get( iv1 ), pose_data->get( iv2 ), fframe - v1 ); 169 m_transforms.delocalize( pose_data->get_tree() ); 170 147 171 } 172 m_skeleton.assign( m_transforms, bind_data->get_pose_binding(), bind_data->get_bone_transforms() ); 148 173 } 149 m_skeleton.assign( m_transforms, bind_data->get_bone_transforms() );150 174 } 151 175 } -
trunk/nv/formats/assimp_loader.hh
r482 r485 17 17 { 18 18 19 struct assimp_data; 20 19 21 class assimp_loader : public mesh_loader 20 22 { … … 31 33 void scene_report() const; 32 34 private: 33 data_node_list* release_merged_bones( data_channel_set* meshes ); 34 bool load_bones( size_t index, array_ref< data_node_info > bones ); 35 bool is_node_animated(); 36 void build_skeleton( vector< data_node_info >& skeleton, const void* node, int parent_id ); 37 data_node_list* release_merged_bones(); 35 38 void load_mesh_data( data_channel_set* data, size_t index, data_node_info& info ); 36 39 sint16 load_node( uint32 anim_id, array_ref< data_channel_set* > nodes, array_ref< data_node_info > infos, const void* vnode, sint16 this_id, sint16 parent_id ); 40 void scan_nodes( const void* node ) const; 37 41 uint32 count_nodes( const void* node ) const; 38 data_channel_set* create_keys( const void* vnode ); 42 data_channel_set* create_keys( const void* vnode, const transform& tr ); 43 44 45 assimp_data* m_data; 46 47 vector< data_channel_set* > m_meshes; 48 vector< data_node_info > m_mesh_info; 49 hash_store< shash64, uint16 > m_bone_names; 39 50 40 51 const_string m_ext; 41 52 uint32 m_assimp_flags; 42 const void* m_scene;43 53 size_t m_mesh_count; 44 54 }; -
trunk/nv/formats/nmd_loader.hh
r482 r485 11 11 #include <nv/interface/mesh_loader.hh> 12 12 #include <nv/interface/mesh_data.hh> 13 #include <nv/gfx/skeleton_instance.hh> 13 14 #include <nv/stl/vector.hh> 14 15 #include <nv/stl/string_table.hh> 16 // 17 #include <nv/gfx/poses.hh> 15 18 16 19 namespace nv … … 20 23 { 21 24 MESH, 22 ANIMATION,25 BONES, 23 26 NODE, 24 27 STRINGS, 25 DATA 28 DATA, 29 POSES, 26 30 }; 27 31 … … 78 82 { 79 83 public: 80 explicit nmd_loader( string_table* strings ) : mesh_loader( strings ), m_node_data( nullptr ), m_bone_data( nullptr ) {}84 explicit nmd_loader( string_table* strings ) : mesh_loader( strings ), /*m_node_data( nullptr ), */m_bone_data( nullptr ), m_pose_data_set( nullptr ) {} 81 85 virtual bool load( stream& source ); 82 86 virtual data_channel_set* release_mesh_data( size_t index, data_node_info& info ); … … 87 91 virtual size_t get_mesh_count() const { return m_meshes.size(); } 88 92 virtual ~nmd_loader(); 93 94 // 95 pose_data_set* release_pose_data_set() { auto result = m_pose_data_set; m_pose_data_set = nullptr; return result; } 89 96 private: 90 97 void reset(); … … 92 99 bool load_mesh( stream& source, const nmd_element_header& e ); 93 100 bool load_strings( stream& source ); 94 bool load_ animation( stream& source, const nmd_element_header& e );101 bool load_bones( stream& source, const nmd_element_header& e ); 95 102 bool load_channel( stream& source, data_channel_set* channel_set ); 96 103 bool load_channel_set( stream& source, data_channel_set* channel_set, data_node_info& info, const nmd_element_header& e ); 97 104 98 mesh_nodes_data* m_node_data; 105 // 106 bool load_poses( stream& source, const nmd_element_header& e ); 107 108 109 // mesh_nodes_data* m_node_data; 99 110 data_node_list* m_bone_data; 100 111 vector< data_node_info > m_infos; 101 112 vector< data_channel_set* > m_meshes; 113 114 // 115 pose_data_set* m_pose_data_set; 102 116 }; 103 117 … … 106 120 void nmd_dump_strings( stream& stream_out, const string_table& strings ); 107 121 void nmd_dump_element( stream& stream_out, const data_channel_set& data, const data_node_info& info, nmd_type type ); 108 void nmd_dump_nodes( stream& stream_out, const mesh_nodes_data& nodes );109 122 void nmd_dump_bones( stream& stream_out, const data_node_list& nodes ); 123 void nmd_dump_poses( stream& stream_out, const array_view< skeleton_transforms* > poses, shash64 name ); 124 void nmd_dump_pose( stream& stream_out, const skeleton_transforms& pose, shash64 name ); 110 125 void nmd_dump( stream& stream_out, array_view< data_channel_set* > meshes, array_view< data_node_info > infos, const nv::data_node_list* nodes, const string_table* strings /*= nullptr*/, uint64 name /*= 0 */ ); 111 void nmd_dump( stream& stream_out, array_view< data_channel_set* > meshes, array_view< data_node_info > infos, const mesh_nodes_data* nodes, const string_table* strings = nullptr, uint64 name = 0 );112 void nmd_dump( stream& stream_out, const mesh_nodes_data& animation, const string_table* strings = nullptr, uint64 name = 0 );113 114 126 115 127 } -
trunk/nv/gfx/skeleton_instance.hh
r484 r485 66 66 public: 67 67 skeleton_binding() {} 68 void assign( const skeleton_binding& other ); 68 69 void prepare( const mesh_nodes_data* node_data, const data_node_list& bone_data ); 70 void prepare( const data_node_list& pose_data, const data_node_list& bone_data ); 69 71 uint32 size() const { return m_indices.size(); }; 70 72 uint32 skeleton_size() const { return m_bone_count; }; … … 81 83 { 82 84 public: 85 friend class pose_data_set; 86 83 87 skeleton_transforms() {} 84 const transform* transforms() const { return m_transforms.data(); }88 const transform* xforms() const { return m_transforms.data(); } 85 89 size_t size() const { return m_transforms.size(); } 86 90 void assign( const data_node_list* node_data ); 87 91 void assign( const skeleton_transforms& other ); 92 88 93 void interpolate_linear( const skeleton_transforms& a, const skeleton_transforms& b, float t ); 89 94 void interpolate_nlerp( const skeleton_transforms& a, const skeleton_transforms& b, float t ); … … 91 96 void interpolate4( const skeleton_transforms& s1, const skeleton_transforms& v1, const skeleton_transforms& v2, const skeleton_transforms& s2, float t ); 92 97 void interpolate_squad( const skeleton_transforms& s1, const skeleton_transforms& v1, const skeleton_transforms& v2, const skeleton_transforms& s2, float t ); 93 void animate_local( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame ); 94 void animate( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, bool local = false ) 98 99 // void animate( const mesh_nodes_data* node_data, float frame, bool local = false ) 100 // { 101 // if ( local ) 102 // { 103 // animate_local( node_data, frame ); 104 // return; 105 // } 106 // if ( m_transforms.size() != node_data->size() ) 107 // m_transforms.resize( node_data->size() ); 108 // for ( uint32 n = 0; n < node_data->size(); ++n ) 109 // if ( node_data->get_info( n ).parent_id == -1 ) 110 // animate_rec( node_data, frame, n, transform(), false ); 111 // } 112 void blend_slerp( const skeleton_transforms& a, const skeleton_transforms& b, float t, float blend ); 113 114 // void blend( const mesh_nodes_data* node_data, float frame, float blend, bool local = false ) 115 // { 116 // NV_ASSERT( m_transforms.size() == node_data->size(), "skeleton size wrong!" ); 117 // if ( local ) 118 // { 119 // blend_local( node_data, frame, blend ); 120 // return; 121 // } 122 // for ( uint32 n = 0; n < node_data->size(); ++n ) 123 // if ( node_data->get_info( n ).parent_id == -1 ) 124 // blend_rec( node_data, frame, n, transform(), false, blend ); 125 // } 126 127 void delocalize( const data_node_tree& node_data ) 95 128 { 96 if ( local ) 97 { 98 animate_local( node_data, binding, frame ); 99 return; 100 } 101 if ( m_transforms.size() != binding.skeleton_size() ) 102 m_transforms.resize( binding.skeleton_size() ); 103 for ( uint32 n = 0; n < node_data->size(); ++n ) 104 if ( node_data->get_info(n).parent_id == -1 ) 105 animate_rec( node_data, binding, frame, n, transform(), false ); 106 } 107 void blend_local( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, float blend ); 108 void blend( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, float blend, bool local = false ) 109 { 110 NV_ASSERT( m_transforms.size() == binding.skeleton_size(), "skeleton size wrong!" ); 111 if ( local ) 112 { 113 blend_local( node_data, binding, frame, blend ); 114 return; 115 } 116 for ( uint32 n = 0; n < node_data->size(); ++n ) 117 if ( node_data->get_info( n ).parent_id == -1 ) 118 blend_rec( node_data, binding, frame, n, transform(), false, blend); 129 for ( uint32 n = 0; n < node_data.size(); ++n ) 130 if ( node_data[n].parent_id == -1 ) 131 delocalize_rec( node_data, n, transform() ); 119 132 } 120 133 121 void delocalize( const data_node_tree& node_data, const skeleton_binding& binding ) 122 { 123 NV_ASSERT( m_transforms.size() == binding.skeleton_size(), "skeleton size wrong!" ); 124 for ( uint32 n = 0; n < node_data.size(); ++n ) 125 if ( node_data[ n ].parent_id == -1 ) 126 delocalize_rec( node_data, binding, n, transform() ); 127 } 134 void delocalize_rec( const data_node_tree& node_data, uint32 id, const transform& parent ); 128 135 129 void delocalize_rec( const data_node_tree& node_data, const skeleton_binding& binding, uint32 id, const transform& parent ); 130 void animate_rec( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, uint32 id, const transform& parent, bool local ); 131 void blend_rec( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, uint32 id, const transform& parent, bool local, float blend ); 132 protected: 136 // void animate_rec( const mesh_nodes_data* node_data, float frame, uint32 id, const transform& parent, bool local ); 137 // void blend_rec( const mesh_nodes_data* node_data, float frame, uint32 id, const transform& parent, bool local, float blend ); 138 // void animate_local( const mesh_nodes_data* node_data, float frame ); 139 // void blend_local( const mesh_nodes_data* node_data, float frame, float blend ); 140 141 // protected: 133 142 dynamic_array< transform > m_transforms; 134 143 }; … … 140 149 const mat4* transforms() const { return m_matrix.data(); } 141 150 size_t size() const { return m_matrix.size(); } 151 void assign( const skeleton_transforms& skeleton, const skeleton_binding& binding, const bone_transforms& bones ); 142 152 void assign( const skeleton_transforms& skeleton, const bone_transforms& binding ); 143 153 void assign( const bone_transforms& binding ); 144 // void animate_( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame );145 154 protected: 146 // void animate_rec( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, uint32 id, const transform& parent );147 // void animate_flat( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame );148 155 149 156 dynamic_array< mat4 > m_matrix; -
trunk/nv/gl/gl_context.hh
r473 r485 52 52 virtual void update( texture t, const void* data ); 53 53 virtual void update( buffer b, const void* data, size_t offset, size_t size ); 54 virtual void update( buffer b, uint32 index, const void* data, size_t offset, size_t size );54 // virtual void update( buffer b, uint32 index, const void* data, size_t offset, size_t size ); 55 55 56 56 virtual void clear( const clear_state& cs ); -
trunk/nv/gl/gl_device.hh
r473 r485 56 56 57 57 virtual int get_attribute_location( program p, const string_view& name, bool fatal = true ) const; 58 virtual bool bind_block( program p, const string_view& name, uint32 index ); 58 59 virtual int get_block_location( program p, const string_view& name, bool fatal = true ) const; 59 60 virtual void prepare_program( program p ); -
trunk/nv/interface/context.hh
r480 r485 95 95 virtual void update( texture, const void* ) = 0; 96 96 virtual void update( buffer, const void*, size_t /*offset*/, size_t /*size*/ ) = 0; 97 virtual void update( buffer, uint32 /*index*/, const void* , size_t /*offset*/, size_t /*size*/ ) = 0;97 // virtual void update( buffer, uint32 /*index*/, const void* , size_t /*offset*/, size_t /*size*/ ) = 0; 98 98 99 99 virtual void clear( const clear_state& cs ) = 0; -
trunk/nv/interface/device.hh
r484 r485 211 211 virtual int get_attribute_location( program p, const string_view& name, bool fatal = true ) const = 0; 212 212 virtual int get_block_location( program p, const string_view& name, bool fatal = true ) const = 0; 213 213 virtual bool bind_block( program p, const string_view& name, uint32 index ) = 0; 214 214 215 215 template < typename T > -
trunk/nv/interface/interpolation_raw.hh
r471 r485 13 13 #include <nv/core/transform.hh> 14 14 #include <nv/stl/math.hh> 15 #include <nv/interface/interpolate.hh> 15 16 #include <nv/interface/data_descriptor.hh> 16 17 … … 29 30 inline uint32 interpolate_raw_quat( float factor, const float* k1, const float* k2, float* result ) 30 31 { 31 *( reinterpret_cast<quat*>(result) ) = interpolate( *( reinterpret_cast<const quat*>(k1) ), *( reinterpret_cast<const quat*>(k2) ), factor );32 *( reinterpret_cast<quat*>(result) ) = math::slerp( *( reinterpret_cast<const quat*>(k1) ), *( reinterpret_cast<const quat*>(k2) ), factor ); 32 33 return 4; 33 34 } -
trunk/nv/interface/mesh_data.hh
r482 r485 61 61 { 62 62 m_name = other.m_name; 63 for ( auto node : other ) 64 m_data.assign( other.m_data ); 63 m_data.assign( other.m_data ); 65 64 } 66 65 … … 81 80 { 82 81 return m_data[i]; 82 } 83 84 bool matches( const data_node_list& other ) const 85 { 86 if ( size() != other.size() ) return false; 87 for ( size_t i = 0; i < size(); ++i ) 88 if ( m_data[i].name != other.m_data[i].name ) return false; 89 return true; 90 } 91 92 sint16 resolve( shash64 name ) const 93 { 94 for ( size_t i = 0; i < size(); ++i ) 95 if ( m_data[i].name == name ) 96 return sint16(i); 97 return -1; 83 98 } 84 99 -
trunk/nv/lib/assimp.hh
r454 r485 17 17 18 18 #if NV_PLATFORM == NV_WINDOWS 19 # define NV_ASSIMP_PATH "assimp 32.dll"19 # define NV_ASSIMP_PATH "assimp.dll" 20 20 #elif NV_PLATFORM == NV_APPLE 21 21 # define NV_ASSIMP_PATH "" -
trunk/nv/stl/math.hh
r471 r485 220 220 }; 221 221 222 template < typename T >223 T interpolate( const T& lhs, const T& rhs, float f )224 {225 return math::mix( lhs, rhs, f );226 }227 228 template <>229 inline quat interpolate( const quat& lhs, const quat& rhs, float f )230 {231 return math::slerp( lhs, rhs, f );232 }233 234 222 template <typename T> 235 223 math::tvec3<T> normalize_safe( -
trunk/nv/stl/math/quaternion.hh
r484 r485 197 197 inline tquat<T> lerp( const tquat<T>& a, const tquat<T>& b, T m ) 198 198 { 199 return a * ( T( 1 ) - m ) + ( b * m ); 199 tquat<T> aa = dot( a, b ) > T( 0 ) ? a : -a; 200 return aa * ( T( 1 ) - m ) + ( b * m ); 200 201 } 201 202 … … 203 204 inline tquat<T> nlerp( const tquat<T>& a, const tquat<T>& b, T m ) 204 205 { 205 tquat<T> result( a * ( T( 1 ) - m ) + ( b * m ) );206 return normalize( result);206 tquat<T> aa = dot( a, b ) > T( 0 ) ? a : -a; 207 return normalize( aa * ( T( 1 ) - m ) + ( b * m ) ); 207 208 } 208 209 … … 210 211 inline tquat<T> slerp( const tquat<T>& x, const tquat<T>& y, T m ) 211 212 { 212 tquat<T> z = y;213 tquat<T> z = x; 213 214 T cos_theta = dot( x, y ); 214 215 if ( cos_theta < T( 0 ) ) 215 216 { 216 z = - y;217 z = -x; 217 218 cos_theta = -cos_theta; 218 219 } … … 220 221 { 221 222 return tquat<T>( 222 mix( x.w, z.w, m ),223 mix( x.x, z.x, m ),224 mix( x.y, z.y, m ),225 mix( x.z, z.z, m ) );223 mix( z.w, y.w, m ), 224 mix( z.x, y.x, m ), 225 mix( z.y, y.y, m ), 226 mix( z.z, y.z, m ) ); 226 227 } 227 228 else 228 229 { 229 230 T angle = nv::acos( cos_theta ); 230 return ( nv::sin( ( T( 1 ) - m ) * angle ) * x + nv::sin( m * angle ) * z ) / nv::sin( angle ); 231 } 232 } 233 234 template < typename T > 235 inline tquat<T> weighted_slerp( const tquat<T>& x, const tquat<T>& y, T m, T m1 ) 236 { 237 tquat<T> z = y; 238 T cos_theta = dot( x, y ); 239 if ( cos_theta < T( 0 ) ) 240 { 241 z = -y; 242 cos_theta = -cos_theta; 243 } 244 if ( cos_theta > T( 1 ) - epsilon<T>() ) 245 { 246 return tquat<T>( 247 x.w * m + z.w * m1, 248 x.x * m + z.x * m1, 249 x.y * m + z.y * m1, 250 x.z * m + z.z * m1 ); 251 } 252 else 253 { 254 T angle = nv::acos( cos_theta ); 255 return ( nv::sin( m1 * angle ) * x + nv::sin( m * angle ) * z ) / nv::sin( angle ); 256 } 257 } 258 231 return ( nv::sin( ( T( 1 ) - m ) * angle ) * z + nv::sin( m * angle ) * y ) / nv::sin( angle ); 232 } 233 } 259 234 260 235 template < typename T > -
trunk/nv/stl/string.hh
r467 r485 100 100 } 101 101 102 inline string_view without_extension( string_view filename ) 103 { 104 size_t lastdot = filename.find_last_of( '.' ); 105 if ( string_view::npos != lastdot ) 106 return filename.substr( 0, lastdot ); 107 return filename; 108 } 109 102 110 struct string_hash_tag {}; 103 111 … … 117 125 inline string_hash( const string_base<S>& rhs ) : inherited_type( hash_string< H >( rhs.data(), rhs.size() ) ) {} 118 126 constexpr string_hash( const char* str, size_t len ) : inherited_type( hash_string< H >( str, len ) ) {} 127 constexpr string_hash( const char* str ) : inherited_type( hash_string< H >( str ) ) {} 119 128 120 129 // Literal constructors -
trunk/nv/stl/string/short_string.hh
r473 r485 45 45 inline string_buffer_base& operator=( string_buffer_base&& other ) = default; 46 46 47 inline string_buffer_base( const string_buffer_base& copy ) 48 { 49 assign( copy.data(), copy.size() ); 50 } 51 52 inline string_buffer_base& operator=( const string_buffer_base& other ) 53 { 54 assign( other.data(), other.size() ); 55 return ( *this ); 56 } 57 58 47 59 using Storage::clear; 48 60 -
trunk/nv/stl/string_table.hh
r432 r485 37 37 string_table( stream& in ); 38 38 void insert( string_table* in ); 39 39 40 key_type insert( const value_type& str ) 40 41 { -
trunk/src/engine/material_manager.cc
r484 r485 21 21 if ( !mat->paths[i].empty() ) 22 22 if ( auto data = m_image_manager->get( mat->paths[i] ).lock() ) 23 { 23 24 result->textures[i] = m_context->get_device()->create_texture( &*data, smp ); 25 } 24 26 add( id, result ); 25 27 return true; -
trunk/src/engine/resource_system.cc
r477 r485 34 34 } 35 35 } 36 -
trunk/src/formats/assimp_loader.cc
r482 r485 12 12 13 13 using namespace nv; 14 15 namespace nv { 16 17 struct assimp_data 18 { 19 const aiScene* scene; 20 vector< const aiBone* > bones; 21 vector< const aiNode* > nodes; 22 vector< const aiMesh* > meshes; 23 vector< const aiNode* > skeletons; 24 25 hash_store< shash64, const aiBone* > bone_by_name; 26 hash_store< shash64, const aiNode* > node_by_name; 27 }; 28 29 } 14 30 15 31 const unsigned MAX_BONES = 64; … … 58 74 59 75 nv::assimp_loader::assimp_loader( string_table* strings, const string_view& a_ext, uint32 a_assimp_flags /*= 0 */ ) 60 : mesh_loader( strings ), m_ scene( nullptr ), m_mesh_count(0)76 : mesh_loader( strings ), m_mesh_count(0) 61 77 { 62 78 m_ext = a_ext; … … 76 92 aiProcess_SortByPType | 77 93 aiProcess_FindDegenerates | 78 aiProcess_Find InvalidData |94 aiProcess_FindDegenerates | 79 95 0 ); 80 96 } 97 m_data = new assimp_data; 98 m_data->scene = nullptr; 81 99 } 82 100 … … 85 103 { 86 104 load_assimp_library(); 87 if ( m_ scene != nullptr ) aiReleaseImport( reinterpret_cast<const aiScene*>( m_scene ));88 m_ scene = nullptr;105 if ( m_data->scene != nullptr ) aiReleaseImport( m_data->scene ); 106 m_data->scene = nullptr; 89 107 m_mesh_count = 0; 90 108 NV_LOG_NOTICE( "AssImp loading file..." ); … … 99 117 return false; 100 118 } 101 m_ scene= scene;102 m_mesh_count = scene->mNumMeshes;119 m_data->scene = scene; 120 m_mesh_count = scene->mNumMeshes; 103 121 NV_LOG_NOTICE( "Loading successfull" ); 122 123 scan_nodes( scene->mRootNode ); 124 125 for ( unsigned i = 0; i < scene->mRootNode->mNumChildren; ++i ) 126 { 127 const aiNode* node = scene->mRootNode->mChildren[i]; 128 if ( node->mNumMeshes == 0 ) 129 m_data->skeletons.push_back( node ); 130 } 131 132 for ( nv::uint32 i = 0; i < m_mesh_count; i++ ) 133 { 134 data_node_info info; 135 data_channel_set* data = data_channel_set_creator::create_set( 2 ); 136 load_mesh_data( data, i, info ); 137 m_meshes.push_back( data ); 138 m_mesh_info.push_back( info ); 139 } 140 141 scene_report(); 104 142 return true; 105 143 } … … 108 146 { 109 147 if ( index >= m_mesh_count ) return nullptr; 110 data_channel_set* result = data_channel_set_creator::create_set( 2 ); 111 load_mesh_data( result, index, info ); 112 return result; 148 info = m_mesh_info[index]; 149 return m_meshes[index]; 113 150 } 114 151 void nv::assimp_loader::load_mesh_data( data_channel_set* data, size_t index, data_node_info& info ) 115 152 { 116 const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene ); 117 const aiMesh* mesh = scene->mMeshes[ index ]; 153 const aiMesh* mesh = m_data->scene->mMeshes[ index ]; 118 154 119 155 bool skinned = mesh->mNumBones > 0; … … 125 161 desc.initialize< assimp_plain_vtx >(); 126 162 data_channel_set_creator maccess( data ); 127 const char* name = mesh->mName.data; 163 string64 name( mesh->mName.data, mesh->mName.length ); 164 if ( mesh->mName.length == 0 ) 165 { 166 for ( auto node : m_data->nodes ) 167 { 168 if ( node->mMeshes ) 169 for ( uint32 i = 0; i < node->mNumMeshes; ++i ) 170 if ( node->mMeshes[i] == index ) 171 { 172 name.assign( node->mName.data, node->mName.length ); 173 if ( i != 0 ) 174 { 175 name.append( "#0" ); 176 name.append( i ); 177 } 178 } 179 180 } 181 } 128 182 info.name = make_name( name ); 129 183 info.parent_id = -1; 184 int hack_for_node_anim; 185 if ( is_node_animated() ) 186 info.parent_id = index; 187 188 130 189 uint8* cdata = maccess.add_channel( desc, mesh->mNumVertices ).raw_data(); 131 190 uint16* indices = reinterpret_cast<uint16*>( maccess.add_channel< index_u16 >( mesh->mNumFaces * 3 ).raw_data() ); … … 188 247 nv::assimp_loader::~assimp_loader() 189 248 { 190 if ( m_scene != nullptr ) aiReleaseImport( reinterpret_cast<const aiScene*>( m_scene ) ); 191 } 192 193 bool nv::assimp_loader::load_bones( size_t index, array_ref< data_node_info > bones ) 194 { 195 if ( m_scene == nullptr ) return false; 196 const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene ); 197 const aiMesh* mesh = scene->mMeshes[ index ]; 198 199 for (unsigned int m=0; m<mesh->mNumBones; m++) 200 { 201 aiBone* bone = mesh->mBones[m]; 202 mat4 offset = assimp_mat4_cast( bone->mOffsetMatrix ); 203 const char* name = bone->mName.data; 204 bones[m].name = make_name( name ); 205 bones[m].transform = offset; 206 } 207 return true; 249 if ( m_data->scene != nullptr ) aiReleaseImport( m_data->scene ); 250 delete m_data; 208 251 } 209 252 210 253 void nv::assimp_loader::scene_report() const 211 254 { 212 const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene ); 213 if ( scene == nullptr ) return; 255 if ( m_data->scene == nullptr ) return; 214 256 215 257 NV_LOG_NOTICE( "------------------------" ); 216 NV_LOG_NOTICE( "Texture count - ", scene->mNumTextures );217 NV_LOG_NOTICE( "Animation count - ", scene->mNumAnimations );218 NV_LOG_NOTICE( "Material count - ", scene->mNumMaterials );219 NV_LOG_NOTICE( "Meshes count - ", scene->mNumMeshes );258 NV_LOG_NOTICE( "Texture count - ", m_data->scene->mNumTextures ); 259 NV_LOG_NOTICE( "Animation count - ", m_data->scene->mNumAnimations ); 260 NV_LOG_NOTICE( "Material count - ", m_data->scene->mNumMaterials ); 261 NV_LOG_NOTICE( "Meshes count - ", m_data->scene->mNumMeshes ); 220 262 NV_LOG_NOTICE( "------------------------" ); 221 263 222 aiNode* root = scene->mRootNode;264 aiNode* root = m_data->scene->mRootNode; 223 265 if (root) 224 266 { … … 233 275 NV_LOG_NOTICE( "------------------------" ); 234 276 235 if ( scene->mNumMeshes > 0 )236 { 237 for ( nv::uint32 mc = 0; mc < scene->mNumMeshes; mc++ )238 { 239 aiMesh* mesh = scene->mMeshes[mc];240 241 NV_LOG_NOTICE( "Mesh #", mc, " - ", string_view( static_cast<char*>( mesh->mName.data ) ) );277 if ( m_data->scene->mNumMeshes > 0 ) 278 { 279 for ( nv::uint32 mc = 0; mc < m_data->scene->mNumMeshes; mc++ ) 280 { 281 aiMesh* mesh = m_data->scene->mMeshes[mc]; 282 283 NV_LOG_NOTICE( "Mesh #", mc, " - ", string_view( static_cast<char*>( mesh->mName.data ), mesh->mName.length ) ); 242 284 NV_LOG_NOTICE( " bones - ", mesh->mNumBones ); 243 285 NV_LOG_NOTICE( " uvs - ", mesh->mNumUVComponents[0] ); … … 259 301 NV_LOG_NOTICE( "------------------------" ); 260 302 303 for ( auto node : m_data->nodes ) 304 { 305 NV_LOG_NOTICE( "Node : ", string_view( node->mName.data, node->mName.length ) ); 306 } 307 308 for ( auto skeleton : m_data->skeletons ) 309 { 310 NV_LOG_NOTICE( "Skeleton : ", string_view( skeleton->mName.data, skeleton->mName.length ) ); 311 } 261 312 262 313 // if ( scene->mNumMaterials > 0 ) … … 283 334 } 284 335 285 data_node_list* nv::assimp_loader::release_merged_bones( data_channel_set* meshes ) 286 { 287 const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene ); 288 data_node_list* result = new data_node_list( make_name( "bones" ) ); 289 hash_store< shash64, uint16 > names; 336 bool nv::assimp_loader::is_node_animated() 337 { 338 return is_animated() && m_data->skeletons.empty(); 339 } 340 341 void nv::assimp_loader::build_skeleton( vector< data_node_info >& skeleton, const void* node, int parent_id ) 342 { 343 const aiNode* ainode = reinterpret_cast<const aiNode*>( node ); 344 345 if ( ainode->mNumMeshes > 0 ) 346 { 347 int error; 348 int bug_this_works_only_if_before_releasing_meshes; 349 350 nv::uint32 mid = ainode->mMeshes[0]; 351 m_mesh_info[mid].parent_id = parent_id; 352 return; 353 } 354 355 string_view name( ainode->mName.data, ainode->mName.length ); 356 if ( name.starts_with( '_' ) ) return; 357 358 data_node_info info; 359 info.name = make_name( name ); 360 info.parent_id = parent_id; 361 362 int this_id = skeleton.size(); 363 skeleton.push_back( info ); 364 for ( unsigned i = 0; i < ainode->mNumChildren; ++i ) 365 { 366 build_skeleton( skeleton, ainode->mChildren[i], this_id ); 367 } 368 } 369 370 data_node_list* nv::assimp_loader::release_merged_bones() 371 { 372 if ( m_data->skeletons.empty() ) return nullptr; 373 vector< data_node_info > bone_data; 374 hash_store< shash64, uint16 > bone_map; 375 376 { 377 const aiNode* skeleton = m_data->skeletons[0]; 378 build_skeleton( bone_data, skeleton, -1 ); 379 380 for ( uint32 i = 0; i < bone_data.size(); ++i ) 381 { 382 bone_map[bone_data[i].name] = uint16(i); 383 } 384 } 385 290 386 for ( unsigned int m = 0; m < m_mesh_count; ++m ) 291 387 { 292 388 uint16 translate[MAX_BONES]; 293 389 vector< data_node_info > bones; 294 const aiMesh* mesh = scene->mMeshes[ m];390 const aiMesh* mesh = m_data->scene->mMeshes[m]; 295 391 if ( mesh->mNumBones != 0 ) 296 392 { 297 bones.resize( mesh->mNumBones ); 298 NV_ASSERT( false, "parent ids for bones are not loaded!" ); 299 load_bones( m, bones ); 300 for ( unsigned int b = 0; b < mesh->mNumBones; ++b ) 393 for ( unsigned int b = 0; b < mesh->mNumBones; b++ ) 301 394 { 302 303 data_node_info bone = bones[b]; 304 auto iname = names.find( bone.name ); 305 if ( iname == names.end() ) 395 aiBone* bone = mesh->mBones[b]; 396 mat4 offset = assimp_mat4_cast( bone->mOffsetMatrix ); 397 shash64 bone_name( bone->mName.data ); 398 399 int remove_this; 400 401 NV_ASSERT( bone_map.find( shash64( bone->mName.data ) ) != bone_map.end(), "BONE NOT FOUND!" ); 402 uint16 index = bone_map[bone_name]; 403 bone_data[index].transform = offset; 404 translate[b] = index; 405 } 406 407 data_channel_access< assimp_skinned_vtx > channel( const_cast<raw_data_channel*>( m_meshes[m]->get_channel( 0 ) ) ); 408 for ( unsigned v = 0; v < channel.size(); ++v ) 409 { 410 assimp_skinned_vtx& vertex = channel.data()[v]; 411 for ( int i = 0; i < 4; ++i ) 306 412 { 307 NV_ASSERT( result->size() < MAX_BONES, "Too many bones to merge!" ); 308 uint16 index = uint16( result->size() ); 309 result->append( bone ); 310 names[ bone.name ] = index; 311 translate[b] = index; 312 } 313 else 314 { 315 translate[b] = iname->second; 316 } 317 } 318 if ( m > 0 && bones.size() > 0 ) 319 { 320 data_channel_access< assimp_skinned_vtx > channel( const_cast< raw_data_channel* >( meshes[m].get_channel(0) ) ); 321 for ( unsigned v = 0; v < channel.size(); ++v ) 322 { 323 assimp_skinned_vtx& vertex = channel.data()[v]; 324 325 for ( int i = 0 ; i < 4; ++i) 413 if ( vertex.boneweight[i] > 0.0f ) 326 414 { 327 if ( vertex.boneweight[i] > 0.0f ) 328 { 329 vertex.boneindex[i] = int( translate[vertex.boneindex[i]] ); 330 } 415 vertex.boneindex[i] = int( translate[vertex.boneindex[i]] ); 331 416 } 332 417 } 333 418 } 334 } 335 } 336 //result->initialize(); 337 338 return result; 419 420 } 421 } 422 423 for ( uint32 i = 0; i < bone_data.size(); ++i ) 424 { 425 int error; // not really, just 426 int check_this_shit; 427 if ( bone_data[i].transform == mat4() ) 428 { 429 mat4 tr = nv::math::inverse( assimp_mat4_cast( m_data->node_by_name[bone_data[i].name]->mTransformation ) ); 430 bone_data[i].transform = tr * bone_data[bone_data[i].parent_id].transform; 431 } 432 // list->append( bone_data[i] ); 433 } 434 435 436 data_node_list* list = new data_node_list( make_name( "bones" ) ); 437 for ( uint32 i = 0; i < bone_data.size(); ++i ) 438 { 439 list->append( bone_data[i] ); 440 } 441 442 return list; 339 443 } 340 444 341 445 mesh_nodes_data* nv::assimp_loader::release_mesh_nodes_data( size_t index /*= 0*/ ) 342 446 { 343 if ( m_ scene == nullptr ) return nullptr;344 const aiScene* scene = reinterpret_cast<const aiScene*>( m_ scene );447 if ( m_data->scene == nullptr ) return nullptr; 448 const aiScene* scene = reinterpret_cast<const aiScene*>( m_data->scene ); 345 449 if ( scene->mRootNode == nullptr || scene->mAnimations == nullptr || scene->mAnimations[index] == nullptr) return nullptr; 346 450 … … 349 453 350 454 uint32 count = count_nodes( scene->mRootNode ); 455 count = count - 1; 351 456 352 457 uint16 frame_rate = static_cast<uint16>( anim->mTicksPerSecond ); 353 uint16 duration = static_cast<uint16>( anim->mDuration ) ;458 uint16 duration = static_cast<uint16>( anim->mDuration )+1; 354 459 355 460 data_channel_set** temp = new data_channel_set*[ count ]; 356 data_node_info* temp2 = new data_node_info[count ];461 data_node_info* temp2 = new data_node_info[count ]; 357 462 array_ref< data_channel_set* > temp_ref( temp, count ); 358 463 array_ref< data_node_info > temp2_ref( temp2, count ); 359 load_node( index, temp_ref, temp2_ref, root, 0, -1 ); 464 465 nv::sint16 next = 0; 466 for ( unsigned i = 0; i < scene->mRootNode->mNumChildren; ++i ) 467 { 468 next = load_node( index, temp_ref, temp2_ref, scene->mRootNode->mChildren[i], next, -1 ); 469 } 470 // load_node( index, temp_ref, temp2_ref, scene->mRootNode, 0, -1 ); 360 471 361 472 mesh_nodes_data* result = new mesh_nodes_data( make_name( static_cast<const char*>( anim->mName.data ) ), frame_rate, duration ); … … 372 483 data_node_list* nv::assimp_loader::release_data_node_list( size_t index /*= 0 */ ) 373 484 { 485 return release_merged_bones(); 486 } 487 488 bool nv::assimp_loader::is_animated( size_t /*= 0 */ ) 489 { 374 490 int this_is_incorrect; 375 NV_ASSERT( false, "unimplemented!" ); 376 // mesh_nodes_data* half_result = release_mesh_nodes_data( index ); 377 // data_node_list* result = new data_node_list( half_result->get_name() ); 378 // for ( auto node : *half_result ) 379 // result->append( node->get_info() ); 380 // delete half_result; 381 // return result; 382 return nullptr; 383 } 384 385 bool nv::assimp_loader::is_animated( size_t /*= 0 */ ) 386 { 387 int this_is_incorrect; 388 return false; 491 return m_mesh_count == 0 || m_data->scene->mNumAnimations > 0 && m_data->skeletons.size() == 0; 492 } 493 494 int indent = 0; 495 496 void nv::assimp_loader::scan_nodes( const void* node ) const 497 { 498 const aiNode* ainode = reinterpret_cast<const aiNode*>( node ); 499 m_data->nodes.push_back( ainode ); 500 m_data->node_by_name[shash64(ainode->mName.data)] = ainode; 501 502 for ( unsigned i = 0; i < ainode->mNumChildren; ++i ) 503 { 504 scan_nodes( ainode->mChildren[i] ); 505 } 389 506 } 390 507 … … 402 519 nv::sint16 nv::assimp_loader::load_node( uint32 anim_id, array_ref< data_channel_set* > nodes, array_ref< data_node_info > infos, const void* vnode, sint16 this_id, sint16 parent_id ) 403 520 { 404 const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );405 521 const aiNode* node = reinterpret_cast<const aiNode*>( vnode ); 406 522 string_view name( static_cast< const char* >( node->mName.data ) ); 407 const aiAnimation* anim = scene->mAnimations[anim_id];523 const aiAnimation* anim = m_data->scene->mAnimations[anim_id]; 408 524 const aiNodeAnim* anode = nullptr; 409 525 … … 415 531 } 416 532 417 nodes[ this_id ] = anode ? create_keys( anode ) : data_channel_set_creator::create_set( 0 ); 533 534 transform t = nv::transform( nv::assimp_mat4_cast( node->mTransformation ) ); 535 536 nodes[ this_id ] = anode ? create_keys( anode, t ) : data_channel_set_creator::create_set( 0 ); 418 537 419 538 infos[this_id].name = make_name( name ); … … 424 543 // node's without keys 425 544 // TODO: this can probably be deleted 426 infos[this_id].transform = nv::assimp_mat4_cast( node->mTransformation ); 427 if ( this_id == 0 ) infos[this_id].transform = mat4(); 545 // infos[this_id].transform = nv::assimp_mat4_cast( node->mTransformation ); 546 // if ( this_id == 0 ) infos[this_id].transform = mat4(); 547 428 548 429 549 nv::sint16 next = this_id + 1; … … 436 556 } 437 557 438 data_channel_set* nv::assimp_loader::create_keys( const void* vnode )439 { 440 const aiNodeAnim* node = reinterpret_cast< const aiNodeAnim* >( vnode );558 data_channel_set* nv::assimp_loader::create_keys( const void* vnode, const transform& tr ) 559 { 560 const aiNodeAnim* node = reinterpret_cast< const aiNodeAnim* >( vnode ); 441 561 if ( node->mNumPositionKeys == 0 && node->mNumRotationKeys == 0 && node->mNumScalingKeys == 0 ) 442 562 { 443 563 return data_channel_set_creator::create_set( 0 ); 444 564 } 445 565 566 /* OLD 446 567 data_channel_set* set = data_channel_set_creator::create_set( 2 ); 447 568 data_channel_set_creator key_set( set ); … … 461 582 rchannel[np].rotation = assimp_quat_cast(node->mRotationKeys[np].mValue ); 462 583 } 584 */ 585 data_channel_set* set = data_channel_set_creator::create_set( 1 ); 586 data_channel_set_creator key_set( set ); 587 588 assimp_key_tr* channel = key_set.add_channel< assimp_key_tr >( node->mNumPositionKeys ).data(); 589 for ( unsigned np = 0; np < node->mNumPositionKeys; ++np ) 590 { 591 channel[np].tform.set_position( assimp_vec3_cast( node->mPositionKeys[np].mValue ) ); 592 channel[np].tform.set_orientation( assimp_quat_cast( node->mRotationKeys[np].mValue ) ); 593 if ( is_node_animated() ) 594 channel[np].tform = tr.inverse() * channel[np].tform ; 595 } 596 463 597 // if ( node->mNumScalingKeys > 0 ) 464 598 // { … … 503 637 nv::size_t nv::assimp_loader::get_nodes_data_count() const 504 638 { 505 if ( m_scene == nullptr ) return 0; 506 const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene ); 507 return scene->mNumAnimations; 508 } 509 510 639 if ( m_data->scene == nullptr ) return 0; 640 return m_data->scene->mNumAnimations; 641 } 642 643 -
trunk/src/formats/nmd_loader.cc
r482 r485 26 26 { 27 27 case nmd_type::MESH : load_mesh( source, element_header ); break; 28 case nmd_type:: ANIMATION : load_animation( source, element_header ); break;28 case nmd_type::BONES : load_bones( source, element_header ); break; 29 29 case nmd_type::STRINGS : load_strings( source ); break; 30 case nmd_type::POSES : load_poses( source, element_header ); break; 30 31 default: NV_ASSERT( false, "UNKNOWN NMD ELEMENT!" ); break; 31 32 } … … 39 40 data_node_info info; 40 41 load_channel_set( source, mesh, info, e ); 41 // m_mesh_names.push_back( e.name );42 42 m_infos.push_back( info ); 43 43 m_meshes.push_back( mesh ); … … 56 56 { 57 57 for ( auto mesh : m_meshes ) if ( mesh ) delete mesh; 58 if ( m_node_data ) delete m_node_data;59 58 if ( m_bone_data ) delete m_bone_data; 59 if ( m_pose_data_set ) delete m_pose_data_set; 60 60 m_meshes.clear(); 61 61 62 m_node_data = nullptr;63 62 m_bone_data = nullptr; 64 63 } … … 85 84 } 86 85 87 bool nv::nmd_loader::load_ animation( stream& source, const nmd_element_header& e )88 { 89 NV_ASSERT( m_ node_data == nullptr, "MULTIPLE NODE ENTRIES!" );86 bool nv::nmd_loader::load_bones( stream& source, const nmd_element_header& e ) 87 { 88 NV_ASSERT( m_bone_data == nullptr, "MULTIPLE NODE ENTRIES!" ); 90 89 nmd_animation_header animation_header; 91 90 source.read( &animation_header, sizeof( animation_header ), 1 ); 92 m_node_data = new mesh_nodes_data( e.name, animation_header.frame_rate, animation_header.frame_count );93 91 m_bone_data = new data_node_list( e.name ); 94 92 for ( uint32 i = 0; i < e.children; ++i ) … … 102 100 load_channel_set( source, set, info, element_header ); 103 101 m_bone_data->append( info ); 104 m_node_data->append( set, info ); 105 } 106 m_node_data->initialize(); 102 delete set; 103 } 107 104 return true; 108 105 } … … 131 128 } 132 129 130 bool nv::nmd_loader::load_poses( stream& source, const nmd_element_header& e ) 131 { 132 if ( m_pose_data_set == nullptr ) 133 { 134 NV_ASSERT_ALWAYS( m_bone_data, "POSES WITHOUT BONES!" ); 135 m_pose_data_set = new pose_data_set; 136 m_pose_data_set->initialize( *m_bone_data ); 137 } 138 139 uint32 count = e.children; 140 shash64 name = e.name; 141 142 auto& set = m_pose_data_set->m_sets[ name ]; 143 NV_ASSERT_ALWAYS( !set.name, "SET REWRITE!" ); 144 set.name = name; 145 set.count = count; 146 set.start = m_pose_data_set->size(); 147 148 for ( uint32 i = 0; i < count; ++i ) 149 { 150 uint32 length = 0; 151 source.read( &length, sizeof( length ), 1 ); 152 m_pose_data_set->m_data.push_back( skeleton_transforms() ); 153 auto& data = m_pose_data_set->m_data.back().m_transforms; 154 data.resize( length ); 155 source.read( &data[0], length * sizeof( transform ), 1 ); 156 } 157 return true; 158 } 159 133 160 mesh_nodes_data* nv::nmd_loader::release_mesh_nodes_data( size_t ) 134 161 { 135 mesh_nodes_data* result = m_node_data; 136 m_node_data = nullptr; 137 return result; 162 return nullptr; 138 163 } 139 164 … … 147 172 bool nv::nmd_loader::is_animated( size_t /*= 0 */ ) 148 173 { 149 if ( !m_node_data ) return false; 150 return m_node_data->is_animated(); 174 return m_pose_data_set != nullptr; 151 175 } 152 176 … … 194 218 } 195 219 196 void nv::nmd_dump_ nodes( stream& stream_out, const mesh_nodes_data& nodes )220 void nv::nmd_dump_bones( stream& stream_out, const data_node_list& nodes ) 197 221 { 198 222 uint32 total = sizeof( nmd_animation_header ); … … 200 224 { 201 225 total += sizeof( nmd_element_header ); 202 for ( uint32 c = 0; c < node->size(); ++c )203 {204 total += sizeof( nmd_channel_header );205 total += node->get_channel( c )->raw_size();206 }207 226 } 208 227 209 228 nmd_element_header header; 210 header.type = nmd_type::ANIMATION; 211 header.children = static_cast<uint16>( nodes.size() ); 212 header.size = total; 213 header.name = nodes.get_name(); 214 header.transform = mat4(); 215 header.parent_id = -1; 216 header.attributes = 0; 217 218 stream_out.write( &header, sizeof( header ), 1 ); 219 220 nmd_animation_header aheader; 221 aheader.frame_rate = nodes.get_fps(); 222 aheader.frame_count = nodes.get_frame_count(); 223 aheader.unused = false; 224 stream_out.write( &aheader, sizeof( aheader ), 1 ); 225 226 for ( uint32 i = 0; i < nodes.size(); ++i ) 227 { 228 nmd_dump_element( stream_out, *nodes[i], nodes.get_info(i), nv::nmd_type::NODE ); 229 } 230 } 231 232 void nv::nmd_dump_bones( stream& stream_out, const data_node_list& nodes ) 233 { 234 uint32 total = sizeof( nmd_animation_header ); 235 for ( auto node : nodes ) 236 { 237 total += sizeof( nmd_element_header ); 238 } 239 240 nmd_element_header header; 241 header.type = nmd_type::ANIMATION; 229 header.type = nmd_type::BONES; 242 230 header.children = static_cast<uint16>( nodes.size() ); 243 231 header.size = total; … … 269 257 } 270 258 259 void nv::nmd_dump_poses( stream& stream_out, const array_view< skeleton_transforms* > poses, shash64 name ) 260 { 261 nmd_element_header pheader; 262 pheader.type = nv::nmd_type::POSES; 263 pheader.children = poses.size(); 264 pheader.size = sizeof( transform ) * poses.size() * ( poses.size() > 0 ? poses[0]->size() : 0 ) 265 + sizeof( uint32 ) * poses.size(); 266 pheader.name = name; 267 pheader.parent_id = -1; 268 pheader.attributes = 0; 269 stream_out.write( &pheader, sizeof( pheader ), 1 ); 270 for ( auto pose : poses ) 271 { 272 uint32 count = pose->size(); 273 stream_out.write( &count, sizeof( count ), 1 ); 274 stream_out.write( pose->xforms(), sizeof( transform ) * count, 1 ); 275 } 276 } 277 278 void nv::nmd_dump_pose( stream& stream_out, const skeleton_transforms& pose, shash64 name ) 279 { 280 nmd_element_header pheader; 281 pheader.type = nv::nmd_type::POSES; 282 pheader.children = 1; 283 pheader.size = sizeof( transform ) * pose.size(); 284 pheader.name = name; 285 pheader.parent_id = -1; 286 pheader.attributes = 0; 287 stream_out.write( &pheader, sizeof( pheader ), 1 ); 288 uint32 count = pose.size(); 289 stream_out.write( &count, sizeof( count ), 1 ); 290 stream_out.write( pose.xforms(), sizeof( transform ) * count, 1 ); 291 } 292 271 293 void nv::nmd_dump_strings( stream& stream_out, const string_table& strings ) 272 294 { … … 282 304 } 283 305 284 void nv::nmd_dump( stream& stream_out, array_view< data_channel_set* > meshes, array_view< data_node_info > infos, const mesh_nodes_data* nodes, const string_table* strings /*= nullptr*/, uint64 name /*= 0 */ )306 void nv::nmd_dump( stream& stream_out, array_view< data_channel_set* > meshes, array_view< data_node_info > infos, const nv::data_node_list* nodes, const string_table* strings /*= nullptr*/, uint64 name /*= 0 */ ) 285 307 { 286 308 uint32 elements = ( strings ? 1 : 0 ) // +1 string array … … 297 319 if ( nodes && nodes->size() > 0 ) 298 320 { 299 nmd_dump_ nodes( stream_out, *nodes );321 nmd_dump_bones( stream_out, *nodes ); 300 322 } 301 323 … … 305 327 } 306 328 } 307 308 void nv::nmd_dump( stream& stream_out, array_view< data_channel_set* > meshes, array_view< data_node_info > infos, const nv::data_node_list* nodes, const string_table* strings /*= nullptr*/, uint64 name /*= 0 */ )309 {310 uint32 elements = ( strings ? 1 : 0 ) // +1 string array311 + meshes.size() // meshes312 + ( nodes && nodes->size() > 0 ? 1 : 0 ); // nodes313 nmd_dump_header( stream_out, elements, name );314 315 for ( uint32 i = 0; i < meshes.size(); ++i )316 {317 NV_ASSERT( meshes[i], "mesh is null!" );318 nmd_dump_element( stream_out, *meshes[i], infos[i], nv::nmd_type::MESH );319 }320 321 if ( nodes && nodes->size() > 0 )322 {323 nmd_dump_bones( stream_out, *nodes );324 }325 326 if ( strings )327 {328 nmd_dump_strings( stream_out, *strings );329 }330 }331 332 void nv::nmd_dump( stream& stream_out, const mesh_nodes_data& animation, const string_table* strings, uint64 name )333 {334 uint32 elements = ( strings ? 1 : 0 ) // +1 string array335 + ( animation.size() > 0 ? 1 : 0 ); // nodes336 nmd_dump_header( stream_out, elements, name );337 338 if ( animation.size() > 0 )339 {340 nmd_dump_nodes( stream_out, animation );341 }342 343 if ( strings )344 {345 nmd_dump_strings( stream_out, *strings );346 }347 } -
trunk/src/gfx/skeleton_instance.cc
r484 r485 8 8 9 9 #include "nv/core/profiler.hh" 10 11 void nv::skeleton_binding::assign( const skeleton_binding& other ) 12 { 13 m_indices.assign( other.m_indices ); 14 m_key = other.m_key; 15 m_bone_count = other.m_bone_count; 16 } 10 17 11 18 void nv::skeleton_binding::prepare( const mesh_nodes_data* node_data, const data_node_list& bone_data ) … … 45 52 } 46 53 54 void nv::skeleton_binding::prepare( const data_node_list& pose_data, const data_node_list& bone_data ) 55 { 56 if ( m_indices.empty() ) 57 { 58 // TODO: either fixed size struct or static allocator 59 hash_store< shash64, uint16 > bone_names; 60 m_indices.resize( pose_data.size() ); 61 62 for ( nv::uint16 bi = 0; bi < bone_data.size(); ++bi ) 63 bone_names[bone_data[bi].name] = bi; 64 65 for ( uint32 n = 0; n < pose_data.size(); ++n ) 66 { 67 sint16 bone_id = -1; 68 auto bi = bone_names.find( pose_data[ n ].name ); 69 if ( bi != bone_names.end() ) 70 { 71 bone_id = sint16( bi->second ); 72 } 73 m_indices[n] = bone_id; 74 75 } 76 m_bone_count = bone_data.size(); 77 } 78 } 79 80 81 void nv::skeleton_instance::assign( const skeleton_transforms& skeleton, const skeleton_binding& binding, const bone_transforms& bones ) 82 { 83 if ( bones.size() != m_matrix.size() ) 84 m_matrix.resize( bones.size() ); 85 const transform* transforms = skeleton.xforms(); 86 for ( uint32 n = 0; n < skeleton.size(); ++n ) 87 { 88 sint16 bone_id = binding.m_indices[n]; 89 if ( bone_id >= 0 ) 90 { 91 int too_complex; 92 transform tr( bones.m_offsets[bone_id] ); 93 tr.set_orientation( normalize( tr.get_orientation() ) ); 94 m_matrix[bone_id] = ( transforms[n] * tr ).extract(); 95 } 96 } 97 } 98 99 47 100 void nv::skeleton_instance::assign( const skeleton_transforms& skeleton, const bone_transforms& bones ) 48 101 { 49 102 if ( bones.size() != m_matrix.size() ) 50 103 m_matrix.resize( bones.size() ); 51 const transform* transforms = skeleton. transforms();104 const transform* transforms = skeleton.xforms(); 52 105 for ( uint32 n = 0; n < skeleton.size(); ++n ) 53 106 { … … 90 143 } 91 144 92 if ( m_transforms.size() > 0 )93 m_transforms[0] = nv::interpolate( a.m_transforms[0], b.m_transforms[0], t);145 // if ( m_transforms.size() > 0 ) 146 // m_transforms[0] = nv::interpolate( a.m_transforms[0], b.m_transforms[0], t, interpolation::SPHERICAL ); 94 147 } 95 148 … … 107 160 ); 108 161 } 109 110 if ( m_transforms.size() > 0 )111 m_transforms[0] = nv::interpolate( a.m_transforms[0], b.m_transforms[0], t );112 162 } 113 163 … … 120 170 for ( uint32 n = 0; n < a.size(); ++n ) 121 171 { 122 m_transforms[n] = nv::interpolate( a.m_transforms[n], b.m_transforms[n], t ); 123 } 124 } 172 m_transforms[n] = nv::interpolate( a.m_transforms[n], b.m_transforms[n], t, interpolation::SPHERICAL ); 173 } 174 } 175 176 void nv::skeleton_transforms::blend_slerp( const skeleton_transforms& a, const skeleton_transforms& b, float t, float blend ) 177 { 178 NV_ASSERT( a.size() == b.size(), "!!!" ); 179 if ( m_transforms.size() != a.size() ) 180 m_transforms.resize( a.size() ); 181 for ( uint32 n = 0; n < a.size(); ++n ) 182 { 183 transform tr = nv::interpolate( a.m_transforms[n], b.m_transforms[n], t, interpolation::SPHERICAL ); 184 m_transforms[n] = nv::interpolate( m_transforms[n], tr, blend, interpolation::SPHERICAL ); 185 } 186 } 187 188 125 189 126 190 void nv::skeleton_transforms::interpolate4( const skeleton_transforms& s1, const skeleton_transforms& v1, const skeleton_transforms& v2, const skeleton_transforms& s2, float t ) … … 155 219 qr = normalize( qr ); 156 220 157 if ( n == 0 )158 qr = nv::math::slerp( v1.m_transforms[n].get_orientation(), v2.m_transforms[n].get_orientation(), t );159 160 221 m_transforms[n] = transform( 161 222 weights[0] * s1.m_transforms[n].get_position() + … … 181 242 nv::quat ss1 = s1.m_transforms[n].get_orientation(); 182 243 nv::quat ss2 = s2.m_transforms[n].get_orientation(); 244 nv::quat sv1 = v1.m_transforms[n].get_orientation(); 245 nv::quat sv2 = v2.m_transforms[n].get_orientation(); 246 183 247 nv::quat q = normalize( nv::math::squad( 184 v1.m_transforms[n].get_orientation(), 185 v2.m_transforms[n].get_orientation(), 186 nv::math::intermediate( ss1, v1.m_transforms[n].get_orientation(), v2.m_transforms[n].get_orientation() ), 187 nv::math::intermediate( v1.m_transforms[n].get_orientation(), v2.m_transforms[n].get_orientation(), ss2 ), 248 sv1, sv2, 249 nv::math::intermediate( ss1, sv1, sv2 ), 250 nv::math::intermediate( sv1, sv2, ss2 ), 188 251 t ) ); 189 if ( n == 0 ) q = nv::math::slerp(190 v1.m_transforms[n].get_orientation(),191 v2.m_transforms[n].get_orientation(), t );192 252 193 253 m_transforms[n] = transform( … … 196 256 ); 197 257 } 198 258 199 259 } 200 260 … … 204 264 } 205 265 206 void nv::skeleton_transforms::animate_local( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame ) 207 { 208 if ( m_transforms.size() != binding.skeleton_size() ) 209 m_transforms.resize( binding.skeleton_size() ); 210 for ( uint32 n = 0; n < node_data->size(); ++n ) 211 { 212 const data_channel_set* node = ( *node_data )[n]; 213 sint16 bone_id = binding.m_indices[n]; 214 if ( bone_id >= 0 ) 215 { 216 if ( node->size() > 0 ) 217 { 218 m_transforms[bone_id] = raw_channel_interpolator( node, binding.m_key ).get< transform >( frame ); 219 } 220 int confirm_that_not_needed; 221 // else 222 // m_transforms[bone_id] = transform( node->get_transform() ); 223 } 224 } 225 } 226 227 void nv::skeleton_transforms::blend_local( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, float blend ) 228 { 229 if ( m_transforms.size() != binding.skeleton_size() ) 230 m_transforms.resize( binding.skeleton_size() ); 231 for ( uint32 n = 0; n < node_data->size(); ++n ) 232 { 233 const data_channel_set* node = ( *node_data )[n]; 234 sint16 bone_id = binding.m_indices[n]; 235 if ( bone_id >= 0 ) 236 { 237 238 transform tr = node->size() > 0 ? raw_channel_interpolator( node, binding.m_key ).get< transform >( frame ) : transform( /*node->get_transform()*/ ); int confirm_that_not_needed; 239 m_transforms[bone_id] = nv::interpolate( m_transforms[bone_id], tr, blend ); 240 } 241 } 242 } 243 244 void nv::skeleton_transforms::delocalize_rec( const data_node_tree& node_data, const skeleton_binding& binding, uint32 id, const transform& parent ) 245 { 246 sint16 bone_id = binding.m_indices[id]; 266 // void nv::skeleton_transforms::blend_local( const mesh_nodes_data* node_data, float frame, float blend ) 267 // { 268 // if ( m_transforms.size() != node_data->size() ) 269 // m_transforms.resize( node_data->size() ); 270 // for ( uint32 n = 0; n < node_data->size(); ++n ) 271 // { 272 // const data_channel_set* node = ( *node_data )[n]; 273 // int inefficient_store_key; 274 // 275 // transform tr = node->size() > 0 ? raw_channel_interpolator( node ).get< transform >( frame ) : transform( /*node->get_transform()*/ ); int confirm_that_not_needed; 276 // m_transforms[n] = nv::interpolate( m_transforms[n], tr, blend, interpolation::SPHERICAL ); 277 // } 278 // } 279 // 280 // void nv::skeleton_transforms::animate_local( const mesh_nodes_data* node_data, float frame ) 281 // { 282 // if ( m_transforms.size() != node_data->size() ) 283 // m_transforms.resize( node_data->size() ); 284 // for ( uint32 n = 0; n < node_data->size(); ++n ) 285 // { 286 // const data_channel_set* node = ( *node_data )[n]; 287 // if ( node->size() > 0 ) 288 // { 289 // int inefficient_store_key; 290 // m_transforms[n] = raw_channel_interpolator( node ).get< transform >( frame ); 291 // } 292 // } 293 // } 294 295 void nv::skeleton_transforms::delocalize_rec( const data_node_tree& node_data, uint32 id, const transform& parent ) 296 { 247 297 transform global_mat = parent; 248 if ( bone_id >= 0 ) 249 { 250 global_mat *= m_transforms[bone_id]; 251 m_transforms[bone_id] = global_mat; 252 } 298 global_mat *= m_transforms[id]; 299 m_transforms[id] = global_mat; 253 300 for ( auto child : node_data.children( id ) ) 254 301 { 255 delocalize_rec( node_data, binding, child, global_mat ); 256 } 257 } 258 259 void nv::skeleton_transforms::animate_rec( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, uint32 id, const transform& parent, bool local ) 260 { 261 const data_channel_set* node = ( *node_data )[id]; 262 transform node_mat; 263 264 if ( node->size() > 0 ) 265 node_mat = raw_channel_interpolator( node, binding.m_key ).get< transform >( frame ); 266 int confirm_that_not_needed; 267 // else 268 // node_mat = transform( node->get_transform() ); 269 sint16 bone_id = binding.m_indices[id]; 270 transform global_mat = parent * node_mat; 271 if ( bone_id >= 0 ) 272 { 273 m_transforms[bone_id] = local ? node_mat : global_mat; 274 } 275 for ( auto child : node_data->children( id ) ) 276 { 277 animate_rec( node_data, binding, frame, child, global_mat, local ); 278 } 279 } 280 281 void nv::skeleton_transforms::blend_rec( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, uint32 id, const transform& parent, bool local, float blend ) 282 { 283 const data_channel_set* node = ( *node_data )[id]; 284 int confirm_that_not_needed; 285 transform node_mat/*( node->get_transform() )*/; 286 287 if ( node->size() > 0 ) 288 { 289 raw_channel_interpolator interpolator( node, binding.m_key ); 290 node_mat = interpolator.get< transform >( frame ); 291 } 292 sint16 bone_id = binding.m_indices[id]; 293 transform global_mat = parent * node_mat; 294 if ( bone_id >= 0 ) 295 { 296 m_transforms[bone_id] = nv::interpolate( m_transforms[bone_id], local ? node_mat : global_mat, blend ); 297 } 298 for ( auto child : node_data->children( id ) ) 299 { 300 blend_rec( node_data, binding, frame, child, global_mat, local, blend ); 301 } 302 } 303 302 delocalize_rec( node_data, child, global_mat ); 303 } 304 } 305 306 // void nv::skeleton_transforms::blend_rec( const mesh_nodes_data* node_data, float frame, uint32 id, const transform& parent, bool local, float blend ) 307 // { 308 // const data_channel_set* node = ( *node_data )[id]; 309 // int confirm_that_not_needed; 310 // transform node_mat/*( node->get_transform() )*/; 311 // 312 // if ( node->size() > 0 ) 313 // { 314 // int inefficient_store_key; 315 // 316 // raw_channel_interpolator interpolator( node ); 317 // node_mat = interpolator.get< transform >( frame ); 318 // } 319 // transform global_mat = parent * node_mat; 320 // m_transforms[id] = nv::interpolate( m_transforms[id], local ? node_mat : global_mat, blend, interpolation::SPHERICAL ); 321 // for ( auto child : node_data->children( id ) ) 322 // { 323 // blend_rec( node_data, frame, child, global_mat, local, blend ); 324 // } 325 // 326 // } 327 // 328 // void nv::skeleton_transforms::animate_rec( const mesh_nodes_data* node_data, float frame, uint32 id, const transform& parent, bool local ) 329 // { 330 // const data_channel_set* node = ( *node_data )[id]; 331 // transform node_mat; 332 // int inefficient_store_key; 333 // 334 // if ( node->size() > 0 ) 335 // node_mat = raw_channel_interpolator( node ).get< transform >( frame ); 336 // int confirm_that_not_needed; 337 // // else 338 // // node_mat = transform( node->get_transform() ); 339 // transform global_mat = parent * node_mat; 340 // m_transforms[id] = local ? node_mat : global_mat; 341 // for ( auto child : node_data->children( id ) ) 342 // { 343 // animate_rec( node_data, frame, child, global_mat, local ); 344 // } 345 // 346 // } 304 347 305 348 void nv::bone_transforms::prepare( const data_node_list& bone_data ) -
trunk/src/gl/gl_context.cc
r473 r485 354 354 } 355 355 356 void nv::gl_context::update( buffer b, uint32 index, const void* data, size_t offset, size_t size )357 {358 const gl_buffer_info* info = static_cast<const gl_buffer_info*>( m_device->get_buffer_info( b ) );359 if ( info )360 {361 GLenum glenum = buffer_type_to_enum( info->type );362 if ( size == 0 )363 glBindBufferBase( glenum, index, info->glid );364 else365 glBindBufferRange( glenum, index, info->glid, offset, size );366 glBufferSubData( glenum, GLintptr( offset ), GLsizeiptr( size ), data );367 }368 }356 // void nv::gl_context::update( buffer b, uint32 index, const void* data, size_t offset, size_t size ) 357 // { 358 // const gl_buffer_info* info = static_cast<const gl_buffer_info*>( m_device->get_buffer_info( b ) ); 359 // if ( info ) 360 // { 361 // GLenum glenum = buffer_type_to_enum( info->type ); 362 // if ( size == 0 ) 363 // glBindBufferBase( glenum, index, info->glid ); 364 // else 365 // glBindBufferRange( glenum, index, info->glid, offset, size ); 366 // glBufferSubData( glenum, GLintptr( offset ), GLsizeiptr( size ), data ); 367 // } 368 // } 369 369 370 370 void gl_context::update( buffer b, const void* data, nv::size_t offset, nv::size_t size ) -
trunk/src/gl/gl_device.cc
r477 r485 340 340 } 341 341 342 bool nv::gl_device::bind_block( program p, const string_view& name, uint32 index ) 343 { 344 const gl_program_info* info = m_programs.get( p ); 345 if ( info ) 346 { 347 int id = get_block_location( p, name, false ); 348 if ( id < 0 ) return false; 349 glUniformBlockBinding( info->glid, unsigned( id ), index ); 350 return true; 351 } 352 return false; 353 } 354 342 355 int nv::gl_device::get_block_location( program p, const string_view& name, bool fatal /*= true */ ) const 343 356 { 357 const gl_program_info* info = m_programs.get( p ); 358 if ( info ) 359 { 360 int result = glGetUniformBlockIndex( info->glid, name.data() ); 361 if ( result >= 0 ) return result; 362 if ( fatal ) 363 { 364 NV_LOG_CRITICAL( "gl_device : block '", name, "' not found in program!" ); 365 NV_ABORT( "gl_device : block not found!" ); 366 } 367 } 344 368 return -1; 345 369 }
Note: See TracChangeset
for help on using the changeset viewer.