244 lines
4.9 KiB
C++
244 lines
4.9 KiB
C++
/*
|
|
* Copyright (c) 2001-2015, Haiku, Inc.
|
|
* Distributed under the terms of the MIT license.
|
|
*
|
|
* Authors:
|
|
* Axel Dörfler, axeld@pinc-software.de
|
|
* Stephan Aßmus <superstippi@gmx.de>
|
|
* Adrien Destugues <pulkomandy@pulkomandy.tk>
|
|
* Julian Harnath <julian.harnath@rwth-aachen.de>
|
|
*/
|
|
|
|
#ifndef SIMPLE_TRANSFORM_H
|
|
#define SIMPLE_TRANSFORM_H
|
|
|
|
#include <GradientLinear.h>
|
|
#include <GradientRadial.h>
|
|
#include <GradientRadialFocus.h>
|
|
#include <GradientDiamond.h>
|
|
#include <GradientConic.h>
|
|
#include <Point.h>
|
|
#include <Region.h>
|
|
|
|
#include "IntPoint.h"
|
|
#include "IntRect.h"
|
|
|
|
|
|
class SimpleTransform {
|
|
public:
|
|
SimpleTransform()
|
|
:
|
|
fScale(1.0)
|
|
{
|
|
}
|
|
|
|
void AddOffset(float x, float y)
|
|
{
|
|
fOffset.x += x;
|
|
fOffset.y += y;
|
|
}
|
|
|
|
void SetScale(float scale)
|
|
{
|
|
fScale = scale;
|
|
}
|
|
|
|
void Apply(BPoint* point) const
|
|
{
|
|
_Apply(point->x, point->y);
|
|
}
|
|
|
|
void Apply(IntPoint* point) const
|
|
{
|
|
_Apply(point->x, point->y);
|
|
}
|
|
|
|
void Apply(BRect* rect) const
|
|
{
|
|
if (fScale == 1.0) {
|
|
rect->OffsetBy(fOffset.x, fOffset.y);
|
|
} else {
|
|
_Apply(rect->left, rect->top);
|
|
_Apply(rect->right, rect->bottom);
|
|
}
|
|
}
|
|
|
|
void Apply(IntRect* rect) const
|
|
{
|
|
if (fScale == 1.0) {
|
|
rect->OffsetBy(fOffset.x, fOffset.y);
|
|
} else {
|
|
_Apply(rect->left, rect->top);
|
|
_Apply(rect->right, rect->bottom);
|
|
}
|
|
}
|
|
|
|
void Apply(BRegion* region) const
|
|
{
|
|
if (fScale == 1.0) {
|
|
region->OffsetBy(fOffset.x, fOffset.y);
|
|
} else {
|
|
// TODO: optimize some more
|
|
BRegion converted;
|
|
int32 count = region->CountRects();
|
|
for (int32 i = 0; i < count; i++) {
|
|
BRect r = region->RectAt(i);
|
|
BPoint lt(r.LeftTop());
|
|
BPoint rb(r.RightBottom());
|
|
// offset to bottom right corner of pixel before transformation
|
|
rb.x++;
|
|
rb.y++;
|
|
// apply transformation
|
|
_Apply(lt.x, lt.y);
|
|
_Apply(rb.x, rb.y);
|
|
// reset bottom right to pixel "index"
|
|
rb.x--;
|
|
rb.y--;
|
|
// add rect to converted region
|
|
// NOTE/TODO: the rect would not have to go
|
|
// through the whole intersection test process,
|
|
// it is guaranteed not to overlap with any rect
|
|
// already contained in the region
|
|
converted.Include(BRect(lt, rb));
|
|
}
|
|
*region = converted;
|
|
}
|
|
}
|
|
|
|
void Apply(BGradient* gradient) const
|
|
{
|
|
switch (gradient->GetType()) {
|
|
case BGradient::TYPE_LINEAR:
|
|
{
|
|
BGradientLinear* linear = (BGradientLinear*) gradient;
|
|
BPoint start = linear->Start();
|
|
BPoint end = linear->End();
|
|
Apply(&start);
|
|
Apply(&end);
|
|
linear->SetStart(start);
|
|
linear->SetEnd(end);
|
|
break;
|
|
}
|
|
|
|
case BGradient::TYPE_RADIAL:
|
|
{
|
|
BGradientRadial* radial = (BGradientRadial*) gradient;
|
|
BPoint center = radial->Center();
|
|
Apply(¢er);
|
|
radial->SetCenter(center);
|
|
break;
|
|
}
|
|
|
|
case BGradient::TYPE_RADIAL_FOCUS:
|
|
{
|
|
BGradientRadialFocus* radialFocus =
|
|
(BGradientRadialFocus*)gradient;
|
|
BPoint center = radialFocus->Center();
|
|
BPoint focal = radialFocus->Focal();
|
|
Apply(¢er);
|
|
Apply(&focal);
|
|
radialFocus->SetCenter(center);
|
|
radialFocus->SetFocal(focal);
|
|
break;
|
|
}
|
|
|
|
case BGradient::TYPE_DIAMOND:
|
|
{
|
|
BGradientDiamond* diamond = (BGradientDiamond*) gradient;
|
|
BPoint center = diamond->Center();
|
|
Apply(¢er);
|
|
diamond->SetCenter(center);
|
|
break;
|
|
}
|
|
|
|
case BGradient::TYPE_CONIC:
|
|
{
|
|
BGradientConic* conic = (BGradientConic*) gradient;
|
|
BPoint center = conic->Center();
|
|
Apply(¢er);
|
|
conic->SetCenter(center);
|
|
break;
|
|
}
|
|
|
|
case BGradient::TYPE_NONE:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Make sure the gradient is fully padded so that out of bounds access
|
|
// get the correct colors
|
|
gradient->SortColorStopsByOffset();
|
|
|
|
BGradient::ColorStop* end = gradient->ColorStopAtFast(
|
|
gradient->CountColorStops() - 1);
|
|
|
|
if (end->offset != 255)
|
|
gradient->AddColor(end->color, 255);
|
|
|
|
BGradient::ColorStop* start = gradient->ColorStopAtFast(0);
|
|
|
|
if (start->offset != 0)
|
|
gradient->AddColor(start->color, 0);
|
|
|
|
gradient->SortColorStopsByOffset();
|
|
}
|
|
|
|
void Apply(BPoint* destination, const BPoint* source, int32 count) const
|
|
{
|
|
// TODO: optimize this, it should be smarter
|
|
while (count--) {
|
|
*destination = *source;
|
|
Apply(destination);
|
|
source++;
|
|
destination++;
|
|
}
|
|
}
|
|
|
|
void Apply(BRect* destination, const BRect* source, int32 count) const
|
|
{
|
|
// TODO: optimize this, it should be smarter
|
|
while (count--) {
|
|
*destination = *source;
|
|
Apply(destination);
|
|
source++;
|
|
destination++;
|
|
}
|
|
}
|
|
|
|
void Apply(BRegion* destination, const BRegion* source, int32 count) const
|
|
{
|
|
// TODO: optimize this, it should be smarter
|
|
while (count--) {
|
|
*destination = *source;
|
|
Apply(destination);
|
|
source++;
|
|
destination++;
|
|
}
|
|
}
|
|
|
|
private:
|
|
void _Apply(int32& x, int32& y) const
|
|
{
|
|
x *= (int32)fScale;
|
|
y *= (int32)fScale;
|
|
x += (int32)fOffset.x;
|
|
y += (int32)fOffset.y;
|
|
}
|
|
|
|
void _Apply(float& x, float& y) const
|
|
{
|
|
x *= fScale;
|
|
y *= fScale;
|
|
x += fOffset.x;
|
|
y += fOffset.y;
|
|
}
|
|
|
|
private:
|
|
BPoint fOffset;
|
|
float fScale;
|
|
};
|
|
|
|
|
|
#endif // SIMPLE_TRANSFORM_H
|