Implementats els shaders

This commit is contained in:
2025-02-20 08:48:55 +01:00
parent cc0f050c50
commit 9cb57e2ff2
20 changed files with 957 additions and 104 deletions

View File

@@ -36,6 +36,7 @@ El joc permet tant l'ús del teclat com d'un comandament. Les tecles per a jugar
- **Tecla F1**: Disminueix la mida de la finestra. - **Tecla F1**: Disminueix la mida de la finestra.
- **Tecla F2**: Augmenta la mida de la finestra. - **Tecla F2**: Augmenta la mida de la finestra.
- **Tecla F3**: Alterna entre el mode de pantalla completa i el mode finestra. - **Tecla F3**: Alterna entre el mode de pantalla completa i el mode finestra.
- **Tecla F4**: Activa o desactiva els shaders
- **Tecla F5**: Canvia la paleta de colors del joc. - **Tecla F5**: Canvia la paleta de colors del joc.
- **Tecla B**: Activa o desactiva el marge de colors en mode finestra. - **Tecla B**: Activa o desactiva el marge de colors en mode finestra.

234
data/shaders/crtpi_192.glsl Normal file
View File

@@ -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 2
#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.05
#define CURVATURE_Y 0.1
#define MASK_BRIGHTNESS 0.80
#define SCANLINE_WEIGHT 6.0
#define SCANLINE_GAP_BRIGHTNESS 0.12
#define BLOOM_FACTOR 3.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 / 192.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(256.0, 192.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

234
data/shaders/crtpi_240.glsl Normal file
View File

@@ -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 2
#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.05
#define CURVATURE_Y 0.1
#define MASK_BRIGHTNESS 0.80
#define SCANLINE_WEIGHT 6.0
#define SCANLINE_GAP_BRIGHTNESS 0.12
#define BLOOM_FACTOR 3.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

View File

@@ -131,6 +131,7 @@ void Director::initOptions()
options->videoMode = 0; options->videoMode = 0;
options->windowSize = 3; options->windowSize = 3;
options->filter = FILTER_NEAREST; options->filter = FILTER_NEAREST;
options->shaders = false;
options->vSync = true; options->vSync = true;
options->integerScale = true; options->integerScale = true;
options->keepAspect = true; options->keepAspect = true;
@@ -373,6 +374,7 @@ bool Director::saveConfig()
file << "filter=FILTER_LINEAL\n"; file << "filter=FILTER_LINEAL\n";
} }
file << "shaders=" + boolToString(options->shaders) + "\n";
file << "vSync=" + boolToString(options->vSync) + "\n"; file << "vSync=" + boolToString(options->vSync) + "\n";
file << "integerScale=" + boolToString(options->integerScale) + "\n"; file << "integerScale=" + boolToString(options->integerScale) + "\n";
file << "keepAspect=" + boolToString(options->keepAspect) + "\n"; file << "keepAspect=" + boolToString(options->keepAspect) + "\n";
@@ -1106,6 +1108,11 @@ bool Director::setOptions(options_t *options, std::string var, std::string value
} }
} }
else if (var == "shaders")
{
options->shaders = stringToBool(value);
}
else if (var == "vSync") else if (var == "vSync")
{ {
options->vSync = stringToBool(value); options->vSync = stringToBool(value);
@@ -1262,9 +1269,10 @@ void Director::initInput()
input->bindKey(input_exit, SDL_SCANCODE_ESCAPE); input->bindKey(input_exit, SDL_SCANCODE_ESCAPE);
input->bindKey(input_window_dec_size, SDL_SCANCODE_F1); input->bindKey(input_window_dec_size, SDL_SCANCODE_F1);
input->bindKey(input_window_inc_size, SDL_SCANCODE_F2); input->bindKey(input_window_inc_size, SDL_SCANCODE_F2);
input->bindKey(input_window_fullscreen, SDL_SCANCODE_F3); input->bindKey(input_toggle_videomode, SDL_SCANCODE_F3);
input->bindKey(input_swap_palette, SDL_SCANCODE_F5); input->bindKey(input_toggle_shaders, SDL_SCANCODE_F4);
input->bindKey(input_switch_music, SDL_SCANCODE_M); input->bindKey(input_toggle_palette, SDL_SCANCODE_F5);
input->bindKey(input_toggle_music, SDL_SCANCODE_M);
input->bindKey(input_toggle_border, SDL_SCANCODE_B); input->bindKey(input_toggle_border, SDL_SCANCODE_B);
// Mando - Movimiento // Mando - Movimiento
@@ -1282,8 +1290,8 @@ void Director::initInput()
input->bindGameControllerButton(input_pause, SDL_CONTROLLER_BUTTON_START); input->bindGameControllerButton(input_pause, SDL_CONTROLLER_BUTTON_START);
input->bindGameControllerButton(input_exit, SDL_CONTROLLER_BUTTON_BACK); input->bindGameControllerButton(input_exit, SDL_CONTROLLER_BUTTON_BACK);
#endif #endif
input->bindGameControllerButton(input_swap_palette, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); input->bindGameControllerButton(input_toggle_palette, SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
input->bindGameControllerButton(input_switch_music, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); input->bindGameControllerButton(input_toggle_music, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
input->bindGameControllerButton(input_toggle_border, SDL_CONTROLLER_BUTTON_X); input->bindGameControllerButton(input_toggle_border, SDL_CONTROLLER_BUTTON_X);
} }
@@ -1300,7 +1308,7 @@ bool Director::initSDL()
bool success = true; bool success = true;
// Inicializa SDL // Inicializa SDL
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO) < 0) if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{ {
if (options->console) if (options->console)
{ {
@@ -1322,6 +1330,12 @@ bool Director::initSDL()
} }
} }
// Activa el render OpenGL
if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"))
{
std::cout << "Warning: opengl not enabled!\n";
}
// Crea la ventana // Crea la ventana
int incW = 0; int incW = 0;
int incH = 0; int incH = 0;
@@ -1331,7 +1345,7 @@ bool Director::initSDL()
incH = options->borderHeight * 2; incH = options->borderHeight * 2;
} }
window = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (options->gameWidth + incW) * options->windowSize, (options->gameHeight + incH) * options->windowSize, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); window = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (options->gameWidth + incW) * options->windowSize, (options->gameHeight + incH) * options->windowSize, SDL_WINDOW_HIDDEN);
if (window == nullptr) if (window == nullptr)
{ {
if (options->console) if (options->console)
@@ -1343,8 +1357,6 @@ bool Director::initSDL()
else else
{ {
// Crea un renderizador para la ventana. El vsync se activa en funcion de las opciones // Crea un renderizador para la ventana. El vsync se activa en funcion de las opciones
// Uint32 flags = SDL_RENDERER_SOFTWARE;
// Uint32 flags = SDL_RENDERER_ACCELERATED;
Uint32 flags = 0; Uint32 flags = 0;
if (options->vSync) if (options->vSync)
{ {
@@ -1400,6 +1412,10 @@ bool Director::setFileList()
asset->add(prefix + "/data/font/subatomic.png", t_font); asset->add(prefix + "/data/font/subatomic.png", t_font);
asset->add(prefix + "/data/font/subatomic.txt", t_font); asset->add(prefix + "/data/font/subatomic.txt", t_font);
// Shaders
asset->add(prefix + "/data/shaders/crtpi_192.glsl", t_data);
asset->add(prefix + "/data/shaders/crtpi_240.glsl", t_data);
// Datos // Datos
asset->add(prefix + "/data/input/gamecontrollerdb.txt", t_data); asset->add(prefix + "/data/input/gamecontrollerdb.txt", t_data);

View File

@@ -197,7 +197,7 @@ void EnterID::render()
text->writeDX(TXT_CENTER | TXT_COLOR, GAMECANVAS_CENTER_X, jailerIDPos, jailerID, 1, color); text->writeDX(TXT_CENTER | TXT_COLOR, GAMECANVAS_CENTER_X, jailerIDPos, jailerID, 1, color);
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
screen->blit(); screen->render();
} }
// Inicializa los textos // Inicializa los textos

View File

@@ -93,12 +93,12 @@ void Credits::checkInput()
else if (input->checkInput(input_toggle_border, REPEAT_FALSE)) else if (input->checkInput(input_toggle_border, REPEAT_FALSE))
{ {
screen->switchBorder(); screen->toggleBorder();
} }
else if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) else if (input->checkInput(input_toggle_videomode, REPEAT_FALSE))
{ {
screen->switchVideoMode(); screen->toggleVideoMode();
} }
else if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) else if (input->checkInput(input_window_dec_size, REPEAT_FALSE))
@@ -111,7 +111,7 @@ void Credits::checkInput()
screen->incWindowSize(); screen->incWindowSize();
} }
else if (input->checkInput(input_swap_palette, REPEAT_FALSE)) else if (input->checkInput(input_toggle_palette, REPEAT_FALSE))
{ {
switchPalette(); switchPalette();
} }
@@ -338,7 +338,7 @@ void Credits::render()
} }
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
screen->blit(); screen->render();
} }
// Bucle para el logo del juego // Bucle para el logo del juego

View File

@@ -87,13 +87,13 @@ void Demo::checkInput()
else if (input->checkInput(input_toggle_border, REPEAT_FALSE)) else if (input->checkInput(input_toggle_border, REPEAT_FALSE))
{ {
screen->switchBorder(); screen->toggleBorder();
reLoadTextures(); reLoadTextures();
} }
else if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) else if (input->checkInput(input_toggle_videomode, REPEAT_FALSE))
{ {
screen->switchVideoMode(); screen->toggleVideoMode();
reLoadTextures(); reLoadTextures();
} }
@@ -109,7 +109,7 @@ void Demo::checkInput()
reLoadTextures(); reLoadTextures();
} }
else if (input->checkInput(input_swap_palette, REPEAT_FALSE)) else if (input->checkInput(input_toggle_palette, REPEAT_FALSE))
{ {
switchPalette(); switchPalette();
} }
@@ -170,7 +170,7 @@ void Demo::render()
screen->renderFX(); screen->renderFX();
// Actualiza la pantalla // Actualiza la pantalla
screen->blit(); screen->render();
} }
// Escribe el nombre de la pantalla // Escribe el nombre de la pantalla

View File

@@ -140,7 +140,7 @@ void Ending::render()
// text->write(0, 0, std::to_string(counter)); // text->write(0, 0, std::to_string(counter));
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
screen->blit(); screen->render();
} }
// Comprueba el manejador de eventos // Comprueba el manejador de eventos
@@ -170,12 +170,12 @@ void Ending::checkInput()
else if (input->checkInput(input_toggle_border, REPEAT_FALSE)) else if (input->checkInput(input_toggle_border, REPEAT_FALSE))
{ {
screen->switchBorder(); screen->toggleBorder();
} }
else if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) else if (input->checkInput(input_toggle_videomode, REPEAT_FALSE))
{ {
screen->switchVideoMode(); screen->toggleVideoMode();
} }
else if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) else if (input->checkInput(input_window_dec_size, REPEAT_FALSE))
@@ -188,7 +188,7 @@ void Ending::checkInput()
screen->incWindowSize(); screen->incWindowSize();
} }
else if (input->checkInput(input_swap_palette, REPEAT_FALSE)) else if (input->checkInput(input_toggle_palette, REPEAT_FALSE))
{ {
switchPalette(); switchPalette();
} }

View File

@@ -174,7 +174,7 @@ void Ending2::render()
} }
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
screen->blit(); screen->render();
} }
// Comprueba el manejador de eventos // Comprueba el manejador de eventos
@@ -204,12 +204,12 @@ void Ending2::checkInput()
else if (input->checkInput(input_toggle_border, REPEAT_FALSE)) else if (input->checkInput(input_toggle_border, REPEAT_FALSE))
{ {
screen->switchBorder(); screen->toggleBorder();
} }
else if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) else if (input->checkInput(input_toggle_videomode, REPEAT_FALSE))
{ {
screen->switchVideoMode(); screen->toggleVideoMode();
} }
else if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) else if (input->checkInput(input_window_dec_size, REPEAT_FALSE))
@@ -222,7 +222,7 @@ void Ending2::checkInput()
screen->incWindowSize(); screen->incWindowSize();
} }
else if (input->checkInput(input_swap_palette, REPEAT_FALSE)) else if (input->checkInput(input_toggle_palette, REPEAT_FALSE))
{ {
switchPalette(); switchPalette();
} }

View File

@@ -192,7 +192,7 @@ void Game::checkInput()
section->name = SECTION_TITLE; section->name = SECTION_TITLE;
} }
else if (input->checkInput(input_switch_music, REPEAT_FALSE)) else if (input->checkInput(input_toggle_music, REPEAT_FALSE))
{ {
board.music = !board.music; board.music = !board.music;
board.music ? JA_ResumeMusic() : JA_PauseMusic(); board.music ? JA_ResumeMusic() : JA_PauseMusic();
@@ -205,16 +205,21 @@ void Game::checkInput()
else if (input->checkInput(input_toggle_border, REPEAT_FALSE)) else if (input->checkInput(input_toggle_border, REPEAT_FALSE))
{ {
screen->switchBorder(); screen->toggleBorder();
reLoadTextures(); reLoadTextures();
} }
else if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) else if (input->checkInput(input_toggle_videomode, REPEAT_FALSE))
{ {
screen->switchVideoMode(); screen->toggleVideoMode();
reLoadTextures(); reLoadTextures();
} }
else if (input->checkInput(input_toggle_shaders, REPEAT_FALSE))
{
screen->toggleShaders();
}
else if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) else if (input->checkInput(input_window_dec_size, REPEAT_FALSE))
{ {
screen->decWindowSize(); screen->decWindowSize();
@@ -227,7 +232,7 @@ void Game::checkInput()
reLoadTextures(); reLoadTextures();
} }
else if (input->checkInput(input_swap_palette, REPEAT_FALSE)) else if (input->checkInput(input_toggle_palette, REPEAT_FALSE))
{ {
switchPalette(); switchPalette();
} }
@@ -314,7 +319,7 @@ void Game::render()
#endif #endif
// Actualiza la pantalla // Actualiza la pantalla
screen->blit(); screen->render();
} }
#ifdef DEBUG #ifdef DEBUG

View File

@@ -111,7 +111,7 @@ void GameOver::render()
text->writeDX(TXT_CENTER | TXT_COLOR, GAMECANVAS_CENTER_X, y + 120, options->stats.worstNightmare, 1, color); text->writeDX(TXT_CENTER | TXT_COLOR, GAMECANVAS_CENTER_X, y + 120, options->stats.worstNightmare, 1, color);
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
screen->blit(); screen->render();
} }
// Comprueba el manejador de eventos // Comprueba el manejador de eventos
@@ -141,12 +141,12 @@ void GameOver::checkInput()
else if (input->checkInput(input_toggle_border, REPEAT_FALSE)) else if (input->checkInput(input_toggle_border, REPEAT_FALSE))
{ {
screen->switchBorder(); screen->toggleBorder();
} }
else if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) else if (input->checkInput(input_toggle_videomode, REPEAT_FALSE))
{ {
screen->switchVideoMode(); screen->toggleVideoMode();
} }
else if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) else if (input->checkInput(input_window_dec_size, REPEAT_FALSE))
@@ -159,7 +159,7 @@ void GameOver::checkInput()
screen->incWindowSize(); screen->incWindowSize();
} }
else if (input->checkInput(input_swap_palette, REPEAT_FALSE)) else if (input->checkInput(input_toggle_palette, REPEAT_FALSE))
{ {
switchPalette(); switchPalette();
} }

View File

@@ -101,12 +101,12 @@ void LoadingScreen::checkInput()
else if (input->checkInput(input_toggle_border, REPEAT_FALSE)) else if (input->checkInput(input_toggle_border, REPEAT_FALSE))
{ {
screen->switchBorder(); screen->toggleBorder();
} }
else if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) else if (input->checkInput(input_toggle_videomode, REPEAT_FALSE))
{ {
screen->switchVideoMode(); screen->toggleVideoMode();
} }
else if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) else if (input->checkInput(input_window_dec_size, REPEAT_FALSE))
@@ -119,7 +119,7 @@ void LoadingScreen::checkInput()
screen->incWindowSize(); screen->incWindowSize();
} }
else if (input->checkInput(input_swap_palette, REPEAT_FALSE)) else if (input->checkInput(input_toggle_palette, REPEAT_FALSE))
{ {
switchPalette(); switchPalette();
} }
@@ -274,7 +274,7 @@ void LoadingScreen::render()
renderLoad(); renderLoad();
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
screen->blit(); screen->render();
} }
// Bucle para el logo del juego // Bucle para el logo del juego
@@ -287,7 +287,7 @@ void LoadingScreen::run()
// Limpia la pantalla // Limpia la pantalla
screen->start(); screen->start();
screen->clean(); screen->clean();
screen->blit(); screen->render();
while (section->name == SECTION_LOADING_SCREEN) while (section->name == SECTION_LOADING_SCREEN)
{ {
@@ -354,5 +354,5 @@ void LoadingScreen::recreateLoadingScreen()
} }
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
screen->blit(); screen->render();
} }

View File

@@ -94,12 +94,12 @@ void Logo::checkInput()
else if (input->checkInput(input_toggle_border, REPEAT_FALSE)) else if (input->checkInput(input_toggle_border, REPEAT_FALSE))
{ {
screen->switchBorder(); screen->toggleBorder();
} }
else if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) else if (input->checkInput(input_toggle_videomode, REPEAT_FALSE))
{ {
screen->switchVideoMode(); screen->toggleVideoMode();
} }
else if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) else if (input->checkInput(input_window_dec_size, REPEAT_FALSE))
@@ -112,7 +112,7 @@ void Logo::checkInput()
screen->incWindowSize(); screen->incWindowSize();
} }
else if (input->checkInput(input_swap_palette, REPEAT_FALSE)) else if (input->checkInput(input_toggle_palette, REPEAT_FALSE))
{ {
switchPalette(); switchPalette();
} }
@@ -294,7 +294,7 @@ void Logo::render()
sprite2->render(); sprite2->render();
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
screen->blit(); screen->render();
} }
// Bucle para el logo del juego // Bucle para el logo del juego

View File

@@ -171,16 +171,21 @@ void Title::checkInput()
else if (input->checkInput(input_toggle_border, REPEAT_FALSE)) else if (input->checkInput(input_toggle_border, REPEAT_FALSE))
{ {
screen->switchBorder(); screen->toggleBorder();
resource->reLoadTextures(); resource->reLoadTextures();
} }
else if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) else if (input->checkInput(input_toggle_videomode, REPEAT_FALSE))
{ {
screen->switchVideoMode(); screen->toggleVideoMode();
resource->reLoadTextures(); resource->reLoadTextures();
} }
else if (input->checkInput(input_toggle_shaders, REPEAT_FALSE))
{
screen->toggleShaders();
}
else if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) else if (input->checkInput(input_window_dec_size, REPEAT_FALSE))
{ {
screen->decWindowSize(); screen->decWindowSize();
@@ -193,7 +198,7 @@ void Title::checkInput()
resource->reLoadTextures(); resource->reLoadTextures();
} }
else if (input->checkInput(input_swap_palette, REPEAT_FALSE)) else if (input->checkInput(input_toggle_palette, REPEAT_FALSE))
{ {
switchPalette(); switchPalette();
} }
@@ -326,7 +331,7 @@ void Title::render()
if (state == show_menu) if (state == show_menu)
{ {
// Dibuja la textura de fondo // Dibuja la textura de fondo
SDL_RenderCopy(renderer, bgTexture, nullptr, nullptr); SDL_RenderCopy(renderer, bgTexture, nullptr, nullptr);
// Dibuja la marquesina // Dibuja la marquesina
@@ -350,7 +355,7 @@ void Title::render()
} }
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
screen->blit(); screen->render();
} }
// Bucle para el logo del juego // Bucle para el logo del juego
@@ -438,10 +443,10 @@ void Title::fillTexture()
sprite->render(); sprite->render();
// Borra la firma // Borra la firma
//const color_t coverColor = stringToColor(options->palette, "black"); // const color_t coverColor = stringToColor(options->palette, "black");
//SDL_SetRenderDrawColor(renderer, coverColor.r, coverColor.g, coverColor.b, 0xFF); // SDL_SetRenderDrawColor(renderer, coverColor.r, coverColor.g, coverColor.b, 0xFF);
//SDL_Rect coverRect = {28, 11, 21, 5}; // SDL_Rect coverRect = {28, 11, 21, 5};
//SDL_RenderFillRect(renderer, &coverRect); // SDL_RenderFillRect(renderer, &coverRect);
// Escribe el texto en la textura // Escribe el texto en la textura
const color_t textColor = stringToColor(options->palette, "green"); const color_t textColor = stringToColor(options->palette, "green");

View File

@@ -22,12 +22,13 @@ enum inputs_e
// Inputs personalizados // Inputs personalizados
input_jump, input_jump,
input_window_fullscreen,
input_window_inc_size, input_window_inc_size,
input_window_dec_size, input_window_dec_size,
input_toggle_videomode,
input_toggle_border, input_toggle_border,
input_switch_music, input_toggle_music,
input_swap_palette, input_toggle_palette,
input_toggle_shaders,
// Input obligatorio // Input obligatorio
input_number_of_inputs input_number_of_inputs

View File

@@ -0,0 +1,251 @@
#ifndef NO_SHADERS
#include "jail_shader.h"
#include <SDL2/SDL_rect.h> // para SDL_Point
#include <stdlib.h> // para NULL, free, malloc, exit
#include <string.h> // para strncmp
#include <iostream> // para basic_ostream, char_traits, operator<<
#ifdef __APPLE__
#include "CoreFoundation/CoreFoundation.h"
#include <OpenGL/OpenGL.h>
#if ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
#include <OpenGL/gl3.h>
#else
#include <OpenGL/gl.h>
#endif //! ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
#else
#include <SDL2/SDL_opengl.h>
#endif
namespace shader
{
SDL_Window *win = nullptr;
SDL_Renderer *renderer = nullptr;
GLuint programId = 0;
SDL_Texture *backBuffer = nullptr;
SDL_Point win_size = {320 * 4, 256 * 4};
SDL_Point tex_size = {320, 256};
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);
}
}
}
#endif

View File

@@ -0,0 +1,48 @@
#ifndef NO_SHADERS
#pragma once
#include <SDL2/SDL_render.h> // para SDL_Texture
#include <SDL2/SDL_video.h> // para SDL_Window
// 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();
}
#endif

View File

@@ -1,5 +1,8 @@
#include "screen.h" #include "screen.h"
#include "jail_shader.h"
#include <string> #include <string>
#include <fstream> // Para basic_ifstream, ifstream
#include <iterator> // Para istreambuf_iterator, operator==
#include <iostream> #include <iostream>
// Constructor // Constructor
@@ -51,6 +54,9 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options
// Inicializa variables // Inicializa variables
notifyActive = false; notifyActive = false;
// Muestra la ventana
SDL_ShowWindow(window);
} }
// Destructor // Destructor
@@ -81,29 +87,19 @@ void Screen::startDrawOnBorder()
} }
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
void Screen::blit() void Screen::render()
{ {
// Vuelve a dejar el renderizador en modo normal // Renderiza sobre gameCanvas los overlays
SDL_SetRenderTarget(renderer, nullptr);
// Borra el contenido previo
// SDL_SetRenderDrawColor(renderer, borderColor.r, borderColor.g, borderColor.b, 0xFF);
// SDL_RenderClear(renderer);
// Copia la textura del borde en la ventana
if (options->borderEnabled)
{
SDL_RenderCopy(renderer, borderCanvas, nullptr, nullptr);
}
// Copia la textura de juego en la ventana en la posición adecuada
SDL_RenderCopy(renderer, gameCanvas, nullptr, &dest);
// Dibuja las notificaciones
renderNotifications(); renderNotifications();
// Muestra por pantalla el renderizador // Si está el borde activo, vuelca gameCanvas sobre borderCanvas
SDL_RenderPresent(renderer); if (options->borderEnabled)
{
gameCanvasToBorderCanvas();
}
// Muestra el contenido por pantalla
renderPresent();
} }
// Establece el modo de video // Establece el modo de video
@@ -118,9 +114,6 @@ void Screen::setVideoMode(int videoMode)
// Muestra el puntero // Muestra el puntero
SDL_ShowCursor(SDL_ENABLE); SDL_ShowCursor(SDL_ENABLE);
// Esconde la ventana
// SDL_HideWindow(window);
// Modifica el tamaño de la ventana en función del borde // Modifica el tamaño de la ventana en función del borde
if (options->borderEnabled) if (options->borderEnabled)
{ {
@@ -139,9 +132,6 @@ void Screen::setVideoMode(int videoMode)
// Modifica el tamaño de la ventana // Modifica el tamaño de la ventana
SDL_SetWindowSize(window, windowWidth * options->windowSize, windowHeight * options->windowSize); SDL_SetWindowSize(window, windowWidth * options->windowSize, windowHeight * options->windowSize);
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
// Muestra la ventana
// SDL_ShowWindow(window);
} }
// Si está activo el modo de pantalla completa añade el borde // Si está activo el modo de pantalla completa añade el borde
@@ -204,10 +194,27 @@ void Screen::setVideoMode(int videoMode)
// Establece el tamaño de las notificaciones // Establece el tamaño de las notificaciones
setNotificationSize(); setNotificationSize();
// Reinicia los shaders
if (options->shaders)
{
const std::string glsl_file = options->screen.windowHeight == 192 ? "crtpi_192.glsl" : "crtpi_240.glsl";
std::ifstream f(asset->get(glsl_file).c_str());
std::string source((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
if (options->borderEnabled)
{
shader::init(window, borderCanvas, source.c_str());
}
else
{
shader::init(window, gameCanvas, source.c_str());
}
}
} }
// Camibia entre pantalla completa y ventana // Camibia entre pantalla completa y ventana
void Screen::switchVideoMode() void Screen::toggleVideoMode()
{ {
options->videoMode = (options->videoMode == 0) ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0; options->videoMode = (options->videoMode == 0) ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0;
setVideoMode(options->videoMode); setVideoMode(options->videoMode);
@@ -240,10 +247,11 @@ void Screen::incWindowSize()
void Screen::setBorderColor(color_t color) void Screen::setBorderColor(color_t color)
{ {
borderColor = color; borderColor = color;
auto temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, borderCanvas); SDL_SetRenderTarget(renderer, borderCanvas);
SDL_SetRenderDrawColor(renderer, borderColor.r, borderColor.g, borderColor.b, 0xFF); SDL_SetRenderDrawColor(renderer, borderColor.r, borderColor.g, borderColor.b, 0xFF);
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
SDL_SetRenderTarget(renderer, nullptr); SDL_SetRenderTarget(renderer, temp);
} }
// Cambia el tipo de mezcla // Cambia el tipo de mezcla
@@ -271,7 +279,7 @@ void Screen::setBorderEnabled(bool value)
} }
// Cambia entre borde visible y no visible // Cambia entre borde visible y no visible
void Screen::switchBorder() void Screen::toggleBorder()
{ {
options->borderEnabled = !options->borderEnabled; options->borderEnabled = !options->borderEnabled;
setVideoMode(0); setVideoMode(0);
@@ -428,14 +436,10 @@ void Screen::showNotification(std::string text1, std::string text2, int icon)
// Dibuja las notificaciones // Dibuja las notificaciones
void Screen::renderNotifications() void Screen::renderNotifications()
{ {
if (!notifyActive) if (notifyActive)
{ {
return; notify->render();
} }
SDL_RenderSetLogicalSize(renderer, notificationLogicalWidth, notificationLogicalHeight);
notify->render();
SDL_RenderSetLogicalSize(renderer, windowWidth, windowHeight);
} }
// Establece el tamaño de las notificaciones // Establece el tamaño de las notificaciones
@@ -461,3 +465,47 @@ void Screen::setNotificationSize()
notificationLogicalHeight = windowHeight / 3; notificationLogicalHeight = windowHeight / 3;
} }
} }
// Copia el gameCanvas en el borderCanvas
void Screen::gameCanvasToBorderCanvas()
{
auto temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, borderCanvas);
SDL_SetRenderDrawColor(renderer, borderColor.r, borderColor.g, borderColor.b, 0xFF);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, gameCanvas, nullptr, &dest);
SDL_SetRenderTarget(renderer, temp);
}
// Muestra el contenido de Screen por pantalla
void Screen::renderPresent()
{
SDL_SetRenderTarget(renderer, nullptr);
SDL_SetRenderDrawColor(renderer, borderColor.r, borderColor.g, borderColor.b, 0xFF);
SDL_RenderClear(renderer);
if (options->shaders)
{
// Aplica shaders y renderiza el contenido
shader::render();
}
else
{
if (options->borderEnabled)
{
SDL_RenderCopy(renderer, borderCanvas, nullptr, nullptr);
}
else
{
SDL_RenderCopy(renderer, gameCanvas, nullptr, &dest);
}
SDL_RenderPresent(renderer);
}
}
// Cambia el estado de los shaders
void Screen::toggleShaders()
{
options->shaders = !options->shaders;
setVideoMode(options->videoMode);
}

View File

@@ -69,6 +69,12 @@ private:
// Establece el tamaño de las notificaciones // Establece el tamaño de las notificaciones
void setNotificationSize(); void setNotificationSize();
// Copia el gameCanvas en el borderCanvas
void gameCanvasToBorderCanvas();
// Muestra el contenido de Screen por pantalla
void renderPresent();
public: public:
// Constructor // Constructor
Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options_t *options); Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options_t *options);
@@ -86,13 +92,13 @@ public:
void startDrawOnBorder(); void startDrawOnBorder();
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
void blit(); void render();
// Establece el modo de video // Establece el modo de video
void setVideoMode(int videoMode); void setVideoMode(int videoMode);
// Camibia entre pantalla completa y ventana // Camibia entre pantalla completa y ventana
void switchVideoMode(); void toggleVideoMode();
// Cambia el tamaño de la ventana // Cambia el tamaño de la ventana
void setWindowSize(int size); void setWindowSize(int size);
@@ -117,7 +123,7 @@ public:
void setBorderEnabled(bool value); void setBorderEnabled(bool value);
// Cambia entre borde visible y no visible // Cambia entre borde visible y no visible
void switchBorder(); void toggleBorder();
// Activa el fade // Activa el fade
void setFade(); void setFade();
@@ -142,6 +148,9 @@ public:
// Muestra una notificación de texto por pantalla; // Muestra una notificación de texto por pantalla;
void showNotification(std::string text1 = "", std::string text2 = "", int icon = -1); void showNotification(std::string text1 = "", std::string text2 = "", int icon = -1);
// Cambia el estado de los shaders
void toggleShaders();
}; };
#endif #endif

View File

@@ -132,6 +132,7 @@ struct options_t
int windowSize; // Contiene el valor por el que se multiplica el tamaño de la ventana int windowSize; // Contiene el valor por el que se multiplica el tamaño de la ventana
Uint32 filter; // Filtro usado para el escalado de la imagen Uint32 filter; // Filtro usado para el escalado de la imagen
bool vSync; // Indica si se quiere usar vsync o no bool vSync; // Indica si se quiere usar vsync o no
bool shaders; // Indica si se van a usar shaders o no
int gameWidth; // Ancho de la resolucion nativa del juego int gameWidth; // Ancho de la resolucion nativa del juego
int gameHeight; // Alto de la resolucion nativa del juego int gameHeight; // Alto de la resolucion nativa del juego
bool integerScale; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa bool integerScale; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa