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