1 module rpui.render.renderer;
2 
3 import std.math;
4 
5 import gapi.vec;
6 import gapi.transform;
7 import gapi.shader;
8 import gapi.shader_uniform;
9 import gapi.texture;
10 import gapi.geometry;
11 import gapi.geometry_quad;
12 import gapi.opengl;
13 import gapi.font;
14 import gapi.text;
15 
16 import rpui.events;
17 import rpui.theme;
18 import rpui.widget;
19 import rpui.render.components;
20 import rpui.primitives;
21 
22 interface Renderer {
23     void onCreate(Widget widget, in string style);
24 
25     void onRender();
26 
27     void onProgress(in ProgressEvent event);
28 }
29 
30 class DummyRenderer : Renderer {
31     override void onCreate(Widget widget, in string style) {
32     }
33 
34     override void onRender() {
35     }
36 
37     override void onProgress(in ProgressEvent event) {
38     }
39 }
40 
41 interface RenderSystem {
42     void onRender();
43 }
44 
45 void renderTexAtlasQuad(
46     in Theme theme,
47     in StatefulTexAtlasTextureQuad quad,
48     in QuadTransforms transforms,
49     in float alpha = 1.0f,
50 ) {
51     renderTexAtlasQuad(
52         theme,
53         quad.geometry,
54         quad.texture,
55         quad.texCoords[quad.state].normilizedTexCoords,
56         transforms,
57         alpha
58     );
59 }
60 
61 void renderTexAtlasQuad(
62     in Theme theme,
63     in TexAtlasTextureQuad quad,
64     in QuadTransforms transforms,
65     in float alpha = 1.0f,
66 ) {
67     renderTexAtlasQuad(
68         theme,
69         quad.geometry,
70         quad.texture,
71         quad.texCoords.normilizedTexCoords,
72         transforms,
73         alpha
74     );
75 }
76 
77 void renderTexAtlasQuad(
78     in Theme theme,
79     in Geometry geometry,
80     in Texture2D texture,
81     in Texture2DCoords texCoord,
82     in QuadTransforms transforms,
83     in float alpha = 1.0f,
84 ) {
85     const shader = theme.shaders.textureAtlasShader;
86     bindShaderProgram(shader);
87 
88     setShaderProgramUniformMatrix(shader, "MVP", transforms.mvpMatrix);
89     setShaderProgramUniformTexture(shader, "texture", texture, 0);
90     setShaderProgramUniformVec2f(shader,"texOffset", texCoord.offset);
91     setShaderProgramUniformVec2f(shader,"texSize", texCoord.size);
92     setShaderProgramUniformFloat(shader, "alpha", alpha);
93 
94     bindVAO(geometry.vao);
95     bindIndices(geometry.indicesBuffer);
96     renderIndexedGeometry(cast(uint) quadIndices.length, GL_TRIANGLE_STRIP);
97 }
98 
99 void renderColorQuad(
100     in Theme theme,
101     in Geometry geometry,
102     in vec4 color,
103     in QuadTransforms transforms
104 ) {
105     const shader = theme.shaders.colorShader;
106     bindShaderProgram(shader);
107 
108     setShaderProgramUniformMatrix(shader, "MVP", transforms.mvpMatrix);
109     setShaderProgramUniformVec4f(shader, "color", color);
110 
111     bindVAO(geometry.vao);
112     bindIndices(geometry.indicesBuffer);
113     renderIndexedGeometry(cast(uint) quadIndices.length, GL_TRIANGLE_STRIP);
114 }
115 
116 void renderColorLines(
117     in Theme theme,
118     in LinesGeometry geometry,
119     in vec4 color,
120     in LinesTransforms transforms
121 ) {
122     const shader = theme.shaders.colorShader;
123     bindShaderProgram(shader);
124 
125     setShaderProgramUniformMatrix(shader, "MVP", transforms.mvpMatrix);
126     setShaderProgramUniformVec4f(shader, "color", color);
127 
128     bindVAO(geometry.vao);
129     bindIndices(geometry.indicesBuffer);
130 
131     renderIndexedGeometry(geometry.pointsCount, GL_LINES);
132 }
133 
134 void renderBlock(in Theme theme, in Block block, in BlockTransforms transforms, in float alpha = 1.0f) {
135     renderHorizontalChain(theme, block.topChain, transforms.topChain, Widget.PartDraws.all, alpha);
136     renderHorizontalChain(theme, block.bottomChain, transforms.bottomChain, Widget.PartDraws.all, alpha);
137     renderHorizontalChain(theme, block.middleChain, transforms.middleChain, Widget.PartDraws.all, alpha);
138 }
139 
140 void renderHorizontalChain(
141     in Theme theme,
142     in StatefulChain chain,
143     in HorizontalChainTransforms transforms,
144     in Widget.PartDraws partDraws = Widget.PartDraws.all,
145     in float alpha = 1.0f
146 ) {
147     renderHorizontalChain(
148         theme,
149         chain.parts,
150         chain.texCoords[chain.state],
151         transforms,
152         partDraws,
153         alpha
154     );
155 }
156 
157 void renderHorizontalChain(
158     in Theme theme,
159     in Chain chain,
160     in HorizontalChainTransforms transforms,
161     in Widget.PartDraws partDraws = Widget.PartDraws.all,
162     in float alpha = 1.0f
163 ) {
164     renderHorizontalChain(
165         theme,
166         chain.parts,
167         chain.texCoords,
168         transforms,
169         partDraws,
170         alpha
171     );
172 }
173 
174 void renderHorizontalChain(
175     in Theme theme,
176     in TextureQuad[ChainPart] parts,
177     in Texture2DCoords[ChainPart] texCoords,
178     in HorizontalChainTransforms transforms,
179     in Widget.PartDraws partDraws = Widget.PartDraws.all,
180     in float alpha = 1.0f
181 ) {
182     if (partDraws == Widget.PartDraws.left || partDraws == Widget.PartDraws.all) {
183         renderTexAtlasQuad(
184             theme,
185             parts[ChainPart.left].geometry,
186             parts[ChainPart.left].texture,
187             texCoords[ChainPart.left],
188             transforms.quadTransforms[ChainPart.left],
189             alpha
190         );
191     }
192 
193     if (partDraws == Widget.PartDraws.right || partDraws == Widget.PartDraws.all) {
194         renderTexAtlasQuad(
195             theme,
196             parts[ChainPart.right].geometry,
197             parts[ChainPart.right].texture,
198             texCoords[ChainPart.right],
199             transforms.quadTransforms[ChainPart.right],
200             alpha
201         );
202     }
203 
204     renderTexAtlasQuad(
205         theme,
206         parts[ChainPart.center].geometry,
207         parts[ChainPart.center].texture,
208         texCoords[ChainPart.center],
209         transforms.quadTransforms[ChainPart.center],
210         alpha
211     );
212 }
213 
214 void renderVerticalChain(
215     in Theme theme,
216     in TextureQuad[ChainPart] parts,
217     in Texture2DCoords[ChainPart] texCoords,
218     in HorizontalChainTransforms transforms
219 ) {
220     renderTexAtlasQuad(
221         theme,
222         parts[ChainPart.top].geometry,
223         parts[ChainPart.top].texture,
224         texCoords[ChainPart.top],
225         transforms.quadTransforms[ChainPart.top]
226     );
227 
228     renderTexAtlasQuad(
229         theme,
230         parts[ChainPart.bottom].geometry,
231         parts[ChainPart.bottom].texture,
232         texCoords[ChainPart.bottom],
233         transforms.quadTransforms[ChainPart.bottom]
234     );
235 
236     renderTexAtlasQuad(
237         theme,
238         parts[ChainPart.middle].geometry,
239         parts[ChainPart.middle].texture,
240         texCoords[ChainPart.middle],
241         transforms.quadTransforms[ChainPart.middle]
242     );
243 }
244 
245 void renderUiText(
246     in Theme theme,
247     in StatefulUiText text,
248     in UiTextTransforms transforms
249 ) {
250     renderUiText(
251         theme,
252         text.render,
253         text.attrs[text.state],
254         transforms
255     );
256 }
257 
258 void renderUiText(
259     in Theme theme,
260     in UiTextRender text,
261     in UiTextAttributes attrs,
262     in UiTextTransforms transforms
263 ) {
264     bindShaderProgram(theme.shaders.textShader);
265 
266     setShaderProgramUniformVec4f(theme.shaders.textShader, "color", attrs.color);
267     setShaderProgramUniformTexture(theme.shaders.textShader, "texture", text.texture, 0);
268     setShaderProgramUniformMatrix(theme.shaders.textShader, "MVP", transforms.mvpMatrix);
269 
270     bindVAO(text.geometry.vao);
271     bindIndices(text.geometry.indicesBuffer);
272 
273     renderIndexedGeometry(cast(uint) quadIndices.length, GL_TRIANGLE_STRIP);
274 }