#include #include #include #include #include typedef struct RGBA { alignas(4) uint8_t rgba[4]; } RGBA; static inline RGBA Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a){ return (RGBA){ r*a/0xFF, g*a/0xFF, b*a/0xFF, a }; } typedef void draw_pixel_f(void* ctx, long x, long y, RGBA color); struct draw_pixel_callback { void* ctx; draw_pixel_f* call; }; void draw_circle(struct draw_pixel_callback draw_pixel, long pos_x, long pos_y, unsigned n, const float r[static restrict n], const RGBA c[static restrict n]){ if(!n) return; const size_t size = ceil(r[0]); for(size_t y=size; y--; ){ const float y2 = (float)y*y; int i = 0; for(size_t x=size; x--; ){ const float x2 = (float)x*x; const float center_to_pixel = sqrt(x2 + y2); for(; i 0xFF) cit = 0x100; color.rgba[0] = (last_color.rgba[0]*cit + color.rgba[0]*(0x100-cit)) / 0x100; color.rgba[1] = (last_color.rgba[1]*cit + color.rgba[1]*(0x100-cit)) / 0x100; color.rgba[2] = (last_color.rgba[2]*cit + color.rgba[2]*(0x100-cit)) / 0x100; color.rgba[3] = (last_color.rgba[3]*cit + color.rgba[3]*(0x100-cit)) / 0x100; } draw_pixel.call(draw_pixel.ctx, pos_x-x, pos_y-y, color); if(x) draw_pixel.call(draw_pixel.ctx, pos_x+x, pos_y-y, color); if(y){ draw_pixel.call(draw_pixel.ctx, pos_x-x, pos_y+y, color); if(x) draw_pixel.call(draw_pixel.ctx, pos_x+x, pos_y+y, color); } } } } struct canvas { size_t width; size_t height; void* data; }; static inline int min(int a, int b){ return a < b ? a : b; } static inline RGBA RGBA_overlay_premultiplied(RGBA s, RGBA d){ return (RGBA){ min( s.rgba[0] + d.rgba[0] * (0xFF-s.rgba[3]) / 0xFF, 0xFF ), min( s.rgba[1] + d.rgba[1] * (0xFF-s.rgba[3]) / 0xFF, 0xFF ), min( s.rgba[2] + d.rgba[2] * (0xFF-s.rgba[3]) / 0xFF, 0xFF ), min( s.rgba[3] + d.rgba[3] * (0xFF-s.rgba[3]) / 0xFF, 0xFF ), }; } draw_pixel_f canvas_draw_pixel; void canvas_draw_pixel(void* ctx, long x, long y, RGBA color){ const struct canvas*const img = ctx; RGBA (*const data)[img->width] = img->data; if(x<0 || y<0 || x>=img->width ||y>=img->height) return; data[y][x] = RGBA_overlay_premultiplied(color, data[y][x]); } void premultiplied_to_straight(size_t n, RGBA data[n]){ for(size_t i=0; i