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