#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