Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Completed Lab/QTWiredSprites.c
////////// |
// |
// 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-1998 by Apple Computer, Inc., all rights reserved. |
// |
// Change History (most recent first): |
// |
// <5> 03/20/00 rtm made changes to get things running under CarbonLib |
// <4> 07/30/99 rtm added QTWired_AddCursorChangeOnMouseOver to illustrate new |
// sprite-as-button behaviors added in QT4; added this action to penguin one |
// <3> 09/30/98 rtm tweaked call to AddMovieResource to create single-fork movies |
// <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 it's "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 zero and one. |
// |
// The second penguin moves once per second. This occurs whether the movie's rate is currently zero 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 zero, |
// 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 zero. (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; |
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, /* fsspec for the movie to be created */ |
FOUR_CHAR_CODE('TVOD'), /* creator value for the new file */ |
smSystemScript, /* script in which the movie file should be created */ |
myFlags, /* movie creation flags */ |
&myResRefNum, /* file reference for movie file return here */ |
&myMovie); /* new movie identifier return here */ |
if (myErr != noErr) |
goto bail; |
// select the "no controller" movie controller option |
myType = EndianU32_NtoB(myType); |
SetUserDataItem(GetMovieUserData(myMovie), |
&myType, |
sizeof(myType), |
kUserDataMovieControllerType, |
1); |
////////// |
// |
// create the sprite track and media |
// |
////////// |
myTrack = NewMovieTrack(myMovie, |
((long)kSpriteTrackWidth << 16), /* display width in pixels */ |
((long)kSpriteTrackHeight << 16), /* display height in pixels */ |
kNoVolume); /* volume setting of the track */ |
myMedia = NewTrackMedia(myTrack, |
SpriteMediaType, /* type of media to create */ |
kSpriteMediaTimeScale, /* media time scale */ |
NULL, /* data ref, pass nil to use the file the movie was created in */ |
0); /* data ref type, pass nil to use the file the movie was created in */ |
////////// |
// |
// 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, /* the key frame sample */ |
kGoToBeginningButtonUp, /* pict resource id */ |
&myKeyColor, /* RGBColor that should be used as the transparency color */ |
kGoToBeginningButtonUpIndex, /* atom id for the kSpriteImageAtomType atom */ |
NULL, /* optional sprite registration point */ |
NULL); /* optional sprite image name */ |
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, myID = kWalkDownRightCycleStart; myIndex <= kPenguinDownRightCycleEndIndex; myIndex++, myID++) |
AddPICTImageToKeyFrameSample(mySample, myID, &myKeyColor, myIndex, NULL, NULL); |
/* assign group IDs to the images - you must assign group IDs to your sprite sample |
if you want a sprite to display images with non-equivalent image descriptions |
(i.e., images with different dimensions) */ |
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, /* sprite location */ |
&isVisible, /* sprite visible property */ |
&myLayer, /* sprite layer (smaller #'s are further forward) */ |
&myIndex, /* sprite index property */ |
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); |
QTWired_AddCursorChangeOnMouseOver(mySample, 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); |
////////// |
// |
// 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, Jackson |
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, &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); |
} |
////////// |
// |
// 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 zero. 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; |
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); |
return(noErr); |
} |
////////// |
// |
// 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); |
} |
////////// |
// |
// QTWired_AddCursorChangeOnMouseOver |
// Add a cursor-change-on-mouse-over action to the sprite having the specified ID |
// in the specified atom container. |
// |
// Here we use the new "sprite behaviors atom" introduced in QuickTime 4.0, which |
// simplifies adding button-like capabilities to sprites. |
// |
////////// |
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); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-02-25