1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: MIT
3
4#include "scene.h"
5
6#include <cstdlib>
7#include <iostream>
8#include <stdlib.h>
9#include <stdio.h>
10#include <chrono>
11
12#include <GLES2/gl2.h>
13#include <GLES2/gl2platform.h>
14
15static GLint compile_shader(GLuint program, GLuint shader_type, const GLchar *const *source)
16{
17 auto shader_id = glCreateShader(type: shader_type);
18 glShaderSource(shader: shader_id, count: 1, string: source, length: nullptr);
19 glCompileShader(shader: shader_id);
20
21 GLint compiled = 0;
22 glGetShaderiv(shader: shader_id, GL_COMPILE_STATUS, params: &compiled);
23 if (!compiled) {
24 GLint infoLen = 0;
25 glGetShaderiv(shader: shader_id, GL_INFO_LOG_LENGTH, params: &infoLen);
26 if (infoLen > 1) {
27 char *infoLog = reinterpret_cast<char *>(malloc(size: sizeof(char) * infoLen));
28 glGetShaderInfoLog(shader: shader_id, bufSize: infoLen, NULL, infoLog);
29 fprintf(stderr, format: "Error compiling %s shader:\n%s\n",
30 shader_type == GL_FRAGMENT_SHADER ? "fragment shader" : "vertex shader",
31 infoLog);
32 free(ptr: infoLog);
33 }
34 glDeleteShader(shader: shader_id);
35 exit(status: 1);
36 }
37 glAttachShader(program, shader: shader_id);
38
39 return shader_id;
40}
41
42class OpenGLUnderlay
43{
44public:
45 OpenGLUnderlay(slint::ComponentWeakHandle<App> app) : app_weak(app) { }
46
47 void operator()(slint::RenderingState state, slint::GraphicsAPI)
48 {
49 switch (state) {
50 case slint::RenderingState::RenderingSetup:
51 setup();
52 break;
53 case slint::RenderingState::BeforeRendering:
54 if (auto app = app_weak.lock()) {
55 render(enable_rotation: (*app)->get_rotation_enabled());
56 (*app)->window().request_redraw();
57 }
58 break;
59 case slint::RenderingState::AfterRendering:
60 break;
61 case slint::RenderingState::RenderingTeardown:
62 teardown();
63 break;
64 }
65 }
66
67private:
68 void setup()
69 {
70 program = glCreateProgram();
71
72 const GLchar *const fragment_shader =
73 "#version 100\n"
74 "precision mediump float;\n"
75 "varying vec2 frag_position;\n"
76 "uniform float effect_time;\n"
77 "uniform float rotation_time;\n"
78 "float roundRectDistance(vec2 pos, vec2 rect_size, float radius)\n"
79 "{\n"
80 " vec2 q = abs(pos) - rect_size + radius;\n"
81 " return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - radius;\n"
82 "}\n"
83 "void main() {\n"
84 " vec2 size = vec2(0.4, 0.5) + 0.2 * cos(effect_time / 500. + vec2(0.3, 0.2));\n"
85 " float radius = 0.5 * sin(effect_time / 300.);\n"
86 " float a = rotation_time / 800.0;\n"
87 " float d = roundRectDistance(mat2(cos(a), -sin(a), sin(a), cos(a)) * "
88 "frag_position, size, radius);\n"
89 " vec3 col = (d > 0.0) ? vec3(sin(d * 0.2), 0.4 * cos(effect_time / 1000.0 + d "
90 "* 0.8), "
91 "sin(d * 1.2)) : vec3(0.2 * cos(d * 0.1), 0.17 * sin(d * 0.4), 0.96 * "
92 "abs(sin(effect_time "
93 "/ 500. - d * 0.9)));\n"
94 " col *= 0.8 + 0.5 * sin(50.0 * d);\n"
95 " col = mix(col, vec3(0.9), 1.0 - smoothstep(0.0, 0.03, abs(d) ));\n"
96 " gl_FragColor = vec4(col, 1.0);\n"
97 "}\n";
98
99 const GLchar *const vertex_shader = "#version 100\n"
100 "attribute vec2 position;\n"
101 "varying vec2 frag_position;\n"
102 "void main() {\n"
103 " frag_position = position;\n"
104 " gl_Position = vec4(position, 0.0, 1.0);\n"
105 "}\n";
106
107 auto fragment_shader_id = compile_shader(program, GL_FRAGMENT_SHADER, source: &fragment_shader);
108 auto vertex_shader_id = compile_shader(program, GL_VERTEX_SHADER, source: &vertex_shader);
109
110 GLint linked = 0;
111 glLinkProgram(program);
112 glGetProgramiv(program, GL_LINK_STATUS, params: &linked);
113
114 if (!linked) {
115 GLint infoLen = 0;
116 glGetProgramiv(program, GL_INFO_LOG_LENGTH, params: &infoLen);
117 if (infoLen > 1) {
118 char *infoLog = reinterpret_cast<char *>(malloc(size: sizeof(char) * infoLen));
119 glGetProgramInfoLog(program, bufSize: infoLen, NULL, infoLog);
120 fprintf(stderr, format: "Error linking shader:\n%s\n", infoLog);
121 free(ptr: infoLog);
122 }
123 glDeleteProgram(program);
124 exit(status: 1);
125 }
126 glDetachShader(program, shader: fragment_shader_id);
127 glDetachShader(program, shader: vertex_shader_id);
128
129 position_location = glGetAttribLocation(program, name: "position");
130 effect_time_location = glGetUniformLocation(program, name: "effect_time");
131 rotation_time_location = glGetUniformLocation(program, name: "rotation_time");
132 }
133
134 void render(bool enable_rotation)
135 {
136 glUseProgram(program);
137 const float vertices[] = { -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0 };
138 glVertexAttribPointer(index: position_location, size: 2, GL_FLOAT, GL_FALSE, stride: 0, pointer: vertices);
139 glEnableVertexAttribArray(index: position_location);
140
141 auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
142 d: std::chrono::steady_clock::now() - start_time);
143 glUniform1f(location: effect_time_location, v0: elapsed.count());
144 if (enable_rotation) {
145 glUniform1f(location: rotation_time_location, v0: elapsed.count());
146 } else {
147 glUniform1f(location: rotation_time_location, v0: 0.0);
148 }
149
150 glDrawArrays(GL_TRIANGLE_STRIP, first: 0, count: 4);
151 glUseProgram(program: 0);
152 }
153
154 void teardown() { glDeleteProgram(program); }
155
156 slint::ComponentWeakHandle<App> app_weak;
157 GLuint program = 0;
158 GLuint position_location = 0;
159 GLuint effect_time_location = 0;
160 GLuint rotation_time_location = 0;
161 std::chrono::time_point<std::chrono::steady_clock> start_time =
162 std::chrono::steady_clock::now();
163};
164
165int main()
166{
167 auto app = App::create();
168
169 if (auto error = app->window().set_rendering_notifier(OpenGLUnderlay(app))) {
170 if (*error == slint::SetRenderingNotifierError::Unsupported) {
171 fprintf(stderr,
172 format: "This example requires the use of a GL renderer. Please run with the "
173 "environment variable SLINT_BACKEND=winit set.\n");
174 } else {
175 fprintf(stderr, format: "Unknown error calling set_rendering_notifier\n");
176 }
177 exit(EXIT_FAILURE);
178 }
179
180 app->run();
181}
182

source code of slint/examples/opengl_underlay/main.cpp