Merge branch 'svn/trunk' r4319
This commit is contained in:
commit
be6b446028
7 changed files with 1026 additions and 29 deletions
|
@ -80,11 +80,15 @@ typedef struct {
|
|||
Bit8u *cacheRead;
|
||||
Bitu inHeight, inLine, outLine;
|
||||
} scale;
|
||||
#if C_OPENGL
|
||||
char* shader_src;
|
||||
#endif
|
||||
RenderPal_t pal;
|
||||
bool updating;
|
||||
bool active;
|
||||
bool aspect;
|
||||
bool fullFrame;
|
||||
bool forceUpdate;
|
||||
} Render_t;
|
||||
|
||||
extern Render_t render;
|
||||
|
@ -93,6 +97,8 @@ void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,float fps,double ratio,bool
|
|||
bool RENDER_StartUpdate(void);
|
||||
void RENDER_EndUpdate(bool abort);
|
||||
void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue);
|
||||
bool RENDER_GetForceUpdate(void);
|
||||
void RENDER_SetForceUpdate(bool);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -51,6 +51,7 @@ void GFX_Events(void);
|
|||
Bitu GFX_GetBestMode(Bitu flags);
|
||||
Bitu GFX_GetRGB(Bit8u red,Bit8u green,Bit8u blue);
|
||||
Bitu GFX_SetSize(Bitu width,Bitu height,Bitu flags,double scalex,double scaley,GFX_CallBack_t cb);
|
||||
void GFX_SetShader(const char* src);
|
||||
|
||||
void GFX_ResetScreen(void);
|
||||
void GFX_Start(void);
|
||||
|
|
|
@ -471,6 +471,14 @@ void DOSBOX_Init(void) {
|
|||
const char* force[] = { "", "forced", 0 };
|
||||
Pstring = Pmulti->GetSection()->Add_string("force",Property::Changeable::Always,"");
|
||||
Pstring->Set_values(force);
|
||||
#if C_OPENGL
|
||||
Pstring = secprop->Add_path("glshader",Property::Changeable::Always,"none");
|
||||
Pstring->Set_help("Path to GLSL shader source to use with OpenGL output (\"none\" to disable).\n"
|
||||
"Can be either an absolute path, a file in the \"glshaders\" subdirectory\n"
|
||||
"of the DOSBox configuration directory, or one of the built-in shaders:\n"
|
||||
"advinterp2x, advinterp3x, advmame2x, advmame3x, rgb2x, rgb3x, scan2x,\n"
|
||||
"scan3x, tv2x, tv3x, sharp.");
|
||||
#endif
|
||||
|
||||
secprop=control->AddSection_prop("cpu",&CPU_Init,true);//done
|
||||
const char* cores[] = { "auto",
|
||||
|
|
|
@ -7,5 +7,5 @@ libgui_a_SOURCES = sdlmain.cpp sdl_mapper.cpp dosbox_logo.h \
|
|||
render_templates_sai.h render_templates_hq.h \
|
||||
render_templates_hq2x.h render_templates_hq3x.h \
|
||||
midi.cpp midi_win32.h midi_oss.h midi_coreaudio.h midi_alsa.h \
|
||||
midi_coremidi.h sdl_gui.cpp dosbox_splash.h
|
||||
midi_coremidi.h sdl_gui.cpp dosbox_splash.h render_glsl.h
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "dosbox.h"
|
||||
#include "video.h"
|
||||
|
@ -30,8 +32,10 @@
|
|||
#include "cross.h"
|
||||
#include "hardware.h"
|
||||
#include "support.h"
|
||||
#include "shell.h"
|
||||
|
||||
#include "render_scalers.h"
|
||||
#include "render_glsl.h"
|
||||
|
||||
Render_t render;
|
||||
ScalerLineHandler_t RENDER_DrawLine;
|
||||
|
@ -228,6 +232,7 @@ void RENDER_EndUpdate( bool abort ) {
|
|||
total += render.frameskip.hadSkip[i];
|
||||
LOG_MSG( "Skipped frame %d %d", PIC_Ticks, (total * 100) / RENDER_SKIP_CACHE );
|
||||
#endif
|
||||
if (RENDER_GetForceUpdate()) GFX_EndUpdate(0);
|
||||
}
|
||||
render.frameskip.index = (render.frameskip.index + 1) & (RENDER_SKIP_CACHE - 1);
|
||||
render.updating=false;
|
||||
|
@ -427,6 +432,9 @@ forcenormal:
|
|||
}
|
||||
}
|
||||
/* Setup the scaler variables */
|
||||
#if C_OPENGL
|
||||
GFX_SetShader(render.shader_src);
|
||||
#endif
|
||||
gfx_flags=GFX_SetSize(width,height,gfx_flags,gfx_scalew,gfx_scaleh,&RENDER_CallBack);
|
||||
if (gfx_flags & GFX_CAN_8)
|
||||
render.scale.outMode = scalerMode8;
|
||||
|
@ -571,6 +579,76 @@ static void ChangeScaler(bool pressed) {
|
|||
RENDER_CallBack( GFX_CallBackReset );
|
||||
} */
|
||||
|
||||
bool RENDER_GetForceUpdate(void) {
|
||||
return render.forceUpdate;
|
||||
}
|
||||
|
||||
void RENDER_SetForceUpdate(bool f) {
|
||||
render.forceUpdate = f;
|
||||
}
|
||||
|
||||
#if C_OPENGL
|
||||
static bool RENDER_GetShader(std::string& shader_path) {
|
||||
char* src;
|
||||
std::stringstream buf;
|
||||
std::ifstream fshader(shader_path.c_str(), std::ios_base::binary);
|
||||
if (!fshader.is_open()) fshader.open((shader_path + ".glsl").c_str(), std::ios_base::binary);
|
||||
if (fshader.is_open()) {
|
||||
buf << fshader.rdbuf();
|
||||
fshader.close();
|
||||
}
|
||||
else if (shader_path == "advinterp2x") buf << advinterp2x_glsl;
|
||||
else if (shader_path == "advinterp3x") buf << advinterp3x_glsl;
|
||||
else if (shader_path == "advmame2x") buf << advmame2x_glsl;
|
||||
else if (shader_path == "advmame3x") buf << advmame3x_glsl;
|
||||
else if (shader_path == "rgb2x") buf << rgb2x_glsl;
|
||||
else if (shader_path == "rgb3x") buf << rgb3x_glsl;
|
||||
else if (shader_path == "scan2x") buf << scan2x_glsl;
|
||||
else if (shader_path == "scan3x") buf << scan3x_glsl;
|
||||
else if (shader_path == "tv2x") buf << tv2x_glsl;
|
||||
else if (shader_path == "tv3x") buf << tv3x_glsl;
|
||||
else if (shader_path == "sharp") buf << sharp_glsl;
|
||||
|
||||
if (!buf.str().empty()) {
|
||||
std::string s = buf.str();
|
||||
if (first_shell) {
|
||||
std::string pre_defs;
|
||||
Bitu count = first_shell->GetEnvCount();
|
||||
for (Bitu i=0; i < count; i++) {
|
||||
std::string env;
|
||||
if (!first_shell->GetEnvNum(i, env))
|
||||
continue;
|
||||
if (env.compare(0, 9, "GLSHADER_")==0) {
|
||||
size_t brk = s.find('=');
|
||||
if (brk == std::string::npos) continue;
|
||||
env[brk] = ' ';
|
||||
pre_defs += "#define " + env.substr(0) + '\n';
|
||||
}
|
||||
}
|
||||
if (!pre_defs.empty()) {
|
||||
// if "#version" occurs it must be before anything except comments and whitespace
|
||||
size_t pos = buf.str().find("#version ");
|
||||
if (pos != std::string::npos) pos = buf.str().find('\n', pos+9);
|
||||
if (pos == std::string::npos) pos = 0;
|
||||
else ++pos;
|
||||
s = buf.str().insert(pos, pre_defs);
|
||||
}
|
||||
}
|
||||
// keep the same buffer if contents aren't different
|
||||
if (render.shader_src==NULL || s != render.shader_src) {
|
||||
src = strdup(s.c_str());
|
||||
if (src==NULL) LOG_MSG("WARNING: Couldn't copy shader source");
|
||||
} else {
|
||||
src = render.shader_src;
|
||||
render.shader_src = NULL;
|
||||
}
|
||||
} else src = NULL;
|
||||
free(render.shader_src);
|
||||
render.shader_src = src;
|
||||
return src != NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
void RENDER_Init(Section * sec) {
|
||||
Section_prop * section=static_cast<Section_prop *>(sec);
|
||||
|
||||
|
@ -624,10 +702,31 @@ void RENDER_Init(Section * sec) {
|
|||
else if (scaler == "scan3x"){ render.scale.op = scalerOpScan;render.scale.size = 3; }
|
||||
#endif
|
||||
|
||||
#if C_OPENGL
|
||||
char* shader_src = render.shader_src;
|
||||
Prop_path *sh = section->Get_path("glshader");
|
||||
f = (std::string)sh->GetValue();
|
||||
if (f.empty() || f=="none") {
|
||||
free(render.shader_src);
|
||||
render.shader_src = NULL;
|
||||
} else if (!RENDER_GetShader(sh->realpath)) {
|
||||
std::string path;
|
||||
Cross::GetPlatformConfigDir(path);
|
||||
path = path + "glshaders" + CROSS_FILESPLIT + f;
|
||||
if (!RENDER_GetShader(path) && (sh->realpath==f || !RENDER_GetShader(f))) {
|
||||
sh->SetValue("none");
|
||||
LOG_MSG("Shader file \"%s\" not found", f.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//If something changed that needs a ReInit
|
||||
// Only ReInit when there is a src.bpp (fixes crashes on startup and directly changing the scaler without a screen specified yet)
|
||||
if(running && render.src.bpp && ((render.aspect != aspect) || (render.scale.op != scaleOp) ||
|
||||
(render.scale.size != scalersize) || (render.scale.forced != scalerforced) ||
|
||||
#if C_OPENGL
|
||||
(render.shader_src != shader_src) ||
|
||||
#endif
|
||||
render.scale.forced))
|
||||
RENDER_CallBack( GFX_CallBackReset );
|
||||
|
||||
|
|
576
src/gui/render_glsl.h
Normal file
576
src/gui/render_glsl.h
Normal file
|
@ -0,0 +1,576 @@
|
|||
/*
|
||||
* Copyright (C) 2002-2019 The DOSBox Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#if C_OPENGL
|
||||
|
||||
static const char advinterp2x_glsl[] =
|
||||
"varying vec2 v_texCoord;\n"
|
||||
"uniform sampler2D rubyTexture;\n"
|
||||
"uniform vec2 rubyInputSize;\n"
|
||||
"uniform vec2 rubyOutputSize;\n"
|
||||
"uniform vec2 rubyTextureSize;\n"
|
||||
""
|
||||
"#if defined(VERTEX)\n"
|
||||
"attribute vec4 a_position;\n"
|
||||
""
|
||||
"void main() {\n"
|
||||
" gl_Position = a_position;\n"
|
||||
" v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)*rubyInputSize;\n"
|
||||
"}\n"
|
||||
""
|
||||
"#elif defined(FRAGMENT)\n"
|
||||
""
|
||||
"vec3 getadvinterp2xtexel(vec2 coord) {\n"
|
||||
" vec2 base = floor(coord/vec2(2.0))+vec2(0.5);\n"
|
||||
" vec3 c4 = texture2D(rubyTexture, base/rubyTextureSize).xyz;\n"
|
||||
" vec3 c1 = texture2D(rubyTexture, (base-vec2(0.0,1.0))/rubyTextureSize).xyz;\n"
|
||||
" vec3 c7 = texture2D(rubyTexture, (base+vec2(0.0,1.0))/rubyTextureSize).xyz;\n"
|
||||
" vec3 c3 = texture2D(rubyTexture, (base-vec2(1.0,0.0))/rubyTextureSize).xyz;\n"
|
||||
" vec3 c5 = texture2D(rubyTexture, (base+vec2(1.0,0.0))/rubyTextureSize).xyz;\n"
|
||||
""
|
||||
" bool outer = c1 != c7 && c3 != c5;\n"
|
||||
" bool c3c1 = outer && c3==c1;\n"
|
||||
" bool c1c5 = outer && c1==c5;\n"
|
||||
" bool c3c7 = outer && c3==c7;\n"
|
||||
" bool c7c5 = outer && c7==c5;\n"
|
||||
""
|
||||
" vec3 l00 = mix(c3,c4,c3c1?3.0/8.0:1.0);\n"
|
||||
" vec3 l01 = mix(c5,c4,c1c5?3.0/8.0:1.0);\n"
|
||||
" vec3 l10 = mix(c3,c4,c3c7?3.0/8.0:1.0);\n"
|
||||
" vec3 l11 = mix(c5,c4,c7c5?3.0/8.0:1.0);\n"
|
||||
""
|
||||
" coord = max(floor(mod(coord, 2.0)), 0.0);\n"
|
||||
" /* 2x2 output:\n"
|
||||
" * |x=0|x=1\n"
|
||||
" * y=0|l00|l01\n"
|
||||
" * y=1|l10|l11\n"
|
||||
" */\n"
|
||||
""
|
||||
" return mix(mix(l00,l01,coord.x), mix(l10,l11,coord.x), coord.y);\n"
|
||||
"}\n"
|
||||
""
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec2 coord = v_texCoord;\n"
|
||||
"#if defined(OPENGLNB)\n"
|
||||
" gl_FragColor = getadvinterp2xtexel(coord);\n"
|
||||
"#else\n"
|
||||
" coord -= 0.5;\n"
|
||||
" vec3 c0 = getadvinterp2xtexel(coord);\n"
|
||||
" vec3 c1 = getadvinterp2xtexel(coord+vec2(1.0,0.0));\n"
|
||||
" vec3 c2 = getadvinterp2xtexel(coord+vec2(0.0,1.0));\n"
|
||||
" vec3 c3 = getadvinterp2xtexel(coord+vec2(1.0));\n"
|
||||
""
|
||||
" coord = fract(max(coord,0.0));\n"
|
||||
" gl_FragColor = vec4(mix(mix(c0,c1,coord.x), mix(c2,c3,coord.x), coord.y), 1.0);\n"
|
||||
"#endif\n"
|
||||
"}\n"
|
||||
"#endif";
|
||||
|
||||
static const char advinterp3x_glsl[] =
|
||||
"varying vec2 v_texCoord;\n"
|
||||
"uniform sampler2D rubyTexture;\n"
|
||||
"uniform vec2 rubyInputSize;\n"
|
||||
"uniform vec2 rubyOutputSize;\n"
|
||||
"uniform vec2 rubyTextureSize;\n"
|
||||
""
|
||||
"#if defined(VERTEX)\n"
|
||||
"attribute vec4 a_position;\n"
|
||||
""
|
||||
"void main() {\n"
|
||||
" gl_Position = a_position;\n"
|
||||
" v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)/2.0*rubyInputSize*3.0;\n"
|
||||
"}\n"
|
||||
""
|
||||
"#elif defined(FRAGMENT)\n"
|
||||
""
|
||||
"vec3 getadvinterp3xtexel(vec2 coord) {\n"
|
||||
" vec2 base = floor(coord/vec2(3.0))+vec2(0.5);\n"
|
||||
" vec3 c0 = texture2D(rubyTexture, (base-vec2(1.0,1.0))/rubyTextureSize).xyz;\n"
|
||||
" vec3 c1 = texture2D(rubyTexture, (base-vec2(0.0,1.0))/rubyTextureSize).xyz;\n"
|
||||
" vec3 c2 = texture2D(rubyTexture, (base-vec2(-1.0,1.0))/rubyTextureSize).xyz;\n"
|
||||
" vec3 c3 = texture2D(rubyTexture, (base-vec2(1.0,0.0))/rubyTextureSize).xyz;\n"
|
||||
" vec3 c4 = texture2D(rubyTexture, base/rubyTextureSize).xyz;\n"
|
||||
" vec3 c5 = texture2D(rubyTexture, (base+vec2(1.0,0.0))/rubyTextureSize).xyz;\n"
|
||||
" vec3 c6 = texture2D(rubyTexture, (base+vec2(-1.0,1.0))/rubyTextureSize).xyz;\n"
|
||||
" vec3 c7 = texture2D(rubyTexture, (base+vec2(0.0,1.0))/rubyTextureSize).xyz;\n"
|
||||
" vec3 c8 = texture2D(rubyTexture, (base+vec2(1.0,1.0))/rubyTextureSize).xyz;\n"
|
||||
""
|
||||
" bool outer = c1 != c7 && c3 != c5;\n"
|
||||
""
|
||||
" vec3 l00 = mix(c3,c4,(outer && c3==c1) ? 3.0/8.0:1.0);\n"
|
||||
" vec3 l01 = (outer && ((c3==c1&&c4!=c2)||(c5==c1&&c4!=c0))) ? c1 : c4;\n"
|
||||
" vec3 l02 = mix(c5,c4,(outer && c5==c1) ? 3.0/8.0:1.0);\n"
|
||||
" vec3 l10 = (outer && ((c3==c1&&c4!=c6)||(c3==c7&&c4!=c0))) ? c3 : c4;\n"
|
||||
" vec3 l11 = c4;\n"
|
||||
" vec3 l12 = (outer && ((c5==c1&&c4!=c8)||(c5==c7&&c4!=c2))) ? c5 : c4;\n"
|
||||
" vec3 l20 = mix(c3,c4,(outer && c3==c7) ? 3.0/8.0:1.0);\n"
|
||||
" vec3 l21 = (outer && ((c3==c7&&c4!=c8)||(c5==c7&&c4!=c6))) ? c7 : c4;\n"
|
||||
" vec3 l22 = mix(c5,c4,(outer && c5==c7) ? 3.0/8.0:1.0);\n"
|
||||
""
|
||||
" coord = mod(coord, 3.0);\n"
|
||||
" bvec2 l = lessThan(coord, vec2(1.0));\n"
|
||||
" bvec2 h = greaterThanEqual(coord, vec2(2.0));\n"
|
||||
""
|
||||
" if (h.x) {\n"
|
||||
" l01 = l02;\n"
|
||||
" l11 = l12;\n"
|
||||
" l21 = l22;\n"
|
||||
" }\n"
|
||||
" if (h.y) {\n"
|
||||
" l10 = l20;\n"
|
||||
" l11 = l21;\n"
|
||||
" }\n"
|
||||
" if (l.x) {\n"
|
||||
" l01 = l00;\n"
|
||||
" l11 = l10;\n"
|
||||
" }\n"
|
||||
" return l.y ? l01 : l11;\n"
|
||||
"}\n"
|
||||
""
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec2 coord = v_texCoord;\n"
|
||||
"#if defined(OPENGLNB)\n"
|
||||
" gl_FragColor = getadvinterp3xtexel(coord);\n"
|
||||
"#else\n"
|
||||
" coord -= 0.5;\n"
|
||||
" vec3 c0 = getadvinterp3xtexel(coord);\n"
|
||||
" vec3 c1 = getadvinterp3xtexel(coord+vec2(1.0,0.0));\n"
|
||||
" vec3 c2 = getadvinterp3xtexel(coord+vec2(0.0,1.0));\n"
|
||||
" vec3 c3 = getadvinterp3xtexel(coord+vec2(1.0));\n"
|
||||
""
|
||||
" coord = fract(max(coord,0.0));\n"
|
||||
" gl_FragColor = vec4(mix(mix(c0,c1,coord.x), mix(c2,c3,coord.x), coord.y), 1.0);\n"
|
||||
"#endif\n"
|
||||
"}\n"
|
||||
"#endif";
|
||||
|
||||
static const char advmame2x_glsl[] =
|
||||
"varying vec2 v_texCoord;\n"
|
||||
"uniform sampler2D rubyTexture;\n"
|
||||
"uniform vec2 rubyInputSize;\n"
|
||||
"uniform vec2 rubyOutputSize;\n"
|
||||
"uniform vec2 rubyTextureSize;\n"
|
||||
""
|
||||
"#if defined(VERTEX)\n"
|
||||
"attribute vec4 a_position;\n"
|
||||
""
|
||||
"void main() {\n"
|
||||
" gl_Position = a_position;\n"
|
||||
" v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)*rubyInputSize;\n"
|
||||
"}\n"
|
||||
""
|
||||
"#elif defined(FRAGMENT)\n"
|
||||
""
|
||||
"vec3 getadvmame2xtexel(vec2 coord) {\n"
|
||||
" vec2 base = floor(coord/vec2(2.0))+vec2(0.5);\n"
|
||||
" vec3 c4 = texture2D(rubyTexture, base/rubyTextureSize).xyz;\n"
|
||||
" vec3 c1 = texture2D(rubyTexture, (base-vec2(0.0,1.0))/rubyTextureSize).xyz;\n"
|
||||
" vec3 c7 = texture2D(rubyTexture, (base+vec2(0.0,1.0))/rubyTextureSize).xyz;\n"
|
||||
" vec3 c3 = texture2D(rubyTexture, (base-vec2(1.0,0.0))/rubyTextureSize).xyz;\n"
|
||||
" vec3 c5 = texture2D(rubyTexture, (base+vec2(1.0,0.0))/rubyTextureSize).xyz;\n"
|
||||
""
|
||||
" bool outer = c1 != c7 && c3 != c5;\n"
|
||||
" bool c3c1 = outer && c3==c1;\n"
|
||||
" bool c1c5 = outer && c1==c5;\n"
|
||||
" bool c3c7 = outer && c3==c7;\n"
|
||||
" bool c7c5 = outer && c7==c5;\n"
|
||||
""
|
||||
" vec3 l00 = mix(c4,c3,c3c1?1.0:0.0);\n"
|
||||
" vec3 l01 = mix(c4,c5,c1c5?1.0:0.0);\n"
|
||||
" vec3 l10 = mix(c4,c3,c3c7?1.0:0.0);\n"
|
||||
" vec3 l11 = mix(c4,c5,c7c5?1.0:0.0);\n"
|
||||
""
|
||||
" coord = max(floor(mod(coord, 2.0)), 0.0);\n"
|
||||
" /* 2x2 output:\n"
|
||||
" * |x=0|x=1\n"
|
||||
" * y=0|l00|l01\n"
|
||||
" * y=1|l10|l11\n"
|
||||
" */\n"
|
||||
""
|
||||
" return mix(mix(l00,l01,coord.x), mix(l10,l11,coord.x), coord.y);\n"
|
||||
"}\n"
|
||||
""
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec2 coord = v_texCoord;\n"
|
||||
"#if defined(OPENGLNB)\n"
|
||||
" gl_FragColor = getadvmame2xtexel(coord);\n"
|
||||
"#else\n"
|
||||
" coord -= 0.5;\n"
|
||||
" vec3 c0 = getadvmame2xtexel(coord);\n"
|
||||
" vec3 c1 = getadvmame2xtexel(coord+vec2(1.0,0.0));\n"
|
||||
" vec3 c2 = getadvmame2xtexel(coord+vec2(0.0,1.0));\n"
|
||||
" vec3 c3 = getadvmame2xtexel(coord+vec2(1.0));\n"
|
||||
""
|
||||
" coord = fract(max(coord,0.0));\n"
|
||||
" gl_FragColor = vec4(mix(mix(c0,c1,coord.x), mix(c2,c3,coord.x), coord.y), 1.0);\n"
|
||||
"#endif\n"
|
||||
"}\n"
|
||||
"#endif";
|
||||
|
||||
static const char advmame3x_glsl[] =
|
||||
"varying vec2 v_texCoord;\n"
|
||||
"uniform sampler2D rubyTexture;\n"
|
||||
"uniform vec2 rubyInputSize;\n"
|
||||
"uniform vec2 rubyOutputSize;\n"
|
||||
"uniform vec2 rubyTextureSize;\n"
|
||||
""
|
||||
"#if defined(VERTEX)\n"
|
||||
"attribute vec4 a_position;\n"
|
||||
""
|
||||
"void main() {\n"
|
||||
" gl_Position = a_position;\n"
|
||||
" v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)/2.0*rubyInputSize*3.0;\n"
|
||||
"}\n"
|
||||
""
|
||||
"#elif defined(FRAGMENT)\n"
|
||||
""
|
||||
"vec3 getadvmame3xtexel(vec2 coord) {\n"
|
||||
" vec2 base = floor(coord/vec2(3.0))+vec2(0.5);\n"
|
||||
" coord = mod(coord, 3.0);\n"
|
||||
" bvec2 l = lessThan(coord, vec2(1.0));\n"
|
||||
" bvec2 h = greaterThanEqual(coord, vec2(2.0));\n"
|
||||
" bvec2 m = equal(l,h);\n"
|
||||
""
|
||||
" vec2 left = vec2(h.x?1.0:-1.0, 0.0);\n"
|
||||
" vec2 up = vec2(0.0, h.y?1.0:-1.0);\n"
|
||||
" if (l==h) left.x = 0.0; // hack for center pixel, will ensure outer==false\n"
|
||||
" if (m.y) {\n"
|
||||
" // swap\n"
|
||||
" left -= up;\n"
|
||||
" up += left;\n"
|
||||
" left = up - left;\n"
|
||||
" }\n"
|
||||
""
|
||||
" vec3 c0 = texture2D(rubyTexture, (base+up+left)/rubyTextureSize).xyz;\n"
|
||||
" vec3 c1 = texture2D(rubyTexture, (base+up)/rubyTextureSize).xyz;\n"
|
||||
" vec3 c2 = texture2D(rubyTexture, (base+up-left)/rubyTextureSize).xyz;\n"
|
||||
" vec3 c3 = texture2D(rubyTexture, (base+left)/rubyTextureSize).xyz;\n"
|
||||
" vec3 c4 = texture2D(rubyTexture, base/rubyTextureSize).xyz;\n"
|
||||
" vec3 c5 = texture2D(rubyTexture, (base-left)/rubyTextureSize).xyz;\n"
|
||||
" vec3 c7 = texture2D(rubyTexture, (base-up)/rubyTextureSize).xyz;\n"
|
||||
""
|
||||
" bool outer = c1 != c7 && c3 != c5;\n"
|
||||
" bool check1 = c3==c1 && (!any(m) || c4!=c2);\n"
|
||||
" bool check2 = any(m) && c5==c1 && c4!=c0;\n"
|
||||
""
|
||||
" return (outer && (check1 || check2)) ? c1 : c4;\n"
|
||||
"}\n"
|
||||
""
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec2 coord = v_texCoord;\n"
|
||||
"#if defined(OPENGLNB)\n"
|
||||
" gl_FragColor = getadvmame3xtexel(coord);\n"
|
||||
"#else\n"
|
||||
" coord -= 0.5;\n"
|
||||
" vec3 c0 = getadvmame3xtexel(coord);\n"
|
||||
" vec3 c1 = getadvmame3xtexel(coord+vec2(1.0,0.0));\n"
|
||||
" vec3 c2 = getadvmame3xtexel(coord+vec2(0.0,1.0));\n"
|
||||
" vec3 c3 = getadvmame3xtexel(coord+vec2(1.0));\n"
|
||||
""
|
||||
" coord = fract(max(coord,0.0));\n"
|
||||
" gl_FragColor = vec4(mix(mix(c0,c1,coord.x), mix(c2,c3,coord.x), coord.y), 1.0);\n"
|
||||
"#endif\n"
|
||||
"}\n"
|
||||
"#endif";
|
||||
|
||||
static const char rgb2x_glsl[] =
|
||||
"varying vec2 v_texCoord;\n"
|
||||
"uniform sampler2D rubyTexture;\n"
|
||||
"uniform vec2 rubyInputSize;\n"
|
||||
"uniform vec2 rubyOutputSize;\n"
|
||||
"uniform vec2 rubyTextureSize;\n"
|
||||
""
|
||||
"#if defined(VERTEX)\n"
|
||||
"attribute vec4 a_position;\n"
|
||||
""
|
||||
"void main() {\n"
|
||||
" gl_Position = a_position;\n"
|
||||
" v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)/2.0*rubyInputSize * 2.0;\n"
|
||||
"}\n"
|
||||
""
|
||||
"#elif defined(FRAGMENT)\n"
|
||||
""
|
||||
"vec4 getRGB2xtexel(vec2 coord) {\n"
|
||||
" vec2 mid = vec2(0.5);\n"
|
||||
" vec4 s = texture2D(rubyTexture, (floor(coord/vec2(2.0))+mid)/rubyTextureSize);\n"
|
||||
""
|
||||
" coord = max(floor(mod(coord, 2.0)), 0.0);\n"
|
||||
" /* 2x2 output:\n"
|
||||
" * |x=0|x=1\n"
|
||||
" * y=0| r | g\n"
|
||||
" * y=1| b |rgb\n"
|
||||
" */\n"
|
||||
""
|
||||
" s.r *= 1.0 - abs(coord.x - coord.y);\n"
|
||||
" s.g *= coord.x;\n"
|
||||
" s.b *= coord.y;\n"
|
||||
" return s;\n"
|
||||
"}\n"
|
||||
""
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec2 coord = v_texCoord;\n"
|
||||
"#if defined(OPENGLNB)\n"
|
||||
" gl_FragColor = getRGB2xtexel(coord);\n"
|
||||
"#else\n"
|
||||
" coord -= 0.5;\n"
|
||||
" vec4 c0 = getRGB2xtexel(coord);\n"
|
||||
" vec4 c1 = getRGB2xtexel(coord+vec2(1.0,0.0));\n"
|
||||
" vec4 c2 = getRGB2xtexel(coord+vec2(0.0,1.0));\n"
|
||||
" vec4 c3 = getRGB2xtexel(coord+vec2(1.0));\n"
|
||||
""
|
||||
" coord = fract(max(coord,0.0));\n"
|
||||
" gl_FragColor = mix(mix(c0,c1,coord.x), mix(c2,c3,coord.x), coord.y);\n"
|
||||
"#endif\n"
|
||||
"}\n"
|
||||
"#endif";
|
||||
|
||||
static const char rgb3x_glsl[] =
|
||||
"varying vec2 v_texCoord;\n"
|
||||
"uniform sampler2D rubyTexture;\n"
|
||||
"uniform vec2 rubyInputSize;\n"
|
||||
"uniform vec2 rubyOutputSize;\n"
|
||||
"uniform vec2 rubyTextureSize;\n"
|
||||
""
|
||||
"#if defined(VERTEX)\n"
|
||||
"attribute vec4 a_position;\n"
|
||||
""
|
||||
"void main() {\n"
|
||||
" gl_Position = a_position;\n"
|
||||
" v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)/2.0*rubyInputSize * 3.0;\n"
|
||||
"}\n"
|
||||
""
|
||||
"#elif defined(FRAGMENT)\n"
|
||||
""
|
||||
"vec4 getRGB3xtexel(vec2 coord) {\n"
|
||||
" vec2 mid = vec2(0.5);\n"
|
||||
" vec4 s = texture2D(rubyTexture, (floor(coord/vec2(3.0))+mid)/rubyTextureSize);\n"
|
||||
""
|
||||
" coord = max(floor(mod(coord, 3.0)), 0.0);\n"
|
||||
" /* 3x3 output:\n"
|
||||
" * | l | m | h\n"
|
||||
" * l|rgb| g | b\n"
|
||||
" * m| g | r |rgb\n"
|
||||
" * h|rgb| b | r\n"
|
||||
" */\n"
|
||||
" vec2 l = step(0.0, -coord);\n"
|
||||
" vec2 m = vec2(1.0) - abs(coord-1.0);\n"
|
||||
" vec2 h = step(2.0, coord);\n"
|
||||
""
|
||||
" s.r *= l.x + m.y - 2.0*l.x*m.y + h.x*h.y;\n"
|
||||
" s.g *= l.x + l.y*m.x + h.x*m.y;\n"
|
||||
" s.b *= l.x*l.y + h.x + h.y - 2.0*h.x*h.y;\n"
|
||||
" return s;\n"
|
||||
"}\n"
|
||||
""
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec2 coord = v_texCoord;\n"
|
||||
"#if defined(OPENGLNB)\n"
|
||||
" gl_FragColor = getRGB3xtexel(coord);\n"
|
||||
"#else\n"
|
||||
" coord -= 0.5;\n"
|
||||
" vec4 c0 = getRGB3xtexel(coord);\n"
|
||||
" vec4 c1 = getRGB3xtexel(coord+vec2(1.0,0.0));\n"
|
||||
" vec4 c2 = getRGB3xtexel(coord+vec2(0.0,1.0));\n"
|
||||
" vec4 c3 = getRGB3xtexel(coord+vec2(1.0));\n"
|
||||
""
|
||||
" coord = fract(max(coord,0.0));\n"
|
||||
" gl_FragColor = mix(mix(c0,c1,coord.x), mix(c2,c3,coord.x), coord.y);\n"
|
||||
"#endif\n"
|
||||
"}\n"
|
||||
"#endif";
|
||||
|
||||
static const char scan2x_glsl[] =
|
||||
"varying vec2 v_texCoord;\n"
|
||||
"uniform vec2 rubyInputSize;\n"
|
||||
"uniform vec2 rubyOutputSize;\n"
|
||||
"uniform vec2 rubyTextureSize;\n"
|
||||
""
|
||||
"#if defined(VERTEX)\n"
|
||||
"attribute vec4 a_position;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = a_position;\n"
|
||||
" v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)/2.0*rubyInputSize;\n"
|
||||
"}\n"
|
||||
""
|
||||
"#elif defined(FRAGMENT)\n"
|
||||
"uniform sampler2D rubyTexture;\n"
|
||||
""
|
||||
"void main() {\n"
|
||||
" vec2 prescale = vec2(2.0);\n"
|
||||
" vec2 texel = v_texCoord;\n"
|
||||
" vec2 texel_floored = floor(texel);\n"
|
||||
" vec2 s = fract(texel);\n"
|
||||
" vec2 region_range = vec2(0.5) - vec2(0.5) / prescale;\n"
|
||||
""
|
||||
" vec2 center_dist = s - vec2(0.5);\n"
|
||||
" vec2 f = (center_dist - clamp(center_dist, -region_range, region_range)) * prescale + vec2(0.5);\n"
|
||||
""
|
||||
" vec2 mod_texel = min(texel_floored + f, rubyInputSize-0.5);\n"
|
||||
" vec4 p = texture2D(rubyTexture, mod_texel/rubyTextureSize);\n"
|
||||
" float ss = abs(s.y*2.0-1.0);\n"
|
||||
" p -= p*ss;\n"
|
||||
""
|
||||
" gl_FragColor = p;\n"
|
||||
"}\n"
|
||||
"#endif";
|
||||
|
||||
static const char scan3x_glsl[] =
|
||||
"varying vec2 v_texCoord;\n"
|
||||
"uniform vec2 rubyInputSize;\n"
|
||||
"uniform vec2 rubyOutputSize;\n"
|
||||
"uniform vec2 rubyTextureSize;\n"
|
||||
""
|
||||
"#if defined(VERTEX)\n"
|
||||
"attribute vec4 a_position;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = a_position;\n"
|
||||
" v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)/2.0*rubyInputSize;\n"
|
||||
"}\n"
|
||||
""
|
||||
"#elif defined(FRAGMENT)\n"
|
||||
"uniform sampler2D rubyTexture;\n"
|
||||
""
|
||||
"void main() {\n"
|
||||
" vec2 prescale = vec2(3.0);\n"
|
||||
" vec2 texel = v_texCoord;\n"
|
||||
" vec2 texel_floored = floor(texel);\n"
|
||||
" vec2 s = fract(texel);\n"
|
||||
" vec2 region_range = vec2(0.5) - vec2(0.5) / prescale;\n"
|
||||
""
|
||||
" vec2 center_dist = s - 0.5;\n"
|
||||
" vec2 f = (center_dist - clamp(center_dist, -region_range, region_range)) * prescale + vec2(0.5);\n"
|
||||
""
|
||||
" vec2 mod_texel = min(texel_floored + f, rubyInputSize-0.5);\n"
|
||||
" vec4 p = texture2D(rubyTexture, mod_texel/rubyTextureSize);\n"
|
||||
" float m = s.y*6.0;\n"
|
||||
" m -= clamp(m, 2.0, 4.0);\n"
|
||||
" m = abs(m/2.0);\n"
|
||||
" gl_FragColor = p - p*m;\n"
|
||||
"}\n"
|
||||
"#endif";
|
||||
|
||||
static const char tv2x_glsl[] =
|
||||
"varying vec2 v_texCoord;\n"
|
||||
"uniform vec2 rubyInputSize;\n"
|
||||
"uniform vec2 rubyOutputSize;\n"
|
||||
"uniform vec2 rubyTextureSize;\n"
|
||||
""
|
||||
"#if defined(VERTEX)\n"
|
||||
"attribute vec4 a_position;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = a_position;\n"
|
||||
" v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)/2.0*rubyInputSize;\n"
|
||||
"}\n"
|
||||
""
|
||||
"#elif defined(FRAGMENT)\n"
|
||||
"uniform sampler2D rubyTexture;\n"
|
||||
""
|
||||
"void main() {\n"
|
||||
" vec2 prescale = vec2(2.0);\n"
|
||||
" vec2 texel = v_texCoord;\n"
|
||||
" vec2 texel_floored = floor(texel);\n"
|
||||
" vec2 s = fract(texel);\n"
|
||||
" vec2 region_range = vec2(0.5) - vec2(0.5) / prescale;\n"
|
||||
""
|
||||
" vec2 center_dist = s - 0.5;\n"
|
||||
" vec2 f = (center_dist - clamp(center_dist, -region_range, region_range)) * prescale + vec2(0.5);\n"
|
||||
""
|
||||
" vec2 mod_texel = min(texel_floored + f, rubyInputSize-0.5);\n"
|
||||
" vec4 p = texture2D(rubyTexture, mod_texel/rubyTextureSize);\n"
|
||||
" float ss = abs(s.y*2.0-1.0);\n"
|
||||
" p -= p*ss*3.0/8.0;\n"
|
||||
""
|
||||
" gl_FragColor = p;\n"
|
||||
"}\n"
|
||||
"#endif";
|
||||
|
||||
static const char tv3x_glsl[] =
|
||||
"varying vec2 v_texCoord;\n"
|
||||
"uniform vec2 rubyInputSize;\n"
|
||||
"uniform vec2 rubyOutputSize;\n"
|
||||
"uniform vec2 rubyTextureSize;\n"
|
||||
""
|
||||
"#if defined(VERTEX)\n"
|
||||
"attribute vec4 a_position;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = a_position;\n"
|
||||
" v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)/2.0*rubyInputSize;\n"
|
||||
"}\n"
|
||||
""
|
||||
"#elif defined(FRAGMENT)\n"
|
||||
"uniform sampler2D rubyTexture;\n"
|
||||
""
|
||||
"void main() {\n"
|
||||
" vec2 prescale = vec2(3.0);\n"
|
||||
" vec2 texel = v_texCoord;\n"
|
||||
" vec2 texel_floored = floor(texel);\n"
|
||||
" vec2 s = fract(texel);\n"
|
||||
" vec2 region_range = vec2(0.5) - vec2(0.5) / prescale;\n"
|
||||
""
|
||||
" vec2 center_dist = s - 0.5;\n"
|
||||
" vec2 f = (center_dist - clamp(center_dist, -region_range, region_range)) * prescale + vec2(0.5);\n"
|
||||
""
|
||||
" vec2 mod_texel = min(texel_floored + f, rubyInputSize-0.5);\n"
|
||||
" vec4 p = texture2D(rubyTexture, mod_texel/rubyTextureSize);\n"
|
||||
" float ss = abs(s.y*2.0-1.0);\n"
|
||||
" p -= p*ss*11.0/16.0;\n"
|
||||
""
|
||||
" gl_FragColor = p;\n"
|
||||
"}\n"
|
||||
"#endif";
|
||||
|
||||
static const char sharp_glsl[] =
|
||||
"varying vec2 v_texCoord;\n"
|
||||
"uniform vec2 rubyInputSize;\n"
|
||||
"uniform vec2 rubyOutputSize;\n"
|
||||
"uniform vec2 rubyTextureSize;\n"
|
||||
"varying vec2 prescale; // const set by vertex shader\n"
|
||||
""
|
||||
"#if defined(VERTEX)\n"
|
||||
"attribute vec4 a_position;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = a_position;\n"
|
||||
" v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)/2.0*rubyInputSize;\n"
|
||||
" prescale = ceil(rubyOutputSize / rubyInputSize);\n"
|
||||
"}\n"
|
||||
""
|
||||
"#elif defined(FRAGMENT)\n"
|
||||
"uniform sampler2D rubyTexture;\n"
|
||||
""
|
||||
"void main() {\n"
|
||||
" const vec2 halfp = vec2(0.5);\n"
|
||||
" vec2 texel_floored = floor(v_texCoord);\n"
|
||||
" vec2 s = fract(v_texCoord);\n"
|
||||
" vec2 region_range = halfp - halfp / prescale;\n"
|
||||
""
|
||||
" vec2 center_dist = s - halfp;\n"
|
||||
" vec2 f = (center_dist - clamp(center_dist, -region_range, region_range)) * prescale + halfp;\n"
|
||||
""
|
||||
" vec2 mod_texel = min(texel_floored + f, rubyInputSize-halfp);\n"
|
||||
" gl_FragColor = texture2D(rubyTexture, mod_texel / rubyTextureSize);\n"
|
||||
"}\n"
|
||||
"#endif";
|
||||
|
||||
|
||||
#endif
|
|
@ -53,6 +53,7 @@
|
|||
#include "keyboard.h"
|
||||
#include "cpu.h"
|
||||
#include "control.h"
|
||||
#include "render.h"
|
||||
|
||||
#define MAPPERFILE "mapper-sdl2-" VERSION ".map"
|
||||
//#define DISABLE_JOYSTICK
|
||||
|
@ -96,6 +97,53 @@ PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL;
|
|||
PFNGLMAPBUFFERARBPROC glMapBufferARB = NULL;
|
||||
PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL;
|
||||
|
||||
#ifndef GL_VERSION_2_0
|
||||
#define GL_VERSION_2_0 1
|
||||
typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
|
||||
typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
|
||||
typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
|
||||
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
|
||||
typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
|
||||
typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
|
||||
typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
|
||||
typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
|
||||
typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
|
||||
typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
|
||||
typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
|
||||
typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
|
||||
#endif
|
||||
|
||||
PFNGLATTACHSHADERPROC glAttachShader = NULL;
|
||||
PFNGLCOMPILESHADERPROC glCompileShader = NULL;
|
||||
PFNGLCREATEPROGRAMPROC glCreateProgram = NULL;
|
||||
PFNGLCREATESHADERPROC glCreateShader = NULL;
|
||||
PFNGLDELETEPROGRAMPROC glDeleteProgram = NULL;
|
||||
PFNGLDELETESHADERPROC glDeleteShader = NULL;
|
||||
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = NULL;
|
||||
PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation = NULL;
|
||||
PFNGLGETPROGRAMIVPROC glGetProgramiv = NULL;
|
||||
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = NULL;
|
||||
PFNGLGETSHADERIVPROC glGetShaderiv = NULL;
|
||||
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = NULL;
|
||||
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = NULL;
|
||||
PFNGLLINKPROGRAMPROC glLinkProgram = NULL;
|
||||
PFNGLSHADERSOURCEPROC glShaderSource = NULL;
|
||||
PFNGLUNIFORM2FPROC glUniform2f = NULL;
|
||||
PFNGLUNIFORM1IPROC glUniform1i = NULL;
|
||||
PFNGLUSEPROGRAMPROC glUseProgram = NULL;
|
||||
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = NULL;
|
||||
|
||||
#ifndef GL_SHADER_COMPILER
|
||||
#define GL_SHADER_COMPILER 0x8DFA
|
||||
#endif
|
||||
|
||||
#endif // C_OPENGL
|
||||
|
||||
#if !(ENVIRON_INCLUDED)
|
||||
|
@ -183,6 +231,18 @@ struct SDL_Block {
|
|||
bool packed_pixel;
|
||||
bool paletted_texture;
|
||||
bool pixel_buffer_object;
|
||||
|
||||
bool use_shader;
|
||||
GLuint program_object;
|
||||
const char *shader_src;
|
||||
struct {
|
||||
GLint texture_size;
|
||||
GLint input_size;
|
||||
GLint output_size;
|
||||
GLint frame_count;
|
||||
} ruby;
|
||||
GLuint actual_frame_count;
|
||||
GLfloat vertex_data[2*3];
|
||||
} opengl;
|
||||
#endif // C_OPENGL
|
||||
struct {
|
||||
|
@ -222,6 +282,23 @@ struct SDL_Block {
|
|||
static SDL_Block sdl;
|
||||
|
||||
#if C_OPENGL
|
||||
static char const shader_src_default[] =
|
||||
"varying vec2 v_texCoord;\n"
|
||||
"#if defined(VERTEX)\n"
|
||||
"uniform vec2 rubyTextureSize;\n"
|
||||
"uniform vec2 rubyInputSize;\n"
|
||||
"attribute vec4 a_position;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = a_position;\n"
|
||||
" v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)/2.0*rubyInputSize/rubyTextureSize;\n"
|
||||
"}\n"
|
||||
"#elif defined(FRAGMENT)\n"
|
||||
"uniform sampler2D rubyTexture;\n\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = texture2D(rubyTexture, v_texCoord);\n"
|
||||
"}\n"
|
||||
"#endif\n";
|
||||
|
||||
#ifdef DB_OPENGL_ERROR
|
||||
void OPENGL_ERROR(const char* message) {
|
||||
GLenum r = glGetError();
|
||||
|
@ -577,6 +654,76 @@ static SDL_Window * GFX_SetupWindowScaled(SCREEN_TYPES screenType)
|
|||
}
|
||||
}
|
||||
|
||||
#if C_OPENGL
|
||||
/* Create a GLSL shader object, load the shader source, and compile the shader. */
|
||||
static GLuint BuildShader ( GLenum type, const char *shaderSrc ) {
|
||||
GLuint shader;
|
||||
GLint compiled;
|
||||
const char* src_strings[2];
|
||||
std::string top;
|
||||
|
||||
// look for "#version" because it has to occur first
|
||||
const char *ver = strstr(shaderSrc, "#version ");
|
||||
if (ver) {
|
||||
const char *endline = strchr(ver+9, '\n');
|
||||
if (endline) {
|
||||
top.assign(shaderSrc, endline-shaderSrc+1);
|
||||
shaderSrc = endline+1;
|
||||
}
|
||||
}
|
||||
|
||||
top += (type==GL_VERTEX_SHADER) ? "#define VERTEX 1\n":"#define FRAGMENT 1\n";
|
||||
if (!sdl.opengl.bilinear)
|
||||
top += "#define OPENGLNB 1\n";
|
||||
|
||||
src_strings[0] = top.c_str();
|
||||
src_strings[1] = shaderSrc;
|
||||
|
||||
// Create the shader object
|
||||
shader = glCreateShader(type);
|
||||
if (shader == 0) return 0;
|
||||
|
||||
// Load the shader source
|
||||
glShaderSource(shader, 2, src_strings, NULL);
|
||||
|
||||
// Compile the shader
|
||||
glCompileShader(shader);
|
||||
|
||||
// Check the compile status
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
|
||||
|
||||
if (!compiled) {
|
||||
GLint infoLen = 0;
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
|
||||
|
||||
if (infoLen>1) {
|
||||
char* infoLog = (char*)malloc(infoLen);
|
||||
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
|
||||
LOG_MSG("Error compiling shader: %s", infoLog);
|
||||
free(infoLog);
|
||||
}
|
||||
|
||||
glDeleteShader(shader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
static bool GFX_LoadGLShaders(const char *src, GLuint *vertex, GLuint *fragment) {
|
||||
GLuint s = BuildShader(GL_VERTEX_SHADER, src);
|
||||
if (s) {
|
||||
*vertex = s;
|
||||
s = BuildShader(GL_FRAGMENT_SHADER, src);
|
||||
if (s) {
|
||||
*fragment = s;
|
||||
return true;
|
||||
}
|
||||
glDeleteShader(*vertex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
Bitu GFX_SetSize(Bitu width,Bitu height,Bitu flags,double scalex,double scaley,GFX_CallBack_t callback) {
|
||||
if (sdl.updating)
|
||||
GFX_EndUpdate( 0 );
|
||||
|
@ -749,6 +896,100 @@ dosurface:
|
|||
}
|
||||
/* Sync to VBlank if desired */
|
||||
SDL_GL_SetSwapInterval(sdl.desktop.vsync ? 1 : 0);
|
||||
|
||||
if (sdl.opengl.use_shader) {
|
||||
GLboolean t;
|
||||
// confirm current context supports shaders
|
||||
glGetBooleanv(GL_SHADER_COMPILER, &t);
|
||||
if (t) {
|
||||
// check if existing program is valid
|
||||
if (sdl.opengl.program_object) {
|
||||
// reset error
|
||||
glGetError();
|
||||
glUseProgram(sdl.opengl.program_object);
|
||||
if (glGetError() != GL_NO_ERROR) {
|
||||
// program is not usable (probably new context), purge it
|
||||
glDeleteProgram(sdl.opengl.program_object);
|
||||
sdl.opengl.program_object = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// does program need to be rebuilt?
|
||||
if (sdl.opengl.program_object == 0) {
|
||||
GLuint vertexShader, fragmentShader;
|
||||
const char *src = sdl.opengl.shader_src;
|
||||
if (src && !GFX_LoadGLShaders(src, &vertexShader, &fragmentShader)) {
|
||||
LOG_MSG("SDL:OPENGL:Failed to compile shader, falling back to default");
|
||||
src = NULL;
|
||||
}
|
||||
if (src == NULL && !GFX_LoadGLShaders(shader_src_default, &vertexShader, &fragmentShader)) {
|
||||
LOG_MSG("SDL:OPENGL:Failed to compile default shader!");
|
||||
goto dosurface;
|
||||
}
|
||||
|
||||
sdl.opengl.program_object = glCreateProgram();
|
||||
if (!sdl.opengl.program_object) {
|
||||
glDeleteShader(vertexShader);
|
||||
glDeleteShader(fragmentShader);
|
||||
LOG_MSG("SDL:OPENGL:Can't create program object, falling back to surface");
|
||||
goto dosurface;
|
||||
}
|
||||
glAttachShader(sdl.opengl.program_object, vertexShader);
|
||||
glAttachShader(sdl.opengl.program_object, fragmentShader);
|
||||
// Link the program
|
||||
glLinkProgram(sdl.opengl.program_object);
|
||||
// Even if we *are* successful, we may delete the shader objects
|
||||
glDeleteShader(vertexShader);
|
||||
glDeleteShader(fragmentShader);
|
||||
|
||||
// Check the link status
|
||||
GLint isProgramLinked;
|
||||
glGetProgramiv(sdl.opengl.program_object, GL_LINK_STATUS, &isProgramLinked);
|
||||
if (!isProgramLinked) {
|
||||
GLint infoLen = 0;
|
||||
|
||||
glGetProgramiv(sdl.opengl.program_object, GL_INFO_LOG_LENGTH, &infoLen);
|
||||
if (infoLen>1) {
|
||||
char *infoLog = (char*)malloc(infoLen);
|
||||
glGetProgramInfoLog(sdl.opengl.program_object, infoLen, NULL, infoLog);
|
||||
LOG_MSG("SDL:OPENGL:Error link prograram:\n %s", infoLog);
|
||||
free(infoLog);
|
||||
}
|
||||
|
||||
glDeleteProgram(sdl.opengl.program_object);
|
||||
sdl.opengl.program_object = 0;
|
||||
goto dosurface;
|
||||
}
|
||||
|
||||
glUseProgram(sdl.opengl.program_object);
|
||||
|
||||
GLint u = glGetAttribLocation(sdl.opengl.program_object, "a_position");
|
||||
// upper left
|
||||
sdl.opengl.vertex_data[0] = -1.0f;
|
||||
sdl.opengl.vertex_data[1] = 1.0f;
|
||||
// lower left
|
||||
sdl.opengl.vertex_data[2] = -1.0f;
|
||||
sdl.opengl.vertex_data[3] = -3.0f;
|
||||
// upper right
|
||||
sdl.opengl.vertex_data[4] = 3.0f;
|
||||
sdl.opengl.vertex_data[5] = 1.0f;
|
||||
// Load the vertex positions
|
||||
glVertexAttribPointer(u, 2, GL_FLOAT, GL_FALSE, 0, sdl.opengl.vertex_data);
|
||||
glEnableVertexAttribArray(u);
|
||||
|
||||
u = glGetUniformLocation(sdl.opengl.program_object, "rubyTexture");
|
||||
glUniform1i(u, 0);
|
||||
|
||||
sdl.opengl.ruby.texture_size = glGetUniformLocation(sdl.opengl.program_object, "rubyTextureSize");
|
||||
sdl.opengl.ruby.input_size = glGetUniformLocation(sdl.opengl.program_object, "rubyInputSize");
|
||||
sdl.opengl.ruby.output_size = glGetUniformLocation(sdl.opengl.program_object, "rubyOutputSize");
|
||||
sdl.opengl.ruby.frame_count = glGetUniformLocation(sdl.opengl.program_object, "rubyFrameCount");
|
||||
// Don't force updating unless a shader depends on frame_count
|
||||
RENDER_SetForceUpdate(sdl.opengl.ruby.frame_count != (GLint)-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the texture and display list */
|
||||
if (sdl.opengl.pixel_buffer_object) {
|
||||
glGenBuffersARB(1, &sdl.opengl.buffer);
|
||||
|
@ -781,8 +1022,6 @@ dosurface:
|
|||
sdl.clip.h);
|
||||
}
|
||||
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
|
||||
if (sdl.opengl.texture > 0) {
|
||||
glDeleteTextures(1,&sdl.opengl.texture);
|
||||
}
|
||||
|
@ -805,33 +1044,47 @@ dosurface:
|
|||
delete [] emptytex;
|
||||
|
||||
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glShadeModel (GL_FLAT);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
SDL_GL_SwapWindow(sdl.window);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glDisable (GL_DEPTH_TEST);
|
||||
glDisable (GL_LIGHTING);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
glLoadIdentity ();
|
||||
|
||||
GLfloat tex_width=((GLfloat)(width)/(GLfloat)texsize);
|
||||
GLfloat tex_height=((GLfloat)(height)/(GLfloat)texsize);
|
||||
if (sdl.opengl.program_object) {
|
||||
// Set shader variables
|
||||
glUniform2f(sdl.opengl.ruby.texture_size, (float)texsize, (float)texsize);
|
||||
glUniform2f(sdl.opengl.ruby.input_size, (float)width, (float)height);
|
||||
glUniform2f(sdl.opengl.ruby.output_size, sdl.clip.w, sdl.clip.h);
|
||||
// The following uniform is *not* set right now
|
||||
sdl.opengl.actual_frame_count = 0;
|
||||
} else {
|
||||
GLfloat tex_width=((GLfloat)(width)/(GLfloat)texsize);
|
||||
GLfloat tex_height=((GLfloat)(height)/(GLfloat)texsize);
|
||||
|
||||
if (glIsList(sdl.opengl.displaylist)) glDeleteLists(sdl.opengl.displaylist, 1);
|
||||
sdl.opengl.displaylist = glGenLists(1);
|
||||
glNewList(sdl.opengl.displaylist, GL_COMPILE);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glBindTexture(GL_TEXTURE_2D, sdl.opengl.texture);
|
||||
glShadeModel(GL_FLAT);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
// upper left
|
||||
glTexCoord2f(0,0); glVertex2f(-1.0f, 1.0f);
|
||||
// lower left
|
||||
glTexCoord2f(0,tex_height*2); glVertex2f(-1.0f,-3.0f);
|
||||
// upper right
|
||||
glTexCoord2f(tex_width*2,0); glVertex2f(3.0f, 1.0f);
|
||||
glEnd();
|
||||
if (glIsList(sdl.opengl.displaylist)) glDeleteLists(sdl.opengl.displaylist, 1);
|
||||
sdl.opengl.displaylist = glGenLists(1);
|
||||
glNewList(sdl.opengl.displaylist, GL_COMPILE);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glEndList();
|
||||
glBegin(GL_TRIANGLES);
|
||||
// upper left
|
||||
glTexCoord2f(0,0); glVertex2f(-1.0f, 1.0f);
|
||||
// lower left
|
||||
glTexCoord2f(0,tex_height*2); glVertex2f(-1.0f,-3.0f);
|
||||
// upper right
|
||||
glTexCoord2f(tex_width*2,0); glVertex2f(3.0f, 1.0f);
|
||||
glEnd();
|
||||
|
||||
glEndList();
|
||||
}
|
||||
|
||||
OPENGL_ERROR("End of setsize");
|
||||
|
||||
|
@ -839,7 +1092,7 @@ dosurface:
|
|||
retFlags = GFX_CAN_32 | GFX_SCALING;
|
||||
if (sdl.opengl.pixel_buffer_object)
|
||||
retFlags |= GFX_HARDWARE;
|
||||
break;
|
||||
break;
|
||||
}//OPENGL
|
||||
#endif //C_OPENGL
|
||||
default:
|
||||
|
@ -851,6 +1104,19 @@ dosurface:
|
|||
return retFlags;
|
||||
}
|
||||
|
||||
void GFX_SetShader(const char* src) {
|
||||
#if C_OPENGL
|
||||
if (!sdl.opengl.use_shader || src == sdl.opengl.shader_src)
|
||||
return;
|
||||
|
||||
sdl.opengl.shader_src = src;
|
||||
if (sdl.opengl.program_object) {
|
||||
glDeleteProgram(sdl.opengl.program_object);
|
||||
sdl.opengl.program_object = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GFX_ToggleMouseCapture(void) {
|
||||
assertm(sdl.mouse.control_choice != NoMouse,
|
||||
"SDL: Mouse capture is invalid when NoMouse is configured [Logic Bug]");
|
||||
|
@ -1013,8 +1279,9 @@ bool GFX_StartUpdate(Bit8u * & pixels,Bitu & pitch) {
|
|||
void GFX_EndUpdate( const Bit16u *changedLines ) {
|
||||
if (!sdl.update_display_contents)
|
||||
return;
|
||||
if (!sdl.updating)
|
||||
if (((sdl.desktop.type != SCREEN_OPENGL) || !RENDER_GetForceUpdate()) && !sdl.updating)
|
||||
return;
|
||||
bool actually_updating = sdl.updating;
|
||||
sdl.updating=false;
|
||||
switch (sdl.desktop.type) {
|
||||
case SCREEN_SURFACE:
|
||||
|
@ -1047,6 +1314,15 @@ void GFX_EndUpdate( const Bit16u *changedLines ) {
|
|||
case SCREEN_OPENGL:
|
||||
// Clear drawing area. Some drivers (on Linux) have more than 2 buffers and the screen might
|
||||
// be dirty because of other programs.
|
||||
if (!actually_updating) {
|
||||
/* Don't really update; Just increase the frame counter.
|
||||
* If we tried to update it may have not worked so well
|
||||
* with VSync...
|
||||
* (Think of 60Hz on the host with 70Hz on the client.)
|
||||
*/
|
||||
sdl.opengl.actual_frame_count++;
|
||||
return;
|
||||
}
|
||||
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
if (sdl.opengl.pixel_buffer_object) {
|
||||
|
@ -1056,8 +1332,6 @@ void GFX_EndUpdate( const Bit16u *changedLines ) {
|
|||
sdl.draw.width, sdl.draw.height, GL_BGRA_EXT,
|
||||
GL_UNSIGNED_INT_8_8_8_8_REV, 0);
|
||||
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
|
||||
glCallList(sdl.opengl.displaylist);
|
||||
SDL_GL_SwapWindow(sdl.window);
|
||||
} else if (changedLines) {
|
||||
Bitu y = 0, index = 0;
|
||||
glBindTexture(GL_TEXTURE_2D, sdl.opengl.texture);
|
||||
|
@ -1074,9 +1348,17 @@ void GFX_EndUpdate( const Bit16u *changedLines ) {
|
|||
}
|
||||
index++;
|
||||
}
|
||||
glCallList(sdl.opengl.displaylist);
|
||||
SDL_GL_SwapWindow(sdl.window);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sdl.opengl.program_object) {
|
||||
glUniform1i(sdl.opengl.ruby.frame_count, sdl.opengl.actual_frame_count++);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
} else {
|
||||
glCallList(sdl.opengl.displaylist);
|
||||
}
|
||||
SDL_GL_SwapWindow(sdl.window);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
@ -1354,6 +1636,31 @@ static void GUI_StartUp(Section * sec) {
|
|||
}
|
||||
}
|
||||
if (sdl.desktop.want_type == SCREEN_OPENGL) {
|
||||
sdl.opengl.program_object = 0;
|
||||
glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader");
|
||||
glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader");
|
||||
glCreateProgram = (PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram");
|
||||
glCreateShader = (PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader");
|
||||
glDeleteProgram = (PFNGLDELETEPROGRAMPROC)SDL_GL_GetProcAddress("glDeleteProgram");
|
||||
glDeleteShader = (PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader");
|
||||
glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)SDL_GL_GetProcAddress("glEnableVertexAttribArray");
|
||||
glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)SDL_GL_GetProcAddress("glGetAttribLocation");
|
||||
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv");
|
||||
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)SDL_GL_GetProcAddress("glGetProgramInfoLog");
|
||||
glGetShaderiv = (PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv");
|
||||
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog");
|
||||
glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)SDL_GL_GetProcAddress("glGetUniformLocation");
|
||||
glLinkProgram = (PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram");
|
||||
glShaderSource = (PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource");
|
||||
glUniform2f = (PFNGLUNIFORM2FPROC)SDL_GL_GetProcAddress("glUniform2f");
|
||||
glUniform1i = (PFNGLUNIFORM1IPROC)SDL_GL_GetProcAddress("glUniform1i");
|
||||
glUseProgram = (PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram");
|
||||
glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)SDL_GL_GetProcAddress("glVertexAttribPointer");
|
||||
sdl.opengl.use_shader = (glAttachShader && glCompileShader && glCreateProgram && glDeleteProgram && glDeleteShader && \
|
||||
glEnableVertexAttribArray && glGetAttribLocation && glGetProgramiv && glGetProgramInfoLog && \
|
||||
glGetShaderiv && glGetShaderInfoLog && glGetUniformLocation && glLinkProgram && glShaderSource && \
|
||||
glUniform2f && glUniform1i && glUseProgram && glVertexAttribPointer);
|
||||
|
||||
sdl.opengl.buffer=0;
|
||||
sdl.opengl.framebuf=0;
|
||||
sdl.opengl.texture=0;
|
||||
|
@ -1372,7 +1679,7 @@ static void GUI_StartUp(Section * sec) {
|
|||
sdl.opengl.pixel_buffer_object=(strstr(gl_ext,"GL_ARB_pixel_buffer_object") != NULL ) &&
|
||||
glGenBuffersARB && glBindBufferARB && glDeleteBuffersARB && glBufferDataARB &&
|
||||
glMapBufferARB && glUnmapBufferARB;
|
||||
} else {
|
||||
} else {
|
||||
sdl.opengl.packed_pixel = false;
|
||||
sdl.opengl.paletted_texture = false;
|
||||
sdl.opengl.pixel_buffer_object = false;
|
||||
|
|
Loading…
Add table
Reference in a new issue