Add sound support, partly resolves #5
This commit is contained in:
parent
c1dcc1ff48
commit
b5df633d48
|
@ -27,7 +27,8 @@ bpy.propertyGroupLayouts = {
|
||||||
{ "name": "isWall", "type": "boolean" },
|
{ "name": "isWall", "type": "boolean" },
|
||||||
{ "name": "isBG", "type": "boolean" },
|
{ "name": "isBG", "type": "boolean" },
|
||||||
{ "name": "isSprite", "type": "boolean" },
|
{ "name": "isSprite", "type": "boolean" },
|
||||||
{ "name": "isLerp", "type": "boolean" }
|
{ "name": "isLerp", "type": "boolean" },
|
||||||
|
{ "name": "isXA", "type": "boolean" }
|
||||||
],
|
],
|
||||||
"Others": [
|
"Others": [
|
||||||
{ "name": "mass", "type": "int" }
|
{ "name": "mass", "type": "int" }
|
||||||
|
|
|
@ -79,6 +79,17 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||||
description = "By default, the script looks for / saves textures in the ./TEX folder. You can tell it to use a different folder.",
|
description = "By default, the script looks for / saves textures in the ./TEX folder. You can tell it to use a different folder.",
|
||||||
default="TEX"
|
default="TEX"
|
||||||
)
|
)
|
||||||
|
exp_XAmode = IntProperty(
|
||||||
|
name="XA mode",
|
||||||
|
description ="XA sector size : 0 = 2352, 1=2336",
|
||||||
|
min=0, max=1,
|
||||||
|
default=1
|
||||||
|
)
|
||||||
|
exp_isoCfg = StringProperty(
|
||||||
|
name="mkpsxiso config folder",
|
||||||
|
description = "Where should we look for mkpsxiso's config file ?",
|
||||||
|
default= "." + os.sep + "config" + os.sep + "3dcam.xml"
|
||||||
|
)
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
### Globals declaration
|
### Globals declaration
|
||||||
global nextTpage, freeTpage
|
global nextTpage, freeTpage
|
||||||
|
@ -86,7 +97,12 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||||
global tpageY
|
global tpageY
|
||||||
global TIMbpp
|
global TIMbpp
|
||||||
global timFolder
|
global timFolder
|
||||||
|
XAmode = self.exp_XAmode
|
||||||
|
# Set Scale
|
||||||
|
scale = self.exp_Scale
|
||||||
### Functions
|
### Functions
|
||||||
|
def psxLoc(location, scale=scale):
|
||||||
|
return round(location * scale)
|
||||||
def triangulate_object(obj):
|
def triangulate_object(obj):
|
||||||
# Triangulate an object's mesh
|
# Triangulate an object's mesh
|
||||||
# Source : https://blender.stackexchange.com/questions/45698/triangulate-mesh-in-python/45722#45722
|
# Source : https://blender.stackexchange.com/questions/45698/triangulate-mesh-in-python/45722#45722
|
||||||
|
@ -330,6 +346,231 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||||
else:
|
else:
|
||||||
linear = ( 1 + a ) * pow( component, 1 / 2.4 ) - a
|
linear = ( 1 + a ) * pow( component, 1 / 2.4 ) - a
|
||||||
return linear
|
return linear
|
||||||
|
### Sound conversion and export
|
||||||
|
class Sound:
|
||||||
|
def __init__(self, objName, soundName, soundPath, convertedSoundPath, parent, location, volume, volume_min, volume_max, index, XAfile=-1, XAchannel=-1, XAsize=-1, XAend=-1):
|
||||||
|
self.objName = objName
|
||||||
|
self.soundName = soundName
|
||||||
|
self.soundPath = soundPath
|
||||||
|
self.convertedSoundPath = convertedSoundPath
|
||||||
|
self.parent = parent
|
||||||
|
self.location = location
|
||||||
|
self.volume = volume
|
||||||
|
self.volume_min = volume_min
|
||||||
|
self.volume_max = volume_max
|
||||||
|
self.index = index
|
||||||
|
self.XAfile = XAfile
|
||||||
|
self.XAchannel = XAchannel
|
||||||
|
self.XAsize = XAsize
|
||||||
|
self.XAend = XAend
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.convertedSoundPath == other.convertedSoundPath
|
||||||
|
|
||||||
|
def sound2XA( soundPath, soundName, soundFolder="XA", bpp=4, XAfile=0, XAchannel=0 ):
|
||||||
|
# Convert sound file to XA
|
||||||
|
# exports in ./XA by default
|
||||||
|
# ffmpeg -i input.mp3 -acodec pcm_s16le -ac 2 -ar 44100 output.wav
|
||||||
|
# psxavenc -f 37800 -t xa -b 4 -c 2 -F 1 -C 0 "../hello_cdda/audio/beach.wav" "xa/beach.xa"
|
||||||
|
exe = ""
|
||||||
|
if os.name == 'nt':
|
||||||
|
exe = ".exe"
|
||||||
|
# find export folder
|
||||||
|
filepath = self.filepath
|
||||||
|
# ~ filepath = bpy.data.filepath
|
||||||
|
expFolder = os.path.dirname(bpy.path.abspath(filepath)) + os.sep + soundFolder + os.sep
|
||||||
|
# create if non-existent
|
||||||
|
if not os.path.exists(expFolder):
|
||||||
|
os.mkdir(expFolder)
|
||||||
|
# find file base name
|
||||||
|
basename = soundName.split('.')[0]
|
||||||
|
exportPath = expFolder + basename + ".xa"
|
||||||
|
# Convert to 16-B WAV
|
||||||
|
subprocess.call( [ "ffmpeg" + exe, "-i", soundPath, "-acodec", "pcm_s16le", "-ac", "2", "-ar", "44100", "-y", "/tmp/tmp.wav"] )
|
||||||
|
# Convert WAV to XA
|
||||||
|
subprocess.call( [ "psxavenc" + exe, "-f", "37800", "-t", "xa", "-b", str(bpp), "-c", "2", "-F", str(XAfile), "-C", str(XAchannel), "/tmp/tmp.wav", exportPath ] )
|
||||||
|
return exportPath
|
||||||
|
|
||||||
|
def XAmanifest(XAlist, soundFolder="XA", XAchannels=8):
|
||||||
|
# generate manifest file
|
||||||
|
# find export folder
|
||||||
|
filepath = self.filepath
|
||||||
|
expFolder = os.path.dirname(bpy.path.abspath(filepath)) + os.sep + soundFolder + os.sep
|
||||||
|
XAfiles = []
|
||||||
|
for file_index in range(len(XAlist)):
|
||||||
|
manifestFile = open(os.path.normpath(expFolder + "inter_" + str(file_index) + ".txt" ), "w+")
|
||||||
|
# ~ print("\nFile_" + str(file_index) + " :")
|
||||||
|
lines = XAchannels
|
||||||
|
for xa in XAlist[file_index]:
|
||||||
|
manifestFile.write( str(XAmode) + " xa " + xa.convertedSoundPath + " " + str(xa.XAfile) + " " + str(xa.XAchannel) + "\n" )
|
||||||
|
lines -= 1
|
||||||
|
while lines:
|
||||||
|
manifestFile.write( str(XAmode) + " null\n")
|
||||||
|
lines -= 1
|
||||||
|
manifestFile.close()
|
||||||
|
|
||||||
|
def writeIsoCfg(configFile, insertString):
|
||||||
|
# Write insertString one line above searchString
|
||||||
|
print(configFile)
|
||||||
|
print(insertString)
|
||||||
|
searchString = "<dummy sectors"
|
||||||
|
if os.path.exists(configFile):
|
||||||
|
with open(configFile,"r+") as fd:
|
||||||
|
content = fd.readlines()
|
||||||
|
for index, line in enumerate(content):
|
||||||
|
if insertString in content[index]:
|
||||||
|
break
|
||||||
|
if searchString in line and insertString not in content[index] and insertString not in content[index-1]:
|
||||||
|
content.insert(index, insertString)
|
||||||
|
break
|
||||||
|
fd.seek(0)
|
||||||
|
fd.writelines(content)
|
||||||
|
else:
|
||||||
|
print("No mkpsxiso config file were found.")
|
||||||
|
|
||||||
|
def addXAtoISO(XAinterList, configFile, soundFolder="XA"):
|
||||||
|
# Add XA file to mkpsxiso config file if it existsd
|
||||||
|
filepath = self.filepath
|
||||||
|
expFolder = os.path.dirname(bpy.path.abspath(filepath)) + os.sep + soundFolder + os.sep
|
||||||
|
for xa in range(len(XAlist)):
|
||||||
|
XAfilePath = expFolder + "inter_" + str(xa) + ".xa"
|
||||||
|
insertString = '\t\t\t<file name="INTER_' + str(xa) + '.XA" type="xa" source="' + XAfilePath + '"/>\n'
|
||||||
|
writeIsoCfg(configFile, insertString)
|
||||||
|
|
||||||
|
def XAinterleave(XAlist, soundFolder="XA"):
|
||||||
|
# Generate interleaved XA files from existing XA files referenced in soundFiles
|
||||||
|
exe = ""
|
||||||
|
if os.name == 'nt':
|
||||||
|
exe = ".exe"
|
||||||
|
# find export folder
|
||||||
|
filepath = self.filepath
|
||||||
|
for xa in range(len(XAlist)):
|
||||||
|
manifestFile = expFolder + "inter_" + str(xa) + ".txt"
|
||||||
|
outputFile = expFolder + "inter_" + str(xa) + ".xa"
|
||||||
|
subprocess.call( [ "xainterleave" + exe, str(XAmode), manifestFile, outputFile ])
|
||||||
|
|
||||||
|
def sound2VAG( soundPath, soundName, soundFolder="VAG"):
|
||||||
|
# Convert sound file to VAG
|
||||||
|
# exports in ./VAG by default
|
||||||
|
# For windows users, add '.exe' to the command
|
||||||
|
exe = ""
|
||||||
|
if os.name == 'nt':
|
||||||
|
exe = ".exe"
|
||||||
|
# find export folder
|
||||||
|
filepath = self.filepath
|
||||||
|
# ~ filepath = bpy.data.filepath
|
||||||
|
expFolder = os.path.dirname(bpy.path.abspath(filepath)) + os.sep + soundFolder + os.sep
|
||||||
|
# create if non-existent
|
||||||
|
if not os.path.exists(expFolder):
|
||||||
|
os.mkdir(expFolder)
|
||||||
|
# find file base name
|
||||||
|
basename = soundName.split('.')[0]
|
||||||
|
exportPath = expFolder + basename + ".vag"
|
||||||
|
# Convert to RAW WAV data
|
||||||
|
subprocess.call( [ "ffmpeg" + exe, "-i", soundPath, "-f", "s16le", "-ac", "1", "-ar", "44100", "-y", "/tmp/tmp.dat"] )
|
||||||
|
# Convert WAV to VAG
|
||||||
|
subprocess.call( [ "wav2vag" + exe, "/tmp/tmp.dat", exportPath, "-sraw16", "-freq=44100" ] )
|
||||||
|
return exportPath
|
||||||
|
|
||||||
|
def writeExtList(f, soundName, level_symbols):
|
||||||
|
soundName = soundName.split('.')[0]
|
||||||
|
f.write("extern u_char _binary_VAG_" + soundName + "_vag_start;\n")
|
||||||
|
|
||||||
|
def writeVAGbank(f, soundList, level_symbols):
|
||||||
|
index = 0
|
||||||
|
SPU = 0
|
||||||
|
dups = []
|
||||||
|
for file_index in range(len(soundList)):
|
||||||
|
if soundList[file_index].XAsize == -1 :
|
||||||
|
if soundList[file_index] not in dups:
|
||||||
|
writeExtList(f, soundList[file_index].soundName, level_symbols)
|
||||||
|
dups.append(soundList[file_index])
|
||||||
|
index += 1
|
||||||
|
f.write("\nVAGbank " + fileName + "_VAGBank = {\n" +
|
||||||
|
"\t" + str(index) + ",\n" +
|
||||||
|
"\t{\n")
|
||||||
|
for sound in soundList:
|
||||||
|
if sound.XAsize == -1:
|
||||||
|
f.write("\t\t{ &_binary_VAG_" + sound.soundName.split('.')[0] + "_vag_start, SPU_0" + str(SPU) + "CH, 0 }")
|
||||||
|
if SPU < index - 1:
|
||||||
|
f.write(",\n")
|
||||||
|
sound.index = SPU
|
||||||
|
SPU += 1
|
||||||
|
f.write("\n\t}\n};\n\n" )
|
||||||
|
level_symbols.append("VAGbank " + fileName + "_VAGBank")
|
||||||
|
# If SPU, we're using VAGs
|
||||||
|
return SPU
|
||||||
|
|
||||||
|
|
||||||
|
def writeXAbank(f, XAfiles, level_symbols):
|
||||||
|
index = 0
|
||||||
|
XAinter = []
|
||||||
|
# ~ soundName = objName.split('.')[0]
|
||||||
|
for file_index in range(len(XAfiles)):
|
||||||
|
if XAfiles[file_index].XAsize != -1:
|
||||||
|
index += 1
|
||||||
|
if XAfiles[file_index].XAfile not in range( len( XAinter ) ) :
|
||||||
|
XAinter.append( list() )
|
||||||
|
XAinter[ XAfiles[file_index].XAfile ].append(XAfiles[file_index])
|
||||||
|
for XAlistIndex in range(len(XAinter)):
|
||||||
|
f.write("XAbank " + fileName + "_XABank_" + str(XAlistIndex) + " = {\n" +
|
||||||
|
"\t\"\\\\INTER_" + str(XAlistIndex) + ".XA;1\",\n" +
|
||||||
|
"\t" + str(len(XAinter[XAlistIndex])) + ",\n" +
|
||||||
|
"\t0,\n" +
|
||||||
|
"\t{\n")
|
||||||
|
index = 0
|
||||||
|
for sound in XAinter[XAlistIndex]:
|
||||||
|
if sound.XAsize != -1:
|
||||||
|
f.write( "\t\t{ " + str(index) + ", " + str(sound.XAsize) + ", " + str(sound.XAfile) + ", " + str(sound.XAchannel) + ", 0, " + str(sound.XAend) + " * XA_CHANNELS, -1 },\n" )
|
||||||
|
sound.index = index
|
||||||
|
index += 1
|
||||||
|
f.write( "\t}\n};\n" )
|
||||||
|
level_symbols.append("XAbank " + fileName + "_XABank_" + str(XAlistIndex))
|
||||||
|
return XAinter
|
||||||
|
|
||||||
|
def writeXAfiles(f, XAlist, fileName):
|
||||||
|
# Write XAFiles struct
|
||||||
|
f.write("XAfiles " + fileName + "_XAFiles = {\n" +
|
||||||
|
"\t" + str(len(XAlist)) + ",\n" +
|
||||||
|
"\t{\n")
|
||||||
|
if XAlist:
|
||||||
|
for xa in range(len(XAlist)):
|
||||||
|
f.write("\t\t&" + fileName + "_XABank_" + str(xa))
|
||||||
|
if xa < len(XAlist) - 1:
|
||||||
|
f.write(",")
|
||||||
|
else:
|
||||||
|
f.write("\t\t0")
|
||||||
|
f.write("\n\t}\n};\n")
|
||||||
|
level_symbols.append("XAfiles " + fileName + "_XAFiles")
|
||||||
|
def writeSoundObj(f, soundFiles, level_symbols):
|
||||||
|
index = 0
|
||||||
|
# Write SOUND_OBJECT structures
|
||||||
|
for obj in soundFiles:
|
||||||
|
f.write("SOUND_OBJECT " + fileName + "_" + obj.objName.replace(".", "_") + " = {\n" +
|
||||||
|
"\t{" + str(psxLoc(obj.location.x)) + "," + str(psxLoc(obj.location.y)) + "," + str(psxLoc(obj.location.z)) + "},\n" +
|
||||||
|
"\t" + str(obj.volume * 0x3fff) + ", " + str(obj.volume_min * 0x3fff) + ", " + str(obj.volume_max * 0x3fff) + ",\n" )
|
||||||
|
if obj.XAsize == -1 :
|
||||||
|
f.write("\t&" + fileName + "_VAGBank.samples[" + str(obj.index) + "],\n" +
|
||||||
|
"\t0,\n")
|
||||||
|
else:
|
||||||
|
f.write("\t0,\n" +
|
||||||
|
"\t&" + fileName + "_XABank_" + str(obj.XAfile) + ".samples[" + str(obj.index) + "],\n")
|
||||||
|
if obj.parent:
|
||||||
|
f.write( "\t&" + fileName + "_mesh" + CleanName(obj.parent.name) + "\n")
|
||||||
|
else:
|
||||||
|
f.write("\t0\n")
|
||||||
|
f.write("};\n\n")
|
||||||
|
index += 1
|
||||||
|
level_symbols.append("SOUND_OBJECT " + fileName + "_" + obj.objName.replace(".", "_"))
|
||||||
|
f.write("LEVEL_SOUNDS " + fileName + "_sounds = {\n" +
|
||||||
|
"\t" + str(index) + ",\n" +
|
||||||
|
"\t{\n")
|
||||||
|
for obj in range(len(soundFiles)):
|
||||||
|
f.write( "\t\t&" + fileName + "_" + soundFiles[obj].objName.replace(".", "_"))
|
||||||
|
if obj < len(soundFiles) - 1 :
|
||||||
|
f.write(",\n")
|
||||||
|
f.write("\n\t}\n};\n\n")
|
||||||
|
level_symbols.append("LEVEL_SOUNDS " + fileName + "_sounds")
|
||||||
|
return index
|
||||||
# Set rendering resolution to 320x240
|
# Set rendering resolution to 320x240
|
||||||
bpy.context.scene.render.resolution_x = 320
|
bpy.context.scene.render.resolution_x = 320
|
||||||
bpy.context.scene.render.resolution_y = 240
|
bpy.context.scene.render.resolution_y = 240
|
||||||
|
@ -355,8 +596,6 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||||
for o in range(len(bpy.data.objects)):
|
for o in range(len(bpy.data.objects)):
|
||||||
if bpy.data.objects[o].type == 'MESH':
|
if bpy.data.objects[o].type == 'MESH':
|
||||||
triangulate_object(bpy.data.objects[o])
|
triangulate_object(bpy.data.objects[o])
|
||||||
# Set Scale
|
|
||||||
scale = self.exp_Scale
|
|
||||||
# Get export directory path
|
# Get export directory path
|
||||||
filepath = self.filepath
|
filepath = self.filepath
|
||||||
if self.exp_expMode:
|
if self.exp_expMode:
|
||||||
|
@ -478,6 +717,14 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||||
"struct CHILDREN;\n" +
|
"struct CHILDREN;\n" +
|
||||||
"struct NODE;\n" +
|
"struct NODE;\n" +
|
||||||
"struct QUAD;\n" +
|
"struct QUAD;\n" +
|
||||||
|
"struct LEVEL;\n" +
|
||||||
|
"struct VAGsound;\n" +
|
||||||
|
"struct VAGbank;\n" +
|
||||||
|
"struct XAsound;\n" +
|
||||||
|
"struct XAbank;\n" +
|
||||||
|
"struct XAfiles;\n" +
|
||||||
|
"struct SOUND_OBJECT;\n" +
|
||||||
|
"struct LEVEL_SOUNDS;\n" +
|
||||||
"\n")
|
"\n")
|
||||||
# BODY
|
# BODY
|
||||||
h.write("typedef struct BODY {\n" +
|
h.write("typedef struct BODY {\n" +
|
||||||
|
@ -581,6 +828,54 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||||
"\tCHILDREN * objects;\n" +
|
"\tCHILDREN * objects;\n" +
|
||||||
"\tCHILDREN * rigidbodies;\n" +
|
"\tCHILDREN * rigidbodies;\n" +
|
||||||
"\t} NODE;\n\n")
|
"\t} NODE;\n\n")
|
||||||
|
# SOUND
|
||||||
|
# VAG
|
||||||
|
h.write("//VAG\n" +
|
||||||
|
"typedef struct VAGsound {\n" +
|
||||||
|
"\tu_char * VAGfile; // Pointer to VAG data address\n" +
|
||||||
|
"\tu_long spu_channel; // SPU voice to playback to\n" +
|
||||||
|
"\tu_long spu_address; // SPU address for memory freeing spu mem\n" +
|
||||||
|
"\t} VAGsound;\n\n" )
|
||||||
|
|
||||||
|
h.write("typedef struct VAGbank {\n" +
|
||||||
|
"\tu_int index;\n" +
|
||||||
|
"\tVAGsound samples[];\n" +
|
||||||
|
"\t} VAGbank;\n\n")
|
||||||
|
|
||||||
|
h.write("// XA\n" +
|
||||||
|
"typedef struct XAsound {\n" +
|
||||||
|
"\tu_int id;\n" +
|
||||||
|
"\tu_int size;\n" +
|
||||||
|
"\tu_char file, channel;\n" +
|
||||||
|
"\tu_int start, end;\n" +
|
||||||
|
"\tint cursor;\n" +
|
||||||
|
"\t} XAsound;\n\n")
|
||||||
|
|
||||||
|
h.write("typedef struct XAbank {\n" +
|
||||||
|
"\tchar name[16];\n" +
|
||||||
|
"\tu_int index;\n" +
|
||||||
|
"\tint offset;\n" +
|
||||||
|
"\tXAsound samples[];\n" +
|
||||||
|
"\t} XAbank;\n\n")
|
||||||
|
|
||||||
|
h.write("typedef struct XAfiles {\n" +
|
||||||
|
"\tu_int index;\n" +
|
||||||
|
"\tXAbank * banks[];\n" +
|
||||||
|
"\t} XAfiles;\n\n" )
|
||||||
|
|
||||||
|
h.write("typedef struct SOUND_OBJECT {\n" +
|
||||||
|
"\tVECTOR location;\n" +
|
||||||
|
"\tint volume, volume_min, volume_max;\n" +
|
||||||
|
"\tVAGsound * VAGsample;\n" +
|
||||||
|
"\tXAsound * XAsample;\n" +
|
||||||
|
"\tMESH * parent;\n" +
|
||||||
|
"} SOUND_OBJECT;\n\n" )
|
||||||
|
|
||||||
|
h.write("typedef struct LEVEL_SOUNDS {\n" +
|
||||||
|
"\tint index;\n" +
|
||||||
|
"\tSOUND_OBJECT * sounds[];\n" +
|
||||||
|
"} LEVEL_SOUNDS;\n\n")
|
||||||
|
|
||||||
# LEVEL
|
# LEVEL
|
||||||
h.write("typedef struct LEVEL {\n" +
|
h.write("typedef struct LEVEL {\n" +
|
||||||
"\tCVECTOR * BGc;\n" +
|
"\tCVECTOR * BGc;\n" +
|
||||||
|
@ -596,6 +891,9 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||||
"\tCAMPATH * camPath;\n" +
|
"\tCAMPATH * camPath;\n" +
|
||||||
"\tCAMANGLE ** camAngles;\n" +
|
"\tCAMANGLE ** camAngles;\n" +
|
||||||
"\tNODE * curNode;\n" +
|
"\tNODE * curNode;\n" +
|
||||||
|
"\tLEVEL_SOUNDS * levelSounds;\n" +
|
||||||
|
"\tVAGbank * VAG;\n" +
|
||||||
|
"\tXAfiles * XA;\n" +
|
||||||
"\t} LEVEL;\n")
|
"\t} LEVEL;\n")
|
||||||
h.close()
|
h.close()
|
||||||
## Level Data (level.c)
|
## Level Data (level.c)
|
||||||
|
@ -1479,6 +1777,86 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||||
level_symbols.append( "MESH * " + fileName + "_propPtr" )
|
level_symbols.append( "MESH * " + fileName + "_propPtr" )
|
||||||
level_symbols.append( "CAMANGLE * " + fileName + "_camPtr" )
|
level_symbols.append( "CAMANGLE * " + fileName + "_camPtr" )
|
||||||
level_symbols.append( "NODE * " + fileName + "_curNode" )
|
level_symbols.append( "NODE * " + fileName + "_curNode" )
|
||||||
|
## Sound
|
||||||
|
# Build a dictionary of objects that have child SPEAKER objects
|
||||||
|
# These objects's positions will have to be updated
|
||||||
|
spkrParents = defaultdict(dict)
|
||||||
|
spkrOrphans = []
|
||||||
|
# array of Sound objects
|
||||||
|
soundFiles = []
|
||||||
|
# current XA files and channel
|
||||||
|
freeXAfile = 0
|
||||||
|
freeXAchannel = 0
|
||||||
|
for obj in bpy.data.objects:
|
||||||
|
# if obj is a speaker
|
||||||
|
if obj.type == 'SPEAKER':
|
||||||
|
if obj.data.sound is not None:
|
||||||
|
# and child of a mesh
|
||||||
|
if obj.parent is not None:
|
||||||
|
if obj.parent.type == 'MESH':
|
||||||
|
parent = obj.parent
|
||||||
|
# if parent exists in parent list, append to child list
|
||||||
|
# ~ if obj.parent.name in spkrParents:
|
||||||
|
# ~ spkrParents[obj.parent.name].append(obj.name)
|
||||||
|
# ~ else:
|
||||||
|
# if parent does not exist in list yet, create array
|
||||||
|
# ~ spkrParents[obj.parent.name] = [obj.name]
|
||||||
|
# has no parent
|
||||||
|
else:
|
||||||
|
# ~ spkrOrphans.append(obj.name)
|
||||||
|
parent = 0
|
||||||
|
# get sound informations
|
||||||
|
objName = obj.name
|
||||||
|
soundName = obj.data.sound.name
|
||||||
|
soundPath = bpy.path.abspath(obj.data.sound.filepath)
|
||||||
|
location = obj.location
|
||||||
|
volume = int(obj.data.volume)
|
||||||
|
volume_min = int(obj.data.volume_min)
|
||||||
|
volume_max = int(obj.data.volume_max)
|
||||||
|
# convert sound
|
||||||
|
if obj.data.get('isXA'):
|
||||||
|
XAsectorsize = 2336 if XAmode else 2352
|
||||||
|
if freeXAchannel > 7:
|
||||||
|
freeXAfile += 1
|
||||||
|
freeXAchannel = 0
|
||||||
|
convertedSoundPath = sound2XA(soundPath, soundName, bpp=4, XAfile=freeXAfile, XAchannel=freeXAchannel)
|
||||||
|
XAfile = freeXAfile
|
||||||
|
XAchannel = freeXAchannel
|
||||||
|
freeXAchannel += 1
|
||||||
|
if os.path.exists(convertedSoundPath):
|
||||||
|
XAsize = os.path.getsize(convertedSoundPath)
|
||||||
|
XAend = int((( XAsize / XAsectorsize ) - 1))
|
||||||
|
else:
|
||||||
|
XAsize = -1
|
||||||
|
XAend = -1
|
||||||
|
soundFiles.append( Sound( objName, soundName, soundPath, convertedSoundPath, parent, location, volume, volume_min, volume_max, -1, XAfile, XAchannel, XAsize, XAend ) )
|
||||||
|
else:
|
||||||
|
convertedSoundPath = sound2VAG(soundPath, soundName)
|
||||||
|
soundFiles.append( Sound( objName, soundName, soundPath, convertedSoundPath, parent, location, volume, volume_min, volume_max, -1 ) )
|
||||||
|
# Default values
|
||||||
|
XAFiles = "0"
|
||||||
|
VAGBank = "0"
|
||||||
|
level_sounds = "0"
|
||||||
|
# If sound objects in scene
|
||||||
|
if soundFiles:
|
||||||
|
# Deal with VAGs
|
||||||
|
VAGBank = writeVAGbank(f, soundFiles, level_symbols)
|
||||||
|
if VAGBank and VAGBank != "0":
|
||||||
|
VAGBank = fileName + "_VAGBank"
|
||||||
|
# Deal with XA
|
||||||
|
XAlist = writeXAbank(f, soundFiles, level_symbols)
|
||||||
|
writeXAfiles(f, XAlist, fileName)
|
||||||
|
if XAlist:
|
||||||
|
XAmanifest(XAlist)
|
||||||
|
XAinterleave(XAlist)
|
||||||
|
# Update mkpsxiso config file if it exists
|
||||||
|
configFile = expFolder + os.sep + os.path.relpath(self.exp_isoCfg)
|
||||||
|
addXAtoISO(XAlist, configFile)
|
||||||
|
XAFiles = len(XAlist)
|
||||||
|
# Write Sound obj
|
||||||
|
level_sounds = writeSoundObj(f, soundFiles, level_symbols)
|
||||||
|
if level_sounds and level_sounds != "0":
|
||||||
|
level_sounds = fileName + "_sounds"
|
||||||
# Write LEVEL struct
|
# Write LEVEL struct
|
||||||
f.write(
|
f.write(
|
||||||
"LEVEL " + fileName + " = {\n" +
|
"LEVEL " + fileName + " = {\n" +
|
||||||
|
@ -1495,7 +1873,12 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||||
"\t&" + fileName + "_camPath,\n" +
|
"\t&" + fileName + "_camPath,\n" +
|
||||||
"\t(CAMANGLE **)&" + fileName + "_camAngles,\n" +
|
"\t(CAMANGLE **)&" + fileName + "_camAngles,\n" +
|
||||||
"\t&" + fileName + "_node" + CleanName(nodePtr) + ",\n" +
|
"\t&" + fileName + "_node" + CleanName(nodePtr) + ",\n" +
|
||||||
|
"\t&" + level_sounds + ",\n" +
|
||||||
|
"\t&" + VAGBank + ",\n" +
|
||||||
|
"\t&" + fileName + "_XAFiles\n" +
|
||||||
"};\n\n")
|
"};\n\n")
|
||||||
|
# TODO : generate mkpsxiso config file
|
||||||
|
#
|
||||||
# Set default camera back in Blender
|
# Set default camera back in Blender
|
||||||
if defaultCam != 'NULL':
|
if defaultCam != 'NULL':
|
||||||
bpy.context.scene.camera = bpy.data.objects[ defaultCam ]
|
bpy.context.scene.camera = bpy.data.objects[ defaultCam ]
|
||||||
|
@ -1528,8 +1911,9 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||||
## Level forward declarations (level.h)
|
## Level forward declarations (level.h)
|
||||||
h = open(os.path.normpath(level_h),"w+")
|
h = open(os.path.normpath(level_h),"w+")
|
||||||
h.write(
|
h.write(
|
||||||
'#pragma once\n\n' +
|
'#pragma once\n' +
|
||||||
'#include "../custom_types.h"\n\n'
|
'#include "../custom_types.h"\n' +
|
||||||
|
'#include "../include/defines.h"\n\n'
|
||||||
)
|
)
|
||||||
for symbol in level_symbols:
|
for symbol in level_symbols:
|
||||||
h.write( "extern " + symbol + ";\n")
|
h.write( "extern " + symbol + ";\n")
|
||||||
|
|
Loading…
Reference in New Issue