From b800ab207355b4108daecf945b5bb5a7cd2e2ef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Valor=20Mart=C3=ADnez?= Date: Sun, 30 Jun 2024 08:14:30 +0200 Subject: [PATCH] =?UTF-8?q?Primera=20implementaci=C3=B3n=20funcional=20de?= =?UTF-8?q?=20shaders?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- data/shaders/crtpi.glsl | 234 ++++++++++++++++++++++++++++++++++++++ source/common/jshader.cpp | 229 +++++++++++++++++++++++++++++++++++++ source/common/jshader.h | 44 +++++++ source/common/screen.cpp | 54 +++++---- source/common/utils.h | 1 + source/director.cpp | 31 ++++- source/title.h | 3 - 8 files changed, 571 insertions(+), 27 deletions(-) create mode 100644 data/shaders/crtpi.glsl create mode 100644 source/common/jshader.cpp create mode 100644 source/common/jshader.h diff --git a/Makefile b/Makefile index 9b79184..a06b0f9 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ ifeq ($(OS),Windows_NT) else FixPath = $1 SOURCES := $(shell find $(DIR_SOURCES) -name '*.cpp') - CXXFLAGS:= -std=c++11 -Wall -Os -ffunction-sections -fdata-sections + CXXFLAGS:= -std=c++11 -Wall -Os -ffunction-sections -fdata-sections -framework OpenGL -Wno-deprecated LDFLAGS := -lSDL2 RM = rm -f MKD:= mkdir -p diff --git a/data/shaders/crtpi.glsl b/data/shaders/crtpi.glsl new file mode 100644 index 0000000..7739b85 --- /dev/null +++ b/data/shaders/crtpi.glsl @@ -0,0 +1,234 @@ +/* + crt-pi - A Raspberry Pi friendly CRT shader. + + Copyright (C) 2015-2016 davej + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + +Notes: + +This shader is designed to work well on Raspberry Pi GPUs (i.e. 1080P @ 60Hz on a game with a 4:3 aspect ratio). It pushes the Pi's GPU hard and enabling some features will slow it down so that it is no longer able to match 1080P @ 60Hz. You will need to overclock your Pi to the fastest setting in raspi-config to get the best results from this shader: 'Pi2' for Pi2 and 'Turbo' for original Pi and Pi Zero. Note: Pi2s are slower at running the shader than other Pis, this seems to be down to Pi2s lower maximum memory speed. Pi2s don't quite manage 1080P @ 60Hz - they drop about 1 in 1000 frames. You probably won't notice this, but if you do, try enabling FAKE_GAMMA. + +SCANLINES enables scanlines. You'll almost certainly want to use it with MULTISAMPLE to reduce moire effects. SCANLINE_WEIGHT defines how wide scanlines are (it is an inverse value so a higher number = thinner lines). SCANLINE_GAP_BRIGHTNESS defines how dark the gaps between the scan lines are. Darker gaps between scan lines make moire effects more likely. + +GAMMA enables gamma correction using the values in INPUT_GAMMA and OUTPUT_GAMMA. FAKE_GAMMA causes it to ignore the values in INPUT_GAMMA and OUTPUT_GAMMA and approximate gamma correction in a way which is faster than true gamma whilst still looking better than having none. You must have GAMMA defined to enable FAKE_GAMMA. + +CURVATURE distorts the screen by CURVATURE_X and CURVATURE_Y. Curvature slows things down a lot. + +By default the shader uses linear blending horizontally. If you find this too blury, enable SHARPER. + +BLOOM_FACTOR controls the increase in width for bright scanlines. + +MASK_TYPE defines what, if any, shadow mask to use. MASK_BRIGHTNESS defines how much the mask type darkens the screen. + +*/ + +#pragma parameter CURVATURE_X "Screen curvature - horizontal" 0.10 0.0 1.0 0.01 +#pragma parameter CURVATURE_Y "Screen curvature - vertical" 0.15 0.0 1.0 0.01 +#pragma parameter MASK_BRIGHTNESS "Mask brightness" 0.70 0.0 1.0 0.01 +#pragma parameter SCANLINE_WEIGHT "Scanline weight" 6.0 0.0 15.0 0.1 +#pragma parameter SCANLINE_GAP_BRIGHTNESS "Scanline gap brightness" 0.12 0.0 1.0 0.01 +#pragma parameter BLOOM_FACTOR "Bloom factor" 1.5 0.0 5.0 0.01 +#pragma parameter INPUT_GAMMA "Input gamma" 2.4 0.0 5.0 0.01 +#pragma parameter OUTPUT_GAMMA "Output gamma" 2.2 0.0 5.0 0.01 + +// Haven't put these as parameters as it would slow the code down. +#define SCANLINES +#define MULTISAMPLE +#define GAMMA +//#define FAKE_GAMMA +#define CURVATURE +//#define SHARPER +// MASK_TYPE: 0 = none, 1 = green/magenta, 2 = trinitron(ish) +#define MASK_TYPE 1 + + +#ifdef GL_ES +#define COMPAT_PRECISION mediump +precision mediump float; +#else +#define COMPAT_PRECISION +#endif + +#ifdef PARAMETER_UNIFORM +uniform COMPAT_PRECISION float CURVATURE_X; +uniform COMPAT_PRECISION float CURVATURE_Y; +uniform COMPAT_PRECISION float MASK_BRIGHTNESS; +uniform COMPAT_PRECISION float SCANLINE_WEIGHT; +uniform COMPAT_PRECISION float SCANLINE_GAP_BRIGHTNESS; +uniform COMPAT_PRECISION float BLOOM_FACTOR; +uniform COMPAT_PRECISION float INPUT_GAMMA; +uniform COMPAT_PRECISION float OUTPUT_GAMMA; +#else +#define CURVATURE_X 0.25 +#define CURVATURE_Y 0.45 +#define MASK_BRIGHTNESS 0.70 +#define SCANLINE_WEIGHT 6.0 +#define SCANLINE_GAP_BRIGHTNESS 0.12 +#define BLOOM_FACTOR 1.5 +#define INPUT_GAMMA 2.4 +#define OUTPUT_GAMMA 2.2 +#endif + +/* COMPATIBILITY + - GLSL compilers +*/ + +//uniform vec2 TextureSize; +#if defined(CURVATURE) +varying vec2 screenScale; +#endif +varying vec2 TEX0; +varying float filterWidth; + +#if defined(VERTEX) +//uniform mat4 MVPMatrix; +//attribute vec4 VertexCoord; +//attribute vec2 TexCoord; +//uniform vec2 InputSize; +//uniform vec2 OutputSize; + +void main() +{ +#if defined(CURVATURE) + screenScale = vec2(1.0, 1.0); //TextureSize / InputSize; +#endif + filterWidth = (768.0 / 240.0) / 3.0; + TEX0 = vec2(gl_MultiTexCoord0.x, 1.0-gl_MultiTexCoord0.y)*1.0001; + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +} +#elif defined(FRAGMENT) + +uniform sampler2D Texture; + +#if defined(CURVATURE) +vec2 Distort(vec2 coord) +{ + vec2 CURVATURE_DISTORTION = vec2(CURVATURE_X, CURVATURE_Y); + // Barrel distortion shrinks the display area a bit, this will allow us to counteract that. + vec2 barrelScale = 1.0 - (0.23 * CURVATURE_DISTORTION); + coord *= screenScale; + coord -= vec2(0.5); + float rsq = coord.x * coord.x + coord.y * coord.y; + coord += coord * (CURVATURE_DISTORTION * rsq); + coord *= barrelScale; + if (abs(coord.x) >= 0.5 || abs(coord.y) >= 0.5) + coord = vec2(-1.0); // If out of bounds, return an invalid value. + else + { + coord += vec2(0.5); + coord /= screenScale; + } + + return coord; +} +#endif + +float CalcScanLineWeight(float dist) +{ + return max(1.0-dist*dist*SCANLINE_WEIGHT, SCANLINE_GAP_BRIGHTNESS); +} + +float CalcScanLine(float dy) +{ + float scanLineWeight = CalcScanLineWeight(dy); +#if defined(MULTISAMPLE) + scanLineWeight += CalcScanLineWeight(dy-filterWidth); + scanLineWeight += CalcScanLineWeight(dy+filterWidth); + scanLineWeight *= 0.3333333; +#endif + return scanLineWeight; +} + +void main() +{ + vec2 TextureSize = vec2(320.0, 240.0); +#if defined(CURVATURE) + vec2 texcoord = Distort(TEX0); + if (texcoord.x < 0.0) + gl_FragColor = vec4(0.0); + else +#else + vec2 texcoord = TEX0; +#endif + { + vec2 texcoordInPixels = texcoord * TextureSize; +#if defined(SHARPER) + vec2 tempCoord = floor(texcoordInPixels) + 0.5; + vec2 coord = tempCoord / TextureSize; + vec2 deltas = texcoordInPixels - tempCoord; + float scanLineWeight = CalcScanLine(deltas.y); + vec2 signs = sign(deltas); + deltas.x *= 2.0; + deltas = deltas * deltas; + deltas.y = deltas.y * deltas.y; + deltas.x *= 0.5; + deltas.y *= 8.0; + deltas /= TextureSize; + deltas *= signs; + vec2 tc = coord + deltas; +#else + float tempY = floor(texcoordInPixels.y) + 0.5; + float yCoord = tempY / TextureSize.y; + float dy = texcoordInPixels.y - tempY; + float scanLineWeight = CalcScanLine(dy); + float signY = sign(dy); + dy = dy * dy; + dy = dy * dy; + dy *= 8.0; + dy /= TextureSize.y; + dy *= signY; + vec2 tc = vec2(texcoord.x, yCoord + dy); +#endif + + vec3 colour = texture2D(Texture, tc).rgb; + +#if defined(SCANLINES) +#if defined(GAMMA) +#if defined(FAKE_GAMMA) + colour = colour * colour; +#else + colour = pow(colour, vec3(INPUT_GAMMA)); +#endif +#endif + scanLineWeight *= BLOOM_FACTOR; + colour *= scanLineWeight; + +#if defined(GAMMA) +#if defined(FAKE_GAMMA) + colour = sqrt(colour); +#else + colour = pow(colour, vec3(1.0/OUTPUT_GAMMA)); +#endif +#endif +#endif +#if MASK_TYPE == 0 + gl_FragColor = vec4(colour, 1.0); +#else +#if MASK_TYPE == 1 + float whichMask = fract((gl_FragCoord.x*1.0001) * 0.5); + vec3 mask; + if (whichMask < 0.5) + mask = vec3(MASK_BRIGHTNESS, 1.0, MASK_BRIGHTNESS); + else + mask = vec3(1.0, MASK_BRIGHTNESS, 1.0); +#elif MASK_TYPE == 2 + float whichMask = fract((gl_FragCoord.x*1.0001) * 0.3333333); + vec3 mask = vec3(MASK_BRIGHTNESS, MASK_BRIGHTNESS, MASK_BRIGHTNESS); + if (whichMask < 0.3333333) + mask.x = 1.0; + else if (whichMask < 0.6666666) + mask.y = 1.0; + else + mask.z = 1.0; +#endif + + gl_FragColor = vec4(colour * mask, 1.0); +#endif + } +} +#endif diff --git a/source/common/jshader.cpp b/source/common/jshader.cpp new file mode 100644 index 0000000..06ea620 --- /dev/null +++ b/source/common/jshader.cpp @@ -0,0 +1,229 @@ +#include "jshader.h" + +#include + +#ifdef __APPLE__ +#include "CoreFoundation/CoreFoundation.h" +#include + +#if ESSENTIAL_GL_PRACTICES_SUPPORT_GL3 +#include +#else +#include +#endif //!ESSENTIAL_GL_PRACTICES_SUPPORT_GL3 +#else +#include +#include +#endif + +namespace shader +{ + SDL_Window *win = nullptr; + SDL_Renderer *renderer = nullptr; + GLuint programId = 0; + SDL_Texture* backBuffer = nullptr; + SDL_Point win_size = {640, 480}; + SDL_Point tex_size = {320, 240}; + bool usingOpenGL; + + #ifndef __APPLE__ + + // I'm avoiding the use of GLEW or some extensions handler, but that + // doesn't mean you should... + PFNGLCREATESHADERPROC glCreateShader; + PFNGLSHADERSOURCEPROC glShaderSource; + PFNGLCOMPILESHADERPROC glCompileShader; + PFNGLGETSHADERIVPROC glGetShaderiv; + PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; + PFNGLDELETESHADERPROC glDeleteShader; + PFNGLATTACHSHADERPROC glAttachShader; + PFNGLCREATEPROGRAMPROC glCreateProgram; + PFNGLLINKPROGRAMPROC glLinkProgram; + PFNGLVALIDATEPROGRAMPROC glValidateProgram; + PFNGLGETPROGRAMIVPROC glGetProgramiv; + PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; + PFNGLUSEPROGRAMPROC glUseProgram; + + bool initGLExtensions() { + glCreateShader = (PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader"); + glShaderSource = (PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource"); + glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader"); + glGetShaderiv = (PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv"); + glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog"); + glDeleteShader = (PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader"); + glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader"); + glCreateProgram = (PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram"); + glLinkProgram = (PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram"); + glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)SDL_GL_GetProcAddress("glValidateProgram"); + glGetProgramiv = (PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv"); + glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)SDL_GL_GetProcAddress("glGetProgramInfoLog"); + glUseProgram = (PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram"); + + return glCreateShader && glShaderSource && glCompileShader && glGetShaderiv && + glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram && + glLinkProgram && glValidateProgram && glGetProgramiv && glGetProgramInfoLog && + glUseProgram; + } + + #endif + + GLuint compileShader(const char* source, GLuint shaderType) { + // Create ID for shader + GLuint result = glCreateShader(shaderType); + // Add define depending on shader type + const char *sources[2] = { shaderType==GL_VERTEX_SHADER?"#define VERTEX\n":"#define FRAGMENT\n", source }; + // Define shader text + glShaderSource(result, 2, sources, NULL); + // Compile shader + glCompileShader(result); + + //Check vertex shader for errors + GLint shaderCompiled = GL_FALSE; + glGetShaderiv( result, GL_COMPILE_STATUS, &shaderCompiled ); + if( shaderCompiled != GL_TRUE ) { + std::cout << "Error en la compilación: " << result << "!" << std::endl; + GLint logLength; + glGetShaderiv(result, GL_INFO_LOG_LENGTH, &logLength); + if (logLength > 0) + { + GLchar *log = (GLchar*)malloc(logLength); + glGetShaderInfoLog(result, logLength, &logLength, log); + std::cout << "Shader compile log:" << log << std::endl; + free(log); + } + glDeleteShader(result); + result = 0; +// } else { +// std::cout << "Shader compilado correctamente. Id = " << result << std::endl; + } + return result; + } + + GLuint compileProgram(const char* vertexShaderSource, const char* fragmentShaderSource) { + GLuint programId = 0; + GLuint vtxShaderId, fragShaderId; + + programId = glCreateProgram(); + + vtxShaderId = compileShader(vertexShaderSource, GL_VERTEX_SHADER); + fragShaderId = compileShader(fragmentShaderSource?fragmentShaderSource:vertexShaderSource, GL_FRAGMENT_SHADER); + + if(vtxShaderId && fragShaderId) { + // Associate shader with program + glAttachShader(programId, vtxShaderId); + glAttachShader(programId, fragShaderId); + glLinkProgram(programId); + glValidateProgram(programId); + + // Check the status of the compile/link + GLint logLen; + glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &logLen); + if(logLen > 0) { + char* log = (char*) malloc(logLen * sizeof(char)); + // Show any errors as appropriate + glGetProgramInfoLog(programId, logLen, &logLen, log); + std::cout << "Prog Info Log: " << std::endl << log << std::endl; + free(log); + } + } + if(vtxShaderId) { + glDeleteShader(vtxShaderId); + } + if(fragShaderId) { + glDeleteShader(fragShaderId); + } + return programId; + } + + const bool init(SDL_Window* win, SDL_Texture* backBuffer, const char* vertexShader, const char* fragmentShader) + { + shader::win = win; + shader::renderer = SDL_GetRenderer(win); + shader::backBuffer = backBuffer; + SDL_GetWindowSize(win, &win_size.x, &win_size.y); + int access; + SDL_QueryTexture(backBuffer, NULL, &access, &tex_size.x, &tex_size.y); + if (access != SDL_TEXTUREACCESS_TARGET) + { + std::cout << "ERROR FATAL: La textura per al render ha de tindre SDL_TEXTUREACCESS_TARGET definit." << std::endl; + exit(1); + } + + SDL_RendererInfo rendererInfo; + SDL_GetRendererInfo(renderer, &rendererInfo); + + if(!strncmp(rendererInfo.name, "opengl", 6)) { + //std::cout << "Es OpenGL!" << std::endl; + #ifndef __APPLE__ + if (!initGLExtensions()) { + std::cout << "WARNING: No s'han pogut inicialitzar les extensions d'OpenGL!" << std::endl; + usingOpenGL = false; + return false; + } + #endif + // Compilar el shader y dejarlo listo para usar. + programId = compileProgram(vertexShader, fragmentShader); + //std::cout << "programId = " << programId << std::endl; + } else { + std::cout << "WARNING: El driver del renderer no es OpenGL." << std::endl; + usingOpenGL = false; + return false; + } + usingOpenGL = true; + return true; + } + + void render() + { + GLint oldProgramId; + // Guarrada para obtener el textureid (en driverdata->texture) + //Detach the texture + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + + SDL_SetRenderTarget(renderer, NULL); + SDL_RenderClear(renderer); + + if (usingOpenGL) { + SDL_GL_BindTexture(backBuffer, NULL, NULL); + if(programId != 0) { + glGetIntegerv(GL_CURRENT_PROGRAM,&oldProgramId); + glUseProgram(programId); + } + + GLfloat minx, miny, maxx, maxy; + GLfloat minu, maxu, minv, maxv; + + // Coordenadas de la ventana donde pintar. + minx = 0.0f; + miny = 0.0f; + maxx = tex_size.x; + maxy = tex_size.y; + + minu = 0.0f; + maxu = 1.0f; + minv = 0.0f; + maxv = 1.0f; + + glViewport(0, 0, win_size.x, win_size.y); + + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(minu, minv); + glVertex2f(minx, miny); + glTexCoord2f(maxu, minv); + glVertex2f(maxx, miny); + glTexCoord2f(minu, maxv); + glVertex2f(minx, maxy); + glTexCoord2f(maxu, maxv); + glVertex2f(maxx, maxy); + glEnd(); + SDL_GL_SwapWindow(win); + + if(programId != 0) { + glUseProgram(oldProgramId); + } + } else { + SDL_RenderCopy(renderer, backBuffer, NULL, NULL); + SDL_RenderPresent(renderer); + } + } +} diff --git a/source/common/jshader.h b/source/common/jshader.h new file mode 100644 index 0000000..556f796 --- /dev/null +++ b/source/common/jshader.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +// TIPS: +// ======================================================================= +// Abans de crear el renderer, cridar a la següent funció: +// +// SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); +// +// Aixó li diu que volem un renderer que use especificament opengl. A més, +// al crear el renderer li tenim que dir que el volem que use acceeració +// per hardware, i que soporte render a textura. Per exemple: +// +// SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | +// SDL_RENDERER_TARGETTEXTURE); +// +// Per altra part, al crear la textura tenim que definir que puga ser target +// de renderitzat (SDL_TEXTUREACCESS_TARGET), per exemple: +// +// SDL_Texture *tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, +// SDL_TEXTUREACCESS_TARGET, 320, 240); +// +// Els shaders li'ls passem com una cadena, som nosaltres els que s'encarreguem +// de carregarlos de disc, amb fopen, ifstream, jfile o el que vullgues. +// Si els tens en un std::string, passa-li-la com "cadena.c_str()". +// +// Poden ser els dos el mateix arxiu, com fa libRetro, jo desde dins ja fique +// els defines necessaris. Si es el mateix arxiu, pots no ficar el quart paràmetre. +// +// Els shaders de libRetro no funcionen directament, hi ha que fer algunes modificacions. +// +// El pintat final de la teua escena l'has de fer com si "backBuffer" fora la pantalla. +// +// Ah! una cosa mes: al compilar, en Linux afegir "-lGL", en Windows afegir "-lopengl32". +// En Mac ni idea + +namespace shader +{ + const bool init(SDL_Window* win, SDL_Texture* backBuffer, + const char* vertexShader, const char* fragmentShader=nullptr); + + void render(); +} diff --git a/source/common/screen.cpp b/source/common/screen.cpp index 1c6bc9d..94593ef 100644 --- a/source/common/screen.cpp +++ b/source/common/screen.cpp @@ -1,6 +1,9 @@ #include "screen.h" #include #include +#include "jshader.h" +#include +#include // Constructor Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options_t *options) @@ -12,8 +15,7 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options this->asset = asset; // Inicializa variables - windowWidth = 0; - windowHeight = 0; + SDL_GetRendererOutputSize(renderer, &windowWidth, &windowHeight); gameCanvasWidth = options->video.gameWidth; gameCanvasHeight = options->video.gameHeight; borderWidth = options->video.border.width * 2; @@ -72,18 +74,25 @@ void Screen::blit() // Actualiza y dibuja el efecto de flash en la pantalla doFlash(); - // Vuelve a dejar el renderizador en modo normal - SDL_SetRenderTarget(renderer, nullptr); + if (options->video.shaders) + { + shader::render(); + } + else + { + // Vuelve a dejar el renderizador en modo normal + SDL_SetRenderTarget(renderer, nullptr); - // Borra el contenido previo - SDL_SetRenderDrawColor(renderer, borderColor.r, borderColor.g, borderColor.b, 0xFF); - SDL_RenderClear(renderer); + // Borra el contenido previo + SDL_SetRenderDrawColor(renderer, borderColor.r, borderColor.g, borderColor.b, 0xFF); + SDL_RenderClear(renderer); - // Copia la textura de juego en el renderizador en la posición adecuada - SDL_RenderCopy(renderer, gameCanvas, nullptr, &dest); + // Copia la textura de juego en el renderizador en la posición adecuada + SDL_RenderCopy(renderer, gameCanvas, nullptr, &dest); - // Muestra por pantalla el renderizador - SDL_RenderPresent(renderer); + // Muestra por pantalla el renderizador + SDL_RenderPresent(renderer); + } } // Establece el modo de video @@ -170,8 +179,20 @@ void Screen::setVideoMode(int videoMode) } } + // Reinicia los shaders + if (options->video.shaders) + { + std::ifstream f(asset->get("crtpi.glsl").c_str()); + std::string source((std::istreambuf_iterator(f)), std::istreambuf_iterator()); + + shader::init(window, gameCanvas, source.c_str()); + } + // Modifica el tamaño del renderizador - SDL_RenderSetLogicalSize(renderer, windowWidth, windowHeight); + else + { + SDL_RenderSetLogicalSize(renderer, windowWidth, windowHeight); + } // Actualiza las opciones options->video.mode = videoMode; @@ -377,13 +398,6 @@ void Screen::doFlash() SDL_SetRenderTarget(renderer, temp); // Actualiza la lógica del efecto - if (flashEffect.counter < flashEffect.lenght) - { - flashEffect.counter++; - } - else - { - flashEffect.enabled = false; - } + flashEffect.counter < flashEffect.lenght ? flashEffect.counter++ : flashEffect.enabled = false; } } \ No newline at end of file diff --git a/source/common/utils.h b/source/common/utils.h index 4a79641..e0b9b1c 100644 --- a/source/common/utils.h +++ b/source/common/utils.h @@ -121,6 +121,7 @@ struct op_video_t bool integerScale; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa bool keepAspect; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa op_border_t border; // Opciones para el borde la pantalla de juego + bool shaders; // Indica si se van a usar shaders para los filtros de video }; // Estructura para las opciones de musica diff --git a/source/director.cpp b/source/director.cpp index 0636b0b..a9744d6 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -148,7 +148,6 @@ bool Director::initSDL() // Inicializa SDL if (SDL_Init(SDL_INIT_EVERYTHING) < 0) - // if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO) < 0) { if (options->console) { @@ -166,10 +165,19 @@ bool Director::initSDL() { if (options->console) { - std::cout << "Warning: Nearest texture filtering not enabled!\n"; + std::cout << "Warning: texture filtering not enabled!\n"; } } + if (options->video.shaders) + if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl")) + { + if (options->console) + { + std::cout << "Warning: opengl not enabled!\n"; + } + } + // Crea la ventana int incW = 0; int incH = 0; @@ -178,7 +186,7 @@ bool Director::initSDL() incW = options->video.border.width * 2; incH = options->video.border.height * 2; } - window = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (param->gameWidth + incW) * options->video.window.size, (param->gameHeight + incH) * options->video.window.size, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); + window = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (param->gameWidth + incW) * options->video.window.size, (param->gameHeight + incH) * options->video.window.size, 0); if (window == nullptr) { if (options->console) @@ -195,6 +203,13 @@ bool Director::initSDL() { flags = flags | SDL_RENDERER_PRESENTVSYNC; } + + // La aceleración se activa según las opciones + if (options->video.shaders) + { + flags = flags | SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE; + } + renderer = SDL_CreateRenderer(window, -1, flags); if (renderer == nullptr) @@ -270,6 +285,9 @@ bool Director::setFileList() asset->add(prefix + "/data/sound/powerball.wav", t_sound); asset->add(prefix + "/data/sound/notify.wav", t_sound); + // Shaders + asset->add(prefix + "/data/shaders/crtpi.glsl", t_data); + // Texturas asset->add(prefix + "/data/gfx/balloon1.png", t_bitmap); asset->add(prefix + "/data/gfx/balloon1.ani", t_data); @@ -404,6 +422,7 @@ void Director::initOptions() options->video.border.width = 0; options->video.border.height = 0; options->video.border.enabled = false; + options->video.shaders = true; // Opciones de audio options->audio.music.enabled = true; @@ -617,6 +636,7 @@ bool Director::saveConfigFile() file << "border.enabled=" + boolToString(options->video.border.enabled) + "\n"; file << "border.width=" + std::to_string(options->video.border.width) + "\n"; file << "border.height=" + std::to_string(options->video.border.height) + "\n"; + file << "video.shaders=" + boolToString(options->video.shaders) + "\n"; // Opciones de audio file << "\n## AUDIO\n"; @@ -807,6 +827,11 @@ bool Director::setOptions(options_t *options, std::string var, std::string value options->video.border.height = std::stoi(value); } + else if (var == "video.shaders") + { + options->video.shaders = stringToBool(value); + } + // Opciones de audio else if (var == "music.enabled") { diff --git a/source/title.h b/source/title.h index 03dcf42..c39a46a 100644 --- a/source/title.h +++ b/source/title.h @@ -38,9 +38,6 @@ private: Asset *asset; // Objeto que gestiona todos los ficheros de recursos Input *input; // Objeto para leer las entradas de teclado o mando Lang *lang; // Objeto para gestionar los textos en diferentes idiomas - Instructions *instructions; // Objeto para la sección de las instrucciones - HiScoreTable *hiScoreTable; // Objeto para mostrar las mejores puntuaciones online - Game *demoGame; // Objeto para lanzar la demo del juego SDL_Event *eventHandler; // Manejador de eventos section_t *section; // Indicador para el bucle del titulo Background *backgroundObj; // Objeto para dibujar el fondo del juego