/*************************************************************************** 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