mirror of
https://github.com/microsoft/Microsoft-3D-Movie-Maker.git
synced 2024-11-25 11:42:35 +01:00
485 lines
11 KiB
C++
485 lines
11 KiB
C++
/***************************************************************************
|
|
|
|
Texture map (br_pixmap wrapper) class
|
|
|
|
***************************************************************************/
|
|
#include "bren.h"
|
|
|
|
ASSERTNAME
|
|
|
|
RTCLASS(TMAP)
|
|
|
|
|
|
/***************************************************************************
|
|
A PFNRPO to read TMAP objects.
|
|
***************************************************************************/
|
|
bool TMAP::FReadTmap(PCRF pcrf, CTG ctg, CNO cno, PBLCK pblck,
|
|
PBACO *ppbaco, long *pcb)
|
|
{
|
|
AssertPo(pcrf, 0);
|
|
AssertPo(pblck, 0);
|
|
AssertNilOrVarMem(ppbaco);
|
|
AssertVarMem(pcb);
|
|
|
|
PTMAP ptmap;
|
|
|
|
*pcb = pblck->Cb(fTrue);
|
|
if (pvNil == ppbaco)
|
|
return fTrue;
|
|
ptmap = PtmapRead(pcrf->Pcfl(), ctg, cno);
|
|
if (pvNil == ptmap)
|
|
{
|
|
TrashVar(ppbaco);
|
|
TrashVar(pcb);
|
|
return fFalse;
|
|
}
|
|
AssertPo(ptmap, 0);
|
|
*ppbaco = ptmap;
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Read a TMAP from a chunk
|
|
***************************************************************************/
|
|
PTMAP TMAP::PtmapRead(PCFL pcfl, CTG ctg, CNO cno)
|
|
{
|
|
TMAPF tmapf;
|
|
BLCK blck;
|
|
TMAP *ptmap;
|
|
|
|
ptmap = NewObj TMAP;
|
|
if (pvNil == ptmap)
|
|
goto LFail;
|
|
|
|
if (!pcfl->FFind(ctg, cno, &blck) || !blck.FUnpackData())
|
|
goto LFail;
|
|
if (!blck.FReadRgb(&tmapf, size(TMAPF), 0))
|
|
goto LFail;
|
|
|
|
if (kboCur != tmapf.bo)
|
|
SwapBytesBom(&tmapf, kbomTmapf);
|
|
Assert(kboCur == tmapf.bo, "bad TMAPF");
|
|
|
|
ptmap->_bpmp.identifier = (char *)ptmap; // to get TMAP from a (BPMP *)
|
|
if (!FAllocPv((void **)&ptmap->_bpmp.pixels,
|
|
LwMul(tmapf.cbRow, tmapf.dyp), fmemClear, mprNormal))
|
|
{
|
|
goto LFail;
|
|
}
|
|
ptmap->_bpmp.map = pvNil;
|
|
ptmap->_bpmp.row_bytes = tmapf.cbRow;
|
|
ptmap->_bpmp.type = tmapf.type;
|
|
ptmap->_bpmp.flags = tmapf.grftmap;
|
|
ptmap->_bpmp.base_x = tmapf.xpLeft;
|
|
ptmap->_bpmp.base_y = tmapf.ypTop;
|
|
ptmap->_bpmp.width = tmapf.dxp;
|
|
ptmap->_bpmp.height = tmapf.dyp;
|
|
ptmap->_bpmp.origin_x = tmapf.xpOrigin;
|
|
ptmap->_bpmp.origin_y = tmapf.ypOrigin;
|
|
|
|
if (!blck.FReadRgb(ptmap->_bpmp.pixels, LwMul(tmapf.cbRow, tmapf.dyp),
|
|
size(TMAPF)))
|
|
{
|
|
goto LFail;
|
|
}
|
|
return ptmap;
|
|
LFail:
|
|
ReleasePpo(&ptmap);
|
|
return pvNil;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Create a TMAP from a BRender BPMP...used only for importing PIX's
|
|
***************************************************************************/
|
|
PTMAP TMAP::PtmapNewFromBpmp(BPMP *pbpmp)
|
|
{
|
|
PTMAP ptmap;
|
|
|
|
ptmap = NewObj TMAP;
|
|
if (pvNil == ptmap)
|
|
return pvNil;
|
|
ptmap->_bpmp = *pbpmp;
|
|
ptmap->_bpmp.identifier = (char *)ptmap;
|
|
pbpmp->identifier = (char *)ptmap;
|
|
ptmap->_fImported = fTrue;
|
|
return ptmap;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
destructor
|
|
***************************************************************************/
|
|
TMAP::~TMAP(void)
|
|
{
|
|
if (_fImported)
|
|
{
|
|
// REVIEW *****: this crashes BRender...why?
|
|
// BrMemFree(_bpmp.pixels);
|
|
}
|
|
else
|
|
FreePpv((void **)&_bpmp.pixels);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Write a TMAP to a chunk
|
|
***************************************************************************/
|
|
bool TMAP::FWrite(PCFL pcfl, CTG ctg, CNO *pcno)
|
|
{
|
|
AssertThis(0);
|
|
BLCK blck;
|
|
|
|
if (!pcfl->FAdd(size(TMAPF) + LwMul(_bpmp.row_bytes, _bpmp.height),
|
|
ctg, pcno, &blck))
|
|
{
|
|
return fFalse;
|
|
}
|
|
|
|
return FWrite(&blck);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Write a TMAP to the given FLO
|
|
***************************************************************************/
|
|
bool TMAP::FWrite(PBLCK pblck)
|
|
{
|
|
TMAPF tmapf;
|
|
|
|
tmapf.bo = kboCur;
|
|
tmapf.osk = koskCur;
|
|
tmapf.cbRow = _bpmp.row_bytes;
|
|
tmapf.type = _bpmp.type;
|
|
tmapf.grftmap = _bpmp.flags;
|
|
tmapf.xpLeft = _bpmp.base_x;
|
|
tmapf.ypTop = _bpmp.base_y;
|
|
tmapf.dxp = _bpmp.width;
|
|
tmapf.dyp = _bpmp.height;
|
|
tmapf.xpOrigin = _bpmp.origin_x;
|
|
tmapf.ypOrigin = _bpmp.origin_y;
|
|
if (!pblck->FWriteRgb(&tmapf, size(TMAPF), 0))
|
|
return fFalse;
|
|
if (!pblck->FWriteRgb(_bpmp.pixels, LwMul(tmapf.cbRow, tmapf.dyp),
|
|
size(TMAPF)))
|
|
{
|
|
return fFalse;
|
|
}
|
|
return fTrue;
|
|
}
|
|
|
|
#ifdef WIN
|
|
|
|
#define CALCDIST( bRed1, bGreen1, bBlue1, bRed2, bGreen2, bBlue2 ) \
|
|
(((bRed1)-(bRed2))*((bRed1)-(bRed2)) + ((bGreen1)-(bGreen2))*((bGreen1)-(bGreen2)) \
|
|
+ ((bBlue1)-(bBlue2))*((bBlue1)-(bBlue2)))
|
|
|
|
/*
|
|
* PtmapReadNative -- Creates a TMAP object, reading the data from a .BMP file
|
|
*
|
|
* input:
|
|
* pfni -- the FNI to read the data from
|
|
* pglclr -- the colors to map to.
|
|
*
|
|
* output:
|
|
* returns the pointer to the new TMAP
|
|
*/
|
|
PTMAP TMAP::PtmapReadNative(FNI *pfni, PGL pglclr)
|
|
{
|
|
byte *prgb = pvNil;
|
|
PTMAP ptmap = pvNil;
|
|
long dxp, dyp;
|
|
bool fUpsideDown;
|
|
long iclrBest, igl;
|
|
long iprgb;
|
|
long dist, min;
|
|
CLR clr, clrSrc;
|
|
PGL pglclrSrc;
|
|
PGL pglCache;
|
|
|
|
AssertPo(pfni, 0);
|
|
|
|
if (FReadBitmap(pfni, &prgb, &pglclrSrc, &dxp, &dyp, &fUpsideDown))
|
|
{
|
|
Assert(!fUpsideDown, 0);
|
|
AssertPo(pglclrSrc, 0);
|
|
|
|
if (pglclr != pvNil)
|
|
{
|
|
AssertIn(pglclr->IvMac(), 0, 257);
|
|
|
|
//
|
|
// Do a closest color match
|
|
//
|
|
|
|
pglCache = GL::PglNew(size(long), pglclrSrc->IvMac());
|
|
|
|
if (pglCache != pvNil)
|
|
{
|
|
|
|
iclrBest = ivNil;
|
|
for (igl = 0; igl < pglclrSrc->IvMac(); igl++)
|
|
{
|
|
AssertDo(pglCache->FAdd(&iclrBest), "Ensured by creation");
|
|
}
|
|
|
|
}
|
|
|
|
for (iprgb = 0; iprgb < (dxp * dyp); iprgb++)
|
|
{
|
|
|
|
if (pglCache != pvNil)
|
|
{
|
|
pglCache->Get(prgb[iprgb], &iclrBest);
|
|
|
|
if (iclrBest != ivNil)
|
|
{
|
|
prgb[iprgb] = (BYTE)iclrBest;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
pglclrSrc->Get(prgb[iprgb], &clrSrc);
|
|
|
|
iclrBest = ivNil;
|
|
min = klwMax;
|
|
|
|
for (igl = 0; igl < pglclr->IvMac(); igl++)
|
|
{
|
|
|
|
pglclr->Get(igl, &clr);
|
|
dist = CALCDIST( clrSrc.bRed, clrSrc.bGreen, clrSrc.bBlue,
|
|
clr.bRed, clr.bGreen, clr.bBlue);
|
|
|
|
if (dist <= min)
|
|
{
|
|
min = dist;
|
|
iclrBest = igl;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (iclrBest != ivNil)
|
|
{
|
|
AssertIn(iclrBest, 0, pglclr->IvMac());
|
|
|
|
if (pglCache != pvNil)
|
|
{
|
|
pglCache->Put(prgb[iprgb], &iclrBest);
|
|
}
|
|
|
|
prgb[iprgb] = (BYTE)iclrBest;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ReleasePpo(&pglCache);
|
|
|
|
}
|
|
|
|
ReleasePpo(&pglclrSrc);
|
|
|
|
ptmap = TMAP::PtmapNew(prgb, dxp, dyp);
|
|
}
|
|
|
|
return ptmap;
|
|
}
|
|
#endif // WIN
|
|
|
|
#ifdef MAC
|
|
PTMAP TMAP::PtmapReadNative(FNI *pfni)
|
|
{
|
|
RawRtn(); // REVIEW peted: NYI
|
|
return pvNil;
|
|
}
|
|
#endif // MAC
|
|
|
|
/*
|
|
* PtmapNew -- Given pixel data and attributes, creates a new TMAP with
|
|
* the given information.
|
|
*
|
|
* input:
|
|
* prgbPixels -- the actual pixels for the TMAP
|
|
* pbmh -- The bitmap header from the .BMP file
|
|
*
|
|
* output:
|
|
* returns the pointer to the new TMAP
|
|
*/
|
|
PTMAP TMAP::PtmapNew(byte *prgbPixels, long dxp, long dyp)
|
|
{
|
|
PTMAP ptmap;
|
|
|
|
Assert(dxp <= ksuMax, "bitmap too wide");
|
|
Assert(dyp <= ksuMax, "bitmap too high");
|
|
|
|
if ((ptmap = NewObj TMAP) != pvNil)
|
|
{
|
|
ptmap->_fImported = fFalse;
|
|
ptmap->_bpmp.identifier = (char *)ptmap;
|
|
ptmap->_bpmp.pixels = prgbPixels;
|
|
ptmap->_bpmp.map = pvNil;
|
|
ptmap->_bpmp.row_bytes = (br_int_16)dxp;
|
|
ptmap->_bpmp.type = BR_PMT_INDEX_8;
|
|
ptmap->_bpmp.flags = BR_PMF_LINEAR;
|
|
ptmap->_bpmp.base_x = ptmap->_bpmp.base_y = 0;
|
|
ptmap->_bpmp.width = (br_uint_16)dxp;
|
|
ptmap->_bpmp.height = (br_uint_16)dyp;
|
|
ptmap->_bpmp.origin_x = ptmap->_bpmp.origin_y = 0;
|
|
}
|
|
AssertPo(ptmap, 0);
|
|
return ptmap;
|
|
}
|
|
|
|
/******************************************************************************
|
|
FWriteTmapChkFile
|
|
Writes a stand-alone file with a TMAP chunk in it. The file can
|
|
be later read in by the CHCM class with the FILE command.
|
|
|
|
Arguments:
|
|
PFNI pfniDst -- FNI indicating the name of the output file
|
|
bool fCompress -- fTrue if the chunk date is to be compressed
|
|
PMSNK pmsnkErr -- optional message sink to direct errors to
|
|
|
|
Returns: fTrue if the file was written successfully
|
|
|
|
************************************************************ PETED ***********/
|
|
bool TMAP::FWriteTmapChkFile(PFNI pfniDst, bool fCompress, PMSNK pmsnkErr)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pfniDst, ffniFile);
|
|
AssertNilOrPo(pmsnkErr, 0);
|
|
|
|
bool fRet = fFalse;
|
|
long lwSig;
|
|
PSZ pszErr = pvNil;
|
|
FLO flo;
|
|
|
|
if (pvNil == (flo.pfil = FIL::PfilCreate(pfniDst)))
|
|
{
|
|
pszErr = PszLit("Couldn't create destination file\n");
|
|
goto LFail;
|
|
}
|
|
flo.fp = size(long);
|
|
flo.cb = CbOnFile();
|
|
|
|
if (fCompress)
|
|
{
|
|
BLCK blck;
|
|
|
|
if (!blck.FSetTemp(flo.cb) || !FWrite(&blck))
|
|
{
|
|
pszErr = PszLit("allocation failure\n");
|
|
goto LFail;
|
|
}
|
|
if (!blck.FPackData())
|
|
lwSig = klwSigUnpackedFile;
|
|
else
|
|
{
|
|
lwSig = klwSigPackedFile;
|
|
flo.cb = blck.Cb(fTrue);
|
|
}
|
|
if (!flo.pfil->FWriteRgb(&lwSig, size(long), 0) ||
|
|
!blck.FWriteToFlo(&flo, fTrue))
|
|
{
|
|
pszErr = PszLit("writing to destination file failed\n");
|
|
goto LFail;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lwSig = klwSigUnpackedFile;
|
|
if (!flo.pfil->FWriteRgb(&lwSig, size(long), 0) || !FWriteFlo(&flo))
|
|
{
|
|
pszErr = PszLit("writing to destination file failed\n");
|
|
goto LFail;
|
|
}
|
|
}
|
|
|
|
fRet = fTrue;
|
|
LFail:
|
|
if (pszErr != pvNil && pmsnkErr != pvNil)
|
|
pmsnkErr->ReportLine(pszErr);
|
|
if (!fRet && pvNil != flo.pfil)
|
|
flo.pfil->SetTemp();
|
|
ReleasePpo(&flo.pfil);
|
|
return fRet;
|
|
}
|
|
|
|
|
|
#ifdef NOT_YET_REVIEWED
|
|
byte * TMAP::PrgbBuildInverseTable(void)
|
|
{
|
|
byte *prgb, *prgbT, iclr;
|
|
long cbRgb;
|
|
|
|
if (_pbpmp->type != BR_PMT_RGB_888)
|
|
return pvNil;
|
|
|
|
if (!FAllocPv((void **)&prgb, cbRgb = _pbpmp->height, fmemNil, mprNormal))
|
|
return pvNil;
|
|
|
|
for (prgbT = prgb, iclr = 0; iclr < cbRgb; prgbT++, iclr++)
|
|
*prgbT = iclr;
|
|
|
|
_SortInverseTable(prgb, cbRgb, BR_COLOUR_RGB(0, 0, 0), BR_COLOUR_RGB(0xFF, 0xFF, 0xFF));
|
|
return prgb;
|
|
}
|
|
|
|
void TMAP::_SortInverseTable(byte *prgb, long cbRgb, BRCLR brclrLo, BRCLR brclrHi)
|
|
{
|
|
long cbRgb1 = 0, cbRgb2 = 0;
|
|
byte *prgb2, *prgbRead, bT;
|
|
BRCLR brclrPivot = brclrLo + (brclrHi - brclrLo) / 2;
|
|
BRCLR *pbrclr;
|
|
|
|
prgb2 = prgb + cbRgb;
|
|
prgbRead = prgb;
|
|
while (cbRgb--)
|
|
{
|
|
pbrclr = 0; // pbrclr from index *prgb;
|
|
if (*pbrclr <= brclrPivot)
|
|
{
|
|
prgbRead++;
|
|
cbRgb1++;
|
|
}
|
|
else
|
|
{
|
|
bT = *prgb2;
|
|
*--prgb2 = *prgbRead;
|
|
*prgbRead = bT;
|
|
cbRgb2++;
|
|
}
|
|
}
|
|
if (cbRgb1 > 1)
|
|
_SortInverseTable(prgb, cbRgb1, brclrLo, brclrPivot);
|
|
if (cbRgb2 > 1)
|
|
_SortInverseTable(prgb2, cbRgb2, brclrPivot + 1, brclrHi);
|
|
}
|
|
#endif // NOT_YET_REVIEWED
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Assert the validity of the TMAP.
|
|
***************************************************************************/
|
|
void TMAP::AssertValid(ulong grf)
|
|
{
|
|
TMAP_PAR::AssertValid(fobjAllocated);
|
|
if (!_fImported)
|
|
AssertPvCb(_bpmp.pixels, LwMul(_bpmp.row_bytes, _bpmp.height));
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Mark memory used by the TMAP.
|
|
***************************************************************************/
|
|
void TMAP::MarkMem(void)
|
|
{
|
|
AssertThis(0);
|
|
TMAP_PAR::MarkMem();
|
|
if (!_fImported)
|
|
MarkPv(_bpmp.pixels);
|
|
}
|
|
#endif // DEBUG
|