Blame c++/perspective/src/surface.cpp

Ivan Mahonin 531f67
Ivan Mahonin 531f67
#include "surface.h"
Ivan Mahonin 531f67
Ivan Mahonin 531f67
Ivan Mahonin 531f67
Surface::Surface():
Ivan Mahonin 531f67
	m_width(), m_height(), m_pitch(), m_origin() { }
Ivan Mahonin 531f67
Ivan Mahonin 531f67
Surface::Surface(const Surface &):
Ivan Mahonin 531f67
	m_width(), m_height(), m_pitch(), m_origin() { }
Ivan Mahonin 531f67
Ivan Mahonin 531f67
void
Ivan Mahonin 531f67
Surface::reset() {
Ivan Mahonin 531f67
	m_width = m_height = m_pitch = 0;
Ivan Mahonin 531f67
	m_origin = NULL;
Ivan Mahonin 531f67
}
Ivan Mahonin 531f67
Ivan Mahonin 4dc49c
void
Ivan Mahonin 4dc49c
Surface::mult_alpha() {
Ivan Mahonin 4dc49c
	if (empty()) return;
Ivan Mahonin 4dc49c
	const int h = height();
Ivan Mahonin 4dc49c
	const int w = width();
Ivan Mahonin 4dc49c
	const int dr = pitch() - width();
Ivan Mahonin 4dc49c
	Color *c = m_origin;
Ivan Mahonin 4dc49c
	for(int r = 0; r < h; ++r, c += dr)
Ivan Mahonin 4dc49c
		for(Color *end = c + w; c != end; ++c)
Ivan Mahonin 4dc49c
			c->mult_alpha();
Ivan Mahonin 4dc49c
}
Ivan Mahonin 4dc49c
Ivan Mahonin 4dc49c
void
Ivan Mahonin 4dc49c
Surface::demult_alpha() {
Ivan Mahonin 4dc49c
	if (empty()) return;
Ivan Mahonin 4dc49c
	const int h = height();
Ivan Mahonin 4dc49c
	const int w = width();
Ivan Mahonin 4dc49c
	const int dr = pitch() - width();
Ivan Mahonin 4dc49c
	Color *c = m_origin;
Ivan Mahonin 4dc49c
	for(int r = 0; r < h; ++r, c += dr)
Ivan Mahonin 4dc49c
		for(Color *end = c + w; c != end; ++c)
Ivan Mahonin 4dc49c
			c->demult_alpha();
Ivan Mahonin 4dc49c
}
Ivan Mahonin 4dc49c
Ivan Mahonin 4dc49c
Color
Ivan Mahonin 4dc49c
Surface::get_pixel(Real x, Real y) const {
Ivan Mahonin 4dc49c
	// linear interpolation
Ivan Mahonin 4dc49c
	if ( empty()
Ivan Mahonin 4dc49c
	  || x < 0 || x > width() - 1
Ivan Mahonin 4dc49c
	  || y < 0 || y > height() - 1 )
Ivan Mahonin 4dc49c
		return Color();
Ivan Mahonin 4dc49c
	
Ivan Mahonin 4dc49c
	int x0 = (int)floor(x), x1 = x0 + 1;
Ivan Mahonin 4dc49c
	int y0 = (int)floor(y), y1 = y0 + 1;
Ivan Mahonin 4dc49c
	Real px = x - x0, ppx = 1.0 - px;
Ivan Mahonin 4dc49c
	Real py = y - y0, ppy = 1.0 - py;
Ivan Mahonin 4dc49c
	
Ivan Mahonin 4dc49c
	x0 = iclamp(x0, 0, width() - 1);
Ivan Mahonin 4dc49c
	x1 = iclamp(x1, 0, width() - 1);
Ivan Mahonin 4dc49c
	y0 = iclamp(y0, 0, height() - 1);
Ivan Mahonin 4dc49c
	y1 = iclamp(y1, 0, height() - 1);
Ivan Mahonin 4dc49c
Ivan Mahonin 4dc49c
	Real k[] = { ppx*ppy, px*ppy, ppx*py, px*py };
Ivan Mahonin 4dc49c
	const Color *corners[] = { &row(y0)[x0], &row(y0)[x1], &row(y1)[x0], &row(y1)[x1] };
Ivan Mahonin 4dc49c
	Color sum;
Ivan Mahonin 4dc49c
	for(int i = 0; i < 4; ++i) {
Ivan Mahonin 4dc49c
		const Color &c = *corners[i];
Ivan Mahonin 4dc49c
		Real a = c.a * k[i];
Ivan Mahonin 4dc49c
		for(int j = 0; j < 3; ++j)
Ivan Mahonin 4dc49c
			sum.channels[j] += c.channels[j]*a;
Ivan Mahonin 4dc49c
		sum.a += a;
Ivan Mahonin 4dc49c
	}
Ivan Mahonin 4dc49c
	
Ivan Mahonin 4dc49c
	if (sum.a <= real_precision)
Ivan Mahonin 4dc49c
		return Color();
Ivan Mahonin 4dc49c
Ivan Mahonin 4dc49c
	Real aa = 1.0/sum.a;
Ivan Mahonin 4dc49c
	for(int j = 0; j < 3; ++j)
Ivan Mahonin 4dc49c
		sum.channels[j] *= aa;
Ivan Mahonin 4dc49c
	return sum;
Ivan Mahonin 4dc49c
}
Ivan Mahonin 4dc49c
Ivan Mahonin 4dc49c
Color
Ivan Mahonin 4dc49c
Surface::get_pixel_premulted(Real x, Real y) const {
Ivan Mahonin 4dc49c
	// linear interpolation
Ivan Mahonin 4dc49c
	if ( empty()
Ivan Mahonin 4dc49c
	  || x < 0 || x > width() - 1
Ivan Mahonin 4dc49c
	  || y < 0 || y > height() - 1 )
Ivan Mahonin 4dc49c
		return Color();
Ivan Mahonin 4dc49c
	
Ivan Mahonin 4dc49c
	int x0 = (int)floor(x), x1 = x0 + 1;
Ivan Mahonin 4dc49c
	int y0 = (int)floor(y), y1 = y0 + 1;
Ivan Mahonin 4dc49c
	Real px = x - x0, ppx = 1.0 - px;
Ivan Mahonin 4dc49c
	Real py = y - y0, ppy = 1.0 - py;
Ivan Mahonin 4dc49c
	
Ivan Mahonin 4dc49c
	x0 = iclamp(x0, 0, width() - 1);
Ivan Mahonin 4dc49c
	x1 = iclamp(x1, 0, width() - 1);
Ivan Mahonin 4dc49c
	y0 = iclamp(y0, 0, height() - 1);
Ivan Mahonin 4dc49c
	y1 = iclamp(y1, 0, height() - 1);
Ivan Mahonin 4dc49c
Ivan Mahonin 4dc49c
	Color sum;
Ivan Mahonin 4dc49c
	Real k[] = { ppx*ppy, px*ppy, ppx*py, px*py };
Ivan Mahonin 4dc49c
	const Color *corners[] = { &row(y0)[x0], &row(y0)[x1], &row(y1)[x0], &row(y1)[x1] };
Ivan Mahonin 4dc49c
	for(int i = 0; i < 4; ++i)
Ivan Mahonin 4dc49c
		for(int j = 0; j < 4; ++j)
Ivan Mahonin 4dc49c
			sum.channels[j] += corners[i]->channels[j]*k[i];
Ivan Mahonin 4dc49c
	return sum;
Ivan Mahonin 4dc49c
}
Ivan Mahonin 4dc49c
Ivan Mahonin 531f67
void Surface::copy(int width, int height, const Color *src_origin, Color *dest_origin, int src_pitch, int dest_pitch) {
Ivan Mahonin 531f67
#ifndef NDEBUG
Ivan Mahonin 531f67
	{ // check source and destination ranges
Ivan Mahonin 531f67
		assert(dest_origin);
Ivan Mahonin 531f67
		assert(src_origin);
Ivan Mahonin 531f67
		
Ivan Mahonin 531f67
		Color *dest_begin = dest_origin + begin_offset(width, height, dest_pitch),
Ivan Mahonin 531f67
		      *dest_end   = dest_origin + end_offset(width, height, dest_pitch);
Ivan Mahonin 531f67
		const Color *src_begin = src_origin + begin_offset(width, height, src_pitch),
Ivan Mahonin 531f67
		            *src_end   = src_origin + end_offset(width, height, src_pitch);
Ivan Mahonin 531f67
		assert(src_end <= dest_begin || dest_end <= src_begin);
Ivan Mahonin 531f67
	}
Ivan Mahonin 531f67
#endif
Ivan Mahonin 531f67
	
Ivan Mahonin 531f67
	if (!src_pitch) src_pitch = width;
Ivan Mahonin 531f67
	if (!dest_pitch) dest_pitch = width;
Ivan Mahonin 531f67
Ivan Mahonin 531f67
	const Color *src_row = src_origin;
Ivan Mahonin 531f67
	for( Color *dest_row = dest_origin, *dest_row_end = dest_row + height*dest_pitch;
Ivan Mahonin 531f67
		 dest_row != dest_row_end;
Ivan Mahonin 531f67
		 dest_row += dest_pitch, src_row += src_pitch )
Ivan Mahonin 531f67
	{
Ivan Mahonin 531f67
		const Color *src_col = src_row;
Ivan Mahonin 531f67
		for( Color *dest_col = dest_row, *dest_col_end = dest_col + width;
Ivan Mahonin 531f67
			dest_col != dest_col_end;
Ivan Mahonin 531f67
			++dest_col, ++src_col )
Ivan Mahonin 531f67
		{ *dest_col = *src_col; }
Ivan Mahonin 531f67
	}
Ivan Mahonin 531f67
}
Ivan Mahonin 531f67
Ivan Mahonin a1942e
Glib::RefPtr<Gdk::Pixbuf>
Ivan Mahonin a1942e
Surface::to_pixbuf() const {
Ivan Mahonin a1942e
	if (empty())
Ivan Mahonin a1942e
		return Glib::RefPtr<Gdk::Pixbuf>();
Ivan Mahonin a1942e
	Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create(
Ivan Mahonin a1942e
		Gdk::COLORSPACE_RGB, true, 8, width(), height() );
Ivan Mahonin a1942e
	guint8 *pixels = pixbuf->get_pixels();
Ivan Mahonin a1942e
	int stride = pixbuf->get_rowstride();
Ivan Mahonin a1942e
	for(int r = 0; r < height(); ++r) {
Ivan Mahonin a1942e
		const Color *src_row = row(r);
Ivan Mahonin a1942e
		guint8 *pixel = pixels;
Ivan Mahonin a1942e
		pixels += stride;
Ivan Mahonin a1942e
		for(int c = 0; c < width(); ++c) {
Ivan Mahonin a1942e
			const Color &color = src_row[c];
Ivan Mahonin a1942e
			*(pixel++) = (guint8)(color.b*255.9);
Ivan Mahonin 57974f
			*(pixel++) = (guint8)(color.g*255.9);
Ivan Mahonin 57974f
			*(pixel++) = (guint8)(color.r*255.9);
Ivan Mahonin a1942e
			*(pixel++) = (guint8)(color.a*255.9);
Ivan Mahonin a1942e
		}
Ivan Mahonin a1942e
	}
Ivan Mahonin a1942e
	return pixbuf;
Ivan Mahonin a1942e
}
Ivan Mahonin a1942e
Ivan Mahonin a1942e
Cairo::RefPtr<Cairo::ImageSurface>
Ivan Mahonin 4dc49c
Surface::to_cairo_surface(bool premulted) const {
Ivan Mahonin a1942e
	if (empty())
Ivan Mahonin a1942e
		return Cairo::RefPtr<Cairo::ImageSurface>();
Ivan Mahonin a1942e
	Cairo::RefPtr<Cairo::ImageSurface> cairo_surface =
Ivan Mahonin a1942e
		Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, width(), height());
Ivan Mahonin a1942e
	cairo_surface->flush();
Ivan Mahonin a1942e
	unsigned char *pixels = cairo_surface->get_data();
Ivan Mahonin a1942e
	int stride = cairo_surface->get_stride();
Ivan Mahonin a1942e
	for(int r = 0; r < height(); ++r) {
Ivan Mahonin a1942e
		const Color *src_row = row(r);
Ivan Mahonin a1942e
		unsigned char *pixel = pixels;
Ivan Mahonin a1942e
		pixels += stride;
Ivan Mahonin a1942e
		for(int c = 0; c < width(); ++c) {
Ivan Mahonin 4dc49c
			Color color = src_row[c];
Ivan Mahonin 4dc49c
			if (!premulted) color.mult_alpha();
Ivan Mahonin a1942e
			*(pixel++) = (guint8)(color.b*255.9);
Ivan Mahonin 57974f
			*(pixel++) = (guint8)(color.g*255.9);
Ivan Mahonin 57974f
			*(pixel++) = (guint8)(color.r*255.9);
Ivan Mahonin a1942e
			*(pixel++) = (guint8)(color.a*255.9);
Ivan Mahonin a1942e
		}
Ivan Mahonin a1942e
	}
Ivan Mahonin a1942e
	cairo_surface->mark_dirty();
Ivan Mahonin a1942e
	return cairo_surface;
Ivan Mahonin a1942e
}
Ivan Mahonin a1942e
Ivan Mahonin 531f67
Ivan Mahonin 531f67
void DataSurface::clear() {
Ivan Mahonin 531f67
	if (Color *data = data_begin()) delete[] data;
Ivan Mahonin 531f67
	reset();
Ivan Mahonin 531f67
}
Ivan Mahonin 531f67
Ivan Mahonin 531f67
void DataSurface::init(int width, int height, int pitch, const Color *src_origin, int src_pitch) {
Ivan Mahonin 531f67
	Color *origin = NULL;
Ivan Mahonin 531f67
	if (width > 0 && height > 0) {
Ivan Mahonin 531f67
		if (!pitch) pitch = width;
Ivan Mahonin 531f67
		
Ivan Mahonin 531f67
		int count = data_count(width, height, pitch);
Ivan Mahonin 531f67
		int offset = begin_offset(width, height, pitch);
Ivan Mahonin 531f67
		Color *data = new Color[count];
Ivan Mahonin 531f67
		origin = data - offset;
Ivan Mahonin 531f67
		
Ivan Mahonin 531f67
		if (src_origin)
Ivan Mahonin 531f67
			copy(width, height, src_origin, origin, src_pitch, pitch);
Ivan Mahonin 531f67
	} else {
Ivan Mahonin 531f67
		width = 0;
Ivan Mahonin 531f67
		height = 0;
Ivan Mahonin 531f67
		pitch = 0;
Ivan Mahonin 531f67
	}
Ivan Mahonin 531f67
	
Ivan Mahonin 531f67
	clear();
Ivan Mahonin 531f67
	m_width = width;
Ivan Mahonin 531f67
	m_height = height;
Ivan Mahonin 531f67
	m_pitch = pitch;
Ivan Mahonin 531f67
	m_origin = origin;
Ivan Mahonin 531f67
}
Ivan Mahonin 531f67
Ivan Mahonin 531f67
Ivan Mahonin 531f67
void AliasSurface::init(Color *origin, int width, int height, int pitch) {
Ivan Mahonin 531f67
	clear();
Ivan Mahonin 531f67
	if (origin && width > 0 && height > 0) {
Ivan Mahonin 531f67
		m_width = width;
Ivan Mahonin 531f67
		m_height = height;
Ivan Mahonin 531f67
		m_pitch = pitch ? pitch : width;
Ivan Mahonin 531f67
		m_origin = origin;
Ivan Mahonin 531f67
	}
Ivan Mahonin 531f67
}