From f87303c58fee0e8af819372386843111432ab444 Mon Sep 17 00:00:00 2001 From: Paul Manias Date: Mon, 24 Feb 2025 21:10:50 +0000 Subject: [PATCH] [Vectors] Scene defs will now respond to drawing updates when their state is modified. --- src/vector/painters/gradient.cpp | 88 +++++++++++++++++++------- src/vector/painters/image.cpp | 68 ++++++++++++++++---- src/vector/painters/pattern.cpp | 21 +++++- src/vector/scene/scene.cpp | 26 ++++---- src/vector/scene/scene_draw.cpp | 6 ++ src/vector/transformers/transition.cpp | 3 +- src/vector/vector.h | 27 ++++++-- src/vector/vectors/path.cpp | 15 ++++- 8 files changed, 195 insertions(+), 59 deletions(-) diff --git a/src/vector/painters/gradient.cpp b/src/vector/painters/gradient.cpp index cb722481..714eed7a 100644 --- a/src/vector/painters/gradient.cpp +++ b/src/vector/painters/gradient.cpp @@ -31,7 +31,7 @@ GRADIENT_TABLE * get_fill_gradient_table(extPainter &Painter, DOUBLE Opacity) GradientColours *cols = ((extVectorGradient *)Painter.Gradient)->Colours; if (!cols) { log.warning("No colour table in gradient %p.", Painter.Gradient); - return NULL; + return nullptr; } if (Opacity >= 1.0) { // Return the original gradient table if no translucency is applicable. @@ -45,7 +45,7 @@ GRADIENT_TABLE * get_fill_gradient_table(extPainter &Painter, DOUBLE Opacity) Painter.GradientTable = new (std::nothrow) GRADIENT_TABLE(); if (!Painter.GradientTable) { log.warning("Failed to allocate fill gradient table"); - return NULL; + return nullptr; } Painter.GradientAlpha = Opacity; @@ -68,7 +68,7 @@ GRADIENT_TABLE * get_stroke_gradient_table(extVector &Vector) if (!cols) { if (!cols) { log.warning("No colour table referenced in stroke gradient %p for vector #%d.", Vector.Stroke.Gradient, Vector.UID); - return NULL; + return nullptr; } } @@ -84,7 +84,7 @@ GRADIENT_TABLE * get_stroke_gradient_table(extVector &Vector) Vector.Stroke.GradientTable = new (std::nothrow) GRADIENT_TABLE(); if (!Vector.Stroke.GradientTable) { log.warning("Failed to allocate stroke gradient table"); - return NULL; + return nullptr; } Vector.Stroke.GradientAlpha = opacity; @@ -151,8 +151,8 @@ GradientColours::GradientColours(const std::array &Map, double Resolu static ERR VECTORGRADIENT_Free(extVectorGradient *Self) { - if (Self->ID) { FreeResource(Self->ID); Self->ID = NULL; } - if (Self->Colours) { delete Self->Colours; Self->Colours = NULL; } + if (Self->ID) { FreeResource(Self->ID); Self->ID = nullptr; } + if (Self->Colours) { delete Self->Colours; Self->Colours = nullptr; } Self->Stops.~vector(); Self->ColourMap.~basic_string(); @@ -161,7 +161,7 @@ static ERR VECTORGRADIENT_Free(extVectorGradient *Self) next = node->Next; FreeResource(node); } - Self->Matrices = NULL; + Self->Matrices = nullptr; return ERR::Okay; } @@ -231,6 +231,7 @@ static ERR VECTORGRADIENT_SET_CenterX(extVectorGradient *Self, Unit &Value) if (Value.scaled()) Self->Flags = (Self->Flags | VGF::SCALED_CX) & (~VGF::FIXED_CX); else Self->Flags = (Self->Flags | VGF::FIXED_CX) & (~VGF::SCALED_CX); Self->CenterX = Value; + Self->modified(); return ERR::Okay; } @@ -256,6 +257,7 @@ static ERR VECTORGRADIENT_SET_CenterY(extVectorGradient *Self, Unit &Value) else Self->Flags = (Self->Flags | VGF::FIXED_CY) & (~VGF::SCALED_CY); Self->CenterY = Value; + Self->modified(); return ERR::Okay; } @@ -298,6 +300,8 @@ static ERR VECTORGRADIENT_SET_Colour(extVectorGradient *Self, FLOAT *Value, LONG else return log.warning(ERR::InvalidValue); } else Self->Colour.Alpha = 0; + + Self->modified(); return ERR::Okay; } /********************************************************************************************************************* @@ -319,7 +323,7 @@ The use of colourmaps and custom stops are mutually exclusive. static ERR VECTORGRADIENT_GET_ColourMap(extVectorGradient *Self, CSTRING *Value) { if (!Self->ColourMap.empty()) *Value = Self->ColourMap.c_str(); - else *Value = NULL; + else *Value = nullptr; return ERR::Okay; } @@ -332,6 +336,7 @@ static ERR VECTORGRADIENT_SET_ColourMap(extVectorGradient *Self, CSTRING Value) Self->Colours = new (std::nothrow) GradientColours(glColourMaps[Value], Self->Resolution); if (!Self->Colours) return ERR::AllocMemory; Self->ColourMap = Value; + Self->modified(); return ERR::Okay; } else return ERR::NotFound; @@ -376,6 +381,7 @@ static ERR VECTORGRADIENT_SET_FocalRadius(extVectorGradient *Self, Unit &Value) else Self->Flags = (Self->Flags | VGF::FIXED_FOCAL_RADIUS) & (~VGF::SCALED_FOCAL_RADIUS); Self->FocalRadius = Value; + Self->modified(); return ERR::Okay; } else return ERR::OutOfRange; @@ -403,6 +409,7 @@ static ERR VECTORGRADIENT_SET_FocalX(extVectorGradient *Self, Unit &Value) else Self->Flags = (Self->Flags | VGF::FIXED_FX) & (~VGF::SCALED_FX); Self->FocalX = Value; + Self->modified(); return ERR::Okay; } @@ -428,6 +435,7 @@ static ERR VECTORGRADIENT_SET_FocalY(extVectorGradient *Self, Unit &Value) else Self->Flags = (Self->Flags | VGF::FIXED_FY) & (~VGF::SCALED_FY); Self->FocalY = Value; + Self->modified(); return ERR::Okay; } @@ -455,7 +463,7 @@ static ERR VECTORGRADIENT_SET_ID(extVectorGradient *Self, CSTRING Value) Self->NumericID = strhash(Value); } else { - Self->ID = NULL; + Self->ID = nullptr; Self->NumericID = 0; } return ERR::Okay; @@ -485,8 +493,8 @@ static ERR VECTORGRADIENT_SET_Matrices(extVectorGradient *Self, VectorMatrix *Va while (Value) { VectorMatrix *matrix; if (AllocMemory(sizeof(VectorMatrix), MEM::DATA|MEM::NO_CLEAR, &matrix) IS ERR::Okay) { - matrix->Vector = NULL; - matrix->Next = NULL; + matrix->Vector = nullptr; + matrix->Next = nullptr; matrix->ScaleX = Value->ScaleX; matrix->ScaleY = Value->ScaleY; matrix->ShearX = Value->ShearX; @@ -507,9 +515,10 @@ static ERR VECTORGRADIENT_SET_Matrices(extVectorGradient *Self, VectorMatrix *Va next = node->Next; FreeResource(node); } - Self->Matrices = NULL; + Self->Matrices = nullptr; } + Self->modified(); return ERR::Okay; } @@ -534,7 +543,7 @@ static ERR VECTORGRADIENT_GET_NumericID(extVectorGradient *Self, LONG *Value) static ERR VECTORGRADIENT_SET_NumericID(extVectorGradient *Self, LONG Value) { Self->NumericID = Value; - if (Self->ID) { FreeResource(Self->ID); Self->ID = NULL; } + if (Self->ID) { FreeResource(Self->ID); Self->ID = nullptr; } return ERR::Okay; } @@ -562,6 +571,7 @@ static ERR VECTORGRADIENT_SET_Radius(extVectorGradient *Self, Unit &Value) else Self->Flags = (Self->Flags | VGF::FIXED_RADIUS) & (~VGF::SCALED_RADIUS); Self->Radius = Value; + Self->modified(); return ERR::Okay; } else return ERR::OutOfRange; @@ -589,6 +599,7 @@ static ERR VECTORGRADIENT_SET_Resolution(extVectorGradient *Self, double Value) if ((Self->Colours) and (Self->Colours->resolution != Value)) { if (Self->initialised()) { + Self->modified(); if (!Self->Stops.empty()) { auto copy = Self->Stops; VECTORGRADIENT_SET_Stops(Self, copy.data(), copy.size()); @@ -606,10 +617,21 @@ static ERR VECTORGRADIENT_SET_Resolution(extVectorGradient *Self, double Value) /********************************************************************************************************************* -FIELD- -SpreadMethod: The behaviour to use when the gradient bounds do not match the vector path. +SpreadMethod: Determines the rendering behaviour to use when gradient colours are cycled. + +SpreadMethod determines what happens when the first cycle of gradient colours is exhausted and needs to begin again. +The default setting is `VSPREAD::PAD`. -Indicates what happens if the gradient starts or ends inside the bounds of the target vector. The default is -`VSPREAD::PAD`. Other valid options for gradients are `REFLECT`, `REPEAT` and `CLIP`. +*********************************************************************************************************************/ + +static ERR VECTORGRADIENT_SET_SpreadMethod(extVectorGradient *Self, VSPREAD Value) +{ + Self->SpreadMethod = Value; + Self->modified(); + return ERR::Okay; +} + +/********************************************************************************************************************* -FIELD- Stops: Defines the colours to use for the gradient. @@ -631,6 +653,7 @@ static ERR VECTORGRADIENT_SET_Stops(extVectorGradient *Self, GradientStop *Value Self->Stops.clear(); if (Elements >= 2) { + Self->modified(); Self->Stops.insert(Self->Stops.end(), &Value[0], &Value[Elements]); if (Self->Colours) delete Self->Colours; Self->Colours = new (std::nothrow) GradientColours(Self->Stops, Self->ColourSpace, 1.0, Self->Resolution); @@ -671,11 +694,13 @@ static ERR VECTORGRADIENT_SET_Transform(extVectorGradient *Self, CSTRING Command pf::Log log; if (!Commands) return log.warning(ERR::InvalidValue); + + Self->modified(); if (!Self->Matrices) { VectorMatrix *matrix; if (AllocMemory(sizeof(VectorMatrix), MEM::DATA|MEM::NO_CLEAR, &matrix) IS ERR::Okay) { - matrix->Vector = NULL; + matrix->Vector = nullptr; matrix->Next = Self->Matrices; matrix->ScaleX = 1.0; matrix->ScaleY = 1.0; @@ -703,6 +728,17 @@ Lookup: VGT The type of the gradient to be drawn is specified here. +*********************************************************************************************************************/ + +static ERR VECTORGRADIENT_SET_Type(extVectorGradient *Self, VGT Value) +{ + Self->Type = Value; + Self->modified(); + return ERR::Okay; +} + +/********************************************************************************************************************* + -FIELD- Units: Defines the coordinate system for #X1, #Y1, #X2 and #Y2. @@ -733,6 +769,7 @@ static ERR VECTORGRADIENT_SET_X1(extVectorGradient *Self, Unit &Value) else Self->Flags = (Self->Flags | VGF::FIXED_X1) & (~VGF::SCALED_X1); Self->X1 = Value; Self->CalcAngle = true; + Self->modified(); return ERR::Okay; } @@ -761,6 +798,7 @@ static ERR VECTORGRADIENT_SET_X2(extVectorGradient *Self, Unit &Value) else Self->Flags = (Self->Flags | VGF::FIXED_X2) & (~VGF::SCALED_X2); Self->X2 = Value; Self->CalcAngle = true; + Self->modified(); return ERR::Okay; } @@ -787,6 +825,7 @@ static ERR VECTORGRADIENT_SET_Y1(extVectorGradient *Self, Unit &Value) else Self->Flags = (Self->Flags | VGF::FIXED_Y1) & (~VGF::SCALED_Y1); Self->Y1 = Value; Self->CalcAngle = true; + Self->modified(); return ERR::Okay; } @@ -813,6 +852,7 @@ static ERR VECTORGRADIENT_SET_Y2(extVectorGradient *Self, Unit &Value) else Self->Flags = (Self->Flags | VGF::FIXED_Y2) & (~VGF::SCALED_Y2); Self->Y2 = Value; Self->CalcAngle = true; + Self->modified(); return ERR::Okay; } @@ -831,12 +871,12 @@ static const FieldArray clGradientFields[] = { { "FocalY", FDF_UNIT|FDF_DOUBLE|FDF_SCALED|FDF_RW, VECTORGRADIENT_GET_FocalY, VECTORGRADIENT_SET_FocalY }, { "Radius", FDF_UNIT|FDF_DOUBLE|FDF_SCALED|FDF_RW, VECTORGRADIENT_GET_Radius, VECTORGRADIENT_SET_Radius }, { "FocalRadius", FDF_UNIT|FDF_DOUBLE|FDF_SCALED|FDF_RW, VECTORGRADIENT_GET_FocalRadius, VECTORGRADIENT_SET_FocalRadius }, - { "Resolution", FDF_DOUBLE|FDF_RW, NULL, VECTORGRADIENT_SET_Resolution }, - { "SpreadMethod", FDF_LONG|FDF_LOOKUP|FDF_RW, NULL, NULL, &clVectorGradientSpreadMethod }, - { "Units", FDF_LONG|FDF_LOOKUP|FDF_RI, NULL, NULL, &clVectorGradientUnits }, - { "Type", FDF_LONG|FDF_LOOKUP|FDF_RW, NULL, NULL, &clVectorGradientType }, - { "Flags", FDF_LONGFLAGS|FDF_RW, NULL, NULL, &clVectorGradientFlags }, - { "ColourSpace", FDF_LONG|FDF_RI, NULL, NULL, &clVectorGradientColourSpace }, + { "Resolution", FDF_DOUBLE|FDF_RW, nullptr, VECTORGRADIENT_SET_Resolution }, + { "SpreadMethod", FDF_LONG|FDF_LOOKUP|FDF_RW, nullptr, VECTORGRADIENT_SET_SpreadMethod, &clVectorGradientSpreadMethod }, + { "Units", FDF_LONG|FDF_LOOKUP|FDF_RI, nullptr, nullptr, &clVectorGradientUnits }, + { "Type", FDF_LONG|FDF_LOOKUP|FDF_RW, nullptr, VECTORGRADIENT_SET_Type, &clVectorGradientType }, + { "Flags", FDF_LONGFLAGS|FDF_RW, nullptr, nullptr, &clVectorGradientFlags }, + { "ColourSpace", FDF_LONG|FDF_RI, nullptr, nullptr, &clVectorGradientColourSpace }, // Virtual fields { "Colour", FDF_VIRTUAL|FD_FLOAT|FDF_ARRAY|FD_RW, VECTORGRADIENT_GET_Colour, VECTORGRADIENT_SET_Colour }, { "ColourMap", FDF_VIRTUAL|FDF_STRING|FDF_W, VECTORGRADIENT_GET_ColourMap, VECTORGRADIENT_SET_ColourMap }, @@ -849,7 +889,7 @@ static const FieldArray clGradientFields[] = { { "ID", FDF_VIRTUAL|FDF_STRING|FDF_RW, VECTORGRADIENT_GET_ID, VECTORGRADIENT_SET_ID }, { "Stops", FDF_VIRTUAL|FDF_ARRAY|FDF_STRUCT|FDF_RW, VECTORGRADIENT_GET_Stops, VECTORGRADIENT_SET_Stops, "GradientStop" }, { "TotalStops", FDF_LONG|FDF_R, VECTORGRADIENT_GET_TotalStops }, - { "Transform", FDF_VIRTUAL|FDF_STRING|FDF_W, NULL, VECTORGRADIENT_SET_Transform }, + { "Transform", FDF_VIRTUAL|FDF_STRING|FDF_W, nullptr, VECTORGRADIENT_SET_Transform }, END_FIELD }; diff --git a/src/vector/painters/image.cpp b/src/vector/painters/image.cpp index 21f8b670..7c173a06 100644 --- a/src/vector/painters/image.cpp +++ b/src/vector/painters/image.cpp @@ -51,6 +51,17 @@ vector. +*********************************************************************************************************************/ + +static ERR IMAGE_SET_AspectRatio(extVectorImage *Self, ARF Value) +{ + Self->AspectRatio = Value; + Self->modified(); + return ERR::Okay; +} + +/********************************************************************************************************************* + -FIELD- Bitmap: Reference to a source bitmap for the rendering algorithm. @@ -68,7 +79,7 @@ static ERR IMAGE_SET_Bitmap(extVectorImage *Self, objBitmap *Value) } Self->Bitmap = Value; - Self->Picture = NULL; + Self->Picture = nullptr; return ERR::Okay; } @@ -111,6 +122,17 @@ The SpreadMethod defines the way in which the image is tiled within the target a available space. It is secondary to the application of #AspectRatio. The default setting is `CLIP`, which prevents the image from being tiled. +*********************************************************************************************************************/ + +static ERR IMAGE_SET_SpreadMethod(extVectorImage* Self, VSPREAD Value) +{ + Self->SpreadMethod = Value; + Self->modified(); + return ERR::Okay; +} + +/********************************************************************************************************************* + -FIELD- Units: Declares the coordinate system to use for the #X and #Y values. @@ -119,16 +141,36 @@ This field declares the coordinate system that is used for values in the #X and -FIELD- X: Apply a horizontal offset to the image, the origin of which is determined by the #Units value. +*********************************************************************************************************************/ + +static ERR IMAGE_SET_X(extVectorImage *Self, DOUBLE Value) +{ + Self->X = Value; + Self->modified(); + return ERR::Okay; +} + +/********************************************************************************************************************* + -FIELD- Y: Apply a vertical offset to the image, the origin of which is determined by the #Units value. -END- *********************************************************************************************************************/ +static ERR IMAGE_SET_Y(extVectorImage *Self, DOUBLE Value) +{ + Self->X = Value; + Self->modified(); + return ERR::Okay; +} + +//******************************************************************************************************************** + static const ActionArray clImageActions[] = { { AC::Init, IMAGE_Init }, { AC::NewObject, IMAGE_NewObject }, - { AC::NIL, NULL } + { AC::NIL, nullptr } }; static const FieldDef clImageSpread[] = { @@ -137,13 +179,13 @@ static const FieldDef clImageSpread[] = { { "ReflectX", VSPREAD::REFLECT_X }, { "ReflectY", VSPREAD::REFLECT_Y }, { "Clip", VSPREAD::CLIP }, - { NULL, 0 } + { nullptr, 0 } }; static const FieldDef clImageUnits[] = { { "BoundingBox", VUNIT::BOUNDING_BOX }, // Coordinates are relative to the object's bounding box { "UserSpace", VUNIT::USERSPACE }, // Coordinates are relative to the current viewport - { NULL, 0 } + { nullptr, 0 } }; static const FieldDef clImageDimensions[] = { @@ -151,18 +193,18 @@ static const FieldDef clImageDimensions[] = { { "FixedY", DMF::FIXED_Y }, { "ScaledX", DMF::SCALED_X }, { "ScaledY", DMF::SCALED_Y }, - { NULL, 0 } + { nullptr, 0 } }; static const FieldArray clImageFields[] = { - { "X", FDF_DOUBLE|FDF_RW }, - { "Y", FDF_DOUBLE|FDF_RW }, - { "Picture", FDF_OBJECT|FDF_RW, NULL, IMAGE_SET_Picture, CLASSID::PICTURE }, - { "Bitmap", FDF_OBJECT|FDF_RW, NULL, IMAGE_SET_Bitmap, CLASSID::BITMAP }, - { "Units", FDF_LONG|FDF_LOOKUP|FDF_RW, NULL, NULL, &clImageUnits }, - { "Dimensions", FDF_LONGFLAGS|FDF_RW, NULL, NULL, &clImageDimensions }, - { "SpreadMethod", FDF_LONG|FDF_LOOKUP|FDF_RW, NULL, NULL, &clImageSpread }, - { "AspectRatio", FDF_LONGFLAGS|FDF_RW, NULL, NULL, &clAspectRatio }, + { "X", FDF_DOUBLE|FDF_RW, nullptr, IMAGE_SET_X }, + { "Y", FDF_DOUBLE|FDF_RW, nullptr, IMAGE_SET_Y }, + { "Picture", FDF_OBJECT|FDF_RW, nullptr, IMAGE_SET_Picture, CLASSID::PICTURE }, + { "Bitmap", FDF_OBJECT|FDF_RW, nullptr, IMAGE_SET_Bitmap, CLASSID::BITMAP }, + { "Units", FDF_LONG|FDF_LOOKUP|FDF_RW, nullptr, nullptr, &clImageUnits }, + { "Dimensions", FDF_LONGFLAGS|FDF_RW, nullptr, nullptr, &clImageDimensions }, + { "SpreadMethod", FDF_LONG|FDF_LOOKUP|FDF_RW, nullptr, IMAGE_SET_SpreadMethod, &clImageSpread }, + { "AspectRatio", FDF_LONGFLAGS|FDF_RW, nullptr, IMAGE_SET_AspectRatio, &clAspectRatio }, END_FIELD }; diff --git a/src/vector/painters/pattern.cpp b/src/vector/painters/pattern.cpp index fe14d05f..33ae4861 100644 --- a/src/vector/painters/pattern.cpp +++ b/src/vector/painters/pattern.cpp @@ -149,6 +149,7 @@ static ERR PATTERN_SET_Height(extVectorPattern *Self, Unit &Value) if (Value.scaled()) Self->Dimensions = (Self->Dimensions | DMF::SCALED_HEIGHT) & (~DMF::FIXED_HEIGHT); else Self->Dimensions = (Self->Dimensions | DMF::FIXED_HEIGHT) & (~DMF::SCALED_HEIGHT); Self->Height = Value; + Self->modified(); return ERR::Okay; } @@ -224,6 +225,7 @@ static ERR VECTORPATTERN_SET_Matrices(extVectorPattern *Self, VectorMatrix *Valu Self->Matrices = NULL; } + Self->modified(); return ERR::Okay; } @@ -242,6 +244,7 @@ static ERR PATTERN_SET_Opacity(extVectorPattern *Self, DOUBLE Value) if (Value < 0.0) Value = 0; else if (Value > 1.0) Value = 1.0; Self->Opacity = Value; + Self->modified(); return ERR::Okay; } @@ -259,6 +262,17 @@ SpreadMethod: The behaviour to use when the pattern bounds do not match the vect Indicates what happens if the pattern starts or ends inside the bounds of the target vector. The default value is PAD. +*********************************************************************************************************************/ + +static ERR PATTERN_SET_SpreadMethod(extVectorPattern *Self, VSPREAD Value) +{ + Self->SpreadMethod = Value; + Self->modified(); + return ERR::Okay; +} + +/********************************************************************************************************************* + -FIELD- Transform: Applies a transform to the pattern during the render process. @@ -272,6 +286,8 @@ static ERR PATTERN_SET_Transform(extVectorPattern *Self, CSTRING Commands) if (!Commands) return log.warning(ERR::InvalidValue); + Self->modified(); + if (!Self->Matrices) { VectorMatrix *matrix; if (AllocMemory(sizeof(VectorMatrix), MEM::DATA|MEM::NO_CLEAR, &matrix) IS ERR::Okay) { @@ -340,6 +356,7 @@ static ERR PATTERN_SET_Width(extVectorPattern *Self, Unit &Value) if (Value.scaled()) Self->Dimensions = (Self->Dimensions | DMF::SCALED_WIDTH) & (~DMF::FIXED_WIDTH); else Self->Dimensions = (Self->Dimensions | DMF::FIXED_WIDTH) & (~DMF::SCALED_WIDTH); Self->Width = Value; + Self->modified(); return ERR::Okay; } @@ -363,6 +380,7 @@ static ERR PATTERN_SET_X(extVectorPattern *Self, Unit &Value) if (Value.scaled()) Self->Dimensions = (Self->Dimensions | DMF::SCALED_X) & (~DMF::FIXED_X); else Self->Dimensions = (Self->Dimensions | DMF::FIXED_X) & (~DMF::SCALED_X); Self->X = Value; + Self->modified(); return ERR::Okay; } @@ -387,6 +405,7 @@ static ERR PATTERN_SET_Y(extVectorPattern *Self, Unit &Value) if (Value.scaled()) Self->Dimensions = (Self->Dimensions | DMF::SCALED_Y) & (~DMF::FIXED_Y); else Self->Dimensions = (Self->Dimensions | DMF::FIXED_Y) & (~DMF::SCALED_Y); Self->Y = Value; + Self->modified(); return ERR::Okay; } @@ -435,7 +454,7 @@ static const FieldArray clPatternFields[] = { { "Opacity", FDF_DOUBLE|FDF_RW, NULL, PATTERN_SET_Opacity }, { "Scene", FDF_LOCAL|FDF_R }, { "Inherit", FDF_OBJECT|FDF_RW, NULL, PATTERN_SET_Inherit }, - { "SpreadMethod", FDF_LONG|FDF_LOOKUP|FDF_RW, NULL, NULL, &clPatternSpread }, + { "SpreadMethod", FDF_LONG|FDF_LOOKUP|FDF_RW, NULL, PATTERN_SET_SpreadMethod, &clPatternSpread }, { "Units", FDF_LONG|FDF_LOOKUP|FDF_RW, NULL, NULL, &clPatternUnits }, { "ContentUnits", FDF_LONG|FDF_LOOKUP|FDF_RW, NULL, NULL, &clPatternUnits }, { "Dimensions", FDF_LONGFLAGS|FDF_R, NULL, NULL, &clPatternDimensions }, diff --git a/src/vector/scene/scene.cpp b/src/vector/scene/scene.cpp index a16ad2bd..669e8f92 100644 --- a/src/vector/scene/scene.cpp +++ b/src/vector/scene/scene.cpp @@ -210,18 +210,22 @@ static ERR VECTORSCENE_AddDef(extVectorScene *Self, struct sc::AddDef *Args) OBJECTPTR def = Args->Def; - if ((def->classID() IS CLASSID::VECTORSCENE) or - (def->baseClassID() IS CLASSID::VECTOR) or - (def->classID() IS CLASSID::VECTORGRADIENT) or - (def->classID() IS CLASSID::VECTORIMAGE) or - (def->classID() IS CLASSID::VECTORPATH) or - (def->classID() IS CLASSID::VECTORPATTERN) or - (def->baseClassID() IS CLASSID::VECTORFILTER) or - (def->classID() IS CLASSID::VECTORTRANSITION) or - (def->classID() IS CLASSID::VECTORCLIP)) { - // The use of this object as a definition is valid. + switch(def->classID()) { + case CLASSID::VECTORGRADIENT: ((extVectorGradient*)def)->HostScene = Self; break; + case CLASSID::VECTORIMAGE: ((extVectorImage *)def)->HostScene = Self; break; + case CLASSID::VECTORPATH: ((extVectorPath*)def)->HostScene = Self; break; + case CLASSID::VECTORPATTERN: ((extVectorPattern*)def)->HostScene = Self; break; + case CLASSID::VECTORTRANSITION: ((extVectorTransition*)def)->HostScene = Self; break; + case CLASSID::VECTORCLIP: ((extVectorClip*)def)->HostScene = Self; break; + case CLASSID::VECTORSCENE: break; + + default: + switch(def->baseClassID()) { + case CLASSID::VECTOR: break; + case CLASSID::VECTORFILTER: break; + default: return log.warning(ERR::InvalidObject); + } } - else return log.warning(ERR::InvalidObject); // If the resource does not belong to the Scene object, this can lead to invalid pointer references diff --git a/src/vector/scene/scene_draw.cpp b/src/vector/scene/scene_draw.cpp index f2bfa454..f4e4a16c 100644 --- a/src/vector/scene/scene_draw.cpp +++ b/src/vector/scene/scene_draw.cpp @@ -66,6 +66,10 @@ class SceneRenderer SceneRenderer(extVectorScene *pScene) : Scene(pScene) { } void draw(objBitmap *, objVectorViewport *); + + ~SceneRenderer() { + Scene->ShareModified = false; + } }; //******************************************************************************************************************** @@ -898,6 +902,8 @@ void SceneRenderer::draw_vectors(extVector *CurrentVector, VectorState &ParentSt bool redraw = view->vpRefreshBuffer; view->vpRefreshBuffer = false; + if ((!redraw) and (Scene->ShareModified)) redraw = true; + if (view->vpBuffer) { if ((view->vpBuffer->Width != view->vpFixedWidth) or (view->vpBuffer->Height != view->vpFixedHeight)) { view->vpBuffer->resize(view->vpFixedWidth, view->vpFixedHeight); diff --git a/src/vector/transformers/transition.cpp b/src/vector/transformers/transition.cpp index 152f3280..a4749a5b 100644 --- a/src/vector/transformers/transition.cpp +++ b/src/vector/transformers/transition.cpp @@ -1,7 +1,7 @@ /********************************************************************************************************************* -CLASS- -VectorTransition: Transitions are used to gradually apply transforms over distance. +VectorTransition: Transitions are used to incrementally apply transforms over distance. The VectorTransition class is used to gradually transform vector shapes over the length of a path. This feature is not SVG compliant, though it can be utilised from SVG files via the 'parasol:' name space. @@ -189,6 +189,7 @@ static ERR TRANSITION_SET_Stops(extVectorTransition *Self, Transition *Value, LO set_stop_transform(Self, &Self->Stops[i], Value[i].Transform); last_offset = Value[i].Offset; + Self->modified(); } return ERR::Okay; } diff --git a/src/vector/vector.h b/src/vector/vector.h index 395aeb18..930baca6 100644 --- a/src/vector/vector.h +++ b/src/vector/vector.h @@ -299,6 +299,15 @@ class FeedbackSubscription { //******************************************************************************************************************** +class SceneDef { + public: + extVectorScene *HostScene; + + inline void modified(); +}; + +//******************************************************************************************************************** + constexpr LONG MAX_TRANSITION_STOPS = 10; struct TransitionStop { // Passed to the Stops field. @@ -307,7 +316,7 @@ struct TransitionStop { // Passed to the Stops field. agg::trans_affine *AGGTransform; }; -class extVectorTransition : public objVectorTransition { +class extVectorTransition : public objVectorTransition, public SceneDef { public: LONG TotalStops; // Total number of stops registered. @@ -315,7 +324,7 @@ class extVectorTransition : public objVectorTransition { bool Dirty:1; }; -class extVectorGradient : public objVectorGradient { +class extVectorGradient : public objVectorGradient, public SceneDef { public: using create = pf::Create; @@ -332,13 +341,12 @@ class extVectorGradient : public objVectorGradient { bool CalcAngle; // True if the Angle/Length values require recalculation. }; -class extVectorImage : public objVectorImage { +class extVectorImage : public objVectorImage, public SceneDef { public: using create = pf::Create; - }; -class extVectorPattern : public objVectorPattern { +class extVectorPattern : public objVectorPattern, public SceneDef { public: using create = pf::Create; @@ -471,6 +479,7 @@ class extVectorScene : public objVectorScene { LONG InputHandle; PTC Cursor; // Current cursor image bool RefreshCursor; + bool ShareModified; // True if a shareable object has been modified (e.g. VectorGradient), requiring a redraw of any vectors that use it. UBYTE BufferCount; // Active tally of viewports that are buffered. }; @@ -512,7 +521,7 @@ class extVectorPoly : public extVector { bool Closed:1; // Polygons are closed (TRUE) and Polylines are open (FALSE) }; -class extVectorPath : public extVector { +class extVectorPath : public extVector, public SceneDef { public: static constexpr CLASSID CLASS_ID = CLASSID::VECTORPATH; static constexpr CSTRING CLASS_NAME = "VectorPath"; @@ -570,7 +579,7 @@ class GradientColours { //******************************************************************************************************************** -class extVectorClip : public objVectorClip { +class extVectorClip : public objVectorClip, public SceneDef { public: static constexpr CLASSID CLASS_ID = CLASSID::VECTORCLIP; static constexpr CSTRING CLASS_NAME = "VectorClip"; @@ -1241,3 +1250,7 @@ template TClipRectangle::TClipRectangle(const extVector *pVector) { template TClipRectangle::TClipRectangle(const class extVectorViewport *pVector) { *this = pVector->vpBounds; } + +inline void SceneDef::modified() { + if (HostScene) HostScene->ShareModified = true; +} diff --git a/src/vector/vectors/path.cpp b/src/vector/vectors/path.cpp index 47596dee..7ca5cdd6 100644 --- a/src/vector/vectors/path.cpp +++ b/src/vector/vectors/path.cpp @@ -219,6 +219,7 @@ static ERR VECTORPATH_Clear(extVectorPath *Self) { Self->Commands.clear(); reset_path(Self); + Self->modified(); return ERR::Okay; } @@ -284,12 +285,13 @@ static ERR VECTORPATH_AddCommand(extVectorPath *Self, struct vp::AddCommand *Arg if ((total_cmds <= 0) or (total_cmds > 1000000)) return log.warning(ERR::Args); - PathCommand *list = Args->Commands; + auto list = Args->Commands; for (LONG i=0; i < total_cmds; i++) { Self->Commands.push_back(list[i]); } reset_path(Self); + Self->modified(); return ERR::Okay; } @@ -356,6 +358,7 @@ static ERR VECTORPATH_RemoveCommand(extVectorPath *Self, struct vp::RemoveComman Self->Commands.erase(first, last); reset_path(Self); + Self->modified(); return ERR::Okay; } @@ -392,6 +395,7 @@ static ERR VECTORPATH_SetCommand(extVectorPath *Self, struct vp::SetCommand *Arg copymem(Args->Command, &Self->Commands[Args->Index], total_cmds * sizeof(PathCommand)); reset_path(Self); + Self->modified(); return ERR::Okay; } @@ -436,6 +440,7 @@ static ERR VECTORPATH_SetCommandList(extVectorPath *Self, struct vp::SetCommandL } reset_path(Self); + Self->modified(); return ERR::Okay; } @@ -469,7 +474,10 @@ static ERR VECTORPATH_SET_Commands(extVectorPath *Self, PathCommand *Value, LONG Self->Commands.push_back(Value[i]); } - if (Self->initialised()) reset_path(Self); + if (Self->initialised()) { + reset_path(Self); + Self->modified(); + } return ERR::Okay; } @@ -495,6 +503,7 @@ static ERR VECTORPATH_SET_PathLength(extVectorPath *Self, LONG Value) { if (Value >= 0) { Self->PathLength = Value; + Self->modified(); return ERR::Okay; } else return ERR::InvalidValue; @@ -537,6 +546,7 @@ static ERR VECTORPATH_SET_Sequence(extVectorPath *Self, CSTRING Value) ERR error = ERR::Okay; if (Value) error = read_path(Self->Commands, Value); reset_path(Self); + Self->modified(); return error; } @@ -560,6 +570,7 @@ static ERR VECTORPATH_SET_TotalCommands(extVectorPath *Self, LONG Value) pf::Log log; if (Value < 0) return log.warning(ERR::OutOfRange); Self->Commands.resize(Value); + Self->modified(); return ERR::Okay; }