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.3 by cebix, 2003-07-14T13:59:02Z vs.
Revision 1.11 by cebix, 2010-04-23T11:12:05Z

# Line 2 | Line 2
2   *  Display_SDL.h - C64 graphics display, emulator window handling,
3   *                  SDL specific stuff
4   *
5 < *  Frodo (C) 1994-1997,2002-2003 Christian Bauer
5 > *  Frodo Copyright (C) Christian Bauer
6   *
7   *  This program is free software; you can redistribute it and/or modify
8   *  it under the terms of the GNU General Public License as published by
# 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 37 | Line 45 | static C64Display *c64_disp;
45   static struct sigaction pulse_sa;
46   static itimerval pulse_tv;
47  
48 + // SDL joysticks
49 + static SDL_Joystick *joy[2] = {NULL, NULL};
50 +
51   // Colors for speedometer/drive LEDs
52   enum {
53          black = 0,
# Line 49 | 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 73 | Line 97 | enum {
97   int init_graphics(void)
98   {
99          // Init SDL
100 <        if (SDL_Init(SDL_INIT_VIDEO) < 0) {
100 >        if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO) < 0) {
101                  fprintf(stderr, "Couldn't initialize SDL (%s)\n", SDL_GetError());
102                  return 0;
103          }
104  
81        // Open window
82        SDL_WM_SetCaption(VERSION_STRING, "Frodo");
83        screen = SDL_SetVideoMode(DISPLAY_X, DISPLAY_Y + 17, 8, SDL_DOUBLEBUF);
84
105          return 1;
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 95 | Line 165 | C64Display::C64Display(C64 *the_c64) : T
165          quit_requested = false;
166          speedometer_string[0] = 0;
167  
168 +        // Open window
169 +        SDL_WM_SetCaption(VERSION_STRING, "Frodo");
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)
317 +                SDL_ShowCursor(0);
318 +
319          // LEDs off
320          for (int i=0; i<4; i++)
321                  led_state[i] = old_led_state[i] = LED_OFF;
# Line 119 | Line 340 | C64Display::C64Display(C64 *the_c64) : T
340  
341   C64Display::~C64Display()
342   {
343 +        pulse_tv.it_interval.tv_sec = 0;
344 +        pulse_tv.it_interval.tv_usec = 0;
345 +        pulse_tv.it_value.tv_sec = 0;
346 +        pulse_tv.it_value.tv_usec = 0;
347 +        setitimer(ITIMER_REAL, &pulse_tv, NULL);
348 +
349          SDL_Quit();
350 +
351 +        c64_disp = NULL;
352   }
353  
354  
# Line 129 | 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 190 | 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 426 | Line 678 | void C64Display::PollKeyboard(uint8 *key
678                                  switch (event.key.keysym.sym) {
679  
680                                          case SDLK_F9:   // F9: Invoke SAM
681 <                                                SAM(TheC64);
681 >                                                if (ThePrefs.DisplayType == DISPTYPE_WINDOW)  // don't invoke in fullscreen mode
682 >                                                        SAM(TheC64);
683                                                  break;
684  
685 <                                        case SDLK_F10:  // F10: Quit
686 <                                                quit_requested = true;
685 >                                        case SDLK_F10:  // F10: Prefs/Quit
686 >                                                TheC64->Pause();
687 >                                                if (ThePrefs.DisplayType == DISPTYPE_SCREEN) {  // exit fullscreen mode
688 >                                                        SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
689 >                                                        SDL_ShowCursor(1);
690 >                                                }
691 >
692 >                                                if (!TheApp->RunPrefsEditor()) {
693 >                                                        quit_requested = true;
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();
702                                                  break;
703  
704                                          case SDLK_F11:  // F11: NMI (Restore)
# Line 472 | 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;
# Line 492 | Line 767 | bool C64Display::NumLock(void)
767  
768  
769   /*
770 + *  Open/close joystick drivers given old and new state of
771 + *  joystick preferences
772 + */
773 +
774 + void C64::open_close_joystick(int port, int oldjoy, int newjoy)
775 + {
776 +        if (oldjoy != newjoy) {
777 +                joy_minx[port] = joy_miny[port] = 32767;        // Reset calibration
778 +                joy_maxx[port] = joy_maxy[port] = -32768;
779 +                if (newjoy) {
780 +                        joy[port] = SDL_JoystickOpen(newjoy - 1);
781 +                        if (joy[port] == NULL)
782 +                                fprintf(stderr, "Couldn't open joystick %d\n", port + 1);
783 +                } else {
784 +                        if (joy[port]) {
785 +                                SDL_JoystickClose(joy[port]);
786 +                                joy[port] = NULL;
787 +                        }
788 +                }
789 +        }
790 + }
791 +
792 + void C64::open_close_joysticks(int oldjoy1, int oldjoy2, int newjoy1, int newjoy2)
793 + {
794 +        open_close_joystick(0, oldjoy1, newjoy1);
795 +        open_close_joystick(1, oldjoy2, newjoy2);
796 + }
797 +
798 +
799 + /*
800 + *  Poll joystick port, return CIA mask
801 + */
802 +
803 + uint8 C64::poll_joystick(int port)
804 + {
805 +        uint8 j = 0xff;
806 +
807 +        if (port == 0 && (joy[0] || joy[1]))
808 +                SDL_JoystickUpdate();
809 +
810 +        if (joy[port]) {
811 +                int x = SDL_JoystickGetAxis(joy[port], 0), y = SDL_JoystickGetAxis(joy[port], 1);
812 +
813 +                if (x > joy_maxx[port])
814 +                        joy_maxx[port] = x;
815 +                if (x < joy_minx[port])
816 +                        joy_minx[port] = x;
817 +                if (y > joy_maxy[port])
818 +                        joy_maxy[port] = y;
819 +                if (y < joy_miny[port])
820 +                        joy_miny[port] = y;
821 +
822 +                if (joy_maxx[port] - joy_minx[port] < 100 || joy_maxy[port] - joy_miny[port] < 100)
823 +                        return 0xff;
824 +
825 +                if (x < (joy_minx[port] + (joy_maxx[port]-joy_minx[port])/3))
826 +                        j &= 0xfb;                                                      // Left
827 +                else if (x > (joy_minx[port] + 2*(joy_maxx[port]-joy_minx[port])/3))
828 +                        j &= 0xf7;                                                      // Right
829 +
830 +                if (y < (joy_miny[port] + (joy_maxy[port]-joy_miny[port])/3))
831 +                        j &= 0xfe;                                                      // Up
832 +                else if (y > (joy_miny[port] + 2*(joy_maxy[port]-joy_miny[port])/3))
833 +                        j &= 0xfd;                                                      // Down
834 +
835 +                if (SDL_JoystickGetButton(joy[port], 0))
836 +                        j &= 0xef;                                                      // Button
837 +        }
838 +
839 +        return j;
840 + }
841 +
842 +
843 + /*
844   *  Allocate C64 colors
845   */
846  
# Line 521 | Line 870 | void C64Display::InitColors(uint8 *color
870   *  Show a requester (error message)
871   */
872  
873 < long int ShowRequester(char *a,char *b,char *)
873 > long int ShowRequester(const char *a, const char *b, const char *)
874   {
875          printf("%s: %s\n", a, b);
876          return 1;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines