fa128e1a7b7ff68058dbbc5272200977170c3a7d
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;
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);
75 // clamp the changed portion to [min,max], no need for bigger
76 if ( curMax > max ) curMax=max;
77 if ( curMin < min ) curMin=min;
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)*/;
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 }
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;
213 }
214 int AlphaLigne::AddBord(float spos,float sval,float epos,float eval)
215 {
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;
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 }
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;
243 }
245 void AlphaLigne::Flatten(void)
246 {
247 // just sort
248 if ( nbStep > 0 ) qsort(steps,nbStep,sizeof(alpha_step),CmpStep);
249 }
250 void AlphaLigne::AddRun(int st,float pente)
251 {
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;
259 }
261 void AlphaLigne::Raster(raster_info &dest,void* color,RasterInRunFunc worker)
262 {
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;
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 }
304 }