Blame c++/contourgl/test.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
93cbac
#include <fstream></fstream>
93cbac
#include <iostream></iostream>
93cbac
93cbac
#include <gl gl.h=""></gl>
93cbac
#include <gl glext.h=""></gl>
93cbac
#include <gl glx.h=""></gl>
93cbac
93cbac
#include "test.h"
93cbac
93cbac
#include "contour.h"
93cbac
#include "rendersw.h"
93cbac
#include "contourbuilder.h"
93cbac
93cbac
93cbac
using namespace std;
93cbac
93cbac
93cbac
class Test::Helper {
93cbac
public:
93cbac
	static void save_rgba(
93cbac
		const void *buffer,
93cbac
		int width,
93cbac
		int height,
93cbac
		bool flip,
93cbac
		const string &filename )
93cbac
	{
93cbac
		// create file
93cbac
		ofstream f(filename.c_str(), ofstream::out | ofstream::trunc | ofstream::binary);
93cbac
93cbac
		// write header
93cbac
		unsigned char targa_header[] = {
93cbac
			0,    // Length of the image ID field (0 - no ID field)
93cbac
			0,    // Whether a color map is included (0 - no colormap)
93cbac
			2,    // Compression and color types (2 - uncompressed true-color image)
93cbac
			0, 0, 0, 0, 0, // Color map specification (not need for us)
93cbac
			0, 0, // X-origin
93cbac
			0, 0, // Y-origin
93cbac
			(unsigned char)(width & 0xff), // Image width
93cbac
			(unsigned char)(width >> 8),
93cbac
			(unsigned char)(height & 0xff), // Image height
93cbac
			(unsigned char)(height >> 8),
93cbac
			32,   // Bits per pixel
93cbac
			0     // Image descriptor (keep zero for capability)
93cbac
		};
93cbac
		f.write((char*)targa_header, sizeof(targa_header));
93cbac
93cbac
		// write data
93cbac
		if (flip) {
93cbac
			int line_size = 4*width;
93cbac
			const char *end = (char*)buffer;
93cbac
			const char *current = end + height*line_size;
93cbac
			while(current > end) {
93cbac
				current -= line_size;
93cbac
				f.write(current, line_size);
93cbac
			}
93cbac
		} else {
93cbac
			f.write((const char*)buffer, 4*width*height);
93cbac
		}
93cbac
	}
93cbac
93cbac
	static void save_viewport(const string &filename) {
93cbac
		glFinish();
93cbac
		int vp[4] = {};
93cbac
		glGetIntegerv(GL_VIEWPORT, vp);
93cbac
		char *buffer = new char[vp[2]*vp[3]*4];
93cbac
		glReadPixels(vp[0], vp[1], vp[2], vp[3], GL_BGRA, GL_UNSIGNED_BYTE, buffer);
93cbac
		save_rgba(buffer, vp[2], vp[3], false, filename);
93cbac
		delete buffer;
93cbac
	}
93cbac
93cbac
	static void save_surface(const Surface &surface, const string &filename) {
93cbac
		unsigned char *buffer = new unsigned char[4*surface.count()];
93cbac
		unsigned char *j = buffer;
93cbac
		for(Color *i = surface.data, *end = i + surface.count(); i != end; ++i, j += 4) {
93cbac
			j[0] = (unsigned char)roundf(max(0.f, min(1.f, i->b))*255.f);
93cbac
			j[1] = (unsigned char)roundf(max(0.f, min(1.f, i->g))*255.f);
93cbac
			j[2] = (unsigned char)roundf(max(0.f, min(1.f, i->r))*255.f);
93cbac
			j[3] = (unsigned char)roundf(max(0.f, min(1.f, i->a))*255.f);
93cbac
		}
93cbac
		save_rgba(buffer, surface.width, surface.height, false, filename);
93cbac
		delete buffer;
93cbac
	}
93cbac
93cbac
	static void draw_contour_strip(const vector<vector> &c) {</vector>
93cbac
		glBegin(GL_TRIANGLE_STRIP);
93cbac
		for(vector<vector>::const_iterator i = c.begin(); i != c.end(); ++i) {</vector>
93cbac
			glVertex2d(i->x, i->y);
93cbac
			glVertex2d(-1.0, i->y);
93cbac
		}
93cbac
		glEnd();
93cbac
	}
93cbac
93cbac
	static void draw_contour_strip(const Contour &c) {
93cbac
		glBegin(GL_TRIANGLE_STRIP);
93cbac
		const Contour::ChunkList &chunks = c.get_chunks();
93cbac
		Vector prev;
93cbac
		for(Contour::ChunkList::const_iterator i = chunks.begin(); i != chunks.end(); ++i) {
93cbac
			if ( i->type == Contour::LINE
93cbac
			  || i->type == Contour::CLOSE)
93cbac
			{
93cbac
				glVertex2d(i->p1.x, i->p1.y);
93cbac
				glVertex2d(-1.0, i->p1.y);
93cbac
				prev.x = -1.0;
93cbac
				prev.y = i->p1.y;
93cbac
			} else {
93cbac
				glVertex2d(prev.x, prev.y);
93cbac
				glVertex2d(prev.x, prev.y);
93cbac
				glVertex2d(i->p1.x, i->p1.y);
93cbac
				glVertex2d(i->p1.x, i->p1.y);
93cbac
				prev = i->p1;
93cbac
			}
93cbac
		}
93cbac
		glEnd();
93cbac
	}
93cbac
8de121
	static void draw_contour_strip(const int &count) {
8de121
		glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
8de121
	}
8de121
93cbac
	template<typename t=""></typename>
93cbac
	static void draw_contour(const T &c, bool even_odd, bool invert) {
93cbac
		glPushAttrib(GL_ALL_ATTRIB_BITS);
93cbac
		glEnable(GL_STENCIL_TEST);
93cbac
93cbac
		// render mask
93cbac
		glClear(GL_STENCIL_BUFFER_BIT);
93cbac
		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
93cbac
		glStencilFunc(GL_ALWAYS, 0, 0);
93cbac
		if (even_odd) {
8de121
			glStencilOp(GL_INCR_WRAP, GL_INCR_WRAP, GL_INCR_WRAP);
93cbac
		} else {
93cbac
			glStencilOpSeparate(GL_FRONT, GL_INCR_WRAP, GL_INCR_WRAP, GL_INCR_WRAP);
93cbac
			glStencilOpSeparate(GL_BACK, GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP);
93cbac
		}
93cbac
		draw_contour_strip(c);
93cbac
93cbac
		// fill mask
93cbac
		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
93cbac
		glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
93cbac
		if (!even_odd && !invert)
93cbac
			glStencilFunc(GL_NOTEQUAL, 0, -1);
93cbac
		if (!even_odd &&  invert)
93cbac
			glStencilFunc(GL_EQUAL, 0, -1);
93cbac
		if ( even_odd && !invert)
93cbac
			glStencilFunc(GL_EQUAL, 1, 1);
93cbac
		if ( even_odd &&  invert)
93cbac
			glStencilFunc(GL_EQUAL, 0, 1);
93cbac
93cbac
		glBegin(GL_TRIANGLE_STRIP);
93cbac
		glVertex2d(-1.0, -1.0);
93cbac
		glVertex2d( 1.0, -1.0);
93cbac
		glVertex2d(-1.0,  1.0);
93cbac
		glVertex2d( 1.0,  1.0);
93cbac
		glEnd();
93cbac
93cbac
		glPopAttrib();
93cbac
	}
93cbac
};
93cbac
93cbac
Test::Wrapper::~Wrapper() {
93cbac
	if (!surface) glFinish();
93cbac
	Real ms = 1000.0*(Real)(clock() - t)/(Real)(CLOCKS_PER_SEC);
93cbac
	cout << ms << " ms - " << filename << endl;
93cbac
93cbac
	if (filename.size() > 4 && filename.substr(filename.size()-4, 4) == ".tga") {
93cbac
		if (surface)
93cbac
			Helper::save_surface(*surface, filename);
93cbac
		else
93cbac
			Helper::save_viewport(filename);
93cbac
	}
93cbac
93cbac
	if (surface) {
93cbac
		surface->clear();
93cbac
	} else {
93cbac
		glClear(GL_COLOR_BUFFER_BIT);
93cbac
		glFinish();
93cbac
	}
93cbac
}
93cbac
93cbac
void Test::test1() {
93cbac
	vector<vector> c;</vector>
93cbac
	ContourBuilder::build_simple(c);
93cbac
	cout << c.size() << " vertices" << endl;
93cbac
93cbac
	glPushAttrib(GL_ALL_ATTRIB_BITS);
93cbac
	glColor4d(0.0, 0.0, 1.0, 1.0);
93cbac
93cbac
	{
93cbac
		Wrapper t("test_1_contour.tga");
93cbac
		glBegin(GL_LINE_STRIP);
93cbac
		for(vector<vector>::const_iterator i = c.begin(); i != c.end(); ++i)</vector>
93cbac
			glVertex2d(i->x, i->y);
93cbac
		glEnd();
93cbac
	}
93cbac
93cbac
	{
93cbac
		Wrapper t("test_1_contour_fill.tga");
93cbac
		Helper::draw_contour(c, false, false);
93cbac
	}
93cbac
93cbac
	{
93cbac
		Wrapper t("test_1_contour_fill_invert.tga");
93cbac
		Helper::draw_contour(c, false, true);
93cbac
	}
93cbac
93cbac
	{
93cbac
		Wrapper t("test_1_contour_evenodd.tga");
93cbac
		Helper::draw_contour(c, true, false);
93cbac
	}
93cbac
93cbac
	{
93cbac
		Wrapper t("test_1_contour_evenodd_invert.tga");
93cbac
		Helper::draw_contour(c, true, true);
93cbac
	}
93cbac
93cbac
	glPopAttrib();
93cbac
}
93cbac
93cbac
void Test::test2() {
93cbac
	Contour c, cc;
93cbac
	ContourBuilder::build(cc);
93cbac
	cout << cc.get_chunks().size() << " commands" << endl;
93cbac
93cbac
	Rect bounds;
93cbac
	bounds.p0 = Vector(-1.0, -1.0);
93cbac
	bounds.p1 = Vector( 1.0,  1.0);
93cbac
	Vector min_size(1.0/1024.0, 1.0/1024.0);
93cbac
93cbac
	{
93cbac
		Wrapper("test_2_split");
93cbac
		cc.split(c, bounds, min_size);
93cbac
	}
93cbac
93cbac
	const Contour::ChunkList &chunks = c.get_chunks();
93cbac
	cout << chunks.size() << " vertices" << endl;
93cbac
93cbac
	glPushAttrib(GL_ALL_ATTRIB_BITS);
93cbac
	glColor4d(0.0, 0.0, 1.0, 1.0);
93cbac
8de121
	GLuint buf_id = 0;
8de121
	int count = 0;
8de121
	vector<vector> vertices;</vector>
8de121
8de121
	{
8de121
		Wrapper t("test_2_init_buffer");
8de121
		vertices.resize(4*chunks.size());
8de121
		glGenBuffers(1, &buf_id);
8de121
		glBindBuffer(GL_ARRAY_BUFFER, buf_id);
8de121
		glBufferData( GL_ARRAY_BUFFER,
8de121
				      vertices.size()*sizeof(Vector),
8de121
					  &vertices.front(),
8de121
					  GL_DYNAMIC_DRAW );
8de121
		vertices.clear();
8de121
	}
8de121
8de121
8de121
	{
8de121
		Wrapper t("test_2_prepare_data");
8de121
		for(Contour::ChunkList::const_iterator i = chunks.begin(); i != chunks.end(); ++i) {
8de121
			if ( i->type == Contour::LINE
8de121
			  || i->type == Contour::CLOSE)
8de121
			{
8de121
				vertices.push_back(i->p1);
8de121
				vertices.push_back(Vector(-1.0, i->p1.y));
8de121
			} else {
8de121
				vertices.push_back(vertices.empty() ? Vector() : vertices.back());
8de121
				vertices.push_back(vertices.back());
8de121
				vertices.push_back(i->p1);
8de121
				vertices.push_back(i->p1);
8de121
			}
8de121
		}
8de121
		count = vertices.size();
8de121
	}
8de121
8de121
	{
8de121
		Wrapper t("test_2_send_data");
8de121
		glBufferData( GL_ARRAY_BUFFER,
8de121
					  vertices.size()*sizeof(Vector),
8de121
					  &vertices.front(),
8de121
					  GL_DYNAMIC_DRAW );
8de121
		glVertexPointer(2, GL_FLOAT, sizeof(Vector), 0);
8de121
	}
8de121
93cbac
	{
93cbac
		Wrapper t("test_2_contour.tga");
93cbac
		glBegin(GL_LINE_STRIP);
93cbac
		for(Contour::ChunkList::const_iterator i = chunks.begin(); i != chunks.end(); ++i)
93cbac
			glVertex2d(i->p1.x, i->p1.y);
93cbac
		glEnd();
93cbac
	}
93cbac
93cbac
	{
93cbac
		Wrapper t("test_2_contour_fill.tga");
8de121
		Helper::draw_contour(count, false, false);
93cbac
	}
93cbac
93cbac
	{
93cbac
		Wrapper t("test_2_contour_fill_invert.tga");
8de121
		Helper::draw_contour(count, false, true);
93cbac
	}
93cbac
93cbac
	{
93cbac
		Wrapper t("test_2_contour_evenodd.tga");
8de121
		Helper::draw_contour(count, true, false);
93cbac
	}
93cbac
93cbac
	{
93cbac
		Wrapper t("test_2_contour_evenodd_invert.tga");
8de121
		Helper::draw_contour(count, true, true);
93cbac
	}
93cbac
93cbac
	glPopAttrib();
93cbac
}
93cbac
93cbac
void Test::test3() {
93cbac
	Contour c;
93cbac
	ContourBuilder::build(c);
93cbac
	cout << c.get_chunks().size() << " commands" << endl;
93cbac
93cbac
	Rect bounds;
93cbac
	bounds.p0 = Vector(-1.0, -1.0);
93cbac
	bounds.p1 = Vector( 1.0,  1.0);
93cbac
	Rect pixel_bounds;
93cbac
	pixel_bounds.p0 = Vector(   0.0,    0.0);
93cbac
	pixel_bounds.p1 = Vector(1024.0, 1024.0);
93cbac
93cbac
	c.transform(bounds, pixel_bounds);
93cbac
93cbac
	Polyspan polyspan;
93cbac
	polyspan.init(0, 0, 1024, 1024);
93cbac
93cbac
	Surface surface(1024, 1024);
93cbac
	Color color(0.f, 0.f, 1.f, 1.f);
93cbac
93cbac
	{
93cbac
		Wrapper("test_3_build_polyspan");
93cbac
		c.to_polyspan(polyspan);
93cbac
	}
93cbac
93cbac
	cout << polyspan.get_covers().size() << " covers" << endl;
93cbac
93cbac
	glPushAttrib(GL_ALL_ATTRIB_BITS);
93cbac
	glColor4d(0.0, 0.0, 1.0, 1.0);
93cbac
	{
93cbac
		Wrapper t("test_3_polyspan_gl_lines.tga");
93cbac
		glBegin(GL_LINE_STRIP);
93cbac
		for(Polyspan::cover_array::const_iterator i = polyspan.get_covers().begin(); i != polyspan.get_covers().end(); ++i)
93cbac
			glVertex2d((double)i->x/1024.0*2.0 - 1.0, (double)i->y/1024.0*2.0 - 1.0);
93cbac
		glEnd();
93cbac
	}
93cbac
	glPopAttrib();
93cbac
93cbac
93cbac
	{
93cbac
		Wrapper("test_3_polyspan_sort");
93cbac
		polyspan.sort_marks();
93cbac
	}
93cbac
93cbac
	{
93cbac
		Wrapper t("test_3_polyspan_fill.tga", surface);
93cbac
		RenderSW::polyspan(surface, polyspan, color, false, false);
93cbac
	}
93cbac
93cbac
	{
93cbac
		Wrapper t("test_3_polyspan_fill_invert.tga", surface);
93cbac
		RenderSW::polyspan(surface, polyspan, color, false, true);
93cbac
	}
93cbac
93cbac
	{
93cbac
		Wrapper t("test_3_polyspan_evenodd.tga", surface);
93cbac
		RenderSW::polyspan(surface, polyspan, color, true, false);
93cbac
	}
93cbac
93cbac
	{
93cbac
		Wrapper t("test_3_polyspan_evenodd_invert.tga", surface);
93cbac
		RenderSW::polyspan(surface, polyspan, color, true, true);
93cbac
	}
93cbac
}
93cbac