#include "Renderer.hpp" #include "../core/Egl.hpp" #include "../config/ConfigManager.hpp" #include "../helpers/Color.hpp" #include "../core/Output.hpp" #include "mtx.hpp" #include #include #include #include "Shaders.hpp" #include "widgets/PasswordInputField.hpp" #include "widgets/Background.hpp" inline const float fullVerts[] = { 1, 0, // top right 0, 0, // top left 1, 1, // bottom right 0, 1, // bottom left }; GLuint compileShader(const GLuint& type, std::string src) { auto shader = glCreateShader(type); auto shaderSource = src.c_str(); glShaderSource(shader, 1, (const GLchar**)&shaderSource, nullptr); glCompileShader(shader); GLint ok; glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); RASSERT(ok != GL_FALSE, "compileShader() failed! GL_COMPILE_STATUS not OK!"); return shader; } GLuint createProgram(const std::string& vert, const std::string& frag) { auto vertCompiled = compileShader(GL_VERTEX_SHADER, vert); RASSERT(vertCompiled, "Compiling shader failed. VERTEX NULL! Shader source:\n\n{}", vert.c_str()); auto fragCompiled = compileShader(GL_FRAGMENT_SHADER, frag); RASSERT(fragCompiled, "Compiling shader failed. FRAGMENT NULL! Shader source:\n\n{}", frag.c_str()); auto prog = glCreateProgram(); glAttachShader(prog, vertCompiled); glAttachShader(prog, fragCompiled); glLinkProgram(prog); glDetachShader(prog, vertCompiled); glDetachShader(prog, fragCompiled); glDeleteShader(vertCompiled); glDeleteShader(fragCompiled); GLint ok; glGetProgramiv(prog, GL_LINK_STATUS, &ok); RASSERT(ok != GL_FALSE, "createProgram() failed! GL_LINK_STATUS not OK!"); return prog; } static void glMessageCallbackA(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { if (type != GL_DEBUG_TYPE_ERROR) return; Debug::log(LOG, "[gl] {}", (const char*)message); } CRenderer::CRenderer() { g_pEGL->makeCurrent(nullptr); glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(glMessageCallbackA, 0); GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC); rectShader.program = prog; rectShader.proj = glGetUniformLocation(prog, "proj"); rectShader.color = glGetUniformLocation(prog, "color"); rectShader.posAttrib = glGetAttribLocation(prog, "pos"); rectShader.topLeft = glGetUniformLocation(prog, "topLeft"); rectShader.fullSize = glGetUniformLocation(prog, "fullSize"); rectShader.radius = glGetUniformLocation(prog, "radius"); prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBA); texShader.program = prog; texShader.proj = glGetUniformLocation(prog, "proj"); texShader.tex = glGetUniformLocation(prog, "tex"); texShader.alphaMatte = glGetUniformLocation(prog, "texMatte"); texShader.alpha = glGetUniformLocation(prog, "alpha"); texShader.texAttrib = glGetAttribLocation(prog, "texcoord"); texShader.matteTexAttrib = glGetAttribLocation(prog, "texcoordMatte"); texShader.posAttrib = glGetAttribLocation(prog, "pos"); texShader.discardOpaque = glGetUniformLocation(prog, "discardOpaque"); texShader.discardAlpha = glGetUniformLocation(prog, "discardAlpha"); texShader.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue"); texShader.topLeft = glGetUniformLocation(prog, "topLeft"); texShader.fullSize = glGetUniformLocation(prog, "fullSize"); texShader.radius = glGetUniformLocation(prog, "radius"); texShader.applyTint = glGetUniformLocation(prog, "applyTint"); texShader.tint = glGetUniformLocation(prog, "tint"); texShader.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte"); wlr_matrix_identity(projMatrix.data()); asyncResourceGatherer = std::make_unique(); } static int frames = 0; // CRenderer::SRenderFeedback CRenderer::renderLock(const CSessionLockSurface& surf) { static auto* const PDISABLEBAR = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:disable_loading_bar"); matrixProjection(projection.data(), surf.size.x, surf.size.y, WL_OUTPUT_TRANSFORM_NORMAL); g_pEGL->makeCurrent(surf.eglSurface); glViewport(0, 0, surf.size.x, surf.size.y); glScissor(frames, 0, surf.size.x, surf.size.y); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); SRenderFeedback feedback; if (!asyncResourceGatherer->ready) { // render status if (!**PDISABLEBAR) { CBox progress = {0, 0, asyncResourceGatherer->progress * surf.size.x, 2}; renderRect(progress, CColor{0.2f, 0.1f, 0.1f, 1.f}, 0); } } else { if (!asyncResourceGatherer->applied) { asyncResourceGatherer->apply(); gatheredAt = std::chrono::system_clock::now(); } // render widgets const auto WIDGETS = getOrCreateWidgetsFor(&surf); for (auto& w : *WIDGETS) { feedback.needsFrame = w->draw() || feedback.needsFrame; } } frames++; Debug::log(TRACE, "frame {}", frames); feedback.needsFrame = feedback.needsFrame || !asyncResourceGatherer->ready; return feedback; } void CRenderer::renderRect(const CBox& box, const CColor& col, int rounding) { float matrix[9]; wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, projMatrix.data()); // TODO: write own, don't use WLR here float glMatrix[9]; wlr_matrix_multiply(glMatrix, projection.data(), matrix); glUseProgram(rectShader.program); glUniformMatrix3fv(rectShader.proj, 1, GL_TRUE, glMatrix); // premultiply the color as well as we don't work with straight alpha glUniform4f(rectShader.color, col.r * col.a, col.g * col.a, col.b * col.a, col.a); const auto TOPLEFT = Vector2D(box.x, box.y); const auto FULLSIZE = Vector2D(box.width, box.height); // Rounded corners glUniform2f(rectShader.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(rectShader.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); glUniform1f(rectShader.radius, rounding); glVertexAttribPointer(rectShader.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glEnableVertexAttribArray(rectShader.posAttrib); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisableVertexAttribArray(rectShader.posAttrib); } void CRenderer::renderTexture(const CBox& box, const CTexture& tex, float a, int rounding) { float matrix[9]; wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_FLIPPED_180 /* ugh coordinate spaces */, 0, projMatrix.data()); // TODO: write own, don't use WLR here float glMatrix[9]; wlr_matrix_multiply(glMatrix, projection.data(), matrix); CShader* shader = &texShader; glActiveTexture(GL_TEXTURE0); glBindTexture(tex.m_iTarget, tex.m_iTexID); glUseProgram(shader->program); glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); glUniform1i(shader->tex, 0); glUniform1f(shader->alpha, a); const auto TOPLEFT = Vector2D(box.x, box.y); const auto FULLSIZE = Vector2D(box.width, box.height); // Rounded corners glUniform2f(shader->topLeft, TOPLEFT.x, TOPLEFT.y); glUniform2f(shader->fullSize, FULLSIZE.x, FULLSIZE.y); glUniform1f(shader->radius, rounding); glUniform1i(shader->discardOpaque, 0); glUniform1i(shader->discardAlpha, 0); glUniform1i(shader->applyTint, 0); glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glEnableVertexAttribArray(shader->posAttrib); glEnableVertexAttribArray(shader->texAttrib); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->texAttrib); glBindTexture(tex.m_iTarget, 0); } std::vector>* CRenderer::getOrCreateWidgetsFor(const CSessionLockSurface* surf) { if (!widgets.contains(surf)) { const auto CWIDGETS = g_pConfigManager->getWidgetConfigs(); for (auto& c : CWIDGETS) { if (!c.monitor.empty() && c.monitor != surf->output->stringPort) continue; // by type if (c.type == "background") widgets[surf].emplace_back(std::make_unique(surf->size, std::string{"background:"} + std::any_cast(c.values.at("path")))); if (c.type == "input-field") { const auto SIZE = std::any_cast(c.values.at("size")); widgets[surf].emplace_back(std::make_unique( surf->size, Vector2D{SIZE.x, SIZE.y}, std::any_cast(c.values.at("outer_color")), std::any_cast(c.values.at("inner_color")), std::any_cast(c.values.at("outline_thickness")), std::any_cast(c.values.at("fade_on_empty")))); } } } return &widgets[surf]; }