1
0
Fork 0

Add OpenGL shader support. (patch by ny00123 and refined by jmarsh). Add several builtin ones that mimic the scalers and some extra. Thanks jmarsh

Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@4319
This commit is contained in:
Peter Veenstra 2020-02-10 18:59:01 +00:00
parent 62ab91a269
commit 4a565a75ed
7 changed files with 1021 additions and 30 deletions

View file

@ -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

View file

@ -59,6 +59,7 @@ void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries);
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);

View file

@ -472,6 +472,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",

View file

@ -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

View file

@ -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;
@ -229,6 +233,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;
@ -428,6 +433,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;
@ -572,6 +580,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);
@ -625,10 +703,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
View 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

View file

@ -49,6 +49,7 @@
#include "cpu.h"
#include "cross.h"
#include "control.h"
#include "render.h"
#define MAPPERFILE "mapper-" VERSION ".map"
//#define DISABLE_JOYSTICK
@ -92,6 +93,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)
@ -190,6 +238,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
struct {
@ -229,6 +289,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();
@ -583,6 +660,76 @@ void GFX_TearDown(void) {
}
}
#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 );
@ -760,11 +907,106 @@ dosurface:
#if SDL_VERSION_ATLEAST(1, 2, 11)
SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 0 );
#endif
GFX_SetupSurfaceScaled(SDL_OPENGL,0);
// try 32 bits first then 16
if (GFX_SetupSurfaceScaled(SDL_OPENGL,32)==NULL) GFX_SetupSurfaceScaled(SDL_OPENGL,16);
if (!sdl.surface || sdl.surface->format->BitsPerPixel<15) {
LOG_MSG("SDL:OPENGL: Can't open drawing surface, are you running in 16bpp (or higher) mode?");
goto dosurface;
}
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,9 +1023,7 @@ dosurface:
glViewport((sdl.surface->w-sdl.clip.w)/2,(sdl.surface->h-sdl.clip.h)/2,sdl.clip.w,sdl.clip.h);
} else {
glViewport(sdl.clip.x,sdl.clip.y,sdl.clip.w,sdl.clip.h);
}
glMatrixMode (GL_PROJECTION);
}
if (sdl.opengl.texture > 0) {
glDeleteTextures(1,&sdl.opengl.texture);
@ -810,32 +1050,42 @@ dosurface:
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapBuffers();
glClear(GL_COLOR_BUFFER_BIT);
glShadeModel (GL_FLAT);
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);
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);
glBindTexture(GL_TEXTURE_2D, sdl.opengl.texture);
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");
@ -843,7 +1093,7 @@ dosurface:
retFlags = GFX_CAN_32 | GFX_SCALING;
if (sdl.opengl.pixel_buffer_object)
retFlags |= GFX_HARDWARE;
break;
break;
}//OPENGL
#endif //C_OPENGL
default:
@ -856,6 +1106,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_CaptureMouse(void) {
sdl.mouse.locked=!sdl.mouse.locked;
if (sdl.mouse.locked) {
@ -1019,8 +1282,9 @@ void GFX_EndUpdate( const Bit16u *changedLines ) {
#if C_DDRAW
int ret;
#endif
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:
@ -1085,6 +1349,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) {
@ -1094,8 +1367,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_SwapBuffers();
} else if (changedLines) {
Bitu y = 0, index = 0;
glBindTexture(GL_TEXTURE_2D, sdl.opengl.texture);
@ -1112,9 +1383,14 @@ void GFX_EndUpdate( const Bit16u *changedLines ) {
}
index++;
}
glCallList(sdl.opengl.displaylist);
SDL_GL_SwapBuffers();
}
} 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_SwapBuffers();
break;
#endif
default:
@ -1438,6 +1714,31 @@ static void GUI_StartUp(Section * sec) {
LOG_MSG("Could not initialize OpenGL, switching back to surface");
sdl.desktop.want_type = SCREEN_SURFACE;
} else {
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;