re-add libretro shader support, add default shaders and lua API
This commit is contained in:
parent
d67a0319da
commit
fee744aa1b
10 changed files with 1370 additions and 26 deletions
|
@ -341,6 +341,7 @@ set(video_SRCS
|
|||
src/video/png.cpp
|
||||
src/video/sdl.cpp
|
||||
src/video/video.cpp
|
||||
src/video/shaders.cpp
|
||||
)
|
||||
source_group(video FILES ${video_SRCS})
|
||||
|
||||
|
@ -573,6 +574,7 @@ set(stratagus_generic_HDRS
|
|||
src/include/vec2i.h
|
||||
src/include/version.h
|
||||
src/include/video.h
|
||||
src/include/shaders.h
|
||||
src/include/viewport.h
|
||||
src/include/wav.h
|
||||
src/include/widgets.h
|
||||
|
|
20
src/include/shaders.h
Normal file
20
src/include/shaders.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef __SHADERS_H__
|
||||
#define __SHADERS_H__
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#ifndef __APPLE__
|
||||
extern bool LoadShaderExtensions();
|
||||
extern void RenderWithShader(SDL_Renderer *renderer, SDL_Window* win, SDL_Texture* backBuffer);
|
||||
extern const char* NextShader();
|
||||
#else
|
||||
bool LoadShaderExtensions() {
|
||||
}
|
||||
void RenderWithShader(SDL_Renderer*, SDL_Window*, SDL_Texture*) {
|
||||
}
|
||||
int NextShader() {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -34,7 +34,7 @@
|
|||
//@{
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
#include "shaders.h"
|
||||
#include "guichan.h"
|
||||
|
||||
#include "color.h"
|
||||
|
|
|
@ -18,7 +18,6 @@ public:
|
|||
|
||||
CVideo Video;
|
||||
void ToggleFullScreen(void);
|
||||
void SwitchToShader(void);
|
||||
|
||||
class CGraphic
|
||||
{
|
||||
|
|
|
@ -102,6 +102,8 @@ double FrameTicks; /// Frame length in ms
|
|||
|
||||
const EventCallback *Callbacks;
|
||||
|
||||
static bool CanUseShaders = false;
|
||||
|
||||
bool IsSDLWindowVisible = true;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
|
@ -255,17 +257,11 @@ static void InitKey2Str()
|
|||
*/
|
||||
void InitVideoSdl()
|
||||
{
|
||||
Uint32 flags = 0;
|
||||
Uint32 flags = SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
|
||||
if (SDL_WasInit(SDL_INIT_VIDEO) == 0) {
|
||||
//Wyrmgus start
|
||||
//#ifndef USE_WIN32
|
||||
//Wyrmgus end
|
||||
// Fix tablet input in full-screen mode
|
||||
SDL_setenv("SDL_MOUSE_RELATIVE", "0", 1);
|
||||
//Wyrmgus start
|
||||
//#endif
|
||||
//Wyrmgus end
|
||||
int res = SDL_Init(
|
||||
SDL_INIT_AUDIO | SDL_INIT_VIDEO |
|
||||
SDL_INIT_TIMER);
|
||||
|
@ -333,6 +329,7 @@ void InitVideoSdl()
|
|||
SDL_GetRendererInfo(TheRenderer, &rendererInfo);
|
||||
if(!strncmp(rendererInfo.name, "opengl", 6)) {
|
||||
puts("[Renderer] Got OpenGL");
|
||||
CanUseShaders = LoadShaderExtensions();
|
||||
}
|
||||
SDL_SetRenderDrawColor(TheRenderer, 0, 0, 0, 255);
|
||||
Video.ResizeScreen(Video.Width, Video.Height);
|
||||
|
@ -555,10 +552,6 @@ static void SdlDoEvent(const EventCallback &callbacks, SDL_Event &event)
|
|||
event.key.keysym.sym, event.key.keysym.sym < 128 ? event.key.keysym.sym : 0);
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_RESIZED:
|
||||
Video.ResizeScreen(event.window.data1, event.window.data2);
|
||||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
Exit(0);
|
||||
break;
|
||||
|
@ -659,20 +652,24 @@ void RealizeVideoMemory()
|
|||
if (NumRects) {
|
||||
//SDL_UpdateWindowSurfaceRects(TheWindow, Rects, NumRects);
|
||||
SDL_UpdateTexture(TheTexture, NULL, TheScreen->pixels, TheScreen->pitch);
|
||||
SDL_RenderClear(TheRenderer);
|
||||
//for (int i = 0; i < NumRects; i++)
|
||||
// SDL_UpdateTexture(TheTexture, &Rects[i], TheScreen->pixels, TheScreen->pitch);
|
||||
SDL_RenderCopy(TheRenderer, TheTexture, NULL, NULL);
|
||||
if (EnableDebugPrint) {
|
||||
// show a bar representing fps scaled by 10
|
||||
SDL_SetRenderDrawColor(TheRenderer, 255, 0, 0, 255);
|
||||
Uint32 nextTick = SDL_GetTicks();
|
||||
double fps = 10000.0 / (nextTick - LastTick);
|
||||
SDL_RenderDrawLine(TheRenderer, 0, 0, floorl(fps), 0);
|
||||
SDL_SetRenderDrawColor(TheRenderer, 0, 0, 0, 255);
|
||||
LastTick = nextTick;
|
||||
if (CanUseShaders) {
|
||||
RenderWithShader(TheRenderer, TheWindow, TheTexture);
|
||||
} else {
|
||||
SDL_RenderClear(TheRenderer);
|
||||
//for (int i = 0; i < NumRects; i++)
|
||||
// SDL_UpdateTexture(TheTexture, &Rects[i], TheScreen->pixels, TheScreen->pitch);
|
||||
SDL_RenderCopy(TheRenderer, TheTexture, NULL, NULL);
|
||||
if (EnableDebugPrint) {
|
||||
// show a bar representing fps scaled by 10
|
||||
SDL_SetRenderDrawColor(TheRenderer, 255, 0, 0, 255);
|
||||
Uint32 nextTick = SDL_GetTicks();
|
||||
double fps = 10000.0 / (nextTick - LastTick);
|
||||
SDL_RenderDrawLine(TheRenderer, 0, 0, floorl(fps), 0);
|
||||
SDL_SetRenderDrawColor(TheRenderer, 0, 0, 0, 255);
|
||||
LastTick = nextTick;
|
||||
}
|
||||
SDL_RenderPresent(TheRenderer);
|
||||
}
|
||||
SDL_RenderPresent(TheRenderer);
|
||||
NumRects = 0;
|
||||
}
|
||||
HideCursor();
|
||||
|
|
431
src/video/shaders.cpp
Normal file
431
src/video/shaders.cpp
Normal file
|
@ -0,0 +1,431 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Tim Felgentreff
|
||||
* Copyright (c) 2017 Augusto Ruiz
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "shaders.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_opengl.h>
|
||||
#include <SDL_opengl_glext.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "stratagus.h"
|
||||
#include "parameters.h"
|
||||
#include "video.h"
|
||||
#include "game.h"
|
||||
#include "iolib.h"
|
||||
#include "script.h"
|
||||
|
||||
#ifndef __APPLE__
|
||||
// Avoiding the use of GLEW or some extensions handler
|
||||
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;
|
||||
|
||||
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
|
||||
PFNGLUNIFORM1IPROC glUniform1i;
|
||||
PFNGLUNIFORM1FPROC glUniform1f;
|
||||
PFNGLUNIFORM2FPROC glUniform2f;
|
||||
PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
|
||||
|
||||
PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation;
|
||||
PFNGLVERTEXATTRIB4FPROC glVertexAttrib4f;
|
||||
|
||||
#ifdef WIN32
|
||||
#define CCONV __stdcall
|
||||
#else
|
||||
#define CCONV
|
||||
#endif
|
||||
|
||||
void (CCONV *lazyGlBegin)(GLenum);
|
||||
void (CCONV *lazyGlEnd)(void);
|
||||
void (CCONV *lazyGlTexCoord2f)(GLfloat, GLfloat);
|
||||
void (CCONV *lazyGlVertex2f)(GLfloat, GLfloat);
|
||||
void (CCONV *lazyGlGetIntegerv)(GLenum, GLint*);
|
||||
void (CCONV *lazyGlGetFloatv)(GLenum, GLfloat*);
|
||||
void (CCONV *lazyGlViewport)(GLint, GLint, GLsizei, GLsizei);
|
||||
void (CCONV *lazyGlMatrixMode)(GLenum);
|
||||
void (CCONV *lazyGlLoadIdentity)(void);
|
||||
void (CCONV *lazyGlOrtho)(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble);
|
||||
|
||||
static const int MAX_SHADERS = 128;
|
||||
static GLuint shaderPrograms[MAX_SHADERS + 1] = { (GLuint) 0 };
|
||||
static const char* shaderNames[MAX_SHADERS + 1] = { NULL };
|
||||
static char shadersLoaded = -1;
|
||||
static int currentShaderIdx = 0;
|
||||
|
||||
const char* none =
|
||||
#include "./shaders/noshader.glsl"
|
||||
;
|
||||
const char* CRT =
|
||||
#include "./shaders/crt.glsl"
|
||||
;
|
||||
const char* VHS =
|
||||
#include "./shaders/vhs.glsl"
|
||||
;
|
||||
const char* xBRZ =
|
||||
#include "./shaders/xbrz.glsl"
|
||||
;
|
||||
|
||||
static GLuint compileShader(const char* source, GLuint shaderType) {
|
||||
// Create ID for shader
|
||||
GLuint result = glCreateShader(shaderType);
|
||||
// Define shader text
|
||||
glShaderSource(result, 1, &source, 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 during compilation: " << 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 compiled correctly. Id = " << result << std::endl;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static GLuint compileProgramSource(std::string source) {
|
||||
GLuint programId = 0;
|
||||
GLuint vtxShaderId, fragShaderId;
|
||||
|
||||
vtxShaderId = compileShader((std::string("#define VERTEX\n") + source).c_str(), GL_VERTEX_SHADER);
|
||||
fragShaderId = compileShader((std::string("#define FRAGMENT\n") + source).c_str(), GL_FRAGMENT_SHADER);
|
||||
|
||||
if(vtxShaderId && fragShaderId) {
|
||||
programId = glCreateProgram();
|
||||
// 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;
|
||||
}
|
||||
|
||||
static GLuint compileProgram(std::string shaderFile) {
|
||||
std::ifstream f(shaderFile);
|
||||
std::string source((std::istreambuf_iterator<char>(f)),
|
||||
std::istreambuf_iterator<char>());
|
||||
std::cout << "[Shaders] Compiling shader: " << shaderFile << std::endl;
|
||||
return compileProgramSource(source);
|
||||
}
|
||||
|
||||
static void loadShaders() {
|
||||
int numShdr = 0;
|
||||
|
||||
#define COMPILE_BUILTIN_SHADER(name) \
|
||||
std::cout << "[Shaders] Compiling shader: " #name << std::endl; \
|
||||
shaderPrograms[numShdr] = compileProgramSource(std::string(name)); \
|
||||
shaderNames[numShdr] = #name ; \
|
||||
numShdr++;
|
||||
COMPILE_BUILTIN_SHADER(none);
|
||||
COMPILE_BUILTIN_SHADER(xBRZ);
|
||||
COMPILE_BUILTIN_SHADER(CRT);
|
||||
COMPILE_BUILTIN_SHADER(VHS);
|
||||
#undef COMPILE_BUILTIN_SHADER
|
||||
|
||||
std::vector<FileList> flp;
|
||||
std::string shaderPath(StratagusLibPath);
|
||||
char *cShaderPath;
|
||||
#ifdef _WIN32
|
||||
shaderPath.append("\\shaders\\");
|
||||
int fullpathsize = ExpandEnvironmentStrings(shaderPath.c_str(), NULL, 0);
|
||||
cShaderPath = (char*)calloc(fullpathsize + 1, sizeof(char));
|
||||
ExpandEnvironmentStrings(shaderPath.c_str(), cShaderPath, fullpathsize);
|
||||
#else
|
||||
shaderPath.append("/shaders/");
|
||||
cShaderPath = (char*)shaderPath.c_str();
|
||||
#endif
|
||||
int n = ReadDataDirectory(cShaderPath, flp);
|
||||
int shaderFileToIdx[1024];
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int pos = flp[i].name.find(".glsl");
|
||||
if (pos > 0) {
|
||||
GLuint program = compileProgram(shaderPath + flp[i].name);
|
||||
if (program) {
|
||||
shaderPrograms[numShdr] = program;
|
||||
shaderNames[numShdr] = strdup(flp[i].name.c_str());
|
||||
numShdr += 1;
|
||||
if (numShdr >= MAX_SHADERS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderWithShader(SDL_Renderer *renderer, SDL_Window* win, SDL_Texture* backBuffer) {
|
||||
GLint oldProgramId;
|
||||
// Detach the texture
|
||||
SDL_SetRenderTarget(renderer, NULL);
|
||||
SDL_RenderClear(renderer);
|
||||
|
||||
SDL_GL_BindTexture(backBuffer, NULL, NULL);
|
||||
GLuint shaderProgram = shaderPrograms[currentShaderIdx];
|
||||
if (shaderProgram != 0) {
|
||||
lazyGlGetIntegerv(GL_CURRENT_PROGRAM, &oldProgramId);
|
||||
glUseProgram(shaderProgram);
|
||||
}
|
||||
|
||||
// These are the default uniforms and attrs for glsl converted libretro shaders
|
||||
GLint Texture = glGetUniformLocation(shaderProgram, "Texture");
|
||||
GLint MVPMatrix = glGetUniformLocation(shaderProgram, "MVPMatrix");
|
||||
GLint FrameDirection = glGetUniformLocation(shaderProgram, "FrameDirection");
|
||||
GLint FrameCount = glGetUniformLocation(shaderProgram, "FrameCount");
|
||||
GLint OutputSize = glGetUniformLocation(shaderProgram, "OutputSize");
|
||||
GLint TextureSize = glGetUniformLocation(shaderProgram, "TextureSize");
|
||||
GLint InputSize = glGetUniformLocation(shaderProgram, "InputSize");
|
||||
// (timfel): If I manually set the VertexCoord, it's wrong? But I have to set TexCoord? no idea...
|
||||
// GLint VertexCoord = glGetAttribLocation(shaderProgram, "VertexCoord");
|
||||
GLint TexCoord = glGetAttribLocation(shaderProgram, "TexCoord");
|
||||
|
||||
// Window coordinates
|
||||
int w, h, xBorder = 0, yBorder = 0;
|
||||
SDL_GL_GetDrawableSize(win, &w, &h);
|
||||
|
||||
// letterboxing
|
||||
double xScale = (double)w / Video.Width;
|
||||
double yScale = (double)h / Video.Height;
|
||||
if (xScale > yScale) {
|
||||
xScale = yScale;
|
||||
xBorder = std::floor((w - (Video.Width * yScale)) / 2.0);
|
||||
w = Video.Width * yScale;
|
||||
} else {
|
||||
yScale = xScale;
|
||||
yBorder = std::floor((h - (Video.Height * xScale)) / 2.0);
|
||||
h = Video.Height * xScale;
|
||||
}
|
||||
|
||||
glUniform1i(Texture, 0);
|
||||
GLfloat modelview[4 * 4];
|
||||
GLfloat projection[4 * 4];
|
||||
lazyGlGetFloatv(GL_MODELVIEW_MATRIX, modelview);
|
||||
lazyGlGetFloatv(GL_PROJECTION_MATRIX, projection);
|
||||
GLfloat matrix[4 * 4] = {0.0f};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for(int j = 0; j < 4; j++) {
|
||||
for (int k = 0; k < 4; k++) {
|
||||
matrix[i * 4 + j] += modelview[i * 4 + k] * projection[k * 4 + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
glUniformMatrix4fv(MVPMatrix, 1, GL_FALSE, matrix);
|
||||
glUniform1f(FrameDirection, 1);
|
||||
glUniform1f(FrameCount, 1);
|
||||
glUniform2f(OutputSize, (float)w, (float)h);
|
||||
glUniform2f(TextureSize, (float)Video.Width, (float)Video.Height);
|
||||
glUniform2f(InputSize, (float)Video.Width, (float)Video.Height);
|
||||
|
||||
GLfloat minx, miny, maxx, maxy;
|
||||
GLfloat minu, maxu, minv, maxv;
|
||||
|
||||
minx = 0.0f;
|
||||
miny = 0.0f;
|
||||
maxx = w;
|
||||
maxy = h;
|
||||
|
||||
minu = 0.0f;
|
||||
maxu = 1.0f;
|
||||
minv = 0.0f;
|
||||
maxv = 1.0f;
|
||||
|
||||
|
||||
lazyGlMatrixMode(GL_PROJECTION);
|
||||
lazyGlLoadIdentity();
|
||||
lazyGlOrtho(0.0f, w, h, 0.0f, 0.0f, 1.0f);
|
||||
lazyGlViewport(xBorder, yBorder, w, h);
|
||||
|
||||
lazyGlBegin(GL_TRIANGLE_STRIP);
|
||||
glVertexAttrib4f(TexCoord, minu, minv, 0, 0);
|
||||
lazyGlTexCoord2f(minu, minv);
|
||||
lazyGlVertex2f(minx, miny);
|
||||
|
||||
glVertexAttrib4f(TexCoord, maxu, minv, 0, 0);
|
||||
lazyGlTexCoord2f(maxu, minv);
|
||||
lazyGlVertex2f(maxx, miny);
|
||||
|
||||
glVertexAttrib4f(TexCoord, minu, maxv, 0, 0);
|
||||
lazyGlTexCoord2f(minu, maxv);
|
||||
lazyGlVertex2f(minx, maxy);
|
||||
|
||||
glVertexAttrib4f(TexCoord, maxu, maxv, 0, 0);
|
||||
lazyGlTexCoord2f(maxu, maxv);
|
||||
lazyGlVertex2f(maxx, maxy);
|
||||
lazyGlEnd();
|
||||
SDL_GL_SwapWindow(win);
|
||||
|
||||
if (shaderProgram != 0) {
|
||||
glUseProgram(oldProgramId);
|
||||
}
|
||||
}
|
||||
|
||||
const char* NextShader() {
|
||||
if (shaderPrograms[++currentShaderIdx] == 0) {
|
||||
currentShaderIdx = 0;
|
||||
}
|
||||
std::cout << "NextShader: " << shaderNames[currentShaderIdx] << std::endl;
|
||||
return shaderNames[currentShaderIdx];
|
||||
}
|
||||
|
||||
static int CclGetShader(lua_State *l) {
|
||||
LuaCheckArgs(l, 0);
|
||||
const char* shaderName = shaderNames[currentShaderIdx];
|
||||
if (shaderName) {
|
||||
lua_pushstring(l, shaderName);
|
||||
} else {
|
||||
lua_pushnil(l);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int CclSetShader(lua_State *l) {
|
||||
LuaCheckArgs(l, 1);
|
||||
const char* shaderName = LuaToString(l, 1);
|
||||
for (int i = 0; i < MAX_SHADERS; i++) {
|
||||
const char* n = shaderNames[i];
|
||||
if (n) {
|
||||
if (!strcmp(n, shaderName)) {
|
||||
currentShaderIdx = i;
|
||||
std::cout << "SetShader: " << shaderNames[currentShaderIdx] << std::endl;
|
||||
lua_pushboolean(l, 1);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
lua_pushboolean(l, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int CclGetShaderNames(lua_State *l) {
|
||||
LuaCheckArgs(l, 0);
|
||||
lua_newtable(l);
|
||||
for (int i = 0; shaderNames[i] != NULL; i++) {
|
||||
lua_pushstring(l, shaderNames[i]);
|
||||
lua_rawseti(l, -2, i + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool LoadShaderExtensions() {
|
||||
if (shadersLoaded != -1) {
|
||||
return shadersLoaded == 1;
|
||||
}
|
||||
|
||||
*(void **) (&lazyGlBegin) = SDL_GL_GetProcAddress("glBegin");
|
||||
*(void **) (&lazyGlEnd) = SDL_GL_GetProcAddress("glEnd");
|
||||
*(void **) (&lazyGlTexCoord2f) = SDL_GL_GetProcAddress("glTexCoord2f");
|
||||
*(void **) (&lazyGlVertex2f) = SDL_GL_GetProcAddress("glVertex2f");
|
||||
*(void **) (&lazyGlGetIntegerv) = SDL_GL_GetProcAddress("glGetIntegerv");
|
||||
*(void **) (&lazyGlGetFloatv) = SDL_GL_GetProcAddress("glGetFloatv");
|
||||
*(void **) (&lazyGlViewport) = SDL_GL_GetProcAddress("glViewport");
|
||||
*(void **) (&lazyGlMatrixMode) = SDL_GL_GetProcAddress("glMatrixMode");
|
||||
*(void **) (&lazyGlOrtho) = SDL_GL_GetProcAddress("glOrtho");
|
||||
*(void **) (&lazyGlLoadIdentity) = SDL_GL_GetProcAddress("glLoadIdentity");
|
||||
|
||||
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");
|
||||
glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)SDL_GL_GetProcAddress("glGetUniformLocation");
|
||||
glUniform1i = (PFNGLUNIFORM1IPROC)SDL_GL_GetProcAddress("glUniform1i");
|
||||
glUniform1f = (PFNGLUNIFORM1FPROC)SDL_GL_GetProcAddress("glUniform1f");
|
||||
glUniform2f = (PFNGLUNIFORM2FPROC)SDL_GL_GetProcAddress("glUniform2f");
|
||||
glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)SDL_GL_GetProcAddress("glUniformMatrix4fv");
|
||||
glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)SDL_GL_GetProcAddress("glGetAttribLocation");
|
||||
glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)SDL_GL_GetProcAddress("glVertexAttrib4f");
|
||||
|
||||
if (lazyGlBegin && lazyGlEnd && lazyGlTexCoord2f && lazyGlVertex2f && lazyGlGetIntegerv &&
|
||||
glCreateShader && glShaderSource && glCompileShader && glGetShaderiv &&
|
||||
glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram &&
|
||||
glLinkProgram && glValidateProgram && glGetProgramiv && glGetProgramInfoLog &&
|
||||
glUseProgram && glGetUniformLocation && glUniform1i && glUniform1f && glUniform2f &&
|
||||
glUniformMatrix4fv && glGetAttribLocation && glVertexAttrib4f) {
|
||||
shadersLoaded = 1;
|
||||
loadShaders();
|
||||
} else {
|
||||
shadersLoaded = 0;
|
||||
}
|
||||
|
||||
lua_register(Lua, "GetShaderNames", CclGetShaderNames);
|
||||
lua_register(Lua, "GetShader", CclGetShader);
|
||||
lua_register(Lua, "SetShader", CclSetShader);
|
||||
|
||||
return shadersLoaded == 1;
|
||||
}
|
||||
|
||||
#endif
|
271
src/video/shaders/crt.glsl
Normal file
271
src/video/shaders/crt.glsl
Normal file
|
@ -0,0 +1,271 @@
|
|||
R"(
|
||||
/*
|
||||
CRT Shader by EasyMode
|
||||
License: GPL
|
||||
|
||||
A flat CRT shader ideally for 1080p or higher displays.
|
||||
|
||||
Recommended Settings:
|
||||
|
||||
Video
|
||||
- Aspect Ratio: 4:3
|
||||
- Integer Scale: Off
|
||||
|
||||
Shader
|
||||
- Filter: Nearest
|
||||
- Scale: Don't Care
|
||||
|
||||
Example RGB Mask Parameter Settings:
|
||||
|
||||
Aperture Grille (Default)
|
||||
- Dot Width: 1
|
||||
- Dot Height: 1
|
||||
- Stagger: 0
|
||||
|
||||
Lottes' Shadow Mask
|
||||
- Dot Width: 2
|
||||
- Dot Height: 1
|
||||
- Stagger: 3
|
||||
*/
|
||||
|
||||
// Parameter lines go here:
|
||||
#pragma parameter SHARPNESS_H SharpnessHorizontal 0.5 0.0 1.0 0.05
|
||||
#pragma parameter SHARPNESS_V SharpnessVertical 1.0 0.0 1.0 0.05
|
||||
#pragma parameter MASK_STRENGTH MaskStrength 0.3 0.0 1.0 0.01
|
||||
#pragma parameter MASK_DOT_WIDTH MaskDotWidth 1.0 1.0 100.0 1.0
|
||||
#pragma parameter MASK_DOT_HEIGHT MaskDotHeight 1.0 1.0 100.0 1.0
|
||||
#pragma parameter MASK_STAGGER MaskStagger 0.0 0.0 100.0 1.0
|
||||
#pragma parameter MASK_SIZE MaskSize 1.0 1.0 100.0 1.0
|
||||
#pragma parameter SCANLINE_STRENGTH ScanlineStrength 1.0 0.0 1.0 0.05
|
||||
#pragma parameter SCANLINE_BEAM_WIDTH_MIN ScanlineBeamWidthMin. 1.5 0.5 5.0 0.5
|
||||
#pragma parameter SCANLINE_BEAM_WIDTH_MAX ScanlineBeamWidthMax. 1.5 0.5 5.0 0.5
|
||||
#pragma parameter SCANLINE_BRIGHT_MIN ScanlineBrightnessMin. 0.35 0.0 1.0 0.05
|
||||
#pragma parameter SCANLINE_BRIGHT_MAX ScanlineBrightnessMax. 0.65 0.0 1.0 0.05
|
||||
#pragma parameter SCANLINE_CUTOFF ScanlineCutoff 400.0 1.0 1000.0 1.0
|
||||
#pragma parameter GAMMA_INPUT GammaInput 2.0 0.1 5.0 0.1
|
||||
#pragma parameter GAMMA_OUTPUT GammaOutput 1.8 0.1 5.0 0.1
|
||||
#pragma parameter BRIGHT_BOOST BrightnessBoost 1.2 1.0 2.0 0.01
|
||||
#pragma parameter DILATION Dilation 1.0 0.0 1.0 1.0
|
||||
|
||||
#if defined(VERTEX)
|
||||
|
||||
#if __VERSION__ >= 130
|
||||
#define COMPAT_VARYING out
|
||||
#define COMPAT_ATTRIBUTE in
|
||||
#define COMPAT_TEXTURE texture
|
||||
#else
|
||||
#define COMPAT_VARYING varying
|
||||
#define COMPAT_ATTRIBUTE attribute
|
||||
#define COMPAT_TEXTURE texture2D
|
||||
#endif
|
||||
|
||||
#ifdef GL_ES
|
||||
#define COMPAT_PRECISION mediump
|
||||
#else
|
||||
#define COMPAT_PRECISION
|
||||
#endif
|
||||
|
||||
COMPAT_ATTRIBUTE vec4 VertexCoord;
|
||||
COMPAT_ATTRIBUTE vec4 COLOR;
|
||||
COMPAT_ATTRIBUTE vec4 TexCoord;
|
||||
COMPAT_VARYING vec4 COL0;
|
||||
COMPAT_VARYING vec4 TEX0;
|
||||
|
||||
vec4 _oPosition1;
|
||||
uniform mat4 MVPMatrix;
|
||||
uniform COMPAT_PRECISION int FrameDirection;
|
||||
uniform COMPAT_PRECISION int FrameCount;
|
||||
uniform COMPAT_PRECISION vec2 OutputSize;
|
||||
uniform COMPAT_PRECISION vec2 TextureSize;
|
||||
uniform COMPAT_PRECISION vec2 InputSize;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = MVPMatrix * VertexCoord;
|
||||
COL0 = COLOR;
|
||||
TEX0.xy = TexCoord.xy;
|
||||
}
|
||||
|
||||
#elif defined(FRAGMENT)
|
||||
|
||||
#if __VERSION__ >= 130
|
||||
#define COMPAT_VARYING in
|
||||
#define COMPAT_TEXTURE texture
|
||||
out vec4 FragColor;
|
||||
#else
|
||||
#define COMPAT_VARYING varying
|
||||
#define FragColor gl_FragColor
|
||||
#define COMPAT_TEXTURE texture2D
|
||||
#endif
|
||||
|
||||
#ifdef GL_ES
|
||||
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
||||
precision highp float;
|
||||
#else
|
||||
precision mediump float;
|
||||
precision mediump int;
|
||||
#endif
|
||||
#define COMPAT_PRECISION mediump
|
||||
#else
|
||||
#define COMPAT_PRECISION
|
||||
#endif
|
||||
|
||||
uniform COMPAT_PRECISION int FrameDirection;
|
||||
uniform COMPAT_PRECISION int FrameCount;
|
||||
uniform COMPAT_PRECISION vec2 OutputSize;
|
||||
uniform COMPAT_PRECISION vec2 TextureSize;
|
||||
uniform COMPAT_PRECISION vec2 InputSize;
|
||||
uniform sampler2D Texture;
|
||||
COMPAT_VARYING vec4 TEX0;
|
||||
|
||||
#define FIX(c) max(abs(c), 1e-5)
|
||||
#define PI 3.141592653589
|
||||
|
||||
#define TEX2D(c) dilate(COMPAT_TEXTURE(Texture, c))
|
||||
|
||||
// compatibility #defines
|
||||
#define Source Texture
|
||||
#define vTexCoord TEX0.xy
|
||||
|
||||
#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
|
||||
#define outsize vec4(OutputSize, 1.0 / OutputSize)
|
||||
|
||||
#ifdef PARAMETER_UNIFORM
|
||||
// All parameter floats need to have COMPAT_PRECISION in front of them
|
||||
uniform COMPAT_PRECISION float SHARPNESS_H;
|
||||
uniform COMPAT_PRECISION float SHARPNESS_V;
|
||||
uniform COMPAT_PRECISION float MASK_STRENGTH;
|
||||
uniform COMPAT_PRECISION float MASK_DOT_WIDTH;
|
||||
uniform COMPAT_PRECISION float MASK_DOT_HEIGHT;
|
||||
uniform COMPAT_PRECISION float MASK_STAGGER;
|
||||
uniform COMPAT_PRECISION float MASK_SIZE;
|
||||
uniform COMPAT_PRECISION float SCANLINE_STRENGTH;
|
||||
uniform COMPAT_PRECISION float SCANLINE_BEAM_WIDTH_MIN;
|
||||
uniform COMPAT_PRECISION float SCANLINE_BEAM_WIDTH_MAX;
|
||||
uniform COMPAT_PRECISION float SCANLINE_BRIGHT_MIN;
|
||||
uniform COMPAT_PRECISION float SCANLINE_BRIGHT_MAX;
|
||||
uniform COMPAT_PRECISION float SCANLINE_CUTOFF;
|
||||
uniform COMPAT_PRECISION float GAMMA_INPUT;
|
||||
uniform COMPAT_PRECISION float GAMMA_OUTPUT;
|
||||
uniform COMPAT_PRECISION float BRIGHT_BOOST;
|
||||
uniform COMPAT_PRECISION float DILATION;
|
||||
#else
|
||||
#define SHARPNESS_H 0.5
|
||||
#define SHARPNESS_V 1.0
|
||||
#define MASK_STRENGTH 0.3
|
||||
#define MASK_DOT_WIDTH 1.0
|
||||
#define MASK_DOT_HEIGHT 1.0
|
||||
#define MASK_STAGGER 0.0
|
||||
#define MASK_SIZE 1.0
|
||||
#define SCANLINE_STRENGTH 1.0
|
||||
#define SCANLINE_BEAM_WIDTH_MIN 1.5
|
||||
#define SCANLINE_BEAM_WIDTH_MAX 1.5
|
||||
#define SCANLINE_BRIGHT_MIN 0.35
|
||||
#define SCANLINE_BRIGHT_MAX 0.65
|
||||
#define SCANLINE_CUTOFF 400.0
|
||||
#define GAMMA_INPUT 2.0
|
||||
#define GAMMA_OUTPUT 1.8
|
||||
#define BRIGHT_BOOST 1.2
|
||||
#define DILATION 1.0
|
||||
#endif
|
||||
|
||||
// Set to 0 to use linear filter and gain speed
|
||||
#define ENABLE_LANCZOS 1
|
||||
|
||||
vec4 dilate(vec4 col)
|
||||
{
|
||||
vec4 x = mix(vec4(1.0), col, DILATION);
|
||||
|
||||
return col * x;
|
||||
}
|
||||
|
||||
float curve_distance(float x, float sharp)
|
||||
{
|
||||
|
||||
/*
|
||||
apply half-circle s-curve to distance for sharper (more pixelated) interpolation
|
||||
single line formula for Graph Toy:
|
||||
0.5 - sqrt(0.25 - (x - step(0.5, x)) * (x - step(0.5, x))) * sign(0.5 - x)
|
||||
*/
|
||||
|
||||
float x_step = step(0.5, x);
|
||||
float curve = 0.5 - sqrt(0.25 - (x - x_step) * (x - x_step)) * sign(0.5 - x);
|
||||
|
||||
return mix(x, curve, sharp);
|
||||
}
|
||||
|
||||
mat4 get_color_matrix(vec2 co, vec2 dx)
|
||||
{
|
||||
return mat4(TEX2D(co - dx), TEX2D(co), TEX2D(co + dx), TEX2D(co + 2.0 * dx));
|
||||
}
|
||||
|
||||
vec3 filter_lanczos(vec4 coeffs, mat4 color_matrix)
|
||||
{
|
||||
vec4 col = color_matrix * coeffs;
|
||||
vec4 sample_min = min(color_matrix[1], color_matrix[2]);
|
||||
vec4 sample_max = max(color_matrix[1], color_matrix[2]);
|
||||
|
||||
col = clamp(col, sample_min, sample_max);
|
||||
|
||||
return col.rgb;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 dx = vec2(SourceSize.z, 0.0);
|
||||
vec2 dy = vec2(0.0, SourceSize.w);
|
||||
vec2 pix_co = vTexCoord * SourceSize.xy - vec2(0.5, 0.5);
|
||||
vec2 tex_co = (floor(pix_co) + vec2(0.5, 0.5)) * SourceSize.zw;
|
||||
vec2 dist = fract(pix_co);
|
||||
float curve_x;
|
||||
vec3 col, col2;
|
||||
|
||||
#if ENABLE_LANCZOS
|
||||
curve_x = curve_distance(dist.x, SHARPNESS_H * SHARPNESS_H);
|
||||
|
||||
vec4 coeffs = PI * vec4(1.0 + curve_x, curve_x, 1.0 - curve_x, 2.0 - curve_x);
|
||||
|
||||
coeffs = FIX(coeffs);
|
||||
coeffs = 2.0 * sin(coeffs) * sin(coeffs * 0.5) / (coeffs * coeffs);
|
||||
coeffs /= dot(coeffs, vec4(1.0));
|
||||
|
||||
col = filter_lanczos(coeffs, get_color_matrix(tex_co, dx));
|
||||
col2 = filter_lanczos(coeffs, get_color_matrix(tex_co + dy, dx));
|
||||
#else
|
||||
curve_x = curve_distance(dist.x, SHARPNESS_H);
|
||||
|
||||
col = mix(TEX2D(tex_co).rgb, TEX2D(tex_co + dx).rgb, curve_x);
|
||||
col2 = mix(TEX2D(tex_co + dy).rgb, TEX2D(tex_co + dx + dy).rgb, curve_x);
|
||||
#endif
|
||||
|
||||
col = mix(col, col2, curve_distance(dist.y, SHARPNESS_V));
|
||||
col = pow(col, vec3(GAMMA_INPUT / (DILATION + 1.0)));
|
||||
|
||||
float luma = dot(vec3(0.2126, 0.7152, 0.0722), col);
|
||||
float bright = (max(col.r, max(col.g, col.b)) + luma) * 0.5;
|
||||
float scan_bright = clamp(bright, SCANLINE_BRIGHT_MIN, SCANLINE_BRIGHT_MAX);
|
||||
float scan_beam = clamp(bright * SCANLINE_BEAM_WIDTH_MAX, SCANLINE_BEAM_WIDTH_MIN, SCANLINE_BEAM_WIDTH_MAX);
|
||||
float scan_weight = 1.0 - pow(cos(vTexCoord.y * 2.0 * PI * SourceSize.y) * 0.5 + 0.5, scan_beam) * SCANLINE_STRENGTH;
|
||||
|
||||
float mask = 1.0 - MASK_STRENGTH;
|
||||
vec2 mod_fac = floor(vTexCoord * outsize.xy * SourceSize.xy / (InputSize.xy * vec2(MASK_SIZE, MASK_DOT_HEIGHT * MASK_SIZE)));
|
||||
int dot_no = int(mod((mod_fac.x + mod(mod_fac.y, 2.0) * MASK_STAGGER) / MASK_DOT_WIDTH, 3.0));
|
||||
vec3 mask_weight;
|
||||
|
||||
if (dot_no == 0) mask_weight = vec3(1.0, mask, mask);
|
||||
else if (dot_no == 1) mask_weight = vec3(mask, 1.0, mask);
|
||||
else mask_weight = vec3(mask, mask, 1.0);
|
||||
|
||||
if (InputSize.y >= SCANLINE_CUTOFF)
|
||||
scan_weight = 1.0;
|
||||
|
||||
col2 = col.rgb;
|
||||
col *= vec3(scan_weight);
|
||||
col = mix(col, col2, scan_bright);
|
||||
col *= mask_weight;
|
||||
col = pow(col, vec3(1.0 / GAMMA_OUTPUT));
|
||||
|
||||
FragColor = vec4(col * BRIGHT_BOOST, 1.0);
|
||||
}
|
||||
#endif
|
||||
)"
|
15
src/video/shaders/noshader.glsl
Normal file
15
src/video/shaders/noshader.glsl
Normal file
|
@ -0,0 +1,15 @@
|
|||
R"(
|
||||
#if defined(VERTEX)
|
||||
varying vec2 v_texCoord;
|
||||
void main() {
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
v_texCoord = vec2(gl_MultiTexCoord0);
|
||||
}
|
||||
#elif defined(FRAGMENT)
|
||||
varying vec2 v_texCoord;
|
||||
uniform sampler2D tex0;
|
||||
void main() {
|
||||
gl_FragColor = texture2D(tex0, v_texCoord);
|
||||
}
|
||||
#endif
|
||||
)"
|
232
src/video/shaders/vhs.glsl
Normal file
232
src/video/shaders/vhs.glsl
Normal file
|
@ -0,0 +1,232 @@
|
|||
R"(
|
||||
// VHS shader
|
||||
// by hunterk
|
||||
// adapted from ompuco's more AVdistortion shadertoy:
|
||||
// https://www.shadertoy.com/view/XlsczN
|
||||
|
||||
// Parameter lines go here:
|
||||
#pragma parameter wiggle Wiggle 0.0 0.0 10.0 1.0
|
||||
#pragma parameter smear ChromaSmear 0.5 0.0 1.0 0.05
|
||||
|
||||
#if defined(VERTEX)
|
||||
|
||||
#if __VERSION__ >= 130
|
||||
#define COMPAT_VARYING out
|
||||
#define COMPAT_ATTRIBUTE in
|
||||
#define COMPAT_TEXTURE texture
|
||||
#else
|
||||
#define COMPAT_VARYING varying
|
||||
#define COMPAT_ATTRIBUTE attribute
|
||||
#define COMPAT_TEXTURE texture2D
|
||||
#endif
|
||||
|
||||
#ifdef GL_ES
|
||||
#define COMPAT_PRECISION mediump
|
||||
#else
|
||||
#define COMPAT_PRECISION
|
||||
#endif
|
||||
|
||||
COMPAT_ATTRIBUTE vec4 VertexCoord;
|
||||
COMPAT_ATTRIBUTE vec4 COLOR;
|
||||
COMPAT_ATTRIBUTE vec4 TexCoord;
|
||||
COMPAT_VARYING vec4 COL0;
|
||||
COMPAT_VARYING vec4 TEX0;
|
||||
|
||||
vec4 _oPosition1;
|
||||
uniform mat4 MVPMatrix;
|
||||
uniform COMPAT_PRECISION int FrameDirection;
|
||||
uniform COMPAT_PRECISION int FrameCount;
|
||||
uniform COMPAT_PRECISION vec2 OutputSize;
|
||||
uniform COMPAT_PRECISION vec2 TextureSize;
|
||||
uniform COMPAT_PRECISION vec2 InputSize;
|
||||
|
||||
// compatibility #defines
|
||||
#define vTexCoord TEX0.xy
|
||||
#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
|
||||
#define OutSize vec4(OutputSize, 1.0 / OutputSize)
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = MVPMatrix * VertexCoord;
|
||||
TEX0.xy = TexCoord.xy;
|
||||
}
|
||||
|
||||
#elif defined(FRAGMENT)
|
||||
|
||||
#ifdef GL_ES
|
||||
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
||||
precision highp float;
|
||||
#else
|
||||
precision mediump float;
|
||||
#endif
|
||||
#define COMPAT_PRECISION mediump
|
||||
#else
|
||||
#define COMPAT_PRECISION
|
||||
#endif
|
||||
|
||||
#if __VERSION__ >= 130
|
||||
#define COMPAT_VARYING in
|
||||
#define COMPAT_TEXTURE texture
|
||||
out COMPAT_PRECISION vec4 FragColor;
|
||||
#else
|
||||
#define COMPAT_VARYING varying
|
||||
#define FragColor gl_FragColor
|
||||
#define COMPAT_TEXTURE texture2D
|
||||
#endif
|
||||
|
||||
uniform COMPAT_PRECISION int FrameDirection;
|
||||
uniform COMPAT_PRECISION int FrameCount;
|
||||
uniform COMPAT_PRECISION vec2 OutputSize;
|
||||
uniform COMPAT_PRECISION vec2 TextureSize;
|
||||
uniform COMPAT_PRECISION vec2 InputSize;
|
||||
uniform sampler2D Texture;
|
||||
uniform sampler2D play;
|
||||
COMPAT_VARYING vec4 TEX0;
|
||||
|
||||
// compatibility #defines
|
||||
#define Source Texture
|
||||
#define vTexCoord TEX0.xy
|
||||
|
||||
#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
|
||||
#define OutSize vec4(OutputSize, 1.0 / OutputSize)
|
||||
|
||||
#ifdef PARAMETER_UNIFORM
|
||||
uniform COMPAT_PRECISION float wiggle;
|
||||
uniform COMPAT_PRECISION float smear;
|
||||
#else
|
||||
#define wiggle 3.0
|
||||
#define smear 0.5
|
||||
#endif
|
||||
|
||||
#define iTime mod(float(FrameCount), 7.0)
|
||||
#define iChannel0 Texture
|
||||
|
||||
//YIQ/RGB shit
|
||||
vec3 rgb2yiq(vec3 c){
|
||||
return vec3(
|
||||
(0.2989*c.x + 0.5959*c.y + 0.2115*c.z),
|
||||
(0.5870*c.x - 0.2744*c.y - 0.5229*c.z),
|
||||
(0.1140*c.x - 0.3216*c.y + 0.3114*c.z)
|
||||
);
|
||||
}
|
||||
|
||||
vec3 yiq2rgb(vec3 c){
|
||||
return vec3(
|
||||
( 1.0*c.x + 1.0*c.y + 1.0*c.z),
|
||||
( 0.956*c.x - 0.2720*c.y - 1.1060*c.z),
|
||||
(0.6210*c.x - 0.6474*c.y + 1.7046*c.z)
|
||||
);
|
||||
}
|
||||
|
||||
vec2 Circle(float Start, float Points, float Point)
|
||||
{
|
||||
float Rad = (3.141592 * 2.0 * (1.0 / Points)) * (Point + Start);
|
||||
//return vec2(sin(Rad), cos(Rad));
|
||||
return vec2(-(.3+Rad), cos(Rad));
|
||||
|
||||
}
|
||||
|
||||
vec3 Blur(vec2 uv, float d){
|
||||
float t = (sin(iTime*5.0+uv.y*5.0))/10.0;
|
||||
float b = 1.0;
|
||||
t=0.0;
|
||||
vec2 PixelOffset=vec2(d+.0005*t,0);
|
||||
|
||||
float Start = 2.0 / 14.0;
|
||||
vec2 Scale = 0.66 * 4.0 * 2.0 * PixelOffset.xy;
|
||||
|
||||
vec3 N0 = COMPAT_TEXTURE(iChannel0, uv + Circle(Start, 14.0, 0.0) * Scale).rgb;
|
||||
vec3 N1 = COMPAT_TEXTURE(iChannel0, uv + Circle(Start, 14.0, 1.0) * Scale).rgb;
|
||||
vec3 N2 = COMPAT_TEXTURE(iChannel0, uv + Circle(Start, 14.0, 2.0) * Scale).rgb;
|
||||
vec3 N3 = COMPAT_TEXTURE(iChannel0, uv + Circle(Start, 14.0, 3.0) * Scale).rgb;
|
||||
vec3 N4 = COMPAT_TEXTURE(iChannel0, uv + Circle(Start, 14.0, 4.0) * Scale).rgb;
|
||||
vec3 N5 = COMPAT_TEXTURE(iChannel0, uv + Circle(Start, 14.0, 5.0) * Scale).rgb;
|
||||
vec3 N6 = COMPAT_TEXTURE(iChannel0, uv + Circle(Start, 14.0, 6.0) * Scale).rgb;
|
||||
vec3 N7 = COMPAT_TEXTURE(iChannel0, uv + Circle(Start, 14.0, 7.0) * Scale).rgb;
|
||||
vec3 N8 = COMPAT_TEXTURE(iChannel0, uv + Circle(Start, 14.0, 8.0) * Scale).rgb;
|
||||
vec3 N9 = COMPAT_TEXTURE(iChannel0, uv + Circle(Start, 14.0, 9.0) * Scale).rgb;
|
||||
vec3 N10 = COMPAT_TEXTURE(iChannel0, uv + Circle(Start, 14.0, 10.0) * Scale).rgb;
|
||||
vec3 N11 = COMPAT_TEXTURE(iChannel0, uv + Circle(Start, 14.0, 11.0) * Scale).rgb;
|
||||
vec3 N12 = COMPAT_TEXTURE(iChannel0, uv + Circle(Start, 14.0, 12.0) * Scale).rgb;
|
||||
vec3 N13 = COMPAT_TEXTURE(iChannel0, uv + Circle(Start, 14.0, 13.0) * Scale).rgb;
|
||||
vec3 N14 = COMPAT_TEXTURE(iChannel0, uv).rgb;
|
||||
|
||||
vec4 clr = COMPAT_TEXTURE(iChannel0, uv);
|
||||
float W = 1.0 / 15.0;
|
||||
|
||||
clr.rgb=
|
||||
(N0 * W) +
|
||||
(N1 * W) +
|
||||
(N2 * W) +
|
||||
(N3 * W) +
|
||||
(N4 * W) +
|
||||
(N5 * W) +
|
||||
(N6 * W) +
|
||||
(N7 * W) +
|
||||
(N8 * W) +
|
||||
(N9 * W) +
|
||||
(N10 * W) +
|
||||
(N11 * W) +
|
||||
(N12 * W) +
|
||||
(N13 * W) +
|
||||
(N14 * W);
|
||||
return vec3(clr.xyz)*b;
|
||||
}
|
||||
|
||||
float onOff(float a, float b, float c, float framecount)
|
||||
{
|
||||
return step(c, sin((framecount * 0.001) + a*cos((framecount * 0.001)*b)));
|
||||
}
|
||||
|
||||
vec2 jumpy(vec2 uv, float framecount)
|
||||
{
|
||||
vec2 look = uv;
|
||||
float window = 1./(1.+80.*(look.y-mod(framecount/4.,1.))*(look.y-mod(framecount/4.,1.)));
|
||||
look.x += 0.05 * sin(look.y*10. + framecount)/20.*onOff(4.,4.,.3, framecount)*(0.5+cos(framecount*20.))*window;
|
||||
float vShift = (0.1*wiggle) * 0.4*onOff(2.,3.,.9, framecount)*(sin(framecount)*sin(framecount*20.) +
|
||||
(0.5 + 0.1*sin(framecount*200.)*cos(framecount)));
|
||||
look.y = mod(look.y - 0.01 * vShift, 1.);
|
||||
return look;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
float timer = (float(FrameDirection) > 0.5) ? float(FrameCount) : 0.0;
|
||||
float d = 0.1 - ceil(mod(iTime/3.0,1.0) + 0.5) * 0.1;
|
||||
vec2 uv = jumpy(vTexCoord.xy, iTime);
|
||||
vec2 uv2 = uv;
|
||||
|
||||
float s = 0.0001 * -d + 0.0001 * wiggle * sin(iTime);
|
||||
|
||||
float e = min(.30,pow(max(0.0,cos(uv.y*4.0+.3)-.75)*(s+0.5)*1.0,3.0))*25.0;
|
||||
float r = (iTime*(2.0*s));
|
||||
uv.x+=abs(r*pow(min(.003,(-uv.y+(.01*mod(iTime, 17.0))))*3.0,2.0));
|
||||
|
||||
d=.051+abs(sin(s/4.0));
|
||||
float c = max(0.0001,.002*d) * smear;
|
||||
vec2 uvo = uv;
|
||||
vec4 final;
|
||||
final.xyz =Blur(uv,c+c*(uv.x));
|
||||
float y = rgb2yiq(final.xyz).r;
|
||||
|
||||
uv.x+=.01*d;
|
||||
c*=6.0;
|
||||
final.xyz =Blur(uv,c);
|
||||
float i = rgb2yiq(final.xyz).g;
|
||||
|
||||
uv.x+=.005*d;
|
||||
|
||||
c*=2.50;
|
||||
final.xyz =Blur(uv,c);
|
||||
float q = rgb2yiq(final.xyz).b;
|
||||
final = vec4(yiq2rgb(vec3(y,i,q))-pow(s+e*2.0,3.0), 1.0);
|
||||
|
||||
vec4 play_osd = COMPAT_TEXTURE(play, uv2 * TextureSize.xy / InputSize.xy);
|
||||
float show_overlay = (mod(timer, 100.0) < 50.0) && (timer != 0.0) && (timer < 500.0) ? play_osd.a : 0.0;
|
||||
show_overlay = clamp(show_overlay, 0.0, 1.0);
|
||||
final = mix(final, play_osd, show_overlay);
|
||||
|
||||
FragColor = final;
|
||||
}
|
||||
#endif
|
||||
)"
|
377
src/video/shaders/xbrz.glsl
Normal file
377
src/video/shaders/xbrz.glsl
Normal file
|
@ -0,0 +1,377 @@
|
|||
R"(
|
||||
/*
|
||||
Hyllian's xBR-vertex code and texel mapping
|
||||
|
||||
Copyright (C) 2011/2016 Hyllian - sergiogdb@gmail.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// This shader also uses code and/or concepts from xBRZ as it appears
|
||||
// in the Desmume source code. The license for which is as follows:
|
||||
|
||||
// ****************************************************************************
|
||||
// * This file is part of the HqMAME project. It is distributed under *
|
||||
// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 *
|
||||
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
|
||||
// * *
|
||||
// * Additionally and as a special exception, the author gives permission *
|
||||
// * to link the code of this program with the MAME library (or with modified *
|
||||
// * versions of MAME that use the same license as MAME), and distribute *
|
||||
// * linked combinations including the two. You must obey the GNU General *
|
||||
// * Public License in all respects for all of the code used other than MAME. *
|
||||
// * If you modify this file, you may extend this exception to your version *
|
||||
// * of the file, but you are not obligated to do so. If you do not wish to *
|
||||
// * do so, delete this exception statement from your version. *
|
||||
// ****************************************************************************
|
||||
|
||||
#if defined(VERTEX)
|
||||
|
||||
#if __VERSION__ >= 130
|
||||
#define COMPAT_VARYING out
|
||||
#define COMPAT_ATTRIBUTE in
|
||||
#define COMPAT_TEXTURE texture
|
||||
#else
|
||||
#define COMPAT_VARYING varying
|
||||
#define COMPAT_ATTRIBUTE attribute
|
||||
#define COMPAT_TEXTURE texture2D
|
||||
#endif
|
||||
|
||||
#ifdef GL_ES
|
||||
#define COMPAT_PRECISION mediump
|
||||
#else
|
||||
#define COMPAT_PRECISION
|
||||
#endif
|
||||
|
||||
COMPAT_ATTRIBUTE vec4 VertexCoord;
|
||||
COMPAT_ATTRIBUTE vec4 COLOR;
|
||||
COMPAT_ATTRIBUTE vec4 TexCoord;
|
||||
COMPAT_VARYING vec4 COL0;
|
||||
COMPAT_VARYING vec4 TEX0;
|
||||
|
||||
vec4 _oPosition1;
|
||||
uniform mat4 MVPMatrix;
|
||||
uniform COMPAT_PRECISION int FrameDirection;
|
||||
uniform COMPAT_PRECISION int FrameCount;
|
||||
uniform COMPAT_PRECISION vec2 OutputSize;
|
||||
uniform COMPAT_PRECISION vec2 TextureSize;
|
||||
uniform COMPAT_PRECISION vec2 InputSize;
|
||||
|
||||
// compatibility #defines
|
||||
#define vTexCoord TEX0.xy
|
||||
#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
|
||||
#define OutSize vec4(OutputSize, 1.0 / OutputSize)
|
||||
|
||||
#ifdef PARAMETER_UNIFORM
|
||||
uniform COMPAT_PRECISION float WHATEVER;
|
||||
#else
|
||||
#define WHATEVER 0.0
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = MVPMatrix * VertexCoord;
|
||||
TEX0.xy = TexCoord.xy * 1.0001;
|
||||
}
|
||||
|
||||
#elif defined(FRAGMENT)
|
||||
|
||||
#ifdef GL_ES
|
||||
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
||||
precision highp float;
|
||||
#else
|
||||
precision mediump float;
|
||||
#endif
|
||||
#define COMPAT_PRECISION mediump
|
||||
#else
|
||||
#define COMPAT_PRECISION
|
||||
#endif
|
||||
|
||||
#if __VERSION__ >= 130
|
||||
#define COMPAT_VARYING in
|
||||
#define COMPAT_TEXTURE texture
|
||||
out COMPAT_PRECISION vec4 FragColor;
|
||||
#else
|
||||
#define COMPAT_VARYING varying
|
||||
#define FragColor gl_FragColor
|
||||
#define COMPAT_TEXTURE texture2D
|
||||
#endif
|
||||
|
||||
uniform COMPAT_PRECISION int FrameDirection;
|
||||
uniform COMPAT_PRECISION int FrameCount;
|
||||
uniform COMPAT_PRECISION vec2 OutputSize;
|
||||
uniform COMPAT_PRECISION vec2 TextureSize;
|
||||
uniform COMPAT_PRECISION vec2 InputSize;
|
||||
uniform sampler2D Texture;
|
||||
COMPAT_VARYING vec4 TEX0;
|
||||
|
||||
// compatibility #defines
|
||||
#define Source Texture
|
||||
#define vTexCoord TEX0.xy
|
||||
|
||||
#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
|
||||
#define OutSize vec4(OutputSize, 1.0 / OutputSize)
|
||||
|
||||
#define BLEND_NONE 0
|
||||
#define BLEND_NORMAL 1
|
||||
#define BLEND_DOMINANT 2
|
||||
#define LUMINANCE_WEIGHT 1.0
|
||||
#define EQUAL_COLOR_TOLERANCE 30.0/255.0
|
||||
#define STEEP_DIRECTION_THRESHOLD 2.2
|
||||
#define DOMINANT_DIRECTION_THRESHOLD 3.6
|
||||
|
||||
float DistYCbCr(vec3 pixA, vec3 pixB)
|
||||
{
|
||||
const vec3 w = vec3(0.2627, 0.6780, 0.0593);
|
||||
const float scaleB = 0.5 / (1.0 - w.b);
|
||||
const float scaleR = 0.5 / (1.0 - w.r);
|
||||
vec3 diff = pixA - pixB;
|
||||
float Y = dot(diff.rgb, w);
|
||||
float Cb = scaleB * (diff.b - Y);
|
||||
float Cr = scaleR * (diff.r - Y);
|
||||
|
||||
return sqrt(((LUMINANCE_WEIGHT * Y) * (LUMINANCE_WEIGHT * Y)) + (Cb * Cb) + (Cr * Cr));
|
||||
}
|
||||
|
||||
bool IsPixEqual(const vec3 pixA, const vec3 pixB)
|
||||
{
|
||||
return (DistYCbCr(pixA, pixB) < EQUAL_COLOR_TOLERANCE);
|
||||
}
|
||||
|
||||
float get_left_ratio(vec2 center, vec2 origin, vec2 direction, vec2 scale)
|
||||
{
|
||||
vec2 P0 = center - origin;
|
||||
vec2 proj = direction * (dot(P0, direction) / dot(direction, direction));
|
||||
vec2 distv = P0 - proj;
|
||||
vec2 orth = vec2(-direction.y, direction.x);
|
||||
float side = sign(dot(P0, orth));
|
||||
float v = side * length(distv * scale);
|
||||
|
||||
// return step(0, v);
|
||||
return smoothstep(-sqrt(2.0)/2.0, sqrt(2.0)/2.0, v);
|
||||
}
|
||||
|
||||
#define eq(a,b) (a == b)
|
||||
#define neq(a,b) (a != b)
|
||||
|
||||
#define P(x,y) COMPAT_TEXTURE(Source, coord + SourceSize.zw * vec2(x, y)).rgb
|
||||
|
||||
void main()
|
||||
{
|
||||
//---------------------------------------
|
||||
// Input Pixel Mapping: -|x|x|x|-
|
||||
// x|A|B|C|x
|
||||
// x|D|E|F|x
|
||||
// x|G|H|I|x
|
||||
// -|x|x|x|-
|
||||
|
||||
vec2 scale = OutputSize.xy * SourceSize.zw;
|
||||
vec2 pos = fract(vTexCoord * SourceSize.xy) - vec2(0.5, 0.5);
|
||||
vec2 coord = vTexCoord - pos * SourceSize.zw;
|
||||
|
||||
vec3 A = P(-1.,-1.);
|
||||
vec3 B = P( 0.,-1.);
|
||||
vec3 C = P( 1.,-1.);
|
||||
vec3 D = P(-1., 0.);
|
||||
vec3 E = P( 0., 0.);
|
||||
vec3 F = P( 1., 0.);
|
||||
vec3 G = P(-1., 1.);
|
||||
vec3 H = P( 0., 1.);
|
||||
vec3 I = P( 1., 1.);
|
||||
|
||||
// blendResult Mapping: x|y|
|
||||
// w|z|
|
||||
ivec4 blendResult = ivec4(BLEND_NONE,BLEND_NONE,BLEND_NONE,BLEND_NONE);
|
||||
|
||||
// Preprocess corners
|
||||
// Pixel Tap Mapping: -|-|-|-|-
|
||||
// -|-|B|C|-
|
||||
// -|D|E|F|x
|
||||
// -|G|H|I|x
|
||||
// -|-|x|x|-
|
||||
if (!((eq(E,F) && eq(H,I)) || (eq(E,H) && eq(F,I))))
|
||||
{
|
||||
float dist_H_F = DistYCbCr(G, E) + DistYCbCr(E, C) + DistYCbCr(P(0,2), I) + DistYCbCr(I, P(2.,0.)) + (4.0 * DistYCbCr(H, F));
|
||||
float dist_E_I = DistYCbCr(D, H) + DistYCbCr(H, P(1,2)) + DistYCbCr(B, F) + DistYCbCr(F, P(2.,1.)) + (4.0 * DistYCbCr(E, I));
|
||||
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_H_F) < dist_E_I;
|
||||
blendResult.z = ((dist_H_F < dist_E_I) && neq(E,F) && neq(E,H)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
|
||||
}
|
||||
|
||||
|
||||
// Pixel Tap Mapping: -|-|-|-|-
|
||||
// -|A|B|-|-
|
||||
// x|D|E|F|-
|
||||
// x|G|H|I|-
|
||||
// -|x|x|-|-
|
||||
if (!((eq(D,E) && eq(G,H)) || (eq(D,G) && eq(E,H))))
|
||||
{
|
||||
float dist_G_E = DistYCbCr(P(-2.,1.) , D) + DistYCbCr(D, B) + DistYCbCr(P(-1.,2.), H) + DistYCbCr(H, F) + (4.0 * DistYCbCr(G, E));
|
||||
float dist_D_H = DistYCbCr(P(-2.,0.) , G) + DistYCbCr(G, P(0.,2.)) + DistYCbCr(A, E) + DistYCbCr(E, I) + (4.0 * DistYCbCr(D, H));
|
||||
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_D_H) < dist_G_E;
|
||||
blendResult.w = ((dist_G_E > dist_D_H) && neq(E,D) && neq(E,H)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
|
||||
}
|
||||
|
||||
// Pixel Tap Mapping: -|-|x|x|-
|
||||
// -|A|B|C|x
|
||||
// -|D|E|F|x
|
||||
// -|-|H|I|-
|
||||
// -|-|-|-|-
|
||||
if (!((eq(B,C) && eq(E,F)) || (eq(B,E) && eq(C,F))))
|
||||
{
|
||||
float dist_E_C = DistYCbCr(D, B) + DistYCbCr(B, P(1.,-2.)) + DistYCbCr(H, F) + DistYCbCr(F, P(2.,-1.)) + (4.0 * DistYCbCr(E, C));
|
||||
float dist_B_F = DistYCbCr(A, E) + DistYCbCr(E, I) + DistYCbCr(P(0.,-2.), C) + DistYCbCr(C, P(2.,0.)) + (4.0 * DistYCbCr(B, F));
|
||||
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_B_F) < dist_E_C;
|
||||
blendResult.y = ((dist_E_C > dist_B_F) && neq(E,B) && neq(E,F)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
|
||||
}
|
||||
|
||||
// Pixel Tap Mapping: -|x|x|-|-
|
||||
// x|A|B|C|-
|
||||
// x|D|E|F|-
|
||||
// -|G|H|-|-
|
||||
// -|-|-|-|-
|
||||
if (!((eq(A,B) && eq(D,E)) || (eq(A,D) && eq(B,E))))
|
||||
{
|
||||
float dist_D_B = DistYCbCr(P(-2.,0.), A) + DistYCbCr(A, P(0.,-2.)) + DistYCbCr(G, E) + DistYCbCr(E, C) + (4.0 * DistYCbCr(D, B));
|
||||
float dist_A_E = DistYCbCr(P(-2.,-1.), D) + DistYCbCr(D, H) + DistYCbCr(P(-1.,-2.), B) + DistYCbCr(B, F) + (4.0 * DistYCbCr(A, E));
|
||||
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_D_B) < dist_A_E;
|
||||
blendResult.x = ((dist_D_B < dist_A_E) && neq(E,D) && neq(E,B)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
|
||||
}
|
||||
|
||||
vec3 res = E;
|
||||
|
||||
// Pixel Tap Mapping: -|-|-|-|-
|
||||
// -|-|B|C|-
|
||||
// -|D|E|F|x
|
||||
// -|G|H|I|x
|
||||
// -|-|x|x|-
|
||||
if(blendResult.z != BLEND_NONE)
|
||||
{
|
||||
float dist_F_G = DistYCbCr(F, G);
|
||||
float dist_H_C = DistYCbCr(H, C);
|
||||
bool doLineBlend = (blendResult.z == BLEND_DOMINANT ||
|
||||
!((blendResult.y != BLEND_NONE && !IsPixEqual(E, G)) || (blendResult.w != BLEND_NONE && !IsPixEqual(E, C)) ||
|
||||
(IsPixEqual(G, H) && IsPixEqual(H, I) && IsPixEqual(I, F) && IsPixEqual(F, C) && !IsPixEqual(E, I))));
|
||||
|
||||
vec2 origin = vec2(0.0, 1.0 / sqrt(2.0));
|
||||
vec2 direction = vec2(1.0, -1.0);
|
||||
if(doLineBlend)
|
||||
{
|
||||
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_F_G <= dist_H_C) && neq(E,G) && neq(D,G);
|
||||
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_H_C <= dist_F_G) && neq(E,C) && neq(B,C);
|
||||
origin = haveShallowLine? vec2(0.0, 0.25) : vec2(0.0, 0.5);
|
||||
direction.x += haveShallowLine? 1.0: 0.0;
|
||||
direction.y -= haveSteepLine? 1.0: 0.0;
|
||||
}
|
||||
|
||||
vec3 blendPix = mix(H,F, step(DistYCbCr(E, F), DistYCbCr(E, H)));
|
||||
res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale));
|
||||
}
|
||||
|
||||
// Pixel Tap Mapping: -|-|-|-|-
|
||||
// -|A|B|-|-
|
||||
// x|D|E|F|-
|
||||
// x|G|H|I|-
|
||||
// -|x|x|-|-
|
||||
if(blendResult.w != BLEND_NONE)
|
||||
{
|
||||
float dist_H_A = DistYCbCr(H, A);
|
||||
float dist_D_I = DistYCbCr(D, I);
|
||||
bool doLineBlend = (blendResult.w == BLEND_DOMINANT ||
|
||||
!((blendResult.z != BLEND_NONE && !IsPixEqual(E, A)) || (blendResult.x != BLEND_NONE && !IsPixEqual(E, I)) ||
|
||||
(IsPixEqual(A, D) && IsPixEqual(D, G) && IsPixEqual(G, H) && IsPixEqual(H, I) && !IsPixEqual(E, G))));
|
||||
|
||||
vec2 origin = vec2(-1.0 / sqrt(2.0), 0.0);
|
||||
vec2 direction = vec2(1.0, 1.0);
|
||||
if(doLineBlend)
|
||||
{
|
||||
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_H_A <= dist_D_I) && neq(E,A) && neq(B,A);
|
||||
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_D_I <= dist_H_A) && neq(E,I) && neq(F,I);
|
||||
origin = haveShallowLine? vec2(-0.25, 0.0) : vec2(-0.5, 0.0);
|
||||
direction.y += haveShallowLine? 1.0: 0.0;
|
||||
direction.x += haveSteepLine? 1.0: 0.0;
|
||||
}
|
||||
origin = origin;
|
||||
direction = direction;
|
||||
|
||||
vec3 blendPix = mix(H,D, step(DistYCbCr(E, D), DistYCbCr(E, H)));
|
||||
res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale));
|
||||
}
|
||||
|
||||
// Pixel Tap Mapping: -|-|x|x|-
|
||||
// -|A|B|C|x
|
||||
// -|D|E|F|x
|
||||
// -|-|H|I|-
|
||||
// -|-|-|-|-
|
||||
if(blendResult.y != BLEND_NONE)
|
||||
{
|
||||
float dist_B_I = DistYCbCr(B, I);
|
||||
float dist_F_A = DistYCbCr(F, A);
|
||||
bool doLineBlend = (blendResult.y == BLEND_DOMINANT ||
|
||||
!((blendResult.x != BLEND_NONE && !IsPixEqual(E, I)) || (blendResult.z != BLEND_NONE && !IsPixEqual(E, A)) ||
|
||||
(IsPixEqual(I, F) && IsPixEqual(F, C) && IsPixEqual(C, B) && IsPixEqual(B, A) && !IsPixEqual(E, C))));
|
||||
|
||||
vec2 origin = vec2(1.0 / sqrt(2.0), 0.0);
|
||||
vec2 direction = vec2(-1.0, -1.0);
|
||||
|
||||
if(doLineBlend)
|
||||
{
|
||||
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_B_I <= dist_F_A) && neq(E,I) && neq(H,I);
|
||||
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_F_A <= dist_B_I) && neq(E,A) && neq(D,A);
|
||||
origin = haveShallowLine? vec2(0.25, 0.0) : vec2(0.5, 0.0);
|
||||
direction.y -= haveShallowLine? 1.0: 0.0;
|
||||
direction.x -= haveSteepLine? 1.0: 0.0;
|
||||
}
|
||||
|
||||
vec3 blendPix = mix(F,B, step(DistYCbCr(E, B), DistYCbCr(E, F)));
|
||||
res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale));
|
||||
}
|
||||
|
||||
// Pixel Tap Mapping: -|x|x|-|-
|
||||
// x|A|B|C|-
|
||||
// x|D|E|F|-
|
||||
// -|G|H|-|-
|
||||
// -|-|-|-|-
|
||||
if(blendResult.x != BLEND_NONE)
|
||||
{
|
||||
float dist_D_C = DistYCbCr(D, C);
|
||||
float dist_B_G = DistYCbCr(B, G);
|
||||
bool doLineBlend = (blendResult.x == BLEND_DOMINANT ||
|
||||
!((blendResult.w != BLEND_NONE && !IsPixEqual(E, C)) || (blendResult.y != BLEND_NONE && !IsPixEqual(E, G)) ||
|
||||
(IsPixEqual(C, B) && IsPixEqual(B, A) && IsPixEqual(A, D) && IsPixEqual(D, G) && !IsPixEqual(E, A))));
|
||||
|
||||
vec2 origin = vec2(0.0, -1.0 / sqrt(2.0));
|
||||
vec2 direction = vec2(-1.0, 1.0);
|
||||
if(doLineBlend)
|
||||
{
|
||||
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_D_C <= dist_B_G) && neq(E,C) && neq(F,C);
|
||||
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_B_G <= dist_D_C) && neq(E,G) && neq(H,G);
|
||||
origin = haveShallowLine? vec2(0.0, -0.25) : vec2(0.0, -0.5);
|
||||
direction.x -= haveShallowLine? 1.0: 0.0;
|
||||
direction.y += haveSteepLine? 1.0: 0.0;
|
||||
}
|
||||
|
||||
vec3 blendPix = mix(D,B, step(DistYCbCr(E, B), DistYCbCr(E, D)));
|
||||
res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale));
|
||||
}
|
||||
|
||||
FragColor = vec4(res, 1.0);
|
||||
}
|
||||
#endif
|
||||
)"
|
Loading…
Reference in a new issue