|
1 /* Copyright (c) 2009 The Khronos Group Inc. |
|
2 * |
|
3 * Permission is hereby granted, free of charge, to any person obtaining a |
|
4 * copy of this software and/or associated documentation files (the |
|
5 * "Materials"), to deal in the Materials without restriction, including |
|
6 * without limitation the rights to use, copy, modify, merge, publish, |
|
7 * distribute, sublicense, and/or sell copies of the Materials, and to |
|
8 * permit persons to whom the Materials are furnished to do so, subject to |
|
9 * the following conditions: |
|
10 * |
|
11 * The above copyright notice and this permission notice shall be included |
|
12 * in all copies or substantial portions of the Materials. |
|
13 * |
|
14 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
|
18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
|
19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
|
20 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. |
|
21 */ |
|
22 /*! \ingroup wfc |
|
23 * \file wfcelement.c |
|
24 * |
|
25 * \brief SI Element handling |
|
26 */ |
|
27 #include <stdio.h> |
|
28 #include <stdlib.h> |
|
29 #include <math.h> |
|
30 #include <string.h> |
|
31 |
|
32 #include <WF/wfc.h> |
|
33 |
|
34 #include "wfcelement.h" |
|
35 #include "wfccontext.h" |
|
36 #include "wfcdevice.h" |
|
37 #include "wfcstructs.h" |
|
38 #include "wfcimageprovider.h" |
|
39 #include "owfnativestream.h" |
|
40 #include "owfattributes.h" |
|
41 #include "owfmemory.h" |
|
42 #include "owfobject.h" |
|
43 |
|
44 #include "owfdebug.h" |
|
45 |
|
46 #ifdef __cplusplus |
|
47 extern "C" { |
|
48 #endif |
|
49 |
|
50 #define FIRST_ELEMENT_HANDLE 3000 |
|
51 |
|
52 #define FAIL_IF(c,e) if (c) { return e; } |
|
53 |
|
54 |
|
55 static const WFCbitfield validTransparencyModes[] = { |
|
56 WFC_TRANSPARENCY_NONE, |
|
57 WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA, |
|
58 WFC_TRANSPARENCY_SOURCE, |
|
59 WFC_TRANSPARENCY_MASK, |
|
60 WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA | |
|
61 WFC_TRANSPARENCY_SOURCE, |
|
62 WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA | |
|
63 WFC_TRANSPARENCY_MASK |
|
64 }; |
|
65 |
|
66 /*--------------------------------------------------------------------------- |
|
67 * |
|
68 *----------------------------------------------------------------------------*/ |
|
69 void |
|
70 WFC_Element_Initialize(WFC_ELEMENT* element) |
|
71 { |
|
72 element->dstRect[0] = 0; |
|
73 element->dstRect[1] = 0; |
|
74 element->dstRect[2] = 0; |
|
75 element->dstRect[3] = 0; |
|
76 element->srcRect[0] = 0; |
|
77 element->srcRect[1] = 0; |
|
78 element->srcRect[2] = 0; |
|
79 element->srcRect[3] = 0; |
|
80 |
|
81 element->source = WFC_INVALID_HANDLE; |
|
82 element->sourceFlip = WFC_FALSE; |
|
83 element->sourceRotation = WFC_ROTATION_0; |
|
84 element->sourceScaleFilter = WFC_SCALE_FILTER_NONE; |
|
85 element->transparencyTypes = 0; |
|
86 element->globalAlpha = OWF_ALPHA_MAX_VALUE; |
|
87 element->maskHandle = WFC_INVALID_HANDLE; |
|
88 element->sourceHandle = WFC_INVALID_HANDLE; |
|
89 } |
|
90 |
|
91 /*--------------------------------------------------------------------------- |
|
92 * |
|
93 *----------------------------------------------------------------------------*/ |
|
94 OWF_API_CALL void |
|
95 WFC_Element_Destroy(WFC_ELEMENT* element) |
|
96 { |
|
97 if (element) |
|
98 { |
|
99 DPRINT(("WFC_Element_Destroy")); |
|
100 |
|
101 DPRINT((" element = %p (%d)", element, element->handle)); |
|
102 |
|
103 DESTROY(element->cachedSource); |
|
104 DESTROY(element->cachedMask); |
|
105 |
|
106 DPRINT((" cachedSource = %p (%d)", element->cachedSource, |
|
107 element->cachedSource ? |
|
108 element->cachedSource->handle : |
|
109 0)); |
|
110 DPRINT((" cachedMask = %p (%d)", element->cachedMask, |
|
111 element->cachedMask ? |
|
112 element->cachedMask->handle : |
|
113 0)); |
|
114 |
|
115 DESTROY(element->source); |
|
116 DESTROY(element->mask); |
|
117 |
|
118 DPRINT((" source = %p (%d)", element->source, |
|
119 element->source ? |
|
120 element->source->handle : |
|
121 0)); |
|
122 DPRINT((" mask = %p (%d)", element->mask, |
|
123 element->mask ? |
|
124 element->mask->handle : |
|
125 0)); |
|
126 DESTROY(element->context); |
|
127 |
|
128 OWF_Pool_PutObject(element); |
|
129 } |
|
130 } |
|
131 |
|
132 /*--------------------------------------------------------------------------- |
|
133 * Create new element into context |
|
134 * |
|
135 * \param context Context into which to create the element |
|
136 * |
|
137 * \return New element object or NULL |
|
138 *----------------------------------------------------------------------------*/ |
|
139 OWF_API_CALL WFC_ELEMENT* |
|
140 WFC_Element_Create(WFC_CONTEXT* context) |
|
141 { |
|
142 static WFCint nextElementHandle = FIRST_ELEMENT_HANDLE; |
|
143 WFC_ELEMENT* element; |
|
144 |
|
145 element = (WFC_ELEMENT*)OWF_Pool_GetObject(context->elementPool); |
|
146 |
|
147 if (element) |
|
148 { |
|
149 WFC_Element_Initialize(element); |
|
150 |
|
151 element->handle = nextElementHandle++; |
|
152 |
|
153 ADDREF(element->context, context); |
|
154 element->device = context->device; |
|
155 } |
|
156 return element; |
|
157 } |
|
158 |
|
159 /*--------------------------------------------------------------------------- |
|
160 * |
|
161 *----------------------------------------------------------------------------*/ |
|
162 OWF_API_CALL WFC_ELEMENT* |
|
163 WFC_Element_Clone(WFC_ELEMENT* element) |
|
164 { |
|
165 WFC_ELEMENT* clone; |
|
166 WFC_CONTEXT* context; |
|
167 |
|
168 OWF_ASSERT(element); |
|
169 |
|
170 DPRINT(("WFC_Element_Clone: element = %d, context = %d", element->handle, |
|
171 element->context->handle)); |
|
172 |
|
173 context = CONTEXT(element->context); |
|
174 clone = (WFC_ELEMENT*)OWF_Pool_GetObject(context->elementPool); |
|
175 |
|
176 if (clone) |
|
177 { |
|
178 WFC_Element_Initialize(clone); |
|
179 |
|
180 clone->handle = element->handle; |
|
181 |
|
182 clone->sourceFlip = element->sourceFlip; |
|
183 clone->sourceRotation = element->sourceRotation; |
|
184 clone->sourceScaleFilter= element->sourceScaleFilter; |
|
185 clone->transparencyTypes= element->transparencyTypes; |
|
186 clone->globalAlpha = element->globalAlpha; |
|
187 clone->maskHandle = element->maskHandle; |
|
188 clone->sourceHandle = element->sourceHandle; |
|
189 |
|
190 ADDREF(clone->cachedMask, element->cachedMask); |
|
191 ADDREF(clone->cachedSource, element->cachedSource); |
|
192 |
|
193 ADDREF(clone->mask, element->mask); |
|
194 ADDREF(clone->source, element->source); |
|
195 clone->device = element->device; |
|
196 |
|
197 ADDREF(clone->context, element->context); |
|
198 |
|
199 memcpy(clone->srcRect, element->srcRect, 4 * sizeof(WFCfloat)); |
|
200 memcpy(clone->dstRect, element->dstRect, 4 * sizeof(WFCfloat)); |
|
201 |
|
202 } |
|
203 |
|
204 return clone; |
|
205 } |
|
206 |
|
207 /*--------------------------------------------------------------------------- |
|
208 * |
|
209 *----------------------------------------------------------------------------*/ |
|
210 static WFCboolean WFC_Element_ClampRectangle(const char* rtype, |
|
211 WFCfloat* rect) |
|
212 { |
|
213 /* |
|
214 * int -> float conversion: |
|
215 * ------------------------ |
|
216 * |
|
217 * above 2^24 we start to lose precision when performing |
|
218 * conversions between floats & ints, thus we must clamp |
|
219 * values above in order to avoid nasty sign-change effects |
|
220 * and other weird side-effects. |
|
221 * |
|
222 */ |
|
223 |
|
224 const WFCfloat LIMIT = 1.6777216E7f; |
|
225 WFCint i; |
|
226 WFCboolean clamped = WFC_FALSE; |
|
227 |
|
228 /* Prevent compiler warning when DPRINT is disabled */ |
|
229 (void) rtype; |
|
230 |
|
231 for (i = 0; i < 4; i++) |
|
232 { |
|
233 if (fabs(rect[i]) > LIMIT) |
|
234 { |
|
235 #ifdef DEBUG |
|
236 static const char* coord[4] = {"x", "y", "width", "height"}; |
|
237 (void)coord[0]; |
|
238 #endif |
|
239 |
|
240 DPRINT((" Warning: Precision loss in element's %s rectangle's " |
|
241 "%s coordinate.", |
|
242 rtype, coord[i])); |
|
243 |
|
244 rect[i] = rect[i] < 0 ? -LIMIT : LIMIT; |
|
245 |
|
246 clamped = WFC_TRUE; |
|
247 } |
|
248 } |
|
249 return clamped; |
|
250 } |
|
251 /*=========================================================================== |
|
252 * |
|
253 * Attribute set-time checking functions. These are used for checking |
|
254 * the attributes before saving them into elements. Attributes are validated |
|
255 * for 2nd time during commit, where e.g. destination rectangle size vs. |
|
256 * mask size dependency is checked. |
|
257 * |
|
258 *============================================================================*/ |
|
259 |
|
260 /*--------------------------------------------------------------------------- |
|
261 * |
|
262 *----------------------------------------------------------------------------*/ |
|
263 static WFCErrorCode |
|
264 WFC_Element_ValidateSourceRectangle(WFC_ELEMENT* element, |
|
265 WFCfloat* rect) |
|
266 { |
|
267 WFCErrorCode result = WFC_ERROR_NONE; |
|
268 |
|
269 #ifndef DEBUG |
|
270 (void) element; |
|
271 #endif |
|
272 |
|
273 OWF_ASSERT(element); |
|
274 OWF_ASSERT(rect); |
|
275 |
|
276 if (rect[0] < 0.0f || rect[1] < 0.0f || rect[2] < 0.0f || rect[3] < 0.0f) |
|
277 { |
|
278 result = WFC_ERROR_ILLEGAL_ARGUMENT; |
|
279 } |
|
280 else if (WFC_Element_ClampRectangle("source", rect)) |
|
281 { |
|
282 result = WFC_ERROR_NONE; |
|
283 } |
|
284 return result; |
|
285 } |
|
286 |
|
287 /*--------------------------------------------------------------------------- |
|
288 * |
|
289 *----------------------------------------------------------------------------*/ |
|
290 static WFCErrorCode |
|
291 WFC_Element_ValidateDestinationRectangle(WFC_ELEMENT* element, |
|
292 WFCfloat* rect) |
|
293 { |
|
294 WFCErrorCode result = WFC_ERROR_NONE; |
|
295 |
|
296 #ifndef DEBUG |
|
297 (void) element; |
|
298 #endif |
|
299 |
|
300 OWF_ASSERT(element); |
|
301 OWF_ASSERT(rect); |
|
302 |
|
303 DPRINT(("WFC_Element_ValidateDestinationRectangle(element = %d)", |
|
304 element->handle)); |
|
305 |
|
306 if (rect[2] < 0.0f || rect[3] < 0.0f) |
|
307 { |
|
308 result = WFC_ERROR_ILLEGAL_ARGUMENT; |
|
309 } |
|
310 else if (WFC_Element_ClampRectangle("destination", rect)) |
|
311 { |
|
312 /* ... return error or something here? */ |
|
313 result = WFC_ERROR_NONE; |
|
314 } |
|
315 |
|
316 /* Hmm.. let's clamp the rectangle even more! To 16k*16k at max; |
|
317 * in OWF_Image_Create we calculate the byte size of the image buffer |
|
318 * required, and if we have 4bpp, we get overflow for pixelcounts |
|
319 * >= 65536*16384. */ |
|
320 rect[2] = CLAMP(rect[2], 0, 16384); |
|
321 rect[3] = CLAMP(rect[3], 0, 16384); |
|
322 |
|
323 return result; |
|
324 } |
|
325 |
|
326 #define BOOLEAN_TO_ERROR(x) ((x) ? WFC_ERROR_NONE : WFC_ERROR_ILLEGAL_ARGUMENT) |
|
327 |
|
328 /*--------------------------------------------------------------------------- |
|
329 * |
|
330 *----------------------------------------------------------------------------*/ |
|
331 static WFCErrorCode |
|
332 WFC_Element_ValidateScalarAttributei(WFC_ELEMENT* element, |
|
333 WFCElementAttrib attrib, |
|
334 WFCint value) |
|
335 { |
|
336 WFCErrorCode result = WFC_ERROR_NONE; |
|
337 |
|
338 OWF_ASSERT(element); |
|
339 |
|
340 switch (attrib) |
|
341 { |
|
342 case WFC_ELEMENT_SOURCE: |
|
343 { |
|
344 WFC_IMAGE_PROVIDER* source; |
|
345 |
|
346 source = WFC_Device_FindImageProvider(element->device, |
|
347 value, |
|
348 WFC_IMAGE_SOURCE); |
|
349 |
|
350 result = BOOLEAN_TO_ERROR((WFC_INVALID_HANDLE == value) || |
|
351 ((WFC_INVALID_HANDLE != value) && |
|
352 (NULL != source))); |
|
353 break; |
|
354 } |
|
355 |
|
356 case WFC_ELEMENT_MASK: |
|
357 { |
|
358 WFC_IMAGE_PROVIDER* mask; |
|
359 |
|
360 mask = WFC_Device_FindImageProvider(element->device, |
|
361 value, |
|
362 WFC_IMAGE_MASK); |
|
363 |
|
364 result = BOOLEAN_TO_ERROR((WFC_INVALID_HANDLE == value) || |
|
365 ((WFC_INVALID_HANDLE != value) && |
|
366 (NULL != mask))); |
|
367 break; |
|
368 } |
|
369 |
|
370 case WFC_ELEMENT_SOURCE_ROTATION: |
|
371 { |
|
372 WFCRotation rotation = (WFCRotation) value; |
|
373 |
|
374 result = BOOLEAN_TO_ERROR((WFC_ROTATION_0 == rotation || |
|
375 WFC_ROTATION_90 == rotation || |
|
376 WFC_ROTATION_180 == rotation || |
|
377 WFC_ROTATION_270 == rotation)); |
|
378 break; |
|
379 } |
|
380 |
|
381 case WFC_ELEMENT_SOURCE_SCALE_FILTER: |
|
382 { |
|
383 WFCScaleFilter filter = (WFCScaleFilter) value; |
|
384 |
|
385 result = BOOLEAN_TO_ERROR((WFC_SCALE_FILTER_NONE == filter || |
|
386 WFC_SCALE_FILTER_FASTER == filter || |
|
387 WFC_SCALE_FILTER_BETTER == filter)); |
|
388 break; |
|
389 } |
|
390 |
|
391 case WFC_ELEMENT_SOURCE_FLIP: |
|
392 { |
|
393 WFCboolean flip = (WFCboolean) value; |
|
394 |
|
395 result = BOOLEAN_TO_ERROR((WFC_TRUE == flip || |
|
396 WFC_FALSE == flip)); |
|
397 break; |
|
398 } |
|
399 |
|
400 case WFC_ELEMENT_TRANSPARENCY_TYPES: |
|
401 { |
|
402 WFCint ii; |
|
403 WFCint count = sizeof(validTransparencyModes) / |
|
404 sizeof(WFCbitfield); |
|
405 WFCbitfield types = (WFCbitfield) value; |
|
406 |
|
407 result = WFC_ERROR_ILLEGAL_ARGUMENT; |
|
408 for (ii = 0; ii < count; ii++) { |
|
409 if (types == validTransparencyModes[ii]) |
|
410 { |
|
411 result = WFC_ERROR_NONE; |
|
412 break; |
|
413 } |
|
414 } |
|
415 break; |
|
416 } |
|
417 |
|
418 default: |
|
419 { |
|
420 result = WFC_ERROR_BAD_ATTRIBUTE; |
|
421 break; |
|
422 } |
|
423 } |
|
424 return result; |
|
425 } |
|
426 |
|
427 /*--------------------------------------------------------------------------- |
|
428 * |
|
429 *----------------------------------------------------------------------------*/ |
|
430 static WFCErrorCode |
|
431 WFC_Element_ValidateScalarAttributef(WFC_ELEMENT* element, |
|
432 WFCElementAttrib attrib, |
|
433 WFCfloat value) |
|
434 { |
|
435 WFCErrorCode result = WFC_ERROR_NONE; |
|
436 |
|
437 #ifndef DEBUG |
|
438 (void) element; |
|
439 #endif |
|
440 |
|
441 OWF_ASSERT(element); |
|
442 |
|
443 switch (attrib) |
|
444 { |
|
445 case WFC_ELEMENT_GLOBAL_ALPHA: |
|
446 { |
|
447 result = BOOLEAN_TO_ERROR(value >= OWF_ALPHA_MIN_VALUE && |
|
448 value <= OWF_ALPHA_MAX_VALUE); |
|
449 break; |
|
450 } |
|
451 |
|
452 /* SPECIAL CASES */ |
|
453 case WFC_ELEMENT_SOURCE_FLIP: |
|
454 case WFC_ELEMENT_SOURCE_ROTATION: |
|
455 case WFC_ELEMENT_SOURCE_SCALE_FILTER: |
|
456 case WFC_ELEMENT_TRANSPARENCY_TYPES: |
|
457 case WFC_ELEMENT_SOURCE: |
|
458 case WFC_ELEMENT_MASK: |
|
459 { |
|
460 /* NOTE! special early out here. */ |
|
461 result = WFC_ERROR_BAD_ATTRIBUTE; |
|
462 break; |
|
463 } |
|
464 |
|
465 default: |
|
466 { |
|
467 result = WFC_ERROR_ILLEGAL_ARGUMENT; |
|
468 break; |
|
469 } |
|
470 } |
|
471 |
|
472 return result; |
|
473 } |
|
474 |
|
475 /*--------------------------------------------------------------------------- |
|
476 * |
|
477 *----------------------------------------------------------------------------*/ |
|
478 static void |
|
479 WFC_Element_SetElementImageProvider(WFC_ELEMENT* element, |
|
480 WFC_IMAGE_PROVIDER_TYPE type, |
|
481 WFCHandle handle) |
|
482 { |
|
483 WFC_IMAGE_PROVIDER* provider; |
|
484 |
|
485 OWF_ASSERT(element); |
|
486 |
|
487 provider = WFC_Device_FindImageProvider(element->device, handle, type); |
|
488 |
|
489 switch (type) |
|
490 { |
|
491 case WFC_IMAGE_SOURCE: |
|
492 { |
|
493 DESTROY(element->cachedSource); |
|
494 ADDREF(element->cachedSource, provider); |
|
495 element->sourceHandle = handle; |
|
496 break; |
|
497 } |
|
498 case WFC_IMAGE_MASK: |
|
499 { |
|
500 DESTROY(element->cachedMask); |
|
501 ADDREF(element->cachedMask, provider); |
|
502 element->maskHandle = handle; |
|
503 break; |
|
504 } |
|
505 } |
|
506 } |
|
507 |
|
508 /*--------------------------------------------------------------------------- |
|
509 * \brief Set vector integer attribute for an element |
|
510 * |
|
511 * \param element Element |
|
512 * \param attrib Attribute name |
|
513 * \param count Attribute size |
|
514 * \param values Attribute vector value |
|
515 * |
|
516 *----------------------------------------------------------------------------*/ |
|
517 OWF_API_CALL WFCErrorCode |
|
518 WFC_Element_SetAttribiv(WFC_ELEMENT* element, |
|
519 WFCElementAttrib attrib, |
|
520 WFCint count, |
|
521 const WFCint* values) |
|
522 { |
|
523 WFCErrorCode result = WFC_ERROR_NONE; |
|
524 |
|
525 |
|
526 FAIL_IF(NULL == values, WFC_ERROR_ILLEGAL_ARGUMENT); |
|
527 |
|
528 switch (attrib) |
|
529 { |
|
530 /* Vector attributes */ |
|
531 case WFC_ELEMENT_SOURCE_RECTANGLE: |
|
532 case WFC_ELEMENT_DESTINATION_RECTANGLE: |
|
533 { |
|
534 WFCfloat rect[4]; |
|
535 |
|
536 rect[0] = values[0]; |
|
537 rect[1] = values[1]; |
|
538 rect[2] = values[2]; |
|
539 rect[3] = values[3]; |
|
540 |
|
541 result = WFC_Element_SetAttribfv(element, attrib, count, rect); |
|
542 break; |
|
543 } |
|
544 |
|
545 case WFC_ELEMENT_GLOBAL_ALPHA: |
|
546 { |
|
547 WFCfloat fvalue = values[0] / |
|
548 (WFCfloat) OWF_BYTE_MAX_VALUE; |
|
549 |
|
550 result = WFC_Element_SetAttribfv(element, |
|
551 attrib, |
|
552 1, |
|
553 &fvalue); |
|
554 break; |
|
555 } |
|
556 |
|
557 /* Scalar attributes */ |
|
558 default: |
|
559 { |
|
560 WFCint value; |
|
561 |
|
562 FAIL_IF(1 != count, WFC_ERROR_ILLEGAL_ARGUMENT); |
|
563 |
|
564 value = values[0]; |
|
565 |
|
566 /* Validate the value thus ensuring it is safe to change it */ |
|
567 result = WFC_Element_ValidateScalarAttributei(element, |
|
568 attrib, |
|
569 value); |
|
570 if (WFC_ERROR_NONE != result) |
|
571 { |
|
572 break; |
|
573 } |
|
574 |
|
575 switch (attrib) |
|
576 { |
|
577 case WFC_ELEMENT_SOURCE: |
|
578 { |
|
579 WFC_Element_SetElementImageProvider(element, |
|
580 WFC_IMAGE_SOURCE, |
|
581 value); |
|
582 break; |
|
583 } |
|
584 case WFC_ELEMENT_MASK: |
|
585 { |
|
586 WFC_Element_SetElementImageProvider(element, |
|
587 WFC_IMAGE_MASK, |
|
588 value); |
|
589 break; |
|
590 } |
|
591 case WFC_ELEMENT_SOURCE_FLIP: |
|
592 { |
|
593 element->sourceFlip = (WFCboolean)value; |
|
594 break; |
|
595 } |
|
596 case WFC_ELEMENT_SOURCE_ROTATION: |
|
597 { |
|
598 element->sourceRotation = (WFCRotation)value; |
|
599 break; |
|
600 } |
|
601 case WFC_ELEMENT_SOURCE_SCALE_FILTER: |
|
602 { |
|
603 element->sourceScaleFilter = (WFCScaleFilter)value; |
|
604 break; |
|
605 } |
|
606 case WFC_ELEMENT_TRANSPARENCY_TYPES: |
|
607 { |
|
608 element->transparencyTypes = value; |
|
609 break; |
|
610 } |
|
611 default: |
|
612 { |
|
613 result = WFC_ERROR_BAD_ATTRIBUTE; |
|
614 break; |
|
615 } |
|
616 } |
|
617 break; |
|
618 } |
|
619 } |
|
620 |
|
621 return result; |
|
622 } |
|
623 |
|
624 /*--------------------------------------------------------------------------- |
|
625 * |
|
626 *----------------------------------------------------------------------------*/ |
|
627 OWF_API_CALL WFCErrorCode |
|
628 WFC_Element_SetAttribfv(WFC_ELEMENT* element, |
|
629 WFCElementAttrib attrib, |
|
630 WFCint count, |
|
631 const WFCfloat* values) |
|
632 { |
|
633 WFCErrorCode result = WFC_ERROR_NONE; |
|
634 |
|
635 FAIL_IF(NULL == values, WFC_ERROR_ILLEGAL_ARGUMENT); |
|
636 |
|
637 switch (attrib) |
|
638 { |
|
639 /* Vector attributes */ |
|
640 case WFC_ELEMENT_SOURCE_RECTANGLE: |
|
641 case WFC_ELEMENT_DESTINATION_RECTANGLE: |
|
642 { |
|
643 WFCfloat clamped[4]; |
|
644 |
|
645 FAIL_IF(4 != count, WFC_ERROR_ILLEGAL_ARGUMENT); |
|
646 |
|
647 memcpy(clamped, values, 4 * sizeof(WFCfloat)); |
|
648 |
|
649 if (WFC_ELEMENT_SOURCE_RECTANGLE == attrib) |
|
650 { |
|
651 /* this clamps the rectangle, in case it has values that |
|
652 * cause precision loss or other fuzzy behaviour. */ |
|
653 result = WFC_Element_ValidateSourceRectangle(element, clamped); |
|
654 |
|
655 if (WFC_ERROR_NONE == result) |
|
656 { |
|
657 memcpy(element->srcRect, clamped, 4 * sizeof(WFCfloat)); |
|
658 |
|
659 DPRINT((" Source rectangle set to (%.2f,%.2f,%.2f,%.2f)", |
|
660 clamped[0], clamped[1], clamped[2], clamped[3])); |
|
661 } |
|
662 else |
|
663 { |
|
664 DPRINT((" Source rectangle (%.2f,%.2f,%.2f,%.2f) is " \ |
|
665 "invalid", |
|
666 values[0], values[1], values[2], values[3])); |
|
667 } |
|
668 } |
|
669 else |
|
670 { |
|
671 result = WFC_Element_ValidateDestinationRectangle(element, |
|
672 clamped); |
|
673 if (WFC_ERROR_NONE == result) |
|
674 { |
|
675 memcpy(element->dstRect, clamped, 4 * sizeof(WFCfloat)); |
|
676 |
|
677 DPRINT((" Destination rectangle set to " \ |
|
678 "(%.2f,%.2f,%.2f,%.2f)", |
|
679 clamped[0], clamped[1], clamped[2], clamped[3])); |
|
680 } |
|
681 else |
|
682 { |
|
683 DPRINT((" Destination rectangle (%.2f,%.2f,%.2f,%.2f) is " |
|
684 "invalid", |
|
685 values[0], values[1], values[2], values[3])); |
|
686 } |
|
687 } |
|
688 break; |
|
689 } |
|
690 |
|
691 /* scalar attributes */ |
|
692 case WFC_ELEMENT_GLOBAL_ALPHA: |
|
693 { |
|
694 /* values[0] must be [0, 1] */ |
|
695 WFCfloat value = values[0]; |
|
696 |
|
697 /* value is [0, 1] map to [0, OWF_ALPHA_MAX] */ |
|
698 value = value * OWF_ALPHA_MAX_VALUE; |
|
699 |
|
700 /* validate the value */ |
|
701 result = WFC_Element_ValidateScalarAttributef(element, |
|
702 attrib, |
|
703 value); |
|
704 |
|
705 if (WFC_ERROR_NONE != result) |
|
706 { |
|
707 /* invalid value for attribute, out we go */ |
|
708 break; |
|
709 } |
|
710 |
|
711 element->globalAlpha = value; |
|
712 break; |
|
713 } |
|
714 |
|
715 default: |
|
716 { |
|
717 result = WFC_ERROR_BAD_ATTRIBUTE; |
|
718 break; |
|
719 } |
|
720 } |
|
721 |
|
722 return result; |
|
723 } |
|
724 |
|
725 /*--------------------------------------------------------------------------- |
|
726 * Attribute getters |
|
727 *----------------------------------------------------------------------------*/ |
|
728 OWF_API_CALL WFCErrorCode |
|
729 WFC_Element_GetAttribiv(WFC_ELEMENT* element, |
|
730 WFCElementAttrib attrib, |
|
731 WFCint count, |
|
732 WFCint* values) |
|
733 { |
|
734 WFCErrorCode result = WFC_ERROR_NONE; |
|
735 |
|
736 |
|
737 FAIL_IF(NULL == values, WFC_ERROR_ILLEGAL_ARGUMENT); |
|
738 |
|
739 switch (attrib) |
|
740 { |
|
741 /* Vector attributes */ |
|
742 case WFC_ELEMENT_SOURCE_RECTANGLE: |
|
743 case WFC_ELEMENT_DESTINATION_RECTANGLE: |
|
744 { |
|
745 WFCfloat rect[4] = {0.0, 0.0, 0.0, 0.0}; |
|
746 |
|
747 result = WFC_Element_GetAttribfv(element, attrib, count, rect); |
|
748 |
|
749 if (WFC_ERROR_NONE == result) |
|
750 { |
|
751 values[0] = floor(rect[0]); |
|
752 values[1] = floor(rect[1]); |
|
753 values[2] = floor(rect[2]); |
|
754 values[3] = floor(rect[3]); |
|
755 } |
|
756 break; |
|
757 } |
|
758 |
|
759 /* Scalar attributes */ |
|
760 default: |
|
761 { |
|
762 FAIL_IF(1 != count, WFC_ERROR_ILLEGAL_ARGUMENT); |
|
763 |
|
764 switch (attrib) |
|
765 { |
|
766 /* pure int attributes */ |
|
767 case WFC_ELEMENT_SOURCE: |
|
768 { |
|
769 *values = element->sourceHandle; |
|
770 break; |
|
771 } |
|
772 case WFC_ELEMENT_MASK: |
|
773 { |
|
774 *values = element->maskHandle; |
|
775 break; |
|
776 } |
|
777 case WFC_ELEMENT_SOURCE_FLIP: |
|
778 { |
|
779 *values = element->sourceFlip; |
|
780 break; |
|
781 } |
|
782 case WFC_ELEMENT_SOURCE_ROTATION: |
|
783 { |
|
784 *values = element->sourceRotation; |
|
785 break; |
|
786 } |
|
787 case WFC_ELEMENT_SOURCE_SCALE_FILTER: |
|
788 { |
|
789 *values = element->sourceScaleFilter; |
|
790 break; |
|
791 } |
|
792 case WFC_ELEMENT_TRANSPARENCY_TYPES: |
|
793 { |
|
794 *values = element->transparencyTypes; |
|
795 break; |
|
796 } |
|
797 case WFC_ELEMENT_GLOBAL_ALPHA: |
|
798 { |
|
799 WFCfloat fvalue; |
|
800 |
|
801 WFC_Element_GetAttribfv(element, attrib, 1, &fvalue); |
|
802 *values = floor(OWF_BYTE_MAX_VALUE * fvalue / |
|
803 OWF_ALPHA_MAX_VALUE); |
|
804 break; |
|
805 } |
|
806 default: |
|
807 { |
|
808 result = WFC_ERROR_BAD_ATTRIBUTE; |
|
809 break; |
|
810 } |
|
811 } |
|
812 break; |
|
813 } |
|
814 } |
|
815 |
|
816 return result; |
|
817 } |
|
818 |
|
819 /*--------------------------------------------------------------------------- |
|
820 * |
|
821 *----------------------------------------------------------------------------*/ |
|
822 OWF_API_CALL WFCErrorCode |
|
823 WFC_Element_GetAttribfv(WFC_ELEMENT* element, |
|
824 WFCElementAttrib attrib, |
|
825 WFCint count, |
|
826 WFCfloat* values) |
|
827 { |
|
828 WFCErrorCode result = WFC_ERROR_NONE; |
|
829 |
|
830 FAIL_IF(NULL == values, WFC_ERROR_ILLEGAL_ARGUMENT); |
|
831 |
|
832 switch (attrib) |
|
833 { |
|
834 /* Vector attributes */ |
|
835 case WFC_ELEMENT_SOURCE_RECTANGLE: |
|
836 case WFC_ELEMENT_DESTINATION_RECTANGLE: |
|
837 { |
|
838 FAIL_IF(4 != count, WFC_ERROR_ILLEGAL_ARGUMENT); |
|
839 |
|
840 if (WFC_ELEMENT_SOURCE_RECTANGLE == attrib) |
|
841 { |
|
842 values[0] = element->srcRect[0]; |
|
843 values[1] = element->srcRect[1]; |
|
844 values[2] = element->srcRect[2]; |
|
845 values[3] = element->srcRect[3]; |
|
846 } |
|
847 else |
|
848 { |
|
849 values[0] = element->dstRect[0]; |
|
850 values[1] = element->dstRect[1]; |
|
851 values[2] = element->dstRect[2]; |
|
852 values[3] = element->dstRect[3]; |
|
853 } |
|
854 break; |
|
855 } |
|
856 |
|
857 /* Scalar attributes */ |
|
858 default: |
|
859 { |
|
860 switch (attrib) |
|
861 { |
|
862 case WFC_ELEMENT_GLOBAL_ALPHA: |
|
863 { |
|
864 *values = element->globalAlpha; |
|
865 break; |
|
866 } |
|
867 default: |
|
868 { |
|
869 result = WFC_ERROR_BAD_ATTRIBUTE; |
|
870 break; |
|
871 } |
|
872 } |
|
873 break; |
|
874 } |
|
875 } |
|
876 |
|
877 return result; |
|
878 } |
|
879 |
|
880 /*--------------------------------------------------------------------------- |
|
881 * Attribute checkers to use during commit to check element |
|
882 * for inconsistencies. |
|
883 *----------------------------------------------------------------------------*/ |
|
884 static WFCboolean |
|
885 WFC_Element_CheckAttribute(WFC_ELEMENT* element, |
|
886 WFCElementAttrib attrib) |
|
887 { |
|
888 #define VALIDATE_SCALAR_I(v) \ |
|
889 (WFC_Element_ValidateScalarAttributei(element, attrib, v) == \ |
|
890 WFC_ERROR_NONE ? WFC_TRUE : WFC_FALSE) |
|
891 #define VALIDATE_SCALAR_F(v) \ |
|
892 (WFC_Element_ValidateScalarAttributef(element, attrib, v) == \ |
|
893 WFC_ERROR_NONE ? WFC_TRUE : WFC_FALSE) |
|
894 |
|
895 WFCboolean result = WFC_TRUE; |
|
896 |
|
897 DPRINT(("WFC_Element_CheckAttribute(%08x,%0x)", |
|
898 element, attrib)); |
|
899 |
|
900 switch (attrib) |
|
901 { |
|
902 /* |
|
903 INTEGER-ATTRIBUTES |
|
904 */ |
|
905 case WFC_ELEMENT_SOURCE: |
|
906 { |
|
907 /* Validated when the attribute was modified */ |
|
908 break; |
|
909 } |
|
910 |
|
911 case WFC_ELEMENT_MASK: |
|
912 { |
|
913 /* Validated when the attribute was modified */ |
|
914 break; |
|
915 } |
|
916 |
|
917 case WFC_ELEMENT_SOURCE_FLIP: |
|
918 { |
|
919 result = VALIDATE_SCALAR_I(element->sourceFlip) ? WFC_TRUE: WFC_FALSE; |
|
920 if (!result) |
|
921 { |
|
922 DPRINT((" Element source flipping is invalid (%d)", |
|
923 element->sourceFlip)); |
|
924 } |
|
925 break; |
|
926 } |
|
927 |
|
928 case WFC_ELEMENT_SOURCE_ROTATION: |
|
929 { |
|
930 result = VALIDATE_SCALAR_I(element->sourceRotation) ? WFC_TRUE: WFC_FALSE; |
|
931 |
|
932 if (!result) |
|
933 { |
|
934 DPRINT((" Element source rotation is invalid (%d)", |
|
935 element->sourceRotation)); |
|
936 } |
|
937 break; |
|
938 } |
|
939 |
|
940 case WFC_ELEMENT_SOURCE_SCALE_FILTER: |
|
941 { |
|
942 result = VALIDATE_SCALAR_I(element->sourceScaleFilter) ? WFC_TRUE: WFC_FALSE; |
|
943 |
|
944 if (!result) |
|
945 { |
|
946 DPRINT((" Element source scale filter is invalid (%d)", |
|
947 element->sourceScaleFilter)); |
|
948 } |
|
949 break; |
|
950 } |
|
951 |
|
952 case WFC_ELEMENT_TRANSPARENCY_TYPES: |
|
953 { |
|
954 result = VALIDATE_SCALAR_I(element->transparencyTypes) ? WFC_TRUE: WFC_FALSE; |
|
955 |
|
956 if (!result) |
|
957 { |
|
958 DPRINT((" Element transparency type is invalid (%x)", |
|
959 element->transparencyTypes)); |
|
960 } |
|
961 break; |
|
962 } |
|
963 |
|
964 case WFC_ELEMENT_GLOBAL_ALPHA: |
|
965 { |
|
966 result = VALIDATE_SCALAR_F(element->globalAlpha) ? WFC_TRUE: WFC_FALSE; |
|
967 if (!result) |
|
968 { |
|
969 DPRINT((" Element global alpha is invalid (%d)", |
|
970 element->globalAlpha)); |
|
971 } |
|
972 break; |
|
973 } |
|
974 |
|
975 case WFC_ELEMENT_DESTINATION_RECTANGLE: |
|
976 { |
|
977 WFC_IMAGE_PROVIDER* mask; |
|
978 |
|
979 /* The <0 test is repeated in SetAttribfv ValidateDestinationRectangle */ |
|
980 if (element->dstRect[2] < 0 || element->dstRect[3] < 0) |
|
981 { |
|
982 DPRINT((" Element destination rectangle has negative " |
|
983 "width/height")); |
|
984 result = WFC_FALSE; |
|
985 break; |
|
986 } |
|
987 if (element->maskHandle!=WFC_INVALID_HANDLE) |
|
988 { |
|
989 result = WFC_Element_CheckAttribute(element, WFC_ELEMENT_MASK); |
|
990 |
|
991 if (result) |
|
992 { |
|
993 mask = WFC_Device_FindMask(element->device, |
|
994 element->maskHandle); |
|
995 if (!mask) |
|
996 { |
|
997 DPRINT((" Mask handle is valid, but mask object now destroyed")); |
|
998 mask=element->cachedMask; |
|
999 if (!mask) |
|
1000 { |
|
1001 mask=element->mask; |
|
1002 } |
|
1003 } |
|
1004 if (mask) |
|
1005 { |
|
1006 WFCint maskWidth, maskHeight; |
|
1007 |
|
1008 DPRINT((" Element has a mask")); |
|
1009 /* if the element has a mask, then width & height must match |
|
1010 the dimensions of that mask */ |
|
1011 owfNativeStreamGetHeader(mask->streamHandle,&maskWidth, &maskHeight,NULL,NULL,NULL); |
|
1012 |
|
1013 if (element->dstRect[2] != maskWidth || |
|
1014 element->dstRect[3] != maskHeight) |
|
1015 { |
|
1016 DPRINT((" Mask size (%dx%d) != element size (%d,%d)", |
|
1017 maskWidth, maskHeight, |
|
1018 (int)element->dstRect[2], |
|
1019 (int)element->dstRect[3])); |
|
1020 result = WFC_FALSE; |
|
1021 break; |
|
1022 } |
|
1023 } |
|
1024 else |
|
1025 { |
|
1026 DPRINT((" No mask pointers could be opened! Scene not safe!")); |
|
1027 result = WFC_FALSE; |
|
1028 } |
|
1029 } |
|
1030 } |
|
1031 break; |
|
1032 } |
|
1033 |
|
1034 case WFC_ELEMENT_SOURCE_RECTANGLE: |
|
1035 { |
|
1036 WFC_IMAGE_PROVIDER* source; |
|
1037 |
|
1038 result = WFC_Element_CheckAttribute(element, WFC_ELEMENT_SOURCE); |
|
1039 |
|
1040 if (result && element->sourceHandle!=WFC_INVALID_HANDLE) |
|
1041 { /* no source is valid - the element "will not affect composition results" */ |
|
1042 source = WFC_Device_FindImageProvider(element->device, |
|
1043 element->sourceHandle, |
|
1044 WFC_IMAGE_SOURCE); |
|
1045 |
|
1046 result = WFC_TRUE; |
|
1047 if (!source) |
|
1048 { |
|
1049 DPRINT((" Source handle is valid, but source object now destroyed")); |
|
1050 source=element->cachedSource; |
|
1051 if (!source) |
|
1052 { |
|
1053 source=element->source; |
|
1054 } |
|
1055 } |
|
1056 |
|
1057 if (source) |
|
1058 { |
|
1059 WFCint sourceWidth, sourceHeight; |
|
1060 |
|
1061 owfNativeStreamGetHeader(source->streamHandle,&sourceWidth, &sourceHeight,NULL,NULL,NULL); |
|
1062 /* The <0 test is repeated in SetAttribfv ValidateSourceRectangle */ |
|
1063 if ((element->srcRect[0] < 0) || |
|
1064 (element->srcRect[1] < 0) || |
|
1065 (element->srcRect[2] < 0) || |
|
1066 (element->srcRect[3] < 0) || |
|
1067 (element->srcRect[0] + element->srcRect[2]) > sourceWidth || |
|
1068 (element->srcRect[1] + element->srcRect[3]) > sourceHeight) |
|
1069 { |
|
1070 DPRINT((" Source rectangle out of bounds")); |
|
1071 DPRINT((" (%f,%f,%f,%f), source size %dx%d", |
|
1072 element->srcRect[0], element->srcRect[1], |
|
1073 element->srcRect[2], element->srcRect[3], |
|
1074 sourceWidth, sourceHeight)); |
|
1075 result = WFC_FALSE; |
|
1076 break; |
|
1077 } |
|
1078 } |
|
1079 else |
|
1080 { |
|
1081 DPRINT((" No source pointers could be opened! Scene not safe!")); |
|
1082 result = WFC_FALSE; |
|
1083 } |
|
1084 } |
|
1085 break; |
|
1086 } |
|
1087 |
|
1088 case WFC_ELEMENT_FORCE_32BIT: |
|
1089 { |
|
1090 /* to keep compiler happy */ |
|
1091 OWF_ASSERT(0); |
|
1092 break; |
|
1093 } |
|
1094 } |
|
1095 |
|
1096 return result; |
|
1097 |
|
1098 #undef VALIDATE_SCALAR_F |
|
1099 #undef VALIDATE_SCALAR_I |
|
1100 } |
|
1101 |
|
1102 /*--------------------------------------------------------------------------- |
|
1103 * |
|
1104 *----------------------------------------------------------------------------*/ |
|
1105 OWF_API_CALL WFCboolean |
|
1106 WFC_Element_HasConflicts(WFC_ELEMENT* element) |
|
1107 { |
|
1108 #define CHECK(x) \ |
|
1109 if (!WFC_Element_CheckAttribute(element, x)) \ |
|
1110 {\ |
|
1111 DPRINT(("Element %d: Conflict in attribute %08x", element->handle, x));\ |
|
1112 return WFC_TRUE; \ |
|
1113 } |
|
1114 |
|
1115 CHECK(WFC_ELEMENT_SOURCE); |
|
1116 CHECK(WFC_ELEMENT_MASK); |
|
1117 CHECK(WFC_ELEMENT_SOURCE_RECTANGLE); |
|
1118 CHECK(WFC_ELEMENT_DESTINATION_RECTANGLE); |
|
1119 CHECK(WFC_ELEMENT_SOURCE_FLIP); |
|
1120 CHECK(WFC_ELEMENT_SOURCE_ROTATION); |
|
1121 CHECK(WFC_ELEMENT_SOURCE_SCALE_FILTER); |
|
1122 CHECK(WFC_ELEMENT_TRANSPARENCY_TYPES); |
|
1123 CHECK(WFC_ELEMENT_GLOBAL_ALPHA); |
|
1124 |
|
1125 #undef CHECK |
|
1126 |
|
1127 /* all ok, no conflicts */ |
|
1128 return WFC_FALSE; |
|
1129 } |
|
1130 |
|
1131 /*--------------------------------------------------------------------------- |
|
1132 * |
|
1133 *----------------------------------------------------------------------------*/ |
|
1134 OWF_API_CALL WFCboolean |
|
1135 WFC_Element_AffectsCompositionResults(WFC_ELEMENT* element) |
|
1136 { |
|
1137 if ( (element->transparencyTypes&WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA) |
|
1138 && element->globalAlpha==OWF_FULLY_TRANSPARENT ) |
|
1139 { |
|
1140 return WFC_FALSE; |
|
1141 } |
|
1142 if (element->sourceHandle==WFC_INVALID_HANDLE) |
|
1143 { |
|
1144 return WFC_FALSE; |
|
1145 } |
|
1146 if (element->dstRect[2]==0.0f || element->dstRect[3]==0.0f) |
|
1147 { |
|
1148 return WFC_FALSE; |
|
1149 } |
|
1150 if (element->srcRect[2]==0.0f || element->srcRect[3]==0.0f) |
|
1151 { |
|
1152 return WFC_FALSE; |
|
1153 } |
|
1154 return WFC_TRUE; |
|
1155 |
|
1156 } |
|
1157 /*--------------------------------------------------------------------------- |
|
1158 * |
|
1159 *----------------------------------------------------------------------------*/ |
|
1160 OWF_API_CALL void |
|
1161 WFC_Element_Commit(WFC_ELEMENT* element) |
|
1162 { |
|
1163 OWF_ASSERT(element); |
|
1164 |
|
1165 DPRINT(("WFC_Element_Commit(element = %d)\n", element->handle)); |
|
1166 |
|
1167 /* replace source/mask ONLY if it has changed. without these checks, |
|
1168 * both source and mask would be overwritten whenever one of them |
|
1169 * is changed. |
|
1170 */ |
|
1171 |
|
1172 if (element->cachedSource != element->source) |
|
1173 { |
|
1174 element->source = element->cachedSource; |
|
1175 } |
|
1176 |
|
1177 if (element->cachedMask != element->mask) |
|
1178 { |
|
1179 element->mask = element->cachedMask; |
|
1180 } |
|
1181 |
|
1182 /* these must be reset now that the element is committed -- the only purpose |
|
1183 * of these cached ones is to have source/mask object pointers in the |
|
1184 * element so that source/mask can be safely deleted from the device even |
|
1185 * if that particular image provider is set as source/mask for some element |
|
1186 * that is not yet committed. |
|
1187 */ |
|
1188 |
|
1189 DPRINT((" Prior to destroying cached objects:")); |
|
1190 DPRINT((" R(cachedMask) = %d", REFCOUNT(element->cachedMask))); |
|
1191 DPRINT((" R(cachedSource) = %d", REFCOUNT(element->cachedSource))); |
|
1192 |
|
1193 element->cachedSource = NULL; |
|
1194 element->cachedMask = NULL; |
|
1195 |
|
1196 DPRINT((" new source = %d\n", element->source ? |
|
1197 element->source->handle : 0)); |
|
1198 DPRINT((" new mask = %d\n", element->mask ? |
|
1199 element->mask->handle : 0)); |
|
1200 } |
|
1201 |
|
1202 |
|
1203 |
|
1204 #ifdef __cplusplus |
|
1205 } |
|
1206 #endif |
|
1207 |