Notifications
Clear all

[Closed] [SDK]: Exporter class method for NoteTrack Collection…

never worked with NoteTracks in max sdk, but there is a sample code in SDK:
from …\maxsdk\samples\import_export\vrmlexp\vrmlexp.cpp


 void
 VRBLExport::StartNode(INode* node, Object* obj, int level, BOOL outputName)
 {
 	if (node->IsRootNode()) {
 		mStream.Printf(_T("Separator {
"));
 		return;
 	}
 	Indent(level);
 	if (obj->SuperClassID() == CAMERA_CLASS_ID ||
 		obj->SuperClassID() == LIGHT_CLASS_ID  || !outputName) {
 	 // Lights and cameras need different top-level names for triggers
 		mStream.Printf(_T("DEF %s_TopLevel Separator {
"), mNodes.GetNodeName(node));
 	} else {
 		mStream.Printf(_T("DEF %s Separator {
"), mNodes.GetNodeName(node));
 		if (IsMirror(node)) {
 			Indent(level+1);
 			mStream.Printf(_T("ShapeHints {
"));
 			Indent(level+2);
 			mStream.Printf(_T("vertexOrdering CLOCKWISE
"));
 			Indent(level+1);
 			mStream.Printf(_T("}
"));
 		}
 	}
 
 	if (!obj)
 		return;
 
 	// Put note tracks as info nodes
 	int numNotes = node->NumNoteTracks();
 	for(int i=0; i < numNotes; i++) {
 		DefNoteTrack *nt = (DefNoteTrack*) node->GetNoteTrack(i);
 		for (int j = 0; j < nt->keys.Count(); j++) {
 			NoteKey* nk = nt->keys[j];
 			TSTR note = nk->note;
 			if (note.Length() > 0) {
 				Indent(level+1);
 				mStream.Printf(_T("Info { string \"frame %d: %s\" }
"),
 						nk->time/GetTicksPerFrame(), note.data());
 			}
 		}
 	}
 }
 

also look at …\maxsdk\samples\import_export\vrmlexp\vrml2.cpp
can be helpful too.

In the body of the “DoExport” method m_noteCatalog is never initialized to anything… just passed into the CollectNotes method as:

so you are indexing into an uninitialized vector

with

if ( l_index == 0 )
 {     
   catalog[k] = m_noNotes; 
 } 
 else 
 {    
   catalog[k].x = startNum;    
   catalog[k].y = l_index; 
   startNum += l_index; // increment starting note number for next frame 
}

then ?

:argh: well I will fix that in a jiffy… I overlooked doing that inside the CollectNotes method.

OK, so that fixed it. How embarrassing… @Klunk-1 and @denisT – Thank you both.

So here is the final code for my exporter’s CollectNotes method:

void ROFFexport::CollectNotes(INode* node, std::vector<IPoint2>& catalog, NoteKeyTab& noteList)
 {
 	int l_start =  (m_pExportOptions->nSegFrom) * GetTicksPerFrame();
 	int l_end = (m_pExportOptions->nSegTo) * GetTicksPerFrame();
 	int k;
 	TimeValue t;  // Value in ticks
 	int numFrames = (l_end - l_start) + 1;
 	int numNoteTracks = node->NumNoteTracks();
 	int startNum = 0;
 	catalog.resize(numFrames);
 
 	for(k = 0, t = l_start; t <= l_end; t += GetTicksPerFrame(), k++)
 	{			
 		int l_index = 0;
 		for(int i = 0; i < numNoteTracks; i++)
 		{
 			DefNoteTrack* nt = (DefNoteTrack*)node->GetNoteTrack(i);
 			//Cycle thru note keys to see if a key exists at TimeValue t
 			int numKeys = nt->NumKeys();
 			for (int j = 0; j < numKeys; j++)
 			{
 				NoteKey* nk = nt->keys[j];
 				TimeValue keyTime = ( nk->time );
 				if (keyTime == t)
 				{
 					// We have a key at TimeValue t... so append to noteList 
 					noteList.Append(1,&nk);
 					l_index++; // increment local index (total notes on frame k)
 				}
 			}
 		}
 		if ( l_index == 0 )
 		{
 			catalog[k] = m_noNotes;
 		}
 		else
 		{
 			catalog[k] = IPoint2(startNum, l_index);
 			startNum += l_index; // increment starting note number for next frame
 		}
 	}
 }

I just wanted to post an update here in case anyone ever attempted to recycle this code snippet… wrapping up my exporter (just need to implement that progress bar class)… I kept having a 3ds Max Application Error crash following a File > Reset (or File > Exit with no Reset) after exporting a test scene. I isolated this problem to my CollectNotes method… but couldn’t find my error.

    ...finally, with Klunk's help-- he pointed out that something was going wrong with my NoteKeyTab& noteList parameter that was causing it to trash memory.  So I abandoned trying to use NoteKeyTab like a general container and replaced it with:  Tab&lt; NoteKey* &gt;& noteList
    
    ...and my File &gt; Reset (or File &gt; Exit with no Reset) crashes disappeared.  I also resized the notes catalog, and filled it with a default value of (-1,0) [meaning no notes on that frame], before passing it into the method-- so here is the updated code:
void ROFF2Export::CollectNotes(INode* node, std::vector<IPoint2>& catalog, Tab<NoteKey*>& noteList, int& totalNotes)
        {
        	int l_start =  (m_pExportOptions->nSegFrom) * GetTicksPerFrame(); // Convert to Ticks
        	int l_end = (m_pExportOptions->nSegTo) * GetTicksPerFrame(); // Convert to Ticks
        	int k;
        	TimeValue t;  // Value in ticks
        	int numNoteTracks = node->NumNoteTracks();
        	int startNum = 0;
        
        	for(k = 0, t = l_start; t <= l_end; t += GetTicksPerFrame(), k++)
        	{	
        		int l_count = 0;
        		for(int i = 0; i < numNoteTracks; i++)
        		{
        			DefNoteTrack* nt = (DefNoteTrack*)node->GetNoteTrack(i);
        			
        			//Cycle thru note keys to see if key exists at TimeValue t
        			int numKeys = nt->keys.Count();
        			if ( numKeys > 0 )
        			{
        				for (int j = 0; j < numKeys; j++)
        				{	
        					NoteKey* nk = nt->keys[j];
        					TimeValue keyTime = ( nk->time );
        					if (keyTime == t)
        					{
        						// We have a key at TimeValue t... so append to noteList
        						noteList.Append(1, &nk); 
        						l_count++; // increment local count (total notes per frame k)
        					}
        				}
        			}
        		}
        		if ( l_count > 0 )
        		{
        			catalog[k].x = startNum;
        			catalog[k].y = l_count;
        			startNum += l_count; // increment starting note number for next frame
        		}
        	}
        	
        	totalNotes = noteList.Count();
        }

Edit: I realize that subAnims can have their own NoteTracks… but for my purposes– the method above only looks for NoteTracks on the node itself.

Page 3 / 3