[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" ) )
)
I agree with muhammadfredo, MaxScript already has a great way of reading and writing text files through XML files.
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.
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