mirror of
https://github.com/ApfelTeeSaft/lightspeed64.git
synced 2026-08-26 19:33:24 +00:00
Switch node options split up into separate geolayouts. Fixed bug where override meshes not showing up in header.
This commit is contained in:
+9
-5
@@ -341,7 +341,8 @@ class SM64_ExportGeolayoutObject(bpy.types.Operator):
|
||||
modelLoadInfo = (None, None)
|
||||
|
||||
if context.scene.geoUseBank0:
|
||||
addrRange, startRAM = exportGeolayoutObjectBinaryBank0(
|
||||
addrRange, startRAM, geoStart = \
|
||||
exportGeolayoutObjectBinaryBank0(
|
||||
romfileOutput, obj, exportRange,
|
||||
finalTransform, *modelLoadInfo, textDumpFilePath,
|
||||
context.scene.f3d_type, context.scene.isHWv1,
|
||||
@@ -368,7 +369,8 @@ class SM64_ExportGeolayoutObject(bpy.types.Operator):
|
||||
if context.scene.geoUseBank0:
|
||||
self.report({'INFO'}, 'Success! Geolayout at (' + \
|
||||
hex(addrRange[0]) + ', ' + hex(addrRange[1]) + \
|
||||
'), to write to RAM Address ' + hex(startRAM))
|
||||
'), to write to RAM Address ' + hex(startRAM) + \
|
||||
', with geolayout starting at ' + hex(geoStart))
|
||||
else:
|
||||
self.report({'INFO'}, 'Success! Geolayout at (' + \
|
||||
hex(addrRange[0]) + ', ' + hex(addrRange[1]) + \
|
||||
@@ -497,7 +499,8 @@ class SM64_ExportGeolayoutArmature(bpy.types.Operator):
|
||||
modelLoadInfo = (None, None)
|
||||
|
||||
if context.scene.geoUseBank0:
|
||||
addrRange, startRAM = exportGeolayoutArmatureBinaryBank0(
|
||||
addrRange, startRAM, geoStart = \
|
||||
exportGeolayoutArmatureBinaryBank0(
|
||||
romfileOutput, armatureObj, obj, exportRange,
|
||||
finalTransform, *modelLoadInfo, textDumpFilePath,
|
||||
context.scene.f3d_type, context.scene.isHWv1,
|
||||
@@ -523,7 +526,8 @@ class SM64_ExportGeolayoutArmature(bpy.types.Operator):
|
||||
if context.scene.geoUseBank0:
|
||||
self.report({'INFO'}, 'Success! Geolayout at (' + \
|
||||
hex(addrRange[0]) + ', ' + hex(addrRange[1]) + \
|
||||
'), to write to RAM Address ' + hex(startRAM))
|
||||
'), to write to RAM Address ' + hex(startRAM) + \
|
||||
', with geolayout starting at ' + hex(geoStart))
|
||||
else:
|
||||
self.report({'INFO'}, 'Success! Geolayout at (' + \
|
||||
hex(addrRange[0]) + ', ' + hex(addrRange[1]) + \
|
||||
@@ -1457,7 +1461,7 @@ def register():
|
||||
bpy.types.Scene.geoRAMAddr = bpy.props.StringProperty(name = 'RAM Address',
|
||||
default = '80000000')
|
||||
bpy.types.Scene.geoTexDir = bpy.props.StringProperty(
|
||||
name ='Include Path', default = '/level/ddd/')
|
||||
name ='Include Path', default = '/actors/mario/')
|
||||
bpy.types.Scene.geoSaveTextures = bpy.props.BoolProperty(
|
||||
name = 'Save Textures As PNGs')
|
||||
bpy.types.Scene.geoSeparateTextureDef = bpy.props.BoolProperty(
|
||||
|
||||
@@ -1677,6 +1677,8 @@ class FMesh:
|
||||
data = self.draw.to_c_def()
|
||||
for triangleList in self.triangleLists:
|
||||
data += triangleList.to_c_def()
|
||||
for materialTuple, drawOverride in self.drawMatOverrides.items():
|
||||
data += drawOverride.to_c_def()
|
||||
return data
|
||||
|
||||
class FMaterial:
|
||||
|
||||
@@ -61,7 +61,8 @@ class CameraSettingsPanel(bpy.types.Panel):
|
||||
prop_split(layout, camera, 'camType', 'Camera Type')
|
||||
prop_split(layout, camera, 'envType', 'Environment Type')
|
||||
|
||||
def saveCameraSettingsToGeolayout(geolayout, cameraObj, rootObj):
|
||||
def saveCameraSettingsToGeolayout(geolayoutGraph, cameraObj, rootObj):
|
||||
geolayout = geolayoutGraph.startGeolayout
|
||||
camera = cameraObj.data
|
||||
screenAreaNode = TransformNode(ScreenAreaNode(
|
||||
camera.useDefaultScreenRect, 0xA, camera.screenPos, camera.screenSize))
|
||||
@@ -93,14 +94,16 @@ def saveCameraSettingsToGeolayout(geolayout, cameraObj, rootObj):
|
||||
frustumNode.children.append(cameraNode)
|
||||
|
||||
startDLNode = TransformNode(StartNode())
|
||||
cameraNode.children.append(startDLNode)
|
||||
meshGeolayout = geolayoutGraph.addGeolayout(rootObj, rootObj.name)
|
||||
meshGeolayout.nodes.append(startDLNode)
|
||||
geolayoutGraph.addJumpNode(cameraNode, geolayout, meshGeolayout)
|
||||
|
||||
# Moving textures here
|
||||
|
||||
cameraNode.children.append(TransformNode(RenderObjNode()))
|
||||
cameraNode.children.append(TransformNode(EnvFunctionNode(camera.envType)))
|
||||
|
||||
return startDLNode
|
||||
return meshGeolayout
|
||||
|
||||
cam_classes = (
|
||||
CameraSettingsPanel,
|
||||
|
||||
@@ -3,26 +3,147 @@ from .sm64_geolayout_utility import *
|
||||
from .utility import *
|
||||
from .sm64_constants import *
|
||||
import struct
|
||||
import copy
|
||||
|
||||
class GeolayoutGraph:
|
||||
def __init__(self, name):
|
||||
self.startGeolayout = Geolayout(name, True)
|
||||
# dict of Object : Geolayout
|
||||
self.secondaryGeolayouts = {}
|
||||
# dict of Geolayout : Geolayout List (which geolayouts are called)
|
||||
self.geolayoutCalls = {}
|
||||
self.sortedList = []
|
||||
self.sortedListGenerated = False
|
||||
|
||||
def checkListSorted(self):
|
||||
if not self.sortedListGenerated:
|
||||
raise ValueError("Must generate sorted geolayout list first " +\
|
||||
'before calling this function.')
|
||||
|
||||
def size(self):
|
||||
self.checkListSorted()
|
||||
size = 0
|
||||
for geolayout in self.sortedList:
|
||||
size += geolayout.size()
|
||||
|
||||
return size
|
||||
|
||||
def addGeolayout(self, obj, name):
|
||||
geolayout = Geolayout(name, False)
|
||||
self.secondaryGeolayouts[obj] = geolayout
|
||||
return geolayout
|
||||
|
||||
def addJumpNode(self, parentNode, caller, callee, index = None):
|
||||
if index is None:
|
||||
parentNode.children.append(TransformNode(JumpNode(
|
||||
True, callee)))
|
||||
else:
|
||||
parentNode.children.insert(index, TransformNode(JumpNode(
|
||||
True, callee)))
|
||||
self.addGeolayoutCall(caller, callee)
|
||||
|
||||
def addGeolayoutCall(self, caller, callee):
|
||||
if caller not in self.geolayoutCalls:
|
||||
self.geolayoutCalls[caller] = []
|
||||
self.geolayoutCalls[caller].append(callee)
|
||||
|
||||
def sortGeolayouts(self, geolayoutList, geolayout, callOrder):
|
||||
if geolayout in self.geolayoutCalls:
|
||||
for calledGeolayout in self.geolayoutCalls[geolayout]:
|
||||
geoIndex = geolayoutList.index(geolayout)
|
||||
if calledGeolayout in geolayoutList:
|
||||
callIndex = geolayoutList.index(calledGeolayout)
|
||||
if callIndex < geoIndex:
|
||||
continue
|
||||
else:
|
||||
raise ValueError('Circular geolayout dependency.' +\
|
||||
str(callOrder))
|
||||
else:
|
||||
geolayoutList.insert(geolayoutList.index(geolayout),
|
||||
calledGeolayout)
|
||||
callOrder = copy.copy(callOrder)
|
||||
callOrder.append(calledGeolayout)
|
||||
self.sortGeolayouts(geolayoutList, calledGeolayout,
|
||||
callOrder)
|
||||
return geolayoutList
|
||||
|
||||
def generateSortedList(self):
|
||||
self.sortedList = self.sortGeolayouts([self.startGeolayout],
|
||||
self.startGeolayout, [self.startGeolayout])
|
||||
self.sortedListGenerated = True
|
||||
|
||||
def set_addr(self, address):
|
||||
self.checkListSorted()
|
||||
for geolayout in self.sortedList:
|
||||
geolayout.startAddress = address
|
||||
address += geolayout.size()
|
||||
print(geolayout.name + " - " + \
|
||||
str(geolayout.startAddress))
|
||||
return address
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
self.checkListSorted()
|
||||
data = bytearray(0)
|
||||
for geolayout in self.sortedList:
|
||||
data += geolayout.to_binary(segmentData)
|
||||
return data
|
||||
|
||||
def save_binary(self, romfile, segmentData):
|
||||
for geolayout in self.sortedList:
|
||||
geolayout.save_binary(romfile, segmentData)
|
||||
|
||||
def to_c(self):
|
||||
self.checkListSorted()
|
||||
data = ''
|
||||
for geolayout in self.sortedList:
|
||||
data += geolayout.to_c()
|
||||
return data
|
||||
|
||||
def to_c_def(self):
|
||||
self.checkListSorted()
|
||||
data = ''
|
||||
for geolayout in self.sortedList:
|
||||
data += geolayout.to_c_def()
|
||||
return data
|
||||
|
||||
def toTextDump(self, segmentData):
|
||||
self.checkListSorted()
|
||||
data = ''
|
||||
for geolayout in self.sortedList:
|
||||
data += geolayout.toTextDump(segmentData) + '\n'
|
||||
return data
|
||||
|
||||
class Geolayout:
|
||||
def __init__(self, name):
|
||||
def __init__(self, name, isStartGeo):
|
||||
self.nodes = []
|
||||
self.name = toAlnum(name)
|
||||
# dict of Object : geolayout
|
||||
self.secondaryGeolayouts = {}
|
||||
self.startAddress = 0
|
||||
self.isStartGeo = isStartGeo
|
||||
|
||||
def size(self):
|
||||
size = 4 # end command
|
||||
for node in self.nodes:
|
||||
size += node.size()
|
||||
return size
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
endCmd = GEO_END if self.isStartGeo else GEO_RETURN
|
||||
data = bytearray(0)
|
||||
for node in self.nodes:
|
||||
data += node.to_binary(segmentData)
|
||||
data += bytearray([GEO_END, 0x00, 0x00, 0x00])
|
||||
data += bytearray([endCmd, 0x00, 0x00, 0x00])
|
||||
return data
|
||||
|
||||
def save_binary(self, romfile, segmentData):
|
||||
romfile.seek(self.startAddress)
|
||||
romfile.write(self.to_binary(segmentData))
|
||||
|
||||
def to_c(self):
|
||||
endCmd = 'GEO_END' if self.isStartGeo else 'GEO_RETURN'
|
||||
data = 'const GeoLayout ' + self.name + '[] = {\n'
|
||||
for node in self.nodes:
|
||||
data += node.to_c(1)
|
||||
data += '\t' + 'GEO_END(),\n'
|
||||
data += '\t' + endCmd + '(),\n'
|
||||
data += '};\n'
|
||||
return data
|
||||
|
||||
@@ -30,10 +151,11 @@ class Geolayout:
|
||||
return 'extern const GeoLayout ' + self.name + '[];\n'
|
||||
|
||||
def toTextDump(self, segmentData):
|
||||
endCmd = '01' if self.isStartGeo else '03'
|
||||
data = ''
|
||||
for node in self.nodes:
|
||||
data += node.toTextDump(1, segmentData)
|
||||
data += '01 00 00 00'
|
||||
data += node.toTextDump(0, segmentData)
|
||||
data += endCmd + ' 00 00 00\n'
|
||||
return data
|
||||
|
||||
class TransformNode:
|
||||
@@ -41,7 +163,16 @@ class TransformNode:
|
||||
self.node = node
|
||||
self.children = []
|
||||
self.parent = None
|
||||
|
||||
|
||||
def size(self):
|
||||
size = self.node.size() if self.node is not None else 0
|
||||
if len(self.children) > 0 and type(self.node) in nodeGroupClasses:
|
||||
size += 8 # node open/close
|
||||
for child in self.children:
|
||||
size += child.size()
|
||||
|
||||
return size
|
||||
|
||||
# Function commands usually effect the following command, so it is similar
|
||||
# to a parent child relationship.
|
||||
def to_binary(self, segmentData):
|
||||
@@ -104,7 +235,6 @@ class TransformNode:
|
||||
raise ValueError("A switch bone must have at least one child bone.")
|
||||
return data
|
||||
|
||||
|
||||
class SwitchOverrideNode:
|
||||
def __init__(self, material, specificMat, drawLayer, overrideType):
|
||||
self.material = material
|
||||
@@ -112,6 +242,30 @@ class SwitchOverrideNode:
|
||||
self.drawLayer = drawLayer
|
||||
self.overrideType = overrideType
|
||||
|
||||
class JumpNode:
|
||||
def __init__(self, storeReturn, geolayout):
|
||||
self.geolayout = geolayout
|
||||
self.storeReturn = storeReturn
|
||||
self.hasDL = False
|
||||
|
||||
def size(self):
|
||||
return 8
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
if segmentData is not None:
|
||||
startAddress = encodeSegmentedAddr(self.geolayout.startAddress,
|
||||
segmentData)
|
||||
else:
|
||||
startAddress = bytearray([0x00] * 4)
|
||||
command = bytearray([GEO_BRANCH,
|
||||
0x01 if self.storeReturn else 0x00, 0x00, 0x00])
|
||||
command.extend(startAddress)
|
||||
return command
|
||||
|
||||
def to_c(self):
|
||||
return "GEO_BRANCH(" + ('1, ' if self.storeReturn else '0, ') + \
|
||||
self.geolayout.name + '),'
|
||||
|
||||
# We add Function commands to nonDeformTransformData because any skinned
|
||||
# 0x15 commands should go before them, as they are usually preceding
|
||||
# an empty transform command (of which they modify?)
|
||||
@@ -120,6 +274,9 @@ class FunctionNode:
|
||||
self.geo_func = geo_func
|
||||
self.func_param = func_param
|
||||
self.hasDL = False
|
||||
|
||||
def size(self):
|
||||
return 8
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_CALL_ASM, 0x00])
|
||||
@@ -136,6 +293,9 @@ class HeldObjectNode:
|
||||
self.geo_func = geo_func
|
||||
self.translate = translate
|
||||
self.hasDL = False
|
||||
|
||||
def size(self):
|
||||
return 12
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_HELD_OBJECT, 0x00])
|
||||
@@ -155,6 +315,9 @@ class StartNode:
|
||||
def __init__(self):
|
||||
self.hasDL = False
|
||||
|
||||
def size(self):
|
||||
return 4
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_START, 0x00, 0x00, 0x00])
|
||||
return command
|
||||
@@ -165,6 +328,9 @@ class StartNode:
|
||||
class EndNode:
|
||||
def __init__(self):
|
||||
self.hasDL = False
|
||||
|
||||
def size(self):
|
||||
return 4
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_END, 0x00, 0x00, 0x00])
|
||||
@@ -178,10 +344,14 @@ class EndNode:
|
||||
# Afterward, for each switch node the node hierarchy is duplicated and
|
||||
# the correct diplsay lists are added.
|
||||
class SwitchNode:
|
||||
def __init__(self, geo_func, func_param):
|
||||
def __init__(self, geo_func, func_param, name):
|
||||
self.switchFunc = geo_func
|
||||
self.defaultCase = func_param
|
||||
self.hasDL = False
|
||||
self.name = name
|
||||
|
||||
def size(self):
|
||||
return 8
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_SWITCH, 0x00])
|
||||
@@ -206,6 +376,20 @@ class TranslateRotateNode:
|
||||
|
||||
self.fMesh = None
|
||||
self.DLmicrocode = None
|
||||
|
||||
def size(self):
|
||||
if self.fieldLayout == 0:
|
||||
size = 16
|
||||
elif self.fieldLayout == 1:
|
||||
size = 8
|
||||
elif self.fieldLayout == 2:
|
||||
size = 8
|
||||
elif self.fieldLayout == 3:
|
||||
size = 4
|
||||
|
||||
if self.hasDL:
|
||||
size += 4
|
||||
return size
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
params = ((1 if self.hasDL else 0) << 7) & \
|
||||
@@ -284,6 +468,9 @@ class TranslateNode:
|
||||
self.translate = translate
|
||||
self.fMesh = None
|
||||
self.DLmicrocode = None
|
||||
|
||||
def size(self):
|
||||
return 12 if self.hasDL else 8
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
params = ((1 if self.hasDL else 0) << 7) | self.drawLayer
|
||||
@@ -316,6 +503,9 @@ class RotateNode:
|
||||
self.rotate = rotate
|
||||
self.fMesh = None
|
||||
self.DLmicrocode = None
|
||||
|
||||
def size(self):
|
||||
return 12 if self.hasDL else 8
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
params = ((1 if self.hasDL else 0) << 7) | self.drawLayer
|
||||
@@ -349,6 +539,9 @@ class BillboardNode:
|
||||
self.translate = translate
|
||||
self.fMesh = None
|
||||
self.DLmicrocode = None
|
||||
|
||||
def size(self):
|
||||
return 12 if self.hasDL else 8
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
params = ((1 if self.hasDL else 0) << 7) | self.drawLayer
|
||||
@@ -377,6 +570,9 @@ class DisplayListNode:
|
||||
self.hasDL = True
|
||||
self.fMesh = None
|
||||
self.DLmicrocode = None
|
||||
|
||||
def size(self):
|
||||
return 8
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
if self.DLmicrocode is None:
|
||||
@@ -400,6 +596,9 @@ class ShadowNode:
|
||||
self.shadowScale = shadow_scale
|
||||
self.hasDL = False
|
||||
|
||||
def size(self):
|
||||
return 8
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_START_W_SHADOW, 0x00])
|
||||
command.extend(self.shadowType.to_bytes(2, 'big'))
|
||||
@@ -421,6 +620,9 @@ class ScaleNode:
|
||||
self.fMesh = None
|
||||
self.DLmicrocode = None
|
||||
|
||||
def size(self):
|
||||
return 12 if self.hasDL else 8
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
params = ((1 if self.hasDL else 0) << 7) | self.drawLayer
|
||||
command = bytearray([GEO_SCALE, params, 0x00, 0x00])
|
||||
@@ -442,6 +644,9 @@ class StartRenderAreaNode:
|
||||
def __init__(self, cullingRadius):
|
||||
self.cullingRadius = cullingRadius
|
||||
self.hasDL = False
|
||||
|
||||
def size(self):
|
||||
return 4
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_START_W_RENDERAREA, 0x00])
|
||||
@@ -458,6 +663,9 @@ class DisplayListWithOffsetNode:
|
||||
self.translate = translate
|
||||
self.fMesh = None
|
||||
self.DLmicrocode = None
|
||||
|
||||
def size(self):
|
||||
return 12
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_LOAD_DL_W_OFFSET, self.drawLayer])
|
||||
@@ -478,22 +686,25 @@ class DisplayListWithOffsetNode:
|
||||
(self.DLmicrocode.name if self.hasDL else 'NULL') + '),'
|
||||
|
||||
class ScreenAreaNode:
|
||||
def __init__(self, useDefaults, entryMinus2Count, position, size):
|
||||
def __init__(self, useDefaults, entryMinus2Count, position, dimensions):
|
||||
self.useDefaults = useDefaults
|
||||
self.entryMinus2Count = entryMinus2Count
|
||||
self.position = position
|
||||
self.size = size
|
||||
self.dimensions = dimensions
|
||||
|
||||
def size(self):
|
||||
return 12
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
position = [160, 120] if self.useDefaults else self.position
|
||||
size = [160, 120] if self.useDefaults else self.size
|
||||
dimensions = [160, 120] if self.useDefaults else self.dimensions
|
||||
entryMinus2Count = 0xA if self.useDefaults else self.entryMinus2Count
|
||||
command = bytearray([GEO_SET_RENDER_AREA, 0x00])
|
||||
command.extend(entryMinus2Count.to_bytes(2, 'big', signed = False))
|
||||
command.extend(position[0].to_bytes(2, 'big', signed = True))
|
||||
command.extend(position[1].to_bytes(2, 'big', signed = True))
|
||||
command.extend(size[0].to_bytes(2, 'big', signed = True))
|
||||
command.extend(size[1].to_bytes(2, 'big', signed = True))
|
||||
command.extend(dimensions[0].to_bytes(2, 'big', signed = True))
|
||||
command.extend(dimensions[1].to_bytes(2, 'big', signed = True))
|
||||
return command
|
||||
|
||||
def to_c(self):
|
||||
@@ -504,11 +715,15 @@ class ScreenAreaNode:
|
||||
else:
|
||||
return 'GEO_NODE_SCREEN_AREA(' + str(self.entryMinus2Count) +\
|
||||
', ' + str(self.position[0]) + ', ' + str(self.position[1]) +\
|
||||
', ' + str(self.size[0]) + ', ' + str(self.size[1]) + '),'
|
||||
', ' + str(self.dimensions[0]) + ', ' + \
|
||||
str(self.dimensions[1]) + '),'
|
||||
|
||||
class OrthoNode:
|
||||
def __init__(self, scale):
|
||||
self.scale = scale
|
||||
|
||||
def size(self):
|
||||
return 4
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_SET_ORTHO, 0x00])
|
||||
@@ -524,19 +739,24 @@ class FrustumNode:
|
||||
self.fov = fov
|
||||
self.near = int(round(100 * near))
|
||||
self.far = int(round(100 * far))
|
||||
self.useFunc = True # Always use function?
|
||||
|
||||
def size(self):
|
||||
return 12 if self.useFunc else 8
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_SET_CAMERA_FRUSTRUM, 0x00])
|
||||
command = bytearray([GEO_SET_CAMERA_FRUSTRUM,
|
||||
0x01 if self.useFunc else 0x00])
|
||||
command.extend(bytearray(struct.pack(">f", self.fov)))
|
||||
command.extend(self.near.to_bytes(2, 'big', signed = True)) # Conversion?
|
||||
command.extend(self.far.to_bytes(2, 'big', signed = True)) # Conversion?
|
||||
|
||||
if True: # Always use function?
|
||||
if self.useFunc:
|
||||
command.extend(bytes.fromhex('8029AA3C'))
|
||||
return command
|
||||
|
||||
def to_c(self):
|
||||
if False: # Always use function?
|
||||
if not self.useFunc:
|
||||
return 'GEO_CAMERA_FRUSTUM(' + format(self.fov, '.4f') +\
|
||||
', ' + str(self.near) + ', ' + str(self.far) + '),'
|
||||
else:
|
||||
@@ -547,6 +767,9 @@ class FrustumNode:
|
||||
class ZBufferNode:
|
||||
def __init__(self, enable):
|
||||
self.enable = enable
|
||||
|
||||
def size(self):
|
||||
return 4
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_SET_Z_BUF, 0x01 if self.enable else 0x00,
|
||||
@@ -564,6 +787,9 @@ class CameraNode:
|
||||
self.lookAt = \
|
||||
[int(round(value / sm64ToBlenderScale)) for value in lookAt]
|
||||
|
||||
def size(self):
|
||||
return 20
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_CAMERA, 0x00])
|
||||
command.extend(self.camType.to_bytes(2, 'big', signed = True))
|
||||
@@ -589,6 +815,9 @@ class CameraNode:
|
||||
class RenderObjNode:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def size(self):
|
||||
return 4
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_SETUP_OBJ_RENDER, 0x00, 0x00, 0x00])
|
||||
@@ -601,6 +830,9 @@ class BackgroundNode:
|
||||
def __init__(self, isColor, backgroundValue):
|
||||
self.isColor = isColor
|
||||
self.backgroundValue = backgroundValue
|
||||
|
||||
def size(self):
|
||||
return 8
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_SET_BG, 0x00])
|
||||
@@ -623,6 +855,9 @@ class BackgroundNode:
|
||||
class EnvFunctionNode:
|
||||
def __init__(self, index):
|
||||
self.index = index
|
||||
|
||||
def size(self):
|
||||
return 8
|
||||
|
||||
def to_binary(self, segmentData):
|
||||
command = bytearray([GEO_CALL_ASM, 0x00])
|
||||
|
||||
@@ -26,7 +26,8 @@ def findStartBone(armatureObj):
|
||||
(poseBone.bone_group.name != "SwitchOption" and \
|
||||
poseBone.bone_group.name != "Ignore"):
|
||||
return poseBone.name
|
||||
raise ValueError("No non switch option start bone could be found.")
|
||||
raise ValueError("No non switch option start bone could be found " +\
|
||||
'in ' + armatureObj.name + '. Is this the root armature?')
|
||||
|
||||
def prepareGeolayoutExport(armatureObj, obj):
|
||||
# Make object and armature space the same.
|
||||
@@ -89,19 +90,23 @@ def convertArmatureToGeolayout(armatureObj, obj, convertTransformMatrix,
|
||||
mathutils.Matrix.Diagonal(armatureObj.scale).to_4x4()
|
||||
|
||||
# Start geolayout
|
||||
geolayout = Geolayout(armatureObj.name)
|
||||
if camera is not None:
|
||||
geolayoutGraph = GeolayoutGraph(armatureObj.name + '_level')
|
||||
cameraObj = getCameraObj(camera)
|
||||
rootNode = saveCameraSettingsToGeolayout(
|
||||
geolayout, cameraObj, armatureObj)
|
||||
meshGeolayout = saveCameraSettingsToGeolayout(
|
||||
geolayoutGraph, cameraObj, armatureObj)
|
||||
else:
|
||||
geolayoutGraph = GeolayoutGraph(armatureObj.name)
|
||||
rootNode = TransformNode(StartNode())
|
||||
geolayout.nodes.append(rootNode)
|
||||
geolayoutGraph.startGeolayout.nodes.append(rootNode)
|
||||
meshGeolayout = geolayoutGraph.startGeolayout
|
||||
processBone(fModel, startBoneName, obj, armatureObj,
|
||||
convertTransformMatrix, None, None, None, rootNode, [], '',
|
||||
geolayout, infoDict)
|
||||
generateSwitchOptions(geolayout.nodes[0])
|
||||
return geolayout, fModel
|
||||
convertTransformMatrix, None, None, None, meshGeolayout.nodes[0],
|
||||
[], '', meshGeolayout, geolayoutGraph, infoDict)
|
||||
generateSwitchOptions(meshGeolayout.nodes[0], meshGeolayout, geolayoutGraph,
|
||||
'')
|
||||
geolayoutGraph.generateSortedList()
|
||||
return geolayoutGraph, fModel
|
||||
|
||||
def selectMeshChildrenOnly(obj):
|
||||
obj.select_set(True)
|
||||
@@ -119,15 +124,16 @@ def convertObjectToGeolayout(obj, convertTransformMatrix,
|
||||
# mathutils.Matrix.Diagonal(obj.scale).to_4x4()
|
||||
|
||||
# Start geolayout
|
||||
geolayout = Geolayout(obj.name)
|
||||
if camera is not None:
|
||||
geolayoutGraph = GeolayoutGraph(obj.name + '_level')
|
||||
cameraObj = getCameraObj(camera)
|
||||
rootNode = saveCameraSettingsToGeolayout(
|
||||
geolayout, cameraObj, obj)
|
||||
meshGeolayout = saveCameraSettingsToGeolayout(
|
||||
geolayoutGraph, cameraObj, obj)
|
||||
else:
|
||||
geolayoutGraph = GeolayoutGraph(obj.name)
|
||||
rootNode = TransformNode(StartNode())
|
||||
geolayout.nodes.append(rootNode)
|
||||
geolayout.nodes.append(TransformNode(StartNode()))
|
||||
geolayoutGraph.startGeolayout.nodes.append(rootNode)
|
||||
meshGeolayout = geolayoutGraph.startGeolayout
|
||||
|
||||
# Duplicate objects to apply scale / modifiers / linked data
|
||||
bpy.ops.object.select_all(action = 'DESELECT')
|
||||
@@ -148,7 +154,8 @@ def convertObjectToGeolayout(obj, convertTransformMatrix,
|
||||
bpy.ops.object.modifier_apply(apply_as='DATA',
|
||||
modifier=modifier.name)
|
||||
processMesh(fModel, tempObj, convertTransformMatrix,
|
||||
rootNode, True)
|
||||
meshGeolayout.nodes[0], True, geolayoutGraph.startGeolayout,
|
||||
geolayoutGraph)
|
||||
cleanupDuplicatedObjects(allObjs)
|
||||
obj.select_set(True)
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
@@ -158,26 +165,27 @@ def convertObjectToGeolayout(obj, convertTransformMatrix,
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
raise Exception(str(e))
|
||||
|
||||
return geolayout, fModel
|
||||
geolayoutGraph.generateSortedList()
|
||||
return geolayoutGraph, fModel
|
||||
|
||||
# C Export
|
||||
def exportGeolayoutArmatureC(armatureObj, obj, convertTransformMatrix,
|
||||
f3dType, isHWv1, dirPath, texDir, savePNG, texSeparate, camera):
|
||||
geolayout, fModel = convertArmatureToGeolayout(armatureObj, obj,
|
||||
geolayoutGraph, fModel = convertArmatureToGeolayout(armatureObj, obj,
|
||||
convertTransformMatrix, f3dType, isHWv1, camera)
|
||||
|
||||
saveGeolayoutC(armatureObj.name, geolayout, fModel, dirPath, texDir,
|
||||
saveGeolayoutC(armatureObj.name, geolayoutGraph, fModel, dirPath, texDir,
|
||||
savePNG, texSeparate)
|
||||
|
||||
def exportGeolayoutObjectC(obj, convertTransformMatrix,
|
||||
f3dType, isHWv1, dirPath, texDir, savePNG, texSeparate, camera):
|
||||
geolayout, fModel = convertObjectToGeolayout(obj,
|
||||
geolayoutGraph, fModel = convertObjectToGeolayout(obj,
|
||||
convertTransformMatrix, f3dType, isHWv1, camera)
|
||||
|
||||
saveGeolayoutC(obj.name, geolayout, fModel, dirPath, texDir,
|
||||
saveGeolayoutC(obj.name, geolayoutGraph, fModel, dirPath, texDir,
|
||||
savePNG, texSeparate)
|
||||
|
||||
def saveGeolayoutC(dirName, geolayout, fModel, dirPath, texDir, savePNG,
|
||||
def saveGeolayoutC(dirName, geolayoutGraph, fModel, dirPath, texDir, savePNG,
|
||||
texSeparate):
|
||||
geoDirPath = os.path.join(dirPath, toAlnum(dirName))
|
||||
|
||||
@@ -196,13 +204,13 @@ def saveGeolayoutC(dirName, geolayout, fModel, dirPath, texDir, savePNG,
|
||||
dlFile.close()
|
||||
|
||||
geoPath = os.path.join(geoDirPath, 'geo.inc.c')
|
||||
geoData = geolayout.to_c()
|
||||
geoData = geolayoutGraph.to_c()
|
||||
geoFile = open(geoPath, 'w')
|
||||
geoFile.write(geoData)
|
||||
geoFile.close()
|
||||
|
||||
headerPath = os.path.join(geoDirPath, 'header.h')
|
||||
cDefine = geolayout.to_c_def() + fModel.to_c_def()
|
||||
cDefine = geolayoutGraph.to_c_def() + fModel.to_c_def()
|
||||
cDefFile = open(headerPath, 'w')
|
||||
cDefFile.write(cDefine)
|
||||
cDefFile.close()
|
||||
@@ -213,29 +221,32 @@ def exportGeolayoutArmatureBinaryBank0(romfile, armatureObj, obj, exportRange,
|
||||
convertTransformMatrix, levelCommandPos, modelID, textDumpFilePath,
|
||||
f3dType, isHWv1, RAMAddr, camera):
|
||||
|
||||
geolayout, fModel = convertArmatureToGeolayout(armatureObj, obj,
|
||||
geolayoutGraph, fModel = convertArmatureToGeolayout(armatureObj, obj,
|
||||
convertTransformMatrix, f3dType, isHWv1, camera)
|
||||
|
||||
return saveGeolayoutBinaryBank0(romfile, fModel, geolayout, exportRange,
|
||||
levelCommandPos, modelID, textDumpFilePath, f3dType, isHWv1, RAMAddr)
|
||||
return saveGeolayoutBinaryBank0(romfile, fModel, geolayoutGraph,
|
||||
exportRange, levelCommandPos, modelID, textDumpFilePath,
|
||||
f3dType, isHWv1, RAMAddr)
|
||||
|
||||
def exportGeolayoutObjectBinaryBank0(romfile, obj, exportRange,
|
||||
convertTransformMatrix, levelCommandPos, modelID, textDumpFilePath,
|
||||
f3dType, isHWv1, RAMAddr, camera):
|
||||
|
||||
geolayout, fModel = convertObjectToGeolayout(obj,
|
||||
geolayoutGraph, fModel = convertObjectToGeolayout(obj,
|
||||
convertTransformMatrix, f3dType, isHWv1, camera)
|
||||
|
||||
return saveGeolayoutBinaryBank0(romfile, fModel, geolayout, exportRange,
|
||||
levelCommandPos, modelID, textDumpFilePath, f3dType, isHWv1, RAMAddr)
|
||||
return saveGeolayoutBinaryBank0(romfile, fModel, geolayoutGraph,
|
||||
exportRange, levelCommandPos, modelID, textDumpFilePath,
|
||||
f3dType, isHWv1, RAMAddr)
|
||||
|
||||
def saveGeolayoutBinaryBank0(romfile, fModel, geolayout, exportRange,
|
||||
def saveGeolayoutBinaryBank0(romfile, fModel, geolayoutGraph, exportRange,
|
||||
levelCommandPos, modelID, textDumpFilePath, f3dType, isHWv1, RAMAddr):
|
||||
fModel.freePalettes()
|
||||
segmentData = copy.copy(bank0Segment)
|
||||
startRAM = get64bitAlignedAddr(RAMAddr)
|
||||
nonGeoStartAddr = startRAM + len(geolayout.to_binary(None))
|
||||
nonGeoStartAddr = startRAM + geolayoutGraph.size()
|
||||
|
||||
geolayoutGraph.set_addr(startRAM)
|
||||
addrRange = fModel.set_addr(nonGeoStartAddr)
|
||||
addrEndInROM = addrRange[1] - startRAM + exportRange[0]
|
||||
if addrEndInROM > exportRange[1]:
|
||||
@@ -243,8 +254,7 @@ def saveGeolayoutBinaryBank0(romfile, fModel, geolayout, exportRange,
|
||||
', which is larger than the specified range.')
|
||||
bytesIO = BytesIO()
|
||||
#actualRAMAddr = get64bitAlignedAddr(RAMAddr)
|
||||
bytesIO.seek(startRAM)
|
||||
bytesIO.write(geolayout.to_binary(segmentData))
|
||||
geolayoutGraph.save_binary(bytesIO, segmentData)
|
||||
fModel.save_binary(bytesIO, segmentData)
|
||||
|
||||
data = bytesIO.getvalue()[startRAM:]
|
||||
@@ -254,11 +264,13 @@ def saveGeolayoutBinaryBank0(romfile, fModel, geolayout, exportRange,
|
||||
romfile.seek(startAddress)
|
||||
romfile.write(data)
|
||||
|
||||
segPointerData = encodeSegmentedAddr(startRAM, segmentData)
|
||||
geoStart = geolayoutGraph.startGeolayout.startAddress
|
||||
segPointerData = encodeSegmentedAddr(geoStart, segmentData)
|
||||
geoWriteLevelCommand(romfile, segPointerData, levelCommandPos, modelID)
|
||||
geoWriteTextDump(textDumpFilePath, geolayout, segmentData)
|
||||
geoWriteTextDump(textDumpFilePath, geolayoutGraph, segmentData)
|
||||
|
||||
return ((startAddress, startAddress + len(data)), startRAM + 0x80000000)
|
||||
return ((startAddress, startAddress + len(data)), startRAM + 0x80000000,
|
||||
geoStart + 0x80000000)
|
||||
|
||||
|
||||
# Binary Export
|
||||
@@ -266,10 +278,10 @@ def exportGeolayoutArmatureBinary(romfile, armatureObj, obj, exportRange,
|
||||
convertTransformMatrix, levelData, levelCommandPos, modelID,
|
||||
textDumpFilePath, f3dType, isHWv1, camera):
|
||||
|
||||
geolayout, fModel = convertArmatureToGeolayout(armatureObj, obj,
|
||||
geolayoutGraph, fModel = convertArmatureToGeolayout(armatureObj, obj,
|
||||
convertTransformMatrix, f3dType, isHWv1, camera)
|
||||
|
||||
return saveGeolayoutBinary(romfile, geolayout, fModel, exportRange,
|
||||
return saveGeolayoutBinary(romfile, geolayoutGraph, fModel, exportRange,
|
||||
convertTransformMatrix, levelData, levelCommandPos, modelID,
|
||||
textDumpFilePath, f3dType, isHWv1)
|
||||
|
||||
@@ -277,14 +289,14 @@ def exportGeolayoutObjectBinary(romfile, obj, exportRange,
|
||||
convertTransformMatrix, levelData, levelCommandPos, modelID,
|
||||
textDumpFilePath, f3dType, isHWv1, camera):
|
||||
|
||||
geolayout, fModel = convertObjectToGeolayout(obj,
|
||||
geolayoutGraph, fModel = convertObjectToGeolayout(obj,
|
||||
convertTransformMatrix, f3dType, isHWv1, camera)
|
||||
|
||||
return saveGeolayoutBinary(romfile, geolayout, fModel, exportRange,
|
||||
return saveGeolayoutBinary(romfile, geolayoutGraph, fModel, exportRange,
|
||||
convertTransformMatrix, levelData, levelCommandPos, modelID,
|
||||
textDumpFilePath, f3dType, isHWv1)
|
||||
|
||||
def saveGeolayoutBinary(romfile, geolayout, fModel, exportRange,
|
||||
def saveGeolayoutBinary(romfile, geolayoutGraph, fModel, exportRange,
|
||||
convertTransformMatrix, levelData, levelCommandPos, modelID,
|
||||
textDumpFilePath, f3dType, isHWv1):
|
||||
fModel.freePalettes()
|
||||
@@ -292,19 +304,20 @@ def saveGeolayoutBinary(romfile, geolayout, fModel, exportRange,
|
||||
# Get length of data, then actually write it after relative addresses
|
||||
# are found.
|
||||
startAddress = get64bitAlignedAddr(exportRange[0])
|
||||
nonGeoStartAddr = startAddress + len(geolayout.to_binary(None))
|
||||
nonGeoStartAddr = startAddress + geolayoutGraph.size()
|
||||
|
||||
geolayoutGraph.set_addr(startAddress)
|
||||
addrRange = fModel.set_addr(nonGeoStartAddr)
|
||||
if addrRange[1] > exportRange[1]:
|
||||
raise ValueError('Size too big: Data ends at ' + hex(addrRange[1]) +\
|
||||
', which is larger than the specified range.')
|
||||
romfile.seek(startAddress)
|
||||
romfile.write(geolayout.to_binary(levelData))
|
||||
geolayoutGraph.save_binary(romfile, levelData)
|
||||
fModel.save_binary(romfile, levelData)
|
||||
|
||||
segPointerData = encodeSegmentedAddr(startAddress, levelData)
|
||||
geoStart = geolayoutGraph.startGeolayout.startAddress
|
||||
segPointerData = encodeSegmentedAddr(geoStart, levelData)
|
||||
geoWriteLevelCommand(romfile, segPointerData, levelCommandPos, modelID)
|
||||
geoWriteTextDump(textDumpFilePath, geolayout, levelData)
|
||||
geoWriteTextDump(textDumpFilePath, geolayoutGraph, levelData)
|
||||
|
||||
return (startAddress, addrRange[1]), bytesToHex(segPointerData)
|
||||
|
||||
@@ -316,10 +329,10 @@ def geoWriteLevelCommand(romfile, segPointerData, levelCommandPos, modelID):
|
||||
romfile.seek(levelCommandPos + 4)
|
||||
romfile.write(segPointerData)
|
||||
|
||||
def geoWriteTextDump(textDumpFilePath, geolayout, levelData):
|
||||
def geoWriteTextDump(textDumpFilePath, geolayoutGraph, levelData):
|
||||
if textDumpFilePath is not None:
|
||||
openfile = open(textDumpFilePath, 'w')
|
||||
openfile.write(geolayout.toTextDump(levelData))
|
||||
openfile.write(geolayoutGraph.toTextDump(levelData))
|
||||
openfile.close()
|
||||
|
||||
# Switch Handling Process
|
||||
@@ -330,11 +343,19 @@ def geoWriteTextDump(textDumpFilePath, geolayout, levelData):
|
||||
|
||||
# Afterward, the node hierarchy is traversed again, and any SwitchOverride
|
||||
# nodes are converted to actual geolayout node hierarchies.
|
||||
def generateSwitchOptions(transformNode):
|
||||
def generateSwitchOptions(transformNode, geolayout, geolayoutGraph, prefix):
|
||||
if isinstance(transformNode.node, JumpNode):
|
||||
for node in transformNode.node.geolayout.nodes:
|
||||
generateSwitchOptions(node, transformNode.node.geolayout,
|
||||
geolayoutGraph, prefix)
|
||||
overrideNodes = []
|
||||
if isinstance(transformNode.node, SwitchNode):
|
||||
switchName = transformNode.node.name
|
||||
prefix += '_' + switchName
|
||||
#prefix = switchName
|
||||
i = 0
|
||||
while i < len(transformNode.children):
|
||||
prefixName = prefix + '_opt' + str(i)
|
||||
childNode = transformNode.children[i]
|
||||
if isinstance(childNode.node, SwitchOverrideNode):
|
||||
drawLayer = childNode.node.drawLayer
|
||||
@@ -343,24 +364,55 @@ def generateSwitchOptions(transformNode):
|
||||
overrideType = childNode.node.overrideType
|
||||
|
||||
# This should be a 0xB node
|
||||
copyNode = duplicateNode(transformNode.children[0],
|
||||
transformNode, transformNode.children.index(childNode))
|
||||
#copyNode = duplicateNode(transformNode.children[0],
|
||||
# transformNode, transformNode.children.index(childNode))
|
||||
index = transformNode.children.index(childNode)
|
||||
transformNode.children.remove(childNode)
|
||||
|
||||
# Switch option bones should have unique names across all
|
||||
# armatures.
|
||||
optionGeolayout = geolayoutGraph.addGeolayout(
|
||||
childNode, prefixName)
|
||||
geolayoutGraph.addJumpNode(transformNode, geolayout,
|
||||
optionGeolayout, index)
|
||||
optionGeolayout.nodes.append(TransformNode(StartNode()))
|
||||
copyNode = optionGeolayout.nodes[0]
|
||||
|
||||
#i -= 1
|
||||
# Assumes each switch child has only one child
|
||||
for overrideChild in transformNode.children[0].children:
|
||||
generateOverrideHierarchy(copyNode, overrideChild,
|
||||
material, specificMat, overrideType, drawLayer, index)
|
||||
# Assumes first child is a jump node to option 0
|
||||
# assumes overrideChild starts with a Start node
|
||||
option0Nodes = transformNode.children[0].node.geolayout.nodes
|
||||
if len(option0Nodes) == 1 and \
|
||||
isinstance(option0Nodes[0].node, StartNode):
|
||||
for startChild in option0Nodes[0].children:
|
||||
generateOverrideHierarchy(copyNode, startChild,
|
||||
material, specificMat, overrideType, drawLayer,
|
||||
option0Nodes[0].children.index(startChild),
|
||||
optionGeolayout, geolayoutGraph,
|
||||
optionGeolayout.name)
|
||||
else:
|
||||
for overrideChild in option0Nodes:
|
||||
generateOverrideHierarchy(copyNode, overrideChild,
|
||||
material, specificMat, overrideType, drawLayer,
|
||||
option0Nodes.index(overrideChild),
|
||||
optionGeolayout, geolayoutGraph,
|
||||
optionGeolayout.name)
|
||||
if material is not None:
|
||||
overrideNodes.append(copyNode)
|
||||
i += 1
|
||||
for childNode in transformNode.children:
|
||||
for i in range(len(transformNode.children)):
|
||||
childNode = transformNode.children[i]
|
||||
if isinstance(transformNode.node, SwitchNode):
|
||||
prefixName = prefix + '_opt' + str(i)
|
||||
else:
|
||||
prefixName = prefix
|
||||
|
||||
if childNode not in overrideNodes:
|
||||
generateSwitchOptions(childNode)
|
||||
generateSwitchOptions(childNode, geolayout, geolayoutGraph, prefixName)
|
||||
|
||||
def generateOverrideHierarchy(parentCopyNode, transformNode,
|
||||
material, specificMat, overrideType, drawLayer, index):
|
||||
material, specificMat, overrideType, drawLayer, index, geolayout,
|
||||
geolayoutGraph, switchOptionName):
|
||||
#print(transformNode.node)
|
||||
if isinstance(transformNode.node, SwitchOverrideNode) and \
|
||||
material is not None:
|
||||
@@ -369,7 +421,29 @@ def generateOverrideHierarchy(parentCopyNode, transformNode,
|
||||
copyNode = TransformNode(copy.copy(transformNode.node))
|
||||
copyNode.parent = parentCopyNode
|
||||
parentCopyNode.children.insert(index, copyNode)
|
||||
if not isinstance(copyNode.node, SwitchOverrideNode) and\
|
||||
if isinstance(transformNode.node, JumpNode):
|
||||
jumpName = switchOptionName + '_jump_' +\
|
||||
transformNode.node.geolayout.name
|
||||
jumpGeolayout = geolayoutGraph.addGeolayout(transformNode, jumpName)
|
||||
oldGeolayout = copyNode.node.geolayout
|
||||
copyNode.node.geolayout = jumpGeolayout
|
||||
geolayoutGraph.addGeolayoutCall(geolayout, jumpGeolayout)
|
||||
startNode = TransformNode(StartNode())
|
||||
jumpGeolayout.nodes.append(startNode)
|
||||
if len(oldGeolayout.nodes) == 1 and \
|
||||
isinstance(oldGeolayout.nodes[0].node, StartNode):
|
||||
for node in oldGeolayout.nodes[0].children:
|
||||
generateOverrideHierarchy(startNode, node, material, specificMat,
|
||||
overrideType, drawLayer,
|
||||
oldGeolayout.nodes[0].children.index(node),
|
||||
jumpGeolayout, geolayoutGraph, jumpName)
|
||||
else:
|
||||
for node in oldGeolayout.nodes:
|
||||
generateOverrideHierarchy(startNode, node, material, specificMat,
|
||||
overrideType, drawLayer, oldGeolayout.nodes.index(node),
|
||||
jumpGeolayout, geolayoutGraph, jumpName)
|
||||
|
||||
elif not isinstance(copyNode.node, SwitchOverrideNode) and\
|
||||
copyNode.node.hasDL:
|
||||
if material is not None:
|
||||
copyNode.node.DLmicrocode = \
|
||||
@@ -378,8 +452,9 @@ def generateOverrideHierarchy(parentCopyNode, transformNode,
|
||||
copyNode.node.drawLayer = drawLayer
|
||||
|
||||
for child in transformNode.children:
|
||||
generateOverrideHierarchy(copyNode, child, material, specificMat, overrideType,
|
||||
drawLayer, transformNode.children.index(child))
|
||||
generateOverrideHierarchy(copyNode, child, material, specificMat,
|
||||
overrideType, drawLayer, transformNode.children.index(child),
|
||||
geolayout, geolayoutGraph, switchOptionName)
|
||||
|
||||
def addStartNode(transformNode):
|
||||
optionNode = TransformNode(StartNode())
|
||||
@@ -411,7 +486,8 @@ def addPreRenderAreaNode(parentTransformNode, cullingRadius):
|
||||
|
||||
# This function should be called on a copy of an object
|
||||
# The copy will have modifiers / scale applied and will be made single user
|
||||
def processMesh(fModel, obj, transformMatrix, parentTransformNode, isRoot):
|
||||
def processMesh(fModel, obj, transformMatrix, parentTransformNode,
|
||||
geolayout, geolayoutGraph, isRoot):
|
||||
#finalTransform = copy.deepcopy(transformMatrix)
|
||||
|
||||
if not isinstance(obj.data, bpy.types.Mesh):
|
||||
@@ -465,7 +541,8 @@ def processMesh(fModel, obj, transformMatrix, parentTransformNode, isRoot):
|
||||
transformNode.parent = parentTransformNode
|
||||
|
||||
for childObj in obj.children:
|
||||
processMesh(fModel, childObj, transformMatrix, transformNode, False)
|
||||
processMesh(fModel, childObj, transformMatrix, transformNode,
|
||||
geolayout, geolayoutGraph, False)
|
||||
|
||||
# need to remember last geometry holding parent bone.
|
||||
# to do skinning, add the 0x15 command before any non-geometry bone groups.
|
||||
@@ -484,7 +561,7 @@ def processMesh(fModel, obj, transformMatrix, parentTransformNode, isRoot):
|
||||
|
||||
def processBone(fModel, boneName, obj, armatureObj, transformMatrix,
|
||||
lastTranslateName, lastRotateName, lastDeformName, parentTransformNode,
|
||||
materialOverrides, namePrefix, geolayout, infoDict):
|
||||
materialOverrides, namePrefix, geolayout, geolayoutGraph, infoDict):
|
||||
bone = armatureObj.data.bones[boneName]
|
||||
poseBone = armatureObj.pose.bones[boneName]
|
||||
boneGroup = poseBone.bone_group
|
||||
@@ -549,7 +626,7 @@ def processBone(fModel, boneName, obj, armatureObj, transformMatrix,
|
||||
if bone.geo_func == '':
|
||||
raise ValueError('Switch bone ' + boneName + \
|
||||
' function value is empty.')
|
||||
node = SwitchNode(bone.geo_func, bone.func_param)
|
||||
node = SwitchNode(bone.geo_func, bone.func_param, boneName)
|
||||
processSwitchBoneMatOverrides(materialOverrides, bone)
|
||||
|
||||
elif boneGroup.name == 'Start':
|
||||
@@ -613,7 +690,6 @@ def processBone(fModel, boneName, obj, armatureObj, transformMatrix,
|
||||
|
||||
transformNode = TransformNode(node)
|
||||
|
||||
# TODO: HERE!!!
|
||||
if node.hasDL:
|
||||
meshGroup = saveModelGivenVertexGroup(
|
||||
fModel, obj, bone.name, lastDeformName,
|
||||
@@ -646,36 +722,48 @@ def processBone(fModel, boneName, obj, armatureObj, transformMatrix,
|
||||
else:
|
||||
parentTransformNode.children.append(transformNode)
|
||||
transformNode.parent = parentTransformNode
|
||||
|
||||
isSwitch = isinstance(transformNode.node, SwitchNode)
|
||||
if isSwitch:
|
||||
switchTransformNode = transformNode
|
||||
option0Node = addStartNode(transformNode)
|
||||
#option0Node = addPreTranslateRotateNode(armatureObj, transformNode,
|
||||
# mathutils.Vector((0,0,0)), mathutils.Quaternion())
|
||||
transformNode = option0Node
|
||||
|
||||
#print(boneGroup.name if boneGroup is not None else "Offset")
|
||||
if len(bone.children) > 0:
|
||||
#print("\tHas Children")
|
||||
if boneGroup is not None and boneGroup.name == 'Function':
|
||||
raise ValueError("Function bones cannot have children. They instead affect the next sibling bone in alphabetical order.")
|
||||
if not isinstance(transformNode.node, SwitchNode):
|
||||
#print(boneGroup.name if boneGroup is not None else "Offset")
|
||||
if len(bone.children) > 0:
|
||||
#print("\tHas Children")
|
||||
if boneGroup is not None and boneGroup.name == 'Function':
|
||||
raise ValueError("Function bones cannot have children. They instead affect the next sibling bone in alphabetical order.")
|
||||
|
||||
# Handle child nodes
|
||||
# nonDeformTransformData should be modified to be sent to children,
|
||||
# otherwise it should not be modified for parent.
|
||||
# This is so it can be used for siblings.
|
||||
childrenNames = sorted([bone.name for bone in bone.children])
|
||||
for name in childrenNames:
|
||||
processBone(fModel, name, obj, armatureObj,
|
||||
finalTransform, lastTranslateName, lastRotateName,
|
||||
lastDeformName, transformNode, materialOverrides,
|
||||
namePrefix, geolayout,
|
||||
geolayoutGraph, infoDict)
|
||||
#transformNode.children.append(childNode)
|
||||
#childNode.parent = transformNode
|
||||
|
||||
# Handle child nodes
|
||||
# nonDeformTransformData should be modified to be sent to children,
|
||||
# otherwise it should not be modified for parent.
|
||||
# This is so it can be used for siblings.
|
||||
childrenNames = sorted([bone.name for bone in bone.children])
|
||||
for name in childrenNames:
|
||||
processBone(fModel, name, obj, armatureObj,
|
||||
finalTransform, lastTranslateName, lastRotateName,
|
||||
lastDeformName, transformNode, materialOverrides, namePrefix,
|
||||
geolayout, infoDict)
|
||||
#transformNode.children.append(childNode)
|
||||
#childNode.parent = transformNode
|
||||
|
||||
# see generateSwitchOptions() for explanation.
|
||||
if isSwitch:
|
||||
else:
|
||||
#print(boneGroup.name if boneGroup is not None else "Offset")
|
||||
if len(bone.children) > 0:
|
||||
optionGeolayout = \
|
||||
geolayoutGraph.addGeolayout(
|
||||
transformNode, boneName + '_opt0')
|
||||
geolayoutGraph.addJumpNode(transformNode, geolayout,
|
||||
optionGeolayout)
|
||||
optionGeolayout.nodes.append(TransformNode(StartNode()))
|
||||
childrenNames = sorted([bone.name for bone in bone.children])
|
||||
for name in childrenNames:
|
||||
processBone(fModel, name, obj, armatureObj,
|
||||
finalTransform, lastTranslateName, lastRotateName,
|
||||
lastDeformName, optionGeolayout.nodes[0], materialOverrides,
|
||||
namePrefix, optionGeolayout,
|
||||
geolayoutGraph, infoDict)
|
||||
#transformNode.children.append(childNode)
|
||||
#childNode.parent = transformNode
|
||||
|
||||
bone = armatureObj.data.bones[boneName]
|
||||
for switchIndex in range(len( bone.switch_options)):
|
||||
switchOption = bone.switch_options[switchIndex]
|
||||
@@ -689,11 +777,12 @@ def processBone(fModel, boneName, obj, armatureObj, transformMatrix,
|
||||
raise ValueError('Error: In switch bone ' + boneName +\
|
||||
' for option ' + str(switchIndex) + \
|
||||
', the object provided is not an armature.')
|
||||
elif optionArmature in geolayout.secondaryGeolayouts:
|
||||
raise ValueError('Error: In switch bone ' + boneName +\
|
||||
' for option ' + str(switchIndex) + \
|
||||
', the armature provided cannot be used more than once' + \
|
||||
' as a switch option in the entire geolayout.')
|
||||
elif optionArmature in geolayoutGraph.secondaryGeolayouts:
|
||||
optionGeolayout = geolayoutGraph.secondaryGeolayouts[
|
||||
optionArmature]
|
||||
geolayoutGraph.addJumpNode(
|
||||
transformNode, geolayout, optionGeolayout)
|
||||
continue
|
||||
|
||||
#optionNode = addStartNode(switchTransformNode)
|
||||
|
||||
@@ -704,10 +793,21 @@ def processBone(fModel, boneName, obj, armatureObj, transformMatrix,
|
||||
switchOptionRotate = mathutils.Quaternion()
|
||||
|
||||
# Armature doesn't matter here since node is not based off bone
|
||||
translateRotateNode = addPreTranslateRotateNode(
|
||||
switchTransformNode, translate, rotate @ switchOptionRotate)
|
||||
optionGeolayout = \
|
||||
geolayoutGraph.addGeolayout(
|
||||
optionArmature, optionArmature.name)
|
||||
geolayoutGraph.addJumpNode(transformNode, geolayout,
|
||||
optionGeolayout)
|
||||
|
||||
geolayout.secondaryGeolayouts[optionArmature] = translateRotateNode
|
||||
rotAxis, rotAngle = (rotate @ switchOptionRotate
|
||||
).to_axis_angle()
|
||||
if rotAngle > 0.00001 or translate.length > 0.0001:
|
||||
startNode = TransformNode(
|
||||
TranslateRotateNode(1, 0, False, translate,
|
||||
rotate @ switchOptionRotate))
|
||||
else:
|
||||
startNode = TransformNode(StartNode())
|
||||
optionGeolayout.nodes.append(startNode)
|
||||
|
||||
childrenNames = sorted(
|
||||
[bone.name for bone in optionBone.children])
|
||||
@@ -734,8 +834,9 @@ def processBone(fModel, boneName, obj, armatureObj, transformMatrix,
|
||||
processBone(fModel, name, optionObj,
|
||||
optionArmature,
|
||||
finalTransform, optionBone.name, optionBone.name,
|
||||
optionBone.name, translateRotateNode, materialOverrides,
|
||||
optionBone.name, geolayout, optionInfoDict)
|
||||
optionBone.name, startNode,
|
||||
materialOverrides, optionBone.name,
|
||||
optionGeolayout, geolayoutGraph, optionInfoDict)
|
||||
else:
|
||||
if switchOption.switchType == 'Material':
|
||||
material = switchOption.materialOverride
|
||||
@@ -757,8 +858,8 @@ def processBone(fModel, boneName, obj, armatureObj, transformMatrix,
|
||||
overrideNode = TransformNode(SwitchOverrideNode(
|
||||
material, specificMat, drawLayer,
|
||||
switchOption.materialOverrideType))
|
||||
overrideNode.parent = switchTransformNode
|
||||
switchTransformNode.children.append(overrideNode)
|
||||
overrideNode.parent = transformNode
|
||||
transformNode.children.append(overrideNode)
|
||||
|
||||
def processSwitchBoneMatOverrides(materialOverrides, switchBone):
|
||||
for switchOption in switchBone.switch_options:
|
||||
@@ -1050,11 +1151,13 @@ def saveModelGivenVertexGroup(fModel, obj, vertexGroup,
|
||||
fMeshGroup = saveSkinnedMeshByMaterial(skinnedFaces, fModel,
|
||||
vertexGroup, obj, currentMatrix, parentMatrix, namePrefix, infoDict)
|
||||
else:
|
||||
fMeshGroup = FMeshGroup(toAlnum(namePrefix + vertexGroup),
|
||||
fMeshGroup = FMeshGroup(toAlnum(namePrefix + \
|
||||
('_' if namePrefix != '' else '') + vertexGroup),
|
||||
FMesh(toAlnum(namePrefix + vertexGroup) + '_mesh'), None)
|
||||
|
||||
# Save mesh group
|
||||
checkUniqueBoneNames(fModel, toAlnum(namePrefix + vertexGroup), vertexGroup)
|
||||
checkUniqueBoneNames(fModel, toAlnum(namePrefix + \
|
||||
('_' if namePrefix != '' else '') + vertexGroup), vertexGroup)
|
||||
fModel.meshGroups[toAlnum(namePrefix + vertexGroup)] = fMeshGroup
|
||||
|
||||
# Save unskinned mesh
|
||||
|
||||
Reference in New Issue
Block a user