Blame c++/iir_blur/surface.cpp

bw 249abc
/*
bw 8a6d22
    ......... 2016 Ivan Mahonin
bw 249abc
bw 249abc
    This program is free software: you can redistribute it and/or modify
bw 249abc
    it under the terms of the GNU General Public License as published by
bw 249abc
    the Free Software Foundation, either version 3 of the License, or
bw 249abc
    (at your option) any later version.
bw 249abc
bw 249abc
    This program is distributed in the hope that it will be useful,
bw 249abc
    but WITHOUT ANY WARRANTY; without even the implied warranty of
bw 249abc
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
bw 249abc
    GNU General Public License for more details.
bw 249abc
bw 249abc
    You should have received a copy of the GNU General Public License
bw 249abc
    along with this program.  If not, see <http: licenses="" www.gnu.org="">.</http:>
bw 249abc
*/
bw 249abc
bw 249abc
#include <cstring></cstring>
bw 249abc
#include <cmath></cmath>
bw 249abc
bw 249abc
#include <fstream></fstream>
bw 249abc
bw 249abc
#include "surface.h"
bw 249abc
bw 249abc
bw 249abc
using namespace std;
bw 249abc
bw 249abc
bw 249abc
Surface::Surface(int width, int height):
bw 249abc
	buffer(new Color[width*height]),
bw 249abc
	width(width),
bw 249abc
	height(height),
bw 249abc
	color(),
bw 249abc
	x(),
bw 249abc
	y(),
bw 249abc
	blending(true)
bw 249abc
{
bw 249abc
	memset(buffer, 0, sizeof(Color)*width*height);
bw 249abc
}
bw 249abc
bw 249abc
Surface::~Surface()
bw 249abc
	{ delete[] buffer; }
bw 249abc
bw 249abc
unsigned int Surface::convert_channel(double c) {
bw 249abc
	int i = (int)round(c*255.0);
bw 249abc
	return i < 0 ? 0 : i > 255 ? 255 : (unsigned char)i;
bw 249abc
}
bw 249abc
bw 249abc
unsigned int Surface::blend_channel(unsigned int a, unsigned int dest, unsigned int src)
bw 249abc
{
bw 8a6d22
	return ((dest*(255-a) + a*src) >> 8) & 0xff;
bw 249abc
}
bw 249abc
bw 249abc
Surface::Color Surface::convert_color(double r, double g, double b, double a) {
bw 249abc
	return  convert_channel(r)
bw 249abc
		 | (convert_channel(g) << 8)
bw 249abc
		 | (convert_channel(b) << 16)
bw 249abc
		 | (convert_channel(a) << 24);
bw 249abc
}
bw 249abc
bw 249abc
Surface::Color Surface::blend(Color dest, Color src) {
bw 249abc
	unsigned int sa = src >> 24;
bw 249abc
	if (sa >= 255) return src; else if (sa == 0) return dest;
bw 249abc
	unsigned int da = (dest >> 24) + sa;
bw 249abc
	if (da > 255) da = 255;
bw 8a6d22
	return  blend_channel(sa, dest & 0xff, src & 0xff)
bw 8a6d22
		 | (blend_channel(sa, (dest >> 8) & 0xff, (src >> 8) & 0xff) << 8)
bw 8a6d22
		 | (blend_channel(sa, (dest >> 16) & 0xff, (src >> 16) & 0xff) << 16)
bw 249abc
		 | (da << 24);
bw 249abc
}
bw 249abc
bw 249abc
void Surface::line(Color color, int x0, int y0, int x1, int y1, bool blending) {
bw 249abc
	if (x1 < x0) swap(x1, x0);
bw 249abc
	if (y1 < y0) swap(y1, y0);
bw 249abc
	int pdx = y1 - y0;
bw 249abc
	int pdy = x0 - x1;
bw 249abc
	int d = 0;
bw 249abc
	for(int x = x0, y = y0; x <= x1 && y <= y1;) {
bw 249abc
		if (blending) blend_point(x, y, color); else set_point(x, y, color);
bw 249abc
		if (abs(d+pdx) < abs(d+pdy))
bw 249abc
			{ d += pdx; ++x; } else { d += pdy; ++y; }
bw 249abc
	}
bw 249abc
}
bw 249abc
bw 249abc
void Surface::rect(Color color, int x0, int y0, int x1, int y1, bool blending) {
bw 249abc
	if (x1 < x0) swap(x1, x0);
bw 249abc
	if (y1 < y0) swap(y1, y0);
bw 249abc
	for(int x = x0; x < x1; ++x)
bw 249abc
		for(int y = y0; y < y1; ++y)
bw 249abc
			if (blending) blend_point(x, y, color); else set_point(x, y, color);
bw 249abc
}
bw 249abc
bw 249abc
void Surface::save(const string &filename) const
bw 249abc
{
bw 249abc
	// create file
bw 249abc
	ofstream f(("results/" + filename).c_str(), ofstream::out | ofstream::trunc | ofstream::binary);
bw 249abc
bw 249abc
	// write header
bw 249abc
	unsigned char targa_header[] = {
bw 249abc
		0,    // Length of the image ID field (0 - no ID field)
bw 249abc
		0,    // Whether a color map is included (0 - no colormap)
bw 249abc
		2,    // Compression and color types (2 - uncompressed true-color image)
bw 249abc
		0, 0, 0, 0, 0, // Color map specification (not need for us)
bw 249abc
		0, 0, // X-origin
bw 249abc
		0, 0, // Y-origin
bw 249abc
		(unsigned char)(width & 0xff), // Image width
bw 249abc
		(unsigned char)(width >> 8),
bw 249abc
		(unsigned char)(height & 0xff), // Image height
bw 249abc
		(unsigned char)(height >> 8),
bw 249abc
		32,   // Bits per pixel
bw 249abc
		0     // Image descriptor (keep zero for capability)
bw 249abc
	};
bw 249abc
	f.write((char*)targa_header, sizeof(targa_header));
bw 249abc
bw 249abc
	// write data
bw 249abc
	if (true) {
bw 249abc
		int line_size = 4*width;
bw 249abc
		const char *end = (char*)buffer;
bw 249abc
		const char *current = end + height*line_size;
bw 249abc
		while(current > end) {
bw 249abc
			current -= line_size;
bw 249abc
			f.write(current, line_size);
bw 249abc
		}
bw 249abc
	} else {
bw 249abc
		f.write((const char*)buffer, 4*width*height);
bw 249abc
	}
bw 249abc
}