2 * Copyright 2006, Haiku.
3 * Distributed under the terms of the MIT License.
6 * Stephan Aßmus <superstippi@gmx.de>
9 #include "GradientTransformable.h"
21 Gradient::Gradient(bool empty
)
32 fType(GRADIENT_LINEAR
),
33 fInterpolation(INTERPOLATION_SMOOTH
),
34 fInheritTransformation(true)
37 AddColor(BGradient::ColorStop(0, 0, 0, 255, 0.0), 0);
38 AddColor(BGradient::ColorStop(255, 255, 255, 255, 1.0), 1);
43 Gradient::Gradient(BMessage
* archive
)
45 : BArchivable(archive
),
54 fType(GRADIENT_LINEAR
),
55 fInterpolation(INTERPOLATION_SMOOTH
),
56 fInheritTransformation(true)
61 // read transformation
62 int32 size
= Transformable::matrix_size
;
64 ssize_t dataSize
= size
* sizeof(double);
65 if (archive
->FindData("transformation", B_DOUBLE_TYPE
,
66 &matrix
, &dataSize
) == B_OK
67 && dataSize
== (ssize_t
)(size
* sizeof(double)))
68 LoadFrom((const double*)matrix
);
71 BGradient::ColorStop step
;
72 for (int32 i
= 0; archive
->FindFloat("offset", i
, &step
.offset
) >= B_OK
; i
++) {
73 if (archive
->FindInt32("color", i
, (int32
*)&step
.color
) >= B_OK
)
78 if (archive
->FindInt32("type", (int32
*)&fType
) < B_OK
)
79 fType
= GRADIENT_LINEAR
;
81 if (archive
->FindInt32("interpolation", (int32
*)&fInterpolation
) < B_OK
)
82 fInterpolation
= INTERPOLATION_SMOOTH
;
84 if (archive
->FindBool("inherit transformation",
85 &fInheritTransformation
) < B_OK
)
86 fInheritTransformation
= true;
90 Gradient::Gradient(const Gradient
& other
)
97 : Transformable(other
),
102 fInterpolation(other
.fInterpolation
),
103 fInheritTransformation(other
.fInheritTransformation
)
105 for (int32 i
= 0; BGradient::ColorStop
* step
= other
.ColorAt(i
); i
++) {
111 Gradient::~Gradient()
119 Gradient::Archive(BMessage
* into
, bool deep
) const
121 status_t ret
= BArchivable::Archive(into
, deep
);
125 int32 size
= Transformable::matrix_size
;
128 ret
= into
->AddData("transformation", B_DOUBLE_TYPE
,
129 matrix
, size
* sizeof(double));
134 for (int32 i
= 0; BGradient::ColorStop
* step
= ColorAt(i
); i
++) {
135 ret
= into
->AddInt32("color", (const uint32
&)step
->color
);
138 ret
= into
->AddFloat("offset", step
->offset
);
143 // gradient and interpolation type
145 ret
= into
->AddInt32("type", (int32
)fType
);
147 ret
= into
->AddInt32("interpolation", (int32
)fInterpolation
);
149 ret
= into
->AddBool("inherit transformation", fInheritTransformation
);
153 ret
= into
->AddString("class", "Gradient");
157 #endif // ICON_O_MATIC
163 Gradient::operator=(const Gradient
& other
)
166 AutoNotificationSuspender
_(this);
171 SetType(other
.fType
);
172 SetInterpolation(other
.fInterpolation
);
173 SetInheritTransformation(other
.fInheritTransformation
);
180 Gradient::operator==(const Gradient
& other
) const
182 if (Transformable::operator==(other
))
183 return ColorStepsAreEqual(other
);
189 Gradient::operator!=(const Gradient
& other
) const
191 return !(*this == other
);
194 // ColorStepsAreEqual
196 Gradient::ColorStepsAreEqual(const Gradient
& other
) const
198 int32 count
= CountColors();
199 if (count
== other
.CountColors() &&
200 fType
== other
.fType
&&
201 fInterpolation
== other
.fInterpolation
&&
202 fInheritTransformation
== other
.fInheritTransformation
) {
205 for (int32 i
= 0; i
< count
; i
++) {
206 BGradient::ColorStop
* ourStep
= ColorAtFast(i
);
207 BGradient::ColorStop
* otherStep
= other
.ColorAtFast(i
);
208 if (*ourStep
!= *otherStep
) {
220 Gradient::SetColors(const Gradient
& other
)
223 AutoNotificationSuspender
_(this);
227 for (int32 i
= 0; BGradient::ColorStop
* step
= other
.ColorAt(i
); i
++)
237 Gradient::AddColor(const rgb_color
& color
, float offset
)
239 // find the correct index (sorted by offset)
240 BGradient::ColorStop
* step
= new BGradient::ColorStop(color
, offset
);
242 int32 count
= CountColors();
243 for (; index
< count
; index
++) {
244 BGradient::ColorStop
* s
= ColorAtFast(index
);
245 if (s
->offset
> step
->offset
)
248 if (!fColors
.AddItem((void*)step
, index
)) {
258 Gradient::AddColor(const BGradient::ColorStop
& color
, int32 index
)
260 BGradient::ColorStop
* step
= new BGradient::ColorStop(color
);
261 if (!fColors
.AddItem((void*)step
, index
)) {
271 Gradient::RemoveColor(int32 index
)
273 BGradient::ColorStop
* step
274 = (BGradient::ColorStop
*)fColors
.RemoveItem(index
);
287 Gradient::SetColor(int32 index
, const BGradient::ColorStop
& color
)
289 if (BGradient::ColorStop
* step
= ColorAt(index
)) {
290 if (*step
!= color
) {
291 step
->color
= color
.color
;
292 step
->offset
= color
.offset
;
302 Gradient::SetColor(int32 index
, const rgb_color
& color
)
304 if (BGradient::ColorStop
* step
= ColorAt(index
)) {
305 if ((uint32
&)step
->color
!= (uint32
&)color
) {
316 Gradient::SetOffset(int32 index
, float offset
)
318 BGradient::ColorStop
* step
= ColorAt(index
);
319 if (step
&& step
->offset
!= offset
) {
320 step
->offset
= offset
;
331 Gradient::CountColors() const
333 return fColors
.CountItems();
337 BGradient::ColorStop
*
338 Gradient::ColorAt(int32 index
) const
340 return (BGradient::ColorStop
*)fColors
.ItemAt(index
);
344 BGradient::ColorStop
*
345 Gradient::ColorAtFast(int32 index
) const
347 return (BGradient::ColorStop
*)fColors
.ItemAtFast(index
);
354 Gradient::SetType(gradients_type type
)
364 Gradient::SetInterpolation(interpolation_type type
)
366 if (fInterpolation
!= type
) {
367 fInterpolation
= type
;
372 // SetInheritTransformation
374 Gradient::SetInheritTransformation(bool inherit
)
376 if (fInheritTransformation
!= inherit
) {
377 fInheritTransformation
= inherit
;
388 // this aint' a real gauss function
391 return (1.0 - 2.0 * f
*f
);
401 Gradient::MakeGradient(uint32
* colors
, int32 count
) const
403 BGradient::ColorStop
* from
= ColorAt(0);
408 // find the step with the lowest offset
409 for (int32 i
= 0; BGradient::ColorStop
* step
= ColorAt(i
); i
++) {
410 if (step
->offset
< from
->offset
)
414 // current index into "colors" array
415 int32 index
= (int32
)floorf(count
* from
->offset
+ 0.5);
420 // make sure we fill the entire array
422 uint8
* c
= (uint8
*)&colors
[0];
423 for (int32 i
= 0; i
< index
; i
++) {
424 c
[0] = from
->color
.red
;
425 c
[1] = from
->color
.green
;
426 c
[2] = from
->color
.blue
;
427 c
[3] = from
->color
.alpha
;
432 // put all steps that we need to interpolate to into a list
433 BList
nextSteps(fColors
.CountItems() - 1);
434 for (int32 i
= 0; BGradient::ColorStop
* step
= ColorAt(i
); i
++) {
436 nextSteps
.AddItem((void*)step
);
439 // interpolate "from" to "to"
440 while (!nextSteps
.IsEmpty()) {
442 // find the step with the next offset
443 BGradient::ColorStop
* to
= NULL
;
444 float nextOffsetDist
= 2.0;
445 for (int32 i
= 0; BGradient::ColorStop
* step
446 = (BGradient::ColorStop
*)nextSteps
.ItemAt(i
); i
++) {
447 float d
= step
->offset
- from
->offset
;
448 if (d
< nextOffsetDist
&& d
>= 0) {
456 nextSteps
.RemoveItem((void*)to
);
459 int32 offset
= (int32
)floorf((count
- 1) * to
->offset
+ 0.5);
462 int32 dist
= offset
- index
;
464 uint8
* c
= (uint8
*)&colors
[index
];
466 uint16 fromRed
= kGammaTable
[from
->color
.red
];
467 uint16 fromGreen
= kGammaTable
[from
->color
.green
];
468 uint16 fromBlue
= kGammaTable
[from
->color
.blue
];
469 uint16 toRed
= kGammaTable
[to
->color
.red
];
470 uint16 toGreen
= kGammaTable
[to
->color
.green
];
471 uint16 toBlue
= kGammaTable
[to
->color
.blue
];
473 for (int32 i
= index
; i
<= offset
; i
++) {
474 float f
= (float)(offset
- i
) / (float)(dist
+ 1);
475 if (fInterpolation
== INTERPOLATION_SMOOTH
)
478 c
[0] = kInverseGammaTable
[(uint16
)floor(fromBlue
* f
+ toBlue
* t
+ 0.5)];
479 c
[1] = kInverseGammaTable
[(uint16
)floor(fromGreen
* f
+ toGreen
* t
+ 0.5)];
480 c
[2] = kInverseGammaTable
[(uint16
)floor(fromRed
* f
+ toRed
* t
+ 0.5)];
481 c
[3] = (uint8
)floor(from
->color
.alpha
* f
+ to
->color
.alpha
* t
+ 0.5);
485 for (int32 i
= index
; i
<= offset
; i
++) {
486 float f
= (float)(offset
- i
) / (float)(dist
+ 1);
487 if (fInterpolation
== INTERPOLATION_SMOOTH
)
490 c
[0] = (uint8
)floor(from
->color
.red
* f
+ to
->color
.red
* t
+ 0.5);
491 c
[1] = (uint8
)floor(from
->color
.green
* f
+ to
->color
.green
* t
+ 0.5);
492 c
[2] = (uint8
)floor(from
->color
.blue
* f
+ to
->color
.blue
* t
+ 0.5);
493 c
[3] = (uint8
)floor(from
->color
.alpha
* f
+ to
->color
.alpha
* t
+ 0.5);
496 #endif // GAMMA_BLEND
499 // the current "to" will be the "from" in the next interpolation
502 // make sure we fill the entire array
504 uint8
* c
= (uint8
*)&colors
[index
];
505 for (int32 i
= index
; i
< count
; i
++) {
506 c
[0] = from
->color
.red
;
507 c
[1] = from
->color
.green
;
508 c
[2] = from
->color
.blue
;
509 c
[3] = from
->color
.alpha
;
517 Gradient::FitToBounds(const BRect
& bounds
)
520 parl
[0] = bounds
.left
;
521 parl
[1] = bounds
.top
;
522 parl
[2] = bounds
.right
;
523 parl
[3] = bounds
.top
;
524 parl
[4] = bounds
.right
;
525 parl
[5] = bounds
.bottom
;
526 agg::trans_affine
transform(-200.0, -200.0, 200.0, 200.0, parl
);
532 string_for_type(gradients_type type
)
535 case GRADIENT_LINEAR
:
536 return "GRADIENT_LINEAR";
537 case GRADIENT_CIRCULAR
:
538 return "GRADIENT_CIRCULAR";
539 case GRADIENT_DIAMOND
:
540 return "GRADIENT_DIAMOND";
542 return "GRADIENT_CONIC";
544 return "GRADIENT_XY";
545 case GRADIENT_SQRT_XY
:
546 return "GRADIENT_SQRT_XY";
551 //string_for_interpolation
553 string_for_interpolation(interpolation_type type
)
556 case INTERPOLATION_LINEAR
:
557 return "INTERPOLATION_LINEAR";
558 case INTERPOLATION_SMOOTH
:
559 return "INTERPOLATION_SMOOTH";
566 Gradient::GradientArea() const
568 BRect
area(0, 0, 64, 64);
570 case GRADIENT_LINEAR
:
571 case GRADIENT_CIRCULAR
:
572 case GRADIENT_DIAMOND
:
575 case GRADIENT_SQRT_XY
:
581 // TransformationChanged()
583 Gradient::TransformationChanged()
590 Gradient::PrintToStream() const
592 printf("Gradient: type: %s, interpolation: %s, inherits transform: %d\n",
593 string_for_type(fType
),
594 string_for_interpolation(fInterpolation
),
595 fInheritTransformation
);
596 for (int32 i
= 0; BGradient::ColorStop
* step
= ColorAt(i
); i
++) {
597 printf(" %" B_PRId32
": offset: %.1f -> color(%d, %d, %d, %d)\n",
608 Gradient::_MakeEmpty()
610 int32 count
= CountColors();
611 for (int32 i
= 0; i
< count
; i
++)
612 delete ColorAtFast(i
);