class_name RSMFormat ## Byte Length: 4 [br] ## GRAT var signature: String = "GRSM" ## Byte Type: u8 [br] ## Byte Length: 2 var version: Version ## Byte Type: u32 [br] ## Byte Length: 4 var animation_length: int ## Byte Type: u32 [br] ## Byte Length: 4 var shade_type: int ## Byte Type: u8 [br] ## Byte Length: 1 ## Versions: [>=1.4] var alpha: int ## Byte Type: u8 [br] ## Byte Length: 16 ## Versions: [<2.2] var reserved: PackedByteArray ## Byte Type: f32 [br] ## Byte Length: 4 ## Versions: [>=2.2] var frames_per_second: float ## Byte Type: u32 [br] ## Byte Length: 4 ## Versions: [<2.3] var texture_count: int ## Length: [member texture_count] ## Byte Length: 40 ## Versions: [<2.3] var texture_names: Array[String] ## Byte Type: u8 ## Byte Length: 40 ## Versions: [<2.2] var root_node_name: String ## Byte Type: u32 [br] ## Byte Length: 4 ## Versions: [>=2.2] var root_node_count: int ## Length: [member root_node_count] ## Byte Length: 40 var root_node_names: Array[String] ## Byte Type: u32 [br] ## Byte Length: 4 var node_count: int ## Length: [member node_count] var nodes: Array[ModelNode] static func from_bytes(bytes: ByteStream) -> RSMFormat: var rsm_format = RSMFormat.new() bytes.advance(rsm_format.signature.length()) @warning_ignore("shadowed_variable") var version = Version.new() version.major = bytes.decode_u8() version.minor = bytes.decode_u8() rsm_format.version = version rsm_format.animation_length = bytes.decode_u32() rsm_format.shade_type = bytes.decode_u32() if version.higher_than(1, 3): # >= 1.4 rsm_format.alpha = bytes.decode_u8() if version.lower_than(2, 2): # < 2.2 rsm_format.reserved = bytes.get_buffer(16).bytes if version.higher_than(2, 1): # >= 2.2 rsm_format.frames_per_second = bytes.decode_float() if version.lower_than(2, 3): # < 2.3 rsm_format.texture_count = bytes.decode_u32() rsm_format.texture_names = [] as Array[String] for _n in rsm_format.texture_count: rsm_format.texture_names.append(bytes.get_string_from_ascii(40)) if version.lower_than(2, 2): rsm_format.root_node_name = bytes.get_string_from_ascii(40) if version.higher_than(2, 1): # >= 2.2 rsm_format.root_node_count = bytes.decode_u32() rsm_format.root_node_names = [] as Array[String] for _n in rsm_format.root_node_count: rsm_format.root_node_names.append(bytes.get_string_from_ascii(40)) rsm_format.node_count = bytes.decode_u32() rsm_format.nodes = [] as Array[ModelNode] for _n in rsm_format.node_count: rsm_format.nodes.append(ModelNode.from_bytes(bytes, version)) #print(inst_to_dict(rsm_format)) #print(inst_to_dict(rsm_format.nodes[0].texture_coordinates[0])) #rsm_format.nodes[0].texture_coordinates.clear() #print(inst_to_dict(rsm_format.nodes[0].faces[0])) #rsm_format.nodes[0].faces.clear() #print(inst_to_dict(rsm_format.nodes[0])) return rsm_format func convert(data_path: String) -> Node3D: var root_node := Node3D.new() root_node.name = root_node_name #node.set_script(load("res://extractor/model.gd")) for model_node in nodes: var node: Node = model_node.convert(texture_names, data_path) root_node.add_child(node) return root_node class ModelNode: ## Byte Type: u8 [br] ## Byte Length: 40 var node_name: String ## Byte Type: u8 [br] ## Byte Length: 40 var parent_node_name: String ## Byte Type: u32 [br] ## Byte Length: 4 [br] ## Versions: [<2.3] var texture_count: int ## Byte Type: u32 [br] ## Byte Length: 4 [br] ## Length: [member texture_count] [br] ## Versions: [<2.3] var texture_indices: Array[int] ## Byte Type: u32 [br] ## Byte Length: 4 [br] ## Versions: [>=2.3] var texture_name_count: int ## Byte Length: 40 [br] ## Length: [member texture_name_count] [br] ## Versions: [>=2.3] var texture_names: Array[String] ## Byte Type: f32 [br] ## Byte Length: 4 * 9 [br] ## Length: 9 [br] ## 3 x 3 Matrix. Each element represents a column. var offset_matrix: Array[Vector3] ## Byte Type: f32 [br] ## Byte Length: 4 * 3 [br] ## Versions: [<2.2] var translation_1: Vector3 ## Byte Type: f32 [br] ## Byte Length: 4 * 3 [br] var translation_2: Vector3 ## Byte Type: f32 [br] ## Byte Length: 4 [br] ## Versions: [<2.2] var rotation_angle: float ## Byte Type: f32 [br] ## Byte Length: 4 * 3 [br] ## Versions: [<2.2] var rotation_axis: Vector3 ## Byte Type: f32 [br] ## Byte Length: 4 * 3 [br] ## Versions: [<2.2] var scale: Vector3 ## Byte Type: u32 [br] ## Byte Length: 4 var vertex_position_count: int ## Byte Type: f32 [br] ## Byte Length: 4 * 3 * [member vertex_position_count] [br] ## Length: [member vertex_position_count] var vertex_positions: Array[Vector3] ## Byte Type: u32 [br] ## Byte Length: 4 var texture_coordinate_count: int ## Length: [member texture_coordinate_count] var texture_coordinates: Array[TextureCoordinate] ## Byte Type: u32 [br] ## Byte Length: 4 var face_count: int ## Length: [member face_count] var faces: Array[Face] ## Byte Type: u32 [br] ## Byte Length: 4 ## Versions: [>=1.6] var scale_keyframe_count: int ## Length: [member scale_keyframe_count] ## Versions: [>=1.6] var scale_keyframes: Array[ScaleKeyframe] ## Byte Type: u32 [br] ## Byte Length: 4 var rotation_keyframe_count: int ## Length: [member scale_keyframe_count] var rotation_keyframes: Array[RotationKeyframe] ## Byte Type: u32 [br] ## Byte Length: 4 ## Versions: [>=2.2] var translation_keyframe_count: int ## Length: [member scale_keyframe_count] ## Versions: [>=2.2] var translation_keyframes: Array[TranslationKeyframe] ## Byte Type: u32 [br] ## Byte Length: 4 ## Versions: [>=2.3] var textures_keyframe_count: int ## Length: [member scale_keyframe_count] ## Versions: [>=2.3] var textures_keyframes: Array[TexturesKeyframe] static func from_bytes(bytes: ByteStream, version: Version) -> ModelNode: var node = ModelNode.new() node.node_name = bytes.get_string_from_utf8(40) node.parent_node_name = bytes.get_string_from_ascii(40) if version.lower_than(2, 3): # < 2.3 node.texture_count = bytes.decode_u32() node.texture_indices = [] as Array[int] for _n in node.texture_count: node.texture_indices.append(bytes.decode_u32()) if version.higher_than(2, 2): # >= 2.3 node.texture_name_count = bytes.decode_u32() node.texture_names = [] as Array[String] for _n in node.texture_name_count: node.texture_names.append(bytes.get_string_from_ascii(40)) node.offset_matrix = [] as Array[Vector3] for _in in 3: node.offset_matrix.append(Vector3( bytes.decode_float(), bytes.decode_float(), bytes.decode_float() )) if version.lower_than(2, 2): node.translation_1 = Vector3( bytes.decode_float(), bytes.decode_float(), bytes.decode_float() ) node.translation_2 = Vector3( bytes.decode_float(), bytes.decode_float(), bytes.decode_float() ) if version.lower_than(2, 2): node.rotation_angle = bytes.decode_float() node.rotation_axis = Vector3( bytes.decode_float(), bytes.decode_float(), bytes.decode_float() ) node.scale = Vector3( bytes.decode_float(), bytes.decode_float(), bytes.decode_float() ) node.vertex_position_count = bytes.decode_u32() node.vertex_positions = [] as Array[Vector3] for _n in node.vertex_position_count: node.vertex_positions.append(Vector3( bytes.decode_float(), bytes.decode_float(), bytes.decode_float() )) node.texture_coordinate_count = bytes.decode_u32() node.texture_coordinates = [] as Array[TextureCoordinate] for _n in node.texture_coordinate_count: node.texture_coordinates.append(TextureCoordinate.from_bytes(bytes, version)) node.face_count = bytes.decode_u32() node.faces = [] as Array[Face] for _n in node.face_count: node.faces.append(Face.from_bytes(bytes, version)) if version.higher_than(1, 5): # >= 1.6 node.scale_keyframe_count = bytes.decode_u32() node.scale_keyframes = [] as Array[ScaleKeyframe] for _n in node.scale_keyframe_count: node.scale_keyframes.append(ScaleKeyframe.from_bytes(bytes)) node.rotation_keyframe_count = bytes.decode_u32() node.rotation_keyframes = [] as Array[RotationKeyframe] for _n in node.rotation_keyframe_count: node.rotation_keyframes.append(RotationKeyframe.from_bytes(bytes)) if version.higher_than(2, 1): # >= 2.2 node.translation_keyframe_count = bytes.decode_u32() node.translation_keyframes = [] as Array[ScaleKeyframe] for _n in node.translation_keyframe_count: node.translation_keyframes.append(TranslationKeyframe.from_bytes(bytes)) if version.higher_than(2, 2): # >= 2.3 node.textures_keyframe_count = bytes.decode_u32() node.textures_keyframes = [] as Array[TexturesKeyframe] for _n in node.textures_keyframe_count: node.textures_keyframes.append(TexturesKeyframe.from_bytes(bytes)) return node func convert(textures: Array[String], data_path: String): var node := MeshInstance3D.new() node.name = node_name node.translate(translation_2) if rotation_axis != Vector3.ZERO: node.rotate(rotation_axis, rotation_angle) node.scale = scale var surface_tool := SurfaceTool.new() surface_tool.begin(Mesh.PRIMITIVE_TRIANGLES) var mesh := ArrayMesh.new() for idx in faces.size(): var face := faces[idx] surface_tool.add_triangle_fan( PackedVector3Array(face.vertex_position_indices.map(func(idx): return vertex_positions[idx]) ), PackedVector2Array(face.texture_coordinate_indices.map(func(idx): return texture_coordinates[idx].coordinates) ) ) surface_tool.commit(mesh) var material := StandardMaterial3D.new() material.albedo_texture = load("%s/data/texture/%s" % [data_path, textures[face.texture_index]]) mesh.surface_set_material(idx, material) node.mesh = mesh return node class TextureCoordinate: ## Byte Type: u32 [br] ## Byte Length: 4 [br] ## Versions: [>=1.2] var color: int ## Byte Type: f32 [br] ## Byte Length: 4 * 2 [br] ## Note: possibly wrong if version < 1.2 var coordinates: Vector2 static func from_bytes(bytes: ByteStream, version: Version) -> TextureCoordinate: var data = TextureCoordinate.new() if version.higher_than(1, 1): data.color = bytes.decode_u32() data.coordinates = Vector2( bytes.decode_float(), bytes.decode_float() ) return data class Face: ## Byte Type: u32 [br] ## Byte Length: 4 [br] ## Versions: [>=2.2] var length: int ## Byte Type: u16 [br] ## Byte Length: 2 * 3 ## Length: 3 var vertex_position_indices: Array[int] ## Byte Type: u16 [br] ## Byte Length: 2 * 3 ## Length: 3 var texture_coordinate_indices: Array[int] ## Byte Type: u16 [br] ## Byte Length: 2 var texture_index: int ## Byte Type: u16 [br] ## Byte Length: 2 var padding: int ## Byte Type: i32 [br] ## Byte Length: 4 var two_sided: int ## Byte Type: i32 [br] ## Byte Length: 4 var smooth_group: int ## Byte Type: i32 [br] ## Length: ([member length] - 24) / 4 [br] ## Versions: [>=2.2] # TODO: saturating_sub? var smooth_group_extra: Array[int] static func from_bytes(bytes: ByteStream, version: Version) -> Face: var data = Face.new() if version.higher_than(2, 1): data.length = bytes.decode_u32() data.vertex_position_indices = [] as Array[int] for _in in 3: data.vertex_position_indices.append(bytes.decode_u16()) data.texture_coordinate_indices = [] as Array[int] for _in in 3: data.texture_coordinate_indices.append(bytes.decode_u16()) data.texture_index = bytes.decode_u16() data.padding = bytes.decode_u16() data.two_sided = bytes.decode_s32() data.smooth_group = bytes.decode_s32() if version.higher_than(2, 1): data.smooth_group_extra = [] as Array[int] for _n in ((data.length - 24) / 4): data.smooth_group_extra.append(bytes.decode_s32()) return data class ScaleKeyframe: ## Byte Type: u32 [br] ## Byte Length: 4 [br] var frame: int ## Byte Type: f32 [br] ## Byte Length: 4 * 3 [br] var scale: Vector3 ## Byte Type: f32 [br] ## Byte Length: 4 [br] var reserved: float static func from_bytes(bytes: ByteStream) -> ScaleKeyframe: var data = ScaleKeyframe.new() data.frame = bytes.decode_u32() data.scale = Vector3( bytes.decode_float(), bytes.decode_float(), bytes.decode_float() ) data.reserved = bytes.decode_float() return data class RotationKeyframe: ## Byte Type: u32 [br] ## Byte Length: 4 [br] var frame: int ## Byte Type: f32 [br] ## Byte Length: 4 * 3 [br] var rotation: Vector4 static func from_bytes(bytes: ByteStream) -> RotationKeyframe: var data = RotationKeyframe.new() data.frame = bytes.decode_u32() data.rotation = Vector4( bytes.decode_float(), bytes.decode_float(), bytes.decode_float(), bytes.decode_float() ) return data class TranslationKeyframe: ## Byte Type: u32 [br] ## Byte Length: 4 [br] var frame: int ## Byte Type: f32 [br] ## Byte Length: 4 * 3 [br] var translation: Vector3 ## Byte Type: f32 [br] ## Byte Length: 4 [br] var reserved: float static func from_bytes(bytes: ByteStream) -> ScaleKeyframe: var data = ScaleKeyframe.new() data.frame = bytes.decode_u32() data.translation = Vector3( bytes.decode_float(), bytes.decode_float(), bytes.decode_float() ) data.reserved = bytes.decode_float() return data enum TextureOperation { ## Texture translation on the X axis. The texture is tiled. Translation_X, ## Texture translation on the Y axis. The texture is tiled. Translation_Y, ## Texture multiplication on the X axis. The texture is tiled. Scale_X, ## Texture multiplication on the Y axis. The texture is tiled. Scale_Y, ## Texture rotation around (0, 0). The texture is not tiled. Rotation, } class TexturesKeyframe: ## Byte Type: u32 [br] ## Byte Length: 4 var texture_index: int ## Byte Type: u32 [br] ## Byte Length: 4 var texture_keyframe_count: int ## Length: [member texture_keyframe_count] var texture_keyframes: Array[TextureKeyframe] static func from_bytes(bytes: ByteStream) -> TexturesKeyframe: var data = TexturesKeyframe.new() data.texture_index = bytes.decode_u32() data.texture_keyframe_count = bytes.decode_u32() data.texture_keyframes = [] as Array[TextureKeyframe] for _n in data.texture_keyframe_count: data.texture_keyframes.append(TextureKeyframe.from_bytes(bytes)) return data class TextureKeyframe: ## Byte Type: u8 var operation_type: TextureOperation ## Byte Type: u32 [br] ## Byte Length: 4 var frame_count: int ## Length: [member frame_count] var texture_frames: Array[TextureFrame] static func from_bytes(bytes: ByteStream) -> TextureKeyframe: var data = TextureKeyframe.new() data.operation_type = bytes.decode_u8() data.frame_count = bytes.decode_u32() data.texture_frames = [] as Array[TextureFrame] for _n in data.frame_count: data.texture_frames.append(TextureFrame.from_bytes(bytes)) return data class TextureFrame: ## Byte Type: u32 [br] ## Byte Length: 4 [br] var frame: int ## Byte Type: f32 [br] ## Byte Length: 4 [br] var translation: float static func from_bytes(bytes: ByteStream) -> TextureFrame: var data = TextureFrame.new() data.frame = bytes.decode_u32() data.translation = bytes.decode_float() return data