1 /**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 **************************************************************************/
26
27 #include "VG/openvg.h"
28 #include "VG/vgu.h"
29
30 #include "matrix.h"
31 #include "path.h"
32 #include "handle.h"
33
34 #include "util/u_debug.h"
35 #include "util/u_pointer.h"
36
37 #include <math.h>
38 #include <assert.h>
39
40
vgu_append_float_coords(VGPath path,const VGubyte * cmds,VGint num_cmds,const VGfloat * coords,VGint num_coords)41 static void vgu_append_float_coords(VGPath path,
42 const VGubyte *cmds,
43 VGint num_cmds,
44 const VGfloat *coords,
45 VGint num_coords)
46 {
47 VGubyte common_data[40 * sizeof(VGfloat)];
48 struct path *p = handle_to_path(path);
49
50 vg_float_to_datatype(path_datatype(p), common_data, coords, num_coords);
51 vgAppendPathData(path, num_cmds, cmds, common_data);
52 }
53
vguLine(VGPath path,VGfloat x0,VGfloat y0,VGfloat x1,VGfloat y1)54 VGUErrorCode vguLine(VGPath path,
55 VGfloat x0, VGfloat y0,
56 VGfloat x1, VGfloat y1)
57 {
58 static const VGubyte cmds[] = {VG_MOVE_TO_ABS, VG_LINE_TO_ABS};
59 VGfloat coords[4];
60 VGbitfield caps;
61
62 if (path == VG_INVALID_HANDLE) {
63 return VGU_BAD_HANDLE_ERROR;
64 }
65 caps = vgGetPathCapabilities(path);
66 if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
67 return VGU_PATH_CAPABILITY_ERROR;
68 }
69
70 coords[0] = x0;
71 coords[1] = y0;
72 coords[2] = x1;
73 coords[3] = y1;
74
75 vgu_append_float_coords(path, cmds, 2, coords, 4);
76
77 return VGU_NO_ERROR;
78 }
79
vguPolygon(VGPath path,const VGfloat * points,VGint count,VGboolean closed)80 VGUErrorCode vguPolygon(VGPath path,
81 const VGfloat * points,
82 VGint count,
83 VGboolean closed)
84 {
85 VGubyte *cmds;
86 VGfloat *coords;
87 VGbitfield caps;
88 VGint i;
89
90 if (path == VG_INVALID_HANDLE) {
91 return VGU_BAD_HANDLE_ERROR;
92 }
93
94 if (!points || count <= 0 || !is_aligned(points)) {
95 return VGU_ILLEGAL_ARGUMENT_ERROR;
96 }
97
98 caps = vgGetPathCapabilities(path);
99 if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
100 return VGU_PATH_CAPABILITY_ERROR;
101 }
102
103 cmds = malloc(sizeof(VGubyte) * count + 1);
104 coords = malloc(sizeof(VGfloat) * count * 2);
105
106 cmds[0] = VG_MOVE_TO_ABS;
107 coords[0] = points[0];
108 coords[1] = points[1];
109 for (i = 1; i < count; ++i) {
110 cmds[i] = VG_LINE_TO_ABS;
111 coords[2*i + 0] = points[2*i + 0];
112 coords[2*i + 1] = points[2*i + 1];
113 }
114
115 if (closed) {
116 cmds[i] = VG_CLOSE_PATH;
117 ++i;
118 }
119
120 vgu_append_float_coords(path, cmds, i, coords, 2*i);
121
122 free(cmds);
123 free(coords);
124
125 return VGU_NO_ERROR;
126 }
127
vguRect(VGPath path,VGfloat x,VGfloat y,VGfloat width,VGfloat height)128 VGUErrorCode vguRect(VGPath path,
129 VGfloat x, VGfloat y,
130 VGfloat width, VGfloat height)
131 {
132 static const VGubyte cmds[] = {VG_MOVE_TO_ABS,
133 VG_HLINE_TO_REL,
134 VG_VLINE_TO_REL,
135 VG_HLINE_TO_REL,
136 VG_CLOSE_PATH
137 };
138 VGfloat coords[5];
139 VGbitfield caps;
140
141 if (path == VG_INVALID_HANDLE) {
142 return VGU_BAD_HANDLE_ERROR;
143 }
144 caps = vgGetPathCapabilities(path);
145 if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
146 return VGU_PATH_CAPABILITY_ERROR;
147 }
148 if (width <= 0 || height <= 0) {
149 return VGU_ILLEGAL_ARGUMENT_ERROR;
150 }
151
152 coords[0] = x;
153 coords[1] = y;
154 coords[2] = width;
155 coords[3] = height;
156 coords[4] = -width;
157
158 vgu_append_float_coords(path, cmds, 5, coords, 5);
159
160 return VGU_NO_ERROR;
161 }
162
vguRoundRect(VGPath path,VGfloat x,VGfloat y,VGfloat width,VGfloat height,VGfloat arcWidth,VGfloat arcHeight)163 VGUErrorCode vguRoundRect(VGPath path,
164 VGfloat x, VGfloat y,
165 VGfloat width,
166 VGfloat height,
167 VGfloat arcWidth,
168 VGfloat arcHeight)
169 {
170 static const VGubyte cmds[] = {VG_MOVE_TO_ABS,
171 VG_HLINE_TO_REL,
172 VG_SCCWARC_TO_REL,
173 VG_VLINE_TO_REL,
174 VG_SCCWARC_TO_REL,
175 VG_HLINE_TO_REL,
176 VG_SCCWARC_TO_REL,
177 VG_VLINE_TO_REL,
178 VG_SCCWARC_TO_REL,
179 VG_CLOSE_PATH
180 };
181 VGfloat c[26];
182 VGbitfield caps;
183
184 if (path == VG_INVALID_HANDLE) {
185 return VGU_BAD_HANDLE_ERROR;
186 }
187 caps = vgGetPathCapabilities(path);
188 if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
189 return VGU_PATH_CAPABILITY_ERROR;
190 }
191 if (width <= 0 || height <= 0) {
192 return VGU_ILLEGAL_ARGUMENT_ERROR;
193 }
194
195 c[0] = x + arcWidth/2; c[1] = y;
196
197 c[2] = width - arcWidth;
198
199 c[3] = arcWidth/2; c[4] = arcHeight/2; c[5] = 0;
200 c[6] = arcWidth/2; c[7] = arcHeight/2;
201
202 c[8] = height - arcHeight;
203
204 c[9] = arcWidth/2; c[10] = arcHeight/2; c[11] = 0;
205 c[12] = -arcWidth/2; c[13] = arcHeight/2;
206
207 c[14] = -(width - arcWidth);
208
209 c[15] = arcWidth/2; c[16] = arcHeight/2; c[17] = 0;
210 c[18] = -arcWidth/2; c[19] = -arcHeight/2;
211
212 c[20] = -(height - arcHeight);
213
214 c[21] = arcWidth/2; c[22] = arcHeight/2; c[23] = 0;
215 c[24] = arcWidth/2; c[25] = -arcHeight/2;
216
217 vgu_append_float_coords(path, cmds, 10, c, 26);
218
219 return VGU_NO_ERROR;
220 }
221
vguEllipse(VGPath path,VGfloat cx,VGfloat cy,VGfloat width,VGfloat height)222 VGUErrorCode vguEllipse(VGPath path,
223 VGfloat cx, VGfloat cy,
224 VGfloat width,
225 VGfloat height)
226 {
227 static const VGubyte cmds[] = {VG_MOVE_TO_ABS,
228 VG_SCCWARC_TO_REL,
229 VG_SCCWARC_TO_REL,
230 VG_CLOSE_PATH
231 };
232 VGfloat coords[12];
233 VGbitfield caps;
234
235 if (path == VG_INVALID_HANDLE) {
236 return VGU_BAD_HANDLE_ERROR;
237 }
238 caps = vgGetPathCapabilities(path);
239 if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
240 return VGU_PATH_CAPABILITY_ERROR;
241 }
242 if (width <= 0 || height <= 0) {
243 return VGU_ILLEGAL_ARGUMENT_ERROR;
244 }
245
246 coords[0] = cx + width/2; coords[1] = cy;
247
248 coords[2] = width/2; coords[3] = height/2; coords[4] = 0;
249 coords[5] = -width; coords[6] = 0;
250
251 coords[7] = width/2; coords[8] = height/2; coords[9] = 0;
252 coords[10] = width; coords[11] = 0;
253
254 vgu_append_float_coords(path, cmds, 4, coords, 11);
255
256 return VGU_NO_ERROR;
257 }
258
vguArc(VGPath path,VGfloat x,VGfloat y,VGfloat width,VGfloat height,VGfloat startAngle,VGfloat angleExtent,VGUArcType arcType)259 VGUErrorCode vguArc(VGPath path,
260 VGfloat x, VGfloat y,
261 VGfloat width, VGfloat height,
262 VGfloat startAngle,
263 VGfloat angleExtent,
264 VGUArcType arcType)
265 {
266 VGubyte cmds[11];
267 VGfloat coords[40];
268 VGbitfield caps;
269 VGfloat last = startAngle + angleExtent;
270 VGint i, c = 0;
271
272 if (path == VG_INVALID_HANDLE) {
273 return VGU_BAD_HANDLE_ERROR;
274 }
275 caps = vgGetPathCapabilities(path);
276 if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
277 return VGU_PATH_CAPABILITY_ERROR;
278 }
279 if (width <= 0 || height <= 0) {
280 return VGU_ILLEGAL_ARGUMENT_ERROR;
281 }
282 if (arcType != VGU_ARC_OPEN &&
283 arcType != VGU_ARC_CHORD &&
284 arcType != VGU_ARC_PIE) {
285 return VGU_ILLEGAL_ARGUMENT_ERROR;
286 }
287
288 cmds[c] = VG_MOVE_TO_ABS; ++c;
289 coords[0] = x+cos(DEGREES_TO_RADIANS(startAngle))*width/2;
290 coords[1] = y+sin(DEGREES_TO_RADIANS(startAngle))*height/2;
291 #ifdef DEBUG_VGUARC
292 debug_printf("start [%f, %f]\n", coords[0], coords[1]);
293 #endif
294 i = 2;
295 if (angleExtent > 0) {
296 VGfloat angle = startAngle + 180;
297 while (angle < last) {
298 cmds[c] = VG_SCCWARC_TO_ABS; ++c;
299 coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0;
300 coords[i+3] = x + cos(DEGREES_TO_RADIANS(angle))*width/2;
301 coords[i+4] = y + sin(DEGREES_TO_RADIANS(angle))*height/2;
302 #ifdef DEBUG_VGUARC
303 debug_printf("1 [%f, %f]\n", coords[i+3],
304 coords[i+4]);
305 #endif
306 i += 5;
307 angle += 180;
308 }
309 cmds[c] = VG_SCCWARC_TO_ABS; ++c;
310 coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0;
311 coords[i+3] = x+cos(DEGREES_TO_RADIANS(last))*width/2;
312 coords[i+4] = y+sin(DEGREES_TO_RADIANS(last))*height/2;
313 #ifdef DEBUG_VGUARC
314 debug_printf("2 [%f, %f]\n", coords[i+3],
315 coords[i+4]);
316 #endif
317 i += 5;
318 } else {
319 VGfloat angle = startAngle - 180;
320 while (angle > last) {
321 cmds[c] = VG_SCWARC_TO_ABS; ++c;
322 coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0;
323 coords[i+3] = x + cos(DEGREES_TO_RADIANS(angle)) * width/2;
324 coords[i+4] = y + sin(DEGREES_TO_RADIANS(angle)) * height/2;
325 #ifdef DEBUG_VGUARC
326 debug_printf("3 [%f, %f]\n", coords[i+3],
327 coords[i+4]);
328 #endif
329 angle -= 180;
330 i += 5;
331 }
332 cmds[c] = VG_SCWARC_TO_ABS; ++c;
333 coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0;
334 coords[i+3] = x + cos(DEGREES_TO_RADIANS(last)) * width/2;
335 coords[i+4] = y + sin(DEGREES_TO_RADIANS(last)) * height/2;
336 #ifdef DEBUG_VGUARC
337 debug_printf("4 [%f, %f]\n", coords[i+3],
338 coords[i+4]);
339 #endif
340 i += 5;
341 }
342
343 if (arcType == VGU_ARC_PIE) {
344 cmds[c] = VG_LINE_TO_ABS; ++c;
345 coords[i] = x; coords[i + 1] = y;
346 i += 2;
347 }
348 if (arcType == VGU_ARC_PIE || arcType == VGU_ARC_CHORD) {
349 cmds[c] = VG_CLOSE_PATH;
350 ++c;
351 }
352
353 assert(c < 11);
354
355 vgu_append_float_coords(path, cmds, c, coords, i);
356
357 return VGU_NO_ERROR;
358 }
359
vguComputeWarpQuadToSquare(VGfloat sx0,VGfloat sy0,VGfloat sx1,VGfloat sy1,VGfloat sx2,VGfloat sy2,VGfloat sx3,VGfloat sy3,VGfloat * matrix)360 VGUErrorCode vguComputeWarpQuadToSquare(VGfloat sx0, VGfloat sy0,
361 VGfloat sx1, VGfloat sy1,
362 VGfloat sx2, VGfloat sy2,
363 VGfloat sx3, VGfloat sy3,
364 VGfloat * matrix)
365 {
366 struct matrix mat;
367
368 if (!matrix || !is_aligned(matrix))
369 return VGU_ILLEGAL_ARGUMENT_ERROR;
370
371 if (!matrix_quad_to_square(sx0, sy0,
372 sx1, sy1,
373 sx2, sy2,
374 sx3, sy3,
375 &mat))
376 return VGU_BAD_WARP_ERROR;
377
378 if (!matrix_is_invertible(&mat))
379 return VGU_BAD_WARP_ERROR;
380
381 memcpy(matrix, mat.m, sizeof(VGfloat) * 9);
382
383 return VGU_NO_ERROR;
384 }
385
vguComputeWarpSquareToQuad(VGfloat dx0,VGfloat dy0,VGfloat dx1,VGfloat dy1,VGfloat dx2,VGfloat dy2,VGfloat dx3,VGfloat dy3,VGfloat * matrix)386 VGUErrorCode vguComputeWarpSquareToQuad(VGfloat dx0, VGfloat dy0,
387 VGfloat dx1, VGfloat dy1,
388 VGfloat dx2, VGfloat dy2,
389 VGfloat dx3, VGfloat dy3,
390 VGfloat * matrix)
391 {
392 struct matrix mat;
393
394 if (!matrix || !is_aligned(matrix))
395 return VGU_ILLEGAL_ARGUMENT_ERROR;
396
397 if (!matrix_square_to_quad(dx0, dy0,
398 dx1, dy1,
399 dx2, dy2,
400 dx3, dy3,
401 &mat))
402 return VGU_BAD_WARP_ERROR;
403
404 if (!matrix_is_invertible(&mat))
405 return VGU_BAD_WARP_ERROR;
406
407 memcpy(matrix, mat.m, sizeof(VGfloat) * 9);
408
409 return VGU_NO_ERROR;
410 }
411
vguComputeWarpQuadToQuad(VGfloat dx0,VGfloat dy0,VGfloat dx1,VGfloat dy1,VGfloat dx2,VGfloat dy2,VGfloat dx3,VGfloat dy3,VGfloat sx0,VGfloat sy0,VGfloat sx1,VGfloat sy1,VGfloat sx2,VGfloat sy2,VGfloat sx3,VGfloat sy3,VGfloat * matrix)412 VGUErrorCode vguComputeWarpQuadToQuad(VGfloat dx0, VGfloat dy0,
413 VGfloat dx1, VGfloat dy1,
414 VGfloat dx2, VGfloat dy2,
415 VGfloat dx3, VGfloat dy3,
416 VGfloat sx0, VGfloat sy0,
417 VGfloat sx1, VGfloat sy1,
418 VGfloat sx2, VGfloat sy2,
419 VGfloat sx3, VGfloat sy3,
420 VGfloat * matrix)
421 {
422 struct matrix mat;
423
424 if (!matrix || !is_aligned(matrix))
425 return VGU_ILLEGAL_ARGUMENT_ERROR;
426
427 if (!matrix_quad_to_quad(dx0, dy0,
428 dx1, dy1,
429 dx2, dy2,
430 dx3, dy3,
431 sx0, sy0,
432 sx1, sy1,
433 sx2, sy2,
434 sx3, sy3,
435 &mat))
436 return VGU_BAD_WARP_ERROR;
437
438 memcpy(matrix, mat.m, sizeof(VGfloat) * 9);
439
440 return VGU_NO_ERROR;
441 }
442