mirror of
https://github.com/microsoft/Microsoft-3D-Movie-Maker.git
synced 2024-11-22 10:22:40 +01:00
551 lines
13 KiB
C++
551 lines
13 KiB
C++
/* Copyright (c) Microsoft Corporation.
|
|
Licensed under the MIT License. */
|
|
|
|
/***************************************************************************
|
|
Author: ShonK
|
|
Project: Kauai
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
This is a class that knows how to create GOKs, Help Balloons and
|
|
Kidspace script interpreters. It exists so an app can customize
|
|
default behavior.
|
|
|
|
***************************************************************************/
|
|
#include "kidframe.h"
|
|
ASSERTNAME
|
|
|
|
|
|
RTCLASS(GOKD)
|
|
RTCLASS(GKDS)
|
|
RTCLASS(WOKS)
|
|
|
|
/***************************************************************************
|
|
Static method to read a GKDS from the CRF. This is a CRF object reader.
|
|
***************************************************************************/
|
|
bool GKDS::FReadGkds(PCRF pcrf, CTG ctg, CNO cno, PBLCK pblck,
|
|
PBACO *ppbaco, long *pcb)
|
|
{
|
|
PGKDS pgkds;
|
|
GOKDF gokdf;
|
|
HQ hq;
|
|
LOP *qlop;
|
|
long cb;
|
|
|
|
*pcb = pblck->Cb(fTrue);
|
|
if (pvNil == ppbaco)
|
|
return fTrue;
|
|
|
|
if (!pblck->FUnpackData())
|
|
return fFalse;
|
|
*pcb = pblck->Cb();
|
|
|
|
if (*pcb < size(GOKDF) + size(LOP) || CbRoundToLong(*pcb) != *pcb)
|
|
{
|
|
Bug("Bad GOKD");
|
|
return fFalse;
|
|
}
|
|
|
|
if (!pblck->FReadRgb(&gokdf, size(GOKDF), 0))
|
|
return fFalse;
|
|
if (gokdf.bo == kboOther)
|
|
SwapBytesBom(&gokdf, kbomGokdf);
|
|
else if (gokdf.bo != kboCur)
|
|
{
|
|
Bug("Bad GOKD 2");
|
|
return fFalse;
|
|
}
|
|
|
|
if (!pblck->FMoveMin(size(gokdf)))
|
|
return fFalse;
|
|
hq = pblck->HqFree();
|
|
if (hqNil == hq)
|
|
return fFalse;
|
|
cb = CbOfHq(hq);
|
|
|
|
if (pvNil == (pgkds = NewObj GKDS))
|
|
{
|
|
FreePhq(&hq);
|
|
return fFalse;
|
|
}
|
|
pgkds->_hqData = hq;
|
|
pgkds->_gokk = gokdf.gokk;
|
|
if (gokdf.bo == kboOther)
|
|
SwapBytesRglw(QvFromHq(hq), cb / size(long));
|
|
|
|
qlop = (LOP *)QvFromHq(hq);
|
|
for (pgkds->_clop = 0; ; qlop++)
|
|
{
|
|
if (cb < size(LOP))
|
|
{
|
|
Bug("Bad LOP list in GOKD");
|
|
ReleasePpo(&pgkds);
|
|
return fFalse;
|
|
}
|
|
pgkds->_clop++;
|
|
cb -= size(LOP);
|
|
if (hidNil == qlop->hidPar)
|
|
break;
|
|
}
|
|
if ((cb % size(CUME)) != 0)
|
|
{
|
|
Bug("Bad CUME list in GOKD");
|
|
ReleasePpo(&pgkds);
|
|
return fFalse;
|
|
}
|
|
pgkds->_ccume = cb / size(CUME);
|
|
*ppbaco = pgkds;
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Destructor for a GKDS object.
|
|
***************************************************************************/
|
|
GKDS::~GKDS(void)
|
|
{
|
|
FreePhq(&_hqData);
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Assert the validity of a GKDS.
|
|
***************************************************************************/
|
|
void GKDS::AssertValid(ulong grf)
|
|
{
|
|
LOP *qrglop;
|
|
|
|
GKDS_PAR::AssertValid(0);
|
|
AssertHq(_hqData);
|
|
AssertIn(_clop, 0, kcbMax);
|
|
AssertIn(_ccume, 0, kcbMax);
|
|
Assert(LwMul(_clop, size(LOP)) + LwMul(_ccume, size(CUME)) == CbOfHq(_hqData),
|
|
"GKDS _hqData wrong size");
|
|
qrglop = (LOP *)QvFromHq(_hqData);
|
|
Assert(qrglop[_clop - 1].hidPar == hidNil, "bad rglop in GKDS");
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Mark memory for the GKDS.
|
|
***************************************************************************/
|
|
void GKDS::MarkMem(void)
|
|
{
|
|
AssertValid(0);
|
|
GKDS_PAR::MarkMem();
|
|
MarkHq(_hqData);
|
|
}
|
|
#endif //DEBUG
|
|
|
|
|
|
/***************************************************************************
|
|
Return the GOK kind id.
|
|
***************************************************************************/
|
|
long GKDS::Gokk(void)
|
|
{
|
|
AssertThis(0);
|
|
return _gokk;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Look for a cursor map entry in this GKDS.
|
|
***************************************************************************/
|
|
bool GKDS::FGetCume(ulong grfcust, long sno, CUME *pcume)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcume);
|
|
CUME *qcume;
|
|
long ccume;
|
|
ulong fbitSno = (1L << (sno & 0x1F));
|
|
|
|
if (0 == _ccume)
|
|
return fFalse;
|
|
|
|
qcume = (CUME *)PvAddBv(QvFromHq(_hqData), LwMul(_clop, size(LOP)));
|
|
for (ccume = _ccume; ccume > 0; ccume--, qcume++)
|
|
{
|
|
if ((qcume->grfbitSno & fbitSno) &&
|
|
(qcume->grfcustMask & grfcust) == qcume->grfcust)
|
|
{
|
|
*pcume = *qcume;
|
|
return fTrue;
|
|
}
|
|
}
|
|
TrashVar(pcume);
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the location map entry from the parent id.
|
|
***************************************************************************/
|
|
void GKDS::GetLop(long hidPar, LOP *plop)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(plop);
|
|
LOP *qlop;
|
|
|
|
for (qlop = (LOP *)QvFromHq(_hqData); ; qlop++)
|
|
{
|
|
if (hidNil == qlop->hidPar || hidPar == qlop->hidPar)
|
|
break;
|
|
}
|
|
*plop = *qlop;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Constructor for a World of Kidspace GOB.
|
|
***************************************************************************/
|
|
WOKS::WOKS(GCB *pgcb, PSTRG pstrg) : WOKS_PAR(pgcb),
|
|
_clokAnim(CMH::HidUnique()),
|
|
_clokNoSlip(CMH::HidUnique(), fclokNoSlip),
|
|
_clokGen(CMH::HidUnique()),
|
|
_clokReset(CMH::HidUnique(), fclokReset)
|
|
{
|
|
AssertThis(0);
|
|
AssertNilOrPo(pstrg, 0);
|
|
|
|
if (pvNil == pstrg)
|
|
pstrg = &_strg;
|
|
_pstrg = pstrg;
|
|
_pstrg->AddRef();
|
|
|
|
_clokAnim.Start(0);
|
|
_clokNoSlip.Start(0);
|
|
_clokGen.Start(0);
|
|
_clokReset.Start(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Destructor for a kidspace world.
|
|
***************************************************************************/
|
|
WOKS::~WOKS(void)
|
|
{
|
|
ReleasePpo(&_pstrg);
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Assert the validity of a WOKS.
|
|
***************************************************************************/
|
|
void WOKS::AssertValid(ulong grf)
|
|
{
|
|
WOKS_PAR::AssertValid(0);
|
|
AssertPo(&_strg, 0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Mark memory for the WOKS.
|
|
***************************************************************************/
|
|
void WOKS::MarkMem(void)
|
|
{
|
|
AssertValid(0);
|
|
WOKS_PAR::MarkMem();
|
|
MarkMemObj(&_strg);
|
|
}
|
|
#endif //DEBUG
|
|
|
|
|
|
/***************************************************************************
|
|
Return whether the GOB is in this kidspace world.
|
|
***************************************************************************/
|
|
bool WOKS::FGobIn(PGOB pgob)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pgob, 0);
|
|
|
|
for ( ; pgob != this; pgob = pgob->PgobPar())
|
|
{
|
|
if (pgob == pvNil)
|
|
return fFalse;
|
|
}
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get a GOKD from the given chunk.
|
|
***************************************************************************/
|
|
PGOKD WOKS::PgokdFetch(CTG ctg, CNO cno, PRCA prca)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(prca, 0);
|
|
|
|
return (PGOKD)prca->PbacoFetch(ctg, cno, GKDS::FReadGkds);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Create a new gob in this kidspace world.
|
|
***************************************************************************/
|
|
PGOK WOKS::PgokNew(PGOB pgobPar, long hid, CNO cnoGokd, PRCA prca)
|
|
{
|
|
AssertThis(0);
|
|
AssertNilOrPo(pgobPar, 0);
|
|
PGOKD pgokd;
|
|
PGOK pgok;
|
|
|
|
if (pgobPar == pvNil)
|
|
pgobPar = this;
|
|
else if (!FGobIn(pgobPar))
|
|
{
|
|
// parent isn't in this kidspace world
|
|
Bug("Parent is not in this kidspace world");
|
|
return pvNil;
|
|
}
|
|
|
|
if (hidNil == hid)
|
|
hid = CMH::HidUnique();
|
|
else if (pvNil != PcmhFromHid(hid))
|
|
{
|
|
BugVar("command handler with this ID already exists", &hid);
|
|
return pvNil;
|
|
}
|
|
|
|
if (pvNil == (pgokd = PgokdFetch(kctgGokd, cnoGokd, prca)))
|
|
return pvNil;
|
|
|
|
pgok = GOK::PgokNew(this, pgobPar, hid, pgokd, prca);
|
|
ReleasePpo(&pgokd);
|
|
|
|
return pgok;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Create a new script interpreter for this kidspace world.
|
|
***************************************************************************/
|
|
PSCEG WOKS::PscegNew(PRCA prca, PGOB pgob)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(prca, 0);
|
|
AssertPo(pgob, 0);
|
|
|
|
return NewObj SCEG(this, prca, pgob);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Create a new help balloon.
|
|
***************************************************************************/
|
|
PHBAL WOKS::PhbalNew(PGOB pgobPar, PRCA prca, CNO cnoTopic, PHTOP phtop)
|
|
{
|
|
AssertThis(0);
|
|
AssertNilOrPo(pgobPar, 0);
|
|
AssertPo(prca, 0);
|
|
AssertNilOrVarMem(phtop);
|
|
|
|
if (pgobPar == pvNil)
|
|
pgobPar = this;
|
|
else if (!FGobIn(pgobPar))
|
|
{
|
|
// parent isn't in this kidspace world
|
|
Bug("Parent is not in this kidspace world");
|
|
return pvNil;
|
|
}
|
|
|
|
return HBAL::PhbalCreate(this, pgobPar, prca, cnoTopic, phtop);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the command handler for this hid.
|
|
***************************************************************************/
|
|
PCMH WOKS::PcmhFromHid(long hid)
|
|
{
|
|
AssertThis(0);
|
|
PCMH pcmh;
|
|
|
|
switch (hid)
|
|
{
|
|
case hidNil:
|
|
return pvNil;
|
|
|
|
case khidApp:
|
|
return vpappb;
|
|
}
|
|
|
|
if (pvNil != (pcmh = PclokFromHid(hid)))
|
|
return pcmh;
|
|
return PgobFromHid(hid);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the clock having the given hid.
|
|
***************************************************************************/
|
|
PCLOK WOKS::PclokFromHid(long hid)
|
|
{
|
|
AssertThis(0);
|
|
|
|
if (khidClokGokGen == hid)
|
|
return &_clokGen;
|
|
if (khidClokGokReset == hid)
|
|
return &_clokReset;
|
|
|
|
return CLOK::PclokFromHid(hid);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the parent gob of the given gob. This is here so a kidspace world
|
|
can limit what scripts can get to.
|
|
***************************************************************************/
|
|
PGOB WOKS::PgobParGob(PGOB pgob)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pgob, 0);
|
|
|
|
pgob = pgob->PgobPar();
|
|
if (pvNil == pgob || !FGobIn(pgob))
|
|
return pvNil;
|
|
return pgob;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Find a file given a string.
|
|
***************************************************************************/
|
|
bool WOKS::FFindFile(PSTN pstnSrc, PFNI pfni)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pstnSrc, 0);
|
|
AssertPo(pfni, 0);
|
|
|
|
return pfni->FBuildFromPath(pstnSrc);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Put up an alert (and don't return until it is dismissed).
|
|
***************************************************************************/
|
|
bool WOKS::TGiveAlert(PSTN pstn, long bk, long cok)
|
|
{
|
|
AssertThis(0);
|
|
|
|
return vpappb->TGiveAlertSz(pstn->Psz(), bk, cok);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Put up an alert (and don't return until it is dismissed).
|
|
***************************************************************************/
|
|
void WOKS::Print(PSTN pstn)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pstn, 0);
|
|
|
|
// REVIEW shonk: implement WOKS::Print better
|
|
#ifdef WIN
|
|
OutputDebugString(pstn->Psz());
|
|
OutputDebugString(PszLit("\n"));
|
|
#endif //WIN
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return the current cursor state. This takes the frame cursor state from
|
|
vpappb and the rest from this kidspace world.
|
|
***************************************************************************/
|
|
ulong WOKS::GrfcustCur(bool fAsynch)
|
|
{
|
|
AssertThis(0);
|
|
|
|
return GrfcustAdjust(vpappb->GrfcustCur(fAsynch));
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Modify the current cursor state. This sets the frame values in vpappb
|
|
and the rest in this kidspace world.
|
|
***************************************************************************/
|
|
void WOKS::ModifyGrfcust(ulong grfcustOr, ulong grfcustXor)
|
|
{
|
|
AssertThis(0);
|
|
|
|
// write all the bits to the app. Also adjust our internal _grfcust
|
|
vpappb->ModifyGrfcust(grfcustOr, grfcustXor);
|
|
|
|
_grfcust |= grfcustOr;
|
|
_grfcust ^= grfcustXor;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Adjust the given grfcust (take the Frame bits from it and combine with
|
|
our other bits).
|
|
***************************************************************************/
|
|
ulong WOKS::GrfcustAdjust(ulong grfcust)
|
|
{
|
|
AssertThis(0);
|
|
|
|
grfcust &= kgrfcustFrame;
|
|
grfcust |= _grfcust & (kgrfcustKid | kgrfcustApp);
|
|
return grfcust;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Do a modal help topic.
|
|
***************************************************************************/
|
|
bool WOKS::FModalTopic(PRCA prca, CNO cnoTopic, long *plwRet)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(prca, 0);
|
|
AssertVarMem(plwRet);
|
|
|
|
GCB gcb;
|
|
PWOKS pwoksModal;
|
|
GTE gte;
|
|
PGOB pgob;
|
|
ulong grfgte;
|
|
bool fRet = fFalse;
|
|
|
|
gte.Init(this, fgteNil);
|
|
while (gte.FNextGob(&pgob, &grfgte, fgteNil))
|
|
{
|
|
if (!(grfgte & fgtePre) || !pgob->FIs(kclsGOK))
|
|
continue;
|
|
|
|
((PGOK)pgob)->Suspend();
|
|
}
|
|
|
|
if (vpappb->FPushModal())
|
|
{
|
|
gcb.Set(CMH::HidUnique(), this, fgobNil, kginMark);
|
|
gcb._rcRel.Set(0, 0, krelOne, krelOne);
|
|
|
|
if (pvNil != (pwoksModal = NewObj WOKS(&gcb, _pstrg)))
|
|
{
|
|
vpsndm->PauseAll();
|
|
vpcex->SetModalGob(pwoksModal);
|
|
if (pvNil != pwoksModal->PhbalNew(pwoksModal, prca, cnoTopic))
|
|
fRet = FPure(vpappb->FModalLoop(plwRet));
|
|
vpcex->SetModalGob(pvNil);
|
|
vpsndm->ResumeAll();
|
|
}
|
|
|
|
ReleasePpo(&pwoksModal);
|
|
vpappb->PopModal();
|
|
}
|
|
|
|
gte.Init(this, fgteNil);
|
|
while (gte.FNextGob(&pgob, &grfgte, fgteNil))
|
|
{
|
|
if (!(grfgte & fgtePre) || !pgob->FIs(kclsGOK))
|
|
continue;
|
|
|
|
((PGOK)pgob)->Resume();
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|