1 | /* |
2 | * This file is part of KQuickCharts |
3 | * SPDX-FileCopyrightText: 2019 Arjen Hiemstra <ahiemstra@heimr.nl> |
4 | * |
5 | * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL |
6 | */ |
7 | |
8 | #ifndef SDF_SHADER_H |
9 | #define SDF_SHADER_H |
10 | |
11 | #include <QSGMaterialShader> |
12 | |
13 | struct UniformDataStream { |
14 | inline UniformDataStream(QSGMaterialShader::RenderState &state) noexcept |
15 | : bytes(state.uniformData()->data()) |
16 | { |
17 | } |
18 | |
19 | ~UniformDataStream() |
20 | { |
21 | } |
22 | |
23 | template<typename Data> |
24 | friend inline UniformDataStream &operator<<(UniformDataStream &stream, const Data &data) |
25 | { |
26 | constexpr uint dataSize = sizeof(Data); |
27 | stream.align(size: dataSize); |
28 | memcpy(stream.bytes, &data, dataSize); |
29 | stream.bytes += dataSize; |
30 | stream.offset += dataSize; |
31 | return stream; |
32 | } |
33 | |
34 | template<typename Data> |
35 | inline void skip(const Data &data = {}) |
36 | { |
37 | constexpr uint dataSize = sizeof(Data); |
38 | |
39 | align(size: dataSize); |
40 | Q_UNUSED(data); |
41 | bytes += dataSize; |
42 | offset += dataSize; |
43 | } |
44 | |
45 | inline void skipComponents(uint count) |
46 | { |
47 | const uint skipCount = count * 4; |
48 | align(size: 4); |
49 | bytes += skipCount; |
50 | offset += skipCount; |
51 | } |
52 | |
53 | friend inline UniformDataStream &operator<<(UniformDataStream &stream, const QMatrix4x4 &m) |
54 | { |
55 | constexpr uint Matrix4x4Size = 4 * 4 * 4; |
56 | |
57 | stream.align(size: Matrix4x4Size); |
58 | memcpy(dest: stream.bytes, src: m.constData(), n: Matrix4x4Size); |
59 | stream.bytes += Matrix4x4Size; |
60 | stream.offset += Matrix4x4Size; |
61 | return stream; |
62 | } |
63 | |
64 | friend inline UniformDataStream &operator<<(UniformDataStream &stream, const QColor &color) |
65 | { |
66 | constexpr uint ColorSize = 4 * 4; |
67 | |
68 | stream.align(size: ColorSize); |
69 | std::array<float, 4> colorArray; |
70 | color.getRgbF(r: &colorArray[0], g: &colorArray[1], b: &colorArray[2], a: &colorArray[3]); |
71 | memcpy(dest: stream.bytes, src: colorArray.data(), n: ColorSize); |
72 | stream.bytes += ColorSize; |
73 | stream.offset += ColorSize; |
74 | return stream; |
75 | } |
76 | |
77 | template<typename T> |
78 | friend inline UniformDataStream &operator<<(UniformDataStream &stream, const QList<T> &v) |
79 | { |
80 | for (const auto &item : v) { |
81 | stream << item; |
82 | // Using std140, array elements are padded to a size of 16 bytes per element. |
83 | stream.align(size: 16); |
84 | } |
85 | return stream; |
86 | } |
87 | |
88 | char *bytes; |
89 | size_t padding = 16; |
90 | size_t offset = 0; |
91 | |
92 | private: |
93 | // Encode alignment rules for std140. |
94 | // Minimum alignment is 4 bytes. |
95 | // Vec2 alignment is 8 bytes. |
96 | // Vec3 and Vec4 alignment is 16 bytes. |
97 | inline void align(uint size) |
98 | { |
99 | if (size <= 4) { |
100 | const auto padding = offset % 4 > 0 ? 4 - offset % 4 : 0; |
101 | offset += padding; |
102 | bytes += padding; |
103 | } else if (size <= 8) { |
104 | auto padding = offset % 8 > 0 ? 8 - offset % 8 : 0; |
105 | offset += padding; |
106 | bytes += padding; |
107 | } else { |
108 | auto padding = offset % 16 > 0 ? 16 - offset % 16 : 0; |
109 | offset += padding; |
110 | bytes += padding; |
111 | } |
112 | } |
113 | }; |
114 | |
115 | class SDFShader : public QSGMaterialShader |
116 | { |
117 | public: |
118 | SDFShader(); |
119 | virtual ~SDFShader(); |
120 | |
121 | void setShaders(const QString &vertex, const QString &fragment); |
122 | }; |
123 | |
124 | #endif // SDF_SHADER_H |
125 | |