Merge branch '7.8'
[mesa.git] / src / gallium / state_trackers / vega / api_path.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
29 #include "vg_context.h"
30 #include "path.h"
31 #include "polygon.h"
32 #include "paint.h"
33
34 #include "pipe/p_context.h"
35 #include "util/u_inlines.h"
36 #include "util/u_draw_quad.h"
37
38 VGPath vgCreatePath(VGint pathFormat,
39 VGPathDatatype datatype,
40 VGfloat scale, VGfloat bias,
41 VGint segmentCapacityHint,
42 VGint coordCapacityHint,
43 VGbitfield capabilities)
44 {
45 struct vg_context *ctx = vg_current_context();
46
47 if (pathFormat != VG_PATH_FORMAT_STANDARD) {
48 vg_set_error(ctx, VG_UNSUPPORTED_PATH_FORMAT_ERROR);
49 return VG_INVALID_HANDLE;
50 }
51 if (datatype < VG_PATH_DATATYPE_S_8 ||
52 datatype > VG_PATH_DATATYPE_F) {
53 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
54 return VG_INVALID_HANDLE;
55 }
56 if (!scale) {
57 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
58 return VG_INVALID_HANDLE;
59 }
60
61 return (VGPath)path_create(datatype, scale, bias,
62 segmentCapacityHint, coordCapacityHint,
63 capabilities);
64 }
65
66 void vgClearPath(VGPath path, VGbitfield capabilities)
67 {
68 struct vg_context *ctx = vg_current_context();
69 struct path *p = 0;
70
71 if (path == VG_INVALID_HANDLE) {
72 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
73 return;
74 }
75
76 p = (struct path *)path;
77 path_clear(p, capabilities);
78 }
79
80 void vgDestroyPath(VGPath p)
81 {
82 struct path *path = 0;
83 struct vg_context *ctx = vg_current_context();
84
85 if (p == VG_INVALID_HANDLE) {
86 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
87 return;
88 }
89
90 path = (struct path *)p;
91 path_destroy(path);
92 }
93
94 void vgRemovePathCapabilities(VGPath path,
95 VGbitfield capabilities)
96 {
97 struct vg_context *ctx = vg_current_context();
98 VGbitfield current;
99 struct path *p;
100
101 if (path == VG_INVALID_HANDLE) {
102 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
103 return;
104 }
105
106 p = (struct path*)path;
107 current = path_capabilities(p);
108 path_set_capabilities(p, (current &
109 (~(capabilities & VG_PATH_CAPABILITY_ALL))));
110 }
111
112 VGbitfield vgGetPathCapabilities(VGPath path)
113 {
114 struct vg_context *ctx = vg_current_context();
115 struct path *p = 0;
116
117 if (path == VG_INVALID_HANDLE) {
118 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
119 return 0;
120 }
121 p = (struct path*)path;
122 return path_capabilities(p);
123 }
124
125 void vgAppendPath(VGPath dstPath, VGPath srcPath)
126 {
127 struct vg_context *ctx = vg_current_context();
128 struct path *src, *dst;
129
130 if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) {
131 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
132 return;
133 }
134 src = (struct path *)srcPath;
135 dst = (struct path *)dstPath;
136
137 if (!(path_capabilities(src) & VG_PATH_CAPABILITY_APPEND_FROM) ||
138 !(path_capabilities(dst) & VG_PATH_CAPABILITY_APPEND_TO)) {
139 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
140 return;
141 }
142 path_append_path(dst, src);
143 }
144
145 void vgAppendPathData(VGPath dstPath,
146 VGint numSegments,
147 const VGubyte * pathSegments,
148 const void * pathData)
149 {
150 struct vg_context *ctx = vg_current_context();
151 struct path *p = 0;
152 VGint i;
153
154 if (dstPath == VG_INVALID_HANDLE) {
155 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
156 return;
157 }
158 if (!pathSegments) {
159 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
160 return;
161 }
162 if (numSegments <= 0) {
163 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
164 return;
165 }
166 for (i = 0; i < numSegments; ++i) {
167 if (pathSegments[i] > VG_LCWARC_TO_REL) {
168 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
169 return;
170 }
171 }
172
173 p = (struct path*)dstPath;
174
175 if (!pathData || !is_aligned_to(pathData, path_datatype_size(p))) {
176 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
177 return;
178 }
179
180 if (!(path_capabilities(p)&VG_PATH_CAPABILITY_APPEND_TO)) {
181 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
182 return;
183 }
184
185 path_append_data(p, numSegments, pathSegments, pathData);
186 }
187
188 void vgModifyPathCoords(VGPath dstPath,
189 VGint startIndex,
190 VGint numSegments,
191 const void * pathData)
192 {
193 struct vg_context *ctx = vg_current_context();
194 struct path *p = 0;
195
196 if (dstPath == VG_INVALID_HANDLE) {
197 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
198 return;
199 }
200 if (startIndex < 0 || numSegments <= 0) {
201 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
202 return;
203 }
204
205 p = (struct path *)dstPath;
206
207 if (!pathData || !is_aligned_to(pathData, path_datatype_size(p))) {
208 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
209 return;
210 }
211
212 if (startIndex + numSegments > path_num_segments(p)) {
213 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
214 return;
215 }
216 if (!(path_capabilities(p)&VG_PATH_CAPABILITY_MODIFY)) {
217 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
218 return;
219 }
220 path_modify_coords(p, startIndex, numSegments, pathData);
221 }
222
223 void vgTransformPath(VGPath dstPath, VGPath srcPath)
224 {
225 struct vg_context *ctx = vg_current_context();
226 struct path *src = 0, *dst = 0;
227
228 if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) {
229 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
230 return;
231 }
232 src = (struct path *)srcPath;
233 dst = (struct path *)dstPath;
234
235 if (!(path_capabilities(src) & VG_PATH_CAPABILITY_TRANSFORM_FROM) ||
236 !(path_capabilities(dst) & VG_PATH_CAPABILITY_TRANSFORM_TO)) {
237 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
238 return;
239 }
240 path_transform(dst, src);
241 }
242
243 VGboolean vgInterpolatePath(VGPath dstPath,
244 VGPath startPath,
245 VGPath endPath,
246 VGfloat amount)
247 {
248 struct vg_context *ctx = vg_current_context();
249 struct path *start = 0, *dst = 0, *end = 0;
250
251 if (dstPath == VG_INVALID_HANDLE ||
252 startPath == VG_INVALID_HANDLE ||
253 endPath == VG_INVALID_HANDLE) {
254 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
255 return VG_FALSE;
256 }
257 dst = (struct path *)dstPath;
258 start = (struct path *)startPath;
259 end = (struct path *)endPath;
260
261 if (!(path_capabilities(dst) & VG_PATH_CAPABILITY_INTERPOLATE_TO) ||
262 !(path_capabilities(start) & VG_PATH_CAPABILITY_INTERPOLATE_FROM) ||
263 !(path_capabilities(end) & VG_PATH_CAPABILITY_INTERPOLATE_FROM)) {
264 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
265 return VG_FALSE;
266 }
267
268 return path_interpolate(dst,
269 start, end, amount);
270 }
271
272 VGfloat vgPathLength(VGPath path,
273 VGint startSegment,
274 VGint numSegments)
275 {
276 struct vg_context *ctx = vg_current_context();
277 struct path *p = 0;
278
279 if (path == VG_INVALID_HANDLE) {
280 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
281 return -1;
282 }
283 if (startSegment < 0) {
284 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
285 return -1;
286 }
287 if (numSegments <= 0) {
288 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
289 return -1;
290 }
291 p = (struct path*)path;
292
293 if (!(path_capabilities(p) & VG_PATH_CAPABILITY_PATH_LENGTH)) {
294 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
295 return -1;
296 }
297 if (startSegment + numSegments > path_num_segments(p)) {
298 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
299 return -1;
300 }
301
302 return path_length(p, startSegment, numSegments);
303 }
304
305 void vgPointAlongPath(VGPath path,
306 VGint startSegment,
307 VGint numSegments,
308 VGfloat distance,
309 VGfloat * x, VGfloat * y,
310 VGfloat * tangentX,
311 VGfloat * tangentY)
312 {
313 struct vg_context *ctx = vg_current_context();
314 struct path *p = 0;
315 VGbitfield caps;
316
317 if (path == VG_INVALID_HANDLE) {
318 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
319 return;
320 }
321 if (startSegment < 0) {
322 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
323 return;
324 }
325 if (numSegments <= 0) {
326 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
327 return;
328 }
329
330 if (!is_aligned(x) || !is_aligned(y) ||
331 !is_aligned(tangentX) || !is_aligned(tangentY)) {
332 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
333 return;
334 }
335
336 p = (struct path*)path;
337
338 caps = path_capabilities(p);
339 if (!(caps & VG_PATH_CAPABILITY_POINT_ALONG_PATH) ||
340 !(caps & VG_PATH_CAPABILITY_TANGENT_ALONG_PATH)) {
341 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
342 return;
343 }
344
345 if (startSegment + numSegments > path_num_segments(p)) {
346 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
347 return;
348 }
349
350 {
351 VGfloat point[2], normal[2];
352 path_point(p, startSegment, numSegments, distance,
353 point, normal);
354 if (x)
355 *x = point[0];
356 if (y)
357 *y = point[1];
358 if (tangentX)
359 *tangentX = -normal[1];
360 if (tangentY)
361 *tangentY = normal[0];
362 }
363 }
364
365 void vgPathBounds(VGPath path,
366 VGfloat * minX,
367 VGfloat * minY,
368 VGfloat * width,
369 VGfloat * height)
370 {
371 struct vg_context *ctx = vg_current_context();
372 struct path *p = 0;
373 VGbitfield caps;
374
375 if (path == VG_INVALID_HANDLE) {
376 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
377 return;
378 }
379
380 if (!minX || !minY || !width || !height) {
381 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
382 return;
383 }
384
385 if (!is_aligned(minX) || !is_aligned(minY) ||
386 !is_aligned(width) || !is_aligned(height)) {
387 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
388 return;
389 }
390
391 p = (struct path*)path;
392
393 caps = path_capabilities(p);
394 if (!(caps & VG_PATH_CAPABILITY_PATH_BOUNDS)) {
395 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
396 return;
397 }
398
399 path_bounding_rect(p, minX, minY, width, height);
400 }
401
402 void vgPathTransformedBounds(VGPath path,
403 VGfloat * minX,
404 VGfloat * minY,
405 VGfloat * width,
406 VGfloat * height)
407 {
408 struct vg_context *ctx = vg_current_context();
409 struct path *p = 0;
410 VGbitfield caps;
411
412 if (path == VG_INVALID_HANDLE) {
413 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
414 return;
415 }
416
417 if (!minX || !minY || !width || !height) {
418 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
419 return;
420 }
421
422 if (!is_aligned(minX) || !is_aligned(minY) ||
423 !is_aligned(width) || !is_aligned(height)) {
424 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
425 return;
426 }
427
428 p = (struct path*)path;
429
430 caps = path_capabilities(p);
431 if (!(caps & VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS)) {
432 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
433 return;
434 }
435
436 #if 0
437 /* faster, but seems to have precision problems... */
438 path_bounding_rect(p, minX, minY, width, height);
439 if (*width > 0 && *height > 0) {
440 VGfloat pts[] = {*minX, *minY,
441 *minX + *width, *minY,
442 *minX + *width, *minY + *height,
443 *minX, *minY + *height};
444 struct matrix *matrix = &ctx->state.vg.path_user_to_surface_matrix;
445 VGfloat maxX, maxY;
446 matrix_map_point(matrix, pts[0], pts[1], pts + 0, pts + 1);
447 matrix_map_point(matrix, pts[2], pts[3], pts + 2, pts + 3);
448 matrix_map_point(matrix, pts[4], pts[5], pts + 4, pts + 5);
449 matrix_map_point(matrix, pts[6], pts[7], pts + 6, pts + 7);
450 *minX = MIN2(pts[0], MIN2(pts[2], MIN2(pts[4], pts[6])));
451 *minY = MIN2(pts[1], MIN2(pts[3], MIN2(pts[5], pts[7])));
452 maxX = MAX2(pts[0], MAX2(pts[2], MAX2(pts[4], pts[6])));
453 maxY = MAX2(pts[1], MAX2(pts[3], MAX2(pts[5], pts[7])));
454 *width = maxX - *minX;
455 *height = maxY - *minY;
456 }
457 #else
458 {
459 struct path *dst = path_create(VG_PATH_DATATYPE_F, 1.0, 0,
460 0, 0, VG_PATH_CAPABILITY_ALL);
461 path_transform(dst, p);
462 path_bounding_rect(dst, minX, minY, width, height);
463 path_destroy(dst);
464 }
465 #endif
466 }
467
468
469 void vgDrawPath(VGPath path, VGbitfield paintModes)
470 {
471 struct vg_context *ctx = vg_current_context();
472
473 if (path == VG_INVALID_HANDLE) {
474 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
475 return;
476 }
477
478 if (!(paintModes & (VG_STROKE_PATH | VG_FILL_PATH))) {
479 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
480 return;
481 }
482
483 if (path_is_empty((struct path*)path))
484 return;
485 path_render((struct path*)path, paintModes);
486 }
487