|
|
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 |
}
|