Merge branch '7.8'
[mesa.git] / src / gallium / state_trackers / vega / vgu.c
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
33 #include "util/u_debug.h"
34 #include "util/u_pointer.h"
35
36 #include <math.h>
37 #include <assert.h>
38
39 static VGboolean is_aligned_to(const void *ptr, VGbyte alignment)
40 {
41 void *aligned = align_pointer(ptr, alignment);
42 return (ptr == aligned) ? VG_TRUE : VG_FALSE;
43 }
44
45 static VGboolean is_aligned(const void *ptr)
46 {
47 return is_aligned_to(ptr, 4);
48 }
49
50 static void vgu_append_float_coords(VGPath path,
51 const VGubyte *cmds,
52 VGint num_cmds,
53 const VGfloat *coords,
54 VGint num_coords)
55 {
56 VGubyte common_data[40 * sizeof(VGfloat)];
57 struct path *p = (struct path *)path;
58
59 vg_float_to_datatype(path_datatype(p), common_data, coords, num_coords);
60 vgAppendPathData(path, num_cmds, cmds, common_data);
61 }
62
63 VGUErrorCode vguLine(VGPath path,
64 VGfloat x0, VGfloat y0,
65 VGfloat x1, VGfloat y1)
66 {
67 static const VGubyte cmds[] = {VG_MOVE_TO_ABS, VG_LINE_TO_ABS};
68 VGfloat coords[4];
69 VGbitfield caps;
70
71 if (path == VG_INVALID_HANDLE) {
72 return VGU_BAD_HANDLE_ERROR;
73 }
74 caps = vgGetPathCapabilities(path);
75 if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
76 return VGU_PATH_CAPABILITY_ERROR;
77 }
78
79 coords[0] = x0;
80 coords[1] = y0;
81 coords[2] = x1;
82 coords[3] = y1;
83
84 vgu_append_float_coords(path, cmds, 2, coords, 4);
85
86 return VGU_NO_ERROR;
87 }
88
89 VGUErrorCode vguPolygon(VGPath path,
90 const VGfloat * points,
91 VGint count,
92 VGboolean closed)
93 {
94 VGubyte *cmds;
95 VGfloat *coords;
96 VGbitfield caps;
97 VGint i;
98
99 if (path == VG_INVALID_HANDLE) {
100 return VGU_BAD_HANDLE_ERROR;
101 }
102
103 if (!points || count <= 0 || !is_aligned(points)) {
104 return VGU_ILLEGAL_ARGUMENT_ERROR;
105 }
106
107 caps = vgGetPathCapabilities(path);
108 if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
109 return VGU_PATH_CAPABILITY_ERROR;
110 }
111
112 cmds = malloc(sizeof(VGubyte) * count + 1);
113 coords = malloc(sizeof(VGfloat) * count * 2);
114
115 cmds[0] = VG_MOVE_TO_ABS;
116 coords[0] = points[0];
117 coords[1] = points[1];
118 for (i = 1; i < count; ++i) {
119 cmds[i] = VG_LINE_TO_ABS;
120 coords[2*i + 0] = points[2*i + 0];
121 coords[2*i + 1] = points[2*i + 1];
122 }
123
124 if (closed) {
125 cmds[i] = VG_CLOSE_PATH;
126 ++i;
127 }
128
129 vgu_append_float_coords(path, cmds, i, coords, 2*i);
130
131 free(cmds);
132 free(coords);
133
134 return VGU_NO_ERROR;
135 }
136
137 VGUErrorCode vguRect(VGPath path,
138 VGfloat x, VGfloat y,
139 VGfloat width, VGfloat height)
140 {
141 static const VGubyte cmds[] = {VG_MOVE_TO_ABS,
142 VG_HLINE_TO_REL,
143 VG_VLINE_TO_REL,
144 VG_HLINE_TO_REL,
145 VG_CLOSE_PATH
146 };
147 VGfloat coords[5];
148 VGbitfield caps;
149
150 if (path == VG_INVALID_HANDLE) {
151 return VGU_BAD_HANDLE_ERROR;
152 }
153 caps = vgGetPathCapabilities(path);
154 if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
155 return VGU_PATH_CAPABILITY_ERROR;
156 }
157 if (width <= 0 || height <= 0) {
158 return VGU_ILLEGAL_ARGUMENT_ERROR;
159 }
160
161 coords[0] = x;
162 coords[1] = y;
163 coords[2] = width;
164 coords[3] = height;
165 coords[4] = -width;
166
167 vgu_append_float_coords(path, cmds, 5, coords, 5);
168
169 return VGU_NO_ERROR;
170 }
171
172 VGUErrorCode vguRoundRect(VGPath path,
173 VGfloat x, VGfloat y,
174 VGfloat width,
175 VGfloat height,
176 VGfloat arcWidth,
177 VGfloat arcHeight)
178 {
179 static const VGubyte cmds[] = {VG_MOVE_TO_ABS,
180 VG_HLINE_TO_REL,
181 VG_SCCWARC_TO_REL,
182 VG_VLINE_TO_REL,
183 VG_SCCWARC_TO_REL,
184 VG_HLINE_TO_REL,
185 VG_SCCWARC_TO_REL,
186 VG_VLINE_TO_REL,
187 VG_SCCWARC_TO_REL,
188 VG_CLOSE_PATH
189 };
190 VGfloat c[26];
191 VGbitfield caps;
192
193 if (path == VG_INVALID_HANDLE) {
194 return VGU_BAD_HANDLE_ERROR;
195 }
196 caps = vgGetPathCapabilities(path);
197 if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
198 return VGU_PATH_CAPABILITY_ERROR;
199 }
200 if (width <= 0 || height <= 0) {
201 return VGU_ILLEGAL_ARGUMENT_ERROR;
202 }
203
204 c[0] = x + arcWidth/2; c[1] = y;
205
206 c[2] = width - arcWidth;
207
208 c[3] = arcWidth/2; c[4] = arcHeight/2; c[5] = 0;
209 c[6] = arcWidth/2; c[7] = arcHeight/2;
210
211 c[8] = height - arcHeight;
212
213 c[9] = arcWidth/2; c[10] = arcHeight/2; c[11] = 0;
214 c[12] = -arcWidth/2; c[13] = arcHeight/2;
215
216 c[14] = -(width - arcWidth);
217
218 c[15] = arcWidth/2; c[16] = arcHeight/2; c[17] = 0;
219 c[18] = -arcWidth/2; c[19] = -arcHeight/2;
220
221 c[20] = -(height - arcHeight);
222
223 c[21] = arcWidth/2; c[22] = arcHeight/2; c[23] = 0;
224 c[24] = arcWidth/2; c[25] = -arcHeight/2;
225
226 vgu_append_float_coords(path, cmds, 10, c, 26);
227
228 return VGU_NO_ERROR;
229 }
230
231 VGUErrorCode vguEllipse(VGPath path,
232 VGfloat cx, VGfloat cy,
233 VGfloat width,
234 VGfloat height)
235 {
236 static const VGubyte cmds[] = {VG_MOVE_TO_ABS,
237 VG_SCCWARC_TO_REL,
238 VG_SCCWARC_TO_REL,
239 VG_CLOSE_PATH
240 };
241 VGfloat coords[12];
242 VGbitfield caps;
243
244 if (path == VG_INVALID_HANDLE) {
245 return VGU_BAD_HANDLE_ERROR;
246 }
247 caps = vgGetPathCapabilities(path);
248 if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
249 return VGU_PATH_CAPABILITY_ERROR;
250 }
251 if (width <= 0 || height <= 0) {
252 return VGU_ILLEGAL_ARGUMENT_ERROR;
253 }
254
255 coords[0] = cx + width/2; coords[1] = cy;
256
257 coords[2] = width/2; coords[3] = height/2; coords[4] = 0;
258 coords[5] = -width; coords[6] = 0;
259
260 coords[7] = width/2; coords[8] = height/2; coords[9] = 0;
261 coords[10] = width; coords[11] = 0;
262
263 vgu_append_float_coords(path, cmds, 4, coords, 11);
264
265 return VGU_NO_ERROR;
266 }
267
268 VGUErrorCode vguArc(VGPath path,
269 VGfloat x, VGfloat y,
270 VGfloat width, VGfloat height,
271 VGfloat startAngle,
272 VGfloat angleExtent,
273 VGUArcType arcType)
274 {
275 VGubyte cmds[11];
276 VGfloat coords[40];
277 VGbitfield caps;
278 VGfloat last = startAngle + angleExtent;
279 VGint i, c = 0;
280
281 if (path == VG_INVALID_HANDLE) {
282 return VGU_BAD_HANDLE_ERROR;
283 }
284 caps = vgGetPathCapabilities(path);
285 if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
286 return VGU_PATH_CAPABILITY_ERROR;
287 }
288 if (width <= 0 || height <= 0) {
289 return VGU_ILLEGAL_ARGUMENT_ERROR;
290 }
291 if (arcType != VGU_ARC_OPEN &&
292 arcType != VGU_ARC_CHORD &&
293 arcType != VGU_ARC_PIE) {
294 return VGU_ILLEGAL_ARGUMENT_ERROR;
295 }
296
297 cmds[c] = VG_MOVE_TO_ABS; ++c;
298 coords[0] = x+cos(DEGREES_TO_RADIANS(startAngle))*width/2;
299 coords[1] = y+sin(DEGREES_TO_RADIANS(startAngle))*height/2;
300 #ifdef DEBUG_VGUARC
301 debug_printf("start [%f, %f]\n", coords[0], coords[1]);
302 #endif
303 i = 2;
304 if (angleExtent > 0) {
305 VGfloat angle = startAngle + 180;
306 while (angle < last) {
307 cmds[c] = VG_SCCWARC_TO_ABS; ++c;
308 coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0;
309 coords[i+3] = x + cos(DEGREES_TO_RADIANS(angle))*width/2;
310 coords[i+4] = y + sin(DEGREES_TO_RADIANS(angle))*height/2;
311 #ifdef DEBUG_VGUARC
312 debug_printf("1 [%f, %f]\n", coords[i+3],
313 coords[i+4]);
314 #endif
315 i += 5;
316 angle += 180;
317 }
318 cmds[c] = VG_SCCWARC_TO_ABS; ++c;
319 coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0;
320 coords[i+3] = x+cos(DEGREES_TO_RADIANS(last))*width/2;
321 coords[i+4] = y+sin(DEGREES_TO_RADIANS(last))*height/2;
322 #ifdef DEBUG_VGUARC
323 debug_printf("2 [%f, %f]\n", coords[i+3],
324 coords[i+4]);
325 #endif
326 i += 5;
327 } else {
328 VGfloat angle = startAngle - 180;
329 while (angle > last) {
330 cmds[c] = VG_SCWARC_TO_ABS; ++c;
331 coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0;
332 coords[i+3] = x + cos(DEGREES_TO_RADIANS(angle)) * width/2;
333 coords[i+4] = y + sin(DEGREES_TO_RADIANS(angle)) * height/2;
334 #ifdef DEBUG_VGUARC
335 debug_printf("3 [%f, %f]\n", coords[i+3],
336 coords[i+4]);
337 #endif
338 angle -= 180;
339 i += 5;
340 }
341 cmds[c] = VG_SCWARC_TO_ABS; ++c;
342 coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0;
343 coords[i+3] = x + cos(DEGREES_TO_RADIANS(last)) * width/2;
344 coords[i+4] = y + sin(DEGREES_TO_RADIANS(last)) * height/2;
345 #ifdef DEBUG_VGUARC
346 debug_printf("4 [%f, %f]\n", coords[i+3],
347 coords[i+4]);
348 #endif
349 i += 5;
350 }
351
352 if (arcType == VGU_ARC_PIE) {
353 cmds[c] = VG_LINE_TO_ABS; ++c;
354 coords[i] = x; coords[i + 1] = y;
355 i += 2;
356 }
357 if (arcType == VGU_ARC_PIE || arcType == VGU_ARC_CHORD) {
358 cmds[c] = VG_CLOSE_PATH;
359 ++c;
360 }
361
362 assert(c < 11);
363
364 vgu_append_float_coords(path, cmds, c, coords, i);
365
366 return VGU_NO_ERROR;
367 }
368
369 VGUErrorCode vguComputeWarpQuadToSquare(VGfloat sx0, VGfloat sy0,
370 VGfloat sx1, VGfloat sy1,
371 VGfloat sx2, VGfloat sy2,
372 VGfloat sx3, VGfloat sy3,
373 VGfloat * matrix)
374 {
375 struct matrix mat;
376
377 if (!matrix || !is_aligned(matrix))
378 return VGU_ILLEGAL_ARGUMENT_ERROR;
379
380 if (!matrix_quad_to_square(sx0, sy0,
381 sx1, sy1,
382 sx2, sy2,
383 sx3, sy3,
384 &mat))
385 return VGU_BAD_WARP_ERROR;
386
387 if (!matrix_is_invertible(&mat))
388 return VGU_BAD_WARP_ERROR;
389
390 memcpy(matrix, mat.m, sizeof(VGfloat) * 9);
391
392 return VGU_NO_ERROR;
393 }
394
395 VGUErrorCode vguComputeWarpSquareToQuad(VGfloat dx0, VGfloat dy0,
396 VGfloat dx1, VGfloat dy1,
397 VGfloat dx2, VGfloat dy2,
398 VGfloat dx3, VGfloat dy3,
399 VGfloat * matrix)
400 {
401 struct matrix mat;
402
403 if (!matrix || !is_aligned(matrix))
404 return VGU_ILLEGAL_ARGUMENT_ERROR;
405
406 if (!matrix_square_to_quad(dx0, dy0,
407 dx1, dy1,
408 dx2, dy2,
409 dx3, dy3,
410 &mat))
411 return VGU_BAD_WARP_ERROR;
412
413 if (!matrix_is_invertible(&mat))
414 return VGU_BAD_WARP_ERROR;
415
416 memcpy(matrix, mat.m, sizeof(VGfloat) * 9);
417
418 return VGU_NO_ERROR;
419 }
420
421 VGUErrorCode vguComputeWarpQuadToQuad(VGfloat dx0, VGfloat dy0,
422 VGfloat dx1, VGfloat dy1,
423 VGfloat dx2, VGfloat dy2,
424 VGfloat dx3, VGfloat dy3,
425 VGfloat sx0, VGfloat sy0,
426 VGfloat sx1, VGfloat sy1,
427 VGfloat sx2, VGfloat sy2,
428 VGfloat sx3, VGfloat sy3,
429 VGfloat * matrix)
430 {
431 struct matrix mat;
432
433 if (!matrix || !is_aligned(matrix))
434 return VGU_ILLEGAL_ARGUMENT_ERROR;
435
436 if (!matrix_quad_to_quad(dx0, dy0,
437 dx1, dy1,
438 dx2, dy2,
439 dx3, dy3,
440 sx0, sy0,
441 sx1, sy1,
442 sx2, sy2,
443 sx3, sy3,
444 &mat))
445 return VGU_BAD_WARP_ERROR;
446
447 memcpy(matrix, mat.m, sizeof(VGfloat) * 9);
448
449 return VGU_NO_ERROR;
450 }