/* Copyright (c) Microsoft Corporation. Licensed under the MIT License. */ /*************************************************************************** scene.cpp Author: Sean Selitrennikoff Date: August, 1994 This file contains all functionality for scene manipulation. THIS IS A CODE REVIEWED FILE Basic scene private classes: Scene Chop Undo Object (SUNC) BASE ---> UNDB ---> MUNB ---> SUNC Scene Background Undo Object (SUNK) BASE ---> UNDB ---> MUNB ---> SUNK Scene Pause Undo Object (SUNP) BASE ---> UNDB ---> MUNB ---> SUNP Scene Text box Undo Object (SUNX) BASE ---> UNDB ---> MUNB ---> SUNX Scene Sound Undo Object (SUNS) BASE ---> UNDB ---> MUNB ---> SUNS Scene Title Undo Object (SUNT) BASE ---> UNDB ---> MUNB ---> SUNT ***************************************************************************/ #include "soc.h" ASSERTNAME // // Scene event types // enum SEVT { // StartEv FrmEv Param sevtAddActr, // X pactr/chid sevtPlaySnd, // X SSE (Scene Sound Event) sevtAddTbox, // X ptbox/chid sevtChngCamera, // X icam sevtSetBkgd, // X Background Tag sevtPause // X type, duration }; // // Struct for saving event pause information // struct SEVP { WIT wit; long dts; }; // // Scene thumbnails // const kdxpThumbnail = 144; const kdypThumbnail = 81; const kbTransparent = 250; // // Scene event // struct SEV { long nfrm; // frame number of the event. SEVT sevt; // event type }; const kbomSev = 0xF0000000; const kbomLong = 0xC0000000; // // Header for the scene chunk when on file // struct SCENH { short bo; short osk; long nfrmLast; long nfrmFirst; TRANS trans; }; const kbomScenh = 0x5FC00000; /**************************************** TAGC - Tag,Chid combo ****************************************/ const BOM kbomChid = 0xC0000000; const BOM kbomTagc = kbomChid | (kbomTag >> 2); typedef struct TAGC *PTAGC; struct TAGC { CHID chid; TAG tag; }; /**************************************** SSE - scene sound event ****************************************/ const BOM kbomSse = 0xFF000000; typedef struct SSE *PSSE; struct SSE { long vlm; long sty; // sound type bool fLoop; long ctagc; // TAGC _rgtagcSnd[_ctagc]; // variable array of tagcs follows SSE protected: static long _Cb(long ctagc) { return size(SSE) + LwMul(ctagc, size(TAGC)); } SSE(void) {}; public: static PSSE PsseNew(long ctagc); static PSSE PsseNew(long vlm, long sty, bool fLoop, long ctagc, TAGC *prgtagc); static PSSE PsseDupFromGg(PGG pgg, long iv, bool fDupTags = fTrue); PTAG Ptag(long itagc) { PTAGC prgtagc = (PTAGC)PvAddBv(this, size(SSE)); return &(prgtagc[itagc].tag); } PTAGC Ptagc(long itagc) { PTAGC prgtagc = (PTAGC)PvAddBv(this, size(SSE)); return &(prgtagc[itagc]); } CHID *Pchid(long itagc) { PTAGC prgtagc = (PTAGC)PvAddBv(this, size(SSE)); return &(prgtagc[itagc].chid); } PSSE PsseAddTagChid(PTAG ptag, long chid); PSSE PsseDup(void); void PlayAllSounds(PMVIE pmvie, ulong dtsStart = 0); void SwapBytes(void) { long itagc; SwapBytesBom(this, kbomSse); for (itagc = 0; itagc < ctagc; itagc++) { SwapBytesBom(Ptag(itagc), kbomTag); SwapBytesBom(Pchid(itagc), kbomChid); } } long Cb(void) { return size(SSE) + LwMul(ctagc, size(TAGC)); } }; void ReleasePpsse(PSSE *ppsse); // // Undo object for chopping operation. // typedef class SUNC *PSUNC; #define SUNC_PAR MUNB #define kclsSUNC 'SUNC' class SUNC : public SUNC_PAR { RTCLASS_DEC MARKMEM ASSERT protected: CNO _cno; PCRF _pcrf; SUNC(void) { } public: static PSUNC PsuncNew(void); ~SUNC(void); bool FSave(PSCEN pscen); virtual bool FDo(PDOCB pdocb); virtual bool FUndo(PDOCB pdocb); }; // // Undo object for background operations // typedef class SUNK *PSUNK; #define SUNK_PAR MUNB #define kclsSUNK 'SUNK' class SUNK : public SUNK_PAR { RTCLASS_DEC MARKMEM ASSERT protected: TAG _tag; long _icam; bool _fSetBkgd; SUNK(void) { } public: static PSUNK PsunkNew(void); ~SUNK(void); void SetTag(PTAG ptag) { _tag = *ptag; } void SetIcam(long icam) { _icam = icam; } void SetFBkgd(bool fSetBkgd) { _fSetBkgd = fSetBkgd; } virtual bool FDo(PDOCB pdocb); virtual bool FUndo(PDOCB pdocb); }; // // Undo object for transition operations // typedef class SUNR *PSUNR; #define SUNR_PAR MUNB #define kclsSUNR 'SUNR' class SUNR : public SUNR_PAR { RTCLASS_DEC MARKMEM ASSERT protected: TRANS _trans; SUNR(void) { } public: static PSUNR PsunrNew(void); ~SUNR(void); void SetTrans(TRANS trans) { _trans = trans; } virtual bool FDo(PDOCB pdocb); virtual bool FUndo(PDOCB pdocb); }; // // Undo object for pause operations // typedef class SUNP *PSUNP; #define SUNP_PAR MUNB #define kclsSUNP 'SUNP' class SUNP : public SUNP_PAR { RTCLASS_DEC MARKMEM ASSERT protected: WIT _wit; long _dts; bool _fAdd; SUNP(void) { } public: static PSUNP PsunpNew(void); ~SUNP(void); void SetWit(WIT wit) { _wit = wit; } void SetDts(long dts) { _dts = dts; } void SetAdd(bool fAdd) { _fAdd = fAdd; } virtual bool FDo(PDOCB pdocb); virtual bool FUndo(PDOCB pdocb); }; // // Undo object for text box operations // typedef class SUNX *PSUNX; #define SUNX_PAR MUNB #define kclsSUNX 'SUNX' class SUNX : public SUNX_PAR { RTCLASS_DEC MARKMEM ASSERT protected: PTBOX _ptbox; bool _fAdd; long _itbox; long _nfrmFirst; long _nfrmLast; SUNX(void) { } public: static PSUNX PsunxNew(void); ~SUNX(void); void SetNfrmFirst(long nfrm) { _nfrmFirst = nfrm; } void SetNfrmLast(long nfrm) { _nfrmLast = nfrm; } void SetItbox(long itbox) { _itbox = itbox; } void SetTbox(PTBOX ptbox) { _ptbox = ptbox; } void SetAdd(bool fAdd) { _fAdd = fAdd; } virtual bool FDo(PDOCB pdocb); virtual bool FUndo(PDOCB pdocb); }; // // Undo object for sound operations // typedef class SUNS *PSUNS; #define SUNS_PAR MUNB #define kclsSUNS 'SUNS' class SUNS : public SUNS_PAR { RTCLASS_DEC MARKMEM ASSERT protected: PSSE _psse; // may be pvNil long _sty; // sty to use if _psse is pvNil SUNS(void) { } public: static PSUNS PsunsNew(void); ~SUNS(void); bool FSetSnd(PSSE psse) { PSSE psseDup = psse->PsseDup(); if (psseDup == pvNil) return fFalse; ReleasePpsse(&_psse); _psse = psseDup; _sty = _psse->sty; return fTrue; } void SetSty(long sty) { _sty = sty; } virtual bool FDo(PDOCB pdocb); virtual bool FUndo(PDOCB pdocb); }; // // Undo object for title operations // typedef class SUNT *PSUNT; #define SUNT_PAR MUNB #define kclsSUNT 'SUNT' class SUNT : public SUNT_PAR { RTCLASS_DEC MARKMEM ASSERT protected: STN _stn; SUNT(void) { } public: static PSUNT PsuntNew(void); ~SUNT(void); void SetName(PSTN pstn) { AssertPo(pstn, 0); _stn = *pstn; } virtual bool FDo(PDOCB pdocb); virtual bool FUndo(PDOCB pdocb); }; RTCLASS(SCEN) RTCLASS(SUNT) RTCLASS(SUNS) RTCLASS(SUNA) RTCLASS(SUNK) RTCLASS(SUNP) RTCLASS(SUNX) RTCLASS(SUNC) RTCLASS(SUNR) /**************************************************** * * Constructor for scenes. This function is private, use PscenNew() * for public construction. * * Parameters: * pmvie - The movie this scene belongs to. * * Returns: * None. * ****************************************************/ SCEN::SCEN(PMVIE pmvie) { AssertNilOrPo(pmvie, 0); _pmvie = pmvie; _nfrmCur = 1; _nfrmLast = 1; _nfrmFirst = 1; _trans = transDissolve; // default transition // // By default we disable pauses in the studio // _grfscen = fscenPauses; } /**************************************************** * * Exported constructor for scenes. * * Parameters: * pmvie - The movie this scene belongs to. * * * Returns: * pvNil, on failure, else a pointer to an allocated SCEN object. * ****************************************************/ PSCEN SCEN::PscenNew(PMVIE pmvie) { AssertNilOrPo(pmvie, 0); PSCEN pscen; // // Create the object // pscen = NewObj SCEN(pmvie); if (pscen == pvNil) { goto LFail; } // // Initialize event list // pscen->_pggsevFrm = GG::PggNew(size(SEV)); if (pscen->_pggsevFrm == pvNil) { goto LFail; } pscen->_isevFrmLim = 0; pscen->_pggsevStart = GG::PggNew(size(SEV)); if (pscen->_pggsevStart == pvNil) { goto LFail; } pscen->_pglpactr = GL::PglNew(size(PACTR), 0); if (pscen->_pglpactr == pvNil) { goto LFail; } pscen->_pglptbox = GL::PglNew(size(PTBOX), 0); if (pscen->_pglptbox == pvNil) { goto LFail; } if (vpcex != pvNil) { vpcex->EnqueueCid(cidSceneLoaded); } AssertPo(pscen, 0); return(pscen); LFail: ReleasePpo(&pscen); return(pvNil); } /**************************************************** * * Destructor for scenes. * * Parameters: * None. * * Returns: * None. * ****************************************************/ SCEN::~SCEN(void) { AssertBaseThis(0); long isev; PSEV qsev; PTBOX ptbox; PACTR pactr; // // Remove starting events // if (_pggsevStart != pvNil) { for (isev=0; isev < _pggsevStart->IvMac(); isev++) { qsev = (PSEV)_pggsevStart->QvFixedGet(isev); switch (qsev->sevt) { case sevtAddActr: _pggsevStart->Get(isev, &pactr); AssertPo(pactr, 0); ReleasePpo(&pactr); break; case sevtAddTbox: _pggsevStart->Get(isev, &ptbox); AssertPo(ptbox, 0); ReleasePpo(&ptbox); break; case sevtChngCamera: case sevtSetBkgd: break; case sevtPause: case sevtPlaySnd: Bug("Invalid event in event stream."); break; default: Bug("Unknown event type"); break; } } } ReleasePpo(&_pggsevStart); // // Walk and delete all frame events. // if (_pggsevFrm != pvNil) { for (isev=0; isev < _pggsevFrm->IvMac(); isev++) { // // For each event, release any child objects. // qsev=(PSEV)_pggsevFrm->QvFixedGet(isev); switch (qsev->sevt) { case sevtAddTbox: case sevtAddActr: case sevtSetBkgd: Assert(0, "Invalid event in event stream."); break; case sevtPlaySnd: { PSSE psse; long itagc; psse = (PSSE)_pggsevFrm->QvGet(isev); for (itagc = 0; itagc < psse->ctagc; itagc++) { TAGM::CloseTag(psse->Ptag(itagc)); } break; } case sevtPause: case sevtChngCamera: break; default: Bug("Unknown event type"); break; } } } // // Delete frame event list. // ReleasePpo(&_pggsevFrm); // // Remove the GL of actors. We do not Release the actors // themselves as our reference was released above in the // the _pggsevStart. // ReleasePpo(&_pglpactr); // // Remove the GL of tboxes. We do not Release the tboxes // themselves as our reference was released above in the // the _pggsevStart. // ReleasePpo(&_pglptbox); // // Release the background // ReleasePpo(&_pbkgd); // // Release the thumbnail // ReleasePpo(&_pmbmp); // // Free the background sound // ReleasePpsse(&_psseBkgd); } /**************************************************** * * Destructor for scenes. This method is used to not only * destruct a scene, but to remove all lights, actors and * text boxes from the rendering area. This is necessary * because Undo will hold references to actors, etc, causing * their destructors to not be called. * * Parameters: * ppscen - A pointer to the scene to destroy. * * Returns: * None. * ****************************************************/ void SCEN::Close(PSCEN *ppscen) { AssertPo(*ppscen, 0); if (pvNil != (*ppscen)->_pbkgd) { (*ppscen)->_pbkgd->TurnOffLights(); } (*ppscen)->HideActors(); (*ppscen)->HideTboxes(); ReleasePpo(ppscen); } #ifdef DEBUG /**************************************************** * Mark memory used by the SCEN * * Parameters: * None. * * Returns: * None. * ****************************************************/ void SCEN::MarkMem(void) { AssertThis(0); long iactr; long itbox; PACTR pactr; PTBOX ptbox; SCEN_PAR::MarkMem(); MarkMemObj(_pggsevStart); MarkMemObj(_pggsevFrm); MarkMemObj(_pglpactr); MarkMemObj(_pglptbox); MarkMemObj(_pmbmp); for (iactr = 0; iactr < _pglpactr->IvMac(); iactr++) { _pglpactr->Get(iactr, &pactr); MarkMemObj(pactr); } for (itbox = 0; itbox < _pglptbox->IvMac(); itbox++) { _pglptbox->Get(itbox, &ptbox); MarkMemObj(ptbox); } if (_psseBkgd != pvNil) MarkPv(_psseBkgd); } /*************************************************************************** Assert the validity of the SCEN. ***************************************************************************/ void SCEN::AssertValid(ulong grf) { long isev; SEV sev; SCEN_PAR::AssertValid(fobjAllocated); AssertPo(&_stnName, 0); AssertNilOrPo(_pactrSelected, 0); AssertNilOrPo(_pbkgd, 0); AssertNilOrPo(_pmbmp, 0); AssertPo(_pglpactr, 0); AssertPo(_pglptbox, 0); AssertPo(_pggsevFrm, 0); AssertPo(_pggsevStart, 0); AssertPo(_pmvie, 0); for (isev = 0; isev < _pggsevFrm->IvMac(); isev++) { sev = *(PSEV)_pggsevFrm->QvFixedGet(isev); switch (sev.sevt) { case sevtPlaySnd: case sevtPause: case sevtChngCamera: break; default: Bug("Unknown event type"); } } for (isev = 0; isev < _pggsevStart->IvMac(); isev++) { sev = *(PSEV)_pggsevStart->QvFixedGet(isev); switch (sev.sevt) { case sevtAddActr: case sevtSetBkgd: case sevtAddTbox: break; default: Bug("Unknown event type"); } } } #endif /**************************************************** * * Sets the transition of the scene and creates an undo object. * * Parameters: * trans - Transition type. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FSetTransition(TRANS trans) { AssertThis(0); PSUNR psunr; psunr = SUNR::PsunrNew(); if (psunr == pvNil) { return(fFalse); } if (!_pmvie->FAddUndo(psunr)) { return(fFalse); } ReleasePpo(&psunr); SetTransitionCore(trans); return(fTrue); } /**************************************************** * * Sets the name of the scene and creates an undo object. * * Parameters: * psz - Null terminated string. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FSetName(PSTN pstn) { AssertThis(0); AssertPo(pstn, 0); PSUNT psunt; psunt = SUNT::PsuntNew(); if (psunt != pvNil) { psunt->SetName(&_stnName); } if (psunt == pvNil) { return(fFalse); } if (!_pmvie->FAddUndo(psunt)) { return(fFalse); } ReleasePpo(&psunt); SetNameCore(pstn); return(fTrue); } /**************************************************** * * This routine jumps to an arbitrary frame, updating actors, and adding * new frames to the scene if needed. * * Parameters: * nFrm - The frame number to jump to. This may be positive or negative * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FGotoFrm(long nfrm) { AssertThis(0); bool fSoundInFrame = fFalse, fUpdateSndFrame = nfrm != _nfrmCur; SEV sev; PMVU pmvu; void *qvVar; long isev; long nfrmOld = _nfrmCur; if (nfrm < _nfrmCur) { // // Assume no pause type // Pmvie()->Pmcc()->PauseType(witNil); // // Go backwards // if (nfrm < _nfrmFirst) { // // Move first frame back in time // _MoveBackFirstFrame(nfrm); _MarkMovieDirty(); } _nfrmCur = nfrm; // // Unplay all events to dest frame. // for (;_isevFrmLim > 0; _isevFrmLim--) { _pggsevFrm->GetFixed(_isevFrmLim - 1, &sev); if (sev.nfrm <= _nfrmCur) { break; } qvVar = _pggsevFrm->QvGet(_isevFrmLim - 1); if (!_FUnPlaySev(&sev, qvVar)) { PushErc(ercSocGotoFrameFailure); return(fFalse); } } // // Play events in this frame // for (isev = _isevFrmLim - 1; isev >= 0; isev--) { _pggsevFrm->GetFixed(isev, &sev); if (sev.nfrm < _nfrmCur) { break; } qvVar = _pggsevFrm->QvGet(isev); if (!_FPlaySev(&sev, qvVar, _grfscen)) { PushErc(ercSocGotoFrameFailure); return(fFalse); } if (sev.sevt == sevtPlaySnd && sev.nfrm == _nfrmCur) fSoundInFrame = fTrue; } } else if (nfrm > _nfrmCur) { pmvu = (PMVU)Pmvie()->PddgGet(0); AssertNilOrPo(pmvu, 0); if ((pmvu != pvNil) && (pmvu->Tool() == toolRecordSameAction)) { Pmvie()->Pmcc()->PlayUISound(toolRecordSameAction); } _nfrmCur = nfrm; // // Assume no pause type // Pmvie()->Pmcc()->PauseType(witNil); // // Go forwards // if (_nfrmCur > _nfrmLast) { _nfrmLast = _nfrmCur; _MarkMovieDirty(); } // // Play all events to dest frame. // for (; _isevFrmLim < _pggsevFrm->IvMac(); _isevFrmLim++) { _pggsevFrm->GetFixed(_isevFrmLim, &sev); if (sev.nfrm > _nfrmCur) { break; } qvVar = _pggsevFrm->QvGet(_isevFrmLim); if (!_FPlaySev(&sev, qvVar, (sev.nfrm==_nfrmCur ? _grfscen : (_grfscen | fscenSounds | fscenPauses)))) { PushErc(ercSocGotoFrameFailure); return(fFalse); } if (sev.sevt == sevtPlaySnd && sev.nfrm == _nfrmCur) fSoundInFrame = fTrue; } } if (!(_grfscen & fscenActrs) && !_FForceActorsToFrm(nfrm, &fSoundInFrame)) { return(fFalse); } if (!(_grfscen & fscenTboxes) && !_FForceTboxesToFrm(nfrm)) { return(fFalse); } if (!(_grfscen & fscenActrs)) { _DoPrerenderingWork(fFalse); } Pmvie()->InvalViews(); if (fUpdateSndFrame) Pmvie()->Pmcc()->SetSndFrame(fSoundInFrame); return(fTrue); } /**************************************************** * * This function is an optimization which could be completely * skipped if desired. The idea is to not render actors frame * after frame if they're not moving or changing at all. So * when we hit a camera change, we look ahead to see if any * actors are unchanging before the next camera change. If * there are, we hide the changing actors (so only the unchanging * ones are visible), then "take a snapshot" of the world with * the unchanging actors (via BWLD::Prerender()), and use the * snapshot as the background RGB and Z buffer until the next * camera view change. We only prerender if the movie is * playing. * * Parameters: * fStartNow - if fTrue, start prerendering even if there's no * camera change in this frame. If fFalse, only * start prerendering if there is a camera view * change in this frame, or if this is the first * frame of the scene. * * Returns: * none * ****************************************************/ void SCEN::_DoPrerenderingWork(bool fStartNow) { AssertThis(0); long isev; SEV sev; long nfrmNextChange; long ipactr; PACTR pactr; long cactrPrerendered; // // If the movie was playing and there was a camera view change // in this frame, prerender any actors that don't change from // here to the next camera view change or the end of the scene. // if (!Pmvie()->FPlaying()) { return; // only prerender if the movie is playing } // Do prerender if this is the first frame of the scene // (even though there's no sevtChngCamera), or if fStartNow // is fTrue, or if there is a sevtChngCamera in this // frame. Otherwise, just return. if (_nfrmCur != _nfrmFirst && !fStartNow) { for (isev = _isevFrmLim - 1; isev >= 0; isev--) { _pggsevFrm->GetFixed(isev, &sev); if (sev.nfrm != _nfrmCur) { return; // no camera view change in this frame } if (sev.sevt == sevtChngCamera) { break; // found one! } } if (isev < 0) { return; // no camera view in this frame } } // Find when the next view change is nfrmNextChange = _nfrmLast; // if no more view changes, go til end of scene for (isev = _isevFrmLim; isev < _pggsevFrm->IvMac(); isev++) { _pggsevFrm->GetFixed(isev, &sev); if (sev.sevt == sevtChngCamera) { nfrmNextChange = sev.nfrm; break; } } // Hide all actors that can't be prerendered this time, and count how many // can be prerendered this time cactrPrerendered = 0; for (ipactr = 0; ipactr < _pglpactr->IvMac(); ipactr++) { _pglpactr->Get(ipactr, &pactr); if (pactr->FMustRender(nfrmNextChange)) { pactr->Hide(); } else { cactrPrerendered++; if (pactr->FPrerendered()) { // Actor was prerendered in last view and in this // view. Temporarily show the actor so it shows // up in the prerendered background pactr->Show(); pactr->SetPrerendered(fFalse); } } } if (cactrPrerendered > 0) { Pmvie()->Pbwld()->Prerender(); } // Show all the actors that were hidden (and show them again if they were // prerendered last time and can't be now), and hide the newly prerendered // actors. for (ipactr = 0; ipactr < _pglpactr->IvMac(); ipactr++) { _pglpactr->Get(ipactr, &pactr); if (pactr->FMustRender(nfrmNextChange)) { pactr->Show(); if (pactr->FPrerendered()) { pactr->Show(); pactr->SetPrerendered(fFalse); } } else { Assert(!pactr->FPrerendered(), "no actor should be marked prerendered here"); pactr->Hide(); pactr->SetPrerendered(fTrue); } } } /**************************************************** * * Ends any current prerendering by restoring the background * RGB and Z buffers of the BWLD, showing all previously * hidden actors, and marking all actors as not prerendered. * * Parameters: * none * * Returns: * none * ****************************************************/ void SCEN::_EndPrerendering(void) { AssertThis(0); long ipactr; PACTR pactr; // Show all the actors that were being prerendered Pmvie()->Pbwld()->Unprerender(); for (ipactr = 0; ipactr < _pglpactr->IvMac(); ipactr++) { _pglpactr->Get(ipactr, &pactr); if (pactr->FPrerendered()) { pactr->Show(); pactr->SetPrerendered(fFalse); } } } /**************************************************** * * This routine replays all the events, filtered by * grfscen, in the current frame. * * Parameters: * grfscen - Events to play. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FReplayFrm(ulong grfscen) { AssertThis(0); SEV sev; void *qvVar; long isev, iactr; long nfrmOld = _nfrmCur; PACTR pactr; // // Play events in this frame // for (isev = _isevFrmLim - 1; isev >= 0; isev--) { _pggsevFrm->GetFixed(isev, &sev); if (sev.nfrm < _nfrmCur) { break; } qvVar = _pggsevFrm->QvGet(isev); // Note: FReplayFrm always suppresses camera changes if (!_FPlaySev(&sev, qvVar, (~grfscen) | fscenCams)) { PushErc(ercSocGotoFrameFailure); return(fFalse); } } if (grfscen & fscenActrs) { for (iactr = 0; iactr < _pglpactr->IvMac(); iactr++) { _pglpactr->Get(iactr, &pactr); AssertPo(pactr, 0); if (!pactr->FReplayFrame(grfscen)) { return(fFalse); } } } return(fTrue); } /**************************************************** * * This routine recalculates the length of the movie. * * Parameters: * None. * * Returns: * None. * ****************************************************/ void SCEN::InvalFrmRange(void) { AssertThis(0); PACTR pactr; PTBOX ptbox; long ipo; long nfrmStart, nfrmLast; for (ipo=0; ipo < _pglpactr->IvMac(); ipo++) { _pglpactr->Get(ipo, &pactr); if (pactr->FGetLifetime(&nfrmStart, &nfrmLast)) { if (nfrmStart < _nfrmFirst) { _MoveBackFirstFrame(nfrmStart); } if (nfrmLast > _nfrmLast) { _nfrmLast = nfrmLast; } } } for (ipo=0; ipo < _pglptbox->IvMac(); ipo++) { _pglptbox->Get(ipo, &ptbox); if (ptbox->FGetLifetime(&nfrmStart, &nfrmLast)) { if (nfrmStart < _nfrmFirst) { _MoveBackFirstFrame(nfrmStart); } if (nfrmLast > _nfrmLast) { _nfrmLast = nfrmLast; } } } } /**************************************************** * * This routine plays a single event. * * Be careful not to modify _pggsevFrm or _pggsevStart from * within this routine. * * Parameters: * psev - Pointer to the scene event to play. * qvVar- Pointer to the variable part of the event. * grfscen - Flags of currently disabled event types. * * Returns: * fTrue if the event was played, fFalse in the case of failure. * ****************************************************/ bool SCEN::_FPlaySev(PSEV psev, void *qvVar, ulong grfscen) { AssertThis(0); AssertVarMem(psev); PACTR pactr; PTBOX ptbox; PBKGD pbkgd; TAG tag; WIT wit; long dts; switch (psev->sevt) { case sevtPlaySnd: PSSE psse; psse = (PSSE)qvVar; // If it's midi, copy it to _psseBkgd if (psse->sty == styMidi) { PSSE psseDup; psseDup = psse->PsseDup(); if (psseDup == pvNil) return fFalse; ReleasePpsse(&_psseBkgd); _psseBkgd = psseDup; _nfrmSseBkgd = psev->nfrm; } if (grfscen & fscenSounds) { return (fTrue); } psse->PlayAllSounds(Pmvie()); break; case sevtSetBkgd: tag = *(PTAG)qvVar; pbkgd = (PBKGD)vptagm->PbacoFetch(&tag, BKGD::FReadBkgd); if (pvNil == pbkgd) { return fFalse; } if (!pbkgd->FSetCamera(_pmvie->Pbwld(), 0)) { ReleasePpo(&pbkgd); return(fFalse); } if (Pmvie()->Trans() == transNil) { Pmvie()->SetTrans(transCut); // so we do palette change at next draw } _pbkgd = pbkgd; _tagBkgd = tag; break; case sevtAddActr: // // Add the actor to the roll call. // pactr = *(PACTR *)qvVar; AssertPo(pactr, 0); if (_pglpactr->FPush(&pactr) == fFalse) { return(fFalse); } pactr->SetPscen(this); // // Plop them into this frame // if (!pactr->FGotoFrame(_nfrmCur)) { _pglpactr->FPop(&pactr); return(fFalse); } break; case sevtPause: wit = (WIT)(*(long *)qvVar); Pmvie()->Pmcc()->PauseType(wit); if (grfscen & fscenPauses) { return(fTrue); } dts = *((long *)qvVar + 1); Pmvie()->DoPause(wit, dts); break; case sevtAddTbox: // // Add the text box to the scene // ptbox = *(PTBOX *)qvVar; AssertPo(ptbox, 0); // // Insert at the end, because tbox ordering is important // since the client uses itbox to find text boxes. // if (!_pglptbox->FInsert(_pglptbox->IvMac(), &ptbox)) { return(fFalse); } // // Plop them into this frame // if (!ptbox->FGotoFrame(_nfrmCur)) { _pglptbox->Delete(_pglptbox->IvMac() - 1); return(fFalse); } break; case sevtChngCamera: Assert(_pbkgd != pvNil, "No background in the scene"); if (grfscen & fscenCams) { return(fTrue); } if (!_pbkgd->FSetCamera(_pmvie->Pbwld(), *(long *)qvVar)) { return(fFalse); } break; default: Bug("Unhandled sevt"); break; } return(fTrue); } /**************************************************** * * This routine undoes a single event. * * Parameters: * psev - Pointer to the scene event to unplay. * qvVar- Pointer to the variable part of the event. * * * Returns: * fTrue if the unplay worked, else fFalse. * ****************************************************/ bool SCEN::_FUnPlaySev(PSEV psev, void *qvVar) { AssertThis(0); AssertVarMem(psev); SEV sev; long isev; PSEV qsevTmp; switch (psev->sevt) { case sevtPlaySnd: // // Go backwards and find previous background sound. // for (isev = _isevFrmLim - 1; isev >= 0; isev--) { qsevTmp = (PSEV)_pggsevFrm->QvFixedGet(isev); if ((qsevTmp->sevt == sevtPlaySnd) && (qsevTmp->nfrm < _nfrmCur)) { sev = *qsevTmp; _FPlaySev(&sev, _pggsevFrm->QvGet(isev), _grfscen | fscenSounds); // Ignore failure. return(fTrue); } } // // Not found -- clear variables. // ReleasePpsse(&_psseBkgd); break; case sevtAddActr: case sevtAddTbox: case sevtPause: break; case sevtChngCamera: Assert(_pbkgd != pvNil, "No background in scene"); // // Go backwards and find previous camera position. // for (isev = _isevFrmLim - 1; isev >= 0; isev--) { qsevTmp = (PSEV)_pggsevFrm->QvFixedGet(isev); if ((qsevTmp->sevt == sevtChngCamera) && (qsevTmp->nfrm < _nfrmCur)) { sev = *qsevTmp; AssertDo(_FPlaySev(&sev, _pggsevFrm->QvGet(isev), _grfscen), "Should not fail."); return(fTrue); } } // // Not found -- use starting camera, which is always camera 0. // sev.sevt = sevtChngCamera; isev = 0; if (!_FPlaySev(&sev, &isev, _grfscen)) { Assert(0, "Should never happen"); return(fFalse); } break; } return(fTrue); } /**************************************************** * * This routine moves back stuff that is currently * in the first frame of the movie to the given frame. * * Parameters: * nfrm - New first frame. * * Returns: * None. * ****************************************************/ void SCEN::_MoveBackFirstFrame(long nfrm) { AssertThis(0); Assert(nfrm < _nfrmFirst, "Can only be called to extend scene back."); long isev; SEV sev; // // Move back all events that must persist in the // first frame. // for (isev = 0; isev < _pggsevFrm->IvMac(); isev++) { _pggsevFrm->GetFixed(isev, &sev); if (sev.nfrm != _nfrmFirst) { break; } if (sev.sevt == sevtChngCamera) { // // Move this back // sev.nfrm = nfrm; _pggsevFrm->PutFixed(isev, &sev); _pggsevFrm->Move(isev, 0); } } // // Set new first frame // _nfrmFirst = nfrm; } /**************************************************** * * This routine adds a sound to the event list for this frame. * * Parameters: * fLoop - should the sound loop? * fQueue - queue after existing sounds, or replace them? * vlm - volume to play this sound at * sty - sound type (midi, speech, or SFX) * ctag - number of sounds * prgtag - array of MSND tags * * * Returns: * fTrue, if successful, else fFalse. * ****************************************************/ bool SCEN::FAddSndCore(bool fLoop, bool fQueue, long vlm, long sty, long ctag, PTAG prgtag) { AssertThis(0); AssertPvCb(prgtag, LwMul(ctag, size(TAG))); Assert(!fQueue || (ctag == 1), "if fQueue'ing, you should only be adding one sound"); Assert(!fQueue || !fLoop, "can't both queue and loop"); AssertIn(sty, 0, styLim); SEV sev; PSSE psseOld; PSSE psseNew; long isev; CHID chid; long isevSnd = ivNil; PTAG ptag; PMSND pmsnd; long itag, itagBase; // // Find any other sevtPlaySnd events in this frame with the same sty // for (isev = _isevFrmLim - 1; isev >= 0; isev--) { _pggsevFrm->GetFixed(isev, &sev); if (sev.nfrm != _nfrmCur) break; if (sev.sevt == sevtPlaySnd) { psseOld = (PSSE)_pggsevFrm->QvGet(isev); if (psseOld->sty == sty) { // Found a match, which we will either add to or replace isevSnd = isev; break; } } } if (isevSnd == ivNil) { fQueue = fFalse; // nothing to queue to } sev.nfrm = _nfrmCur; sev.sevt = sevtPlaySnd; if (!fQueue) { PTAGC prgtagc; long itagc; if (!FAllocPv((void **)&prgtagc, LwMul(size(TAGC), ctag), fmemClear, mprNormal)) return fFalse; for (itagc = 0; itagc < ctag; itagc++) { prgtagc[itagc].tag = prgtag[itagc]; if (prgtagc[itagc].tag.sid == ksidUseCrf) { if (!_pmvie->FChidFromUserSndCno(prgtag[itagc].cno, &chid)) { FreePpv((void **)&prgtagc); return fFalse; } prgtagc[itagc].chid = chid; } else { TrashVar(&prgtagc[itagc].chid); } } // Create new event, replace any old event of same sty itagBase = 0; psseNew = SSE::PsseNew(vlm, sty, fLoop, ctag, prgtagc); FreePpv((void **)&prgtagc); if (pvNil == psseNew) { return fFalse; } if (!_FAddSev(&sev, psseNew->Cb(), psseNew)) { ReleasePpsse(&psseNew); return fFalse; } if (isevSnd != ivNil) { // Delete old event, if any PSSE psse; long itagc; psse = (PSSE)_pggsevFrm->QvGet(isevSnd); for (itagc = 0; itagc < psse->ctagc; itagc++) { TAGM::CloseTag(psse->Ptag(itagc)); } _pggsevFrm->Delete(isevSnd); _isevFrmLim--; } } else // we're queueing { // Add this sound to isevSnd psseOld = SSE::PsseDupFromGg(_pggsevFrm, isevSnd); if (pvNil == psseOld) { return fFalse; } // ctag == 1 if (prgtag[0].sid == ksidUseCrf) { if (!_pmvie->FChidFromUserSndCno(prgtag[0].cno, &chid)) { ReleasePpsse(&psseOld); return fFalse; } } else TrashVar(&chid); itagBase = psseOld->ctagc; psseNew = psseOld->PsseAddTagChid(prgtag, chid); if (pvNil == psseNew) { ReleasePpsse(&psseOld); return fFalse; } if (!_pggsevFrm->FPut(isevSnd, psseNew->Cb(), psseNew)) { ReleasePpsse(&psseOld); ReleasePpsse(&psseNew); return fFalse; } ReleasePpsse(&psseOld); } // // Play only these sounds // for (itag = 0; itag < ctag; itag++) { ptag = &(prgtag[itag]); if (ptag->sid == ksidUseCrf) { if (!Pmvie()->FResolveSndTag(ptag, *(psseNew->Pchid(itag + itagBase)))) continue; } pmsnd = (PMSND)vptagm->PbacoFetch(ptag, MSND::FReadMsnd); if (pvNil == pmsnd) continue; // Only queue if it's not the first sound. Pmvie()->Pmsq()->FEnqueue(pmsnd, 0, fLoop, (itag != 0), vlm, pmsnd->Spr(fLoop ? toolLooper : toolSounder), fFalse, 0); ReleasePpo(&pmsnd); } if (!_FPlaySev(&sev, psseNew, _grfscen | fscenSounds)) { // non-fatal error...ignore it } FreePpv((void **)&psseNew); // don't ReleasePpsse because GG got the tags _MarkMovieDirty(); Pmvie()->Pmcc()->SetSndFrame(fTrue); return fTrue; } /**************************************************** * * This routine adds a sound to the event list for this frame. * Note: The chid's in the tagc are current * * Parameters: * fLoop - should the sound loop? * fQueue - queue after existing sounds, or replace them? * vlm - volume to play this sound at * sty - sound type (midi, speech, or SFX) * ctag - number of sounds * prgtagc - array of MSND tags * * * Returns: * fTrue, if successful, else fFalse. * ****************************************************/ bool SCEN::FAddSndCoreTagc(bool fLoop, bool fQueue, long vlm, long sty, long ctagc, PTAGC prgtagc) { AssertThis(0); AssertPvCb(prgtagc, LwMul(ctagc, size(TAGC))); Assert(!fQueue || (ctagc == 1), "if fQueue'ing, you should only be adding one sound"); Assert(!fQueue || !fLoop, "can't both queue and loop"); AssertIn(sty, 0, styLim); SEV sev; PSSE psseOld; PSSE psseNew; long isev; long isevSnd = ivNil; // // Find any other sevtPlaySnd events in this frame with the same sty // for (isev = _isevFrmLim - 1; isev >= 0; isev--) { _pggsevFrm->GetFixed(isev, &sev); if (sev.nfrm != _nfrmCur) break; if (sev.sevt == sevtPlaySnd) { psseOld = (PSSE)_pggsevFrm->QvGet(isev); if (psseOld->sty == sty) { // Found a match, which we will either add to or replace isevSnd = isev; break; } } } if (isevSnd == ivNil) { fQueue = fFalse; // nothing to queue to } sev.nfrm = _nfrmCur; sev.sevt = sevtPlaySnd; if (!fQueue) { // Create new event, replace any old event of same sty psseNew = SSE::PsseNew(vlm, sty, fLoop, ctagc, prgtagc); if (pvNil == psseNew) return fFalse; if (!_FAddSev(&sev, psseNew->Cb(), psseNew)) { ReleasePpsse(&psseNew); return fFalse; } if (isevSnd != ivNil) { // Delete old event, if any PSSE psse; long itagc; psse = (PSSE)_pggsevFrm->QvGet(isevSnd); for (itagc = 0; itagc < psse->ctagc; itagc++) { TAGM::CloseTag(psse->Ptag(itagc)); } _pggsevFrm->Delete(isevSnd); _isevFrmLim--; } } else // we're queueing { Bug("Should never queue when undoing"); } if (!_FPlaySev(&sev, psseNew, _grfscen)) { // non-fatal error...ignore it } FreePpv((void **)&psseNew); // don't ReleasePpsse because GG got the tags _MarkMovieDirty(); Pmvie()->Pmcc()->SetSndFrame(fTrue); return fTrue; } /**************************************************** * * This routine adds a sound to the event list for this frame * and creates an undo object for the action. * * Parameters: * ptag - pointer to the tag for the sound. * fLoop - whether to loop the sound * fQueue - queue after existing sounds, or replace them? * vlm - volume to play this sound at * sty - sound type (midi, speech, or SFX) * * Returns: * fTrue, if successful, else fFalse. * ****************************************************/ bool SCEN::FAddSnd(PTAG ptag, bool fLoop, bool fQueue, long vlm, long sty) { AssertThis(0); AssertVarMem(ptag); Assert(!fQueue || !fLoop, "can't both queue and loop"); AssertIn(sty, 0, styLim); PSUNS psuns; PSSE psse; bool fFound; // Create a SUNS with nil _psse psuns = SUNS::PsunsNew(); if (psuns == pvNil) { return(fFalse); } psuns->SetSty(sty); // grab sound before edit, if any if (!FGetSnd(sty, &fFound, &psse)) { ReleasePpo(&psuns); return fFalse; } if (fFound) { if (!psuns->FSetSnd(psse)) { ReleasePpsse(&psse); ReleasePpo(&psuns); return fFalse; } ReleasePpsse(&psse); } if (!_pmvie->FAddUndo(psuns)) { ReleasePpo(&psuns); return(fFalse); } ReleasePpo(&psuns); if (!FAddSndCore(fLoop, fQueue, vlm, sty, 1, ptag)) { _pmvie->ClearUndo(); return(fFalse); } return(fTrue); } /**************************************************** * * This routine removes a sound from the event list for this frame. * * Parameters: * sty - the type of sound to remove * * * Returns: * None * ****************************************************/ void SCEN::RemSndCore(long sty) { AssertThis(0); AssertIn(sty, 0, styLim); PSEV qsev; long isev; // // Find the sound // for (isev= _isevFrmLim - 1; isev >= 0; isev--) { qsev = (PSEV)_pggsevFrm->QvFixedGet(isev); if (qsev->nfrm != _nfrmCur) { Bug("sty not found"); return; } if ((qsev->sevt == sevtPlaySnd) && ((PSSE)_pggsevFrm->QvGet(isev))->sty == sty) { // // Remove it // PSSE psse; long itagc; psse = (PSSE)_pggsevFrm->QvGet(isev); for (itagc = 0; itagc < psse->ctagc; itagc++) { TAGM::CloseTag(psse->Ptag(itagc)); } _pggsevFrm->Delete(isev); _isevFrmLim--; if (sty == styMidi) { ReleasePpsse(&_psseBkgd); } UpdateSndFrame(); _MarkMovieDirty(); return; } } Bug("No such sound"); } /**************************************************** * * This routine removes a sound from the event list for this frame * and creates an undo object for the action. * * Parameters: * sty - the type of sound to remove * * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FRemSnd(long sty) { AssertThis(0); AssertIn(sty, 0, styLim); PSUNS psuns; PSSE psse = pvNil; long isev; PSEV qsev; psuns = SUNS::PsunsNew(); if (psuns == pvNil) { return(fFalse); } // // Find the sound // for (isev= _isevFrmLim - 1; isev >= 0; isev--) { qsev = (PSEV)_pggsevFrm->QvFixedGet(isev); if (qsev->nfrm != _nfrmCur) { Bug("sty not found"); return fTrue; } if ((qsev->sevt == sevtPlaySnd) && ((PSSE)_pggsevFrm->QvGet(isev))->sty == sty) { psse = SSE::PsseDupFromGg(_pggsevFrm, isev); if (psse == pvNil) { return fFalse; } } } if (!psuns->FSetSnd(psse)) { ReleasePpsse(&psse); return fFalse; } ReleasePpsse(&psse); if (!_pmvie->FAddUndo(psuns)) { ReleasePpo(&psuns); return(fFalse); } ReleasePpo(&psuns); RemSndCore(sty); return(fTrue); } /**************************************************** * * This routine finds a specific sound in the current frame. * * Parameters: * sty - sound type to search for * pfFound - set to fTrue if a sound is found, else fFalse * ppsse - gets a pointer to the SSE if it is found * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FGetSnd(long sty, bool *pfFound, PSSE *ppsse) { AssertThis(0); AssertIn(sty, 0, styLim); AssertVarMem(ppsse); PSEV qsev; long isev; *pfFound = fFalse; // // Check event list. // for (isev= _isevFrmLim - 1; isev >= 0; isev--) { qsev = (PSEV)_pggsevFrm->QvFixedGet(isev); if (qsev->nfrm != _nfrmCur) { break; // sound not found } if (qsev->sevt == sevtPlaySnd) { if (sty == ((PSSE)_pggsevFrm->QvGet(isev))->sty) { *ppsse = SSE::PsseDupFromGg(_pggsevFrm, isev); if (*ppsse == pvNil) { return fFalse; // memory error } *pfFound = fTrue; return fTrue; } } } // // End of list...sound not found // return(fTrue); } /**************************************************** * * This routine plays the background sound, if any. * If the sound really started at an earlier frame, * this function tries to resume the sound at the * appropriate offset into the sound (dtsStart). * * Parameters: * none * * Returns: * none * ****************************************************/ void SCEN::PlayBkgdSnd(void) { AssertThis(0); ulong dtsStart; ulong dfrm; if (pvNil != _psseBkgd) { dfrm = Nfrm() - _nfrmSseBkgd; Assert(dfrm >= 0, "this sound is in the future!"); dtsStart = LwMulDiv(dfrm, kdtsSecond, kfps); _psseBkgd->PlayAllSounds(Pmvie(), dtsStart); } } /**************************************************** * * This routine queries what sounds are attched to the * scene at the current frame * * Parameters: * sty - the sound type to query * * Returns: * fFalse if an error occurs * ****************************************************/ bool SCEN::FQuerySnd(long sty, PGL *ppgltagSnd, long *pvlm, bool *pfLoop) { AssertThis(0); AssertVarMem(ppgltagSnd); AssertVarMem(pvlm); AssertVarMem(pfLoop); PSSE psse; bool fFound; long itag; *ppgltagSnd = pvNil; if (!FGetSnd(sty, &fFound, &psse)) { return fFalse; // error } if (!fFound) { return fTrue; // no sounds (*ppglTagSnd is nil) } *ppgltagSnd = GL::PglNew(size(TAG), psse->ctagc); if (pvNil == *ppgltagSnd) { ReleasePpsse(&psse); return fFalse; } AssertDo((*ppgltagSnd)->FSetIvMac(psse->ctagc), "PglNew should have ensured space"); for (itag = 0; itag < psse->ctagc; itag++) { (*ppgltagSnd)->Put(itag, psse->Ptag(itag)); } *pvlm = psse->vlm; *pfLoop = psse->fLoop; ReleasePpsse(&psse); return fTrue; } /**************************************************** * * This routine changes the volume of the sound of * type sty at the current frame to vlmNew * * Parameters: * sty - the sound type to query * vlmNew - the new volume * * Returns: * none * ****************************************************/ void SCEN::SetSndVlmCore(long sty, long vlmNew) { AssertThis(0); AssertIn(sty, 0, styLim); AssertIn(vlmNew, 0, kvlmFull + 1); PSEV qsev; long isev; PSSE psse; // // Check event list. // for (isev = _isevFrmLim - 1; isev >= 0; isev--) { qsev = (PSEV)_pggsevFrm->QvFixedGet(isev); if (qsev->nfrm != _nfrmCur) { Bug("No such sound"); break; // sound not found } if (qsev->sevt == sevtPlaySnd) { psse = ((PSSE)_pggsevFrm->QvGet(isev)); if (sty == psse->sty) { psse->vlm = vlmNew; _MarkMovieDirty(); return; } } } // // End of list...sound not found // Bug("No such sound"); } /****************************************************************************** UpdateSndFrame Enumerates all scene events for the current frame, and asks all actors to enumerate all of their actor events for the current frame, looking for a sound event. Has the movie's MCC update the frame-sound state based on the results of the search. ************************************************************ PETED ***********/ void SCEN::UpdateSndFrame(void) { bool fSoundInFrame = fFalse; long iv = _isevFrmLim; while (iv-- > 0) { PSEV qsev = (PSEV)_pggsevFrm->QvFixedGet(iv); if (qsev->nfrm != _nfrmCur) { iv = -1; break; } if (qsev->sevt == sevtPlaySnd) { fSoundInFrame = fTrue; goto LDone; } } while (++iv < _pglpactr->IvMac()) { PACTR pactr; _pglpactr->Get(iv, &pactr); AssertPo(pactr, 0); if (pactr->FSoundInFrm()) { fSoundInFrame = fTrue; goto LDone; } } LDone: Pmvie()->Pmcc()->SetSndFrame(fSoundInFrame); } /**************************************************** * * This routine adds an event to the current frame of the current scene. * * Parameters: * psev - Pointer to the event to add. * cbVar- Size of pvVar buffer, in bytes. * pvVar- Pointer to the variable part of the event. * * Returns: * fTrue, if successful, else fFalse. * ****************************************************/ bool SCEN::_FAddSev(PSEV psev, long cbVar, void *pvVar) { AssertThis(0); AssertVarMem(psev); AssertIn(cbVar, 0, klwMax); bool fRetValue; // // Add the event to the scene // _MarkMovieDirty(); fRetValue = _pggsevFrm->FInsert(_isevFrmLim++, cbVar, pvVar, psev); if (!fRetValue) { _isevFrmLim--; } return(fRetValue); } /**************************************************** * * This routine sets the selected actor to the given one. * * Parameters: * pactr - Pointer to the actr to select. pvNil is a * valid value and deselects the current actor and tbox. * * Returns: * None * ****************************************************/ void SCEN::SelectActr(ACTR *pactr) { AssertThis(0); AssertNilOrPo(pactr, 0); PMVU pmvu; pmvu = (PMVU)Pmvie()->PddgGet(0); AssertNilOrPo(pmvu, 0); if ((pmvu != pvNil) && !pmvu->FTextMode()) { if (pvNil != _pactrSelected) { _pactrSelected->Unhilite(); } if (pvNil != pactr) { pactr->Hilite(); } if (_ptboxSelected != pvNil) { _ptboxSelected->Select(fFalse); } } _pmvie->InvalViews(); _pactrSelected = pactr; _pmvie->BuildActionMenu(); } /**************************************************** * * This routine sets the selected text box to the given one. * * Parameters: * ptbox - Pointer to the tbox to select. pvNil is a * valid value and deselects the current actor and tbox. * * Returns: * None * ****************************************************/ void SCEN::SelectTbox(PTBOX ptbox) { AssertThis(0); AssertNilOrPo(ptbox, 0); PMVU pmvu; pmvu = (PMVU)Pmvie()->PddgGet(0); AssertNilOrPo(pmvu, 0); _pmvie->InvalViews(); if ((pmvu != pvNil) && pmvu->FTextMode()) { if (pvNil != _pactrSelected) { _pactrSelected->Unhilite(); _pmvie->BuildActionMenu(); } if ((ptbox == _ptboxSelected) && ((ptbox == pvNil) || ptbox->FSelected())) { return; } if (pvNil != _ptboxSelected) { _ptboxSelected->Select(fFalse); } if (pvNil != ptbox) { ptbox->Select(fTrue); } } _ptboxSelected = ptbox; _pmvie->Pmcc()->TboxSelected(); } /**************************************************** * * This routine adds an actor to the scene at the current frame, * if the arid is aridNil, else it replaces the actor in the * scene with the same arid. * * Parameters: * pactr - Pointer to the actr to add. * * * Returns: * fTrue, if successful, else fFalse. * ****************************************************/ bool SCEN::FAddActrCore(ACTR *pactr) { AssertThis(0); AssertPo(pactr, 0); PSEV qsev; SEV sev; long isev; long ipactr; STN stn; PACTR pactrOld; bool fRetValue; // // Check if actor is in Scene already. // for (isev=0; isev < _pggsevStart->IvMac(); isev++) { qsev = (PSEV)_pggsevStart->QvFixedGet(isev); if (qsev->sevt != sevtAddActr) { continue; } _pggsevStart->Get(isev, (void *)&pactrOld); if (pactrOld->Arid() != pactr->Arid()) { continue; } // // Replace actor in scene roll call // for (ipactr = 0; ipactr < _pglpactr->IvMac(); ipactr++) { _pglpactr->Get(ipactr, &pactrOld); if (pactrOld->Arid() == pactr->Arid()) { pactr->AddRef(); pactr->SetPscen(this); // // Plop them into this frame // if (!pactr->FGotoFrame(_nfrmCur)) { ReleasePpo(&pactr); return(fFalse); } // // Replace starting actor // _pggsevStart->Put(isev, &pactr); _pglpactr->Put(ipactr, &pactr); SelectActr(pactr); pactrOld->Hide(); ReleasePpo(&pactrOld); InvalFrmRange(); _MarkMovieDirty(); UpdateSndFrame(); return(fTrue); } } Bug("Cannot find actor in Roll call"); } // // Add actor to inital list of events to do. // sev.sevt = sevtAddActr; fRetValue = _pggsevStart->FInsert(0, size(PACTR), &pactr, &sev); if (fRetValue) { pactr->AddRef(); pactr->Ptmpl()->GetName(&stn); if (!_pmvie->FAddToRollCall(pactr, &stn)) { _pggsevStart->Delete(0); ReleasePpo(&pactr); return(fFalse); } fRetValue = _FPlaySev(&sev, &pactr, _grfscen); if (!fRetValue) { _pmvie->RemFromRollCall(pactr); _pggsevStart->Delete(0); ReleasePpo(&pactr); } else { InvalFrmRange(); _MarkMovieDirty(); UpdateSndFrame(); } } return(fRetValue); } /**************************************************** * * This routine adds an actor to the scene at the current frame. * This auto magically selects the actor and places them on stage. * * Parameters: * pactr - Pointer to the actr to add. * * * Returns: * fTrue, if successful, else fFalse. * ****************************************************/ bool SCEN::FAddActr(ACTR *pactr) { AssertThis(0); AssertPo(pactr, 0); if (!FAddActrCore(pactr)) { return(fFalse); } if (!pactr->FAddOnStageCore()) { RemActrCore(pactr->Arid()); return(fFalse); } SelectActr(pactr); // // The MVU creates the undo object for this because of the mouse // placement. // return(fTrue); } /**************************************************** * * This routine removes an actor from the scene. * * Parameters: * arid - The actor id to remove. * * * Returns: * None * ****************************************************/ void SCEN::RemActrCore(long arid) { AssertThis(0); PSEV qsev; PACTR pactrTmp; long isev; // // Check if actor is in Scene already. // for (isev=0; isev < _pggsevStart->IvMac(); isev++) { qsev = (PSEV)_pggsevStart->QvFixedGet(isev); if (qsev->sevt != sevtAddActr) { continue; } _pggsevStart->Get(isev, &pactrTmp); if (pactrTmp->Arid() != arid) { continue; } // // Remove actor from inital list of events to do. // _pggsevStart->Delete(isev); // // Remove actor from the scene roll call // for (isev=0; isev < _pglpactr->IvMac(); isev++) { _pglpactr->Get(isev, &pactrTmp); if (pactrTmp->Arid() != arid) { continue; } _pglpactr->Delete(isev); // // Remove actor as the currently selected actor // if (_pactrSelected == pactrTmp) { PMVU pmvu; _pactrSelected = pvNil; pmvu = (PMVU)_pmvie->PddgGet(0); if (pmvu != pvNil) { pmvu->EndPlaceActor(); } } // // Remove actor from the movie roll call // _pmvie->RemFromRollCall(pactrTmp); pactrTmp->Hide(); ReleasePpo(&pactrTmp); _MarkMovieDirty(); UpdateSndFrame(); return; } Bug("Actor does not exist in roll call"); _MarkMovieDirty(); return; } Bug("Actor does not exist in scene"); } /**************************************************** * * This routine removes an actor from the scene, and * creates an undo object for the action. * * Parameters: * arid - The actor id to remove. * * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FRemActr(long arid) { AssertThis(0); AssertIn(arid, 0, 500); PSUNA psuna; long ipactr; PACTR pactr; // // Find the actor for undo purposes // for (ipactr=0; ipactr < _pglpactr->IvMac(); ipactr++) { _pglpactr->Get(ipactr, &pactr); if (pactr->Arid() == arid) { break; } } AssertPo(pactr, 0); pactr->AddRef(); psuna = SUNA::PsunaNew(); if (psuna == pvNil) { ReleasePpo(&pactr); return(fFalse); } psuna->SetActr(pactr); psuna->SetType(utDel); if (!_pmvie->FAddUndo(psuna)) { return(fFalse); } ReleasePpo(&psuna); RemActrCore(arid); return(fTrue); } /**************************************************** * * This routine returns the actor pointed at by the mouse. * * Parameters: * xp - X position of the mouse within the display space. * yp - Y position of the mouse within the display space. * pibset - Place to store the index of the group of body parts hit. * * Returns: * Pointer to the actor, pvNil if none. * ****************************************************/ ACTR *SCEN::PactrFromPt(long xp, long yp, long *pibset) { AssertThis(0); AssertVarMem(pibset); ACTR *pactr; BODY *pbody; long ipactr; pbody = BODY::PbodyClicked(xp, yp, Pmvie()->Pbwld(), pibset); if (pvNil == pbody) { return pvNil; } // // loop through actors, call FIsMyBody() // for (ipactr = 0; ipactr < _pglpactr->IvMac(); ipactr++) { _pglpactr->Get(ipactr, &pactr); if (pactr->FIsMyBody(pbody)) { return pactr; } } Bug("weird...we clicked a pbody, but we don't know whose it is!"); return pvNil; } /**************************************************** * * This routine adds a text box to the scene at the current frame * * Parameters: * ptbox - Pointer to the text box to add. * * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FAddTboxCore(PTBOX ptbox) { AssertThis(0); AssertPo(ptbox, 0); SEV sev; bool fRetValue; #ifdef DEBUG PSEV qsev; long isev; // // Search for duplicate tbox // for (isev= 0; isev < _pggsevStart->IvMac(); isev++) { qsev = (PSEV)_pggsevStart->QvFixedGet(isev); if ((qsev->sevt == sevtAddTbox) && (ptbox == (PTBOX)_pggsevStart->QvGet(isev))) { Bug("Error, adding same text box twice"); return(fTrue); } } #endif // // Add text box to event list. // sev.sevt = sevtAddTbox; ptbox->SetScen(this); fRetValue = _pggsevStart->FInsert(_pggsevStart->IvMac(), size(PTBOX), &ptbox, &sev ); if (fRetValue) { ptbox->AddRef(); fRetValue = _FPlaySev(&sev, &ptbox, _grfscen); if (!fRetValue) { _pggsevStart->Delete(_pggsevStart->IvMac() - 1); } else { _MarkMovieDirty(); } } return(fRetValue); } /**************************************************** * * This routine adds a text box to the scene at the current frame * creates an undo object for the action. * * Parameters: * ptbox - Pointer to the text box to add. * * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FAddTbox(PTBOX ptbox) { PSUNX psunx; long itbox; long nfrmFirst, nfrmLast; psunx = SUNX::PsunxNew(); if (psunx == pvNil) { return(fFalse); } if (!FAddTboxCore(ptbox)) { ReleasePpo(&psunx); return(fFalse); } ptbox->AddRef(); ptbox->FGetLifetime(&nfrmFirst, &nfrmLast); psunx->SetTbox(ptbox); // transfers the reference count to the undo object psunx->SetNfrmFirst(nfrmFirst); psunx->SetNfrmLast((nfrmLast == _nfrmLast) ? klwMax : nfrmLast); for (itbox = 0; itbox < _pglptbox->IvMac(); itbox++) { if (ptbox == PtboxFromItbox(itbox)) { psunx->SetItbox(itbox); break; } } AssertIn(itbox, 0, _pglptbox->IvMac()); psunx->SetAdd(fTrue); if (!_pmvie->FAddUndo(psunx)) { PushErc(ercSocNotUndoable); ReleasePpo(&psunx); return(fFalse); } ReleasePpo(&psunx); return(fTrue); } /**************************************************** * * This routine removes a text box from the scene. * * Parameters: * ptbox - Pointer to the text box to remove. * * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FRemTboxCore(PTBOX ptbox) { AssertThis(0); AssertPo(ptbox, 0); PSEV qsev; long isev; long itbox; long nfrmStart, nfrmLast; // // Check if currently selected tbox. // if (ptbox == _ptboxSelected) { _ptboxSelected = pvNil; if (ptbox != pvNil) { ptbox->Select(fFalse); } } // // Find the text box // for (isev = 0; isev < _pggsevStart->IvMac(); isev++) { qsev = (PSEV)_pggsevStart->QvFixedGet(isev); if ((qsev->sevt == sevtAddTbox) && ((*(PTBOX *)_pggsevStart->QvGet(isev)) == ptbox)) { // // Remove it. Do not ReleasePpo() here as reference count // gets transfered to callee. // _pggsevStart->Delete(isev); // // Find it in the _pglptbox // for (itbox = 0; itbox < _pglptbox->IvMac(); itbox++) { if (*(PTBOX *)_pglptbox->QvGet(itbox) == ptbox) { if (_ptboxSelected == ptbox) { _ptboxSelected = pvNil; } _pglptbox->Delete(itbox); if (ptbox->FGetLifetime(&nfrmStart, &nfrmLast)) { // // This will guarantee that the tbox doesn't leave // any display on the rendering area. // AssertDo(ptbox->FGotoFrame(nfrmStart - 1), "Could not remove a text box"); } ReleasePpo(&ptbox); _MarkMovieDirty(); return(fTrue); } } Bug("Text box not found in GL"); return(fFalse); } } Bug("Error! Could not find text box for removal"); return(fFalse); } /**************************************************** * * This routine removes a text box from the scene, * creates an undo object for the action. * * Parameters: * ptbox - Pointer to the text box to remove. * * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FRemTbox(PTBOX ptbox) { AssertThis(0); AssertPo(ptbox, 0); PSUNX psunx; long nfrmFirst, nfrmLast; psunx = SUNX::PsunxNew(); if (psunx == pvNil) { return(fFalse); } ptbox->AddRef(); ptbox->FGetLifetime(&nfrmFirst, &nfrmLast); psunx->SetTbox(ptbox); // transfers the reference count to the undo object psunx->SetAdd(fFalse); psunx->SetNfrmFirst(nfrmFirst); psunx->SetNfrmLast((nfrmLast == _nfrmLast) ? klwMax : nfrmLast); if (!_pmvie->FAddUndo(psunx)) { ReleasePpo(&psunx); return(fFalse); } ReleasePpo(&psunx); if (!FRemTboxCore(ptbox)) { _pmvie->ClearUndo(); return(fFalse); } return(fTrue); } /**************************************************** * * This routine gets the ith text box. * * Parameters: * itbox - Index of the text box to get. * * Returns: * Pointer to the text box if itbox is valid, else pvNil. * ****************************************************/ TBOX *SCEN::PtboxFromItbox(long itbox) { AssertThis(0); Assert(itbox >= 0, "Bad index value"); long ipo; PTBOX ptbox; for (ipo = 0; ipo < _pglptbox->IvMac(); ipo++) { _pglptbox->Get(ipo, &ptbox); itbox--; if (itbox == -1) { break; } } if (itbox != -1) { ptbox = pvNil; } return(ptbox); } /**************************************************** * * This routine adds/removes a pause to the scene at the current frame. * * Parameters: * pwit - The pause type, witNil removes a pause, returns old pause type. * pdts - Valid only if wit==witForTime, dts is in clock ticks, returns * old wait time if old wit was witForTime. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FPauseCore(WIT *pwit, long *pdts) { AssertThis(0); AssertIn(*pwit, witNil, witLim); AssertIn(*pdts, 0, klwMax); SEV sev; long isev; PSEV qsev; SEVP sevp; WIT witOld; long dtsOld; // // Start at the first event of this frame. // for (isev=_isevFrmLim-1; isev >= 0; isev--) { qsev = (PSEV)_pggsevFrm->QvFixedGet(isev); if (qsev->nfrm != _nfrmCur) { break; } // // Find a pause // if (qsev->sevt == sevtPause) { // // Replace the event // _pggsevFrm->Get(isev, &sevp); witOld = sevp.wit; dtsOld = sevp.dts; if (*pwit == witNil) { _pggsevFrm->Delete(isev); _isevFrmLim--; } else { sevp.wit = *pwit; sevp.dts = *pdts; _pggsevFrm->Put(isev, &sevp); } *pwit = witOld; *pdts = dtsOld; return(fTrue); } } // // Add pause to event list. // sev.nfrm = _nfrmCur; sev.sevt = sevtPause; sevp.wit = *pwit; sevp.dts = *pdts; if (!_FAddSev(&sev, size(long) * 2, &sevp)) { return(fFalse); } *pwit = witNil; *pdts = 0; return(fTrue); } /**************************************************** * * This routine adds/removes a pause to the scene at the current frame * and creates an undo object for the action. * * Parameters: * wit - The pause type, removes pause if wit==witNil. * dts - Valid only if wit==witForTime, dts is in clock ticks. * * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FPause(WIT wit, long dts) { PSUNP psunp; psunp = SUNP::PsunpNew(); if (psunp == pvNil) { return(fFalse); } if (!FPauseCore(&wit, &dts)) { ReleasePpo(&psunp); return(fFalse); } psunp->SetWit(wit); psunp->SetDts(dts); psunp->SetAdd(fTrue); if (!_pmvie->FAddUndo(psunp)) { FPauseCore(&wit, &dts); ReleasePpo(&psunp); return(fFalse); } ReleasePpo(&psunp); return(fTrue); } /**************************************************** * * This routine sets the background for the scene. * * Parameters: * ptag - Pointer to the background tag to put on the scene. * ptagOld - Place to store the old background tag. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FSetBkgdCore(PTAG ptag, PTAG ptagOld) { AssertThis(0); AssertVarMem(ptag); AssertVarMem(ptagOld); SEV sev; long isev; TAG tag; long vlm; bool fLoop; PMSND pmsnd; long sty; if (_pbkgd != pvNil) { // // Replace background // for (isev = 0; isev < _pggsevStart->IvMac(); isev++) { _pggsevStart->GetFixed(isev, &sev); if (sev.sevt == sevtSetBkgd) { _pggsevStart->Get(isev, ptagOld); if (!_pggsevStart->FPut(isev, size(TAG), ptag)) { return(fFalse); } _pbkgd->TurnOffLights(); ReleasePpo(&_pbkgd); _MarkMovieDirty(); if (!_FPlaySev(&sev, ptag, _grfscen)) { _pggsevStart->FPut(isev, size(TAG), ptagOld); _FPlaySev(&sev, ptagOld, _grfscen); return(fFalse); } AssertPo(_pbkgd, 0); _pbkgd->GetName(&_stnName); goto LSuccess; } } Bug("No background event found"); return(fFalse); } TrashVar(ptagOld); // // Add set background event and play it. // sev.sevt = sevtSetBkgd; if (!_pggsevStart->FInsert(0, size(TAG), ptag, &sev)) { return(fFalse); } if (!_FPlaySev(&sev, ptag, _grfscen)) { _pggsevStart->Delete(0); return(fFalse); } AssertPo(_pbkgd, 0); _pbkgd->GetName(&_stnName); _MarkMovieDirty(); LSuccess: while (_pggsevFrm->IvMac() != 0) { // // Remove stale scene events // _pggsevFrm->Delete(_pggsevFrm->IvMac() - 1); } _isevFrmLim = 0; // Add the default sound for the new background, if any _pbkgd->GetDefaultSound(&tag, &vlm, &fLoop); if (tag.sid != ksidInvalid) // new background sound { // Note: since FSetBkgdCore is only called at edit time, // it's okay to call FCacheTag. The background default // sound is not an intrinsic part of the BKGD...it's more // of a "serving suggestion" that the user can remove // once the background is added. Assert(!_pmvie->FPlaying(), "Shouldn't cache tags if movie is playing!"); if (vptagm->FCacheTagToHD(&tag)) { pmsnd = (PMSND)vptagm->PbacoFetch(&tag, MSND::FReadMsnd); if (pvNil != pmsnd) { sty = pmsnd->Sty(); ReleasePpo(&pmsnd); // non-destructive if we fail FAddSndCore(fLoop, fFalse, vlm, sty, 1, &tag); } } } _pmvie->Pmcc()->SceneChange(); if (vpcex != pvNil) { vpcex->EnqueueCid(cidSceneLoaded); } return(fTrue); } /**************************************************** * * This routine sets the background for the scene. * * Parameters: * pbkgd - Pointer to the background to put on the scene. * * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FSetBkgd(PTAG ptag) { AssertThis(0); AssertVarMem(ptag); TAG tagOld; PSUNK psunk; long icam; if (_pbkgd != pvNil) { icam = _pbkgd->Icam(); } if (!FSetBkgdCore(ptag, &tagOld)) { return(fFalse); } #ifdef DEBUG long lw; TrashVar(&lw); Assert(tagOld.sid != lw, "Use CORE function to set first background"); #endif psunk = SUNK::PsunkNew(); if (psunk == pvNil) { if (!FSetBkgdCore(&tagOld, ptag)) { _pmvie->ClearUndo(); PushErc(ercSocNotUndoable); } return(fFalse); } psunk->SetTag(&tagOld); psunk->SetIcam(icam); psunk->SetFBkgd(fTrue); if (!_pmvie->FAddUndo(psunk)) { ReleasePpo(&psunk); if (!FSetBkgdCore(&tagOld, ptag)) { _pmvie->ClearUndo(); PushErc(ercSocNotUndoable); } return(fFalse); } ReleasePpo(&psunk); return(fTrue); } /**************************************************** * * This routine returns if a scene is currently empty * * Parameters: * None. * * Returns: * fTrue if the scene contains only camera changes and sounds * and is only 1 frame long, else fFalse. * ****************************************************/ bool SCEN::FIsEmpty(void) { AssertThis(0); long isev; SEV sev; if ((_pggsevStart->IvMac() != 1) || ((_nfrmLast - _nfrmFirst) > 0)) { return(fFalse); } for (isev = 0; isev < _pggsevFrm->IvMac(); isev++) { _pggsevFrm->GetFixed(isev, &sev); if (sev.sevt != sevtChngCamera && sev.sevt != sevtPlaySnd) { return(fFalse); } } return(fTrue); } /**************************************************** * * This routine changes the camera view point at this frame. * * Parameters: * icam - The camera number in the BKGD to switch to. * * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FChangeCamCore(long icam, long *picamOld) { AssertThis(0); AssertIn(icam, 0, 500); AssertVarMem(picamOld); PSEV qsev, qsevOld; SEV sev; long isev, isevCam; // // Check for a current camera change. // *picamOld = 0; for (isev= _isevFrmLim - 1; isev >= 0; isev--) { qsev = (PSEV)_pggsevFrm->QvFixedGet(isev); if (qsev->sevt == sevtChngCamera) { if (qsev->nfrm == _nfrmCur) { // // Check if this new camera matches the previous // camera // for (isevCam = isev - 1; isevCam >= 0; isevCam--) { qsevOld = (PSEV)_pggsevFrm->QvFixedGet(isevCam); if (qsevOld->sevt == sevtChngCamera) { _pggsevFrm->Get(isevCam, picamOld); break; } } // // If they are equal, then change camera to // previous camera and remove this change event. // if (*picamOld == icam) { qsevOld = (PSEV)_pggsevFrm->QvFixedGet(isev); _pggsevFrm->Get(isev, picamOld); if (_FPlaySev(qsevOld, &icam, _grfscen)) { _pggsevFrm->Delete(isev); _isevFrmLim--; _MarkMovieDirty(); goto LSuccess; } return(fFalse); } // // Change it // _pggsevFrm->Get(isev, picamOld); _pggsevFrm->Put(isev, &icam); _MarkMovieDirty(); if (_FPlaySev(qsev, &icam, _grfscen)) { goto LSuccess; } return(fFalse); } else { _pggsevFrm->Get(isev, picamOld); break; } } } if (*picamOld == icam) { goto LSuccess; } // // Add camera change to event list. // sev.nfrm = _nfrmCur; sev.sevt = sevtChngCamera; if (_FAddSev(&sev, size(long), &icam)) { if (_FPlaySev(&sev, &icam, _grfscen)) { goto LSuccess; } else { _pggsevFrm->Delete(--_isevFrmLim); } } return(fFalse); LSuccess: // // Check for later camera change // for (isev = _isevFrmLim; isev < _pggsevFrm->IvMac(); isev++) { long icamNext; qsev = (PSEV)_pggsevFrm->QvFixedGet(isev); if (qsev->sevt == sevtChngCamera) { _pggsevFrm->Get(isev, &icamNext); if (icamNext == icam) { _pggsevFrm->Delete(isev); _isevFrmLim; } break; } } return(fTrue); } /**************************************************** * * This routine changes the camera view point at this frame * and creates an undo object for the action. * * Parameters: * icam - The camera number in the BKGD to switch to. * * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FChangeCam(long icam) { long icamOld; PSUNK psunk; TAG tagCam; if (!vptagm->FBuildChildTag(&_tagBkgd, icam, kctgCam, &tagCam)) { return fFalse; } if (!vptagm->FCacheTagToHD(&tagCam)) { return fFalse; } if (!FChangeCamCore(icam, &icamOld)) { return(fFalse); } psunk = SUNK::PsunkNew(); if (psunk == pvNil) { if (!FChangeCamCore(icam, &icamOld)) { _pmvie->ClearUndo(); PushErc(ercSocNotUndoable); } return(fFalse); } psunk->SetIcam(icamOld); psunk->SetFBkgd(fFalse); if (!_pmvie->FAddUndo(psunk)) { ReleasePpo(&psunk); if (!FChangeCamCore(icam, &icamOld)) { _pmvie->ClearUndo(); PushErc(ercSocNotUndoable); } return(fFalse); } ReleasePpo(&psunk); return(fTrue); } /**************************************************** * * This routine reads in a scene from a chunky file. * * Parameters: * pcrf - Pointer to the chunky file to read from. * cno - Cno within the chunky file to read. * * Returns: * pvNil, if failure, else a pointer to the scene. * ****************************************************/ SCEN *SCEN::PscenRead(PMVIE pmvie, PCRF pcrf, CNO cno) { AssertPo(pmvie, 0); AssertPo(pcrf, 0); PSCEN pscen = pvNil; BLCK blck; KID kid; long isevFrm = 0; long isevStart = 0; SEV sev; PSEV qsev; short bo; PACTR pactr; PTBOX ptbox; CHID chid; SCENH scenh; PCFL pcfl; pcfl = pcrf->Pcfl(); // // Find the chunk and read in the header. // if (!pcfl->FFind(kctgScen, cno, &blck) || !blck.FUnpackData() || (blck.Cb() != size(SCENH)) || !blck.FReadRgb(&scenh, size(SCENH), 0)) { goto LFail0; } // // Check header for byte swapping // if (scenh.bo == kboOther) { SwapBytesBom(&scenh, kbomScenh); } else { Assert(scenh.bo == kboCur, "Bad Chunky file"); } // // Create our scene object. // pscen = NewObj SCEN(pmvie); if (pscen == pvNil) { goto LFail0; } pscen->_isevFrmLim = 0; // // Initialize roll call for actors // pscen->_pglpactr = GL::PglNew(size(PACTR), 0); if (pscen->_pglpactr == pvNil) { goto LFail0; } // // Initialize roll call for text boxes // pscen->_pglptbox = GL::PglNew(size(PTBOX), 0); if (pscen->_pglptbox == pvNil) { goto LFail0; } // // Read Frame information // pscen->_nfrmLast = scenh.nfrmLast; pscen->_nfrmFirst = scenh.nfrmFirst; pscen->_trans = scenh.trans; pscen->_nfrmCur = pscen->_nfrmFirst - 1; // // Read in thumbnail // if (pcfl->FGetKidChidCtg(kctgScen, cno, 0, kctgThumbMbmp, &kid) && pcfl->FFind(kid.cki.ctg, kid.cki.cno, &blck)) { pscen->_pmbmp = MBMP::PmbmpRead(&blck); } // // Read in GG of Frame events // if (!pcfl->FGetKidChidCtg(kctgScen, cno, 0, kctgFrmGg, &kid) || !pcfl->FFind(kid.cki.ctg, kid.cki.cno, &blck)) { goto LFail0; } pscen->_pggsevFrm = GG::PggRead(&blck, &bo); if (pscen->_pggsevFrm == pvNil) { goto LFail0; } Assert(pscen->_pggsevFrm->CbFixed() == size(SEV), "Bad GG read for event"); // // Convert all open tags to pointers. // for (; isevFrm < pscen->_pggsevFrm->IvMac(); isevFrm++) { qsev = (PSEV)pscen->_pggsevFrm->QvFixedGet(isevFrm); // // Swap byte ordering of entry // if (bo == kboOther) { SwapBytesBom((void *)qsev, kbomSev); } // // Open all tags // switch (qsev->sevt) { case sevtPlaySnd: PSSE psse; long itag; psse = SSE::PsseDupFromGg(pscen->_pggsevFrm, isevFrm, fFalse); if (pvNil == psse) goto LFail1; if (bo == kboOther) { psse->SwapBytes(); } for (itag = 0; itag < psse->ctagc; itag++) { if (!TAGM::FOpenTag(psse->Ptag(itag), pcrf, pcfl)) { while (itag-- > 0) TAGM::CloseTag(psse->Ptag(itag)); FreePpv((void **)&psse); // don't ReleasePpsse...tags are already closed goto LFail1; } } // Put SSE with opened tags back in GG pscen->_pggsevFrm->Put(isevFrm, psse); FreePpv((void **)&psse); // don't ReleasePpsse because GG keeps the tags break; case sevtChngCamera: case sevtPause: break; case sevtAddActr: case sevtSetBkgd: case sevtAddTbox: default: Assert(0, "Bad event in frame event list"); break; } } // // Read starting events // ReleasePpo(&pscen->_pggsevStart); if (!pcfl->FGetKidChidCtg(kctgScen, cno, 1, kctgStartGg, &kid) || !pcfl->FFind(kid.cki.ctg, kid.cki.cno, &blck)) { goto LFail1; } pscen->_pggsevStart = GG::PggRead(&blck, &bo); if (pscen->_pggsevStart == pvNil) { goto LFail1; } Assert(pscen->_pggsevStart->CbFixed() == size(SEV), "Bad GG read for event"); // // Convert all open tags to pointers. // for (; isevStart < pscen->_pggsevStart->IvMac(); isevStart++) { qsev = (PSEV)pscen->_pggsevStart->QvFixedGet(isevStart); // // Swap byte ordering of entry // if (bo == kboOther) { SwapBytesBom((void *)qsev, kbomSev); } // // Convert CHIDs to pointers // switch (qsev->sevt) { case sevtAddActr: pscen->_pggsevStart->Get(isevStart, &chid); if (bo == kboOther) { SwapBytesBom((void *)&chid, kbomLong); } if (!pcfl->FGetKidChidCtg(kctgScen, cno, chid, kctgActr, &kid)) { goto LFail1; } pactr = ACTR::PactrRead(pcrf, kid.cki.cno); AssertNilOrPo(pactr, 0); if (pactr == pvNil) { goto LFail1; } pscen->_pggsevStart->Put(isevStart, &pactr); break; case sevtAddTbox: pscen->_pggsevStart->Get(isevStart, &chid); if (bo == kboOther) { SwapBytesBom((void *)&chid, kbomLong); } if (!pcfl->FGetKidChidCtg(kctgScen, cno, chid, kctgTbox, &kid)) { goto LFail1; } ptbox = TBOX::PtboxRead(pcrf, kid.cki.cno, pscen); AssertNilOrPo(ptbox, 0); if (ptbox == pvNil) { goto LFail1; } pscen->_pggsevStart->Put(isevStart, &ptbox); break; case sevtSetBkgd: case sevtChngCamera: break; case sevtPause: case sevtPlaySnd: default: Bug("Bad event in start event list"); break; } } // // Read Name // pcfl->FGetName(kctgScen, cno, &pscen->_stnName); AssertPo(pscen, 0); return(pscen); LFail1: // // Destroy all created objects // while (isevStart--) { pscen->_pggsevStart->GetFixed(isevStart, &sev); switch (sev.sevt) { case sevtAddActr: pscen->_pggsevStart->Get(isevStart, &pactr); ReleasePpo(&pactr); break; case sevtAddTbox: pscen->_pggsevStart->Get(isevStart, &ptbox); ReleasePpo(&ptbox); break; case sevtChngCamera: case sevtSetBkgd: case sevtPause: break; } } ReleasePpo(&pscen->_pggsevStart); // // Destroy all created objects // while (isevFrm--) { pscen->_pggsevFrm->GetFixed(isevFrm, &sev); switch (sev.sevt) { case sevtAddActr: case sevtAddTbox: Bug("Bad event in frame list"); break; case sevtPlaySnd: PSSE qsse; long itag; qsse = (PSSE)pscen->_pggsevFrm->QvGet(isevFrm); if (qsse->Cb() != (pscen->_pggsevFrm->CbFixed() + pscen->_pggsevFrm->Cb(isevFrm))) { Bug("Wrong size for SSE in GG"); continue; } /* Close all tags; retrieve qsse each time...in theory, nothing that happens during CloseTag should cause mem to move, but this is a failure case, so it's okay to be slow, especially when we can be safe-not-sorry. */ for (itag = 0; itag < qsse->ctagc; itag++) { qsse = (PSSE)pscen->_pggsevFrm->QvGet(isevFrm); TAGM::CloseTag(qsse->Ptag(itag)); } break; case sevtSetBkgd: case sevtChngCamera: case sevtPause: break; } } ReleasePpo(&pscen->_pggsevFrm); LFail0: ReleasePpo(&pscen); return(pvNil); } /**************************************************** * * This routine plays all the starting events for a scene. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FPlayStartEvents(bool fActorsOnly) { AssertThis(0); long isev; // // This needs to play all the events in _pggsevStart // for (isev=0; isev < _pggsevStart->IvMac(); isev++) { SEV sev; _pggsevStart->GetFixed(isev, &sev); if (fActorsOnly && sev.sevt != sevtAddActr) continue; if (!_FPlaySev(&sev, _pggsevStart->QvGet(isev), _grfscen)) { return(fFalse); } } return(fTrue); } /**************************************************** * * This routine returns the bkgd tag in *ptag * ****************************************************/ bool SCEN::FGetTagBkgd(PTAG ptag) { AssertThis(0); AssertVarMem(ptag); SEV sev; long isevStart; for (isevStart = 0; isevStart < _pggsevStart->IvMac(); isevStart++) { sev = *(PSEV)_pggsevStart->QvFixedGet(isevStart); if (sevtSetBkgd == sev.sevt) { *ptag = *(PTAG)_pggsevStart->QvGet(isevStart); return fTrue; } } return fFalse; } /**************************************************** * * This routine writes a scene into a chunky file. * * Parameters: * pcrf - Pointer to the chunky file to write to. * pcno - Cno within the chunky file written to. * * Returns: * fFalse if it fails, else fTrue. * ****************************************************/ bool SCEN::FWrite(PCRF pcrf, CNO *pcno) { AssertThis(0); AssertPo(pcrf, 0); PGG pggFrmTemp = pvNil; PGG pggStartTemp = pvNil; SEV sev; CHID chidActr, chidTbox; CNO cnoChild, cnoFrmEvent, cnoStartEvent; SCENH scenh; long isevFrm = -1; long isevStart = -1; long cb; BLCK blck; PCFL pcfl; chidActr = chidTbox = 0; pcfl = pcrf->Pcfl(); *pcno = cnoNil; // // Get a new CNO for this chunk // if (!pcfl->FAdd(0, kctgScen, pcno)) { goto LFail; } // // Copy frame event GG to temporary GG // pggFrmTemp = GG::PggNew(size(SEV)); if (pggFrmTemp == pvNil) { goto LFail; } for (isevFrm = 0; isevFrm < _pggsevFrm->IvMac(); isevFrm++) { sev = *(PSEV)_pggsevFrm->QvFixedGet(isevFrm); // // Convert pointers in the GG to CHIDs // switch (sev.sevt) { case sevtPlaySnd: { bool fSuccess = fFalse; PSSE psse; long itag; KID kid; psse = SSE::PsseDupFromGg(_pggsevFrm, isevFrm); if (pvNil == psse) { goto LFail; } for (itag = 0; itag < psse->ctagc; itag++) { // For user sounds, the tag's cno must already be correct. // Note: FResolveSndTag can't succeed if the msnd chunk is // not yet a child of the scene. if (psse->Ptagc(itag)->tag.sid != ksidUseCrf) continue; // tag will be closed by ReleasePpsse // If the msnd chunk already exists as this chid of this scene, continue if (pcfl->FGetKidChidCtg(kctgScen, *pcno, *psse->Pchid(itag), kctgMsnd, &kid)) continue; // tag will be closed by ReleasePpsse // If the msnd does not exist in this file, it exists in the main movie if (!pcfl->FFind(kctgMsnd, psse->Ptag(itag)->cno)) continue; // tag will be closed by ReleasePpsse // The msnd chunk has not been adopted into the scene as the specified chid if (!pcfl->FAdoptChild(kctgScen, *pcno, kctgMsnd, psse->Ptag(itag)->cno, *psse->Pchid(itag))) { goto LEndPlaySnd; } } if (pggFrmTemp->FInsert(isevFrm, psse->Cb(), psse, &sev)) { fSuccess = fTrue; } LEndPlaySnd: ReleasePpsse(&psse); if (!fSuccess) { goto LFail; } break; } case sevtChngCamera: if (!pggFrmTemp->FInsert(isevFrm, size(long), _pggsevFrm->QvGet(isevFrm), &sev)) { goto LFail; } break; case sevtPause: if (!pggFrmTemp->FInsert(isevFrm, size(SEVP), _pggsevFrm->QvGet(isevFrm), &sev)) { goto LFail; } break; case sevtAddActr: case sevtSetBkgd: case sevtAddTbox: Assert(0, "Bad event in frame event list"); break; } } // // Copy start event GG to temporary GG // pggStartTemp = GG::PggNew(size(SEV)); if (pggStartTemp == pvNil) { goto LFail; } for (isevStart = 0; isevStart < _pggsevStart->IvMac(); isevStart++) { sev = *(PSEV)_pggsevStart->QvFixedGet(isevStart); // // Convert pointers in the GG to CHIDs // switch (sev.sevt) { case sevtAddActr: if (!pcfl->FAddChild(kctgScen, *pcno, chidActr, 0, kctgActr, &cnoChild)) { goto LFail; } if (!(*(PACTR *)_pggsevStart->QvGet(isevStart))->FWrite(pcfl, cnoChild, *pcno)) { goto LFail; } if (!pggStartTemp->FInsert(isevStart, size(CHID), &chidActr, &sev)) { goto LFail; } chidActr++; break; case sevtSetBkgd: if (!TAGM::FSaveTag((PTAG)_pggsevStart->QvGet(isevStart), pcrf, fFalse)) { goto LFail; } if (!pggStartTemp->FInsert(isevStart, size(TAG), _pggsevStart->QvGet(isevStart), &sev)) { goto LFail; } break; case sevtChngCamera: if (!pggStartTemp->FInsert(isevStart, size(long), _pggsevStart->QvGet(isevStart), &sev)) { goto LFail; } break; case sevtAddTbox: if (!pcfl->FAddChild(kctgScen, *pcno, chidTbox, 0, kctgTbox, &cnoChild)) { goto LFail; } if (!(*(PTBOX *)_pggsevStart->QvGet(isevStart))->FWrite(pcfl, cnoChild)) { goto LFail; } if (!pggStartTemp->FInsert(isevStart, size(CHID), &chidTbox, &sev)) { goto LFail; } chidTbox++; break; case sevtPause: case sevtPlaySnd: default: Assert(0, "Bad event in frame event list"); break; } } // // Save info into scene chunk // cb = pggFrmTemp->CbOnFile(); if (!pcfl->FAdd(cb, kctgFrmGg, &cnoFrmEvent, &blck)) { goto LFail; } if (!pggFrmTemp->FWrite(&blck)) { pcfl->Delete(kctgFrmGg, cnoFrmEvent); goto LFail; } if (!pcfl->FAdoptChild(kctgScen, *pcno, kctgFrmGg, cnoFrmEvent, 0)) { pcfl->Delete(kctgFrmGg, cnoFrmEvent); goto LFail; } pcfl->SetLoner(kctgFrmGg, cnoFrmEvent, fFalse); cb = pggStartTemp->CbOnFile(); if (!pcfl->FAdd(cb, kctgStartGg, &cnoStartEvent, &blck)) { goto LFail; } if (!pggStartTemp->FWrite(&blck)) { pcfl->Delete(kctgStartGg, cnoStartEvent); goto LFail; } if (!pcfl->FAdoptChild(kctgScen, *pcno, kctgStartGg, cnoStartEvent, 1)) { pcfl->Delete(kctgStartGg, cnoStartEvent); goto LFail; } pcfl->SetLoner(kctgStartGg, cnoStartEvent, fFalse); // // Save thumbnail, if there is one. // _UpdateThumbnail(); if (_pmbmp != pvNil) { cb = _pmbmp->CbOnFile(); if (!pcfl->FAdd(cb, kctgThumbMbmp, &cnoChild, &blck)) { goto LFail; } if (!_pmbmp->FWrite(&blck)) { pcfl->Delete(kctgThumbMbmp, cnoChild); goto LFail; } if (!pcfl->FAdoptChild(kctgScen, *pcno, kctgThumbMbmp, cnoChild, 0)) { pcfl->Delete(kctgThumbMbmp, cnoChild); goto LFail; } pcfl->SetLoner(kctgThumbMbmp, cnoChild, fFalse); } // // Create header buffer for scene chunk // scenh.bo = kboCur; scenh.osk = koskCur; scenh.nfrmLast = _nfrmLast; scenh.nfrmFirst = _nfrmFirst; scenh.trans = _trans; // // Write scene chunk // if (!pcfl->FSetName(kctgScen, *pcno, &_stnName)) { goto LFail; } if (!pcfl->FPutPv((void *)&scenh, size(SCENH), kctgScen, *pcno)) { goto LFail; } ReleasePpo(&pggFrmTemp); ReleasePpo(&pggStartTemp); return(fTrue); LFail: // // Delete chunks createdk. // if (*pcno != cnoNil) { pcfl->Delete(kctgScen, *pcno); } ReleasePpo(&pggStartTemp); ReleasePpo(&pggFrmTemp); return(fFalse); } /**************************************************** * * This routine resolves all sound tags * * Parameters: * None * Returns: * None * ****************************************************/ bool SCEN::FResolveAllSndTags(CNO cnoScen) { AssertThis(0); long ipactr, ipactrMac; long isev, isevMac; bool fSuccess = fFalse; ipactrMac = _pglpactr->IvMac(); for (ipactr = 0; ipactr < ipactrMac; ipactr++) { PACTR pactr; _pglpactr->Get(ipactr, &pactr); if (!pactr->FResolveAllSndTags(cnoScen)) goto LFail; } _pggsevFrm->Lock(); isevMac = _pggsevFrm->IvMac(); for (isev = 0; isev < isevMac; isev++) { long itag; PSSE psse; SEV sev; sev = *(PSEV)_pggsevFrm->QvFixedGet(isev); if (sev.sevt != sevtPlaySnd) continue; psse = (PSSE)_pggsevFrm->QvGet(isev); for (itag = 0; itag < psse->ctagc; itag++) { if (psse->Ptag(itag)->sid == ksidUseCrf) { if (!_pmvie->FResolveSndTag(psse->Ptag(itag), *psse->Pchid(itag), cnoScen)) { goto LFail; } } } } _pggsevFrm->Unlock(); fSuccess = fTrue; LFail: return fSuccess; } /**************************************************** * * This routine removes all actors from movie's roll call. * * Parameters: * fDelIfOnlyRef -- fTrue indicates to remove the roll-call entry * if a given actr is only referenced by this scene. * * Returns: * None * ****************************************************/ void SCEN::RemActrsFromRollCall(bool fDelIfOnlyRef) { AssertThis(0); PACTR pactr; long ipactr; for (ipactr = 0; ipactr < _pglpactr->IvMac(); ipactr++) { _pglpactr->Get(ipactr, &pactr); Pmvie()->RemFromRollCall(pactr, fDelIfOnlyRef); } } /**************************************************** * * This routine adds all actors to movie's roll call. * * Parameters: * None * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FAddActrsToRollCall(void) { AssertThis(0); PACTR pactr; long ipactr; STN stn; for (ipactr = 0; ipactr < _pglpactr->IvMac(); ipactr++) { _pglpactr->Get(ipactr, &pactr); AssertPo(pactr, 0); pactr->GetName(&stn); if (!Pmvie()->FAddToRollCall(pactr, &stn)) { for (; ipactr > 0 ; ) { ipactr--; _pglpactr->Get(ipactr, &pactr); Pmvie()->RemFromRollCall(pactr); } return(fFalse); } } return(fTrue); } /**************************************************** * * This routine returns the scene's thumbnail. * * Parameters: * None * * Returns: * None * ****************************************************/ PMBMP SCEN::PmbmpThumbnail(void) { AssertThis(0); _UpdateThumbnail(); return(_pmbmp); } /**************************************************** * * This routine updates the mbmp associated with the * thumbnail for the scene. * * Parameters: * None * * Returns: * None * ****************************************************/ void SCEN::_UpdateThumbnail(void) { AssertThis(0); long nfrmCur; PGPT pgpt, pgptThumb; PMVU pmvu; PTBOX ptbox = PtboxSelected(); PACTR pactr = PactrSelected(); RC rc, rcThumb; long grfscenSave; long dtimSnd; dtimSnd = Pmvie()->Pmsq()->DtimSnd(); Pmvie()->Pmsq()->SndOff(); pmvu = (PMVU)Pmvie()->PddgGet(0); if ((_pbkgd == pvNil) || (pmvu == pvNil)) { goto LEnd; } AssertPo(pmvu, 0); if (!Pmvie()->FDirty()) { goto LEnd; } rc.Set(0, 0, Pmvie()->Pmcc()->Dxp(), Pmvie()->Pmcc()->Dyp()); pgpt = GPT::PgptNewOffscreen(&rc, 8); if (pgpt == pvNil) { goto LEnd; } AssertPo(pgpt, 0); rcThumb.Set(0, 0, kdxpThumbnail, kdypThumbnail); pgptThumb = GPT::PgptNewOffscreen(&rcThumb, 8); if (pgptThumb == pvNil) { ReleasePpo(&pgpt); goto LEnd; } AssertPo(pgptThumb, 0); pgptThumb->SetOffscreenColors(Pmvie()->PglclrThumbPalette()); grfscenSave = _grfscen; Disable(fscenPauses | fscenSounds); nfrmCur = _nfrmCur; if ((_nfrmCur != _nfrmFirst) && !FGotoFrm(_nfrmFirst)) { ReleasePpo(&pgpt); ReleasePpo(&pgptThumb); _grfscen = grfscenSave; goto LEnd; } if (pmvu->FTextMode()) { SelectTbox(pvNil); } else { SelectActr(pvNil); } pmvu->DrawTree(pgpt, pvNil, &rc, fgobNoVis); if (pmvu->FTextMode()) { SelectTbox(ptbox); } else { SelectActr(pactr); } BLOCK{ GNV gnv(pgpt); GNV gnvThumb(pgptThumb); gnvThumb.CopyPixels(&gnv, &rc, &rcThumb); ReleasePpo(&_pmbmp); _pmbmp = MBMP::PmbmpNew(pgptThumb->PrgbLockPixels(), pgptThumb->CbRow(), kdypThumbnail, &rcThumb, 0, 0, kbTransparent ); pgptThumb->Unlock(); ReleasePpo(&pgpt); ReleasePpo(&pgptThumb); if ((nfrmCur > _nfrmFirst) && (nfrmCur <= _nfrmLast)) { FGotoFrm(nfrmCur); } _grfscen = grfscenSave; } LEnd: Pmvie()->Pmsq()->SndOnDtim(dtimSnd); return; } /**************************************************** * * This routine marks the movie as dirty. * * Parameters: * fDirty - Set dirty or not. * * Returns: * None * ****************************************************/ void SCEN::MarkDirty(bool fDirty) { AssertThis(0); if (fDirty) { _MarkMovieDirty(); } } /**************************************************** * * This routine pastes an actor into the current scene * * Parameters: * pactr - Pointer to the actor to paste * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FPasteActrCore(PACTR pactr) { AssertThis(0); AssertPo(pactr, 0); // // Paste the actor. // if (!pactr->FPaste(_nfrmCur, this)) { return(fFalse); } // // Add the actor // if (!FAddActrCore(pactr)) { return(fFalse); } InvalFrmRange(); if (!pactr->FGotoFrame(_nfrmCur)) { RemActrCore(pactr->Arid()); return(fFalse); } _MarkMovieDirty(); _pmvie->Pmcc()->UpdateRollCall(); UpdateSndFrame(); return(fTrue); } /**************************************************** * * This routine pastes an actor into the current scene * and creates an undo object for the action. * * NOTE: This does not need an undo object, since the * tool is getting set to a "place" tool, which will * create the appropriate undo type. * * Parameters: * pactr - Pointer to the actor to paste * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::FPasteActr(PACTR pactr) { AssertThis(0); AssertPo(pactr, 0); if (!FPasteActrCore(pactr)) { return(fFalse); } return(fTrue); } /**************************************************** * * This routine makes all actors go to a specific frame. * * Parameters: * nfrm - Frame number to go to. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::_FForceActorsToFrm(long nfrm, bool *pfSoundInFrame) { AssertThis(0); AssertIn(nfrm, klwMin, klwMax); PACTR pactr; long iactr; for (iactr = 0; iactr < _pglpactr->IvMac(); iactr++) { _pglpactr->Get(iactr, &pactr); AssertPo(pactr, 0); if (!pactr->FGotoFrame(nfrm, pfSoundInFrame)) { return(fFalse); } } return(fTrue); } /**************************************************** * * This routine makes all text boxes go to a specific frame. * * Parameters: * nfrm - Frame number to go to. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SCEN::_FForceTboxesToFrm(long nfrm) { AssertThis(0); AssertIn(nfrm, klwMin, klwMax); PTBOX ptbox; long itbox; for (itbox = 0; itbox < _pglptbox->IvMac(); itbox++) { _pglptbox->Get(itbox, &ptbox); AssertPo(ptbox, 0); if (!ptbox->FGotoFrame(nfrm)) { return(fFalse); } } return(fTrue); } /**************************************************** * * Hides all text boxes in this scene * * Parameters: * None. * * Returns: * None. * ****************************************************/ void SCEN::HideTboxes(void) { AssertThis(0); PTBOX ptbox; long iptbox; long nfrmStart, nfrmLast; for (iptbox = 0; iptbox < _pglptbox->IvMac(); iptbox++) { _pglptbox->Get(iptbox, &ptbox); AssertPo(ptbox, 0); if (ptbox->FGetLifetime(&nfrmStart, &nfrmLast)) { AssertDo(ptbox->FGotoFrame(nfrmStart - 1), "Could not remove a text box"); } } } /**************************************************** * * Hides all actors in this scene * * Parameters: * * Returns: * None. * ****************************************************/ void SCEN::HideActors(void) { AssertThis(0); PACTR pactr; long ipactr; for (ipactr = 0; ipactr < _pglpactr->IvMac(); ipactr++) { _pglpactr->Get(ipactr, &pactr); AssertPo(pactr, 0); pactr->Hide(); } } /**************************************************** * * Shows all actors in this scene * * Parameters: * * Returns: * None. * ****************************************************/ void SCEN::ShowActors(void) { AssertThis(0); PACTR pactr; long ipactr; for (ipactr = 0; ipactr < _pglpactr->IvMac(); ipactr++) { _pglpactr->Get(ipactr, &pactr); AssertPo(pactr, 0); pactr->Show(); } } /**************************************************** * * This routine marks the movie dirty. * * Parameters: * None * * Returns: * None. * ****************************************************/ void SCEN::_MarkMovieDirty() { AssertThis(0); if (_pmvie != pvNil) { _pmvie->SetDirty(); } } /**************************************************** * * This routine sets the scene to the given movie * * Parameters: * pmvie - The new parent movie * * Returns: * None. * ****************************************************/ void SCEN::SetMvie(PMVIE pmvie) { AssertThis(0); AssertPo(pmvie, 0); _pmvie = pmvie; } /**************************************************** * * This routine reads from a chunky file and creates * a list of all the tags in the scene. * * Parameters: * pcfl - Pointer to the chunky file to read from. * cno - Cno within the chunky file to read. * ptagl - tag list to put tags in * * Returns: * fFalse if an error occurred, else fTrue * ****************************************************/ bool SCEN::FAddTagsToTagl(PCFL pcfl, CNO cno, PTAGL ptagl) { AssertPo(pcfl, 0); AssertPo(ptagl, 0); BLCK blck; KID kid; long isev; PSEV qsev; short bo; PGG pggsev; TAG tag; TAG tagBkgd; PGL pgltagSrc; TAG tagSrc; long itagSrc; CHID chid; tagBkgd.sid = ksidInvalid; // // Read starting events // if (!pcfl->FGetKidChidCtg(kctgScen, cno, 1, kctgStartGg, &kid)) { return fFalse; } if (!pcfl->FFind(kid.cki.ctg, kid.cki.cno, &blck)) { return fFalse; } pggsev = GG::PggRead(&blck, &bo); if (pggsev == pvNil) { return fFalse; } Assert(pggsev->CbFixed() == size(SEV), "Bad GG read for event"); // // Find all tags in starting events // for (isev = 0; isev < pggsev->IvMac(); isev++) { qsev = (PSEV)pggsev->QvFixedGet(isev); // // Swap byte ordering of entry // if (bo == kboOther) { SwapBytesBom((void *)qsev, kbomSev); } // // Find appropriate event types // switch (qsev->sevt) { case sevtAddActr: pggsev->Get(isev, &chid); if (bo == kboOther) { SwapBytesBom((void *)&chid, kbomLong); } if (!pcfl->FGetKidChidCtg(kctgScen, cno, chid, kctgActr, &kid)) { ReleasePpo(&pggsev); return fFalse; } else { bool fError; pgltagSrc = ACTR::PgltagFetch(pcfl, kid.cki.cno, &fError); if (fError) { ReleasePpo(&pgltagSrc); ReleasePpo(&pggsev); return fFalse; } if (pgltagSrc != pvNil) { for (itagSrc = 0; itagSrc < pgltagSrc->IvMac(); itagSrc++) { pgltagSrc->Get(itagSrc, &tagSrc); if (!ptagl->FInsertTag(&tagSrc)) { ReleasePpo(&pgltagSrc); ReleasePpo(&pggsev); return fFalse; } } ReleasePpo(&pgltagSrc); } } break; case sevtSetBkgd: pggsev->Get(isev, &tag); if (bo == kboOther) { SwapBytesBom((void *)&tag, kbomTag); } if (!BKGD::FAddTagsToTagl(&tag, ptagl)) { ReleasePpo(&pggsev); return fFalse; } tagBkgd = tag; break; case sevtAddTbox: break; case sevtPlaySnd: case sevtChngCamera: case sevtPause: default: Bug("Bad event in start event list"); break; } } ReleasePpo(&pggsev); // // Read in GG of Frame events // if (!pcfl->FGetKidChidCtg(kctgScen, cno, 0, kctgFrmGg, &kid)) { return fFalse; } if (!pcfl->FFind(kid.cki.ctg, kid.cki.cno, &blck)) { return fFalse; } pggsev = GG::PggRead(&blck, &bo); if (pggsev == pvNil) { return fFalse; } Assert(pggsev->CbFixed() == size(SEV), "Bad GG read for event"); // // Look in all events for tags // for (isev = 0; isev < pggsev->IvMac(); isev++) { qsev = (PSEV)pggsev->QvFixedGet(isev); // // Swap byte ordering of entry // if (bo == kboOther) { SwapBytesBom((void *)qsev, kbomSev); } // // Find appropriate event types // switch (qsev->sevt) { case sevtChngCamera: pggsev->Get(isev, &chid); if (bo == kboOther) { SwapBytesBom((void *)&chid, kbomLong); } if (tagBkgd.sid == ksidInvalid) { Bug("no background event!?"); ReleasePpo(&pggsev); return fFalse; } if (!ptagl->FInsertChild(&tagBkgd, chid, kctgCam)) { ReleasePpo(&pggsev); return fFalse; } break; case sevtPause: break; case sevtPlaySnd: PSSE psse; long itag; psse = SSE::PsseDupFromGg(pggsev, isev, fFalse); if (pvNil == psse) { ReleasePpo(&pggsev); return fFalse; } if (bo == kboOther) { psse->SwapBytes(); } // // Insert the tags in order // for (itag = 0; itag < psse->ctagc; itag++) { if (!ptagl->FInsertTag(psse->Ptag(itag))) { ReleasePpsse(&psse); ReleasePpo(&pggsev); return fFalse; } } ReleasePpsse(&psse); break; case sevtAddActr: case sevtSetBkgd: case sevtAddTbox: default: Bug("Bad event in frame event list"); break; } } ReleasePpo(&pggsev); return fTrue; } /**************************************************** * * This returns the actor in the current scene with * the given arid. * * Parameters: * Arid to look for. * * Returns: * pvNil if failure, else the actor. * ****************************************************/ PACTR SCEN::PactrFromArid(long arid) { AssertThis(0); Assert(arid != aridNil, "Bad long"); long iactr; PACTR pactr; // // Search current scene for the actor. // for (iactr = 0; iactr < _pglpactr->IvMac(); iactr++) { _pglpactr->Get(iactr, &pactr); if (pactr->Arid() == arid) { return(pactr); } } return(pvNil); } /**************************************************** * * This routine chops off the rest of the scene. * * Parameters: * None. * * Returns: * fTrue is successful, else fFalse if failure. * ****************************************************/ bool SCEN::FChopCore() { AssertThis(0); PTBOX ptbox; PACTR pactr; bool fAlive; long ipo; long nfrmStart, nfrmLast; if (_nfrmCur == _nfrmLast) { return(fTrue); } // // Chop all actors off // for (ipo = 0; ipo < _pglpactr->IvMac();) { _pglpactr->Get(ipo, &pactr); AssertPo(pactr, 0); pactr->DeleteFwdCore(fTrue, &fAlive); if (!fAlive) { RemActrCore(pactr->Arid()); } else { ipo++; } } // // Chop all text boxes off // for (ipo = 0; ipo < _pglptbox->IvMac();) { _pglptbox->Get(ipo, &ptbox); AssertPo(ptbox, 0); if (ptbox->FGetLifetime(&nfrmStart, &nfrmLast) && (nfrmStart > _nfrmCur)) { // // Ok if this fails. // FRemTboxCore(ptbox); } else { if (nfrmLast >= _nfrmCur) { // // Here we extend the lifetime of the text box to // infinite, cuz we removed the frame with the // Hide(). // if (ptbox->FGotoFrame(klwMax - 1)) { ptbox->FShowCore(); ptbox->FGotoFrame(_nfrmCur); } } ipo++; } } // // Remove all scene events from here forward // for (; _isevFrmLim < _pggsevFrm->IvMac(); ) { _pggsevFrm->Delete(_isevFrmLim); } // // Set new limit // if (_nfrmLast != _nfrmCur) { _nfrmLast = _nfrmCur; Pmvie()->SetDirty(); } return(fTrue); } /**************************************************** * * This routine chops off the rest of the scene and * creates an undo object as well. * * Parameters: * None. * * Returns: * fTrue is successful, else fFalse if failure. * ****************************************************/ bool SCEN::FChop() { PSUNC psunc; bool fValid; if (_nfrmCur == _nfrmLast) { return(fTrue); } psunc = SUNC::PsuncNew(); if (psunc != pvNil) { fValid = psunc->FSave(this); } else { fValid = fFalse; } if (!fValid || !Pmvie()->FAddUndo(psunc)) { ReleasePpo(&psunc); return(fFalse); } ReleasePpo(&psunc); if (!FChopCore()) { Pmvie()->ClearUndo(); return(fFalse); } return(fTrue); } /**************************************************** * * This routine chops off the rest of the scene, backwards * * Parameters: * None. * * Returns: * fTrue is successful, else fFalse if failure. * ****************************************************/ bool SCEN::FChopBackCore() { AssertThis(0); PTBOX ptbox; PACTR pactr; SEV sev; bool fAlive; bool fCopyCam; long ipo; long nfrmStart, nfrmLast; if (_nfrmCur == _nfrmFirst) { return(fTrue); } // // Chop all actors off // for (ipo = 0; ipo < _pglpactr->IvMac();) { _pglpactr->Get(ipo, &pactr); AssertPo(pactr, 0); pactr->DeleteBackCore(&fAlive); if (!fAlive) { RemActrCore(pactr->Arid()); } else { ipo++; } } // // Chop all text boxes off // for (ipo = 0; ipo < _pglptbox->IvMac();) { _pglptbox->Get(ipo, &ptbox); AssertPo(ptbox, 0); if (ptbox->FGetLifetime(&nfrmStart, &nfrmLast) && (nfrmLast < _nfrmCur)) { // // Ok if this fails. // FRemTboxCore(ptbox); } else { if (nfrmStart < _nfrmCur) { Assert(ptbox->FIsVisible(), "Bad tbox"); ptbox->SetStartFrame(_nfrmCur); } ipo++; } } // // Remove all scene events from here backward, except camera // changes, keep the most recent camera change. // fCopyCam = fTrue; for (; _isevFrmLim > 0; ) { _isevFrmLim--; _pggsevFrm->GetFixed(_isevFrmLim, &sev); if ((sev.sevt == sevtChngCamera) && (fCopyCam)) { fCopyCam = fFalse; sev.nfrm = _nfrmCur; _pggsevFrm->PutFixed(_isevFrmLim, &sev); } else { if (sev.nfrm == _nfrmCur) { continue; } _pggsevFrm->Delete(_isevFrmLim); } } _isevFrmLim = 0; for (; _isevFrmLim < _pggsevFrm->IvMac(); _isevFrmLim++) { _pggsevFrm->GetFixed(_isevFrmLim, &sev); if (sev.nfrm != _nfrmCur) { break; } } // // Set new limit // if (_nfrmFirst != _nfrmCur) { _nfrmFirst = _nfrmCur; Pmvie()->SetDirty(); } // // If _psseBkgd got chopped, get rid of it // if (_psseBkgd != pvNil && _nfrmSseBkgd < _nfrmFirst) { ReleasePpsse(&_psseBkgd); TrashVar(&_nfrmSseBkgd); } return(fTrue); } /**************************************************** * * This routine chops off the rest of the scene, backwards, * and creates an undo object as well. * * Parameters: * None. * * Returns: * fTrue is successful, else fFalse if failure. * ****************************************************/ bool SCEN::FChopBack() { PSUNC psunc; bool fValid; if (_nfrmCur == _nfrmFirst) { return(fTrue); } psunc = SUNC::PsuncNew(); if (psunc != pvNil) { fValid = psunc->FSave(this); } else { fValid = fFalse; } if (!fValid || !Pmvie()->FAddUndo(psunc)) { ReleasePpo(&psunc); return(fFalse); } ReleasePpo(&psunc); if (!FChopBackCore()) { Pmvie()->ClearUndo(); return(fFalse); } return(fTrue); } /**************************************************** * * This routine does any startup for playback * * Parameters: * None. * * Returns: * None. * ****************************************************/ bool SCEN::FStartPlaying() { AssertThis(0); long ipactr, iptbox; PACTR pactr; PTBOX ptbox; PTBXG ptbxg; long nfrmFirst, nfrmLast; // // Make sure all actors have state variables updated // (they might not be in the theater right after // loading the movie) // for (ipactr = 0; ipactr < _pglpactr->IvMac(); ipactr++) { _pglpactr->Get(ipactr, &pactr); if (!pactr->FGetLifetime(&nfrmFirst, &nfrmLast)) return fFalse; } for (iptbox = 0; iptbox < _pglptbox->IvMac(); iptbox++) { _pglptbox->Get(iptbox, &ptbox); if ((ptbox->FStory() && ptbox->FIsVisible()) || (!ptbox->FStory() && ptbox->FGetLifetime(&nfrmFirst, &nfrmLast) && (nfrmFirst == _nfrmCur))) { ptbxg = (PTBXG)ptbox->PddgGet(0); ptbxg->Scroll(scaNil); } } // // Start prerendering at this frame, even if there's // no camera view change. // _DoPrerenderingWork(fTrue); return fTrue; } /**************************************************** * * This routine cleans up after a playback has stopped. * * Parameters: * None. * * Returns: * None. * ****************************************************/ void SCEN::StopPlaying() { AssertThis(0); long itbox; PTBOX ptbox; _EndPrerendering(); // Stop prerendering for (itbox = 0; itbox < _pglptbox->IvMac(); itbox++) { _pglptbox->Get(itbox, &ptbox); AssertPo(ptbox, 0); ptbox->CleanDdg(); } } /****************************************************************************** FTransOnFile For a given SCEN chunk on a given CRF, get the scene transition state for the scene. Arguments: PCRF pcrf -- the chunky resource file the SCEN lives on CNO cno -- the CNO of the SCEN chunk TRANS *ptrans -- pointer to memory to take the transition setting Returns: fTrue if it was able to set *ptrans, fFalse if something failed ************************************************************ PETED ***********/ bool SCEN::FTransOnFile(PCRF pcrf, CNO cno, TRANS *ptrans) { BLCK blck; SCENH scenh; PCFL pcfl = pcrf->Pcfl(); TrashVar(ptrans); if (!pcfl->FFind(kctgScen, cno, &blck)) goto LFail; if (!blck.FUnpackData() || blck.Cb() != size(SCENH)) goto LFail; if (!blck.FReadRgb(&scenh, size(SCENH), 0)) goto LFail; *ptrans = scenh.trans; return fTrue; LFail: return fFalse; } /****************************************************************************** FSetTransOnFile For a given SCEN chunk on a given CRF, set the scene transition state for the scene. Arguments: PCRF pcrf -- the chunky resource file the SCEN lives on CNO cno -- the CNO of the SCEN chunk TRANS trans -- the transition state to use Returns: fTrue if the routine could guarantee that the scene has the given transition state. ************************************************************ PETED ***********/ bool SCEN::FSetTransOnFile(PCRF pcrf, CNO cno, TRANS trans) { BLCK blck; SCENH scenh; PCFL pcfl = pcrf->Pcfl(); if (!pcfl->FFind(kctgScen, cno, &blck)) goto LFail; if (!blck.FUnpackData() || blck.Cb() != size(SCENH)) goto LFail; if (!blck.FReadRgb(&scenh, size(SCENH), 0)) goto LFail; if (scenh.trans != trans) { scenh.trans = trans; if (!pcfl->FPutPv(&scenh, size(SCENH), kctgScen, cno)) goto LFail; } return fTrue; LFail: return fFalse; } // // // // UNDO STUFF // // // /**************************************************** * * Public constructor for scene undo objects for name * related commands. * * Parameters: * None. * * Returns: * pvNil if failure, else a pointer to the movie undo. * ****************************************************/ PSUNT SUNT::PsuntNew() { PSUNT psunt; psunt = NewObj SUNT(); return(psunt); } /**************************************************** * * Destructor for scene naming undo objects * ****************************************************/ SUNT::~SUNT(void) { AssertBaseThis(0); } /**************************************************** * * Does a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNT::FDo(PDOCB pdocb) { AssertThis(0); STN stn; if (!_pmvie->FSwitchScen(_iscen)) { _pmvie->Pmsq()->FlushMsq(); _pmvie->ClearUndo(); return(fFalse); } _pmvie->Pscen()->GetName(&stn); _pmvie->Pscen()->SetNameCore(&_stn); _stn = stn; _pmvie->Pmsq()->FlushMsq(); return(fTrue); } /**************************************************** * * Undoes a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNT::FUndo(PDOCB pdocb) { AssertThis(0); return(FDo(pdocb)); } #ifdef DEBUG /**************************************************** * Mark memory used by the SUNT * * Parameters: * None. * * Returns: * None. * ****************************************************/ void SUNT::MarkMem(void) { AssertThis(0); SUNT_PAR::MarkMem(); } /*************************************************************************** Assert the validity of the SUNT. ***************************************************************************/ void SUNT::AssertValid(ulong grf) { } #endif /**************************************************** * * Public constructor for scene undo objects for sound * related commands. * * Parameters: * None. * * Returns: * pvNil if failure, else a pointer to the movie undo. * ****************************************************/ PSUNS SUNS::PsunsNew() { PSUNS psuns; psuns = NewObj SUNS(); return(psuns); } /**************************************************** * * Destructor for scene sound undo objects * ****************************************************/ SUNS::~SUNS(void) { AssertBaseThis(0); ReleasePpsse(&_psse); } /**************************************************** * * Does a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNS::FDo(PDOCB pdocb) { AssertThis(0); AssertPo(pdocb, 0); long isevSnd = ivNil; bool fFound; PSSE psseOld = pvNil; if (!_pmvie->FSwitchScen(_iscen)) { _pmvie->ClearUndo(); return(fFalse); } if (!_pmvie->Pscen()->FGotoFrm(_nfrm)) { _pmvie->ClearUndo(); return(fFalse); } _pmvie->Pmsq()->FlushMsq(); // swap the event in the event list (if any) with _psse (if any) if (!_pmvie->Pscen()->FGetSnd(_sty, &fFound, &psseOld)) { _pmvie->ClearUndo(); return(fFalse); } if (_psse != pvNil) { if (fFound) { _pmvie->Pscen()->RemSndCore(psseOld->sty); if (!_pmvie->Pscen()->FAddSndCoreTagc(_psse->fLoop, fFalse, _psse->vlm, _psse->sty, _psse->ctagc, _psse->Ptagc(0))) { ReleasePpsse(&psseOld); _pmvie->ClearUndo(); return(fFalse); } ReleasePpsse(&_psse); _psse = psseOld; _sty = psseOld->sty; } else // no sse to replace, just add this one { if (!_pmvie->Pscen()->FAddSndCoreTagc(_psse->fLoop, fFalse, _psse->vlm, _psse->sty, _psse->ctagc, _psse->Ptagc(0))) { _pmvie->ClearUndo(); return(fFalse); } ReleasePpsse(&_psse); } } else // _psse is pvNil...remember what's there then nuke the event { if (!fFound) { Bug("where's the sound event?"); return(fFalse); } else { if (!FSetSnd(psseOld)) { _pmvie->ClearUndo(); return(fFalse); } ReleasePpsse(&psseOld); _pmvie->Pscen()->RemSndCore(_sty); } } _pmvie->Pmsq()->PlayMsq(); return(fTrue); } /**************************************************** * * Undoes a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNS::FUndo(PDOCB pdocb) { AssertThis(0); AssertPo(pdocb, 0); return FDo(pdocb); } #ifdef DEBUG /**************************************************** * Mark memory used by the SUNS * * Parameters: * None. * * Returns: * None. * ****************************************************/ void SUNS::MarkMem(void) { AssertThis(0); SUNS_PAR::MarkMem(); if (_psse != pvNil) MarkPv(_psse); } /*************************************************************************** Assert the validity of the SUNS. ***************************************************************************/ void SUNS::AssertValid(ulong grf) { SUNS_PAR::AssertValid(grf); if (_psse != pvNil) { AssertPvCb(_psse, size(SSE)); AssertPvCb(_psse, _psse->Cb()); Assert(_sty == _psse->sty, "sty's don't match"); } } #endif /**************************************************** * * Public constructor for scene undo objects for actor * related commands. * * Parameters: * None. * * Returns: * pvNil if failure, else a pointer to the movie undo. * ****************************************************/ PSUNA SUNA::PsunaNew() { PSUNA psuna; psuna = NewObj SUNA(); return(psuna); } /**************************************************** * * Destructor for scene actor undo objects * ****************************************************/ SUNA::~SUNA(void) { AssertBaseThis(0); ReleasePpo(&_pactr); } /**************************************************** * * Does a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNA::FDo(PDOCB pdocb) { AssertThis(0); PACTR pactr, pactrDup; if (!_pmvie->FSwitchScen(_iscen)) { goto LFail; } if (!_pmvie->Pscen()->FGotoFrm(_nfrm)) { goto LFail; } if (_ut == utAdd) { if (!_pmvie->Pscen()->FAddActrCore(_pactr)) { goto LFail; } _pmvie->Pscen()->SelectActr(_pactr); if (!_pactr->FDup(&pactrDup, fTrue)) { goto LFail; } pactrDup->SetArid(_pactr->Arid()); ReleasePpo(&_pactr); SetActr(pactrDup); } else if (_ut == utDel) { _pmvie->Pscen()->RemActrCore(_pactr->Arid()); } else { Assert(_ut == utRep, "Bad Grf"); pactr = _pmvie->Pscen()->PactrFromArid(_pactr->Arid()); if (!pactr->FDup(&pactrDup, fTrue)) { goto LFail; } if (!_pmvie->Pscen()->FAddActrCore(_pactr)) { goto LFail; } _pmvie->Pscen()->SelectActr(_pactr); pactrDup->SetArid(_pactr->Arid()); ReleasePpo(&_pactr); SetActr(pactrDup); } _pmvie->Pmsq()->FlushMsq(); _pmvie->Pmcc()->UpdateRollCall(); return(fTrue); LFail: _pmvie->Pmsq()->FlushMsq(); _pmvie->ClearUndo(); return(fFalse); } /**************************************************** * * Undoes a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNA::FUndo(PDOCB pdocb) { AssertThis(0); PACTR pactr, pactrDup; if (!_pmvie->FSwitchScen(_iscen)) { goto LFail; } if (!_pmvie->Pscen()->FGotoFrm(_nfrm)) { goto LFail; } if (_ut == utAdd) { _pmvie->Pscen()->RemActrCore(_pactr->Arid()); } else if (_ut == utDel) { if (!_pactr->FDup(&pactrDup, fTrue)) { goto LFail; } pactrDup->SetArid(_pactr->Arid()); if (!_pmvie->Pscen()->FAddActrCore(pactrDup)) { ReleasePpo(&pactrDup); goto LFail; } _pmvie->Pscen()->SelectActr(pactrDup); ReleasePpo(&pactrDup); } else { Assert(_ut == utRep, "Bad Grf"); pactr = _pmvie->Pscen()->PactrFromArid(_pactr->Arid()); if (!pactr->FDup(&pactrDup, fTrue)) { goto LFail; } if (!_pmvie->Pscen()->FAddActrCore(_pactr)) { goto LFail; } _pmvie->Pscen()->SelectActr(_pactr); pactrDup->SetArid(_pactr->Arid()); ReleasePpo(&_pactr); SetActr(pactrDup); } _pmvie->Pmsq()->FlushMsq(); _pmvie->Pmcc()->UpdateRollCall(); return(fTrue); LFail: _pmvie->Pmsq()->FlushMsq(); _pmvie->ClearUndo(); return(fFalse); } #ifdef DEBUG /**************************************************** * Mark memory used by the SUNA * * Parameters: * None. * * Returns: * None. * ****************************************************/ void SUNA::MarkMem(void) { AssertThis(0); SUNA_PAR::MarkMem(); MarkMemObj(_pactr); } /*************************************************************************** Assert the validity of the SUNA. ***************************************************************************/ void SUNA::AssertValid(ulong grf) { AssertPo(_pactr, 0); } #endif /**************************************************** * * Public constructor for scene undo objects for text box * related commands. * * Parameters: * None. * * Returns: * pvNil if failure, else a pointer to the movie undo. * ****************************************************/ PSUNX SUNX::PsunxNew() { PSUNX psunx; psunx = NewObj SUNX(); return(psunx); } /**************************************************** * * Destructor for scene text box undo objects * ****************************************************/ SUNX::~SUNX(void) { AssertBaseThis(0); ReleasePpo(&_ptbox); } /**************************************************** * * Does a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNX::FDo(PDOCB pdocb) { AssertThis(0); PTBOX ptbox; if (!_pmvie->FSwitchScen(_iscen)) { goto LFail; } if (_fAdd) { if (!_pmvie->Pscen()->FGotoFrm(_nfrmFirst)) { goto LFail; } if (!_pmvie->Pscen()->FAddTboxCore(_ptbox)) { _pmvie->Pscen()->FGotoFrm(_nfrm); goto LFail; } if (_nfrmLast < _pmvie->Pscen()->NfrmLast()) { AssertDo(_ptbox->FGotoFrame(_nfrmLast + 1), "Should never fail"); _ptbox->HideCore(); } _pmvie->Pscen()->SelectTbox(_ptbox); if (_pmvie->Pscen()->FGotoFrm(_nfrm)) { // // Find the new itbox for this tbox. // for (_itbox = 0; ; _itbox++) { ptbox = _pmvie->Pscen()->PtboxFromItbox(_itbox); AssertPo(ptbox, 0); if (ptbox == _ptbox) { break; } } } } else { if (!_pmvie->Pscen()->FGotoFrm(_nfrm)) { goto LFail; } // // NOTE: ptbox may be different than _ptbox since // we may have switched away from the scene. // ptbox = _pmvie->Pscen()->PtboxFromItbox(_itbox); if (!_pmvie->Pscen()->FRemTboxCore(ptbox)) { goto LFail; } } _pmvie->Pmsq()->FlushMsq(); return(fTrue); LFail: _pmvie->Pmsq()->FlushMsq(); _pmvie->ClearUndo(); return(fFalse); } /**************************************************** * * Undoes a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNX::FUndo(PDOCB pdocb) { AssertThis(0); PTBOX ptbox; if (!_pmvie->FSwitchScen(_iscen)) { goto LFail; } if (_fAdd) { if (!_pmvie->Pscen()->FGotoFrm(_nfrm)) { goto LFail; } // // NOTE: ptbox may be different than _ptbox since // we may have switched away from the scene. // ptbox = _pmvie->Pscen()->PtboxFromItbox(_itbox); if (!_pmvie->Pscen()->FRemTboxCore(ptbox)) { ReleasePpo(&ptbox); goto LFail; } } else { if (!_pmvie->Pscen()->FGotoFrm(_nfrmFirst)) { goto LFail; } if (!_pmvie->Pscen()->FAddTboxCore(_ptbox)) { goto LFail; } if (_nfrmLast < _pmvie->Pscen()->NfrmLast()) { AssertDo(_ptbox->FGotoFrame(_nfrmLast + 1), "Should never fail"); _ptbox->HideCore(); } _pmvie->Pscen()->SelectTbox(_ptbox); if (_pmvie->Pscen()->FGotoFrm(_nfrm)) { // // Find the new itbox for this tbox. // for (_itbox = 0; ; _itbox++) { ptbox = _pmvie->Pscen()->PtboxFromItbox(_itbox); AssertPo(ptbox, 0); if (ptbox == _ptbox) { break; } } } } _pmvie->Pmsq()->FlushMsq(); return(fTrue); LFail: _pmvie->Pmsq()->FlushMsq(); _pmvie->ClearUndo(); return(fFalse); } #ifdef DEBUG /**************************************************** * Mark memory used by the SUNX * * Parameters: * None. * * Returns: * None. * ****************************************************/ void SUNX::MarkMem(void) { AssertThis(0); SUNX_PAR::MarkMem(); MarkMemObj(_ptbox); } /*************************************************************************** Assert the validity of the SUNX. ***************************************************************************/ void SUNX::AssertValid(ulong grf) { AssertPo(_ptbox, 0); } #endif /**************************************************** * * Public constructor for scene undo objects for transition * related commands. * * Parameters: * None. * * Returns: * pvNil if failure, else a pointer to the movie undo. * ****************************************************/ PSUNR SUNR::PsunrNew() { PSUNR psunr; psunr = NewObj SUNR(); return(psunr); } /**************************************************** * * Destructor for scene transition undo objects * ****************************************************/ SUNR::~SUNR(void) { AssertBaseThis(0); } /**************************************************** * * Does a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNR::FDo(PDOCB pdocb) { AssertThis(0); TRANS trans; if (!_pmvie->FSwitchScen(_iscen)) { goto LFail; } if (!_pmvie->Pscen()->FGotoFrm(_nfrm)) { goto LFail; } trans = _pmvie->Pscen()->Trans(); _pmvie->Pscen()->SetTransitionCore(_trans); _trans = trans; _pmvie->Pmsq()->FlushMsq(); return(fTrue); LFail: _pmvie->Pmsq()->FlushMsq(); _pmvie->ClearUndo(); return(fFalse); } /**************************************************** * * Undoes a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNR::FUndo(PDOCB pdocb) { AssertThis(0); return(FDo(pdocb)); } #ifdef DEBUG /**************************************************** * Mark memory used by the SUNR * * Parameters: * None. * * Returns: * None. * ****************************************************/ void SUNR::MarkMem(void) { AssertThis(0); SUNR_PAR::MarkMem(); } /*************************************************************************** Assert the validity of the SUNR. ***************************************************************************/ void SUNR::AssertValid(ulong grf) { } #endif /**************************************************** * * Public constructor for scene undo objects for pause * related commands. * * Parameters: * None. * * Returns: * pvNil if failure, else a pointer to the movie undo. * ****************************************************/ PSUNP SUNP::PsunpNew() { PSUNP psunp; psunp = NewObj SUNP(); return(psunp); } /**************************************************** * * Destructor for scene pause undo objects * ****************************************************/ SUNP::~SUNP(void) { AssertBaseThis(0); } /**************************************************** * * Does a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNP::FDo(PDOCB pdocb) { AssertThis(0); WIT wit = _wit; if (!_pmvie->FSwitchScen(_iscen)) { goto LFail; } if (!_pmvie->Pscen()->FGotoFrm(_nfrm)) { goto LFail; } if (!_pmvie->Pscen()->FPauseCore(&_wit, &_dts)) { goto LFail; } _pmvie->Pmcc()->PauseType(wit); _pmvie->Pmsq()->FlushMsq(); return(fTrue); LFail: _pmvie->Pmsq()->FlushMsq(); _pmvie->ClearUndo(); return(fFalse); } /**************************************************** * * Undoes a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNP::FUndo(PDOCB pdocb) { return(FDo(pdocb)); } #ifdef DEBUG /**************************************************** * Mark memory used by the SUNP * * Parameters: * None. * * Returns: * None. * ****************************************************/ void SUNP::MarkMem(void) { AssertThis(0); SUNP_PAR::MarkMem(); } /*************************************************************************** Assert the validity of the SUNP. ***************************************************************************/ void SUNP::AssertValid(ulong grf) { } #endif /**************************************************** * * Public constructor for scene undo objects for background * related commands. * * Parameters: * None. * * Returns: * pvNil if failure, else a pointer to the movie undo. * ****************************************************/ PSUNK SUNK::PsunkNew() { PSUNK psunk; psunk = NewObj SUNK(); return(psunk); } /**************************************************** * * Destructor for scene background undo objects * ****************************************************/ SUNK::~SUNK(void) { AssertBaseThis(0); } /**************************************************** * * Does a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNK::FDo(PDOCB pdocb) { AssertThis(0); TAG tagOld; long icamOld, icam; if (!_pmvie->FSwitchScen(_iscen)) { goto LFail; } if (_fSetBkgd) { if (_pmvie->Pscen()->Pbkgd() != pvNil) { icam = _pmvie->Pscen()->Pbkgd()->Icam(); } if (!_pmvie->Pscen()->FSetBkgdCore(&_tag, &tagOld)) { goto LFail; } if (!_pmvie->Pscen()->FChangeCamCore(_icam, &icamOld)) { goto LFail; } _tag = tagOld; _icam = icam; } else { if (!_pmvie->Pscen()->FGotoFrm(_nfrm)) { goto LFail; } if (!_pmvie->Pscen()->FChangeCamCore(_icam, &icamOld)) { goto LFail; } _icam = icamOld; } _pmvie->Pmsq()->FlushMsq(); return(fTrue); LFail: _pmvie->Pmsq()->FlushMsq(); _pmvie->ClearUndo(); return(fFalse); } /**************************************************** * * Undoes a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNK::FUndo(PDOCB pdocb) { AssertThis(0); return(FDo(pdocb)); } #ifdef DEBUG /**************************************************** * Mark memory used by the SUNK * * Parameters: * None. * * Returns: * None. * ****************************************************/ void SUNK::MarkMem(void) { AssertThis(0); SUNK_PAR::MarkMem(); } /*************************************************************************** Assert the validity of the SUNK. ***************************************************************************/ void SUNK::AssertValid(ulong grf) { } #endif /**************************************************** * * Public constructor for scene undo objects for background * chop commands. * * Parameters: * None. * * Returns: * pvNil if failure, else a pointer to the movie undo. * ****************************************************/ PSUNC SUNC::PsuncNew() { PSUNC psunc; psunc = NewObj SUNC(); return(psunc); } /**************************************************** * * Destructor for scene pause undo objects * ****************************************************/ SUNC::~SUNC(void) { AssertBaseThis(0); ReleasePpo(&_pcrf); } /**************************************************** * * This function saves away a copy of the scene. * * Parameters: * pscen - The scene to save away. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNC::FSave(PSCEN pscen) { PCFL pcfl; bool fRet; pcfl = CFL::PcflCreateTemp(); if (pcfl == pvNil) { return(fFalse); } _pcrf = CRF::PcrfNew(pcfl, 0); if (_pcrf == pvNil) { ReleasePpo(&pcfl); return(fFalse); } ReleasePpo(&pcfl); vpappb->BeginLongOp(); fRet = pscen->FWrite(_pcrf, &_cno); vpappb->EndLongOp(); return(fRet); } /**************************************************** * * Does a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNC::FDo(PDOCB pdocb) { AssertThis(0); PSCEN pscen; PSCEN pscenSave; vpappb->BeginLongOp(); pscen = SCEN::PscenRead(_pmvie, _pcrf, _cno); if (pscen == pvNil) { goto LFail; } if (!pscen->FPlayStartEvents()) { SCEN::Close(&pscen); goto LFail; } if (!_pmvie->FSwitchScen(_iscen)) { SCEN::Close(&pscen); goto LFail; } pscenSave = _pmvie->Pscen(); pscenSave->AddRef(); if (!_pmvie->FInsScenCore(_iscen, pscen)) { ReleasePpo(&pscenSave); SCEN::Close(&pscen); goto LFail; } SCEN::Close(&pscen); _pcrf->Pcfl()->Delete(kctgScen, _cno); pscenSave->SetNfrmCur(pscenSave->NfrmFirst() - 1); if (!pscenSave->FWrite(_pcrf, &_cno)) { _pmvie->FRemScenCore(_iscen + 1); SCEN::Close(&pscenSave); goto LFail; } SCEN::Close(&pscenSave); if (!_pmvie->FRemScenCore(_iscen + 1)) { goto LFail; } // // We don't care if we can't switch, everything was restored. // if (_pmvie->FSwitchScen(_iscen)) { _pmvie->Pscen()->FGotoFrm(_nfrm); _pmvie->InvalViewsAndScb(); } vpappb->EndLongOp(); return(fTrue); LFail: _pmvie->Pmsq()->FlushMsq(); _pmvie->ClearUndo(); vpappb->EndLongOp(); return(fFalse); } /**************************************************** * * Undoes a command stored in an undo object. * * Parameters: * None. * * Returns: * fTrue if successful, else fFalse. * ****************************************************/ bool SUNC::FUndo(PDOCB pdocb) { AssertThis(0); return(FDo(pdocb)); } #ifdef DEBUG /**************************************************** * Mark memory used by the SUNC * * Parameters: * None. * * Returns: * None. * ****************************************************/ void SUNC::MarkMem(void) { AssertThis(0); SUNC_PAR::MarkMem(); MarkMemObj(_pcrf); } /*************************************************************************** Assert the validity of the SUNC. ***************************************************************************/ void SUNC::AssertValid(ulong grf) { AssertNilOrPo(_pcrf, grf); } #endif /*************************************************************************** Static function to allocate a SSE with room for ctag TAGs. ***************************************************************************/ PSSE SSE::PsseNew(long ctag) { Assert(ctag > 0, 0); PSSE psse; if (!FAllocPv((void **)&psse, _Cb(ctag), fmemNil, mprNormal)) return pvNil; return psse; } /*************************************************************************** Creates a new SSE ***************************************************************************/ PSSE SSE::PsseNew(long vlm, long sty, bool fLoop, long ctagc, TAGC *prgtagc) { Assert(ctagc > 0, 0); AssertPvCb(prgtagc, LwMul(ctagc, size(TAGC))); PSSE psse; long itagc; psse = PsseNew(ctagc); if (pvNil == psse) return pvNil; psse->vlm = vlm; psse->sty = sty; psse->fLoop = fLoop; psse->ctagc = ctagc; for (itagc = 0; itagc < ctagc; itagc++) { *psse->Ptagc(itagc) = prgtagc[itagc]; TAGM::DupTag(psse->Ptag(itagc)); } return psse; } /*************************************************************************** Properly cleans up and frees a SSE ***************************************************************************/ void ReleasePpsse(PSSE *ppsse) { AssertVarMem(ppsse); if (*ppsse == pvNil) return; PSSE psse = *ppsse; long itagc; AssertIn(psse->ctagc, 0, 1000); // sanity check on ctagc AssertIn(psse->sty, styNil, styLim); for (itagc = 0; itagc < psse->ctagc; itagc++) { if (psse->Ptag(itagc)->pcrf != pvNil) TAGM::CloseTag(psse->Ptag(itagc)); } FreePpv((void **)ppsse); } /*************************************************************************** Static function to allocate and read a SSE from a GG. This is tricky because I can't do a pgg->Get() since the SSE is variable-sized, and I need to do QvGet twice since I'm allocating memory in this function. ***************************************************************************/ PSSE SSE::PsseDupFromGg(PGG pgg, long iv, bool fDupTags) { AssertPo(pgg, 0); AssertIn(iv, 0, pgg->IvMac()); Assert(pgg->Cb(iv) >= size(SSE), "variable part too small"); long ctagc; PSSE psse; long itagc; ctagc = ((PSSE)pgg->QvGet(iv))->ctagc; psse = PsseNew(ctagc); CopyPb(pgg->QvGet(iv), psse, _Cb(ctagc)); for (itagc = 0; itagc < psse->ctagc; itagc++) { if (fDupTags) { if (psse->Ptag(itagc)->sid == ksidUseCrf) { AssertPo(psse->Ptag(itagc)->pcrf, 0); TAGM::DupTag(psse->Ptag(itagc)); } } else { // Clear the crf on read, since the caller isn't having us dupe the tag psse->Ptag(itagc)->pcrf = pvNil; } } return psse; } /*************************************************************************** Returns a PSSE just like this SSE except with ptag & chid added ***************************************************************************/ PSSE SSE::PsseAddTagChid(PTAG ptag, long chid) { AssertVarMem(ptag); PSSE psseNew; TAGC tagc; tagc.tag = *ptag; tagc.chid = chid; psseNew = SSE::PsseNew(ctagc + 1); if (pvNil == psseNew) return pvNil; CopyPb(this, psseNew, Cb()); *psseNew->Ptagc(psseNew->ctagc) = tagc; psseNew->ctagc++; TAGM::DupTag(ptag); return psseNew; } /*************************************************************************** Return a duplicate of this SSE ***************************************************************************/ PSSE SSE::PsseDup(void) { PSSE psse; long itagc; if (!FAllocPv((void **)&psse, size(SSE) + LwMul(ctagc, size(TAGC)), fmemNil, mprNormal)) { return pvNil; } CopyPb(this, psse, size(SSE) + LwMul(ctagc, size(TAGC))); for (itagc = 0; itagc < psse->ctagc; itagc++) TAGM::DupTag(psse->Ptag(itagc)); return psse; } /*************************************************************************** Play all sounds in this SSE -> Enqueue the sounds in the SSE ***************************************************************************/ void SSE::PlayAllSounds(PMVIE pmvie, ulong dtsStart) { PMSND pmsnd; long itag; long tool = fLoop ? toolLooper : toolSounder; for (itag = 0; itag < ctagc; itag++) { if (Ptag(itag)->sid == ksidUseCrf) { if (!pmvie->FResolveSndTag(Ptag(itag), *Pchid(itag))) continue; } pmsnd = (PMSND)vptagm->PbacoFetch(Ptag(itag), MSND::FReadMsnd); if (pvNil == pmsnd) return; // Only queue if it's not the first sound; only start at dtsStart for first sound pmvie->Pmsq()->FEnqueue(pmsnd, 0, fLoop, (itag != 0), vlm, pmsnd->Spr(tool), fFalse, (itag == 0 ? dtsStart : 0)); ReleasePpo(&pmsnd); } }