OpenVG 1.0 State Tracker
[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 "pipe/p_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_CLOSE_PATH ||
168 pathSegments[i] > VG_LCWARC_TO_REL) {
169 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
170 return;
171 }
172 }
173
174 p = (struct path*)dstPath;
175
176 if (!pathData || !is_aligned_to(pathData, path_datatype_size(p))) {
177 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
178 return;
179 }
180
181 if (!(path_capabilities(p)&VG_PATH_CAPABILITY_APPEND_TO)) {
182 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
183 return;
184 }
185
186 path_append_data(p, numSegments, pathSegments, pathData);
187 }
188
189 void vgModifyPathCoords(VGPath dstPath,
190 VGint startIndex,
191 VGint numSegments,
192 const void * pathData)
193 {
194 struct vg_context *ctx = vg_current_context();
195 struct path *p = 0;
196
197 if (dstPath == VG_INVALID_HANDLE) {
198 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
199 return;
200 }
201 if (startIndex < 0 || numSegments <= 0) {
202 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
203 return;
204 }
205
206 p = (struct path *)dstPath;
207
208 if (!pathData || !is_aligned_to(pathData, path_datatype_size(p))) {
209 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
210 return;
211 }
212
213 if (startIndex + numSegments > path_num_segments(p)) {
214 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
215 return;
216 }
217 if (!(path_capabilities(p)&VG_PATH_CAPABILITY_MODIFY)) {
218 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
219 return;
220 }
221 path_modify_coords(p, startIndex, numSegments, pathData);
222 }
223
224 void vgTransformPath(VGPath dstPath, VGPath srcPath)
225 {
226 struct vg_context *ctx = vg_current_context();
227 struct path *src = 0, *dst = 0;
228
229 if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) {
230 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
231 return;
232 }
233 src = (struct path *)srcPath;
234 dst = (struct path *)dstPath;
235
236 if (!(path_capabilities(src) & VG_PATH_CAPABILITY_TRANSFORM_FROM) ||
237 !(path_capabilities(dst) & VG_PATH_CAPABILITY_TRANSFORM_TO)) {
238 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
239 return;
240 }
241 path_transform(dst, src);
242 }
243
244 VGboolean vgInterpolatePath(VGPath dstPath,
245 VGPath startPath,
246 VGPath endPath,
247 VGfloat amount)
248 {
249 struct vg_context *ctx = vg_current_context();
250 struct path *start = 0, *dst = 0, *end = 0;
251
252 if (dstPath == VG_INVALID_HANDLE ||
253 startPath == VG_INVALID_HANDLE ||
254 endPath == VG_INVALID_HANDLE) {
255 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
256 return VG_FALSE;
257 }
258 dst = (struct path *)dstPath;
259 start = (struct path *)startPath;
260 end = (struct path *)endPath;
261
262 if (!(path_capabilities(dst) & VG_PATH_CAPABILITY_INTERPOLATE_TO) ||
263 !(path_capabilities(start) & VG_PATH_CAPABILITY_INTERPOLATE_FROM) ||
264 !(path_capabilities(end) & VG_PATH_CAPABILITY_INTERPOLATE_FROM)) {
265 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
266 return VG_FALSE;
267 }
268
269 return path_interpolate(dst,
270 start, end, amount);
271 }
272
273 VGfloat vgPathLength(VGPath path,
274 VGint startSegment,
275 VGint numSegments)
276 {
277 struct vg_context *ctx = vg_current_context();
278 struct path *p = 0;
279
280 if (path == VG_INVALID_HANDLE) {
281 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
282 return -1;
283 }
284 if (startSegment < 0) {
285 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
286 return -1;
287 }
288 if (numSegments <= 0) {
289 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
290 return -1;
291 }
292 p = (struct path*)path;
293
294 if (!(path_capabilities(p) & VG_PATH_CAPABILITY_PATH_LENGTH)) {
295 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
296 return -1;
297 }
298 if (startSegment + numSegments > path_num_segments(p)) {
299 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
300 return -1;
301 }
302
303 return path_length(p, startSegment, numSegments);
304 }
305
306 void vgPointAlongPath(VGPath path,
307 VGint startSegment,
308 VGint numSegments,
309 VGfloat distance,
310 VGfloat * x, VGfloat * y,
311 VGfloat * tangentX,
312 VGfloat * tangentY)
313 {
314 struct vg_context *ctx = vg_current_context();
315 struct path *p = 0;
316 VGbitfield caps;
317
318 if (path == VG_INVALID_HANDLE) {
319 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
320 return;
321 }
322 if (startSegment < 0) {
323 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
324 return;
325 }
326 if (numSegments <= 0) {
327 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
328 return;
329 }
330
331 if (!is_aligned(x) || !is_aligned(y) ||
332 !is_aligned(tangentX) || !is_aligned(tangentY)) {
333 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
334 return;
335 }
336
337 p = (struct path*)path;
338
339 caps = path_capabilities(p);
340 if (!(caps & VG_PATH_CAPABILITY_POINT_ALONG_PATH) ||
341 !(caps & VG_PATH_CAPABILITY_TANGENT_ALONG_PATH)) {
342 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
343 return;
344 }
345
346 if (startSegment + numSegments > path_num_segments(p)) {
347 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
348 return;
349 }
350
351 {
352 VGfloat point[2], normal[2];
353 path_point(p, startSegment, numSegments, distance,
354 point, normal);
355 if (x)
356 *x = point[0];
357 if (y)
358 *y = point[1];
359 if (tangentX)
360 *tangentX = -normal[1];
361 if (tangentY)
362 *tangentY = normal[0];
363 }
364 }
365
366 void vgPathBounds(VGPath path,
367 VGfloat * minX,
368 VGfloat * minY,
369 VGfloat * width,
370 VGfloat * height)
371 {
372 struct vg_context *ctx = vg_current_context();
373 struct path *p = 0;
374 VGbitfield caps;
375
376 if (path == VG_INVALID_HANDLE) {
377 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
378 return;
379 }
380
381 if (!minX || !minY || !width || !height) {
382 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
383 return;
384 }
385
386 if (!is_aligned(minX) || !is_aligned(minY) ||
387 !is_aligned(width) || !is_aligned(height)) {
388 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
389 return;
390 }
391
392 p = (struct path*)path;
393
394 caps = path_capabilities(p);
395 if (!(caps & VG_PATH_CAPABILITY_PATH_BOUNDS)) {
396 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
397 return;
398 }
399
400 path_bounding_rect(p, minX, minY, width, height);
401 }
402
403 void vgPathTransformedBounds(VGPath path,
404 VGfloat * minX,
405 VGfloat * minY,
406 VGfloat * width,
407 VGfloat * height)
408 {
409 struct vg_context *ctx = vg_current_context();
410 struct path *p = 0;
411 VGbitfield caps;
412
413 if (path == VG_INVALID_HANDLE) {
414 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
415 return;
416 }
417
418 if (!minX || !minY || !width || !height) {
419 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
420 return;
421 }
422
423 if (!is_aligned(minX) || !is_aligned(minY) ||
424 !is_aligned(width) || !is_aligned(height)) {
425 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
426 return;
427 }
428
429 p = (struct path*)path;
430
431 caps = path_capabilities(p);
432 if (!(caps & VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS)) {
433 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
434 return;
435 }
436
437 #if 0
438 /* faster, but seems to have precision problems... */
439 path_bounding_rect(p, minX, minY, width, height);
440 if (*width > 0 && *height > 0) {
441 VGfloat pts[] = {*minX, *minY,
442 *minX + *width, *minY,
443 *minX + *width, *minY + *height,
444 *minX, *minY + *height};
445 struct matrix *matrix = &ctx->state.vg.path_user_to_surface_matrix;
446 VGfloat maxX, maxY;
447 matrix_map_point(matrix, pts[0], pts[1], pts + 0, pts + 1);
448 matrix_map_point(matrix, pts[2], pts[3], pts + 2, pts + 3);
449 matrix_map_point(matrix, pts[4], pts[5], pts + 4, pts + 5);
450 matrix_map_point(matrix, pts[6], pts[7], pts + 6, pts + 7);
451 *minX = MIN2(pts[0], MIN2(pts[2], MIN2(pts[4], pts[6])));
452 *minY = MIN2(pts[1], MIN2(pts[3], MIN2(pts[5], pts[7])));
453 maxX = MAX2(pts[0], MAX2(pts[2], MAX2(pts[4], pts[6])));
454 maxY = MAX2(pts[1], MAX2(pts[3], MAX2(pts[5], pts[7])));
455 *width = maxX - *minX;
456 *height = maxY - *minY;
457 }
458 #else
459 {
460 struct path *dst = path_create(VG_PATH_DATATYPE_F, 1.0, 0,
461 0, 0, VG_PATH_CAPABILITY_ALL);
462 path_transform(dst, p);
463 path_bounding_rect(dst, minX, minY, width, height);
464 path_destroy(dst);
465 }
466 #endif
467 }
468
469
470 void vgDrawPath(VGPath path, VGbitfield paintModes)
471 {
472 struct vg_context *ctx = vg_current_context();
473
474 if (path == VG_INVALID_HANDLE) {
475 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
476 return;
477 }
478
479 if (!(paintModes & (VG_STROKE_PATH | VG_FILL_PATH))) {
480 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
481 return;
482 }
483
484 if (path_is_empty((struct path*)path))
485 return;
486 path_render((struct path*)path, paintModes);
487 }
488