1 module rpui.render.components_factory;
2 
3 import std.traits;
4 import std.string;
5 import std.container.array;
6 
7 import rpdl;
8 
9 import gapi.texture;
10 import gapi.geometry;
11 import gapi.geometry_quad;
12 import gapi.shader;
13 import gapi.text;
14 import gapi.vec;
15 
16 import rpui.render.components;
17 import rpui.gapi_rpdl_exts;
18 import rpui.theme;
19 import rpui.primitives;
20 
21 StatefulChain createStatefulChainFromRdpl(
22     Theme theme,
23     in Orientation orientation,
24     in string style,
25     immutable State[] states = [EnumMembers!State]
26 ) {
27     StatefulChain chain;
28 
29     immutable chainParts = orientation == Orientation.horizontal
30         ? horizontalChainParts
31         : verticalChainParts;
32 
33     foreach (immutable part; chainParts) {
34         chain.parts[part] = createUiSkinTextureQuad(theme);
35 
36         foreach (immutable state; states) {
37             const texCoords = createOriginalWithNormilizedTextureCoordsFromRdpl(
38                 theme,
39                 style ~ "." ~ getStateRdplName(state) ~ "." ~ getChainPartRdplName(part)
40             );
41             chain.texCoords[state][part] = texCoords.normilizedTexCoords;
42             chain.widths[part] = orientation == Orientation.horizontal
43                 ? texCoords.originalTexCoords.size.x
44                 : texCoords.originalTexCoords.size.y;
45         }
46     }
47 
48     return chain;
49 }
50 
51 Chain createChainFromRdpl(Theme theme, in Orientation orientation, in string style) {
52     Chain chain;
53 
54     immutable chainParts = orientation == Orientation.horizontal
55         ? horizontalChainParts
56         : verticalChainParts;
57 
58     foreach (immutable part; chainParts) {
59         chain.parts[part] = createUiSkinTextureQuad(theme);
60 
61         const texCoords = createOriginalWithNormilizedTextureCoordsFromRdpl(
62             theme,
63             style ~ "." ~ getChainPartRdplName(part)
64         );
65 
66         chain.texCoords[part] = texCoords.normilizedTexCoords;
67         chain.widths[part] = texCoords.originalTexCoords.size.x;
68         chain.height = texCoords.originalTexCoords.size.y;
69     }
70 
71     return chain;
72 }
73 
74 Block createBlockFromRdpl(Theme theme, in string style) {
75     Block block;
76 
77     block.topChain = createChainFromRdpl(theme, Orientation.horizontal, style ~ ".Top");
78     block.middleChain = createChainFromRdpl(theme, Orientation.horizontal, style ~ ".Middle");
79     block.bottomChain = createChainFromRdpl(theme, Orientation.horizontal, style ~ ".Bottom");
80 
81     block.widths[BlockRow.top] = block.topChain.widths;
82     block.widths[BlockRow.middle] = block.middleChain.widths;
83     block.widths[BlockRow.bottom] = block.bottomChain.widths;
84 
85     block.heights[BlockRow.top] = block.topChain.height;
86     block.heights[BlockRow.middle] = block.middleChain.height;
87     block.heights[BlockRow.bottom] = block.bottomChain.height;
88 
89     return block;
90 }
91 
92 TextureQuad createUiSkinTextureQuad(in Theme theme) {
93     TextureQuad quad;
94     quad.geometry = createGeometry();
95     quad.texture = theme.skin;
96 
97     return quad;
98 }
99 
100 StatefulTexAtlasTextureQuad createStatefulTexAtlasTextureQuadFromRdpl(
101     Theme theme,
102     in string style,
103     in string name,
104     immutable State[] states = [EnumMembers!State]
105 ) {
106     StatefulTexAtlasTextureQuad quad;
107 
108     quad.geometry = createGeometry();
109     quad.texture = theme.skin;
110 
111     foreach (immutable state; states) {
112         const texCoords = createOriginalWithNormilizedTextureCoordsFromRdpl(
113             theme,
114             style ~ "." ~ getStateRdplName(state) ~ "." ~ name
115         );
116         quad.texCoords[state] = texCoords;
117     }
118 
119     return quad;
120 }
121 
122 TexAtlasTextureQuad createTexAtlasTextureQuadFromRdpl(
123     Theme theme,
124     in string style,
125     in string name
126 ) {
127     TexAtlasTextureQuad quad;
128 
129     quad.geometry = createGeometry();
130     quad.texture = theme.skin;
131     quad.texCoords = createOriginalWithNormilizedTextureCoordsFromRdpl(
132         theme,
133         style ~ "." ~ name
134     );
135 
136     return quad;
137 }
138 
139 TexAtlasTextureQuad createTexAtlasTextureQuad(
140     Texture2D texture,
141     Texture2DCoords texCoords
142 ) {
143     return TexAtlasTextureQuad(
144         createGeometry(),
145         texture,
146         OriginalWithNormilizedTextureCoords(texCoords, texCoords)
147     );
148 }
149 
150 OriginalWithNormilizedTextureCoords createOriginalWithNormilizedTextureCoordsFromRdpl(
151     Theme theme,
152     in string style,
153 ) {
154     const textCoord = theme.tree.data.getTexCoord(style);
155     const normilized = normilizeTexture2DCoords(textCoord, theme.skin);
156 
157     return OriginalWithNormilizedTextureCoords(textCoord, normilized);
158 }
159 
160 Texture2DCoords createNormilizedTextureCoordsFromRdpl(
161     Theme theme,
162     in string style,
163 ) {
164     const textCoord = theme.tree.data.getTexCoord(style);
165     return normilizeTexture2DCoords(textCoord, theme.skin);
166 }
167 
168 UiText createUiTextFromRdpl(
169     Theme theme,
170     in string style,
171     in string name
172 ) {
173     UiText text;
174 
175     text.render = createUiTextRenderObject();
176     text.attrs = createTextAttributesFromRdpl(theme, style ~ "." ~ name);
177 
178     return text;
179 }
180 
181 StatefulUiText createStatefulUiTextFromRdpl(
182     Theme theme,
183     in string style,
184     in string name,
185     immutable State[] states = [EnumMembers!State]
186 ) {
187     StatefulUiText text;
188     text.render = createUiTextRenderObject();
189 
190     foreach (immutable state; states) {
191         text.attrs[state] = createTextAttributesFromRdpl(
192             theme,
193             style ~ "." ~ getStateRdplName(state) ~ "." ~ name
194         );
195     }
196 
197     return text;
198 }
199 
200 UiTextAttributes createTextAttributesFromRdpl(Theme theme, in string style) {
201     UiTextAttributes attrs;
202 
203     attrs.color = theme.tree.data.getNormColor(style ~ ".color");
204     attrs.offset = theme.tree.data.optVec2f(style ~ ".offset", vec2(0, 0));
205     attrs.fontSize = theme.tree.data.optInteger(style ~ ".fontSize.0", theme.regularFontSize);
206     attrs.textAlign = theme.tree.data.optEnum(style ~ ".textAlign.0", Align.center);
207     attrs.textVerticalAlign = theme.tree.data.optEnum(style ~ ".textVerticalAlign.0", VerticalAlign.middle);
208     // TODO: read from rdpl
209     attrs.font = theme.regularFont;
210 
211     return attrs;
212 }
213 
214 UiTextRender createUiTextRenderObject() {
215     return UiTextRender(createGeometry(), createText());
216 }
217 
218 Geometry createGeometry() {
219     Geometry geometry;
220 
221     geometry.indicesBuffer = createIndicesBuffer(quadIndices);
222     geometry.verticesBuffer = createVector2fBuffer(quadVertices);
223     geometry.texCoordsBuffer = createVector2fBuffer(quadTexCoords);
224 
225     geometry.vao = createVAO();
226     bindVAO(geometry.vao);
227 
228     createVector2fVAO(geometry.verticesBuffer, inAttrPosition);
229     createVector2fVAO(geometry.texCoordsBuffer, inAttrTextCoords);
230 
231     return geometry;
232 }
233 
234 LinesGeometry createDynamicLinesGeometry(ref Array!vec2 vertices, ref Array!uint indices) {
235     LinesGeometry geometry;
236 
237     geometry.indicesBuffer = createIndicesBuffer(indices, false);
238     geometry.verticesBuffer = createVector2fBuffer(vertices, false);
239 
240     geometry.vao = createVAO();
241     bindVAO(geometry.vao);
242 
243     createVector2fVAO(geometry.verticesBuffer, inAttrPosition);
244 
245     return geometry;
246 }
247 
248 void updateLinesGeometryData(ref LinesGeometry geometry, ref Array!vec2 vertices, ref Array!uint indices) {
249     updateIndicesBufferData(geometry.indicesBuffer, indices);
250     updateVector2fBufferData(geometry.verticesBuffer, vertices);
251     geometry.pointsCount = cast(uint) indices.length;
252 }