|
|
d989ab |
/*
|
|
|
d989ab |
......... 2015 Ivan Mahonin
|
|
|
d989ab |
|
|
|
d989ab |
This program is free software: you can redistribute it and/or modify
|
|
|
d989ab |
it under the terms of the GNU General Public License as published by
|
|
|
d989ab |
the Free Software Foundation, either version 3 of the License, or
|
|
|
d989ab |
(at your option) any later version.
|
|
|
d989ab |
|
|
|
d989ab |
This program is distributed in the hope that it will be useful,
|
|
|
d989ab |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
d989ab |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
d989ab |
GNU General Public License for more details.
|
|
|
d989ab |
|
|
|
d989ab |
You should have received a copy of the GNU General Public License
|
|
|
d989ab |
along with this program. If not, see <http: licenses="" www.gnu.org="">.</http:>
|
|
|
d989ab |
*/
|
|
|
d989ab |
|
|
|
013f0c |
// paths format:
|
|
|
013f0c |
// {
|
|
|
013f0c |
// int count,
|
|
|
013f0c |
// paths: [
|
|
|
013f0c |
// {
|
|
|
013f0c |
// int point_count,
|
|
|
013f0c |
// int flags,
|
|
|
013f0c |
// float4 color,
|
|
|
013f0c |
// points: [ float2, ... ]
|
|
|
013f0c |
// },
|
|
|
013f0c |
// ...
|
|
|
013f0c |
// ]
|
|
|
013f0c |
// }
|
|
|
013f0c |
|
|
|
67876c |
|
|
|
013f0c |
kernel void draw(
|
|
|
2517eb |
const int width,
|
|
|
2517eb |
const int height,
|
|
|
c7fa36 |
global int *mark_buffer,
|
|
|
2517eb |
global float4 *image,
|
|
|
2517eb |
global const char *paths_buffer )
|
|
|
d989ab |
{
|
|
|
5890eb |
const float e = 1e-6f;
|
|
|
013f0c |
|
|
|
2517eb |
int id = (int)get_local_id(0);
|
|
|
2517eb |
int count = (int)get_local_size(0);
|
|
|
013f0c |
|
|
|
013f0c |
int paths_count = *(global int *)paths_buffer;
|
|
|
2517eb |
global const char *paths = paths_buffer + sizeof(int);
|
|
|
c7fa36 |
|
|
|
013f0c |
int pixels_count = width*height;
|
|
|
013f0c |
float2 size = (float2)((float)width, (float)height);
|
|
|
c7fa36 |
int w1 = width - 1;
|
|
|
c7fa36 |
int h1 = height - 1;
|
|
|
c7fa36 |
|
|
|
2517eb |
local int bound_minx;
|
|
|
2517eb |
local int bound_miny;
|
|
|
2517eb |
local int bound_maxx;
|
|
|
2517eb |
local int bound_maxy;
|
|
|
013f0c |
|
|
|
013f0c |
// draw paths
|
|
|
013f0c |
for(int p = 0; p < paths_count; ++p) {
|
|
|
2517eb |
int points_count = *(global const int *)paths; paths += sizeof(int);
|
|
|
2517eb |
int flags = *(global const int *)paths; paths += sizeof(int);
|
|
|
c7fa36 |
|
|
|
013f0c |
float4 color;
|
|
|
2517eb |
color.x = *(global const float *)paths; paths += sizeof(float);
|
|
|
2517eb |
color.y = *(global const float *)paths; paths += sizeof(float);
|
|
|
2517eb |
color.z = *(global const float *)paths; paths += sizeof(float);
|
|
|
2517eb |
color.w = *(global const float *)paths; paths += sizeof(float);
|
|
|
c7fa36 |
|
|
|
2517eb |
global const float *points = (global const float *)paths;
|
|
|
013f0c |
paths += 2*points_count*sizeof(float);
|
|
|
013f0c |
|
|
|
013f0c |
int segments_count = points_count - 1;
|
|
|
013f0c |
if (segments_count <= 0) continue;
|
|
|
013f0c |
|
|
|
2517eb |
bool invert = flags & 1;
|
|
|
2517eb |
bool evenodd = flags & 2;
|
|
|
013f0c |
|
|
|
2517eb |
if (id == 0) {
|
|
|
2517eb |
bound_minx = invert ? 0 : (int)floor(points[0] + e);
|
|
|
2517eb |
bound_miny = invert ? 0 : (int)floor(points[1] + e);
|
|
|
2517eb |
bound_maxx = invert ? w1 : bound_minx;
|
|
|
2517eb |
bound_maxy = invert ? h1 : bound_miny;
|
|
|
2517eb |
}
|
|
|
2517eb |
barrier(CLK_GLOBAL_MEM_FENCE | CLK_LOCAL_MEM_FENCE);
|
|
|
d989ab |
|
|
|
013f0c |
// trace path
|
|
|
013f0c |
for(int i = id; i < segments_count; i += count) {
|
|
|
013f0c |
int ii = 2*i;
|
|
|
013f0c |
float2 p0 = { points[ii + 0], points[ii + 1] };
|
|
|
013f0c |
float2 p1 = { points[ii + 2], points[ii + 3] };
|
|
|
013f0c |
|
|
|
2517eb |
int p1x = (int)floor(p1.x + e);
|
|
|
2517eb |
int p1y = (int)floor(p1.y + e);
|
|
|
2517eb |
atomic_min(&bound_minx, p1x);
|
|
|
2517eb |
atomic_min(&bound_miny, p1y);
|
|
|
2517eb |
atomic_max(&bound_maxx, p1x);
|
|
|
2517eb |
atomic_max(&bound_maxy, p1y);
|
|
|
013f0c |
|
|
|
013f0c |
bool flipx = p1.x < p0.x;
|
|
|
013f0c |
bool flipy = p1.y < p0.y;
|
|
|
013f0c |
if (flipx) { p0.x = size.x - p0.x; p1.x = size.x - p1.x; }
|
|
|
013f0c |
if (flipy) { p0.y = size.y - p0.y; p1.y = size.y - p1.y; }
|
|
|
013f0c |
float2 d = p1 - p0;
|
|
|
013f0c |
float kx = fabs(d.y) < e ? 1e10 : d.x/d.y;
|
|
|
013f0c |
float ky = fabs(d.x) < e ? 1e10 : d.y/d.x;
|
|
|
013f0c |
|
|
|
013f0c |
while(p0.x != p1.x || p0.y != p1.y) {
|
|
|
013f0c |
int ix = (int)floor(p0.x + e);
|
|
|
013f0c |
int iy = (int)floor(p0.y + e);
|
|
|
013f0c |
if (iy > h1) break;
|
|
|
0b3288 |
|
|
|
2517eb |
float px = (float)(ix + 1);
|
|
|
2517eb |
float py = (float)(iy + 1);
|
|
|
013f0c |
float2 pp1 = p1;
|
|
|
2517eb |
if (pp1.x > px) { pp1.x = px; pp1.y = p0.y + ky*(px - p0.x); }
|
|
|
2517eb |
if (pp1.y > py) { pp1.y = py; pp1.x = p0.x + kx*(py - p0.y); }
|
|
|
013f0c |
|
|
|
013f0c |
if (iy >= 0) {
|
|
|
013f0c |
// calc values
|
|
|
013f0c |
float cover = pp1.y - p0.y;
|
|
|
2517eb |
float area = px - 0.5f*(p0.x + pp1.x);
|
|
|
013f0c |
if (flipx) { ix = w1 - ix; area = 1.f - area; }
|
|
|
013f0c |
if (flipy) { iy = h1 - iy; cover = -cover; }
|
|
|
013f0c |
ix = clamp(ix, 0, w1);
|
|
|
013f0c |
|
|
|
013f0c |
// store in buffer
|
|
|
013f0c |
global int *mark = mark_buffer + (iy*width + ix)*2;
|
|
|
013f0c |
atomic_add(mark, (int)round(area*cover*65536.f));
|
|
|
013f0c |
atomic_add(mark + 1, (int)round(cover*65536.f));
|
|
|
013f0c |
}
|
|
|
013f0c |
|
|
|
013f0c |
p0 = pp1;
|
|
|
013f0c |
}
|
|
|
013f0c |
}
|
|
|
2517eb |
barrier(CLK_GLOBAL_MEM_FENCE | CLK_LOCAL_MEM_FENCE);
|
|
|
2517eb |
|
|
|
2517eb |
// read bounds
|
|
|
2517eb |
int minx = max(bound_minx, 0);
|
|
|
2517eb |
int miny = max(bound_miny, 0);
|
|
|
2517eb |
int maxx = min(bound_maxx, w1);
|
|
|
2517eb |
int maxy = min(bound_maxy, h1);
|
|
|
2517eb |
barrier(CLK_GLOBAL_MEM_FENCE | CLK_LOCAL_MEM_FENCE);
|
|
|
2517eb |
|
|
|
013f0c |
// fill
|
|
|
2517eb |
for(int row = miny + id; row <= maxy; row += count) {
|
|
|
2517eb |
global int *mark = mark_buffer + (row*width + minx)*2;
|
|
|
2517eb |
global float4 *pixel = image + row*width + minx;
|
|
|
2517eb |
global float4 *pixel_end = pixel - minx + maxx + 1;
|
|
|
2517eb |
int icover = 0;
|
|
|
2517eb |
|
|
|
2517eb |
while(pixel < pixel_end) {
|
|
|
013f0c |
// read mark (alpha, cover)
|
|
|
2517eb |
int ialpha = abs(icover + *mark); *mark = 0; ++mark;
|
|
|
2517eb |
icover += *mark; *mark = 0; ++mark;
|
|
|
2517eb |
|
|
|
2517eb |
if (evenodd) ialpha = 65536 - abs(ialpha%131072 - 65536);
|
|
|
2517eb |
if (invert) ialpha = 65536 - ialpha;
|
|
|
013f0c |
|
|
|
2517eb |
//if (!ialpha) continue;
|
|
|
013f0c |
|
|
|
013f0c |
// write color
|
|
|
2517eb |
float alpha = (float)ialpha/65536.f*color.w;
|
|
|
2517eb |
*pixel = *pixel*(1.f - alpha) + color*alpha;
|
|
|
2517eb |
++pixel;
|
|
|
013f0c |
}
|
|
|
013f0c |
}
|
|
|
d989ab |
}
|
|
|
d989ab |
}
|
|
|
013f0c |
|