diff --git a/blender/__init__.py b/blender/__init__.py index 56bc58c..9037248 100644 --- a/blender/__init__.py +++ b/blender/__init__.py @@ -6,7 +6,7 @@ "name": "Sonic Adventure I/O", "author": "Justin113D, ItsEasyActually, X-Hax", "description": "Import/Exporter for Sonic Adventure Model, Animation and other Formats.", - "version": (2, 1, 0), + "version": (2, 1, 1), "blender": (4, 0, 0), "location": "", "warning": "", diff --git a/blender/__initdev__.py b/blender/__initdev__.py index 36889d5..1d96418 100644 --- a/blender/__initdev__.py +++ b/blender/__initdev__.py @@ -6,7 +6,7 @@ "name": "Sonic Adventure I/O TEST BUILD", "author": "Justin113D, ItsEasyActually, X-Hax", "description": "Import/Exporter for Sonic Adventure Model, Animation and other Formats.", - "version": (2, 1, 0), + "version": (2, 1, 1), "blender": (4, 0, 0), "location": "", "warning": "", diff --git a/blender/source/exporting/o_enum.py b/blender/source/exporting/o_enum.py index 93aed32..9a0d7c1 100644 --- a/blender/source/exporting/o_enum.py +++ b/blender/source/exporting/o_enum.py @@ -7,9 +7,10 @@ GC_TEXCOORD_SOURCE, GC_TEXCOORD_MATRIX, ATTACH_FORMAT, - MODEL_FORMAT + MODEL_FORMAT, + EVENT_TYPE ) -from ..dotnet import SAIO_NET, SA3D_Modeling +from ..dotnet import SAIO_NET, SA3D_Modeling, SA3D_SA2Event def to_node_attributes(node_properties): @@ -80,3 +81,6 @@ def to_attach_format(attach_format: str): def to_model_format(model_format: str): return getattr(SA3D_Modeling.MODEL_FORMAT, MODEL_FORMAT[model_format]) + +def to_event_type(event_type: str): + return getattr(SA3D_SA2Event.EVENT_TYPE, EVENT_TYPE[event_type]) diff --git a/blender/source/exporting/o_event.py b/blender/source/exporting/o_event.py index cea9a56..65eea17 100644 --- a/blender/source/exporting/o_event.py +++ b/blender/source/exporting/o_event.py @@ -1,6 +1,7 @@ import bpy from bpy.types import Object as BObject +from . import o_enum from .o_event_cutinfo import CutInfo from .o_shapemotion import ShapeMotionEvaluator from .o_model import ModelEvaluator, ModelData @@ -46,6 +47,7 @@ def get_base_scene(context: bpy.types.Context): class EventExporter: context: bpy.types.Context + event_type: str optimize: bool anim_parameters: AnimParameters @@ -75,11 +77,13 @@ class EventExporter: def __init__( self, context: bpy.types.Context, + event_type: str, optimize: bool, auto_node_attributes: bool, anim_parameters: AnimParameters): self.context = context + self.event_type = event_type self.optimize = optimize self.anim_parameters = anim_parameters @@ -158,7 +162,7 @@ def _collect_objects(self): self.entry_source_scene[obj] = self.base_scene - self.shared_entries.sort(key=lambda x: x.name) + self.shared_entries.sort(key=lambda x: x.name.lower()) event_properties = self.base_scene.saio_scene.event for name in OVERLAY_UPGRADE_LUT.values(): @@ -207,6 +211,9 @@ def _collect_objects(self): if obj not in self.entry_source_scene: self.entry_source_scene[obj] = cutinfo.scene + cutinfo.entries.sort(key=lambda x: x.name.lower()) + cutinfo.particles.sort(key=lambda x: x.name.lower()) + if len(self.blare) > 64: raise UserException("Can't have more than 64 blare models!") @@ -268,11 +275,10 @@ def _convert_model(self, obj: bpy.types.Object): self.uv_animated_objects.extend(uv_meshes) def _convert_models(self): - base_entries = [] - base_entries.extend(self.shared_entries) - base_entries.extend(self.shadows) - base_entries.extend(self.upgrades) - base_entries = set(base_entries) + base_entries = set() + base_entries.update(self.shared_entries) + base_entries.update(self.shadows) + base_entries.update(self.upgrades) for entry in base_entries: self._convert_model(entry) @@ -623,12 +629,13 @@ def _setup_animated_scene(self, cutinfo: CutInfo): motion = None if obj in cutinfo.motions: motion = cutinfo.motions[obj] + motion.EnsureKeyframes(posrot) result.ParticleMotions.Add(motion) return result def _setup_eventdata(self): - self.event_data = SA3D_SA2Event.MODEL_DATA(SA3D_SA2Event.EVENT_TYPE.gc) + self.event_data = SA3D_SA2Event.MODEL_DATA(o_enum.to_event_type(self.event_type)) self.event_data.EnableDropShadows = \ self.base_scene.saio_scene.event.drop_shadow_control diff --git a/blender/source/exporting/o_event_cutinfo.py b/blender/source/exporting/o_event_cutinfo.py index 1e882de..dfbf1e3 100644 --- a/blender/source/exporting/o_event_cutinfo.py +++ b/blender/source/exporting/o_event_cutinfo.py @@ -169,7 +169,7 @@ def _setup_temp_object_action( self, action: bpy.types.Action, obj: BObject, - only_location: bool = False): + no_scale: bool = False): def create_curve(field, length): for i in range(length): @@ -181,16 +181,15 @@ def create_curve(field, length): create_curve("location", 3) - if only_location: - return - - create_curve("scale", 3) - if obj.rotation_mode == 'QUATERNION': create_curve("rotation_quaternion", 4) else: create_curve("rotation_euler", 3) + if not no_scale: + create_curve("scale", 3) + + def _setup_temp_target_action(self, action: bpy.types.Action, obj): def create_curve(field, index): @@ -324,7 +323,7 @@ def _prepare_particle_actions(self): action = self._setup_action( particle.animation_data, particle.name, - lambda x: self._setup_temp_object_action(x, particle, True)) + lambda x: self._setup_temp_object_action(x, particle)) if action is not None: self.output_actions[particle] = action diff --git a/blender/source/exporting/o_landtable.py b/blender/source/exporting/o_landtable.py index e581a2e..adfb369 100644 --- a/blender/source/exporting/o_landtable.py +++ b/blender/source/exporting/o_landtable.py @@ -195,10 +195,10 @@ def _eval_animated(self, objects: set[bpy.types.Object]): self._optimize, self._write_specular, self._apply_modifs, - False, # apply posing + False, # Dont apply posing self._automatic_node_attributes, self._force_sort_bones, - False) # flip vertex colors + False) # Dont flip vertex colors modeldata = evaluator.evaluate(objects) @@ -233,10 +233,10 @@ def evaluate(self, objects: set[bpy.types.Object]): self._setup() self._organize_objects(objects) - for objects in self._anim_objects: - self._eval_animated(objects) + for anim_tree in self._anim_objects: + self._eval_animated(anim_tree) - for obj in self._le_objects: + for obj in sorted(self._le_objects, key=lambda x: x.name.lower()): if obj.type == 'MESH' and len(obj.data.polygons) > 0: self._eval_entry(obj) diff --git a/blender/source/exporting/o_model.py b/blender/source/exporting/o_model.py index bc7ac1a..23ba64d 100644 --- a/blender/source/exporting/o_model.py +++ b/blender/source/exporting/o_model.py @@ -92,7 +92,7 @@ def __init__( apply_pose: bool = False, automatic_node_attributes: bool = True, force_sort_bones: bool = False, - flip_vertex_color_channels: bool = False,): + flip_vertex_color_channels: bool = False): self._context = context self._attach_format = attach_format diff --git a/blender/source/exporting/o_node.py b/blender/source/exporting/o_node.py index 306c915..a1b6521 100644 --- a/blender/source/exporting/o_node.py +++ b/blender/source/exporting/o_node.py @@ -239,9 +239,9 @@ def _evaluate_object_tree(self, objects: set[BObject]): self._hierarchy_dictionary[obj] = [] for hierarchy_objects in self._hierarchy_dictionary.values(): - hierarchy_objects.sort(key=lambda x: x.name) + hierarchy_objects.sort(key=lambda x: x.name.lower()) - self._parentless.sort(key=lambda x: x.name) + self._parentless.sort(key=lambda x: x.name.lower()) def _eval_object(self, obj: BObject, parent_index: int): @@ -261,7 +261,7 @@ def _eval_bone(self, bone: PoseBone, parent_index: int): children = list(bone.children) if self._force_sort_bones: - children.sort(key=lambda x: x.name) + children.sort(key=lambda x: x.name.lower()) for child in children: self._eval_bone(child, index) diff --git a/blender/source/importing/i_texture.py b/blender/source/importing/i_texture.py index 132cba6..9b96b48 100644 --- a/blender/source/importing/i_texture.py +++ b/blender/source/importing/i_texture.py @@ -15,7 +15,7 @@ def process_texture_set(texture_set, texture_list): img.pack() tex = texture_list.new(name=texture.Name, image=img) - tex.global_index = texture.GlobalIndex + tex.global_index = SAIO_NET.TEXTURE.ToSigned(texture.GlobalIndex) tex.override_width = texture.OverrideWidth tex.override_height = texture.OverrideHeight diff --git a/blender/source/register/operators/export_operators.py b/blender/source/register/operators/export_operators.py index a813742..c6fed7a 100644 --- a/blender/source/register/operators/export_operators.py +++ b/blender/source/register/operators/export_operators.py @@ -413,6 +413,19 @@ class SAIO_OT_Export_Event(NodeAnimExportOperator): show_bone_localspace = False + event_type: EnumProperty( + name="Event Type", + description="Type of event to export", + items=( + ('DCBETA', "Dreamcast Beta", "Event targetting Dreamcast beta builds"), + ('DC', "Dreamcast", "Event targetting Dreamcast"), + ('DCGC', "Dreamcast-Gamecube", + "Event targetting Gamecube (and ports) but with Greamcast formatting"), + ('GC', "Gamecube", "Event targetting Gamecube and ports"), + ), + default='GC' + ) + optimize: BoolProperty( name="Optimize", description="Optimize if possible", @@ -445,6 +458,7 @@ class SAIO_OT_Export_Event(NodeAnimExportOperator): ) def draw(self, context: bpy.types.Context): + self.layout.prop(self, "event_type") self.layout.prop(self, "optimize") self.layout.prop(self, "auto_node_attributes") self.layout.prop(self, "export_textures") @@ -459,6 +473,7 @@ def export(self, context: bpy.types.Context): exporter = o_event.EventExporter( context, + self.event_type, self.optimize, self.auto_node_attributes, anim_parameters) diff --git a/blender/source/register/operators/tool_operators.py b/blender/source/register/operators/tool_operators.py index ab2c2f3..4b96f83 100644 --- a/blender/source/register/operators/tool_operators.py +++ b/blender/source/register/operators/tool_operators.py @@ -315,7 +315,7 @@ def add_children( resultMeshes.append(parent) children: list[bpy.types.Object] = [child for child in parent.children] - children.sort(key=lambda x: x.name) + children.sort(key=lambda x: x.name.lower()) for child in children: SAIO_OT_ArmatureFromObjects.add_children( diff --git a/blender/source/register/property_groups/texture_properties.py b/blender/source/register/property_groups/texture_properties.py index 86a4f2a..e52915e 100644 --- a/blender/source/register/property_groups/texture_properties.py +++ b/blender/source/register/property_groups/texture_properties.py @@ -28,8 +28,7 @@ class SAIO_Texture(bpy.types.PropertyGroup): global_index: IntProperty( name="Global Index", description="The global texture id in the texture file", - default=0, - min=0 + default=0 ) override_width: IntProperty( diff --git a/blender/source/register/ui/material_panel.py b/blender/source/register/ui/material_panel.py index 877730d..6f47c23 100644 --- a/blender/source/register/ui/material_panel.py +++ b/blender/source/register/ui/material_panel.py @@ -144,8 +144,8 @@ def rendering_prop(label, name): rendering_menu.separator(factor=2) rendering_prop("Double Sided:", "double_sided") + rendering_prop("Ignore Lighting:", "ignore_diffuse") rendering_prop("Ignore Ambient Lighting:", "ignore_ambient") - rendering_prop("Ignore Diffuse Lighting:", "ignore_diffuse") rendering_prop("Ignore Specular Lighting:", "ignore_specular") rendering_prop("Flat Shading:", "flat_shading") diff --git a/blender/source/utility/bone_utils.py b/blender/source/utility/bone_utils.py index e5de786..8c395aa 100644 --- a/blender/source/utility/bone_utils.py +++ b/blender/source/utility/bone_utils.py @@ -14,7 +14,7 @@ def _get_bone( children = list(bone.children) if force_sort: - children.sort(key=lambda b: b.name) + children.sort(key=lambda b: b.name.lower()) for b in children: _get_bone(b, force_sort, shape, result) diff --git a/blender/source/utility/enum_lut.py b/blender/source/utility/enum_lut.py index 026c0ac..d1d0760 100644 --- a/blender/source/utility/enum_lut.py +++ b/blender/source/utility/enum_lut.py @@ -377,3 +377,17 @@ 'SA2': 'SA2', 'SA2B': 'SA2B' } + +EVENT_TYPE = { + "dcbeta": "DCBETA", + "DCBETA" : "dcbeta", + + "dc": "DC", + "DC" : "dc", + + "dcgc": "DCGC", + "DCGC" : "dcgc", + + "gc": "GC", + "GC" : "gc" +} diff --git a/blender/source/utility/material_setup.py b/blender/source/utility/material_setup.py index 9866cff..f3053e3 100644 --- a/blender/source/utility/material_setup.py +++ b/blender/source/utility/material_setup.py @@ -444,7 +444,7 @@ def assemble_texture_list( texlist = world.saio_texture_list texs = list(texs) - texs.sort(key=lambda x: x.name) + texs.sort(key=lambda x: x.name.lower()) index = global_index_offset for tex in texs: item = texlist.new(image=tex) diff --git a/dotnet/Model.cs b/dotnet/Model.cs index abc96f7..a6d92fe 100644 --- a/dotnet/Model.cs +++ b/dotnet/Model.cs @@ -143,16 +143,19 @@ public static Model Process(Node node, bool optimize, bool flipVertexColors = fa meshes = WeightedMesh.MergeAtRoots(meshes); } - foreach(WeightedMesh mesh in meshes) + if(flipVertexColors) { - foreach(BufferCorner[] corners in mesh.TriangleSets) + foreach(WeightedMesh mesh in meshes) { - for(int i = 0; i < corners.Length; i++) + foreach(BufferCorner[] corners in mesh.TriangleSets) { - Color color = corners[i].Color; - (color.Alpha, color.Blue) = (color.Blue, color.Alpha); - (color.Red, color.Green) = (color.Green, color.Red); - corners[i].Color = color; + for(int i = 0; i < corners.Length; i++) + { + Color color = corners[i].Color; + (color.Alpha, color.Blue) = (color.Blue, color.Alpha); + (color.Red, color.Green) = (color.Green, color.Red); + corners[i].Color = color; + } } } } diff --git a/dotnet/SAIO.NET.csproj b/dotnet/SAIO.NET.csproj index b91bf21..e2e5bce 100644 --- a/dotnet/SAIO.NET.csproj +++ b/dotnet/SAIO.NET.csproj @@ -12,12 +12,12 @@ - - - - + + + + - + diff --git a/dotnet/Texture.cs b/dotnet/Texture.cs index e4e4f1c..f9c0b29 100644 --- a/dotnet/Texture.cs +++ b/dotnet/Texture.cs @@ -27,12 +27,14 @@ public static float[] GetData(Image texture) return result; } - public static Image Create(string name, uint globalIndex, int width, int height, bool? index4, float[] colors) + public static Image Create(string name, int globalIndex, int width, int height, bool? index4, float[] colors) { ReadOnlySpan source = colors; int destIndex = 0; int pixRowSize = width * 4; + uint unsignedGlobalIndex = unchecked((uint)globalIndex); + if(index4 == null) { byte[] pixelData = new byte[width * height * 4]; @@ -47,7 +49,7 @@ public static Image Create(string name, uint globalIndex, int width, int height, } } - return new ColorTexture(width, height, pixelData, name, globalIndex); + return new ColorTexture(width, height, pixelData, name, unsignedGlobalIndex); } else { @@ -67,11 +69,16 @@ public static Image Create(string name, uint globalIndex, int width, int height, } } - return new IndexTexture(width, height, pixelData, name, globalIndex) + return new IndexTexture(width, height, pixelData, name, unsignedGlobalIndex) { IsIndex4 = index4.Value }; } } + + public static int ToSigned(uint number) + { + return unchecked((int)number); + } } }