diff --git a/c++/contourgl/Makefile b/c++/contourgl/Makefile index dfe2f43..98eca6f 100644 --- a/c++/contourgl/Makefile +++ b/c++/contourgl/Makefile @@ -1,9 +1,10 @@ DEPLIBS = gl x11 OpenCL -CXXFLAGS = -O0 -g -Wall -fmessage-length=0 `pkg-config --cflags $(DEPLIBS)` -DGL_GLEXT_PROTOTYPES +CXXFLAGS = -O3 -Wall -fmessage-length=0 `pkg-config --cflags $(DEPLIBS)` -DGL_GLEXT_PROTOTYPES HEADERS = \ clcontext.h \ + clrender.h \ contour.h \ contourbuilder.h \ environment.h \ @@ -11,8 +12,8 @@ HEADERS = \ glcontext.h \ measure.h \ polyspan.h \ - rendersw.h \ shaders.h \ + swrender.h \ test.h \ triangulator.h \ utils.h @@ -20,6 +21,7 @@ HEADERS = \ SOURCES = \ contourgl.cpp \ clcontext.cpp \ + clrender.cpp \ contour.cpp \ contourbuilder.cpp \ environment.cpp \ @@ -27,8 +29,8 @@ SOURCES = \ glcontext.cpp \ measure.cpp \ polyspan.cpp \ - rendersw.cpp \ shaders.cpp \ + swrender.cpp \ test.cpp \ triangulator.cpp \ utils.cpp @@ -36,6 +38,7 @@ SOURCES = \ OBJS = \ contourgl.o \ clcontext.o \ + clrender.o \ contour.o \ contourbuilder.o \ environment.o \ @@ -43,8 +46,8 @@ OBJS = \ glcontext.o \ measure.o \ polyspan.o \ - rendersw.o \ shaders.o \ + swrender.o \ test.o \ triangulator.o \ utils.o diff --git a/c++/contourgl/clrender.cpp b/c++/contourgl/clrender.cpp new file mode 100644 index 0000000..18d0dae --- /dev/null +++ b/c++/contourgl/clrender.cpp @@ -0,0 +1,108 @@ +/* + ......... 2015 Ivan Mahonin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "clrender.h" + + +using namespace std; + + +ClRender::ClRender(ClContext &cl): cl(cl) { + // TODO: init programs +} + +ClRender::~ClRender() { + // TODO: release programs +} + +void ClRender::contour(const Contour &contour, Surface &target) { + // TODO: + // split contour + // resterize lines + // fill +} + + + +void SwRenderAlt::line(const Vector &p0, const Vector &p1) { + int iy0 = min(max((int)floor(p0.y), 0), height); + int iy1 = min(max((int)floor(p1.y), 0), height); + if (iy1 < iy0) swap(iy0, iy1); + + Vector d = p1 - p0; + Vector k( fabs(d.y) < 1e-6 ? 0.0 : d.x/d.y, + fabs(d.x) < 1e-6 ? 0.0 : d.y/d.x ); + + for(int r = iy0; r <= iy1; ++r) { + Real y = (Real)iy0; + + Vector pp0 = p0; + pp0.y -= y; + if (pp0.y < 0.0) { + pp0.y = 0.0; + pp0.x = p0.x - k.x*y; + } else + if (pp0.y > 1.0) { + pp0.y = 1.0; + pp0.x = p0.x - k.x*(y - 1.0); + } + + Vector pp1 = p1; + pp1.y -= y; + if (pp1.y < 0.0) { + pp1.y = 0.0; + pp1.x = p0.x - k.x*y; + } else + if (pp1.y > 1.0) { + pp1.y = 1.0; + pp1.x = p0.x - k.x*(y - 1.0); + } + + int ix0 = min(max((int)floor(pp0.x), 0), width); + int ix1 = min(max((int)floor(pp1.x), 0), width); + if (ix1 < ix0) swap(ix0, ix1); + for(int c = ix0; c <= ix1; ++c) { + Real x = (Real)ix0; + + Vector ppp0 = pp0; + ppp0.x -= x; + if (ppp0.x < 0.0) { + ppp0.x = 0.0; + ppp0.y = pp0.y - k.y*x; + } else + if (ppp0.x > 1.0) { + ppp0.x = 1.0; + ppp0.y = pp0.y - k.y*(x - 1.0); + } + + Vector ppp1 = pp1; + ppp1.x -= x; + if (ppp1.x < 0.0) { + ppp1.x = 0.0; + ppp1.y = pp0.y - k.y*x; + } else + if (ppp1.x > 1.0) { + ppp1.x = 1.0; + ppp1.y = pp0.y - k.y*(x - 1.0); + } + + Real cover = ppp0.y - ppp1.y; + Real area = (0.5*(ppp1.x + ppp1.x) - 1.0)*cover; + (*this)[r][c].add(area, cover); + } + } +} diff --git a/c++/contourgl/clrender.h b/c++/contourgl/clrender.h new file mode 100644 index 0000000..065e10b --- /dev/null +++ b/c++/contourgl/clrender.h @@ -0,0 +1,64 @@ +/* + ......... 2015 Ivan Mahonin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _RASTERIZER_H_ +#define _RASTERIZER_H_ + +#include + +#include "clcontext.h" +#include "geometry.h" +#include "contour.h" +#include "swrender.h" + + +class ClRender { +public: + ClContext &cl; + + ClRender(ClContext &cl); + ~ClRender(); + + void contour(const Contour &contour, Surface &target); +}; + + +class SwRenderAlt { +public: + struct Pixel { + Real area; + Real cover; + Pixel(): area(), cover() { } + void add(Real area, Real cover) { this->area += area; this->cover += cover; } + }; + +private: + std::vector data; + +public: + const int width; + const int height; + + SwRenderAlt(int width, int height): data(width*height), width(width), height(height) { } + + Pixel* operator[] (int row) { return &data.front() + row*width; } + const Pixel* operator[] (int row) const { return &data.front() + row*width; } + + void line(const Vector &p0, const Vector &p1); +}; + +#endif diff --git a/c++/contourgl/measure.h b/c++/contourgl/measure.h index c8ff69a..1903d74 100644 --- a/c++/contourgl/measure.h +++ b/c++/contourgl/measure.h @@ -23,7 +23,7 @@ #include #include -#include "rendersw.h" +#include "swrender.h" class Measure { diff --git a/c++/contourgl/rendersw.cpp b/c++/contourgl/rendersw.cpp deleted file mode 100644 index 0b233f8..0000000 --- a/c++/contourgl/rendersw.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - ......... 2015 Ivan Mahonin - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "rendersw.h" - - -using namespace std; - - -void RenderSW::fill( - Surface &target, - const Color &color ) -{ - for(Color *i = target.data, *end = i + target.count(); i != end; ++i) - *i = color; -} - -void RenderSW::fill( - Surface &target, - const Color &color, - int left, - int top, - int width, - int height ) -{ - int step = target.width - width; - for(Color *i = &target[top][left], *end = i + height*target.width; i < end; i += step) - for(Color *rowend = i + width; i < rowend; ++i) - *i = color; -} - -void RenderSW::row( - Surface &target, - const Color &color, - int left, - int top, - int length ) -{ - for(Color *i = &target[top][left], *end = i + length; i < end; ++i) - *i = color; -} - -void RenderSW::row_alpha( - Surface &target, - const Color &color, - Color::type alpha, - int left, - int top, - int length ) -{ - for(Color *i = &target[top][left], *end = i + length; i < end; ++i) { - i->r = i->r*(1.f - alpha) + color.r*alpha; - i->g = i->g*(1.f - alpha) + color.g*alpha; - i->b = i->b*(1.f - alpha) + color.b*alpha; - i->a = i->a*(1.f - alpha) + color.a*alpha; - } -} - -void RenderSW::polyspan( - Surface &target, - const Polyspan &polyspan, - const Color &color, - bool evenodd, - bool invert ) -{ - const ContextRect &window = polyspan.get_window(); - const Polyspan::cover_array &covers = polyspan.get_covers(); - - Polyspan::cover_array::const_iterator cur_mark = covers.begin(); - Polyspan::cover_array::const_iterator end_mark = covers.end(); - - Real cover = 0, area = 0, alpha = 0; - int y = 0, x = 0; - - if (cur_mark == end_mark) { - // no marks at all - if (invert) - fill( target, color, - window.minx, window.miny, - window.maxx - window.minx, window.maxy - window.miny ); - return; - } - - // fill initial rect / line - if (invert) { - // fill all the area above the first vertex - y = window.miny; - int l = window.maxx - window.minx; - - fill( target, color, - window.minx, window.miny, - l, cur_mark->y - window.miny ); - - // fill the area to the left of the first vertex on that line - l = cur_mark->x - window.minx; - if (l) - row(target, color, window.minx, cur_mark->y, l); - } - - while(true) { - y = cur_mark->y; - x = cur_mark->x; - - area = cur_mark->area; - cover += cur_mark->cover; - - // accumulate for the current pixel - while(++cur_mark != covers.end()) { - if (y != cur_mark->y || x != cur_mark->x) - break; - area += cur_mark->area; - cover += cur_mark->cover; - } - - // draw pixel - based on covered area - if (area) { // if we're ok, draw the current pixel - alpha = polyspan.extract_alpha(cover - area, evenodd); - if (invert) alpha = 1 - alpha; - if (alpha) { - Color::type a = (Color::type)alpha; - Color &c = target[y][x]; - c.r = c.r*(1.f - a) + color.r*a; - c.g = c.g*(1.f - a) + color.g*a; - c.b = c.b*(1.f - a) + color.b*a; - c.a = c.a*(1.f - a) + color.a*a; - } - ++x; - } - - // if we're done, don't use iterator and exit - if (cur_mark == end_mark) - break; - - // if there is no more live pixels on this line, goto next - if (y != cur_mark->y) { - if (invert) { - // fill the area at the end of the line - row(target, color, x, y, window.maxx - x); - - // fill area at the beginning of the next line - row(target, color, window.minx, cur_mark->y, cur_mark->x - window.minx); - } - - cover = 0; - continue; - } - - // draw span to next pixel - based on total amount of pixel cover - if (x < cur_mark->x) { - alpha = polyspan.extract_alpha(cover, evenodd); - if (invert) alpha = 1.0 - alpha; - if (alpha) - row_alpha(target, color, alpha, x, y, cur_mark->x - x); - } - } - - // fill the after stuff - if (invert) { - // fill the area at the end of the line - row(target, color, x, y, window.maxx - x); - - // fill area at the beginning of the next line - fill( target, color, - window.minx, y+1, - window.maxx - window.minx, window.maxy - y - 1 ); - } -} diff --git a/c++/contourgl/rendersw.h b/c++/contourgl/rendersw.h deleted file mode 100644 index 3237b79..0000000 --- a/c++/contourgl/rendersw.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - ......... 2015 Ivan Mahonin - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef _RENDERSW_H_ -#define _RENDERSW_H_ - -#include - -#include "polyspan.h" - -class Color { -public: - typedef float type; - union { - struct { type r, g, b, a; }; - struct { type channels[4]; }; - }; - - Color(): r(), g(), b(), a() { } - Color(type r, type g, type b, type a): r(r), g(g), b(b), a(a) { } - Color(const Color &color, type a): r(color.r), g(color.g), b(color.b), a(color.a*a) { } -}; - -class Surface { -public: - const int width, height; - Color * const data; - - Surface(int width, int height): - width(width), height(height), data(new Color[width*height]) - { clear(); } - - ~Surface() - { delete data; } - - void clear() { memset(data, 0, count()*sizeof(Color)); } - int count() const { return width*height; } - Color* operator[] (int row) { return data + row*width; } - const Color* operator[] (int row) const { return data + row*width; } -}; - -class RenderSW { -public: - static void fill( - Surface &target, - const Color &color ); - - static void fill( - Surface &target, - const Color &color, - int left, - int top, - int width, - int height ); - - static void row( - Surface &target, - const Color &color, - int left, - int top, - int length ); - - static void row_alpha( - Surface &target, - const Color &color, - Color::type alpha, - int left, - int top, - int length ); - - static void polyspan( - Surface &target, - const Polyspan &polyspan, - const Color &color, - bool evenodd, - bool invert ); -}; - -#endif diff --git a/c++/contourgl/shaders.h b/c++/contourgl/shaders.h index 649ce12..05a7537 100644 --- a/c++/contourgl/shaders.h +++ b/c++/contourgl/shaders.h @@ -22,7 +22,7 @@ #include #include -#include "rendersw.h" +#include "swrender.h" class Shaders { public: diff --git a/c++/contourgl/swrender.cpp b/c++/contourgl/swrender.cpp new file mode 100644 index 0000000..8eb11ce --- /dev/null +++ b/c++/contourgl/swrender.cpp @@ -0,0 +1,181 @@ +/* + ......... 2015 Ivan Mahonin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "swrender.h" + + +using namespace std; + + +void SwRender::fill( + Surface &target, + const Color &color ) +{ + for(Color *i = target.data, *end = i + target.count(); i != end; ++i) + *i = color; +} + +void SwRender::fill( + Surface &target, + const Color &color, + int left, + int top, + int width, + int height ) +{ + int step = target.width - width; + for(Color *i = &target[top][left], *end = i + height*target.width; i < end; i += step) + for(Color *rowend = i + width; i < rowend; ++i) + *i = color; +} + +void SwRender::row( + Surface &target, + const Color &color, + int left, + int top, + int length ) +{ + for(Color *i = &target[top][left], *end = i + length; i < end; ++i) + *i = color; +} + +void SwRender::row_alpha( + Surface &target, + const Color &color, + Color::type alpha, + int left, + int top, + int length ) +{ + for(Color *i = &target[top][left], *end = i + length; i < end; ++i) { + i->r = i->r*(1.f - alpha) + color.r*alpha; + i->g = i->g*(1.f - alpha) + color.g*alpha; + i->b = i->b*(1.f - alpha) + color.b*alpha; + i->a = i->a*(1.f - alpha) + color.a*alpha; + } +} + +void SwRender::polyspan( + Surface &target, + const Polyspan &polyspan, + const Color &color, + bool evenodd, + bool invert ) +{ + const ContextRect &window = polyspan.get_window(); + const Polyspan::cover_array &covers = polyspan.get_covers(); + + Polyspan::cover_array::const_iterator cur_mark = covers.begin(); + Polyspan::cover_array::const_iterator end_mark = covers.end(); + + Real cover = 0, area = 0, alpha = 0; + int y = 0, x = 0; + + if (cur_mark == end_mark) { + // no marks at all + if (invert) + fill( target, color, + window.minx, window.miny, + window.maxx - window.minx, window.maxy - window.miny ); + return; + } + + // fill initial rect / line + if (invert) { + // fill all the area above the first vertex + y = window.miny; + int l = window.maxx - window.minx; + + fill( target, color, + window.minx, window.miny, + l, cur_mark->y - window.miny ); + + // fill the area to the left of the first vertex on that line + l = cur_mark->x - window.minx; + if (l) + row(target, color, window.minx, cur_mark->y, l); + } + + while(true) { + y = cur_mark->y; + x = cur_mark->x; + + area = cur_mark->area; + cover += cur_mark->cover; + + // accumulate for the current pixel + while(++cur_mark != covers.end()) { + if (y != cur_mark->y || x != cur_mark->x) + break; + area += cur_mark->area; + cover += cur_mark->cover; + } + + // draw pixel - based on covered area + if (area) { // if we're ok, draw the current pixel + alpha = polyspan.extract_alpha(cover - area, evenodd); + if (invert) alpha = 1 - alpha; + if (alpha) { + Color::type a = (Color::type)alpha; + Color &c = target[y][x]; + c.r = c.r*(1.f - a) + color.r*a; + c.g = c.g*(1.f - a) + color.g*a; + c.b = c.b*(1.f - a) + color.b*a; + c.a = c.a*(1.f - a) + color.a*a; + } + ++x; + } + + // if we're done, don't use iterator and exit + if (cur_mark == end_mark) + break; + + // if there is no more live pixels on this line, goto next + if (y != cur_mark->y) { + if (invert) { + // fill the area at the end of the line + row(target, color, x, y, window.maxx - x); + + // fill area at the beginning of the next line + row(target, color, window.minx, cur_mark->y, cur_mark->x - window.minx); + } + + cover = 0; + continue; + } + + // draw span to next pixel - based on total amount of pixel cover + if (x < cur_mark->x) { + alpha = polyspan.extract_alpha(cover, evenodd); + if (invert) alpha = 1.0 - alpha; + if (alpha) + row_alpha(target, color, alpha, x, y, cur_mark->x - x); + } + } + + // fill the after stuff + if (invert) { + // fill the area at the end of the line + row(target, color, x, y, window.maxx - x); + + // fill area at the beginning of the next line + fill( target, color, + window.minx, y+1, + window.maxx - window.minx, window.maxy - y - 1 ); + } +} diff --git a/c++/contourgl/swrender.h b/c++/contourgl/swrender.h new file mode 100644 index 0000000..679ae7e --- /dev/null +++ b/c++/contourgl/swrender.h @@ -0,0 +1,93 @@ +/* + ......... 2015 Ivan Mahonin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _SWRENDER_H_ +#define _SWRENDER_H_ + +#include + +#include "polyspan.h" + +class Color { +public: + typedef float type; + union { + struct { type r, g, b, a; }; + struct { type channels[4]; }; + }; + + Color(): r(), g(), b(), a() { } + Color(type r, type g, type b, type a): r(r), g(g), b(b), a(a) { } + Color(const Color &color, type a): r(color.r), g(color.g), b(color.b), a(color.a*a) { } +}; + +class Surface { +public: + const int width, height; + Color * const data; + + Surface(int width, int height): + width(width), height(height), data(new Color[width*height]) + { clear(); } + + ~Surface() + { delete data; } + + void clear() { memset(data, 0, count()*sizeof(Color)); } + int count() const { return width*height; } + Color* operator[] (int row) { return data + row*width; } + const Color* operator[] (int row) const { return data + row*width; } +}; + +class SwRender { +public: + static void fill( + Surface &target, + const Color &color ); + + static void fill( + Surface &target, + const Color &color, + int left, + int top, + int width, + int height ); + + static void row( + Surface &target, + const Color &color, + int left, + int top, + int length ); + + static void row_alpha( + Surface &target, + const Color &color, + Color::type alpha, + int left, + int top, + int length ); + + static void polyspan( + Surface &target, + const Polyspan &polyspan, + const Color &color, + bool evenodd, + bool invert ); +}; + +#endif diff --git a/c++/contourgl/test.cpp b/c++/contourgl/test.cpp index d973de4..539e368 100644 --- a/c++/contourgl/test.cpp +++ b/c++/contourgl/test.cpp @@ -308,22 +308,22 @@ void Test::test3() { { Measure t("test_3_polyspan_fill.tga", surface); - RenderSW::polyspan(surface, polyspan, color, false, false); + SwRender::polyspan(surface, polyspan, color, false, false); } { Measure t("test_3_polyspan_fill_invert.tga", surface); - RenderSW::polyspan(surface, polyspan, color, false, true); + SwRender::polyspan(surface, polyspan, color, false, true); } { Measure t("test_3_polyspan_evenodd.tga", surface); - RenderSW::polyspan(surface, polyspan, color, true, false); + SwRender::polyspan(surface, polyspan, color, true, false); } { Measure t("test_3_polyspan_evenodd_invert.tga", surface); - RenderSW::polyspan(surface, polyspan, color, true, true); + SwRender::polyspan(surface, polyspan, color, true, true); } } @@ -531,7 +531,7 @@ void Test::test4() { { Measure t("test_4_sw_render_polyspans.tga", surface); for(int i = 0; i < (int)contours_sw.size(); ++i) - RenderSW::polyspan(surface, polyspans[i], contours_sw[i].color, contours_sw[i].evenodd, contours_sw[i].invert); + SwRender::polyspan(surface, polyspans[i], contours_sw[i].color, contours_sw[i].evenodd, contours_sw[i].invert); } } } diff --git a/c++/contourgl/utils.h b/c++/contourgl/utils.h index 9639734..15a1617 100644 --- a/c++/contourgl/utils.h +++ b/c++/contourgl/utils.h @@ -21,7 +21,7 @@ #include #include "geometry.h" -#include "rendersw.h" +#include "swrender.h" class Utils { public: