Skip to content

Commit 484bda4

Browse files
StarryThrone陈杰
andauthored
Add 3D rendering context support with depth occlusion for layers. (#1098)
Co-authored-by: 陈杰 <chenjie@chenjiedeMac-mini.local>
1 parent b985a1f commit 484bda4

37 files changed

+2507
-559
lines changed

include/tgfx/core/Matrix3D.h

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ class Matrix3D {
7474
*/
7575
Vec4 getRow(int i) const;
7676

77+
/**
78+
* Sets the matrix values at the given row.
79+
* @param i Row index, valid range 0..3.
80+
* @param v Vector containing the values to set.
81+
*/
82+
void setRow(int i, const Vec4& v);
83+
7784
/**
7885
* Returns the matrix value at the given row and column.
7986
* @param r Row index, valid range 0..3.
@@ -204,6 +211,11 @@ class Matrix3D {
204211
postSkew(kxy, 0, kyx, 0, 0, 0);
205212
}
206213

214+
/**
215+
* Concatenates the given matrix with this matrix, and stores the result in this matrix. M' = M * m.
216+
*/
217+
void preConcat(const Matrix3D& m);
218+
207219
/**
208220
* Concatenates this matrix with the given matrix, and stores the result in this matrix. M' = M * m.
209221
*/
@@ -253,9 +265,24 @@ class Matrix3D {
253265

254266
/**
255267
* Maps a 3D point using this matrix.
268+
* The point is treated as (x, y, z, 1) in homogeneous coordinates.
256269
* The returned result is the coordinate after perspective division.
257270
*/
258-
Vec3 mapVec3(const Vec3& v) const;
271+
Vec3 mapPoint(const Vec3& point) const;
272+
273+
/**
274+
* Maps a 3D vector using this matrix.
275+
* The vector is treated as (x, y, z, 0) in homogeneous coordinates, so translation does not
276+
* affect the result.
277+
*/
278+
Vec3 mapVector(const Vec3& vector) const;
279+
280+
/**
281+
* Maps a 4D homogeneous coordinate (x, y, z, w) using this matrix.
282+
* If the current matrix contains a perspective transformation, the returned Vec4 is not
283+
* perspective-divided; i.e., the w component of the result may not be 1.
284+
*/
285+
Vec4 mapHomogeneous(float x, float y, float z, float w) const;
259286

260287
/**
261288
* Returns true if the matrix is an identity matrix.
@@ -293,11 +320,6 @@ class Matrix3D {
293320
*/
294321
void setConcat(const Matrix3D& a, const Matrix3D& b);
295322

296-
/**
297-
* Concatenates the given matrix with this matrix, and stores the result in this matrix. M' = M * m.
298-
*/
299-
void preConcat(const Matrix3D& m);
300-
301323
/**
302324
* Pre-concatenates a scale to this matrix. M' = M * S.
303325
*/
@@ -308,34 +330,25 @@ class Matrix3D {
308330
*/
309331
Matrix3D transpose() const;
310332

311-
/**
312-
* Maps a 4D point (x, y, z, w) using this matrix.
313-
* If the current matrix contains a perspective transformation, the returned Vec4 is not
314-
* perspective-divided; i.e., the w component of the result may not be 1.
315-
*/
316-
Vec4 mapPoint(float x, float y, float z, float w) const;
317-
318333
Vec4 getCol(int i) const {
319334
Vec4 v;
320335
memcpy(&v, values + i * 4, sizeof(Vec4));
321336
return v;
322337
}
323338

324-
void setAll(float m00, float m01, float m02, float m03, float m10, float m11, float m12,
325-
float m13, float m20, float m21, float m22, float m23, float m30, float m31,
326-
float m32, float m33);
327-
328-
void setRow(int i, const Vec4& v) {
329-
values[i + 0] = v.x;
330-
values[i + 4] = v.y;
331-
values[i + 8] = v.z;
332-
values[i + 12] = v.w;
333-
}
334-
339+
/**
340+
* Sets the matrix values at the given column.
341+
* @param i Column index, valid range 0..3.
342+
* @param v Vector containing the values to set.
343+
*/
335344
void setColumn(int i, const Vec4& v) {
336345
memcpy(&values[i * 4], v.ptr(), sizeof(v));
337346
}
338347

348+
void setAll(float m00, float m01, float m02, float m03, float m10, float m11, float m12,
349+
float m13, float m20, float m21, float m22, float m23, float m30, float m31,
350+
float m32, float m33);
351+
339352
void setIdentity() {
340353
*this = Matrix3D();
341354
}
@@ -353,7 +366,7 @@ class Matrix3D {
353366
}
354367

355368
Vec4 operator*(const Vec4& v) const {
356-
return this->mapPoint(v.x, v.y, v.z, v.w);
369+
return this->mapHomogeneous(v.x, v.y, v.z, v.w);
357370
}
358371

359372
float values[16] = {.0f};

include/tgfx/core/Vec.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,13 @@ struct Vec3 {
172172
return sqrtf(Dot(*this, *this));
173173
}
174174

175+
/**
176+
* Returns the squared length of the vector.
177+
*/
178+
float lengthSquared() const {
179+
return Dot(*this, *this);
180+
}
181+
175182
/**
176183
* Returns a pointer to the vector's immutable data.
177184
*/

include/tgfx/layers/Layer.h

Lines changed: 68 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class DisplayList;
3737
class DrawArgs;
3838
class RegionTransformer;
3939
class RootLayer;
40+
class Render3DContext;
4041
struct LayerStyleSource;
4142
struct MaskData;
4243
class BackgroundContext;
@@ -125,6 +126,8 @@ class Layer : public std::enable_shared_from_this<Layer> {
125126

126127
/**
127128
* Sets the blend mode of the layer.
129+
* Note: Layers inside a 3D Rendering Context (see preserve3D()) always use SrcOver blend mode
130+
* regardless of this setting.
128131
*/
129132
void setBlendMode(BlendMode value);
130133

@@ -139,6 +142,8 @@ class Layer : public std::enable_shared_from_this<Layer> {
139142

140143
/**
141144
* Sets whether the layer passes through its background to sublayers.
145+
* Note: Layers that can start or extend a 3D Rendering Context (see preserve3D()) always disable
146+
* pass-through background regardless of this setting.
142147
*/
143148
void setPassThroughBackground(bool value);
144149

@@ -178,6 +183,39 @@ class Layer : public std::enable_shared_from_this<Layer> {
178183
*/
179184
void setMatrix3D(const Matrix3D& value);
180185

186+
/**
187+
* Returns whether the layer preserves the 3D state of its content and child layers. The default
188+
* value is false.
189+
*
190+
* When false, content and child layers are projected onto the layer's local space. Child layers
191+
* are drawn in the order they were added, so later-added opaque layers completely cover earlier
192+
* ones.
193+
*
194+
* When true, 3D rendering is enabled. If the parent layer has preserve3D disabled, this layer
195+
* establishes a new 3D Rendering Context. If the parent also has preserve3D enabled, this layer
196+
* inherits and extends the parent's context.
197+
*
198+
* Within a 3D Rendering Context, all child layers share the coordinate space of the context
199+
* root's parent (or the DisplayList if no parent exists). Depth occlusion is applied based on
200+
* actual 3D positions: opaque pixels closer to the observer occlude those farther away at the
201+
* same xy coordinates.
202+
*
203+
* Note: preserve3D falls back to false behavior when any of the following conditions are met:
204+
* 1. Layer styles is not empty.
205+
* 2. Filters is not empty.
206+
* 3. Mask is not empty.
207+
* These features require projecting child layers into the current layer's local coordinate
208+
* system, which is incompatible with 3D context preservation.
209+
*/
210+
bool preserve3D() const {
211+
return _preserve3D;
212+
}
213+
214+
/**
215+
* Sets whether the layer preserves the 3D state of its content and child layers.
216+
*/
217+
void setPreserve3D(bool value);
218+
181219
/**
182220
* Returns whether the layer is visible. The default value is true.
183221
*/
@@ -217,6 +255,8 @@ class Layer : public std::enable_shared_from_this<Layer> {
217255

218256
/**
219257
* Sets whether the layer is allowed to be composited as a separate group from their parent.
258+
* Note: Layers inside a 3D Rendering Context (see preserve3D()) always apply alpha individually
259+
* to each element regardless of this setting.
220260
*/
221261
void setAllowsGroupOpacity(bool value);
222262

@@ -233,6 +273,14 @@ class Layer : public std::enable_shared_from_this<Layer> {
233273

234274
/**
235275
* Sets the list of layer styles applied to the layer.
276+
* Note: Background-dependent layer styles (e.g., BackgroundBlurStyle) have the following
277+
* limitations:
278+
* 1. Layers that start a 3D Rendering Context (see preserve3D()) disable background styles for
279+
* the entire subtree rooted at that layer. The 3D Rendering Context uses a different rendering
280+
* strategy that has not yet fully adapted background layer drawing.
281+
* 2. Layers with a 3D or projection transformation disable background styles for all descendant
282+
* layers (excluding the layer itself), because descendants cannot correctly obtain the
283+
* background.
236284
*/
237285
void setLayerStyles(const std::vector<std::shared_ptr<LayerStyle>>& value);
238286

@@ -577,17 +625,22 @@ class Layer : public std::enable_shared_from_this<Layer> {
577625

578626
void drawDirectly(const DrawArgs& args, Canvas* canvas, float alpha);
579627

580-
void drawDirectly(const DrawArgs& args, Canvas* canvas, float alpha,
581-
const std::vector<LayerStyleExtraSourceType>& styleExtraSourceTypes);
582-
583628
void drawContents(const DrawArgs& args, Canvas* canvas, float alpha,
584629
const LayerStyleSource* layerStyleSource = nullptr,
585-
const Layer* stopChild = nullptr,
586-
const std::vector<LayerStyleExtraSourceType>& styleExtraSourceTypes = {});
630+
const Layer* stopChild = nullptr);
587631

588632
bool drawChildren(const DrawArgs& args, Canvas* canvas, float alpha,
589633
const Layer* stopChild = nullptr);
590634

635+
void drawByStarting3DContext(const DrawArgs& args, Canvas* canvas);
636+
637+
std::optional<DrawArgs> createChildArgs(const DrawArgs& args, Canvas* canvas, Layer* child,
638+
bool skipBackground, int childIndex,
639+
int lastBackgroundIndex);
640+
641+
void drawChild(const DrawArgs& args, Canvas* canvas, Layer* child, float alpha,
642+
const Matrix3D& transform3D, Render3DContext* context3D, bool started3DContext);
643+
591644
float drawBackgroundLayers(const DrawArgs& args, Canvas* canvas);
592645

593646
std::unique_ptr<LayerStyleSource> getLayerStyleSource(const DrawArgs& args, const Matrix& matrix,
@@ -598,7 +651,7 @@ class Layer : public std::enable_shared_from_this<Layer> {
598651

599652
/**
600653
* Gets the background image of the minimum axis-aligned bounding box after drawing the layer
601-
* subtree with the current layer as the root node.
654+
* subtree with the current layer as the root node
602655
*/
603656
std::shared_ptr<Image> getBoundsBackgroundImage(const DrawArgs& args, float contentScale,
604657
Point* offset);
@@ -608,12 +661,8 @@ class Layer : public std::enable_shared_from_this<Layer> {
608661
void drawLayerStyles(const DrawArgs& args, Canvas* canvas, float alpha,
609662
const LayerStyleSource* source, LayerStylePosition position);
610663

611-
void drawLayerStyles(const DrawArgs& args, Canvas* canvas, float alpha,
612-
const LayerStyleSource* source, LayerStylePosition position,
613-
const std::vector<LayerStyleExtraSourceType>& styleExtraSourceTypes);
614-
615664
void drawBackgroundLayerStyles(const DrawArgs& args, Canvas* canvas, float alpha,
616-
const Matrix3D& transform);
665+
const Matrix3D& transform3D);
617666

618667
bool getLayersUnderPointInternal(float x, float y, std::vector<std::shared_ptr<Layer>>* results);
619668

@@ -657,27 +706,18 @@ class Layer : public std::enable_shared_from_this<Layer> {
657706
const Matrix3D* transform3D,
658707
const std::shared_ptr<MaskFilter>& maskFilter);
659708

660-
std::shared_ptr<Image> getContentImage(
661-
const DrawArgs& args, const Matrix& contentMatrix, const std::optional<Rect>& clipBounds,
662-
const std::vector<LayerStyleExtraSourceType>& extraSourceTypes, Matrix* imageMatrix);
709+
std::shared_ptr<Image> getContentImage(const DrawArgs& args, const Matrix& contentMatrix,
710+
const std::optional<Rect>& clipBounds,
711+
Matrix* imageMatrix);
663712

664-
std::shared_ptr<Image> getPassThroughContentImage(
665-
const DrawArgs& args, Canvas* canvas, const std::optional<Rect>& clipBounds,
666-
const std::vector<LayerStyleExtraSourceType>& extraSourceTypes, Matrix* imageMatrix);
713+
std::shared_ptr<Image> getPassThroughContentImage(const DrawArgs& args, Canvas* canvas,
714+
const std::optional<Rect>& clipBounds,
715+
Matrix* imageMatrix);
667716

668717
std::optional<Rect> computeContentBounds(const std::optional<Rect>& clipBounds,
669718
bool excludeEffects);
670719

671-
/**
672-
* Returns the equivalent transformation matrix adapted for a custom anchor point.
673-
* The matrix is defined based on a local coordinate system, with the transformation anchor point
674-
* being the origin of that coordinate system. This function returns an affine transformation
675-
* matrix that produces the same visual effect when using any point within this coordinate system
676-
* as the new origin and anchor point.
677-
* @param matrix The original transformation matrix.
678-
* @param anchor The specified anchor point.
679-
*/
680-
Matrix3D anchorAdaptedMatrix(const Matrix3D& matrix, const Point& anchor) const;
720+
bool canPreserve3D() const;
681721

682722
void invalidateSubtree();
683723

@@ -703,6 +743,7 @@ class Layer : public std::enable_shared_from_this<Layer> {
703743
float _alpha = 1.0f;
704744
// The actual transformation matrix that determines the geometric position of the layer
705745
Matrix3D _matrix3D = {};
746+
bool _preserve3D = false;
706747
std::shared_ptr<Layer> _mask = nullptr;
707748
Layer* maskOwner = nullptr;
708749
std::unique_ptr<Rect> _scrollRect = nullptr;

include/tgfx/layers/filters/LayerFilter.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ class LayerFilter : public LayerProperty {
5353
BlurFilter,
5454
ColorMatrixFilter,
5555
DropShadowFilter,
56-
InnerShadowFilter,
57-
Transform3DFilter
56+
InnerShadowFilter
5857
};
5958

6059
virtual Type type() const {

0 commit comments

Comments
 (0)