Notifications
Clear all

[Closed] Load/apply and read information from .txt file

I was looking for some solution. I wrote script what save information to custom .txt file but how I can apply this information from .txt file to my selected object or scene (if object exist).

My .txt file with saved informations: (not all)

    sliderTime = 0f
    $LThigh.rotation.angle = 262.649
    $LThigh.rotation.axis = [-0.023208,-0.992486,-0.120137]
    
    sliderTime = 1f
    $LThigh.rotation.angle = 262.829
    $LThigh.rotation.axis = [-0.0210054,-0.992386,-0.121363]
    
    sliderTime = 2f
    $LThigh.rotation.angle = 263.275
    $LThigh.rotation.axis = [-0.0153616,-0.992001,-0.125288]
    
    sliderTime = 3f
    $LThigh.rotation.angle = 263.775
    $LThigh.rotation.axis = [-0.00758744,-0.991397,-0.130672]
    
    sliderTime = 4f
    $LThigh.rotation.angle = 264.171
    $LThigh.rotation.axis = [3.06296e-005,-0.990606,-0.136745]
    
    sliderTime = 5f
    $LThigh.rotation.angle = 264.547
    $LThigh.rotation.axis = [0.00555852,-0.990092,-0.140307]
    
    ...
    

I was trying to write it but I don’t know how I have this so far:

on PasteKeys pressed do
(
fName= getOpenFileName types:“Text(.txt)|.txt|All files|.|”
txtFile = openFile fName mode:“r”

       with animate on (
       try (
       
       while not (eof txtFile) do
       (
       tmp = readline txtFile 
       )
           ) catch ( print "ERROR" )
       )

)

9 Replies

why you are not using xml instead of txt?

I agree with muhammadfredo, MaxScript already has a great way of reading and writing text files through XML files.

maxscript? what way is it?

2 Replies
(@tayloranimated)
Joined: 11 months ago

Posts: 0

Opps, my mistake, I was thinking INI files. The help file for these can be found here http://docs.autodesk.com/3DSMAX/14/ENU/MAXScript%20Help%202012/ They can give you a quick way to have some preset preferences saved either beforehand or written through your script. I’ve used this in the past to create some ongoing preferences for my tools.

(@denist)
Joined: 11 months ago

Posts: 0

INI file is good for storing some settings but it was not intended to store massive data (like animation or geometry).

XML is a right way for saving/loading data. First, because it’s the fashion. Second, because .NET provides a lot of service to work with XML, and it’s easy to find samples about any subject of XML reading/writing/searching.

But if your data supposes only direct reading and writing (no seeking, no complicated parsing, etc.) the plain TXT still might work better.

So, XML will be a good way. If yes how I can save me information to XML file and then load – apply to scene? I was trying to work only on .txt file not .xml

tried these:

fn main =
 (
 	clearListener()
 	scriptdir = getFilenamePath (getSourceFileName())
 	filename = getOpenFileName types:"Text(*.txt)|*.txt|" filename:(scriptdir + "\	est.txt")
 	if filename==undefined do return undefined
 	fin = OpenFile filename mode:"rt"
 	if fin==undefined do return undefined
 		
 	/* variant 1 */
 	try while not EOF fin do row = readExpr fin catch (close fin ; return undefined)
 	/* variant 2 */
 	try while not EOF fin do ( execute (readLine fin) ; skipToNextLine fin) catch (close fin ; return undefined)
 	/* variant 3 */
 	try while not EOF fin do
 	(
 		row = readLine fin
 		skipToNextLine fin
 		if row.count<1 then continue
 		isSlidderValue = findString row "sliderTime" != undefined
 		isRotationAngle = findString row "rotation.angle" != undefined
 		isRotationAxis = findString row "rotation.axis" != undefined
 		if isSlidderValue then
 		( 
 			t = (filterString row " 
\r	=")[2] as time
 			format "time : %
" t
 		)
 		else if isRotationAngle then
 		(
 			format "evaluate : %
" row
 			execute row
 		)
 		else if isRotationAxis then
 		(
 			format "evaluate : %
" row
 			execute row
 		)
 	) catch (close fin ; return undefined)
 	close fin
 )
 main()

but depends heavily on which is the easiest way to write and read for your purpose, in my personal opition i prefer write as BinaryStream , exemple create a File.anim with your custom format.

I usually made this code because it allows you to control all phases:

/* the .anim file format can be this:
 
 String :"ANIM"
 Integer : numofnodes
 |
 |_	string : "nodename1"
 |	Integer : numofframe
 |	Float[numofframe] : times array
 |	Point3[numofframe] : position keys
 |	Quat[numofframe] : rotation keys
 |	
 |_	string : "nodename2"
 	Integer : numofframe
 	Float[numofframe] : times array
 	Point3[numofframe] : position keys
 	Quat[numofframe] : rotation keys
 etc...
 */
 
 Struct NODESTRUCT
 (
 	handle = 0, -- the unique node id used in max , storing directly the node objects is more slow
 	keyrot = #(), -- a list of rotation key and frame time
 	keypos = #(), -- a list of position key
 	keytime = #(), -- a list of time key
 	
 	function getAnim =
 	(
 		/* first get all data*/
 		if (obj = maxops.getnodebyhandle handle) ==undefined do return undefined -- exit in case of error
 		PosCtrl = obj.position.controller = TCB_position() -- some game use this interpolation controller
 		RotCtrl = obj.rotation.controller = TCB_rotation() -- quaternion
 		nKpos = numKeys PosCtrl
 		nKrot = numKeys RotCtrl
 		keytime.count = 0
 		for k=1 to nKpos do append keytime (getKeyTime PosCtrl k as integer)
 		for k=1 to nKrot do append keytime (getKeyTime RotCtrl k as integer)
 		sort keytime
 		makeuniquearray keytime 
 		
 		/* a good idea is inizialize the array dimension, append function is very slow */
 		keyrot.count = keypos.cont = keytime.count
 		for k=1 to keytime.count do
 		(
 			t = keytime[k]
 			at time t keypos[k] = PosCtrl.value
 			at time t keyrot[k] = RotCtrl.value
 		)
 		OK		
 	),
 	function setAnim =
 	(
 		if (obj = maxops.getnodebyhandle handle) ==undefined do return undefined -- exit in case of error
 		format "Build Animation function for node : %
" obj.name
 		OK
 	),
 	
 	function read fin =
 	(
 		nodename = readString fin
 		obj = getnodebyname nodename
 		handle  = if obj == undefined then 0 else obj.handle 
 		numkey = readLong fin #unsigned -- the cont can't be <0
 		/* a good idea is inizialize the array dimension, append function is very slow */
 		keyrot.count = keypos.cont = keytime.count = numkey
 		for k=1 to numkey do
 		(
 			keytime[k] = readLong fin
 			keypos[k] = point3 (readFloat fin) (readFloat fin) (readFloat fin)
 			keyrot[k] = quat (readFloat fin) (readFloat fin) (readFloat fin) (readFloat fin)
 		)
 		OK
 	),
 	function write fout =
 	(
 		if (obj = maxops.getnodebyhandle handle) ==undefined do return undefined -- exit in case of error
 		writeString fout obj.name
 		writeLong fout keytime.count #unsigned -- the cont can't be <0
 		for k=1 to keytime.count do
 		(
 			writeLong fout keytime[k]
 			writeFloat fout keypos[k].x
 			writeFloat fout keypos[k].y
 			writeFloat fout keypos[k].z
 			writeFloat fout keyrot[k].x
 			writeFloat fout keyrot[k].y
 			writeFloat fout keyrot[k].z
 			writeFloat fout keyrot[k].w
 		)
 		OK
 	)
 )
 
 try DestroyDialog AnimRollout catch OK
 rollout AnimRollout "animation tool"
 (
 	button btnImportAnim "Open" width:70 across:2 toolTip:"import animation , the nodes name saved must find in the scene"
 	button btnSaveAnim "Save" width:70 toolTip:"save animation from a selection of nodes"
 	on btnImportAnim pressed do
 	(
 		theNodeList = #()
 		filename = getOpenFileName types:"myanim(*.anim)|*.anim"
 		if filename!=undefined and (fin = fopen filename "rb")!=undefined then
 		(
 			/* step 1 : get all node*/
 			version = readString fin
 			NumNodes = readLong fin
 			theNodeList.count = NumNodes
 			for n=1 to NumNodes do
 			(
 				theNodeList[n]  = NODESTRUCT()
 				if (theNodeList[n].read fin)!=OK do print "ERROR reading"
 			)
 			fclose fin
 		)
 		/* step 2 : if correct then building*/
 		for theNode in theNodeList do theNode.setAnim()
 		
 	)
 	
 	on btnSaveAnim pressed do
 	(
 		/* step 1 : get all node , you can build some filter or controller */
 		theNodeList = for obj in selection collect NODESTRUCT handle:obj.handle
 		/* step 2 : get all node's corrrect data, if wrong delete it before open file*/
 		for n=theNodeList.count to 1 by -1 where theNodeList[n].getAnim()!=OK do deleteitem theNodeList n
 		/* step 3 : save if exist a list*/
 		if theNodeList.count>0 then 	
 		(
 			filename = getSaveFileName types:"myanim(*.anim)|*.anim"
 			if filename!=undefined and (fout = fopen filename "wb")!=undefined then
 			(
 				writeString fout "VERSION00" -- a custom string
 				writeLong fout theNodeList.count -- very important to memorize the number of struct written
 				for theNode in theNodeList do theNode.write fout
 				fflush fout -- in my work sometime windows don't write the temporaney data, this ensure all output in the file
 				fclose fout
 			)
 		) else MessageBox "Please select one or more nodes"	
 	)
 )
 createDialog AnimRollout
 

how you can see, write a binary file occupies less space, the data are easy to read and write and you can also apply some compression algorithm

Thank johnwhile you are very helpfull