void QTTarg_SetTrackProperties (Media theMedia, UInt32 theIdleFrequency)
{
	QTAtomContainer		myTrackProperties;
	RGBColor			myBackgroundColor;
	Boolean				hasActions;
	UInt32				myFrequency;
	OSErr				myErr = noErr;
		
	// add a background color to the sprite track
	myBackgroundColor.red = EndianU16_NtoB(0xffff);
	myBackgroundColor.green = EndianU16_NtoB(0xffff);
	myBackgroundColor.blue = EndianU16_NtoB(0xffff);
	
	myErr = QTNewAtomContainer(&myTrackProperties);
	if (myErr == noErr) {
		QTInsertChild(myTrackProperties, 0, kSpriteTrackPropertyBackgroundColor, 1, 1, sizeof(myBackgroundColor), &myBackgroundColor, NULL);

		// tell the movie controller that this sprite track has actions
		hasActions = true;
		QTInsertChild(myTrackProperties, 0, kSpriteTrackPropertyHasActions, 1, 1, sizeof(hasActions), &hasActions, NULL);
	
		// tell the sprite track to generate QTIdleEvents
		myFrequency = EndianU32_NtoB(theIdleFrequency);
		QTInsertChild(myTrackProperties, 0, kSpriteTrackPropertyQTIdleEventsFrequency, 1, 1, sizeof(myFrequency), &myFrequency, NULL);

		SetMediaPropertyAtom(theMedia, myTrackProperties);
		
		QTDisposeAtomContainer(myTrackProperties);
	}
}
Beispiel #2
0
//------------------------------------------------
void visitprops(TPropertyGroup &pg, int &index, QTAtomContainer &atoms, QTAtom parent)
{
	int count = pg.getPropertyCount();
	while (index < count) {
		TStringProperty *p = (TStringProperty *)pg.getProperty(index++);
		string str0 = p->getName();
		const char *buf = str0.c_str();
		int atomType, id, sonCount;
		sscanf(buf, "%d %d %d", &atomType, &id, &sonCount);
		QTAtom newAtom;
		if (sonCount == 0) {
			wstring appow = p->getValue();
			string appo = toString(appow);
			const char *str = appo.c_str();

			vector<UCHAR> buf;
			while (strlen(str) > 0) {
				if (str[0] == 'z') {
					int count = atoi(str + 1);
					str += (count < 10) ? 4 : ((count < 100) ? 5 : 6);
					while (count--)
						buf.push_back(0);
				} else {
					int val = atoi(str);
					assert(val >= 0 && val < 256);

					str += (val < 10) ? 2 : ((val < 100) ? 3 : 4);
					buf.push_back(val);
				}
			}
			//const unsigned short*bufs = str1.c_str();
			//UCHAR *bufc = new UCHAR[size];
			//for (int i=0; i<size; i++)
			// {
			//	assert(bufs[i]<257);
			//	bufc[i] = (UCHAR)(bufs[i]-1);
			//	}
			void *ptr = 0;
			if (buf.size() != 0) {
				ptr = &(buf[0]);
			}
			QTInsertChild(atoms, parent, (QTAtomType)atomType, (QTAtomID)id, 0,
						  buf.size(), (void *)ptr, 0);
		} else {
			QTInsertChild(atoms, parent, (QTAtomType)atomType, (QTAtomID)id,
						  0, 0, 0, &newAtom);
			visitprops(pg, index, atoms, newAtom);
		}
	}
}
Beispiel #3
0
void send_movie_changed_notification(Movie movie) {
    QTAtomContainer container;

    if(QTNewAtomContainer(&container) == noErr) {
        QTAtom anAction;
        OSType whichAction = EndianU32_NtoB(kActionMovieChanged);

        OSErr err = QTInsertChild(container, kParentAtomIsContainer, kAction, 1, 0, 0, NULL, &anAction);

        if(err == noErr)
            err = QTInsertChild(container, anAction, kWhichAction, 1, 0, sizeof(whichAction), &whichAction, NULL);

        if(err == noErr)
            MovieExecuteWiredActions(movie, 0, container);

        QTDisposeAtomContainer(container);
    }
}
OSErr SpriteUtils_AddSpriteToSample (QTAtomContainer theSample, QTAtomContainer theSprite, QTAtomID theSpriteID)
{
	QTAtom				mySpriteAtom = 0;
	OSErr				myErr = paramErr;
	
	// see if the sample already contains a sprite atom of the specified ID
	mySpriteAtom = QTFindChildByID(theSample, kParentAtomIsContainer, kSpriteAtomType, theSpriteID, NULL);
	if (mySpriteAtom != 0)
		goto bail;
	
	// here, the index 0 means to append the sprite to the sample
	myErr = QTInsertChild(theSample, kParentAtomIsContainer, kSpriteAtomType, theSpriteID, 0, 0, NULL, &mySpriteAtom);
	if (myErr != noErr)
		goto bail;

	myErr = QTInsertChildren(theSample, mySpriteAtom, theSprite);
	
bail:
	return(myErr);
}
static OSErr SpriteUtils_SetImageGroupID (QTAtomContainer theKeySample, QTAtom theImagesContainerAtom, short theImageIndex, long theGroupID)
{
	QTAtom			myImageAtom, myImageGroupAtom;
	OSErr			myErr = noErr;
	
	myImageAtom = QTFindChildByIndex(theKeySample, theImagesContainerAtom, kSpriteImageAtomType, theImageIndex, NULL);
	if (myImageAtom == 0)	{ 
		myErr = cannotFindAtomErr;
		goto bail;
	}

	myImageGroupAtom = QTFindChildByIndex(theKeySample, myImageAtom, kSpriteImageGroupIDAtomType, 1, NULL);
	if (myImageGroupAtom == 0) {
		myErr = QTInsertChild(theKeySample, myImageAtom, kSpriteImageGroupIDAtomType, 1, 1, 0, NULL, &myImageGroupAtom);
		if (myErr != noErr)
			goto bail;
	}

	theGroupID = EndianU32_NtoB(theGroupID);
	myErr = QTSetAtomData(theKeySample, myImageGroupAtom, sizeof(theGroupID), &theGroupID);

bail:
	return(myErr);
}
OSErr QTWired_MakeSpriteDraggable (QTAtomContainer theContainer, QTAtomID theID)
{
	QTAtom								mySpriteAtom = 0;
	QTAtom								myEventAtom = 0;
	QTAtom								myActionAtom = 0;
	QTAtom								myParamAtom = 0;
	QTAtom								myConditionalAtom, myExpressionAtom, myOperatorAtom, myOperandAtom, myOperandTypeAtom, myActionListAtom, myParameterAtom;
	short								myOperandIndex;
	long								myAction;
	QTAtomID							myVariableID;
	float								myVariableValue;
	float								myConstantValue;
	Boolean								myIsAbsolute;
	OSErr								myErr = noErr;
	
	// find the sprite atom with the specified ID in the specified container
	mySpriteAtom = QTFindChildByID(theContainer, kParentAtomIsContainer, kSpriteAtomType, theID, NULL);
	if (mySpriteAtom == 0) {
		// if there is none, insert a new sprite atom into the specified container
		myErr = QTInsertChild(theContainer, kParentAtomIsContainer, kSpriteAtomType, theID, 1, 0, NULL, &mySpriteAtom);
		if (myErr != noErr)
			goto bail;
	}
	
	//////////
	//
	// add a mouse click event handler
	//
	//////////
	
	// find the event atom of type kQTEventMouseClick in the sprite atom
	myEventAtom = QTFindChildByID(theContainer, mySpriteAtom, kQTEventType, kQTEventMouseClick, NULL);
	if (myEventAtom == 0) {
		// if there is none, insert a new event atom of type kQTEventMouseClick into the sprite atom
		myErr = QTInsertChild(theContainer, mySpriteAtom, kQTEventType, kQTEventMouseClick, 1, 0, NULL, &myEventAtom);
		if (myErr != noErr)
			goto bail;
	}
	
	// add an action atom to the mouse click event handler
	myErr = QTInsertChild(theContainer, myEventAtom, kAction, 0, 0, 0, NULL, &myActionAtom);
	if (myErr != noErr)
		goto bail;
	
	myAction = EndianU32_NtoB(kActionSpriteTrackSetVariable);
	myErr = QTInsertChild(theContainer, myActionAtom, kWhichAction, 1, 1, sizeof(myAction), &myAction, NULL);
	if (myErr != noErr)
		goto bail;
			
	// add parameters to the set variable action: variable ID (QTAtomID) and value (float)
	myVariableID = EndianU32_NtoB(kMouseStateVariableID);
	myErr = QTInsertChild(theContainer, myActionAtom, kActionParameter, 0, (short)kFirstParam, sizeof(myVariableID), &myVariableID, NULL);
	if (myErr != noErr)
		goto bail;
	
	myVariableValue = (float)1;
	EndianUtils_Float_NtoB(&myVariableValue);
	myErr = QTInsertChild(theContainer, myActionAtom, kActionParameter, 0, (short)kSecondParam, sizeof(myVariableValue), &myVariableValue, NULL);
	if (myErr != noErr)
		goto bail;
	
	//////////
	//
	// add a mouse click end event handler
	//
	//////////
	
	// find the event atom of type kQTEventMouseClick in the sprite atom
	myEventAtom = QTFindChildByID(theContainer, mySpriteAtom, kQTEventType, kQTEventMouseClickEnd, NULL);
	if (myEventAtom == 0) {
		// if there is none, insert a new event atom of type kQTEventMouseClick into the sprite atom
		myErr = QTInsertChild(theContainer, mySpriteAtom, kQTEventType, kQTEventMouseClickEnd, 1, 0, NULL, &myEventAtom);
		if (myErr != noErr)
			goto bail;
	}
	
	// add an action atom to the mouse click event handler
	myErr = QTInsertChild(theContainer, myEventAtom, kAction, 0, 0, 0, NULL, &myActionAtom);
	if (myErr != noErr)
		goto bail;
	
	myAction = EndianU32_NtoB(kActionSpriteTrackSetVariable);
	myErr = QTInsertChild(theContainer, myActionAtom, kWhichAction, 1, 1, sizeof(myAction), &myAction, NULL);
	if (myErr != noErr)
		goto bail;
	
	// add parameters to the set variable action: variable ID (QTAtomID) and value (float)
	myVariableID = EndianU32_NtoB(kMouseStateVariableID);
	myErr = QTInsertChild(theContainer, myActionAtom, kActionParameter, 0, (short)kFirstParam, sizeof(myVariableID), &myVariableID, NULL);
	if (myErr != noErr)
		goto bail;
	
	myVariableValue = (float)0;
	EndianUtils_Float_NtoB(&myVariableValue);
	myErr = QTInsertChild(theContainer, myActionAtom, kActionParameter, 0, (short)kSecondParam, sizeof(myVariableValue), &myVariableValue, NULL);
	if (myErr != noErr)
		goto bail;
	
	//////////
	//
	// add an idle event handler
	//
	//////////
	
	// find the event atom of type kQTEventIdle in the sprite atom
	myEventAtom = QTFindChildByID(theContainer, mySpriteAtom, kQTEventType, kQTEventIdle, NULL);
	if (myEventAtom == 0) {
		// if there is none, insert a new event atom of type kQTEventIdle into the sprite atom
		myErr = QTInsertChild(theContainer, mySpriteAtom, kQTEventType, kQTEventIdle, 1, 0, NULL, &myEventAtom);
		if (myErr != noErr)
			goto bail;
	}
	
	// add an action atom to the mouse click event handler
	myErr = QTInsertChild(theContainer, myEventAtom, kAction, 0, 0, 0, NULL, &myActionAtom);
	if (myErr != noErr)
		goto bail;
	
	myAction = EndianU32_NtoB(kActionCase);
	myErr = QTInsertChild(theContainer, myActionAtom, kWhichAction, 1, 1, sizeof(myAction), &myAction, NULL);
	if (myErr != noErr)
		goto bail;

	// add a parameter atom to the kActionCase action atom; this will serve as a parent to hold the expression and action atoms
	myErr = QTInsertChild(theContainer, myActionAtom, kActionParameter, 1, kFirstParam, 0, NULL, &myParamAtom);
	if (myErr != noErr)
		goto bail;
	
	// the condition atom
	myErr = QTInsertChild(theContainer, myParamAtom, kConditionalAtomType, 0, 1, 0, NULL, &myConditionalAtom);
	if (myErr != noErr)
		goto bail;

	myErr = QTInsertChild(theContainer, myConditionalAtom, kExpressionContainerAtomType, 1, 1, 0, NULL, &myExpressionAtom);
	if (myErr != noErr)
		goto bail;

	myErr = QTInsertChild(theContainer, myExpressionAtom, kOperatorAtomType, kOperatorEqualTo, 1, 0, NULL, &myOperatorAtom);
	if (myErr != noErr)
		goto bail;
		
	// add the operands to the operator atom
	myOperandIndex = 1;	
	myConstantValue = 1;
	myErr = QTInsertChild(theContainer, myOperatorAtom, kOperandAtomType, 0, myOperandIndex, 0, NULL, &myOperandAtom);
	if (myErr != noErr)
		goto bail;
	
	myErr = QTInsertChild(theContainer, myOperandAtom, kOperandConstant, 1, 1, 0, NULL, &myOperandTypeAtom);
	if (myErr != noErr)
		goto bail;

	EndianUtils_Float_NtoB(&myConstantValue);
	myErr = QTSetAtomData(theContainer, myOperandTypeAtom, sizeof(myConstantValue), &myConstantValue);
	
	myOperandIndex = 2;
	myVariableID = kMouseStateVariableID;
	myErr = QTInsertChild(theContainer, myOperatorAtom, kOperandAtomType, 0, myOperandIndex, 0, NULL, &myOperandAtom);
	if (myErr != noErr)
		goto bail;
	
	myErr = QTInsertChild(theContainer, myOperandAtom, kOperandSpriteTrackVariable, 1, 1, 0, NULL, &myOperandTypeAtom);
	if (myErr != noErr)
		goto bail;
	
	myVariableID = EndianU32_NtoB(myVariableID);
	myErr = QTInsertChild(theContainer, myOperandTypeAtom, kActionParameter, 1, 1, sizeof(myVariableID), &myVariableID, NULL);
	if (myErr != noErr)
		goto bail;

	// add an action list atom
	myErr = QTInsertChild(theContainer, myConditionalAtom, kActionListAtomType, 1, 1, 0, NULL, &myActionListAtom);
	if (myErr != noErr)
		goto bail;

	// add sprite translate action
	myErr = QTInsertChild(theContainer, myActionListAtom, kAction, 0, 0, 0, NULL, &myActionAtom);
	if (myErr != noErr)
		goto bail;
	
	myAction = EndianU32_NtoB(kActionSpriteTranslate);
	myErr = QTInsertChild(theContainer, myActionAtom, kWhichAction, 1, 1, sizeof(myAction), &myAction, NULL);
	if (myErr != noErr)
		goto bail;
		
	//////////
	//
	// add parameters to the translate action: Fixed x, Fixed y, Boolean isAbsolute
	//
	//////////
	
	// first parameter: get current mouse position x
	myErr = QTInsertChild(theContainer, myActionAtom, kActionParameter, 0, (short)kFirstParam, 0, NULL, &myParameterAtom);
	if (myErr != noErr)
		goto bail;
		
	myErr = QTInsertChild(theContainer, myParameterAtom, kExpressionContainerAtomType, 1, 1, 0, NULL, &myExpressionAtom);
	if (myErr != noErr)
		goto bail;

	myErr = QTInsertChild(theContainer, myExpressionAtom, kOperandAtomType, 0, 1, 0, NULL, &myOperandAtom);
	if (myErr != noErr)
		goto bail;
		
	myErr = QTInsertChild(theContainer, myOperandAtom, kOperandMouseLocalHLoc, 1, 1, 0, NULL, NULL);
	if (myErr != noErr)
		goto bail;

	// second parameter: get current mouse position y
	myErr = QTInsertChild(theContainer, myActionAtom, kActionParameter, 0, (short)kSecondParam, 0, NULL, &myParameterAtom);
	if (myErr != noErr)
		goto bail;
		
	myErr = QTInsertChild(theContainer, myParameterAtom, kExpressionContainerAtomType, 1, 1, 0, NULL, &myExpressionAtom);
	if (myErr != noErr)
		goto bail;

	myErr = QTInsertChild(theContainer, myExpressionAtom, kOperandAtomType, 0, 1, 0, NULL, &myOperandAtom);
	if (myErr != noErr)
		goto bail;
		
	myErr = QTInsertChild(theContainer, myOperandAtom, kOperandMouseLocalVLoc, 1, 1, 0, NULL, NULL);
	if (myErr != noErr)
		goto bail;

	myIsAbsolute = true;
	myErr = QTInsertChild(theContainer, myActionAtom, kActionParameter, 0, (short)kThirdParam, sizeof(myIsAbsolute), &myIsAbsolute, NULL);
	
bail:
	return(myErr);
}
OSErr QTWired_AddCursorChangeOnMouseOver (QTAtomContainer theContainer, QTAtomID theID)
{
	QTAtom								mySpriteAtom = 0;
	QTAtom								myBehaviorAtom = 0;
	QTSpriteButtonBehaviorStruct		myBehaviorRec;
	OSErr								myErr = noErr;
	
	// find the sprite atom with the specified ID in the specified container
	mySpriteAtom = QTFindChildByID(theContainer, kParentAtomIsContainer, kSpriteAtomType, theID, NULL);
	if (mySpriteAtom == 0) {
		// if there is none, insert a new sprite atom into the specified container
		myErr = QTInsertChild(theContainer, kParentAtomIsContainer, kSpriteAtomType, theID, 0, 0, NULL, &mySpriteAtom);
		if (myErr != noErr)
			goto bail;
	}
	
	// insert a new sprite behaviors atom into the sprite atom
	myErr = QTInsertChild(theContainer, mySpriteAtom, kSpriteBehaviorsAtomType, 1, 1, 0, NULL, &myBehaviorAtom);
	if (myErr != noErr)
		goto bail;

	//////////
	//
	// insert three atoms into the sprite behaviors atom; these three atoms specify what to do on each
	// of the four defined state transitions for the (1) sprite image, (2) cursor, and (3) status string
	//
	//////////
	
	// set the sprite image behavior; -1 means: no change associated with this state transition
	myBehaviorRec.notOverNotPressedStateID = EndianS32_NtoB(-1);
	myBehaviorRec.overNotPressedStateID = EndianS32_NtoB(-1);
	myBehaviorRec.overPressedStateID = EndianS32_NtoB(-1);
	myBehaviorRec.notOverPressedStateID = EndianS32_NtoB(-1);

	myErr = QTInsertChild(theContainer, myBehaviorAtom, kSpriteImageBehaviorAtomType, 1, 1, sizeof(QTSpriteButtonBehaviorStruct), &myBehaviorRec, NULL);
	if (myErr != noErr)
		goto bail;
	
	// set the sprite cursor behavior; -1 means: no change associated with this state transition
	myBehaviorRec.notOverNotPressedStateID = EndianS32_NtoB(-1);
	myBehaviorRec.overNotPressedStateID = EndianS32_NtoB(kQTCursorOpenHand);
	myBehaviorRec.overPressedStateID = EndianS32_NtoB(-1);
	myBehaviorRec.notOverPressedStateID = EndianS32_NtoB(-1);

	myErr = QTInsertChild(theContainer, myBehaviorAtom, kSpriteCursorBehaviorAtomType, 1, 1, sizeof(QTSpriteButtonBehaviorStruct), &myBehaviorRec, NULL);
	if (myErr != noErr)
		goto bail;
	
	// set the status string behavior; -1 means: no change associated with this state transition
	myBehaviorRec.notOverNotPressedStateID = EndianS32_NtoB(-1);
	myBehaviorRec.overNotPressedStateID = EndianS32_NtoB(-1);
	myBehaviorRec.overPressedStateID = EndianS32_NtoB(-1);
	myBehaviorRec.notOverPressedStateID = EndianS32_NtoB(-1);

	myErr = QTInsertChild(theContainer, myBehaviorAtom, kSpriteStatusStringsBehaviorAtomType, 1, 1, sizeof(QTSpriteButtonBehaviorStruct), &myBehaviorRec, NULL);
	if (myErr != noErr)
		goto bail;
			
bail:
	return(myErr);
}
OSErr QTWired_CreateWiredSpritesMovie (void)
{
	short					myResRefNum = 0;
	short					myResID = movieInDataForkResID;
	Movie					myMovie = NULL;
	Track					myTrack;
	Media					myMedia;
	FSSpec					myFile;
	Boolean					myIsSelected = false;
	Boolean					myIsReplacing = false;	
	StringPtr 				myPrompt = QTUtils_ConvertCToPascalString(kWiredSavePrompt);
	StringPtr 				myFileName = QTUtils_ConvertCToPascalString(kWiredSaveFileName);
	QTAtomContainer			mySample = NULL;
	QTAtomContainer			myActions = NULL;
	QTAtomContainer			myBeginButton, myPrevButton, myNextButton, myEndButton;
	QTAtomContainer			myPenguinOne, myPenguinTwo, myPenguinOneOverride;
	QTAtomContainer			myBeginActionButton, myPrevActionButton, myNextActionButton, myEndActionButton;
	QTAtomContainer			myPenguinOneAction, myPenguinTwoAction;
	RGBColor				myKeyColor;
	Point					myLocation;
	short					isVisible, myLayer, myIndex, myID, i, myDelta;
	Boolean					hasActions;
	long					myFlags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile;
	OSType					myType = FOUR_CHAR_CODE('none');
	UInt32					myFrequency;
	QTAtom					myEventAtom;
	long					myLoopingFlags;
	ModifierTrackGraphicsModeRecord		myGraphicsMode;
	OSErr					myErr = noErr;

	//////////
	//
	// create a new movie file and set its controller type
	//
	//////////

	// ask the user for the name of the new movie file
	QTFrame_PutFile(myPrompt, myFileName, &myFile, &myIsSelected, &myIsReplacing);
	if (!myIsSelected)
		goto bail;

	// create a movie file for the destination movie
	myErr = CreateMovieFile(&myFile, FOUR_CHAR_CODE('TVOD'), smSystemScript, myFlags, &myResRefNum, &myMovie);
	if (myErr != noErr)
		goto bail;
	
	// select the "no controller" movie controller
	myType = EndianU32_NtoB(myType);
	SetUserDataItem(GetMovieUserData(myMovie), &myType, sizeof(myType), kUserDataMovieControllerType, 1);
	
	//////////
	//
	// create the sprite track and media
	//
	//////////
	
	myTrack = NewMovieTrack(myMovie, ((long)kSpriteTrackWidth << 16), ((long)kSpriteTrackHeight << 16), kNoVolume);
	myMedia = NewTrackMedia(myTrack, SpriteMediaType, kSpriteMediaTimeScale, NULL, 0);

	//////////
	//
	// create a key frame sample containing six sprites and all of their shared images
	//
	//////////

	// create a new, empty key frame sample
	myErr = QTNewAtomContainer(&mySample);
	if (myErr != noErr)
		goto bail;

	myKeyColor.red = 0xffff;						// white
	myKeyColor.green = 0xffff;
	myKeyColor.blue = 0xffff;

	// add images to the key frame sample
	SpriteUtils_AddPICTImageToKeyFrameSample(mySample, kGoToBeginningButtonUp, &myKeyColor, kGoToBeginningButtonUpIndex, NULL, NULL);
	SpriteUtils_AddPICTImageToKeyFrameSample(mySample, kGoToBeginningButtonDown, &myKeyColor, kGoToBeginningButtonDownIndex, NULL, NULL);
	SpriteUtils_AddPICTImageToKeyFrameSample(mySample, kGoToEndButtonUp, &myKeyColor, kGoToEndButtonUpIndex, NULL, NULL);
	SpriteUtils_AddPICTImageToKeyFrameSample(mySample, kGoToEndButtonDown, &myKeyColor, kGoToEndButtonDownIndex, NULL, NULL);
	SpriteUtils_AddPICTImageToKeyFrameSample(mySample, kGoToPrevButtonUp, &myKeyColor, kGoToPrevButtonUpIndex, NULL, NULL);
	SpriteUtils_AddPICTImageToKeyFrameSample(mySample, kGoToPrevButtonDown, &myKeyColor, kGoToPrevButtonDownIndex, NULL, NULL);
	SpriteUtils_AddPICTImageToKeyFrameSample(mySample, kGoToNextButtonUp, &myKeyColor, kGoToNextButtonUpIndex, NULL, NULL);
	SpriteUtils_AddPICTImageToKeyFrameSample(mySample, kGoToNextButtonDown, &myKeyColor, kGoToNextButtonDownIndex, NULL, NULL);
	SpriteUtils_AddPICTImageToKeyFrameSample(mySample, kPenguinForward, &myKeyColor, kPenguinForwardIndex, NULL, NULL);
	SpriteUtils_AddPICTImageToKeyFrameSample(mySample, kPenguinLeft, &myKeyColor, kPenguinLeftIndex, NULL, NULL);
	SpriteUtils_AddPICTImageToKeyFrameSample(mySample, kPenguinRight, &myKeyColor, kPenguinRightIndex, NULL, NULL);
	SpriteUtils_AddPICTImageToKeyFrameSample(mySample, kPenguinClosed, &myKeyColor, kPenguinClosedIndex, NULL, NULL);

	for (myIndex = kPenguinDownRightCycleStartIndex, myID = kWalkDownRightCycleStart; myIndex <= kPenguinDownRightCycleEndIndex; myIndex++, myID++)
		SpriteUtils_AddPICTImageToKeyFrameSample(mySample, myID, &myKeyColor, myIndex, NULL, NULL);
	
	// assign group IDs to the images
	SpriteUtils_AssignImageGroupIDsToKeyFrame(mySample);
	
	//////////
	//
	// add samples to the sprite track's media
	//
	//////////
	
	BeginMediaEdits(myMedia);

	// go to beginning button with no actions
	myErr = QTNewAtomContainer(&myBeginButton);
	if (myErr != noErr)
		goto bail;
	myLocation.h	= (1 * kSpriteTrackWidth / 8) - (kStartEndButtonWidth / 2);
	myLocation.v	= (4 * kSpriteTrackHeight / 5) - (kStartEndButtonHeight / 2);
	isVisible		= false;
	myLayer			= 1;
	myIndex			= kGoToBeginningButtonUpIndex;
	myErr = SpriteUtils_SetSpriteData(myBeginButton, &myLocation, &isVisible, &myLayer, &myIndex, NULL, NULL, myActions);
	if (myErr != noErr)
		goto bail;

	// go to previous button with no actions
	myErr = QTNewAtomContainer(&myPrevButton);
	if (myErr != noErr)
		goto bail;
	myLocation.h 	= (3 * kSpriteTrackWidth / 8) - (kNextPrevButtonWidth / 2);
	myLocation.v	= (4 * kSpriteTrackHeight / 5) - (kStartEndButtonHeight / 2);
	isVisible		= false;
	myLayer			= 1;
	myIndex			= kGoToPrevButtonUpIndex;
	myErr = SpriteUtils_SetSpriteData(myPrevButton, &myLocation, &isVisible, &myLayer, &myIndex, NULL, NULL, myActions);
	if (myErr != noErr)
		goto bail;

	// go to next button with no actions
	myErr = QTNewAtomContainer(&myNextButton);
	if (myErr != noErr)
		goto bail;
	myLocation.h 	= (5 * kSpriteTrackWidth / 8) - (kNextPrevButtonWidth / 2);
	myLocation.v	= (4 * kSpriteTrackHeight / 5) - (kStartEndButtonHeight / 2);
	isVisible		= false;
	myLayer			= 1;
	myIndex			= kGoToNextButtonUpIndex;
	myErr = SpriteUtils_SetSpriteData(myNextButton, &myLocation, &isVisible, &myLayer, &myIndex, NULL, NULL, myActions);
	if (myErr != noErr)
		goto bail;

	// go to end button with no actions
	myErr = QTNewAtomContainer(&myEndButton);
	if (myErr != noErr)
		goto bail;
	myLocation.h 	= (7 * kSpriteTrackWidth / 8) - (kStartEndButtonWidth / 2);
	myLocation.v	= (4 * kSpriteTrackHeight / 5) - (kStartEndButtonHeight / 2);
	isVisible		= false;
	myLayer			= 1;
	myIndex			= kGoToEndButtonUpIndex;
	myErr = SpriteUtils_SetSpriteData(myEndButton, &myLocation, &isVisible, &myLayer, &myIndex, NULL, NULL, myActions);
	if (myErr != noErr)
		goto bail;

	// first penguin sprite with no actions
	myErr = QTNewAtomContainer(&myPenguinOne);
	if (myErr != noErr)
		goto bail;
	myLocation.h 	= (3 * kSpriteTrackWidth / 8) - (kPenguinWidth / 2);
	myLocation.v 	= (kSpriteTrackHeight / 4) - (kPenguinHeight / 2);
	isVisible		= true;
	myLayer			= 2;
	myIndex			= kPenguinDownRightCycleStartIndex;
	myGraphicsMode.graphicsMode = blend;
	myGraphicsMode.opColor.red = myGraphicsMode.opColor.green = myGraphicsMode.opColor.blue = 0x8FFF;	// grey
	myErr = SpriteUtils_SetSpriteData(myPenguinOne, &myLocation, &isVisible, &myLayer, &myIndex, &myGraphicsMode, NULL, myActions);
	if (myErr != noErr)
		goto bail;
		
	// second penguin sprite with no actions
	myErr = QTNewAtomContainer(&myPenguinTwo);
	if (myErr != noErr)
		goto bail;
	myLocation.h 	= (5 * kSpriteTrackWidth / 8) - (kPenguinWidth / 2);
	myLocation.v 	= (kSpriteTrackHeight / 4) - (kPenguinHeight / 2);
	isVisible		= true;
	myLayer			= 3;
	myIndex			= kPenguinForwardIndex;
	myErr = SpriteUtils_SetSpriteData(myPenguinTwo, &myLocation, &isVisible, &myLayer, &myIndex, NULL, NULL, myActions);
	if (myErr != noErr)
		goto bail;

	//////////
	//
	// add actions to the six sprites
	//
	//////////

	// add go to beginning button
	myErr = QTCopyAtom(myBeginButton, kParentAtomIsContainer, &myBeginActionButton);
	if (myErr != noErr)
		goto bail;

	WiredUtils_AddSpriteSetImageIndexAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, kGoToBeginningButtonDownIndex, NULL);
	WiredUtils_AddSpriteSetImageIndexAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, NULL, kGoToBeginningButtonUpIndex, NULL);
	WiredUtils_AddMovieGoToBeginningAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseClickEndTriggerButton);
	WiredUtils_AddSpriteSetVisibleAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, 0, NULL, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, 0, NULL, false, NULL);
	SpriteUtils_AddSpriteToSample(mySample, myBeginActionButton, kGoToBeginningSpriteID);	
	QTDisposeAtomContainer(myBeginActionButton);

	// add go to prev button
	myErr = QTCopyAtom(myPrevButton, kParentAtomIsContainer, &myPrevActionButton);
	if (myErr != noErr)
		goto bail;

	WiredUtils_AddSpriteSetImageIndexAction(myPrevActionButton, kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, kGoToPrevButtonDownIndex, NULL);
	WiredUtils_AddSpriteSetImageIndexAction(myPrevActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, NULL, kGoToPrevButtonUpIndex, NULL);
	WiredUtils_AddMovieStepBackwardAction(myPrevActionButton, kParentAtomIsContainer, kQTEventMouseClickEndTriggerButton);
	WiredUtils_AddSpriteSetVisibleAction(myPrevActionButton, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, 0, NULL, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPrevActionButton, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, 0, NULL, false, NULL);
	SpriteUtils_AddSpriteToSample(mySample, myPrevActionButton, kGoToPrevSpriteID);
	QTDisposeAtomContainer(myPrevActionButton);

	// add go to next button
	myErr = QTCopyAtom(myNextButton, kParentAtomIsContainer, &myNextActionButton);
	if (myErr != noErr)
		goto bail;

	WiredUtils_AddSpriteSetImageIndexAction(myNextActionButton, kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, kGoToNextButtonDownIndex, NULL);
	WiredUtils_AddSpriteSetImageIndexAction(myNextActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, NULL, kGoToNextButtonUpIndex, NULL);
	WiredUtils_AddMovieStepForwardAction(myNextActionButton, kParentAtomIsContainer, kQTEventMouseClickEndTriggerButton);
	WiredUtils_AddSpriteSetVisibleAction(myNextActionButton, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, 0, NULL, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myNextActionButton, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, 0, NULL, false, NULL);
	SpriteUtils_AddSpriteToSample(mySample, myNextActionButton, kGoToNextSpriteID);
	QTDisposeAtomContainer(myNextActionButton);

	// add go to end button
	myErr = QTCopyAtom(myEndButton, kParentAtomIsContainer, &myEndActionButton);
	if (myErr != noErr)
		goto bail;

	WiredUtils_AddSpriteSetImageIndexAction(myEndActionButton, kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, kGoToEndButtonDownIndex, NULL);
	WiredUtils_AddSpriteSetImageIndexAction(myEndActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, NULL, kGoToEndButtonUpIndex, NULL);
	WiredUtils_AddMovieGoToEndAction(myEndActionButton, kParentAtomIsContainer, kQTEventMouseClickEndTriggerButton);
	WiredUtils_AddSpriteSetVisibleAction(myEndActionButton, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, 0, NULL, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myEndActionButton, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, 0, NULL, false, NULL);
	SpriteUtils_AddSpriteToSample(mySample, myEndActionButton, kGoToEndSpriteID);
	QTDisposeAtomContainer(myEndActionButton);

	// add penguin one
	myErr = QTCopyAtom(myPenguinOne, kParentAtomIsContainer, &myPenguinOneAction);
	if (myErr != noErr)
		goto bail;

	// show the buttons on mouse enter and hide them on mouse exit
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, kTargetSpriteID, (void *)kGoToBeginningSpriteID, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, kTargetSpriteID, (void *)kGoToBeginningSpriteID, false, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, kTargetSpriteID, (void *)kGoToPrevSpriteID, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, kTargetSpriteID, (void *)kGoToPrevSpriteID, false, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, kTargetSpriteID, (void *)kGoToNextSpriteID, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, kTargetSpriteID, (void *)kGoToNextSpriteID, false, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, kTargetSpriteID, (void *)kGoToEndSpriteID, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, kTargetSpriteID, (void *)kGoToEndSpriteID, false, NULL);
	SpriteUtils_AddSpriteToSample(mySample, myPenguinOneAction, kPenguinOneSpriteID);
	QTWired_AddCursorChangeOnMouseOver(mySample, kPenguinOneSpriteID);
	QTDisposeAtomContainer(myPenguinOneAction);

	// add penguin two
	myErr = QTCopyAtom(myPenguinTwo, kParentAtomIsContainer, &myPenguinTwoAction);
	if (myErr != noErr)
		goto bail;

	// blink when clicked on
	WiredUtils_AddSpriteSetImageIndexAction(myPenguinTwoAction, kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, kPenguinClosedIndex, NULL);
	WiredUtils_AddSpriteSetImageIndexAction(myPenguinTwoAction, kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, NULL, kPenguinForwardIndex, NULL);

	WiredUtils_AddQTEventAtom(myPenguinTwoAction, kParentAtomIsContainer, kQTEventMouseClickEndTriggerButton, &myEventAtom);

	// toggle the movie rate and both of the birds' graphics modes
	QTWired_AddPenguinTwoConditionalActions(myPenguinTwoAction, myEventAtom);

	QTWired_AddWraparoundMatrixOnIdle(myPenguinTwoAction);

	SpriteUtils_AddSpriteToSample(mySample, myPenguinTwoAction, kPenguinTwoSpriteID);
	QTDisposeAtomContainer(myPenguinTwoAction);
	
	// add an action for when the key frame is loaded, to set the movie's looping mode to palindrome;
	// note that this will actually be triggered every time the key frame is reloaded,
	// so if the operation was expensive we could use a conditional to test if we've already done it
	myLoopingFlags = loopTimeBase | palindromeLoopTimeBase;
	WiredUtils_AddMovieSetLoopingFlagsAction(mySample, kParentAtomIsContainer, kQTEventFrameLoaded, myLoopingFlags);

	// add the key frame sample to the sprite track media
	//
	// to add the sample data in a compressed form, you would use a QuickTime DataCodec to perform the
	// compression; replace the call to the utility AddSpriteSampleToMedia with a call to the utility
	// AddCompressedSpriteSampleToMedia to do this
	
	SpriteUtils_AddSpriteSampleToMedia(myMedia, mySample, kSpriteMediaFrameDuration, true, NULL);	
	//SpriteUtils_AddCompressedSpriteSampleToMedia(myMedia, mySample, kSpriteMediaFrameDuration, true, zlibDataCompressorSubType, NULL);

	//////////
	//
	// add a few override samples to move penguin one and change its image index
	//
	//////////

	// original penguin one location
	myLocation.h 	= (3 * kSpriteTrackWidth / 8) - (kPenguinWidth / 2);
	myLocation.v 	= (kSpriteTrackHeight / 4) - (kPenguinHeight / 2);

	myDelta = (kSpriteTrackHeight / 2) / kNumOverrideSamples;
	myIndex = kPenguinDownRightCycleStartIndex;
	
	for (i = 1; i <= kNumOverrideSamples; i++) {
		QTRemoveChildren(mySample, kParentAtomIsContainer);
		QTNewAtomContainer(&myPenguinOneOverride);

		myLocation.h += myDelta;
		myLocation.v += myDelta;
		myIndex++;
		if (myIndex > kPenguinDownRightCycleEndIndex)
			myIndex = kPenguinDownRightCycleStartIndex;
			
		SpriteUtils_SetSpriteData(myPenguinOneOverride, &myLocation, NULL, NULL, &myIndex, NULL, NULL, NULL);
		SpriteUtils_AddSpriteToSample(mySample, myPenguinOneOverride, kPenguinOneSpriteID);
		SpriteUtils_AddSpriteSampleToMedia(myMedia, mySample, kSpriteMediaFrameDuration, false, NULL);	
		QTDisposeAtomContainer(myPenguinOneOverride);
	}

	EndMediaEdits(myMedia);
	
	// add the media to the track
	InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), fixed1);
	
	//////////
	//
	// set the sprite track properties
	//
	//////////
	{
		QTAtomContainer		myTrackProperties;
		RGBColor			myBackgroundColor;
		
		// add a background color to the sprite track
		myBackgroundColor.red = EndianU16_NtoB(0x8000);
		myBackgroundColor.green = EndianU16_NtoB(0);
		myBackgroundColor.blue = EndianU16_NtoB(0xffff);
		
		QTNewAtomContainer(&myTrackProperties);
		QTInsertChild(myTrackProperties, 0, kSpriteTrackPropertyBackgroundColor, 1, 1, sizeof(RGBColor), &myBackgroundColor, NULL);

		// tell the movie controller that this sprite track has actions, Jackson
		hasActions = true;
		QTInsertChild(myTrackProperties, 0, kSpriteTrackPropertyHasActions, 1, 1, sizeof(hasActions), &hasActions, NULL);
	
		// tell the sprite track to generate QTIdleEvents
		myFrequency = EndianU32_NtoB(2);
		QTInsertChild(myTrackProperties, 0, kSpriteTrackPropertyQTIdleEventsFrequency, 1, 1, sizeof(myFrequency), &myFrequency, NULL);
		myErr = SetMediaPropertyAtom(myMedia, myTrackProperties);
		if (myErr != noErr)
			goto bail;

		QTDisposeAtomContainer(myTrackProperties);
	}
	
	//////////
	//
	// finish up
	//
	//////////
	
	// add the movie resource to the movie file
	myErr = AddMovieResource(myMovie, myResRefNum, &myResID, myFile.name);
	
bail:
	free(myPrompt);
	free(myFileName);

	if (mySample != NULL)
		QTDisposeAtomContainer(mySample);

	if (myBeginButton != NULL)
		QTDisposeAtomContainer(myBeginButton);	
			
	if (myPrevButton != NULL)
		QTDisposeAtomContainer(myPrevButton);
				
	if (myNextButton != NULL)
		QTDisposeAtomContainer(myNextButton);
				
	if (myEndButton != NULL)
		QTDisposeAtomContainer(myEndButton);		
		
	if (myResRefNum != 0)
		CloseMovieFile(myResRefNum);

	if (myMovie != NULL)
		DisposeMovie(myMovie);
		
	return(myErr);
}
OSErr SpriteUtils_AddCompressedImageToKeyFrameSample (QTAtomContainer theKeySample, ImageDescriptionHandle theImageDesc, long theDataSize, Ptr theCompressedDataPtr, QTAtomID theImageID, FixedPoint *theRegistrationPoint, StringPtr theImageName)
{
	Handle						myImageData = NULL;
	QTAtom						myDefaultsAtom, myImagesContainerAtom, myImageAtom;
	ImageDescriptionHandle		myImageDesc = NULL;
	OSErr						myErr = noErr;

#if TARGET_RT_LITTLE_ENDIAN
	myImageDesc = (ImageDescriptionHandle)NewHandle(GetHandleSize((Handle)theImageDesc));
	BlockMoveData(*theImageDesc, *myImageDesc, GetHandleSize((Handle)theImageDesc));
	EndianUtils_ImageDescription_NtoB(myImageDesc);
#else
	myImageDesc = theImageDesc;			// already is big endian
#endif

	// append compressed picture data to myImageDesc to obtain sprite image data
	myImageData = NewHandle(0);
	myErr = MemError();
	if (myErr != noErr)
		goto bail;
	
	myErr = HandAndHand((Handle)myImageDesc, myImageData);
	if (myErr != noErr)
		goto bail;
	
	myErr = PtrAndHand(theCompressedDataPtr, myImageData, theDataSize);
	if (myErr != noErr)
		goto bail;
	
	myDefaultsAtom = QTFindChildByIndex(theKeySample, 0, kSpriteSharedDataAtomType, 1, NULL);
	if (myDefaultsAtom == 0) {
		myErr = QTInsertChild(theKeySample, kParentAtomIsContainer, kSpriteSharedDataAtomType, 1, 0, 0, NULL, &myDefaultsAtom);
		if (myErr != noErr)
			goto bail;
	}
		
	myImagesContainerAtom = QTFindChildByIndex(theKeySample, myDefaultsAtom, kSpriteImagesContainerAtomType, 1, NULL);
	if (myImagesContainerAtom == 0) {
		myErr = QTInsertChild(theKeySample, myDefaultsAtom, kSpriteImagesContainerAtomType, 1, 0, 0, NULL, &myImagesContainerAtom);
		if (myErr != noErr)
			goto bail;
	}

	myErr = QTInsertChild(theKeySample, myImagesContainerAtom, kSpriteImageAtomType, theImageID, 0, 0, NULL, &myImageAtom);
	if (myErr != noErr)
		goto bail;

	HLock(myImageData);
	myErr = QTInsertChild(theKeySample, myImageAtom, kSpriteImageDataAtomType, 1, 0, GetHandleSize(myImageData), *myImageData, NULL);
	if (myErr != noErr)
		goto bail;
	HUnlock(myImageData);
	
	if (theRegistrationPoint != NULL) {
		FixedPoint 			myRegistrationPoint;
		
		myRegistrationPoint.x = EndianS32_NtoB(theRegistrationPoint->x);
		myRegistrationPoint.y = EndianS32_NtoB(theRegistrationPoint->y);
		
		myErr = QTInsertChild(theKeySample, myImageAtom, kSpriteImageRegistrationAtomType, 1, 0, sizeof(myRegistrationPoint), &myRegistrationPoint, NULL);
		if (myErr != noErr)
			goto bail;
	} else {
		FixedPoint 			myRegistrationPoint = { 0, 0 };		// flipping {0,0} doesn't change anything so we don't flip
		
		myErr = QTInsertChild(theKeySample, myImageAtom, kSpriteImageRegistrationAtomType, 1, 0, sizeof(myRegistrationPoint), &myRegistrationPoint, NULL);
		if (myErr != noErr)
			goto bail;
	}
	
	if (theImageName != NULL) {
		myErr = QTInsertChild(theKeySample, myImageAtom, kSpriteImageNameAtomType, 1, 0, theImageName[0], &theImageName[1], NULL);
		if (myErr != noErr)
			goto bail;
	}

bail:
#if TARGET_RT_LITTLE_ENDIAN
	if (myImageDesc != NULL)
		DisposeHandle((Handle)myImageDesc);
#else
	// myImageDesc is still theImageDesc, so don't dispose of it
#endif

	if (myImageData != NULL)
		DisposeHandle(myImageData);
		
	return(myErr);
}
OSErr SpriteUtils_SetSpriteData (QTAtomContainer theSprite, Point *theLocation, short *theVisible, short *theLayer, short *theImageIndex, ModifierTrackGraphicsModeRecord *theGraphicsMode, StringPtr theSpriteName, QTAtomContainer theActionAtoms)
{
	QTAtom				myPropertyAtom;
	OSErr				myErr = noErr;
	
	if (theSprite == NULL)
		return(paramErr);
		
	// set the sprite location data
	if (theLocation != NULL) {
		MatrixRecord	myMatrix;
		
		SetIdentityMatrix(&myMatrix);
		myMatrix.matrix[2][0] = ((long)theLocation->h << 16);
		myMatrix.matrix[2][1] = ((long)theLocation->v << 16);
		EndianUtils_MatrixRecord_NtoB(&myMatrix);

		myPropertyAtom = QTFindChildByIndex(theSprite, kParentAtomIsContainer, kSpritePropertyMatrix, 1, NULL);
		if (myPropertyAtom == 0)
			myErr = QTInsertChild(theSprite, kParentAtomIsContainer, kSpritePropertyMatrix, 1, 0, sizeof(MatrixRecord), &myMatrix, NULL);
		else
			myErr = QTSetAtomData(theSprite, myPropertyAtom, sizeof(MatrixRecord), &myMatrix);
			
		if (myErr != noErr)
			goto bail;
	}
	
	// set the sprite visibility state
	if (theVisible != NULL) {
		short 			myVisible = *theVisible;
		
		myVisible = EndianS16_NtoB(myVisible);
		
		myPropertyAtom = QTFindChildByIndex(theSprite, kParentAtomIsContainer, kSpritePropertyVisible, 1, NULL);
		if (myPropertyAtom == 0)
			myErr = QTInsertChild(theSprite, kParentAtomIsContainer, kSpritePropertyVisible, 1, 0, sizeof(short), &myVisible, NULL);
		else
			myErr = QTSetAtomData(theSprite, myPropertyAtom, sizeof(short), &myVisible);
			
		if (myErr != noErr)
			goto bail;
	}
	
	// set the sprite layer
	if (theLayer != NULL) {
		short 			myLayer = *theLayer;
		
		myLayer = EndianS16_NtoB(myLayer);

		myPropertyAtom = QTFindChildByIndex(theSprite, 0, kSpritePropertyLayer, 1, NULL);
		if (myPropertyAtom == 0)
			myErr = QTInsertChild(theSprite, 0, kSpritePropertyLayer, 1, 0, sizeof(short), &myLayer, NULL);
		else
			myErr = QTSetAtomData(theSprite, myPropertyAtom, sizeof(short), &myLayer);
			
		if (myErr != noErr)
			goto bail;
	}
	
	// set the sprite image index
	if (theImageIndex != NULL) {
		short 			myImageIndex = *theImageIndex;

		myImageIndex = EndianS16_NtoB(myImageIndex);
		
		myPropertyAtom = QTFindChildByIndex(theSprite, kParentAtomIsContainer, kSpritePropertyImageIndex, 1, NULL);
		if (myPropertyAtom == 0)
			myErr = QTInsertChild(theSprite, kParentAtomIsContainer, kSpritePropertyImageIndex, 1, 0, sizeof(short), &myImageIndex, NULL);
		else
			myErr = QTSetAtomData(theSprite, myPropertyAtom, sizeof(short), &myImageIndex);
			
		if (myErr != noErr)
			goto bail;
	}
	
	// set the sprite graphics mode
	if (theGraphicsMode != NULL) {
		ModifierTrackGraphicsModeRecord		myGraphicsMode;
		
		myGraphicsMode.graphicsMode = EndianU32_NtoB(theGraphicsMode->graphicsMode);
		myGraphicsMode.opColor.red = EndianU16_NtoB(theGraphicsMode->opColor.red);
		myGraphicsMode.opColor.green = EndianU16_NtoB(theGraphicsMode->opColor.green);
		myGraphicsMode.opColor.blue = EndianU16_NtoB(theGraphicsMode->opColor.blue);

		myPropertyAtom = QTFindChildByIndex(theSprite, kParentAtomIsContainer, kSpritePropertyGraphicsMode, 1, NULL);
		if (myPropertyAtom == 0)
			myErr = QTInsertChild(theSprite, kParentAtomIsContainer, kSpritePropertyGraphicsMode, 1, 0, sizeof(myGraphicsMode), &myGraphicsMode, NULL);
		else
			myErr = QTSetAtomData(theSprite, myPropertyAtom, sizeof(myGraphicsMode), &myGraphicsMode);
			
		if (myErr != noErr)
			goto bail;
	}
	
	// set the sprite name
	if (theSpriteName != NULL) {
		QTAtom 		mySpriteNameAtom;
		
		mySpriteNameAtom = QTFindChildByIndex(theSprite, kParentAtomIsContainer, kSpriteNameAtomType, 1, NULL);
		if (mySpriteNameAtom == 0)
			myErr = QTInsertChild(theSprite, kParentAtomIsContainer, kSpriteNameAtomType, 1, 0, theSpriteName[0] + 1, theSpriteName, NULL);
		else
			myErr = QTSetAtomData(theSprite, mySpriteNameAtom, theSpriteName[0] + 1, theSpriteName);

		if (myErr != noErr)
			goto bail;
	}
	
	// set the action atoms
	if (theActionAtoms != NULL)
		myErr = QTInsertChildren(theSprite, kParentAtomIsContainer, theActionAtoms);
	
bail:
	if ((myErr != noErr) && (theSprite != NULL))
		QTRemoveChildren(theSprite, 0);

	return(myErr);
}
void QTEffects_RespondToDialogSelection (OSErr theErr)
{
	Boolean					myDialogWasCancelled = false;
	short					myResID = movieInDataForkResID;
	UInt16					myMovieIter;
	short					mySrcMovieRefNum = 0;
	Movie					myPrevSrcMovie = NULL;
	Track					myPrevSrcTrack = NULL;
	Movie					myNextSrcMovie = NULL;
	Track					myNextSrcTrack = NULL;
	short					myDestMovieRefNum = 0;
	FSSpec					myFile;
	Boolean					myIsSelected = false;
	Boolean					myIsReplacing = false;	
	StringPtr 				myPrompt = QTUtils_ConvertCToPascalString(kEffectsSaveMoviePrompt);
	StringPtr 				myFileName = QTUtils_ConvertCToPascalString(kEffectsSaveMovieFileName);
	Movie					myDestMovie = NULL;
	Fixed					myDestMovieWidth, myDestMovieHeight;
	ImageDescriptionHandle	myDesc = NULL;
	Track					videoTrackFX, videoTrackA, videoTrackB;
	Media					videoMediaFX, videoMediaA, videoMediaB;
	TimeValue				myCurrentDuration = 0;
	TimeValue				myReturnedDuration;
	Boolean					isFirstTransition = true;
	TimeValue				myMediaTransitionDuration;
	TimeValue				myMediaFXStartTime, myMediaFXDuration;
	OSType					myEffectCode;
	long					myFlags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile;
	long					myLong;
	OSErr					myErr = noErr;

	// standard parameter box has been dismissed, so remember that fact
	gEffectsDialog = 0L;
	
	myDialogWasCancelled = (theErr == userCanceledErr);
	
	// we're finished with the effect list and movie posters	
	QTDisposeAtomContainer(gEffectList);
	
	if (gPosterA != NULL)
		KillPicture(gPosterA);
		
	if (gPosterB != NULL)
		KillPicture(gPosterB);
	
	// when the sign says stop, then stop
	if (myDialogWasCancelled)
		goto bail;

	// add atoms naming the sources to gEffectSample
	myLong = EndianU32_NtoB(kSourceOneName);
	QTInsertChild(gEffectSample, kParentAtomIsContainer, kEffectSourceName, 1, 0, sizeof(myLong), &myLong, NULL);

	myLong = EndianU32_NtoB(kSourceTwoName);
	QTInsertChild(gEffectSample, kParentAtomIsContainer, kEffectSourceName, 2, 0, sizeof(myLong), &myLong, NULL);
	
	// extract the 'what' atom to find out what kind of effect it is
	{
		QTAtom			myEffectAtom;
		QTAtomID		myEffectAtomID;
		long			myEffectCodeSize;
		Ptr				myEffectCodePtr;

		myEffectAtom = QTFindChildByIndex(gEffectSample, kParentAtomIsContainer, kParameterWhatName, kParameterWhatID, &myEffectAtomID);
		
		myErr = QTLockContainer(gEffectSample);
		BailError(myErr);

		myErr = QTGetAtomDataPtr(gEffectSample, myEffectAtom, &myEffectCodeSize, &myEffectCodePtr);
		BailError(myErr);

		if (myEffectCodeSize != sizeof(OSType)) {
			myErr = paramErr;
			goto bail;
		}
		
		myEffectCode = *(OSType *)myEffectCodePtr;		// "tsk"
		myEffectCode = EndianU32_BtoN(myEffectCode);	// because the data is read from an atom container
		
		myErr = QTUnlockContainer(gEffectSample);
		BailError(myErr);
	}

	// ask the user for the name of the new movie file
	QTFrame_PutFile(myPrompt, myFileName, &myFile, &myIsSelected, &myIsReplacing);
	if (!myIsSelected)
		goto bail;				// deal with user cancelling

	// create a movie file for the destination movie
	myErr = CreateMovieFile(&myFile, FOUR_CHAR_CODE('TVOD'), 0, myFlags, &myDestMovieRefNum, &myDestMovie);
	BailError(myErr);
	
	// open the first file as a movie; call the first movie myPrevSrcMovie
	myErr = OpenMovieFile(&gSpecList[0], &mySrcMovieRefNum, fsRdPerm);
	BailError(myErr);
	
	myErr = NewMovieFromFile(&myPrevSrcMovie, mySrcMovieRefNum, NULL, NULL, 0, NULL);
	BailError(myErr);
	
	myErr = CloseMovieFile(mySrcMovieRefNum);
	BailError(myErr);
	
	// if the movie is shorter than kMinimumDuration, scale it to that length
	SetMovieTimeScale(myPrevSrcMovie, kTimeScale);
	myErr = QTEffects_GetFirstVideoTrackInMovie(myPrevSrcMovie, &myPrevSrcTrack);
	BailNil(myPrevSrcTrack);
	
	if (GetTrackDuration(myPrevSrcTrack) < kMinimumDuration) {
		myErr = ScaleTrackSegment(myPrevSrcTrack, 0, GetTrackDuration(myPrevSrcTrack), kMinimumDuration);
		BailError(myErr);
	}
	
	// find out how big the first movie is; we'll use it as the size of all our tracks
	GetTrackDimensions(myPrevSrcTrack, &myDestMovieWidth, &myDestMovieHeight);
	
#if USES_MAKE_IMAGE_DESC_FOR_EFFECT
	// create a new sample description for the effect,
	// which is just an image description specifying the effect and its dimensions
	myErr = MakeImageDescriptionForEffect(myEffectCode, &myDesc);
	if (myErr != noErr)
		BailError(myErr);
#else
	// create a new sample description for the effect,
	// which is just an image description specifying the effect and its dimensions
	myDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
	BailNil(myDesc);
	
	(**myDesc).idSize = sizeof(ImageDescription);
	(**myDesc).cType = myEffectCode;
	(**myDesc).hRes = 72L << 16;
	(**myDesc).vRes = 72L << 16;
	(**myDesc).dataSize = 0L;
	(**myDesc).frameCount = 1;
	(**myDesc).depth = 0;
	(**myDesc).clutID = -1;
#endif
	
	// fill in the fields of the sample description
	(**myDesc).vendor = kAppleManufacturer;
	(**myDesc).temporalQuality = codecNormalQuality;
	(**myDesc).spatialQuality = codecNormalQuality;
	(**myDesc).width = FixRound(myDestMovieWidth);
	(**myDesc).height = FixRound(myDestMovieHeight);

	// add three video tracks to the destination movie:
	// 	- videoTrackFX is where the effects and stills live; it's user-visible.
	//	- videoTrackA is where the "source A"s for effects live; it's hidden by the input map
	//	- videoTrackB is where the "source B"s for effects live; it's hidden by the input map
	videoTrackFX = NewMovieTrack(myDestMovie, myDestMovieWidth, myDestMovieHeight, 0);
	BailNil(videoTrackFX);
	videoMediaFX = NewTrackMedia(videoTrackFX, VideoMediaType, kTimeScale, NULL, 0);
	BailNil(videoMediaFX);
	myErr = BeginMediaEdits(videoMediaFX);
	BailError(myErr);
	
	videoTrackA = NewMovieTrack(myDestMovie, myDestMovieWidth, myDestMovieHeight, 0);
	BailNil(videoTrackA);
	videoMediaA = NewTrackMedia(videoTrackA, VideoMediaType, kTimeScale, NULL, 0);
	BailNil(videoMediaA);

	videoTrackB = NewMovieTrack(myDestMovie, myDestMovieWidth, myDestMovieHeight, 0);
	BailNil(videoTrackB);
	videoMediaB = NewTrackMedia(videoTrackB, VideoMediaType, kTimeScale, NULL, 0);
	BailNil(videoMediaB);

	// create the input map
	{
		long				myRefIndex1, myRefIndex2;
		QTAtomContainer		myInputMap;
		QTAtom				myInputAtom;
		OSType				myInputType;

		QTNewAtomContainer(&myInputMap);

		// first input
		if (videoTrackA) {
		
			AddTrackReference(videoTrackFX, videoTrackA, kTrackModifierReference, &myRefIndex1);
			QTInsertChild(myInputMap, kParentAtomIsContainer, kTrackModifierInput, myRefIndex1, 0, 0, NULL, &myInputAtom);
	
			myInputType = EndianU32_NtoB(kTrackModifierTypeImage);
			QTInsertChild(myInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(myInputType), &myInputType, NULL);
	
			myLong = EndianU32_NtoB(kSourceOneName);
			QTInsertChild(myInputMap, myInputAtom, kEffectDataSourceType, 1, 0, sizeof(myLong), &myLong, NULL);
		}

		// second input
		if (videoTrackB) {
		
			AddTrackReference(videoTrackFX, videoTrackB, kTrackModifierReference, &myRefIndex2);
			QTInsertChild(myInputMap, kParentAtomIsContainer, kTrackModifierInput, myRefIndex2, 0, 0, NULL, &myInputAtom);
	
			myInputType = EndianU32_NtoB(kTrackModifierTypeImage);
			QTInsertChild(myInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(myInputType), &myInputType, NULL);
	
			myLong = EndianU32_NtoB(kSourceTwoName);
			QTInsertChild(myInputMap, myInputAtom, kEffectDataSourceType, 1, 0, sizeof(myLong), &myLong, NULL);
		}

		// set that map
		SetMediaInputMap(GetTrackMedia(videoTrackFX), myInputMap);
		
		QTDisposeAtomContainer(myInputMap);
	}

	myCurrentDuration = 0;

#if MAKE_STILL_SECTIONS
	// copy the first sample of the first video track of the first movie to videoTrackFX, with duration kStillDuration.
	myErr = CopyPortionOfTrackToTrack(myPrevSrcTrack, eStartPortion + eMiddlePortion, videoTrackFX, myCurrentDuration, &myReturnedDuration);
	BailError(myErr);
	
	myCurrentDuration += myReturnedDuration;
#endif 

	// now process any remaining files
	myMovieIter = 1;
	while (myMovieIter < gSpecCount) {
		
		// open the next file as a movie; call it nextSourceMovie
		myErr = OpenMovieFile(&gSpecList[myMovieIter], &mySrcMovieRefNum, fsRdPerm);
		BailError(myErr);
		
		myErr = NewMovieFromFile(&myNextSrcMovie, mySrcMovieRefNum, NULL, NULL, 0, NULL);
		BailError(myErr);
		
		// we're done with the movie file, so close it
		myErr = CloseMovieFile(mySrcMovieRefNum);
		BailError(myErr);
		
		// if the movie is shorter than kMinimumDuration, scale it to that length
		SetMovieTimeScale(myNextSrcMovie, kTimeScale);
		myErr = QTEffects_GetFirstVideoTrackInMovie(myNextSrcMovie, &myNextSrcTrack);
		BailNil(myNextSrcTrack);
		
		if (GetTrackDuration(myNextSrcTrack) < kMinimumDuration) {
			myErr = ScaleTrackSegment(myNextSrcTrack, 0, GetTrackDuration(myNextSrcTrack), kMinimumDuration);
			BailError(myErr);
		}

		// create a transition effect from the previous source movie's first video sample to the next source movie's first video sample
		// (the effect should have duration kEffectDuration);
		// this involves adding one sample to each of the three video tracks:
		
		//    sample from previous source movie	 -> videoTrackA
		myErr = QTEffects_CopyPortionOfTrackToTrack(myPrevSrcTrack, eFinishPortion, videoTrackA, myCurrentDuration, &myReturnedDuration);
		BailError(myErr);
		
		//    sample from next source movie    	 -> videoTrackB
		myErr = QTEffects_CopyPortionOfTrackToTrack(myNextSrcTrack, eStartPortion, videoTrackB, myCurrentDuration, &myReturnedDuration);
		BailError(myErr);
		
		//    effect sample                 	  -> videoTrackFX
		if (isFirstTransition) {
			myMediaTransitionDuration = myReturnedDuration;
			myMediaFXStartTime = GetMediaDuration(videoMediaFX);
			myErr = AddMediaSample(videoMediaFX, gEffectSample, 0, GetHandleSize(gEffectSample), myMediaTransitionDuration, (SampleDescriptionHandle)myDesc, 1, 0, NULL);
			BailError(myErr);
			
			myMediaFXDuration = GetMediaDuration(videoMediaFX) - myMediaFXStartTime;
			isFirstTransition = false;
		}
		
		myErr = InsertMediaIntoTrack(videoTrackFX, myCurrentDuration, myMediaFXStartTime, myMediaFXDuration, FixRatio(myReturnedDuration, myMediaTransitionDuration));
		BailError(myErr);
		
		myCurrentDuration += myReturnedDuration;
		
#if MAKE_STILL_SECTIONS
		// copy the first video sample of myNextSrcMovie to videoTrackFX, with duration kStillDuration.
		myErr = QTEffects_CopyPortionOfTrackToTrack(myNextSrcTrack, eMiddlePortion + (myMovieIter + 1 == theSpecCount) ? eFinishPortion : 0, videoTrackFX, myCurrentDuration, &myReturnedDuration);
		BailError(myErr);
		
		myCurrentDuration += myReturnedDuration;
#endif // MAKE_STILL_SECTIONS
		
		// dispose of previous source movie.  
		DisposeMovie(myPrevSrcMovie);
		
		myPrevSrcMovie = myNextSrcMovie;
		myPrevSrcTrack = myNextSrcTrack;
		myNextSrcMovie = NULL;
		myNextSrcTrack = NULL;
		
		myMovieIter++;
	} // while
	
	myErr = EndMediaEdits(videoMediaFX);
	BailError(myErr);

	myErr = AddMovieResource(myDestMovie, myDestMovieRefNum, &myResID, "\pMovie 1");
	BailError(myErr);
	
	CloseMovieFile(myDestMovieRefNum);
	
	if (myPrevSrcMovie != NULL)
		DisposeMovie(myPrevSrcMovie);
		
	DisposeMovie(myDestMovie);
	
bail:
	free(myPrompt);
	free(myFileName);

	QTDisposeAtomContainer(gEffectSample);
	DisposeHandle((Handle)myDesc);

	return;
}