mirror of
https://github.com/microsoft/Microsoft-3D-Movie-Maker.git
synced 2024-11-27 13:43:03 +00:00
1617 lines
33 KiB
C++
1617 lines
33 KiB
C++
/* Copyright (c) Microsoft Corporation.
|
|
Licensed under the MIT License. */
|
|
|
|
/***************************************************************************
|
|
|
|
Actor Edit. Cut/Copy/Paste/Undo
|
|
|
|
Primary authors:
|
|
ACLP::(clipbd) Seanse
|
|
AUND::(undo) Seanse
|
|
ACTR::(undo) Seanse
|
|
ACTR::(vacuum) *****
|
|
ACTR::(dup/restore) *****
|
|
Review Status: Reviewed
|
|
|
|
***************************************************************************/
|
|
|
|
#include "soc.h"
|
|
|
|
ASSERTNAME
|
|
RTCLASS(AUND)
|
|
|
|
/***************************************************************************
|
|
|
|
Duplicate the actor from this frame through
|
|
the end of subroute or (if fEntireScene) the end of the scene
|
|
|
|
***************************************************************************/
|
|
bool ACTR::FCopy(PACTR *ppactr, bool fEntireScene)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(ppactr);
|
|
|
|
long iaev;
|
|
long iaevLast;
|
|
AEV aev;
|
|
AEVACTN aevactn;
|
|
AEVSND aevsnd;
|
|
RPT rpt;
|
|
RPT rptOld;
|
|
RPT *prptSrc;
|
|
RPT *prptDest;
|
|
|
|
(*ppactr) = PactrNew(&_tagTmpl);
|
|
|
|
if (*ppactr == pvNil)
|
|
{
|
|
return fFalse;
|
|
}
|
|
|
|
// If the current point is between nodes, a node will
|
|
// be inserted. Compute its dwr.
|
|
_pglrpt->Get(_rtelCur.irpt, &rpt);
|
|
rptOld.dwr = rpt.dwr;
|
|
rpt.dwr = BrsSub(rptOld.dwr, _rtelCur.dwrOffset);
|
|
|
|
//
|
|
// Gather all earlier events & move to the current one
|
|
// It is sufficient to begin with the current subroute
|
|
// Note: Add events will require later translation of nfrm
|
|
//
|
|
for (iaev = _iaevAddCur; iaev < _iaevCur; iaev++)
|
|
{
|
|
_pggaev->GetFixed(iaev, &aev);
|
|
|
|
//Is this an event we want to copy?
|
|
switch (aev.aet)
|
|
{
|
|
case aetActn: // Copy, editing current cel only
|
|
_pggaev->Get(iaev, &aevactn);
|
|
aevactn.celn = _celnCur;
|
|
break;
|
|
|
|
// copy
|
|
case aetAdd:
|
|
case aetCost:
|
|
case aetPull:
|
|
case aetSize:
|
|
case aetRotF:
|
|
case aetFreeze:
|
|
case aetStep:
|
|
case aetMove:
|
|
break;
|
|
|
|
// The following events are not automatically copied
|
|
case aetSnd:
|
|
_pggaev->Get(iaev, &aevsnd);
|
|
// Update the cno for the chid from the original movie
|
|
// The scene this came from may be lost later
|
|
if (!_pscen->Pmvie()->FResolveSndTag(&aevsnd.tag, aevsnd.chid))
|
|
{
|
|
goto LFail;
|
|
}
|
|
_pggaev->Put(iaev, &aevsnd);
|
|
if (aevsnd.celn == smmNil && iaev >= _iaevFrmMin)
|
|
break;
|
|
if (iaev > _iaevActnCur &&
|
|
aevsnd.celn != smmNil)
|
|
{
|
|
// Retain current motion match sounds
|
|
break;
|
|
}
|
|
continue;
|
|
case aetTweak:
|
|
case aetRotH:
|
|
#ifdef BUG1950
|
|
//REVIEW (*****): Postponed till v2.0
|
|
if (iaev >= _iaevCur) // Code change not yet verified
|
|
#else //!BUG1950
|
|
if (iaev >= _iaevFrmMin)
|
|
#endif //!BUG1950
|
|
{
|
|
// Retain these events from this frame
|
|
break;
|
|
}
|
|
continue;
|
|
case aetRem:
|
|
continue; // Do not copy
|
|
|
|
default:
|
|
Bug("Unknown event type... Copy or Not?");
|
|
break;
|
|
}
|
|
|
|
//set the event to happen right here.
|
|
aev.rtel.dnfrm = 0;
|
|
aev.rtel.irpt = 0;
|
|
aev.rtel.dwrOffset = 0;
|
|
iaevLast = (*ppactr)->_pggaev->IvMac();
|
|
|
|
// Insert aev. Tag ref count will be updated.
|
|
_pggaev->Lock();
|
|
if (!(*ppactr)->_FInsertAev(iaevLast,
|
|
_pggaev->Cb(iaev),
|
|
(aev.aet == aetActn) ? &aevactn : _pggaev->QvGet(iaev),
|
|
&aev,
|
|
fFalse))
|
|
{
|
|
_pggaev->Unlock();
|
|
goto LFail;
|
|
}
|
|
_pggaev->Unlock();
|
|
(*ppactr)->_MergeAev(0, iaevLast);
|
|
}
|
|
|
|
//
|
|
// Copy remaining events, adjusting their locations
|
|
//
|
|
for (iaev = _iaevCur; iaev < _pggaev->IvMac(); iaev++)
|
|
{
|
|
_pggaev->GetFixed(iaev, &aev);
|
|
|
|
if ((!fEntireScene) &&
|
|
(aetAdd == aev.aet) &&
|
|
(*ppactr)->_pggaev->IvMac() > 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//Adjust the event indicies.
|
|
aev.rtel.irpt -= _rtelCur.irpt;
|
|
|
|
if (aev.rtel.irpt == 0)
|
|
{
|
|
if (aev.rtel.dwrOffset == _rtelCur.dwrOffset)
|
|
{
|
|
aev.rtel.dwrOffset = rZero;
|
|
if (aev.rtel.dnfrm < _rtelCur.dnfrm)
|
|
{
|
|
aev.rtel.dnfrm = 0;
|
|
}
|
|
else
|
|
{
|
|
aev.rtel.dnfrm -= _rtelCur.dnfrm;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (rpt.dwr == rZero)
|
|
aev.rtel.dwrOffset = rZero;
|
|
else
|
|
{
|
|
aev.rtel.dwrOffset = BrsSub(aev.rtel.dwrOffset, _rtelCur.dwrOffset);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Insert will update the tag ref count
|
|
iaevLast = (*ppactr)->_pggaev->IvMac();
|
|
_pggaev->Lock();
|
|
if (!(*ppactr)->_FInsertAev(iaevLast,
|
|
_pggaev->Cb(iaev), _pggaev->QvGet(iaev), &aev, fFalse))
|
|
{
|
|
_pggaev->Unlock();
|
|
goto LFail;
|
|
}
|
|
_pggaev->Unlock();
|
|
}
|
|
|
|
//
|
|
// Add the point we are at.
|
|
//
|
|
if (!(*ppactr)->_pglrpt->FInsert(0, &rpt))
|
|
{
|
|
goto LFail;
|
|
}
|
|
|
|
//
|
|
// Copy the rest of the subroute or route
|
|
//
|
|
if ((_rtelCur.irpt + 1) < _pglrpt->IvMac())
|
|
{
|
|
// Locate the amount of route to copy
|
|
//
|
|
long irptLim = _pglrpt->IvMac();
|
|
long irpt;
|
|
|
|
if (!fEntireScene)
|
|
{
|
|
for (irpt = _rtelCur.irpt; irpt < irptLim; irpt++)
|
|
{
|
|
_pglrpt->Get(irpt, &rpt);
|
|
if (rZero == rpt.dwr)
|
|
{
|
|
irptLim = irpt + 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!(*ppactr)->_pglrpt->FSetIvMac((*ppactr)->_pglrpt->IvMac() +
|
|
irptLim - (_rtelCur.irpt + 1)))
|
|
{
|
|
goto LFail;
|
|
}
|
|
|
|
prptSrc = (RPT *)_pglrpt->QvGet(_rtelCur.irpt + 1);
|
|
prptDest = (RPT *)(*ppactr)->_pglrpt->QvGet(1);
|
|
CopyPb(prptSrc, prptDest,
|
|
LwMul(irptLim - (_rtelCur.irpt + 1), size(RPT)));
|
|
}
|
|
else
|
|
{
|
|
// Mark the end of the path
|
|
rpt.dwr = rZero;
|
|
(*ppactr)->_pglrpt->Put(0,&rpt);
|
|
}
|
|
|
|
(*ppactr)->_SetStateRewound();
|
|
|
|
AssertPo(*ppactr, 0);
|
|
return fTrue;
|
|
|
|
LFail:
|
|
ReleasePpo(ppactr);
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Duplicate the entire actor from *this onto *ppactr
|
|
This is not from this frame on. The entire actor is duplicated.
|
|
This does not duplicate the Brender body.
|
|
Default is fReset = fFalse;
|
|
|
|
NOTE:
|
|
Upon exit, the new actor will still be in the scene.
|
|
If (!fReset), all state information will have been retained.
|
|
|
|
***************************************************************************/
|
|
bool ACTR::FDup(PACTR *ppactr, bool fReset)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(ppactr);
|
|
|
|
long cactRef;
|
|
PACTR pactrSrc = this;
|
|
PACTR pactrDest;
|
|
|
|
// Due to state var duplication, using NewObj, not PactrNew
|
|
pactrDest = (*ppactr) = NewObj ACTR();
|
|
if (*ppactr == pvNil)
|
|
{
|
|
return fFalse;
|
|
}
|
|
|
|
// AddRef only if attached to a scene
|
|
if (pvNil != _pbody)
|
|
_pbody->AddRef();
|
|
_ptmpl->AddRef();
|
|
TAGM::DupTag(&_tagTmpl);
|
|
|
|
// Copy over all members
|
|
// Note that both copies will point to the same *_pbody & *_ptmpl
|
|
cactRef = pactrDest->_cactRef;
|
|
*(pactrDest) = *pactrSrc;
|
|
pactrDest->_cactRef = cactRef;
|
|
pactrDest->_fTimeFrozen = fFalse;
|
|
|
|
if (!pactrDest->_FCreateGroups())
|
|
{
|
|
goto LFail;
|
|
}
|
|
|
|
if (!_FDupCopy(pactrSrc, pactrDest))
|
|
{
|
|
goto LFail;
|
|
}
|
|
|
|
if (fReset)
|
|
{
|
|
(*ppactr)->Reset();
|
|
}
|
|
return fTrue;
|
|
|
|
LFail:
|
|
ReleasePpo(ppactr);
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Restore the actor from *ppactr onto *this
|
|
|
|
***************************************************************************/
|
|
void ACTR::Restore(PACTR pactr)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pactr);
|
|
|
|
long cactRef;
|
|
PACTR pactrSrc = pactr;
|
|
PACTR pactrDest = this;
|
|
|
|
Assert(pactr->_ptmpl == _ptmpl, "Restore ptmpl logic error");
|
|
Assert(pactr->_pbody == _pbody, "Restore pbody logic error");
|
|
|
|
// Copy over all members
|
|
// Note that both copies will point to the same *_pbody & *_ptmpl
|
|
cactRef = pactrDest->_cactRef;
|
|
PGG pggaev = pactrDest->_pggaev;
|
|
PGL pglrpt = pactrDest->_pglrpt;
|
|
PGL pglsmm = pactrDest->_pglsmm;
|
|
*(pactrDest) = *pactrSrc;
|
|
pactrDest->_cactRef = cactRef;
|
|
pactrDest->_pggaev = pggaev;
|
|
pactrDest->_pglrpt = pglrpt;
|
|
pactrDest->_pglsmm = pglsmm;
|
|
|
|
// Swap the gl and gg structures
|
|
SwapVars(&pactrSrc->_pggaev, &pactrDest->_pggaev);
|
|
SwapVars(&pactrSrc->_pglrpt, &pactrDest->_pglrpt);
|
|
SwapVars(&pactrSrc->_pglsmm, &pactrDest->_pglsmm);
|
|
|
|
pactr->_pscen->Pmvie()->InvalViews();
|
|
|
|
return;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
Restore this actor from an undo object pactrRestore.
|
|
|
|
***************************************************************************/
|
|
void ACTR::_RestoreFromUndo(PACTR pactrRestore)
|
|
{
|
|
AssertBaseThis(0);
|
|
AssertVarMem(pactrRestore);
|
|
Assert(pactrRestore->_pbody == pvNil, "Not restoring from undo object");
|
|
|
|
long nfrmCur = _nfrmCur;
|
|
PSCEN pscen = pactrRestore->_pscen;
|
|
|
|
// Modify pactrRestore for Restore()
|
|
pactrRestore->_pbody = _pbody;
|
|
pactrRestore->_pscen = _pscen;
|
|
_Hide(); // Added actor will show
|
|
Restore(pactrRestore);
|
|
|
|
// Restore pactrRestore to be unmodified
|
|
pactrRestore->_pbody = pvNil;
|
|
pactrRestore->_pscen = pscen;
|
|
|
|
FGotoFrame(nfrmCur); // No further recovery meaningful
|
|
_pscen->Pmvie()->InvalViews();
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
Copy the GG and GL structures for actor duplication/restoration
|
|
|
|
NOTE:
|
|
This is not from this frame on. The entire actor is duplicated.
|
|
|
|
***************************************************************************/
|
|
bool ACTR::_FDupCopy(PACTR pactrSrc, PACTR pactrDest)
|
|
{
|
|
AssertBaseThis(0);
|
|
AssertPo(pactrDest->_pggaev, 0);
|
|
AssertPo(pactrDest->_pglrpt, 0);
|
|
|
|
RPT *prptSrc;
|
|
RPT *prptDest;
|
|
SMM *psmmSrc;
|
|
SMM *psmmDest;
|
|
|
|
//
|
|
// Copy all events.
|
|
//
|
|
if (!pactrDest->_pggaev->FCopyEntries(pactrSrc->_pggaev, 0, 0,
|
|
pactrSrc->_pggaev->IvMac()))
|
|
{
|
|
goto LFail;
|
|
}
|
|
|
|
{
|
|
_pggaev->Lock();
|
|
for (long iaev = 0; iaev < _pggaev->IvMac(); iaev++)
|
|
{
|
|
PTAG ptag;
|
|
|
|
if (_FIsIaevTag(_pggaev, iaev, &ptag))
|
|
TAGM::DupTag(ptag);
|
|
}
|
|
_pggaev->Unlock();
|
|
}
|
|
|
|
//
|
|
// Copy Route
|
|
//
|
|
if (pactrSrc->_pglrpt->IvMac() > 0)
|
|
{
|
|
if (!pactrDest->_pglrpt->FSetIvMac(pactrSrc->_pglrpt->IvMac()))
|
|
{
|
|
goto LFail;
|
|
}
|
|
|
|
prptSrc = (RPT *)pactrSrc->_pglrpt->QvGet(0);
|
|
prptDest = (RPT *)pactrDest->_pglrpt->QvGet(0);
|
|
CopyPb(prptSrc, prptDest, LwMul(pactrSrc->_pglrpt->IvMac(), size(RPT)));
|
|
}
|
|
|
|
//
|
|
// Copy Smm
|
|
//
|
|
if (pactrSrc->_pglsmm->IvMac() > 0)
|
|
{
|
|
if (!pactrDest->_pglsmm->FSetIvMac(pactrSrc->_pglsmm->IvMac()))
|
|
{
|
|
goto LFail;
|
|
}
|
|
|
|
psmmSrc = (SMM *)pactrSrc->_pglsmm->QvGet(0);
|
|
psmmDest = (SMM *)pactrDest->_pglsmm->QvGet(0);
|
|
CopyPb(psmmSrc, psmmDest, LwMul(pactrSrc->_pglsmm->IvMac(), size(SMM)));
|
|
}
|
|
|
|
return fTrue;
|
|
|
|
LFail:
|
|
if (this != pactrDest)
|
|
ReleasePpo(&pactrDest);
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Duplicate the indicated portion of the route from this frame on
|
|
from actor "this" to actor *ppactr.
|
|
Note **: The point on the route may not land on a node. If between
|
|
nodes, insert a point to make the two route sections identical.
|
|
|
|
***************************************************************************/
|
|
bool ACTR::FCopyRte(PACTR *ppactr, bool fEntireScene)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(ppactr);
|
|
|
|
long irpt;
|
|
long dnrpt;
|
|
long irptLim;
|
|
RPT rpt;
|
|
RPT rpt1;
|
|
RPT rptNode;
|
|
|
|
(*ppactr) = PactrNew(&_tagTmpl);
|
|
if (*ppactr == pvNil)
|
|
{
|
|
return fFalse;
|
|
}
|
|
|
|
//
|
|
// Insert the current point
|
|
//
|
|
_GetXyzFromRtel(&_rtelCur, &rpt.xyz);
|
|
_pglrpt->Get(_rtelCur.irpt, &rptNode);
|
|
rpt.dwr = rZero;
|
|
|
|
if (_rtelCur.dwrOffset == rZero)
|
|
{
|
|
rpt.dwr = rptNode.dwr;
|
|
}
|
|
else if (rptNode.dwr > rZero && _rtelCur.irpt < _pglrpt->IvMac() - 1)
|
|
{
|
|
_pglrpt->Get(_rtelCur.irpt + 1, &rpt1);
|
|
rpt.dwr = BR_LENGTH3(BrsSub(rpt1.xyz.dxr, rpt.xyz.dxr),
|
|
BrsSub(rpt1.xyz.dyr, rpt.xyz.dyr),
|
|
BrsSub(rpt1.xyz.dzr, rpt.xyz.dzr));
|
|
if (rZero == rpt.dwr)
|
|
{
|
|
rpt.dwr = rEps; //Epsilon. Prevent pathological incorrect end-of-path
|
|
}
|
|
}
|
|
|
|
if (!(*ppactr)->_pglrpt->FInsert(0, &rpt))
|
|
{
|
|
goto LFail;
|
|
}
|
|
|
|
if ((!fEntireScene) && rpt.dwr == rZero)
|
|
{
|
|
goto LEnd;
|
|
}
|
|
|
|
//
|
|
// If copying subroute only, determine amount to copy
|
|
//
|
|
irptLim = _pglrpt->IvMac();
|
|
if (!fEntireScene)
|
|
{
|
|
for (irpt = _rtelCur.irpt + 1; irpt < irptLim; irpt++)
|
|
{
|
|
_pglrpt->Get(irpt, &rpt);
|
|
if (rZero == rpt.dwr)
|
|
{
|
|
irptLim = irpt + 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copy indicated portion of the route
|
|
//
|
|
dnrpt = irptLim - (_rtelCur.irpt + 1);
|
|
if (dnrpt > 0 && !(*ppactr)->_pglrpt->FEnsureSpace(dnrpt, fgrpNil))
|
|
goto LFail;
|
|
|
|
for (irpt = _rtelCur.irpt + 1; irpt < irptLim; irpt++)
|
|
{
|
|
_pglrpt->Get(irpt, &rpt);
|
|
|
|
if (!(*ppactr)->_pglrpt->FInsert(irpt - _rtelCur.irpt, &rpt))
|
|
{
|
|
goto LFail;
|
|
}
|
|
|
|
if ((!fEntireScene) && (rZero == rpt.dwr))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
LEnd:
|
|
(*ppactr)->_SetStateRewound();
|
|
return fTrue;
|
|
|
|
LFail:
|
|
ReleasePpo(ppactr);
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Paste the rte from the clipboard pactr to the current actor's current
|
|
frame onward.
|
|
On failure, unwinding is expected to be via the dup'd actor from undo.
|
|
This overwrites the end of the current subroute.
|
|
NOTE: To be meaningful, the pasted route section is translated to
|
|
extend from the current point.
|
|
|
|
***************************************************************************/
|
|
bool ACTR::FPasteRte(PACTR pactr)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pactr);
|
|
|
|
AEV aev;
|
|
RPT rpt;
|
|
RPT rptCur;
|
|
XYZ dxyz;
|
|
long iaev;
|
|
long irpt;
|
|
#ifdef STATIC
|
|
bool fStatic;
|
|
#endif //STATIC
|
|
long crptDel = 0;
|
|
long crptNew = pactr->_pglrpt->IvMac() - 1;
|
|
|
|
if (crptNew <= 0)
|
|
{
|
|
PushErc(ercSocNothingToPaste);
|
|
return fFalse;
|
|
}
|
|
|
|
if (!_pglrpt->FEnsureSpace(crptNew, fgrpNil) ||
|
|
!_pggaev->FEnsureSpace( 1, kcbVarStep, fgrpNil))
|
|
{
|
|
return fFalse;
|
|
}
|
|
|
|
//
|
|
// May be positioned between nodes -> potentially
|
|
// insert the current point
|
|
//
|
|
_GetXyzFromRtel(&_rtelCur, &rptCur.xyz);
|
|
if (rZero != _rtelCur.dwrOffset)
|
|
{
|
|
BRS dwrCur = _rtelCur.dwrOffset;
|
|
_rtelCur.irpt++;
|
|
_rtelCur.dwrOffset = rZero;
|
|
_rtelCur.dnfrm = 0;
|
|
if (!_FInsertGgRpt(_rtelCur.irpt, &rptCur, dwrCur))
|
|
return fFalse;
|
|
_GetXyzFromRtel(&_rtelCur, &_xyzCur);
|
|
_AdjustAevForRteIns(_rtelCur.irpt, 0);
|
|
}
|
|
|
|
//
|
|
// Delete to the end of this *sub*route
|
|
//
|
|
for (irpt = _rtelCur.irpt + 1; irpt < _pglrpt->IvMac(); irpt++)
|
|
{
|
|
_pglrpt->Get(irpt, &rpt);
|
|
crptDel++;
|
|
if (rpt.dwr == rZero)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (crptDel > 0)
|
|
{
|
|
_pglrpt->Delete(_rtelCur.irpt, crptDel);
|
|
}
|
|
|
|
//
|
|
// Remove events until the end of the *sub*route
|
|
// Space optimization: should precede paste
|
|
// Update location pointer of events of later subroutes
|
|
//
|
|
for (iaev = _iaevCur; iaev < _pggaev->IvMac(); iaev++)
|
|
{
|
|
_pggaev->GetFixed(iaev, &aev);
|
|
if (aev.rtel.irpt > _rtelCur.irpt + crptDel)
|
|
{
|
|
aev.rtel.irpt += crptNew - crptDel;
|
|
_pggaev->PutFixed(iaev, &aev);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
_RemoveAev(iaev, fFalse);
|
|
iaev--;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Paste in the new route.
|
|
// Translate the points of this section of route
|
|
// Adjust the aev presently
|
|
//
|
|
pactr->_pglrpt->Get(0, &rpt);
|
|
dxyz.dxr = BrsSub(rptCur.xyz.dxr, rpt.xyz.dxr);
|
|
dxyz.dyr = BrsSub(rptCur.xyz.dyr, rpt.xyz.dyr);
|
|
dxyz.dzr = BrsSub(rptCur.xyz.dzr, rpt.xyz.dzr);
|
|
for (irpt = 1; irpt <= crptNew; irpt++)
|
|
{
|
|
pactr->_pglrpt->Get(irpt, &rpt);
|
|
rpt.xyz.dxr = BrsAdd(rpt.xyz.dxr, dxyz.dxr);
|
|
rpt.xyz.dyr = BrsAdd(rpt.xyz.dyr, dxyz.dyr);
|
|
rpt.xyz.dzr = BrsAdd(rpt.xyz.dzr, dxyz.dzr);
|
|
AssertDo(_pglrpt->FInsert(_rtelCur.irpt + irpt, &rpt), "Logic error");
|
|
}
|
|
|
|
//
|
|
// Set the right dwr distance from the current point to
|
|
// the first point on the new section of route
|
|
//
|
|
_pglrpt->Get(_rtelCur.irpt + 1, &rpt);
|
|
rptCur.dwr = BR_LENGTH3(BrsSub(rpt.xyz.dxr, rptCur.xyz.dxr),
|
|
BrsSub(rpt.xyz.dyr, rptCur.xyz.dyr),
|
|
BrsSub(rpt.xyz.dzr, rptCur.xyz.dzr));
|
|
if (rZero == rptCur.dwr)
|
|
rptCur.dwr = rEps; //Epsilon. Prevent pathological incorrect end-of-path
|
|
_pglrpt->Put(_rtelCur.irpt, &rptCur);
|
|
|
|
#ifdef STATIC
|
|
//
|
|
// Force floating behavior on a static action
|
|
//
|
|
Assert(_iaevActnCur >= 0, "Actor has no action");
|
|
if (!_FGetStatic(_anidCur, &fStatic))
|
|
return fFalse;
|
|
if (fStatic)
|
|
{
|
|
if (!FSetStep(kdwrNil))
|
|
return fFalse;
|
|
}
|
|
#else //!STATIC
|
|
// Force continuation onto newly pasted path
|
|
if (!FSetStep(kdwrNil))
|
|
return fFalse;
|
|
#endif //!STATIC
|
|
|
|
//
|
|
// Set new end of path freeze & step events
|
|
//
|
|
long faevfrz = (long)fTrue;
|
|
BRS dwrStep = rZero;
|
|
aev.aet = aetFreeze;
|
|
aev.rtel.irpt = _rtelCur.irpt + crptNew;
|
|
aev.rtel.dnfrm = 0;
|
|
aev.rtel.dwrOffset = rZero;
|
|
aev.nfrm = _nfrmCur; //will be updated in ComputeLifetime()
|
|
if (!_FInsertAev(_iaevCur, kcbVarFreeze, &faevfrz, &aev))
|
|
return fFalse;
|
|
aev.aet = aetStep;
|
|
if (!_FInsertAev(_iaevCur, kcbVarStep, &dwrStep, &aev))
|
|
return fFalse;
|
|
|
|
_fLifeDirty = fTrue;
|
|
_pscen->InvalFrmRange();
|
|
_pscen->MarkDirty();
|
|
|
|
_PositionBody(&_xyzCur);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Put an already existing actor in this scene.
|
|
|
|
***************************************************************************/
|
|
bool ACTR::FPaste(long nfrm, SCEN *pscen)
|
|
{
|
|
AssertThis(0);
|
|
|
|
AEV aev;
|
|
RPT rpt;
|
|
AEVADD aevadd;
|
|
AEVSND aevsnd;
|
|
BRS xrCam = rZero;
|
|
BRS yrCam = rZero;
|
|
BRS zrCam = kzrDefault;
|
|
BRS xr, yr, zr;
|
|
long iaev;
|
|
long dnfrm;
|
|
#ifdef BUG1888
|
|
PTMPL ptmpl;
|
|
PCRF pcrf;
|
|
TAG tag;
|
|
|
|
//
|
|
// Ensure that the tag to the TDT being pasted is in the current movie.
|
|
//
|
|
if (FIsTdt())
|
|
{
|
|
Assert(_tagTmpl.sid == ksidUseCrf, "TDTs should be stored in a document!");
|
|
|
|
if (!pscen->Pmvie()->FEnsureAutosave(&pcrf))
|
|
{
|
|
return fFalse;
|
|
}
|
|
if (pcrf != _tagTmpl.pcrf)
|
|
{
|
|
// Need to save this actor's tagTmpl in this movie because it came from another movie
|
|
|
|
tag = _tagTmpl;
|
|
TAGM::DupTag(&tag);
|
|
// Save the tag to the movie's _pcrfAutosave. The tag now
|
|
// points to the copy in this movie.
|
|
if (!TAGM::FSaveTag(&tag, pcrf, fTrue))
|
|
{
|
|
TAGM::CloseTag(&tag);
|
|
return fFalse;
|
|
}
|
|
// Get a template based on the new tag
|
|
ptmpl = (PTMPL)vptagm->PbacoFetch(&tag, TMPL::FReadTmpl);
|
|
if (pvNil == ptmpl)
|
|
{
|
|
TAGM::CloseTag(&tag);
|
|
return fFalse;
|
|
}
|
|
// Change the actor to use the new tag and template
|
|
TAGM::CloseTag(&_tagTmpl);
|
|
_tagTmpl = tag;
|
|
ReleasePpo(&_ptmpl);
|
|
_ptmpl = ptmpl;
|
|
}
|
|
}
|
|
#endif //BUG1888
|
|
|
|
//
|
|
// Update lifetime
|
|
//
|
|
_nfrmFirst = nfrm;
|
|
_fLifeDirty = fTrue;
|
|
_nfrmCur = nfrm - 1;
|
|
SetPscen(pscen);
|
|
|
|
// Always place actors on the "floor"
|
|
_GetNewOrigin(&xr, &yr, &zr);
|
|
|
|
Assert(_pggaev->IvMac() > 0, "Nothing to paste!");
|
|
_pggaev->GetFixed(0, &aev);
|
|
if (aev.aet != aetAdd)
|
|
return fFalse;
|
|
dnfrm = aev.nfrm - nfrm;
|
|
|
|
//
|
|
// Begin by locating the actor at (xr,yr,zr)
|
|
// There are no Full path or Sub path translations at this point.
|
|
// Note: In order to place a pasted actor at the insertion point,
|
|
// the translation needs to compensate for the distance
|
|
// recorded in each path point -> subtract the first path point.
|
|
_pglrpt->Get(0, &rpt);
|
|
_dxyzSubRte.dxr = rZero;
|
|
_dxyzSubRte.dyr = rZero;
|
|
_dxyzSubRte.dzr = rZero;
|
|
_dxyzFullRte.dxr = BrsSub(xr, rpt.xyz.dxr);
|
|
_dxyzFullRte.dyr = BrsSub(yr, rpt.xyz.dyr);
|
|
_dxyzFullRte.dzr = BrsSub(zr, rpt.xyz.dzr);
|
|
_pggaev->Get(0, &aevadd);
|
|
_dxyzFullRte.dxr = BrsSub(_dxyzFullRte.dxr, aevadd.dxr);
|
|
_dxyzFullRte.dyr = BrsSub(_dxyzFullRte.dyr, aevadd.dyr);
|
|
_dxyzFullRte.dzr = BrsSub(_dxyzFullRte.dzr, aevadd.dzr);
|
|
|
|
//
|
|
// Translate the new actor in time
|
|
// Update sound events
|
|
for (iaev = 0; iaev < _pggaev->IvMac(); iaev++)
|
|
{
|
|
_pggaev->GetFixed(iaev, &aev);
|
|
if (dnfrm != 0)
|
|
{
|
|
aev.nfrm -= dnfrm;
|
|
_pggaev->PutFixed(iaev, &aev);
|
|
}
|
|
if (aetSnd != aev.aet)
|
|
continue;
|
|
_pggaev->Get(iaev, &aevsnd);
|
|
if (aevsnd.tag.sid != ksidUseCrf)
|
|
continue;
|
|
// Save tag (this may be a new movie)
|
|
if (!aevsnd.tag.pcrf->Pcfl()->FFind(aevsnd.tag.ctg, aevsnd.tag.cno))
|
|
{
|
|
PushErc(ercSocNoSndOnPaste);
|
|
_RemoveAev(iaev);
|
|
iaev--;
|
|
continue;
|
|
}
|
|
if (!_pscen->Pmvie()->FSaveTagSnd(&aevsnd.tag))
|
|
{
|
|
Bug("Expected to locate user sound chunk");
|
|
_RemoveAev(iaev);
|
|
iaev--;
|
|
}
|
|
else
|
|
{
|
|
// Adopt this sound into the new scene
|
|
if (!_pscen->Pmvie()->FChidFromUserSndCno(aevsnd.tag.cno, &aevsnd.chid))
|
|
return fFalse;
|
|
// Update event
|
|
_pggaev->Put(iaev, &aevsnd);
|
|
}
|
|
}
|
|
|
|
// Rotate 3D spletters to face the camera
|
|
if (_ptmpl->FIsTdt())
|
|
{
|
|
_pggaev->Get(0, &aevadd);
|
|
aevadd.ya = _pscen->Pbkgd()->BraRotYCamera();
|
|
_pggaev->Put(0, &aevadd);
|
|
}
|
|
|
|
_UpdateXyzRte();
|
|
_pscen->MarkDirty();
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Make an actor look like they were just read in, and never in a scene.
|
|
|
|
***************************************************************************/
|
|
void ACTR::Reset(void)
|
|
{
|
|
_pscen = pvNil;
|
|
ReleasePpo(&_pbody); // Sets _pbody = pvNil
|
|
_nfrmCur = knfrmInvalid;
|
|
|
|
_InitState();
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
// BEGIN CLIPBOARD STUFF
|
|
//
|
|
//
|
|
//
|
|
//
|
|
|
|
RTCLASS(ACLP)
|
|
|
|
/***************************************************************************
|
|
|
|
Create an actor clipboard object
|
|
This is from the current frame forward
|
|
|
|
***************************************************************************/
|
|
PACLP ACLP::PaclpNew(PACTR pactr, bool fRteOnly, bool fEntireScene)
|
|
{
|
|
AssertPo(pactr, 0);
|
|
Assert(!fRteOnly || !fEntireScene, "Expecting subroute only");
|
|
|
|
PACLP paclp;
|
|
PACTR pactrTmp;
|
|
STN stn, stnCopyOf;
|
|
|
|
paclp = NewObj ACLP();
|
|
|
|
if (paclp == pvNil)
|
|
{
|
|
return(pvNil);
|
|
}
|
|
|
|
if (fRteOnly)
|
|
{
|
|
if (!pactr->FCopyRte(&pactrTmp, fEntireScene))
|
|
{
|
|
ReleasePpo(&paclp);
|
|
return(pvNil);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!pactr->FCopy(&pactrTmp, fEntireScene))
|
|
{
|
|
ReleasePpo(&paclp);
|
|
return(pvNil);
|
|
}
|
|
AssertPo(pactrTmp, 0);
|
|
|
|
pactr->GetName(&stn);
|
|
|
|
pactr->Pscen()->Pmvie()->Pmcc()->GetStn(idsEngineCopyOf, &stnCopyOf);
|
|
|
|
if (!FEqualRgb(stn.Psz(), stnCopyOf.Psz(), CchSz(stnCopyOf.Psz()) * size(achar)))
|
|
{
|
|
paclp->_stnName = stnCopyOf;
|
|
if (!paclp->_stnName.FAppendCh(kchSpace) || !paclp->_stnName.FAppendStn(&stn))
|
|
{
|
|
PushErc(ercSocNameTooLong);
|
|
ReleasePpo(&paclp);
|
|
return(pvNil);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
paclp->_stnName = stn;
|
|
}
|
|
|
|
}
|
|
|
|
paclp->_pactr = pactrTmp;
|
|
paclp->_fRteOnly = fRteOnly;
|
|
AssertPo(paclp, 0);
|
|
|
|
return(paclp);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
Destroys an actor clipboard object
|
|
|
|
***************************************************************************/
|
|
ACLP::~ACLP(void)
|
|
{
|
|
ReleasePpo(&_pactr);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
Pastes an actor clipboard object
|
|
|
|
***************************************************************************/
|
|
bool ACLP::FPaste(PMVIE pmvie)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pmvie, 0);
|
|
|
|
PACTR pactrNew;
|
|
|
|
if (_fRteOnly)
|
|
{
|
|
return (pmvie->FPasteActrPath(_pactr));
|
|
}
|
|
|
|
//
|
|
// Duplicate the actor
|
|
//
|
|
if (!_pactr->FDup(&pactrNew, fTrue))
|
|
{
|
|
return(fFalse);
|
|
}
|
|
AssertPo(pactrNew, 0);
|
|
|
|
if (!pmvie->FPasteActr(pactrNew))
|
|
{
|
|
ReleasePpo(&pactrNew);
|
|
return(fFalse);
|
|
}
|
|
|
|
if (!pmvie->FNameActr(pactrNew->Arid(), &_stnName))
|
|
{
|
|
pmvie->Pscen()->RemActrCore(pactrNew->Arid());
|
|
ReleasePpo(&pactrNew);
|
|
return(fFalse);
|
|
}
|
|
|
|
ReleasePpo(&pactrNew);
|
|
return(fTrue);
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
/****************************************************
|
|
* Mark memory used by the ACLP
|
|
*
|
|
* Parameters:
|
|
* None.
|
|
*
|
|
* Returns:
|
|
* None.
|
|
*
|
|
****************************************************/
|
|
void ACLP::MarkMem(void)
|
|
{
|
|
ACLP_PAR::MarkMem();
|
|
MarkMemObj(_pactr);
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Assert the validity of the ACLP
|
|
*
|
|
* Parameters:
|
|
* grf - bit array of options
|
|
*
|
|
* Returns:
|
|
* None.
|
|
*
|
|
**************************************************************************/
|
|
void ACLP::AssertValid(ulong grf)
|
|
{
|
|
ACLP_PAR::AssertValid(fobjAllocated);
|
|
_pactr->AssertValid(grf);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Create an undo object
|
|
|
|
***************************************************************************/
|
|
bool ACTR::FCreateUndo(PACTR pactrDup, bool fSndUndo, PSTN pstn)
|
|
{
|
|
AssertPo(pactrDup, 0);
|
|
AssertNilOrPo(pstn, 0);
|
|
|
|
PAUND paund;
|
|
|
|
paund = AUND::PaundNew();
|
|
|
|
if (paund == pvNil)
|
|
{
|
|
return fFalse;
|
|
}
|
|
|
|
paund->SetPactr(pactrDup);
|
|
paund->SetArid(_arid);
|
|
paund->SetSndUndo(fSndUndo);
|
|
if (pvNil != pstn)
|
|
paund->SetStn(pstn);
|
|
|
|
if (!_pscen->Pmvie()->FAddUndo(paund))
|
|
{
|
|
_pscen->Pmvie()->ClearUndo();
|
|
ReleasePpo(&paund);
|
|
return(fFalse);
|
|
}
|
|
|
|
ReleasePpo(&paund);
|
|
|
|
//
|
|
// Detach from the scene
|
|
//
|
|
pactrDup->Reset();
|
|
|
|
return(fTrue);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Add (or replace) an action, and create an undo object
|
|
|
|
***************************************************************************/
|
|
bool ACTR::FSetAction(long anid, long celn, bool fFreeze, PACTR *ppactrDup)
|
|
{
|
|
AssertThis(0);
|
|
AssertNilOrVarMem(ppactrDup);
|
|
|
|
PACTR pactrDup;
|
|
|
|
if (!FDup(&pactrDup))
|
|
{
|
|
return(fFalse);
|
|
}
|
|
|
|
if (!FSetActionCore(anid, celn, fFreeze))
|
|
{
|
|
Restore(pactrDup);
|
|
ReleasePpo(&pactrDup);
|
|
return fFalse;
|
|
}
|
|
|
|
if (!FCreateUndo(pactrDup))
|
|
{
|
|
Restore(pactrDup);
|
|
ReleasePpo(&pactrDup);
|
|
return(fFalse);
|
|
}
|
|
|
|
if (pvNil == ppactrDup)
|
|
ReleasePpo(&pactrDup);
|
|
else
|
|
*ppactrDup = pactrDup;
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Add the event to the event list: Add actor on the stage, and create undo
|
|
object.
|
|
|
|
***************************************************************************/
|
|
bool ACTR::FAddOnStage(void)
|
|
{
|
|
AssertThis(0);
|
|
|
|
PACTR pactrDup;
|
|
|
|
if (!FDup(&pactrDup))
|
|
{
|
|
return(fFalse);
|
|
}
|
|
|
|
if (!FAddOnStageCore())
|
|
{
|
|
Restore(pactrDup);
|
|
ReleasePpo(&pactrDup);
|
|
return fFalse;
|
|
}
|
|
|
|
if (!FCreateUndo(pactrDup))
|
|
{
|
|
Restore(pactrDup);
|
|
ReleasePpo(&pactrDup);
|
|
return(fFalse);
|
|
}
|
|
|
|
ReleasePpo(&pactrDup);
|
|
return fTrue;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
Normalize an actor.
|
|
|
|
***************************************************************************/
|
|
bool ACTR::FNormalize(ulong grfnorm)
|
|
{
|
|
AssertThis(0);
|
|
|
|
PACTR pactrDup;
|
|
|
|
if (!FDup(&pactrDup))
|
|
{
|
|
return(fFalse);
|
|
}
|
|
|
|
if (!FNormalizeCore(grfnorm))
|
|
{
|
|
Restore(pactrDup);
|
|
ReleasePpo(&pactrDup);
|
|
return fFalse;
|
|
}
|
|
|
|
if (!FCreateUndo(pactrDup))
|
|
{
|
|
Restore(pactrDup);
|
|
ReleasePpo(&pactrDup);
|
|
return(fFalse);
|
|
}
|
|
|
|
ReleasePpo(&pactrDup);
|
|
return fTrue;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
Set the Costume for a body part
|
|
Add the event to the event list
|
|
|
|
***************************************************************************/
|
|
bool ACTR::FSetCostume(long ibset, TAG *ptag, long cmid, bool fCmtl)
|
|
{
|
|
AssertThis(0);
|
|
Assert(fCmtl || ibset >= 0, "Invalid ibset argument");
|
|
AssertVarMem(ptag);
|
|
|
|
PACTR pactrDup;
|
|
|
|
FDup(&pactrDup);
|
|
|
|
if (!FSetCostumeCore(ibset, ptag, cmid, fCmtl))
|
|
{
|
|
Restore(pactrDup);
|
|
ReleasePpo(&pactrDup);
|
|
return fFalse;
|
|
}
|
|
|
|
if (!FCreateUndo(pactrDup))
|
|
{
|
|
Restore(pactrDup);
|
|
ReleasePpo(&pactrDup);
|
|
return(fFalse);
|
|
}
|
|
|
|
ReleasePpo(&pactrDup);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Delete the path and events from this frame and beyond
|
|
**NOTE: This does not send the actor offstage. See FRemFromStageCore.
|
|
|
|
On Input: fDeleteAll specifies full route vs subroute deletion
|
|
Returns *pfAlive = false if all events and route for this actor
|
|
have been deleted
|
|
|
|
***************************************************************************/
|
|
bool ACTR::FDelete(bool *pfAlive, bool fDeleteAll)
|
|
{
|
|
AssertThis(0);
|
|
PACTR pactrDup;
|
|
long iaevCurSav;
|
|
AEV *paev;
|
|
|
|
if (!FDup(&pactrDup))
|
|
{
|
|
if (pvNil != pfAlive)
|
|
TrashVar(pfAlive);
|
|
return fFalse ;
|
|
}
|
|
|
|
// Unless we are deleting to the end of the scene,
|
|
// we need to special case deletion that begins at
|
|
// the same frame as the Add event - otherwise, the
|
|
// code backs up one frame, putting the current frame
|
|
// on the previous subroute.
|
|
// Note: FDelete() does not require that the current
|
|
// frame be later than _nfrmFirst.
|
|
if (_iaevAddCur >= 0 && !fDeleteAll)
|
|
{
|
|
paev = (AEV *)_pggaev->QvFixedGet(_iaevAddCur);
|
|
if (_nfrmCur == paev->nfrm)
|
|
{
|
|
if (!_FDeleteEntireSubrte())
|
|
goto LFail;
|
|
if (pvNil != pfAlive)
|
|
*pfAlive = FPure(_pggaev->IvMac() > 0);
|
|
goto LDeleted;
|
|
}
|
|
}
|
|
|
|
// Go to the previous frame to update state variables
|
|
iaevCurSav = _iaevCur;
|
|
if (!FGotoFrame(_nfrmCur - 1))
|
|
{
|
|
goto LFail;
|
|
}
|
|
|
|
#ifndef BUG1870
|
|
// The next two lines are obsolete & cause placement orientation bugs
|
|
// Save the current orientation
|
|
_SaveCurPathOrien();
|
|
#endif //!BUG1870
|
|
|
|
DeleteFwdCore(fDeleteAll, pfAlive, iaevCurSav);
|
|
|
|
// Return to original frame
|
|
// _nfrmCur was decremented above
|
|
if (!FGotoFrame(_nfrmCur + 1))
|
|
{
|
|
goto LFail;
|
|
}
|
|
|
|
/* Might have deleted some sound events */
|
|
if (Pscen() != pvNil)
|
|
Pscen()->UpdateSndFrame();
|
|
|
|
LDeleted:
|
|
// The frame slider never required lifetime recomputation at this point.
|
|
// Motion match sounds and prerendering both do, however.
|
|
if (!_FComputeLifetime())
|
|
PushErc(ercSocBadFrameSlider);
|
|
|
|
if (!FCreateUndo(pactrDup))
|
|
{
|
|
Restore(pactrDup);
|
|
ReleasePpo(&pactrDup);
|
|
return fFalse;
|
|
}
|
|
|
|
ReleasePpo(&pactrDup);
|
|
return fTrue;
|
|
|
|
LFail:
|
|
PushErc(ercSocGotoFrameFailure);
|
|
ReleasePpo(&pactrDup);
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Add the event to the event list: Remove actor from the stage, and an Undo.
|
|
NOTE: This should be called <before> the call to place the actor offstage
|
|
***************************************************************************/
|
|
bool ACTR::FRemFromStage(void)
|
|
{
|
|
AssertThis(0);
|
|
|
|
PACTR pactr;
|
|
|
|
if (!FDup(&pactr))
|
|
{
|
|
return(fFalse);
|
|
}
|
|
|
|
if (!FRemFromStageCore())
|
|
{
|
|
Restore(pactr);
|
|
return fFalse;
|
|
}
|
|
|
|
if (!FCreateUndo(pactr))
|
|
{
|
|
Restore(pactr);
|
|
ReleasePpo(&pactr);
|
|
return(fFalse);
|
|
}
|
|
|
|
ReleasePpo(&pactr);
|
|
return fTrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************
|
|
*
|
|
* Public constructor for actor undo objects.
|
|
*
|
|
* Parameters:
|
|
* None.
|
|
*
|
|
* Returns:
|
|
* pvNil if failure, else a pointer to the movie undo.
|
|
*
|
|
****************************************************/
|
|
PAUND AUND::PaundNew()
|
|
{
|
|
PAUND paund;
|
|
paund = NewObj AUND();
|
|
AssertNilOrPo(paund, 0);
|
|
return(paund);
|
|
}
|
|
|
|
/****************************************************
|
|
*
|
|
* Destructor for actor undo objects
|
|
*
|
|
****************************************************/
|
|
AUND::~AUND(void)
|
|
{
|
|
AssertBaseThis(0);
|
|
ReleasePpo(&_pactr);
|
|
}
|
|
|
|
|
|
/****************************************************
|
|
*
|
|
* Does a command stored in an undo object.
|
|
*
|
|
* Parameters:
|
|
* None.
|
|
*
|
|
* Returns:
|
|
* fTrue if successful, else fFalse.
|
|
*
|
|
****************************************************/
|
|
bool AUND::FDo(PDOCB pdocb)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pdocb, 0);
|
|
|
|
long nfrmTmp;
|
|
bool fRet;
|
|
|
|
if (!_fSoonerLater)
|
|
{
|
|
return(FUndo(pdocb));
|
|
}
|
|
|
|
nfrmTmp = _nfrm;
|
|
_nfrm = _nfrmLast;
|
|
|
|
fRet = FUndo(pdocb);
|
|
|
|
_nfrm = nfrmTmp;
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
/****************************************************
|
|
*
|
|
* Undoes a command stored in an undo object.
|
|
*
|
|
* Parameters:
|
|
* None.
|
|
*
|
|
* Returns:
|
|
* fTrue if successful, else fFalse.
|
|
*
|
|
****************************************************/
|
|
bool AUND::FUndo(PDOCB pdocb)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pdocb, 0);
|
|
|
|
PACTR pactr;
|
|
PMVU pmvu;
|
|
|
|
if (!_pmvie->FSwitchScen(_iscen))
|
|
{
|
|
return(fFalse);
|
|
}
|
|
|
|
if (!_pmvie->Pscen()->FGotoFrm(_nfrm))
|
|
{
|
|
_pmvie->ClearUndo();
|
|
return(fFalse);
|
|
}
|
|
|
|
_pmvie->Pmsq()->FlushMsq();
|
|
|
|
pactr = _pmvie->Pscen()->PactrFromArid(_arid);
|
|
AssertNilOrPo(pactr, 0);
|
|
|
|
if (pactr != pvNil)
|
|
{
|
|
pactr->AddRef();
|
|
}
|
|
|
|
|
|
//
|
|
// Have scene replace the old actor with this one
|
|
//
|
|
if (_pactr == pvNil)
|
|
{
|
|
_pmvie->Pscen()->RemActrCore(pactr->Arid());
|
|
}
|
|
else
|
|
{
|
|
if (_stn.Cch() != 0)
|
|
{
|
|
// Undo actor name change
|
|
STN stn;
|
|
if (_pmvie->FGetName(_arid, &stn))
|
|
{
|
|
// If FNameActr fails, the actor will not have
|
|
// the correct name...not great, but the user's document
|
|
// won't be corrupted or anything. Someone will push a
|
|
// ercOom, so I ignore the return value here.
|
|
_pmvie->FNameActr(_pactr->Arid(), &_stn);
|
|
_stn = stn;
|
|
}
|
|
}
|
|
|
|
if (_arid != _pactr->Arid())
|
|
{
|
|
_pmvie->Pscen()->RemActrCore(_arid);
|
|
_arid = _pactr->Arid();
|
|
}
|
|
|
|
if (!_pmvie->Pscen()->FAddActrCore(_pactr))
|
|
{
|
|
ReleasePpo(&pactr);
|
|
return(fFalse);
|
|
}
|
|
|
|
pmvu = (PMVU)_pmvie->PddgGet(0);
|
|
AssertNilOrPo(pmvu, 0);
|
|
|
|
if ((pmvu != pvNil) && !pmvu->FTextMode())
|
|
{
|
|
_pmvie->Pscen()->SelectActr(_pactr);
|
|
}
|
|
|
|
ReleasePpo(&_pactr);
|
|
}
|
|
|
|
_pmvie->Pscen()->InvalFrmRange();
|
|
|
|
_pactr = pactr;
|
|
|
|
if (pactr != pvNil)
|
|
{
|
|
pactr->Reset();
|
|
}
|
|
|
|
if (_fSndUndo)
|
|
{
|
|
_pmvie->Pmsq()->PlayMsq();
|
|
}
|
|
else
|
|
{
|
|
_pmvie->Pmsq()->FlushMsq();
|
|
}
|
|
|
|
return(fTrue);
|
|
}
|
|
|
|
/****************************************************
|
|
* Set the actor for this undo object.
|
|
*
|
|
* Parameters:
|
|
* pactr - Actor to use
|
|
*
|
|
* Returns:
|
|
* None.
|
|
*
|
|
****************************************************/
|
|
void AUND::SetPactr(PACTR pactr)
|
|
{
|
|
AssertThis(0);
|
|
|
|
_pactr = pactr;
|
|
pactr->AddRef();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
/****************************************************
|
|
* Mark memory used by the AUND
|
|
*
|
|
* Parameters:
|
|
* None.
|
|
*
|
|
* Returns:
|
|
* None.
|
|
*
|
|
****************************************************/
|
|
void AUND::MarkMem(void)
|
|
{
|
|
AssertThis(0);
|
|
AUND_PAR::MarkMem();
|
|
MarkMemObj(_pactr);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Assert the validity of the AUND.
|
|
***************************************************************************/
|
|
void AUND::AssertValid(ulong grf)
|
|
{
|
|
AssertNilOrPo(_pactr, 0);
|
|
}
|
|
#endif
|