Here is something to get you started. You say you want to export a file for each child of the switch. I wonder if you really want a file for each "state" of the switch. It could be that for your switches, this is the same (if each switch mask has exactly one child ON and the rest OFF). But in general a switch mask may have more than one child ON. The code below finds all the switch nodes in your db and prints some info about each one. For each mask on the switch it prints out which children (plural) are ON and which are OFF for that mask. If you really want to know each child of the switch regardless of the mask states, that is easy enough to do using mgGetChild. We'll follow up with a separate script showing the export file part but this should get you going. Let us know if you have any questions.
# this function is called when the walk function finds a switch node in # the hierarchy def ProcessSwitch(switchNode): # get the node name name = mgGetName(switchNode) # get the number of masks defined for the switch numMasks = mgGetSwitchMaskCount(switchNode) on_off = { 0 : "on", 1 : "off" } # get the number of children for the switch node # each switch mask will have this many bits. # each bit tells you whether or not "that" child is ON or OFF numChildren = mgCountChild(switchNode) print "switch name:",name,"numMasks:",numMasks,"numChildren:",numChildren # loop through the masks defined for the switch for maskNum in range(0, numMasks): print "mask:",maskNum # loop through the "bits" of the mask - again there will be one # bit per child. that bit will tell you if that child is ON/OFF for childNum in range(0, numChildren): b,on = mgGetSwitchBit (switchNode, maskNum, childNum) print " child",childNum,"is",on_off[on] def PreCallback (db, parent, rec, i): code = mgGetCode(rec) if (code == fltSwitch): ProcessSwitch(rec) return MG_TRUE # walk the database, looking for switch nodes db = mgGetCurrentDb () mgWalk (db, PreCallback, None, None, 0)
Here is the typical output you'll see when you run this script on your db:
Run Script started <PrintSwitch.py>... switch name: sw1 numMasks: 3 numChildren: 6 mask: 0 child 0 is off child 1 is off child 2 is on child 3 is on child 4 is on child 5 is on mask: 1 child 0 is on child 1 is on child 2 is off child 3 is off child 4 is on child 5 is on mask: 2 child 0 is on child 1 is on child 2 is on child 3 is on child 4 is off child 5 is off Run Script finished
Thanks Steve,
Much appreciated. I do in fact mean to write all children - I don't know of a better way to do it.
I am porting some files to Unity for a project we are doing here. The workflow I have requires me to export FLT to OBJ.
As you know FLT files contain OpenFlight nodes which are not supported by the OBJ file format. One of these is is/are switches - the source file contains several switch nodes, and I need the geometry they contain.
I plan to get specific nodes from a configuration file that contains the switch index, effectively the child of the switch. We haven't done anything with masks, some switches have them, but I think most do not. So a config for child 0 would be the 1st child, 4 = the 5th child, etc.
I suppose I could have the script only grab the required child, and not do a global dump. My thought was to process the source file once, and then choose the file/s I need from the output for any additional processing.
On a somewhat related note - you know the file export codes? I have one for dxf that works:
mgExportDb (db, exportFileName, "D8A67204-C573-4EC5-B1E2-E1DC93EB78E9", None, None)
Is there one for OBJ..? The docs I am using (v16) indicates:
mgExportDb exports the contents of the OpenFlight database db to a different file format on disk. The file format is specified by name formatName and version formatVersion. The name of the file created is specified by fileName. An argument list specifies a list of format specific parameters to control the export operation. The in-memory representation of db is not affected by this function. In particular, the database db retains its original file name so subsequent calls to mgWriteDb will write out the original file name, not the name you specified to mgExportDb. Note that this behavior is different from that of mgSaveAsDb which changes the file name associated with the in-memory representation of db. Note: If invoked from within the modeler environment, this function will fail if either db or the named file is open in an active window. The only valid format name is MEFN_OPENFLIGHT.
Thanks!
And here is a script that should be close to what you want. Let us know if you have any questions or need clarification on any of this code.
# temp files for copying palettes between existing and new dbs created # change these for your folder structure COLORPALETTE = "d:/share/colorpalette.color" TEXTUREPLETTE = "d:/share/texturepalette.txt" MATERIALPALETTE = "d:/share/materialpalette.materials" # this is where you want new files to be saved. {0} is # replaced by 1,2,3,... etc for each switch mask set saved # change this (but leave {0} somewhere in pattern) NEWFILEROOT = "d:/share/switchmask_{0}.flt" def CopyColorPalette(dstDb, srcDb): # copy the color palette from srcDb to dstDb mgWriteColorPalette(srcDb, COLORPALETTE) mgReadColorPalette(dstDb, COLORPALETTE) def CopyTexturePalette(dstDb, srcDb): # copy the texture palette from srcDb to dstDb mgWriteTexturePalette(srcDb, TEXTUREPLETTE) mgReadTexturePalette(dstDb, TEXTUREPLETTE) def CopyMaterialPalette(dstDb, srcDb): # copy the material palette from srcDb to dstDb mgWriteMaterialFile(srcDb, MATERIALPALETTE) mgReadMaterialFile(dstDb, MATERIALPALETTE) def CopyPalettes(dstDb, srcDb): # copy color/texture/material palettes from scrDb to dstDb # if you need other palettes there are more read/write palette # functions in the API (light point, light source, texture mapping, etc) CopyColorPalette(dstDb, srcDb) CopyTexturePalette(dstDb, srcDb) CopyMaterialPalette(dstDb, srcDb) # this function saves a new db file containing the nodes in the recList # presumably these are the nodes that are ON in a switch mask def SaveNode(fileName, srcDb, recList): # overwrite file if it already exists mgSetNewOverwriteFlag(MG_TRUE) # make the new db newDb = mgNewDb(fileName) if (newDb): # new dbs always have db-g1-g2 # we'll attach new nodes under g2 which is child of g1 which is child of db g2 = mgGetChild(mgGetChild(newDb)) for rec in recList: # for each node in the recList... # make a copy in the newDb newRec = mgDuplicateToDb(rec, newDb) # attach it to g2 in newDb mgAttach(g2, newRec) # copy color/texture/material palettes from original db to newDb CopyPalettes(newDb, srcDb) # write and close mgWriteDb(newDb) mgCloseDb(newDb) print fileName,"created and saved" # this function is called when the walk function finds a switch node in # the hierarchy def ProcessSwitch(switchNode): # get the switch node name name = mgGetName(switchNode) # get the number of masks defined for the switch numMasks = mgGetSwitchMaskCount(switchNode) on_off = { 0 : "on", 1 : "off" } # get the number of children for the switch node # each switch mask will have this many bits. # each bit tells you whether or not "that" child is ON or OFF numChildren = mgCountChild(switchNode) print "switch name:",name,"numMasks:",numMasks,"numChildren:",numChildren fileNum = 1 # loop through the masks defined for the switch for maskNum in range(0, numMasks): print "mask:",maskNum # build a list of nodes that are ON for this mask recList = list() # loop through the "bits" of the mask - again there will be one # bit per child. that bit will tell you if that child is ON/OFF for childNum in range(0, numChildren): b,on = mgGetSwitchBit (switchNode, maskNum, childNum) print " child",childNum,"is",on_off[on] child = mgGetChildNth(switchNode, childNum+1) # first child is 1, not 0 !! # add this child to the list if it is ON in this mask if (on): recList.append(child) if (len(recList) > 0): # if there are any children ON in this mask, save them to a new file # make the new file name, it is the root file name with {0} replaced by 1,2,3, etc fileName = NEWFILEROOT.format(fileNum) fileNum = fileNum + 1 # ready for next new file name db = mgRec2Db(switchNode) # save the nodes in this list (recList) to this fileName SaveNode(fileName, db, recList) def PreCallback (db, parent, rec, i): code = mgGetCode(rec) if (code == fltSwitch): # this node is a switch node, process it ProcessSwitch(rec) return MG_TRUE # walk the database, looking for switch nodes db = mgGetCurrentDb () mgWalk (db, PreCallback, None, None, 0)
Shawn, looks like our replies crossed in the night.
Note that mgExportDb (in Creator 16) only works for non-current versions of OpenFlight. It won't export to OBJ or any other non-OpenFlight format. It was in Creator 17 that mgExportDb was changed to support non-OpenFlight formats. In Creator 16 you'll have to export (save) to OpenFlight (like my script does) and then export in Creator those OpenFlight files to OBJ.
Shawn, here is an updated version of the last script. It has two switch "processing" functions:
ProcessSwitchMasks - this function (formerly ProcessSwitch in previous script) writes out a new db per mask of the switch
ProcessSwitchChildren - this function (new) writes out a new db per child of the switch
I left both functions in the script but changed the Walk Function (PreCallback) to call the latter. If you ever wanted to change it, you could make it call the former.
# temp files for copying palettes between existing and new dbs created # change these for your folder structure COLORPALETTE = "d:/share/colorpalette.color" TEXTUREPLETTE = "d:/share/texturepalette.txt" MATERIALPALETTE = "d:/share/materialpalette.materials" # this is where you want new files to be saved. {0} is # replaced by 1,2,3,... etc for each switch mask set saved # change this (but leave {0} somewhere in pattern) NEWFILEROOT = "d:/share/switchmask_{0}.flt" def CopyColorPalette(dstDb, srcDb): # copy the color palette from srcDb to dstDb mgWriteColorPalette(srcDb, COLORPALETTE) mgReadColorPalette(dstDb, COLORPALETTE) def CopyTexturePalette(dstDb, srcDb): # copy the texture palette from srcDb to dstDb mgWriteTexturePalette(srcDb, TEXTUREPLETTE) mgReadTexturePalette(dstDb, TEXTUREPLETTE) def CopyMaterialPalette(dstDb, srcDb): # copy the material palette from srcDb to dstDb mgWriteMaterialFile(srcDb, MATERIALPALETTE) mgReadMaterialFile(dstDb, MATERIALPALETTE) def CopyPalettes(dstDb, srcDb): # copy color/texture/material palettes from scrDb to dstDb # if you need other palettes there are more read/write palette # functions in the API (light point, light source, texture mapping, etc) CopyColorPalette(dstDb, srcDb) CopyTexturePalette(dstDb, srcDb) CopyMaterialPalette(dstDb, srcDb) # this function saves a new db file containing the nodes in the recList # presumably these are the nodes that are ON in a switch mask def SaveNode(fileName, srcDb, recList): # overwrite file if it already exists mgSetNewOverwriteFlag(MG_TRUE) # make the new db newDb = mgNewDb(fileName) if (newDb): # new dbs always have db-g1-g2 # we'll attach new nodes under g2 which is child of g1 which is child of db g2 = mgGetChild(mgGetChild(newDb)) for rec in recList: # for each node in the recList... # make a copy in the newDb newRec = mgDuplicateToDb(rec, newDb) # attach it to g2 in newDb mgAttach(g2, newRec) # copy color/texture/material palettes from original db to newDb CopyPalettes(newDb, srcDb) # write and close mgWriteDb(newDb) mgCloseDb(newDb) print fileName,"created and saved" # this function is called when the walk function finds a switch node in # the hierarchy and you want to process the "masks" of the switch def ProcessSwitchMasks(switchNode): # get the switch node name name = mgGetName(switchNode) # get the number of masks defined for the switch numMasks = mgGetSwitchMaskCount(switchNode) on_off = { 0 : "on", 1 : "off" } # get the number of children for the switch node # each switch mask will have this many bits. # each bit tells you whether or not "that" child is ON or OFF numChildren = mgCountChild(switchNode) print "switch name:",name,"numMasks:",numMasks,"numChildren:",numChildren fileNum = 1 # loop through the masks defined for the switch for maskNum in range(0, numMasks): print "mask:",maskNum # build a list of nodes that are ON for this mask recList = list() # loop through the "bits" of the mask - again there will be one # bit per child. that bit will tell you if that child is ON/OFF for childNum in range(0, numChildren): b,on = mgGetSwitchBit (switchNode, maskNum, childNum) print " child",childNum,"is",on_off[on] child = mgGetChildNth(switchNode, childNum+1) # first child is 1, not 0 !! # add this child to the list if it is ON in this mask if (on): recList.append(child) if (len(recList) > 0): # if there are any children ON in this mask, save them to a new file # make the new file name, it is the root file name with {0} replaced by 1,2,3, etc fileName = NEWFILEROOT.format(fileNum) fileNum = fileNum + 1 # ready for next new file name db = mgRec2Db(switchNode) # save the nodes in this list (recList) to this fileName SaveNode(fileName, db, recList) # this function is called when the walk function finds a switch node in # the hierarchy and you want to process the children of the switch def ProcessSwitchChildren(switchNode): # get the switch node name name = mgGetName(switchNode) numChildren = mgCountChild(switchNode) print "switch name:",name,"numChildren:",numChildren fileNum = 1 # loop through the children under the switch for childNum in range(0, numChildren): # build a list of nodes (will just contain one node - the current child) recList = list() child = mgGetChildNth(switchNode, childNum+1) # first child is 1, not 0 !! recList.append(child) if (len(recList) > 0): # if there are any children ON in this mask, save them to a new file # make the new file name, it is the root file name with {0} replaced by 1,2,3, etc fileName = NEWFILEROOT.format(fileNum) fileNum = fileNum + 1 # ready for next new file name db = mgRec2Db(switchNode) # save the nodes in this list (recList) to this fileName SaveNode(fileName, db, recList) def PreCallback (db, parent, rec, i): code = mgGetCode(rec) if (code == fltSwitch): # this node is a switch node, process it ProcessSwitchChildren(rec) return MG_TRUE # walk the database, looking for switch nodes db = mgGetCurrentDb () mgWalk (db, PreCallback, None, None, 0)
Steve,
You are awesome, thanks! This seems to work as advertised (I killed the session early just because things were taking a while, but files are present!!).
I'm driving Creator 18 but am using the API refs from v16 - thanks for clarifying.
Ok, got it. Time to get the OF API 18 refs ;-)
SInce you're using CR 18, you can use mgExportDb to write other (non-OpenFlight) formats. Go to Script>OpenFlight Script Editor and do Help>On Creator Script to get the format keys for the different formats. Also you could use the Creator Script Snippet Wizard (also off the OpenFlight Script Editor) to paste the mgExportDb snippet for the format you choose there.
Have fun scripting!!
Downloading now, thanks!
I appreciate the tips. Scripting does not come naturally, but with practice I hope to be able to at least roll around in the docs and snippets ;)
If you have some extra time (and have not done so yet) I might also recommend checking out the OpenFlight API Developer Guides. These documents give you a frame of reference for the OpenFlight API, the OpenFlight Scene Graph and how it is structured. OpenFlight Script, after all, is merely a Python wrapper to this API. Perhaps the concepts in the Developer Guides might help you to better understand how to structure and implement your scripts.
I've got an almost-working script which produces a file for each switch child. I'm seeing an issue with the files that are created - they lose the texture reference; i.e., the map/index is present in the file texture palette, but the reference to the image file on disk is unresolved.
So I try replacing the pattern in Creator, and it looks OK, but I save the file and re-open it and the texture is again missing.
I have also tried running changeallpaths but that does not fix the issue either.
Is there something wrong or incomplete in the script to cause this, or should I be looking at file permissions..??
I'll try attaching the relevant files here.
Thx
I looked at your script and nothing jumps out at me. I also looked at the FLT file you attached (I assume this is one of the output files). It looks fine. The palette contains a single PNG texture. I did notice the PNG file in the palette has NO PATH. If the original file (containing the switch nodes) and this output file are NOT in the same folder, the output file won't be able to locate the PNG file. Could that be your problem? The file you run through this script is in one folder and you are writing the output files to another? That would explain why, when you open the output file, the PNG file could not be found since the NO PATH would be releative to original OpenFlight file.
I can't explain why after you fix this in Creator and reopen the file, the path is still broken but I don't believe that would have anything to do with the script itself (since you do this well after the script has completed and left the scene).
Hi Chris,
Yeah, I get why the file is the way it is since the script is making a brand new file (thanks Steve!) for each switch child.
I can't explain why after you fix this in Creator and reopen the file, the path is still broken but I don't believe that would have anything to do with the script itself (since you do this well after the script has completed and left the scene).
Ah - User error - the texture palette is set to no path. So, no fix!
But I don't understand why changeallpaths also fails on it.
Thx
Actually, Shawn this is still Steve Thompson replying to you. For some reason my profile on the Presagis web site got corrupted. It thinks I am Chris Longhurst. Working to get that fixed currently.
Shawn
How do I inventory a FLT file for switches, and export a file for each node child?
I only see docs (samples) for creating a switch from scratch.
I'm interested in building a script to process files external from Creator.
Am digging through the API docs.
Pointers gratefully accepted.
Thanks!