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