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