~ubuntu-branches/debian/squeeze/stella/squeeze

« back to all changes in this revision

Viewing changes to src/common/FrameBufferGL.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Stephen Kitt
  • Date: 2010-07-12 23:49:36 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20100712234936-juawrr3etzhr2qpv
Tags: 3.1.2-1
* New maintainer (closes: #532039).
* New upstream version (closes: #461121):
  - includes launcher (closes: #396058).
* Fix the reference to the X Window System in the description (closes:
  #411815).
* Move to main, DFSG-free ROMs are available (see README.Debian).
* Enhance the package description.
* Drop the libslang2-dev dependency (closes: #560274).
* Remove the Encoding entry from stella.desktop.
* Avoid ignoring errors when cleaning.
* Add ${misc:Depends} to the package dependencies.
* Provide a doc-base file to install the documentation using doc-base.
* Switch to debhelper 7 with a simplified rules file.
* Use autotools-dev to provide updated configuration files.
* Update to Standards-Version 3.9.0:
  - Move to menu section Applications/Emulators.
  - Move the homepage declaration.
* Re-write the manpage.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
//============================================================================
2
2
//
3
 
//   SSSS    tt          lll  lll       
4
 
//  SS  SS   tt           ll   ll        
5
 
//  SS     tttttt  eeee   ll   ll   aaaa 
 
3
//   SSSS    tt          lll  lll
 
4
//  SS  SS   tt           ll   ll
 
5
//  SS     tttttt  eeee   ll   ll   aaaa
6
6
//   SSSS    tt   ee  ee  ll   ll      aa
7
7
//      SS   tt   eeeeee  ll   ll   aaaaa  --  "An Atari 2600 VCS Emulator"
8
8
//  SS  SS   tt   ee      ll   ll  aa  aa
9
9
//   SSSS     ttt  eeeee llll llll  aaaaa
10
10
//
11
 
// Copyright (c) 1995-2008 by Bradford W. Mott and the Stella team
 
11
// Copyright (c) 1995-2010 by Bradford W. Mott, Stephen Anthony
 
12
// and the Stella Team
12
13
//
13
 
// See the file "license" for information on usage and redistribution of
 
14
// See the file "License.txt" for information on usage and redistribution of
14
15
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
15
16
//
16
 
// $Id: FrameBufferGL.cxx,v 1.102 2008/04/28 15:53:05 stephena Exp $
 
17
// $Id: FrameBufferGL.cxx 2003 2010-04-11 13:44:22Z stephena $
17
18
//============================================================================
18
19
 
19
20
#ifdef DISPLAY_OPENGL
21
22
#include <SDL.h>
22
23
#include <SDL_syswm.h>
23
24
#include <sstream>
 
25
#include <time.h>
24
26
 
25
27
#include "bspf.hxx"
26
28
 
27
29
#include "Console.hxx"
28
30
#include "Font.hxx"
29
 
#include "MediaSrc.hxx"
30
31
#include "OSystem.hxx"
31
32
#include "Settings.hxx"
32
 
#include "Surface.hxx"
 
33
#include "TIA.hxx"
 
34
#include "GLShaderProgs.hxx"
33
35
 
34
36
#include "FrameBufferGL.hxx"
35
37
 
36
 
// Maybe this code could be cleaner ...
37
 
static void (APIENTRY* p_glClear)( GLbitfield );
38
 
static void (APIENTRY* p_glEnable)( GLenum );
39
 
static void (APIENTRY* p_glDisable)( GLenum );
40
 
static void (APIENTRY* p_glPushAttrib)( GLbitfield );
41
 
static const GLubyte* (APIENTRY* p_glGetString)( GLenum );
42
 
static void (APIENTRY* p_glHint)( GLenum, GLenum );
43
 
static void (APIENTRY* p_glShadeModel)( GLenum );
44
 
 
45
 
// Matrix
46
 
static void (APIENTRY* p_glMatrixMode)( GLenum );
47
 
static void (APIENTRY* p_glOrtho)( GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble );
48
 
static void (APIENTRY* p_glViewport)( GLint, GLint, GLsizei, GLsizei );
49
 
static void (APIENTRY* p_glPushMatrix)( void );
50
 
static void (APIENTRY* p_glLoadIdentity)( void );
51
 
 
52
 
// Drawing
53
 
static void (APIENTRY* p_glBegin)( GLenum );
54
 
static void (APIENTRY* p_glEnd)( void );
55
 
static void (APIENTRY* p_glVertex2i)( GLint, GLint );
56
 
static void (APIENTRY* p_glTexCoord2f)( GLfloat, GLfloat );
57
 
 
58
 
// Raster funcs
59
 
static void (APIENTRY* p_glReadPixels)( GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid* );
60
 
static void (APIENTRY* p_glPixelStorei)( GLenum, GLint );
61
 
 
62
 
// Texture mapping
63
 
static void (APIENTRY* p_glTexEnvf)( GLenum, GLenum, GLfloat );
64
 
static void (APIENTRY* p_glGenTextures)( GLsizei, GLuint* ); // 1.1
65
 
static void (APIENTRY* p_glDeleteTextures)( GLsizei, const GLuint* ); // 1.1
66
 
static void (APIENTRY* p_glBindTexture)( GLenum, GLuint );   // 1.1
67
 
static void (APIENTRY* p_glTexImage2D)( GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid* );
68
 
static void (APIENTRY* p_glTexSubImage2D)( GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid* ); // 1.1
69
 
static void (APIENTRY* p_glTexParameteri)( GLenum, GLenum, GLint );
 
38
// OpenGL functions we'll be using in Stella
 
39
#define OGL_DECLARE(RET,FUNC,PARAMS) static RET (APIENTRY* p_ ## FUNC) PARAMS
 
40
 
 
41
OGL_DECLARE(void,glClear,(GLbitfield));
 
42
OGL_DECLARE(void,glEnable,(GLenum));
 
43
OGL_DECLARE(void,glDisable,(GLenum));
 
44
OGL_DECLARE(void,glPushAttrib,(GLbitfield));
 
45
OGL_DECLARE(const GLubyte*,glGetString,(GLenum));
 
46
OGL_DECLARE(void,glHint,(GLenum, GLenum));
 
47
OGL_DECLARE(void,glShadeModel,(GLenum));
 
48
OGL_DECLARE(void,glMatrixMode,(GLenum));
 
49
OGL_DECLARE(void,glOrtho,(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble));
 
50
OGL_DECLARE(void,glViewport,(GLint, GLint, GLsizei, GLsizei));
 
51
OGL_DECLARE(void,glPushMatrix,(void));
 
52
OGL_DECLARE(void,glLoadIdentity,(void));
 
53
OGL_DECLARE(void,glBegin,(GLenum));
 
54
OGL_DECLARE(void,glEnd,(void));
 
55
OGL_DECLARE(void,glVertex2i,(GLint, GLint));
 
56
OGL_DECLARE(void,glTexCoord2f,(GLfloat, GLfloat));
 
57
OGL_DECLARE(void,glReadPixels,(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid*));
 
58
OGL_DECLARE(void,glPixelStorei,(GLenum, GLint));
 
59
OGL_DECLARE(void,glTexEnvf,(GLenum, GLenum, GLfloat));
 
60
OGL_DECLARE(void,glGenTextures,(GLsizei, GLuint*));
 
61
OGL_DECLARE(void,glDeleteTextures,(GLsizei, const GLuint*));
 
62
OGL_DECLARE(void,glActiveTexture,(GLenum));
 
63
OGL_DECLARE(void,glBindTexture,(GLenum, GLuint));
 
64
OGL_DECLARE(void,glTexImage2D,(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*));
 
65
OGL_DECLARE(void,glTexSubImage2D,(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*));
 
66
OGL_DECLARE(void,glTexParameteri,(GLenum, GLenum, GLint));
 
67
OGL_DECLARE(GLuint,glCreateShader,(GLenum));
 
68
OGL_DECLARE(void,glDeleteShader,(GLuint));
 
69
OGL_DECLARE(void,glShaderSource,(GLuint, int, const char**, int));
 
70
OGL_DECLARE(void,glCompileShader,(GLuint));
 
71
OGL_DECLARE(GLuint,glCreateProgram,(void));
 
72
OGL_DECLARE(void,glDeleteProgram,(GLuint));
 
73
OGL_DECLARE(void,glAttachShader,(GLuint, GLuint));
 
74
OGL_DECLARE(void,glLinkProgram,(GLuint));
 
75
OGL_DECLARE(void,glUseProgram,(GLuint));
 
76
OGL_DECLARE(GLint,glGetUniformLocation,(GLuint, const char*));
 
77
OGL_DECLARE(void,glUniform1i,(GLint, GLint));
 
78
OGL_DECLARE(void,glUniform1f,(GLint, GLfloat));
 
79
OGL_DECLARE(void,glCopyTexImage2D,(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint));
 
80
OGL_DECLARE(void,glCopyTexSubImage2D,(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei));
 
81
OGL_DECLARE(void,glGetIntegerv,(GLenum, GLint*));
 
82
OGL_DECLARE(void,glTexEnvi,(GLenum, GLenum, GLint));
 
83
OGL_DECLARE(void,glMultiTexCoord2f,(GLenum, GLfloat, GLfloat));
 
84
OGL_DECLARE(GLenum,glGetError,(void));
70
85
 
71
86
 
72
87
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
73
88
FrameBufferGL::FrameBufferGL(OSystem* osystem)
74
89
  : FrameBuffer(osystem),
75
 
    myTexture(NULL),
 
90
    myTiaSurface(NULL),
 
91
    myFilterParamName("GL_NEAREST"),
76
92
    myHaveTexRectEXT(false),
77
 
    myFilterParamName("GL_NEAREST"),
78
 
    myWidthScaleFactor(1.0),
79
 
    myHeightScaleFactor(1.0),
80
93
    myDirtyFlag(true)
81
94
{
 
95
  // We need a pixel format for palette value calculations
 
96
  // It's done this way (vs directly accessing a FBSurfaceGL object)
 
97
  // since the structure may be needed before any FBSurface's have
 
98
  // been created
 
99
  SDL_Surface* s = SDL_CreateRGBSurface(SDL_SWSURFACE, 1, 1, 16,
 
100
                     0x00007c00, 0x000003e0, 0x0000001f, 0x00000000);
 
101
  myPixelFormat = *(s->format);
 
102
  SDL_FreeSurface(s);
82
103
}
83
104
 
84
105
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
85
106
FrameBufferGL::~FrameBufferGL()
86
107
{
87
 
  if(myTexture)
88
 
    SDL_FreeSurface(myTexture);
89
 
 
90
 
  p_glDeleteTextures(1, &myBuffer.texture);
 
108
  // We're taking responsibility for this surface
 
109
  delete myTiaSurface;
91
110
}
92
111
 
93
112
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
96
115
  if(myLibraryLoaded)
97
116
    return true;
98
117
 
99
 
  if(SDL_WasInit(SDL_INIT_VIDEO) == 0)
100
 
    SDL_Init(SDL_INIT_VIDEO);
101
 
 
102
118
  // Try both the specified library and auto-detection
103
119
  bool libLoaded = (library != "" && SDL_GL_LoadLibrary(library.c_str()) >= 0);
104
120
  bool autoLoaded = false;
110
126
}
111
127
 
112
128
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
113
 
bool FrameBufferGL::loadFuncs()
 
129
bool FrameBufferGL::loadFuncs(GLFunctionality functionality)
114
130
{
 
131
#define OGL_INIT(RET,FUNC,PARAMS) \
 
132
  p_ ## FUNC = (RET(APIENTRY*)PARAMS) SDL_GL_GetProcAddress(#FUNC); if(!p_ ## FUNC) return false
 
133
 
115
134
  if(myLibraryLoaded)
116
135
  {
117
136
    // Fill the function pointers for GL functions
118
137
    // If anything fails, we'll know it immediately, and return false
119
 
    // Yes, this syntax is ugly, but I can type it out faster than the time
120
 
    // it takes to figure our macro magic to do it neatly
121
 
    p_glClear = (void(APIENTRY*)(GLbitfield))
122
 
      SDL_GL_GetProcAddress("glClear"); if(!p_glClear) return false;
123
 
    p_glEnable = (void(APIENTRY*)(GLenum))
124
 
      SDL_GL_GetProcAddress("glEnable"); if(!p_glEnable) return false;
125
 
    p_glDisable = (void(APIENTRY*)(GLenum))
126
 
      SDL_GL_GetProcAddress("glDisable"); if(!p_glDisable) return false;
127
 
    p_glPushAttrib = (void(APIENTRY*)(GLbitfield))
128
 
      SDL_GL_GetProcAddress("glPushAttrib"); if(!p_glPushAttrib) return false;
129
 
    p_glGetString = (const GLubyte*(APIENTRY*)(GLenum))
130
 
      SDL_GL_GetProcAddress("glGetString"); if(!p_glGetString) return false;
131
 
    p_glHint = (void(APIENTRY*)(GLenum, GLenum))
132
 
      SDL_GL_GetProcAddress("glHint"); if(!p_glHint) return false;
133
 
    p_glShadeModel = (void(APIENTRY*)(GLenum))
134
 
      SDL_GL_GetProcAddress("glShadeModel"); if(!p_glShadeModel) return false;
135
 
 
136
 
    p_glMatrixMode = (void(APIENTRY*)(GLenum))
137
 
      SDL_GL_GetProcAddress("glMatrixMode"); if(!p_glMatrixMode) return false;
138
 
    p_glOrtho = (void(APIENTRY*)(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble))
139
 
      SDL_GL_GetProcAddress("glOrtho"); if(!p_glOrtho) return false;
140
 
    p_glViewport = (void(APIENTRY*)(GLint, GLint, GLsizei, GLsizei))
141
 
      SDL_GL_GetProcAddress("glViewport"); if(!p_glViewport) return false;
142
 
    p_glPushMatrix = (void(APIENTRY*)(void))
143
 
      SDL_GL_GetProcAddress("glPushMatrix"); if(!p_glPushMatrix) return false;
144
 
    p_glLoadIdentity = (void(APIENTRY*)(void))
145
 
      SDL_GL_GetProcAddress("glLoadIdentity"); if(!p_glLoadIdentity) return false;
146
 
 
147
 
    p_glBegin = (void(APIENTRY*)(GLenum))
148
 
      SDL_GL_GetProcAddress("glBegin"); if(!p_glBegin) return false;
149
 
    p_glEnd = (void(APIENTRY*)(void))
150
 
      SDL_GL_GetProcAddress("glEnd"); if(!p_glEnd) return false;
151
 
    p_glVertex2i = (void(APIENTRY*)(GLint, GLint))
152
 
      SDL_GL_GetProcAddress("glVertex2i"); if(!p_glVertex2i) return false;
153
 
    p_glTexCoord2f = (void(APIENTRY*)(GLfloat, GLfloat))
154
 
      SDL_GL_GetProcAddress("glTexCoord2f"); if(!p_glTexCoord2f) return false;
155
 
 
156
 
    p_glReadPixels = (void(APIENTRY*)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid*))
157
 
      SDL_GL_GetProcAddress("glReadPixels"); if(!p_glReadPixels) return false;
158
 
    p_glPixelStorei = (void(APIENTRY*)(GLenum, GLint))
159
 
      SDL_GL_GetProcAddress("glPixelStorei"); if(!p_glPixelStorei) return false;
160
 
 
161
 
    p_glTexEnvf = (void(APIENTRY*)(GLenum, GLenum, GLfloat))
162
 
      SDL_GL_GetProcAddress("glTexEnvf"); if(!p_glTexEnvf) return false;
163
 
    p_glGenTextures = (void(APIENTRY*)(GLsizei, GLuint*))
164
 
      SDL_GL_GetProcAddress("glGenTextures"); if(!p_glGenTextures) return false;
165
 
    p_glDeleteTextures = (void(APIENTRY*)(GLsizei, const GLuint*))
166
 
      SDL_GL_GetProcAddress("glDeleteTextures"); if(!p_glDeleteTextures) return false;
167
 
    p_glBindTexture = (void(APIENTRY*)(GLenum, GLuint))
168
 
      SDL_GL_GetProcAddress("glBindTexture"); if(!p_glBindTexture) return false;
169
 
    p_glTexImage2D = (void(APIENTRY*)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*))
170
 
      SDL_GL_GetProcAddress("glTexImage2D"); if(!p_glTexImage2D) return false;
171
 
    p_glTexSubImage2D = (void(APIENTRY*)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*))
172
 
      SDL_GL_GetProcAddress("glTexSubImage2D"); if(!p_glTexSubImage2D) return false;
173
 
    p_glTexParameteri = (void(APIENTRY*)(GLenum, GLenum, GLint))
174
 
      SDL_GL_GetProcAddress("glTexParameteri"); if(!p_glTexParameteri) return false;
 
138
    switch(functionality)
 
139
    {
 
140
      case kGL_BASIC:
 
141
        OGL_INIT(void,glClear,(GLbitfield));
 
142
        OGL_INIT(void,glEnable,(GLenum));
 
143
        OGL_INIT(void,glDisable,(GLenum));
 
144
        OGL_INIT(void,glPushAttrib,(GLbitfield));
 
145
        OGL_INIT(const GLubyte*,glGetString,(GLenum));
 
146
        OGL_INIT(void,glHint,(GLenum, GLenum));
 
147
        OGL_INIT(void,glShadeModel,(GLenum));
 
148
 
 
149
        OGL_INIT(void,glMatrixMode,(GLenum));
 
150
        OGL_INIT(void,glOrtho,(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble));
 
151
        OGL_INIT(void,glViewport,(GLint, GLint, GLsizei, GLsizei));
 
152
        OGL_INIT(void,glPushMatrix,(void));
 
153
        OGL_INIT(void,glLoadIdentity,(void));
 
154
 
 
155
        OGL_INIT(void,glBegin,(GLenum));
 
156
        OGL_INIT(void,glEnd,(void));
 
157
        OGL_INIT(void,glVertex2i,(GLint, GLint));
 
158
        OGL_INIT(void,glTexCoord2f,(GLfloat, GLfloat));
 
159
 
 
160
        OGL_INIT(void,glReadPixels,(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid*));
 
161
        OGL_INIT(void,glPixelStorei,(GLenum, GLint));
 
162
 
 
163
        OGL_INIT(void,glTexEnvf,(GLenum, GLenum, GLfloat));
 
164
        OGL_INIT(void,glGenTextures,(GLsizei, GLuint*));
 
165
        OGL_INIT(void,glDeleteTextures,(GLsizei, const GLuint*));
 
166
        OGL_INIT(void,glActiveTexture,(GLenum));
 
167
        OGL_INIT(void,glBindTexture,(GLenum, GLuint));
 
168
        OGL_INIT(void,glTexImage2D,(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*));
 
169
        OGL_INIT(void,glTexSubImage2D,(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*));
 
170
        OGL_INIT(void,glTexParameteri,(GLenum, GLenum, GLint));
 
171
        break; // kGLBasic
 
172
 
 
173
      case kGL_SHADER:
 
174
        OGL_INIT(GLuint,glCreateShader,(GLenum));
 
175
        OGL_INIT(void,glDeleteShader,(GLuint));
 
176
        OGL_INIT(void,glShaderSource,(GLuint, int, const char**, int));
 
177
        OGL_INIT(void,glCompileShader,(GLuint));
 
178
        OGL_INIT(GLuint,glCreateProgram,(void));
 
179
        OGL_INIT(void,glDeleteProgram,(GLuint));
 
180
        OGL_INIT(void,glAttachShader,(GLuint, GLuint));
 
181
        OGL_INIT(void,glLinkProgram,(GLuint));
 
182
        OGL_INIT(void,glUseProgram,(GLuint));
 
183
        OGL_INIT(GLint,glGetUniformLocation,(GLuint, const char*));
 
184
        OGL_INIT(void,glUniform1i,(GLint, GLint));
 
185
        OGL_INIT(void,glUniform1f,(GLint, GLfloat));
 
186
        OGL_INIT(void,glCopyTexImage2D,(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint));
 
187
        OGL_INIT(void,glCopyTexSubImage2D,(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei));
 
188
        OGL_INIT(void,glGetIntegerv,(GLenum, GLint*));
 
189
        OGL_INIT(void,glTexEnvi,(GLenum, GLenum, GLint));
 
190
        OGL_INIT(void,glMultiTexCoord2f,(GLenum, GLfloat, GLfloat));
 
191
        OGL_INIT(GLenum,glGetError,(void));
 
192
        break;  // kGLShader
 
193
    }
175
194
  }
176
195
  else
177
196
    return false;
180
199
}
181
200
 
182
201
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
183
 
bool FrameBufferGL::initSubsystem(VideoMode mode)
 
202
bool FrameBufferGL::initSubsystem(VideoMode& mode)
184
203
{
185
204
  mySDLFlags |= SDL_OPENGL;
186
205
 
234
253
}
235
254
 
236
255
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
237
 
bool FrameBufferGL::setVidMode(VideoMode mode)
 
256
bool FrameBufferGL::setVidMode(VideoMode& mode)
238
257
{
239
258
  bool inUIMode =
240
259
    myOSystem->eventHandler().state() == EventHandler::S_LAUNCHER ||
241
260
    myOSystem->eventHandler().state() == EventHandler::S_DEBUGGER;
242
261
 
243
 
  myScreenDim.x = myScreenDim.y = 0;
244
 
  myScreenDim.w = mode.screen_w;
245
 
  myScreenDim.h = mode.screen_h;
246
 
 
247
 
  myImageDim.x = mode.image_x;
248
 
  myImageDim.y = mode.image_y;
249
 
  myImageDim.w = mode.image_w;
250
 
  myImageDim.h = mode.image_h;
251
 
 
252
 
  // Normally, we just scale to the given zoom level
253
 
  myWidthScaleFactor  = (float) mode.zoom;
254
 
  myHeightScaleFactor = (float) mode.zoom;
255
 
 
256
 
  // Activate aspect ratio correction in TIA mode
257
 
  int iaspect = myOSystem->settings().getInt("gl_aspect");
258
 
  if(!inUIMode && iaspect < 100)
259
 
  {
260
 
    float aspectFactor = float(iaspect) / 100.0;
261
 
    myWidthScaleFactor *= aspectFactor;
262
 
    myImageDim.w = (uInt16)(float(myImageDim.w) * aspectFactor);
263
 
  }
264
 
 
265
 
  // Activate stretching if its been requested in fullscreen mode
266
 
  float stretchFactor = 1.0;
267
 
  if(fullScreen() && (myImageDim.w < myScreenDim.w) &&
268
 
     (myImageDim.h < myScreenDim.h))
269
 
  {
270
 
    const string& gl_fsmax = myOSystem->settings().getString("gl_fsmax");
271
 
 
272
 
    // Only stretch in certain modes
273
 
    if((gl_fsmax == "always") || 
274
 
       (inUIMode && gl_fsmax == "ui") ||
275
 
       (!inUIMode && gl_fsmax == "tia"))
 
262
  // Grab the initial width and height before it's updated below
 
263
  uInt32 baseWidth = mode.image_w / mode.gfxmode.zoom;
 
264
  uInt32 baseHeight = mode.image_h / mode.gfxmode.zoom;
 
265
 
 
266
  // Update the graphics filter options
 
267
  myUseTexture = true;  myTextureStag = false;
 
268
  const string& tv_tex = myOSystem->settings().getString("tv_tex");
 
269
  if(tv_tex == "stag")        myTextureStag = true;
 
270
  else if(tv_tex != "normal") myUseTexture = false;
 
271
 
 
272
  myUseBleed = true;
 
273
  const string& tv_bleed = myOSystem->settings().getString("tv_bleed");
 
274
  if(tv_bleed == "low")         myBleedQuality = 0;
 
275
  else if(tv_bleed == "medium") myBleedQuality = 1;
 
276
  else if(tv_bleed == "high")   myBleedQuality = 2;
 
277
  else  myUseBleed = false;
 
278
 
 
279
  myUseNoise = true;
 
280
  const string& tv_noise = myOSystem->settings().getString("tv_noise");
 
281
  if(tv_noise == "low")         myNoiseQuality = 5;
 
282
  else if(tv_noise == "medium") myNoiseQuality = 15;
 
283
  else if(tv_noise == "high")   myNoiseQuality = 25;
 
284
  else  myUseNoise = false;
 
285
 
 
286
  myUseGLPhosphor = myOSystem->settings().getBool("tv_phos");
 
287
 
 
288
  // Set the zoom level
 
289
  myZoomLevel = mode.gfxmode.zoom;
 
290
 
 
291
  // Aspect ratio and fullscreen stretching only applies to the TIA
 
292
  if(!inUIMode)
 
293
  {
 
294
    // Aspect ratio (depends on whether NTSC or PAL is detected)
 
295
    const string& frate = myOSystem->console().about().InitialFrameRate;
 
296
    int aspect =
 
297
      myOSystem->settings().getInt(frate == "60" ? "gl_aspectn" : "gl_aspectp");
 
298
    mode.image_w = (uInt16)(float(mode.image_w * aspect) / 100.0);
 
299
 
 
300
    // Fullscreen mode stretching
 
301
    if(fullScreen() && myOSystem->settings().getBool("gl_fsmax") &&
 
302
       (mode.image_w < mode.screen_w) && (mode.image_h < mode.screen_h))
276
303
    {
277
 
      float scaleX = float(myImageDim.w) / myScreenDim.w;
278
 
      float scaleY = float(myImageDim.h) / myScreenDim.h;
 
304
      float stretchFactor = 1.0;
 
305
      float scaleX = float(mode.image_w) / mode.screen_w;
 
306
      float scaleY = float(mode.image_h) / mode.screen_h;
279
307
 
280
308
      if(scaleX > scaleY)
281
 
        stretchFactor = float(myScreenDim.w) / myImageDim.w;
 
309
        stretchFactor = float(mode.screen_w) / mode.image_w;
282
310
      else
283
 
        stretchFactor = float(myScreenDim.h) / myImageDim.h;
 
311
        stretchFactor = float(mode.screen_h) / mode.image_h;
 
312
 
 
313
      mode.image_w = (Uint16) (stretchFactor * mode.image_w);
 
314
      mode.image_h = (Uint16) (stretchFactor * mode.image_h);
284
315
    }
285
316
  }
286
 
  myWidthScaleFactor  *= stretchFactor;
287
 
  myHeightScaleFactor *= stretchFactor;
288
317
 
289
318
  // Now re-calculate the dimensions
290
 
  myImageDim.w = (Uint16) (stretchFactor * myImageDim.w);
291
 
  myImageDim.h = (Uint16) (stretchFactor * myImageDim.h);
292
 
  if(!fullScreen()) myScreenDim.w = myImageDim.w;
293
 
  myImageDim.x = (myScreenDim.w - myImageDim.w) / 2;
294
 
  myImageDim.y = (myScreenDim.h - myImageDim.h) / 2;
 
319
  if(!fullScreen()) mode.screen_w = mode.image_w;
 
320
  mode.image_x = (mode.screen_w - mode.image_w) >> 1;
 
321
  mode.image_y = (mode.screen_h - mode.image_h) >> 1;
295
322
 
296
323
  SDL_GL_SetAttribute( SDL_GL_RED_SIZE,   myRGB[0] );
297
324
  SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, myRGB[1] );
298
325
  SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE,  myRGB[2] );
299
326
  SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, myRGB[3] );
300
327
  SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
301
 
  SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 );
 
328
//  if(myOSystem->settings().getBool("gl_accel"))
 
329
//    SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 );
302
330
 
303
331
  // There's no guarantee this is supported on all hardware
304
332
  // We leave it to the user to test and decide
306
334
  SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, vsync );
307
335
 
308
336
  // Create screen containing GL context
309
 
  myScreen = SDL_SetVideoMode(myScreenDim.w, myScreenDim.h, 0, mySDLFlags);
 
337
  myScreen = SDL_SetVideoMode(mode.screen_w, mode.screen_h, 0, mySDLFlags);
310
338
  if(myScreen == NULL)
311
339
  {
312
340
    cerr << "ERROR: Unable to open SDL window: " << SDL_GetError() << endl;
313
341
    return false;
314
342
  }
315
 
 
316
 
  // Reload OpenGL function pointers.  This only seems to be needed for Windows
317
 
  // Vista, but it shouldn't hurt on other systems.
318
 
  if(!loadFuncs())
 
343
  // Make sure the flags represent the current screen state
 
344
  mySDLFlags = myScreen->flags;
 
345
 
 
346
  // Load OpenGL function pointers
 
347
  // Basic functionaity is an absolute requirement
 
348
  // TV effects require GLSL, but not having them still allows basic GL support
 
349
  myGLSLAvailable = myFBOAvailable = false;
 
350
  if(loadFuncs(kGL_BASIC))
 
351
  {
 
352
    // Grab OpenGL version number
 
353
    string version((const char *)p_glGetString(GL_VERSION));
 
354
    myGLVersion = atof(version.substr(0, 3).c_str());
 
355
 
 
356
    // TV effects depend on the GLSL functions being available
 
357
    myGLSLAvailable = loadFuncs(kGL_SHADER);
 
358
  }
 
359
  else
319
360
    return false;
320
361
 
321
362
  // Check for some extensions that can potentially speed up operation
329
370
    myHaveTexRectEXT = false;
330
371
 
331
372
  // Initialize GL display
332
 
  p_glViewport(myImageDim.x, myImageDim.y, myImageDim.w, myImageDim.h);
 
373
  p_glViewport(0, 0, mode.screen_w, mode.screen_h);
333
374
  p_glShadeModel(GL_FLAT);
334
375
  p_glDisable(GL_CULL_FACE);
335
376
  p_glDisable(GL_DEPTH_TEST);
339
380
 
340
381
  p_glMatrixMode(GL_PROJECTION);
341
382
  p_glLoadIdentity();
342
 
  p_glOrtho(0.0, myImageDim.w, myImageDim.h, 0.0, 0.0, 1.0);
 
383
  p_glOrtho(0.0, mode.screen_w, mode.screen_h, 0.0, -1.0, 1.0);
343
384
  p_glMatrixMode(GL_MODELVIEW);
 
385
  p_glPushMatrix();
344
386
  p_glLoadIdentity();
345
387
 
346
 
  // Allocate GL textures
347
 
  createTextures();
348
 
 
349
 
  p_glEnable(myBuffer.target);
 
388
/*
 
389
cerr << "dimensions: " << (fullScreen() ? "(full)" : "") << endl
 
390
        << "  screen w = " << mode.screen_w << endl
 
391
        << "  screen h = " << mode.screen_h << endl
 
392
        << "  image x  = " << mode.image_x << endl
 
393
        << "  image y  = " << mode.image_y << endl
 
394
        << "  image w  = " << mode.image_w << endl
 
395
        << "  image h  = " << mode.image_h << endl
 
396
        << "  base w   = " << baseWidth << endl
 
397
        << "  base h   = " << baseHeight << endl
 
398
        << endl;
 
399
*/
 
400
 
 
401
  ////////////////////////////////////////////////////////////////////
 
402
  // Note that the following must be done in the order given
 
403
  // Basically, all surfaces must first be free'd before being
 
404
  // recreated
 
405
  // So, we delete the TIA surface first, then reset all other surfaces
 
406
  // (which frees all surfaces and then reloads all surfaces), then
 
407
  // re-create the TIA surface (if necessary)
 
408
  // In this way, all free()'s come before all reload()'s
 
409
  ////////////////////////////////////////////////////////////////////
 
410
 
 
411
  // The framebuffer only takes responsibility for TIA surfaces
 
412
  // Other surfaces (such as the ones used for dialogs) are allocated
 
413
  // in the Dialog class
 
414
  delete myTiaSurface;  myTiaSurface = NULL;
 
415
 
 
416
  // Any previously allocated textures currently in use by various UI items
 
417
  // need to be refreshed as well (only seems to be required for OSX)
 
418
  resetSurfaces();
 
419
 
 
420
  if(!inUIMode)
 
421
  {
 
422
    // The actual TIA image is only half of that specified by baseWidth
 
423
    // The stretching can be done in hardware now that the TIA surface
 
424
    // and other UI surfaces are no longer tied together
 
425
    // Note that this may change in the future, when we add more
 
426
    // complex filters/scalers, but for now it's fine
 
427
    //
 
428
    // Also note that TV filtering is only available with OpenGL 2.0+
 
429
    // The hint we provide here is only that GLSL is available and
 
430
    // TV effects *can* be applied to this surface
 
431
    // The specific TV effect settings still determine whether any
 
432
    // filtering *will* be applied in such a case
 
433
    myTiaSurface = new FBSurfaceGL(*this, baseWidth>>1, baseHeight,
 
434
                                     mode.image_w, mode.image_h,
 
435
                                     myGLSLAvailable);
 
436
    myTiaSurface->setPos(mode.image_x, mode.image_y);
 
437
    myTiaSurface->setFilter(myOSystem->settings().getString("gl_filter"));
 
438
  }
350
439
 
351
440
  // Make sure any old parts of the screen are erased
352
441
  p_glClear(GL_COLOR_BUFFER_BIT);
357
446
}
358
447
 
359
448
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
360
 
void FrameBufferGL::drawMediaSource()
361
 
{
362
 
  MediaSource& mediasrc = myOSystem->console().mediaSource();
 
449
void FrameBufferGL::invalidate()
 
450
{
 
451
// TODO - add code for this
 
452
}
 
453
 
 
454
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
455
void FrameBufferGL::drawTIA(bool fullRedraw)
 
456
{
 
457
  const TIA& tia = myOSystem->console().tia();
363
458
 
364
459
  // Copy the mediasource framebuffer to the RGB texture
365
 
  uInt8* currentFrame  = mediasrc.currentFrameBuffer();
366
 
  uInt8* previousFrame = mediasrc.previousFrameBuffer();
367
 
  uInt32 width         = mediasrc.width();
368
 
  uInt32 height        = mediasrc.height();
369
 
  uInt16* buffer       = (uInt16*) myTexture->pixels;
 
460
  uInt8* currentFrame  = tia.currentFrameBuffer();
 
461
  uInt8* previousFrame = tia.previousFrameBuffer();
 
462
  uInt32 width         = tia.width();
 
463
  uInt32 height        = tia.height();
 
464
  uInt32 pitch         = myTiaSurface->pitch();
 
465
  uInt16* buffer       = (uInt16*) myTiaSurface->pixels();
370
466
 
371
467
  // TODO - is this fast enough?
372
468
  if(!myUsePhosphor)
382
478
        uInt8 v = currentFrame[bufofs];
383
479
        uInt8 w = previousFrame[bufofs];
384
480
 
385
 
        if(v != w || theRedrawTIAIndicator)
 
481
        if(v != w || fullRedraw)
386
482
        {
387
483
          // If we ever get to this point, we know the current and previous
388
484
          // buffers differ.  In that case, make sure the changes are
389
485
          // are drawn in postFrameUpdate()
390
486
          myDirtyFlag = true;
391
487
 
392
 
          buffer[pos] = buffer[pos+1] = (uInt16) myDefPalette[v];
 
488
          buffer[pos] = (uInt16) myDefPalette[v];
393
489
        }
394
 
        pos += 2;
 
490
        pos++;
395
491
      }
396
492
      bufofsY    += width;
397
 
      screenofsY += myBuffer.pitch;
 
493
      screenofsY += pitch;
398
494
    }
399
495
  }
400
496
  else
401
497
  {
402
498
    // Phosphor mode always implies a dirty update,
403
 
    // so we don't care about theRedrawTIAIndicator
 
499
    // so we don't care about fullRedraw
404
500
    myDirtyFlag = true;
405
501
 
406
502
    uInt32 bufofsY    = 0;
415
511
        uInt8 w = previousFrame[bufofs];
416
512
 
417
513
        buffer[pos++] = (uInt16) myAvgPalette[v][w];
418
 
        buffer[pos++] = (uInt16) myAvgPalette[v][w];
419
514
      }
420
515
      bufofsY    += width;
421
 
      screenofsY += myBuffer.pitch;
 
516
      screenofsY += pitch;
422
517
    }
423
518
  }
424
 
}
425
519
 
426
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
427
 
void FrameBufferGL::preFrameUpdate()
428
 
{
 
520
  // And blit the surface
 
521
  myTiaSurface->addDirtyRect(0, 0, 0, 0);
 
522
  myTiaSurface->update();
429
523
}
430
524
 
431
525
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
433
527
{
434
528
  if(myDirtyFlag)
435
529
  {
436
 
    // Texturemap complete texture to surface so we have free scaling 
437
 
    // and antialiasing 
438
 
    uInt32 w = myImageDim.w, h = myImageDim.h;
439
 
 
440
 
    p_glTexSubImage2D(myBuffer.target, 0, 0, 0,
441
 
                      myBuffer.texture_width, myBuffer.texture_height,
442
 
                      myBuffer.format, myBuffer.type, myBuffer.pixels);
443
 
    p_glBegin(GL_QUADS);
444
 
      p_glTexCoord2f(myBuffer.tex_coord[0], myBuffer.tex_coord[1]); p_glVertex2i(0, 0);
445
 
      p_glTexCoord2f(myBuffer.tex_coord[2], myBuffer.tex_coord[1]); p_glVertex2i(w, 0);
446
 
      p_glTexCoord2f(myBuffer.tex_coord[2], myBuffer.tex_coord[3]); p_glVertex2i(w, h);
447
 
      p_glTexCoord2f(myBuffer.tex_coord[0], myBuffer.tex_coord[3]); p_glVertex2i(0, h);
448
 
    p_glEnd();
449
 
 
450
 
    // Overlay UI dialog boxes
451
 
 
452
 
 
453
530
    // Now show all changes made to the texture
454
531
    SDL_GL_SwapBuffers();
455
 
 
456
532
    myDirtyFlag = false;
457
533
  }
458
534
}
459
535
 
460
536
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
537
void FrameBufferGL::enablePhosphor(bool enable, int blend)
 
538
{
 
539
  myUsePhosphor   = enable;
 
540
  myPhosphorBlend = blend;
 
541
 
 
542
  myRedrawEntireFrame = true;
 
543
}
 
544
 
 
545
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
546
FBSurface* FrameBufferGL::createSurface(int w, int h, bool isBase) const
 
547
{
 
548
  // Ignore 'isBase' argument; all GL surfaces are separate
 
549
  // Also, since this method will only be called for use in external
 
550
  // dialogs which cannot be scaled, the base and scaled parameters
 
551
  // are equal
 
552
  return new FBSurfaceGL((FrameBufferGL&)*this, w, h, w, h);
 
553
}
 
554
 
 
555
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
461
556
void FrameBufferGL::scanline(uInt32 row, uInt8* data) const
462
557
{
463
558
  // Invert the row, since OpenGL rows start at the bottom
464
559
  // of the framebuffer
465
 
  row = myImageDim.h + myImageDim.y - row - 1;
 
560
  const GUI::Rect& image = imageRect();
 
561
  row = image.height() + image.y() - row - 1;
466
562
 
467
563
  p_glPixelStorei(GL_PACK_ALIGNMENT, 1);
468
 
  p_glReadPixels(myImageDim.x, row, myImageDim.w, 1, GL_RGB, GL_UNSIGNED_BYTE, data);
469
 
}
470
 
 
471
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
472
 
void FrameBufferGL::toggleFilter()
473
 
{
474
 
  if(myBuffer.filter == GL_NEAREST)
475
 
  {
476
 
    myBuffer.filter = GL_LINEAR;
477
 
    myOSystem->settings().setString("gl_filter", "linear");
478
 
    showMessage("Filtering: GL_LINEAR");
479
 
  }
480
 
  else
481
 
  {
482
 
    myBuffer.filter = GL_NEAREST;
483
 
    myOSystem->settings().setString("gl_filter", "nearest");
484
 
    showMessage("Filtering: GL_NEAREST");
485
 
  }
486
 
 
487
 
  p_glBindTexture(myBuffer.target, myBuffer.texture);
488
 
  p_glTexParameteri(myBuffer.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
489
 
  p_glTexParameteri(myBuffer.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
490
 
  p_glTexParameteri(myBuffer.target, GL_TEXTURE_MAG_FILTER, myBuffer.filter);
491
 
  p_glTexParameteri(myBuffer.target, GL_TEXTURE_MIN_FILTER, myBuffer.filter);
492
 
 
493
 
  // The filtering has changed, so redraw the entire screen
494
 
  theRedrawTIAIndicator = true;
495
 
}
496
 
 
497
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
498
 
void FrameBufferGL::hLine(uInt32 x, uInt32 y, uInt32 x2, int color)
499
 
{
500
 
  uInt16* buffer = (uInt16*) myTexture->pixels + y * myBuffer.pitch + x;
 
564
  p_glReadPixels(image.x(), row, image.width(), 1, GL_RGB, GL_UNSIGNED_BYTE, data);
 
565
}
 
566
 
 
567
 
 
568
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
569
//  FBSurfaceGL implementation follows ...
 
570
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
571
 
 
572
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
573
FBSurfaceGL::FBSurfaceGL(FrameBufferGL& buffer,
 
574
                         uInt32 baseWidth, uInt32 baseHeight,
 
575
                         uInt32 scaleWidth, uInt32 scaleHeight,
 
576
                         bool allowFiltering)
 
577
  : myFB(buffer),
 
578
    myTexture(NULL),
 
579
    myTexID(0),
 
580
    myFilterTexID(0),
 
581
    mySubMaskTexID(0),
 
582
    myNoiseMaskTexID(NULL),
 
583
    myPhosphorTexID(0),
 
584
    mySubpixelTexture(NULL),
 
585
    myNoiseTexture(NULL),
 
586
    myXOrig(0),
 
587
    myYOrig(0),
 
588
    myWidth(scaleWidth),
 
589
    myHeight(scaleHeight),
 
590
    myBleedProgram(0),
 
591
    myTextureProgram(0),
 
592
    myNoiseProgram(0),
 
593
    myPhosphorProgram(0),
 
594
    myTextureNoiseProgram(0),
 
595
    myNoiseNum(0),
 
596
    myTvFiltersEnabled(false)
 
597
{
 
598
  // Fill buffer struct with valid data
 
599
  // This changes depending on the texturing used
 
600
  myTexCoord[0] = 0.0f;
 
601
  myTexCoord[1] = 0.0f;
 
602
  if(myFB.myHaveTexRectEXT)
 
603
  {
 
604
    myTexWidth    = baseWidth;
 
605
    myTexHeight   = baseHeight;
 
606
    myTexTarget   = GL_TEXTURE_RECTANGLE_ARB;
 
607
    myTexCoord[2] = (GLfloat) myTexWidth;
 
608
    myTexCoord[3] = (GLfloat) myTexHeight;
 
609
 
 
610
    // This is a quick fix, a better one will come later
 
611
    myTvFiltersEnabled = false;
 
612
  }
 
613
  else
 
614
  {
 
615
    myTexWidth    = power_of_two(baseWidth);
 
616
    myTexHeight   = power_of_two(baseHeight);
 
617
    myTexTarget   = GL_TEXTURE_2D;
 
618
    myTexCoord[2] = (GLfloat) baseWidth / myTexWidth;
 
619
    myTexCoord[3] = (GLfloat) baseHeight / myTexHeight;
 
620
  }
 
621
 
 
622
  // Based on experimentation, the following is the fastest 16-bit
 
623
  // format for OpenGL (on all platforms)
 
624
  myTexture = SDL_CreateRGBSurface(SDL_SWSURFACE,
 
625
                  myTexWidth, myTexHeight, 16,
 
626
                  0x00007c00, 0x000003e0, 0x0000001f, 0x00000000);
 
627
  myPitch = myTexture->pitch >> 1;
 
628
 
 
629
  // The 'allowFiltering' boolean is only a hint that filtering is allowed
 
630
  // on this surface
 
631
  // We still need to check if the functionality exists to do it
 
632
  if(allowFiltering)
 
633
  {
 
634
    // It's only enabled if we use one of the filters *AND* GLSL is available
 
635
    myTvFiltersEnabled = myFB.myGLSLAvailable &&
 
636
       (myFB.myUseTexture || myFB.myUseNoise ||
 
637
        myFB.myUseBleed || myFB.myUseGLPhosphor);
 
638
  }
 
639
  else
 
640
    myTvFiltersEnabled = false;
 
641
 
 
642
  // Only do this if TV filters enabled, otherwise it won't be used anyway
 
643
  if(myTvFiltersEnabled)
 
644
  {
 
645
    // For a reason that hasn't been investigated yet, some of the filter and mask
 
646
    // texture coordinates need to be swapped in order for it not to render upside down
 
647
 
 
648
    myFilterTexCoord[0] = 0.0f;
 
649
    myFilterTexCoord[3] = 0.0f;
 
650
 
 
651
    if(myFB.myHaveTexRectEXT)
 
652
    {
 
653
      myFilterTexWidth = scaleWidth;
 
654
      myFilterTexHeight = scaleHeight;
 
655
      myFilterTexCoord[2] = (GLfloat) myFilterTexWidth;
 
656
      myFilterTexCoord[1] = (GLfloat) myFilterTexHeight;
 
657
    }
 
658
    else
 
659
    {
 
660
      myFilterTexWidth = power_of_two(scaleWidth);
 
661
      myFilterTexHeight = power_of_two(scaleHeight);
 
662
      myFilterTexCoord[2] = (GLfloat) scaleWidth / myFilterTexWidth;
 
663
      myFilterTexCoord[1] = (GLfloat) scaleHeight / myFilterTexHeight;
 
664
    }
 
665
 
 
666
    // Only do this if TV and color bleed filters are enabled
 
667
    // This filer applies a color averaging of surrounding pixels for each pixel
 
668
    if(myFB.myUseBleed)
 
669
    {
 
670
      // Load shader programs. If it fails, don't use this filter.
 
671
      myBleedProgram = genShader(SHADER_BLEED);
 
672
      if(myBleedProgram == 0)
 
673
      {
 
674
        myFB.myUseBleed = false;
 
675
        cout << "ERROR: Failed to make bleed programs" << endl;
 
676
      }
 
677
    }
 
678
 
 
679
    // If the texture and noise filters are enabled together, we can use a single shader
 
680
    // Make sure we can use three textures at once first
 
681
    GLint texUnits;
 
682
    p_glGetIntegerv(GL_MAX_TEXTURE_UNITS, &texUnits);
 
683
    if(texUnits >= 3 && myFB.myUseTexture && myFB.myUseNoise)
 
684
    {
 
685
      // Load shader program. If it fails, don't use this shader.
 
686
      myTextureNoiseProgram = genShader(SHADER_TEXNOISE);
 
687
      if(myTextureNoiseProgram == 0)
 
688
      {
 
689
        cout << "ERROR: Failed to make texture/noise program" << endl;
 
690
 
 
691
        // Load shader program. If it fails, don't use this filter.
 
692
        myTextureProgram = genShader(SHADER_TEX);
 
693
        if(myTextureProgram == 0)
 
694
        {
 
695
          myFB.myUseTexture = false;
 
696
          cout << "ERROR: Failed to make texture program" << endl;
 
697
        }
 
698
 
 
699
        // Load shader program. If it fails, don't use this filter.
 
700
        myNoiseProgram = genShader(SHADER_NOISE);
 
701
        if(myNoiseProgram == 0)
 
702
        {
 
703
          myFB.myUseNoise = false;
 
704
          cout << "ERROR: Failed to make noise program" << endl;
 
705
        }
 
706
      }
 
707
    }
 
708
    // Else, detect individual settings
 
709
    else
 
710
    {
 
711
      if(myFB.myUseTexture)
 
712
      {
 
713
        // Load shader program. If it fails, don't use this filter.
 
714
        myTextureProgram = genShader(SHADER_TEX);
 
715
        if(myTextureProgram == 0)
 
716
        {
 
717
          myFB.myUseTexture = false;
 
718
          cout << "ERROR: Failed to make texture program" << endl;
 
719
        }
 
720
      }
 
721
 
 
722
      if(myFB.myUseNoise)
 
723
      {
 
724
        // Load shader program. If it fails, don't use this filter.
 
725
        myNoiseProgram = genShader(SHADER_NOISE);
 
726
        if(myNoiseProgram == 0)
 
727
        {
 
728
          myFB.myUseNoise = false;
 
729
          cout << "ERROR: Failed to make noise program" << endl;
 
730
        }
 
731
      }
 
732
    }
 
733
 
 
734
    // Only do this if TV and color texture filters are enabled
 
735
    // This filter applies an RGB color pixel mask as well as a blackspace mask
 
736
    if(myFB.myUseTexture)
 
737
    {
 
738
      // Prepare subpixel texture
 
739
      mySubpixelTexture = SDL_CreateRGBSurface(SDL_SWSURFACE,
 
740
                    myFilterTexWidth, myFilterTexHeight, 16,
 
741
                    0x00007c00, 0x000003e0, 0x0000001f, 0x00000000);
 
742
 
 
743
      uInt32 pCounter = 0;
 
744
      for (uInt32 y = 0; y < (uInt32)myFilterTexHeight; y++)
 
745
      {
 
746
        for (uInt32 x = 0; x < (uInt32)myFilterTexWidth; x++)
 
747
        {
 
748
          // Cause vertical offset for every other black row if enabled
 
749
          uInt32 offsetY;
 
750
          if (!myFB.myTextureStag || x % 6 < 3)
 
751
            offsetY = y;
 
752
          else
 
753
            offsetY = y + 2;
 
754
 
 
755
          // Make a row of black for the mask every so often
 
756
          if (offsetY % 4 == 0)
 
757
          {
 
758
            ((uInt16*)mySubpixelTexture->pixels)[pCounter] = 0x0000;
 
759
          }
 
760
          // Apply the coorect color mask
 
761
          else
 
762
          {
 
763
            ((uInt16*)mySubpixelTexture->pixels)[pCounter] = 0x7c00 >> ((x % 3) * 5);
 
764
          }
 
765
          pCounter++;
 
766
        }
 
767
      }
 
768
    }
 
769
 
 
770
    // Only do this if TV and noise filters are enabled
 
771
    // This filter applies a texture filled with gray pixel of random intensities
 
772
    if(myFB.myUseNoise)
 
773
    {
 
774
      // Get the current number of nose textures to use
 
775
      myNoiseNum = myFB.myNoiseQuality;
 
776
 
 
777
      // Allocate space for noise textures
 
778
      myNoiseTexture = new SDL_Surface*[myNoiseNum];
 
779
      myNoiseMaskTexID = new GLuint[myNoiseNum];
 
780
 
 
781
      // Prepare noise textures
 
782
      for(int i = 0; i < myNoiseNum; i++)
 
783
      {
 
784
        myNoiseTexture[i] = SDL_CreateRGBSurface(SDL_SWSURFACE,
 
785
                    myFilterTexWidth, myFilterTexHeight, 16,
 
786
                    0x00007c00, 0x000003e0, 0x0000001f, 0x00000000);
 
787
      }
 
788
 
 
789
      uInt32 pCounter = 0;
 
790
      for(int i = 0; i < myNoiseNum; i++)
 
791
      {
 
792
        pCounter = 0;
 
793
 
 
794
        // Attempt to make the numbers as random as possible
 
795
        int temp = (unsigned)time(0) + rand()/4;
 
796
        srand(temp);
 
797
 
 
798
        for (uInt32 y = 0; y < (uInt32)myFilterTexHeight; y++)
 
799
        {
 
800
          for (uInt32 x = 0; x < (uInt32)myFilterTexWidth; x++)
 
801
          {
 
802
            // choose random 0 - 2
 
803
            // 0 = 0x0000
 
804
            // 1 = 0x0421
 
805
            // 2 = 0x0842
 
806
            int num = rand() % 3;
 
807
            if (num == 0)
 
808
              ((uInt16*)myNoiseTexture[i]->pixels)[pCounter] = 0x0000;
 
809
            else if (num == 1)
 
810
              ((uInt16*)myNoiseTexture[i]->pixels)[pCounter] = 0x0421;
 
811
            else if (num == 2)
 
812
              ((uInt16*)myNoiseTexture[i]->pixels)[pCounter] = 0x0842;
 
813
 
 
814
            pCounter++;
 
815
          }
 
816
        }
 
817
      }
 
818
    }
 
819
 
 
820
    // Only do this if TV and phosphor filters are enabled
 
821
    // This filter merges the past screen with the current one, to give a phosphor burn-off effect
 
822
    if(myFB.myUseGLPhosphor)
 
823
    {
 
824
      // Load shader program. If it fails, don't use this filter.
 
825
      myPhosphorProgram = genShader(SHADER_PHOS);
 
826
      if(myPhosphorProgram == 0)
 
827
      {
 
828
        myFB.myUseGLPhosphor = false;
 
829
        cout << "ERROR: Failed to make phosphor program" << endl;
 
830
      }
 
831
    }
 
832
  }
 
833
 
 
834
  // Check to see if filters should still be used
 
835
  // Filtering must have been previously enabled, and GLSL must still be
 
836
  // available
 
837
  myTvFiltersEnabled = myTvFiltersEnabled && myFB.myGLSLAvailable &&
 
838
     (myFB.myUseTexture || myFB.myUseNoise ||
 
839
      myFB.myUseBleed || myFB.myUseGLPhosphor);
 
840
 
 
841
  // Associate the SDL surface with a GL texture object
 
842
  reload();
 
843
}
 
844
 
 
845
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
846
FBSurfaceGL::~FBSurfaceGL()
 
847
{
 
848
  if(myTexture)
 
849
    SDL_FreeSurface(myTexture);
 
850
 
 
851
  if(mySubpixelTexture)
 
852
    SDL_FreeSurface(mySubpixelTexture);
 
853
 
 
854
  if(myNoiseTexture)
 
855
    for(int i = 0; i < myNoiseNum; i++)
 
856
      SDL_FreeSurface(myNoiseTexture[i]);
 
857
 
 
858
  free();
 
859
}
 
860
 
 
861
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
862
void FBSurfaceGL::hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color)
 
863
{
 
864
  uInt16* buffer = (uInt16*) myTexture->pixels + y * myPitch + x;
501
865
  while(x++ <= x2)
502
 
    *buffer++ = (uInt16) myDefPalette[color];
 
866
    *buffer++ = (uInt16) myFB.myDefPalette[color];
503
867
}
504
868
 
505
869
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
506
 
void FrameBufferGL::vLine(uInt32 x, uInt32 y, uInt32 y2, int color)
 
870
void FBSurfaceGL::vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color)
507
871
{
508
 
  uInt16* buffer = (uInt16*) myTexture->pixels + y * myBuffer.pitch + x;
 
872
  uInt16* buffer = (uInt16*) myTexture->pixels + y * myPitch + x;
509
873
  while(y++ <= y2)
510
874
  {
511
 
    *buffer = (uInt16) myDefPalette[color];
512
 
    buffer += myBuffer.pitch;
 
875
    *buffer = (uInt16) myFB.myDefPalette[color];
 
876
    buffer += myPitch;
513
877
  }
514
878
}
515
879
 
516
880
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
517
 
void FrameBufferGL::fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, int color)
 
881
void FBSurfaceGL::fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color)
518
882
{
519
883
  // Fill the rectangle
520
884
  SDL_Rect tmp;
522
886
  tmp.y = y;
523
887
  tmp.w = w;
524
888
  tmp.h = h;
525
 
  SDL_FillRect(myTexture, &tmp, myDefPalette[color]);
 
889
  SDL_FillRect(myTexture, &tmp, myFB.myDefPalette[color]);
526
890
}
527
891
 
528
892
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
529
 
void FrameBufferGL::drawChar(const GUI::Font* font, uInt8 chr,
530
 
                             uInt32 tx, uInt32 ty, int color)
 
893
void FBSurfaceGL::drawChar(const GUI::Font* font, uInt8 chr,
 
894
                           uInt32 tx, uInt32 ty, uInt32 color)
531
895
{
532
896
  const FontDesc& desc = font->desc();
533
897
 
537
901
    if (chr == ' ') return;
538
902
    chr = desc.defaultchar;
539
903
  }
540
 
 
541
 
  const Int32 w = font->getCharWidth(chr);
542
 
  const Int32 h = font->getFontHeight();
543
904
  chr -= desc.firstchar;
544
 
  const uInt32* tmp = desc.bits + (desc.offset ? desc.offset[chr] : (chr * h));
545
 
 
546
 
  uInt16* buffer = (uInt16*) myTexture->pixels + ty * myBuffer.pitch + tx;
547
 
  for(int y = 0; y < h; ++y)
548
 
  {
549
 
    const uInt32 ptr = *tmp++;
550
 
    if(ptr)
551
 
    {
552
 
      uInt32 mask = 0x80000000;
553
 
      for(int x = 0; x < w; ++x, mask >>= 1)
554
 
        if(ptr & mask)
555
 
          buffer[x] = (uInt16) myDefPalette[color];
556
 
    }
557
 
    buffer += myBuffer.pitch;
 
905
 
 
906
  // Get the bounding box of the character
 
907
  int bbw, bbh, bbx, bby;
 
908
  if(!desc.bbx)
 
909
  {
 
910
    bbw = desc.fbbw;
 
911
    bbh = desc.fbbh;
 
912
    bbx = desc.fbbx;
 
913
    bby = desc.fbby;
 
914
  }
 
915
  else
 
916
  {
 
917
    bbw = desc.bbx[chr].w;
 
918
    bbh = desc.bbx[chr].h;
 
919
    bbx = desc.bbx[chr].x;
 
920
    bby = desc.bbx[chr].y;
 
921
  }
 
922
 
 
923
  const uInt16* tmp = desc.bits + (desc.offset ? desc.offset[chr] : (chr * desc.fbbh));
 
924
  uInt16* buffer = (uInt16*) myTexture->pixels +
 
925
                   (ty + desc.ascent - bby - bbh) * myPitch +
 
926
                   tx + bbx;
 
927
 
 
928
  for(int y = 0; y < bbh; y++)
 
929
  {
 
930
    const uInt16 ptr = *tmp++;
 
931
    uInt16 mask = 0x8000;
 
932
 
 
933
    for(int x = 0; x < bbw; x++, mask >>= 1)
 
934
      if(ptr & mask)
 
935
        buffer[x] = (uInt16) myFB.myDefPalette[color];
 
936
 
 
937
    buffer += myPitch;
558
938
  }
559
939
}
560
940
 
561
941
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
562
 
void FrameBufferGL::drawBitmap(uInt32* bitmap, Int32 tx, Int32 ty,
563
 
                               int color, Int32 h)
 
942
void FBSurfaceGL::drawBitmap(uInt32* bitmap, uInt32 tx, uInt32 ty,
 
943
                             uInt32 color, uInt32 h)
564
944
{
565
 
  uInt16* buffer = (uInt16*) myTexture->pixels + ty * myBuffer.pitch + tx;
 
945
  uInt16* buffer = (uInt16*) myTexture->pixels + ty * myPitch + tx;
566
946
 
567
 
  for(int y = 0; y < h; ++y)
 
947
  for(uInt32 y = 0; y < h; ++y)
568
948
  {
569
949
    uInt32 mask = 0xF0000000;
570
 
    for(int x = 0; x < 8; ++x, mask >>= 4)
 
950
    for(uInt32 x = 0; x < 8; ++x, mask >>= 4)
571
951
      if(bitmap[y] & mask)
572
 
        buffer[x] = (uInt16) myDefPalette[color];
 
952
        buffer[x] = (uInt16) myFB.myDefPalette[color];
573
953
 
574
 
    buffer += myBuffer.pitch;
 
954
    buffer += myPitch;
575
955
  }
576
956
}
577
957
 
578
958
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
579
 
void FrameBufferGL::drawSurface(const GUI::Surface* surface, Int32 x, Int32 y)
580
 
{
 
959
void FBSurfaceGL::drawPixels(uInt32* data, uInt32 tx, uInt32 ty, uInt32 numpixels)
 
960
{
 
961
  uInt16* buffer = (uInt16*) myTexture->pixels + ty * myPitch + tx;
 
962
 
 
963
  for(uInt32 i = 0; i < numpixels; ++i)
 
964
    *buffer++ = (uInt16) data[i];
 
965
}
 
966
 
 
967
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
968
void FBSurfaceGL::drawSurface(const FBSurface* surface, uInt32 tx, uInt32 ty)
 
969
{
 
970
  const FBSurfaceGL* s = (const FBSurfaceGL*) surface;
 
971
 
581
972
  SDL_Rect dstrect;
582
 
  dstrect.x = x;
583
 
  dstrect.y = y;
 
973
  dstrect.x = tx;
 
974
  dstrect.y = ty;
584
975
  SDL_Rect srcrect;
585
976
  srcrect.x = 0;
586
977
  srcrect.y = 0;
587
 
  srcrect.w = surface->myClipWidth;
588
 
  srcrect.h = surface->myClipHeight;
589
 
 
590
 
  SDL_BlitSurface(surface->myData, &srcrect, myTexture, &dstrect);
591
 
}
592
 
 
593
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
594
 
void FrameBufferGL::bytesToSurface(GUI::Surface* surface, int row,
595
 
                                   uInt8* data, int rowbytes) const
596
 
{
597
 
  SDL_Surface* s = surface->myData;
598
 
  uInt16* pixels = (uInt16*) s->pixels;
599
 
  pixels += (row * s->pitch/2);
600
 
 
601
 
  for(int c = 0; c < rowbytes; c += 3)
602
 
    *pixels++ = SDL_MapRGB(s->format, data[c], data[c+1], data[c+2]);
603
 
}
604
 
 
605
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
606
 
void FrameBufferGL::translateCoords(Int32& x, Int32& y) const
607
 
{
608
 
  // Wow, what a mess :)
609
 
  x = (Int32) ((x - myImageDim.x) / myWidthScaleFactor);
610
 
  y = (Int32) ((y - myImageDim.y) / myHeightScaleFactor);
611
 
}
612
 
 
613
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
614
 
void FrameBufferGL::addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
615
 
{
616
 
  myDirtyFlag = true;
617
 
}
618
 
 
619
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
620
 
void FrameBufferGL::enablePhosphor(bool enable, int blend)
621
 
{
622
 
  myUsePhosphor   = enable;
623
 
  myPhosphorBlend = blend;
624
 
 
625
 
  theRedrawTIAIndicator = true;
626
 
}
627
 
 
628
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
629
 
bool FrameBufferGL::createTextures()
630
 
{
631
 
  if(myTexture)
632
 
  {
633
 
    p_glClear(GL_COLOR_BUFFER_BIT);
634
 
    SDL_GL_SwapBuffers();
635
 
    p_glClear(GL_COLOR_BUFFER_BIT);
636
 
    SDL_FreeSurface(myTexture);
637
 
  }
638
 
  if(myBuffer.texture)  p_glDeleteTextures(1, &myBuffer.texture);
639
 
  memset(&myBuffer, 0, sizeof(glBufferType));
640
 
  myBuffer.filter = GL_NEAREST;
641
 
 
642
 
  // Fill buffer struct with valid data
643
 
  // This changes depending on the texturing used
644
 
  myBuffer.width  = myBaseDim.w;
645
 
  myBuffer.height = myBaseDim.h;
646
 
  myBuffer.tex_coord[0] = 0.0f;
647
 
  myBuffer.tex_coord[1] = 0.0f;
648
 
  if(myHaveTexRectEXT)
649
 
  {
650
 
    myBuffer.texture_width  = myBuffer.width;
651
 
    myBuffer.texture_height = myBuffer.height;
652
 
    myBuffer.target         = GL_TEXTURE_RECTANGLE_ARB;
653
 
    myBuffer.tex_coord[2]   = (GLfloat) myBuffer.texture_width;
654
 
    myBuffer.tex_coord[3]   = (GLfloat) myBuffer.texture_height;
655
 
  }
656
 
  else
657
 
  {
658
 
    myBuffer.texture_width  = power_of_two(myBuffer.width);
659
 
    myBuffer.texture_height = power_of_two(myBuffer.height);
660
 
    myBuffer.target         = GL_TEXTURE_2D;
661
 
    myBuffer.tex_coord[2]   = (GLfloat) myBuffer.width / myBuffer.texture_width;
662
 
    myBuffer.tex_coord[3]   = (GLfloat) myBuffer.height / myBuffer.texture_height;
663
 
  }
664
 
 
665
 
  // Create a texture that best suits the current display depth and system
666
 
  // This code needs to be Apple-specific, otherwise performance is
667
 
  // terrible on a Mac Mini
668
 
#if defined(MAC_OSX)
669
 
  myTexture = SDL_CreateRGBSurface(SDL_SWSURFACE,
670
 
                myBuffer.texture_width, myBuffer.texture_height, 16,
671
 
                0x00007c00, 0x000003e0, 0x0000001f, 0x00000000);
672
 
#else
673
 
  myTexture = SDL_CreateRGBSurface(SDL_SWSURFACE,
674
 
                myBuffer.texture_width, myBuffer.texture_height, 16,
675
 
                0x0000f800, 0x000007e0, 0x0000001f, 0x00000000);
676
 
#endif
677
 
  if(myTexture == NULL)
678
 
    return false;
679
 
 
680
 
  myBuffer.pixels = myTexture->pixels;
681
 
  switch(myTexture->format->BytesPerPixel)
682
 
  {
683
 
    case 2:  // 16-bit
684
 
      myBuffer.pitch = myTexture->pitch/2;
685
 
      break;
686
 
    case 3:  // 24-bit
687
 
      myBuffer.pitch = myTexture->pitch;
688
 
      break;
689
 
    case 4:  // 32-bit
690
 
      myBuffer.pitch = myTexture->pitch/4;
691
 
      break;
692
 
    default:
693
 
      break;
694
 
  }
695
 
 
696
 
  // Create an OpenGL texture from the SDL texture
697
 
  const string& filter = myOSystem->settings().getString("gl_filter");
698
 
  if(filter == "linear")
699
 
  {
700
 
    myBuffer.filter   = GL_LINEAR;
701
 
    myFilterParamName = "GL_LINEAR";
702
 
  }
703
 
  else if(filter == "nearest")
704
 
  {
705
 
    myBuffer.filter   = GL_NEAREST;
706
 
    myFilterParamName = "GL_NEAREST";
707
 
  }
708
 
 
709
 
  p_glGenTextures(1, &myBuffer.texture);
710
 
  p_glBindTexture(myBuffer.target, myBuffer.texture);
711
 
  p_glTexParameteri(myBuffer.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
712
 
  p_glTexParameteri(myBuffer.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
713
 
  p_glTexParameteri(myBuffer.target, GL_TEXTURE_MIN_FILTER, myBuffer.filter);
714
 
  p_glTexParameteri(myBuffer.target, GL_TEXTURE_MAG_FILTER, myBuffer.filter);
 
978
  srcrect.w = s->myWidth;
 
979
  srcrect.h = s->myHeight;
 
980
 
 
981
  SDL_BlitSurface(s->myTexture, &srcrect, myTexture, &dstrect);
 
982
}
 
983
 
 
984
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
985
void FBSurfaceGL::addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
 
986
{
 
987
  // OpenGL mode doesn't make use of dirty rectangles
 
988
  // It's faster to just update the entire surface
 
989
  mySurfaceIsDirty = true;
 
990
}
 
991
 
 
992
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
993
void FBSurfaceGL::getPos(uInt32& x, uInt32& y) const
 
994
{
 
995
  x = myXOrig;
 
996
  y = myYOrig;
 
997
}
 
998
 
 
999
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1000
void FBSurfaceGL::setPos(uInt32 x, uInt32 y)
 
1001
{
 
1002
  myXOrig = x;
 
1003
  myYOrig = y;
 
1004
}
 
1005
 
 
1006
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1007
void FBSurfaceGL::setWidth(uInt32 w)
 
1008
{
 
1009
  // This method can't be used with 'scaled' surface (aka TIA surfaces)
 
1010
  // That shouldn't really matter, though, as all the UI stuff isn't scaled,
 
1011
  // and it's the only thing that uses it
 
1012
  myWidth = w;
 
1013
 
 
1014
  if(myFB.myHaveTexRectEXT)
 
1015
    myTexCoord[2] = (GLfloat) myWidth;
 
1016
  else
 
1017
    myTexCoord[2] = (GLfloat) myWidth / myTexWidth;
 
1018
}
 
1019
 
 
1020
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1021
void FBSurfaceGL::setHeight(uInt32 h)
 
1022
{
 
1023
  // This method can't be used with 'scaled' surface (aka TIA surfaces)
 
1024
  // That shouldn't really matter, though, as all the UI stuff isn't scaled,
 
1025
  // and it's the only thing that uses it
 
1026
  myHeight = h;
 
1027
 
 
1028
  if(myFB.myHaveTexRectEXT)
 
1029
    myTexCoord[3] = (GLfloat) myHeight;
 
1030
  else
 
1031
    myTexCoord[3] = (GLfloat) myHeight / myTexHeight;
 
1032
}
 
1033
 
 
1034
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1035
void FBSurfaceGL::translateCoords(Int32& x, Int32& y) const
 
1036
{
 
1037
  x -= myXOrig;
 
1038
  y -= myYOrig;
 
1039
}
 
1040
 
 
1041
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1042
void FBSurfaceGL::update()
 
1043
{
 
1044
  if(mySurfaceIsDirty)
 
1045
  {
 
1046
    GLint loc;
 
1047
 
 
1048
    // Set a boolean to tell which filter is a first render (if any are applied).
 
1049
    // Being a first render means using the Atari frame buffer instead of the
 
1050
    // previous rendered data.
 
1051
    bool firstRender = true;
 
1052
 
 
1053
    // Render as usual if no filters are used
 
1054
    if(!myTvFiltersEnabled)
 
1055
    {
 
1056
      // Texturemap complete texture to surface so we have free scaling
 
1057
      // and antialiasing
 
1058
      p_glActiveTexture(GL_TEXTURE0);
 
1059
      p_glBindTexture(myTexTarget, myTexID);
 
1060
      p_glTexSubImage2D(myTexTarget, 0, 0, 0, myTexWidth, myTexHeight,
 
1061
                        GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, myTexture->pixels);
 
1062
 
 
1063
      // Pass in texture as a variable
 
1064
      p_glBegin(GL_QUADS);
 
1065
        p_glTexCoord2f(myTexCoord[0], myTexCoord[1]);
 
1066
        p_glVertex2i(myXOrig, myYOrig);
 
1067
 
 
1068
        p_glTexCoord2f(myTexCoord[2], myTexCoord[1]);
 
1069
        p_glVertex2i(myXOrig + myWidth, myYOrig);
 
1070
 
 
1071
        p_glTexCoord2f(myTexCoord[2], myTexCoord[3]);
 
1072
        p_glVertex2i(myXOrig + myWidth, myYOrig + myHeight);
 
1073
 
 
1074
        p_glTexCoord2f(myTexCoord[0], myTexCoord[3]);
 
1075
        p_glVertex2i(myXOrig, myYOrig + myHeight);
 
1076
      p_glEnd();
 
1077
    }
 
1078
 
 
1079
    // If TV filters are enabled
 
1080
    // TODO - check if this IF is necessary, or can it be chained by else to above
 
1081
    if(myTvFiltersEnabled)
 
1082
    {
 
1083
      // If combined texture/noise program exists,
 
1084
      // use the combined one; else do them separately
 
1085
      if(myTextureNoiseProgram != 0)
 
1086
      {
 
1087
        p_glUseProgram(myTextureNoiseProgram);
 
1088
 
 
1089
        // Pass in subpixel mask texture
 
1090
        p_glActiveTexture(GL_TEXTURE1);
 
1091
        p_glBindTexture(myTexTarget, mySubMaskTexID);
 
1092
        loc = p_glGetUniformLocation(myTextureNoiseProgram, "texMask");
 
1093
        p_glUniform1i(loc, 1);
 
1094
 
 
1095
        // Choose random mask texture
 
1096
        int num = rand() % myNoiseNum;
 
1097
        // Pass in noise mask texture
 
1098
        p_glActiveTexture(GL_TEXTURE2);
 
1099
        p_glBindTexture(myTexTarget, myNoiseMaskTexID[num]);
 
1100
        loc = p_glGetUniformLocation(myTextureNoiseProgram, "noiseMask");
 
1101
        p_glUniform1i(loc, 2);
 
1102
 
 
1103
        renderThreeTexture(myTextureNoiseProgram, firstRender);
 
1104
 
 
1105
        // We have rendered, set firstRender to false
 
1106
        firstRender = false;
 
1107
      }
 
1108
      else
 
1109
      {
 
1110
        // Check if texture filter is enabled
 
1111
        if(myFB.myUseTexture)
 
1112
        {
 
1113
          p_glUseProgram(myTextureProgram);
 
1114
 
 
1115
          // Pass in subpixel mask texture
 
1116
          p_glActiveTexture(GL_TEXTURE1);
 
1117
          p_glBindTexture(myTexTarget, mySubMaskTexID);
 
1118
          loc = p_glGetUniformLocation(myTextureProgram, "mask");
 
1119
          p_glUniform1i(loc, 1);
 
1120
 
 
1121
          renderTwoTexture(myTextureProgram, firstRender);
 
1122
 
 
1123
          // We have rendered, set firstRender to false
 
1124
          firstRender = false;
 
1125
        }
 
1126
 
 
1127
        if(myFB.myUseNoise)
 
1128
        {
 
1129
          p_glUseProgram(myNoiseProgram);
 
1130
 
 
1131
          // Choose random mask texture
 
1132
          int num = rand() % myNoiseNum;
 
1133
 
 
1134
          // Pass in noise mask texture
 
1135
          p_glActiveTexture(GL_TEXTURE1);
 
1136
          p_glBindTexture(myTexTarget, myNoiseMaskTexID[num]);
 
1137
          loc = p_glGetUniformLocation(myNoiseProgram, "mask");
 
1138
          p_glUniform1i(loc, 1);
 
1139
 
 
1140
          renderTwoTexture(myNoiseProgram, firstRender);
 
1141
 
 
1142
          // We have rendered, set firstRender to false
 
1143
          firstRender = false;
 
1144
        }
 
1145
      }
 
1146
 
 
1147
      // Check if bleed filter is enabled
 
1148
      if(myFB.myUseBleed)
 
1149
      {
 
1150
        p_glUseProgram(myBleedProgram);
 
1151
 
 
1152
        // Set some values based on high, medium, or low quality bleed. The high quality
 
1153
        // scales by applying additional passes, the low and medium quality scales by using
 
1154
        // a width and height based on the zoom level
 
1155
        int passes;
 
1156
        // High quality
 
1157
        if(myFB.myBleedQuality == 2)
 
1158
        {
 
1159
          // Precalculate pixel shifts
 
1160
          GLfloat pH = 1.0 / myHeight;
 
1161
          GLfloat pW = 1.0 / myWidth;
 
1162
          GLfloat pWx2 = pW * 2.0;
 
1163
 
 
1164
          loc = p_glGetUniformLocation(myBleedProgram, "pH");
 
1165
          p_glUniform1f(loc, pH);
 
1166
          loc = p_glGetUniformLocation(myBleedProgram, "pW");
 
1167
          p_glUniform1f(loc, pW);
 
1168
          loc = p_glGetUniformLocation(myBleedProgram, "pWx2");
 
1169
          p_glUniform1f(loc, pWx2);
 
1170
 
 
1171
          // Set the number of passes based on zoom level
 
1172
          passes = myFB.getZoomLevel();
 
1173
        }
 
1174
        // Medium and low quality
 
1175
        else
 
1176
        {
 
1177
          // The scaling formula was produced through trial and error
 
1178
          // Precalculate pixel shifts
 
1179
          GLfloat pH = 1.0 / (myHeight / (0.35 * myFB.getZoomLevel()));
 
1180
          GLfloat pW = 1.0 / (myWidth / (0.35 * myFB.getZoomLevel()));
 
1181
          GLfloat pWx2 = pW * 2.0;
 
1182
 
 
1183
          loc = p_glGetUniformLocation(myBleedProgram, "pH");
 
1184
          p_glUniform1f(loc, pH);
 
1185
          loc = p_glGetUniformLocation(myBleedProgram, "pW");
 
1186
          p_glUniform1f(loc, pW);
 
1187
          loc = p_glGetUniformLocation(myBleedProgram, "pWx2");
 
1188
          p_glUniform1f(loc, pWx2);
 
1189
 
 
1190
          // Medium quality
 
1191
          if(myFB.myBleedQuality == 1)
 
1192
            passes = 2;
 
1193
          // Low quality
 
1194
          else
 
1195
            passes = 1;
 
1196
        }
 
1197
 
 
1198
        // If we are using a texture effect, we need more bleed
 
1199
        if (myFB.myUseTexture)
 
1200
          passes <<= 1;
 
1201
 
 
1202
        for (int i = 0; i < passes; i++)
 
1203
        {
 
1204
          renderTexture(myBleedProgram, firstRender);
 
1205
 
 
1206
          // We have rendered, set firstRender to false
 
1207
          firstRender = false;
 
1208
        }
 
1209
      }
 
1210
 
 
1211
      // Check if phosphor burn-off filter is enabled
 
1212
      if(myFB.myUseGLPhosphor)
 
1213
      {
 
1214
        p_glUseProgram(myPhosphorProgram);
 
1215
 
 
1216
        // Pass in subpixel mask texture
 
1217
        p_glActiveTexture(GL_TEXTURE1);
 
1218
        p_glBindTexture(myTexTarget, myPhosphorTexID);
 
1219
        loc = p_glGetUniformLocation(myPhosphorProgram, "mask");
 
1220
        p_glUniform1i(loc, 1);
 
1221
 
 
1222
        renderTwoTexture(myPhosphorProgram, firstRender);
 
1223
 
 
1224
        p_glActiveTexture(GL_TEXTURE1);
 
1225
        p_glBindTexture(myTexTarget, myPhosphorTexID);
 
1226
        // We only need to copy the scaled size, which may be smaller than the texture width
 
1227
        p_glCopyTexSubImage2D(myTexTarget, 0, 0, 0, myXOrig, myYOrig, myWidth, myHeight);
 
1228
 
 
1229
        // We have rendered, set firstRender to false
 
1230
        firstRender = false;
 
1231
      }
 
1232
 
 
1233
      // Disable all shader programs for the next rendering pass
 
1234
      // This is placed here since it's a GLSL 2.0-specific function, and
 
1235
      // doesn't exist (and isn't required) for base OpenGL functionality
 
1236
      p_glUseProgram(0);
 
1237
    }
 
1238
 
 
1239
    mySurfaceIsDirty = false;
 
1240
 
 
1241
    // Let postFrameUpdate() know that a change has been made
 
1242
    myFB.myDirtyFlag = true;
 
1243
  }
 
1244
}
 
1245
 
 
1246
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1247
void FBSurfaceGL::renderTexture(GLuint program, bool firstRender)
 
1248
{
 
1249
  GLint loc;
 
1250
  GLfloat texCoord[4];
 
1251
 
 
1252
  p_glActiveTexture(GL_TEXTURE0);
 
1253
 
 
1254
  // If this is a first render, use the Atari frame buffer
 
1255
  if(firstRender)
 
1256
  {
 
1257
    // Pass in Atari frame
 
1258
    p_glBindTexture(myTexTarget, myTexID);
 
1259
    p_glTexSubImage2D(myTexTarget, 0, 0, 0, myTexWidth, myTexHeight,
 
1260
                      GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, myTexture->pixels);
 
1261
 
 
1262
    // Set the texture coord appropriately
 
1263
    texCoord[0] = myTexCoord[0];
 
1264
    texCoord[1] = myTexCoord[1];
 
1265
    texCoord[2] = myTexCoord[2];
 
1266
    texCoord[3] = myTexCoord[3];
 
1267
  }
 
1268
  else
 
1269
  {
 
1270
    // Copy frame buffer to texture, this isn't the fastest way to do it, but it's simple
 
1271
    // (rendering directly to texture instead of copying may be faster)
 
1272
    p_glBindTexture(myTexTarget, myFilterTexID);
 
1273
    // We only need to copy the scaled size, which may be smaller than the texture width
 
1274
    p_glCopyTexSubImage2D(myTexTarget, 0, 0, 0, myXOrig, myYOrig, myWidth, myHeight);
 
1275
 
 
1276
    // Set the texture coord appropriately
 
1277
    texCoord[0] = myFilterTexCoord[0];
 
1278
    texCoord[1] = myFilterTexCoord[1];
 
1279
    texCoord[2] = myFilterTexCoord[2];
 
1280
    texCoord[3] = myFilterTexCoord[3];
 
1281
  }
 
1282
 
 
1283
  // Pass the texture to the program
 
1284
  loc = p_glGetUniformLocation(program, "tex");
 
1285
  p_glUniform1i(loc, 0);
 
1286
 
 
1287
  // Pass in texture as a variable
 
1288
  p_glBegin(GL_QUADS);
 
1289
    p_glTexCoord2f(texCoord[0], texCoord[1]);
 
1290
    p_glVertex2i(myXOrig, myYOrig);
 
1291
 
 
1292
    p_glTexCoord2f(texCoord[2], texCoord[1]);
 
1293
    p_glVertex2i(myXOrig + myWidth, myYOrig);
 
1294
 
 
1295
    p_glTexCoord2f(texCoord[2], texCoord[3]);
 
1296
    p_glVertex2i(myXOrig + myWidth, myYOrig + myHeight);
 
1297
 
 
1298
    p_glTexCoord2f(texCoord[0], texCoord[3]);
 
1299
    p_glVertex2i(myXOrig, myYOrig + myHeight);
 
1300
  p_glEnd();
 
1301
}
 
1302
 
 
1303
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1304
void FBSurfaceGL::renderTwoTexture(GLuint program, bool firstRender)
 
1305
{
 
1306
  GLint loc;
 
1307
  GLfloat texCoord[4];
 
1308
 
 
1309
  p_glActiveTexture(GL_TEXTURE0);
 
1310
 
 
1311
  // If this is a first render, use the Atari frame buffer
 
1312
  if(firstRender)
 
1313
  {
 
1314
    // Pass in Atari frame
 
1315
    p_glBindTexture(myTexTarget, myTexID);
 
1316
    p_glTexSubImage2D(myTexTarget, 0, 0, 0, myTexWidth, myTexHeight,
 
1317
                      GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, myTexture->pixels);
 
1318
 
 
1319
    // Set the texture coord appropriately
 
1320
    texCoord[0] = myTexCoord[0];
 
1321
    texCoord[1] = myTexCoord[1];
 
1322
    texCoord[2] = myTexCoord[2];
 
1323
    texCoord[3] = myTexCoord[3];
 
1324
  }
 
1325
  else
 
1326
  {
 
1327
    // Copy frame buffer to texture, this isn't the fastest way to do it, but it's simple
 
1328
    // (rendering directly to texture instead of copying may be faster)
 
1329
    p_glBindTexture(myTexTarget, myFilterTexID);
 
1330
    // We only need to copy the scaled size, which may be smaller than the texture width
 
1331
    p_glCopyTexSubImage2D(myTexTarget, 0, 0, 0, myXOrig, myYOrig, myWidth, myHeight);
 
1332
 
 
1333
    // Set the filter texture coord appropriately
 
1334
    texCoord[0] = myFilterTexCoord[0];
 
1335
    texCoord[1] = myFilterTexCoord[1];
 
1336
    texCoord[2] = myFilterTexCoord[2];
 
1337
    texCoord[3] = myFilterTexCoord[3];
 
1338
  }
 
1339
 
 
1340
  // Pass the texture to the program
 
1341
  loc = p_glGetUniformLocation(program, "tex");
 
1342
  p_glUniform1i(loc, 0);
 
1343
 
 
1344
  // Pass in textures as variables
 
1345
  p_glBegin(GL_QUADS);
 
1346
    p_glMultiTexCoord2f(GL_TEXTURE0, texCoord[0], texCoord[1]);
 
1347
    p_glMultiTexCoord2f(GL_TEXTURE1, myFilterTexCoord[0], myFilterTexCoord[1]);
 
1348
    p_glVertex2i(myXOrig, myYOrig);
 
1349
 
 
1350
    p_glMultiTexCoord2f(GL_TEXTURE0, texCoord[2], texCoord[1]);
 
1351
    p_glMultiTexCoord2f(GL_TEXTURE1, myFilterTexCoord[2], myFilterTexCoord[1]);
 
1352
    p_glVertex2i(myXOrig + myWidth, myYOrig);
 
1353
 
 
1354
    p_glMultiTexCoord2f(GL_TEXTURE0, texCoord[2], texCoord[3]);
 
1355
    p_glMultiTexCoord2f(GL_TEXTURE1, myFilterTexCoord[2], myFilterTexCoord[3]);
 
1356
    p_glVertex2i(myXOrig + myWidth, myYOrig + myHeight);
 
1357
 
 
1358
    p_glMultiTexCoord2f(GL_TEXTURE0, texCoord[0], texCoord[3]);
 
1359
    p_glMultiTexCoord2f(GL_TEXTURE1, myFilterTexCoord[0], myFilterTexCoord[3]);
 
1360
    p_glVertex2i(myXOrig, myYOrig + myHeight);
 
1361
  p_glEnd();
 
1362
}
 
1363
 
 
1364
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1365
void FBSurfaceGL::renderThreeTexture(GLuint program, bool firstRender)
 
1366
{
 
1367
  GLint loc;
 
1368
  GLfloat texCoord[4];
 
1369
 
 
1370
  p_glActiveTexture(GL_TEXTURE0);
 
1371
 
 
1372
  // If this is a first render, use the Atari frame buffer
 
1373
  if(firstRender)
 
1374
  {
 
1375
    // Pass in Atari frame
 
1376
    p_glBindTexture(myTexTarget, myTexID);
 
1377
    p_glTexSubImage2D(myTexTarget, 0, 0, 0, myTexWidth, myTexHeight,
 
1378
                      GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, myTexture->pixels);
 
1379
 
 
1380
    // Set the texture coord appropriately
 
1381
    texCoord[0] = myTexCoord[0];
 
1382
    texCoord[1] = myTexCoord[1];
 
1383
    texCoord[2] = myTexCoord[2];
 
1384
    texCoord[3] = myTexCoord[3];
 
1385
  }
 
1386
  else
 
1387
  {
 
1388
    // Copy frame buffer to texture, this isn't the fastest way to do it, but it's simple
 
1389
    // (rendering directly to texture instead of copying may be faster)
 
1390
    p_glBindTexture(myTexTarget, myFilterTexID);
 
1391
    // We only need to copy the scaled size, which may be smaller than the texture width
 
1392
    p_glCopyTexSubImage2D(myTexTarget, 0, 0, 0, myXOrig, myYOrig, myWidth, myHeight);
 
1393
 
 
1394
    // Set the filter texture coord appropriately
 
1395
    texCoord[0] = myFilterTexCoord[0];
 
1396
    texCoord[1] = myFilterTexCoord[1];
 
1397
    texCoord[2] = myFilterTexCoord[2];
 
1398
    texCoord[3] = myFilterTexCoord[3];
 
1399
  }
 
1400
 
 
1401
  // Pass the texture to the program
 
1402
  loc = p_glGetUniformLocation(program, "tex");
 
1403
  p_glUniform1i(loc, 0);
 
1404
 
 
1405
  // Pass in textures as variables
 
1406
  p_glBegin(GL_QUADS);
 
1407
    p_glMultiTexCoord2f(GL_TEXTURE0, texCoord[0], texCoord[1]);
 
1408
    p_glMultiTexCoord2f(GL_TEXTURE1, myFilterTexCoord[0], myFilterTexCoord[1]);
 
1409
    p_glMultiTexCoord2f(GL_TEXTURE2, myFilterTexCoord[0], myFilterTexCoord[1]);
 
1410
    p_glVertex2i(myXOrig, myYOrig);
 
1411
 
 
1412
    p_glMultiTexCoord2f(GL_TEXTURE0, texCoord[2], texCoord[1]);
 
1413
    p_glMultiTexCoord2f(GL_TEXTURE1, myFilterTexCoord[2], myFilterTexCoord[1]);
 
1414
    p_glMultiTexCoord2f(GL_TEXTURE2, myFilterTexCoord[2], myFilterTexCoord[1]);
 
1415
    p_glVertex2i(myXOrig + myWidth, myYOrig);
 
1416
 
 
1417
    p_glMultiTexCoord2f(GL_TEXTURE0, texCoord[2], texCoord[3]);
 
1418
    p_glMultiTexCoord2f(GL_TEXTURE1, myFilterTexCoord[2], myFilterTexCoord[3]);
 
1419
    p_glMultiTexCoord2f(GL_TEXTURE2, myFilterTexCoord[2], myFilterTexCoord[3]);
 
1420
    p_glVertex2i(myXOrig + myWidth, myYOrig + myHeight);
 
1421
 
 
1422
    p_glMultiTexCoord2f(GL_TEXTURE0, texCoord[0], texCoord[3]);
 
1423
    p_glMultiTexCoord2f(GL_TEXTURE1, myFilterTexCoord[0], myFilterTexCoord[3]);
 
1424
    p_glMultiTexCoord2f(GL_TEXTURE2, myFilterTexCoord[0], myFilterTexCoord[3]);
 
1425
    p_glVertex2i(myXOrig, myYOrig + myHeight);
 
1426
  p_glEnd();
 
1427
}
 
1428
 
 
1429
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1430
void FBSurfaceGL::free()
 
1431
{
 
1432
  p_glDeleteTextures(1, &myTexID);
 
1433
 
 
1434
  // The below is borken up a bit because of the possible combined texture/noise shader
 
1435
 
 
1436
  if(myFilterTexID)
 
1437
    p_glDeleteTextures(1, &myFilterTexID);
 
1438
 
 
1439
  if(mySubMaskTexID)
 
1440
    p_glDeleteTextures(1, &mySubMaskTexID);
 
1441
 
 
1442
  if(myTextureProgram)
 
1443
    p_glDeleteProgram(myTextureProgram);
 
1444
 
 
1445
  if(myNoiseMaskTexID)
 
1446
  {
 
1447
    delete[] myNoiseTexture;
 
1448
    p_glDeleteTextures(myNoiseNum, myNoiseMaskTexID);
 
1449
    delete[] myNoiseMaskTexID;
 
1450
  }
 
1451
 
 
1452
  if(myNoiseProgram)
 
1453
    p_glDeleteProgram(myNoiseProgram);
 
1454
 
 
1455
  if(myPhosphorTexID)
 
1456
  {
 
1457
    p_glDeleteTextures(1, &myPhosphorTexID);
 
1458
    p_glDeleteProgram(myPhosphorProgram);
 
1459
  }
 
1460
 
 
1461
  if(myTextureNoiseProgram)
 
1462
    p_glDeleteProgram(myTextureNoiseProgram);
 
1463
}
 
1464
 
 
1465
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1466
void FBSurfaceGL::reload()
 
1467
{
 
1468
  // This does a 'soft' reset of the surface
 
1469
  // It seems that on some system (notably, OSX), creating a new SDL window
 
1470
  // destroys the GL context, requiring a reload of all textures
 
1471
  // However, destroying the entire FBSurfaceGL object is wasteful, since
 
1472
  // it will also regenerate SDL software surfaces (which are not required
 
1473
  // to be regenerated)
 
1474
  // Basically, all that needs to be done is to re-call glTexImage2D with a
 
1475
  // new texture ID, so that's what we do here
 
1476
 
 
1477
  p_glActiveTexture(GL_TEXTURE0);
 
1478
  p_glEnable(myTexTarget);
 
1479
 
 
1480
  p_glGenTextures(1, &myTexID);
 
1481
  p_glBindTexture(myTexTarget, myTexID);
 
1482
  p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 
1483
  p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
1484
  p_glTexParameteri(myTexTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 
1485
  p_glTexParameteri(myTexTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
715
1486
 
716
1487
  // Finally, create the texture in the most optimal format
717
 
  GLenum tex_intformat;
718
 
#if defined (MAC_OSX)
719
 
  tex_intformat   = GL_RGB5;
720
 
  myBuffer.format = GL_BGRA;
721
 
  myBuffer.type   = GL_UNSIGNED_SHORT_1_5_5_5_REV;
722
 
#else
723
 
  tex_intformat   = GL_RGB;
724
 
  myBuffer.format = GL_RGB;
725
 
  myBuffer.type   = GL_UNSIGNED_SHORT_5_6_5;
726
 
#endif
727
 
  p_glTexImage2D(myBuffer.target, 0, tex_intformat,
728
 
                 myBuffer.texture_width, myBuffer.texture_height, 0,
729
 
                 myBuffer.format, myBuffer.type, myBuffer.pixels);
730
 
 
731
 
  return true;
732
 
}
733
 
 
734
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
735
 
GUI::Surface* FrameBufferGL::createSurface(int width, int height) const
736
 
{
737
 
  SDL_PixelFormat* fmt = myTexture->format;
738
 
  SDL_Surface* data =
739
 
    SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 16,
740
 
                         fmt->Rmask, fmt->Gmask, fmt->Bmask, fmt->Amask);
741
 
 
742
 
  return data ? new GUI::Surface(width, height, data) : NULL;
 
1488
  p_glTexImage2D(myTexTarget, 0, GL_RGB5,
 
1489
                 myTexWidth, myTexHeight, 0,
 
1490
                 GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, myTexture->pixels);
 
1491
 
 
1492
  // Do the same for the TV filter textures
 
1493
  // Only do this if TV filters are enabled
 
1494
  if(myTvFiltersEnabled)
 
1495
  {
 
1496
    // Generate the generic filter texture
 
1497
    p_glGenTextures(1, &myFilterTexID);
 
1498
    p_glBindTexture(myTexTarget, myFilterTexID);
 
1499
    p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 
1500
    p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
1501
    p_glTexParameteri(myTexTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 
1502
    p_glTexParameteri(myTexTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
1503
    // Make the initial texture, this will get overwritten later
 
1504
    p_glCopyTexImage2D(myTexTarget, 0, GL_RGB5, 0, 0, myFilterTexWidth, myFilterTexHeight, 0);
 
1505
 
 
1506
    // Only do this if TV and color texture filters are enabled
 
1507
    if(myFB.myUseTexture)
 
1508
    {
 
1509
      // Generate the subpixel mask texture
 
1510
      p_glGenTextures(1, &mySubMaskTexID);
 
1511
      p_glBindTexture(myTexTarget, mySubMaskTexID);
 
1512
      p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 
1513
      p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
1514
      p_glTexParameteri(myTexTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 
1515
      p_glTexParameteri(myTexTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
1516
      // Write the data
 
1517
      p_glTexImage2D(myTexTarget, 0, GL_RGB5,
 
1518
                     myFilterTexWidth, myFilterTexHeight, 0,
 
1519
                     GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, mySubpixelTexture->pixels);
 
1520
    }
 
1521
 
 
1522
    // Only do this if TV and noise filters are enabled
 
1523
    if(myFB.myUseNoise)
 
1524
    {
 
1525
      // Generate the noise mask textures
 
1526
      p_glGenTextures(myNoiseNum, myNoiseMaskTexID);
 
1527
      for(int i = 0; i < myNoiseNum; i++)
 
1528
      {
 
1529
        p_glBindTexture(myTexTarget, myNoiseMaskTexID[i]);
 
1530
        p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 
1531
        p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
1532
        p_glTexParameteri(myTexTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 
1533
        p_glTexParameteri(myTexTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
1534
        // Write the data
 
1535
        p_glTexImage2D(myTexTarget, 0, GL_RGB5,
 
1536
                       myFilterTexWidth, myFilterTexHeight, 0,
 
1537
                       GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, myNoiseTexture[i]->pixels);
 
1538
      }
 
1539
    }
 
1540
 
 
1541
    // Only do this if TV and phosphor filters are enabled
 
1542
    if(myFB.myUseGLPhosphor)
 
1543
    {
 
1544
      // Generate the noise mask textures
 
1545
      p_glGenTextures(1, &myPhosphorTexID);
 
1546
      p_glBindTexture(myTexTarget, myPhosphorTexID);
 
1547
      p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 
1548
      p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
1549
      p_glTexParameteri(myTexTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 
1550
      p_glTexParameteri(myTexTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
1551
      // Make the initial texture, this will get overwritten later
 
1552
      p_glCopyTexImage2D(myTexTarget, 0, GL_RGB5, 0, 0, myFilterTexWidth, myFilterTexHeight, 0);
 
1553
    }
 
1554
  }
 
1555
}
 
1556
 
 
1557
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1558
void FBSurfaceGL::setFilter(const string& name)
 
1559
{
 
1560
  // We only do GL_NEAREST or GL_LINEAR for now
 
1561
  GLint filter = GL_NEAREST;
 
1562
  if(name == "linear")
 
1563
    filter = GL_LINEAR;
 
1564
 
 
1565
  p_glBindTexture(myTexTarget, myTexID);
 
1566
  p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 
1567
  p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
1568
  p_glTexParameteri(myTexTarget, GL_TEXTURE_MIN_FILTER, filter);
 
1569
  p_glTexParameteri(myTexTarget, GL_TEXTURE_MAG_FILTER, filter);
 
1570
 
 
1571
  // Do the same for the filter textures
 
1572
  // Only do this if TV filters are enabled
 
1573
  if(myTvFiltersEnabled)
 
1574
  {
 
1575
    p_glBindTexture(myTexTarget, myFilterTexID);
 
1576
    p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 
1577
    p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
1578
    p_glTexParameteri(myTexTarget, GL_TEXTURE_MIN_FILTER, filter);
 
1579
    p_glTexParameteri(myTexTarget, GL_TEXTURE_MAG_FILTER, filter);
 
1580
 
 
1581
    // Only do this if TV and color texture filters are enabled
 
1582
    if(myFB.myUseTexture)
 
1583
    {
 
1584
      p_glBindTexture(myTexTarget, mySubMaskTexID);
 
1585
      p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 
1586
      p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
1587
      p_glTexParameteri(myTexTarget, GL_TEXTURE_MIN_FILTER, filter);
 
1588
      p_glTexParameteri(myTexTarget, GL_TEXTURE_MAG_FILTER, filter);
 
1589
    }
 
1590
 
 
1591
    // Only do this if TV and noise filters are enabled
 
1592
    if(myFB.myUseNoise)
 
1593
    {
 
1594
      for(int i = 0; i < myNoiseNum; i++)
 
1595
      {
 
1596
        p_glBindTexture(myTexTarget, myNoiseMaskTexID[i]);
 
1597
        p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 
1598
        p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
1599
        p_glTexParameteri(myTexTarget, GL_TEXTURE_MIN_FILTER, filter);
 
1600
        p_glTexParameteri(myTexTarget, GL_TEXTURE_MAG_FILTER, filter);
 
1601
      }
 
1602
    }
 
1603
 
 
1604
    // Only do this if TV and phosphor filters are enabled
 
1605
    if(myFB.myUseGLPhosphor)
 
1606
    {
 
1607
      p_glBindTexture(myTexTarget, myPhosphorTexID);
 
1608
      p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 
1609
      p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
1610
      p_glTexParameteri(myTexTarget, GL_TEXTURE_MIN_FILTER, filter);
 
1611
      p_glTexParameteri(myTexTarget, GL_TEXTURE_MAG_FILTER, filter);
 
1612
    }
 
1613
  }
 
1614
 
 
1615
  // The filtering has changed, so redraw the entire screen
 
1616
  mySurfaceIsDirty = true;
 
1617
}
 
1618
 
 
1619
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1620
GLuint FBSurfaceGL::genShader(ShaderType type)
 
1621
{
 
1622
  string fFile = "";
 
1623
  char* fCode = NULL;
 
1624
  switch(type)
 
1625
  {
 
1626
    case SHADER_BLEED:
 
1627
      fFile = "bleed.frag";
 
1628
      fCode = (char*)GLShader::bleed_frag[0];
 
1629
      break;
 
1630
    case SHADER_TEX:
 
1631
      fFile = "texture.frag";
 
1632
      fCode = (char*)GLShader::texture_frag[0];
 
1633
      break;
 
1634
    case SHADER_NOISE:
 
1635
      fFile = "noise.frag";
 
1636
      fCode = (char*)GLShader::noise_frag[0];
 
1637
      break;
 
1638
    case SHADER_PHOS:
 
1639
      fFile = "phosphor.frag";
 
1640
      fCode = (char*)GLShader::phosphor_frag[0];
 
1641
      break;
 
1642
    case SHADER_TEXNOISE:
 
1643
      fFile = "texture_noise.frag";
 
1644
      fCode = (char*)GLShader::texture_noise_frag[0];
 
1645
      break;
 
1646
  }
 
1647
 
 
1648
  // First try opening an external fragment file
 
1649
  // These shader files are stored in 'BASEDIR/shaders/'
 
1650
  char* buffer = NULL;
 
1651
  const string& filename =
 
1652
    myFB.myOSystem->baseDir() + BSPF_PATH_SEPARATOR + "shaders" +
 
1653
    BSPF_PATH_SEPARATOR + fFile;
 
1654
  ifstream in(filename.c_str());
 
1655
  if(in && in.is_open())
 
1656
  {
 
1657
    // Get file size
 
1658
    in.seekg(0, std::ios::end);
 
1659
    streampos size = in.tellg();
 
1660
 
 
1661
    // Reset position
 
1662
    in.seekg(0);
 
1663
 
 
1664
    // Make buffer of proper size;
 
1665
    buffer = new char[size+(streampos)1]; // +1 for '\0'
 
1666
 
 
1667
    // Read in file
 
1668
    in.read(buffer, size);
 
1669
    buffer[in.gcount()] = '\0';
 
1670
    in.close();
 
1671
 
 
1672
    fCode = buffer;
 
1673
  }
 
1674
 
 
1675
  // Make the shader program
 
1676
  GLuint fShader = p_glCreateShader(GL_FRAGMENT_SHADER);
 
1677
  GLuint program = p_glCreateProgram();
 
1678
  p_glShaderSource(fShader, 1, (const char**)&fCode, NULL);
 
1679
  p_glCompileShader(fShader);
 
1680
  p_glAttachShader(program, fShader);
 
1681
  p_glLinkProgram(program);
 
1682
 
 
1683
  // Go ahead and flag the shader for deletion so it is deleted once the program is
 
1684
  p_glDeleteShader(fShader);
 
1685
 
 
1686
  // Clean up
 
1687
  delete[] buffer;
 
1688
 
 
1689
  return program;
743
1690
}
744
1691
 
745
1692
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
746
1693
bool FrameBufferGL::myLibraryLoaded = false;
747
1694
 
 
1695
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1696
float FrameBufferGL::myGLVersion = 0.0;
 
1697
 
 
1698
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1699
bool FrameBufferGL::myGLSLAvailable = false;
 
1700
 
 
1701
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1702
bool FrameBufferGL::myFBOAvailable = false;
 
1703
 
748
1704
#endif  // DISPLAY_OPENGL