Code

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