Microsoft-3D-Movie-Maker/BREN/TMAP.CPP

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