From 350826c303988f9bb0d66ddec448fc5d955d054a Mon Sep 17 00:00:00 2001 From: "Dr. Flarp" Date: Fri, 13 Mar 2026 15:44:14 -0400 Subject: [PATCH 01/13] rework shader pipeline for better consistency currently shaders residing in .system are sent to runShaderPass with incomplete initialization - in particular, all uniformLocations are passed in as 0's. As it stands, the only uniform in these shaders is the sampler2D (texture unit), so it's mostly a lot of wrong-type error no-op's, but it does prevent the proposed OrigTexture feature from working properly. --- workspace/all/common/generic_video.c | 428 ++++++++++++++------------- 1 file changed, 219 insertions(+), 209 deletions(-) diff --git a/workspace/all/common/generic_video.c b/workspace/all/common/generic_video.c index 0d68a74ef..02ce83da0 100644 --- a/workspace/all/common/generic_video.c +++ b/workspace/all/common/generic_video.c @@ -37,42 +37,61 @@ static int shaderResetRequested = 0; // shader stuff -typedef struct Shader { - int srcw; - int srch; - int texw; - int texh; - int filter; +typedef struct ShaderProgram { GLuint shader_p; - int scale; - int srctype; - int scaletype; char *filename; - GLuint texture; - int updated; GLint u_FrameDirection; GLint u_FrameCount; GLint u_OutputSize; GLint u_TextureSize; GLint u_InputSize; GLint OrigInputSize; - GLint texLocation; - GLint texelSizeLocation; + GLint TexLocation; + GLint TexelSizeLocation; ShaderParam *pragmas; // Dynamic array of parsed pragma parameters int num_pragmas; // Count of valid pragma parameters +} ShaderProgram; + +ShaderProgram s_shader_default = {0}; +ShaderProgram s_shader_overlay = {0}; +ShaderProgram s_noshader = {0}; -} Shader; +typedef struct ShaderPass { + ShaderProgram * program; + int filter; + int alpha; + GLuint source_texture; + GLuint target_texture; + int target_updated; + int scale; + int srctype; + int scaletype; + int srcw; + int srch; + int texw; + int texh; +} ShaderPass; + +ShaderPass shaders[MAXSHADERS] = { + { .program = &(ShaderProgram){ .shader_p = 0, .filename = "stock.glsl" }, + .filter = GL_LINEAR, .scale = 1, .scaletype = 0, .srctype = 0, .target_texture = 0, .target_updated = 1 }, + { .program = &(ShaderProgram){ .shader_p = 0, .filename = "stock.glsl" }, + .filter = GL_LINEAR, .scale = 1, .scaletype = 0, .srctype = 0, .target_texture = 0, .target_updated = 1 }, + { .program = &(ShaderProgram){ .shader_p = 0, .filename = "stock.glsl" }, + .filter = GL_LINEAR, .scale = 1, .scaletype = 0, .srctype = 0, .target_texture = 0, .target_updated = 1 } +}; -GLuint g_shader_default = 0; -GLuint g_shader_overlay = 0; -GLuint g_noshader = 0; +ShaderPass sp_finalscale = { .program = &s_shader_default, + .filter = GL_NEAREST, .filter = GL_NEAREST, .alpha = 0, + .target_texture = 0, .target_updated = 1 +}; -Shader* shaders[MAXSHADERS] = { - &(Shader){ .shader_p = 0, .scale = 1, .filter = GL_LINEAR, .scaletype = 1, .srctype = 0, .filename ="stock.glsl", .texture = 0, .updated = 1 }, - &(Shader){ .shader_p = 0, .scale = 1, .filter = GL_LINEAR, .scaletype = 1, .srctype = 0, .filename ="stock.glsl", .texture = 0, .updated = 1 }, - &(Shader){ .shader_p = 0, .scale = 1, .filter = GL_LINEAR, .scaletype = 1, .srctype = 0, .filename ="stock.glsl", .texture = 0, .updated = 1 }, +ShaderPass sp_overlay = { .program = &s_shader_overlay, + .filter = GL_NEAREST, .filter = GL_NEAREST, .alpha = 1, + .target_texture = 0, .target_updated = 1 }; + static int nrofshaders = 0; // choose between 1 and 3 pipelines, > pipelines = more cpu usage, but more shader options and shader upscaling stuff /////////////////////////////// @@ -269,9 +288,7 @@ char* load_shader_source(const char* filename) { return source; } -GLuint load_shader_from_file(GLenum type, const char* filename, const char* path) { - char filepath[256]; - snprintf(filepath, sizeof(filepath), "%s/%s", path, filename); +GLuint load_shader_from_file(GLenum type, const char* filepath) { char* source = load_shader_source(filepath); if (!source) return 0; @@ -431,29 +448,91 @@ GLuint load_shader_from_file(GLenum type, const char* filename, const char* path return shader; } +#define MAX_SHADER_PRAGMAS 32 +void loadShaderPragmas(ShaderProgram *shader, const char *shaderSource) { + shader->pragmas = calloc(MAX_SHADER_PRAGMAS, sizeof(ShaderParam)); + if (!shader->pragmas) { + fprintf(stderr, "Out of memory allocating pragmas for %s\n", shader->filename); + return; + } + shader->num_pragmas = extractPragmaParameters(shaderSource, shader->pragmas, MAX_SHADER_PRAGMAS); +} + +ShaderParam* PLAT_getShaderPragmas(int i) { + return shaders[i].program->pragmas; +} + +void init_shader_program(ShaderProgram * shader, const char * path, const char * filename) { + char filepath[512]; + snprintf(filepath, sizeof(filepath), "%s/%s", path, filename); + + const char *shaderSource = load_shader_source(filepath); + loadShaderPragmas(shader,shaderSource); + + GLuint vertex_shader1 = load_shader_from_file(GL_VERTEX_SHADER, filepath); + GLuint fragment_shader1 = load_shader_from_file(GL_FRAGMENT_SHADER, filepath); + + // Link the shader program + if (shader->shader_p != 0) { + LOG_info("Deleting previous shader %i\n",shader->shader_p); + glDeleteProgram(shader->shader_p); + } + shader->shader_p = link_program(vertex_shader1, fragment_shader1, filename); + + + if (shader->shader_p == 0) { + LOG_info("Shader linking failed for %s\n", filename); + } + + GLint success = 0; + glGetProgramiv(shader->shader_p, GL_LINK_STATUS, &success); + if (!success) { + char infoLog[512]; + glGetProgramInfoLog(shader->shader_p, 512, NULL, infoLog); + LOG_info("Shader Program Linking Failed: %s\n", infoLog); + } else { + LOG_info("Shader Program Linking Success %s shader ID is %i\n", filename,shader->shader_p); + + // Populate uniforms and pragma uniforms + shader->u_FrameDirection = glGetUniformLocation( shader->shader_p, "FrameDirection"); + shader->u_FrameCount = glGetUniformLocation( shader->shader_p, "FrameCount"); + shader->u_OutputSize = glGetUniformLocation( shader->shader_p, "OutputSize"); + shader->u_TextureSize = glGetUniformLocation( shader->shader_p, "TextureSize"); + shader->u_InputSize = glGetUniformLocation( shader->shader_p, "InputSize"); + shader->OrigInputSize = glGetUniformLocation( shader->shader_p, "OrigInputSize"); + shader->TexLocation = glGetUniformLocation(shader->shader_p, "Texture"); + shader->TexelSizeLocation = glGetUniformLocation(shader->shader_p, "texelSize"); + for (int i = 0; i < shader->num_pragmas; ++i) { + shader->pragmas[i].uniformLocation = glGetUniformLocation(shader->shader_p, shader->pragmas[i].name); + shader->pragmas[i].value = shader->pragmas[i].def; + + LOG_info("Param: %s = %f (min: %f, max: %f, step: %f)\n", + shader->pragmas[i].name, + shader->pragmas[i].def, + shader->pragmas[i].min, + shader->pragmas[i].max, + shader->pragmas[i].step); + } + + } + shader->filename = strdup(filename); + +} + void PLAT_initShaders() { SDL_GL_MakeCurrent(vid.window, vid.gl_context); glViewport(0, 0, device_width, device_height); - - GLuint vertex; - GLuint fragment; // Final display shader (simple texture blit) - vertex = load_shader_from_file(GL_VERTEX_SHADER, "default.glsl",SYSSHADERS_FOLDER); - fragment = load_shader_from_file(GL_FRAGMENT_SHADER, "default.glsl",SYSSHADERS_FOLDER); - g_shader_default = link_program(vertex, fragment,"default.glsl"); + init_shader_program(&s_shader_default, SYSSHADERS_FOLDER, "default.glsl"); // Overlay shader, for png overlays and static line/grid overlays - vertex = load_shader_from_file(GL_VERTEX_SHADER, "overlay.glsl",SYSSHADERS_FOLDER); - fragment = load_shader_from_file(GL_FRAGMENT_SHADER, "overlay.glsl",SYSSHADERS_FOLDER); - g_shader_overlay = link_program(vertex, fragment,"overlay.glsl"); + init_shader_program(&s_shader_overlay, SYSSHADERS_FOLDER, "overlay.glsl"); // Stand-In if a shader is supposed to be applied, but wasnt compiled properly (shaper_p == NULL) - vertex = load_shader_from_file(GL_VERTEX_SHADER, "noshader.glsl",SYSSHADERS_FOLDER); - fragment = load_shader_from_file(GL_FRAGMENT_SHADER, "noshader.glsl",SYSSHADERS_FOLDER); - g_noshader = link_program(vertex, fragment,"noshader.glsl"); + init_shader_program(&s_noshader, SYSSHADERS_FOLDER, "noshader.glsl"); - LOG_info("default shaders loaded, %i\n\n",g_shader_default); + LOG_info("default shaders loaded, %i\n\n", s_shader_default.shader_p); } void PLAT_initNotificationTexture(void) { @@ -599,96 +678,35 @@ SDL_Surface* PLAT_initVideo(void) { return vid.screen; } -#define MAX_SHADER_PRAGMAS 32 -void loadShaderPragmas(Shader *shader, const char *shaderSource) { - shader->pragmas = calloc(MAX_SHADER_PRAGMAS, sizeof(ShaderParam)); - if (!shader->pragmas) { - fprintf(stderr, "Out of memory allocating pragmas for %s\n", shader->filename); - return; - } - shader->num_pragmas = extractPragmaParameters(shaderSource, shader->pragmas, MAX_SHADER_PRAGMAS); -} - -ShaderParam* PLAT_getShaderPragmas(int i) { - return shaders[i]->pragmas; -} - void PLAT_updateShader(int i, const char *filename, int *scale, int *filter, int *scaletype, int *srctype) { if (i < 0 || i >= nrofshaders) { return; } - Shader* shader = shaders[i]; + ShaderPass* shader_pass = &shaders[i]; if (filename != NULL) { SDL_GL_MakeCurrent(vid.window, vid.gl_context); LOG_info("loading shader \n"); - char filepath[512]; - snprintf(filepath, sizeof(filepath), SHADERS_FOLDER "/glsl/%s",filename); - const char *shaderSource = load_shader_source(filepath); - loadShaderPragmas(shader,shaderSource); - - GLuint vertex_shader1 = load_shader_from_file(GL_VERTEX_SHADER, filename,SHADERS_FOLDER "/glsl"); - GLuint fragment_shader1 = load_shader_from_file(GL_FRAGMENT_SHADER, filename,SHADERS_FOLDER "/glsl"); - - // Link the shader program - if (shader->shader_p != 0) { - LOG_info("Deleting previous shader %i\n",shader->shader_p); - glDeleteProgram(shader->shader_p); - } - shader->shader_p = link_program(vertex_shader1, fragment_shader1,filename); - - shader->u_FrameDirection = glGetUniformLocation( shader->shader_p, "FrameDirection"); - shader->u_FrameCount = glGetUniformLocation( shader->shader_p, "FrameCount"); - shader->u_OutputSize = glGetUniformLocation( shader->shader_p, "OutputSize"); - shader->u_TextureSize = glGetUniformLocation( shader->shader_p, "TextureSize"); - shader->u_InputSize = glGetUniformLocation( shader->shader_p, "InputSize"); - shader->OrigInputSize = glGetUniformLocation( shader->shader_p, "OrigInputSize"); - shader->texLocation = glGetUniformLocation(shader->shader_p, "Texture"); - shader->texelSizeLocation = glGetUniformLocation(shader->shader_p, "texelSize"); - for (int i = 0; i < shader->num_pragmas; ++i) { - shader->pragmas[i].uniformLocation = glGetUniformLocation(shader->shader_p, shader->pragmas[i].name); - shader->pragmas[i].value = shader->pragmas[i].def; - - LOG_info("Param: %s = %f (min: %f, max: %f, step: %f)\n", - shader->pragmas[i].name, - shader->pragmas[i].def, - shader->pragmas[i].min, - shader->pragmas[i].max, - shader->pragmas[i].step); - } - - if (shader->shader_p == 0) { - LOG_info("Shader linking failed for %s\n", filename); - } + init_shader_program(shader_pass->program, SHADERS_FOLDER "/glsl", filename); + } - GLint success = 0; - glGetProgramiv(shader->shader_p, GL_LINK_STATUS, &success); - if (!success) { - char infoLog[512]; - glGetProgramInfoLog(shader->shader_p, 512, NULL, infoLog); - LOG_info("Shader Program Linking Failed: %s\n", infoLog); - } else { - LOG_info("Shader Program Linking Success %s shader ID is %i\n", filename,shader->shader_p); - } - shader->filename = strdup(filename); - } if (scale != NULL) { - shader->scale = *scale +1; + shader_pass->scale = *scale +1; reloadShaderTextures = 1; } if (scaletype != NULL) { - shader->scaletype = *scaletype; + shader_pass->scaletype = *scaletype; } if (srctype != NULL) { - shader->srctype = *srctype; + shader_pass->srctype = *srctype; } if (filter != NULL) { - shader->filter = (*filter == 1) ? GL_LINEAR : GL_NEAREST; + shader_pass->filter = (*filter == 1) ? GL_LINEAR : GL_NEAREST; reloadShaderTextures = 1; } - shader->updated = 1; + shader_pass->target_updated = 1; } @@ -1621,8 +1639,10 @@ void PLAT_flip(SDL_Surface* IGNORED, int ignored) { } static int frame_count = 0; -void runShaderPass(GLuint src_texture, GLuint shader_program, GLuint* target_texture, - int x, int y, int dst_width, int dst_height, Shader* shader, int alpha, int filter) { +void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, + GLuint * target_texture, int next_filter, + int src_w, int src_h, int tex_w, int tex_h, + int x, int y, int dst_width, int dst_height) { static GLuint static_VAO = 0, static_VBO = 0; static GLuint last_program = 0; @@ -1634,6 +1654,17 @@ void runShaderPass(GLuint src_texture, GLuint shader_program, GLuint* target_tex static int logged_bad_size = 0; GLenum pre_err; + if (!shader_pass) return; + + ShaderProgram * shader_program = shader_pass->program; + + if (!shader_program || !shader_program->shader_p) { + shader_program = &s_noshader; + } + + const int alpha = shader_pass->alpha; + const GLuint shader_program_handle = shader_program->shader_p; + while ((pre_err = glGetError()) != GL_NO_ERROR) { (void)pre_err; } @@ -1663,12 +1694,12 @@ void runShaderPass(GLuint src_texture, GLuint shader_program, GLuint* target_tex last_bound_texture = 0; } - texelSize[0] = 1.0f / shader->texw; - texelSize[1] = 1.0f / shader->texh; + texelSize[0] = 1.0f / tex_w; + texelSize[1] = 1.0f / tex_h; - if (shader_program != last_program) - glUseProgram(shader_program); + if (shader_program_handle != last_program) + glUseProgram(shader_program_handle); if (static_VAO == 0) { glGenVertexArrays(1, &static_VAO); @@ -1687,29 +1718,29 @@ void runShaderPass(GLuint src_texture, GLuint shader_program, GLuint* target_tex glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); } - if (shader_program != last_program) { - GLint posAttrib = glGetAttribLocation(shader_program, "VertexCoord"); + if (shader_program_handle != last_program) { + GLint posAttrib = glGetAttribLocation(shader_program_handle, "VertexCoord"); if (posAttrib >= 0) { glVertexAttribPointer(posAttrib, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(posAttrib); } - GLint texAttrib = glGetAttribLocation(shader_program, "TexCoord"); + GLint texAttrib = glGetAttribLocation(shader_program_handle, "TexCoord"); if (texAttrib >= 0) { glVertexAttribPointer(texAttrib, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(4 * sizeof(float))); glEnableVertexAttribArray(texAttrib); } - if (shader->u_FrameDirection >= 0) glUniform1i(shader->u_FrameDirection, 1); - if (shader->u_FrameCount >= 0) glUniform1i(shader->u_FrameCount, frame_count); - if (shader->u_OutputSize >= 0) glUniform2f(shader->u_OutputSize, dst_width, dst_height); - if (shader->u_TextureSize >= 0) glUniform2f(shader->u_TextureSize, shader->texw, shader->texh); - if (shader->OrigInputSize >= 0) glUniform2f(shader->OrigInputSize, shader->srcw, shader->srch); - if (shader->u_InputSize >= 0) glUniform2f(shader->u_InputSize, shader->srcw, shader->srch); - for (int i = 0; i < shader->num_pragmas; ++i) { - glUniform1f(shader->pragmas[i].uniformLocation, shader->pragmas[i].value); + if (shader_program->u_FrameDirection >= 0) glUniform1i(shader_program->u_FrameDirection, 1); + if (shader_program->u_FrameCount >= 0) glUniform1i(shader_program->u_FrameCount, frame_count); + if (shader_program->u_OutputSize >= 0) glUniform2f(shader_program->u_OutputSize, dst_width, dst_height); + if (shader_program->u_TextureSize >= 0) glUniform2f(shader_program->u_TextureSize, tex_w, tex_h); + if (shader_program->OrigInputSize >= 0) glUniform2f(shader_program->OrigInputSize, src_w, src_h); + if (shader_program->u_InputSize >= 0) glUniform2f(shader_program->u_InputSize, src_w, src_h); + for (int i = 0; i < shader_program->num_pragmas; ++i) { + glUniform1f(shader_program->pragmas[i].uniformLocation, shader_program->pragmas[i].value); } - GLint u_MVP = glGetUniformLocation(shader_program, "MVPMatrix"); + GLint u_MVP = glGetUniformLocation(shader_program_handle, "MVPMatrix"); if (u_MVP >= 0) { float identity[16] = { 1,0,0,0, @@ -1724,9 +1755,9 @@ void runShaderPass(GLuint src_texture, GLuint shader_program, GLuint* target_tex if (target_texture) { if (*target_texture != 0 && !glIsTexture(*target_texture)) { *target_texture = 0; - shader->updated = 1; + shader_pass->target_updated = 1; } - if (*target_texture==0 || shader->updated || reloadShaderTextures) { + if (*target_texture==0 || shader_pass->target_updated || reloadShaderTextures) { // if(target_texture) { // glDeleteTextures(1,target_texture); @@ -1735,12 +1766,12 @@ void runShaderPass(GLuint src_texture, GLuint shader_program, GLuint* target_tex glGenTextures(1, target_texture); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, *target_texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, next_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, next_filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dst_width, dst_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - shader->updated = 0; + shader_pass->target_updated = 0; } if (fbo == 0) { glGenFramebuffers(1, &fbo); @@ -1781,15 +1812,15 @@ void runShaderPass(GLuint src_texture, GLuint shader_program, GLuint* target_tex glViewport(x, y, dst_width, dst_height); - if (shader->texLocation >= 0) glUniform1i(shader->texLocation, 0); + if (shader_program->TexLocation >= 0) glUniform1i(shader_program->TexLocation, 0); - if (shader->texelSizeLocation >= 0) { - glUniform2fv(shader->texelSizeLocation, 1, texelSize); + if (shader_program->TexelSizeLocation >= 0) { + glUniform2fv(shader_program->TexelSizeLocation, 1, texelSize); last_texelSize[0] = texelSize[0]; last_texelSize[1] = texelSize[1]; } glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - last_program = shader_program; + last_program = shader_program_handle; } typedef struct { @@ -2018,8 +2049,8 @@ void PLAT_GL_Swap() { if (src_texture==0) glGenTextures(1, &src_texture); glBindTexture(GL_TEXTURE_2D, src_texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nrofshaders > 0 ? shaders[0]->filter : finalScaleFilter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nrofshaders > 0 ? shaders[0]->filter : finalScaleFilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nrofshaders > 0 ? shaders[0].filter : finalScaleFilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nrofshaders > 0 ? shaders[0].filter : finalScaleFilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } @@ -2039,10 +2070,10 @@ void PLAT_GL_Swap() { for (int i = 0; i < nrofshaders; i++) { int src_w = last_w; int src_h = last_h; - int dst_w = src_w * shaders[i]->scale; - int dst_h = src_h * shaders[i]->scale; + int dst_w = src_w * shaders[i].scale; + int dst_h = src_h * shaders[i].scale; - if (shaders[i]->scale == 9) { + if (shaders[i].scale == 9) { dst_w = dst_rect.w; dst_h = dst_rect.h; } @@ -2052,10 +2083,10 @@ void PLAT_GL_Swap() { int real_input_w = (i == 0) ? vid.blit->src_w : last_w; int real_input_h = (i == 0) ? vid.blit->src_h : last_h; - shaders[i]->srcw = shaders[i]->srctype == 0 ? vid.blit->src_w : shaders[i]->srctype == 2 ? dst_rect.w : real_input_w; - shaders[i]->srch = shaders[i]->srctype == 0 ? vid.blit->src_h : shaders[i]->srctype == 2 ? dst_rect.h : real_input_h; - shaders[i]->texw = shaders[i]->scaletype == 0 ? vid.blit->src_w : shaders[i]->scaletype == 2 ? dst_rect.w : real_input_w; - shaders[i]->texh = shaders[i]->scaletype == 0 ? vid.blit->src_h : shaders[i]->scaletype == 2 ? dst_rect.h : real_input_h; + shaders[i].srcw = shaders[i].srctype == 0 ? vid.blit->src_w : shaders[i].srctype == 2 ? dst_rect.w : real_input_w; + shaders[i].srch = shaders[i].srctype == 0 ? vid.blit->src_h : shaders[i].srctype == 2 ? dst_rect.h : real_input_h; + shaders[i].texw = shaders[i].scaletype == 0 ? vid.blit->src_w : shaders[i].scaletype == 2 ? dst_rect.w : real_input_w; + shaders[i].texh = shaders[i].scaletype == 0 ? vid.blit->src_h : shaders[i].scaletype == 2 ? dst_rect.h : real_input_h; } } @@ -2063,10 +2094,10 @@ void PLAT_GL_Swap() { static int shaderinfoscreen = 0; if (shaderinfocount > 600 && shaderinfoscreen == i) { currentshaderpass = i + 1; - currentshadertexw = shaders[i]->texw; - currentshadertexh = shaders[i]->texh; - currentshadersrcw = shaders[i]->srcw; - currentshadersrch = shaders[i]->srch; + currentshadertexw = shaders[i].texw; + currentshadertexh = shaders[i].texh; + currentshadersrcw = shaders[i].srcw; + currentshadersrch = shaders[i].srch; currentshaderdstw = dst_w; currentshaderdsth = dst_h; shaderinfocount = 0; @@ -2076,28 +2107,14 @@ void PLAT_GL_Swap() { } shaderinfocount++; - if (shaders[i]->shader_p) { - //LOG_info("Shader Pass: Pipeline step %d/%d\n", i + 1, nrofshaders); - runShaderPass( - (i == 0) ? src_texture : shaders[i - 1]->texture, - shaders[i]->shader_p, - &shaders[i]->texture, - 0, 0, dst_w, dst_h, - shaders[i], - 0, - (i == nrofshaders - 1) ? finalScaleFilter : shaders[i + 1]->filter - ); - } else { - runShaderPass( - (i == 0) ? src_texture : shaders[i - 1]->texture, - g_noshader, - &shaders[i]->texture, - 0, 0, dst_w, dst_h, - shaders[i], - 0, - (i == nrofshaders - 1) ? finalScaleFilter : shaders[i + 1]->filter - ); - } + runShaderPass( + &shaders[i], + (i == 0) ? src_texture : shaders[i - 1].target_texture, + &shaders[i].target_texture, + (i == nrofshaders) ? finalScaleFilter : shaders[i+1].filter, + shaders[i].srcw, shaders[i].srch, + shaders[i].texw, shaders[i].texh, + 0, 0, dst_w, dst_h); last_w = dst_w; last_h = dst_h; @@ -2105,65 +2122,58 @@ void PLAT_GL_Swap() { if (nrofshaders > 0) { //LOG_info("Shader Pass: Scale to screen (pipeline size: %d)\n", nrofshaders); - runShaderPass( - shaders[nrofshaders - 1]->texture, - g_shader_default, - NULL, - dst_rect.x, dst_rect.y, dst_rect.w, dst_rect.h, - &(Shader){.srcw = last_w, .srch = last_h, .texw = last_w, .texh = last_h}, - 0, GL_NONE - ); + runShaderPass( + &sp_finalscale, + shaders[nrofshaders - 1].target_texture, + NULL, + GL_NONE, + last_w, last_h, last_w, last_h, + dst_rect.x, dst_rect.y, dst_rect.w, dst_rect.h); } else { //LOG_info("Shader Pass: Scale to screen (pipeline size: %d)\n", nrofshaders); - runShaderPass(src_texture, - g_shader_default, - NULL, - dst_rect.x, dst_rect.y, dst_rect.w, dst_rect.h, - &(Shader){.srcw = vid.blit->src_w, .srch = vid.blit->src_h, .texw = vid.blit->src_w, .texh = vid.blit->src_h}, - 0, GL_NONE); + runShaderPass( + &sp_finalscale, + src_texture, + NULL, + GL_NONE, + vid.blit->src_w, vid.blit->src_h, + vid.blit->src_w, vid.blit->src_h, + dst_rect.x, dst_rect.y, dst_rect.w, dst_rect.h); } if (effect_tex) { //LOG_info("Shader Pass: Screen Effect\n"); - runShaderPass( - effect_tex, - g_shader_overlay, - NULL, - dst_rect.x, dst_rect.y, effect_w, effect_h, - &(Shader){.srcw = effect_w, .srch = effect_h, .texw = effect_w, .texh = effect_h}, - 1, GL_NONE - ); + runShaderPass( + &sp_overlay, effect_tex, NULL, + GL_NONE, + effect_w, effect_h, effect_w, effect_h, + dst_rect.x, dst_rect.y, effect_w, effect_h); } if (overlay_tex) { //LOG_info("Shader Pass: Overlay\n"); - runShaderPass( - overlay_tex, - g_shader_overlay, - NULL, - 0, 0, device_width, device_height, - &(Shader){.srcw = vid.blit->src_w, .srch = vid.blit->src_h, .texw = overlay_w, .texh = overlay_h}, - 1, GL_NONE - ); + runShaderPass( + &sp_overlay, overlay_tex, NULL, + GL_NONE, + vid.blit->src_w, vid.blit->src_h, overlay_w, overlay_h, + 0, 0, device_width, device_height); } // Render notification overlay if present (texture pre-allocated in PLAT_initShaders) if (notif.dirty && notif.surface) { - glBindTexture(GL_TEXTURE_2D, notif.tex); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, notif.surface->w, notif.surface->h, GL_RGBA, GL_UNSIGNED_BYTE, notif.surface->pixels); - notif.dirty = 0; + glBindTexture(GL_TEXTURE_2D, notif.tex); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, notif.surface->w, notif.surface->h, GL_RGBA, GL_UNSIGNED_BYTE, notif.surface->pixels); + notif.dirty = 0; } if (notif.tex && notif.surface) { - runShaderPass( - notif.tex, - g_shader_overlay, - NULL, - notif.x, notif.y, notif.tex_w, notif.tex_h, - &(Shader){.srcw = notif.tex_w, .srch = notif.tex_h, .texw = notif.tex_w, .texh = notif.tex_h}, - 1, GL_NONE - ); + runShaderPass( + &sp_overlay, notif.tex, NULL, + GL_NONE, + notif.tex_w, notif.tex_h, + notif.tex_w, notif.tex_h, + notif.x, notif.y, notif.tex_w, notif.tex_h); } SDL_GL_SwapWindow(vid.window); From b7e3347712431a9c2cba7d752121d15170836c2c Mon Sep 17 00:00:00 2001 From: "Dr. Flarp" Date: Sat, 14 Mar 2026 11:17:33 -0400 Subject: [PATCH 02/13] feat: add support for OrigTexture sampler --- workspace/all/common/generic_video.c | 39 ++++++++++++++++++---------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/workspace/all/common/generic_video.c b/workspace/all/common/generic_video.c index 02ce83da0..c857d2441 100644 --- a/workspace/all/common/generic_video.c +++ b/workspace/all/common/generic_video.c @@ -47,6 +47,7 @@ typedef struct ShaderProgram { GLint u_InputSize; GLint OrigInputSize; GLint TexLocation; + GLint OrigTexLocation; GLint TexelSizeLocation; ShaderParam *pragmas; // Dynamic array of parsed pragma parameters int num_pragmas; // Count of valid pragma parameters @@ -501,6 +502,7 @@ void init_shader_program(ShaderProgram * shader, const char * path, const char * shader->u_InputSize = glGetUniformLocation( shader->shader_p, "InputSize"); shader->OrigInputSize = glGetUniformLocation( shader->shader_p, "OrigInputSize"); shader->TexLocation = glGetUniformLocation(shader->shader_p, "Texture"); + shader->OrigTexLocation = glGetUniformLocation(shader->shader_p, "OrigTexture"); shader->TexelSizeLocation = glGetUniformLocation(shader->shader_p, "texelSize"); for (int i = 0; i < shader->num_pragmas; ++i) { shader->pragmas[i].uniformLocation = glGetUniformLocation(shader->shader_p, shader->pragmas[i].name); @@ -1639,6 +1641,9 @@ void PLAT_flip(SDL_Surface* IGNORED, int ignored) { } static int frame_count = 0; +static GLuint orig_texture = 0; +static int orig_w = 0; +static int orig_h = 0; void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, GLuint * target_texture, int next_filter, int src_w, int src_h, int tex_w, int tex_h, @@ -1734,7 +1739,7 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, if (shader_program->u_FrameCount >= 0) glUniform1i(shader_program->u_FrameCount, frame_count); if (shader_program->u_OutputSize >= 0) glUniform2f(shader_program->u_OutputSize, dst_width, dst_height); if (shader_program->u_TextureSize >= 0) glUniform2f(shader_program->u_TextureSize, tex_w, tex_h); - if (shader_program->OrigInputSize >= 0) glUniform2f(shader_program->OrigInputSize, src_w, src_h); + if (shader_program->OrigInputSize >= 0) glUniform2f(shader_program->OrigInputSize, orig_w, orig_h); if (shader_program->u_InputSize >= 0) glUniform2f(shader_program->u_InputSize, src_w, src_h); for (int i = 0; i < shader_program->num_pragmas; ++i) { glUniform1f(shader_program->pragmas[i].uniformLocation, shader_program->pragmas[i].value); @@ -1813,6 +1818,13 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, if (shader_program->TexLocation >= 0) glUniform1i(shader_program->TexLocation, 0); + + if (shader_program->OrigTexLocation >= 0) { + glUniform1i(shader_program->OrigTexLocation, 1); + glActiveTexture(GL_TEXTURE0+1); + glBindTexture(GL_TEXTURE_2D, orig_texture); + glActiveTexture(GL_TEXTURE0); + } if (shader_program->TexelSizeLocation >= 0) { glUniform2fv(shader_program->TexelSizeLocation, 1, texelSize); @@ -1951,12 +1963,11 @@ void PLAT_GL_Swap() { static int overlay_w = 0, overlay_h = 0; static int overlayload = 0; - static GLuint src_texture = 0; static int src_w_last = 0, src_h_last = 0; static int last_w = 0, last_h = 0; if (shaderResetRequested) { - if (src_texture) { glDeleteTextures(1, &src_texture); src_texture = 0; } + if (orig_texture) { glDeleteTextures(1, &orig_texture); orig_texture = 0; } src_w_last = src_h_last = 0; last_w = last_h = 0; if (effect_tex) { @@ -2041,25 +2052,27 @@ void PLAT_GL_Swap() { pthread_mutex_unlock(&video_prep_mutex); } - if (!src_texture || reloadShaderTextures) { - // if (src_texture) { - // glDeleteTextures(1, &src_texture); - // src_texture = 0; + if (!orig_texture || reloadShaderTextures) { + // if (orig_texture) { + // glDeleteTextures(1, &orig_texture); + // orig_texture = 0; // } - if (src_texture==0) - glGenTextures(1, &src_texture); - glBindTexture(GL_TEXTURE_2D, src_texture); + if (orig_texture==0) + glGenTextures(1, &orig_texture); + glBindTexture(GL_TEXTURE_2D, orig_texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nrofshaders > 0 ? shaders[0].filter : finalScaleFilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nrofshaders > 0 ? shaders[0].filter : finalScaleFilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - glBindTexture(GL_TEXTURE_2D, src_texture); + glBindTexture(GL_TEXTURE_2D, orig_texture); if (vid.blit->src_w != src_w_last || vid.blit->src_h != src_h_last || reloadShaderTextures) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vid.blit->src_w, vid.blit->src_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, vid.blit->src); src_w_last = vid.blit->src_w; src_h_last = vid.blit->src_h; + orig_w = vid.blit->src_w; + orig_h = vid.blit->src_h; } else { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, vid.blit->src_w, vid.blit->src_h, GL_RGBA, GL_UNSIGNED_BYTE, vid.blit->src); } @@ -2109,7 +2122,7 @@ void PLAT_GL_Swap() { runShaderPass( &shaders[i], - (i == 0) ? src_texture : shaders[i - 1].target_texture, + (i == 0) ? orig_texture : shaders[i - 1].target_texture, &shaders[i].target_texture, (i == nrofshaders) ? finalScaleFilter : shaders[i+1].filter, shaders[i].srcw, shaders[i].srch, @@ -2134,7 +2147,7 @@ void PLAT_GL_Swap() { //LOG_info("Shader Pass: Scale to screen (pipeline size: %d)\n", nrofshaders); runShaderPass( &sp_finalscale, - src_texture, + orig_texture, NULL, GL_NONE, vid.blit->src_w, vid.blit->src_h, From a9c71f7a18cf718323b0270674092f3b7b511393 Mon Sep 17 00:00:00 2001 From: "Dr. Flarp" Date: Mon, 16 Mar 2026 17:19:03 -0400 Subject: [PATCH 03/13] reduce WTFs in shader init / default values, simplify runshaderpass call --- workspace/all/common/generic_video.c | 83 ++++++++++++++++++---------- 1 file changed, 54 insertions(+), 29 deletions(-) diff --git a/workspace/all/common/generic_video.c b/workspace/all/common/generic_video.c index c857d2441..a2657419c 100644 --- a/workspace/all/common/generic_video.c +++ b/workspace/all/common/generic_video.c @@ -61,7 +61,6 @@ typedef struct ShaderPass { ShaderProgram * program; int filter; int alpha; - GLuint source_texture; GLuint target_texture; int target_updated; int scale; @@ -73,22 +72,36 @@ typedef struct ShaderPass { int texh; } ShaderPass; -ShaderPass shaders[MAXSHADERS] = { - { .program = &(ShaderProgram){ .shader_p = 0, .filename = "stock.glsl" }, - .filter = GL_LINEAR, .scale = 1, .scaletype = 0, .srctype = 0, .target_texture = 0, .target_updated = 1 }, - { .program = &(ShaderProgram){ .shader_p = 0, .filename = "stock.glsl" }, - .filter = GL_LINEAR, .scale = 1, .scaletype = 0, .srctype = 0, .target_texture = 0, .target_updated = 1 }, - { .program = &(ShaderProgram){ .shader_p = 0, .filename = "stock.glsl" }, - .filter = GL_LINEAR, .scale = 1, .scaletype = 0, .srctype = 0, .target_texture = 0, .target_updated = 1 } +ShaderProgram shader_programs[MAXSHADERS]; +ShaderPass shaders[MAXSHADERS]; + +// memcpy these in initShaders() +const ShaderProgram blank_shader_program = { + .shader_p = 0, .filename = "stock.glsl" +}; +const ShaderPass blank_shader_pass = { .program = NULL, + .filter = GL_LINEAR, .alpha = 0, + .scale = 1, .scaletype = 0, .srctype = 0, + .target_texture = 0, .target_updated = 1 }; -ShaderPass sp_finalscale = { .program = &s_shader_default, - .filter = GL_NEAREST, .filter = GL_NEAREST, .alpha = 0, +ShaderPass s_pass_finalscale = { .program = &s_shader_default, + .filter = GL_NEAREST, .alpha = 0, .target_texture = 0, .target_updated = 1 }; -ShaderPass sp_overlay = { .program = &s_shader_overlay, - .filter = GL_NEAREST, .filter = GL_NEAREST, .alpha = 1, +ShaderPass s_pass_effect = { .program = &s_shader_overlay, + .filter = GL_NEAREST, .alpha = 1, + .target_texture = 0, .target_updated = 1 +}; + +ShaderPass s_pass_overlay = { .program = &s_shader_overlay, + .filter = GL_NEAREST, .alpha = 1, + .target_texture = 0, .target_updated = 1 +}; + +ShaderPass s_pass_notif = { .program = &s_shader_overlay, + .filter = GL_NEAREST, .alpha = 1, .target_texture = 0, .target_updated = 1 }; @@ -525,7 +538,15 @@ void PLAT_initShaders() { SDL_GL_MakeCurrent(vid.window, vid.gl_context); glViewport(0, 0, device_width, device_height); - // Final display shader (simple texture blit) + // Init user shaders + for (int i = 0; i < MAXSHADERS; i++) { + memcpy(&shader_programs[i], &blank_shader_program, sizeof(ShaderProgram)); + memcpy(&shaders[i], &blank_shader_pass, sizeof(ShaderPass)); + shaders[i].program = &shader_programs[i]; + } + + // Init .system shaders + // Final display shader (simple texture blit) init_shader_program(&s_shader_default, SYSSHADERS_FOLDER, "default.glsl"); // Overlay shader, for png overlays and static line/grid overlays @@ -1646,7 +1667,6 @@ static int orig_w = 0; static int orig_h = 0; void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, GLuint * target_texture, int next_filter, - int src_w, int src_h, int tex_w, int tex_h, int x, int y, int dst_width, int dst_height) { static GLuint static_VAO = 0, static_VBO = 0; @@ -1670,6 +1690,11 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, const int alpha = shader_pass->alpha; const GLuint shader_program_handle = shader_program->shader_p; + const int src_w = shader_pass->srcw; + const int src_h = shader_pass->srch; + const int tex_w = shader_pass->texw; + const int tex_h = shader_pass->texh; + while ((pre_err = glGetError()) != GL_NO_ERROR) { (void)pre_err; } @@ -2012,6 +2037,8 @@ void PLAT_GL_Swap() { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, loaded_effect->w, loaded_effect->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, loaded_effect->pixels); effect_w = loaded_effect->w; effect_h = loaded_effect->h; + s_pass_effect.srcw = s_pass_effect.texw = effect_w; + s_pass_effect.srch = s_pass_effect.texh = effect_h; } else { if (effect_tex) { glDeleteTextures(1, &effect_tex); @@ -2040,7 +2067,8 @@ void PLAT_GL_Swap() { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, loaded_overlay->w, loaded_overlay->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, loaded_overlay->pixels); overlay_w = loaded_overlay->w; overlay_h = loaded_overlay->h; - + s_pass_overlay.srcw = s_pass_overlay.texw = overlay_w; + s_pass_overlay.srch = s_pass_overlay.texh = overlay_h; } else { if (overlay_tex) { glDeleteTextures(1, &overlay_tex); @@ -2125,8 +2153,6 @@ void PLAT_GL_Swap() { (i == 0) ? orig_texture : shaders[i - 1].target_texture, &shaders[i].target_texture, (i == nrofshaders) ? finalScaleFilter : shaders[i+1].filter, - shaders[i].srcw, shaders[i].srch, - shaders[i].texw, shaders[i].texh, 0, 0, dst_w, dst_h); last_w = dst_w; @@ -2135,41 +2161,40 @@ void PLAT_GL_Swap() { if (nrofshaders > 0) { //LOG_info("Shader Pass: Scale to screen (pipeline size: %d)\n", nrofshaders); + s_pass_finalscale.srcw = s_pass_finalscale.texw = last_w; + s_pass_finalscale.srch = s_pass_finalscale.texh = last_h; runShaderPass( - &sp_finalscale, + &s_pass_finalscale, shaders[nrofshaders - 1].target_texture, NULL, GL_NONE, - last_w, last_h, last_w, last_h, dst_rect.x, dst_rect.y, dst_rect.w, dst_rect.h); } else { //LOG_info("Shader Pass: Scale to screen (pipeline size: %d)\n", nrofshaders); + s_pass_finalscale.srcw = s_pass_finalscale.texw = orig_w; + s_pass_finalscale.srch = s_pass_finalscale.texh = orig_h; runShaderPass( - &sp_finalscale, + &s_pass_finalscale, orig_texture, NULL, GL_NONE, - vid.blit->src_w, vid.blit->src_h, - vid.blit->src_w, vid.blit->src_h, dst_rect.x, dst_rect.y, dst_rect.w, dst_rect.h); } if (effect_tex) { //LOG_info("Shader Pass: Screen Effect\n"); runShaderPass( - &sp_overlay, effect_tex, NULL, + &s_pass_overlay, effect_tex, NULL, GL_NONE, - effect_w, effect_h, effect_w, effect_h, dst_rect.x, dst_rect.y, effect_w, effect_h); } if (overlay_tex) { //LOG_info("Shader Pass: Overlay\n"); runShaderPass( - &sp_overlay, overlay_tex, NULL, + &s_pass_overlay, overlay_tex, NULL, GL_NONE, - vid.blit->src_w, vid.blit->src_h, overlay_w, overlay_h, 0, 0, device_width, device_height); } @@ -2177,15 +2202,15 @@ void PLAT_GL_Swap() { if (notif.dirty && notif.surface) { glBindTexture(GL_TEXTURE_2D, notif.tex); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, notif.surface->w, notif.surface->h, GL_RGBA, GL_UNSIGNED_BYTE, notif.surface->pixels); + s_pass_notif.srcw = s_pass_notif.texw = notif.tex_w; + s_pass_notif.srch = s_pass_notif.texh = notif.tex_h; notif.dirty = 0; } if (notif.tex && notif.surface) { runShaderPass( - &sp_overlay, notif.tex, NULL, + &s_pass_overlay, notif.tex, NULL, GL_NONE, - notif.tex_w, notif.tex_h, - notif.tex_w, notif.tex_h, notif.x, notif.y, notif.tex_w, notif.tex_h); } From 3a61f6f0d8a44c9f307b63129ec325fd41f8b38b Mon Sep 17 00:00:00 2001 From: "Dr. Flarp" Date: Mon, 16 Mar 2026 20:20:42 -0400 Subject: [PATCH 04/13] nitpicking name consistency --- workspace/all/common/generic_video.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/workspace/all/common/generic_video.c b/workspace/all/common/generic_video.c index a2657419c..c31e81738 100644 --- a/workspace/all/common/generic_video.c +++ b/workspace/all/common/generic_video.c @@ -45,10 +45,10 @@ typedef struct ShaderProgram { GLint u_OutputSize; GLint u_TextureSize; GLint u_InputSize; - GLint OrigInputSize; - GLint TexLocation; - GLint OrigTexLocation; - GLint TexelSizeLocation; + GLint u_OrigInputSize; + GLint u_TexLocation; + GLint u_OrigTexLocation; + GLint u_TexelSizeLocation; ShaderParam *pragmas; // Dynamic array of parsed pragma parameters int num_pragmas; // Count of valid pragma parameters } ShaderProgram; @@ -513,10 +513,10 @@ void init_shader_program(ShaderProgram * shader, const char * path, const char * shader->u_OutputSize = glGetUniformLocation( shader->shader_p, "OutputSize"); shader->u_TextureSize = glGetUniformLocation( shader->shader_p, "TextureSize"); shader->u_InputSize = glGetUniformLocation( shader->shader_p, "InputSize"); - shader->OrigInputSize = glGetUniformLocation( shader->shader_p, "OrigInputSize"); - shader->TexLocation = glGetUniformLocation(shader->shader_p, "Texture"); - shader->OrigTexLocation = glGetUniformLocation(shader->shader_p, "OrigTexture"); - shader->TexelSizeLocation = glGetUniformLocation(shader->shader_p, "texelSize"); + shader->u_OrigInputSize = glGetUniformLocation( shader->shader_p, "OrigInputSize"); + shader->u_TexLocation = glGetUniformLocation(shader->shader_p, "Texture"); + shader->u_OrigTexLocation = glGetUniformLocation(shader->shader_p, "OrigTexture"); + shader->u_TexelSizeLocation = glGetUniformLocation(shader->shader_p, "texelSize"); for (int i = 0; i < shader->num_pragmas; ++i) { shader->pragmas[i].uniformLocation = glGetUniformLocation(shader->shader_p, shader->pragmas[i].name); shader->pragmas[i].value = shader->pragmas[i].def; @@ -1764,7 +1764,7 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, if (shader_program->u_FrameCount >= 0) glUniform1i(shader_program->u_FrameCount, frame_count); if (shader_program->u_OutputSize >= 0) glUniform2f(shader_program->u_OutputSize, dst_width, dst_height); if (shader_program->u_TextureSize >= 0) glUniform2f(shader_program->u_TextureSize, tex_w, tex_h); - if (shader_program->OrigInputSize >= 0) glUniform2f(shader_program->OrigInputSize, orig_w, orig_h); + if (shader_program->u_OrigInputSize >= 0) glUniform2f(shader_program->u_OrigInputSize, orig_w, orig_h); if (shader_program->u_InputSize >= 0) glUniform2f(shader_program->u_InputSize, src_w, src_h); for (int i = 0; i < shader_program->num_pragmas; ++i) { glUniform1f(shader_program->pragmas[i].uniformLocation, shader_program->pragmas[i].value); @@ -1842,17 +1842,17 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, glViewport(x, y, dst_width, dst_height); - if (shader_program->TexLocation >= 0) glUniform1i(shader_program->TexLocation, 0); + if (shader_program->u_TexLocation >= 0) glUniform1i(shader_program->u_TexLocation, 0); - if (shader_program->OrigTexLocation >= 0) { - glUniform1i(shader_program->OrigTexLocation, 1); + if (shader_program->u_OrigTexLocation >= 0) { + glUniform1i(shader_program->u_OrigTexLocation, 1); glActiveTexture(GL_TEXTURE0+1); glBindTexture(GL_TEXTURE_2D, orig_texture); glActiveTexture(GL_TEXTURE0); } - if (shader_program->TexelSizeLocation >= 0) { - glUniform2fv(shader_program->TexelSizeLocation, 1, texelSize); + if (shader_program->u_TexelSizeLocation >= 0) { + glUniform2fv(shader_program->u_TexelSizeLocation, 1, texelSize); last_texelSize[0] = texelSize[0]; last_texelSize[1] = texelSize[1]; } From 496b3a238872b4950fb0cc087ac8d3d10f54c25f Mon Sep 17 00:00:00 2001 From: "Dr. Flarp" Date: Mon, 16 Mar 2026 20:28:16 -0400 Subject: [PATCH 05/13] remove refactored variables --- workspace/all/common/generic_video.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/workspace/all/common/generic_video.c b/workspace/all/common/generic_video.c index c31e81738..3bc5aed4b 100644 --- a/workspace/all/common/generic_video.c +++ b/workspace/all/common/generic_video.c @@ -1687,14 +1687,8 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, shader_program = &s_noshader; } - const int alpha = shader_pass->alpha; const GLuint shader_program_handle = shader_program->shader_p; - const int src_w = shader_pass->srcw; - const int src_h = shader_pass->srch; - const int tex_w = shader_pass->texw; - const int tex_h = shader_pass->texh; - while ((pre_err = glGetError()) != GL_NO_ERROR) { (void)pre_err; } @@ -1724,8 +1718,8 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, last_bound_texture = 0; } - texelSize[0] = 1.0f / tex_w; - texelSize[1] = 1.0f / tex_h; + texelSize[0] = 1.0f / shader_pass->texw; + texelSize[1] = 1.0f / shader_pass->texh; if (shader_program_handle != last_program) @@ -1763,9 +1757,9 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, if (shader_program->u_FrameDirection >= 0) glUniform1i(shader_program->u_FrameDirection, 1); if (shader_program->u_FrameCount >= 0) glUniform1i(shader_program->u_FrameCount, frame_count); if (shader_program->u_OutputSize >= 0) glUniform2f(shader_program->u_OutputSize, dst_width, dst_height); - if (shader_program->u_TextureSize >= 0) glUniform2f(shader_program->u_TextureSize, tex_w, tex_h); + if (shader_program->u_TextureSize >= 0) glUniform2f(shader_program->u_TextureSize, shader_pass->texw, shader_pass->texh); if (shader_program->u_OrigInputSize >= 0) glUniform2f(shader_program->u_OrigInputSize, orig_w, orig_h); - if (shader_program->u_InputSize >= 0) glUniform2f(shader_program->u_InputSize, src_w, src_h); + if (shader_program->u_InputSize >= 0) glUniform2f(shader_program->u_InputSize, shader_pass->srcw, shader_pass->srch); for (int i = 0; i < shader_program->num_pragmas; ++i) { glUniform1f(shader_program->pragmas[i].uniformLocation, shader_program->pragmas[i].value); } @@ -1827,7 +1821,7 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, glBindFramebuffer(GL_FRAMEBUFFER, 0); } - if(alpha==1) { + if(shader_pass->alpha==1) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { From be86e4bf78d44ca47c765e0dc922d1b5b6827292 Mon Sep 17 00:00:00 2001 From: "Dr. Flarp" Date: Tue, 17 Mar 2026 17:53:18 -0400 Subject: [PATCH 06/13] fix compat for Pixel_Transparency.glsl --- workspace/all/common/generic_video.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/workspace/all/common/generic_video.c b/workspace/all/common/generic_video.c index 3bc5aed4b..3b78e2865 100644 --- a/workspace/all/common/generic_video.c +++ b/workspace/all/common/generic_video.c @@ -46,6 +46,7 @@ typedef struct ShaderProgram { GLint u_TextureSize; GLint u_InputSize; GLint u_OrigInputSize; + GLint u_OrigTextureSize; GLint u_TexLocation; GLint u_OrigTexLocation; GLint u_TexelSizeLocation; @@ -514,6 +515,7 @@ void init_shader_program(ShaderProgram * shader, const char * path, const char * shader->u_TextureSize = glGetUniformLocation( shader->shader_p, "TextureSize"); shader->u_InputSize = glGetUniformLocation( shader->shader_p, "InputSize"); shader->u_OrigInputSize = glGetUniformLocation( shader->shader_p, "OrigInputSize"); + shader->u_OrigTextureSize = glGetUniformLocation( shader->shader_p, "OrigTextureSize"); shader->u_TexLocation = glGetUniformLocation(shader->shader_p, "Texture"); shader->u_OrigTexLocation = glGetUniformLocation(shader->shader_p, "OrigTexture"); shader->u_TexelSizeLocation = glGetUniformLocation(shader->shader_p, "texelSize"); @@ -1665,6 +1667,8 @@ static int frame_count = 0; static GLuint orig_texture = 0; static int orig_w = 0; static int orig_h = 0; +static int origtex_w = 0; +static int origtex_h = 0; void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, GLuint * target_texture, int next_filter, int x, int y, int dst_width, int dst_height) { @@ -1759,6 +1763,7 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, if (shader_program->u_OutputSize >= 0) glUniform2f(shader_program->u_OutputSize, dst_width, dst_height); if (shader_program->u_TextureSize >= 0) glUniform2f(shader_program->u_TextureSize, shader_pass->texw, shader_pass->texh); if (shader_program->u_OrigInputSize >= 0) glUniform2f(shader_program->u_OrigInputSize, orig_w, orig_h); + if (shader_program->u_OrigTextureSize >= 0) glUniform2f(shader_program->u_OrigTextureSize, origtex_w, origtex_h); if (shader_program->u_InputSize >= 0) glUniform2f(shader_program->u_InputSize, shader_pass->srcw, shader_pass->srch); for (int i = 0; i < shader_program->num_pragmas; ++i) { glUniform1f(shader_program->pragmas[i].uniformLocation, shader_program->pragmas[i].value); @@ -2095,6 +2100,8 @@ void PLAT_GL_Swap() { src_h_last = vid.blit->src_h; orig_w = vid.blit->src_w; orig_h = vid.blit->src_h; + origtex_w = vid.blit->src_w; + origtex_h = vid.blit->src_h; } else { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, vid.blit->src_w, vid.blit->src_h, GL_RGBA, GL_UNSIGNED_BYTE, vid.blit->src); } From 15f1da92869aeb13616ea6f1e48a292182f86d6b Mon Sep 17 00:00:00 2001 From: "Dr. Flarp" Date: Tue, 17 Mar 2026 18:04:29 -0400 Subject: [PATCH 07/13] reorganize uniform names / order for consistency --- workspace/all/common/generic_video.c | 33 +++++++++++++++------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/workspace/all/common/generic_video.c b/workspace/all/common/generic_video.c index 3b78e2865..f51468963 100644 --- a/workspace/all/common/generic_video.c +++ b/workspace/all/common/generic_video.c @@ -40,16 +40,19 @@ static int shaderResetRequested = 0; typedef struct ShaderProgram { GLuint shader_p; char *filename; + + // Cached from glGetUniformLocation() GLint u_FrameDirection; GLint u_FrameCount; GLint u_OutputSize; GLint u_TextureSize; GLint u_InputSize; - GLint u_OrigInputSize; GLint u_OrigTextureSize; - GLint u_TexLocation; - GLint u_OrigTexLocation; - GLint u_TexelSizeLocation; + GLint u_OrigInputSize; + GLint u_Texture; + GLint u_OrigTexture; + GLint u_texelSize; + ShaderParam *pragmas; // Dynamic array of parsed pragma parameters int num_pragmas; // Count of valid pragma parameters } ShaderProgram; @@ -514,11 +517,11 @@ void init_shader_program(ShaderProgram * shader, const char * path, const char * shader->u_OutputSize = glGetUniformLocation( shader->shader_p, "OutputSize"); shader->u_TextureSize = glGetUniformLocation( shader->shader_p, "TextureSize"); shader->u_InputSize = glGetUniformLocation( shader->shader_p, "InputSize"); - shader->u_OrigInputSize = glGetUniformLocation( shader->shader_p, "OrigInputSize"); shader->u_OrigTextureSize = glGetUniformLocation( shader->shader_p, "OrigTextureSize"); - shader->u_TexLocation = glGetUniformLocation(shader->shader_p, "Texture"); - shader->u_OrigTexLocation = glGetUniformLocation(shader->shader_p, "OrigTexture"); - shader->u_TexelSizeLocation = glGetUniformLocation(shader->shader_p, "texelSize"); + shader->u_OrigInputSize = glGetUniformLocation( shader->shader_p, "OrigInputSize"); + shader->u_Texture = glGetUniformLocation(shader->shader_p, "Texture"); + shader->u_OrigTexture = glGetUniformLocation(shader->shader_p, "OrigTexture"); + shader->u_texelSize = glGetUniformLocation(shader->shader_p, "texelSize"); for (int i = 0; i < shader->num_pragmas; ++i) { shader->pragmas[i].uniformLocation = glGetUniformLocation(shader->shader_p, shader->pragmas[i].name); shader->pragmas[i].value = shader->pragmas[i].def; @@ -1762,9 +1765,9 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, if (shader_program->u_FrameCount >= 0) glUniform1i(shader_program->u_FrameCount, frame_count); if (shader_program->u_OutputSize >= 0) glUniform2f(shader_program->u_OutputSize, dst_width, dst_height); if (shader_program->u_TextureSize >= 0) glUniform2f(shader_program->u_TextureSize, shader_pass->texw, shader_pass->texh); - if (shader_program->u_OrigInputSize >= 0) glUniform2f(shader_program->u_OrigInputSize, orig_w, orig_h); - if (shader_program->u_OrigTextureSize >= 0) glUniform2f(shader_program->u_OrigTextureSize, origtex_w, origtex_h); if (shader_program->u_InputSize >= 0) glUniform2f(shader_program->u_InputSize, shader_pass->srcw, shader_pass->srch); + if (shader_program->u_OrigTextureSize >= 0) glUniform2f(shader_program->u_OrigTextureSize, origtex_w, origtex_h); + if (shader_program->u_OrigInputSize >= 0) glUniform2f(shader_program->u_OrigInputSize, orig_w, orig_h); for (int i = 0; i < shader_program->num_pragmas; ++i) { glUniform1f(shader_program->pragmas[i].uniformLocation, shader_program->pragmas[i].value); } @@ -1841,17 +1844,17 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, glViewport(x, y, dst_width, dst_height); - if (shader_program->u_TexLocation >= 0) glUniform1i(shader_program->u_TexLocation, 0); + if (shader_program->u_Texture >= 0) glUniform1i(shader_program->u_Texture, 0); - if (shader_program->u_OrigTexLocation >= 0) { - glUniform1i(shader_program->u_OrigTexLocation, 1); + if (shader_program->u_OrigTexture >= 0) { + glUniform1i(shader_program->u_OrigTexture, 1); glActiveTexture(GL_TEXTURE0+1); glBindTexture(GL_TEXTURE_2D, orig_texture); glActiveTexture(GL_TEXTURE0); } - if (shader_program->u_TexelSizeLocation >= 0) { - glUniform2fv(shader_program->u_TexelSizeLocation, 1, texelSize); + if (shader_program->u_texelSize >= 0) { + glUniform2fv(shader_program->u_texelSize, 1, texelSize); last_texelSize[0] = texelSize[0]; last_texelSize[1] = texelSize[1]; } From 42572f54248f28d0e638bac6b46eae3d1dd33db5 Mon Sep 17 00:00:00 2001 From: "Dr. Flarp" Date: Tue, 17 Mar 2026 18:53:25 -0400 Subject: [PATCH 08/13] off-by-one oopsies --- workspace/all/common/generic_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workspace/all/common/generic_video.c b/workspace/all/common/generic_video.c index f51468963..8f399d731 100644 --- a/workspace/all/common/generic_video.c +++ b/workspace/all/common/generic_video.c @@ -2156,7 +2156,7 @@ void PLAT_GL_Swap() { &shaders[i], (i == 0) ? orig_texture : shaders[i - 1].target_texture, &shaders[i].target_texture, - (i == nrofshaders) ? finalScaleFilter : shaders[i+1].filter, + (i == nrofshaders - 1) ? finalScaleFilter : shaders[i+1].filter, 0, 0, dst_w, dst_h); last_w = dst_w; From 245a4ad705f3cec9c46f7af94592784ca43e8e97 Mon Sep 17 00:00:00 2001 From: "Dr. Flarp" Date: Wed, 18 Mar 2026 11:00:22 -0400 Subject: [PATCH 09/13] fix: #684 UI desync with shader backend --- workspace/all/common/generic_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workspace/all/common/generic_video.c b/workspace/all/common/generic_video.c index 8f399d731..92d75e4ab 100644 --- a/workspace/all/common/generic_video.c +++ b/workspace/all/common/generic_video.c @@ -708,7 +708,7 @@ SDL_Surface* PLAT_initVideo(void) { void PLAT_updateShader(int i, const char *filename, int *scale, int *filter, int *scaletype, int *srctype) { - if (i < 0 || i >= nrofshaders) { + if (i < 0) { return; } ShaderPass* shader_pass = &shaders[i]; From 83e6ef208138e5910a9010e0b120b2d2b0698b08 Mon Sep 17 00:00:00 2001 From: "Dr. Flarp" Date: Wed, 18 Mar 2026 11:11:13 -0400 Subject: [PATCH 10/13] ShaderPass globals: don't initialize fields that would be overwritten by minarch.c:initShaders() --- workspace/all/common/generic_video.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/workspace/all/common/generic_video.c b/workspace/all/common/generic_video.c index 92d75e4ab..fce88fa63 100644 --- a/workspace/all/common/generic_video.c +++ b/workspace/all/common/generic_video.c @@ -31,7 +31,7 @@ #define NEXTUI_TSAN 1 #endif -static int finalScaleFilter=GL_LINEAR; +static int finalScaleFilter=GL_NEAREST; static int reloadShaderTextures = 1; static int shaderResetRequested = 0; @@ -84,29 +84,23 @@ const ShaderProgram blank_shader_program = { .shader_p = 0, .filename = "stock.glsl" }; const ShaderPass blank_shader_pass = { .program = NULL, - .filter = GL_LINEAR, .alpha = 0, - .scale = 1, .scaletype = 0, .srctype = 0, - .target_texture = 0, .target_updated = 1 + .alpha = 0, .target_texture = 0, .target_updated = 1 }; ShaderPass s_pass_finalscale = { .program = &s_shader_default, - .filter = GL_NEAREST, .alpha = 0, - .target_texture = 0, .target_updated = 1 + .alpha = 0, .target_texture = 0, .target_updated = 1 }; ShaderPass s_pass_effect = { .program = &s_shader_overlay, - .filter = GL_NEAREST, .alpha = 1, - .target_texture = 0, .target_updated = 1 + .alpha = 1, .target_texture = 0, .target_updated = 1 }; ShaderPass s_pass_overlay = { .program = &s_shader_overlay, - .filter = GL_NEAREST, .alpha = 1, - .target_texture = 0, .target_updated = 1 + .alpha = 1, .target_texture = 0, .target_updated = 1 }; ShaderPass s_pass_notif = { .program = &s_shader_overlay, - .filter = GL_NEAREST, .alpha = 1, - .target_texture = 0, .target_updated = 1 + .alpha = 1, .target_texture = 0, .target_updated = 1 }; @@ -881,6 +875,7 @@ void PLAT_setSharpness(int sharpness) { else { finalScaleFilter = GL_NEAREST; } + s_pass_finalscale.filter = finalScaleFilter; reloadShaderTextures = 1; } From 095315a1a2399a6515e36202c583bd996045096e Mon Sep 17 00:00:00 2001 From: "Dr. Flarp" Date: Wed, 18 Mar 2026 11:19:06 -0400 Subject: [PATCH 11/13] remove finalScaleFilter to avoid confusion with its duplicate --- workspace/all/common/generic_video.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/workspace/all/common/generic_video.c b/workspace/all/common/generic_video.c index fce88fa63..e2189ac27 100644 --- a/workspace/all/common/generic_video.c +++ b/workspace/all/common/generic_video.c @@ -31,7 +31,6 @@ #define NEXTUI_TSAN 1 #endif -static int finalScaleFilter=GL_NEAREST; static int reloadShaderTextures = 1; static int shaderResetRequested = 0; @@ -88,6 +87,7 @@ const ShaderPass blank_shader_pass = { .program = NULL, }; ShaderPass s_pass_finalscale = { .program = &s_shader_default, + .filter = GL_NEAREST, .alpha = 0, .target_texture = 0, .target_updated = 1 }; @@ -870,12 +870,11 @@ SDL_Surface* PLAT_resizeVideo(int w, int h, int p) { void PLAT_setSharpness(int sharpness) { if(sharpness==1) { - finalScaleFilter=GL_LINEAR; + s_pass_finalscale.filter = GL_LINEAR; } else { - finalScaleFilter = GL_NEAREST; + s_pass_finalscale.filter = GL_NEAREST; } - s_pass_finalscale.filter = finalScaleFilter; reloadShaderTextures = 1; } @@ -2085,8 +2084,8 @@ void PLAT_GL_Swap() { if (orig_texture==0) glGenTextures(1, &orig_texture); glBindTexture(GL_TEXTURE_2D, orig_texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nrofshaders > 0 ? shaders[0].filter : finalScaleFilter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nrofshaders > 0 ? shaders[0].filter : finalScaleFilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nrofshaders > 0 ? shaders[0].filter : s_pass_finalscale.filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nrofshaders > 0 ? shaders[0].filter : s_pass_finalscale.filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } @@ -2151,7 +2150,7 @@ void PLAT_GL_Swap() { &shaders[i], (i == 0) ? orig_texture : shaders[i - 1].target_texture, &shaders[i].target_texture, - (i == nrofshaders - 1) ? finalScaleFilter : shaders[i+1].filter, + (i == nrofshaders - 1) ? s_pass_finalscale.filter : shaders[i+1].filter, 0, 0, dst_w, dst_h); last_w = dst_w; From 8020fca5a2464ec6276b99e6cd731342783ada72 Mon Sep 17 00:00:00 2001 From: "Dr. Flarp" Date: Tue, 24 Mar 2026 22:09:39 -0400 Subject: [PATCH 12/13] merge branch main into drflarp/shaders_origtexture --- workspace/all/bootlogo/bootlogo.c | 2 +- workspace/all/clock/clock.c | 2 +- workspace/all/common/api.c | 23 +- workspace/all/common/api.h | 2 + workspace/all/common/config.c | 28 +- workspace/all/common/config.h | 18 + workspace/all/common/generic_video.c | 161 +++++---- workspace/all/ledcontrol/ledcontrol.c | 2 +- workspace/all/minarch/minarch.c | 31 +- workspace/all/nextui/nextui.c | 451 +++++++++++++------------- workspace/all/settings/settings.cpp | 49 +-- 11 files changed, 415 insertions(+), 354 deletions(-) diff --git a/workspace/all/bootlogo/bootlogo.c b/workspace/all/bootlogo/bootlogo.c index 57a36a0b3..0f153b0e4 100644 --- a/workspace/all/bootlogo/bootlogo.c +++ b/workspace/all/bootlogo/bootlogo.c @@ -91,7 +91,7 @@ int main(int argc, char *argv[]) PWR_setCPUSpeed(CPU_SPEED_MENU); - screen = GFX_init(MODE_MAIN); + screen = GFX_init(MODE_MENU); PAD_init(); PWR_init(); diff --git a/workspace/all/clock/clock.c b/workspace/all/clock/clock.c index 38970b455..65534c336 100644 --- a/workspace/all/clock/clock.c +++ b/workspace/all/clock/clock.c @@ -22,7 +22,7 @@ enum { int main(int argc , char* argv[]) { PWR_setCPUSpeed(CPU_SPEED_MENU); - SDL_Surface* screen = GFX_init(MODE_MAIN); + SDL_Surface* screen = GFX_init(MODE_MENU); PAD_init(); PWR_init(); InitSettings(); diff --git a/workspace/all/common/api.c b/workspace/all/common/api.c index 1e1d179f9..f5bff9ada 100644 --- a/workspace/all/common/api.c +++ b/workspace/all/common/api.c @@ -281,14 +281,14 @@ int GFX_updateColors(void) { // We are currently micro managing all of these screen-mapped colors, // should just move this to the caller. - THEME_COLOR1 = mapUint(CFG_getColor(1)); - THEME_COLOR2 = mapUint(CFG_getColor(2)); - THEME_COLOR3 = mapUint(CFG_getColor(3)); - THEME_COLOR4 = mapUint(CFG_getColor(4)); - THEME_COLOR5 = mapUint(CFG_getColor(5)); - THEME_COLOR6 = mapUint(CFG_getColor(6)); - THEME_COLOR7 = mapUint(CFG_getColor(7)); - ALT_BUTTON_TEXT_COLOR = uintToColour(CFG_getColor(3)); + THEME_COLOR1 = mapUint(CFG_getColor(COLOR_MAIN)); + THEME_COLOR2 = mapUint(CFG_getColor(COLOR_ACCENT)); + THEME_COLOR3 = mapUint(CFG_getColor(COLOR_ACCENT2)); + THEME_COLOR4 = mapUint(CFG_getColor(COLOR_LIST_TEXT)); + THEME_COLOR5 = mapUint(CFG_getColor(COLOR_LIST_TEXT_SELECTED)); + THEME_COLOR6 = mapUint(CFG_getColor(COLOR_HINT)); + THEME_COLOR7 = mapUint(CFG_getColor(COLOR_BACKGROUND)); + ALT_BUTTON_TEXT_COLOR = uintToColour(CFG_getColor(COLOR_ACCENT2)); return 0; } @@ -308,6 +308,11 @@ SDL_Surface *GFX_init(int mode) CFG_init(GFX_loadSystemFont, GFX_updateColors); + // by default, we will clear with whatever background color the user prefers + // if MODE_MENU /e.g. minarch, clear with default black) + if(mode == MODE_MAIN) + GFX_setClearColor(mapUint(CFG_getColor(COLOR_BACKGROUND))); + // We always have to symlink, does not depend on NTP being enabled PLAT_initTimezones(); PLAT_setCurrentTimezone(PLAT_getCurrentTimezone()); @@ -1823,7 +1828,7 @@ void GFX_blitMessage(TTF_Font *font, char *msg, SDL_Surface *dst, SDL_Rect *dst_ if (len) { - text = TTF_RenderUTF8_Blended_Wrapped(font, line, COLOR_WHITE, dst_rect->w); + text = TTF_RenderUTF8_Blended_Wrapped(font, line, uintToColour(CFG_getColor(COLOR_LIST_TEXT)), dst_rect->w); int x = dst_rect->x; x += (dst_rect->w - text->w) / 2; SDL_BlitSurface(text, NULL, dst, &(SDL_Rect){x, y}); diff --git a/workspace/all/common/api.h b/workspace/all/common/api.h index 3d5bdf097..1cef108f1 100644 --- a/workspace/all/common/api.h +++ b/workspace/all/common/api.h @@ -279,6 +279,7 @@ SDL_Surface* GFX_init(int mode); #define GFX_scrollTextTexture PLAT_scrollTextTexture // (TTF_Font* font, const char* in_name,int x, int y, int w, int h, SDL_Color color, float transparency, SDL_mutex* fontMutex); #define GFX_flipHidden PLAT_flipHidden //(void) #define GFX_GL_screenCapture PLAT_GL_screenCapture //(void) +#define GFX_setClearColor PLAT_setClearColor //(uint32_t color) void GFX_setMode(int mode); int GFX_hdmiChanged(void); @@ -659,6 +660,7 @@ void PLAT_flip(SDL_Surface* screen, int sync); void PLAT_GL_Swap(); void GFX_GL_Swap(); unsigned char* PLAT_GL_screenCapture(int* outWidth, int* outHeight); +void PLAT_setClearColor(uint32_t color); void PLAT_GPU_Flip(); void PLAT_setShaders(int nr); void PLAT_resetShaders(); diff --git a/workspace/all/common/config.c b/workspace/all/common/config.c index f47c4e32d..368464b94 100644 --- a/workspace/all/common/config.c +++ b/workspace/all/common/config.c @@ -401,13 +401,13 @@ void CFG_init(FontLoad_callback_t cb, ColorSet_callback_t ccb) } // load gfx related stuff until we drop the indirection - CFG_setColor(1, CFG_getColor(1)); - CFG_setColor(2, CFG_getColor(2)); - CFG_setColor(3, CFG_getColor(3)); - CFG_setColor(4, CFG_getColor(4)); - CFG_setColor(5, CFG_getColor(5)); - CFG_setColor(6, CFG_getColor(6)); - CFG_setColor(7, CFG_getColor(7)); + CFG_setColor(1, CFG_getColor(COLOR_MAIN)); + CFG_setColor(2, CFG_getColor(COLOR_ACCENT)); + CFG_setColor(3, CFG_getColor(COLOR_ACCENT2)); + CFG_setColor(4, CFG_getColor(COLOR_LIST_TEXT)); + CFG_setColor(5, CFG_getColor(COLOR_LIST_TEXT_SELECTED)); + CFG_setColor(6, CFG_getColor(COLOR_HINT)); + CFG_setColor(7, CFG_getColor(COLOR_BACKGROUND)); // avoid reloading the font if not neccessary if (!fontLoaded) CFG_setFontId(CFG_getFontId()); @@ -1024,31 +1024,31 @@ void CFG_get(const char *key, char *value) } else if (strcmp(key, "color1") == 0) { - sprintf(value, "\"0x%06X\"", CFG_getColor(1)); + sprintf(value, "\"0x%06X\"", CFG_getColor(COLOR_MAIN)); } else if (strcmp(key, "color2") == 0) { - sprintf(value, "\"0x%06X\"", CFG_getColor(2)); + sprintf(value, "\"0x%06X\"", CFG_getColor(COLOR_ACCENT)); } else if (strcmp(key, "color3") == 0) { - sprintf(value, "\"0x%06X\"", CFG_getColor(3)); + sprintf(value, "\"0x%06X\"", CFG_getColor(COLOR_ACCENT2)); } else if (strcmp(key, "color4") == 0) { - sprintf(value, "\"0x%06X\"", CFG_getColor(4)); + sprintf(value, "\"0x%06X\"", CFG_getColor(COLOR_LIST_TEXT)); } else if (strcmp(key, "color5") == 0) { - sprintf(value, "\"0x%06X\"", CFG_getColor(5)); + sprintf(value, "\"0x%06X\"", CFG_getColor(COLOR_LIST_TEXT_SELECTED)); } else if (strcmp(key, "color6") == 0) { - sprintf(value, "\"0x%06X\"", CFG_getColor(6)); + sprintf(value, "\"0x%06X\"", CFG_getColor(COLOR_HINT)); } else if (strcmp(key, "color7") == 0) { - sprintf(value, "\"0x%06X\"", CFG_getColor(7)); + sprintf(value, "\"0x%06X\"", CFG_getColor(COLOR_BACKGROUND)); } else if (strcmp(key, "radius") == 0) { diff --git a/workspace/all/common/config.h b/workspace/all/common/config.h index 56c74ffaf..3665fd8c3 100644 --- a/workspace/all/common/config.h +++ b/workspace/all/common/config.h @@ -71,6 +71,17 @@ enum { RA_SORT_COUNT }; +// Theme colors +enum { + COLOR_MAIN = 1, + COLOR_ACCENT = 2, + COLOR_ACCENT2 = 3, + COLOR_LIST_TEXT = 4, + COLOR_LIST_TEXT_SELECTED = 5, + COLOR_HINT = 6, + COLOR_BACKGROUND = 7 +}; + typedef struct { // Theme @@ -161,6 +172,13 @@ typedef struct #define CFG_DEFAULT_COLOR5 0x000000U #define CFG_DEFAULT_COLOR6 0xffffffU #define CFG_DEFAULT_COLOR7 0x000000U +#define CFG_DEFAULT_COLOR_MAIN CFG_DEFAULT_COLOR1 +#define CFG_DEFAULT_COLOR_ACCENT CFG_DEFAULT_COLOR2 +#define CFG_DEFAULT_COLOR_ACCENT2 CFG_DEFAULT_COLOR3 +#define CFG_DEFAULT_COLOR_LIST_TEXT CFG_DEFAULT_COLOR4 +#define CFG_DEFAULT_COLOR_LIST_TEXT_SELECTED CFG_DEFAULT_COLOR5 +#define CFG_DEFAULT_COLOR_HINT CFG_DEFAULT_COLOR6 +#define CFG_DEFAULT_COLOR_BACKGROUND CFG_DEFAULT_COLOR7 #define CFG_DEFAULT_THUMBRADIUS 20 // unscaled! #define CFG_DEFAULT_SHOWCLOCK false #define CFG_DEFAULT_CLOCK24H true diff --git a/workspace/all/common/generic_video.c b/workspace/all/common/generic_video.c index e2189ac27..79a8346d4 100644 --- a/workspace/all/common/generic_video.c +++ b/workspace/all/common/generic_video.c @@ -34,6 +34,17 @@ static int reloadShaderTextures = 1; static int shaderResetRequested = 0; +static SDL_BlendMode getPremultipliedBlendMode(void) { + return SDL_ComposeCustomBlendMode( + SDL_BLENDFACTOR_ONE, + SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + SDL_BLENDOPERATION_ADD, + SDL_BLENDFACTOR_ONE, + SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + SDL_BLENDOPERATION_ADD + ); +} + // shader stuff typedef struct ShaderProgram { @@ -122,12 +133,13 @@ static struct VID_Context { SDL_Texture* overlay; SDL_Surface* screen; SDL_GLContext gl_context; - + GFX_Renderer* blit; // yeesh int width; int height; int pitch; int sharpness; + uint32_t clear_color; } vid; static int device_width; @@ -260,7 +272,7 @@ GLuint link_program(GLuint vertex_shader, GLuint fragment_shader, const char* ca void* binary = malloc(binaryLength); glGetProgramBinary(program, binaryLength, NULL, &binaryFormat, binary); - mkdir(SDCARD_PATH "/.shadercache", 0755); + mkdir(SDCARD_PATH "/.shadercache", 0755); f = fopen(cache_path, "wb"); if (f) { fwrite(&binaryFormat, sizeof(GLenum), 1, f); @@ -604,7 +616,7 @@ SDL_Surface* PLAT_initVideo(void) { //SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE); SDL_InitSubSystem(SDL_INIT_VIDEO); SDL_ShowCursor(0); - + // SDL_version compiled; // SDL_version linked; // SDL_VERSION(&compiled); @@ -631,7 +643,7 @@ SDL_Surface* PLAT_initVideo(void) { // } // SDL_GetCurrentDisplayMode(0, &mode); // LOG_info("Current display mode: %ix%i (%s)\n", mode.w,mode.h, SDL_GetPixelFormatName(mode.format)); - + int w = FIXED_WIDTH; int h = FIXED_HEIGHT; int p = FIXED_PITCH; @@ -673,33 +685,39 @@ SDL_Surface* PLAT_initVideo(void) { vid.target_layer3 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET , w,h); vid.target_layer4 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET , w,h); vid.target_layer5 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET , w,h); - + vid.target = NULL; // only needed for non-native sizes - + vid.screen = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_ARGB8888); + SDL_BlendMode premult = getPremultipliedBlendMode(); SDL_SetSurfaceBlendMode(vid.screen, SDL_BLENDMODE_BLEND); - SDL_SetTextureBlendMode(vid.stream_layer1, SDL_BLENDMODE_BLEND); - SDL_SetTextureBlendMode(vid.target_layer2, SDL_BLENDMODE_BLEND); - SDL_SetTextureBlendMode(vid.target_layer3, SDL_BLENDMODE_BLEND); - SDL_SetTextureBlendMode(vid.target_layer4, SDL_BLENDMODE_BLEND); + SDL_SetTextureBlendMode(vid.stream_layer1, premult); + SDL_SetTextureBlendMode(vid.target_layer2, premult); + SDL_SetTextureBlendMode(vid.target_layer3, SDL_BLENDMODE_BLEND); // straight alpha game art + SDL_SetTextureBlendMode(vid.target_layer4, premult); SDL_SetTextureBlendMode(vid.target_layer5, SDL_BLENDMODE_BLEND); - + vid.width = w; vid.height = h; vid.pitch = p; - + SDL_transparentBlack = SDL_MapRGBA(vid.screen->format, 0, 0, 0, 0); - + PLAT_setClearColor(SDL_transparentBlack); + device_width = w; device_height = h; device_pitch = p; - + vid.sharpness = SHARPNESS_SOFT; - + return vid.screen; } +void PLAT_setClearColor(uint32_t color) { + vid.clear_color = color; +} + void PLAT_updateShader(int i, const char *filename, int *scale, int *filter, int *scaletype, int *srctype) { if (i < 0) { @@ -742,7 +760,7 @@ void PLAT_setShaders(int nr) { static void clearVideo(void) { for (int i=0; i<3; i++) { SDL_RenderClear(vid.renderer); - SDL_FillRect(vid.screen, NULL, SDL_transparentBlack); + SDL_FillRect(vid.screen, NULL, vid.clear_color); SDL_RenderCopy(vid.renderer, vid.stream_layer1, NULL, NULL); SDL_RenderPresent(vid.renderer); } @@ -793,7 +811,7 @@ void PLAT_clearVideo(SDL_Surface* screen) { SDL_FillRect(screen, NULL, SDL_transparentBlack); } void PLAT_clearAll(void) { - // ok honestely mixing SDL and OpenGL is really bad, but hey it works just got to sometimes clear gpu stuff and pull context back to SDL + // ok honestely mixing SDL and OpenGL is really bad, but hey it works just got to sometimes clear gpu stuff and pull context back to SDL // so yeah clear all layers and pull a flip() to make it switch back to SDL before clearing PLAT_clearLayers(0); PLAT_flip(vid.screen,0); @@ -801,8 +819,8 @@ void PLAT_clearAll(void) { PLAT_flip(vid.screen,0); // then do normal SDL clearing stuff - PLAT_clearVideo(vid.screen); - SDL_SetRenderDrawColor(vid.renderer, 0, 0, 0, 0); + PLAT_clearVideo(vid.screen); + SDL_SetRenderDrawColor(vid.renderer, 0, 0, 0, 0); SDL_RenderClear(vid.renderer); } @@ -831,9 +849,9 @@ static int hard_scale = 4; // TODO: base src size, eg. 160x144 can be 4 static void resizeVideo(int w, int h, int p) { if (w==vid.width && h==vid.height && p==vid.pitch) return; - + // TODO: minarch disables crisp (and nn upscale before linear downscale) when native, is this true? - + if (w>=device_width && h>=device_height) hard_scale = 1; // else if (h>=160) hard_scale = 2; // limits gba and up to 2x (seems sufficient for 640x480) else hard_scale = 4; @@ -842,11 +860,11 @@ static void resizeVideo(int w, int h, int p) { SDL_DestroyTexture(vid.stream_layer1); if (vid.target) SDL_DestroyTexture(vid.target); - + // SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, vid.sharpness==SHARPNESS_SOFT?"1":"0", SDL_HINT_OVERRIDE); vid.stream_layer1 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w,h); - SDL_SetTextureBlendMode(vid.stream_layer1, SDL_BLENDMODE_BLEND); - + SDL_SetTextureBlendMode(vid.stream_layer1, getPremultipliedBlendMode()); + if (vid.sharpness==SHARPNESS_CRISP) { // SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "1", SDL_HINT_OVERRIDE); vid.target = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, w * hard_scale,h * hard_scale); @@ -854,7 +872,7 @@ static void resizeVideo(int w, int h, int p) { else { vid.target = NULL; } - + vid.width = w; vid.height = h; @@ -922,9 +940,9 @@ static void updateEffect(void) { int curr_type = effect.type; int curr_color = effect.color; pthread_mutex_unlock(&video_prep_mutex); - + if (next_scale==curr_scale && next_type==curr_type && next_color==curr_color) return; // unchanged - + // Update effect state with mutex protection pthread_mutex_lock(&video_prep_mutex); int live_scale = effect.scale; @@ -937,10 +955,10 @@ static void updateEffect(void) { int effect_color = effect.color; int live_type = effect.live_type; pthread_mutex_unlock(&video_prep_mutex); - + if (effect_type==EFFECT_NONE) return; // disabled if (effect_type==live_type && effect_scale==live_scale && effect_color==live_color) return; // already loaded - + int opacity = 128; // 1 - 1/2 = 50% if (effect_type==EFFECT_LINE) { if (effect_scale<3) { @@ -994,7 +1012,7 @@ static void updateEffect(void) { } } effectUpdated = 1; - + } int screenx = 0; int screeny = 0; @@ -1005,7 +1023,7 @@ void PLAT_setOffsetX(int x) { } void PLAT_setOffsetY(int y) { if (y < 0 || y > 128) return; - screeny = y - 64; + screeny = y - 64; LOG_info("screeny: %i %i\n",screeny,y); } static int overlayUpdated=0; @@ -1018,7 +1036,7 @@ void PLAT_setOverlay(const char* filename, const char* tag) { free(overlay_path); overlay_path = NULL; } - + pthread_mutex_lock(&video_prep_mutex); overlayUpdated=1; pthread_mutex_unlock(&video_prep_mutex); @@ -1051,7 +1069,7 @@ void applyRoundedCorners(SDL_Surface* surface, SDL_Rect* rect, int radius) { SDL_Rect target = {0, 0, surface->w, surface->h}; if (rect) target = *rect; - + Uint32 transparent_black = SDL_MapRGBA(fmt, 0, 0, 0, 0); // Fully transparent black const int xBeg = target.x; @@ -1072,9 +1090,12 @@ void applyRoundedCorners(SDL_Surface* surface, SDL_Rect* rect, int radius) { void PLAT_clearLayers(int layer) { if(layer==0 || layer==1) { + uint32_t bg = vid.clear_color; SDL_SetRenderTarget(vid.renderer, vid.target_layer1); + SDL_SetRenderDrawColor(vid.renderer, (bg >> 16) & 0xFF, (bg >> 8) & 0xFF, bg & 0xFF, 255); SDL_RenderClear(vid.renderer); } + SDL_SetRenderDrawColor(vid.renderer, 0, 0, 0, 0); if(layer==0 || layer==2) { SDL_SetRenderTarget(vid.renderer, vid.target_layer2); SDL_RenderClear(vid.renderer); @@ -1096,12 +1117,12 @@ void PLAT_clearLayers(int layer) { } void PLAT_drawOnLayer(SDL_Surface *inputSurface, int x, int y, int w, int h, float brightness, bool maintainAspectRatio,int layer) { - if (!inputSurface || !vid.target_layer1 || !vid.renderer) return; + if (!inputSurface || !vid.target_layer1 || !vid.renderer) return; SDL_Texture* tempTexture = SDL_CreateTexture(vid.renderer, - SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_TARGET, - inputSurface->w, inputSurface->h); + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_TARGET, + inputSurface->w, inputSurface->h); if (!tempTexture) { LOG_error("Failed to create temporary texture: %s\n", SDL_GetError()); @@ -1142,12 +1163,12 @@ void PLAT_drawOnLayer(SDL_Surface *inputSurface, int x, int y, int w, int h, flo SDL_SetTextureColorMod(tempTexture, r, g, b); // Aspect ratio handling - SDL_Rect srcRect = { 0, 0, inputSurface->w, inputSurface->h }; - SDL_Rect dstRect = { x, y, w, h }; + SDL_Rect srcRect = { 0, 0, inputSurface->w, inputSurface->h }; + SDL_Rect dstRect = { x, y, w, h }; if (maintainAspectRatio) { float aspectRatio = (float)inputSurface->w / (float)inputSurface->h; - + if (w / (float)h > aspectRatio) { dstRect.w = (int)(h * aspectRatio); } else { @@ -1209,7 +1230,7 @@ void PLAT_animateSurface( else SDL_SetRenderTarget(vid.renderer, vid.target_layer4); - SDL_SetRenderDrawColor(vid.renderer, 0, 0, 0, 0); + SDL_SetRenderDrawColor(vid.renderer, 0, 0, 0, 0); SDL_RenderClear(vid.renderer); SDL_Rect srcRect = { 0, 0, inputSurface->w, inputSurface->h }; @@ -1228,7 +1249,7 @@ int PLAT_textShouldScroll(TTF_Font* font, const char* in_name,int max_width, SDL if (fontMutex) SDL_LockMutex(fontMutex); TTF_SizeUTF8(font, in_name, &text_width, NULL); if (fontMutex) SDL_UnlockMutex(fontMutex); - + if (text_width <= max_width) { return 0; } else { @@ -1344,7 +1365,7 @@ void PLAT_animateSurfaceOpacity( } SDL_UpdateTexture(tempTexture, NULL, inputSurface->pixels, inputSurface->pitch); - SDL_SetTextureBlendMode(tempTexture, SDL_BLENDMODE_BLEND); + SDL_SetTextureBlendMode(tempTexture, SDL_BLENDMODE_BLEND); const int fps = 60; const int frame_delay = 1000 / fps; @@ -1600,12 +1621,12 @@ void PLAT_flipHidden() { void PLAT_flip(SDL_Surface* IGNORED, int ignored) { // dont think we need this here tbh - // SDL_RenderClear(vid.renderer); + // SDL_RenderClear(vid.renderer); if (!vid.blit) { resizeVideo(device_width, device_height, FIXED_PITCH); // !!!??? SDL_UpdateTexture(vid.stream_layer1, NULL, vid.screen->pixels, vid.screen->pitch); SDL_RenderCopy(vid.renderer, vid.target_layer1, NULL, NULL); - SDL_RenderCopy(vid.renderer, vid.target_layer2, NULL, NULL); + SDL_RenderCopy(vid.renderer, vid.target_layer2, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.stream_layer1, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer3, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer4, NULL, NULL); @@ -1613,7 +1634,7 @@ void PLAT_flip(SDL_Surface* IGNORED, int ignored) { SDL_RenderPresent(vid.renderer); return; } - + // Safety check: ensure texture dimensions match blit buffer dimensions if (vid.width != vid.blit->true_w || vid.height != vid.blit->true_h) { // Texture size doesn't match buffer, clear blit and use screen buffer instead @@ -1629,7 +1650,7 @@ void PLAT_flip(SDL_Surface* IGNORED, int ignored) { SDL_RenderPresent(vid.renderer); return; } - + SDL_UpdateTexture(vid.stream_layer1, NULL, vid.blit->src, vid.blit->src_p); SDL_Texture* target = vid.stream_layer1; @@ -1638,7 +1659,7 @@ void PLAT_flip(SDL_Surface* IGNORED, int ignored) { int w = vid.blit->src_w; int h = vid.blit->src_h; if (vid.sharpness == SHARPNESS_CRISP) { - + SDL_SetRenderTarget(vid.renderer, vid.target); SDL_RenderCopy(vid.renderer, vid.stream_layer1, NULL, NULL); SDL_SetRenderTarget(vid.renderer, NULL); @@ -1653,7 +1674,7 @@ void PLAT_flip(SDL_Surface* IGNORED, int ignored) { SDL_Rect* dst_rect = &(SDL_Rect){0, 0, device_width, device_height}; setRectToAspectRatio(dst_rect); - + SDL_RenderCopy(vid.renderer, target, src_rect, dst_rect); SDL_RenderPresent(vid.renderer); @@ -1790,7 +1811,7 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, // } if(*target_texture==0) glGenTextures(1, target_texture); - glActiveTexture(GL_TEXTURE0); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, *target_texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, next_filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, next_filter); @@ -1802,7 +1823,7 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, if (fbo == 0) { glGenFramebuffers(1, &fbo); } - + // Always bind before attaching to avoid stale state after swaps glBindFramebuffer(GL_FRAMEBUFFER, fbo); @@ -1818,7 +1839,7 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, if (status != GL_FRAMEBUFFER_COMPLETE) { LOG_error("Framebuffer incomplete: 0x%X\n", status); } - + } else { glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -1873,7 +1894,7 @@ int prepareFrameThread(void *data) { pthread_mutex_lock(&video_prep_mutex); int effect_updated = effectUpdated; pthread_mutex_unlock(&video_prep_mutex); - + if (effect_updated) { LOG_info("effect updated %s\n",effect_path); if(effect_path) { @@ -1883,7 +1904,7 @@ int prepareFrameThread(void *data) { converted = SDL_ConvertSurfaceFormat(tmp, SDL_PIXELFORMAT_RGBA32, 0); SDL_FreeSurface(tmp); } - + pthread_mutex_lock(&video_prep_mutex); frame_prep.loaded_effect = converted; effectUpdated = 0; @@ -1897,13 +1918,13 @@ int prepareFrameThread(void *data) { pthread_mutex_unlock(&video_prep_mutex); } } - + // Check if effect is disabled pthread_mutex_lock(&video_prep_mutex); int effect_type = effect.type; SDL_Surface* loaded_effect = frame_prep.loaded_effect; pthread_mutex_unlock(&video_prep_mutex); - + if(effect_type == EFFECT_NONE && loaded_effect != 0) { pthread_mutex_lock(&video_prep_mutex); frame_prep.loaded_effect = 0; @@ -1915,7 +1936,7 @@ int prepareFrameThread(void *data) { pthread_mutex_lock(&video_prep_mutex); int overlay_updated = overlayUpdated; pthread_mutex_unlock(&video_prep_mutex); - + if (overlay_updated) { LOG_info("overlay updated\n"); @@ -1926,7 +1947,7 @@ int prepareFrameThread(void *data) { converted = SDL_ConvertSurfaceFormat(tmp, SDL_PIXELFORMAT_RGBA32, 0); SDL_FreeSurface(tmp); } - + pthread_mutex_lock(&video_prep_mutex); frame_prep.loaded_overlay = converted; frame_prep.overlay_ready = 1; @@ -1941,7 +1962,7 @@ int prepareFrameThread(void *data) { } } - SDL_Delay(120); + SDL_Delay(120); } return 0; } @@ -1958,7 +1979,7 @@ void PLAT_GL_Swap() { if (prepare_thread == NULL) { LOG_error("Error creating background thread: %s\n", SDL_GetError()); - return; + return; } } @@ -1991,9 +2012,9 @@ void PLAT_GL_Swap() { if (orig_texture) { glDeleteTextures(1, &orig_texture); orig_texture = 0; } src_w_last = src_h_last = 0; last_w = last_h = 0; - if (effect_tex) { - glDeleteTextures(1, &effect_tex); - effect_tex = 0; + if (effect_tex) { + glDeleteTextures(1, &effect_tex); + effect_tex = 0; effect_w = effect_h = 0; // Force reload by marking as ready again if effect is active pthread_mutex_lock(&video_prep_mutex); @@ -2002,9 +2023,9 @@ void PLAT_GL_Swap() { } pthread_mutex_unlock(&video_prep_mutex); } - if (overlay_tex) { - glDeleteTextures(1, &overlay_tex); - overlay_tex = 0; + if (overlay_tex) { + glDeleteTextures(1, &overlay_tex); + overlay_tex = 0; overlay_w = overlay_h = 0; // Force reload if we had an overlay pthread_mutex_lock(&video_prep_mutex); @@ -2021,7 +2042,7 @@ void PLAT_GL_Swap() { int effect_ready = frame_prep.effect_ready; SDL_Surface* loaded_effect = frame_prep.loaded_effect; pthread_mutex_unlock(&video_prep_mutex); - + if (effect_ready) { if(loaded_effect) { if(!effect_tex) glGenTextures(1, &effect_tex); @@ -2051,7 +2072,7 @@ void PLAT_GL_Swap() { int overlay_ready = frame_prep.overlay_ready; SDL_Surface* loaded_overlay = frame_prep.loaded_overlay; pthread_mutex_unlock(&video_prep_mutex); - + if (overlay_ready) { if(loaded_overlay) { if(!overlay_tex) glGenTextures(1, &overlay_tex); @@ -2204,7 +2225,7 @@ void PLAT_GL_Swap() { s_pass_notif.srch = s_pass_notif.texh = notif.tex_h; notif.dirty = 0; } - + if (notif.tex && notif.surface) { runShaderPass( &s_pass_overlay, notif.tex, NULL, @@ -2261,7 +2282,7 @@ unsigned char* PLAT_GL_screenCapture(int* outWidth, int* outHeight) { glViewport(0, 0, device_width, device_height); GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); - + int width = viewport[2]; int height = viewport[3]; diff --git a/workspace/all/ledcontrol/ledcontrol.c b/workspace/all/ledcontrol/ledcontrol.c index 98759a6ce..b8344ba98 100644 --- a/workspace/all/ledcontrol/ledcontrol.c +++ b/workspace/all/ledcontrol/ledcontrol.c @@ -227,7 +227,7 @@ int main(int argc, char *argv[]) memcpy(lightnames, default_names, sizeof(default_names)); // Copy values } - SDL_Surface* screen = GFX_init(MODE_MENU); + SDL_Surface* screen = GFX_init(MODE_MAIN); PAD_init(); PWR_init(); diff --git a/workspace/all/minarch/minarch.c b/workspace/all/minarch/minarch.c index 81fc45db0..ed2f92abd 100644 --- a/workspace/all/minarch/minarch.c +++ b/workspace/all/minarch/minarch.c @@ -6971,9 +6971,20 @@ static int OptionShaders_optionChanged(MenuList* list, int i) { MenuItem* item = &list->items[y]; item->value = config.shaders.options[y].value; } - // Recursively call Config_syncShaders again for some reason - if(i==SH_SHADERS_PRESET) + + if(i==SH_SHADERS_PRESET) { + // On shader preset change: + // Push all new shader settings to shader engine, + // compile shaders if needed, populate pragmas list initShaders(); + + // Now that we have a list of shader parameters, + // re-read shader preset file to set pragma values in-menu + Config_syncShaders(item->key, item->value); + + // Push parameters to shader engine + applyShaderSettings(); + } return MENU_CALLBACK_NOP; } @@ -8854,7 +8865,7 @@ static void limitFF(void) { last_time = now; } -static void Rewind_run_frame(void) { +static void run_frame(void) { // if rewind is toggled, fast-forward toggle must stay off; fast-forward hold pauses rewind int do_rewind = (rewind_pressed || rewind_toggle) && !(rewind_toggle && ff_hold_active); if (do_rewind) { @@ -8907,16 +8918,8 @@ static void Rewind_run_frame(void) { ff_paused_by_rewind_hold = 0; } - int ff_runs = 1; - if (fast_forward) { - // when "None" is selected, assume a modest 2x instead of unbounded spam - ff_runs = max_ff_speed ? max_ff_speed + 1 : 2; - } - - for (int ff_step = 0; ff_step < ff_runs; ff_step++) { - core.run(); - Rewind_push(0); - } + core.run(); + Rewind_push(0); } limitFF(); } @@ -9087,7 +9090,7 @@ int main(int argc , char* argv[]) { while (!quit) { GFX_startFrame(); - Rewind_run_frame(); + run_frame(); // Process RetroAchievements for this frame RA_doFrame(); diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index c2d921059..4b943b835 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -69,7 +69,7 @@ static void Array_reverse(Array* self) { } } static void Array_free(Array* self) { - free(self->items); + free(self->items); free(self); } static void Array_yoink(Array* self, Array* other) { @@ -228,7 +228,7 @@ static void getUniqueName(Entry* entry, char* out_name) { char* filename = strrchr(entry->path, '/')+1; char emu_tag[256]; getEmuName(entry->path, emu_tag); - + char *tmp; strcpy(out_name, entry->name); tmp = out_name + strlen(out_name); @@ -242,7 +242,7 @@ static void getUniqueName(Entry* entry, char* out_name) { static void Directory_index(Directory* self) { int is_collection = prefixMatch(COLLECTIONS_PATH, self->path); int skip_index = exactMatch(FAUX_RECENT_PATH, self->path) || is_collection; // not alphabetized - + Hash* map = NULL; char map_path[256]; sprintf(map_path, "%s/map.txt", is_collection ? COLLECTIONS_PATH : self->path); @@ -266,7 +266,7 @@ static void Directory_index(Directory* self) { } } fclose(file); - + int resort = 0; int filter = 0; for (int i = 0; i < self->entries->count; i++) { @@ -280,7 +280,7 @@ static void Directory_index(Directory* self) { if (!filter && hide(entry->name)) filter = 1; } } - + if (filter) { Array* entries = Array_new(); for (int i = 0; i < self->entries->count; i++) { @@ -297,7 +297,7 @@ static void Directory_index(Directory* self) { if (resort) EntryArray_sort(self->entries); } } - + Entry* prior = NULL; int alpha = -1; int index = 0; @@ -311,7 +311,7 @@ static void Directory_index(Directory* self) { entry->name = strdup(alias); } } - + if (prior != NULL && exactMatch(prior->name, entry->name)) { free(prior->unique); free(entry->unique); @@ -343,7 +343,7 @@ static void Directory_index(Directory* self) { } entry->alpha = index; } - + prior = entry; } @@ -360,7 +360,7 @@ static Array* getEntries(char* path); static Directory* Directory_new(char* path, int selected) { char display_name[256]; getDisplayName(path, display_name); - + Directory* self = malloc(sizeof(Directory)); self->path = strdup(path); self->name = strdup(display_name); @@ -424,7 +424,7 @@ static Recent* Recent_new(char* path, char* alias) { char emu_name[256]; getEmuName(sd_path, emu_name); - + self->path = strdup(path); self->alias = alias ? strdup(alias) : NULL; self->available = hasEmu(emu_name); @@ -521,12 +521,12 @@ static Entry* entryFromPakName(char* pak_name) // Check in Emus sprintf(pak_path, "%s/Emus/%s.pak", PAKS_PATH, pak_name); - if(exists(pak_path)) + if(exists(pak_path)) return Entry_newNamed(pak_path, ENTRY_PAK, pak_name); // Check in platform Emus sprintf(pak_path, "%s/Emus/%s/%s.pak", SDCARD_PATH, PLATFORM, pak_name); - if(exists(pak_path)) + if(exists(pak_path)) return Entry_newNamed(pak_path, ENTRY_PAK, pak_name); return NULL; @@ -547,31 +547,31 @@ static int hasCue(char* dir_path, char* cue_path) { // NOTE: dir_path not rom_pa } static int hasM3u(char* rom_path, char* m3u_path) { // NOTE: rom_path not dir_path char* tmp; - + strcpy(m3u_path, rom_path); tmp = strrchr(m3u_path, '/') + 1; tmp[0] = '\0'; - + // path to parent directory char base_path[256]; strcpy(base_path, m3u_path); - + tmp = strrchr(m3u_path, '/'); tmp[0] = '\0'; - + // get parent directory name char dir_name[256]; tmp = strrchr(m3u_path, '/'); strcpy(dir_name, tmp); - + // dir_name is also our m3u file name - tmp = m3u_path + strlen(m3u_path); + tmp = m3u_path + strlen(m3u_path); strcpy(tmp, dir_name); // add extension tmp = m3u_path + strlen(m3u_path); strcpy(tmp, ".m3u"); - + return exists(m3u_path); } @@ -590,7 +590,7 @@ static int hasRecents(void) { Recent* recent = Recent_new(disc_path, NULL); if (recent->available) has += 1; Array_push(recents, recent); - + char parent_path[256]; strcpy(parent_path, disc_path); char* tmp = strrchr(parent_path, '/') + 1; @@ -607,9 +607,9 @@ static int hasRecents(void) { normalizeNewline(line); trimTrailingNewlines(line); if (strlen(line)==0) continue; // skip empty lines - + // LOG_info("line: %s\n", line); - + char* path = line; char* alias = NULL; char* tmp = strchr(line,'\t'); @@ -617,7 +617,7 @@ static int hasRecents(void) { tmp[0] = '\0'; alias = tmp+1; } - + char sd_path[256]; sprintf(sd_path, "%s%s", SDCARD_PATH, path); if (exists(sd_path)) { @@ -629,7 +629,7 @@ static int hasRecents(void) { strcpy(parent_path, path); char* tmp = strrchr(parent_path, '/') + 1; tmp[0] = '\0'; - + int found = 0; for (int i=0; icount; i++) { char* path = parent_paths->items[i]; @@ -639,12 +639,12 @@ static int hasRecents(void) { } } if (found) continue; - + Array_push(parent_paths, strdup(parent_path)); } - + // LOG_info("path:%s alias:%s\n", path, alias); - + Recent* recent = Recent_new(path, alias); if (recent->available) has += 1; Array_push(recents, recent); @@ -653,16 +653,16 @@ static int hasRecents(void) { } fclose(file); } - + saveRecents(); - + StringArray_free(parent_paths); return has>0; } static int hasCollections(void) { int has = 0; if (!exists(COLLECTIONS_PATH)) return has; - + DIR *dh = opendir(COLLECTIONS_PATH); struct dirent *dp; while((dp = readdir(dh)) != NULL) { @@ -679,10 +679,10 @@ static int hasRoms(char* dir_name) { char rom_path[256]; getEmuName(dir_name, emu_name); - + // check for emu pak if (!hasEmu(emu_name)) return has; - + // check for at least one non-hidden file (we're going to assume it's a rom) sprintf(rom_path, "%s/%s/", ROMS_PATH, dir_name); DIR *dh = opendir(rom_path); @@ -833,7 +833,7 @@ static Array* getQuickToggles(void) { Entry *settings = entryFromPakName("Settings"); if (settings) Array_push(entries, settings); - + Entry *store = entryFromPakName("Pak Store"); if (store) Array_push(entries, store); @@ -854,7 +854,7 @@ static Array* getQuickToggles(void) { static Array* getRoot(void) { Array* root = Array_new(); - if (hasRecents() && CFG_getShowRecents()) + if (hasRecents() && CFG_getShowRecents()) Array_push(root, Entry_new(FAUX_RECENT_PATH, ENTRY_DIR)); Array *entries = getRoms(); @@ -886,7 +886,7 @@ static Entry* entryFromRecent(Recent* recent) { if(!recent || !recent->available) return NULL; - + char sd_path[256]; sprintf(sd_path, "%s%s", SDCARD_PATH, recent->path); int type = suffixMatch(".pak", sd_path) ? ENTRY_PAK : ENTRY_ROM; // ??? @@ -918,13 +918,13 @@ static Array* getCollection(char* path) { normalizeNewline(line); trimTrailingNewlines(line); if (strlen(line)==0) continue; // skip empty lines - + char sd_path[256]; sprintf(sd_path, "%s%s", SDCARD_PATH, line); if (exists(sd_path)) { int type = suffixMatch(".pak", sd_path) ? ENTRY_PAK : ENTRY_ROM; // ??? Array_push(entries, Entry_new(sd_path, type)); - + // char emu_name[256]; // getEmuName(sd_path, emu_name); // if (hasEmu(emu_name)) { @@ -937,16 +937,16 @@ static Array* getCollection(char* path) { return entries; } static Array* getDiscs(char* path){ - + // TODO: does path have SDCARD_PATH prefix? - + Array* entries = Array_new(); - + char base_path[256]; strcpy(base_path, path); char* tmp = strrchr(base_path, '/') + 1; tmp[0] = '\0'; - + // TODO: limit number of discs supported (to 9?) FILE* file = fopen(path, "r"); if (file) { @@ -956,10 +956,10 @@ static Array* getDiscs(char* path){ normalizeNewline(line); trimTrailingNewlines(line); if (strlen(line)==0) continue; // skip empty lines - + char disc_path[256]; sprintf(disc_path, "%s%s", base_path, line); - + if (exists(disc_path)) { disc += 1; Entry* entry = Entry_new(disc_path, ENTRY_ROM); @@ -981,7 +981,7 @@ static int getFirstDisc(char* m3u_path, char* disc_path) { // based on getDiscs( strcpy(base_path, m3u_path); char* tmp = strrchr(base_path, '/') + 1; tmp[0] = '\0'; - + FILE* file = fopen(m3u_path, "r"); if (file) { char line[256]; @@ -989,9 +989,9 @@ static int getFirstDisc(char* m3u_path, char* disc_path) { // based on getDiscs( normalizeNewline(line); trimTrailingNewlines(line); if (strlen(line)==0) continue; // skip empty lines - + sprintf(disc_path, "%s%s", base_path, line); - + if (exists(disc_path)) found = 1; break; } @@ -1042,7 +1042,7 @@ static int isConsoleDir(char* path) { strcpy(parent_dir, path); tmp = strrchr(parent_dir, '/'); tmp[0] = '\0'; - + return exactMatch(parent_dir, ROMS_PATH); } @@ -1055,8 +1055,8 @@ static Array* getEntries(char* path){ char* tmp = strrchr(collated_path, '('); // 1 because we want to keep the opening parenthesis to avoid collating "Game Boy Color" and "Game Boy Advance" into "Game Boy" // but conditional so we can continue to support a bare tag name as a folder name - if (tmp) tmp[1] = '\0'; - + if (tmp) tmp[1] = '\0'; + DIR *dh = opendir(ROMS_PATH); if (dh!=NULL) { struct dirent *dp; @@ -1068,7 +1068,7 @@ static Array* getEntries(char* path){ if (hide(dp->d_name)) continue; if (dp->d_type!=DT_DIR) continue; strcpy(tmp, dp->d_name); - + if (!prefixMatch(collated_path, full_path)) continue; addEntries(entries, full_path); } @@ -1076,7 +1076,7 @@ static Array* getEntries(char* path){ } } else addEntries(entries, path); // just a subfolder - + EntryArray_sort(entries); return entries; } @@ -1132,9 +1132,9 @@ static void readyResumePath(char* rom_path, int type) { has_preview = 0; char path[256]; strcpy(path, rom_path); - + if (!prefixMatch(ROMS_PATH, path)) return; - + char auto_path[256]; if (type==ENTRY_DIR) { if (!hasCue(path, auto_path)) { // no cue? @@ -1144,7 +1144,7 @@ static void readyResumePath(char* rom_path, int type) { } strcpy(path, auto_path); // cue or m3u if one exists } - + if (!suffixMatch(".m3u", path)) { char m3u_path[256]; if (hasM3u(path, m3u_path)) { @@ -1152,14 +1152,14 @@ static void readyResumePath(char* rom_path, int type) { strcpy(path, m3u_path); } } - + char emu_name[256]; getEmuName(path, emu_name); - + char rom_file[256]; tmp = strrchr(path, '/') + 1; strcpy(rom_file, tmp); - + sprintf(slot_path, "%s/.minui/%s/%s.txt", SHARED_USERDATA_PATH, emu_name, rom_file); // /.userdata/.minui//.ext.txt can_resume = exists(slot_path); @@ -1183,32 +1183,32 @@ static int autoResume(void) { // NOTE: bypasses recents if (!exists(AUTO_RESUME_PATH)) return 0; - + char path[256]; getFile(AUTO_RESUME_PATH, path, 256); unlink(AUTO_RESUME_PATH); sync(); - + // make sure rom still exists char sd_path[256]; sprintf(sd_path, "%s%s", SDCARD_PATH, path); if (!exists(sd_path)) return 0; - + // make sure emu still exists char emu_name[256]; getEmuName(sd_path, emu_name); - + char emu_path[256]; getEmuPath(emu_name, emu_path); - + if (!exists(emu_path)) return 0; - + // putFile(LAST_PATH, FAUX_RECENT_PATH); // saveLast() will crash here because top is NULL char act[256]; sprintf(act, "gametimectl.elf start '%s'", escapeSingleQuotes(sd_path)); system(act); - + char cmd[256]; // dont escape sd_path again because it was already escaped for gametimectl and function modifies input str aswell sprintf(cmd, "'%s' '%s'", escapeSingleQuotes(emu_path), sd_path); @@ -1218,29 +1218,29 @@ static int autoResume(void) { } static void openPak(char* path) { - // NOTE: escapeSingleQuotes() modifies the passed string + // NOTE: escapeSingleQuotes() modifies the passed string // so we need to save the path before we call that // if (prefixMatch(ROMS_PATH, path)) { // addRecent(path); // } saveLast(path); - + char cmd[256]; sprintf(cmd, "'%s/launch.sh'", escapeSingleQuotes(path)); queueNext(cmd); } static void openRom(char* path, char* last) { LOG_info("openRom(%s,%s)\n", path, last); - + char sd_path[256]; strcpy(sd_path, path); - + char m3u_path[256]; int has_m3u = hasM3u(sd_path, m3u_path); - + char recent_path[256]; strcpy(recent_path, has_m3u ? m3u_path : sd_path); - + if (has_m3u && suffixMatch(".m3u", sd_path)) { getFirstDisc(m3u_path, sd_path); } @@ -1257,7 +1257,7 @@ static void openRom(char* path, char* last) { if (has_m3u) { char rom_file[256]; strcpy(rom_file, strrchr(m3u_path, '/') + 1); - + // get disc for state char disc_path_path[256]; sprintf(disc_path_path, "%s/.minui/%s/%s.%s.txt", SHARED_USERDATA_PATH, emu_name, rom_file, slot); // /.userdata/arm-480/.minui//.ext.0.txt @@ -1276,11 +1276,11 @@ static void openRom(char* path, char* last) { } } else putInt(RESUME_SLOT_PATH,8); // resume hidden default state - + char emu_path[256]; getEmuPath(emu_name, emu_path); - - // NOTE: escapeSingleQuotes() modifies the passed string + + // NOTE: escapeSingleQuotes() modifies the passed string // so we need to save the path before we call that addRecent(recent_path, recent_alias); // yiiikes saveLast(last==NULL ? sd_path : last); @@ -1447,7 +1447,7 @@ static void openDirectory(char* path, int auto_launch) { top = Directory_new(path, selected); top->start = start; top->end = end ? end : ((top->entries->countentries->count : MAIN_ROW_COUNT); - + Array_push(stack, top); } else { @@ -1507,10 +1507,10 @@ static void Entry_open(Entry* self) { if (prefixMatch(COLLECTIONS_PATH, top->path)) { char* tmp; char filename[256]; - + tmp = strrchr(self->path, '/'); if (tmp) strcpy(filename, tmp+1); - + char last_path[256]; sprintf(last_path, "%s/%s", top->path, filename); last = last_path; @@ -1546,23 +1546,23 @@ static void loadLast(void) { // call after loading root directory char last_path[256]; getFile(LAST_PATH, last_path, 256); - + char full_path[256]; strcpy(full_path, last_path); - + char* tmp; char filename[256]; tmp = strrchr(last_path, '/'); if (tmp) strcpy(filename, tmp); - + Array* last = Array_new(); while (!exactMatch(last_path, SDCARD_PATH)) { Array_push(last, strdup(last_path)); - + char* slash = strrchr(last_path, '/'); last_path[(slash-last_path)] = '\0'; } - + while (last->count>0) { char* path = Array_pop(last); if (!exactMatch(path, ROMS_PATH)) { // romsDir is effectively root as far as restoring state after a game @@ -1573,10 +1573,10 @@ static void loadLast(void) { // call after loading root directory tmp = strrchr(collated_path, '('); if (tmp) tmp[1] = '\0'; // 1 because we want to keep the opening parenthesis to avoid collating "Game Boy Color" and "Game Boy Advance" into "Game Boy" } - + for (int i=0; ientries->count; i++) { Entry* entry = top->entries->items[i]; - + // NOTE: strlen() is required for collated_path, '\0' wasn't reading as NULL for some reason if (exactMatch(entry->path, path) || (strlen(collated_path) && prefixMatch(collated_path, entry->path)) || (prefixMatch(COLLECTIONS_PATH, full_path) && suffixMatch(filename, entry->path))) { top->selected = i; @@ -1589,7 +1589,7 @@ static void loadLast(void) { // call after loading root directory } } if (last->count==0 && !exactMatch(entry->path, FAUX_RECENT_PATH) && !(!exactMatch(entry->path, COLLECTIONS_PATH) && prefixMatch(COLLECTIONS_PATH, entry->path))) break; // don't show contents of auto-launch dirs - + if (entry->type==ENTRY_DIR) { openDirectory(entry->path, 0); break; @@ -1599,7 +1599,7 @@ static void loadLast(void) { // call after loading root directory } free(path); // we took ownership when we popped it } - + StringArray_free(last); if (top->selected >= 0 && top->selected < top->entries->count) { @@ -1664,7 +1664,7 @@ typedef struct finishedTask { int targetY; int targetTextY; int move_y; - int move_w; + int move_w; int move_h; int frames; int done; @@ -1680,7 +1680,7 @@ typedef struct AnimTask { int startY; int targetY; int targetTextY; - int move_w; + int move_w; int move_h; int frames; AnimTaskCallback callback; @@ -1759,7 +1759,6 @@ static void updatePillTextSurface(const char* entry_name, int move_w, SDL_Color 0, crop_rect.w, crop_rect.h, screen->format->BitsPerPixel, screen->format->format ); if (cropped) { - SDL_SetSurfaceBlendMode(converted, SDL_BLENDMODE_NONE); SDL_BlitSurface(converted, &crop_rect, cropped, NULL); } SDL_FreeSurface(converted); @@ -1809,7 +1808,7 @@ void enqueueBGTask(LoadBackgroundTask* task) { } else { taskBGQueueHead = taskBGQueueTail = node; } - + currentBGQueueSize++; SDL_CondSignal(bgqueueCond); SDL_UnlockMutex(bgqueueMutex); @@ -1843,7 +1842,7 @@ void enqueueThumbTask(LoadBackgroundTask* task) { } else { taskThumbQueueHead = taskThumbQueueTail = node; } - + currentThumbQueueSize++; SDL_CondSignal(thumbqueueCond); SDL_UnlockMutex(thumbqueueMutex); @@ -1973,17 +1972,17 @@ void onThumbLoaded(SDL_Surface* surface) { SDL_UnlockMutex(thumbMutex); return; } - - + + thumbbmp = surface; int img_w = thumbbmp->w; int img_h = thumbbmp->h; double aspect_ratio = (double)img_h / img_w; - int max_w = (int)(screen->w * CFG_getGameArtWidth()); - int max_h = (int)(screen->h * 0.6); + int max_w = (int)(screen->w * CFG_getGameArtWidth()); + int max_h = (int)(screen->h * 0.6); int new_w = max_w; - int new_h = (int)(new_w * aspect_ratio); - + int new_h = (int)(new_w * aspect_ratio); + if (new_h > max_h) { new_h = max_h; new_w = (int)(new_h / aspect_ratio); @@ -2003,7 +2002,7 @@ int pilltargetY =0; int pilltargetTextY =0; void animcallback(finishedTask *task) { SDL_LockMutex(animMutex); - pillRect = task->dst; + pillRect = task->dst; if(pillRect.w > 0 && pillRect.h > 0) { pilltargetY = +screen->w; // move offscreen if(task->done) { @@ -2021,21 +2020,21 @@ bool pillanimdone = false; int animWorker(void* unused) { while (!SDL_AtomicGet(&workerThreadsShutdown)) { SDL_LockMutex(animqueueMutex); - while (!animTaskQueueHead && !SDL_AtomicGet(&workerThreadsShutdown)) { - SDL_CondWait(animqueueCond, animqueueMutex); - } - if (SDL_AtomicGet(&workerThreadsShutdown)) { - SDL_UnlockMutex(animqueueMutex); - break; - } - AnimTaskNode* node = animTaskQueueHead; - animTaskQueueHead = node->next; - if (!animTaskQueueHead) animTtaskQueueTail = NULL; + while (!animTaskQueueHead && !SDL_AtomicGet(&workerThreadsShutdown)) { + SDL_CondWait(animqueueCond, animqueueMutex); + } + if (SDL_AtomicGet(&workerThreadsShutdown)) { + SDL_UnlockMutex(animqueueMutex); + break; + } + AnimTaskNode* node = animTaskQueueHead; + animTaskQueueHead = node->next; + if (!animTaskQueueHead) animTtaskQueueTail = NULL; SDL_UnlockMutex(animqueueMutex); - AnimTask* task = node->task; + AnimTask* task = node->task; finishedTask* finaltask = (finishedTask*)malloc(sizeof(finishedTask)); - int total_frames = task->frames; + int total_frames = task->frames; for (int frame = 0; frame <= total_frames; frame++) { // Check for shutdown at start of each frame if (SDL_AtomicGet(&workerThreadsShutdown)) break; @@ -2045,7 +2044,7 @@ int animWorker(void* unused) { int current_x = task->startX + (int)((task->targetX - task->startX) * t); int current_y = task->startY + (int)(( task->targetY - task->startY) * t); - + SDL_Rect moveDst = { current_x, current_y, task->move_w, task->move_h }; finaltask->dst = moveDst; finaltask->entry_name = task->entry_name; @@ -2063,13 +2062,13 @@ int animWorker(void* unused) { } frameReady = false; SDL_UnlockMutex(frameMutex); - + } SDL_LockMutex(animqueueMutex); if (!animTaskQueueHead) animTtaskQueueTail = NULL; currentAnimQueueSize--; // <-- add this SDL_UnlockMutex(animqueueMutex); - + SDL_LockMutex(animMutex); pillanimdone = true; free(finaltask); @@ -2081,7 +2080,7 @@ void enqueueanmimtask(AnimTask* task) { AnimTaskNode* node = (AnimTaskNode*)malloc(sizeof(AnimTaskNode)); node->task = task; node->next = NULL; - + SDL_LockMutex(animqueueMutex); pillanimdone = false; // If queue is full, drop the oldest task (head) @@ -2123,7 +2122,7 @@ void initImageLoaderPool() { SDL_AtomicSet(&workerThreadsShutdown, 0); SDL_AtomicSet(&animationDrawAtomic, 1); SDL_AtomicSet(&needDrawAtomic, 0); - + thumbqueueMutex = SDL_CreateMutex(); bgqueueMutex = SDL_CreateMutex(); bgqueueCond = SDL_CreateCond(); @@ -2145,13 +2144,13 @@ void initImageLoaderPool() { void cleanupImageLoaderPool() { // Signal all worker threads to exit (atomic set for thread safety) SDL_AtomicSet(&workerThreadsShutdown, 1); - + // Wake up all waiting threads if (bgqueueCond) SDL_CondSignal(bgqueueCond); if (thumbqueueCond) SDL_CondSignal(thumbqueueCond); if (animqueueCond) SDL_CondSignal(animqueueCond); if (flipCond) SDL_CondSignal(flipCond); // Wake up animWorker if stuck waiting for frame flip - + // Wait for all worker threads to finish if (bgLoadThread) { SDL_WaitThread(bgLoadThread, NULL); @@ -2165,10 +2164,10 @@ void cleanupImageLoaderPool() { SDL_WaitThread(animWorkerThread, NULL); animWorkerThread = NULL; } - + // Small delay to ensure llvmpipe/OpenGL threads have completed any pending operations SDL_Delay(10); - + // Acquire and release each mutex before destroying to ensure no thread is in a critical section // This creates a memory barrier and ensures proper synchronization if (bgqueueMutex) { SDL_LockMutex(bgqueueMutex); SDL_UnlockMutex(bgqueueMutex); } @@ -2179,7 +2178,7 @@ void cleanupImageLoaderPool() { if (animMutex) { SDL_LockMutex(animMutex); SDL_UnlockMutex(animMutex); } if (frameMutex) { SDL_LockMutex(frameMutex); SDL_UnlockMutex(frameMutex); } if (fontMutex) { SDL_LockMutex(fontMutex); SDL_UnlockMutex(fontMutex); } - + // Destroy mutexes and condition variables if (bgqueueMutex) SDL_DestroyMutex(bgqueueMutex); if (thumbqueueMutex) SDL_DestroyMutex(thumbqueueMutex); @@ -2189,12 +2188,12 @@ void cleanupImageLoaderPool() { if (animMutex) SDL_DestroyMutex(animMutex); if (frameMutex) SDL_DestroyMutex(frameMutex); if (fontMutex) SDL_DestroyMutex(fontMutex); - + if (bgqueueCond) SDL_DestroyCond(bgqueueCond); if (thumbqueueCond) SDL_DestroyCond(thumbqueueCond); if (animqueueCond) SDL_DestroyCond(animqueueCond); if (flipCond) SDL_DestroyCond(flipCond); - + // Set pointers to NULL after destruction bgqueueMutex = NULL; thumbqueueMutex = NULL; @@ -2215,24 +2214,24 @@ int main (int argc, char *argv[]) { // LOG_info("time from launch to:\n"); // unsigned long main_begin = SDL_GetTicks(); // unsigned long first_draw = 0; - + if (autoResume()) return 0; // nothing to do - + simple_mode = exists(SIMPLE_MODE_PATH); LOG_info("NextUI\n"); InitSettings(); - + screen = GFX_init(MODE_MAIN); - // LOG_info("- graphics init: %lu\n", SDL_GetTicks() - main_begin); - +// LOG_info("- graphics init: %lu\n", SDL_GetTicks() - main_begin); + PAD_init(); // LOG_info("- input init: %lu\n", SDL_GetTicks() - main_begin); VIB_init(); PWR_init(); if (!HAS_POWER_BUTTON && !simple_mode) PWR_disableSleep(); // LOG_info("- power init: %lu\n", SDL_GetTicks() - main_begin); - + // start my threaded image loader :D initImageLoaderPool(); Menu_init(); @@ -2258,7 +2257,7 @@ int main (int argc, char *argv[]) { // make sure we have no running games logged as active anymore (we might be launching back into the UI here) system("gametimectl.elf stop_all"); - + GFX_setVsync(VSYNC_STRICT); PAD_reset(); @@ -2297,16 +2296,16 @@ int main (int argc, char *argv[]) { while (!quit) { GFX_startFrame(); unsigned long now = SDL_GetTicks(); - + PAD_poll(); - + int selected = top->selected; int total = top->entries->count; - + PWR_update(&dirty, &show_setting, NULL, NULL); - + int is_online = PWR_isOnline(); - if (was_online!=is_online) + if (was_online!=is_online) dirty = 1; was_online = is_online; @@ -2466,7 +2465,7 @@ int main (int argc, char *argv[]) { } else if (PAD_tappedSelect(now)) { currentScreen = SCREEN_GAMESWITCHER; - switcher_selected = 0; + switcher_selected = 0; dirty = 1; } else if (total>0) { @@ -2480,7 +2479,7 @@ int main (int argc, char *argv[]) { selected = total-1; int start = total - MAIN_ROW_COUNT; top->start = (start<0) ? 0 : start; - top->end = total; + top->end = total; } else if (selectedstart) { top->start -= 1; @@ -2533,7 +2532,7 @@ int main (int argc, char *argv[]) { } } } - + if (PAD_justRepeated(BTN_L1) && !PAD_isPressed(BTN_R1) && !PWR_ignoreSettingInput(BTN_L1, show_setting)) { // previous alpha Entry* entry = top->entries->items[selected]; int i = entry->alpha-1; @@ -2560,21 +2559,21 @@ int main (int argc, char *argv[]) { } } } - + if (selected!=top->selected) { top->selected = selected; dirty = 1; } Entry* entry = top->entries->items[top->selected]; - - if (dirty && total>0) + + if (dirty && total>0) readyResume(entry); if (total>0 && can_resume && PAD_justReleased(BTN_RESUME)) { should_resume = 1; Entry_open(entry); - + dirty = 1; } else if (total>0 && PAD_justPressed(BTN_A)) { @@ -2592,11 +2591,11 @@ int main (int argc, char *argv[]) { animationdirection = SLIDE_RIGHT; total = top->entries->count; dirty = 1; - + if (total>0) readyResume(top->entries->items[top->selected]); } } - + if(dirty) { SDL_Surface *tmpOldScreen = NULL; SDL_Surface * switcherSur = NULL; @@ -2611,9 +2610,9 @@ int main (int argc, char *argv[]) { if(lastScreen==SCREEN_GAME || lastScreen==SCREEN_OFF) { GFX_clearLayers(LAYER_ALL); } - else { + else { GFX_clearLayers(LAYER_TRANSITION); - if(lastScreen!=SCREEN_GAMELIST) + if(lastScreen!=SCREEN_GAMELIST) GFX_clearLayers(LAYER_THUMBNAIL); GFX_clearLayers(LAYER_SCROLLTEXT); GFX_clearLayers(LAYER_IDK2); @@ -2630,11 +2629,12 @@ int main (int argc, char *argv[]) { Entry *current = qm_row == 0 ? quick->items[qm_col] : quickActions->items[qm_col]; char newBgPath[MAX_PATH]; char fallbackBgPath[MAX_PATH]; + sprintf(newBgPath, SDCARD_PATH "/.media/quick_%s%s.png", current->name, !strcmp(current->name,"Wifi") && !CFG_getWifi() || // wifi or wifi_off, based on state !strcmp(current->name,"Bluetooth") && !CFG_getBluetooth() ? "_off" : ""); // bluetooth or bluetooth_off, based on state sprintf(fallbackBgPath, SDCARD_PATH "/.media/quick.png"); - + // background if(!exists(newBgPath)) strncpy(newBgPath, fallbackBgPath, sizeof(newBgPath) - 1); @@ -2643,11 +2643,11 @@ int main (int argc, char *argv[]) { strncpy(folderBgPath, newBgPath, sizeof(folderBgPath) - 1); startLoadFolderBackground(newBgPath, onBackgroundLoaded, NULL); } - + // buttons (duped and trimmed from below) if (show_setting && !GetHDMI()) GFX_blitHardwareHints(screen, show_setting); else GFX_blitButtonGroup((char*[]){ BTN_SLEEP==BTN_POWER?"POWER":"MENU","SLEEP", NULL }, 0, screen, 0); - + GFX_blitButtonGroup((char*[]){ "B","BACK", "A","OPEN", NULL }, 1, screen, 1); if(CFG_getShowQuickswitcherUI()) { @@ -2669,7 +2669,7 @@ int main (int argc, char *argv[]) { int item_size = SCALE1(MENU_ITEM_SIZE); int item_extra_y = item_space_y - item_size; int item_space_x = screen->w - SCALE1(PADDING + MENU_MARGIN_X + MENU_MARGIN_X + PADDING); - // extra left margin for the first item in order to properly center all of them in the + // extra left margin for the first item in order to properly center all of them in the // available space int item_inset_x = (item_space_x - SCALE1(qm_slots * MENU_ITEM_SIZE + (qm_slots - 1) * MENU_ITEM_MARGIN)) / 2; @@ -2693,7 +2693,7 @@ int main (int argc, char *argv[]) { item_color = THEME_COLOR1; icon_color = THEME_COLOR5; } - + GFX_blitRectColor(ASSET_STATE_BG, screen, &item_rect, item_color); char icon_path[MAX_PATH]; @@ -2702,8 +2702,8 @@ int main (int argc, char *argv[]) { if(bmp) { SDL_Surface* converted = SDL_ConvertSurfaceFormat(bmp, screen->format->format, 0); if (converted) { - SDL_FreeSurface(bmp); - bmp = converted; + SDL_FreeSurface(bmp); + bmp = converted; } } if(bmp) { @@ -2766,9 +2766,9 @@ int main (int argc, char *argv[]) { int y = item_rect.y; x += (SCALE1(PILL_SIZE) - rect.w) / 2; y += (SCALE1(PILL_SIZE) - rect.h) / 2; - + GFX_blitAssetColor(asset, NULL, screen, &(SDL_Rect){x,y}, icon_color); - + ox += item_rect.w + SCALE1(MENU_TOGGLE_MARGIN); } } @@ -2786,7 +2786,7 @@ int main (int argc, char *argv[]) { GFX_clearLayers(LAYER_ALL); ox = 0; oy = 0; - + // For all recents with resumable state (i.e. has savegame), show game switcher carousel if(recents->count > 0) { Entry *selectedEntry = entryFromRecent(recents->items[switcher_selected]); @@ -2794,7 +2794,7 @@ int main (int argc, char *argv[]) { // title pill { int max_width = screen->w - SCALE1(PADDING * 2) - ow; - + char display_name[256]; int text_width = GFX_truncateText(font.large, selectedEntry->name, display_name, max_width, SCALE1(BUTTON_PADDING*2)); max_width = MIN(max_width, text_width); @@ -2830,22 +2830,22 @@ int main (int argc, char *argv[]) { if(has_preview) { // lotta memory churn here - + SDL_Surface* bmp = IMG_Load(preview_path); SDL_Surface* raw_preview = SDL_ConvertSurfaceFormat(bmp, screen->format->format, 0); if (raw_preview) { - SDL_FreeSurface(bmp); - bmp = raw_preview; + SDL_FreeSurface(bmp); + bmp = raw_preview; } if(bmp) { int aw = screen->w; int ah = screen->h; int ax = 0; int ay = 0; - + float aspectRatio = (float)bmp->w / (float)bmp->h; float screenRatio = (float)screen->w / (float)screen->h; - + if (screenRatio > aspectRatio) { aw = (int)(screen->h * aspectRatio); ah = screen->h; @@ -2855,13 +2855,13 @@ int main (int argc, char *argv[]) { } ax = (screen->w - aw) / 2; ay = (screen->h - ah) / 2; - + if(lastScreen == SCREEN_GAME) { // need to flip once so streaming_texture1 is updated GFX_flipHidden(); GFX_animateSurfaceOpacity(bmp,0,0,screen->w,screen->h,0,255,CFG_getMenuTransitions() ? 150:20,LAYER_ALL); - } else if(lastScreen == SCREEN_GAMELIST) { - + } else if(lastScreen == SCREEN_GAMELIST) { + GFX_drawOnLayer(blackBG,0,0,screen->w,screen->h,1.0f,0,LAYER_BACKGROUND); GFX_drawOnLayer(bmp,ax,ay,aw, ah,1.0f,0,LAYER_BACKGROUND); GFX_flipHidden(); @@ -2871,19 +2871,19 @@ int main (int argc, char *argv[]) { GFX_drawOnLayer(tmpOldScreen,0,0,screen->w, screen->h,1.0f,0,LAYER_ALL); GFX_animateSurface(tmpNewScreen,0,0-screen->h,0,0,screen->w,screen->h,CFG_getMenuTransitions() ? 100:20,255,255,LAYER_BACKGROUND); SDL_FreeSurface(tmpNewScreen); - + } else if(lastScreen == SCREEN_GAMESWITCHER) { GFX_flipHidden(); GFX_drawOnLayer(blackBG,0,0,screen->w, screen->h,1.0f,0,LAYER_BACKGROUND); - if(gsanimdir == SLIDE_LEFT) + if(gsanimdir == SLIDE_LEFT) GFX_animateSurface(bmp,ax+screen->w,ay,ax,ay,aw,ah,CFG_getMenuTransitions() ? 80:20,0,255,LAYER_ALL); else if(gsanimdir == SLIDE_RIGHT) GFX_animateSurface(bmp,ax-screen->w,ay,ax,ay,aw,ah,CFG_getMenuTransitions() ? 80:20,0,255,LAYER_ALL); - + GFX_drawOnLayer(bmp,ax,ay,aw,ah,1.0f,0,LAYER_BACKGROUND); } else if(lastScreen == SCREEN_QUICKMENU) { GFX_flipHidden(); - GFX_drawOnLayer(blackBG,0,0,screen->w, screen->h,1.0f,0,LAYER_BACKGROUND); + GFX_drawOnLayer(blackBG,0,0,screen->w, screen->h,1.0f,0,LAYER_BACKGROUND); GFX_drawOnLayer(bmp,ax,ay,aw,ah,1.0f,0,LAYER_BACKGROUND); } SDL_FreeSurface(bmp); // Free after rendering @@ -2892,14 +2892,14 @@ int main (int argc, char *argv[]) { else { SDL_Rect preview_rect = {ox,oy,screen->w,screen->h}; SDL_Surface * tmpsur = SDL_CreateRGBSurfaceWithFormat(0,screen->w,screen->h,screen->format->BitsPerPixel,screen->format->format); - SDL_FillRect(tmpsur, &preview_rect, SDL_MapRGBA(screen->format,0,0,0,255)); + SDL_FillRect(tmpsur, &preview_rect, CFG_getColor(COLOR_BACKGROUND)); if(lastScreen == SCREEN_GAME) { GFX_animateSurfaceOpacity(tmpsur,0,0,screen->w,screen->h,255,0,CFG_getMenuTransitions() ? 150:20,LAYER_BACKGROUND); - } else if(lastScreen == SCREEN_GAMELIST) { + } else if(lastScreen == SCREEN_GAMELIST) { GFX_animateSurface(tmpsur,0,0-screen->h,0,0,screen->w,screen->h,CFG_getMenuTransitions() ? 100:20,255,255,LAYER_ALL); } else if(lastScreen == SCREEN_GAMESWITCHER) { GFX_flipHidden(); - if(gsanimdir == SLIDE_LEFT) + if(gsanimdir == SLIDE_LEFT) GFX_animateSurface(tmpsur,0+screen->w,0,0,0,screen->w,screen->h,CFG_getMenuTransitions() ? 80:20,0,255,LAYER_ALL); else if(gsanimdir == SLIDE_RIGHT) GFX_animateSurface(tmpsur,0-screen->w,0,0,0,screen->w,screen->h,CFG_getMenuTransitions() ? 80:20,0,255,LAYER_ALL); @@ -2915,7 +2915,7 @@ int main (int argc, char *argv[]) { GFX_blitMessage(font.large, "No Recents", screen, &preview_rect); GFX_blitButtonGroup((char*[]){ "B","BACK", NULL }, 1, screen, 1); } - + GFX_flipHidden(); if(switcherSur) SDL_FreeSurface(switcherSur); @@ -2929,22 +2929,22 @@ int main (int argc, char *argv[]) { char tmp_path[MAX_PATH]; strncpy(tmp_path, entry->path, sizeof(tmp_path) - 1); tmp_path[sizeof(tmp_path) - 1] = '\0'; - + char* res_name = strrchr(tmp_path, '/'); if (res_name) res_name++; char path_copy[1024]; strncpy(path_copy, entry->path, sizeof(path_copy) - 1); path_copy[sizeof(path_copy) - 1] = '\0'; - + char* rompath = dirname(path_copy); - + char res_copy[1024]; strncpy(res_copy, res_name, sizeof(res_copy) - 1); res_copy[sizeof(res_copy) - 1] = '\0'; - + char* dot = strrchr(res_copy, '.'); - if (dot) *dot = '\0'; + if (dot) *dot = '\0'; static int lastType = -1; @@ -2972,7 +2972,7 @@ int main (int argc, char *argv[]) { } startLoadFolderBackground(tmppath, onBackgroundLoaded, NULL); } - } + } else if(strcmp(defaultBgPath, folderBgPath) != 0 && exists(defaultBgPath)) { strncpy(folderBgPath, defaultBgPath, sizeof(folderBgPath) - 1); startLoadFolderBackground(defaultBgPath, onBackgroundLoaded, NULL); @@ -2988,10 +2988,10 @@ int main (int argc, char *argv[]) { snprintf(thumbpath, sizeof(thumbpath), "%s/.media/%s.png", rompath, res_copy); had_thumb = 0; startLoadThumb(thumbpath, onThumbLoaded, NULL); - int max_w = (int)(screen->w - (screen->w * CFG_getGameArtWidth())); - int max_h = (int)(screen->h * 0.6); + int max_w = (int)(screen->w - (screen->w * CFG_getGameArtWidth())); + int max_h = (int)(screen->h * 0.6); int new_w = max_w; - int new_h = max_h; + int new_h = max_h; if(exists(thumbpath)) { ox = (int)(max_w) - SCALE1(BUTTON_MARGIN*5); had_thumb = 1; @@ -3004,11 +3004,11 @@ int main (int argc, char *argv[]) { // buttons if (show_setting && !GetHDMI()) GFX_blitHardwareHints(screen, show_setting); else if (can_resume) GFX_blitButtonGroup((char*[]){ "X","RESUME", NULL }, 0, screen, 0); - else GFX_blitButtonGroup((char*[]){ + else GFX_blitButtonGroup((char*[]){ BTN_SLEEP==BTN_POWER?"POWER":"MENU", - BTN_SLEEP==BTN_POWER||simple_mode?"SLEEP":"INFO", + BTN_SLEEP==BTN_POWER||simple_mode?"SLEEP":"INFO", NULL }, 0, screen, 0); - + if (total==0) { if (stack->count>1) { GFX_blitButtonGroup((char*[]){ "B","BACK", NULL }, 0, screen, 1); @@ -3037,13 +3037,13 @@ int main (int argc, char *argv[]) { bool row_is_selected = (j == selected_row); bool row_is_top = (i == top->start); bool row_has_moved = (previous_row != selected_row || previous_depth != stack->count); - if (row_is_top && !(had_thumb)) + if (row_is_top && !(had_thumb)) available_width -= ow; trimSortingMeta(&entry_name); if (entry_unique) // Only render if a unique name exists trimSortingMeta(&entry_unique); - + char display_name[256]; int text_width = GFX_getTextWidth(font.large, entry_unique ? entry_unique : entry_name, display_name, available_width, SCALE1(BUTTON_PADDING * 2)); int max_width = MIN(available_width, text_width); @@ -3056,7 +3056,7 @@ int main (int argc, char *argv[]) { text_color = uintToColour(THEME_COLOR5_255); notext = 1; } - + SDL_LockMutex(fontMutex); SDL_Surface* text = TTF_RenderUTF8_Blended(font.large, entry_name, text_color); SDL_Surface* text_unique = TTF_RenderUTF8_Blended(font.large, display_name, COLOR_DARK_TEXT); @@ -3068,9 +3068,9 @@ int main (int argc, char *argv[]) { GFX_resetScrollText(); bool should_animate = previous_depth == stack->count; SDL_LockMutex(animMutex); - if(globalpill) { - SDL_FreeSurface(globalpill); - globalpill=NULL; + if(globalpill) { + SDL_FreeSurface(globalpill); + globalpill=NULL; } globalpill = SDL_CreateRGBSurfaceWithFormat(SDL_SWSURFACE, max_width, SCALE1(PILL_SIZE), FIXED_DEPTH, screen->format->format); GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){0,0, max_width, SCALE1(PILL_SIZE)}); @@ -3083,7 +3083,7 @@ int main (int argc, char *argv[]) { task->targetX = SCALE1(BUTTON_MARGIN); task->targetY = SCALE1(targetY+PADDING); task->targetTextY = SCALE1(PADDING + targetY) + text_offset_y; - pilltargetTextY = +screen->w; + pilltargetTextY = task->targetTextY; task->move_w = max_width; task->move_h = SCALE1(PILL_SIZE); task->frames = should_animate && CFG_getMenuAnimations() ? 3:1; @@ -3105,7 +3105,7 @@ int main (int argc, char *argv[]) { // update cpu surface here first GFX_clearLayers(LAYER_ALL); folderbgchanged=1; - + GFX_flipHidden(); GFX_animateSurface(switcherSur,0,0,0,0-screen->h,screen->w,screen->h,CFG_getMenuTransitions() ? 100:20,255,255,LAYER_BACKGROUND); animationdirection = ANIM_NONE; @@ -3114,7 +3114,7 @@ int main (int argc, char *argv[]) { if(lastScreen==SCREEN_OFF) { GFX_animateSurfaceOpacity(blackBG,0,0,screen->w,screen->h,255,0,CFG_getMenuTransitions() ? 200:20,LAYER_THUMBNAIL); } - + previous_row = selected_row; previous_depth = stack->count; } @@ -3122,13 +3122,19 @@ int main (int argc, char *argv[]) { // TODO: for some reason screen's dimensions end up being 0x0 in GFX_blitMessage... GFX_blitMessage(font.large, "Empty folder", screen, &(SDL_Rect){0,0,screen->w,screen->h}); //, NULL); } - + lastScreen = SCREEN_GAMELIST; } if(animationdirection != ANIM_NONE) { if(CFG_getMenuTransitions()) { - GFX_clearLayers(LAYER_BACKGROUND); + SDL_LockMutex(bgMutex); + if(folderbgbmp) { + GFX_drawOnLayer(folderbgbmp, 0, 0, screen->w, screen->h, 1.0f, 0, LAYER_BACKGROUND); + } else { + GFX_clearLayers(LAYER_BACKGROUND); + } + SDL_UnlockMutex(bgMutex); folderbgchanged = 1; GFX_clearLayers(LAYER_TRANSITION); GFX_flipHidden(); @@ -3149,8 +3155,9 @@ int main (int argc, char *argv[]) { if(folderbgchanged) { if(folderbgbmp) GFX_drawOnLayer(folderbgbmp,0, 0, screen->w, screen->h,1.0f,0,LAYER_BACKGROUND); - else + else { GFX_clearLayers(LAYER_BACKGROUND); + } folderbgchanged = 0; } SDL_UnlockMutex(bgMutex); @@ -3160,8 +3167,9 @@ int main (int argc, char *argv[]) { if(folderbgchanged) { if(folderbgbmp) GFX_drawOnLayer(folderbgbmp,0, 0, screen->w, screen->h,1.0f,0,LAYER_BACKGROUND); - else + else { GFX_clearLayers(LAYER_BACKGROUND); + } folderbgchanged = 0; } SDL_UnlockMutex(bgMutex); @@ -3170,11 +3178,11 @@ int main (int argc, char *argv[]) { int img_w = thumbbmp->w; int img_h = thumbbmp->h; double aspect_ratio = (double)img_h / img_w; - int max_w = (int)(screen->w * CFG_getGameArtWidth()); - int max_h = (int)(screen->h * 0.6); + int max_w = (int)(screen->w * CFG_getGameArtWidth()); + int max_h = (int)(screen->h * 0.6); int new_w = max_w; - int new_h = (int)(new_w * aspect_ratio); - + int new_h = (int)(new_w * aspect_ratio); + if (new_h > max_h) { new_h = max_h; new_w = (int)(new_h / aspect_ratio); @@ -3192,11 +3200,11 @@ int main (int argc, char *argv[]) { GFX_clearLayers(LAYER_TRANSITION); GFX_clearLayers(LAYER_SCROLLTEXT); - + SDL_LockMutex(animMutex); if (list_show_entry_names) { GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, globallpillW, globalpill->h, 1.0f, 0, LAYER_TRANSITION); - // GFX_drawOnLayer(globalText, SCALE1(PADDING+BUTTON_PADDING), pilltargetTextY, globalText->w, globalText->h, 1.0f, 0, LAYER_SCROLLTEXT); + GFX_drawOnLayer(globalText, SCALE1(PADDING+BUTTON_PADDING), pilltargetTextY, globalText->w, globalText->h, 1.0f, 0, LAYER_SCROLLTEXT); } SDL_UnlockMutex(animMutex); } @@ -3213,8 +3221,9 @@ int main (int argc, char *argv[]) { if(folderbgchanged) { if(folderbgbmp) GFX_drawOnLayer(folderbgbmp,0, 0, screen->w, screen->h,1.0f,0,LAYER_BACKGROUND); - else + else { GFX_clearLayers(LAYER_BACKGROUND); + } folderbgchanged = 0; } SDL_UnlockMutex(bgMutex); @@ -3223,18 +3232,18 @@ int main (int argc, char *argv[]) { int img_w = thumbbmp->w; int img_h = thumbbmp->h; double aspect_ratio = (double)img_h / img_w; - - int max_w = (int)(screen->w * CFG_getGameArtWidth()); - int max_h = (int)(screen->h * 0.6); - + + int max_w = (int)(screen->w * CFG_getGameArtWidth()); + int max_h = (int)(screen->h * 0.6); + int new_w = max_w; - int new_h = (int)(new_w * aspect_ratio); - + int new_h = (int)(new_w * aspect_ratio); + if (new_h > max_h) { new_h = max_h; new_w = (int)(new_h / aspect_ratio); } - + int target_x = screen->w-(new_w + SCALE1(BUTTON_MARGIN*3)); int target_y = (int)(screen->h * 0.50); int center_y = target_y - (new_h / 2); // FIX: use new_h instead of thumbbmp->h @@ -3273,7 +3282,7 @@ int main (int argc, char *argv[]) { int text_width = GFX_getTextWidth(font.large, entry_text, cached_display_name, available_width, SCALE1(BUTTON_PADDING * 2)); int max_width = MIN(available_width, text_width); int text_offset_y = (SCALE1(PILL_SIZE) - TTF_FontHeight(font.large) + 1) >> 1; - + GFX_clearLayers(LAYER_SCROLLTEXT); if (list_show_entry_names) { GFX_scrollTextTexture( @@ -3298,13 +3307,13 @@ int main (int argc, char *argv[]) { } SDL_UnlockMutex(animMutex); PLAT_GPU_Flip(); - } + } } else { GFX_sync(); } dirty = 0; - } + } else { // want to draw only if needed SDL_LockMutex(bgqueueMutex); @@ -3320,7 +3329,7 @@ int main (int argc, char *argv[]) { SDL_UnlockMutex(thumbqueueMutex); SDL_UnlockMutex(bgqueueMutex); } - + SDL_LockMutex(frameMutex); frameReady = true; SDL_CondSignal(flipCond); @@ -3344,20 +3353,20 @@ int main (int argc, char *argv[]) { quit = 1; } } - + Menu_quit(); PWR_quit(); PAD_quit(); - + // Cleanup worker threads and their synchronization primitives cleanupImageLoaderPool(); - + GFX_quit(); // Cleanup video subsystem first to stop GPU threads - + // Now safe to free surfaces after GPU threads are stopped if(blackBG) SDL_FreeSurface(blackBG); if (folderbgbmp) SDL_FreeSurface(folderbgbmp); if (thumbbmp) SDL_FreeSurface(thumbbmp); - + QuitSettings(); -} \ No newline at end of file +} diff --git a/workspace/all/settings/settings.cpp b/workspace/all/settings/settings.cpp index 5717b7790..6710e00ce 100644 --- a/workspace/all/settings/settings.cpp +++ b/workspace/all/settings/settings.cpp @@ -281,33 +281,33 @@ int main(int argc, char *argv[]) [](const std::any &value){ CFG_setFontId(std::any_cast(value)); }, []() { CFG_setFontId(CFG_DEFAULT_FONT_ID);}}, new MenuItem{ListItemType::Color, "Main Color", "The color used to render main UI elements.", colors, color_strings, - []() -> std::any{ return CFG_getColor(1); }, - [](const std::any &value){ CFG_setColor(1, std::any_cast(value)); }, - []() { CFG_setColor(1, CFG_DEFAULT_COLOR1);}}, + []() -> std::any{ return CFG_getColor(COLOR_MAIN); }, + [](const std::any &value){ CFG_setColor(COLOR_MAIN, std::any_cast(value)); }, + []() { CFG_setColor(COLOR_MAIN, CFG_DEFAULT_COLOR1);}}, new MenuItem{ListItemType::Color, "Primary Accent Color", "The color used to highlight important things in the user interface.", colors, color_strings, - []() -> std::any{ return CFG_getColor(2); }, - [](const std::any &value){ CFG_setColor(2, std::any_cast(value)); }, - []() { CFG_setColor(2, CFG_DEFAULT_COLOR2);}}, + []() -> std::any{ return CFG_getColor(COLOR_ACCENT); }, + [](const std::any &value){ CFG_setColor(COLOR_ACCENT, std::any_cast(value)); }, + []() { CFG_setColor(COLOR_ACCENT, CFG_DEFAULT_COLOR2);}}, new MenuItem{ListItemType::Color, "Secondary Accent Color", "A secondary highlight color.", colors, color_strings, - []() -> std::any{ return CFG_getColor(3); }, - [](const std::any &value){ CFG_setColor(3, std::any_cast(value)); }, - []() { CFG_setColor(3, CFG_DEFAULT_COLOR3);}}, + []() -> std::any{ return CFG_getColor(COLOR_ACCENT2); }, + [](const std::any &value){ CFG_setColor(COLOR_ACCENT2, std::any_cast(value)); }, + []() { CFG_setColor(COLOR_ACCENT2, CFG_DEFAULT_COLOR3);}}, new MenuItem{ListItemType::Color, "Hint info Color", "Color for button hints and info", colors, color_strings, - []() -> std::any{ return CFG_getColor(6); }, - [](const std::any &value){ CFG_setColor(6, std::any_cast(value)); }, - []() { CFG_setColor(6, CFG_DEFAULT_COLOR6);}}, + []() -> std::any{ return CFG_getColor(COLOR_HINT); }, + [](const std::any &value){ CFG_setColor(COLOR_HINT, std::any_cast(value)); }, + []() { CFG_setColor(COLOR_HINT, CFG_DEFAULT_COLOR6);}}, new MenuItem{ListItemType::Color, "List Text", "List text color", colors, color_strings, - []() -> std::any{ return CFG_getColor(4); }, - [](const std::any &value){ CFG_setColor(4, std::any_cast(value)); }, - []() { CFG_setColor(4, CFG_DEFAULT_COLOR4);}}, + []() -> std::any{ return CFG_getColor(COLOR_LIST_TEXT); }, + [](const std::any &value){ CFG_setColor(COLOR_LIST_TEXT, std::any_cast(value)); }, + []() { CFG_setColor(COLOR_LIST_TEXT, CFG_DEFAULT_COLOR4);}}, new MenuItem{ListItemType::Color, "List Text Selected", "List selected text color", colors, color_strings, - []() -> std::any { return CFG_getColor(5); }, - [](const std::any &value) { CFG_setColor(5, std::any_cast(value)); }, - []() { CFG_setColor(5, CFG_DEFAULT_COLOR5);}}, - //new MenuItem{ListItemType::Color, "Background color", "Main UI background color", colors, color_strings, - //[]() -> std::any { return CFG_getColor(7); }, - //[](const std::any &value) { CFG_setColor(7, std::any_cast(value)); }, - //[]() { CFG_setColor(7, CFG_DEFAULT_COLOR7);}}, + []() -> std::any { return CFG_getColor(COLOR_LIST_TEXT_SELECTED); }, + [](const std::any &value) { CFG_setColor(COLOR_LIST_TEXT_SELECTED, std::any_cast(value)); }, + []() { CFG_setColor(COLOR_LIST_TEXT_SELECTED, CFG_DEFAULT_COLOR5);}}, + new MenuItem{ListItemType::Color, "Background Color", "Background color used when no background image is set.", colors, color_strings, + []() -> std::any { return CFG_getColor(COLOR_BACKGROUND); }, + [](const std::any &value) { CFG_setColor(COLOR_BACKGROUND, std::any_cast(value)); }, + []() { CFG_setColor(COLOR_BACKGROUND, CFG_DEFAULT_COLOR7);}}, new MenuItem{ListItemType::Generic, "Show battery percentage", "Show battery level as percent in the status pill", {false, true}, on_off, []() -> std::any { return CFG_getShowBatteryPercent(); }, [](const std::any &value) { CFG_setShowBatteryPercent(std::any_cast(value)); }, @@ -595,7 +595,7 @@ int main(int argc, char *argv[]) }); } - if(deviceInfo.hasMuteToggle() && deviceInfo.hasAnalogSticks()){ + if(deviceInfo.hasMuteToggle() && !deviceInfo.hasAnalogSticks()){ muteItems.push_back( new MenuItem{ListItemType::Generic, "Dpad mode when toggled", "Dpad: default. Joystick: Dpad exclusively acts as analog stick.\nBoth: Dpad and Joystick inputs at the same time.", {0, 1, 2}, {"Dpad", "Joystick", "Both"}, []() -> std::any { @@ -852,6 +852,9 @@ int main(int argc, char *argv[]) if(bgbmp) { SDL_Rect image_rect = {0, 0, ctx.screen->w, ctx.screen->h}; SDL_BlitSurface(bgbmp, NULL, ctx.screen, &image_rect); + } else { + uint32_t bgc = CFG_getColor(COLOR_BACKGROUND); + SDL_FillRect(ctx.screen, NULL, SDL_MapRGB(ctx.screen->format, (bgc >> 16) & 0xFF, (bgc >> 8) & 0xFF, bgc & 0xFF)); } int ow = 0; From 744a8b1a406a7d1b2c0b4d1bf4a07b42749b114f Mon Sep 17 00:00:00 2001 From: "Dr. Flarp" Date: Thu, 26 Mar 2026 08:34:23 -0400 Subject: [PATCH 13/13] Revert "merge branch main into drflarp/shaders_origtexture" This reverts commit 8020fca5a2464ec6276b99e6cd731342783ada72. --- workspace/all/bootlogo/bootlogo.c | 2 +- workspace/all/clock/clock.c | 2 +- workspace/all/common/api.c | 23 +- workspace/all/common/api.h | 2 - workspace/all/common/config.c | 28 +- workspace/all/common/config.h | 18 - workspace/all/common/generic_video.c | 161 ++++----- workspace/all/ledcontrol/ledcontrol.c | 2 +- workspace/all/minarch/minarch.c | 31 +- workspace/all/nextui/nextui.c | 451 +++++++++++++------------- workspace/all/settings/settings.cpp | 49 ++- 11 files changed, 354 insertions(+), 415 deletions(-) diff --git a/workspace/all/bootlogo/bootlogo.c b/workspace/all/bootlogo/bootlogo.c index 0f153b0e4..57a36a0b3 100644 --- a/workspace/all/bootlogo/bootlogo.c +++ b/workspace/all/bootlogo/bootlogo.c @@ -91,7 +91,7 @@ int main(int argc, char *argv[]) PWR_setCPUSpeed(CPU_SPEED_MENU); - screen = GFX_init(MODE_MENU); + screen = GFX_init(MODE_MAIN); PAD_init(); PWR_init(); diff --git a/workspace/all/clock/clock.c b/workspace/all/clock/clock.c index 65534c336..38970b455 100644 --- a/workspace/all/clock/clock.c +++ b/workspace/all/clock/clock.c @@ -22,7 +22,7 @@ enum { int main(int argc , char* argv[]) { PWR_setCPUSpeed(CPU_SPEED_MENU); - SDL_Surface* screen = GFX_init(MODE_MENU); + SDL_Surface* screen = GFX_init(MODE_MAIN); PAD_init(); PWR_init(); InitSettings(); diff --git a/workspace/all/common/api.c b/workspace/all/common/api.c index f5bff9ada..1e1d179f9 100644 --- a/workspace/all/common/api.c +++ b/workspace/all/common/api.c @@ -281,14 +281,14 @@ int GFX_updateColors(void) { // We are currently micro managing all of these screen-mapped colors, // should just move this to the caller. - THEME_COLOR1 = mapUint(CFG_getColor(COLOR_MAIN)); - THEME_COLOR2 = mapUint(CFG_getColor(COLOR_ACCENT)); - THEME_COLOR3 = mapUint(CFG_getColor(COLOR_ACCENT2)); - THEME_COLOR4 = mapUint(CFG_getColor(COLOR_LIST_TEXT)); - THEME_COLOR5 = mapUint(CFG_getColor(COLOR_LIST_TEXT_SELECTED)); - THEME_COLOR6 = mapUint(CFG_getColor(COLOR_HINT)); - THEME_COLOR7 = mapUint(CFG_getColor(COLOR_BACKGROUND)); - ALT_BUTTON_TEXT_COLOR = uintToColour(CFG_getColor(COLOR_ACCENT2)); + THEME_COLOR1 = mapUint(CFG_getColor(1)); + THEME_COLOR2 = mapUint(CFG_getColor(2)); + THEME_COLOR3 = mapUint(CFG_getColor(3)); + THEME_COLOR4 = mapUint(CFG_getColor(4)); + THEME_COLOR5 = mapUint(CFG_getColor(5)); + THEME_COLOR6 = mapUint(CFG_getColor(6)); + THEME_COLOR7 = mapUint(CFG_getColor(7)); + ALT_BUTTON_TEXT_COLOR = uintToColour(CFG_getColor(3)); return 0; } @@ -308,11 +308,6 @@ SDL_Surface *GFX_init(int mode) CFG_init(GFX_loadSystemFont, GFX_updateColors); - // by default, we will clear with whatever background color the user prefers - // if MODE_MENU /e.g. minarch, clear with default black) - if(mode == MODE_MAIN) - GFX_setClearColor(mapUint(CFG_getColor(COLOR_BACKGROUND))); - // We always have to symlink, does not depend on NTP being enabled PLAT_initTimezones(); PLAT_setCurrentTimezone(PLAT_getCurrentTimezone()); @@ -1828,7 +1823,7 @@ void GFX_blitMessage(TTF_Font *font, char *msg, SDL_Surface *dst, SDL_Rect *dst_ if (len) { - text = TTF_RenderUTF8_Blended_Wrapped(font, line, uintToColour(CFG_getColor(COLOR_LIST_TEXT)), dst_rect->w); + text = TTF_RenderUTF8_Blended_Wrapped(font, line, COLOR_WHITE, dst_rect->w); int x = dst_rect->x; x += (dst_rect->w - text->w) / 2; SDL_BlitSurface(text, NULL, dst, &(SDL_Rect){x, y}); diff --git a/workspace/all/common/api.h b/workspace/all/common/api.h index 1cef108f1..3d5bdf097 100644 --- a/workspace/all/common/api.h +++ b/workspace/all/common/api.h @@ -279,7 +279,6 @@ SDL_Surface* GFX_init(int mode); #define GFX_scrollTextTexture PLAT_scrollTextTexture // (TTF_Font* font, const char* in_name,int x, int y, int w, int h, SDL_Color color, float transparency, SDL_mutex* fontMutex); #define GFX_flipHidden PLAT_flipHidden //(void) #define GFX_GL_screenCapture PLAT_GL_screenCapture //(void) -#define GFX_setClearColor PLAT_setClearColor //(uint32_t color) void GFX_setMode(int mode); int GFX_hdmiChanged(void); @@ -660,7 +659,6 @@ void PLAT_flip(SDL_Surface* screen, int sync); void PLAT_GL_Swap(); void GFX_GL_Swap(); unsigned char* PLAT_GL_screenCapture(int* outWidth, int* outHeight); -void PLAT_setClearColor(uint32_t color); void PLAT_GPU_Flip(); void PLAT_setShaders(int nr); void PLAT_resetShaders(); diff --git a/workspace/all/common/config.c b/workspace/all/common/config.c index 368464b94..f47c4e32d 100644 --- a/workspace/all/common/config.c +++ b/workspace/all/common/config.c @@ -401,13 +401,13 @@ void CFG_init(FontLoad_callback_t cb, ColorSet_callback_t ccb) } // load gfx related stuff until we drop the indirection - CFG_setColor(1, CFG_getColor(COLOR_MAIN)); - CFG_setColor(2, CFG_getColor(COLOR_ACCENT)); - CFG_setColor(3, CFG_getColor(COLOR_ACCENT2)); - CFG_setColor(4, CFG_getColor(COLOR_LIST_TEXT)); - CFG_setColor(5, CFG_getColor(COLOR_LIST_TEXT_SELECTED)); - CFG_setColor(6, CFG_getColor(COLOR_HINT)); - CFG_setColor(7, CFG_getColor(COLOR_BACKGROUND)); + CFG_setColor(1, CFG_getColor(1)); + CFG_setColor(2, CFG_getColor(2)); + CFG_setColor(3, CFG_getColor(3)); + CFG_setColor(4, CFG_getColor(4)); + CFG_setColor(5, CFG_getColor(5)); + CFG_setColor(6, CFG_getColor(6)); + CFG_setColor(7, CFG_getColor(7)); // avoid reloading the font if not neccessary if (!fontLoaded) CFG_setFontId(CFG_getFontId()); @@ -1024,31 +1024,31 @@ void CFG_get(const char *key, char *value) } else if (strcmp(key, "color1") == 0) { - sprintf(value, "\"0x%06X\"", CFG_getColor(COLOR_MAIN)); + sprintf(value, "\"0x%06X\"", CFG_getColor(1)); } else if (strcmp(key, "color2") == 0) { - sprintf(value, "\"0x%06X\"", CFG_getColor(COLOR_ACCENT)); + sprintf(value, "\"0x%06X\"", CFG_getColor(2)); } else if (strcmp(key, "color3") == 0) { - sprintf(value, "\"0x%06X\"", CFG_getColor(COLOR_ACCENT2)); + sprintf(value, "\"0x%06X\"", CFG_getColor(3)); } else if (strcmp(key, "color4") == 0) { - sprintf(value, "\"0x%06X\"", CFG_getColor(COLOR_LIST_TEXT)); + sprintf(value, "\"0x%06X\"", CFG_getColor(4)); } else if (strcmp(key, "color5") == 0) { - sprintf(value, "\"0x%06X\"", CFG_getColor(COLOR_LIST_TEXT_SELECTED)); + sprintf(value, "\"0x%06X\"", CFG_getColor(5)); } else if (strcmp(key, "color6") == 0) { - sprintf(value, "\"0x%06X\"", CFG_getColor(COLOR_HINT)); + sprintf(value, "\"0x%06X\"", CFG_getColor(6)); } else if (strcmp(key, "color7") == 0) { - sprintf(value, "\"0x%06X\"", CFG_getColor(COLOR_BACKGROUND)); + sprintf(value, "\"0x%06X\"", CFG_getColor(7)); } else if (strcmp(key, "radius") == 0) { diff --git a/workspace/all/common/config.h b/workspace/all/common/config.h index 3665fd8c3..56c74ffaf 100644 --- a/workspace/all/common/config.h +++ b/workspace/all/common/config.h @@ -71,17 +71,6 @@ enum { RA_SORT_COUNT }; -// Theme colors -enum { - COLOR_MAIN = 1, - COLOR_ACCENT = 2, - COLOR_ACCENT2 = 3, - COLOR_LIST_TEXT = 4, - COLOR_LIST_TEXT_SELECTED = 5, - COLOR_HINT = 6, - COLOR_BACKGROUND = 7 -}; - typedef struct { // Theme @@ -172,13 +161,6 @@ typedef struct #define CFG_DEFAULT_COLOR5 0x000000U #define CFG_DEFAULT_COLOR6 0xffffffU #define CFG_DEFAULT_COLOR7 0x000000U -#define CFG_DEFAULT_COLOR_MAIN CFG_DEFAULT_COLOR1 -#define CFG_DEFAULT_COLOR_ACCENT CFG_DEFAULT_COLOR2 -#define CFG_DEFAULT_COLOR_ACCENT2 CFG_DEFAULT_COLOR3 -#define CFG_DEFAULT_COLOR_LIST_TEXT CFG_DEFAULT_COLOR4 -#define CFG_DEFAULT_COLOR_LIST_TEXT_SELECTED CFG_DEFAULT_COLOR5 -#define CFG_DEFAULT_COLOR_HINT CFG_DEFAULT_COLOR6 -#define CFG_DEFAULT_COLOR_BACKGROUND CFG_DEFAULT_COLOR7 #define CFG_DEFAULT_THUMBRADIUS 20 // unscaled! #define CFG_DEFAULT_SHOWCLOCK false #define CFG_DEFAULT_CLOCK24H true diff --git a/workspace/all/common/generic_video.c b/workspace/all/common/generic_video.c index 79a8346d4..e2189ac27 100644 --- a/workspace/all/common/generic_video.c +++ b/workspace/all/common/generic_video.c @@ -34,17 +34,6 @@ static int reloadShaderTextures = 1; static int shaderResetRequested = 0; -static SDL_BlendMode getPremultipliedBlendMode(void) { - return SDL_ComposeCustomBlendMode( - SDL_BLENDFACTOR_ONE, - SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, - SDL_BLENDOPERATION_ADD, - SDL_BLENDFACTOR_ONE, - SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, - SDL_BLENDOPERATION_ADD - ); -} - // shader stuff typedef struct ShaderProgram { @@ -133,13 +122,12 @@ static struct VID_Context { SDL_Texture* overlay; SDL_Surface* screen; SDL_GLContext gl_context; - + GFX_Renderer* blit; // yeesh int width; int height; int pitch; int sharpness; - uint32_t clear_color; } vid; static int device_width; @@ -272,7 +260,7 @@ GLuint link_program(GLuint vertex_shader, GLuint fragment_shader, const char* ca void* binary = malloc(binaryLength); glGetProgramBinary(program, binaryLength, NULL, &binaryFormat, binary); - mkdir(SDCARD_PATH "/.shadercache", 0755); + mkdir(SDCARD_PATH "/.shadercache", 0755); f = fopen(cache_path, "wb"); if (f) { fwrite(&binaryFormat, sizeof(GLenum), 1, f); @@ -616,7 +604,7 @@ SDL_Surface* PLAT_initVideo(void) { //SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE); SDL_InitSubSystem(SDL_INIT_VIDEO); SDL_ShowCursor(0); - + // SDL_version compiled; // SDL_version linked; // SDL_VERSION(&compiled); @@ -643,7 +631,7 @@ SDL_Surface* PLAT_initVideo(void) { // } // SDL_GetCurrentDisplayMode(0, &mode); // LOG_info("Current display mode: %ix%i (%s)\n", mode.w,mode.h, SDL_GetPixelFormatName(mode.format)); - + int w = FIXED_WIDTH; int h = FIXED_HEIGHT; int p = FIXED_PITCH; @@ -685,39 +673,33 @@ SDL_Surface* PLAT_initVideo(void) { vid.target_layer3 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET , w,h); vid.target_layer4 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET , w,h); vid.target_layer5 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET , w,h); - + vid.target = NULL; // only needed for non-native sizes - + vid.screen = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_ARGB8888); - SDL_BlendMode premult = getPremultipliedBlendMode(); SDL_SetSurfaceBlendMode(vid.screen, SDL_BLENDMODE_BLEND); - SDL_SetTextureBlendMode(vid.stream_layer1, premult); - SDL_SetTextureBlendMode(vid.target_layer2, premult); - SDL_SetTextureBlendMode(vid.target_layer3, SDL_BLENDMODE_BLEND); // straight alpha game art - SDL_SetTextureBlendMode(vid.target_layer4, premult); + SDL_SetTextureBlendMode(vid.stream_layer1, SDL_BLENDMODE_BLEND); + SDL_SetTextureBlendMode(vid.target_layer2, SDL_BLENDMODE_BLEND); + SDL_SetTextureBlendMode(vid.target_layer3, SDL_BLENDMODE_BLEND); + SDL_SetTextureBlendMode(vid.target_layer4, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(vid.target_layer5, SDL_BLENDMODE_BLEND); - + vid.width = w; vid.height = h; vid.pitch = p; - + SDL_transparentBlack = SDL_MapRGBA(vid.screen->format, 0, 0, 0, 0); - PLAT_setClearColor(SDL_transparentBlack); - + device_width = w; device_height = h; device_pitch = p; - + vid.sharpness = SHARPNESS_SOFT; - + return vid.screen; } -void PLAT_setClearColor(uint32_t color) { - vid.clear_color = color; -} - void PLAT_updateShader(int i, const char *filename, int *scale, int *filter, int *scaletype, int *srctype) { if (i < 0) { @@ -760,7 +742,7 @@ void PLAT_setShaders(int nr) { static void clearVideo(void) { for (int i=0; i<3; i++) { SDL_RenderClear(vid.renderer); - SDL_FillRect(vid.screen, NULL, vid.clear_color); + SDL_FillRect(vid.screen, NULL, SDL_transparentBlack); SDL_RenderCopy(vid.renderer, vid.stream_layer1, NULL, NULL); SDL_RenderPresent(vid.renderer); } @@ -811,7 +793,7 @@ void PLAT_clearVideo(SDL_Surface* screen) { SDL_FillRect(screen, NULL, SDL_transparentBlack); } void PLAT_clearAll(void) { - // ok honestely mixing SDL and OpenGL is really bad, but hey it works just got to sometimes clear gpu stuff and pull context back to SDL + // ok honestely mixing SDL and OpenGL is really bad, but hey it works just got to sometimes clear gpu stuff and pull context back to SDL // so yeah clear all layers and pull a flip() to make it switch back to SDL before clearing PLAT_clearLayers(0); PLAT_flip(vid.screen,0); @@ -819,8 +801,8 @@ void PLAT_clearAll(void) { PLAT_flip(vid.screen,0); // then do normal SDL clearing stuff - PLAT_clearVideo(vid.screen); - SDL_SetRenderDrawColor(vid.renderer, 0, 0, 0, 0); + PLAT_clearVideo(vid.screen); + SDL_SetRenderDrawColor(vid.renderer, 0, 0, 0, 0); SDL_RenderClear(vid.renderer); } @@ -849,9 +831,9 @@ static int hard_scale = 4; // TODO: base src size, eg. 160x144 can be 4 static void resizeVideo(int w, int h, int p) { if (w==vid.width && h==vid.height && p==vid.pitch) return; - + // TODO: minarch disables crisp (and nn upscale before linear downscale) when native, is this true? - + if (w>=device_width && h>=device_height) hard_scale = 1; // else if (h>=160) hard_scale = 2; // limits gba and up to 2x (seems sufficient for 640x480) else hard_scale = 4; @@ -860,11 +842,11 @@ static void resizeVideo(int w, int h, int p) { SDL_DestroyTexture(vid.stream_layer1); if (vid.target) SDL_DestroyTexture(vid.target); - + // SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, vid.sharpness==SHARPNESS_SOFT?"1":"0", SDL_HINT_OVERRIDE); vid.stream_layer1 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w,h); - SDL_SetTextureBlendMode(vid.stream_layer1, getPremultipliedBlendMode()); - + SDL_SetTextureBlendMode(vid.stream_layer1, SDL_BLENDMODE_BLEND); + if (vid.sharpness==SHARPNESS_CRISP) { // SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "1", SDL_HINT_OVERRIDE); vid.target = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, w * hard_scale,h * hard_scale); @@ -872,7 +854,7 @@ static void resizeVideo(int w, int h, int p) { else { vid.target = NULL; } - + vid.width = w; vid.height = h; @@ -940,9 +922,9 @@ static void updateEffect(void) { int curr_type = effect.type; int curr_color = effect.color; pthread_mutex_unlock(&video_prep_mutex); - + if (next_scale==curr_scale && next_type==curr_type && next_color==curr_color) return; // unchanged - + // Update effect state with mutex protection pthread_mutex_lock(&video_prep_mutex); int live_scale = effect.scale; @@ -955,10 +937,10 @@ static void updateEffect(void) { int effect_color = effect.color; int live_type = effect.live_type; pthread_mutex_unlock(&video_prep_mutex); - + if (effect_type==EFFECT_NONE) return; // disabled if (effect_type==live_type && effect_scale==live_scale && effect_color==live_color) return; // already loaded - + int opacity = 128; // 1 - 1/2 = 50% if (effect_type==EFFECT_LINE) { if (effect_scale<3) { @@ -1012,7 +994,7 @@ static void updateEffect(void) { } } effectUpdated = 1; - + } int screenx = 0; int screeny = 0; @@ -1023,7 +1005,7 @@ void PLAT_setOffsetX(int x) { } void PLAT_setOffsetY(int y) { if (y < 0 || y > 128) return; - screeny = y - 64; + screeny = y - 64; LOG_info("screeny: %i %i\n",screeny,y); } static int overlayUpdated=0; @@ -1036,7 +1018,7 @@ void PLAT_setOverlay(const char* filename, const char* tag) { free(overlay_path); overlay_path = NULL; } - + pthread_mutex_lock(&video_prep_mutex); overlayUpdated=1; pthread_mutex_unlock(&video_prep_mutex); @@ -1069,7 +1051,7 @@ void applyRoundedCorners(SDL_Surface* surface, SDL_Rect* rect, int radius) { SDL_Rect target = {0, 0, surface->w, surface->h}; if (rect) target = *rect; - + Uint32 transparent_black = SDL_MapRGBA(fmt, 0, 0, 0, 0); // Fully transparent black const int xBeg = target.x; @@ -1090,12 +1072,9 @@ void applyRoundedCorners(SDL_Surface* surface, SDL_Rect* rect, int radius) { void PLAT_clearLayers(int layer) { if(layer==0 || layer==1) { - uint32_t bg = vid.clear_color; SDL_SetRenderTarget(vid.renderer, vid.target_layer1); - SDL_SetRenderDrawColor(vid.renderer, (bg >> 16) & 0xFF, (bg >> 8) & 0xFF, bg & 0xFF, 255); SDL_RenderClear(vid.renderer); } - SDL_SetRenderDrawColor(vid.renderer, 0, 0, 0, 0); if(layer==0 || layer==2) { SDL_SetRenderTarget(vid.renderer, vid.target_layer2); SDL_RenderClear(vid.renderer); @@ -1117,12 +1096,12 @@ void PLAT_clearLayers(int layer) { } void PLAT_drawOnLayer(SDL_Surface *inputSurface, int x, int y, int w, int h, float brightness, bool maintainAspectRatio,int layer) { - if (!inputSurface || !vid.target_layer1 || !vid.renderer) return; + if (!inputSurface || !vid.target_layer1 || !vid.renderer) return; SDL_Texture* tempTexture = SDL_CreateTexture(vid.renderer, - SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_TARGET, - inputSurface->w, inputSurface->h); + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_TARGET, + inputSurface->w, inputSurface->h); if (!tempTexture) { LOG_error("Failed to create temporary texture: %s\n", SDL_GetError()); @@ -1163,12 +1142,12 @@ void PLAT_drawOnLayer(SDL_Surface *inputSurface, int x, int y, int w, int h, flo SDL_SetTextureColorMod(tempTexture, r, g, b); // Aspect ratio handling - SDL_Rect srcRect = { 0, 0, inputSurface->w, inputSurface->h }; - SDL_Rect dstRect = { x, y, w, h }; + SDL_Rect srcRect = { 0, 0, inputSurface->w, inputSurface->h }; + SDL_Rect dstRect = { x, y, w, h }; if (maintainAspectRatio) { float aspectRatio = (float)inputSurface->w / (float)inputSurface->h; - + if (w / (float)h > aspectRatio) { dstRect.w = (int)(h * aspectRatio); } else { @@ -1230,7 +1209,7 @@ void PLAT_animateSurface( else SDL_SetRenderTarget(vid.renderer, vid.target_layer4); - SDL_SetRenderDrawColor(vid.renderer, 0, 0, 0, 0); + SDL_SetRenderDrawColor(vid.renderer, 0, 0, 0, 0); SDL_RenderClear(vid.renderer); SDL_Rect srcRect = { 0, 0, inputSurface->w, inputSurface->h }; @@ -1249,7 +1228,7 @@ int PLAT_textShouldScroll(TTF_Font* font, const char* in_name,int max_width, SDL if (fontMutex) SDL_LockMutex(fontMutex); TTF_SizeUTF8(font, in_name, &text_width, NULL); if (fontMutex) SDL_UnlockMutex(fontMutex); - + if (text_width <= max_width) { return 0; } else { @@ -1365,7 +1344,7 @@ void PLAT_animateSurfaceOpacity( } SDL_UpdateTexture(tempTexture, NULL, inputSurface->pixels, inputSurface->pitch); - SDL_SetTextureBlendMode(tempTexture, SDL_BLENDMODE_BLEND); + SDL_SetTextureBlendMode(tempTexture, SDL_BLENDMODE_BLEND); const int fps = 60; const int frame_delay = 1000 / fps; @@ -1621,12 +1600,12 @@ void PLAT_flipHidden() { void PLAT_flip(SDL_Surface* IGNORED, int ignored) { // dont think we need this here tbh - // SDL_RenderClear(vid.renderer); + // SDL_RenderClear(vid.renderer); if (!vid.blit) { resizeVideo(device_width, device_height, FIXED_PITCH); // !!!??? SDL_UpdateTexture(vid.stream_layer1, NULL, vid.screen->pixels, vid.screen->pitch); SDL_RenderCopy(vid.renderer, vid.target_layer1, NULL, NULL); - SDL_RenderCopy(vid.renderer, vid.target_layer2, NULL, NULL); + SDL_RenderCopy(vid.renderer, vid.target_layer2, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.stream_layer1, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer3, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer4, NULL, NULL); @@ -1634,7 +1613,7 @@ void PLAT_flip(SDL_Surface* IGNORED, int ignored) { SDL_RenderPresent(vid.renderer); return; } - + // Safety check: ensure texture dimensions match blit buffer dimensions if (vid.width != vid.blit->true_w || vid.height != vid.blit->true_h) { // Texture size doesn't match buffer, clear blit and use screen buffer instead @@ -1650,7 +1629,7 @@ void PLAT_flip(SDL_Surface* IGNORED, int ignored) { SDL_RenderPresent(vid.renderer); return; } - + SDL_UpdateTexture(vid.stream_layer1, NULL, vid.blit->src, vid.blit->src_p); SDL_Texture* target = vid.stream_layer1; @@ -1659,7 +1638,7 @@ void PLAT_flip(SDL_Surface* IGNORED, int ignored) { int w = vid.blit->src_w; int h = vid.blit->src_h; if (vid.sharpness == SHARPNESS_CRISP) { - + SDL_SetRenderTarget(vid.renderer, vid.target); SDL_RenderCopy(vid.renderer, vid.stream_layer1, NULL, NULL); SDL_SetRenderTarget(vid.renderer, NULL); @@ -1674,7 +1653,7 @@ void PLAT_flip(SDL_Surface* IGNORED, int ignored) { SDL_Rect* dst_rect = &(SDL_Rect){0, 0, device_width, device_height}; setRectToAspectRatio(dst_rect); - + SDL_RenderCopy(vid.renderer, target, src_rect, dst_rect); SDL_RenderPresent(vid.renderer); @@ -1811,7 +1790,7 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, // } if(*target_texture==0) glGenTextures(1, target_texture); - glActiveTexture(GL_TEXTURE0); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, *target_texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, next_filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, next_filter); @@ -1823,7 +1802,7 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, if (fbo == 0) { glGenFramebuffers(1, &fbo); } - + // Always bind before attaching to avoid stale state after swaps glBindFramebuffer(GL_FRAMEBUFFER, fbo); @@ -1839,7 +1818,7 @@ void runShaderPass(ShaderPass * shader_pass, GLuint src_texture, if (status != GL_FRAMEBUFFER_COMPLETE) { LOG_error("Framebuffer incomplete: 0x%X\n", status); } - + } else { glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -1894,7 +1873,7 @@ int prepareFrameThread(void *data) { pthread_mutex_lock(&video_prep_mutex); int effect_updated = effectUpdated; pthread_mutex_unlock(&video_prep_mutex); - + if (effect_updated) { LOG_info("effect updated %s\n",effect_path); if(effect_path) { @@ -1904,7 +1883,7 @@ int prepareFrameThread(void *data) { converted = SDL_ConvertSurfaceFormat(tmp, SDL_PIXELFORMAT_RGBA32, 0); SDL_FreeSurface(tmp); } - + pthread_mutex_lock(&video_prep_mutex); frame_prep.loaded_effect = converted; effectUpdated = 0; @@ -1918,13 +1897,13 @@ int prepareFrameThread(void *data) { pthread_mutex_unlock(&video_prep_mutex); } } - + // Check if effect is disabled pthread_mutex_lock(&video_prep_mutex); int effect_type = effect.type; SDL_Surface* loaded_effect = frame_prep.loaded_effect; pthread_mutex_unlock(&video_prep_mutex); - + if(effect_type == EFFECT_NONE && loaded_effect != 0) { pthread_mutex_lock(&video_prep_mutex); frame_prep.loaded_effect = 0; @@ -1936,7 +1915,7 @@ int prepareFrameThread(void *data) { pthread_mutex_lock(&video_prep_mutex); int overlay_updated = overlayUpdated; pthread_mutex_unlock(&video_prep_mutex); - + if (overlay_updated) { LOG_info("overlay updated\n"); @@ -1947,7 +1926,7 @@ int prepareFrameThread(void *data) { converted = SDL_ConvertSurfaceFormat(tmp, SDL_PIXELFORMAT_RGBA32, 0); SDL_FreeSurface(tmp); } - + pthread_mutex_lock(&video_prep_mutex); frame_prep.loaded_overlay = converted; frame_prep.overlay_ready = 1; @@ -1962,7 +1941,7 @@ int prepareFrameThread(void *data) { } } - SDL_Delay(120); + SDL_Delay(120); } return 0; } @@ -1979,7 +1958,7 @@ void PLAT_GL_Swap() { if (prepare_thread == NULL) { LOG_error("Error creating background thread: %s\n", SDL_GetError()); - return; + return; } } @@ -2012,9 +1991,9 @@ void PLAT_GL_Swap() { if (orig_texture) { glDeleteTextures(1, &orig_texture); orig_texture = 0; } src_w_last = src_h_last = 0; last_w = last_h = 0; - if (effect_tex) { - glDeleteTextures(1, &effect_tex); - effect_tex = 0; + if (effect_tex) { + glDeleteTextures(1, &effect_tex); + effect_tex = 0; effect_w = effect_h = 0; // Force reload by marking as ready again if effect is active pthread_mutex_lock(&video_prep_mutex); @@ -2023,9 +2002,9 @@ void PLAT_GL_Swap() { } pthread_mutex_unlock(&video_prep_mutex); } - if (overlay_tex) { - glDeleteTextures(1, &overlay_tex); - overlay_tex = 0; + if (overlay_tex) { + glDeleteTextures(1, &overlay_tex); + overlay_tex = 0; overlay_w = overlay_h = 0; // Force reload if we had an overlay pthread_mutex_lock(&video_prep_mutex); @@ -2042,7 +2021,7 @@ void PLAT_GL_Swap() { int effect_ready = frame_prep.effect_ready; SDL_Surface* loaded_effect = frame_prep.loaded_effect; pthread_mutex_unlock(&video_prep_mutex); - + if (effect_ready) { if(loaded_effect) { if(!effect_tex) glGenTextures(1, &effect_tex); @@ -2072,7 +2051,7 @@ void PLAT_GL_Swap() { int overlay_ready = frame_prep.overlay_ready; SDL_Surface* loaded_overlay = frame_prep.loaded_overlay; pthread_mutex_unlock(&video_prep_mutex); - + if (overlay_ready) { if(loaded_overlay) { if(!overlay_tex) glGenTextures(1, &overlay_tex); @@ -2225,7 +2204,7 @@ void PLAT_GL_Swap() { s_pass_notif.srch = s_pass_notif.texh = notif.tex_h; notif.dirty = 0; } - + if (notif.tex && notif.surface) { runShaderPass( &s_pass_overlay, notif.tex, NULL, @@ -2282,7 +2261,7 @@ unsigned char* PLAT_GL_screenCapture(int* outWidth, int* outHeight) { glViewport(0, 0, device_width, device_height); GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); - + int width = viewport[2]; int height = viewport[3]; diff --git a/workspace/all/ledcontrol/ledcontrol.c b/workspace/all/ledcontrol/ledcontrol.c index b8344ba98..98759a6ce 100644 --- a/workspace/all/ledcontrol/ledcontrol.c +++ b/workspace/all/ledcontrol/ledcontrol.c @@ -227,7 +227,7 @@ int main(int argc, char *argv[]) memcpy(lightnames, default_names, sizeof(default_names)); // Copy values } - SDL_Surface* screen = GFX_init(MODE_MAIN); + SDL_Surface* screen = GFX_init(MODE_MENU); PAD_init(); PWR_init(); diff --git a/workspace/all/minarch/minarch.c b/workspace/all/minarch/minarch.c index ed2f92abd..81fc45db0 100644 --- a/workspace/all/minarch/minarch.c +++ b/workspace/all/minarch/minarch.c @@ -6971,20 +6971,9 @@ static int OptionShaders_optionChanged(MenuList* list, int i) { MenuItem* item = &list->items[y]; item->value = config.shaders.options[y].value; } - - if(i==SH_SHADERS_PRESET) { - // On shader preset change: - // Push all new shader settings to shader engine, - // compile shaders if needed, populate pragmas list + // Recursively call Config_syncShaders again for some reason + if(i==SH_SHADERS_PRESET) initShaders(); - - // Now that we have a list of shader parameters, - // re-read shader preset file to set pragma values in-menu - Config_syncShaders(item->key, item->value); - - // Push parameters to shader engine - applyShaderSettings(); - } return MENU_CALLBACK_NOP; } @@ -8865,7 +8854,7 @@ static void limitFF(void) { last_time = now; } -static void run_frame(void) { +static void Rewind_run_frame(void) { // if rewind is toggled, fast-forward toggle must stay off; fast-forward hold pauses rewind int do_rewind = (rewind_pressed || rewind_toggle) && !(rewind_toggle && ff_hold_active); if (do_rewind) { @@ -8918,8 +8907,16 @@ static void run_frame(void) { ff_paused_by_rewind_hold = 0; } - core.run(); - Rewind_push(0); + int ff_runs = 1; + if (fast_forward) { + // when "None" is selected, assume a modest 2x instead of unbounded spam + ff_runs = max_ff_speed ? max_ff_speed + 1 : 2; + } + + for (int ff_step = 0; ff_step < ff_runs; ff_step++) { + core.run(); + Rewind_push(0); + } } limitFF(); } @@ -9090,7 +9087,7 @@ int main(int argc , char* argv[]) { while (!quit) { GFX_startFrame(); - run_frame(); + Rewind_run_frame(); // Process RetroAchievements for this frame RA_doFrame(); diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index 4b943b835..c2d921059 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -69,7 +69,7 @@ static void Array_reverse(Array* self) { } } static void Array_free(Array* self) { - free(self->items); + free(self->items); free(self); } static void Array_yoink(Array* self, Array* other) { @@ -228,7 +228,7 @@ static void getUniqueName(Entry* entry, char* out_name) { char* filename = strrchr(entry->path, '/')+1; char emu_tag[256]; getEmuName(entry->path, emu_tag); - + char *tmp; strcpy(out_name, entry->name); tmp = out_name + strlen(out_name); @@ -242,7 +242,7 @@ static void getUniqueName(Entry* entry, char* out_name) { static void Directory_index(Directory* self) { int is_collection = prefixMatch(COLLECTIONS_PATH, self->path); int skip_index = exactMatch(FAUX_RECENT_PATH, self->path) || is_collection; // not alphabetized - + Hash* map = NULL; char map_path[256]; sprintf(map_path, "%s/map.txt", is_collection ? COLLECTIONS_PATH : self->path); @@ -266,7 +266,7 @@ static void Directory_index(Directory* self) { } } fclose(file); - + int resort = 0; int filter = 0; for (int i = 0; i < self->entries->count; i++) { @@ -280,7 +280,7 @@ static void Directory_index(Directory* self) { if (!filter && hide(entry->name)) filter = 1; } } - + if (filter) { Array* entries = Array_new(); for (int i = 0; i < self->entries->count; i++) { @@ -297,7 +297,7 @@ static void Directory_index(Directory* self) { if (resort) EntryArray_sort(self->entries); } } - + Entry* prior = NULL; int alpha = -1; int index = 0; @@ -311,7 +311,7 @@ static void Directory_index(Directory* self) { entry->name = strdup(alias); } } - + if (prior != NULL && exactMatch(prior->name, entry->name)) { free(prior->unique); free(entry->unique); @@ -343,7 +343,7 @@ static void Directory_index(Directory* self) { } entry->alpha = index; } - + prior = entry; } @@ -360,7 +360,7 @@ static Array* getEntries(char* path); static Directory* Directory_new(char* path, int selected) { char display_name[256]; getDisplayName(path, display_name); - + Directory* self = malloc(sizeof(Directory)); self->path = strdup(path); self->name = strdup(display_name); @@ -424,7 +424,7 @@ static Recent* Recent_new(char* path, char* alias) { char emu_name[256]; getEmuName(sd_path, emu_name); - + self->path = strdup(path); self->alias = alias ? strdup(alias) : NULL; self->available = hasEmu(emu_name); @@ -521,12 +521,12 @@ static Entry* entryFromPakName(char* pak_name) // Check in Emus sprintf(pak_path, "%s/Emus/%s.pak", PAKS_PATH, pak_name); - if(exists(pak_path)) + if(exists(pak_path)) return Entry_newNamed(pak_path, ENTRY_PAK, pak_name); // Check in platform Emus sprintf(pak_path, "%s/Emus/%s/%s.pak", SDCARD_PATH, PLATFORM, pak_name); - if(exists(pak_path)) + if(exists(pak_path)) return Entry_newNamed(pak_path, ENTRY_PAK, pak_name); return NULL; @@ -547,31 +547,31 @@ static int hasCue(char* dir_path, char* cue_path) { // NOTE: dir_path not rom_pa } static int hasM3u(char* rom_path, char* m3u_path) { // NOTE: rom_path not dir_path char* tmp; - + strcpy(m3u_path, rom_path); tmp = strrchr(m3u_path, '/') + 1; tmp[0] = '\0'; - + // path to parent directory char base_path[256]; strcpy(base_path, m3u_path); - + tmp = strrchr(m3u_path, '/'); tmp[0] = '\0'; - + // get parent directory name char dir_name[256]; tmp = strrchr(m3u_path, '/'); strcpy(dir_name, tmp); - + // dir_name is also our m3u file name - tmp = m3u_path + strlen(m3u_path); + tmp = m3u_path + strlen(m3u_path); strcpy(tmp, dir_name); // add extension tmp = m3u_path + strlen(m3u_path); strcpy(tmp, ".m3u"); - + return exists(m3u_path); } @@ -590,7 +590,7 @@ static int hasRecents(void) { Recent* recent = Recent_new(disc_path, NULL); if (recent->available) has += 1; Array_push(recents, recent); - + char parent_path[256]; strcpy(parent_path, disc_path); char* tmp = strrchr(parent_path, '/') + 1; @@ -607,9 +607,9 @@ static int hasRecents(void) { normalizeNewline(line); trimTrailingNewlines(line); if (strlen(line)==0) continue; // skip empty lines - + // LOG_info("line: %s\n", line); - + char* path = line; char* alias = NULL; char* tmp = strchr(line,'\t'); @@ -617,7 +617,7 @@ static int hasRecents(void) { tmp[0] = '\0'; alias = tmp+1; } - + char sd_path[256]; sprintf(sd_path, "%s%s", SDCARD_PATH, path); if (exists(sd_path)) { @@ -629,7 +629,7 @@ static int hasRecents(void) { strcpy(parent_path, path); char* tmp = strrchr(parent_path, '/') + 1; tmp[0] = '\0'; - + int found = 0; for (int i=0; icount; i++) { char* path = parent_paths->items[i]; @@ -639,12 +639,12 @@ static int hasRecents(void) { } } if (found) continue; - + Array_push(parent_paths, strdup(parent_path)); } - + // LOG_info("path:%s alias:%s\n", path, alias); - + Recent* recent = Recent_new(path, alias); if (recent->available) has += 1; Array_push(recents, recent); @@ -653,16 +653,16 @@ static int hasRecents(void) { } fclose(file); } - + saveRecents(); - + StringArray_free(parent_paths); return has>0; } static int hasCollections(void) { int has = 0; if (!exists(COLLECTIONS_PATH)) return has; - + DIR *dh = opendir(COLLECTIONS_PATH); struct dirent *dp; while((dp = readdir(dh)) != NULL) { @@ -679,10 +679,10 @@ static int hasRoms(char* dir_name) { char rom_path[256]; getEmuName(dir_name, emu_name); - + // check for emu pak if (!hasEmu(emu_name)) return has; - + // check for at least one non-hidden file (we're going to assume it's a rom) sprintf(rom_path, "%s/%s/", ROMS_PATH, dir_name); DIR *dh = opendir(rom_path); @@ -833,7 +833,7 @@ static Array* getQuickToggles(void) { Entry *settings = entryFromPakName("Settings"); if (settings) Array_push(entries, settings); - + Entry *store = entryFromPakName("Pak Store"); if (store) Array_push(entries, store); @@ -854,7 +854,7 @@ static Array* getQuickToggles(void) { static Array* getRoot(void) { Array* root = Array_new(); - if (hasRecents() && CFG_getShowRecents()) + if (hasRecents() && CFG_getShowRecents()) Array_push(root, Entry_new(FAUX_RECENT_PATH, ENTRY_DIR)); Array *entries = getRoms(); @@ -886,7 +886,7 @@ static Entry* entryFromRecent(Recent* recent) { if(!recent || !recent->available) return NULL; - + char sd_path[256]; sprintf(sd_path, "%s%s", SDCARD_PATH, recent->path); int type = suffixMatch(".pak", sd_path) ? ENTRY_PAK : ENTRY_ROM; // ??? @@ -918,13 +918,13 @@ static Array* getCollection(char* path) { normalizeNewline(line); trimTrailingNewlines(line); if (strlen(line)==0) continue; // skip empty lines - + char sd_path[256]; sprintf(sd_path, "%s%s", SDCARD_PATH, line); if (exists(sd_path)) { int type = suffixMatch(".pak", sd_path) ? ENTRY_PAK : ENTRY_ROM; // ??? Array_push(entries, Entry_new(sd_path, type)); - + // char emu_name[256]; // getEmuName(sd_path, emu_name); // if (hasEmu(emu_name)) { @@ -937,16 +937,16 @@ static Array* getCollection(char* path) { return entries; } static Array* getDiscs(char* path){ - + // TODO: does path have SDCARD_PATH prefix? - + Array* entries = Array_new(); - + char base_path[256]; strcpy(base_path, path); char* tmp = strrchr(base_path, '/') + 1; tmp[0] = '\0'; - + // TODO: limit number of discs supported (to 9?) FILE* file = fopen(path, "r"); if (file) { @@ -956,10 +956,10 @@ static Array* getDiscs(char* path){ normalizeNewline(line); trimTrailingNewlines(line); if (strlen(line)==0) continue; // skip empty lines - + char disc_path[256]; sprintf(disc_path, "%s%s", base_path, line); - + if (exists(disc_path)) { disc += 1; Entry* entry = Entry_new(disc_path, ENTRY_ROM); @@ -981,7 +981,7 @@ static int getFirstDisc(char* m3u_path, char* disc_path) { // based on getDiscs( strcpy(base_path, m3u_path); char* tmp = strrchr(base_path, '/') + 1; tmp[0] = '\0'; - + FILE* file = fopen(m3u_path, "r"); if (file) { char line[256]; @@ -989,9 +989,9 @@ static int getFirstDisc(char* m3u_path, char* disc_path) { // based on getDiscs( normalizeNewline(line); trimTrailingNewlines(line); if (strlen(line)==0) continue; // skip empty lines - + sprintf(disc_path, "%s%s", base_path, line); - + if (exists(disc_path)) found = 1; break; } @@ -1042,7 +1042,7 @@ static int isConsoleDir(char* path) { strcpy(parent_dir, path); tmp = strrchr(parent_dir, '/'); tmp[0] = '\0'; - + return exactMatch(parent_dir, ROMS_PATH); } @@ -1055,8 +1055,8 @@ static Array* getEntries(char* path){ char* tmp = strrchr(collated_path, '('); // 1 because we want to keep the opening parenthesis to avoid collating "Game Boy Color" and "Game Boy Advance" into "Game Boy" // but conditional so we can continue to support a bare tag name as a folder name - if (tmp) tmp[1] = '\0'; - + if (tmp) tmp[1] = '\0'; + DIR *dh = opendir(ROMS_PATH); if (dh!=NULL) { struct dirent *dp; @@ -1068,7 +1068,7 @@ static Array* getEntries(char* path){ if (hide(dp->d_name)) continue; if (dp->d_type!=DT_DIR) continue; strcpy(tmp, dp->d_name); - + if (!prefixMatch(collated_path, full_path)) continue; addEntries(entries, full_path); } @@ -1076,7 +1076,7 @@ static Array* getEntries(char* path){ } } else addEntries(entries, path); // just a subfolder - + EntryArray_sort(entries); return entries; } @@ -1132,9 +1132,9 @@ static void readyResumePath(char* rom_path, int type) { has_preview = 0; char path[256]; strcpy(path, rom_path); - + if (!prefixMatch(ROMS_PATH, path)) return; - + char auto_path[256]; if (type==ENTRY_DIR) { if (!hasCue(path, auto_path)) { // no cue? @@ -1144,7 +1144,7 @@ static void readyResumePath(char* rom_path, int type) { } strcpy(path, auto_path); // cue or m3u if one exists } - + if (!suffixMatch(".m3u", path)) { char m3u_path[256]; if (hasM3u(path, m3u_path)) { @@ -1152,14 +1152,14 @@ static void readyResumePath(char* rom_path, int type) { strcpy(path, m3u_path); } } - + char emu_name[256]; getEmuName(path, emu_name); - + char rom_file[256]; tmp = strrchr(path, '/') + 1; strcpy(rom_file, tmp); - + sprintf(slot_path, "%s/.minui/%s/%s.txt", SHARED_USERDATA_PATH, emu_name, rom_file); // /.userdata/.minui//.ext.txt can_resume = exists(slot_path); @@ -1183,32 +1183,32 @@ static int autoResume(void) { // NOTE: bypasses recents if (!exists(AUTO_RESUME_PATH)) return 0; - + char path[256]; getFile(AUTO_RESUME_PATH, path, 256); unlink(AUTO_RESUME_PATH); sync(); - + // make sure rom still exists char sd_path[256]; sprintf(sd_path, "%s%s", SDCARD_PATH, path); if (!exists(sd_path)) return 0; - + // make sure emu still exists char emu_name[256]; getEmuName(sd_path, emu_name); - + char emu_path[256]; getEmuPath(emu_name, emu_path); - + if (!exists(emu_path)) return 0; - + // putFile(LAST_PATH, FAUX_RECENT_PATH); // saveLast() will crash here because top is NULL char act[256]; sprintf(act, "gametimectl.elf start '%s'", escapeSingleQuotes(sd_path)); system(act); - + char cmd[256]; // dont escape sd_path again because it was already escaped for gametimectl and function modifies input str aswell sprintf(cmd, "'%s' '%s'", escapeSingleQuotes(emu_path), sd_path); @@ -1218,29 +1218,29 @@ static int autoResume(void) { } static void openPak(char* path) { - // NOTE: escapeSingleQuotes() modifies the passed string + // NOTE: escapeSingleQuotes() modifies the passed string // so we need to save the path before we call that // if (prefixMatch(ROMS_PATH, path)) { // addRecent(path); // } saveLast(path); - + char cmd[256]; sprintf(cmd, "'%s/launch.sh'", escapeSingleQuotes(path)); queueNext(cmd); } static void openRom(char* path, char* last) { LOG_info("openRom(%s,%s)\n", path, last); - + char sd_path[256]; strcpy(sd_path, path); - + char m3u_path[256]; int has_m3u = hasM3u(sd_path, m3u_path); - + char recent_path[256]; strcpy(recent_path, has_m3u ? m3u_path : sd_path); - + if (has_m3u && suffixMatch(".m3u", sd_path)) { getFirstDisc(m3u_path, sd_path); } @@ -1257,7 +1257,7 @@ static void openRom(char* path, char* last) { if (has_m3u) { char rom_file[256]; strcpy(rom_file, strrchr(m3u_path, '/') + 1); - + // get disc for state char disc_path_path[256]; sprintf(disc_path_path, "%s/.minui/%s/%s.%s.txt", SHARED_USERDATA_PATH, emu_name, rom_file, slot); // /.userdata/arm-480/.minui//.ext.0.txt @@ -1276,11 +1276,11 @@ static void openRom(char* path, char* last) { } } else putInt(RESUME_SLOT_PATH,8); // resume hidden default state - + char emu_path[256]; getEmuPath(emu_name, emu_path); - - // NOTE: escapeSingleQuotes() modifies the passed string + + // NOTE: escapeSingleQuotes() modifies the passed string // so we need to save the path before we call that addRecent(recent_path, recent_alias); // yiiikes saveLast(last==NULL ? sd_path : last); @@ -1447,7 +1447,7 @@ static void openDirectory(char* path, int auto_launch) { top = Directory_new(path, selected); top->start = start; top->end = end ? end : ((top->entries->countentries->count : MAIN_ROW_COUNT); - + Array_push(stack, top); } else { @@ -1507,10 +1507,10 @@ static void Entry_open(Entry* self) { if (prefixMatch(COLLECTIONS_PATH, top->path)) { char* tmp; char filename[256]; - + tmp = strrchr(self->path, '/'); if (tmp) strcpy(filename, tmp+1); - + char last_path[256]; sprintf(last_path, "%s/%s", top->path, filename); last = last_path; @@ -1546,23 +1546,23 @@ static void loadLast(void) { // call after loading root directory char last_path[256]; getFile(LAST_PATH, last_path, 256); - + char full_path[256]; strcpy(full_path, last_path); - + char* tmp; char filename[256]; tmp = strrchr(last_path, '/'); if (tmp) strcpy(filename, tmp); - + Array* last = Array_new(); while (!exactMatch(last_path, SDCARD_PATH)) { Array_push(last, strdup(last_path)); - + char* slash = strrchr(last_path, '/'); last_path[(slash-last_path)] = '\0'; } - + while (last->count>0) { char* path = Array_pop(last); if (!exactMatch(path, ROMS_PATH)) { // romsDir is effectively root as far as restoring state after a game @@ -1573,10 +1573,10 @@ static void loadLast(void) { // call after loading root directory tmp = strrchr(collated_path, '('); if (tmp) tmp[1] = '\0'; // 1 because we want to keep the opening parenthesis to avoid collating "Game Boy Color" and "Game Boy Advance" into "Game Boy" } - + for (int i=0; ientries->count; i++) { Entry* entry = top->entries->items[i]; - + // NOTE: strlen() is required for collated_path, '\0' wasn't reading as NULL for some reason if (exactMatch(entry->path, path) || (strlen(collated_path) && prefixMatch(collated_path, entry->path)) || (prefixMatch(COLLECTIONS_PATH, full_path) && suffixMatch(filename, entry->path))) { top->selected = i; @@ -1589,7 +1589,7 @@ static void loadLast(void) { // call after loading root directory } } if (last->count==0 && !exactMatch(entry->path, FAUX_RECENT_PATH) && !(!exactMatch(entry->path, COLLECTIONS_PATH) && prefixMatch(COLLECTIONS_PATH, entry->path))) break; // don't show contents of auto-launch dirs - + if (entry->type==ENTRY_DIR) { openDirectory(entry->path, 0); break; @@ -1599,7 +1599,7 @@ static void loadLast(void) { // call after loading root directory } free(path); // we took ownership when we popped it } - + StringArray_free(last); if (top->selected >= 0 && top->selected < top->entries->count) { @@ -1664,7 +1664,7 @@ typedef struct finishedTask { int targetY; int targetTextY; int move_y; - int move_w; + int move_w; int move_h; int frames; int done; @@ -1680,7 +1680,7 @@ typedef struct AnimTask { int startY; int targetY; int targetTextY; - int move_w; + int move_w; int move_h; int frames; AnimTaskCallback callback; @@ -1759,6 +1759,7 @@ static void updatePillTextSurface(const char* entry_name, int move_w, SDL_Color 0, crop_rect.w, crop_rect.h, screen->format->BitsPerPixel, screen->format->format ); if (cropped) { + SDL_SetSurfaceBlendMode(converted, SDL_BLENDMODE_NONE); SDL_BlitSurface(converted, &crop_rect, cropped, NULL); } SDL_FreeSurface(converted); @@ -1808,7 +1809,7 @@ void enqueueBGTask(LoadBackgroundTask* task) { } else { taskBGQueueHead = taskBGQueueTail = node; } - + currentBGQueueSize++; SDL_CondSignal(bgqueueCond); SDL_UnlockMutex(bgqueueMutex); @@ -1842,7 +1843,7 @@ void enqueueThumbTask(LoadBackgroundTask* task) { } else { taskThumbQueueHead = taskThumbQueueTail = node; } - + currentThumbQueueSize++; SDL_CondSignal(thumbqueueCond); SDL_UnlockMutex(thumbqueueMutex); @@ -1972,17 +1973,17 @@ void onThumbLoaded(SDL_Surface* surface) { SDL_UnlockMutex(thumbMutex); return; } - - + + thumbbmp = surface; int img_w = thumbbmp->w; int img_h = thumbbmp->h; double aspect_ratio = (double)img_h / img_w; - int max_w = (int)(screen->w * CFG_getGameArtWidth()); - int max_h = (int)(screen->h * 0.6); + int max_w = (int)(screen->w * CFG_getGameArtWidth()); + int max_h = (int)(screen->h * 0.6); int new_w = max_w; - int new_h = (int)(new_w * aspect_ratio); - + int new_h = (int)(new_w * aspect_ratio); + if (new_h > max_h) { new_h = max_h; new_w = (int)(new_h / aspect_ratio); @@ -2002,7 +2003,7 @@ int pilltargetY =0; int pilltargetTextY =0; void animcallback(finishedTask *task) { SDL_LockMutex(animMutex); - pillRect = task->dst; + pillRect = task->dst; if(pillRect.w > 0 && pillRect.h > 0) { pilltargetY = +screen->w; // move offscreen if(task->done) { @@ -2020,21 +2021,21 @@ bool pillanimdone = false; int animWorker(void* unused) { while (!SDL_AtomicGet(&workerThreadsShutdown)) { SDL_LockMutex(animqueueMutex); - while (!animTaskQueueHead && !SDL_AtomicGet(&workerThreadsShutdown)) { - SDL_CondWait(animqueueCond, animqueueMutex); - } - if (SDL_AtomicGet(&workerThreadsShutdown)) { - SDL_UnlockMutex(animqueueMutex); - break; - } - AnimTaskNode* node = animTaskQueueHead; - animTaskQueueHead = node->next; - if (!animTaskQueueHead) animTtaskQueueTail = NULL; + while (!animTaskQueueHead && !SDL_AtomicGet(&workerThreadsShutdown)) { + SDL_CondWait(animqueueCond, animqueueMutex); + } + if (SDL_AtomicGet(&workerThreadsShutdown)) { + SDL_UnlockMutex(animqueueMutex); + break; + } + AnimTaskNode* node = animTaskQueueHead; + animTaskQueueHead = node->next; + if (!animTaskQueueHead) animTtaskQueueTail = NULL; SDL_UnlockMutex(animqueueMutex); - AnimTask* task = node->task; + AnimTask* task = node->task; finishedTask* finaltask = (finishedTask*)malloc(sizeof(finishedTask)); - int total_frames = task->frames; + int total_frames = task->frames; for (int frame = 0; frame <= total_frames; frame++) { // Check for shutdown at start of each frame if (SDL_AtomicGet(&workerThreadsShutdown)) break; @@ -2044,7 +2045,7 @@ int animWorker(void* unused) { int current_x = task->startX + (int)((task->targetX - task->startX) * t); int current_y = task->startY + (int)(( task->targetY - task->startY) * t); - + SDL_Rect moveDst = { current_x, current_y, task->move_w, task->move_h }; finaltask->dst = moveDst; finaltask->entry_name = task->entry_name; @@ -2062,13 +2063,13 @@ int animWorker(void* unused) { } frameReady = false; SDL_UnlockMutex(frameMutex); - + } SDL_LockMutex(animqueueMutex); if (!animTaskQueueHead) animTtaskQueueTail = NULL; currentAnimQueueSize--; // <-- add this SDL_UnlockMutex(animqueueMutex); - + SDL_LockMutex(animMutex); pillanimdone = true; free(finaltask); @@ -2080,7 +2081,7 @@ void enqueueanmimtask(AnimTask* task) { AnimTaskNode* node = (AnimTaskNode*)malloc(sizeof(AnimTaskNode)); node->task = task; node->next = NULL; - + SDL_LockMutex(animqueueMutex); pillanimdone = false; // If queue is full, drop the oldest task (head) @@ -2122,7 +2123,7 @@ void initImageLoaderPool() { SDL_AtomicSet(&workerThreadsShutdown, 0); SDL_AtomicSet(&animationDrawAtomic, 1); SDL_AtomicSet(&needDrawAtomic, 0); - + thumbqueueMutex = SDL_CreateMutex(); bgqueueMutex = SDL_CreateMutex(); bgqueueCond = SDL_CreateCond(); @@ -2144,13 +2145,13 @@ void initImageLoaderPool() { void cleanupImageLoaderPool() { // Signal all worker threads to exit (atomic set for thread safety) SDL_AtomicSet(&workerThreadsShutdown, 1); - + // Wake up all waiting threads if (bgqueueCond) SDL_CondSignal(bgqueueCond); if (thumbqueueCond) SDL_CondSignal(thumbqueueCond); if (animqueueCond) SDL_CondSignal(animqueueCond); if (flipCond) SDL_CondSignal(flipCond); // Wake up animWorker if stuck waiting for frame flip - + // Wait for all worker threads to finish if (bgLoadThread) { SDL_WaitThread(bgLoadThread, NULL); @@ -2164,10 +2165,10 @@ void cleanupImageLoaderPool() { SDL_WaitThread(animWorkerThread, NULL); animWorkerThread = NULL; } - + // Small delay to ensure llvmpipe/OpenGL threads have completed any pending operations SDL_Delay(10); - + // Acquire and release each mutex before destroying to ensure no thread is in a critical section // This creates a memory barrier and ensures proper synchronization if (bgqueueMutex) { SDL_LockMutex(bgqueueMutex); SDL_UnlockMutex(bgqueueMutex); } @@ -2178,7 +2179,7 @@ void cleanupImageLoaderPool() { if (animMutex) { SDL_LockMutex(animMutex); SDL_UnlockMutex(animMutex); } if (frameMutex) { SDL_LockMutex(frameMutex); SDL_UnlockMutex(frameMutex); } if (fontMutex) { SDL_LockMutex(fontMutex); SDL_UnlockMutex(fontMutex); } - + // Destroy mutexes and condition variables if (bgqueueMutex) SDL_DestroyMutex(bgqueueMutex); if (thumbqueueMutex) SDL_DestroyMutex(thumbqueueMutex); @@ -2188,12 +2189,12 @@ void cleanupImageLoaderPool() { if (animMutex) SDL_DestroyMutex(animMutex); if (frameMutex) SDL_DestroyMutex(frameMutex); if (fontMutex) SDL_DestroyMutex(fontMutex); - + if (bgqueueCond) SDL_DestroyCond(bgqueueCond); if (thumbqueueCond) SDL_DestroyCond(thumbqueueCond); if (animqueueCond) SDL_DestroyCond(animqueueCond); if (flipCond) SDL_DestroyCond(flipCond); - + // Set pointers to NULL after destruction bgqueueMutex = NULL; thumbqueueMutex = NULL; @@ -2214,24 +2215,24 @@ int main (int argc, char *argv[]) { // LOG_info("time from launch to:\n"); // unsigned long main_begin = SDL_GetTicks(); // unsigned long first_draw = 0; - + if (autoResume()) return 0; // nothing to do - + simple_mode = exists(SIMPLE_MODE_PATH); LOG_info("NextUI\n"); InitSettings(); - + screen = GFX_init(MODE_MAIN); -// LOG_info("- graphics init: %lu\n", SDL_GetTicks() - main_begin); - + // LOG_info("- graphics init: %lu\n", SDL_GetTicks() - main_begin); + PAD_init(); // LOG_info("- input init: %lu\n", SDL_GetTicks() - main_begin); VIB_init(); PWR_init(); if (!HAS_POWER_BUTTON && !simple_mode) PWR_disableSleep(); // LOG_info("- power init: %lu\n", SDL_GetTicks() - main_begin); - + // start my threaded image loader :D initImageLoaderPool(); Menu_init(); @@ -2257,7 +2258,7 @@ int main (int argc, char *argv[]) { // make sure we have no running games logged as active anymore (we might be launching back into the UI here) system("gametimectl.elf stop_all"); - + GFX_setVsync(VSYNC_STRICT); PAD_reset(); @@ -2296,16 +2297,16 @@ int main (int argc, char *argv[]) { while (!quit) { GFX_startFrame(); unsigned long now = SDL_GetTicks(); - + PAD_poll(); - + int selected = top->selected; int total = top->entries->count; - + PWR_update(&dirty, &show_setting, NULL, NULL); - + int is_online = PWR_isOnline(); - if (was_online!=is_online) + if (was_online!=is_online) dirty = 1; was_online = is_online; @@ -2465,7 +2466,7 @@ int main (int argc, char *argv[]) { } else if (PAD_tappedSelect(now)) { currentScreen = SCREEN_GAMESWITCHER; - switcher_selected = 0; + switcher_selected = 0; dirty = 1; } else if (total>0) { @@ -2479,7 +2480,7 @@ int main (int argc, char *argv[]) { selected = total-1; int start = total - MAIN_ROW_COUNT; top->start = (start<0) ? 0 : start; - top->end = total; + top->end = total; } else if (selectedstart) { top->start -= 1; @@ -2532,7 +2533,7 @@ int main (int argc, char *argv[]) { } } } - + if (PAD_justRepeated(BTN_L1) && !PAD_isPressed(BTN_R1) && !PWR_ignoreSettingInput(BTN_L1, show_setting)) { // previous alpha Entry* entry = top->entries->items[selected]; int i = entry->alpha-1; @@ -2559,21 +2560,21 @@ int main (int argc, char *argv[]) { } } } - + if (selected!=top->selected) { top->selected = selected; dirty = 1; } Entry* entry = top->entries->items[top->selected]; - - if (dirty && total>0) + + if (dirty && total>0) readyResume(entry); if (total>0 && can_resume && PAD_justReleased(BTN_RESUME)) { should_resume = 1; Entry_open(entry); - + dirty = 1; } else if (total>0 && PAD_justPressed(BTN_A)) { @@ -2591,11 +2592,11 @@ int main (int argc, char *argv[]) { animationdirection = SLIDE_RIGHT; total = top->entries->count; dirty = 1; - + if (total>0) readyResume(top->entries->items[top->selected]); } } - + if(dirty) { SDL_Surface *tmpOldScreen = NULL; SDL_Surface * switcherSur = NULL; @@ -2610,9 +2611,9 @@ int main (int argc, char *argv[]) { if(lastScreen==SCREEN_GAME || lastScreen==SCREEN_OFF) { GFX_clearLayers(LAYER_ALL); } - else { + else { GFX_clearLayers(LAYER_TRANSITION); - if(lastScreen!=SCREEN_GAMELIST) + if(lastScreen!=SCREEN_GAMELIST) GFX_clearLayers(LAYER_THUMBNAIL); GFX_clearLayers(LAYER_SCROLLTEXT); GFX_clearLayers(LAYER_IDK2); @@ -2629,12 +2630,11 @@ int main (int argc, char *argv[]) { Entry *current = qm_row == 0 ? quick->items[qm_col] : quickActions->items[qm_col]; char newBgPath[MAX_PATH]; char fallbackBgPath[MAX_PATH]; - sprintf(newBgPath, SDCARD_PATH "/.media/quick_%s%s.png", current->name, !strcmp(current->name,"Wifi") && !CFG_getWifi() || // wifi or wifi_off, based on state !strcmp(current->name,"Bluetooth") && !CFG_getBluetooth() ? "_off" : ""); // bluetooth or bluetooth_off, based on state sprintf(fallbackBgPath, SDCARD_PATH "/.media/quick.png"); - + // background if(!exists(newBgPath)) strncpy(newBgPath, fallbackBgPath, sizeof(newBgPath) - 1); @@ -2643,11 +2643,11 @@ int main (int argc, char *argv[]) { strncpy(folderBgPath, newBgPath, sizeof(folderBgPath) - 1); startLoadFolderBackground(newBgPath, onBackgroundLoaded, NULL); } - + // buttons (duped and trimmed from below) if (show_setting && !GetHDMI()) GFX_blitHardwareHints(screen, show_setting); else GFX_blitButtonGroup((char*[]){ BTN_SLEEP==BTN_POWER?"POWER":"MENU","SLEEP", NULL }, 0, screen, 0); - + GFX_blitButtonGroup((char*[]){ "B","BACK", "A","OPEN", NULL }, 1, screen, 1); if(CFG_getShowQuickswitcherUI()) { @@ -2669,7 +2669,7 @@ int main (int argc, char *argv[]) { int item_size = SCALE1(MENU_ITEM_SIZE); int item_extra_y = item_space_y - item_size; int item_space_x = screen->w - SCALE1(PADDING + MENU_MARGIN_X + MENU_MARGIN_X + PADDING); - // extra left margin for the first item in order to properly center all of them in the + // extra left margin for the first item in order to properly center all of them in the // available space int item_inset_x = (item_space_x - SCALE1(qm_slots * MENU_ITEM_SIZE + (qm_slots - 1) * MENU_ITEM_MARGIN)) / 2; @@ -2693,7 +2693,7 @@ int main (int argc, char *argv[]) { item_color = THEME_COLOR1; icon_color = THEME_COLOR5; } - + GFX_blitRectColor(ASSET_STATE_BG, screen, &item_rect, item_color); char icon_path[MAX_PATH]; @@ -2702,8 +2702,8 @@ int main (int argc, char *argv[]) { if(bmp) { SDL_Surface* converted = SDL_ConvertSurfaceFormat(bmp, screen->format->format, 0); if (converted) { - SDL_FreeSurface(bmp); - bmp = converted; + SDL_FreeSurface(bmp); + bmp = converted; } } if(bmp) { @@ -2766,9 +2766,9 @@ int main (int argc, char *argv[]) { int y = item_rect.y; x += (SCALE1(PILL_SIZE) - rect.w) / 2; y += (SCALE1(PILL_SIZE) - rect.h) / 2; - + GFX_blitAssetColor(asset, NULL, screen, &(SDL_Rect){x,y}, icon_color); - + ox += item_rect.w + SCALE1(MENU_TOGGLE_MARGIN); } } @@ -2786,7 +2786,7 @@ int main (int argc, char *argv[]) { GFX_clearLayers(LAYER_ALL); ox = 0; oy = 0; - + // For all recents with resumable state (i.e. has savegame), show game switcher carousel if(recents->count > 0) { Entry *selectedEntry = entryFromRecent(recents->items[switcher_selected]); @@ -2794,7 +2794,7 @@ int main (int argc, char *argv[]) { // title pill { int max_width = screen->w - SCALE1(PADDING * 2) - ow; - + char display_name[256]; int text_width = GFX_truncateText(font.large, selectedEntry->name, display_name, max_width, SCALE1(BUTTON_PADDING*2)); max_width = MIN(max_width, text_width); @@ -2830,22 +2830,22 @@ int main (int argc, char *argv[]) { if(has_preview) { // lotta memory churn here - + SDL_Surface* bmp = IMG_Load(preview_path); SDL_Surface* raw_preview = SDL_ConvertSurfaceFormat(bmp, screen->format->format, 0); if (raw_preview) { - SDL_FreeSurface(bmp); - bmp = raw_preview; + SDL_FreeSurface(bmp); + bmp = raw_preview; } if(bmp) { int aw = screen->w; int ah = screen->h; int ax = 0; int ay = 0; - + float aspectRatio = (float)bmp->w / (float)bmp->h; float screenRatio = (float)screen->w / (float)screen->h; - + if (screenRatio > aspectRatio) { aw = (int)(screen->h * aspectRatio); ah = screen->h; @@ -2855,13 +2855,13 @@ int main (int argc, char *argv[]) { } ax = (screen->w - aw) / 2; ay = (screen->h - ah) / 2; - + if(lastScreen == SCREEN_GAME) { // need to flip once so streaming_texture1 is updated GFX_flipHidden(); GFX_animateSurfaceOpacity(bmp,0,0,screen->w,screen->h,0,255,CFG_getMenuTransitions() ? 150:20,LAYER_ALL); - } else if(lastScreen == SCREEN_GAMELIST) { - + } else if(lastScreen == SCREEN_GAMELIST) { + GFX_drawOnLayer(blackBG,0,0,screen->w,screen->h,1.0f,0,LAYER_BACKGROUND); GFX_drawOnLayer(bmp,ax,ay,aw, ah,1.0f,0,LAYER_BACKGROUND); GFX_flipHidden(); @@ -2871,19 +2871,19 @@ int main (int argc, char *argv[]) { GFX_drawOnLayer(tmpOldScreen,0,0,screen->w, screen->h,1.0f,0,LAYER_ALL); GFX_animateSurface(tmpNewScreen,0,0-screen->h,0,0,screen->w,screen->h,CFG_getMenuTransitions() ? 100:20,255,255,LAYER_BACKGROUND); SDL_FreeSurface(tmpNewScreen); - + } else if(lastScreen == SCREEN_GAMESWITCHER) { GFX_flipHidden(); GFX_drawOnLayer(blackBG,0,0,screen->w, screen->h,1.0f,0,LAYER_BACKGROUND); - if(gsanimdir == SLIDE_LEFT) + if(gsanimdir == SLIDE_LEFT) GFX_animateSurface(bmp,ax+screen->w,ay,ax,ay,aw,ah,CFG_getMenuTransitions() ? 80:20,0,255,LAYER_ALL); else if(gsanimdir == SLIDE_RIGHT) GFX_animateSurface(bmp,ax-screen->w,ay,ax,ay,aw,ah,CFG_getMenuTransitions() ? 80:20,0,255,LAYER_ALL); - + GFX_drawOnLayer(bmp,ax,ay,aw,ah,1.0f,0,LAYER_BACKGROUND); } else if(lastScreen == SCREEN_QUICKMENU) { GFX_flipHidden(); - GFX_drawOnLayer(blackBG,0,0,screen->w, screen->h,1.0f,0,LAYER_BACKGROUND); + GFX_drawOnLayer(blackBG,0,0,screen->w, screen->h,1.0f,0,LAYER_BACKGROUND); GFX_drawOnLayer(bmp,ax,ay,aw,ah,1.0f,0,LAYER_BACKGROUND); } SDL_FreeSurface(bmp); // Free after rendering @@ -2892,14 +2892,14 @@ int main (int argc, char *argv[]) { else { SDL_Rect preview_rect = {ox,oy,screen->w,screen->h}; SDL_Surface * tmpsur = SDL_CreateRGBSurfaceWithFormat(0,screen->w,screen->h,screen->format->BitsPerPixel,screen->format->format); - SDL_FillRect(tmpsur, &preview_rect, CFG_getColor(COLOR_BACKGROUND)); + SDL_FillRect(tmpsur, &preview_rect, SDL_MapRGBA(screen->format,0,0,0,255)); if(lastScreen == SCREEN_GAME) { GFX_animateSurfaceOpacity(tmpsur,0,0,screen->w,screen->h,255,0,CFG_getMenuTransitions() ? 150:20,LAYER_BACKGROUND); - } else if(lastScreen == SCREEN_GAMELIST) { + } else if(lastScreen == SCREEN_GAMELIST) { GFX_animateSurface(tmpsur,0,0-screen->h,0,0,screen->w,screen->h,CFG_getMenuTransitions() ? 100:20,255,255,LAYER_ALL); } else if(lastScreen == SCREEN_GAMESWITCHER) { GFX_flipHidden(); - if(gsanimdir == SLIDE_LEFT) + if(gsanimdir == SLIDE_LEFT) GFX_animateSurface(tmpsur,0+screen->w,0,0,0,screen->w,screen->h,CFG_getMenuTransitions() ? 80:20,0,255,LAYER_ALL); else if(gsanimdir == SLIDE_RIGHT) GFX_animateSurface(tmpsur,0-screen->w,0,0,0,screen->w,screen->h,CFG_getMenuTransitions() ? 80:20,0,255,LAYER_ALL); @@ -2915,7 +2915,7 @@ int main (int argc, char *argv[]) { GFX_blitMessage(font.large, "No Recents", screen, &preview_rect); GFX_blitButtonGroup((char*[]){ "B","BACK", NULL }, 1, screen, 1); } - + GFX_flipHidden(); if(switcherSur) SDL_FreeSurface(switcherSur); @@ -2929,22 +2929,22 @@ int main (int argc, char *argv[]) { char tmp_path[MAX_PATH]; strncpy(tmp_path, entry->path, sizeof(tmp_path) - 1); tmp_path[sizeof(tmp_path) - 1] = '\0'; - + char* res_name = strrchr(tmp_path, '/'); if (res_name) res_name++; char path_copy[1024]; strncpy(path_copy, entry->path, sizeof(path_copy) - 1); path_copy[sizeof(path_copy) - 1] = '\0'; - + char* rompath = dirname(path_copy); - + char res_copy[1024]; strncpy(res_copy, res_name, sizeof(res_copy) - 1); res_copy[sizeof(res_copy) - 1] = '\0'; - + char* dot = strrchr(res_copy, '.'); - if (dot) *dot = '\0'; + if (dot) *dot = '\0'; static int lastType = -1; @@ -2972,7 +2972,7 @@ int main (int argc, char *argv[]) { } startLoadFolderBackground(tmppath, onBackgroundLoaded, NULL); } - } + } else if(strcmp(defaultBgPath, folderBgPath) != 0 && exists(defaultBgPath)) { strncpy(folderBgPath, defaultBgPath, sizeof(folderBgPath) - 1); startLoadFolderBackground(defaultBgPath, onBackgroundLoaded, NULL); @@ -2988,10 +2988,10 @@ int main (int argc, char *argv[]) { snprintf(thumbpath, sizeof(thumbpath), "%s/.media/%s.png", rompath, res_copy); had_thumb = 0; startLoadThumb(thumbpath, onThumbLoaded, NULL); - int max_w = (int)(screen->w - (screen->w * CFG_getGameArtWidth())); - int max_h = (int)(screen->h * 0.6); + int max_w = (int)(screen->w - (screen->w * CFG_getGameArtWidth())); + int max_h = (int)(screen->h * 0.6); int new_w = max_w; - int new_h = max_h; + int new_h = max_h; if(exists(thumbpath)) { ox = (int)(max_w) - SCALE1(BUTTON_MARGIN*5); had_thumb = 1; @@ -3004,11 +3004,11 @@ int main (int argc, char *argv[]) { // buttons if (show_setting && !GetHDMI()) GFX_blitHardwareHints(screen, show_setting); else if (can_resume) GFX_blitButtonGroup((char*[]){ "X","RESUME", NULL }, 0, screen, 0); - else GFX_blitButtonGroup((char*[]){ + else GFX_blitButtonGroup((char*[]){ BTN_SLEEP==BTN_POWER?"POWER":"MENU", - BTN_SLEEP==BTN_POWER||simple_mode?"SLEEP":"INFO", + BTN_SLEEP==BTN_POWER||simple_mode?"SLEEP":"INFO", NULL }, 0, screen, 0); - + if (total==0) { if (stack->count>1) { GFX_blitButtonGroup((char*[]){ "B","BACK", NULL }, 0, screen, 1); @@ -3037,13 +3037,13 @@ int main (int argc, char *argv[]) { bool row_is_selected = (j == selected_row); bool row_is_top = (i == top->start); bool row_has_moved = (previous_row != selected_row || previous_depth != stack->count); - if (row_is_top && !(had_thumb)) + if (row_is_top && !(had_thumb)) available_width -= ow; trimSortingMeta(&entry_name); if (entry_unique) // Only render if a unique name exists trimSortingMeta(&entry_unique); - + char display_name[256]; int text_width = GFX_getTextWidth(font.large, entry_unique ? entry_unique : entry_name, display_name, available_width, SCALE1(BUTTON_PADDING * 2)); int max_width = MIN(available_width, text_width); @@ -3056,7 +3056,7 @@ int main (int argc, char *argv[]) { text_color = uintToColour(THEME_COLOR5_255); notext = 1; } - + SDL_LockMutex(fontMutex); SDL_Surface* text = TTF_RenderUTF8_Blended(font.large, entry_name, text_color); SDL_Surface* text_unique = TTF_RenderUTF8_Blended(font.large, display_name, COLOR_DARK_TEXT); @@ -3068,9 +3068,9 @@ int main (int argc, char *argv[]) { GFX_resetScrollText(); bool should_animate = previous_depth == stack->count; SDL_LockMutex(animMutex); - if(globalpill) { - SDL_FreeSurface(globalpill); - globalpill=NULL; + if(globalpill) { + SDL_FreeSurface(globalpill); + globalpill=NULL; } globalpill = SDL_CreateRGBSurfaceWithFormat(SDL_SWSURFACE, max_width, SCALE1(PILL_SIZE), FIXED_DEPTH, screen->format->format); GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){0,0, max_width, SCALE1(PILL_SIZE)}); @@ -3083,7 +3083,7 @@ int main (int argc, char *argv[]) { task->targetX = SCALE1(BUTTON_MARGIN); task->targetY = SCALE1(targetY+PADDING); task->targetTextY = SCALE1(PADDING + targetY) + text_offset_y; - pilltargetTextY = task->targetTextY; + pilltargetTextY = +screen->w; task->move_w = max_width; task->move_h = SCALE1(PILL_SIZE); task->frames = should_animate && CFG_getMenuAnimations() ? 3:1; @@ -3105,7 +3105,7 @@ int main (int argc, char *argv[]) { // update cpu surface here first GFX_clearLayers(LAYER_ALL); folderbgchanged=1; - + GFX_flipHidden(); GFX_animateSurface(switcherSur,0,0,0,0-screen->h,screen->w,screen->h,CFG_getMenuTransitions() ? 100:20,255,255,LAYER_BACKGROUND); animationdirection = ANIM_NONE; @@ -3114,7 +3114,7 @@ int main (int argc, char *argv[]) { if(lastScreen==SCREEN_OFF) { GFX_animateSurfaceOpacity(blackBG,0,0,screen->w,screen->h,255,0,CFG_getMenuTransitions() ? 200:20,LAYER_THUMBNAIL); } - + previous_row = selected_row; previous_depth = stack->count; } @@ -3122,19 +3122,13 @@ int main (int argc, char *argv[]) { // TODO: for some reason screen's dimensions end up being 0x0 in GFX_blitMessage... GFX_blitMessage(font.large, "Empty folder", screen, &(SDL_Rect){0,0,screen->w,screen->h}); //, NULL); } - + lastScreen = SCREEN_GAMELIST; } if(animationdirection != ANIM_NONE) { if(CFG_getMenuTransitions()) { - SDL_LockMutex(bgMutex); - if(folderbgbmp) { - GFX_drawOnLayer(folderbgbmp, 0, 0, screen->w, screen->h, 1.0f, 0, LAYER_BACKGROUND); - } else { - GFX_clearLayers(LAYER_BACKGROUND); - } - SDL_UnlockMutex(bgMutex); + GFX_clearLayers(LAYER_BACKGROUND); folderbgchanged = 1; GFX_clearLayers(LAYER_TRANSITION); GFX_flipHidden(); @@ -3155,9 +3149,8 @@ int main (int argc, char *argv[]) { if(folderbgchanged) { if(folderbgbmp) GFX_drawOnLayer(folderbgbmp,0, 0, screen->w, screen->h,1.0f,0,LAYER_BACKGROUND); - else { + else GFX_clearLayers(LAYER_BACKGROUND); - } folderbgchanged = 0; } SDL_UnlockMutex(bgMutex); @@ -3167,9 +3160,8 @@ int main (int argc, char *argv[]) { if(folderbgchanged) { if(folderbgbmp) GFX_drawOnLayer(folderbgbmp,0, 0, screen->w, screen->h,1.0f,0,LAYER_BACKGROUND); - else { + else GFX_clearLayers(LAYER_BACKGROUND); - } folderbgchanged = 0; } SDL_UnlockMutex(bgMutex); @@ -3178,11 +3170,11 @@ int main (int argc, char *argv[]) { int img_w = thumbbmp->w; int img_h = thumbbmp->h; double aspect_ratio = (double)img_h / img_w; - int max_w = (int)(screen->w * CFG_getGameArtWidth()); - int max_h = (int)(screen->h * 0.6); + int max_w = (int)(screen->w * CFG_getGameArtWidth()); + int max_h = (int)(screen->h * 0.6); int new_w = max_w; - int new_h = (int)(new_w * aspect_ratio); - + int new_h = (int)(new_w * aspect_ratio); + if (new_h > max_h) { new_h = max_h; new_w = (int)(new_h / aspect_ratio); @@ -3200,11 +3192,11 @@ int main (int argc, char *argv[]) { GFX_clearLayers(LAYER_TRANSITION); GFX_clearLayers(LAYER_SCROLLTEXT); - + SDL_LockMutex(animMutex); if (list_show_entry_names) { GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, globallpillW, globalpill->h, 1.0f, 0, LAYER_TRANSITION); - GFX_drawOnLayer(globalText, SCALE1(PADDING+BUTTON_PADDING), pilltargetTextY, globalText->w, globalText->h, 1.0f, 0, LAYER_SCROLLTEXT); + // GFX_drawOnLayer(globalText, SCALE1(PADDING+BUTTON_PADDING), pilltargetTextY, globalText->w, globalText->h, 1.0f, 0, LAYER_SCROLLTEXT); } SDL_UnlockMutex(animMutex); } @@ -3221,9 +3213,8 @@ int main (int argc, char *argv[]) { if(folderbgchanged) { if(folderbgbmp) GFX_drawOnLayer(folderbgbmp,0, 0, screen->w, screen->h,1.0f,0,LAYER_BACKGROUND); - else { + else GFX_clearLayers(LAYER_BACKGROUND); - } folderbgchanged = 0; } SDL_UnlockMutex(bgMutex); @@ -3232,18 +3223,18 @@ int main (int argc, char *argv[]) { int img_w = thumbbmp->w; int img_h = thumbbmp->h; double aspect_ratio = (double)img_h / img_w; - - int max_w = (int)(screen->w * CFG_getGameArtWidth()); - int max_h = (int)(screen->h * 0.6); - + + int max_w = (int)(screen->w * CFG_getGameArtWidth()); + int max_h = (int)(screen->h * 0.6); + int new_w = max_w; - int new_h = (int)(new_w * aspect_ratio); - + int new_h = (int)(new_w * aspect_ratio); + if (new_h > max_h) { new_h = max_h; new_w = (int)(new_h / aspect_ratio); } - + int target_x = screen->w-(new_w + SCALE1(BUTTON_MARGIN*3)); int target_y = (int)(screen->h * 0.50); int center_y = target_y - (new_h / 2); // FIX: use new_h instead of thumbbmp->h @@ -3282,7 +3273,7 @@ int main (int argc, char *argv[]) { int text_width = GFX_getTextWidth(font.large, entry_text, cached_display_name, available_width, SCALE1(BUTTON_PADDING * 2)); int max_width = MIN(available_width, text_width); int text_offset_y = (SCALE1(PILL_SIZE) - TTF_FontHeight(font.large) + 1) >> 1; - + GFX_clearLayers(LAYER_SCROLLTEXT); if (list_show_entry_names) { GFX_scrollTextTexture( @@ -3307,13 +3298,13 @@ int main (int argc, char *argv[]) { } SDL_UnlockMutex(animMutex); PLAT_GPU_Flip(); - } + } } else { GFX_sync(); } dirty = 0; - } + } else { // want to draw only if needed SDL_LockMutex(bgqueueMutex); @@ -3329,7 +3320,7 @@ int main (int argc, char *argv[]) { SDL_UnlockMutex(thumbqueueMutex); SDL_UnlockMutex(bgqueueMutex); } - + SDL_LockMutex(frameMutex); frameReady = true; SDL_CondSignal(flipCond); @@ -3353,20 +3344,20 @@ int main (int argc, char *argv[]) { quit = 1; } } - + Menu_quit(); PWR_quit(); PAD_quit(); - + // Cleanup worker threads and their synchronization primitives cleanupImageLoaderPool(); - + GFX_quit(); // Cleanup video subsystem first to stop GPU threads - + // Now safe to free surfaces after GPU threads are stopped if(blackBG) SDL_FreeSurface(blackBG); if (folderbgbmp) SDL_FreeSurface(folderbgbmp); if (thumbbmp) SDL_FreeSurface(thumbbmp); - + QuitSettings(); -} +} \ No newline at end of file diff --git a/workspace/all/settings/settings.cpp b/workspace/all/settings/settings.cpp index 6710e00ce..5717b7790 100644 --- a/workspace/all/settings/settings.cpp +++ b/workspace/all/settings/settings.cpp @@ -281,33 +281,33 @@ int main(int argc, char *argv[]) [](const std::any &value){ CFG_setFontId(std::any_cast(value)); }, []() { CFG_setFontId(CFG_DEFAULT_FONT_ID);}}, new MenuItem{ListItemType::Color, "Main Color", "The color used to render main UI elements.", colors, color_strings, - []() -> std::any{ return CFG_getColor(COLOR_MAIN); }, - [](const std::any &value){ CFG_setColor(COLOR_MAIN, std::any_cast(value)); }, - []() { CFG_setColor(COLOR_MAIN, CFG_DEFAULT_COLOR1);}}, + []() -> std::any{ return CFG_getColor(1); }, + [](const std::any &value){ CFG_setColor(1, std::any_cast(value)); }, + []() { CFG_setColor(1, CFG_DEFAULT_COLOR1);}}, new MenuItem{ListItemType::Color, "Primary Accent Color", "The color used to highlight important things in the user interface.", colors, color_strings, - []() -> std::any{ return CFG_getColor(COLOR_ACCENT); }, - [](const std::any &value){ CFG_setColor(COLOR_ACCENT, std::any_cast(value)); }, - []() { CFG_setColor(COLOR_ACCENT, CFG_DEFAULT_COLOR2);}}, + []() -> std::any{ return CFG_getColor(2); }, + [](const std::any &value){ CFG_setColor(2, std::any_cast(value)); }, + []() { CFG_setColor(2, CFG_DEFAULT_COLOR2);}}, new MenuItem{ListItemType::Color, "Secondary Accent Color", "A secondary highlight color.", colors, color_strings, - []() -> std::any{ return CFG_getColor(COLOR_ACCENT2); }, - [](const std::any &value){ CFG_setColor(COLOR_ACCENT2, std::any_cast(value)); }, - []() { CFG_setColor(COLOR_ACCENT2, CFG_DEFAULT_COLOR3);}}, + []() -> std::any{ return CFG_getColor(3); }, + [](const std::any &value){ CFG_setColor(3, std::any_cast(value)); }, + []() { CFG_setColor(3, CFG_DEFAULT_COLOR3);}}, new MenuItem{ListItemType::Color, "Hint info Color", "Color for button hints and info", colors, color_strings, - []() -> std::any{ return CFG_getColor(COLOR_HINT); }, - [](const std::any &value){ CFG_setColor(COLOR_HINT, std::any_cast(value)); }, - []() { CFG_setColor(COLOR_HINT, CFG_DEFAULT_COLOR6);}}, + []() -> std::any{ return CFG_getColor(6); }, + [](const std::any &value){ CFG_setColor(6, std::any_cast(value)); }, + []() { CFG_setColor(6, CFG_DEFAULT_COLOR6);}}, new MenuItem{ListItemType::Color, "List Text", "List text color", colors, color_strings, - []() -> std::any{ return CFG_getColor(COLOR_LIST_TEXT); }, - [](const std::any &value){ CFG_setColor(COLOR_LIST_TEXT, std::any_cast(value)); }, - []() { CFG_setColor(COLOR_LIST_TEXT, CFG_DEFAULT_COLOR4);}}, + []() -> std::any{ return CFG_getColor(4); }, + [](const std::any &value){ CFG_setColor(4, std::any_cast(value)); }, + []() { CFG_setColor(4, CFG_DEFAULT_COLOR4);}}, new MenuItem{ListItemType::Color, "List Text Selected", "List selected text color", colors, color_strings, - []() -> std::any { return CFG_getColor(COLOR_LIST_TEXT_SELECTED); }, - [](const std::any &value) { CFG_setColor(COLOR_LIST_TEXT_SELECTED, std::any_cast(value)); }, - []() { CFG_setColor(COLOR_LIST_TEXT_SELECTED, CFG_DEFAULT_COLOR5);}}, - new MenuItem{ListItemType::Color, "Background Color", "Background color used when no background image is set.", colors, color_strings, - []() -> std::any { return CFG_getColor(COLOR_BACKGROUND); }, - [](const std::any &value) { CFG_setColor(COLOR_BACKGROUND, std::any_cast(value)); }, - []() { CFG_setColor(COLOR_BACKGROUND, CFG_DEFAULT_COLOR7);}}, + []() -> std::any { return CFG_getColor(5); }, + [](const std::any &value) { CFG_setColor(5, std::any_cast(value)); }, + []() { CFG_setColor(5, CFG_DEFAULT_COLOR5);}}, + //new MenuItem{ListItemType::Color, "Background color", "Main UI background color", colors, color_strings, + //[]() -> std::any { return CFG_getColor(7); }, + //[](const std::any &value) { CFG_setColor(7, std::any_cast(value)); }, + //[]() { CFG_setColor(7, CFG_DEFAULT_COLOR7);}}, new MenuItem{ListItemType::Generic, "Show battery percentage", "Show battery level as percent in the status pill", {false, true}, on_off, []() -> std::any { return CFG_getShowBatteryPercent(); }, [](const std::any &value) { CFG_setShowBatteryPercent(std::any_cast(value)); }, @@ -595,7 +595,7 @@ int main(int argc, char *argv[]) }); } - if(deviceInfo.hasMuteToggle() && !deviceInfo.hasAnalogSticks()){ + if(deviceInfo.hasMuteToggle() && deviceInfo.hasAnalogSticks()){ muteItems.push_back( new MenuItem{ListItemType::Generic, "Dpad mode when toggled", "Dpad: default. Joystick: Dpad exclusively acts as analog stick.\nBoth: Dpad and Joystick inputs at the same time.", {0, 1, 2}, {"Dpad", "Joystick", "Both"}, []() -> std::any { @@ -852,9 +852,6 @@ int main(int argc, char *argv[]) if(bgbmp) { SDL_Rect image_rect = {0, 0, ctx.screen->w, ctx.screen->h}; SDL_BlitSurface(bgbmp, NULL, ctx.screen, &image_rect); - } else { - uint32_t bgc = CFG_getColor(COLOR_BACKGROUND); - SDL_FillRect(ctx.screen, NULL, SDL_MapRGB(ctx.screen->format, (bgc >> 16) & 0xFF, (bgc >> 8) & 0xFF, bgc & 0xFF)); } int ow = 0;