mirror of
https://github.com/ApfelTeeSaft/lightspeed64.git
synced 2026-08-26 19:33:24 +00:00
339 lines
10 KiB
Python
339 lines
10 KiB
Python
import sys
|
|
import tempfile
|
|
import copy
|
|
import shutil
|
|
import bpy
|
|
import traceback
|
|
import os
|
|
from pathlib import Path
|
|
from .fast64_internal import *
|
|
|
|
import cProfile
|
|
import pstats
|
|
|
|
# info about add on
|
|
bl_info = {
|
|
"name": "Fast64",
|
|
"author": "kurethedead",
|
|
"location": "3DView",
|
|
"description": "Plugin for exporting F3D display lists and other game data related to Super Mario 64.",
|
|
"category": "Import-Export",
|
|
"blender": (2, 82, 0),
|
|
}
|
|
|
|
gameEditorEnum = (
|
|
("SM64", "SM64", "Super Mario 64"),
|
|
("OOT", "OOT", "Ocarina Of Time"),
|
|
)
|
|
|
|
class ArmatureApplyWithMesh(bpy.types.Operator):
|
|
# set bl_ properties
|
|
bl_description = 'Applies current pose as default pose. Useful for ' + \
|
|
"rigging an armature that is not in T/A pose. Note that when using " +\
|
|
" with an SM64 armature, you must revert to the default pose after " +\
|
|
"skinning."
|
|
bl_idname = 'object.armature_apply_w_mesh'
|
|
bl_label = "Apply As Rest Pose"
|
|
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
|
|
|
|
# Called on demand (i.e. button press, menu item)
|
|
# Can also be called from operator search menu (Spacebar)
|
|
def execute(self, context):
|
|
try:
|
|
if context.mode != 'OBJECT':
|
|
bpy.ops.object.mode_set(mode = "OBJECT")
|
|
|
|
if len(context.selected_objects) == 0:
|
|
raise PluginError("Armature not selected.")
|
|
elif type(context.selected_objects[0].data) is not\
|
|
bpy.types.Armature:
|
|
raise PluginError("Armature not selected.")
|
|
|
|
armatureObj = context.selected_objects[0]
|
|
for child in armatureObj.children:
|
|
if type(child.data) is not bpy.types.Mesh:
|
|
continue
|
|
armatureModifier = None
|
|
for modifier in child.modifiers:
|
|
if isinstance(modifier, bpy.types.ArmatureModifier):
|
|
armatureModifier = modifier
|
|
if armatureModifier is None:
|
|
continue
|
|
print(armatureModifier.name)
|
|
bpy.ops.object.select_all(action = "DESELECT")
|
|
context.view_layer.objects.active = child
|
|
bpy.ops.object.modifier_copy(modifier=armatureModifier.name)
|
|
print(len(child.modifiers))
|
|
attemptModifierApply(armatureModifier)
|
|
|
|
bpy.ops.object.select_all(action = "DESELECT")
|
|
context.view_layer.objects.active = armatureObj
|
|
bpy.ops.object.mode_set(mode = "POSE")
|
|
bpy.ops.pose.armature_apply()
|
|
if context.mode != 'OBJECT':
|
|
bpy.ops.object.mode_set(mode = "OBJECT")
|
|
except Exception as e:
|
|
if context.mode != 'OBJECT':
|
|
bpy.ops.object.mode_set(mode = "OBJECT")
|
|
raisePluginError(self, e)
|
|
return {"CANCELLED"}
|
|
|
|
self.report({'INFO'}, 'Applied armature with mesh.')
|
|
return {'FINISHED'} # must return a set
|
|
|
|
class AddBoneGroups(bpy.types.Operator):
|
|
# set bl_ properties
|
|
bl_description = 'Add bone groups respresenting other node types in ' +\
|
|
'SM64 geolayouts (ex. Shadow, Switch, Function).'
|
|
bl_idname = 'object.add_bone_groups'
|
|
bl_label = "Add Bone Groups"
|
|
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
|
|
|
|
# Called on demand (i.e. button press, menu item)
|
|
# Can also be called from operator search menu (Spacebar)
|
|
def execute(self, context):
|
|
try:
|
|
if context.mode != 'OBJECT' and context.mode != 'POSE':
|
|
raise PluginError("Operator can only be used in object or pose mode.")
|
|
elif context.mode == 'POSE':
|
|
bpy.ops.object.mode_set(mode = "OBJECT")
|
|
|
|
if len(context.selected_objects) == 0:
|
|
raise PluginError("Armature not selected.")
|
|
elif type(context.selected_objects[0].data) is not\
|
|
bpy.types.Armature:
|
|
raise PluginError("Armature not selected.")
|
|
|
|
armatureObj = context.selected_objects[0]
|
|
createBoneGroups(armatureObj)
|
|
except Exception as e:
|
|
raisePluginError(self, e)
|
|
return {"CANCELLED"}
|
|
|
|
self.report({'INFO'}, 'Created bone groups.')
|
|
return {'FINISHED'} # must return a set
|
|
|
|
class CreateMetarig(bpy.types.Operator):
|
|
# set bl_ properties
|
|
bl_description = 'SM64 imported armatures are usually not good for ' + \
|
|
'rigging. There are often intermediate bones between deform bones ' + \
|
|
'and they don\'t usually point to their children. This operator ' +\
|
|
'creates a metarig on armature layer 4 useful for IK.'
|
|
bl_idname = 'object.create_metarig'
|
|
bl_label = "Create Animatable Metarig"
|
|
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
|
|
|
|
# Called on demand (i.e. button press, menu item)
|
|
# Can also be called from operator search menu (Spacebar)
|
|
def execute(self, context):
|
|
try:
|
|
if context.mode != 'OBJECT':
|
|
bpy.ops.object.mode_set(mode = "OBJECT")
|
|
|
|
if len(context.selected_objects) == 0:
|
|
raise PluginError("Armature not selected.")
|
|
elif type(context.selected_objects[0].data) is not\
|
|
bpy.types.Armature:
|
|
raise PluginError("Armature not selected.")
|
|
|
|
armatureObj = context.selected_objects[0]
|
|
generateMetarig(armatureObj)
|
|
except Exception as e:
|
|
raisePluginError(self, e)
|
|
return {"CANCELLED"}
|
|
|
|
self.report({'INFO'}, 'Created metarig.')
|
|
return {'FINISHED'} # must return a set
|
|
|
|
class SM64_AddWaterBox(AddWaterBox):
|
|
bl_idname = 'object.sm64_add_water_box'
|
|
|
|
scale : bpy.props.FloatProperty(default = 10)
|
|
preset : bpy.props.StringProperty(default = "Shaded Solid")
|
|
matName : bpy.props.StringProperty(default = "sm64_water_mat")
|
|
|
|
def setEmptyType(self, emptyObj):
|
|
emptyObj.sm64_obj_type = "Water Box"
|
|
|
|
class SM64_ArmatureToolsPanel(bpy.types.Panel):
|
|
bl_idname = "SM64_PT_armature_tools"
|
|
bl_label = "SM64 Tools"
|
|
bl_space_type = 'VIEW_3D'
|
|
bl_region_type = 'UI'
|
|
bl_category = 'SM64'
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return True
|
|
|
|
# called every frame
|
|
def draw(self, context):
|
|
col = self.layout.column()
|
|
col.operator(ArmatureApplyWithMesh.bl_idname)
|
|
col.operator(AddBoneGroups.bl_idname)
|
|
col.operator(CreateMetarig.bl_idname)
|
|
col.operator(SM64_AddWaterBox.bl_idname)
|
|
|
|
class F3D_GlobalSettingsPanel(bpy.types.Panel):
|
|
bl_idname = "F3D_PT_global_settings"
|
|
bl_label = "F3D Global Settings"
|
|
bl_space_type = 'VIEW_3D'
|
|
bl_region_type = 'UI'
|
|
bl_category = 'Fast64'
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return True
|
|
|
|
# called every frame
|
|
def draw(self, context):
|
|
col = self.layout.column()
|
|
prop_split(col, context.scene, 'f3d_type', "F3D Microcode")
|
|
col.prop(context.scene, 'isHWv1')
|
|
col.prop(context.scene, 'saveTextures')
|
|
col.prop(context.scene, 'f3d_simple', text = "Simple Material UI")
|
|
col.prop(context.scene, 'generateF3DNodeGraph', text = "Generate F3D Node Graph For Materials")
|
|
col.prop(context.scene, 'decomp_compatible', invert_checkbox = True, text = 'Homebrew Compatibility')
|
|
col.prop(context.scene, 'ignoreTextureRestrictions')
|
|
if context.scene.ignoreTextureRestrictions:
|
|
col.box().label(text = "Width/height must be < 1024. Must be RGBA32. Must be png format.")
|
|
|
|
class Fast64_GlobalObjectPanel(bpy.types.Panel):
|
|
bl_label = "Global Object Inspector"
|
|
bl_idname = "OBJECT_PT_OOT_Global_Object_Inspector"
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_context = "object"
|
|
bl_options = {'HIDE_HEADER'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return (context.object is not None and context.object.data is None)
|
|
|
|
def draw(self, context):
|
|
box = self.layout
|
|
prop_split(box, context.scene, 'gameEditorMode', "Game")
|
|
|
|
class Fast64_GlobalSettingsPanel(bpy.types.Panel):
|
|
bl_idname = "FAST64_PT_global_settings"
|
|
bl_label = "Fast64 Global Settings"
|
|
bl_space_type = 'VIEW_3D'
|
|
bl_region_type = 'UI'
|
|
bl_category = 'Fast64'
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return True
|
|
|
|
# called every frame
|
|
def draw(self, context):
|
|
col = self.layout.column()
|
|
prop_split(col, context.scene, 'gameEditorMode', "Game")
|
|
col.prop(context.scene, 'exportHiddenGeometry')
|
|
col.prop(context.scene, 'fullTraceback')
|
|
|
|
class Fast64_GlobalToolsPanel(bpy.types.Panel):
|
|
bl_idname = "FAST64_PT_global_tools"
|
|
bl_label = "Fast64 Tools"
|
|
bl_space_type = 'VIEW_3D'
|
|
bl_region_type = 'UI'
|
|
bl_category = 'Fast64'
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return True
|
|
|
|
# called every frame
|
|
def draw(self, context):
|
|
col = self.layout.column()
|
|
col.operator(ArmatureApplyWithMesh.bl_idname)
|
|
#col.operator(CreateMetarig.bl_idname)
|
|
|
|
|
|
#def updateGameEditor(scene, context):
|
|
# if scene.currentGameEditorMode == 'SM64':
|
|
# sm64_panel_unregister()
|
|
# elif scene.currentGameEditorMode == 'Z64':
|
|
# oot_panel_unregister()
|
|
# else:
|
|
# raise PluginError("Unhandled game editor mode " + str(scene.currentGameEditorMode))
|
|
#
|
|
# if scene.gameEditorMode == 'SM64':
|
|
# sm64_panel_register()
|
|
# elif scene.gameEditorMode == 'Z64':
|
|
# oot_panel_register()
|
|
# else:
|
|
# raise PluginError("Unhandled game editor mode " + str(scene.gameEditorMode))
|
|
#
|
|
# scene.currentGameEditorMode = scene.gameEditorMode
|
|
|
|
classes = (
|
|
ArmatureApplyWithMesh,
|
|
AddBoneGroups,
|
|
CreateMetarig,
|
|
SM64_AddWaterBox,
|
|
|
|
#Fast64_GlobalObjectPanel,
|
|
F3D_GlobalSettingsPanel,
|
|
Fast64_GlobalSettingsPanel,
|
|
SM64_ArmatureToolsPanel,
|
|
Fast64_GlobalToolsPanel,
|
|
)
|
|
|
|
# called on add-on enabling
|
|
# register operators and panels here
|
|
# append menu layout drawing function to an existing window
|
|
def register():
|
|
mat_register()
|
|
render_engine_register()
|
|
bsdf_conv_register()
|
|
sm64_register(True)
|
|
oot_register(True)
|
|
|
|
bsdf_conv_panel_regsiter()
|
|
|
|
for cls in classes:
|
|
register_class(cls)
|
|
|
|
f3d_writer_register()
|
|
f3d_parser_register()
|
|
|
|
# ROM
|
|
|
|
bpy.types.Scene.decomp_compatible = bpy.props.BoolProperty(
|
|
name = 'Decomp Compatibility', default = True)
|
|
bpy.types.Scene.ignoreTextureRestrictions = bpy.props.BoolProperty(
|
|
name = 'Ignore Texture Restrictions (Breaks CI Textures)')
|
|
bpy.types.Scene.fullTraceback = \
|
|
bpy.props.BoolProperty(name = 'Show Full Error Traceback', default = False)
|
|
bpy.types.Scene.gameEditorMode = bpy.props.EnumProperty(
|
|
name = 'Game', default = 'SM64', items = gameEditorEnum)
|
|
bpy.types.Scene.saveTextures = bpy.props.BoolProperty(
|
|
name = 'Save Textures As PNGs (Breaks CI Textures)')
|
|
bpy.types.Scene.generateF3DNodeGraph = bpy.props.BoolProperty(name = "Generate F3D Node Graph", default = True)
|
|
bpy.types.Scene.exportHiddenGeometry = bpy.props.BoolProperty(name = "Export Hidden Geometry", default = True)
|
|
bpy.types.Scene.blenderF3DScale = bpy.props.FloatProperty(name = "F3D Blender Scale", default = 100)
|
|
|
|
# called on add-on disabling
|
|
def unregister():
|
|
f3d_writer_unregister()
|
|
f3d_parser_unregister()
|
|
sm64_unregister(True)
|
|
oot_unregister(True)
|
|
mat_unregister()
|
|
bsdf_conv_unregister()
|
|
bsdf_conv_panel_unregsiter()
|
|
render_engine_unregister()
|
|
|
|
del bpy.types.Scene.fullTraceback
|
|
del bpy.types.Scene.decomp_compatible
|
|
del bpy.types.Scene.ignoreTextureRestrictions
|
|
del bpy.types.Scene.saveTextures
|
|
del bpy.types.Scene.gameEditorMode
|
|
del bpy.types.Scene.generateF3DNodeGraph
|
|
del bpy.types.Scene.exportHiddenGeometry
|
|
del bpy.types.Scene.blenderF3DScale
|
|
|
|
for cls in classes:
|
|
unregister_class(cls)
|