Skip to content

Commit

Permalink
Buffered GUI drawing
Browse files Browse the repository at this point in the history
  • Loading branch information
dancazarin committed Feb 17, 2025
1 parent 952d1eb commit bc6c863
Show file tree
Hide file tree
Showing 44 changed files with 660 additions and 241 deletions.
2 changes: 2 additions & 0 deletions examples/showcase/src/ShowcaseComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ void ShowcaseComponent::unhandledEvent(Event& event) {
t->setVSyncInterval(1 - t->vsyncInterval());
} else if (event.keyPressed(KeyCode::F5)) {
tree().root()->dump();
} else if (event.keyPressed(KeyCode::F6)) {
Internal::debugDirtyRect = !Internal::debugDirtyRect;
}
}

Expand Down
9 changes: 2 additions & 7 deletions include/brisk/graphics/Path.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ struct RasterizedPath {
Rectangle bounds; ///< The bounding rectangle of the rasterized path.
};

/**
* @brief A constant rectangle that represents no clipping area.
*/
const inline Rectangle noClipRect{ INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX };

/**
* @brief Enum representing the fill rules for paths.
*/
Expand Down Expand Up @@ -332,14 +327,14 @@ struct Path {
/// Rasterizes the path for filling.
/// @param fill Fill parameters.
/// @param clipRect Clipping rectangle. Pass noClipRect to disable clipping.
RasterizedPath rasterize(const FillParams& fill, Rectangle clipRect) {
RasterizedPath rasterize(const FillParams& fill, Rectangle clipRect = noClipRect) {
return Internal::rasterizePath(*this, fill, clipRect);
}

/// Rasterizes the path for stroking.
/// @param stroke Stroke parameters.
/// @param clipRect Clipping rectangle. Pass noClipRect to disable clipping.
RasterizedPath rasterize(const StrokeParams& stroke, Rectangle clipRect) {
RasterizedPath rasterize(const StrokeParams& stroke, Rectangle clipRect = noClipRect) {
return Internal::rasterizePath(*this, stroke, clipRect);
}

Expand Down
6 changes: 5 additions & 1 deletion include/brisk/graphics/RenderState.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,9 @@ struct RenderState {
float reserved7 = 0;

public:
SIMD<float, 4> padding[16]{ 0, 0, 0, 0, 0, 0, 0 };
Rectangle shaderClip = noClipRect;

SIMD<float, 4> padding[15]{ 0, 0, 0, 0, 0, 0, 0 };

bool compare(const RenderState& second) const;
void premultiply();
Expand Down Expand Up @@ -376,6 +378,8 @@ class RenderContext {
public:
virtual void command(RenderStateEx&& cmd, std::span<const float> data = {}) = 0;

virtual void setClipRect(Rectangle clipRect) = 0;

template <typename T>
void command(RenderStateEx&& cmd, std::span<T> value) {
static_assert(std::is_trivially_copy_constructible_v<T>);
Expand Down
33 changes: 20 additions & 13 deletions include/brisk/graphics/Renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,45 +148,43 @@ class RenderEncoder {
* @brief Returns the rendering device associated with this encoder.
* @return Pointer to the RenderDevice.
*/
virtual RenderDevice* device() const = 0;
virtual RenderDevice* device() const = 0;

/**
* @brief Gets the visual settings for the encoder.
* @return The visual settings.
*/
virtual VisualSettings visualSettings() const = 0;
virtual VisualSettings visualSettings() const = 0;

/**
* @brief Sets the visual settings for the encoder.
* @param visualSettings The visual settings to apply.
*/
virtual void setVisualSettings(const VisualSettings& visualSettings) = 0;
virtual void setVisualSettings(const VisualSettings& visualSettings) = 0;

/**
* @brief Begins the rendering operation.
* @param target The render target.
* @param clear The clear color.
* @param rectangles List of rectangles to clear.
* @param clear The clear color. std::nullopt means no clear command is issued.
*/
virtual void begin(RC<RenderTarget> target, ColorF clear = Palette::transparent,
std::span<const Rectangle> rectangles = {}) = 0;
virtual void begin(RC<RenderTarget> target, std::optional<ColorF> clear = Palette::transparent) = 0;

/**
* @brief Batches rendering commands.
* @param commands The rendering commands.
* @param data Associated data.
*/
virtual void batch(std::span<const RenderState> commands, std::span<const float> data) = 0;
virtual void batch(std::span<const RenderState> commands, std::span<const float> data) = 0;

/**
* @brief Ends the rendering operation.
*/
virtual void end() = 0;
virtual void end() = 0;

/**
* @brief Waits for the rendering to finish.
*/
virtual void wait() = 0;
virtual void wait() = 0;
};

/**
Expand All @@ -200,16 +198,24 @@ class RenderPipeline final : public RenderContext {
* @param encoder The render encoder to execute.
* @param target The render target.
* @param clear The clear color.
* @param rectangles The rectangles to clear.
* @param clipRect The clipping rectangle. Pass noClipRect to disable clipping
*/
RenderPipeline(RC<RenderEncoder> encoder, RC<RenderTarget> target, ColorF clear = Palette::transparent,
std::span<const Rectangle> rectangles = {});
RenderPipeline(RC<RenderEncoder> encoder, RC<RenderTarget> target,
std::optional<ColorF> clear = Palette::transparent, Rectangle clipRect = noClipRect);

void blit(RC<Image> image);

/**
* @brief Destructor for the RenderPipeline.
*/
~RenderPipeline();

Rectangle clipRect() const;

void setClipRect(Rectangle clipRect) final;

using RenderContext::command;

/**
* @brief Issues a rendering command.
* @param cmd The render state command.
Expand All @@ -231,6 +237,7 @@ class RenderPipeline final : public RenderContext {
std::vector<float> m_data; ///< Buffer for associated rendering data.
std::vector<RC<Image>> m_textures; ///< List of textures used in rendering.
int m_numBatches = 0; ///< Number of rendering batches.
Rectangle m_clipRect;

/**
* @brief Flushes the pipeline to issue the batched commands.
Expand Down
97 changes: 61 additions & 36 deletions include/brisk/gui/GUI.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ void boxPainter(Canvas& canvas, const Widget& widget);
namespace Internal {
extern std::atomic_bool debugRelayoutAndRegenerate;
extern std::atomic_bool debugBoundaries;
extern std::atomic_bool debugDirtyRect;
} // namespace Internal

using BindingFunc = function<void(Widget*)>;
Expand Down Expand Up @@ -862,6 +863,10 @@ class WIDGET Widget : public BindingObject<Widget, &uiScheduler> {

Rectangle clientRect() const noexcept;

Rectangle subtreeRect() const noexcept;

Edges invalidationEdges() const noexcept;

////////////////////////////////////////////////////////////////////////////////
// Style & layout
////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -950,6 +955,7 @@ class WIDGET Widget : public BindingObject<Widget, &uiScheduler> {

WidgetTree* tree() const noexcept;
void setTree(WidgetTree* tree);
void treeSet();

Widget* parent() const noexcept;

Expand Down Expand Up @@ -983,6 +989,8 @@ class WIDGET Widget : public BindingObject<Widget, &uiScheduler> {

void paintTo(Canvas& canvas) const;

void invalidate();

Drawable drawable(RectangleF scissors) const;

std::optional<PointF> mousePos() const;
Expand Down Expand Up @@ -1037,6 +1045,7 @@ class WIDGET Widget : public BindingObject<Widget, &uiScheduler> {

Rectangle m_rect{ 0, 0, 0, 0 };
Rectangle m_clientRect{ 0, 0, 0, 0 };
Rectangle m_subtreeRect{ 0, 0, 0, 0 };
EdgesF m_computedMargin{ 0, 0, 0, 0 };
EdgesF m_computedPadding{ 0, 0, 0, 0 };
EdgesF m_computedBorderWidth{ 0, 0, 0, 0 };
Expand Down Expand Up @@ -1283,6 +1292,7 @@ class WIDGET Widget : public BindingObject<Widget, &uiScheduler> {
bool m_animationRequested : 1 { false };
bool m_hasLayout : 1 { false };
bool m_previouslyHasLayout : 1 { false };
bool m_pendingAnimationRequest : 1 { false };

Trigger<> m_rebuildTrigger{};

Expand Down Expand Up @@ -1346,44 +1356,53 @@ class WIDGET Widget : public BindingObject<Widget, &uiScheduler> {
GUIProperty<5, OptFloat, AffectLayout, &This::m_aspect> aspect;
GUIProperty<6, EasingFunction, None, &This::m_backgroundColorEasing> backgroundColorEasing;
GUIProperty<7, float, None, &This::m_backgroundColorTransition> backgroundColorTransition;
GUIProperty<8, ColorF, Transition, &This::m_backgroundColor> backgroundColor;
GUIProperty<8, ColorF, Transition | AffectPaint, &This::m_backgroundColor> backgroundColor;
GUIProperty<9, EasingFunction, None, &This::m_borderColorEasing> borderColorEasing;
GUIProperty<10, float, None, &This::m_borderColorTransition> borderColorTransition;
GUIProperty<11, ColorF, Transition, &This::m_borderColor> borderColor;
GUIProperty<12, CornersL, Resolvable | Inheritable, &This::m_borderRadius, 0> borderRadiusTopLeft;
GUIProperty<13, CornersL, Resolvable | Inheritable, &This::m_borderRadius, 1> borderRadiusTopRight;
GUIProperty<14, CornersL, Resolvable | Inheritable, &This::m_borderRadius, 2> borderRadiusBottomLeft;
GUIProperty<15, CornersL, Resolvable | Inheritable, &This::m_borderRadius, 3> borderRadiusBottomRight;
GUIProperty<16, EdgesL, AffectLayout, &This::m_borderWidth, 0> borderWidthLeft;
GUIProperty<17, EdgesL, AffectLayout, &This::m_borderWidth, 1> borderWidthTop;
GUIProperty<18, EdgesL, AffectLayout, &This::m_borderWidth, 2> borderWidthRight;
GUIProperty<19, EdgesL, AffectLayout, &This::m_borderWidth, 3> borderWidthBottom;
GUIProperty<20, WidgetClip, None, &This::m_clip> clip;
GUIProperty<11, ColorF, Transition | AffectPaint, &This::m_borderColor> borderColor;
GUIProperty<12, CornersL, Resolvable | Inheritable | AffectPaint, &This::m_borderRadius, 0>
borderRadiusTopLeft;
GUIProperty<13, CornersL, Resolvable | Inheritable | AffectPaint, &This::m_borderRadius, 1>
borderRadiusTopRight;
GUIProperty<14, CornersL, Resolvable | Inheritable | AffectPaint, &This::m_borderRadius, 2>
borderRadiusBottomLeft;
GUIProperty<15, CornersL, Resolvable | Inheritable | AffectPaint, &This::m_borderRadius, 3>
borderRadiusBottomRight;
GUIProperty<16, EdgesL, AffectLayout | AffectPaint, &This::m_borderWidth, 0> borderWidthLeft;
GUIProperty<17, EdgesL, AffectLayout | AffectPaint, &This::m_borderWidth, 1> borderWidthTop;
GUIProperty<18, EdgesL, AffectLayout | AffectPaint, &This::m_borderWidth, 2> borderWidthRight;
GUIProperty<19, EdgesL, AffectLayout | AffectPaint, &This::m_borderWidth, 3> borderWidthBottom;
GUIProperty<20, WidgetClip, None | AffectPaint, &This::m_clip> clip;
GUIProperty<21, EasingFunction, None, &This::m_colorEasing> colorEasing;
GUIProperty<22, float, None, &This::m_colorTransition> colorTransition;
GUIProperty<23, ColorF, Transition | Inheritable, &This::m_color> color;
GUIProperty<24, int, None, &This::m_corners> corners;
GUIProperty<23, ColorF, Transition | Inheritable | AffectPaint, &This::m_color> color;
GUIProperty<24, int, AffectPaint, &This::m_corners> corners;
GUIProperty<25, Cursor, None, &This::m_cursor> cursor;
GUIProperty<26, SizeL, AffectLayout, &This::m_dimensions, 0> width;
GUIProperty<27, SizeL, AffectLayout, &This::m_dimensions, 1> height;
GUIProperty<28, Length, AffectLayout, &This::m_flexBasis> flexBasis;
GUIProperty<29, OptFloat, AffectLayout, &This::m_flexGrow> flexGrow;
GUIProperty<30, OptFloat, AffectLayout, &This::m_flexShrink> flexShrink;
GUIProperty<31, Wrap, AffectLayout, &This::m_flexWrap> flexWrap;
GUIProperty<32, std::string, AffectLayout | AffectFont | Inheritable, &This::m_fontFamily> fontFamily;
GUIProperty<32, std::string, AffectLayout | AffectFont | Inheritable | AffectPaint, &This::m_fontFamily>
fontFamily;
GUIProperty<33, Length,
AffectLayout | Resolvable | AffectResolve | AffectFont | Inheritable | RelativeToParent,
AffectLayout | Resolvable | AffectResolve | AffectFont | Inheritable | RelativeToParent |
AffectPaint,
&This::m_fontSize>
fontSize;
GUIProperty<34, FontStyle, AffectLayout | AffectFont | Inheritable, &This::m_fontStyle> fontStyle;
GUIProperty<35, FontWeight, AffectLayout | AffectFont | Inheritable, &This::m_fontWeight> fontWeight;
GUIProperty<34, FontStyle, AffectLayout | AffectFont | Inheritable | AffectPaint, &This::m_fontStyle>
fontStyle;
GUIProperty<35, FontWeight, AffectLayout | AffectFont | Inheritable | AffectPaint, &This::m_fontWeight>
fontWeight;
GUIProperty<36, SizeL, AffectLayout, &This::m_gap, 0> gapColumn;
GUIProperty<37, SizeL, AffectLayout, &This::m_gap, 1> gapRow;
GUIProperty<38, bool, None, &This::m_hidden> hidden;
GUIProperty<38, bool, AffectPaint, &This::m_hidden> hidden;
GUIProperty<39, Justify, AffectLayout, &This::m_justifyContent> justifyContent;
GUIProperty<40, LayoutOrder, AffectLayout, &This::m_layoutOrder> layoutOrder;
GUIProperty<41, Layout, AffectLayout, &This::m_layout> layout;
GUIProperty<42, Length, AffectLayout | Resolvable | AffectFont | Inheritable, &This::m_letterSpacing>
GUIProperty<42, Length, AffectLayout | Resolvable | AffectFont | Inheritable | AffectPaint,
&This::m_letterSpacing>
letterSpacing;
GUIProperty<43, EdgesL, AffectLayout, &This::m_margin, 0> marginLeft;
GUIProperty<44, EdgesL, AffectLayout, &This::m_margin, 1> marginTop;
Expand All @@ -1393,24 +1412,28 @@ class WIDGET Widget : public BindingObject<Widget, &uiScheduler> {
GUIProperty<48, SizeL, AffectLayout, &This::m_maxDimensions, 1> maxHeight;
GUIProperty<49, SizeL, AffectLayout, &This::m_minDimensions, 0> minWidth;
GUIProperty<50, SizeL, AffectLayout, &This::m_minDimensions, 1> minHeight;
GUIProperty<51, float, None, &This::m_opacity> opacity;
GUIProperty<51, float, AffectPaint, &This::m_opacity> opacity;
GUIProperty<52, Overflow, AffectLayout, &This::m_overflow> overflow;
GUIProperty<53, EdgesL, AffectLayout, &This::m_padding, 0> paddingLeft;
GUIProperty<54, EdgesL, AffectLayout, &This::m_padding, 1> paddingTop;
GUIProperty<55, EdgesL, AffectLayout, &This::m_padding, 2> paddingRight;
GUIProperty<56, EdgesL, AffectLayout, &This::m_padding, 3> paddingBottom;
GUIProperty<57, Placement, AffectLayout, &This::m_placement> placement;
GUIProperty<58, Length, Resolvable | Inheritable, &This::m_shadowSize> shadowSize;
GUIProperty<59, ColorF, Transition, &This::m_shadowColor> shadowColor;
GUIProperty<58, Length, Resolvable | Inheritable | AffectPaint, &This::m_shadowSize> shadowSize;
GUIProperty<59, ColorF, Transition | AffectPaint, &This::m_shadowColor> shadowColor;
GUIProperty<60, float, None, &This::m_shadowColorTransition> shadowColorTransition;
GUIProperty<61, EasingFunction, None, &This::m_shadowColorEasing> shadowColorEasing;
GUIProperty<62, Length, AffectLayout | Resolvable | AffectFont | Inheritable, &This::m_tabSize> tabSize;
GUIProperty<63, TextAlign, Inheritable, &This::m_textAlign> textAlign;
GUIProperty<64, TextAlign, Inheritable, &This::m_textVerticalAlign> textVerticalAlign;
GUIProperty<65, TextDecoration, AffectFont | Inheritable, &This::m_textDecoration> textDecoration;
GUIProperty<62, Length, AffectLayout | Resolvable | AffectFont | Inheritable | AffectPaint,
&This::m_tabSize>
tabSize;
GUIProperty<63, TextAlign, Inheritable | AffectPaint, &This::m_textAlign> textAlign;
GUIProperty<64, TextAlign, Inheritable | AffectPaint, &This::m_textVerticalAlign> textVerticalAlign;
GUIProperty<65, TextDecoration, AffectFont | Inheritable | AffectPaint, &This::m_textDecoration>
textDecoration;
GUIProperty<66, PointL, AffectLayout, &This::m_translate> translate;
GUIProperty<67, bool, AffectLayout, &This::m_visible> visible;
GUIProperty<68, Length, AffectLayout | Resolvable | AffectFont | Inheritable, &This::m_wordSpacing>
GUIProperty<68, Length, AffectLayout | Resolvable | AffectFont | Inheritable | AffectPaint,
&This::m_wordSpacing>
wordSpacing;
GUIProperty<69, AlignToViewport, AffectLayout, &This::m_alignToViewport> alignToViewport;
GUIProperty<70, BoxSizingPerAxis, AffectLayout, &This::m_boxSizing> boxSizing;
Expand All @@ -1432,17 +1455,18 @@ class WIDGET Widget : public BindingObject<Widget, &uiScheduler> {
/* 85 unused */
/* 86 unused */
GUIProperty<87, EventDelegate*, None, &This::m_delegate> delegate;
GUIProperty<88, std::string, None, &This::m_hint> hint;
GUIProperty<88, std::string, AffectPaint, &This::m_hint> hint;
GUIProperty<89, std::shared_ptr<const Stylesheet>, AffectStyle, &This::m_stylesheet> stylesheet;
GUIProperty<90, Painter, None, &This::m_painter> painter;
GUIProperty<90, Painter, AffectPaint, &This::m_painter> painter;
GUIProperty<91, bool, None, &This::m_isHintExclusive> isHintExclusive;

GUIPropertyCompound<92, CornersL, Resolvable | Inheritable, &This::m_borderRadius,
GUIPropertyCompound<92, CornersL, Resolvable | Inheritable | AffectPaint, &This::m_borderRadius,
decltype(borderRadiusTopLeft), decltype(borderRadiusTopRight),
decltype(borderRadiusBottomLeft), decltype(borderRadiusBottomRight)>
borderRadius;
GUIPropertyCompound<93, EdgesL, AffectLayout, &This::m_borderWidth, decltype(borderWidthLeft),
decltype(borderWidthTop), decltype(borderWidthRight), decltype(borderWidthBottom)>
GUIPropertyCompound<93, EdgesL, AffectLayout | AffectPaint, &This::m_borderWidth,
decltype(borderWidthLeft), decltype(borderWidthTop), decltype(borderWidthRight),
decltype(borderWidthBottom)>
borderWidth;
GUIPropertyCompound<94, SizeL, AffectLayout, &This::m_dimensions, decltype(width), decltype(height)>
dimensions;
Expand All @@ -1459,12 +1483,13 @@ class WIDGET Widget : public BindingObject<Widget, &uiScheduler> {
GUIPropertyCompound<99, EdgesL, AffectLayout, &This::m_padding, decltype(paddingLeft),
decltype(paddingTop), decltype(paddingRight), decltype(paddingBottom)>
padding;
GUIProperty<100, OpenTypeFeatureFlags, AffectLayout | AffectFont | Inheritable, &This::m_fontFeatures>
GUIProperty<100, OpenTypeFeatureFlags, AffectLayout | AffectFont | Inheritable | AffectPaint,
&This::m_fontFeatures>
fontFeatures;

GUIProperty<101, ColorF, Transition | Inheritable, &This::m_scrollBarColor> scrollBarColor;
GUIProperty<102, Length, Resolvable, &This::m_scrollBarThickness> scrollBarThickness;
GUIProperty<103, Length, Resolvable, &This::m_scrollBarRadius> scrollBarRadius;
GUIProperty<101, ColorF, Transition | Inheritable | AffectPaint, &This::m_scrollBarColor> scrollBarColor;
GUIProperty<102, Length, Resolvable | AffectPaint, &This::m_scrollBarThickness> scrollBarThickness;
GUIProperty<103, Length, Resolvable | AffectPaint, &This::m_scrollBarRadius> scrollBarRadius;

Property<This, Trigger<>, &This::m_onClick> onClick;
Property<This, Trigger<>, &This::m_onDoubleClick> onDoubleClick;
Expand Down
4 changes: 3 additions & 1 deletion include/brisk/gui/GUIWindow.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ class Component;

class GUIWindow : public Window {
public:
void paint(RenderContext& context) override;
void paint(RenderContext& context, bool fullRepaint) override;
void paintImmediate(RenderContext& context) override;
void dpiChanged() override;
void rebuild();
const std::string& getId() const;
Expand Down Expand Up @@ -73,6 +74,7 @@ class GUIWindow : public Window {
std::string m_id;
bool m_frameSkipTestState = false;
std::vector<uint32_t> m_unhandledEvents;
Rectangle m_savedPaintRect{};

void updateWindowLimits();

Expand Down
3 changes: 2 additions & 1 deletion include/brisk/gui/Properties.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,9 @@ enum class PropFlags : uint16_t {
AffectFont = 1 << 5,
Inheritable = 1 << 6,
RelativeToParent = 1 << 7,
AffectPaint = 1 << 8,

Compound = 1 << 8,
Compound = 1 << 9,
};

template <>
Expand Down
Loading

0 comments on commit bc6c863

Please sign in to comment.