# smlrecorder.sml # Script for TNTsim3D that records and plays flight paths using controls # in a dialog created in and opened by the script. Position information for # a flight path is recorded in a set of numeric arrays for replay. Recording # a new flight path replaces the last one in memory. The current flight path # can be saved to a text file (Save button) and reloaded for replay (Open button). ##################################################################################### ### For a script to run under TNTsim3D, it must include an instance of ### class TNTSIM3D named "TNTsim3D". The script must also be saved as an RVC ### object in the TNTsim3D Landscape File you want to run it with. ##################################################################################### # declare class instance for TNTsim3D interface class class TNTSIM3D TNTsim3D; # declare arrays to hold viewer position coordinates and orientation angles in memory numeric maxindices = 10000; array numeric viewerx[maxindices]; array numeric viewery[maxindices]; array numeric viewerz[maxindices]; array numeric orientationx[maxindices]; array numeric orientationy[maxindices]; array numeric orientationz[maxindices]; numeric numindices = 0; # number of indices in array set numeric index = 0; # current index during record or play numeric loop = 0; # State of recorder: 0 = idle, 1 = record, 2 = play, set by toggles on dialog numeric state = 0; # class declarations for dialog controls class GUI_CTRL_PUSHBUTTON save; class GUI_CTRL_TOGGLEBUTTON record, play, pause, stop; class GUI_CTRL_LABEL numberframes, frame; ###################################################################### ### callback procedures for control dialog ###################################################################### proc Enable () { # procedure to enable dialog controls when recording save.SetEnabled(1); play.SetEnabled(1); pause.SetEnabled(1); stop.SetEnabled(1); } proc OnLoop () { # reset loop status when checkbox is changed loop = !loop; } proc OnRecord () { # called when Record button is pressed; Enable(); # enable controls, set state to record, state = 1; # initialize counters, and set status of controls index = 0; numindices = 0; record.SetValue(1, 0); play.SetValue(0, 0); pause.SetValue(0, 0); stop.SetValue(0, 0); } proc OnPlay () { # called when Play button is pressed; state = 2; # set state to play and set status of controls play.SetValue(1, 0); record.SetValue(0, 0); pause.SetValue(0, 0); stop.SetValue(0, 0); } proc OnPause () { # called when Pause button is pressed; state = 0; # set state to pause and set status of controls pause.SetValue(1, 0); stop.SetValue(0, 0); } proc OnStop () { state = 0; index = 0; stop.SetValue(1, 0); record.SetValue(0, 0); play.SetValue(0, 0); pause.SetValue(0, 0); frame.SetLabel(""); } ### procedure to save the recorded flight path in a text file; called when Save ### button on the dialog is pressed proc OnSave ( ) { local class FILE file = GetOutputTextFile("", "Select Output File", "txt"); if (file == 0) return; local numeric idx; for (idx = 0; idx < numindices; idx++) fwritestring(file, sprintf("%f,%f,%f,%f,%f,%f\n", viewerx[idx], viewery[idx], viewerz[idx], orientationx[idx], orientationy[idx], orientationz[idx])); OnStop(); } ### procedure to open a flight path from a text file; called when the Open ### button on the dialog is pressed proc OnOpen ( ) { local class FILE file = GetInputTextFile("", "Select Input File", "txt"); if (file == 0) return; local string string$ = "something"; numindices = 0; while (string$ != "") { string$ = fgetline$(file); if (NumberTokens(string$, ",") != 6) continue; viewerx[numindices] = StrToNum(GetToken(string$, ",", 1)); viewery[numindices] = StrToNum(GetToken(string$, ",", 2)); viewerz[numindices] = StrToNum(GetToken(string$, ",", 3)); orientationx[numindices] = StrToNum(GetToken(string$, ",", 4)); orientationy[numindices] = StrToNum(GetToken(string$, ",", 5)); orientationz[numindices] = StrToNum(GetToken(string$, ",", 6)); numindices++; } numberframes.SetLabel(NumToStr(numindices)); OnStop(); Enable(); } ######################################################################## ### SML function name predefined in TNTsim3D, called for each frame. ### Record or play frame in flight as designated by recorder state. ######################################################################## proc OnFrame () { # if recording, get current viewer position and orientation and store in arrays if (state == 1) { local class POINT3D viewer, orientation; TNTsim3D.GetSceneByOrientation(viewer, orientation); viewerx[index] = viewer.x; # viewer position viewery[index] = viewer.y; viewerz[index] = viewer.z; orientationx[index] = orientation.x; # viewer orientation (x=pitch, orientationy[index] = orientation.y; # y = roll, z = heading azimuth orientationz[index] = orientation.z; numberframes.SetLabel(NumToStr(numindices)); # update count labels on dialog frame.SetLabel(NumToStr(index)); index++; # increment counts numindices++; if (numindices >= maxindices) OnStop(); } # if playback, read stored viewer position and orientation from # arrays and use these to set current frame else if (state == 2) { local class POINT3D viewer, orientation; viewer.x = viewerx[index]; # viewer position viewer.y = viewery[index]; viewer.z = viewerz[index]; orientation.x = orientationx[index]; # viewer orientation (x = pitch, orientation.y = orientationy[index]; # y = roll, z = heading azimuth orientation.z = orientationz[index]; TNTsim3D.SetSceneByOrientation(viewer, orientation); # set frame frame.SetLabel(NumToStr(index)); # update frame count label on dialog index++; if (index >= numindices) { # increment frame count if (loop == 1) index = 0; # if Loop checkbox is on, restart playback else OnStop(); # otherwise stop } } } ########################################################### ### Dialog specification in XML ########################################################### string xml$ = ' '; class XMLDOC doc; # class instance for the XML document numeric err = doc.Parse(xml$); # read the XML and parse into memory if (err < 0) { # if no XML document found, exit PopupError(err); Exit(); } class XMLNODE dlgnode; # class instance for the dialog element in the XML structure dlgnode = doc.GetElementByID("recorder"); # get the dialog element from the XML structure if (dlgnode == 0) { PopupMessage("Could not find dialog node in XML document"); Exit(); } class GUI_DLG dlg; # class instance for the dialog window dlg.SetXMLNode(dlgnode); # set the XML dialog element as the source for the dialog window numeric ret; dlg.CreateModeless(); ret = dlg.Open(); # open as a modeless dialog if ( ret == -1 ) { # exit script if Cancel button on dialog is pressed Exit(); } # get the handle for each dialog control (by its ID) and assign to the previously-declared # class instance save = dlg.GetCtrlByID("Save"); record = dlg.GetCtrlByID("Record"); play = dlg.GetCtrlByID("Play"); pause = dlg.GetCtrlByID("Pause"); stop = dlg.GetCtrlByID("Stop"); numberframes = dlg.GetCtrlByID("NumberFrames"); frame = dlg.GetCtrlByID("Frame");