|
1 /* |
|
2 * Copyright (c) 2006-2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: ?Description |
|
15 * |
|
16 * Note that we do not use OpenVG's line/arc rendering directly, since the |
|
17 * curves we are dealing with may have variable widths, which is not supported |
|
18 * by OpenVG yet. Also, only one opacity factor per path is supported. |
|
19 * |
|
20 */ |
|
21 |
|
22 #include "HuiVg10CurvePath.h" |
|
23 #include "HuiVg10Gc.h" |
|
24 #include "uiacceltk/HuiRealPoint.h" |
|
25 #include "uiacceltk/HuiUtil.h" |
|
26 |
|
27 CHuiVg10CurvePath::CHuiVg10CurvePath() |
|
28 : CHuiCurvePath() |
|
29 { |
|
30 } |
|
31 |
|
32 |
|
33 void CHuiVg10CurvePath::ConstructL() |
|
34 { |
|
35 iPathCommands = 0; |
|
36 iLastOpacityFactor = -1.0; |
|
37 iMaxTupleCount = 0; |
|
38 iUsedTupleCount = 0; |
|
39 iPathCoords = 0; |
|
40 |
|
41 iPath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, |
|
42 1.0f, 0.0f, 32, 32, VG_PATH_CAPABILITY_APPEND_TO); |
|
43 HUI_VG_INVARIANT(); |
|
44 } |
|
45 |
|
46 |
|
47 CHuiVg10CurvePath::~CHuiVg10CurvePath() |
|
48 { |
|
49 Reset(); |
|
50 vgDestroyPath(iPath); |
|
51 iPath = 0; |
|
52 HUI_VG_INVARIANT(); |
|
53 } |
|
54 |
|
55 |
|
56 void CHuiVg10CurvePath::Reset() |
|
57 { |
|
58 CHuiCurvePath::Reset(); |
|
59 ResetPath(); |
|
60 } |
|
61 |
|
62 void CHuiVg10CurvePath::ResetPath() |
|
63 { |
|
64 ResetTuples(); |
|
65 vgClearPath(iPath, VG_PATH_CAPABILITY_APPEND_TO); |
|
66 HUI_VG_INVARIANT(); |
|
67 } |
|
68 |
|
69 void CHuiVg10CurvePath::ResetTuples() |
|
70 { |
|
71 delete[] iPathCoords; |
|
72 delete[] iPathCommands; |
|
73 iPathCoords = 0; |
|
74 iPathCommands = 0; |
|
75 iMaxTupleCount = 0; |
|
76 iUsedTupleCount = 0; |
|
77 } |
|
78 |
|
79 TInt CHuiVg10CurvePath::SegmentTuples(const TSegment& aSegment) const |
|
80 { |
|
81 if(aSegment.iType == ESegmentTypeLine) |
|
82 { |
|
83 return 2; |
|
84 } |
|
85 else if(aSegment.iType == ESegmentTypeArc) |
|
86 { |
|
87 const TReal32 KAnglePerSegment = 5; |
|
88 TInt tuples = Abs(aSegment.iAngleDelta) / KAnglePerSegment + 1; |
|
89 if(tuples < 2) |
|
90 { |
|
91 tuples = 2; |
|
92 } |
|
93 return tuples; |
|
94 } |
|
95 ASSERT(0); |
|
96 return 0; |
|
97 } |
|
98 |
|
99 void CHuiVg10CurvePath::Update(TReal32 aStartPos, TReal32 aEndPos, |
|
100 TReal32 aAlphaFactor, |
|
101 MHuiMappingFunction* aAlphaFunction, |
|
102 MHuiMappingFunction* aWidthFunction) __SOFTFP |
|
103 { |
|
104 const TReal32 KEpsilon = .001; |
|
105 if(!GetVisual() && !NeedUpdate() && Abs(iLastOpacityFactor - aAlphaFactor) < KEpsilon) |
|
106 { |
|
107 // No need to update every time the path is drawn. |
|
108 return; |
|
109 } |
|
110 |
|
111 iLastOpacityFactor = aAlphaFactor; |
|
112 |
|
113 // Allocate enough memory for the path coordinates and commands. This is |
|
114 // the maximum number of path nodes that can be. If aStartPos and aEndPos are |
|
115 // somewhere in the middle, a smaller amount of data is generated. |
|
116 TInt tuples = 0; |
|
117 TInt i = 0; |
|
118 for(i = 0; i < SegmentCount(); ++i) |
|
119 { |
|
120 tuples += SegmentTuples(Segment(i)) - 1; |
|
121 } |
|
122 |
|
123 // One extra tuple for the end. |
|
124 tuples++; |
|
125 |
|
126 TRAPD(err, SetTupleCountL(tuples)); |
|
127 if(err != KErrNone) |
|
128 { |
|
129 ResetPath(); |
|
130 return; |
|
131 } |
|
132 |
|
133 // Generate commands for the entire path, starting from aStartPos |
|
134 // and stopping at aEndPos. |
|
135 TReal32 pos = 0; |
|
136 iUsedTupleCount = 0; |
|
137 |
|
138 for(i = 0; i < SegmentCount(); ++i) |
|
139 { |
|
140 const TSegment& segment = Segment(i); |
|
141 TReal32 segmentEnd = pos + segment.iLength; |
|
142 |
|
143 if(aStartPos > segmentEnd) |
|
144 { |
|
145 // The start is past the end of the segment. |
|
146 continue; |
|
147 } |
|
148 if(aEndPos < pos) |
|
149 { |
|
150 // We're past the end! |
|
151 break; |
|
152 } |
|
153 |
|
154 TReal32 start = pos; |
|
155 TReal32 end = segmentEnd; |
|
156 TBool isFinal = EFalse; |
|
157 |
|
158 if(start < aStartPos) |
|
159 { |
|
160 start = aStartPos; |
|
161 } |
|
162 if(end >= aEndPos || i == SegmentCount() - 1) |
|
163 { |
|
164 end = aEndPos; |
|
165 isFinal = ETrue; |
|
166 } |
|
167 else |
|
168 { |
|
169 isFinal = EFalse; |
|
170 } |
|
171 |
|
172 // Normalize. |
|
173 start -= pos; |
|
174 end -= pos; |
|
175 |
|
176 MakeSegmentTuples(segment, start, end, isFinal, aAlphaFactor, |
|
177 aAlphaFunction, aWidthFunction); |
|
178 |
|
179 pos += segment.iLength; |
|
180 } |
|
181 ASSERT(iUsedTupleCount <= iMaxTupleCount); |
|
182 ASSERT(iUsedTupleCount > 0); |
|
183 |
|
184 // First traverse the curve from start to end |
|
185 vgAppendPathData(iPath, iUsedTupleCount, iPathCommands, iPathCoords); |
|
186 HUI_VG_INVARIANT(); |
|
187 |
|
188 // And then back again on the other side |
|
189 TInt tailIndex = 2 * iMaxTupleCount - iUsedTupleCount; |
|
190 vgAppendPathData(iPath, iUsedTupleCount, &iPathCommands[tailIndex], &iPathCoords[2 * tailIndex]); |
|
191 HUI_VG_INVARIANT(); |
|
192 |
|
193 // We do not need the tuple arrays anymore so we can free them |
|
194 ResetTuples(); |
|
195 |
|
196 CHuiCurvePath::Update(aStartPos, aEndPos, aAlphaFactor, |
|
197 aAlphaFunction, aWidthFunction); |
|
198 } |
|
199 |
|
200 void CHuiVg10CurvePath::SetTupleCountL(TInt aTupleCount) |
|
201 { |
|
202 if(iMaxTupleCount != aTupleCount) |
|
203 { |
|
204 ResetPath(); |
|
205 |
|
206 // Allocate new arrays. |
|
207 iMaxTupleCount = aTupleCount; |
|
208 |
|
209 if(iMaxTupleCount > 0) |
|
210 { |
|
211 iPathCoords = new (ELeave) VGfloat[2 * iMaxTupleCount * 2]; |
|
212 iPathCommands = new (ELeave) VGubyte[iMaxTupleCount * 2]; |
|
213 |
|
214 // Since every path command is the same, we can do this at |
|
215 // allocation time |
|
216 for (TInt i = 0; i < iMaxTupleCount * 2; i++) |
|
217 { |
|
218 iPathCommands[i] = VG_LINE_TO; |
|
219 } |
|
220 } |
|
221 } |
|
222 } |
|
223 |
|
224 void CHuiVg10CurvePath::MakeSegmentTuples(const TSegment& aSegment, |
|
225 TReal32 aStart, TReal32 aEnd, |
|
226 TBool aIsFinal, |
|
227 TReal32 aAlphaFactor, |
|
228 MHuiMappingFunction* aAlphaFunction, |
|
229 MHuiMappingFunction* aWidthFunction) |
|
230 { |
|
231 // aStart and aEnd are in range [0,length]. |
|
232 THuiRealPoint point; |
|
233 THuiRealPoint normal; |
|
234 TReal32 normStart = (aStart + aSegment.iTotalPos) / Length(); |
|
235 TReal32 normEnd = (aEnd + aSegment.iTotalPos) / Length(); |
|
236 |
|
237 if(aSegment.iType == ESegmentTypeLine) |
|
238 { |
|
239 EvaluateSegment(aStart, aSegment, point, &normal); |
|
240 TReal32 width = 1; |
|
241 if(aWidthFunction) |
|
242 { |
|
243 width = aWidthFunction->MapValue(normStart, 0); |
|
244 } |
|
245 TReal32 alpha = 1; |
|
246 if(aAlphaFunction) |
|
247 { |
|
248 alpha = aAlphaFunction->MapValue(normStart, 0); |
|
249 } |
|
250 AddTuple(point, normal, width, alpha * aAlphaFactor); |
|
251 |
|
252 if(aIsFinal) |
|
253 { |
|
254 // Does not reach the end, so we must also make an end tuple. |
|
255 EvaluateSegment(aEnd, aSegment, point, &normal); |
|
256 if(aWidthFunction) |
|
257 { |
|
258 width = aWidthFunction->MapValue(normEnd, 0); |
|
259 } |
|
260 else |
|
261 { |
|
262 width = 1; |
|
263 } |
|
264 if(aAlphaFunction) |
|
265 { |
|
266 alpha = aAlphaFunction->MapValue(normEnd, 0); |
|
267 } |
|
268 else |
|
269 { |
|
270 alpha = 1; |
|
271 } |
|
272 AddTuple(point, normal, width, alpha * aAlphaFactor); |
|
273 } |
|
274 } |
|
275 |
|
276 if(aSegment.iType == ESegmentTypeArc) |
|
277 { |
|
278 // Make a set of tuples. |
|
279 TInt count = SegmentTuples(aSegment); |
|
280 TInt endCount = count; |
|
281 if(aIsFinal) |
|
282 { |
|
283 endCount = count - 1; |
|
284 } |
|
285 else |
|
286 { |
|
287 count--; |
|
288 endCount--; |
|
289 } |
|
290 |
|
291 for(TInt i = 0; i < count; ++i) |
|
292 { |
|
293 TReal32 off = i / TReal32(endCount); |
|
294 EvaluateSegment(aStart + (aEnd - aStart) * off, aSegment, point, |
|
295 &normal); |
|
296 TReal32 width = 1; |
|
297 if(aWidthFunction) |
|
298 { |
|
299 width = aWidthFunction->MapValue(normStart + |
|
300 (normEnd - normStart) * off, 0); |
|
301 } |
|
302 TReal32 alpha = 1; |
|
303 if(aAlphaFunction) |
|
304 { |
|
305 alpha = aAlphaFunction->MapValue(normStart + |
|
306 (normEnd - normStart) * off, 0); |
|
307 } |
|
308 AddTuple(point, normal, width, alpha * aAlphaFactor); |
|
309 } |
|
310 } |
|
311 } |
|
312 |
|
313 void CHuiVg10CurvePath::AddTuple(const THuiRealPoint& aPoint, |
|
314 const THuiRealPoint& aNormal, |
|
315 TReal32 aWidth, TReal32 /*aAlpha*/) |
|
316 { |
|
317 ASSERT(iUsedTupleCount < iMaxTupleCount); |
|
318 |
|
319 // Make a pair of vertices. Normal is to the left. |
|
320 // |
|
321 // The first half of the path goes from the beginning of the curve |
|
322 // to the end, while the second half traverses the same route |
|
323 // backwards: |
|
324 // |
|
325 // 0 iUsedTupleCount |
|
326 // >--->--->---> ... >---v |
|
327 // | | |
|
328 // ^---<---<---< ... <---< |
|
329 // iMaxTupleCount - iMaxtupleCount |
|
330 // iUsedTupleCount |
|
331 // |
|
332 // The coordinate array looks like this: |
|
333 // |
|
334 // +---+---+---+---+---+---+---+---+ N: tuple N left vertex |
|
335 // | 0 | 1 | 2 | X | X | 2'| 1'| 0'| N': tuple N right vertex |
|
336 // +---+---+---+---+---+---+---+---+ X: unused |
|
337 // |
|
338 VGfloat* vertex1 = &iPathCoords[2 * iUsedTupleCount]; |
|
339 VGfloat* vertex2 = &iPathCoords[2 * (2 * iMaxTupleCount - iUsedTupleCount - 1)]; |
|
340 const CHuiVisual* visual = GetVisual(); |
|
341 |
|
342 if (visual) |
|
343 { |
|
344 THuiRealPoint point1(aPoint.iX + aNormal.iX * aWidth/2,aPoint.iY + aNormal.iY * aWidth/2); |
|
345 THuiRealPoint point2(aPoint.iX - aNormal.iX * aWidth/2,aPoint.iY - aNormal.iY * aWidth/2); |
|
346 point1 = visual->LocalPointInPixels(point1); |
|
347 point2 = visual->LocalPointInPixels(point2); |
|
348 vertex1[0] = point1.iX; |
|
349 vertex1[1] = point1.iY; |
|
350 vertex2[0] = point2.iX; |
|
351 vertex2[1] = point2.iY; |
|
352 } |
|
353 else |
|
354 { |
|
355 vertex1[0] = aPoint.iX + aNormal.iX * aWidth/2; |
|
356 vertex1[1] = aPoint.iY + aNormal.iY * aWidth/2; |
|
357 vertex2[0] = aPoint.iX - aNormal.iX * aWidth/2; |
|
358 vertex2[1] = aPoint.iY - aNormal.iY * aWidth/2; |
|
359 } |
|
360 |
|
361 iUsedTupleCount++; |
|
362 } |
|
363 |
|
364 void CHuiVg10CurvePath::Draw(const TPoint& aOrigin, CHuiGc* aGc) const |
|
365 { |
|
366 CHuiVg10Gc* gc = static_cast<CHuiVg10Gc*>(aGc); |
|
367 ASSERT(gc); |
|
368 gc->UpdateColor(); |
|
369 |
|
370 VGPaint paint = vgGetPaint(VG_FILL_PATH); |
|
371 VGfloat color[4], modifiedColor[4]; |
|
372 |
|
373 if (paint != VG_INVALID_HANDLE) |
|
374 { |
|
375 vgGetParameterfv(paint, VG_PAINT_COLOR, 4, color); |
|
376 modifiedColor[0] = color[0]; |
|
377 modifiedColor[1] = color[1]; |
|
378 modifiedColor[2] = color[2]; |
|
379 modifiedColor[3] = iLastOpacityFactor; |
|
380 vgSetParameterfv(paint, VG_PAINT_COLOR, 4, modifiedColor); |
|
381 HUI_VG_INVARIANT(); |
|
382 } |
|
383 |
|
384 gc->UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE); |
|
385 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); |
|
386 vgTranslate(aOrigin.iX, aOrigin.iY); |
|
387 vgDrawPath(iPath, VG_FILL_PATH); |
|
388 vgTranslate(-aOrigin.iX, -aOrigin.iY); |
|
389 vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); |
|
390 |
|
391 HUI_VG_INVARIANT(); |
|
392 |
|
393 if (paint != VG_INVALID_HANDLE) |
|
394 { |
|
395 vgSetParameterfv(paint, VG_PAINT_COLOR, 4, color); |
|
396 HUI_VG_INVARIANT(); |
|
397 } |
|
398 } |