Code

moving trunk for module inkscape
[inkscape.git] / src / livarot / AlphaLigne.cpp
1 /*
2  *  AlphaLigne.cpp
3  *  nlivarot
4  *
5  *  Created by fred on Fri Jul 25 2003.
6  *  public domain
7  *
8  */
10 #include "AlphaLigne.h"
11 //#include "Buffer.h"
13 #include <math.h>
14 #include <glib/gmem.h>
16 AlphaLigne::AlphaLigne(int iMin,int iMax)
17 {
18         min=iMin;
19         max=iMax;
20         if ( max < min+1 ) max=min+1;
21         steps=NULL;
22         nbStep=maxStep=0;
23         before.x=min-1;
24         before.delta=0;
25         after.x=max+1;
26         after.delta=0;
27 }
28 AlphaLigne::~AlphaLigne(void)
29 {
30         g_free(steps);
31         steps=NULL;
32         nbStep=maxStep=0;
33 }
34 void                                             AlphaLigne::Affiche(void)
35 {
36         printf("%i steps\n",nbStep);
37         for (int i=0;i<nbStep;i++) {
38                 printf("(%i %f) ",steps[i].x,steps[i].delta); // localization ok
39         }
40         printf("\n");
41 }
44 void             AlphaLigne::Reset(void)
45 {
46   // reset to empty line
47   // doesn't deallocate the steps array, to minimize memory operations
48         curMin=max;
49         curMax=min;
50         nbStep=0;
51         before.x=min-1;
52         before.delta=0;
53         after.x=max+1;
54         after.delta=0;
55 }
56 int              AlphaLigne::AddBord(float spos,float sval,float epos,float eval,float tPente)
57 {
58 //      printf("%f %f -> %f %f / %f\n",spos,sval,epos,eval,tPente);
59         if ( sval == eval ) return 0;
60   // compute the footprint of [spos,epos] on the line of pixels
61         float  curStF=floor(spos);
62         float  curEnF=floor(epos);
63         int   curSt=(int)curStF;
64         int   curEn=(int)curEnF;
65         
66   // update curMin and curMax
67         if ( curSt > max ) {
68     // we're on the right of the visible portion of the line: bail out!
69     if ( eval < sval ) curMax=max;
70     return 0;
71   }
72         if ( curSt < curMin ) curMin=curSt;
73         if ( ceil(epos) > curMax ) curMax=(int)ceil(epos);
74         
75   // clamp the changed portion to [min,max], no need for bigger
76         if ( curMax > max ) curMax=max;
77         if ( curMin < min ) curMin=min;
78         
79   // total amount of change in pixel coverage from before the right to after the run
80         float    needed=eval-sval;
81         float    needC=/*(int)ldexpf(*/needed/*,24)*/;
82         
83         if ( curEn < min ) {
84     // the added portion is entirely on the left, so we only have to change the initial coverage for the line
85     before.delta+=needC;
86     return 0;
87         }
88   
89   // add the steps
90   // the pixels from [curSt..curEn] (included) intersect with [spos;epos]
91   // since we're dealing with delta in the coverage, there is also a curEn+1 delta, since the curEn pixel intersect
92   // with [spos;epos] and thus has some delta with respect to its next pixel
93   // lots of different cases... ugly
94         if ( curSt == curEn ) {
95                 if ( curSt+1 < min ) {
96                         before.delta+=needC;
97                 } else {
98                         if ( nbStep+2 >= maxStep ) {
99                                 maxStep=2*nbStep+2;
100                                 steps=(alpha_step*)g_realloc(steps,maxStep*sizeof(alpha_step));
101                         }
102                         float  stC=/*(int)ldexpf(*/(eval-sval)*(0.5*(epos-spos)+curStF+1-epos)/*,24)*/;
103                         steps[nbStep].x=curSt;
104                         steps[nbStep].delta=stC;
105                         nbStep++;
106                         steps[nbStep].x=curSt+1;
107                         steps[nbStep].delta=needC-stC; //  au final, on a toujours le bon delta, meme avec une arete completement verticale
108                         nbStep++;
109                 }
110         } else if ( curEn == curSt+1 ) {
111                 if ( curSt+2 < min ) {
112                         before.delta+=needC;
113                 } else {
114                         if ( nbStep+3 >= maxStep ) {
115                                 maxStep=2*nbStep+3;
116                                 steps=(alpha_step*)g_realloc(steps,maxStep*sizeof(alpha_step));
117                         }
118                         float  stC=/*(int)ldexpf(*/0.5*tPente*(curEnF-spos)*(curEnF-spos)/*,24)*/;
119                         float  enC=/*(int)ldexpf(*/tPente-0.5*tPente*((spos-curStF)*(spos-curStF)+(curEnF+1.0-epos)*(curEnF+1.0-epos))/*,24)*/;
120                         steps[nbStep].x=curSt;
121                         steps[nbStep].delta=stC;
122                         nbStep++;
123                         steps[nbStep].x=curEn;
124                         steps[nbStep].delta=enC;
125                         nbStep++;
126                         steps[nbStep].x=curEn+1;
127                         steps[nbStep].delta=needC-stC-enC;
128                         nbStep++;
129                 }
130         } else {
131                 float  stC=/*(int)ldexpf(*/0.5*tPente*(curStF+1-spos)*(curStF+1-spos)/*,24)*/;
132                 float  stFC=/*(int)ldexpf(*/tPente-0.5*tPente*(spos-curStF)*(spos-curStF)/*,24)*/;
133                 float  enC=/*(int)ldexpf(*/tPente-0.5*tPente*(curEnF+1.0-epos)*(curEnF+1.0-epos)/*,24)*/;
134                 float  miC=/*(int)ldexpf(*/tPente/*,24)*/;
135                 if ( curSt < min ) {
136                         if ( curEn > max ) {
137                                 if ( nbStep+(max-min) >= maxStep ) {
138                                         maxStep=2*nbStep+(max-min);
139                                         steps=(alpha_step*)g_realloc(steps,maxStep*sizeof(alpha_step));
140                                 }
141                                 float  bfd=min-curSt-1;
142                                 bfd*=miC;
143                                 before.delta+=stC+bfd;
144                                 for (int i=min;i<max;i++) {
145                                         steps[nbStep].x=i;
146                                         steps[nbStep].delta=miC;
147                                         nbStep++;
148                                 }
149                         } else {
150                                 if ( nbStep+(curEn-min)+2 >= maxStep ) {
151                                         maxStep=2*nbStep+(curEn-min)+2;
152                                         steps=(alpha_step*)g_realloc(steps,maxStep*sizeof(alpha_step));
153                                 }
154                                 float  bfd=min-curSt-1;
155                                 bfd*=miC;
156                                 before.delta+=stC+bfd;
157                                 for (int i=min;i<curEn;i++) {
158                                         steps[nbStep].x=i;
159                                         steps[nbStep].delta=miC;
160                                         nbStep++;
161                                 }
162                                 steps[nbStep].x=curEn;
163                                 steps[nbStep].delta=enC;
164                                 nbStep++;
165                                 steps[nbStep].x=curEn+1;
166                                 steps[nbStep].delta=needC-stC-stFC-enC-(curEn-curSt-2)*miC;
167                                 nbStep++;
168                         }
169                 } else {
170                         if ( curEn > max ) {
171                                 if ( nbStep+3+(max-curSt) >= maxStep ) {
172                                         maxStep=2*nbStep+3+(curEn-curSt);
173                                         steps=(alpha_step*)g_realloc(steps,maxStep*sizeof(alpha_step));
174                                 }
175                                 steps[nbStep].x=curSt;
176                                 steps[nbStep].delta=stC;
177                                 nbStep++;
178                                 steps[nbStep].x=curSt+1;
179                                 steps[nbStep].delta=stFC;
180                                 nbStep++;
181                                 for (int i=curSt+2;i<max;i++) {
182                                         steps[nbStep].x=i;
183                                         steps[nbStep].delta=miC;
184                                         nbStep++;
185                                 }
186                         } else {
187                                 if ( nbStep+3+(curEn-curSt) >= maxStep ) {
188                                         maxStep=2*nbStep+3+(curEn-curSt);
189                                         steps=(alpha_step*)g_realloc(steps,maxStep*sizeof(alpha_step));
190                                 }
191                                 steps[nbStep].x=curSt;
192                                 steps[nbStep].delta=stC;
193                                 nbStep++;
194                                 steps[nbStep].x=curSt+1;
195                                 steps[nbStep].delta=stFC;
196                                 nbStep++;
197                                 for (int i=curSt+2;i<curEn;i++) {
198                                         steps[nbStep].x=i;
199                                         steps[nbStep].delta=miC;
200                                         nbStep++;
201                                 }
202                                 steps[nbStep].x=curEn;
203                                 steps[nbStep].delta=enC;
204                                 nbStep++;
205                                 steps[nbStep].x=curEn+1;
206                                 steps[nbStep].delta=needC-stC-stFC-enC-(curEn-curSt-2)*miC;
207                                 nbStep++;
208                         }
209                 }
210         }
212         return 0;
214 int              AlphaLigne::AddBord(float spos,float sval,float epos,float eval)
216         // pas de pente dans ce cas; on ajoute le delta au premier pixel
217         float   tPente=(eval-sval);
219         float curStF=floor(spos);
220         float curEnF=floor(epos);
221         int   curSt=(int)curStF;
222         int   curEn=(int)curEnF;
223         
224         if ( curSt > max ) {
225     if ( eval < sval ) curMax=max;
226     return 0; // en dehors des limites (attention a ne pas faire ca avec curEn)
227   }
228         if ( curEn < min ) {
229     before.delta+=eval-sval;
230     return 0; // en dehors des limites (attention a ne pas faire ca avec curEn)
231         }
232         
233         if ( curSt < curMin ) curMin=curSt;
234 //      int   curEn=(int)curEnF;
235         if ( ceil(epos) > curMax-1 ) curMax=1+(int)ceil(epos);
236         if ( curSt < min ) {
237                 before.delta+=eval-sval;
238         } else {
239                 AddRun(curSt,/*(int)ldexpf(*/(((float)(curSt+1))-spos)*tPente/*,24)*/);
240                 AddRun(curSt+1,/*(int)ldexpf(*/(spos-((float)(curSt)))*tPente/*,24)*/);
241         }
242         return 0;
245 void             AlphaLigne::Flatten(void)
247   // just sort
248         if ( nbStep > 0 ) qsort(steps,nbStep,sizeof(alpha_step),CmpStep);
250 void             AlphaLigne::AddRun(int st,float pente)
252         if ( nbStep >= maxStep ) {
253                 maxStep=2*nbStep+1;
254                 steps=(alpha_step*)g_realloc(steps,maxStep*sizeof(alpha_step));
255         }
256         int nStep=nbStep++;
257         steps[nStep].x=st;
258         steps[nStep].delta=pente;
261 void             AlphaLigne::Raster(raster_info &dest,void* color,RasterInRunFunc worker)
263   // start by checking if there are actually pixels in need of rasterization
264         if ( curMax <= curMin ) return;
265         if ( dest.endPix <= curMin || dest.startPix >= curMax ) return;
267         int    nMin=curMin,nMax=curMax;
268         float  alpSum=before.delta; // alpSum will be the pixel coverage value, so we start at before.delta
269         int    curStep=0;
270   
271   // first add all the deltas up to the first pixel in need of rasterization
272   while ( curStep < nbStep && steps[curStep].x < nMin ) { 
273     alpSum+=steps[curStep].delta;
274     curStep++;
275   }
276   // just in case, if the line bounds are greater than the buffer bounds.
277         if ( nMin < dest.startPix ) {
278                 for (;( curStep < nbStep && steps[curStep].x < dest.startPix) ;curStep++) alpSum+=steps[curStep].delta;
279                 nMin=dest.startPix;
280         }
281         if ( nMax > dest.endPix ) nMax=dest.endPix;
283   // raster!
284         int       curPos=dest.startPix;
285         for (;curStep<nbStep;curStep++) {
286                 if ( alpSum > 0 && steps[curStep].x > curPos ) {
287       // we're going to change the pixel position curPos, and alpSum is > 0: rasterization needed from
288       // the last position (curPos) up to the pixel we're moving to (steps[curStep].x)
289                         int  nst=curPos,nen=steps[curStep].x;
290 //Buffer::RasterRun(dest,color,nst,alpSum,nen,alpSum);
291       (worker)(dest,color,nst,alpSum,nen,alpSum);
292                 }
293     // add coverage deltas
294                 alpSum+=steps[curStep].delta;
295                 curPos=steps[curStep].x;
296                 if ( curPos >= nMax ) break;
297         }
298   // if we ended the line with alpSum > 0, we need to raster from curPos to the right edge
299         if ( alpSum > 0 && curPos < nMax ) {
300                 int  nst=curPos,nen=max;
301     (worker)(dest,color,nst,alpSum,nen,alpSum);
302 //Buffer::RasterRun(dest,color,nst,alpSum,nen,alpSum);
303         }