Blame c++/contourgl/contourgl.cpp

f2b8c4
/*
f2b8c4
    ......... 2015 Ivan Mahonin
f2b8c4
f2b8c4
    This program is free software: you can redistribute it and/or modify
f2b8c4
    it under the terms of the GNU General Public License as published by
f2b8c4
    the Free Software Foundation, either version 3 of the License, or
f2b8c4
    (at your option) any later version.
f2b8c4
f2b8c4
    This program is distributed in the hope that it will be useful,
f2b8c4
    but WITHOUT ANY WARRANTY; without even the implied warranty of
f2b8c4
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
f2b8c4
    GNU General Public License for more details.
f2b8c4
f2b8c4
    You should have received a copy of the GNU General Public License
f2b8c4
    along with this program.  If not, see <http: licenses="" www.gnu.org="">.</http:>
f2b8c4
*/
f2b8c4
f2b8c4
#include <cmath></cmath>
f2b8c4
f2b8c4
#include <fstream></fstream>
f2b8c4
#include <iostream></iostream>
f2b8c4
#include <vector></vector>
f2b8c4
#include <map></map>
f2b8c4
f2b8c4
#include <assert.h></assert.h>
f2b8c4
f2b8c4
#include <gl gl.h=""></gl>
f2b8c4
#include <gl glext.h=""></gl>
f2b8c4
#include <gl glx.h=""></gl>
f2b8c4
f2b8c4
f2b8c4
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
f2b8c4
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
f2b8c4
typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
f2b8c4
f2b8c4
f2b8c4
using namespace std;
f2b8c4
f2b8c4
f2b8c4
typedef pair<float, float=""> vec2;</float,>
f2b8c4
typedef vector<vec2> contour;</vec2>
f2b8c4
f2b8c4
void save_rgba(const void *buffer, int width, int height, const string &filename) {
f2b8c4
	// create file
f2b8c4
	ofstream f(filename.c_str(), ofstream::out | ofstream::trunc | ofstream::binary);
f2b8c4
f2b8c4
	// write header
f2b8c4
	unsigned char targa_header[] = {
f2b8c4
		0,    // Length of the image ID field (0 - no ID field)
f2b8c4
		0,    // Whether a color map is included (0 - no colormap)
f2b8c4
		2,    // Compression and color types (2 - uncompressed true-color image)
f2b8c4
		0, 0, 0, 0, 0, // Color map specification (not need for us)
f2b8c4
		0, 0, // X-origin
f2b8c4
		0, 0, // Y-origin
f2b8c4
		(unsigned char)(width & 0xff), // Image width
f2b8c4
		(unsigned char)(width >> 8),
f2b8c4
		(unsigned char)(height & 0xff), // Image height
f2b8c4
		(unsigned char)(height >> 8),
f2b8c4
		32,   // Bits per pixel
f2b8c4
		0     // Image descriptor (keep zero for capability)
f2b8c4
	};
f2b8c4
	f.write((char*)targa_header, sizeof(targa_header));
f2b8c4
f2b8c4
	// write data
f2b8c4
	int line_size = 4*width;
f2b8c4
	const char *end = (char*)buffer;
f2b8c4
	const char *current = end + height*line_size;
f2b8c4
	while(current > end) {
f2b8c4
		current -= line_size;
f2b8c4
		f.write(current, line_size);
f2b8c4
	}
f2b8c4
}
f2b8c4
f2b8c4
void save_viewport(const string &filename) {
f2b8c4
	cout << filename << endl;
f2b8c4
	glFinish();
f2b8c4
	int vp[4] = {};
f2b8c4
	glGetIntegerv(GL_VIEWPORT, vp);
f2b8c4
	char *buffer = new char[vp[2]*vp[3]*4];
f2b8c4
	glReadPixels(vp[0], vp[1], vp[2], vp[3], GL_BGRA, GL_UNSIGNED_BYTE, buffer);
f2b8c4
	save_rgba(buffer, vp[2], vp[3], filename);
f2b8c4
}
f2b8c4
f2b8c4
void build_contour(contour &c) {
f2b8c4
	const float min_segment_length = 0.001f;
f2b8c4
	const float rounds = 10.f;
f2b8c4
	const float rounds2 = 1.f;
f2b8c4
f2b8c4
	contour back;
f2b8c4
f2b8c4
	float angle = 360.f;
f2b8c4
	float offset = 0.25f/(rounds + 1.f);
f2b8c4
f2b8c4
	// go front
f2b8c4
	while(true) {
f2b8c4
		float radius = angle/360.f/(rounds + 1.f);
f2b8c4
		float step = min_segment_length*180.f/M_PI/radius;
f2b8c4
		if (radius > 1.f - 2.f*offset) break;
f2b8c4
f2b8c4
		float fr = radius + offset;
f2b8c4
		float fx = fr*sinf(angle/180.f*M_PI);
f2b8c4
		float fy = fr*cosf(angle/180.f*M_PI);
f2b8c4
f2b8c4
		float br = radius - offset;
f2b8c4
		float bx = br*sinf(angle/180.f*M_PI);
f2b8c4
		float by = br*cosf(angle/180.f*M_PI);
f2b8c4
f2b8c4
		c.push_back(vec2(fx, fy));
f2b8c4
		back.push_back(vec2(bx, by));
f2b8c4
f2b8c4
		angle += step;
f2b8c4
	}
f2b8c4
f2b8c4
	float max_angle = angle;
f2b8c4
f2b8c4
	while(true) {
f2b8c4
		float radius = max_angle/360.f/(rounds + 1.f)
f2b8c4
				     + (max_angle-angle)/360.f/rounds2;
f2b8c4
		float step = min_segment_length*180.f/M_PI/radius;
f2b8c4
		if (radius < 1.f/(rounds + 1.f))
f2b8c4
			break;
f2b8c4
f2b8c4
		float fr = radius + offset;
f2b8c4
		float fx = fr*sinf(angle/180.f*M_PI);
f2b8c4
		float fy = fr*cosf(angle/180.f*M_PI);
f2b8c4
f2b8c4
		float br = radius - offset;
f2b8c4
		float bx = br*sinf(angle/180.f*M_PI);
f2b8c4
		float by = br*cosf(angle/180.f*M_PI);
f2b8c4
f2b8c4
		c.push_back(vec2(fx, fy));
f2b8c4
		back.push_back(vec2(bx, by));
f2b8c4
f2b8c4
		angle += step;
f2b8c4
	}
f2b8c4
f2b8c4
f2b8c4
	// go back
f2b8c4
	c.reserve(c.size() + back.size() + 1);
f2b8c4
	for(contour::reverse_iterator ri = back.rbegin(); ri != back.rend(); ++ri)
f2b8c4
		c.push_back(*ri);
f2b8c4
f2b8c4
	// close
f2b8c4
	c.push_back(c.front());
f2b8c4
f2b8c4
	cout << c.size() << " vertices" << endl;
f2b8c4
}
f2b8c4
f2b8c4
void draw_contour_strip(const contour &c) {
f2b8c4
	glBegin(GL_TRIANGLE_STRIP);
f2b8c4
	for(contour::const_iterator i = c.begin(); i != c.end(); ++i) {
f2b8c4
		glVertex2f(i->first, i->second);
f2b8c4
		glVertex2f(-1.f, i->second);
f2b8c4
	}
f2b8c4
	glEnd();
f2b8c4
}
f2b8c4
f2b8c4
f2b8c4
void draw_contour(const contour &c, bool even_odd, bool invert) {
f2b8c4
	glPushAttrib(GL_ALL_ATTRIB_BITS);
f2b8c4
	glEnable(GL_STENCIL_TEST);
f2b8c4
f2b8c4
	// render mask
f2b8c4
	glClear(GL_STENCIL_BUFFER_BIT);
f2b8c4
	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
f2b8c4
	glStencilFunc(GL_ALWAYS, 0, 0);
f2b8c4
	if (even_odd) {
f2b8c4
		glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP);
f2b8c4
	} else {
f2b8c4
		glStencilOpSeparate(GL_FRONT, GL_INCR_WRAP, GL_INCR_WRAP, GL_INCR_WRAP);
f2b8c4
		glStencilOpSeparate(GL_BACK, GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP);
f2b8c4
	}
f2b8c4
	draw_contour_strip(c);
f2b8c4
f2b8c4
	// fill mask
f2b8c4
	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
f2b8c4
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
f2b8c4
	if (!even_odd && !invert)
f2b8c4
		glStencilFunc(GL_NOTEQUAL, 0, -1);
f2b8c4
	if (!even_odd &&  invert)
f2b8c4
		glStencilFunc(GL_EQUAL, 0, -1);
f2b8c4
	if ( even_odd && !invert)
f2b8c4
		glStencilFunc(GL_EQUAL, 1, 1);
f2b8c4
	if ( even_odd &&  invert)
f2b8c4
		glStencilFunc(GL_EQUAL, 0, 1);
f2b8c4
f2b8c4
	glBegin(GL_TRIANGLE_STRIP);
f2b8c4
	glVertex2d(-1.f, -1.f);
f2b8c4
	glVertex2d( 1.f, -1.f);
f2b8c4
	glVertex2d(-1.f,  1.f);
f2b8c4
	glVertex2d( 1.f,  1.f);
f2b8c4
	glEnd();
f2b8c4
f2b8c4
	glPopAttrib();
f2b8c4
}
f2b8c4
f2b8c4
class test_wrapper {
f2b8c4
private:
f2b8c4
	string filename;
f2b8c4
	clock_t t;
f2b8c4
	test_wrapper(const test_wrapper&): t() { }
f2b8c4
	test_wrapper& operator= (const test_wrapper&) { return *this; }
f2b8c4
public:
f2b8c4
	test_wrapper(const string &filename): filename(filename), t(clock()) { }
f2b8c4
	~test_wrapper() {
f2b8c4
		glFinish();
f2b8c4
		cout << 1000.0*(double)(clock() - t)/(double)(CLOCKS_PER_SEC) << " ms" << endl;
f2b8c4
		cout << filename << endl;
f2b8c4
		save_viewport(filename);
f2b8c4
		glClear(GL_COLOR_BUFFER_BIT);
f2b8c4
	}
f2b8c4
};
f2b8c4
f2b8c4
void test() {
f2b8c4
	contour c;
f2b8c4
	build_contour(c);
f2b8c4
f2b8c4
	glColor4f(0.f, 0.f, 1.f, 1.f);
f2b8c4
f2b8c4
	{
f2b8c4
		test_wrapper t("test_contour.tga");
f2b8c4
		glBegin(GL_LINE_STRIP);
f2b8c4
		for(contour::const_iterator i = c.begin(); i != c.end(); ++i)
f2b8c4
			glVertex2f(i->first, i->second);
f2b8c4
		glEnd();
f2b8c4
	}
f2b8c4
f2b8c4
	{
f2b8c4
		test_wrapper t("test_contour_fill.tga");
f2b8c4
		draw_contour(c, false, false);
f2b8c4
	}
f2b8c4
f2b8c4
	{
f2b8c4
		test_wrapper t("test_contour_fill_invert.tga");
f2b8c4
		draw_contour(c, false, true);
f2b8c4
	}
f2b8c4
f2b8c4
	{
f2b8c4
		test_wrapper t("test_contour_evenodd.tga");
f2b8c4
		draw_contour(c, true, false);
f2b8c4
	}
f2b8c4
f2b8c4
	{
f2b8c4
		test_wrapper t("test_contour_evenodd_invert.tga");
f2b8c4
		draw_contour(c, true, true);
f2b8c4
	}
f2b8c4
}
f2b8c4
f2b8c4
int main() {
f2b8c4
	// open display (we will use default display and screen 0)
f2b8c4
	Display *display = XOpenDisplay(NULL);
f2b8c4
	assert(display);
f2b8c4
f2b8c4
	// choose config
f2b8c4
	int config_attribs[] = {
f2b8c4
		GLX_DOUBLEBUFFER,      False,
f2b8c4
		GLX_RED_SIZE,          8,
f2b8c4
		GLX_GREEN_SIZE,        8,
f2b8c4
		GLX_BLUE_SIZE,         8,
f2b8c4
		GLX_ALPHA_SIZE,        8,
f2b8c4
		GLX_DEPTH_SIZE,        24,
f2b8c4
		GLX_STENCIL_SIZE,      8,
f2b8c4
		GLX_ACCUM_RED_SIZE,    8,
f2b8c4
		GLX_ACCUM_GREEN_SIZE,  8,
f2b8c4
		GLX_ACCUM_BLUE_SIZE,   8,
f2b8c4
		GLX_ACCUM_ALPHA_SIZE,  8,
f2b8c4
		GLX_DRAWABLE_TYPE,     GLX_PBUFFER_BIT,
f2b8c4
		None };
f2b8c4
	int nelements = 0;
f2b8c4
	GLXFBConfig *configs = glXChooseFBConfig(display, 0, config_attribs, &nelements);
f2b8c4
	assert(configs != NULL && nelements > 0);
f2b8c4
	GLXFBConfig config = configs[0];
f2b8c4
	assert(config);
f2b8c4
f2b8c4
	// create pbuffer
f2b8c4
	int pbuffer_width = 1024;
f2b8c4
	int pbuffer_height = 1024;
f2b8c4
	int pbuffer_attribs[] = {
f2b8c4
		GLX_PBUFFER_WIDTH, pbuffer_width,
f2b8c4
		GLX_PBUFFER_HEIGHT, pbuffer_height,
f2b8c4
		None };
f2b8c4
	GLXPbuffer pbuffer = glXCreatePbuffer(display, config, pbuffer_attribs);
f2b8c4
	assert(pbuffer);
f2b8c4
f2b8c4
	// create context
f2b8c4
	int context_attribs[] = {
f2b8c4
		GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
f2b8c4
		GLX_CONTEXT_MINOR_VERSION_ARB, 1,
f2b8c4
		None };
f2b8c4
	GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
f2b8c4
	GLXContext context = glXCreateContextAttribsARB(display, config, NULL, True, context_attribs);
f2b8c4
	assert(context);
f2b8c4
f2b8c4
	// make context current
f2b8c4
	glXMakeContextCurrent(display, pbuffer, pbuffer, context);
f2b8c4
f2b8c4
	// set view port
f2b8c4
	glViewport(0, 0, pbuffer_width, pbuffer_height);
f2b8c4
f2b8c4
	// do something
f2b8c4
	test();
f2b8c4
f2b8c4
	// deinitialization
f2b8c4
	glXMakeContextCurrent(display, None, None, NULL);
f2b8c4
	glXDestroyContext(display, context);
f2b8c4
	glXDestroyPbuffer(display, pbuffer);
f2b8c4
	XCloseDisplay(display);
f2b8c4
f2b8c4
	cout << "done" << endl;
f2b8c4
	return 0;
f2b8c4
}