Blob Blame Raw


#include "trop.h"
#include "tconvert.h"
//#include "trastercm.h"
#ifndef TNZCORE_LIGHT
#include "timagecache.h"
#include "ttile.h"
#include "trasterimage.h"
#include "ttoonzimage.h"
#endif

TString TRopException::getMessage() const
{
	return toWideString(message);
}

namespace
{

bool isOpaque32(TRaster32P &ras)
{
	ras->lock();
	UCHAR *m0 = &(ras->pixels()->m);
	if (0 < m0[0] && m0[0] < 255)
		return false;

	int wrap4 = ras->getWrap() * 4;
	int lx4 = ras->getLx() * 4;
	const UCHAR cm = *m0;
	int nrows = ras->getLy();
	while (nrows-- > 0) {
		UCHAR *m1 = m0 + lx4;
		UCHAR *m = m0;
		while (m < m1 && *m == cm)
			m += 4;
		if (m < m1)
			break;
		m0 += wrap4;
	}
	ras->unlock();
	return (nrows <= 0);

	//m_image->setOpaqueFlag(true);
}

} //namespace

bool TRop::isOpaque(TRasterP ras)
{
	TRaster32P ras32 = ras;
	if (ras32)
		return isOpaque32(ras32);
	else if (TRasterGR8P(ras))
		return true;
	else
		throw TRopException("isOpaque: unsupported pixel type");
}

#ifdef TNZ_MACHINE_CHANNEL_ORDER_MRGB
void TRop::swapRBChannels(const TRaster32P &r)
{
	int lx = r->getLx();
	int y = r->getLy();
	r->lock();
	while (--y >= 0) {
		TPixel32 *pix = r->pixels(y);
		TPixel32 *endPix = pix + lx;
		while (pix < endPix) {
			tswap(pix->r, pix->b);
			++pix;
		}
	}
	r->unlock();
}
#endif

TRaster32P TRop::copyAndSwapRBChannels(const TRaster32P &srcRaster)
{
	TRaster32P newRaster(srcRaster->getSize());
	int lx = srcRaster->getLx();
	int y = srcRaster->getLy();
	srcRaster->lock();
	newRaster->lock();
	while (--y >= 0) {
		TPixel32 *pix = srcRaster->pixels(y);
		TPixel32 *newpix = newRaster->pixels(y);
		TPixel32 *endPix = pix + lx;
		while (pix < endPix) {
			newpix->r = pix->b;
			newpix->g = pix->g;
			newpix->b = pix->r;
			newpix->m = pix->m;
			++pix;
			++newpix;
		}
	}
	srcRaster->unlock();
	newRaster->unlock();

	return newRaster;
}

void TRop::copy(TRasterP dst, const TRasterP &src)
{
	assert(!((TRasterCM32P)src) || (TRasterCM32P)dst);
	if (dst->getPixelSize() == src->getPixelSize())
		dst->copy(src);
	else {
		if (dst->getBounds() != src->getBounds()) {
			TRect rect = dst->getBounds() * src->getBounds();
			if (rect.isEmpty())
				return;
			TRop::convert(dst->extract(rect), src->extract(rect));
		} else
			TRop::convert(dst, src);
	}
}

//-------------------------------------------------------------------

namespace
{
template <class Q>
class Gamma_Lut
{

public:
	std::vector<Q> m_table;
	Gamma_Lut(int insteps, int outsteps, double gamma)
	{
		double inspace = (double)(insteps);
		for (int i = 0; i <= insteps; i++)
			m_table.push_back((Q)((outsteps) *
									  (pow(i / inspace, 1.0 / gamma)) +
								  0.5));
	}
};

template <class T, class Q>
void doGammaCorrect(TRasterPT<T> raster, double gamma)
{
	Gamma_Lut<Q> lut(T::maxChannelValue, T::maxChannelValue, gamma);

	int j;
	for (j = 0; j < raster->getLy(); j++) {
		T *pix = raster->pixels(j);
		T *endPix = pix + raster->getLx();
		while (pix < endPix) {
			pix->r = lut.m_table[pix->r];
			pix->b = lut.m_table[pix->b];
			pix->g = lut.m_table[pix->g];
			/*if(pix->m != T::maxChannelValue)
      {
      pix->r= pix->r*pix->m/T::maxChannelValue;
      pix->g= pix->g*pix->m/T::maxChannelValue; 
      pix->b= pix->b*pix->m/T::maxChannelValue;
	    }*/
			*pix++;
		}
	}
}
template <class T, class Q>
void doGammaCorrectRGBM(TRasterPT<T> raster, double gammar, double gammag, double gammab, double gammam)
{
	Gamma_Lut<Q> lutr(T::maxChannelValue, T::maxChannelValue, gammar);
	Gamma_Lut<Q> lutg(T::maxChannelValue, T::maxChannelValue, gammag);
	Gamma_Lut<Q> lutb(T::maxChannelValue, T::maxChannelValue, gammab);
	Gamma_Lut<Q> lutm(T::maxChannelValue, T::maxChannelValue, gammam);
	int j;
	for (j = 0; j < raster->getLy(); j++) {
		T *pix = raster->pixels(j);
		T *endPix = pix + raster->getLx();
		while (pix < endPix) {
			pix->r = lutr.m_table[pix->r];
			pix->g = lutg.m_table[pix->g];
			pix->b = lutb.m_table[pix->b];
			pix->m = lutm.m_table[pix->m];
			/*if(pix->m != T::maxChannelValue)
      {
      pix->r= pix->r*pix->m/T::maxChannelValue;
      pix->g= pix->g*pix->m/T::maxChannelValue; 
      pix->b= pix->b*pix->m/T::maxChannelValue;
	    }*/
			*pix++;
		}
	}
}
}
//-------------------------------------------------------------------

void TRop::gammaCorrect(TRasterP raster, double gamma)
{
	if (gamma <= 0)
		gamma = 0.01;
	raster->lock();

	if ((TRaster32P)raster)
		doGammaCorrect<TPixel32, UCHAR>(raster, gamma);
	else if ((TRaster64P)raster)
		doGammaCorrect<TPixel64, USHORT>(raster, gamma);
	else {
		raster->unlock();
		throw TRopException("isOpaque: unsupported pixel type");
	}
	raster->unlock();
}
//-------------------------------------------------------------------

void TRop::gammaCorrectRGBM(TRasterP raster, double gammar, double gammag,
							double gammab, double gammam)
{
	if (gammar <= 0)
		gammar = 0.01;
	if (gammag <= 0)
		gammag = 0.01;
	if (gammab <= 0)
		gammab = 0.01;
	if (gammam <= 0)
		gammam = 0.01;

	raster->lock();

	if ((TRaster32P)raster)
		doGammaCorrectRGBM<TPixel32, UCHAR>(raster, gammar, gammag, gammab, gammam);
	else if ((TRaster64P)raster)
		doGammaCorrectRGBM<TPixel64, USHORT>(raster, gammar, gammag, gammab, gammam);
	else {
		raster->unlock();
		throw TRopException("isOpaque: unsupported pixel type");
	}
	raster->unlock();
}
//-------------------------------------------------------------------

template <class T>
void doSetChannel(const TRasterPT<T> &rin, const TRasterPT<T> &rout, UCHAR channel, bool greytones)
{

	int lx = rin->getLx();
	int ly = rout->getLy();

	int i, j;
	for (i = 0; i < ly; i++) {
		T *pixin = rin->pixels(i);
		T *pixout = rout->pixels(i);
		if (greytones || channel == TRop::MChan) {
			switch (channel) {
			case TRop::RChan:
				for (j = 0; j < lx; j++, pixin++, pixout++)
					pixout->r = pixout->g = pixout->b = pixout->m = pixin->r;
				break;
			case TRop::GChan:
				for (j = 0; j < lx; j++, pixin++, pixout++)
					pixout->r = pixout->g = pixout->b = pixout->m = pixin->g;
				break;
			case TRop::BChan:
				for (j = 0; j < lx; j++, pixin++, pixout++)
					pixout->r = pixout->g = pixout->b = pixout->m = pixin->b;
				break;
			case TRop::MChan:
				for (j = 0; j < lx; j++, pixin++, pixout++)
					pixout->r = pixout->g = pixout->b = pixout->m = pixin->m;
				break;
			default:
				assert(false);
			}
		} else {
			for (j = 0; j < lx; j++, pixin++, pixout++) {
				pixout->r = channel & TRop::RChan ? pixin->r : 0;
				pixout->b = channel & TRop::BChan ? pixin->b : 0;
				pixout->g = channel & TRop::GChan ? pixin->g : 0;
			}
		}
	}
}

//-------------------------------------------------------------------

void TRop::setChannel(const TRasterP &rin, TRasterP rout, UCHAR chan, bool greytones)
{
	assert(rin->getSize() == rout->getSize());

	rout->lock();

	if ((TRaster32P)rin && (TRaster32P)rout)
		doSetChannel<TPixel32>(rin, rout, chan, greytones);
	else if ((TRaster64P)rin && (TRaster64P)rout)
		doSetChannel<TPixel64>(rin, rout, chan, greytones);
	else {
		rout->unlock();
		throw TRopException("setChannel: unsupported pixel type");
	}

	rout->unlock();
}

//-------------------------------------------------------------------

TRasterP TRop::shrink(TRasterP rin, int shrink)
{
	int pixelSize = rin->getPixelSize();

	int lx = (rin->getLx() - 1) / shrink + 1;
	int ly = (rin->getLy() - 1) / shrink + 1;

	TRasterP rout;

	if ((TRaster32P)rin)
		rout = TRaster32P(lx, ly);
	else if ((TRaster64P)rin)
		rout = TRaster64P(lx, ly);
	if ((TRasterCM32P)rin)
		rout = TRasterCM32P(lx, ly);
	if ((TRasterGR8P)rin)
		rout = TRasterGR8P(lx, ly);

	int i, j;

	for (i = 0; i < ly; i++) {
		UCHAR *bufin = (UCHAR *)rin->getRawData() + (i * shrink) * rin->getWrap() * pixelSize;
		UCHAR *bufout = (UCHAR *)rout->getRawData() + i * rout->getWrap() * pixelSize;
		for (j = 0; j < lx; j++) {
			memcpy(bufout, bufin, pixelSize);
			bufin += shrink * pixelSize;
			bufout += pixelSize;
		}
	}
	return rout;
}

//-------------------------------------------------------------------

template <class T>
void doMakeStereoRaster(const TRasterPT<T> &rleft, const TRasterPT<T> &rright)
{

	int lx = rleft->getLx();
	int ly = rright->getLy();

	for (int i = 0; i < ly; i++) {
		T *pixl = rleft->pixels(i);
		T *pixr = rright->pixels(i);

		for (int j = 0; j < lx; j++, pixl++, pixr++) {
			pixl->g = pixr->g;
			pixl->b = pixr->b;
		}
	}
}

//---------------------------------------

void TRop::makeStereoRaster(const TRasterP &left, const TRasterP &right)
{
	assert(left->getSize() == right->getSize());

	left->lock();

	if ((TRaster32P)left && (TRaster32P)right)
		doMakeStereoRaster<TPixel32>(left, right);
	else if ((TRaster64P)left && (TRaster64P)right)
		doMakeStereoRaster<TPixel64>(left, right);
	else {
		left->unlock();
		throw TRopException("setChannel: unsupported pixel type");
	}

	left->unlock();
}

//-------------------------------------------------------------------
#ifndef TNZCORE_LIGHT

void TTile::addInCache(const TRasterP &raster)
{
	if (!raster) {
		m_rasterId = "";
		return;
	}
	TRasterP rin;

	m_rasterId = TImageCache::instance()->getUniqueId();
	if (raster->getParent()) {
		rin = raster->getParent();
		unsigned long offs = (raster->getRawData() - raster->getParent()->getRawData()) / raster->getPixelSize();
		m_subRect = TRect(TPoint(offs % raster->getWrap(), offs / raster->getWrap()), raster->getSize());
	} else {
		m_subRect = raster->getBounds();
		rin = raster;
	}

	if ((TRasterCM32P)rin)
		TImageCache::instance()->add(m_rasterId, TToonzImageP(rin, rin->getBounds()));
	else if ((TRaster32P)rin || (TRaster64P)rin)
		TImageCache::instance()->add(m_rasterId, TRasterImageP(rin));
	else if ((TRasterGR8P)rin || (TRasterGR16P)rin)
		TImageCache::instance()->add(m_rasterId, TRasterImageP(rin));
	else
		assert(false);
}

TTile::TTile(const TRasterP &raster)
	: m_pos(), m_subRect()
{
	addInCache(raster);
}

TTile::TTile(const TRasterP &raster, TPointD pos)
	: m_pos(pos), m_subRect()
{
	addInCache(raster);
}

void TTile::setRaster(const TRasterP &raster)
{
	if (m_rasterId != "")
		TImageCache::instance()->remove(m_rasterId);
	m_subRect = TRect();
	addInCache(raster);
}

TTile::~TTile()
{
	if (!m_rasterId.empty())
		TImageCache::instance()->remove(m_rasterId);
}

#endif