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 t = m;
@@ -511,7 +511,7 @@ namespace agg
}
//------------------------------------------------------------------------
const trans_perspective&
inline const trans_perspective&
trans_perspective::multiply_inv(const trans_affine& 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 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 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;
*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 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);
*y = std::sqrt(shy * shy + sy * sy);
+6 -1
View File
@@ -95,11 +95,12 @@ Application Icon-O-Matic :
# icon/transformer
AffineTransformer.cpp
CompoundStyleTransformer.cpp
ContourTransformer.cpp
PathSource.cpp
PerspectiveTransformer.cpp
StrokeTransformer.cpp
Transformer.cpp
StyleTransformer.cpp
TransformerFactory.cpp
# icon
@@ -275,6 +276,9 @@ Application Icon-O-Matic :
# transformable
CanvasTransformBox.cpp
ChannelTransform.cpp
PerspectiveBox.cpp
PerspectiveBoxStates.cpp
PerspectiveCommand.cpp
ResetTransformationCommand.cpp
TransformBox.cpp
TransformBoxStates.cpp
@@ -349,6 +353,7 @@ DoCatalogs Icon-O-Matic :
RemoveStylesCommand.cpp
SetColorCommand.cpp
SetGradientCommand.cpp
PerspectiveCommand.cpp
ResetTransformationCommand.cpp
TransformBoxStates.cpp
TransformerFactory.cpp
+18 -1
View File
@@ -59,6 +59,8 @@
#include "MessengerSaver.h"
#include "NativeSaver.h"
#include "PathListView.h"
#include "PerspectiveBox.h"
#include "PerspectiveTransformer.h"
#include "RDefExporter.h"
#include "ScrollView.h"
#include "SimpleFileSaver.h"
@@ -105,6 +107,7 @@ enum {
MSG_PATH_SELECTED = 'vpsl',
MSG_STYLE_SELECTED = 'stsl',
MSG_SHAPE_SELECTED = 'spsl',
MSG_TRANSFORMER_SELECTED = 'trsl',
MSG_SHAPE_RESET_TRANSFORMATION = 'rtsh',
MSG_STYLE_RESET_TRANSFORMATION = 'rtst',
@@ -562,6 +565,20 @@ case MSG_SHAPE_SELECTED: {
fState->AddManipulator(transformBox);
}
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:
fPropertyListView->FocusNameProperty();
@@ -1087,7 +1104,7 @@ MainWindow::_CreateGUI()
fShapeListView = new ShapeListView(BRect(0, 0, splitWidth, 100),
"shape list view", new BMessage(MSG_SHAPE_SELECTED), this);
fTransformerListView = new TransformerListView(BRect(0, 0, splitWidth, 100),
"transformer list view");
"transformer list view", new BMessage(MSG_TRANSFORMER_SELECTED), this);
fPropertyListView = new IconObjectListView();
BLayoutBuilder::Split<>(leftSideView)
@@ -43,6 +43,9 @@ class IconObject : public Observable,
const char* Name() const
{ 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:
BString fName;
};
@@ -201,8 +201,7 @@ TransformerListView::MessageReceived(BMessage* message)
break;
Transformer* transformer
= TransformerFactory::TransformerFor(type,
fShape->VertexSource());
= TransformerFactory::TransformerFor(type, fShape->VertexSource(), fShape);
if (!transformer)
break;
@@ -396,9 +395,9 @@ TransformerListView::SetMenu(BMenu* menu)
message->AddInt32("type", STROKE_TRANSFORMER);
fStrokeMI = new BMenuItem(B_TRANSLATE("Stroke"), message);
// message = new BMessage(MSG_ADD_TRANSFORMER);
// message->AddInt32("type", PERSPECTIVE_TRANSFORMER);
// fPerspectiveMI = new BMenuItem(B_TRANSLATE("Perspective"), message);
message = new BMessage(MSG_ADD_TRANSFORMER);
message->AddInt32("type", PERSPECTIVE_TRANSFORMER);
fPerspectiveMI = new BMenuItem(B_TRANSLATE("Perspective"), message);
// message = new BMessage(MSG_ADD_TRANSFORMER);
// message->AddInt32("type", AFFINE_TRANSFORMER);
@@ -408,6 +407,7 @@ TransformerListView::SetMenu(BMenu* menu)
addMenu->AddItem(fContourMI);
addMenu->AddItem(fStrokeMI);
addMenu->AddItem(fPerspectiveMI);
addMenu->SetTargetForItems(this);
fMenu->AddItem(addMenu);
@@ -82,6 +82,7 @@ class TransformerListView : public SimpleListView,
BMenu* fMenu;
BMenuItem* fContourMI;
BMenuItem* fStrokeMI;
BMenuItem* fPerspectiveMI;
};
#endif // TRANSFORMER_LIST_VIEW_H
@@ -483,11 +483,17 @@ _WriteTransformer(LittleEndianBuffer& buffer, Transformer* t)
|| !buffer.Write(miterLimit))
return false;
} else if (dynamic_cast<PerspectiveTransformer*>(t)) {
} else if (PerspectiveTransformer* perspective
= dynamic_cast<PerspectiveTransformer*>(t)) {
// perspective
if (!buffer.Write((uint8)TRANSFORMER_TYPE_PERSPECTIVE))
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
= dynamic_cast<StrokeTransformer*>(t)) {
@@ -29,7 +29,7 @@ struct style_map {
/*! Turns text into its associated paths and shapes.
Coloring can also be imported from applications, such as StyledEdit, that
specify it.
specify it in a supported format.
*/
class StyledTextImporter : public Importer {
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
TransformBoxListener::TransformBoxListener()
{
}
TransformBoxListener::~TransformBoxListener()
{
}
// #pragma mark -
using namespace TransformBoxStates;
// constructor
@@ -152,7 +142,6 @@ bool
TransformBox::MouseDown(BPoint where)
{
fView->FilterMouse(&where);
// NOTE: filter mouse here and in MouseMoved only
TransformToCanvas(where);
fDragging = true;
@@ -172,7 +161,6 @@ void
TransformBox::MouseMoved(BPoint where)
{
fView->FilterMouse(&where);
// NOTE: filter mouse here and in MouseDown only
TransformToCanvas(where);
if (fMousePos != where) {
@@ -236,12 +224,12 @@ TransformBox::Bounds()
TransformFromCanvas(rb);
TransformFromCanvas(c);
BRect r;
r.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);
r.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);
return r;
BRect bounds;
bounds.left = min5(lt.x, rt.x, lb.x, rb.x, c.x);
bounds.top = min5(lt.y, rt.y, lb.y, rb.y, c.y);
bounds.right = max5(lt.x, rt.x, lb.x, rb.x, c.x);
bounds.bottom = max5(lt.y, rt.y, lb.y, rb.y, c.y);
return bounds;
}
@@ -5,7 +5,6 @@
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/
#ifndef TRANSFORM_BOX_H
#define TRANSFORM_BOX_H
@@ -14,16 +13,21 @@
#include "ChannelTransform.h"
#include "Manipulator.h"
namespace TransformBoxStates {
class DragState;
}
class Command;
class StateView;
class DragState;
class TransformBox;
class TransformCommand;
class TransformBoxListener {
public:
TransformBoxListener();
virtual ~TransformBoxListener();
public:
TransformBoxListener() {}
virtual ~TransformBoxListener() {}
virtual void TransformBoxDeleted(
const TransformBox* box) = 0;
@@ -31,9 +35,8 @@ class TransformBoxListener {
class TransformBox : public ChannelTransform,
public Manipulator {
public:
TransformBox(StateView* view,
BRect box);
public:
TransformBox(StateView* view, BRect box);
virtual ~TransformBox();
// Manipulator interface
@@ -49,10 +52,10 @@ class TransformBox : public ChannelTransform,
virtual BRect TrackingBounds(BView* withinView);
virtual void ModifiersChanged(uint32 modifiers);
virtual bool HandleKeyDown(uint32 key, uint32 modifiers,
Command** _command);
virtual bool HandleKeyUp(uint32 key, uint32 modifiers,
Command** _command);
virtual bool HandleKeyDown(uint32 key,
uint32 modifiers, Command** _command);
virtual bool HandleKeyUp(uint32 key,
uint32 modifiers, Command** _command);
virtual bool UpdateCursor();
@@ -90,15 +93,15 @@ class TransformBox : public ChannelTransform,
bool AddListener(TransformBoxListener* listener);
bool RemoveListener(TransformBoxListener* listener);
private:
DragState* _DragStateFor(BPoint canvasWhere,
float canvasZoom);
private:
TransformBoxStates::DragState* _DragStateFor(
BPoint canvasWhere, float canvasZoom);
void _StrokeBWLine(BView* into,
BPoint from, BPoint to) const;
BPoint from, BPoint to) const;
void _StrokeBWPoint(BView* into,
BPoint point,
double angle) const;
BPoint point, double angle) const;
private:
BRect fOriginalBox;
BPoint fLeftTop;
@@ -110,7 +113,7 @@ class TransformBox : public ChannelTransform,
BPoint fPivotOffset;
TransformCommand* fCurrentCommand;
DragState* fCurrentState;
TransformBoxStates::DragState* fCurrentState;
bool fDragging;
BPoint fMousePos;
@@ -120,25 +123,25 @@ class TransformBox : public ChannelTransform,
BList fListeners;
protected:
protected:
void _NotifyDeleted() const;
// "static" state objects
StateView* fView;
DragState* fDragLTState;
DragState* fDragRTState;
DragState* fDragLBState;
DragState* fDragRBState;
TransformBoxStates::DragState* fDragLTState;
TransformBoxStates::DragState* fDragRTState;
TransformBoxStates::DragState* fDragLBState;
TransformBoxStates::DragState* fDragRBState;
DragState* fDragLState;
DragState* fDragRState;
DragState* fDragTState;
DragState* fDragBState;
TransformBoxStates::DragState* fDragLState;
TransformBoxStates::DragState* fDragRState;
TransformBoxStates::DragState* fDragTState;
TransformBoxStates::DragState* fDragBState;
DragState* fRotateState;
DragState* fTranslateState;
DragState* fOffsetCenterState;
TransformBoxStates::DragState* fRotateState;
TransformBoxStates::DragState* fTranslateState;
TransformBoxStates::DragState* fOffsetCenterState;
};
#endif // TRANSFORM_BOX_H
@@ -10,17 +10,14 @@
#include "TransformBoxStates.h"
#include <math.h>
#include <stdio.h>
#include <Catalog.h>
#include <Cursor.h>
#include <InterfaceDefs.h>
#include <Locale.h>
#include <View.h>
#include "cursors.h"
#include "support.h"
#include "TransformBox.h"
@@ -28,6 +25,9 @@
#define B_TRANSLATION_CONTEXT "Icon-O-Matic-TransformationBoxStates"
using namespace TransformBoxStates;
DragState::DragState(TransformBox* parent)
:
fOrigin(0.0, 0.0),
@@ -36,13 +36,6 @@ DragState::DragState(TransformBox* parent)
}
void
DragState::SetOrigin(BPoint origin)
{
fOrigin = origin;
}
const char*
DragState::ActionName() const
{
@@ -14,16 +14,21 @@
#include <agg_trans_affine.h>
class BView;
class TransformBox;
namespace TransformBoxStates {
// base class
class DragState {
public:
DragState(TransformBox* parent);
virtual ~DragState() {}
virtual void SetOrigin(BPoint origin);
virtual void SetOrigin(BPoint origin)
{ fOrigin = origin; }
virtual void DragTo(BPoint current, uint32 modifiers) = 0;
virtual void UpdateViewCursor(BView* view, BPoint current) const = 0;
@@ -142,4 +147,6 @@ class OffsetCenterState : public DragState {
virtual const char* ActionName() const;
};
} // TransformBoxStates namespace
#endif // TRANSFORM_BOX_STATES_H
+2 -1
View File
@@ -52,11 +52,12 @@ BuildPlatformMergeObjectPIC <libbe_build>icon_kit.o :
# transformer
AffineTransformer.cpp
CompoundStyleTransformer.cpp
ContourTransformer.cpp
PathSource.cpp
PerspectiveTransformer.cpp
StrokeTransformer.cpp
Transformer.cpp
StyleTransformer.cpp
TransformerFactory.cpp
Icon.cpp
+2 -1
View File
@@ -50,11 +50,12 @@ BuildPlatformStaticLibrary libicon_build.a :
# transformer
AffineTransformer.cpp
CompoundStyleTransformer.cpp
ContourTransformer.cpp
PathSource.cpp
PerspectiveTransformer.cpp
StrokeTransformer.cpp
Transformer.cpp
StyleTransformer.cpp
TransformerFactory.cpp
Icon.cpp
+210 -112
View File
@@ -20,108 +20,142 @@
#include <agg_span_image_filter_rgba.h>
#include <agg_span_gradient.h>
#include <agg_span_interpolator_linear.h>
#include <agg_span_interpolator_trans.h>
#include "CompoundStyleTransformer.h"
#include "GradientTransformable.h"
#include "Icon.h"
#include "Shape.h"
#include "Style.h"
#include "StyleTransformer.h"
#include "VectorPath.h"
using std::nothrow;
class IconRenderer::StyleHandler {
struct StyleItem {
Style* style;
Transformation transformation;
const Style* style;
StyleTransformer* transformer;
};
public:
#ifdef ICON_O_MATIC
StyleHandler(::GammaTable& gammaTable, bool showReferences)
: fStyles(20),
fGammaTable(gammaTable),
fShowReferences(showReferences),
fTransparent(0, 0, 0, 0),
fColor(0, 0, 0, 0)
{}
StyleHandler(::GammaTable& gammaTable,
bool showReferences);
#else
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);
StyleHandler(::GammaTable& gammaTable);
#endif
BList fStyles;
::GammaTable& fGammaTable;
~StyleHandler();
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
bool fShowReferences;
void _GenerateImage(agg::rgba8* span,
int x, int y, unsigned len,
const Style* style,
StyleTransformer* transformer);
#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&
IconRenderer::StyleHandler::color(unsigned styleIndex)
{
@@ -164,12 +198,12 @@ IconRenderer::StyleHandler::generate_span(agg::rgba8* span, int x, int y,
#ifdef ICON_O_MATIC
if (styleItem->style->Bitmap()) {
_GenerateImage(span, x, y, len, styleItem->style, styleItem->transformation);
_GenerateImage(span, x, y, len, styleItem->style, styleItem->transformer);
return;
}
#endif // ICON_O_MATIC
Style* style = styleItem->style;
const Style* style = styleItem->style;
Gradient* gradient = style->Gradient();
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: {
agg::gradient_x function;
_GenerateGradient(span, x, y, len, function, -64, 64, colors,
styleItem->transformation);
styleItem->transformer);
break;
}
case GRADIENT_CIRCULAR: {
agg::gradient_radial function;
_GenerateGradient(span, x, y, len, function, 0, 64, colors,
styleItem->transformation);
styleItem->transformer);
break;
}
case GRADIENT_DIAMOND: {
agg::gradient_diamond function;
_GenerateGradient(span, x, y, len, function, 0, 64, colors,
styleItem->transformation);
styleItem->transformer);
break;
}
case GRADIENT_CONIC: {
agg::gradient_conic function;
_GenerateGradient(span, x, y, len, function, 0, 64, colors,
styleItem->transformation);
styleItem->transformer);
break;
}
case GRADIENT_XY: {
agg::gradient_xy function;
_GenerateGradient(span, x, y, len, function, 0, 64, colors,
styleItem->transformation);
styleItem->transformer);
break;
}
case GRADIENT_SQRT_XY: {
agg::gradient_sqrt_xy function;
_GenerateGradient(span, x, y, len, function, 0, 64, colors,
styleItem->transformation);
styleItem->transformer);
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>
void
IconRenderer::StyleHandler::_GenerateGradient(agg::rgba8* span, int x, int y,
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::span_interpolator_linear<> Interpolator;
typedef agg::span_gradient<agg::rgba8,
Interpolator,
GradientFunction,
ColorArray> GradientGenerator;
Interpolator interpolator(gradientTransform);
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
void
IconRenderer::StyleHandler::_GenerateImage(agg::rgba8* span, int x, int y,
unsigned len, Style* style, Transformation& transform)
unsigned len, const Style* style, StyleTransformer* transformer)
{
// bitmap
BBitmap* bbitmap = style->Bitmap();
@@ -252,13 +348,16 @@ IconRenderer::StyleHandler::_GenerateImage(agg::rgba8* span, int x, int y,
PixelFormat pixf_img(bitmap);
// image interpolator
typedef agg::span_interpolator_linear<> interpolator_type;
interpolator_type interpolator(transform);
// TODO: performance could be improved by using agg_interpolator_linear
// 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
typedef agg::image_accessor_wrap<PixelFormat,
agg::wrap_mode_repeat, agg::wrap_mode_repeat> source_type;
source_type source(pixf_img);
typedef agg::image_accessor_clip<PixelFormat> source_type;
agg::rgba8 background(0, 0, 0, 0);
source_type source(pixf_img, background);
// image filter (nearest neighbor)
typedef agg::span_image_filter_rgba_nn<
@@ -424,7 +523,7 @@ IconRenderer::Demultiply()
// #pragma mark -
typedef agg::conv_transform<VertexSource, Transformation> ScaledPath;
typedef agg::conv_transform<VertexSource, Transformable> ScaledPath;
typedef agg::conv_transform<ScaledPath, HintingTransformer> HintedPath;
@@ -467,11 +566,8 @@ IconRenderer::_Render(const BRect& r)
continue;
}
Transformation transform(*shape);
Transformable transform(*shape);
transform.multiply(fGlobalTransform);
// NOTE: this works only because "agg::trans_affine",
// "Transformable" and "Transformation" are all the
// same thing
Style* style = shape->Style();
if (!style)
@@ -483,9 +579,11 @@ IconRenderer::_Render(const BRect& r)
Gradient* gradient = style->Gradient();
bool styleAdded = false;
if (gradient && !gradient->InheritTransformation()) {
styleAdded = styleHandler.AddStyle(style, fGlobalTransform);
styleAdded = styleHandler.AddStyle(
style, fGlobalTransform, NULL);
} else {
styleAdded = styleHandler.AddStyle(style, transform);
styleAdded = styleHandler.AddStyle(
style, transform, shape->Transformers());
}
if (!styleAdded) {
+2 -3
View File
@@ -21,6 +21,7 @@
#include <agg_trans_affine.h>
#include "IconBuild.h"
#include "Transformable.h"
class BBitmap;
@@ -47,8 +48,6 @@ typedef agg::span_allocator<agg::rgba8> SpanAllocator;
typedef agg::rasterizer_compound_aa
<agg::rasterizer_sl_clip_dbl> CompoundRasterizer;
typedef agg::trans_affine Transformation;
class IconRenderer {
public:
IconRenderer(BBitmap* bitmap);
@@ -110,7 +109,7 @@ class IconRenderer {
CompoundRasterizer fRasterizer;
Transformation fGlobalTransform;
Transformable fGlobalTransform;
};
+2 -1
View File
@@ -59,11 +59,12 @@ for architectureObject in [ MultiArchSubDirSetup ] {
# transformer
AffineTransformer.cpp
CompoundStyleTransformer.cpp
ContourTransformer.cpp
PathSource.cpp
PerspectiveTransformer.cpp
StrokeTransformer.cpp
Transformer.cpp
StyleTransformer.cpp
TransformerFactory.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.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#include "FlatIconImporter.h"
@@ -435,7 +436,7 @@ FlatIconImporter::_ParsePaths(LittleEndianBuffer& buffer,
// _ReadTransformer
static Transformer*
_ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source)
_ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source, Shape* shape)
{
uint8 transformerType;
if (!buffer.Read(transformerType))
@@ -479,9 +480,19 @@ _ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source)
}
case TRANSFORMER_TYPE_PERSPECTIVE: {
PerspectiveTransformer* perspective
= new (nothrow) PerspectiveTransformer(source);
// TODO: upgrade AGG to be able to support storage of
// trans_perspective
= new (nothrow) PerspectiveTransformer(source, shape);
if (!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;
}
case TRANSFORMER_TYPE_STROKE: {
@@ -601,7 +612,7 @@ FlatIconImporter::_ReadPathSourceShape(LittleEndianBuffer& buffer,
return NULL;
for (uint32 i = 0; i < transformerCount; i++) {
Transformer* transformer
= _ReadTransformer(buffer, shape->VertexSource());
= _ReadTransformer(buffer, shape->VertexSource(), shape);
if (transformer && !shape->Transformers()->AddItem(transformer)) {
delete transformer;
return NULL;
@@ -651,7 +662,3 @@ FlatIconImporter::_ParseShapes(LittleEndianBuffer& buffer,
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"
#endif // ICON_O_MATIC
#include "Container.h"
#include "PathTransformer.h"
#include "Style.h"
#include "TransformerFactory.h"
#include "VectorPath.h"
@@ -130,7 +131,7 @@ Shape::Shape(const Shape& other)
int32 count = other.Transformers()->CountItems();
for (int32 i = 0; i < count; i++) {
Transformer* original = other.Transformers()->ItemAtFast(i);
Transformer* cloned = original->Clone(fPathSource);
Transformer* cloned = original->Clone();
if (!fTransformers.AddItem(cloned)) {
delete cloned;
break;
@@ -181,7 +182,7 @@ Shape::Unarchive(BMessage* archive)
i++) {
Transformer* transformer
= TransformerFactory::TransformerFor(
&transformerArchive, VertexSource());
&transformerArchive, VertexSource(), this);
if (!transformer || !fTransformers.AddItem(transformer)) {
delete transformer;
}
@@ -452,9 +453,11 @@ Shape::VertexSource()
int32 count = fTransformers.CountItems();
for (int32 i = 0; i < count; i++) {
Transformer* t = (Transformer*)fTransformers.ItemAtFast(i);
t->SetSource(*source);
source = t;
PathTransformer* t = dynamic_cast<PathTransformer*>(fTransformers.ItemAtFast(i));
if (t != NULL) {
t->SetSource(*source);
source = t;
}
}
if (fNeedsUpdate) {
+1 -1
View File
@@ -86,7 +86,7 @@ class Style {
// alpha only applies to bitmaps
void SetAlpha(uint8 alpha)
{ fAlpha = alpha; Notify(); }
uint8 Alpha()
uint8 Alpha() const
{ return fAlpha; }
#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.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#include "Transformable.h"
@@ -11,31 +12,78 @@
#include <stdio.h>
#include <string.h>
// constructor
Transformable::Transformable()
: agg::trans_affine()
{
}
// copy constructor
Transformable::Transformable(const Transformable& other)
: agg::trans_affine(other)
{
}
// destructor
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
Transformable::StoreTo(double matrix[matrix_size]) const
{
store_to(matrix);
}
// LoadFrom
void
Transformable::LoadFrom(const double matrix[matrix_size])
{
@@ -50,7 +98,7 @@ Transformable::LoadFrom(const double matrix[matrix_size])
}
}
// SetTransform
void
Transformable::SetTransform(const Transformable& other)
{
@@ -60,7 +108,7 @@ Transformable::SetTransform(const Transformable& other)
}
}
// operator=
Transformable&
Transformable::operator=(const Transformable& other)
{
@@ -72,7 +120,7 @@ Transformable::operator=(const Transformable& other)
return *this;
}
// Multiply
Transformable&
Transformable::Multiply(const Transformable& other)
{
@@ -83,7 +131,7 @@ Transformable::Multiply(const Transformable& other)
return *this;
}
// Reset
void
Transformable::Reset()
{
@@ -93,17 +141,7 @@ Transformable::Reset()
}
}
// Invert
void
Transformable::Invert()
{
if (!IsIdentity()) {
invert();
TransformationChanged();
}
}
// IsIdentity
bool
Transformable::IsIdentity() const
{
@@ -119,7 +157,7 @@ Transformable::IsIdentity() const
return false;
}
// IsTranslationOnly
bool
Transformable::IsTranslationOnly() const
{
@@ -133,7 +171,7 @@ Transformable::IsTranslationOnly() const
return false;
}
// IsNotDistorted
bool
Transformable::IsNotDistorted() const
{
@@ -142,7 +180,7 @@ Transformable::IsNotDistorted() const
return (m[0] == m[3]);
}
// IsValid
bool
Transformable::IsValid() const
{
@@ -151,7 +189,7 @@ Transformable::IsValid() const
return ((m[0] * m[3] - m[1] * m[2]) != 0.0);
}
// operator==
bool
Transformable::operator==(const Transformable& other) const
{
@@ -162,74 +200,13 @@ Transformable::operator==(const Transformable& other) const
return memcmp(m1, m2, sizeof(m1)) == 0;
}
// operator!=
bool
Transformable::operator!=(const Transformable& other) const
{
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
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)));
}
inline float
max4(float a, float b, float c, float d)
{
return max_c(a, max_c(b, max_c(c, d)));
}
// TransformBounds
BRect
Transformable::TransformBounds(BRect bounds) const
{
@@ -253,10 +231,10 @@ Transformable::TransformBounds(BRect bounds) const
BPoint lb(bounds.left, bounds.bottom);
BPoint rb(bounds.right, bounds.bottom);
Transform(&lt);
Transform(&rt);
Transform(&lb);
Transform(&rb);
StyleTransformer::Transform(&lt);
StyleTransformer::Transform(&rt);
StyleTransformer::Transform(&lb);
StyleTransformer::Transform(&rb);
return BRect(floorf(min4(lt.x, rt.x, lb.x, rb.x)),
floorf(min4(lt.y, rt.y, lb.y, rb.y)),
@@ -266,7 +244,7 @@ Transformable::TransformBounds(BRect bounds) const
return bounds;
}
// TranslateBy
void
Transformable::TranslateBy(BPoint offset)
{
@@ -276,7 +254,7 @@ Transformable::TranslateBy(BPoint offset)
}
}
// RotateBy
void
Transformable::RotateBy(BPoint origin, double degrees)
{
@@ -288,7 +266,7 @@ Transformable::RotateBy(BPoint origin, double degrees)
}
}
// ScaleBy
void
Transformable::ScaleBy(BPoint origin, double xScale, double yScale)
{
@@ -300,7 +278,7 @@ Transformable::ScaleBy(BPoint origin, double xScale, double yScale)
}
}
// ShearBy
void
Transformable::ShearBy(BPoint origin, double xShear, double yShear)
{
@@ -312,7 +290,7 @@ Transformable::ShearBy(BPoint origin, double xShear, double yShear)
}
}
// TransformationChanged
void
Transformable::TransformationChanged()
{
+20 -14
View File
@@ -1,9 +1,10 @@
/*
* Copyright 2006, Haiku.
* Copyright 2006, 2023, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#ifndef TRANSFORMABLE_H
@@ -14,12 +15,17 @@
#include <agg_trans_affine.h>
#include "IconBuild.h"
#include "StyleTransformer.h"
#include "Transformer.h"
_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:
enum {
matrix_size = 6,
@@ -29,6 +35,18 @@ class Transformable : public agg::trans_affine {
Transformable(const Transformable& other);
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 LoadFrom(const double matrix[matrix_size]);
@@ -38,8 +56,6 @@ class Transformable : public agg::trans_affine {
Transformable& Multiply(const Transformable& other);
virtual void Reset();
void Invert();
bool IsIdentity() const;
bool IsTranslationOnly() 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;
// 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
// returns the *bounding box* of that
BRect TransformBounds(BRect bounds) const;
@@ -82,4 +89,3 @@ _USING_ICON_NAMESPACE
#endif // TRANSFORMABLE_H
@@ -26,7 +26,8 @@ using std::nothrow;
// constructor
AffineTransformer::AffineTransformer(VertexSource& source)
: Transformer(source, "Transformation"),
: Transformer("Transformation"),
PathTransformer(source),
Affine(source, *this)
{
}
@@ -34,7 +35,8 @@ AffineTransformer::AffineTransformer(VertexSource& source)
// constructor
AffineTransformer::AffineTransformer(VertexSource& source,
BMessage* archive)
: Transformer(source, archive),
: Transformer(archive),
PathTransformer(source),
Affine(source, *this)
{
if (!archive)
@@ -57,9 +59,9 @@ AffineTransformer::~AffineTransformer()
// Clone
Transformer*
AffineTransformer::Clone(VertexSource& source) const
AffineTransformer::Clone() const
{
AffineTransformer* clone = new (nothrow) AffineTransformer(source);
AffineTransformer* clone = new (nothrow) AffineTransformer(fSource);
if (clone)
clone->multiply(*this);
return clone;
@@ -83,7 +85,7 @@ AffineTransformer::vertex(double* x, double* y)
void
AffineTransformer::SetSource(VertexSource& source)
{
Transformer::SetSource(source);
PathTransformer::SetSource(source);
Affine::attach(source);
}
@@ -10,6 +10,7 @@
#include "IconBuild.h"
#include "PathTransformer.h"
#include "Transformer.h"
#include <agg_conv_transform.h>
@@ -23,6 +24,7 @@ typedef agg::conv_transform<VertexSource,
agg::trans_affine> Affine;
class AffineTransformer : public Transformer,
public PathTransformer,
public Affine,
public agg::trans_affine {
public:
@@ -38,8 +40,10 @@ class AffineTransformer : public Transformer,
virtual ~AffineTransformer();
virtual Transformer* Clone(VertexSource& source) const;
// Transformer interface
virtual Transformer* Clone() const;
// PathTransformer interface
virtual void rewind(unsigned path_id);
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
ContourTransformer::ContourTransformer(VertexSource& source)
: Transformer(source, "Contour"),
: Transformer("Contour"),
PathTransformer(source),
Contour(source)
{
auto_detect_orientation(true);
@@ -36,7 +37,8 @@ ContourTransformer::ContourTransformer(VertexSource& source)
// constructor
ContourTransformer::ContourTransformer(VertexSource& source,
BMessage* archive)
: Transformer(source, archive),
: Transformer(archive),
PathTransformer(source),
Contour(source)
{
auto_detect_orientation(true);
@@ -69,9 +71,9 @@ ContourTransformer::~ContourTransformer()
// Clone
Transformer*
ContourTransformer::Clone(VertexSource& source) const
ContourTransformer::Clone() const
{
ContourTransformer* clone = new (nothrow) ContourTransformer(source);
ContourTransformer* clone = new (nothrow) ContourTransformer(fSource);
if (clone) {
clone->line_join(line_join());
clone->inner_join(inner_join());
@@ -101,7 +103,7 @@ ContourTransformer::vertex(double* x, double* y)
void
ContourTransformer::SetSource(VertexSource& source)
{
Transformer::SetSource(source);
PathTransformer::SetSource(source);
Contour::attach(source);
}
@@ -10,6 +10,7 @@
#include "IconBuild.h"
#include "PathTransformer.h"
#include "Transformer.h"
#include <agg_conv_contour.h>
@@ -21,6 +22,7 @@ _BEGIN_ICON_NAMESPACE
typedef agg::conv_contour<VertexSource> Contour;
class ContourTransformer : public Transformer,
public PathTransformer,
public Contour {
public:
enum {
@@ -35,10 +37,12 @@ class ContourTransformer : public Transformer,
virtual ~ContourTransformer();
virtual Transformer* Clone(VertexSource& source) const;
// Transformer interface
virtual Transformer* Clone() const;
// PathTransformer interface
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);
@@ -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.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#include "PerspectiveTransformer.h"
#ifdef ICON_O_MATIC
# include <Message.h>
#endif
#include <new>
#include <stdio.h>
#include <agg_basics.h>
#include <agg_bounding_rect.h>
#include <Message.h>
#include "Shape.h"
_USING_ICON_NAMESPACE
using std::nothrow;
// constructor
PerspectiveTransformer::PerspectiveTransformer(VertexSource& source)
: Transformer(source, "Perspective"),
Perspective(source, *this)
PerspectiveTransformer::PerspectiveTransformer(VertexSource& source, Shape* shape)
: Transformer("Perspective"),
PathTransformer(source),
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,
BMessage* archive)
: Transformer(source, archive),
Perspective(source, *this)
PerspectiveTransformer::PerspectiveTransformer(
VertexSource& source, Shape* shape, BMessage* archive)
: Transformer(archive),
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()
{
}
// Clone
Transformer*
PerspectiveTransformer::Clone(VertexSource& source) const
{
PerspectiveTransformer* clone
= new (nothrow) PerspectiveTransformer(source);
if (clone) {
// TODO: upgrade AGG
// clone->multiply(*this);
#ifdef ICON_O_MATIC
if (fShape != NULL) {
fShape->RemoveObserver(this);
fShape->ReleaseReference();
}
return clone;
#endif
}
// rewind
// #pragma mark -
Transformer*
PerspectiveTransformer::Clone() const
{
return new (nothrow) PerspectiveTransformer(*this);
}
// #pragma mark -
void
PerspectiveTransformer::rewind(unsigned path_id)
{
Perspective::rewind(path_id);
}
// vertex
unsigned
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);
#endif
}
// SetSource
void
PerspectiveTransformer::SetSource(VertexSource& source)
{
Transformer::SetSource(source);
PathTransformer::SetSource(source);
Perspective::attach(source);
#ifdef ICON_O_MATIC
ObjectChanged(fShape);
#endif
}
// ApproximationScale
double
PerspectiveTransformer::ApproximationScale() const
{
// TODO: upgrade AGG
return fSource.ApproximationScale();// * scale();
return fSource.ApproximationScale() * scale();
}
// #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
// Archive
status_t
PerspectiveTransformer::Archive(BMessage* into, bool deep) const
{
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;
}
// #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
@@ -1,46 +1,76 @@
/*
* Copyright 2006-2007, Haiku.
* Copyright 2006-2007, 2023, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Zardshard
*/
#ifndef PERSPECTIVE_TRANSFORMER_H
#define PERSPECTIVE_TRANSFORMER_H
#include "IconBuild.h"
#include "Transformer.h"
#include <Rect.h>
#include <Point.h>
#include <agg_conv_transform.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
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,
public PathTransformer,
public StyleTransformer,
#ifdef ICON_O_MATIC
public Observer,
#endif
public Perspective,
public agg::trans_perspective {
public:
public:
enum {
archive_code = 'prsp',
};
PerspectiveTransformer(
VertexSource& source);
/*! Initializes starting with the identity transformation.
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(
VertexSource& source,
Shape* shape);
PerspectiveTransformer(
VertexSource& source,
Shape* shape,
BMessage* archive);
PerspectiveTransformer(
const PerspectiveTransformer& other);
virtual ~PerspectiveTransformer();
// Transformer interface
virtual Transformer* Clone(VertexSource& source) const;
virtual Transformer* Clone() const;
// PathTransformer interface
virtual void rewind(unsigned path_id);
virtual unsigned vertex(double* x, double* y);
@@ -48,11 +78,55 @@ class PerspectiveTransformer : public Transformer,
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
// IconObject interface
virtual status_t Archive(BMessage* into,
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
};
@@ -27,7 +27,8 @@ using std::nothrow;
// constructor
StrokeTransformer::StrokeTransformer(VertexSource& source)
: Transformer(source, "Stroke"),
: Transformer("Stroke"),
PathTransformer(source),
Stroke(source)
{
}
@@ -35,7 +36,8 @@ StrokeTransformer::StrokeTransformer(VertexSource& source)
// constructor
StrokeTransformer::StrokeTransformer(VertexSource& source,
BMessage* archive)
: Transformer(source, archive),
: Transformer(archive),
PathTransformer(source),
Stroke(source)
{
if (!archive)
@@ -72,9 +74,9 @@ StrokeTransformer::~StrokeTransformer()
// Clone
Transformer*
StrokeTransformer::Clone(VertexSource& source) const
StrokeTransformer::Clone() const
{
StrokeTransformer* clone = new (nothrow) StrokeTransformer(source);
StrokeTransformer* clone = new (nothrow) StrokeTransformer(fSource);
if (clone) {
clone->line_cap(line_cap());
clone->line_join(line_join());
@@ -105,7 +107,7 @@ StrokeTransformer::vertex(double* x, double* y)
void
StrokeTransformer::SetSource(VertexSource& source)
{
Transformer::SetSource(source);
PathTransformer::SetSource(source);
Stroke::attach(source);
}
@@ -10,6 +10,7 @@
#include "IconBuild.h"
#include "PathTransformer.h"
#include "Transformer.h"
#include <agg_conv_stroke.h>
@@ -21,6 +22,7 @@ _BEGIN_ICON_NAMESPACE
typedef agg::conv_stroke<VertexSource> Stroke;
class StrokeTransformer : public Transformer,
public PathTransformer,
public Stroke {
public:
enum {
@@ -36,8 +38,9 @@ class StrokeTransformer : public Transformer,
virtual ~StrokeTransformer();
// Transformer interface
virtual Transformer* Clone(VertexSource& source) const;
virtual Transformer* Clone() const;
// PathTransformer interface
virtual void rewind(unsigned path_id);
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
#include "IconBuild.h"
#include "VertexSource.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;
};
/*! Base class for all transformers.
All child classes should inherit either PathTransformer, StyleTransformer,
or both.
*/
#ifdef ICON_O_MATIC
class Transformer : public VertexSource,
public IconObject {
class Transformer : public IconObject {
#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
public:
Transformer(VertexSource& source,
const char* name);
Transformer(VertexSource& source,
BMessage* archive);
virtual ~Transformer();
virtual ~Transformer() {}
// Transformer
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;
virtual Transformer* Clone() const = 0;
};
@@ -11,6 +11,7 @@
#include "AffineTransformer.h"
#include "ContourTransformer.h"
#include "PerspectiveTransformer.h"
#include "Shape.h"
#include "StrokeTransformer.h"
#ifdef ICON_O_MATIC
@@ -24,13 +25,13 @@ _USING_ICON_NAMESPACE
// TransformerFor
Transformer*
TransformerFactory::TransformerFor(uint32 type, VertexSource& source)
TransformerFactory::TransformerFor(uint32 type, VertexSource& source, Shape* shape)
{
switch (type) {
case AFFINE_TRANSFORMER:
return new AffineTransformer(source);
case PERSPECTIVE_TRANSFORMER:
return new PerspectiveTransformer(source);
return new PerspectiveTransformer(source, shape);
case CONTOUR_TRANSFORMER:
return new ContourTransformer(source);
case STROKE_TRANSFORMER:
@@ -42,14 +43,13 @@ TransformerFactory::TransformerFor(uint32 type, VertexSource& source)
// TransformerFor
Transformer*
TransformerFactory::TransformerFor(BMessage* message,
VertexSource& source)
TransformerFactory::TransformerFor(BMessage* message, VertexSource& source, Shape* shape)
{
switch (message->what) {
case AffineTransformer::archive_code:
return new AffineTransformer(source, message);
case PerspectiveTransformer::archive_code:
return new PerspectiveTransformer(source, message);
return new PerspectiveTransformer(source, shape, message);
case ContourTransformer::archive_code:
return new ContourTransformer(source, message);
case StrokeTransformer::archive_code:
@@ -20,6 +20,7 @@ class BMessage;
_BEGIN_ICON_NAMESPACE
class Shape;
class Transformer;
class VertexSource;
@@ -35,10 +36,12 @@ class TransformerFactory {
public:
static Transformer* TransformerFor(uint32 type,
VertexSource& source);
VertexSource& source,
Shape* shape);
static Transformer* TransformerFor(BMessage* archive,
VertexSource& source);
VertexSource& source,
Shape* shape);
};