Retired Document
Important: Apple recommends that developers explore QTKit and Core Video for new development in this technology area. See QTKit Framework Reference and Core Video Programming Guide for more information.
QTWiredSprite.c Sample Code
This appendix includes sample code from QTWiredSprite.c
. Note this is only a partial code listing. You can download the full sample code at QuickTime Web site at
http://developer.apple.com/samplecode/Sample_Code/QuickTime/Wired_Movies_and_Sprites.htm |
It is also available on the QuickTime SDK.
Refer to Chapter 3, Sprite Media Handler, and Chapter 4, Authoring Wired Movies and Sprite Animations, for information on how to use this sample code in your application.
// File: QTWiredSprites.c |
// |
// Contains: QuickTime wired sprites support for QuickTime movies. |
// |
// Written by: Sean Allen |
// Revised by: Chris Flick and Tim Monroe |
// Based (heavily!) on the existing MakeActionSpriteMovie.c |
// code written by Sean Allen. |
// |
// Copyright: © 1997-1999 by Apple Computer, Inc., all rights reserved. |
// |
// Change History (most recent first): |
// |
// <2> 03/26/98 rtm made fixes for Windows compiles |
// <1> 03/25/98 rtm first file; integrated existing code |
// with shell framework |
// |
// |
// This sample code creates a wired sprite movie containing one sprite |
//track. The sprite track contains six sprites: two penguins and four |
//buttons. |
// |
// The four buttons are initially invisible. When the mouse enters (or |
// "rolls over") a button, it appears. |
// When the mouse is clicked inside a button, its image changes to its |
//"pressed" image. When the mouse |
// is released, its image changes back to its "unpressed" image. If the |
// mouse is released inside the button, |
// an action is triggered. The buttons perform the actions of go to |
// beginning of movie, step backward, |
// step forward, and go to end of movie. |
// |
// The first penguin shows all of the buttons when the mouse enters it, |
// and hides them when the mouse exits. |
// The first penguin is the only sprite that has properties that are |
// overriden by the override sprite samples. |
// These samples override its matrix (in order to move it) and its image |
// index (in order to make it "waddle"). |
// |
// When the mouse is clicked on the second penguin, it changes its image |
// index to its "eyes closed" image. |
// When the mouse is released, it changes back to its normal image. This |
// makes it appear to blink when clicked on. |
// When the mouse is released over the penguin, several actions are |
// triggered. Both penguins' graphics states are |
// toggled between copyMode and blendMode, and the movie's rate is |
// toggled between 0 and one. |
// |
// The second penguin moves once per second. This occurs whether the |
// movie's rate is currently 0 or one, |
// because it is being triggered by a gated idle event. When the penguin |
// receives the idle event, it changes |
// its matrix using an action which uses min, max, delta, and wraparound |
// options. |
// |
// The movie's looping mode is set to palindrome by a frame-loaded |
// action. |
// |
// So, our general strategy is as follows (though perhaps not in the |
// order listed): |
// |
// (1) Create a new movie file with a single sprite track. |
// (2) Assign the "no controller" movie controller to the movie. |
// (3) Set the sprite track's background color, idle event |
// frequency, and hasActions properties. |
// (4) Convert our PICT resources to animation codec images with |
// transparency. |
// (5) Create a key frame sample containing six sprites and all of |
// their shared images. |
// (6) Assign the sprites their initial property values. |
// (7) Create a frameLoaded event for the key frame. |
// (8) Create some override samples that override the matrix and |
// image index properties of the first penguin sprite. |
// |
// NOTES: |
// |
// *** (1) *** |
// There are event types other that mouse related events (for instance, |
// Idle and FrameLoaded). |
// Idle events are independent of the movie's rate, and they can be |
// gated so they are send at most |
// every n ticks. In our sample movie, the second penguin moves when the |
// movie's rate is 0, |
// and moves only once per second because of the value of the sprite |
// track's idleEventFrequencey property. |
// |
// *** (2) *** |
// Multiple actions may be executed in response to a single event. In |
// our sample movie, rolling over |
// the first penguin shows and hides four different buttons. |
// |
// *** (3) *** |
// Actions may target any sprite or track in the movie. In our sample |
// movie, clicking on one penguin |
// changes the graphics mode of the other. |
// |
// *** (4) *** |
// Conditional and looping control structures are supported. In our |
// sample movie, the second penguin |
// uses the "case statement" action. |
// |
// *** (5) *** |
// Sprite track variables that have not been set have a default value of |
// 0. (The second penguin's |
// conditional code relies on this.) |
// |
// *** (6) *** |
// Wired sprites were previously known as "action sprites". Don't let |
// the names of some of the utility |
// functions confuse you. We'll try to update the source code as time |
// permits. |
// |
// *** (7) *** |
// Penguins don't fly, but I hear they totally shred halfpipes on |
// snowboards. |
// |
////////// |
// header files |
#include "QTWiredSprites.h" |
////////// |
// |
// QTWired_CreateWiredSpritesMovie |
// Create a QuickTime movie containing a wired sprites track. |
// |
////////// |
OSErr QTWired_CreateWiredSpritesMovie (void) |
{ |
short myResRefNum = 0; |
Movie myMovie = NULL; |
Track myTrack; |
Media myMedia; |
StandardFileReply myReply; |
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, myResID, 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 |
StandardPutFile("\pSprite movie file name:", "\pSprite.mov", |
&myReply); |
if (!myReply.sfGood) |
goto bail; |
// create a movie file for the destination movie |
myErr = CreateMovieFile(&myReply.sfFile, FOUR_CHAR_CODE('TVOD'), 0, |
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 |
AddPICTImageToKeyFrameSample(mySample, kGoToBeginningButtonUp, |
&myKeyColor, kGoToBeginningButtonUpIndex, NULL, NULL); |
AddPICTImageToKeyFrameSample(mySample, kGoToBeginningButtonDown, |
&myKeyColor, kGoToBeginningButtonDownIndex, NULL, NULL); |
AddPICTImageToKeyFrameSample(mySample, kGoToEndButtonUp, &myKeyColor, |
kGoToEndButtonUpIndex, NULL, NULL); |
AddPICTImageToKeyFrameSample(mySample, kGoToEndButtonDown, |
&myKeyColor, kGoToEndButtonDownIndex, NULL, NULL); |
AddPICTImageToKeyFrameSample(mySample, kGoToPrevButtonUp, |
&myKeyColor, kGoToPrevButtonUpIndex, NULL, NULL); |
AddPICTImageToKeyFrameSample(mySample, kGoToPrevButtonDown, |
&myKeyColor, kGoToPrevButtonDownIndex, NULL, NULL); |
AddPICTImageToKeyFrameSample(mySample, kGoToNextButtonUp, |
&myKeyColor, kGoToNextButtonUpIndex, NULL, NULL); |
AddPICTImageToKeyFrameSample(mySample, kGoToNextButtonDown, |
&myKeyColor, kGoToNextButtonDownIndex, NULL, NULL); |
AddPICTImageToKeyFrameSample(mySample, kPenguinForward, &myKeyColor, |
kPenguinForwardIndex, NULL, NULL); |
AddPICTImageToKeyFrameSample(mySample, kPenguinLeft, &myKeyColor, |
kPenguinLeftIndex, NULL, NULL); |
AddPICTImageToKeyFrameSample(mySample, kPenguinRight, &myKeyColor, |
kPenguinRightIndex, NULL, NULL); |
AddPICTImageToKeyFrameSample(mySample, kPenguinClosed, &myKeyColor, |
kPenguinClosedIndex, NULL, NULL); |
for (myIndex = kPenguinDownRightCycleStartIndex, myResID = |
kWalkDownRightCycleStart; myIndex <= kPenguinDownRightCycleEndIndex; |
myIndex++, myResID++) |
AddPICTImageToKeyFrameSample(mySample, myResID, &myKeyColor, |
myIndex, NULL, NULL); |
// assign group IDs to the images |
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 = 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 = 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 = 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 = 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 = 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 = 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; |
AddSpriteSetImageIndexAction(myBeginActionButton, |
kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, |
kGoToBeginningButtonDownIndex, NULL); |
AddSpriteSetImageIndexAction(myBeginActionButton, |
kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, |
NULL, kGoToBeginningButtonUpIndex, NULL); |
AddMovieGoToBeginningAction(myBeginActionButton, |
kParentAtomIsContainer, kQTEventMouseClickEndTriggerButton); |
AddSpriteSetVisibleAction(myBeginActionButton, |
kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, 0, NULL, |
true, NULL); |
AddSpriteSetVisibleAction(myBeginActionButton, |
kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, 0, NULL, |
false, NULL); |
AddSpriteToSample(mySample, myBeginActionButton, |
kGoToBeginningSpriteID); |
QTDisposeAtomContainer(myBeginActionButton); |
// add go to prev button |
myErr = QTCopyAtom(myPrevButton, kParentAtomIsContainer, |
&myPrevActionButton); |
if (myErr != noErr) |
goto bail; |
AddSpriteSetImageIndexAction(myPrevActionButton, |
kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, |
kGoToPrevButtonDownIndex, NULL); |
AddSpriteSetImageIndexAction(myPrevActionButton, |
kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, |
NULL, kGoToPrevButtonUpIndex, NULL); |
AddMovieStepBackwardAction(myPrevActionButton, |
kParentAtomIsContainer, kQTEventMouseClickEndTriggerButton); |
AddSpriteSetVisibleAction(myBeginActionButton, |
kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, 0, NULL, |
true, NULL); |
AddSpriteSetVisibleAction(myBeginActionButton, |
kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, 0, NULL, |
false, NULL); |
AddSpriteToSample(mySample, myPrevActionButton, kGoToPrevSpriteID); |
QTDisposeAtomContainer(myPrevActionButton); |
// add go to next button |
myErr = QTCopyAtom(myNextButton, kParentAtomIsContainer, |
&myNextActionButton); |
if (myErr != noErr) |
goto bail; |
AddSpriteSetImageIndexAction(myNextActionButton, |
kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, |
kGoToNextButtonDownIndex, NULL); |
AddSpriteSetImageIndexAction(myNextActionButton, |
kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, |
NULL, kGoToNextButtonUpIndex, NULL); |
AddMovieStepForwardAction(myNextActionButton, kParentAtomIsContainer, |
kQTEventMouseClickEndTriggerButton); |
AddSpriteSetVisibleAction(myBeginActionButton, |
kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, 0, NULL, |
true, NULL); |
AddSpriteSetVisibleAction(myBeginActionButton, |
kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, 0, NULL, |
false, NULL); |
AddSpriteToSample(mySample, myNextActionButton, kGoToNextSpriteID); |
QTDisposeAtomContainer(myNextActionButton); |
// add go to end button |
myErr = QTCopyAtom(myEndButton, kParentAtomIsContainer, |
&myEndActionButton); |
if (myErr != noErr) |
goto bail; |
AddSpriteSetImageIndexAction(myEndActionButton, |
kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, |
kGoToEndButtonDownIndex, NULL); |
AddSpriteSetImageIndexAction(myEndActionButton, |
kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, |
NULL, kGoToEndButtonUpIndex, NULL); |
AddMovieGoToEndAction(myEndActionButton, kParentAtomIsContainer, |
kQTEventMouseClickEndTriggerButton); |
AddSpriteSetVisibleAction(myBeginActionButton, |
kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, 0, NULL, |
true, NULL); |
AddSpriteSetVisibleAction(myBeginActionButton, |
kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, 0, NULL, |
false, NULL); |
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 |
AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, |
kQTEventMouseEnter, 0, NULL, 0, kTargetSpriteID, |
(void *)kGoToBeginningSpriteID, true, NULL); |
AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, |
kQTEventMouseExit, 0, NULL, 0, kTargetSpriteID, |
(void *)kGoToBeginningSpriteID, false, NULL); |
AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, |
kQTEventMouseEnter, 0, NULL, 0, kTargetSpriteID, |
(void *)kGoToPrevSpriteID, true, NULL); |
AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, |
kQTEventMouseExit, 0, NULL, 0, kTargetSpriteID, |
(void *)kGoToPrevSpriteID, false, NULL); |
AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, |
kQTEventMouseEnter, 0, NULL, 0, kTargetSpriteID, |
(void *)kGoToNextSpriteID, true, NULL); |
AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, |
kQTEventMouseExit, 0, NULL, 0, kTargetSpriteID, |
(void *)kGoToNextSpriteID, false, NULL); |
AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, |
kQTEventMouseEnter, 0, NULL, 0, kTargetSpriteID, |
(void *)kGoToEndSpriteID, true, NULL); |
AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, |
kQTEventMouseExit, 0, NULL, 0, kTargetSpriteID, |
(void *)kGoToEndSpriteID, false, NULL); |
AddSpriteToSample(mySample, myPenguinOneAction, kPenguinOneSpriteID); |
QTDisposeAtomContainer(myPenguinOneAction); |
// add penguin two |
myErr = QTCopyAtom(myPenguinTwo, kParentAtomIsContainer, |
&myPenguinTwoAction); |
if (myErr != noErr) |
goto bail; |
// blink when clicked on |
AddSpriteSetImageIndexAction(myPenguinTwoAction, |
kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, |
kPenguinClosedIndex, NULL); |
AddSpriteSetImageIndexAction(myPenguinTwoAction, |
kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, |
NULL, kPenguinForwardIndex, NULL); |
AddQTEventAtom(myPenguinTwoAction, kParentAtomIsContainer, |
kQTEventMouseClickEndTriggerButton, &myEventAtom); |
// toggle the movie rate and both of the birds' graphics modes |
QTWired_AddPenguinTwoConditionalActions(myPenguinTwoAction, |
myEventAtom); |
QTWired_AddWraparoundMatrixOnIdle(myPenguinTwoAction); |
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; |
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 |
AddSpriteSampleToMedia(myMedia, mySample, kSpriteMediaFrameDuration, |
true, NULL); |
//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; |
SetSpriteData(myPenguinOneOverride, &myLocation, NULL, NULL, |
&myIndex, NULL, NULL, NULL); |
AddSpriteToSample(mySample, myPenguinOneOverride, |
kPenguinOneSpriteID); |
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 |
hasActions = true; |
QTInsertChild(myTrackProperties, 0, |
kSpriteTrackPropertyHasActions, 1, 1, |
sizeof(hasActions), &hasActions, NULL); |
// tell the sprite track to generate QTIdleEvents |
myFrequency = EndianU32_NtoB(60); |
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, 0, |
myReply.sfFile.name); |
bail: |
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); |
} |
////////// |
// |
// QTWired_AddPenguinTwoConditionalActions |
// Add actions to the second penguin that transform him (her?) into a two |
// state button |
// that plays or pauses the movie. |
// |
// We are relying on the fact that a "GetVariable" for a variable ID |
// which has never been set |
// will return 0. If we needed a different default value, we could |
// initialize it using the |
// frameLoaded event. |
// |
// A higher-level description of the logic is: |
// |
// On MouseUpInside |
// If (GetVariable(DefaultTrack, 1) = 0) |
// SetMovieRate(1) |
// SetSpriteGraphicsMode(DefaultSprite, { blend, grey } ) |
// SetSpriteGraphicsMode(GetSpriteByID(DefaultTrack, 5), |
// { ditherCopy, white } ) |
// SetVariable(DefaultTrack, 1, 1) |
// ElseIf (GetVariable(DefaultTrack, 1) = 1) |
// SetMovieRate(0) |
// SetSpriteGraphicsMode(DefaultSprite, { ditherCopy, white }) |
// SetSpriteGraphicsMode(GetSpriteByID(DefaultTrack, 5), |
// { blend, grey }) |
// SetVariable(DefaultTrack, 1, 0) |
// Endif |
// End |
// |
////////// |
OSErr QTWired_AddPenguinTwoConditionalActions (QTAtomContainer |
theContainer, QTAtom theEventAtom) |
{ |
QTAtom myNewActionAtom, myNewParamAtom, myConditionalAtom; |
QTAtom myExpressionAtom, myOperatorAtom, myActionListAtom; |
short myParamIndex, myConditionIndex, myOperandIndex; |
float myConstantValue; |
QTAtomID myVariableID; |
ModifierTrackGraphicsModeRecord myBlendMode, myCopyMode; |
OSErr myErr = noErr; |
myBlendMode.graphicsMode = blend; |
myBlendMode.opColor.red = myBlendMode.opColor.green = |
myBlendMode.opColor.blue = 0x8fff; // grey |
myCopyMode.graphicsMode = ditherCopy; |
myCopyMode.opColor.red = myCopyMode.opColor.green = |
myCopyMode.opColor.blue = 0xffff; // white |
AddActionAtom(theContainer, theEventAtom, kActionCase, |
&myNewActionAtom); |
myParamIndex = 1; |
AddActionParameterAtom(theContainer, myNewActionAtom, myParamIndex, |
0, NULL, &myNewParamAtom); |
// first condition |
myConditionIndex = 1; |
AddConditionalAtom(theContainer, myNewParamAtom, myConditionIndex, |
&myConditionalAtom); |
AddExpressionContainerAtomType(theContainer, myConditionalAtom, |
&myExpressionAtom); |
AddOperatorAtom(theContainer, myExpressionAtom, kOperatorEqualTo, |
&myOperatorAtom); |
myOperandIndex = 1; |
myConstantValue = kButtonStateOne; |
AddOperandAtom(theContainer, myOperatorAtom, kOperandConstant, |
myOperandIndex, NULL, myConstantValue); |
myOperandIndex = 2; |
myVariableID = kPenguinStateVariableID; |
AddVariableOperandAtom(theContainer, myOperatorAtom, myOperandIndex, |
0, NULL, 0, myVariableID); |
AddActionListAtom(theContainer, myConditionalAtom, |
&myActionListAtom); |
AddMovieSetRateAction(theContainer, myActionListAtom, 0, |
Long2Fix(1)); |
AddSpriteSetGraphicsModeAction(theContainer, myActionListAtom, 0, 0, |
NULL, 0, 0, NULL, &myBlendMode, NULL); |
AddSpriteSetGraphicsModeAction(theContainer, myActionListAtom, 0, 0, |
NULL, 0, kTargetSpriteID, (void *)kPenguinOneSpriteID, |
&myCopyMode, NULL); |
AddSpriteTrackSetVariableAction(theContainer, myActionListAtom, 0, |
kPenguinStateVariableID, kButtonStateTwo, 0, NULL, 0); |
// second condition |
myConditionIndex = 2; |
AddConditionalAtom(theContainer, myNewParamAtom, myConditionIndex, |
&myConditionalAtom); |
AddExpressionContainerAtomType(theContainer, myConditionalAtom, |
&myExpressionAtom); |
AddOperatorAtom(theContainer, myExpressionAtom, kOperatorEqualTo, |
&myOperatorAtom); |
myOperandIndex = 1; |
myConstantValue = kButtonStateTwo; |
AddOperandAtom(theContainer, myOperatorAtom, kOperandConstant, |
myOperandIndex, NULL, myConstantValue); |
myOperandIndex = 2; |
myVariableID = kPenguinStateVariableID; |
AddVariableOperandAtom(theContainer, myOperatorAtom, myOperandIndex, |
0, NULL, 0, myVariableID); |
AddActionListAtom(theContainer, myConditionalAtom, |
&myActionListAtom); |
AddMovieSetRateAction(theContainer, myActionListAtom, 0, |
Long2Fix(0)); |
AddSpriteSetGraphicsModeAction(theContainer, myActionListAtom, 0, 0, |
NULL, 0, 0, NULL, &myCopyMode, NULL); |
AddSpriteSetGraphicsModeAction(theContainer, myActionListAtom, 0, 0, |
NULL, 0, kTargetSpriteID, (void *)kPenguinOneSpriteID, |
&myBlendMode, NULL); |
AddSpriteTrackSetVariableAction(theContainer, myActionListAtom, 0, |
kPenguinStateVariableID, kButtonStateOne, 0, NULL, 0); |
bail: |
return(myErr); |
} |
////////// |
// |
// QTWired_AddWraparoundMatrixOnIdle |
// Add beginning, end, and change matrices to the specified atom |
// container. |
// |
////////// |
OSErr QTWired_AddWraparoundMatrixOnIdle (QTAtomContainer theContainer) |
{ |
MatrixRecord myMinMatrix, myMaxMatrix, myDeltaMatrix; |
long myFlags = kActionFlagActionIsDelta | |
kActionFlagParameterWrapsAround; |
QTAtom myActionAtom; |
OSErr myErr = noErr; |
myMinMatrix.matrix[0][0] = myMinMatrix.matrix[0][1] = |
myMinMatrix.matrix[0][2] = EndianS32_NtoB(0xffffffff); |
myMinMatrix.matrix[1][0] = myMinMatrix.matrix[1][1] = |
myMinMatrix.matrix[1][2] = EndianS32_NtoB(0xffffffff); |
myMinMatrix.matrix[2][0] = myMinMatrix.matrix[2][1] = |
myMinMatrix.matrix[2][2] = EndianS32_NtoB(0xffffffff); |
myMaxMatrix.matrix[0][0] = myMaxMatrix.matrix[0][1] = |
myMaxMatrix.matrix[0][2] = EndianS32_NtoB(0x7fffffff); |
myMaxMatrix.matrix[1][0] = myMaxMatrix.matrix[1][1] = |
myMaxMatrix.matrix[1][2] = EndianS32_NtoB(0x7fffffff); |
myMaxMatrix.matrix[2][0] = myMaxMatrix.matrix[2][1] = |
myMaxMatrix.matrix[2][2] = EndianS32_NtoB(0x7fffffff); |
myMinMatrix.matrix[2][1] = EndianS32_NtoB(Long2Fix((1 * |
kSpriteTrackHeight / 4) - (kPenguinHeight / 2))); |
myMaxMatrix.matrix[2][1] = EndianS32_NtoB(Long2Fix((3 * |
kSpriteTrackHeight / 4) - (kPenguinHeight / 2))); |
SetIdentityMatrix(&myDeltaMatrix); |
myDeltaMatrix.matrix[2][1] = Long2Fix(1); |
// change location |
myErr = AddSpriteSetMatrixAction(theContainer, |
kParentAtomIsContainer, kQTEventIdle, 0, NULL, 0, 0, NULL, |
&myDeltaMatrix, &myActionAtom); |
if (myErr != noErr) |
goto bail; |
myErr = AddActionParameterOptions(theContainer, myActionAtom, 1, |
myFlags, sizeof(myMinMatrix), &myMinMatrix, |
sizeof(myMaxMatrix), &myMaxMatrix); |
bail: |
return(myErr); |
} |
Copyright © 2003, 2009 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2009-06-01