Icon-O-Matic: Add perspective transformations

As part of adding perspective transformations, agg_trans_perspective.h
was patched to fix a multiple definitions error. This change has been
submitted for review to the "upstream" repositories at [1], [2],
and [3].

Also includes various other improvements such as VertexSource being
split into its own file, code style improvements, and documentation
improvements.

[1] https://sourceforge.net/p/agg/patches/6/
[2] https://github.com/ghaerr/agg-2.6/pull/9
[3] https://github.com/aggeom/agg-2.6/pull/7

Change-Id: I4bffd2f87354bde10155e23145a232a925be6ff3
Reviewed-on: https://review.haiku-os.org/c/haiku/+/6801
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Zardshard
2023-08-22 09:44:49 +00:00
committed by Adrien Destugues
parent a1c86e7ada
commit c6c2c04284
46 changed files with 2072 additions and 528 deletions
+7 -7
View File
@@ -502,7 +502,7 @@ namespace agg
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
const trans_perspective& inline const trans_perspective&
trans_perspective::multiply_inv(const trans_perspective& m) trans_perspective::multiply_inv(const trans_perspective& m)
{ {
trans_perspective t = m; trans_perspective t = m;
@@ -511,7 +511,7 @@ namespace agg
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
const trans_perspective& inline const trans_perspective&
trans_perspective::multiply_inv(const trans_affine& m) trans_perspective::multiply_inv(const trans_affine& m)
{ {
trans_affine t = m; trans_affine t = m;
@@ -520,7 +520,7 @@ namespace agg
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
const trans_perspective& inline const trans_perspective&
trans_perspective::premultiply_inv(const trans_perspective& m) trans_perspective::premultiply_inv(const trans_perspective& m)
{ {
trans_perspective t = m; trans_perspective t = m;
@@ -529,7 +529,7 @@ namespace agg
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
const trans_perspective& inline const trans_perspective&
trans_perspective::premultiply_inv(const trans_affine& m) trans_perspective::premultiply_inv(const trans_affine& m)
{ {
trans_perspective t(m); trans_perspective t(m);
@@ -697,14 +697,14 @@ namespace agg
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
void trans_perspective::translation(double* dx, double* dy) const inline void trans_perspective::translation(double* dx, double* dy) const
{ {
*dx = tx; *dx = tx;
*dy = ty; *dy = ty;
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
void trans_perspective::scaling(double* x, double* y) const inline void trans_perspective::scaling(double* x, double* y) const
{ {
double x1 = 0.0; double x1 = 0.0;
double y1 = 0.0; double y1 = 0.0;
@@ -719,7 +719,7 @@ namespace agg
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
void trans_perspective::scaling_abs(double* x, double* y) const inline void trans_perspective::scaling_abs(double* x, double* y) const
{ {
*x = std::sqrt(sx * sx + shx * shx); *x = std::sqrt(sx * sx + shx * shx);
*y = std::sqrt(shy * shy + sy * sy); *y = std::sqrt(shy * shy + sy * sy);
+6 -1
View File
@@ -95,11 +95,12 @@ Application Icon-O-Matic :
# icon/transformer # icon/transformer
AffineTransformer.cpp AffineTransformer.cpp
CompoundStyleTransformer.cpp
ContourTransformer.cpp ContourTransformer.cpp
PathSource.cpp PathSource.cpp
PerspectiveTransformer.cpp PerspectiveTransformer.cpp
StrokeTransformer.cpp StrokeTransformer.cpp
Transformer.cpp StyleTransformer.cpp
TransformerFactory.cpp TransformerFactory.cpp
# icon # icon
@@ -275,6 +276,9 @@ Application Icon-O-Matic :
# transformable # transformable
CanvasTransformBox.cpp CanvasTransformBox.cpp
ChannelTransform.cpp ChannelTransform.cpp
PerspectiveBox.cpp
PerspectiveBoxStates.cpp
PerspectiveCommand.cpp
ResetTransformationCommand.cpp ResetTransformationCommand.cpp
TransformBox.cpp TransformBox.cpp
TransformBoxStates.cpp TransformBoxStates.cpp
@@ -349,6 +353,7 @@ DoCatalogs Icon-O-Matic :
RemoveStylesCommand.cpp RemoveStylesCommand.cpp
SetColorCommand.cpp SetColorCommand.cpp
SetGradientCommand.cpp SetGradientCommand.cpp
PerspectiveCommand.cpp
ResetTransformationCommand.cpp ResetTransformationCommand.cpp
TransformBoxStates.cpp TransformBoxStates.cpp
TransformerFactory.cpp TransformerFactory.cpp
+18 -1
View File
@@ -59,6 +59,8 @@
#include "MessengerSaver.h" #include "MessengerSaver.h"
#include "NativeSaver.h" #include "NativeSaver.h"
#include "PathListView.h" #include "PathListView.h"
#include "PerspectiveBox.h"
#include "PerspectiveTransformer.h"
#include "RDefExporter.h" #include "RDefExporter.h"
#include "ScrollView.h" #include "ScrollView.h"
#include "SimpleFileSaver.h" #include "SimpleFileSaver.h"
@@ -105,6 +107,7 @@ enum {
MSG_PATH_SELECTED = 'vpsl', MSG_PATH_SELECTED = 'vpsl',
MSG_STYLE_SELECTED = 'stsl', MSG_STYLE_SELECTED = 'stsl',
MSG_SHAPE_SELECTED = 'spsl', MSG_SHAPE_SELECTED = 'spsl',
MSG_TRANSFORMER_SELECTED = 'trsl',
MSG_SHAPE_RESET_TRANSFORMATION = 'rtsh', MSG_SHAPE_RESET_TRANSFORMATION = 'rtsh',
MSG_STYLE_RESET_TRANSFORMATION = 'rtst', MSG_STYLE_RESET_TRANSFORMATION = 'rtst',
@@ -562,6 +565,20 @@ case MSG_SHAPE_SELECTED: {
fState->AddManipulator(transformBox); fState->AddManipulator(transformBox);
} }
break; break;
}
case MSG_TRANSFORMER_SELECTED: {
Transformer* transformer;
if (message->FindPointer("transformer", (void**)&transformer) < B_OK)
transformer = NULL;
fState->DeleteManipulators();
PerspectiveTransformer* perspectiveTransformer =
dynamic_cast<PerspectiveTransformer*>(transformer);
if (perspectiveTransformer != NULL) {
PerspectiveBox* transformBox = new (nothrow) PerspectiveBox(
fCanvasView, perspectiveTransformer);
fState->AddManipulator(transformBox);
}
} }
case MSG_RENAME_OBJECT: case MSG_RENAME_OBJECT:
fPropertyListView->FocusNameProperty(); fPropertyListView->FocusNameProperty();
@@ -1087,7 +1104,7 @@ MainWindow::_CreateGUI()
fShapeListView = new ShapeListView(BRect(0, 0, splitWidth, 100), fShapeListView = new ShapeListView(BRect(0, 0, splitWidth, 100),
"shape list view", new BMessage(MSG_SHAPE_SELECTED), this); "shape list view", new BMessage(MSG_SHAPE_SELECTED), this);
fTransformerListView = new TransformerListView(BRect(0, 0, splitWidth, 100), fTransformerListView = new TransformerListView(BRect(0, 0, splitWidth, 100),
"transformer list view"); "transformer list view", new BMessage(MSG_TRANSFORMER_SELECTED), this);
fPropertyListView = new IconObjectListView(); fPropertyListView = new IconObjectListView();
BLayoutBuilder::Split<>(leftSideView) BLayoutBuilder::Split<>(leftSideView)
@@ -43,6 +43,9 @@ class IconObject : public Observable,
const char* Name() const const char* Name() const
{ return fName.String(); } { return fName.String(); }
// TODO: let IconObject control its own manipulators?
// This would allow VectorPaths to control their own PathManipulator,
// Styles to control their own TransformGradientBox, etc.
private: private:
BString fName; BString fName;
}; };
@@ -201,8 +201,7 @@ TransformerListView::MessageReceived(BMessage* message)
break; break;
Transformer* transformer Transformer* transformer
= TransformerFactory::TransformerFor(type, = TransformerFactory::TransformerFor(type, fShape->VertexSource(), fShape);
fShape->VertexSource());
if (!transformer) if (!transformer)
break; break;
@@ -396,9 +395,9 @@ TransformerListView::SetMenu(BMenu* menu)
message->AddInt32("type", STROKE_TRANSFORMER); message->AddInt32("type", STROKE_TRANSFORMER);
fStrokeMI = new BMenuItem(B_TRANSLATE("Stroke"), message); fStrokeMI = new BMenuItem(B_TRANSLATE("Stroke"), message);
// message = new BMessage(MSG_ADD_TRANSFORMER); message = new BMessage(MSG_ADD_TRANSFORMER);
// message->AddInt32("type", PERSPECTIVE_TRANSFORMER); message->AddInt32("type", PERSPECTIVE_TRANSFORMER);
// fPerspectiveMI = new BMenuItem(B_TRANSLATE("Perspective"), message); fPerspectiveMI = new BMenuItem(B_TRANSLATE("Perspective"), message);
// message = new BMessage(MSG_ADD_TRANSFORMER); // message = new BMessage(MSG_ADD_TRANSFORMER);
// message->AddInt32("type", AFFINE_TRANSFORMER); // message->AddInt32("type", AFFINE_TRANSFORMER);
@@ -408,6 +407,7 @@ TransformerListView::SetMenu(BMenu* menu)
addMenu->AddItem(fContourMI); addMenu->AddItem(fContourMI);
addMenu->AddItem(fStrokeMI); addMenu->AddItem(fStrokeMI);
addMenu->AddItem(fPerspectiveMI);
addMenu->SetTargetForItems(this); addMenu->SetTargetForItems(this);
fMenu->AddItem(addMenu); fMenu->AddItem(addMenu);
@@ -82,6 +82,7 @@ class TransformerListView : public SimpleListView,
BMenu* fMenu; BMenu* fMenu;
BMenuItem* fContourMI; BMenuItem* fContourMI;
BMenuItem* fStrokeMI; BMenuItem* fStrokeMI;
BMenuItem* fPerspectiveMI;
}; };
#endif // TRANSFORMER_LIST_VIEW_H #endif // TRANSFORMER_LIST_VIEW_H
@@ -483,11 +483,17 @@ _WriteTransformer(LittleEndianBuffer& buffer, Transformer* t)
|| !buffer.Write(miterLimit)) || !buffer.Write(miterLimit))
return false; return false;
} else if (dynamic_cast<PerspectiveTransformer*>(t)) { } else if (PerspectiveTransformer* perspective
= dynamic_cast<PerspectiveTransformer*>(t)) {
// perspective // perspective
if (!buffer.Write((uint8)TRANSFORMER_TYPE_PERSPECTIVE)) if (!buffer.Write((uint8)TRANSFORMER_TYPE_PERSPECTIVE))
return false; return false;
// TODO: ... (upgrade AGG for storage support of trans_perspective) double matrix[9];
perspective->store_to(matrix);
for (int32 i = 0; i < 9; i++) {
if (!write_float_24(buffer, (float)matrix[i]))
return false;
}
} else if (StrokeTransformer* stroke } else if (StrokeTransformer* stroke
= dynamic_cast<StrokeTransformer*>(t)) { = dynamic_cast<StrokeTransformer*>(t)) {
@@ -29,7 +29,7 @@ struct style_map {
/*! Turns text into its associated paths and shapes. /*! Turns text into its associated paths and shapes.
Coloring can also be imported from applications, such as StyledEdit, that Coloring can also be imported from applications, such as StyledEdit, that
specify it. specify it in a supported format.
*/ */
class StyledTextImporter : public Importer { class StyledTextImporter : public Importer {
public: public:
@@ -0,0 +1,449 @@
/*
* Copyright 2006-2009, 2023, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#include "PerspectiveBox.h"
#include <stdio.h>
#include <agg_trans_affine.h>
#include <agg_math.h>
#include <View.h>
#include "CanvasView.h"
#include "StateView.h"
#include "support.h"
#include "PerspectiveBoxStates.h"
#include "PerspectiveCommand.h"
#include "PerspectiveTransformer.h"
#define INSET 8.0
using std::nothrow;
using namespace PerspectiveBoxStates;
PerspectiveBox::PerspectiveBox(CanvasView* view,
PerspectiveTransformer* parent)
:
Manipulator(NULL),
fLeftTop(parent->LeftTop()),
fRightTop(parent->RightTop()),
fLeftBottom(parent->LeftBottom()),
fRightBottom(parent->RightBottom()),
fCurrentCommand(NULL),
fCurrentState(NULL),
fDragging(false),
fMousePos(-10000.0, -10000.0),
fModifiers(0),
fPreviousBox(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN),
fCanvasView(view),
fPerspective(parent),
fDragLTState(new DragCornerState(this, &fLeftTop)),
fDragRTState(new DragCornerState(this, &fRightTop)),
fDragLBState(new DragCornerState(this, &fLeftBottom)),
fDragRBState(new DragCornerState(this, &fRightBottom))
{
}
PerspectiveBox::~PerspectiveBox()
{
_NotifyDeleted();
delete fCurrentCommand;
delete fDragLTState;
delete fDragRTState;
delete fDragLBState;
delete fDragRBState;
}
void
PerspectiveBox::Draw(BView* into, BRect updateRect)
{
// convert to canvas view coordinates
BPoint lt = fLeftTop;
BPoint rt = fRightTop;
BPoint lb = fLeftBottom;
BPoint rb = fRightBottom;
fCanvasView->ConvertFromCanvas(&lt);
fCanvasView->ConvertFromCanvas(&rt);
fCanvasView->ConvertFromCanvas(&lb);
fCanvasView->ConvertFromCanvas(&rb);
into->SetDrawingMode(B_OP_COPY);
into->SetHighColor(255, 255, 255, 255);
into->SetLowColor(0, 0, 0, 255);
_StrokeBWLine(into, lt, rt);
_StrokeBWLine(into, rt, rb);
_StrokeBWLine(into, rb, lb);
_StrokeBWLine(into, lb, lt);
_StrokeBWPoint(into, lt, 0.0);
_StrokeBWPoint(into, rt, 90.0);
_StrokeBWPoint(into, rb, 180.0);
_StrokeBWPoint(into, lb, 270.0);
}
// #pragma mark -
bool
PerspectiveBox::MouseDown(BPoint where)
{
fCanvasView->FilterMouse(&where);
fCanvasView->ConvertToCanvas(&where);
fDragging = true;
if (fCurrentState) {
fCurrentState->SetOrigin(where);
delete fCurrentCommand;
fCurrentCommand = new (nothrow) PerspectiveCommand(this, fPerspective,
fPerspective->LeftTop(), fPerspective->RightTop(),
fPerspective->LeftBottom(), fPerspective->RightBottom());
}
return true;
}
void
PerspectiveBox::MouseMoved(BPoint where)
{
fCanvasView->FilterMouse(&where);
fCanvasView->ConvertToCanvas(&where);
if (fMousePos != where) {
fMousePos = where;
if (fCurrentState) {
fCurrentState->DragTo(fMousePos, fModifiers);
fCurrentState->UpdateViewCursor(fCanvasView, fMousePos);
}
}
}
Command*
PerspectiveBox::MouseUp()
{
fDragging = false;
return FinishTransaction();
}
bool
PerspectiveBox::MouseOver(BPoint where)
{
fCanvasView->ConvertToCanvas(&where);
fMousePos = where;
fCurrentState = _DragStateFor(where, fCanvasView->ZoomLevel());
if (fCurrentState) {
fCurrentState->UpdateViewCursor(fCanvasView, fMousePos);
return true;
}
return false;
}
// #pragma mark -
BRect
PerspectiveBox::Bounds()
{
// convert from canvas view coordinates
BPoint lt = fLeftTop;
BPoint rt = fRightTop;
BPoint lb = fLeftBottom;
BPoint rb = fRightBottom;
fCanvasView->ConvertFromCanvas(&lt);
fCanvasView->ConvertFromCanvas(&rt);
fCanvasView->ConvertFromCanvas(&lb);
fCanvasView->ConvertFromCanvas(&rb);
BRect bounds;
bounds.left = min4(lt.x, rt.x, lb.x, rb.x);
bounds.top = min4(lt.y, rt.y, lb.y, rb.y);
bounds.right = max4(lt.x, rt.x, lb.x, rb.x);
bounds.bottom = max4(lt.y, rt.y, lb.y, rb.y);
return bounds;
}
BRect
PerspectiveBox::TrackingBounds(BView* withinView)
{
return withinView->Bounds();
}
// #pragma mark -
void
PerspectiveBox::ModifiersChanged(uint32 modifiers)
{
fModifiers = modifiers;
if (fDragging && fCurrentState) {
fCurrentState->DragTo(fMousePos, fModifiers);
}
}
bool
PerspectiveBox::UpdateCursor()
{
if (fCurrentState) {
fCurrentState->UpdateViewCursor(fCanvasView, fMousePos);
return true;
}
return false;
}
// #pragma mark -
void
PerspectiveBox::AttachedToView(BView* view)
{
view->Invalidate(Bounds().InsetByCopy(-INSET, -INSET));
}
void
PerspectiveBox::DetachedFromView(BView* view)
{
view->Invalidate(Bounds().InsetByCopy(-INSET, -INSET));
}
// pragma mark -
void
PerspectiveBox::ObjectChanged(const Observable* object)
{
}
// pragma mark -
void
PerspectiveBox::TransformTo(
BPoint leftTop, BPoint rightTop, BPoint leftBottom, BPoint rightBottom)
{
if (fLeftTop == leftTop
&& fRightTop == rightTop
&& fLeftBottom == leftBottom
&& fRightBottom == rightBottom)
return;
fLeftTop = leftTop;
fRightTop = rightTop;
fLeftBottom = leftBottom;
fRightBottom = rightBottom;
Update();
}
void
PerspectiveBox::Update(bool deep)
{
BRect r = Bounds();
BRect dirty(r | fPreviousBox);
dirty.InsetBy(-INSET, -INSET);
fCanvasView->Invalidate(dirty);
fPreviousBox = r;
if (deep)
fPerspective->TransformTo(fLeftTop, fRightTop, fLeftBottom, fRightBottom);
}
Command*
PerspectiveBox::FinishTransaction()
{
Command* command = fCurrentCommand;
if (fCurrentCommand) {
fCurrentCommand->SetNewPerspective(
fPerspective->LeftTop(), fPerspective->RightTop(),
fPerspective->LeftBottom(), fPerspective->RightBottom());
fCurrentCommand = NULL;
}
return command;
}
// #pragma mark -
bool
PerspectiveBox::AddListener(PerspectiveBoxListener* listener)
{
if (listener && !fListeners.HasItem((void*)listener))
return fListeners.AddItem((void*)listener);
return false;
}
bool
PerspectiveBox::RemoveListener(PerspectiveBoxListener* listener)
{
return fListeners.RemoveItem((void*)listener);
}
// #pragma mark -
void
PerspectiveBox::_NotifyDeleted() const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
PerspectiveBoxListener* listener
= (PerspectiveBoxListener*)listeners.ItemAtFast(i);
listener->PerspectiveBoxDeleted(this);
}
}
//! where is expected in canvas view coordinates
DragState*
PerspectiveBox::_DragStateFor(BPoint where, float canvasZoom)
{
DragState* state = NULL;
// convert to canvas zoom level
//
// the conversion is necessary, because the "hot regions"
// around a point should be the same size no matter what
// zoom level the canvas is displayed at
float inset = INSET / canvasZoom;
// check if the cursor is over the corners
float dLT = point_point_distance(fLeftTop, where);
float dRT = point_point_distance(fRightTop, where);
float dLB = point_point_distance(fLeftBottom, where);
float dRB = point_point_distance(fRightBottom, where);
float d = min4(dLT, dRT, dLB, dRB);
if (d < inset) {
if (d == dLT)
state = fDragLTState;
else if (d == dRT)
state = fDragRTState;
else if (d == dLB)
state = fDragLBState;
else if (d == dRB)
state = fDragRBState;
}
return state;
}
void
PerspectiveBox::_StrokeBWLine(BView* into, BPoint from, BPoint to) const
{
// find out how to offset the second line optimally
BPoint offset(0.0, 0.0);
// first, do we have a more horizontal line or a more vertical line?
float xDiff = to.x - from.x;
float yDiff = to.y - from.y;
if (fabs(xDiff) > fabs(yDiff)) {
// horizontal
if (xDiff > 0.0) {
offset.y = -1.0;
} else {
offset.y = 1.0;
}
} else {
// vertical
if (yDiff < 0.0) {
offset.x = -1.0;
} else {
offset.x = 1.0;
}
}
// stroke two lines in high and low color of the view
into->StrokeLine(from, to, B_SOLID_LOW);
from += offset;
to += offset;
into->StrokeLine(from, to, B_SOLID_HIGH);
}
void
PerspectiveBox::_StrokeBWPoint(BView* into, BPoint point, double angle) const
{
double x = point.x;
double y = point.y;
double x1 = x;
double y1 = y - 5.0;
double x2 = x - 5.0;
double y2 = y - 5.0;
double x3 = x - 5.0;
double y3 = y;
agg::trans_affine m;
double xOffset = -x;
double yOffset = -y;
agg::trans_affine_rotation r(angle * M_PI / 180.0);
r.transform(&xOffset, &yOffset);
xOffset = x + xOffset;
yOffset = y + yOffset;
m.multiply(r);
m.multiply(agg::trans_affine_translation(xOffset, yOffset));
m.transform(&x, &y);
m.transform(&x1, &y1);
m.transform(&x2, &y2);
m.transform(&x3, &y3);
BPoint p[4];
p[0] = BPoint(x, y);
p[1] = BPoint(x1, y1);
p[2] = BPoint(x2, y2);
p[3] = BPoint(x3, y3);
into->FillPolygon(p, 4, B_SOLID_HIGH);
into->StrokeLine(p[0], p[1], B_SOLID_LOW);
into->StrokeLine(p[1], p[2], B_SOLID_LOW);
into->StrokeLine(p[2], p[3], B_SOLID_LOW);
into->StrokeLine(p[3], p[0], B_SOLID_LOW);
}
@@ -0,0 +1,115 @@
/*
* Copyright 2006-2007, 2023, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#ifndef PERSPECTIVE_BOX_H
#define PERSPECTIVE_BOX_H
#include <List.h>
#include <Point.h>
#include <Referenceable.h>
#include "Manipulator.h"
namespace PerspectiveBoxStates {
class DragState;
}
class CanvasView;
class Command;
class PerspectiveCommand;
class PerspectiveBox;
class PerspectiveTransformer;
class PerspectiveBoxListener {
public:
PerspectiveBoxListener() {}
virtual ~PerspectiveBoxListener() {}
virtual void PerspectiveBoxDeleted(
const PerspectiveBox* box) = 0;
};
class PerspectiveBox : public Manipulator {
public:
PerspectiveBox(CanvasView* view,
PerspectiveTransformer* parent);
virtual ~PerspectiveBox();
// Manipulator interface
virtual void Draw(BView* into, BRect updateRect);
virtual bool MouseDown(BPoint where);
virtual void MouseMoved(BPoint where);
virtual Command* MouseUp();
virtual bool MouseOver(BPoint where);
virtual BRect Bounds();
virtual BRect TrackingBounds(BView* withinView);
virtual void ModifiersChanged(uint32 modifiers);
virtual bool UpdateCursor();
virtual void AttachedToView(BView* view);
virtual void DetachedFromView(BView* view);
// Observer interface
virtual void ObjectChanged(const Observable* object);
// PerspectiveTransformBox
void TransformTo(BPoint leftTop, BPoint rightTop,
BPoint leftBottom, BPoint rightBottom);
virtual void Update(bool deep = true);
Command* FinishTransaction();
// Listener support
bool AddListener(PerspectiveBoxListener* listener);
bool RemoveListener(PerspectiveBoxListener* listener);
private:
void _NotifyDeleted() const;
PerspectiveBoxStates::DragState* _DragStateFor(
BPoint canvasWhere, float canvasZoom);
void _StrokeBWLine(BView* into,
BPoint from, BPoint to) const;
void _StrokeBWPoint(BView* into,
BPoint point, double angle) const;
private:
BPoint fLeftTop;
BPoint fRightTop;
BPoint fLeftBottom;
BPoint fRightBottom;
PerspectiveCommand* fCurrentCommand;
PerspectiveBoxStates::DragState* fCurrentState;
bool fDragging;
BPoint fMousePos;
uint32 fModifiers;
BList fListeners;
BRect fPreviousBox;
// "static" state objects
CanvasView* fCanvasView;
BReference<PerspectiveTransformer> fPerspective;
PerspectiveBoxStates::DragState* fDragLTState;
PerspectiveBoxStates::DragState* fDragRTState;
PerspectiveBoxStates::DragState* fDragLBState;
PerspectiveBoxStates::DragState* fDragRBState;
};
#endif // PERSPECTIVE_BOX_H
@@ -0,0 +1,68 @@
/*
* Copyright 2006-2009, 2023, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#include "PerspectiveBoxStates.h"
#include <Cursor.h>
#include <View.h>
#include "cursors.h"
#include "PerspectiveBox.h"
using namespace PerspectiveBoxStates;
DragState::DragState(PerspectiveBox* parent)
:
fOrigin(0.0, 0.0),
fParent(parent)
{
}
void
DragState::_SetViewCursor(BView* view, const uchar* cursorData) const
{
BCursor cursor(cursorData);
view->SetViewCursor(&cursor);
}
// #pragma mark - DragCornerState
DragCornerState::DragCornerState(PerspectiveBox* parent, BPoint* point)
:
DragState(parent),
fPoint(point)
{
}
void
DragCornerState::SetOrigin(BPoint origin)
{
DragState::SetOrigin(origin);
}
void
DragCornerState::DragTo(BPoint current, uint32 modifiers)
{
*fPoint = current;
fParent->Update(true);
}
void
DragCornerState::UpdateViewCursor(BView* view, BPoint current) const
{
_SetViewCursor(view, kPathMoveCursor);
}
@@ -0,0 +1,58 @@
/*
* Copyright 2006, 2023, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#ifndef PERSPECTIVE_BOX_STATES_H
#define PERSPECTIVE_BOX_STATES_H
#include <Point.h>
class BView;
class PerspectiveBox;
namespace PerspectiveBoxStates {
class DragState {
public:
DragState(PerspectiveBox* parent);
virtual ~DragState() {}
virtual void SetOrigin(BPoint origin)
{ fOrigin = origin; }
virtual void DragTo(BPoint current, uint32 modifiers) = 0;
virtual void UpdateViewCursor(BView* view, BPoint current) const = 0;
protected:
void _SetViewCursor(BView* view,
const uchar* cursorData) const;
BPoint fOrigin;
PerspectiveBox* fParent;
};
class DragCornerState : public DragState {
public:
DragCornerState(
PerspectiveBox* parent, BPoint* point);
virtual ~DragCornerState() {}
virtual void SetOrigin(BPoint origin);
virtual void DragTo(BPoint current, uint32 modifiers);
virtual void UpdateViewCursor(BView* view, BPoint current) const;
private:
BPoint* fPoint;
BPoint fOldOffset;
};
} // PerspectiveBoxStates namespace
#endif // PERSPECTIVE_BOX_STATES_H
@@ -0,0 +1,141 @@
/*
* Copyright 2006-2010, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2006-2009, 2023, Haiku.
* All rights reserved. Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#include "PerspectiveCommand.h"
#include <Catalog.h>
#include <Locale.h>
#include "PerspectiveTransformer.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Icon-O-Matic-PerspectiveCommand"
PerspectiveCommand::PerspectiveCommand(PerspectiveBox* box,
PerspectiveTransformer* transformer, BPoint leftTop, BPoint rightTop
, BPoint leftBottom, BPoint rightBottom)
: fTransformBox(box),
fTransformer(transformer),
fOldLeftTop(leftTop),
fOldRightTop(rightTop),
fOldLeftBottom(leftBottom),
fOldRightBottom(rightBottom),
fNewLeftTop(leftTop),
fNewRightTop(rightTop),
fNewLeftBottom(leftBottom),
fNewRightBottom(rightBottom)
{
if (fTransformer == NULL)
return;
fTransformer->AcquireReference();
if (fTransformBox != NULL)
fTransformBox->AddListener(this);
}
PerspectiveCommand::~PerspectiveCommand()
{
if (fTransformer != NULL)
fTransformer->ReleaseReference();
if (fTransformBox != NULL)
fTransformBox->RemoveListener(this);
}
// pragma mark -
status_t
PerspectiveCommand::InitCheck()
{
if (fTransformer != NULL
&& (fOldLeftTop != fNewLeftTop
|| fOldRightTop != fNewRightTop
|| fOldLeftBottom != fNewLeftBottom
|| fOldRightBottom != fNewRightBottom))
return B_OK;
return B_NO_INIT;
}
status_t
PerspectiveCommand::Perform()
{
// objects are already transformed
return B_OK;
}
status_t
PerspectiveCommand::Undo()
{
if (fTransformBox != NULL) {
fTransformBox->TransformTo(fOldLeftTop, fOldRightTop, fOldLeftBottom, fOldRightBottom);
return B_OK;
}
fTransformer->TransformTo(fOldLeftTop, fOldRightTop, fOldLeftBottom, fOldRightBottom);
return B_OK;
}
status_t
PerspectiveCommand::Redo()
{
if (fTransformBox != NULL) {
fTransformBox->TransformTo(fNewLeftTop, fNewRightTop, fNewLeftBottom, fNewRightBottom);
return B_OK;
}
fTransformer->TransformTo(fNewLeftTop, fNewRightTop, fNewLeftBottom, fNewRightBottom);
return B_OK;
}
void
PerspectiveCommand::GetName(BString& name)
{
name << B_TRANSLATE("Change perspective");
}
// pragma mark -
void
PerspectiveCommand::PerspectiveBoxDeleted(const PerspectiveBox* box)
{
if (fTransformBox == box) {
if (fTransformBox != NULL)
fTransformBox->RemoveListener(this);
fTransformBox = NULL;
}
}
// #pragma mark -
void
PerspectiveCommand::SetNewPerspective(
BPoint leftTop, BPoint rightTop, BPoint leftBottom, BPoint rightBottom)
{
fNewLeftTop = leftTop;
fNewRightTop = rightTop;
fNewLeftBottom = leftBottom;
fNewRightBottom = rightBottom;
}
@@ -0,0 +1,63 @@
/*
* Copyright 2006, 2023, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#ifndef PERSPECTIVE_COMMAND_H
#define PERSPECTIVE_COMMAND_H
#include <Point.h>
#include "Command.h"
#include "PerspectiveBox.h"
class PerspectiveTransformer;
class PerspectiveCommand : public Command, public PerspectiveBoxListener {
public:
PerspectiveCommand(PerspectiveBox* box,
PerspectiveTransformer* transformer,
BPoint leftTop, BPoint rightTop,
BPoint leftBottom, BPoint rightBottom);
virtual ~PerspectiveCommand();
// Command interface
virtual status_t InitCheck();
virtual status_t Perform();
virtual status_t Undo();
virtual status_t Redo();
virtual void GetName(BString& name);
// TransformBoxListener interface
virtual void PerspectiveBoxDeleted(const PerspectiveBox* box);
// PerspectiveCommand
void SetNewPerspective(
BPoint leftTop, BPoint rightTop,
BPoint leftBottom, BPoint rightBottom);
private:
PerspectiveBox* fTransformBox;
PerspectiveTransformer* fTransformer;
BPoint fOldLeftTop;
BPoint fOldRightTop;
BPoint fOldLeftBottom;
BPoint fOldRightBottom;
BPoint fNewLeftTop;
BPoint fNewRightTop;
BPoint fNewLeftBottom;
BPoint fNewRightBottom;
};
#endif // PERSPECTIVE_COMMAND_H
@@ -25,17 +25,7 @@
#define INSET 8.0 #define INSET 8.0
TransformBoxListener::TransformBoxListener() using namespace TransformBoxStates;
{
}
TransformBoxListener::~TransformBoxListener()
{
}
// #pragma mark -
// constructor // constructor
@@ -152,7 +142,6 @@ bool
TransformBox::MouseDown(BPoint where) TransformBox::MouseDown(BPoint where)
{ {
fView->FilterMouse(&where); fView->FilterMouse(&where);
// NOTE: filter mouse here and in MouseMoved only
TransformToCanvas(where); TransformToCanvas(where);
fDragging = true; fDragging = true;
@@ -172,7 +161,6 @@ void
TransformBox::MouseMoved(BPoint where) TransformBox::MouseMoved(BPoint where)
{ {
fView->FilterMouse(&where); fView->FilterMouse(&where);
// NOTE: filter mouse here and in MouseDown only
TransformToCanvas(where); TransformToCanvas(where);
if (fMousePos != where) { if (fMousePos != where) {
@@ -236,12 +224,12 @@ TransformBox::Bounds()
TransformFromCanvas(rb); TransformFromCanvas(rb);
TransformFromCanvas(c); TransformFromCanvas(c);
BRect r; BRect bounds;
r.left = min5(lt.x, rt.x, lb.x, rb.x, c.x); bounds.left = min5(lt.x, rt.x, lb.x, rb.x, c.x);
r.top = min5(lt.y, rt.y, lb.y, rb.y, c.y); bounds.top = min5(lt.y, rt.y, lb.y, rb.y, c.y);
r.right = max5(lt.x, rt.x, lb.x, rb.x, c.x); bounds.right = max5(lt.x, rt.x, lb.x, rb.x, c.x);
r.bottom = max5(lt.y, rt.y, lb.y, rb.y, c.y); bounds.bottom = max5(lt.y, rt.y, lb.y, rb.y, c.y);
return r; return bounds;
} }
@@ -5,7 +5,6 @@
* Authors: * Authors:
* Stephan Aßmus <superstippi@gmx.de> * Stephan Aßmus <superstippi@gmx.de>
*/ */
#ifndef TRANSFORM_BOX_H #ifndef TRANSFORM_BOX_H
#define TRANSFORM_BOX_H #define TRANSFORM_BOX_H
@@ -14,16 +13,21 @@
#include "ChannelTransform.h" #include "ChannelTransform.h"
#include "Manipulator.h" #include "Manipulator.h"
namespace TransformBoxStates {
class DragState;
}
class Command; class Command;
class StateView; class StateView;
class DragState;
class TransformBox; class TransformBox;
class TransformCommand; class TransformCommand;
class TransformBoxListener { class TransformBoxListener {
public: public:
TransformBoxListener(); TransformBoxListener() {}
virtual ~TransformBoxListener(); virtual ~TransformBoxListener() {}
virtual void TransformBoxDeleted( virtual void TransformBoxDeleted(
const TransformBox* box) = 0; const TransformBox* box) = 0;
@@ -31,9 +35,8 @@ class TransformBoxListener {
class TransformBox : public ChannelTransform, class TransformBox : public ChannelTransform,
public Manipulator { public Manipulator {
public: public:
TransformBox(StateView* view, TransformBox(StateView* view, BRect box);
BRect box);
virtual ~TransformBox(); virtual ~TransformBox();
// Manipulator interface // Manipulator interface
@@ -49,10 +52,10 @@ class TransformBox : public ChannelTransform,
virtual BRect TrackingBounds(BView* withinView); virtual BRect TrackingBounds(BView* withinView);
virtual void ModifiersChanged(uint32 modifiers); virtual void ModifiersChanged(uint32 modifiers);
virtual bool HandleKeyDown(uint32 key, uint32 modifiers, virtual bool HandleKeyDown(uint32 key,
Command** _command); uint32 modifiers, Command** _command);
virtual bool HandleKeyUp(uint32 key, uint32 modifiers, virtual bool HandleKeyUp(uint32 key,
Command** _command); uint32 modifiers, Command** _command);
virtual bool UpdateCursor(); virtual bool UpdateCursor();
@@ -90,15 +93,15 @@ class TransformBox : public ChannelTransform,
bool AddListener(TransformBoxListener* listener); bool AddListener(TransformBoxListener* listener);
bool RemoveListener(TransformBoxListener* listener); bool RemoveListener(TransformBoxListener* listener);
private: private:
DragState* _DragStateFor(BPoint canvasWhere, TransformBoxStates::DragState* _DragStateFor(
float canvasZoom); BPoint canvasWhere, float canvasZoom);
void _StrokeBWLine(BView* into, void _StrokeBWLine(BView* into,
BPoint from, BPoint to) const; BPoint from, BPoint to) const;
void _StrokeBWPoint(BView* into, void _StrokeBWPoint(BView* into,
BPoint point, BPoint point, double angle) const;
double angle) const;
private:
BRect fOriginalBox; BRect fOriginalBox;
BPoint fLeftTop; BPoint fLeftTop;
@@ -110,7 +113,7 @@ class TransformBox : public ChannelTransform,
BPoint fPivotOffset; BPoint fPivotOffset;
TransformCommand* fCurrentCommand; TransformCommand* fCurrentCommand;
DragState* fCurrentState; TransformBoxStates::DragState* fCurrentState;
bool fDragging; bool fDragging;
BPoint fMousePos; BPoint fMousePos;
@@ -120,25 +123,25 @@ class TransformBox : public ChannelTransform,
BList fListeners; BList fListeners;
protected: protected:
void _NotifyDeleted() const; void _NotifyDeleted() const;
// "static" state objects // "static" state objects
StateView* fView; StateView* fView;
DragState* fDragLTState; TransformBoxStates::DragState* fDragLTState;
DragState* fDragRTState; TransformBoxStates::DragState* fDragRTState;
DragState* fDragLBState; TransformBoxStates::DragState* fDragLBState;
DragState* fDragRBState; TransformBoxStates::DragState* fDragRBState;
DragState* fDragLState; TransformBoxStates::DragState* fDragLState;
DragState* fDragRState; TransformBoxStates::DragState* fDragRState;
DragState* fDragTState; TransformBoxStates::DragState* fDragTState;
DragState* fDragBState; TransformBoxStates::DragState* fDragBState;
DragState* fRotateState; TransformBoxStates::DragState* fRotateState;
DragState* fTranslateState; TransformBoxStates::DragState* fTranslateState;
DragState* fOffsetCenterState; TransformBoxStates::DragState* fOffsetCenterState;
}; };
#endif // TRANSFORM_BOX_H #endif // TRANSFORM_BOX_H
@@ -10,17 +10,14 @@
#include "TransformBoxStates.h" #include "TransformBoxStates.h"
#include <math.h> #include <math.h>
#include <stdio.h>
#include <Catalog.h> #include <Catalog.h>
#include <Cursor.h> #include <Cursor.h>
#include <InterfaceDefs.h>
#include <Locale.h> #include <Locale.h>
#include <View.h> #include <View.h>
#include "cursors.h" #include "cursors.h"
#include "support.h" #include "support.h"
#include "TransformBox.h" #include "TransformBox.h"
@@ -28,6 +25,9 @@
#define B_TRANSLATION_CONTEXT "Icon-O-Matic-TransformationBoxStates" #define B_TRANSLATION_CONTEXT "Icon-O-Matic-TransformationBoxStates"
using namespace TransformBoxStates;
DragState::DragState(TransformBox* parent) DragState::DragState(TransformBox* parent)
: :
fOrigin(0.0, 0.0), fOrigin(0.0, 0.0),
@@ -36,13 +36,6 @@ DragState::DragState(TransformBox* parent)
} }
void
DragState::SetOrigin(BPoint origin)
{
fOrigin = origin;
}
const char* const char*
DragState::ActionName() const DragState::ActionName() const
{ {
@@ -14,16 +14,21 @@
#include <agg_trans_affine.h> #include <agg_trans_affine.h>
class BView; class BView;
class TransformBox; class TransformBox;
namespace TransformBoxStates {
// base class // base class
class DragState { class DragState {
public: public:
DragState(TransformBox* parent); DragState(TransformBox* parent);
virtual ~DragState() {} virtual ~DragState() {}
virtual void SetOrigin(BPoint origin); virtual void SetOrigin(BPoint origin)
{ fOrigin = origin; }
virtual void DragTo(BPoint current, uint32 modifiers) = 0; virtual void DragTo(BPoint current, uint32 modifiers) = 0;
virtual void UpdateViewCursor(BView* view, BPoint current) const = 0; virtual void UpdateViewCursor(BView* view, BPoint current) const = 0;
@@ -142,4 +147,6 @@ class OffsetCenterState : public DragState {
virtual const char* ActionName() const; virtual const char* ActionName() const;
}; };
} // TransformBoxStates namespace
#endif // TRANSFORM_BOX_STATES_H #endif // TRANSFORM_BOX_STATES_H
+2 -1
View File
@@ -52,11 +52,12 @@ BuildPlatformMergeObjectPIC <libbe_build>icon_kit.o :
# transformer # transformer
AffineTransformer.cpp AffineTransformer.cpp
CompoundStyleTransformer.cpp
ContourTransformer.cpp ContourTransformer.cpp
PathSource.cpp PathSource.cpp
PerspectiveTransformer.cpp PerspectiveTransformer.cpp
StrokeTransformer.cpp StrokeTransformer.cpp
Transformer.cpp StyleTransformer.cpp
TransformerFactory.cpp TransformerFactory.cpp
Icon.cpp Icon.cpp
+2 -1
View File
@@ -50,11 +50,12 @@ BuildPlatformStaticLibrary libicon_build.a :
# transformer # transformer
AffineTransformer.cpp AffineTransformer.cpp
CompoundStyleTransformer.cpp
ContourTransformer.cpp ContourTransformer.cpp
PathSource.cpp PathSource.cpp
PerspectiveTransformer.cpp PerspectiveTransformer.cpp
StrokeTransformer.cpp StrokeTransformer.cpp
Transformer.cpp StyleTransformer.cpp
TransformerFactory.cpp TransformerFactory.cpp
Icon.cpp Icon.cpp
+210 -112
View File
@@ -20,108 +20,142 @@
#include <agg_span_image_filter_rgba.h> #include <agg_span_image_filter_rgba.h>
#include <agg_span_gradient.h> #include <agg_span_gradient.h>
#include <agg_span_interpolator_linear.h> #include <agg_span_interpolator_linear.h>
#include <agg_span_interpolator_trans.h>
#include "CompoundStyleTransformer.h"
#include "GradientTransformable.h" #include "GradientTransformable.h"
#include "Icon.h" #include "Icon.h"
#include "Shape.h" #include "Shape.h"
#include "Style.h" #include "Style.h"
#include "StyleTransformer.h"
#include "VectorPath.h" #include "VectorPath.h"
using std::nothrow; using std::nothrow;
class IconRenderer::StyleHandler { class IconRenderer::StyleHandler {
struct StyleItem { struct StyleItem {
Style* style; const Style* style;
Transformation transformation; StyleTransformer* transformer;
}; };
public: public:
#ifdef ICON_O_MATIC #ifdef ICON_O_MATIC
StyleHandler(::GammaTable& gammaTable, bool showReferences) StyleHandler(::GammaTable& gammaTable,
: fStyles(20), bool showReferences);
fGammaTable(gammaTable),
fShowReferences(showReferences),
fTransparent(0, 0, 0, 0),
fColor(0, 0, 0, 0)
{}
#else #else
StyleHandler(::GammaTable& gammaTable) StyleHandler(::GammaTable& gammaTable);
: fStyles(20),
fGammaTable(gammaTable),
fTransparent(0, 0, 0, 0),
fColor(0, 0, 0, 0)
{}
#endif // ICON_O_MATIC
~StyleHandler()
{
int32 count = fStyles.CountItems();
for (int32 i = 0; i < count; i++)
delete (StyleItem*)fStyles.ItemAtFast(i);
}
bool is_solid(unsigned styleIndex) const
{
StyleItem* styleItem = (StyleItem*)fStyles.ItemAt(styleIndex);
if (!styleItem)
return true;
if (styleItem->style->Gradient())
return false;
#ifdef ICON_O_MATIC
if (styleItem->style->Bitmap() && fShowReferences)
return false;
#endif // ICON_O_MATIC
return true;
}
const agg::rgba8& color(unsigned styleIndex);
void generate_span(agg::rgba8* span, int x, int y,
unsigned len, unsigned styleIndex);
bool AddStyle(Style* style, const Transformation& transformation)
{
if (!style)
return false;
StyleItem* item = new (nothrow) StyleItem;
if (!item)
return false;
item->style = style;
// if the style uses a gradient, the transformation
// is based on the gradient transformation
if (Gradient* gradient = style->Gradient()) {
item->transformation = *gradient;
item->transformation.multiply(transformation);
} else {
item->transformation = transformation;
}
item->transformation.invert();
return fStyles.AddItem((void*)item);
}
private:
template<class GradientFunction>
void _GenerateGradient(agg::rgba8* span, int x, int y, unsigned len,
GradientFunction function, int32 start, int32 end,
const agg::rgba8* gradientColors, Transformation& gradientTransform);
#ifdef ICON_O_MATIC
void _GenerateImage(agg::rgba8* span, int x, int y,
unsigned len, Style* style, Transformation& transform);
#endif #endif
BList fStyles; ~StyleHandler();
::GammaTable& fGammaTable;
bool AddStyle(const Style* style,
const Transformable& transformation,
const Container<Transformer>* transformers);
bool is_solid(unsigned styleIndex) const;
const agg::rgba8& color(unsigned styleIndex);
void generate_span(agg::rgba8* span, int x, int y,
unsigned len, unsigned styleIndex);
private:
StyleTransformer* _MergeTransformers(
const Transformable* styleTransformation,
const Container<Transformer>* transformers,
const Transformable* shapeTransformation);
template<class GradientFunction>
void _GenerateGradient(agg::rgba8* span,
int x, int y, unsigned len,
GradientFunction function,
int32 start, int32 end,
const agg::rgba8* gradientColors,
StyleTransformer* transformer);
#ifdef ICON_O_MATIC #ifdef ICON_O_MATIC
bool fShowReferences; void _GenerateImage(agg::rgba8* span,
int x, int y, unsigned len,
const Style* style,
StyleTransformer* transformer);
#endif #endif
agg::rgba8 fTransparent;
agg::rgba8 fColor; private:
BList fStyles;
::GammaTable& fGammaTable;
#ifdef ICON_O_MATIC
bool fShowReferences;
#endif
agg::rgba8 fTransparent;
agg::rgba8 fColor;
}; };
#ifdef ICON_O_MATIC
IconRenderer::StyleHandler::StyleHandler(::GammaTable& gammaTable, bool showReferences)
: fStyles(20),
fGammaTable(gammaTable),
fShowReferences(showReferences),
fTransparent(0, 0, 0, 0),
fColor(0, 0, 0, 0)
{}
#else
IconRenderer::StyleHandler::StyleHandler(::GammaTable& gammaTable)
: fStyles(20),
fGammaTable(gammaTable),
fTransparent(0, 0, 0, 0),
fColor(0, 0, 0, 0)
{}
#endif
IconRenderer::StyleHandler::~StyleHandler()
{
int32 count = fStyles.CountItems();
for (int32 i = 0; i < count; i++) {
StyleItem* item = (StyleItem*)fStyles.ItemAtFast(i);
delete item->transformer;
delete item;
}
}
bool
IconRenderer::StyleHandler::AddStyle(const Style* style,
const Transformable& transformation, const Container<Transformer>* transformers)
{
if (!style)
return false;
StyleItem* item = new (nothrow) StyleItem;
if (!item)
return false;
item->style = style;
item->transformer = _MergeTransformers(style->Gradient(), transformers, &transformation);
item->transformer->Invert();
return fStyles.AddItem((void*)item);
}
bool
IconRenderer::StyleHandler::is_solid(unsigned styleIndex) const
{
StyleItem* styleItem = (StyleItem*)fStyles.ItemAt(styleIndex);
if (!styleItem)
return true;
if (styleItem->style->Gradient())
return false;
#ifdef ICON_O_MATIC
if (styleItem->style->Bitmap() && fShowReferences)
return false;
#endif // ICON_O_MATIC
return true;
}
const agg::rgba8& const agg::rgba8&
IconRenderer::StyleHandler::color(unsigned styleIndex) IconRenderer::StyleHandler::color(unsigned styleIndex)
{ {
@@ -164,12 +198,12 @@ IconRenderer::StyleHandler::generate_span(agg::rgba8* span, int x, int y,
#ifdef ICON_O_MATIC #ifdef ICON_O_MATIC
if (styleItem->style->Bitmap()) { if (styleItem->style->Bitmap()) {
_GenerateImage(span, x, y, len, styleItem->style, styleItem->transformation); _GenerateImage(span, x, y, len, styleItem->style, styleItem->transformer);
return; return;
} }
#endif // ICON_O_MATIC #endif // ICON_O_MATIC
Style* style = styleItem->style; const Style* style = styleItem->style;
Gradient* gradient = style->Gradient(); Gradient* gradient = style->Gradient();
const agg::rgba8* colors = style->GammaCorrectedColors(fGammaTable); const agg::rgba8* colors = style->GammaCorrectedColors(fGammaTable);
@@ -177,70 +211,132 @@ IconRenderer::StyleHandler::generate_span(agg::rgba8* span, int x, int y,
case GRADIENT_LINEAR: { case GRADIENT_LINEAR: {
agg::gradient_x function; agg::gradient_x function;
_GenerateGradient(span, x, y, len, function, -64, 64, colors, _GenerateGradient(span, x, y, len, function, -64, 64, colors,
styleItem->transformation); styleItem->transformer);
break; break;
} }
case GRADIENT_CIRCULAR: { case GRADIENT_CIRCULAR: {
agg::gradient_radial function; agg::gradient_radial function;
_GenerateGradient(span, x, y, len, function, 0, 64, colors, _GenerateGradient(span, x, y, len, function, 0, 64, colors,
styleItem->transformation); styleItem->transformer);
break; break;
} }
case GRADIENT_DIAMOND: { case GRADIENT_DIAMOND: {
agg::gradient_diamond function; agg::gradient_diamond function;
_GenerateGradient(span, x, y, len, function, 0, 64, colors, _GenerateGradient(span, x, y, len, function, 0, 64, colors,
styleItem->transformation); styleItem->transformer);
break; break;
} }
case GRADIENT_CONIC: { case GRADIENT_CONIC: {
agg::gradient_conic function; agg::gradient_conic function;
_GenerateGradient(span, x, y, len, function, 0, 64, colors, _GenerateGradient(span, x, y, len, function, 0, 64, colors,
styleItem->transformation); styleItem->transformer);
break; break;
} }
case GRADIENT_XY: { case GRADIENT_XY: {
agg::gradient_xy function; agg::gradient_xy function;
_GenerateGradient(span, x, y, len, function, 0, 64, colors, _GenerateGradient(span, x, y, len, function, 0, 64, colors,
styleItem->transformation); styleItem->transformer);
break; break;
} }
case GRADIENT_SQRT_XY: { case GRADIENT_SQRT_XY: {
agg::gradient_sqrt_xy function; agg::gradient_sqrt_xy function;
_GenerateGradient(span, x, y, len, function, 0, 64, colors, _GenerateGradient(span, x, y, len, function, 0, 64, colors,
styleItem->transformation); styleItem->transformer);
break; break;
} }
} }
} }
StyleTransformer*
IconRenderer::StyleHandler::_MergeTransformers(const Transformable* styleTransformation,
const Container<Transformer>* transformers, const Transformable* shapeTransformation)
{
// Figure out how large to make the array
int32 count = 0;
if (styleTransformation != NULL)
count++;
for (int i = 0; i < transformers->CountItems(); i++) {
if (dynamic_cast<StyleTransformer*>(transformers->ItemAtFast(i)))
count++;
}
count++;
// Populate the array
StyleTransformer** styleTransformers = new (nothrow) StyleTransformer*[count];
if (styleTransformers == NULL)
return NULL;
int i = 0;
if (styleTransformation != NULL)
styleTransformers[i++] = new (nothrow) Transformable(*styleTransformation);
for (int j = 0; j < transformers->CountItems(); j++) {
Transformer* transformer = transformers->ItemAtFast(j);
if (dynamic_cast<StyleTransformer*>(transformer) != NULL) {
styleTransformers[i++]
= dynamic_cast<StyleTransformer*>(transformer->Clone());
}
}
styleTransformers[i++] = new (nothrow) Transformable(*shapeTransformation);
CompoundStyleTransformer* styleTransformer
= new (nothrow) CompoundStyleTransformer(styleTransformers, count);
if (styleTransformer == NULL) {
delete[] styleTransformers;
return NULL;
}
return styleTransformer;
}
template<class GradientFunction> template<class GradientFunction>
void void
IconRenderer::StyleHandler::_GenerateGradient(agg::rgba8* span, int x, int y, IconRenderer::StyleHandler::_GenerateGradient(agg::rgba8* span, int x, int y,
unsigned len, GradientFunction function, int32 start, int32 end, unsigned len, GradientFunction function, int32 start, int32 end,
const agg::rgba8* gradientColors, Transformation& gradientTransform) const agg::rgba8* gradientColors, StyleTransformer* transformer)
{ {
// TODO: performance could potentially be improved by avoiding recreating
// these objects on every span
typedef agg::pod_auto_array<agg::rgba8, 256> ColorArray; typedef agg::pod_auto_array<agg::rgba8, 256> ColorArray;
typedef agg::span_interpolator_linear<> Interpolator;
typedef agg::span_gradient<agg::rgba8,
Interpolator,
GradientFunction,
ColorArray> GradientGenerator;
Interpolator interpolator(gradientTransform);
ColorArray array(gradientColors); ColorArray array(gradientColors);
GradientGenerator gradientGenerator(interpolator, function, array,
start, end);
gradientGenerator.generate(span, x, y, len); if (transformer->IsLinear()) {
typedef agg::span_interpolator_linear
<StyleTransformer> Interpolator;
typedef agg::span_gradient<agg::rgba8,
Interpolator,
GradientFunction,
ColorArray> GradientGenerator;
Interpolator interpolator(*transformer);
GradientGenerator gradientGenerator(interpolator, function, array,
start, end);
gradientGenerator.generate(span, x, y, len);
} else {
typedef agg::span_interpolator_trans
<StyleTransformer> Interpolator;
typedef agg::span_gradient<agg::rgba8,
Interpolator,
GradientFunction,
ColorArray> GradientGenerator;
Interpolator interpolator(*transformer);
GradientGenerator gradientGenerator(interpolator, function, array,
start, end);
gradientGenerator.generate(span, x, y, len);
}
} }
#ifdef ICON_O_MATIC #ifdef ICON_O_MATIC
void void
IconRenderer::StyleHandler::_GenerateImage(agg::rgba8* span, int x, int y, IconRenderer::StyleHandler::_GenerateImage(agg::rgba8* span, int x, int y,
unsigned len, Style* style, Transformation& transform) unsigned len, const Style* style, StyleTransformer* transformer)
{ {
// bitmap // bitmap
BBitmap* bbitmap = style->Bitmap(); BBitmap* bbitmap = style->Bitmap();
@@ -252,13 +348,16 @@ IconRenderer::StyleHandler::_GenerateImage(agg::rgba8* span, int x, int y,
PixelFormat pixf_img(bitmap); PixelFormat pixf_img(bitmap);
// image interpolator // image interpolator
typedef agg::span_interpolator_linear<> interpolator_type; // TODO: performance could be improved by using agg_interpolator_linear
interpolator_type interpolator(transform); // where possible, similar to what _GenerateGradient does.
typedef agg::span_interpolator_trans<StyleTransformer>
interpolator_type;
interpolator_type interpolator(*transformer);
// image accessor attached to pixel format of bitmap // image accessor attached to pixel format of bitmap
typedef agg::image_accessor_wrap<PixelFormat, typedef agg::image_accessor_clip<PixelFormat> source_type;
agg::wrap_mode_repeat, agg::wrap_mode_repeat> source_type; agg::rgba8 background(0, 0, 0, 0);
source_type source(pixf_img); source_type source(pixf_img, background);
// image filter (nearest neighbor) // image filter (nearest neighbor)
typedef agg::span_image_filter_rgba_nn< typedef agg::span_image_filter_rgba_nn<
@@ -424,7 +523,7 @@ IconRenderer::Demultiply()
// #pragma mark - // #pragma mark -
typedef agg::conv_transform<VertexSource, Transformation> ScaledPath; typedef agg::conv_transform<VertexSource, Transformable> ScaledPath;
typedef agg::conv_transform<ScaledPath, HintingTransformer> HintedPath; typedef agg::conv_transform<ScaledPath, HintingTransformer> HintedPath;
@@ -467,11 +566,8 @@ IconRenderer::_Render(const BRect& r)
continue; continue;
} }
Transformation transform(*shape); Transformable transform(*shape);
transform.multiply(fGlobalTransform); transform.multiply(fGlobalTransform);
// NOTE: this works only because "agg::trans_affine",
// "Transformable" and "Transformation" are all the
// same thing
Style* style = shape->Style(); Style* style = shape->Style();
if (!style) if (!style)
@@ -483,9 +579,11 @@ IconRenderer::_Render(const BRect& r)
Gradient* gradient = style->Gradient(); Gradient* gradient = style->Gradient();
bool styleAdded = false; bool styleAdded = false;
if (gradient && !gradient->InheritTransformation()) { if (gradient && !gradient->InheritTransformation()) {
styleAdded = styleHandler.AddStyle(style, fGlobalTransform); styleAdded = styleHandler.AddStyle(
style, fGlobalTransform, NULL);
} else { } else {
styleAdded = styleHandler.AddStyle(style, transform); styleAdded = styleHandler.AddStyle(
style, transform, shape->Transformers());
} }
if (!styleAdded) { if (!styleAdded) {
+2 -3
View File
@@ -21,6 +21,7 @@
#include <agg_trans_affine.h> #include <agg_trans_affine.h>
#include "IconBuild.h" #include "IconBuild.h"
#include "Transformable.h"
class BBitmap; class BBitmap;
@@ -47,8 +48,6 @@ typedef agg::span_allocator<agg::rgba8> SpanAllocator;
typedef agg::rasterizer_compound_aa typedef agg::rasterizer_compound_aa
<agg::rasterizer_sl_clip_dbl> CompoundRasterizer; <agg::rasterizer_sl_clip_dbl> CompoundRasterizer;
typedef agg::trans_affine Transformation;
class IconRenderer { class IconRenderer {
public: public:
IconRenderer(BBitmap* bitmap); IconRenderer(BBitmap* bitmap);
@@ -110,7 +109,7 @@ class IconRenderer {
CompoundRasterizer fRasterizer; CompoundRasterizer fRasterizer;
Transformation fGlobalTransform; Transformable fGlobalTransform;
}; };
+2 -1
View File
@@ -59,11 +59,12 @@ for architectureObject in [ MultiArchSubDirSetup ] {
# transformer # transformer
AffineTransformer.cpp AffineTransformer.cpp
CompoundStyleTransformer.cpp
ContourTransformer.cpp ContourTransformer.cpp
PathSource.cpp PathSource.cpp
PerspectiveTransformer.cpp PerspectiveTransformer.cpp
StrokeTransformer.cpp StrokeTransformer.cpp
Transformer.cpp StyleTransformer.cpp
TransformerFactory.cpp TransformerFactory.cpp
Icon.cpp Icon.cpp
+17 -10
View File
@@ -1,9 +1,10 @@
/* /*
* Copyright 2006, Haiku. All rights reserved. * Copyright 2006, 2023, Haiku. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
* Stephan Aßmus <superstippi@gmx.de> * Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/ */
#include "FlatIconImporter.h" #include "FlatIconImporter.h"
@@ -435,7 +436,7 @@ FlatIconImporter::_ParsePaths(LittleEndianBuffer& buffer,
// _ReadTransformer // _ReadTransformer
static Transformer* static Transformer*
_ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source) _ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source, Shape* shape)
{ {
uint8 transformerType; uint8 transformerType;
if (!buffer.Read(transformerType)) if (!buffer.Read(transformerType))
@@ -479,9 +480,19 @@ _ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source)
} }
case TRANSFORMER_TYPE_PERSPECTIVE: { case TRANSFORMER_TYPE_PERSPECTIVE: {
PerspectiveTransformer* perspective PerspectiveTransformer* perspective
= new (nothrow) PerspectiveTransformer(source); = new (nothrow) PerspectiveTransformer(source, shape);
// TODO: upgrade AGG to be able to support storage of if (!perspective)
// trans_perspective return NULL;
double matrix[9];
for (int32 i = 0; i < 9; i++) {
float value;
if (!read_float_24(buffer, value)) {
delete perspective;
return NULL;
}
matrix[i] = value;
}
perspective->load_from(matrix);
return perspective; return perspective;
} }
case TRANSFORMER_TYPE_STROKE: { case TRANSFORMER_TYPE_STROKE: {
@@ -601,7 +612,7 @@ FlatIconImporter::_ReadPathSourceShape(LittleEndianBuffer& buffer,
return NULL; return NULL;
for (uint32 i = 0; i < transformerCount; i++) { for (uint32 i = 0; i < transformerCount; i++) {
Transformer* transformer Transformer* transformer
= _ReadTransformer(buffer, shape->VertexSource()); = _ReadTransformer(buffer, shape->VertexSource(), shape);
if (transformer && !shape->Transformers()->AddItem(transformer)) { if (transformer && !shape->Transformers()->AddItem(transformer)) {
delete transformer; delete transformer;
return NULL; return NULL;
@@ -651,7 +662,3 @@ FlatIconImporter::_ParseShapes(LittleEndianBuffer& buffer,
return B_OK; return B_OK;
} }
+36
View File
@@ -0,0 +1,36 @@
/*
* Copyright 2006-2007, 2023, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#ifndef VERTEX_SOURCE_H
#define VERTEX_SOURCE_H
#include "IconBuild.h"
_BEGIN_ICON_NAMESPACE
class VertexSource {
public:
VertexSource() {}
virtual ~VertexSource() {}
virtual void rewind(unsigned path_id) = 0;
virtual unsigned vertex(double* x, double* y) = 0;
/*! Determines whether open paths should be closed or left open. */
virtual bool WantsOpenPaths() const = 0;
virtual double ApproximationScale() const = 0;
};
_END_ICON_NAMESPACE
#endif // VERTEX_SOURCE_H
+8 -5
View File
@@ -24,6 +24,7 @@
# include "PropertyObject.h" # include "PropertyObject.h"
#endif // ICON_O_MATIC #endif // ICON_O_MATIC
#include "Container.h" #include "Container.h"
#include "PathTransformer.h"
#include "Style.h" #include "Style.h"
#include "TransformerFactory.h" #include "TransformerFactory.h"
#include "VectorPath.h" #include "VectorPath.h"
@@ -130,7 +131,7 @@ Shape::Shape(const Shape& other)
int32 count = other.Transformers()->CountItems(); int32 count = other.Transformers()->CountItems();
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
Transformer* original = other.Transformers()->ItemAtFast(i); Transformer* original = other.Transformers()->ItemAtFast(i);
Transformer* cloned = original->Clone(fPathSource); Transformer* cloned = original->Clone();
if (!fTransformers.AddItem(cloned)) { if (!fTransformers.AddItem(cloned)) {
delete cloned; delete cloned;
break; break;
@@ -181,7 +182,7 @@ Shape::Unarchive(BMessage* archive)
i++) { i++) {
Transformer* transformer Transformer* transformer
= TransformerFactory::TransformerFor( = TransformerFactory::TransformerFor(
&transformerArchive, VertexSource()); &transformerArchive, VertexSource(), this);
if (!transformer || !fTransformers.AddItem(transformer)) { if (!transformer || !fTransformers.AddItem(transformer)) {
delete transformer; delete transformer;
} }
@@ -452,9 +453,11 @@ Shape::VertexSource()
int32 count = fTransformers.CountItems(); int32 count = fTransformers.CountItems();
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
Transformer* t = (Transformer*)fTransformers.ItemAtFast(i); PathTransformer* t = dynamic_cast<PathTransformer*>(fTransformers.ItemAtFast(i));
t->SetSource(*source); if (t != NULL) {
source = t; t->SetSource(*source);
source = t;
}
} }
if (fNeedsUpdate) { if (fNeedsUpdate) {
+1 -1
View File
@@ -86,7 +86,7 @@ class Style {
// alpha only applies to bitmaps // alpha only applies to bitmaps
void SetAlpha(uint8 alpha) void SetAlpha(uint8 alpha)
{ fAlpha = alpha; Notify(); } { fAlpha = alpha; Notify(); }
uint8 Alpha() uint8 Alpha() const
{ return fAlpha; } { return fAlpha; }
#endif // ICON_O_MATIC #endif // ICON_O_MATIC
+74 -96
View File
@@ -1,9 +1,10 @@
/* /*
* Copyright 2006-2009, Haiku. * Copyright 2006-2009, 2023, Haiku.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
* Stephan Aßmus <superstippi@gmx.de> * Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/ */
#include "Transformable.h" #include "Transformable.h"
@@ -11,31 +12,78 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
// constructor
Transformable::Transformable() Transformable::Transformable()
: agg::trans_affine() : agg::trans_affine()
{ {
} }
// copy constructor
Transformable::Transformable(const Transformable& other) Transformable::Transformable(const Transformable& other)
: agg::trans_affine(other) : agg::trans_affine(other)
{ {
} }
// destructor
Transformable::~Transformable() Transformable::~Transformable()
{ {
} }
// StoreTo
// #pragma mark -
void
Transformable::Invert()
{
if (!IsIdentity()) {
invert();
TransformationChanged();
}
}
// #pragma mark -
void
Transformable::InverseTransform(double* x, double* y) const
{
inverse_transform(x, y);
}
void
Transformable::InverseTransform(BPoint* point) const
{
if (point) {
double x = point->x;
double y = point->y;
inverse_transform(&x, &y);
point->x = x;
point->y = y;
}
}
BPoint
Transformable::InverseTransform(const BPoint& point) const
{
BPoint p(point);
InverseTransform(&p);
return p;
}
void void
Transformable::StoreTo(double matrix[matrix_size]) const Transformable::StoreTo(double matrix[matrix_size]) const
{ {
store_to(matrix); store_to(matrix);
} }
// LoadFrom
void void
Transformable::LoadFrom(const double matrix[matrix_size]) Transformable::LoadFrom(const double matrix[matrix_size])
{ {
@@ -50,7 +98,7 @@ Transformable::LoadFrom(const double matrix[matrix_size])
} }
} }
// SetTransform
void void
Transformable::SetTransform(const Transformable& other) Transformable::SetTransform(const Transformable& other)
{ {
@@ -60,7 +108,7 @@ Transformable::SetTransform(const Transformable& other)
} }
} }
// operator=
Transformable& Transformable&
Transformable::operator=(const Transformable& other) Transformable::operator=(const Transformable& other)
{ {
@@ -72,7 +120,7 @@ Transformable::operator=(const Transformable& other)
return *this; return *this;
} }
// Multiply
Transformable& Transformable&
Transformable::Multiply(const Transformable& other) Transformable::Multiply(const Transformable& other)
{ {
@@ -83,7 +131,7 @@ Transformable::Multiply(const Transformable& other)
return *this; return *this;
} }
// Reset
void void
Transformable::Reset() Transformable::Reset()
{ {
@@ -93,17 +141,7 @@ Transformable::Reset()
} }
} }
// Invert
void
Transformable::Invert()
{
if (!IsIdentity()) {
invert();
TransformationChanged();
}
}
// IsIdentity
bool bool
Transformable::IsIdentity() const Transformable::IsIdentity() const
{ {
@@ -119,7 +157,7 @@ Transformable::IsIdentity() const
return false; return false;
} }
// IsTranslationOnly
bool bool
Transformable::IsTranslationOnly() const Transformable::IsTranslationOnly() const
{ {
@@ -133,7 +171,7 @@ Transformable::IsTranslationOnly() const
return false; return false;
} }
// IsNotDistorted
bool bool
Transformable::IsNotDistorted() const Transformable::IsNotDistorted() const
{ {
@@ -142,7 +180,7 @@ Transformable::IsNotDistorted() const
return (m[0] == m[3]); return (m[0] == m[3]);
} }
// IsValid
bool bool
Transformable::IsValid() const Transformable::IsValid() const
{ {
@@ -151,7 +189,7 @@ Transformable::IsValid() const
return ((m[0] * m[3] - m[1] * m[2]) != 0.0); return ((m[0] * m[3] - m[1] * m[2]) != 0.0);
} }
// operator==
bool bool
Transformable::operator==(const Transformable& other) const Transformable::operator==(const Transformable& other) const
{ {
@@ -162,74 +200,13 @@ Transformable::operator==(const Transformable& other) const
return memcmp(m1, m2, sizeof(m1)) == 0; return memcmp(m1, m2, sizeof(m1)) == 0;
} }
// operator!=
bool bool
Transformable::operator!=(const Transformable& other) const Transformable::operator!=(const Transformable& other) const
{ {
return !(*this == other); return !(*this == other);
} }
// Transform
void
Transformable::Transform(double* x, double* y) const
{
transform(x, y);
}
// Transform
void
Transformable::Transform(BPoint* point) const
{
if (point) {
double x = point->x;
double y = point->y;
transform(&x, &y);
point->x = x;
point->y = y;
}
}
// Transform
BPoint
Transformable::Transform(const BPoint& point) const
{
BPoint p(point);
Transform(&p);
return p;
}
// InverseTransform
void
Transformable::InverseTransform(double* x, double* y) const
{
inverse_transform(x, y);
}
// InverseTransform
void
Transformable::InverseTransform(BPoint* point) const
{
if (point) {
double x = point->x;
double y = point->y;
inverse_transform(&x, &y);
point->x = x;
point->y = y;
}
}
// InverseTransform
BPoint
Transformable::InverseTransform(const BPoint& point) const
{
BPoint p(point);
InverseTransform(&p);
return p;
}
inline float inline float
min4(float a, float b, float c, float d) min4(float a, float b, float c, float d)
@@ -237,13 +214,14 @@ min4(float a, float b, float c, float d)
return min_c(a, min_c(b, min_c(c, d))); return min_c(a, min_c(b, min_c(c, d)));
} }
inline float inline float
max4(float a, float b, float c, float d) max4(float a, float b, float c, float d)
{ {
return max_c(a, max_c(b, max_c(c, d))); return max_c(a, max_c(b, max_c(c, d)));
} }
// TransformBounds
BRect BRect
Transformable::TransformBounds(BRect bounds) const Transformable::TransformBounds(BRect bounds) const
{ {
@@ -253,10 +231,10 @@ Transformable::TransformBounds(BRect bounds) const
BPoint lb(bounds.left, bounds.bottom); BPoint lb(bounds.left, bounds.bottom);
BPoint rb(bounds.right, bounds.bottom); BPoint rb(bounds.right, bounds.bottom);
Transform(&lt); StyleTransformer::Transform(&lt);
Transform(&rt); StyleTransformer::Transform(&rt);
Transform(&lb); StyleTransformer::Transform(&lb);
Transform(&rb); StyleTransformer::Transform(&rb);
return BRect(floorf(min4(lt.x, rt.x, lb.x, rb.x)), return BRect(floorf(min4(lt.x, rt.x, lb.x, rb.x)),
floorf(min4(lt.y, rt.y, lb.y, rb.y)), floorf(min4(lt.y, rt.y, lb.y, rb.y)),
@@ -266,7 +244,7 @@ Transformable::TransformBounds(BRect bounds) const
return bounds; return bounds;
} }
// TranslateBy
void void
Transformable::TranslateBy(BPoint offset) Transformable::TranslateBy(BPoint offset)
{ {
@@ -276,7 +254,7 @@ Transformable::TranslateBy(BPoint offset)
} }
} }
// RotateBy
void void
Transformable::RotateBy(BPoint origin, double degrees) Transformable::RotateBy(BPoint origin, double degrees)
{ {
@@ -288,7 +266,7 @@ Transformable::RotateBy(BPoint origin, double degrees)
} }
} }
// ScaleBy
void void
Transformable::ScaleBy(BPoint origin, double xScale, double yScale) Transformable::ScaleBy(BPoint origin, double xScale, double yScale)
{ {
@@ -300,7 +278,7 @@ Transformable::ScaleBy(BPoint origin, double xScale, double yScale)
} }
} }
// ShearBy
void void
Transformable::ShearBy(BPoint origin, double xShear, double yShear) Transformable::ShearBy(BPoint origin, double xShear, double yShear)
{ {
@@ -312,7 +290,7 @@ Transformable::ShearBy(BPoint origin, double xShear, double yShear)
} }
} }
// TransformationChanged
void void
Transformable::TransformationChanged() Transformable::TransformationChanged()
{ {
+21 -15
View File
@@ -1,9 +1,10 @@
/* /*
* Copyright 2006, Haiku. * Copyright 2006, 2023, Haiku.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
* Stephan Aßmus <superstippi@gmx.de> * Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/ */
#ifndef TRANSFORMABLE_H #ifndef TRANSFORMABLE_H
@@ -14,12 +15,17 @@
#include <agg_trans_affine.h> #include <agg_trans_affine.h>
#include "IconBuild.h" #include "IconBuild.h"
#include "StyleTransformer.h"
#include "Transformer.h"
_BEGIN_ICON_NAMESPACE _BEGIN_ICON_NAMESPACE
class Transformable : public agg::trans_affine { /*! The standard affine transformation. */
// TODO: combine with AffineTransformer
class Transformable : public StyleTransformer,
public agg::trans_affine {
public: public:
enum { enum {
matrix_size = 6, matrix_size = 6,
@@ -29,6 +35,18 @@ class Transformable : public agg::trans_affine {
Transformable(const Transformable& other); Transformable(const Transformable& other);
virtual ~Transformable(); virtual ~Transformable();
// StyleTransformer interface
virtual void transform(double* x, double* y) const
{ return agg::trans_affine::transform(x, y); }
virtual void Invert();
virtual bool IsLinear()
{ return true; }
// Transformable
void InverseTransform(double* x, double* y) const;
void InverseTransform(BPoint* point) const;
BPoint InverseTransform(const BPoint& point) const;
void StoreTo(double matrix[matrix_size]) const; void StoreTo(double matrix[matrix_size]) const;
void LoadFrom(const double matrix[matrix_size]); void LoadFrom(const double matrix[matrix_size]);
@@ -38,8 +56,6 @@ class Transformable : public agg::trans_affine {
Transformable& Multiply(const Transformable& other); Transformable& Multiply(const Transformable& other);
virtual void Reset(); virtual void Reset();
void Invert();
bool IsIdentity() const; bool IsIdentity() const;
bool IsTranslationOnly() const; bool IsTranslationOnly() const;
bool IsNotDistorted() const; bool IsNotDistorted() const;
@@ -48,15 +64,6 @@ class Transformable : public agg::trans_affine {
bool operator==(const Transformable& other) const; bool operator==(const Transformable& other) const;
bool operator!=(const Transformable& other) const; bool operator!=(const Transformable& other) const;
// transforms coordiantes
void Transform(double* x, double* y) const;
void Transform(BPoint* point) const;
BPoint Transform(const BPoint& point) const;
void InverseTransform(double* x, double* y) const;
void InverseTransform(BPoint* point) const;
BPoint InverseTransform(const BPoint& point) const;
// transforms the rectangle "bounds" and // transforms the rectangle "bounds" and
// returns the *bounding box* of that // returns the *bounding box* of that
BRect TransformBounds(BRect bounds) const; BRect TransformBounds(BRect bounds) const;
@@ -70,7 +77,7 @@ class Transformable : public agg::trans_affine {
virtual void TransformationChanged(); virtual void TransformationChanged();
// hook function that is called when the transformation // hook function that is called when the transformation
// is changed for some reason // is changed for some reason
virtual void PrintToStream() const; virtual void PrintToStream() const;
}; };
@@ -82,4 +89,3 @@ _USING_ICON_NAMESPACE
#endif // TRANSFORMABLE_H #endif // TRANSFORMABLE_H
@@ -26,7 +26,8 @@ using std::nothrow;
// constructor // constructor
AffineTransformer::AffineTransformer(VertexSource& source) AffineTransformer::AffineTransformer(VertexSource& source)
: Transformer(source, "Transformation"), : Transformer("Transformation"),
PathTransformer(source),
Affine(source, *this) Affine(source, *this)
{ {
} }
@@ -34,7 +35,8 @@ AffineTransformer::AffineTransformer(VertexSource& source)
// constructor // constructor
AffineTransformer::AffineTransformer(VertexSource& source, AffineTransformer::AffineTransformer(VertexSource& source,
BMessage* archive) BMessage* archive)
: Transformer(source, archive), : Transformer(archive),
PathTransformer(source),
Affine(source, *this) Affine(source, *this)
{ {
if (!archive) if (!archive)
@@ -57,9 +59,9 @@ AffineTransformer::~AffineTransformer()
// Clone // Clone
Transformer* Transformer*
AffineTransformer::Clone(VertexSource& source) const AffineTransformer::Clone() const
{ {
AffineTransformer* clone = new (nothrow) AffineTransformer(source); AffineTransformer* clone = new (nothrow) AffineTransformer(fSource);
if (clone) if (clone)
clone->multiply(*this); clone->multiply(*this);
return clone; return clone;
@@ -83,7 +85,7 @@ AffineTransformer::vertex(double* x, double* y)
void void
AffineTransformer::SetSource(VertexSource& source) AffineTransformer::SetSource(VertexSource& source)
{ {
Transformer::SetSource(source); PathTransformer::SetSource(source);
Affine::attach(source); Affine::attach(source);
} }
@@ -10,6 +10,7 @@
#include "IconBuild.h" #include "IconBuild.h"
#include "PathTransformer.h"
#include "Transformer.h" #include "Transformer.h"
#include <agg_conv_transform.h> #include <agg_conv_transform.h>
@@ -23,6 +24,7 @@ typedef agg::conv_transform<VertexSource,
agg::trans_affine> Affine; agg::trans_affine> Affine;
class AffineTransformer : public Transformer, class AffineTransformer : public Transformer,
public PathTransformer,
public Affine, public Affine,
public agg::trans_affine { public agg::trans_affine {
public: public:
@@ -38,8 +40,10 @@ class AffineTransformer : public Transformer,
virtual ~AffineTransformer(); virtual ~AffineTransformer();
virtual Transformer* Clone(VertexSource& source) const; // Transformer interface
virtual Transformer* Clone() const;
// PathTransformer interface
virtual void rewind(unsigned path_id); virtual void rewind(unsigned path_id);
virtual unsigned vertex(double* x, double* y); virtual unsigned vertex(double* x, double* y);
@@ -0,0 +1,72 @@
/*
* Copyright 2023, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Zardshard
*/
#include "CompoundStyleTransformer.h"
#include <string.h>
_USING_ICON_NAMESPACE
CompoundStyleTransformer::CompoundStyleTransformer(
StyleTransformer** transformers, int32 count)
:
fTransformers(transformers),
fCount(count)
{
}
CompoundStyleTransformer::~CompoundStyleTransformer()
{
for (int i = 0; i < fCount; i++)
delete fTransformers[i];
delete[] fTransformers;
}
void
CompoundStyleTransformer::transform(double* x, double* y) const
{
for (int i = 0; i < fCount; i++) {
if (fTransformers[i] != NULL)
fTransformers[i]->transform(x, y);
}
}
void
CompoundStyleTransformer::Invert()
{
// reverse order of pipeline
StyleTransformer* oldOrder[fCount];
memcpy(oldOrder, fTransformers, fCount * sizeof(StyleTransformer*));
for (int i = 0; i < fCount; i++) {
fTransformers[fCount-i-1] = oldOrder[i];
}
// invert individual transformations
for (int i = 0; i < fCount; i++) {
if (fTransformers[i] != NULL)
fTransformers[i]->Invert();
}
}
bool
CompoundStyleTransformer::IsLinear()
{
bool linear = true;
for (int i = 0; i < fCount; i++) {
if (fTransformers[i] != NULL)
linear &= fTransformers[i]->IsLinear();
}
return linear;
}
@@ -0,0 +1,51 @@
/*
* Copyright 2023, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Zardshard
*/
#ifndef COMPOUND_STYLE_TRANSFORMER_H
#define COMPOUND_STYLE_TRANSFORMER_H
#include <SupportDefs.h>
#include "IconBuild.h"
#include "StyleTransformer.h"
_BEGIN_ICON_NAMESPACE
class VertexSource;
class StyleTransformer;
/*! Allows turning an array of StyleTransformers into a single StyleTransformer.
\note This class is not meant to be exposed to the GUI or saved in a file. It
is currently only used for rendering.
*/
class CompoundStyleTransformer : public StyleTransformer {
public:
CompoundStyleTransformer(
StyleTransformer** transformers,
int32 count);
virtual ~CompoundStyleTransformer();
// StyleTransformer interface
virtual void transform(double* x, double* y) const;
virtual void Invert();
virtual bool IsLinear();
private:
StyleTransformer** fTransformers;
int32 fCount;
};
_END_ICON_NAMESPACE
#endif // COMPOUND_STYLE_TRANSFORMER_H
@@ -27,7 +27,8 @@ using std::nothrow;
// constructor // constructor
ContourTransformer::ContourTransformer(VertexSource& source) ContourTransformer::ContourTransformer(VertexSource& source)
: Transformer(source, "Contour"), : Transformer("Contour"),
PathTransformer(source),
Contour(source) Contour(source)
{ {
auto_detect_orientation(true); auto_detect_orientation(true);
@@ -36,7 +37,8 @@ ContourTransformer::ContourTransformer(VertexSource& source)
// constructor // constructor
ContourTransformer::ContourTransformer(VertexSource& source, ContourTransformer::ContourTransformer(VertexSource& source,
BMessage* archive) BMessage* archive)
: Transformer(source, archive), : Transformer(archive),
PathTransformer(source),
Contour(source) Contour(source)
{ {
auto_detect_orientation(true); auto_detect_orientation(true);
@@ -69,9 +71,9 @@ ContourTransformer::~ContourTransformer()
// Clone // Clone
Transformer* Transformer*
ContourTransformer::Clone(VertexSource& source) const ContourTransformer::Clone() const
{ {
ContourTransformer* clone = new (nothrow) ContourTransformer(source); ContourTransformer* clone = new (nothrow) ContourTransformer(fSource);
if (clone) { if (clone) {
clone->line_join(line_join()); clone->line_join(line_join());
clone->inner_join(inner_join()); clone->inner_join(inner_join());
@@ -101,7 +103,7 @@ ContourTransformer::vertex(double* x, double* y)
void void
ContourTransformer::SetSource(VertexSource& source) ContourTransformer::SetSource(VertexSource& source)
{ {
Transformer::SetSource(source); PathTransformer::SetSource(source);
Contour::attach(source); Contour::attach(source);
} }
@@ -10,6 +10,7 @@
#include "IconBuild.h" #include "IconBuild.h"
#include "PathTransformer.h"
#include "Transformer.h" #include "Transformer.h"
#include <agg_conv_contour.h> #include <agg_conv_contour.h>
@@ -21,6 +22,7 @@ _BEGIN_ICON_NAMESPACE
typedef agg::conv_contour<VertexSource> Contour; typedef agg::conv_contour<VertexSource> Contour;
class ContourTransformer : public Transformer, class ContourTransformer : public Transformer,
public PathTransformer,
public Contour { public Contour {
public: public:
enum { enum {
@@ -35,10 +37,12 @@ class ContourTransformer : public Transformer,
virtual ~ContourTransformer(); virtual ~ContourTransformer();
virtual Transformer* Clone(VertexSource& source) const; // Transformer interface
virtual Transformer* Clone() const;
// PathTransformer interface
virtual void rewind(unsigned path_id); virtual void rewind(unsigned path_id);
virtual unsigned vertex(double* x, double* y); virtual unsigned vertex(double* x, double* y);
virtual void SetSource(VertexSource& source); virtual void SetSource(VertexSource& source);
@@ -0,0 +1,51 @@
/*
* Copyright 2006-2007, 2023, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#ifndef PATH_TRANSFORMER_H
#define PATH_TRANSFORMER_H
#include "IconBuild.h"
#include "VertexSource.h"
_BEGIN_ICON_NAMESPACE
/*! A transformation to a VertexSource.
It can add points, move them around, turn them to curves, etc.
*/
class PathTransformer : public VertexSource
{
public:
PathTransformer(VertexSource& source)
: fSource(source) {}
virtual ~PathTransformer() {}
// PathTransformer
virtual void rewind(unsigned path_id)
{ fSource.rewind(path_id); }
virtual unsigned vertex(double* x, double* y)
{ return fSource.vertex(x, y); }
virtual void SetSource(VertexSource& source)
{ fSource = source; }
virtual bool WantsOpenPaths() const
{ return fSource.WantsOpenPaths(); }
virtual double ApproximationScale() const
{ return fSource.ApproximationScale(); }
protected:
VertexSource& fSource;
};
_END_ICON_NAMESPACE
#endif // PATH_TRANSFORMER_H
@@ -1,108 +1,341 @@
/* /*
* Copyright 2006-2007, Haiku. * Copyright 2006-2007, 2023, Haiku.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
* Stephan Aßmus <superstippi@gmx.de> * Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/ */
#include "PerspectiveTransformer.h" #include "PerspectiveTransformer.h"
#ifdef ICON_O_MATIC
# include <Message.h>
#endif
#include <new> #include <new>
#include <stdio.h>
#include <agg_basics.h>
#include <agg_bounding_rect.h>
#include <Message.h>
#include "Shape.h"
_USING_ICON_NAMESPACE _USING_ICON_NAMESPACE
using std::nothrow; using std::nothrow;
// constructor PerspectiveTransformer::PerspectiveTransformer(VertexSource& source, Shape* shape)
PerspectiveTransformer::PerspectiveTransformer(VertexSource& source) : Transformer("Perspective"),
: Transformer(source, "Perspective"), PathTransformer(source),
Perspective(source, *this) Perspective(source, *this),
fShape(shape)
#ifdef ICON_O_MATIC
, fInverted(false)
#endif
{ {
#ifdef ICON_O_MATIC
if (fShape != NULL) {
fShape->AcquireReference();
fShape->AddObserver(this);
ObjectChanged(fShape); // finish initialization
}
#endif
} }
// constructor
PerspectiveTransformer::PerspectiveTransformer(VertexSource& source, PerspectiveTransformer::PerspectiveTransformer(
BMessage* archive) VertexSource& source, Shape* shape, BMessage* archive)
: Transformer(source, archive), : Transformer(archive),
Perspective(source, *this) PathTransformer(source),
Perspective(source, *this),
fShape(shape)
#ifdef ICON_O_MATIC
, fInverted(false)
#endif
{ {
// TODO: upgrade AGG to be able to use load_from() etc double matrix[9];
for (int i = 0; i < 9; i++) {
if (archive->FindDouble("matrix", i, &matrix[i]) != B_OK)
matrix[i] = 0;
}
load_from(matrix);
#ifdef ICON_O_MATIC
if (fShape != NULL) {
fShape->AcquireReference();
fShape->AddObserver(this);
ObjectChanged(fShape); // finish initialization
}
#endif
} }
// destructor
PerspectiveTransformer::PerspectiveTransformer(const PerspectiveTransformer& other)
#ifdef ICON_O_MATIC
: Transformer(other.Name()),
#else
: Transformer(""),
#endif
PathTransformer(other.fSource),
Perspective(fSource, *this),
fShape(other.fShape)
#ifdef ICON_O_MATIC
, fInverted(other.fInverted),
fFromBox(other.fFromBox),
fToLeftTop(other.fToLeftTop),
fToRightTop(other.fToRightTop),
fToLeftBottom(other.fToLeftBottom),
fToRightBottom(other.fToRightBottom),
fValid(other.fValid)
#endif
{
double matrix[9];
other.store_to(matrix);
load_from(matrix);
#ifdef ICON_O_MATIC
if (fShape != NULL) {
fShape->AcquireReference();
fShape->AddObserver(this);
}
#endif
}
PerspectiveTransformer::~PerspectiveTransformer() PerspectiveTransformer::~PerspectiveTransformer()
{ {
} #ifdef ICON_O_MATIC
if (fShape != NULL) {
// Clone fShape->RemoveObserver(this);
Transformer* fShape->ReleaseReference();
PerspectiveTransformer::Clone(VertexSource& source) const
{
PerspectiveTransformer* clone
= new (nothrow) PerspectiveTransformer(source);
if (clone) {
// TODO: upgrade AGG
// clone->multiply(*this);
} }
return clone; #endif
} }
// rewind
// #pragma mark -
Transformer*
PerspectiveTransformer::Clone() const
{
return new (nothrow) PerspectiveTransformer(*this);
}
// #pragma mark -
void void
PerspectiveTransformer::rewind(unsigned path_id) PerspectiveTransformer::rewind(unsigned path_id)
{ {
Perspective::rewind(path_id); Perspective::rewind(path_id);
} }
// vertex
unsigned unsigned
PerspectiveTransformer::vertex(double* x, double* y) PerspectiveTransformer::vertex(double* x, double* y)
{ {
#ifdef ICON_O_MATIC
if (fValid)
return Perspective::vertex(x, y);
else
return agg::path_cmd_stop;
#else
return Perspective::vertex(x, y); return Perspective::vertex(x, y);
#endif
} }
// SetSource
void void
PerspectiveTransformer::SetSource(VertexSource& source) PerspectiveTransformer::SetSource(VertexSource& source)
{ {
Transformer::SetSource(source); PathTransformer::SetSource(source);
Perspective::attach(source); Perspective::attach(source);
#ifdef ICON_O_MATIC
ObjectChanged(fShape);
#endif
} }
// ApproximationScale
double double
PerspectiveTransformer::ApproximationScale() const PerspectiveTransformer::ApproximationScale() const
{ {
// TODO: upgrade AGG return fSource.ApproximationScale() * scale();
return fSource.ApproximationScale();// * scale();
} }
// #pragma mark - // #pragma mark -
void
PerspectiveTransformer::Invert()
{
#ifdef ICON_O_MATIC
fInverted = !fInverted;
// TODO: degenerate matrices may not be adequately handled
bool degenerate = !invert();
fValid = fValid && !degenerate;
#else
invert();
#endif
}
// #pragma mark -
#ifdef ICON_O_MATIC #ifdef ICON_O_MATIC
// Archive
status_t status_t
PerspectiveTransformer::Archive(BMessage* into, bool deep) const PerspectiveTransformer::Archive(BMessage* into, bool deep) const
{ {
status_t ret = Transformer::Archive(into, deep); status_t ret = Transformer::Archive(into, deep);
if (ret == B_OK) into->what = archive_code;
into->what = archive_code;
// TODO: upgrade AGG to be able to use store_to() double matrix[9];
store_to(matrix);
for (int i = 0; i < 9; i++) {
if (ret == B_OK)
ret = into->AddDouble("matrix", matrix[i]);
}
return ret; return ret;
} }
// #prama mark -
void
PerspectiveTransformer::ObjectChanged(const Observable* object)
{
if (fInverted) {
printf("calculating the validity or bounding box of an inverted "
"perspective transformer is currently unsupported.");
return;
}
uint32 pathID[1];
pathID[0] = 0;
double left, top, right, bottom;
agg::bounding_rect(fSource, pathID, 0, 1, &left, &top, &right, &bottom);
BRect newFromBox = BRect(left, top, right, bottom);
// Stop if nothing we care about has changed
// TODO: Can this be done earlier? It would be nice to avoid having to
// recalculate the bounding box before realizing nothing needs to be done.
if (fFromBox == newFromBox)
return;
fFromBox = newFromBox;
_CheckValidity();
double x = fFromBox.left; double y = fFromBox.top;
Transform(&x, &y);
fToLeftTop = BPoint(x, y);
x = fFromBox.right; y = fFromBox.top;
Transform(&x, &y);
fToRightTop = BPoint(x, y);
x = fFromBox.left; y = fFromBox.bottom;
Transform(&x, &y);
fToLeftBottom = BPoint(x, y);
x = fFromBox.right; y = fFromBox.bottom;
Transform(&x, &y);
fToRightBottom = BPoint(x, y);
}
// #pragma mark -
void
PerspectiveTransformer::TransformTo(
BPoint leftTop, BPoint rightTop, BPoint leftBottom, BPoint rightBottom)
{
fToLeftTop = leftTop;
fToRightTop = rightTop;
fToLeftBottom = leftBottom;
fToRightBottom = rightBottom;
double quad[8] = {
fToLeftTop.x, fToLeftTop.y,
fToRightTop.x, fToRightTop.y,
fToRightBottom.x, fToRightBottom.y,
fToLeftBottom.x, fToLeftBottom.y
};
if (!fInverted) {
rect_to_quad(
fFromBox.left, fFromBox.top,
fFromBox.right, fFromBox.bottom, quad);
} else {
quad_to_rect(quad,
fFromBox.left, fFromBox.top,
fFromBox.right, fFromBox.bottom);
}
_CheckValidity();
Notify();
}
// #pragma mark -
void
PerspectiveTransformer::_CheckValidity()
{
// Checks that none of the points are too close to the camera. These tend to
// lead to very big numbers or a divide by zero error. Also checks that all
// points are on the same side of the camera. Transformations with points on
// different sides of the camera look weird and tend to cause crashes.
fValid = true;
double w;
bool positive;
if (!fInverted) {
w = fFromBox.left * w0 + fFromBox.top * w1 + w2;
fValid &= (fabs(w) > 0.00001);
positive = w > 0;
w = fFromBox.right * w0 + fFromBox.top * w1 + w2;
fValid &= (fabs(w) > 0.00001);
fValid &= (w>0)==positive;
w = fFromBox.left * w0 + fFromBox.bottom * w1 + w2;
fValid &= (fabs(w) > 0.00001);
fValid &= (w>0)==positive;
w = fFromBox.right * w0 + fFromBox.bottom * w1 + w2;
fValid &= (fabs(w) > 0.00001);
fValid &= (w>0)==positive;
} else {
w = fToLeftTop.x * w0 + fToLeftTop.y * w1 + w2;
fValid &= (fabs(w) > 0.00001);
positive = w > 0;
w = fToRightTop.x * w0 + fToRightTop.y * w1 + w2;
fValid &= (fabs(w) > 0.00001);
fValid &= (w>0)==positive;
w = fToLeftBottom.x * w0 + fToLeftBottom.y * w1 + w2;
fValid &= (fabs(w) > 0.00001);
fValid &= (w>0)==positive;
w = fToRightBottom.x * w0 + fToRightBottom.y * w1 + w2;
fValid &= (fabs(w) > 0.00001);
fValid &= (w>0)==positive;
}
}
#endif // ICON_O_MATIC #endif // ICON_O_MATIC
@@ -1,46 +1,76 @@
/* /*
* Copyright 2006-2007, Haiku. * Copyright 2006-2007, 2023, Haiku.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
* Stephan Aßmus <superstippi@gmx.de> * Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/ */
#ifndef PERSPECTIVE_TRANSFORMER_H #ifndef PERSPECTIVE_TRANSFORMER_H
#define PERSPECTIVE_TRANSFORMER_H #define PERSPECTIVE_TRANSFORMER_H
#include "IconBuild.h" #include <Rect.h>
#include "Transformer.h" #include <Point.h>
#include <agg_conv_transform.h> #include <agg_conv_transform.h>
#include <agg_trans_perspective.h> #include <agg_trans_perspective.h>
#include "IconBuild.h"
#include "Transformer.h"
#ifdef ICON_O_MATIC
#include "Observer.h"
#endif
#include "PathTransformer.h"
#include "StyleTransformer.h"
#include "VertexSource.h"
_BEGIN_ICON_NAMESPACE _BEGIN_ICON_NAMESPACE
class Shape;
typedef agg::conv_transform<VertexSource,
agg::trans_perspective> Perspective;
typedef agg::conv_transform<VertexSource, agg::trans_perspective> Perspective;
/*! Transforms from the VertexSource's bounding rect to the specified
quadrilateral. This class watches out for invalid transformations if
\c ICON_O_MATIC is set.
*/
class PerspectiveTransformer : public Transformer, class PerspectiveTransformer : public Transformer,
public PathTransformer,
public StyleTransformer,
#ifdef ICON_O_MATIC
public Observer,
#endif
public Perspective, public Perspective,
public agg::trans_perspective { public agg::trans_perspective {
public: public:
enum { enum {
archive_code = 'prsp', archive_code = 'prsp',
}; };
PerspectiveTransformer( /*! Initializes starting with the identity transformation.
VertexSource& source); A valid perspective transformation can be rendered invalid if the shape
changes. Listens to \a shape for updates and determines if the
transformation is still valid if \c ICON_O_MATIC is set.
*/
PerspectiveTransformer( PerspectiveTransformer(
VertexSource& source, VertexSource& source,
Shape* shape);
PerspectiveTransformer(
VertexSource& source,
Shape* shape,
BMessage* archive); BMessage* archive);
PerspectiveTransformer(
const PerspectiveTransformer& other);
virtual ~PerspectiveTransformer(); virtual ~PerspectiveTransformer();
// Transformer interface // Transformer interface
virtual Transformer* Clone(VertexSource& source) const; virtual Transformer* Clone() const;
// PathTransformer interface
virtual void rewind(unsigned path_id); virtual void rewind(unsigned path_id);
virtual unsigned vertex(double* x, double* y); virtual unsigned vertex(double* x, double* y);
@@ -48,11 +78,55 @@ class PerspectiveTransformer : public Transformer,
virtual double ApproximationScale() const; virtual double ApproximationScale() const;
// StyleTransformer interface
virtual void transform(double* x, double* y) const
#ifdef ICON_O_MATIC
{ if (fValid) agg::trans_perspective::transform(x, y); }
#else
{ agg::trans_perspective::transform(x, y); }
#endif
/*! Inverts the perspective transformation.
\warning This class can mostly only transform points when inverted. Most
other features either have not been tested or are missing.
*/
virtual void Invert();
#ifdef ICON_O_MATIC #ifdef ICON_O_MATIC
// IconObject interface // IconObject interface
virtual status_t Archive(BMessage* into, virtual status_t Archive(BMessage* into,
bool deep = true) const; bool deep = true) const;
// Observer interface
virtual void ObjectChanged(const Observable* object);
// PerspectiveTransformer
void TransformTo(BPoint leftTop, BPoint rightTop,
BPoint leftBottom, BPoint rightBottom);
BPoint LeftTop()
{ return fToLeftTop; }
BPoint RightTop()
{ return fToRightTop; }
BPoint LeftBottom()
{ return fToLeftBottom; }
BPoint RightBottom()
{ return fToRightBottom; }
private:
void _CheckValidity();
#endif // ICON_O_MATIC
private:
Shape* fShape;
#ifdef ICON_O_MATIC
bool fInverted;
BRect fFromBox;
BPoint fToLeftTop;
BPoint fToRightTop;
BPoint fToLeftBottom;
BPoint fToRightBottom;
bool fValid;
#endif #endif
}; };
@@ -27,7 +27,8 @@ using std::nothrow;
// constructor // constructor
StrokeTransformer::StrokeTransformer(VertexSource& source) StrokeTransformer::StrokeTransformer(VertexSource& source)
: Transformer(source, "Stroke"), : Transformer("Stroke"),
PathTransformer(source),
Stroke(source) Stroke(source)
{ {
} }
@@ -35,7 +36,8 @@ StrokeTransformer::StrokeTransformer(VertexSource& source)
// constructor // constructor
StrokeTransformer::StrokeTransformer(VertexSource& source, StrokeTransformer::StrokeTransformer(VertexSource& source,
BMessage* archive) BMessage* archive)
: Transformer(source, archive), : Transformer(archive),
PathTransformer(source),
Stroke(source) Stroke(source)
{ {
if (!archive) if (!archive)
@@ -72,9 +74,9 @@ StrokeTransformer::~StrokeTransformer()
// Clone // Clone
Transformer* Transformer*
StrokeTransformer::Clone(VertexSource& source) const StrokeTransformer::Clone() const
{ {
StrokeTransformer* clone = new (nothrow) StrokeTransformer(source); StrokeTransformer* clone = new (nothrow) StrokeTransformer(fSource);
if (clone) { if (clone) {
clone->line_cap(line_cap()); clone->line_cap(line_cap());
clone->line_join(line_join()); clone->line_join(line_join());
@@ -105,7 +107,7 @@ StrokeTransformer::vertex(double* x, double* y)
void void
StrokeTransformer::SetSource(VertexSource& source) StrokeTransformer::SetSource(VertexSource& source)
{ {
Transformer::SetSource(source); PathTransformer::SetSource(source);
Stroke::attach(source); Stroke::attach(source);
} }
@@ -10,6 +10,7 @@
#include "IconBuild.h" #include "IconBuild.h"
#include "PathTransformer.h"
#include "Transformer.h" #include "Transformer.h"
#include <agg_conv_stroke.h> #include <agg_conv_stroke.h>
@@ -21,6 +22,7 @@ _BEGIN_ICON_NAMESPACE
typedef agg::conv_stroke<VertexSource> Stroke; typedef agg::conv_stroke<VertexSource> Stroke;
class StrokeTransformer : public Transformer, class StrokeTransformer : public Transformer,
public PathTransformer,
public Stroke { public Stroke {
public: public:
enum { enum {
@@ -36,8 +38,9 @@ class StrokeTransformer : public Transformer,
virtual ~StrokeTransformer(); virtual ~StrokeTransformer();
// Transformer interface // Transformer interface
virtual Transformer* Clone(VertexSource& source) const; virtual Transformer* Clone() const;
// PathTransformer interface
virtual void rewind(unsigned path_id); virtual void rewind(unsigned path_id);
virtual unsigned vertex(double* x, double* y); virtual unsigned vertex(double* x, double* y);
@@ -0,0 +1,44 @@
/*
* Copyright 2023, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#include "StyleTransformer.h"
#include <Point.h>
_USING_ICON_NAMESPACE
StyleTransformer::~StyleTransformer()
{
}
void
StyleTransformer::Transform(BPoint* point) const
{
if (point) {
double x = point->x;
double y = point->y;
Transform(&x, &y);
point->x = x;
point->y = y;
}
}
BPoint
StyleTransformer::Transform(const BPoint& point) const
{
BPoint p(point);
Transform(&p);
return p;
}
@@ -0,0 +1,61 @@
/*
* Copyright 2023, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#ifndef STYLE_TRANSFORMER_H
#define STYLE_TRANSFORMER_H
#include "IconBuild.h"
class BPoint;
_BEGIN_ICON_NAMESPACE
/*! Warps a shape's style.
Implements the same interface as any other class of the agg:trans_ series.
This class can be used wherever AGG needs a transformer (for example,
agg::span_interpolator_linear<StyleTransformer> is valid).
*/
class StyleTransformer {
public:
StyleTransformer() {}
virtual ~StyleTransformer();
/*! Transform a single point of the shape's style.
This function should be fast since it will be called many times.
\note This function is lowercase so that it satisfies the role of an agg
transformer
*/
virtual void transform(double* x, double* y) const = 0;
/*! Alias of \c transform.
Use of this in our code is preffered because it follows the normal
capitalization scheme.
*/
void Transform(double* x, double* y) const
{ transform(x, y); }
void Transform(BPoint* point) const;
BPoint Transform(const BPoint& point) const;
virtual void Invert() = 0;
/*! Is the transformation a linear transformation?
This allows using linear interpolation instead of calling \c transform
for each point. */
virtual bool IsLinear()
{ return false; }
};
_END_ICON_NAMESPACE
#endif // STYLE_TRANSFORMER_H
-92
View File
@@ -1,92 +0,0 @@
/*
* Copyright 2006-2007, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "Transformer.h"
_USING_ICON_NAMESPACE
// constructor
VertexSource::VertexSource()
{
}
// destructor
VertexSource::~VertexSource()
{
}
// #pragma mark -
// constructor
Transformer::Transformer(VertexSource& source, const char* name)
#ifdef ICON_O_MATIC
: IconObject(name),
#else
:
#endif
fSource(source)
{
}
// constructor
Transformer::Transformer(VertexSource& source,
BMessage* archive)
#ifdef ICON_O_MATIC
: IconObject(archive),
#else
:
#endif
fSource(source)
{
}
// destructor
Transformer::~Transformer()
{
}
// #pragma mark -
// rewind
void
Transformer::rewind(unsigned path_id)
{
fSource.rewind(path_id);
}
// vertex
unsigned
Transformer::vertex(double* x, double* y)
{
return fSource.vertex(x, y);
}
// SetSource
void
Transformer::SetSource(VertexSource& source)
{
fSource = source;
}
// WantsOpenPaths
bool
Transformer::WantsOpenPaths() const
{
return fSource.WantsOpenPaths();
}
// ApproximationScale
double
Transformer::ApproximationScale() const
{
return fSource.ApproximationScale();
}
+19 -36
View File
@@ -17,52 +17,35 @@
#endif #endif
#include "IconBuild.h" #include "IconBuild.h"
#include "VertexSource.h"
_BEGIN_ICON_NAMESPACE _BEGIN_ICON_NAMESPACE
class VertexSource { /*! Base class for all transformers.
public: All child classes should inherit either PathTransformer, StyleTransformer,
VertexSource(); or both.
virtual ~VertexSource(); */
virtual void rewind(unsigned path_id) = 0;
virtual unsigned vertex(double* x, double* y) = 0;
/*! Determines whether open paths should be closed or left open. */
virtual bool WantsOpenPaths() const = 0;
virtual double ApproximationScale() const = 0;
};
#ifdef ICON_O_MATIC #ifdef ICON_O_MATIC
class Transformer : public VertexSource, class Transformer : public IconObject {
public IconObject {
#else #else
class Transformer : public VertexSource { class Transformer {
#endif
public:
#ifdef ICON_O_MATIC
Transformer(const char* name)
: IconObject(name) {}
Transformer(BMessage* archive)
: IconObject(archive) {}
#else
Transformer(const char* name) {}
Transformer(BMessage* archive) {}
#endif #endif
public:
Transformer(VertexSource& source,
const char* name);
Transformer(VertexSource& source,
BMessage* archive);
virtual ~Transformer(); virtual ~Transformer() {}
// Transformer virtual Transformer* Clone() const = 0;
virtual Transformer* Clone(VertexSource& source) const = 0;
virtual void rewind(unsigned path_id);
virtual unsigned vertex(double* x, double* y);
virtual void SetSource(VertexSource& source);
virtual bool WantsOpenPaths() const;
virtual double ApproximationScale() const;
protected:
VertexSource& fSource;
}; };
@@ -11,6 +11,7 @@
#include "AffineTransformer.h" #include "AffineTransformer.h"
#include "ContourTransformer.h" #include "ContourTransformer.h"
#include "PerspectiveTransformer.h" #include "PerspectiveTransformer.h"
#include "Shape.h"
#include "StrokeTransformer.h" #include "StrokeTransformer.h"
#ifdef ICON_O_MATIC #ifdef ICON_O_MATIC
@@ -24,13 +25,13 @@ _USING_ICON_NAMESPACE
// TransformerFor // TransformerFor
Transformer* Transformer*
TransformerFactory::TransformerFor(uint32 type, VertexSource& source) TransformerFactory::TransformerFor(uint32 type, VertexSource& source, Shape* shape)
{ {
switch (type) { switch (type) {
case AFFINE_TRANSFORMER: case AFFINE_TRANSFORMER:
return new AffineTransformer(source); return new AffineTransformer(source);
case PERSPECTIVE_TRANSFORMER: case PERSPECTIVE_TRANSFORMER:
return new PerspectiveTransformer(source); return new PerspectiveTransformer(source, shape);
case CONTOUR_TRANSFORMER: case CONTOUR_TRANSFORMER:
return new ContourTransformer(source); return new ContourTransformer(source);
case STROKE_TRANSFORMER: case STROKE_TRANSFORMER:
@@ -42,14 +43,13 @@ TransformerFactory::TransformerFor(uint32 type, VertexSource& source)
// TransformerFor // TransformerFor
Transformer* Transformer*
TransformerFactory::TransformerFor(BMessage* message, TransformerFactory::TransformerFor(BMessage* message, VertexSource& source, Shape* shape)
VertexSource& source)
{ {
switch (message->what) { switch (message->what) {
case AffineTransformer::archive_code: case AffineTransformer::archive_code:
return new AffineTransformer(source, message); return new AffineTransformer(source, message);
case PerspectiveTransformer::archive_code: case PerspectiveTransformer::archive_code:
return new PerspectiveTransformer(source, message); return new PerspectiveTransformer(source, shape, message);
case ContourTransformer::archive_code: case ContourTransformer::archive_code:
return new ContourTransformer(source, message); return new ContourTransformer(source, message);
case StrokeTransformer::archive_code: case StrokeTransformer::archive_code:
@@ -20,6 +20,7 @@ class BMessage;
_BEGIN_ICON_NAMESPACE _BEGIN_ICON_NAMESPACE
class Shape;
class Transformer; class Transformer;
class VertexSource; class VertexSource;
@@ -35,10 +36,12 @@ class TransformerFactory {
public: public:
static Transformer* TransformerFor(uint32 type, static Transformer* TransformerFor(uint32 type,
VertexSource& source); VertexSource& source,
Shape* shape);
static Transformer* TransformerFor(BMessage* archive, static Transformer* TransformerFor(BMessage* archive,
VertexSource& source); VertexSource& source,
Shape* shape);
}; };