add .gitignore
[xgalaxy.git] / antialias_draw.c
1 #include <stdio.h>
2 #include <errno.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <gtk/gtk.h>
6 #include <math.h>
7 #include <pthread.h>
8
9 #include "tmalloc.h"
10 #include "xgalaxy.h"
11
12
13         
14 void
15 setBrightPoint(GdkGC *gc, int x, int y, int c) {
16         GdkColor color;
17
18         color.red=color.green=color.blue=(255-c)*256;
19         gdk_gc_set_rgb_fg_color(gc, &color);
20
21         gdk_draw_point( XGalaxy.pixmap, gc, x, y );
22 }
23
24 void
25 setBrightPoints(GdkGC *gc, GdkPoint *points, int n,  int c) {
26         GdkColor color;
27
28         color.red=color.green=color.blue=(255-c)*256;
29         gdk_gc_set_rgb_fg_color(gc, &color);
30
31         gdk_draw_points( XGalaxy.pixmap, gc, points, n );
32 }
33
34 #define sqr(x)  ((x)*(x))
35
36 void
37 DrawDisk(GdkGC *gc, double CenterX, double CenterY, double Radius, double Feather, double brightness) {
38 // (c) http://www.simdesign.nl/tips/tip002.html
39 // Draw a disk on Bitmap. Bitmap must be a 256 color (pf8bit)
40 // palette bitmap, and parts outside the disk will get palette
41 // index 0, parts inside will get palette index 255, and in the
42 // antialiased area (feather), the pixels will get values
43 // inbetween.
44 // ***Parameters***
45 // Bitmap:
46 //   The bitmap to draw on
47 // CenterX, CenterY:
48 //   The center of the disk (float precision). Note that [0, 0]
49 //   would be the center of the first pixel. To draw in the
50 //   exact middle of a 100x100 bitmap, use CenterX = 49.5 and
51 //   CenterY = 49.5
52 // Radius:
53 //   The radius of the drawn disk in pixels (float precision)
54 // Feather:
55 //   The feather area. Use 1 pixel for a 1-pixel antialiased
56 //   area. Pixel centers outside 'Radius + Feather / 2' become
57 //   0, pixel centers inside 'Radius - Feather/2' become 255.
58 //   Using a value of 0 will yield a bilevel image.
59 // Copyright (c) 2003 Nils Haeck M.Sc. www.simdesign.nl
60         
61         int  x, y;
62         int  Fact;
63         double  RPF2 = sqr(Radius + Feather/2.0);
64         double  RMF2 = sqr(Radius - Feather/2.0);
65         double   SqY, SqDist;
66         // Determine bounds:
67         int LX = floor(CenterX - RPF2);
68         int RX = ceil (CenterX + RPF2);
69         int LY = floor(CenterY - RPF2);
70         int RY = ceil (CenterY + RPF2);
71         double SqX[RX - LX + 1];
72         GdkPoint darkPoint[ (RY-LY)*(RX-LX) ];
73         int nDarkDoint=0;
74
75
76         // Optimization run: find squares of X first
77         for(x=LX; x<=RX; x++)
78                 SqX[x - LX] = sqr(x - CenterX);
79
80         for(y=LY; y<=RY; y++) {
81                 SqY = sqr(y - CenterY);
82                 // Loop through X values
83                 for(x=LX; x<=RX; x++) {
84
85                         // determine squared distance from center for this pixel
86                         SqDist = SqY + SqX[x - LX];
87
88                         if (SqDist < RMF2) { // inside inner circle? Most often..
89                                 // inside the inner circle.. just give the scanline the
90                                 // new color
91                                 darkPoint[ nDarkDoint ].x = x;
92                                 darkPoint[ nDarkDoint ].y = y;
93                                 nDarkDoint++;
94                         } else  if (SqDist < RPF2) { // inside outer circle? 
95                                 // We are inbetween the inner and outer bound, now
96                                 // mix the color
97                                 Fact = round(((Radius - sqrt(SqDist)) * 2.0 / Feather) * 127.5 + 127.5);
98                                 // just in case limit to [0, 255]
99                                 setBrightPoint(gc, x,y,brightness*fmax(0, fmin(Fact, 255)));
100                         }
101                 }
102         }
103         if (nDarkDoint>0)
104                 setBrightPoints( gc, darkPoint, nDarkDoint, 255*brightness ); 
105 }
106
107 // Draw a line with simple anti-aliasing, suitable for draggable envelope displays.
108 // By Paul Kellett (@mda-vst.com) October 2002.
109 //
110 // The anti-aliasing works by oversampling the drawing position by 256 then using
111 // the fractional part to fade in the pixel on one side of the line while fading
112 // out the pixel on the other side. The ends of the line aren't perfect, but these
113 // will probably be hidden by drag handles.
114 //
115 // Uses fictional function: drawpixel(int x, int y, int brightness) where brightness
116 // is a value from 0 to 255, so it's easiest to draw a red, green or blue line on a
117 // black (or near-black) background.
118
119
120 void
121 drawPixel(GdkGC *gc, GdkColor *color, int x, int y, int c) {
122         GdkColor clr;
123         double ratio = ((double)c)/255.0;
124                 
125         clr.red   = color->red   + (65535-color->red)   * ratio;
126         clr.green = color->green + (65535-color->green) * ratio;
127         clr.blue  = color->blue  + (65535-color->blue)  * ratio;
128         gdk_gc_set_rgb_fg_color(gc, &clr);
129
130         gdk_draw_point( XGalaxy.pixmap, gc, x, y );
131 }
132
133 void 
134 antialiasedLine(GdkGC *gc, int x0, int y0, int x1, int y1, GdkColor *color) {
135   int x, y, xx, yy, v;
136   int dx = x1 - x0;
137   int dy = y1 - y0;
138   
139   if (dx==0 && dy==0) { 
140         drawPixel(gc, color, x1, y1, 0);
141         return;
142   }
143  
144   if(abs(dx) > abs(dy)) //for each x pixel
145   {
146     if(x0 > x1) //for increasing x
147     {
148       x = x0;  x0 = x1;  x1 = x;
149       y = y0;  y0 = y1;  y1 = y;
150     }
151     dy = (dy << 8) / dx; //oversample y by 256
152     yy = y0 << 8;
153     
154     for(x=x0; x<x1; x++) //draw line
155     {
156       v = yy & 0xFF;
157       int y = yy >> 8;
158       yy = yy + dy;
159       drawPixel(gc, color,x, y, 0);
160       drawPixel(gc, color,x, y + 1, 255-v);
161       drawPixel(gc, color,x, y - 1, v);
162     }
163   }
164   else //for each y pixel
165   {
166     if(y0 > y1) //for increasing y
167     {
168       y = y0;  y0 = y1;  y1 = y;
169       x = x0;  x0 = x1;  x1 = x;
170     }
171     dx = (dx << 8) / dy;  //oversample x by 256
172     xx = x0 << 8;
173
174     for(y=y0; y<y1; y++)
175     {
176       v = xx & 0xFF;
177       x = xx >> 8;
178       xx = xx + dx;
179       drawPixel(gc, color,x, y, 0);
180       drawPixel(gc, color,x + 1, y, 255-v);
181       drawPixel(gc, color,x - 1, y, v);
182     }
183   }
184 }