diff options
Diffstat (limited to 'extractor/rsm_format.gd')
-rw-r--r-- | extractor/rsm_format.gd | 653 |
1 files changed, 653 insertions, 0 deletions
diff --git a/extractor/rsm_format.gd b/extractor/rsm_format.gd new file mode 100644 index 0000000..7f16368 --- /dev/null +++ b/extractor/rsm_format.gd @@ -0,0 +1,653 @@ +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_ro(40)) + + if version.lower_than(2, 2): + rsm_format.root_node_name = bytes.get_string_from_ro(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_ro(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] + ## Type: Radiants + 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_ro(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_ro(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.rotation = (rotation_axis * rotation_angle) * Vector3(1,-1,1) + + 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(item_idx): + return vertex_positions[item_idx]) + ), + PackedVector2Array(face.texture_coordinate_indices.map(func(item_idx): + return texture_coordinates[item_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 |