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
41static 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
54VGUErrorCode 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
80VGUErrorCode 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
128VGUErrorCode  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
163VGUErrorCode 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
222VGUErrorCode 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
259VGUErrorCode 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
360VGUErrorCode 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
386VGUErrorCode 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
412VGUErrorCode 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