initial commit
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I6a6a6964ee9e6ebe436ca8328c6e4a7ec7c9d8d4
This commit is contained in:
commit
fcc080871a
11 changed files with 12536 additions and 0 deletions
431
src/render.c
Normal file
431
src/render.c
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
#include "../include/chroma.h"
|
||||
|
||||
// Vertex shader for simple texture rendering
|
||||
static const char *vertex_shader_source =
|
||||
"#version 120\n"
|
||||
"attribute vec2 position;\n"
|
||||
"attribute vec2 texcoord;\n"
|
||||
"varying vec2 v_texcoord;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = vec4(position, 0.0, 1.0);\n"
|
||||
" v_texcoord = texcoord;\n"
|
||||
"}\n";
|
||||
|
||||
// Fragment shader for simple texture rendering
|
||||
static const char *fragment_shader_source =
|
||||
"#version 120\n"
|
||||
"varying vec2 v_texcoord;\n"
|
||||
"uniform sampler2D texture;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = texture2D(texture, v_texcoord);\n"
|
||||
"}\n";
|
||||
|
||||
// Vertices for a fullscreen quad
|
||||
static const float vertices[] = {
|
||||
// Position Texcoord
|
||||
-1.0f, -1.0f, 0.0f, 1.0f, // Bottom left
|
||||
1.0f, -1.0f, 1.0f, 1.0f, // Bottom right
|
||||
1.0f, 1.0f, 1.0f, 0.0f, // Top right
|
||||
-1.0f, 1.0f, 0.0f, 0.0f, // Top left
|
||||
};
|
||||
|
||||
static const unsigned int indices[] = {
|
||||
0, 1, 2, // First triangle
|
||||
2, 3, 0 // Second triangle
|
||||
};
|
||||
|
||||
// Shader compilation helper
|
||||
static GLuint compile_shader(GLenum type, const char *source) {
|
||||
GLuint shader = glCreateShader(type);
|
||||
if (!shader) {
|
||||
chroma_log("ERROR", "Failed to create shader");
|
||||
return 0;
|
||||
}
|
||||
|
||||
glShaderSource(shader, 1, &source, NULL);
|
||||
glCompileShader(shader);
|
||||
|
||||
GLint status;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||
if (status != GL_TRUE) {
|
||||
char log[512];
|
||||
glGetShaderInfoLog(shader, sizeof(log), NULL, log);
|
||||
chroma_log("ERROR", "Shader compilation failed: %s", log);
|
||||
glDeleteShader(shader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
// Shader program creation helper
|
||||
static GLuint create_shader_program(void) {
|
||||
GLuint vertex_shader = compile_shader(GL_VERTEX_SHADER, vertex_shader_source);
|
||||
if (!vertex_shader) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLuint fragment_shader =
|
||||
compile_shader(GL_FRAGMENT_SHADER, fragment_shader_source);
|
||||
if (!fragment_shader) {
|
||||
glDeleteShader(vertex_shader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLuint program = glCreateProgram();
|
||||
if (!program) {
|
||||
chroma_log("ERROR", "Failed to create shader program");
|
||||
glDeleteShader(vertex_shader);
|
||||
glDeleteShader(fragment_shader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
glAttachShader(program, vertex_shader);
|
||||
glAttachShader(program, fragment_shader);
|
||||
glLinkProgram(program);
|
||||
|
||||
GLint status;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
if (status != GL_TRUE) {
|
||||
char log[512];
|
||||
glGetProgramInfoLog(program, sizeof(log), NULL, log);
|
||||
chroma_log("ERROR", "Shader program linking failed: %s", log);
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
}
|
||||
|
||||
glDeleteShader(vertex_shader);
|
||||
glDeleteShader(fragment_shader);
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
// EGL configuration selection
|
||||
static int choose_egl_config(EGLDisplay display, EGLConfig *config) {
|
||||
EGLint attributes[] = {EGL_SURFACE_TYPE,
|
||||
EGL_WINDOW_BIT,
|
||||
EGL_RED_SIZE,
|
||||
8,
|
||||
EGL_GREEN_SIZE,
|
||||
8,
|
||||
EGL_BLUE_SIZE,
|
||||
8,
|
||||
EGL_ALPHA_SIZE,
|
||||
8,
|
||||
EGL_RENDERABLE_TYPE,
|
||||
EGL_OPENGL_BIT,
|
||||
EGL_NONE};
|
||||
|
||||
EGLint num_configs;
|
||||
if (!eglChooseConfig(display, attributes, config, 1, &num_configs)) {
|
||||
chroma_log("ERROR", "Failed to choose EGL config: 0x%04x", eglGetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (num_configs == 0) {
|
||||
chroma_log("ERROR", "No suitable EGL configs found");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EGL initialization
|
||||
int chroma_egl_init(chroma_state_t *state) {
|
||||
if (!state || !state->display) {
|
||||
return CHROMA_ERROR_INIT;
|
||||
}
|
||||
|
||||
// Get EGL display
|
||||
state->egl_display = eglGetDisplay((EGLNativeDisplayType)state->display);
|
||||
if (state->egl_display == EGL_NO_DISPLAY) {
|
||||
chroma_log("ERROR", "Failed to get EGL display: 0x%04x", eglGetError());
|
||||
return CHROMA_ERROR_EGL;
|
||||
}
|
||||
|
||||
// Initialize EGL
|
||||
EGLint major, minor;
|
||||
if (!eglInitialize(state->egl_display, &major, &minor)) {
|
||||
chroma_log("ERROR", "Failed to initialize EGL: 0x%04x", eglGetError());
|
||||
return CHROMA_ERROR_EGL;
|
||||
}
|
||||
|
||||
chroma_log("INFO", "EGL initialized: version %d.%d", major, minor);
|
||||
|
||||
// Bind OpenGL API
|
||||
if (!eglBindAPI(EGL_OPENGL_API)) {
|
||||
chroma_log("ERROR", "Failed to bind OpenGL API: 0x%04x", eglGetError());
|
||||
chroma_egl_cleanup(state);
|
||||
return CHROMA_ERROR_EGL;
|
||||
}
|
||||
|
||||
// Choose EGL config
|
||||
if (choose_egl_config(state->egl_display, &state->egl_config) != 0) {
|
||||
chroma_egl_cleanup(state);
|
||||
return CHROMA_ERROR_EGL;
|
||||
}
|
||||
|
||||
// Create EGL context
|
||||
EGLint context_attributes[] = {EGL_CONTEXT_MAJOR_VERSION, 2,
|
||||
EGL_CONTEXT_MINOR_VERSION, 1, EGL_NONE};
|
||||
|
||||
state->egl_context = eglCreateContext(state->egl_display, state->egl_config,
|
||||
EGL_NO_CONTEXT, context_attributes);
|
||||
if (state->egl_context == EGL_NO_CONTEXT) {
|
||||
chroma_log("ERROR", "Failed to create EGL context: 0x%04x", eglGetError());
|
||||
chroma_egl_cleanup(state);
|
||||
return CHROMA_ERROR_EGL;
|
||||
}
|
||||
|
||||
chroma_log("INFO", "EGL context created successfully");
|
||||
return CHROMA_OK;
|
||||
}
|
||||
|
||||
// EGL cleanup
|
||||
void chroma_egl_cleanup(chroma_state_t *state) {
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->egl_display != EGL_NO_DISPLAY) {
|
||||
eglMakeCurrent(state->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
EGL_NO_CONTEXT);
|
||||
|
||||
if (state->egl_context != EGL_NO_CONTEXT) {
|
||||
eglDestroyContext(state->egl_display, state->egl_context);
|
||||
state->egl_context = EGL_NO_CONTEXT;
|
||||
}
|
||||
|
||||
eglTerminate(state->egl_display);
|
||||
state->egl_display = EGL_NO_DISPLAY;
|
||||
}
|
||||
|
||||
chroma_log("INFO", "EGL cleaned up");
|
||||
}
|
||||
|
||||
// Create surface for output
|
||||
int chroma_surface_create(chroma_state_t *state, chroma_output_t *output) {
|
||||
if (!state || !output || !state->compositor || !state->layer_shell) {
|
||||
return CHROMA_ERROR_INIT;
|
||||
}
|
||||
|
||||
// Create Wayland surface
|
||||
output->surface = wl_compositor_create_surface(state->compositor);
|
||||
if (!output->surface) {
|
||||
chroma_log("ERROR", "Failed to create Wayland surface for output %u",
|
||||
output->id);
|
||||
return CHROMA_ERROR_WAYLAND;
|
||||
}
|
||||
|
||||
// Create layer surface for wallpaper
|
||||
output->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
|
||||
state->layer_shell, output->surface, output->wl_output,
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, "chroma-wallpaper");
|
||||
|
||||
if (!output->layer_surface) {
|
||||
chroma_log("ERROR", "Failed to create layer surface for output %u",
|
||||
output->id);
|
||||
chroma_surface_destroy(output);
|
||||
return CHROMA_ERROR_WAYLAND;
|
||||
}
|
||||
|
||||
// Configure layer surface
|
||||
zwlr_layer_surface_v1_set_size(output->layer_surface, output->width,
|
||||
output->height);
|
||||
zwlr_layer_surface_v1_set_anchor(output->layer_surface,
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
|
||||
zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, -1);
|
||||
zwlr_layer_surface_v1_set_keyboard_interactivity(
|
||||
output->layer_surface, ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE);
|
||||
|
||||
// Add layer surface listener
|
||||
zwlr_layer_surface_v1_add_listener(
|
||||
output->layer_surface, &chroma_layer_surface_listener_impl, output);
|
||||
|
||||
// Commit surface to trigger configure event
|
||||
wl_surface_commit(output->surface);
|
||||
|
||||
// Wait for configure event
|
||||
wl_display_roundtrip(state->display);
|
||||
|
||||
// Create EGL window
|
||||
output->egl_window =
|
||||
wl_egl_window_create(output->surface, output->width, output->height);
|
||||
if (!output->egl_window) {
|
||||
chroma_log("ERROR", "Failed to create EGL window for output %u",
|
||||
output->id);
|
||||
chroma_surface_destroy(output);
|
||||
return CHROMA_ERROR_EGL;
|
||||
}
|
||||
|
||||
// Create EGL surface
|
||||
output->egl_surface =
|
||||
eglCreateWindowSurface(state->egl_display, state->egl_config,
|
||||
(EGLNativeWindowType)output->egl_window, NULL);
|
||||
if (output->egl_surface == EGL_NO_SURFACE) {
|
||||
chroma_log("ERROR", "Failed to create EGL surface for output %u: 0x%04x",
|
||||
output->id, eglGetError());
|
||||
chroma_surface_destroy(output);
|
||||
return CHROMA_ERROR_EGL;
|
||||
}
|
||||
|
||||
chroma_log("INFO", "Created surface for output %u (%dx%d)", output->id,
|
||||
output->width, output->height);
|
||||
|
||||
return CHROMA_OK;
|
||||
}
|
||||
|
||||
// Destroy surface
|
||||
void chroma_surface_destroy(chroma_output_t *output) {
|
||||
if (!output) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (output->egl_surface != EGL_NO_SURFACE) {
|
||||
eglDestroySurface(eglGetCurrentDisplay(), output->egl_surface);
|
||||
output->egl_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
if (output->egl_window) {
|
||||
wl_egl_window_destroy(output->egl_window);
|
||||
output->egl_window = NULL;
|
||||
}
|
||||
|
||||
if (output->layer_surface) {
|
||||
zwlr_layer_surface_v1_destroy(output->layer_surface);
|
||||
output->layer_surface = NULL;
|
||||
}
|
||||
|
||||
if (output->surface) {
|
||||
wl_surface_destroy(output->surface);
|
||||
output->surface = NULL;
|
||||
}
|
||||
|
||||
chroma_log("DEBUG", "Destroyed surface for output %u", output->id);
|
||||
}
|
||||
|
||||
// Create texture from image data
|
||||
static GLuint create_texture_from_image(chroma_image_t *image) {
|
||||
if (!image || !image->loaded || !image->data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
// Set texture parameters
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// Upload texture data
|
||||
GLenum format = (image->channels == 4) ? GL_RGBA : GL_RGB;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, format, image->width, image->height, 0, format,
|
||||
GL_UNSIGNED_BYTE, image->data);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
// Render wallpaper to output
|
||||
int chroma_render_wallpaper(chroma_state_t *state, chroma_output_t *output) {
|
||||
if (!state || !output || !output->image || !output->image->loaded) {
|
||||
return CHROMA_ERROR_INIT;
|
||||
}
|
||||
|
||||
// Make context current
|
||||
if (!eglMakeCurrent(state->egl_display, output->egl_surface,
|
||||
output->egl_surface, state->egl_context)) {
|
||||
chroma_log("ERROR", "Failed to make EGL context current: 0x%04x",
|
||||
eglGetError());
|
||||
return CHROMA_ERROR_EGL;
|
||||
}
|
||||
|
||||
// Set viewport
|
||||
glViewport(0, 0, output->width, output->height);
|
||||
|
||||
// Clear screen
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// Create shader program (should be cached in real implementation)
|
||||
GLuint program = create_shader_program();
|
||||
if (!program) {
|
||||
return CHROMA_ERROR_EGL;
|
||||
}
|
||||
|
||||
// Use shader program
|
||||
glUseProgram(program);
|
||||
|
||||
// Create and bind texture
|
||||
GLuint texture = create_texture_from_image(output->image);
|
||||
if (!texture) {
|
||||
chroma_log("ERROR", "Failed to create texture for output %u", output->id);
|
||||
glDeleteProgram(program);
|
||||
return CHROMA_ERROR_EGL;
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glUniform1i(glGetUniformLocation(program, "texture"), 0);
|
||||
|
||||
// Create vertex buffer objects (should be cached in real implementation)
|
||||
GLuint vbo, ebo;
|
||||
glGenBuffers(1, &vbo);
|
||||
glGenBuffers(1, &ebo);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices,
|
||||
GL_STATIC_DRAW);
|
||||
|
||||
// Set vertex attributes
|
||||
GLint position_attr = glGetAttribLocation(program, "position");
|
||||
GLint texcoord_attr = glGetAttribLocation(program, "texcoord");
|
||||
|
||||
glEnableVertexAttribArray(position_attr);
|
||||
glVertexAttribPointer(position_attr, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float),
|
||||
(void *)0);
|
||||
|
||||
glEnableVertexAttribArray(texcoord_attr);
|
||||
glVertexAttribPointer(texcoord_attr, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float),
|
||||
(void *)(2 * sizeof(float)));
|
||||
|
||||
// Draw
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
|
||||
// Cleanup
|
||||
glDeleteBuffers(1, &vbo);
|
||||
glDeleteBuffers(1, &ebo);
|
||||
glDeleteTextures(1, &texture);
|
||||
glDeleteProgram(program);
|
||||
|
||||
// Swap buffers
|
||||
if (!eglSwapBuffers(state->egl_display, output->egl_surface)) {
|
||||
chroma_log("ERROR", "Failed to swap buffers for output %u: 0x%04x",
|
||||
output->id, eglGetError());
|
||||
return CHROMA_ERROR_EGL;
|
||||
}
|
||||
|
||||
// Commit surface
|
||||
wl_surface_commit(output->surface);
|
||||
|
||||
chroma_log("DEBUG", "Rendered wallpaper to output %u", output->id);
|
||||
return CHROMA_OK;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue