Blame c++/contourgl/swrender.cpp

93cbac
/*
93cbac
    ......... 2015 Ivan Mahonin
93cbac
93cbac
    This program is free software: you can redistribute it and/or modify
93cbac
    it under the terms of the GNU General Public License as published by
93cbac
    the Free Software Foundation, either version 3 of the License, or
93cbac
    (at your option) any later version.
93cbac
93cbac
    This program is distributed in the hope that it will be useful,
93cbac
    but WITHOUT ANY WARRANTY; without even the implied warranty of
93cbac
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
93cbac
    GNU General Public License for more details.
93cbac
93cbac
    You should have received a copy of the GNU General Public License
93cbac
    along with this program.  If not, see <http: licenses="" www.gnu.org="">.</http:>
93cbac
*/
93cbac
572d9c
#include "swrender.h"
93cbac
93cbac
93cbac
using namespace std;
93cbac
93cbac
572d9c
void SwRender::fill(
93cbac
	Surface &target,
93cbac
	const Color &color )
93cbac
{
93cbac
	for(Color *i = target.data, *end = i + target.count(); i != end; ++i)
93cbac
		*i = color;
93cbac
}
93cbac
572d9c
void SwRender::fill(
93cbac
	Surface &target,
93cbac
	const Color &color,
93cbac
	int left,
93cbac
	int top,
93cbac
	int width,
93cbac
	int height )
93cbac
{
93cbac
	int step = target.width - width;
93cbac
	for(Color *i = &target[top][left], *end = i + height*target.width; i < end; i += step)
93cbac
		for(Color *rowend = i + width; i < rowend; ++i)
93cbac
			*i = color;
93cbac
}
93cbac
572d9c
void SwRender::row(
93cbac
	Surface &target,
93cbac
	const Color &color,
93cbac
	int left,
93cbac
	int top,
93cbac
	int length )
93cbac
{
93cbac
	for(Color *i = &target[top][left], *end = i + length; i < end; ++i)
93cbac
		*i = color;
93cbac
}
93cbac
572d9c
void SwRender::row_alpha(
93cbac
	Surface &target,
93cbac
	const Color &color,
93cbac
	Color::type alpha,
93cbac
	int left,
93cbac
	int top,
93cbac
	int length )
93cbac
{
93cbac
	for(Color *i = &target[top][left], *end = i + length; i < end; ++i) {
9edf2e
		i->r = i->r*(1.f - alpha) + color.r*alpha;
9edf2e
		i->g = i->g*(1.f - alpha) + color.g*alpha;
9edf2e
		i->b = i->b*(1.f - alpha) + color.b*alpha;
9edf2e
		i->a = i->a*(1.f - alpha) + color.a*alpha;
93cbac
	}
93cbac
}
93cbac
572d9c
void SwRender::polyspan(
93cbac
	Surface &target,
93cbac
	const Polyspan &polyspan,
93cbac
	const Color &color,
93cbac
	bool evenodd,
93cbac
	bool invert )
93cbac
{
93cbac
	const ContextRect &window = polyspan.get_window();
93cbac
	const Polyspan::cover_array &covers = polyspan.get_covers();
93cbac
93cbac
	Polyspan::cover_array::const_iterator cur_mark = covers.begin();
93cbac
	Polyspan::cover_array::const_iterator end_mark = covers.end();
93cbac
93cbac
	Real cover = 0, area = 0, alpha = 0;
93cbac
	int	y = 0, x = 0;
93cbac
93cbac
	if (cur_mark == end_mark) {
93cbac
		// no marks at all
93cbac
		if (invert)
93cbac
			fill( target, color,
93cbac
				  window.minx, window.miny,
93cbac
				  window.maxx - window.minx, window.maxy - window.miny );
93cbac
		return;
93cbac
	}
93cbac
93cbac
	// fill initial rect / line
93cbac
	if (invert) {
93cbac
		// fill all the area above the first vertex
93cbac
		y = window.miny;
93cbac
		int l = window.maxx - window.minx;
93cbac
93cbac
		fill( target, color,
93cbac
			  window.minx, window.miny,
93cbac
			  l, cur_mark->y - window.miny );
93cbac
93cbac
		// fill the area to the left of the first vertex on that line
93cbac
		l = cur_mark->x - window.minx;
93cbac
		if (l)
93cbac
			row(target, color, window.minx, cur_mark->y, l);
93cbac
	}
93cbac
93cbac
	while(true) {
93cbac
		y = cur_mark->y;
93cbac
		x = cur_mark->x;
93cbac
93cbac
		area = cur_mark->area;
93cbac
		cover += cur_mark->cover;
93cbac
93cbac
		// accumulate for the current pixel
93cbac
		while(++cur_mark != covers.end()) {
93cbac
			if (y != cur_mark->y || x != cur_mark->x)
93cbac
				break;
93cbac
			area += cur_mark->area;
93cbac
			cover += cur_mark->cover;
93cbac
		}
93cbac
93cbac
		// draw pixel - based on covered area
93cbac
		if (area) { // if we're ok, draw the current pixel
93cbac
			alpha = polyspan.extract_alpha(cover - area, evenodd);
93cbac
			if (invert) alpha = 1 - alpha;
93cbac
			if (alpha) {
9edf2e
				Color::type a = (Color::type)alpha;
93cbac
				Color &c = target[y][x];
9edf2e
				c.r = c.r*(1.f - a) + color.r*a;
9edf2e
				c.g = c.g*(1.f - a) + color.g*a;
9edf2e
				c.b = c.b*(1.f - a) + color.b*a;
9edf2e
				c.a = c.a*(1.f - a) + color.a*a;
93cbac
			}
93cbac
			++x;
93cbac
		}
93cbac
93cbac
		// if we're done, don't use iterator and exit
93cbac
		if (cur_mark == end_mark)
93cbac
			break;
93cbac
93cbac
		// if there is no more live pixels on this line, goto next
93cbac
		if (y != cur_mark->y) {
93cbac
			if (invert) {
93cbac
				// fill the area at the end of the line
93cbac
				row(target, color, x, y, window.maxx - x);
93cbac
93cbac
				// fill area at the beginning of the next line
93cbac
				row(target, color, window.minx, cur_mark->y, cur_mark->x - window.minx);
93cbac
			}
93cbac
93cbac
			cover = 0;
93cbac
			continue;
93cbac
		}
93cbac
93cbac
		// draw span to next pixel - based on total amount of pixel cover
93cbac
		if (x < cur_mark->x) {
93cbac
			alpha = polyspan.extract_alpha(cover, evenodd);
93cbac
			if (invert) alpha = 1.0 - alpha;
93cbac
			if (alpha)
93cbac
				row_alpha(target, color, alpha, x, y, cur_mark->x - x);
93cbac
		}
93cbac
	}
93cbac
93cbac
	// fill the after stuff
93cbac
	if (invert) {
93cbac
		// fill the area at the end of the line
93cbac
		row(target, color, x, y, window.maxx - x);
93cbac
93cbac
		// fill area at the beginning of the next line
93cbac
		fill( target, color,
93cbac
			  window.minx, y+1,
93cbac
			  window.maxx - window.minx, window.maxy - y - 1 );
93cbac
	}
93cbac
}