Blob Blame Raw
#pragma once

#ifndef T_RASTER_INCLUDED
#define T_RASTER_INCLUDED

#include "tutil.h"
#include "tgeometry.h"
#include "tpixel.h"
#include "tpixelgr.h"
#include "tsmartpointer.h"
#include "tbigmemorymanager.h"

#undef DVAPI
#undef DVVAR
#ifdef TRASTER_EXPORTS
#define DVAPI DV_EXPORT_API
#define DVVAR DV_EXPORT_VAR
#else
#define DVAPI DV_IMPORT_API
#define DVVAR DV_IMPORT_VAR
#endif

//=========================================================

class DVAPI TRasterType
{
	int m_id;

	/*
public:
	enum Type {
		None,
		BW,
		WB,
		RGBM32,  // LPIXEL, matte channel considered
		RGBM64,  // SPIXEL, matte channel considered 
		CM8,     // color-mapped,  8 bits 
		GR8,     // grey tones, 8 bits 
		CM16,    // color-mapped, 16 bits 
		GR16,    // grey tones, 16 bits 
		RGB555,
		RGB565,
		CM24,    // cmapped, 8+8+8 bits (ink, paint, ramp), +8 bits spare (MSB)
		CM16S12,
		CM16S8   // cmapped, 16 bits, standard SGI 256-color colormap
		// ....
	};
*/

public:
	TRasterType(int id) : m_id(id){};
	int getId() const { return m_id; };
	bool operator==(TRasterType a) { return m_id == a.m_id; };
	bool operator!=(TRasterType a) { return m_id != a.m_id; };
};

//=========================================================

// forward declaration
template <class T>
class TRasterPT;
class TRaster;
typedef TSmartPointerT<TRaster> TRasterP;

//=========================================================
/*!This class stores bitmap images. */
class DVAPI TRaster : public TSmartObject
{

	DECLARE_CLASS_CODE

protected:
	int m_pixelSize;
	int m_lx, m_ly;
	int m_wrap;
	int m_lockCount;
	TRaster *m_parent; // nel caso di sotto-raster
	UCHAR *m_buffer;
	bool m_bufferOwner;
	// i costruttori sono qui per centralizzare la gestione della memoria
	// e' comunque impossibile fare new TRaster perche' e' una classe astratta (clone, extract)

	// crea il buffer associato (NON fa addRef())
	TRaster(int lx, int ly, int pixelSize);

	// si attacca ad un buffer pre-esistente (NON fa addRef() - neanche a parent)
	TRaster(int lx, int ly, int pixelSize,
			int wrap, UCHAR *buffer, TRaster *parent, bool bufferOwner = false);

private:
	static TAtomicVar m_totalMemory;
	TThread::Mutex m_mutex;
	// not implemented
	TRaster(const TRaster &);
	TRaster &operator=(const TRaster &);

public:
#ifdef _DEBUG
	bool m_cashed;
	static unsigned long getTotalMemoryInKB();
#endif

	virtual ~TRaster();

	// accessors
	// TRasterType getType() const {return m_type;};
	int getLx() const { return m_lx; };
	int getLy() const { return m_ly; };
	TDimension getSize() const { return TDimension(m_lx, m_ly); };

	//!Returns the length of a row in pixel.
	int getWrap() const { return m_wrap; }; // lunghezza di una riga in pixel

	TPointD getCenterD() const { return TPointD(0.5 * m_lx, 0.5 * m_ly); };
	TPoint getCenter() const { return TPoint(m_lx / 2, m_ly / 2); };
	TRect getBounds() const { return TRect(0, 0, m_lx - 1, m_ly - 1); };
	int getPixelSize() const { return m_pixelSize; };

	int getRowSize() const { return m_pixelSize * m_lx; };
	// in bytes

	//when the bigMemoryManager is active, remapping can change buffers...need to to lock/unlock them o use them.

	void lock()
	{
		if (!TBigMemoryManager::instance()->isActive())
			return;
		TThread::MutexLocker sl(&m_mutex);
		if (m_parent)
			m_parent->lock();
		else
			++m_lockCount;
	}
	void unlock()
	{
		if (!TBigMemoryManager::instance()->isActive())
			return;
		TThread::MutexLocker sl(&m_mutex);
		if (m_parent)
			m_parent->unlock();
		else {
			assert(m_lockCount > 0);
			--m_lockCount;
		}
	}
	void beginRemapping();
	void endRemapping();
	//!Returns a pointer to the image buffer.
	//WARNING!!!!! before getting the buffer with getRawData(),
	//you have to lock the raster with'lock method, and unlock
	//it when you've done with the buffer
	const UCHAR *getRawData() const { return m_buffer; };

	UCHAR *getRawData() { return m_buffer; };
	//!Returns a pointer to the image buffer positioned in the (x,y) coords.
	const UCHAR *getRawData(int x, int y) const
	{
		assert(0 <= x && x < m_lx && 0 <= y && y < m_ly);
		return m_buffer + (y * m_wrap + x) * m_pixelSize;
	};
	UCHAR *getRawData(int x, int y)
	{
		assert(0 <= x && x < m_lx && 0 <= y && y < m_ly);
		return m_buffer + (y * m_wrap + x) * m_pixelSize;
	};
	bool isEmpty() const { return getSize() == TDimension(); };

	TRasterP getParent() { return m_parent; }
	// creazione di TRaster derivati

	// devono essere virtuali puri perche' il nuovo raster creato deve essere del tipo giusto
	virtual TRasterP clone() const = 0;
	virtual TRasterP extract(TRect &rect) = 0;
	virtual TRasterP create() const = 0;
	virtual TRasterP create(int lx, int ly) const = 0;

	// definita in termini di extract(rect); non lo posso fare subito perche' manca il
	// costruttore di copia di TRasterP
	inline virtual TRasterP extract(int x0, int y0, int x1, int y1);

	// operazioni sui pixel

	// Copia il contenuto di src (spostato di offset) nel raster corrente.
	// Il tipo deve essere lo stesso
	// In caso di dimensione diversa l'area copiata e' l'intersezione dei due getBounds()
	// e i due raster sono allineati in basso a sinistra (src[0,0] -> dst[offset])
	/*!Copies the content of the source raster in the current raster.
     */
	void copy(const TRasterP &src, const TPoint &offset = TPoint());

	void xMirror();
	void yMirror();
	void rotate180();
	void rotate90();

	void clear();
	void clearOutside(const TRect &rect);

	friend class TBigMemoryManager;

protected:
	void fillRawData(const UCHAR *pixel);
	void fillRawDataOutside(const TRect &rect, const UCHAR *pixel);

private:
	void remap(UCHAR *newLocation);
};

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

//
// Smart Pointer a TRaster
//

#ifdef _WIN32
template class DVAPI TSmartPointerT<TRaster>;
#endif

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

inline void detach(TRasterP &r)
{
	if (!r || r->getRefCount() == 1)
		return;
	TRasterP tmp(r->clone());
	r = tmp;
}

//=========================================================

// forward declaration
template <class T>
class TRasterT;

//
// TRasterPT<Pixel>:
//
// Smart Pointer to TRasterT<Pixel>
//

//!\include raster_ex1.cpp
//! \include rasterpt_ex1.cpp
// class TRasterPT<T>
template <class T>
class TRasterPT : public TSmartPointerT<TRasterT<T>>
{

public:
	typedef T Pixel;
	typedef TRasterT<T> Raster;

	TRasterPT(){};

	TRasterPT(int lx, int ly) { create(lx, ly); };
	TRasterPT(const TDimension &d) { create(d.lx, d.ly); };

	inline TRasterPT(const TRasterP &src);
	inline TRasterPT(int lx, int ly, int wrap, T *buffer, bool bufferOwner = false);

	~TRasterPT(){};

	void create(int lx, int ly);
	void create(const TDimension &d) { create(d.lx, d.ly); };

	inline void detach();

	operator TRasterP() const;
};

//=========================================================

//
// TRasterT<Pixel>
//
// e' la classe concreta che discende da TRaster

template <class T>
class TRasterT : public TRaster
{
protected:
	// Constructors are protected to prevent direct allocation of TRasterT instances.
	// Users must adopt the TRasterPT smart pointer syntax instead.

	// Buffer Allocation
	TRasterT(int lx, int ly) : TRaster(lx, ly, sizeof(T)) {}

	// Buffer Attachment
	TRasterT(int lx, int ly, int wrap, T *buffer, TRasterT<T> *parent, bool bufferOwner = false)
		: TRaster(lx, ly, sizeof(T), wrap, reinterpret_cast<UCHAR *>(buffer), parent, bufferOwner) {}

public:
	typedef T Pixel;

	~TRasterT(){};

	// accessors
	//WARNING!!!!! before getting the buffer with pixels(int y),
	//you have to lock the raster with'lock method, and unlock
	//it when you've done with the buffer

	const T *pixels(int y = 0) const
	{
		assert(0 <= y && y < getLy());
		return reinterpret_cast<T *>(m_buffer) + getWrap() * y;
	};
	T *pixels(int y = 0)
	{
		assert(0 <= y && y < getLy());
		return reinterpret_cast<T *>(m_buffer) + getWrap() * y;
	};

	// Derived rasters creation

	TRasterP clone() const
	{
		TRasterP dst = TRasterPT<T>(m_lx, m_ly);
		TRasterP src(const_cast<TRaster *>((const TRaster *)this));
		dst->copy(src);
		return dst;
	}

	TRasterP create() const
	{
		return TRasterPT<T>(m_lx, m_ly);
	}

	virtual TRasterP create(int lx, int ly) const
	{
		return TRasterPT<T>(lx, ly);
	}

	//!\include raster_ex2.cpp
	TRasterP extract(int x0, int y0, int x1, int y1)
	{
		TRect rect(x0, y0, x1, y1);
		return extract(rect);
	};

	TRasterP extract(TRect &rect)
	{
		if (isEmpty() || getBounds().overlaps(rect) == false)
			return TRasterP();
		rect = getBounds() * rect;
		//addRef();
		return TRasterP(
			new TRasterT<T>(rect.getLx(), rect.getLy(), m_wrap,
							pixels(rect.y0) + rect.x0, this));
	};

	TRasterPT<T> extractT(TRect &rect);

	TRasterPT<T> extractT(int x0, int y0, int x1, int y1)
	{
		TRect rect(x0, y0, x1, y1);
		return extractT(rect);
	};

	friend class TRasterPT<T>;

	// Pixel Operations
	void fill(const T &a)
	{
		fillRawData(reinterpret_cast<const UCHAR *>(&a));
	}

	void fillOutside(const TRect &rect, const T &a)
	{
		fillRawDataOutside(rect, reinterpret_cast<const UCHAR *>(&a));
	}
};

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

inline TRasterP TRaster::extract(int x0, int y0, int x1, int y1)
{
	TRect rect(x0, y0, x1, y1);
	return extract(rect);
}

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

template <class T>
TRasterPT<T> TRasterT<T>::extractT(TRect &rect)
{
	if (isEmpty() || getBounds().overlaps(rect) == false) {
		return TRasterPT<T>();
	}
	rect = getBounds() * rect;
	//addRef();
	return TRasterPT<T>(
		new TRasterT<T>(rect.getLx(), rect.getLy(), m_wrap,
						pixels(rect.y0) + rect.x0, this));
}

//=========================================================
//
// metodi inline di TRasterPT
// (n.b. se non si fanno esplicitament "inline" NT si confonde con dll exort/import)
//

template <class T>
inline TRasterPT<T>::TRasterPT(const TRasterP &src)
{
	TSmartPointerT<TRasterT<T>>::m_pointer = dynamic_cast<TRasterT<T> *>(src.getPointer());
	if (TSmartPointerT<TRasterT<T>>::m_pointer)
		TSmartPointerT<TRasterT<T>>::m_pointer->addRef();
}

template <class T>
inline void TRasterPT<T>::create(int lx, int ly)
{
	TRasterT<T> *raster = new TRasterT<T>(lx, ly);
	*this = TRasterPT<T>(raster);
}

template <class T>
inline void TRasterPT<T>::detach()
{
	if (!TSmartPointerT<TRasterT<T>>::m_pointer || TSmartPointerT<TRasterT<T>>::m_pointer->getRefCount() == 1)
		return;
	*this = TRasterPT(TSmartPointerT<TRasterT<T>>::m_pointer->clone());
	// uso l'operator di assign per aggiornare correttamente
	// i reference counts del vecchio e del nuovo raster
}

template <class T>
inline TRasterPT<T>::operator TRasterP() const
{
	return TRasterP(TSmartPointerT<TRasterT<T>>::m_pointer);
}

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

template <class T>
inline TRasterPT<T>::TRasterPT(int lx, int ly, int wrap, T *buffer, bool bufferOwner)
{
	TSmartPointerT<TRasterT<T>>::m_pointer = new TRasterT<T>(lx, ly, wrap, buffer, 0, bufferOwner);
	TSmartPointerT<TRasterT<T>>::m_pointer->addRef();
}

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

#ifdef _WIN32
// su NT e' necessario per evitare un warning nelle classi
// esportate che si riferiscono a TRaster32P/TRaster64P
// su IRIX non compila perche' non riesce ad instanziare le
// funzioni online (!!!)

template class DVAPI TSmartPointerT<TRasterT<TPixel32>>;
template class DVAPI TRasterPT<TPixel32>;

template class DVAPI TSmartPointerT<TRasterT<TPixel64>>;
template class DVAPI TRasterPT<TPixel64>;

template class DVAPI TSmartPointerT<TRasterT<TPixelGR8>>;
template class DVAPI TRasterPT<TPixelGR8>;

template class DVAPI TSmartPointerT<TRasterT<TPixelGR16>>;
template class DVAPI TRasterPT<TPixelGR16>;

template class DVAPI TSmartPointerT<TRasterT<TPixelGRD>>;
template class DVAPI TRasterPT<TPixelGRD>;

template class DVAPI TSmartPointerT<TRasterT<TPixelCY>>;
template class DVAPI TRasterPT<TPixelCY>;

#endif

typedef TRasterPT<TPixel32> TRaster32P;
typedef TRasterPT<TPixel64> TRaster64P;
typedef TRasterPT<TPixelGR8> TRasterGR8P;
typedef TRasterPT<TPixelGR16> TRasterGR16P;
typedef TRasterPT<TPixelGRD> TRasterGRDP;
typedef TRasterPT<TPixelCY> TRasterYUV422P;

//=========================================================

//=========================================================

#endif //__T_RASTER_INCLUDED