Microsoft-3D-Movie-Maker/SRC/ENGINE/SCENE.CPP

7523 lines
135 KiB
C++

/* 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);
}
}