4 #include "renderpoly.h"
6 typedef struct _renderpoint
14 typedef struct _renderline
21 typedef struct _renderbuf
30 static inline void add_pixel(renderbuf_t*buf, double x, int y, segment_dir_t dir, edgestyle_t*fs, int polygon_nr)
36 p.polygon_nr = polygon_nr;
38 if(y >= buf->bbox.ymax || y < buf->bbox.ymin)
41 renderline_t*l = &buf->lines[y-buf->bbox.ymin];
43 if(l->num == l->size) {
45 l->points = (renderpoint_t*)rfx_realloc(l->points, l->size * sizeof(renderpoint_t));
47 l->points[l->num] = p;
51 static void add_line(renderbuf_t*buf, double x1, double y1, double x2, double y2, edgestyle_t*fs, segment_dir_t dir, int polygon_nr)
58 double ny1, ny2, stepx;
61 dir ^= DIR_UP^DIR_DOWN;
73 ny1 = floor(y1) + 1.0 + CUT;
76 ny2 = floor(y2) - 1.0 + CUT;
82 x1 = x1 + (ny1-y1)*stepx;
83 x2 = x2 + (ny2-y2)*stepx;
90 //printf("line %d from %f to %f dir=%s\n", polygon_nr, y1, y2, dir==DIR_UP?"up":"down");
93 double xx = startx + posx;
94 add_pixel(buf, xx, posy, dir, fs, polygon_nr);
100 static int compare_renderpoints(const void * _a, const void * _b)
102 renderpoint_t*a = (renderpoint_t*)_a;
103 renderpoint_t*b = (renderpoint_t*)_b;
104 if(a->x < b->x) return -1;
105 if(a->x > b->x) return 1;
109 static void fill_bitwise(unsigned char*line, int x1, int x2)
113 int b1 = 0xff >> (x1&7);
114 int b2 = 0xff << (1+7-(x2&7));
119 memset(&line[p1+1], 255, p2-(p1+1));
124 unsigned char* render_polygon(gfxpoly_t*polygon, intbbox_t*bbox, double zoom, windrule_t*rule, windcontext_t*context)
126 renderbuf_t _buf, *buf=&_buf;
127 buf->width = (bbox->xmax - bbox->xmin);
128 buf->height = (bbox->ymax - bbox->ymin);
130 buf->zoom = zoom * polygon->gridsize;
131 int width8 = (buf->width+7) >> 3;
133 unsigned char* image = (unsigned char*)malloc(width8*buf->height);
134 memset(image, 0, width8*buf->height);
136 buf->lines = (renderline_t*)rfx_alloc(buf->height*sizeof(renderline_t));
138 for(y=0;y<buf->height;y++) {
139 memset(&buf->lines[y], 0, sizeof(renderline_t));
140 buf->lines[y].points = 0;
141 buf->lines[y].num = 0;
146 gfxpolystroke_t*stroke = polygon->strokes;
147 for(;stroke;stroke=stroke->next) {
148 for(t=0;t<stroke->num_points-1;t++) {
149 point_t a = stroke->points[t];
150 point_t b = stroke->points[t+1];
151 add_line(buf, a.x, a.y, b.x, b.y, stroke->fs, stroke->dir, polygon_nr);
155 for(y=0;y<buf->height;y++) {
156 renderpoint_t*points = buf->lines[y].points;
157 unsigned char*line = &image[width8*y];
159 int num = buf->lines[y].num;
160 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
163 windstate_t fill = rule->start(context);
165 renderpoint_t*p = &points[n];
166 int x = (int)(p->x - bbox->xmin);
173 if(fill.is_filled && lastx<x) {
174 fill_bitwise(line, lastx, x);
176 fill = rule->add(context, fill, p->fs, p->dir, p->polygon_nr);
179 if(fill.is_filled && lastx!=buf->width) {
180 /* we're bleeding, fill over padding, too. */
181 fprintf(stderr, "Polygon %p is bleeding in line %d\n", polygon, y);
182 fill_bitwise(line, lastx, width8*8);
183 assert(line[width8-1]&0x01);
190 for(y=0;y<buf->height;y++) {
191 if(buf->lines[y].points) {
192 free(buf->lines[y].points);
194 memset(&buf->lines[y], 0, sizeof(renderline_t));
197 assert(!bitmap_ok(bbox, image));
199 free(buf->lines);buf->lines=0;
203 #define MAX_WIDTH 8192
204 #define MAX_HEIGHT 4096
206 static inline double max(double a, double b) {return a>b?a:b;}
207 static inline double min(double a, double b) {return a<b?a:b;}
209 static int adjust_x(int xmin, int xmax)
212 while(((xmax - xmin)&0x07) != 0x04)
217 intbbox_t intbbox_new(int x1, int y1, int x2, int y2)
224 b.xmax = adjust_x(b.xmin, b.xmax);
225 b.width = b.xmax - b.xmin;
226 b.height = b.ymax - b.ymin;
230 intbbox_t intbbox_from_polygon(gfxpoly_t*polygon, double zoom)
232 intbbox_t b = {0,0,0,0};
234 double g = zoom*polygon->gridsize;
236 if(polygon->strokes && polygon->strokes->num_points) {
237 b.xmin = polygon->strokes->points[0].x*g;
238 b.ymin = polygon->strokes->points[0].y*g;
239 b.xmax = polygon->strokes->points[0].x*g;
240 b.ymax = polygon->strokes->points[0].y*g;
243 gfxpolystroke_t*stroke = polygon->strokes;
244 for(;stroke;stroke=stroke->next) {
245 for(t=0;t<stroke->num_points;t++) {
246 point_t p = stroke->points[t];
251 if(x1 < b.xmin) b.xmin = x1;
252 if(y1 < b.ymin) b.ymin = y1;
253 if(x2 > b.xmax) b.xmax = x2;
254 if(y2 > b.ymax) b.ymax = y2;
258 if(b.xmax > (int)(MAX_WIDTH*zoom))
259 b.xmax = (int)(MAX_WIDTH*zoom);
260 if(b.ymax > (int)(MAX_HEIGHT*zoom))
261 b.ymax = (int)(MAX_HEIGHT*zoom);
262 if(b.xmin < -(int)(MAX_WIDTH*zoom))
263 b.xmin = -(int)(MAX_WIDTH*zoom);
264 if(b.ymin < -(int)(MAX_HEIGHT*zoom))
265 b.ymin = -(int)(MAX_HEIGHT*zoom);
272 b.xmax = adjust_x(b.xmin, b.xmax);
274 b.width = b.xmax - b.xmin;
275 b.height = b.ymax - b.ymin;
279 #define B11111000 0xf8
280 #define B01111100 0x7c
281 #define B00111110 0x3e
282 #define B00011111 0x1f
283 #define B11100000 0xe0
284 #define B01110000 0x70
285 #define B00111000 0x38
286 #define B00011100 0x1c
287 #define B00001110 0x0e
288 #define B00000111 0x07
289 #define B10000000 0x80
290 #define B01000000 0x40
291 #define B00100000 0x20
292 #define B00010000 0x10
293 #define B00001000 0x08
294 #define B00000100 0x04
295 #define B00000010 0x02
296 #define B00000001 0x01
298 int bitmap_ok(intbbox_t*bbox, unsigned char*data)
301 int width8 = (bbox->width+7) >> 3;
302 for(y=0;y<bbox->height;y++) {
303 if(data[width8-1]&0x01)
310 int compare_bitmaps(intbbox_t*bbox, unsigned char*data1, unsigned char*data2)
315 int height = bbox->height;
316 int width = bbox->width;
317 int width8 = (width+7) >> 3;
318 unsigned char*l1 = &data1[width8*2];
319 unsigned char*l2 = &data2[width8*2];
320 for(y=2;y<height-2;y++) {
321 for(x=0;x<width8;x++) {
322 unsigned char a1 = l1[x-width8*2] & l1[x-width8] & l1[x] &
323 l1[x+width8] & l1[x+width8*2];
324 unsigned char b1 = l2[x-width8*2] & l2[x-width8] & l2[x] &
325 l2[x+width8] & l2[x+width8*2];
326 unsigned char a2 = l1[x-width8*2] | l1[x-width8] | l1[x] |
327 l1[x+width8] | l1[x+width8*2];
328 unsigned char b2 = l2[x-width8*2] | l2[x-width8] | l2[x] |
329 l2[x+width8] | l2[x+width8*2];
332 if((a1&B11111000)==B11111000 && (b2&B11111000)==0) fail=2;
333 if((a1&B01111100)==B01111100 && (b2&B01111100)==0) fail=3;
334 if((a1&B00111110)==B00111110 && (b2&B00111110)==0) fail=4;
335 if((a1&B00011111)==B00011111 && (b2&B00011111)==0) fail=5;
336 if((b1&B11111000)==B11111000 && (a2&B11111000)==0) fail=2;
337 if((b1&B01111100)==B01111100 && (a2&B01111100)==0) fail=3;
338 if((b1&B00111110)==B00111110 && (a2&B00111110)==0) fail=4;
339 if((b1&B00011111)==B00011111 && (a2&B00011111)==0) fail=5;
351 void save_two_bitmaps(intbbox_t*b, unsigned char*data1, unsigned char*data2, char*filename)
353 int width8 = (b->width+7) >> 3;
354 unsigned char*data = malloc(b->width*b->height*4*4);
355 unsigned char*p = data;
357 unsigned char*b1 = data1;
358 unsigned char*b2 = data2;
359 compare_bitmaps(b, data1, data2);
360 //# define MARK ((abs(x-badx)<3 && abs(y-bady)<3)*255)
362 for(y=0;y<b->height;y++) {
363 for(x=0;x<b->width;x++) {
364 unsigned char c1 = (b1[x>>3]&(0x80>>(x&7)))?255:0;
365 unsigned char c2 = (b2[x>>3]&(0x80>>(x&7)))?255:0;
371 for(x=0;x<b->width;x++) {
372 unsigned char c = (b2[x>>3]&(0x80>>(x&7)))?255:0;
382 for(y=0;y<b->height;y++) {
383 for(x=0;x<b->width;x++) {
384 unsigned char c = (b1[x>>3]&(0x80>>(x&7)))?255:0;
390 for(x=0;x<b->width;x++) {
398 writePNG(filename, data, b->width*2, b->height*2);