ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/Display_SDL.h
(Generate patch)

Comparing Frodo4/Src/Display_SDL.h (file contents):
Revision 1.10 by cebix, 2010-04-22T09:09:28Z vs.
Revision 1.11 by cebix, 2010-04-23T11:12:05Z

# Line 25 | Line 25
25  
26   #include <SDL.h>
27  
28 + #ifdef ENABLE_OPENGL
29 + #include <GL/glew.h>
30 + #endif
31 +
32 +
33 + // Display dimensions including drive LEDs etc.
34 + static const int FRAME_WIDTH = DISPLAY_X;
35 + static const int FRAME_HEIGHT = DISPLAY_Y + 16;
36  
37   // Display surface
38   static SDL_Surface *screen = NULL;
# Line 52 | Line 60 | enum {
60          PALETTE_SIZE = 21
61   };
62  
63 + #ifdef ENABLE_OPENGL
64 +
65 + // Display texture dimensions
66 + static const int TEXTURE_SIZE = 512;  // smallest power-of-two that fits DISPLAY_X/Y
67 +
68 + // Texture object for VIC palette
69 + static GLuint palette_tex;
70 +
71 + // Texture object for VIC display
72 + static GLuint vic_tex;
73 +
74 + #endif
75 +
76   /*
77    C64 keyboard matrix:
78  
# Line 85 | Line 106 | int init_graphics(void)
106   }
107  
108  
109 + #ifdef ENABLE_OPENGL
110 + /*
111 + *  Set direct projection (GL coordinates = window pixel coordinates)
112 + */
113 +
114 + static void set_projection()
115 + {
116 +        int width = SDL_GetVideoSurface()->w;
117 +        int height = SDL_GetVideoSurface()->h;
118 +
119 +        glViewport(0, 0, width, height);
120 +        glMatrixMode(GL_PROJECTION);
121 +        glLoadIdentity();
122 +
123 +        float aspect = float(width) / float(height);
124 +        const float want_aspect = float(FRAME_WIDTH) / float(FRAME_HEIGHT);
125 +        int left, right, top, bottom;
126 +        if (aspect > want_aspect) {
127 +                // Window too wide, center horizontally
128 +                top = 0; bottom = FRAME_HEIGHT;
129 +                int diff = (int(FRAME_WIDTH * aspect / want_aspect) - FRAME_WIDTH) / 2;
130 +                left = -diff;
131 +                right = FRAME_WIDTH + diff;
132 +        } else {
133 +                // Window too high, center vertically
134 +                left = 0; right = FRAME_WIDTH;
135 +                int diff = (int(FRAME_HEIGHT * want_aspect / aspect) - FRAME_HEIGHT) / 2;
136 +                top = -diff;
137 +                bottom = FRAME_HEIGHT + diff;
138 +        }
139 +        glOrtho(left, right, bottom, top, -1, 1);
140 +
141 +        glClear(GL_COLOR_BUFFER_BIT);
142 + }
143 +
144 +
145 + /*
146 + *  User resized video display (only possible with OpenGL)
147 + */
148 +
149 + static void video_resized(int width, int height)
150 + {
151 +        uint32 flags = (ThePrefs.DisplayType == DISPTYPE_SCREEN ? SDL_FULLSCREEN : 0);
152 +        flags |= (SDL_ANYFORMAT | SDL_OPENGL | SDL_RESIZABLE);
153 +        SDL_SetVideoMode(width, height, 16, flags);
154 +        set_projection();
155 + }
156 + #endif
157 +
158 +
159   /*
160   *  Display constructor
161   */
# Line 96 | Line 167 | C64Display::C64Display(C64 *the_c64) : T
167  
168          // Open window
169          SDL_WM_SetCaption(VERSION_STRING, "Frodo");
170 <        screen = SDL_SetVideoMode(DISPLAY_X, DISPLAY_Y + 17, 8, SDL_DOUBLEBUF | (ThePrefs.DisplayType == DISPTYPE_SCREEN ? SDL_FULLSCREEN : 0));
170 >        uint32 flags = (ThePrefs.DisplayType == DISPTYPE_SCREEN ? SDL_FULLSCREEN : 0);
171 >
172 > #ifdef ENABLE_OPENGL
173 >
174 >        flags |= (SDL_ANYFORMAT | SDL_OPENGL | SDL_RESIZABLE);
175 >        SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
176 >        SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
177 >        SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
178 >        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
179 >        SDL_Surface *real_screen = SDL_SetVideoMode(FRAME_WIDTH * 2, FRAME_HEIGHT * 2, 16, flags);
180 >        if (!real_screen) {
181 >                fprintf(stderr, "Couldn't initialize OpenGL video output (%s)\n", SDL_GetError());
182 >                exit(1);
183 >        }
184 >
185 >        // VIC display and UI elements are rendered into an off-screen surface
186 >        screen = SDL_CreateRGBSurface(SDL_SWSURFACE, FRAME_WIDTH, FRAME_HEIGHT, 8, 0xff, 0xff, 0xff, 0xff);
187 >
188 >        // We need OpenGL 2.0 or higher
189 >        GLenum err = glewInit();
190 >        if (err != GLEW_OK) {
191 >                fprintf(stderr, "Couldn't initialize GLEW (%s)\n", glewGetErrorString(err));
192 >                exit(1);
193 >        }
194 >
195 >        if (!glewIsSupported("GL_VERSION_2_0")) {
196 >                fprintf(stderr, "Frodo requires OpenGL 2.0 or higher\n");
197 >                exit(1);
198 >        }
199 >
200 >        // Set direct projection
201 >        set_projection();
202 >
203 >        // Set GL state
204 >        glShadeModel(GL_FLAT);
205 >        glDisable(GL_DITHER);
206 >        glColor4f(1.0, 1.0, 1.0, 1.0);
207 >
208 >        // Create fragment shader for emulating a paletted texture
209 >        GLuint shader = glCreateShader(GL_FRAGMENT_SHADER_ARB);
210 >        const char * src =
211 >                "uniform sampler2D screen;"
212 >                "uniform sampler1D palette;"
213 >                "uniform float texSize;"
214 >                "void main()"
215 >                "{"
216 > #if 0
217 >                // Nearest neighbour
218 >                "  vec4 idx = texture2D(screen, gl_TexCoord[0].st);"
219 >                "  gl_FragColor = texture1D(palette, idx.r);"
220 > #else
221 >                // Linear interpolation
222 >                // (setting the GL_TEXTURE_MAG_FILTER to GL_LINEAR would interpolate
223 >                // the color indices which is not what we want; we need to manually
224 >                // interpolate the palette values instead)
225 >                "  const float texel = 1.0 / texSize;"
226 >                "  vec2 st = gl_TexCoord[0].st - vec2(texel * 0.5, texel * 0.5);"
227 >                "  vec4 idx00 = texture2D(screen, st);"
228 >                "  vec4 idx01 = texture2D(screen, st + vec2(0, texel));"
229 >                "  vec4 idx10 = texture2D(screen, st + vec2(texel, 0));"
230 >                "  vec4 idx11 = texture2D(screen, st + vec2(texel, texel));"
231 >                "  float s1 = fract(st.s * texSize);"
232 >                "  float s0 = 1.0 - s1;"
233 >                "  float t1 = fract(st.t * texSize);"
234 >                "  float t0 = 1.0 - t1;"
235 >                "  vec4 color00 = texture1D(palette, idx00.r) * s0 * t0;"
236 >                "  vec4 color01 = texture1D(palette, idx01.r) * s0 * t1;"
237 >                "  vec4 color10 = texture1D(palette, idx10.r) * s1 * t0;"
238 >                "  vec4 color11 = texture1D(palette, idx11.r) * s1 * t1;"
239 >                "  gl_FragColor = color00 + color01 + color10 + color11;"
240 > #endif
241 >                "}";
242 >        glShaderSource(shader, 1, &src, NULL);
243 >        glCompileShader(shader);
244 >
245 >        GLint status;
246 >        glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
247 >        if (status == GL_FALSE) {
248 >                GLint logLength = 0;
249 >                glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
250 >                if (logLength > 0) {
251 >                        GLchar *log = (GLchar *)malloc(logLength);
252 >                        GLint actual;
253 >                        glGetShaderInfoLog(shader, logLength, &actual, log);
254 >                        fprintf(stderr, "%s\n", log);
255 >                        exit(1);
256 >                }
257 >        }
258 >  
259 >        GLuint program = glCreateProgram();
260 >        glAttachShader(program, shader);
261 >        glLinkProgram(program);
262 >        glUseProgram(program);
263 >
264 >        glUniform1f(glGetUniformLocation(program, "texSize"), float(TEXTURE_SIZE));
265 >
266 >        // Create VIC display texture (8-bit color index in the red channel)
267 >        uint8 *tmp = (uint8 *)malloc(TEXTURE_SIZE * TEXTURE_SIZE);
268 >        memset(tmp, 0, TEXTURE_SIZE * TEXTURE_SIZE);
269 >
270 >        glGenTextures(1, &vic_tex);
271 >        glActiveTexture(GL_TEXTURE0);
272 >        glBindTexture(GL_TEXTURE_2D, vic_tex);
273 >        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
274 >        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
275 >        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  // don't interpolate color index values
276 >        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
277 >        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, TEXTURE_SIZE, TEXTURE_SIZE, 0, GL_RED, GL_UNSIGNED_BYTE, tmp);
278 >        glUniform1i(glGetUniformLocation(program, "screen"), 0);
279 >
280 >        free(tmp);
281 >
282 >        // Create VIC palette texture
283 >        tmp = (uint8 *)malloc(256 * 3);
284 >        memset(tmp, 0xff, 256 * 3);
285 >        for (int i=0; i<16; ++i) {
286 >                tmp[i*3+0] = palette_red[i & 0x0f];
287 >                tmp[i*3+1] = palette_green[i & 0x0f];
288 >                tmp[i*3+2] = palette_blue[i & 0x0f];
289 >        }
290 >        tmp[fill_gray*3+0] = tmp[fill_gray*3+1] = tmp[fill_gray*3+2] = 0xd0;
291 >        tmp[shine_gray*3+0] = tmp[shine_gray*3+1] = tmp[shine_gray*3+2] = 0xf0;
292 >        tmp[shadow_gray*3+0] = tmp[shadow_gray*3+1] = tmp[shadow_gray*3+2] = 0x80;
293 >        tmp[red*3+0] = 0xf0;
294 >        tmp[red*3+1] = tmp[red*3+2] = 0;
295 >        tmp[green*3+1] = 0xf0;
296 >        tmp[green*3+0] = tmp[green*3+2] = 0;
297 >
298 >        glGenTextures(1, &palette_tex);
299 >        glActiveTexture(GL_TEXTURE1);
300 >        glBindTexture(GL_TEXTURE_1D, palette_tex);
301 >        glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  // don't interpolate palette entries
302 >        glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
303 >        glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA8, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, tmp);
304 >        glUniform1i(glGetUniformLocation(program, "palette"), 1);
305 >
306 >        free(tmp);
307 >
308 > #else
309 >
310 >        flags |= (SDL_HWSURFACE | SDL_DOUBLEBUF);
311 >        screen = SDL_SetVideoMode(FRAME_WIDTH, FRAME_HEIGHT, 8, flags);
312 >
313 > #endif
314  
315          // Hide mouse pointer in fullscreen mode
316          if (ThePrefs.DisplayType == DISPTYPE_SCREEN)
# Line 144 | Line 358 | C64Display::~C64Display()
358  
359   void C64Display::NewPrefs(Prefs *prefs)
360   {
361 +        // Unused, we handle fullscreen/window mode switches in PollKeyboard()
362   }
363  
364  
# Line 205 | Line 420 | void C64Display::Update(void)
420          draw_string(screen, DISPLAY_X * 4/5 + 8, DISPLAY_Y + 4, "D\x12 11", black, fill_gray);
421          draw_string(screen, 24, DISPLAY_Y + 4, speedometer_string, black, fill_gray);
422  
423 + #ifdef ENABLE_OPENGL
424 +        // Load screen to texture
425 +        glActiveTexture(GL_TEXTURE0);
426 +        glBindTexture(GL_TEXTURE_2D, vic_tex);
427 +        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, FRAME_WIDTH, FRAME_HEIGHT, GL_RED, GL_UNSIGNED_BYTE, screen->pixels);
428 +
429 +        // Draw textured rectangle
430 +        glBegin(GL_QUADS);
431 +                glTexCoord2f(0.0, 0.0);
432 +                glVertex2f(0.0, 0.0);
433 +                glTexCoord2f(float(FRAME_WIDTH) / TEXTURE_SIZE, 0.0);
434 +                glVertex2f(float(FRAME_WIDTH), 0.0);
435 +                glTexCoord2f(float(FRAME_WIDTH) / TEXTURE_SIZE, float(FRAME_HEIGHT) / TEXTURE_SIZE);
436 +                glVertex2f(float(FRAME_WIDTH), float(FRAME_HEIGHT));
437 +                glTexCoord2f(0.0, float(FRAME_HEIGHT) / TEXTURE_SIZE);
438 +                glVertex2f(0.0, float(FRAME_HEIGHT));
439 +        glEnd();
440 +
441 +        // Update display
442 +        SDL_GL_SwapBuffers();
443 + #else
444          // Update display
445          SDL_Flip(screen);
446 + #endif
447   }
448  
449  
# Line 448 | Line 685 | void C64Display::PollKeyboard(uint8 *key
685                                          case SDLK_F10:  // F10: Prefs/Quit
686                                                  TheC64->Pause();
687                                                  if (ThePrefs.DisplayType == DISPTYPE_SCREEN) {  // exit fullscreen mode
688 <                                                        SDL_WM_ToggleFullScreen(screen);
688 >                                                        SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
689                                                          SDL_ShowCursor(1);
690                                                  }
691  
692                                                  if (!TheApp->RunPrefsEditor()) {
693                                                          quit_requested = true;
694 <                                                }
695 <
696 <                                                if (ThePrefs.DisplayType == DISPTYPE_SCREEN) {  // enter fullscreen mode
697 <                                                        SDL_ShowCursor(0);
698 <                                                        SDL_WM_ToggleFullScreen(screen);
694 >                                                } else {
695 >                                                        if (ThePrefs.DisplayType == DISPTYPE_SCREEN) {  // enter fullscreen mode
696 >                                                                SDL_ShowCursor(0);
697 >                                                                SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
698 >                                                        }
699                                                  }
700  
701                                                  TheC64->Resume();
# Line 503 | Line 740 | void C64Display::PollKeyboard(uint8 *key
740                                          translate_key(event.key.keysym.sym, true, key_matrix, rev_matrix, joystick);
741                                  break;
742  
743 + #ifdef ENABLE_OPENGL
744 +                        // Window resized
745 +                        case SDL_VIDEORESIZE:
746 +                                video_resized(event.resize.w, event.resize.h);
747 +                                break;
748 + #endif
749 +
750                          // Quit Frodo
751                          case SDL_QUIT:
752                                  quit_requested = true;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines