Blame c++/contourgl/test.cpp

93cbac
/*
a7622f
    ......... 2015-2018 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
93cbac
#include <fstream></fstream>
93cbac
#include <iostream></iostream>
c7fa36
#include <iomanip></iomanip>
93cbac
93cbac
#include "test.h"
93cbac
#include "contourbuilder.h"
8cd87e
#include "triangulator.h"
49e693
#include "measure.h"
49e693
#include "utils.h"
d989ab
#include "clrender.h"
93cbac
6fa009
#ifdef CUDA
6fa009
#include "cudarender.h"
6fa009
#endif
93cbac
93cbac
using namespace std;
93cbac
93cbac
d9c2d9
void Test::draw_contour(
d9c2d9
	Environment &e,
d9c2d9
	int start,
d9c2d9
	int count,
d9c2d9
	const rect<int> bounds,</int>
d9c2d9
	bool even_odd,
d9c2d9
	bool invert,
d9c2d9
	const Color &color
d9c2d9
) {
d9c2d9
	glScissor(bounds.p0.x, bounds.p0.y, bounds.p1.x-bounds.p0.x, bounds.p1.y-bounds.p0.y);
d9c2d9
	glEnable(GL_SCISSOR_TEST);
49e693
	glEnable(GL_STENCIL_TEST);
93cbac
49e693
	// render mask
a04770
	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
49e693
	glClear(GL_STENCIL_BUFFER_BIT);
49e693
	glStencilFunc(GL_ALWAYS, 0, 0);
49e693
	if (even_odd) {
49e693
		glStencilOp(GL_INCR_WRAP, GL_INCR_WRAP, GL_INCR_WRAP);
93cbac
	} else {
49e693
		glStencilOpSeparate(GL_FRONT, GL_INCR_WRAP, GL_INCR_WRAP, GL_INCR_WRAP);
49e693
		glStencilOpSeparate(GL_BACK, GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP);
49e693
	}
49e693
	e.shaders.simple();
d9c2d9
	glDrawArrays(GL_TRIANGLE_FAN, start, count);
a04770
	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
49e693
49e693
	// fill mask
49e693
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
49e693
	if (!even_odd && !invert)
49e693
		glStencilFunc(GL_NOTEQUAL, 0, -1);
49e693
	if (!even_odd &&  invert)
49e693
		glStencilFunc(GL_EQUAL, 0, -1);
49e693
	if ( even_odd && !invert)
49e693
		glStencilFunc(GL_EQUAL, 1, 1);
49e693
	if ( even_odd &&  invert)
49e693
		glStencilFunc(GL_EQUAL, 0, 1);
49e693
49e693
	e.shaders.color(color);
49e693
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
49e693
49e693
	glDisable(GL_STENCIL_TEST);
d9c2d9
	glDisable(GL_SCISSOR_TEST);
7c6b57
}
7c6b57
f29469
void Test::load(Data &contours, const std::string &filename) {
9edf2e
	vector<vector> groups;</vector>
9edf2e
	groups.push_back(Vector());
9edf2e
f29469
	ifstream f(("data/" + filename).c_str());
9edf2e
	int vertices_count = 0;
9edf2e
	while(f) {
9edf2e
		string s;
9edf2e
		f >> s;
9edf2e
		if (s == "g") {
9edf2e
			Vector t;
9edf2e
			f >> t.x >> t.y;
9edf2e
			groups.push_back(groups.back() + t);
9edf2e
		} else
9edf2e
		if (s == "end") {
9edf2e
			groups.pop_back();
9edf2e
			if ((int)groups.size() == 1)
9edf2e
				break;
9edf2e
		} else
9edf2e
		if (s == "path") {
9edf2e
			contours.push_back(ContourInfo());
9edf2e
			ContourInfo &ci = contours.back();
9edf2e
			f >> ci.invert
9edf2e
			  >> ci.antialias
9edf2e
			  >> ci.evenodd
9edf2e
			  >> ci.color.r
9edf2e
			  >> ci.color.g
9edf2e
			  >> ci.color.b
9edf2e
			  >> ci.color.a;
9edf2e
			bool closed = true;
9edf2e
			while(true) {
9edf2e
				f >> s;
9edf2e
				Vector p1;
9edf2e
				if (s == "M") {
9edf2e
					f >> p1.x >> p1.y;
9edf2e
					ci.contour.move_to(p1 + groups.back());
9edf2e
					closed = false;
9edf2e
				} else
9edf2e
				if (s == "L") {
9edf2e
					f >> p1.x >> p1.y;
9edf2e
					if (closed) {
9edf2e
						ci.contour.move_to(p1 + groups.back());
9edf2e
						closed = false;
9edf2e
					}
9edf2e
					ci.contour.line_to(p1 + groups.back());
9edf2e
				} else
9edf2e
				if (s == "Z") {
9edf2e
					ci.contour.close();
9edf2e
					closed = true;
9edf2e
				} else
9edf2e
				if (s == "end") {
9edf2e
					break;
9edf2e
				} else {
9edf2e
					cout << "bug " << s << endl;
9edf2e
					if (!f) break;
9edf2e
				}
9edf2e
			}
9edf2e
			if (!closed)
9edf2e
				ci.contour.close();
9edf2e
			if (ci.color.a < 0.9999)
9edf2e
				contours.pop_back();
9edf2e
			else
9edf2e
				vertices_count += ci.contour.get_chunks().size();
9edf2e
		} else
9edf2e
		if (s != "") {
9edf2e
			cout << "bug " << s << endl;
9edf2e
		}
9edf2e
	}
9edf2e
	if ((int)groups.size() != 1)
9edf2e
		cout << "bug groups " << groups.size() << endl;
9edf2e
9edf2e
	cout << contours.size() << " contours" << endl;
9edf2e
	cout << vertices_count << " vertices" << endl;
9edf2e
}
9edf2e
f29469
void Test::transform(Data &data, const Rect &from, const Rect &to) {
f29469
	for(Data::iterator i = data.begin(); i != data.end(); ++i)
f29469
		i->contour.transform(from, to);
f29469
}
9edf2e
f29469
void Test::downgrade(Data &from, Data &to) {
f29469
	to = from;
f29469
	Measure t("downgrade");
f29469
	for(Data::iterator i = from.begin(); i != from.end(); ++i)
d9c2d9
		i->contour.downgrade(to[i - from.begin()].contour, Vector(1.f, 1.f));
f29469
}
93cbac
f29469
void Test::split(Data &from, Data &to) {
f29469
	to = from;
f29469
	Measure t("split");
f29469
	for(Data::iterator i = from.begin(); i != from.end(); ++i)
f29469
		i->contour.split(to[i - from.begin()].contour, Rect(0.f, 0.f, 100000.f, 100000.f), Vector(1.f, 1.f));
f29469
}
93cbac
f29469
void Test::test_gl_stencil(Environment &e, Data &data) {
d9c2d9
	Vector size = Utils::get_frame_size();
7c6b57
	GLuint buffer_id = 0;
7c6b57
	GLuint array_id = 0;
a04770
	vector<vec2f> vertices;</vec2f>
f29469
	vector<int> starts(data.size());</int>
f29469
	vector<int> counts(data.size());</int>
d9c2d9
	vector< rect<int> > bounds(data.size());</int>
f29469
f29469
	vertices.push_back(vec2f(-1.f, -1.f));
f29469
	vertices.push_back(vec2f( 1.f, -1.f));
f29469
	vertices.push_back(vec2f(-1.f,  1.f));
f29469
	vertices.push_back(vec2f( 1.f,  1.f));
f29469
	for(int i = 0; i < (int)data.size(); ++i) {
f29469
		starts[i] = (int)vertices.size();
f29469
		const Contour::ChunkList &chunks = data[i].contour.get_chunks();
d9c2d9
		Rect r(chunks.front().p1, chunks.front().p1);
f29469
		for(Contour::ChunkList::const_iterator j = chunks.begin(); j != chunks.end(); ++j) {
d9c2d9
			vertices.push_back(vec2f(j->p1));
d9c2d9
			r = r.expand(j->p1);
8de121
		}
f29469
		counts[i] = (int)vertices.size() - starts[i];
d9c2d9
		bounds[i].p0.x = (int)floor((r.p0.x + 1.0)*0.5*size.x);
d9c2d9
		bounds[i].p0.y = (int)floor((r.p0.y + 1.0)*0.5*size.y);
d9c2d9
		bounds[i].p1.x = (int)ceil ((r.p1.x + 1.0)*0.5*size.x) + 1;
d9c2d9
		bounds[i].p1.y = (int)ceil ((r.p1.y + 1.0)*0.5*size.y) + 1;
8de121
	}
8de121
f29469
	glGenBuffers(1, &buffer_id);
f29469
	glBindBuffer(GL_ARRAY_BUFFER, buffer_id);
f29469
	glBufferData( GL_ARRAY_BUFFER,
f29469
				  vertices.size()*sizeof(vec2f),
f29469
				  &vertices.front(),
f29469
				  GL_DYNAMIC_DRAW );
8de121
f29469
	glGenVertexArrays(1, &array_id);
f29469
	glBindVertexArray(array_id);
93cbac
f29469
	glEnableVertexAttribArray(0);
f29469
	glVertexAttribPointer(0, 2, GL_FLOAT, GL_TRUE, 0, NULL);
6e407d
f29469
	e.shaders.color(Color(0.f, 0.f, 1.f, 1.f));
f29469
	glDrawArrays(GL_TRIANGLE_STRIP, 0, vertices.size());
f29469
	glFinish();
f29469
	glClear(GL_COLOR_BUFFER_BIT);
f29469
	glFinish();
93cbac
93cbac
	{
f29469
		Measure t("render");
f29469
		for(int i = 0; i < (int)data.size(); ++i) {
f29469
			draw_contour(
f29469
				e,
f29469
				starts[i],
f29469
				counts[i],
d9c2d9
				bounds[i],
f29469
				data[i].invert,
f29469
				data[i].evenodd,
f29469
				data[i].color );
f29469
		}
d9c2d9
		glFinish();
93cbac
	}
93cbac
}
93cbac
f29469
void Test::test_sw(Environment &e, Data &data, Surface &surface) {
77d271
	const int warm_up_count = 1000;
77d271
	const int measure_count = 1000;
77d271
	Surface surface_tmp(surface.width, surface.height);
77d271
77d271
	// warm-up
77d271
	for(int ii = 0; ii < warm_up_count; ++ii) {
77d271
		vector<polyspan> polyspans(data.size());</polyspan>
f29469
		for(int i = 0; i < (int)data.size(); ++i) {
f29469
			polyspans[i].init(0, 0, surface.width, surface.height);
f29469
			data[i].contour.to_polyspan(polyspans[i]);
f29469
			polyspans[i].sort_marks();
f29469
		}
77d271
		for(int i = 0; i < (int)data.size(); ++i)
77d271
			SwRender::polyspan(surface_tmp, polyspans[i], data[i].color, data[i].evenodd, data[i].invert);
93cbac
	}
93cbac
77d271
	// measure
77d271
	for(int ii = 0; ii < measure_count; ++ii) {
77d271
		Measure t("render", false, true);
77d271
		vector<polyspan> polyspans(data.size());</polyspan>
77d271
		for(int i = 0; i < (int)data.size(); ++i) {
77d271
			polyspans[i].init(0, 0, surface.width, surface.height);
77d271
			data[i].contour.to_polyspan(polyspans[i]);
77d271
			polyspans[i].sort_marks();
77d271
		}
77d271
		for(int i = 0; i < (int)data.size(); ++i)
77d271
			SwRender::polyspan(surface_tmp, polyspans[i], data[i].color, data[i].evenodd, data[i].invert);
77d271
	}
77d271
77d271
	{ // draw
77d271
		vector<polyspan> polyspans(data.size());</polyspan>
77d271
		for(int i = 0; i < (int)data.size(); ++i) {
77d271
			polyspans[i].init(0, 0, surface.width, surface.height);
77d271
			data[i].contour.to_polyspan(polyspans[i]);
77d271
			polyspans[i].sort_marks();
77d271
		}
f29469
		for(int i = 0; i < (int)data.size(); ++i)
f29469
			SwRender::polyspan(surface, polyspans[i], data[i].color, data[i].evenodd, data[i].invert);
93cbac
	}
93cbac
}
93cbac
f29469
void Test::test_cl(Environment &e, Data &data, Surface &surface) {
013f0c
	// prepare data
013f0c
013f0c
	vector<char> paths(sizeof(int));</char>
013f0c
	int count = 0;
013f0c
	for(Data::const_iterator i = data.begin(); i != data.end(); ++i)
013f0c
		if (int points_count = i->contour.get_chunks().size()) {
013f0c
			++count;
013f0c
013f0c
			int flags = 0;
013f0c
			if (i->invert)  flags |= 1;
013f0c
			if (i->evenodd) flags |= 2;
013f0c
013f0c
			size_t s = paths.size();
013f0c
			paths.resize(paths.size() + sizeof(int) + sizeof(int) + sizeof(Color) + (points_count+1)*sizeof(vec2f));
013f0c
013f0c
			*(int*)&paths[s] = points_count+1; s += sizeof(int);
013f0c
			*(int*)&paths[s] = flags;          s += sizeof(int);
013f0c
			*(Color*)&paths[s] = i->color;     s += sizeof(Color);
013f0c
			vec2f *point = (vec2f*)&paths[s];
013f0c
013f0c
			for(Contour::ChunkList::const_iterator j = i->contour.get_chunks().begin(); j != i->contour.get_chunks().end(); ++j, ++point)
013f0c
				*point = vec2f(j->p1);
013f0c
			*point = vec2f(i->contour.get_chunks().front().p1);
2d0519
		}
013f0c
	*(int*)&paths.front() = count;
013f0c
013f0c
	// draw
9edf2e
f29469
	ClRender clr(e.cl);
f29469
	clr.send_surface(&surface);
d989ab
2517eb
	// warm-up
2517eb
	//clr.send_paths(&paths.front(), paths.size());
2517eb
	//for(int i = 0; i < 1000; ++i)
2517eb
	//	clr.draw();
2517eb
	clr.remove_paths();
2517eb
2517eb
	// actual task
2517eb
	clr.send_surface(&surface);
d989ab
	{
f29469
		Measure t("render");
013f0c
		clr.send_paths(&paths.front(), paths.size());
013f0c
		clr.draw();
f29469
		clr.wait();
c7fa36
	}
f29469
	clr.receive_surface();
9edf2e
}
b09c5d
b09c5d
void Test::test_cl2(Environment &e, Data &data, Surface &surface) {
b09c5d
	// prepare data
b09c5d
b09c5d
	vector<clrender2::path> paths;</clrender2::path>
b09c5d
	vector<clrender2::point> points;</clrender2::point>
b09c5d
	paths.reserve(data.size());
b09c5d
	for(Data::const_iterator i = data.begin(); i != data.end(); ++i)
b09c5d
		if (int points_count = i->contour.get_chunks().size()) {
b09c5d
			ClRender2::Path path;
b09c5d
			path.color = i->color;
b09c5d
			path.invert  = i->invert  ? -1 : 0;
b09c5d
			path.evenodd = i->evenodd ? -1 : 0;
b09c5d
			path.align0 = 0;
b09c5d
			path.align1 = 0;
b09c5d
			paths.push_back(path);
b09c5d
b09c5d
			int first_point_index = (int)points.size();
b09c5d
			int path_index = (int)paths.size() - 1;
b09c5d
			points.reserve(points.size() + points_count + 1);
b09c5d
			for(Contour::ChunkList::const_iterator j = i->contour.get_chunks().begin(); j != i->contour.get_chunks().end(); ++j) {
b09c5d
				ClRender2::Point point;
b09c5d
				point.coord = vec2f(j->p1);
b09c5d
				point.path_index = path_index;
b09c5d
				point.align0 = 0;
b09c5d
				points.push_back(point);
b09c5d
			}
b09c5d
			points.push_back(points[first_point_index]);
b09c5d
		}
b09c5d
b09c5d
	// draw
b09c5d
b09c5d
	ClRender2 clr(e.cl);
b09c5d
b09c5d
	// warm-up
b09c5d
	{
b09c5d
	//clr.send_surface(&surface);
b09c5d
	//clr.send_paths(&paths.front(), (int)paths.size(), &points.front(), (int)points.size());
b09c5d
	//for(int i = 0; i < 1000; ++i)
b09c5d
	//	clr.draw(), clr.wait();
b09c5d
	//clr.remove_paths();
b09c5d
	}
b09c5d
b09c5d
	// actual task
b09c5d
	clr.send_surface(&surface);
b09c5d
	clr.send_paths(&paths.front(), (int)paths.size(), &points.front(), (int)points.size());
b09c5d
	{
b09c5d
		Measure t("render");
b09c5d
		clr.draw();
b09c5d
		clr.wait();
b09c5d
	}
b09c5d
	clr.receive_surface();
b09c5d
}
105dfe
105dfe
void Test::test_cl3(Environment &e, Data &data, Surface &surface) {
105dfe
	// prepare data
8cf99a
	int align = (1024 - 1)/sizeof(vec2f) + 1;
105dfe
	vector<clrender3::path> paths;</clrender3::path>
105dfe
	vector<vec2f> points;</vec2f>
105dfe
	paths.reserve(data.size());
105dfe
	for(Data::const_iterator i = data.begin(); i != data.end(); ++i) {
105dfe
		if (!i->contour.get_chunks().empty()) {
105dfe
			ClRender3::Path path = {};
105dfe
			path.color = i->color;
105dfe
			path.invert = i->invert;
105dfe
			path.evenodd = i->evenodd;
105dfe
f14ea7
			path.bounds.minx = path.bounds.maxx = (int)floor(i->contour.get_chunks().front().p1.x);
f14ea7
			path.bounds.miny = path.bounds.maxy = (int)floor(i->contour.get_chunks().front().p1.y);
105dfe
			path.begin = (int)points.size();
105dfe
			points.reserve(points.size() + i->contour.get_chunks().size() + 1);
105dfe
			for(Contour::ChunkList::const_iterator j = i->contour.get_chunks().begin(); j != i->contour.get_chunks().end(); ++j) {
f14ea7
				int x = (int)floor(j->p1.x);
105dfe
				int y = (int)floor(j->p1.y);
f14ea7
				if (path.bounds.minx > x) path.bounds.minx = x;
f14ea7
				if (path.bounds.maxx < x) path.bounds.maxx = x;
f14ea7
				if (path.bounds.miny > y) path.bounds.miny = y;
f14ea7
				if (path.bounds.maxy < y) path.bounds.maxy = y;
105dfe
				points.push_back(vec2f(j->p1));
105dfe
			}
105dfe
			path.end = (int)points.size();
8cf99a
			do { points.push_back( points[path.begin] ); } while(points.size() % align);
f14ea7
			++path.bounds.maxx;
f14ea7
			++path.bounds.maxy;
105dfe
105dfe
			paths.push_back(path);
105dfe
		}
105dfe
	}
105dfe
105dfe
	// draw
105dfe
105dfe
	ClRender3 clr(e.cl);
105dfe
105dfe
	// warm-up
82f284
	clr.send_surface(&surface);
82f284
	clr.send_points(&points.front(), (int)points.size());
82f284
	for(int ii = 0; ii < 1000; ++ii)
82f284
		for(vector<clrender3::path>::const_iterator i = paths.begin(); i != paths.end(); ++i)</clrender3::path>
82f284
			clr.draw(*i);
82f284
	clr.wait();
105dfe
105dfe
	// measure
82f284
	{
82f284
		for(int ii = 0; ii < 1000; ++ii) {
82f284
			Measure t("render", false, true);
105dfe
			for(vector<clrender3::path>::const_iterator i = paths.begin(); i != paths.end(); ++i)</clrender3::path>
105dfe
				clr.draw(*i);
82f284
			clr.wait();
82f284
		}
82f284
	}
82f284
	clr.send_points(NULL, 0);
82f284
	clr.send_surface(NULL);
105dfe
105dfe
	// actual task
105dfe
	clr.send_surface(&surface);
105dfe
	clr.send_points(&points.front(), (int)points.size());
105dfe
	{
105dfe
		for(vector<clrender3::path>::const_iterator i = paths.begin(); i != paths.end(); ++i)</clrender3::path>
105dfe
			clr.draw(*i);
105dfe
		clr.wait();
105dfe
	}
105dfe
	clr.receive_surface();
105dfe
}
6fa009
6fa009
void Test::test_cu(Environment &e, Data &data, Surface &surface) {
6fa009
#ifdef CUDA
6fa009
	// prepare data
6fa009
	vector<cudarender::path> paths;</cudarender::path>
6fa009
	vector<vec2f> points;</vec2f>
6fa009
	paths.reserve(data.size());
6fa009
	for(Data::const_iterator i = data.begin(); i != data.end(); ++i) {
6fa009
		if (!i->contour.get_chunks().empty()) {
6fa009
			CudaRender::Path path = {};
6fa009
			path.color = i->color;
6fa009
			path.invert = i->invert;
6fa009
			path.evenodd = i->evenodd;
6fa009
6fa009
			path.bounds.minx = path.bounds.maxx = (int)floor(i->contour.get_chunks().front().p1.x);
6fa009
			path.bounds.miny = path.bounds.maxy = (int)floor(i->contour.get_chunks().front().p1.y);
6fa009
			path.begin = (int)points.size();
6fa009
			points.reserve(points.size() + i->contour.get_chunks().size() + 1);
6fa009
			for(Contour::ChunkList::const_iterator j = i->contour.get_chunks().begin(); j != i->contour.get_chunks().end(); ++j) {
6fa009
				int x = (int)floor(j->p1.x);
6fa009
				int y = (int)floor(j->p1.y);
6fa009
				if (path.bounds.minx > x) path.bounds.minx = x;
6fa009
				if (path.bounds.maxx < x) path.bounds.maxx = x;
6fa009
				if (path.bounds.miny > y) path.bounds.miny = y;
6fa009
				if (path.bounds.maxy < y) path.bounds.maxy = y;
6fa009
				points.push_back(vec2f(j->p1));
6fa009
			}
6fa009
			path.end = (int)points.size();
6fa009
			points.push_back( points[path.begin] );
6fa009
			++path.bounds.maxx;
6fa009
			++path.bounds.maxy;
6fa009
6fa009
			paths.push_back(path);
6fa009
		}
6fa009
	}
6fa009
6fa009
	// draw
6fa009
6fa009
	CudaRender cur(e.cu);
6fa009
6fa009
	// warm-up
6fa009
	cur.send_surface(&surface);
6fa009
	cur.send_points(&points.front(), (int)points.size());
6fa009
	for(int ii = 0; ii < 1000; ++ii)
6fa009
		for(vector<cudarender::path>::const_iterator i = paths.begin(); i != paths.end(); ++i)</cudarender::path>
6fa009
			cur.draw(*i);
6fa009
	cur.wait();
6fa009
6fa009
	// measure
6fa009
	{
6fa009
		for(int ii = 0; ii < 1000; ++ii) {
6fa009
			Measure t("render", false, true);
6fa009
			for(vector<cudarender::path>::const_iterator i = paths.begin(); i != paths.end(); ++i)</cudarender::path>
6fa009
				cur.draw(*i);
6fa009
			cur.wait();
6fa009
		}
6fa009
	}
6fa009
	cur.send_points(NULL, 0);
6fa009
	cur.send_surface(NULL);
6fa009
6fa009
	// actual task
6fa009
	cur.send_surface(&surface);
6fa009
	cur.send_points(&points.front(), (int)points.size());
6fa009
	{
6fa009
		for(vector<cudarender::path>::const_iterator i = paths.begin(); i != paths.end(); ++i)</cudarender::path>
6fa009
			cur.draw(*i);
6fa009
		cur.wait();
6fa009
	}
6fa009
	cur.receive_surface();
6fa009
#endif
6fa009
}