removing lots of unused code
[drnoksnes] / platform / sdlv.cpp
1 #include <stdio.h>
2
3 #include <X11/Xlib.h>
4 #include <X11/Xutil.h>
5 #include <SDL.h>
6 #include <SDL_syswm.h>
7
8 #include "snes9x.h"
9 #include "platform.h"
10 #include "gfx.h"
11 #include "ppu.h"
12 #include "sdlv.h"
13
14 #define DIE(format, ...) do { \
15                 fprintf(stderr, "Died at %s:%d: ", __FILE__, __LINE__ ); \
16                 fprintf(stderr, format "\n", ## __VA_ARGS__); \
17                 abort(); \
18         } while (0);
19
20 struct gui GUI;
21
22 SDL_Surface* screen;
23
24 static SDL_Rect windowSize, screenSize;
25 static bool gotWindowSize, gotScreenSize;
26
27 /** The current scaler object */
28 Scaler* scaler;
29
30 /** Use the current window size to calculate screen size.
31         Useful on "single window" platforms, like Hildon.
32  */
33 static void calculateScreenSize()
34 {
35         SDL_SysWMinfo wminfo;
36         SDL_VERSION(&wminfo.version);
37
38         if ( SDL_GetWMInfo(&wminfo) ) {
39                 Display *dpy = wminfo.info.x11.display;
40                 Window w;
41                 SDL_Rect* size;
42                 XWindowAttributes xwa;
43
44                 if (Config.fullscreen) {
45                         w =  wminfo.info.x11.fswindow;
46                         size = &screenSize;
47                         gotScreenSize = true;
48                 } else {
49                         w =  wminfo.info.x11.wmwindow;
50                         size = &windowSize;
51                         gotWindowSize = true;
52                 }
53
54                 XGetWindowAttributes(dpy, w, &xwa);
55                 size->x = xwa.x;
56                 size->y = xwa.y;
57                 size->w = xwa.width;
58                 size->h = xwa.height;
59         }
60 }
61
62 /** Sets the main window title */
63 void S9xSetTitle(const char *title)
64 {
65         // This is a Maemo specific hack, but works on most platforms.
66         SDL_SysWMinfo info;
67         SDL_VERSION(&info.version);
68         if ( SDL_GetWMInfo(&info) ) {
69                 Display *dpy = info.info.x11.display;
70                 Window win;
71                 if (dpy) {
72                         win = info.info.x11.fswindow;
73                         if (win) XStoreName(dpy, win, title);
74                         win = info.info.x11.wmwindow;
75                         if (win) XStoreName(dpy, win, title);
76                 }
77         }
78 }
79
80 static void freeVideoSurface()
81 {
82         screen = 0; // There's no need to free the screen surface.
83         GFX.Screen = 0;
84
85         free(GFX.SubScreen); GFX.SubScreen = 0;
86         free(GFX.ZBuffer); GFX.ZBuffer = 0;
87         free(GFX.SubZBuffer); GFX.SubZBuffer = 0;
88
89         delete scaler; scaler = 0;
90 }
91
92 static void setupVideoSurface()
93 {
94         // Real surface area.
95         const unsigned gameWidth = IMAGE_WIDTH;
96         const unsigned gameHeight = IMAGE_HEIGHT;
97
98 #ifdef MAEMO
99         // Under Maemo we know that the window manager will automatically
100         // resize our windows to fullscreen.
101         // Thus we can use that to detect the screen size.
102         // Of course, this causes flicker, so we try to avoid it when
103         // changing between modes.
104         if ((Config.fullscreen && !gotScreenSize) ||
105                 (!Config.fullscreen && !gotWindowSize)) {
106                 screen = SDL_SetVideoMode(gameWidth, gameHeight, 16,
107                         SDL_SWSURFACE | SDL_RESIZABLE |
108                         (Config.fullscreen ? SDL_FULLSCREEN : 0));
109                 if (!screen) DIE("SDL_SetVideoMode: %s", SDL_GetError());
110                 calculateScreenSize();
111         }
112         if (Config.fullscreen) {
113                 GUI.Width = screenSize.w;
114                 GUI.Height = screenSize.h;
115         } else {
116                 GUI.Width = windowSize.w;
117                 GUI.Height = windowSize.h;
118         }
119 #else
120         GUI.Width = gameWidth;
121         GUI.Height = gameHeight;
122 #endif
123 #if CONF_EXIT_BUTTON
124         ExitBtnReset();
125 #endif
126
127         // Safeguard
128         if (gameHeight > GUI.Height || gameWidth > GUI.Width)
129                 DIE("Video is larger than window size!");
130
131         const ScalerFactory* sFactory = searchForScaler(16, gameWidth, gameHeight);
132
133         screen = SDL_SetVideoMode(GUI.Width, GUI.Height, 16,
134                 SDL_SWSURFACE | (Config.fullscreen ? SDL_FULLSCREEN : 0));
135
136         if (!screen)
137                 DIE("SDL_SetVideoMode: %s", SDL_GetError());
138         
139         SDL_ShowCursor(SDL_DISABLE);
140
141         scaler = sFactory->instantiate(screen, gameWidth, gameHeight);
142
143         // Each scaler may have its own pitch
144         GFX.Pitch = scaler->getDrawBufferPitch();
145         GFX.ZPitch = GFX.Pitch / 2;
146         // gfx & tile.cpp depend on the zbuffer pitch being always half of the color buffer pitch.
147         // Which is a pity, since the color buffer might be much larger.
148
149         GFX.Screen = scaler->getDrawBuffer();
150         GFX.SubScreen = (uint8 *) malloc(GFX.Pitch * IMAGE_HEIGHT);
151         GFX.ZBuffer =  (uint8 *) malloc(GFX.ZPitch * IMAGE_HEIGHT);
152         GFX.SubZBuffer = (uint8 *) malloc(GFX.ZPitch * IMAGE_HEIGHT);
153
154         GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
155         GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
156         GFX.PPL = GFX.Pitch / (screen->format->BitsPerPixel / 8);
157
158         scaler->getRenderedGUIArea(GUI.RenderX, GUI.RenderY, GUI.RenderW, GUI.RenderH);
159         scaler->getRatio(GUI.ScaleX, GUI.ScaleY);
160
161         printf("Video: %dx%d (%dx%d output), %hu bits per pixel, %s, %s\n",
162                 gameWidth, gameHeight,
163                 screen->w, screen->h, screen->format->BitsPerPixel,
164                 Config.fullscreen ? "fullscreen" : "windowed",
165                 scaler->getName());
166 }
167
168 static void drawOnscreenControls()
169 {
170         if (Config.touchscreenInput) {
171                 S9xInputScreenChanged();
172         }
173
174         if (Config.touchscreenShow) {
175                 scaler->pause();
176                 SDL_FillRect(screen, NULL, 0);
177                 S9xInputScreenDraw(screen->pixels, screen->pitch);
178                 SDL_Flip(screen);
179                 scaler->resume();
180         }
181 }
182
183 void S9xInitDisplay(int argc, char ** argv)
184 {       
185         if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) 
186                 DIE("SDL_InitSubSystem(VIDEO): %s", SDL_GetError());
187
188         setupVideoSurface();
189         drawOnscreenControls();
190 }
191
192 void S9xDeinitDisplay()
193 {
194         freeVideoSurface();     
195         SDL_QuitSubSystem(SDL_INIT_VIDEO);
196 }
197
198 void S9xVideoToggleFullscreen()
199 {
200         freeVideoSurface();
201         Config.fullscreen = !Config.fullscreen;
202         setupVideoSurface();
203         drawOnscreenControls();
204 }
205
206 bool videoEventFilter(const SDL_Event& event)
207 {
208         // If we're in power save mode, and this is a defocus event, quit.
209         if (Config.saver) {
210                 if (event.type == SDL_ACTIVEEVENT &&
211                    (event.active.state & SDL_APPINPUTFOCUS) &&
212                    !event.active.gain) {
213                         S9xDoAction(kActionQuit);
214                         return true;
215                 }
216         }
217
218         // Forward video event to the active scaler, if any.
219         if (scaler)
220                 return scaler->filter(event);
221         else
222                 return false;
223 }
224
225 /** Called before rendering a frame.
226         This function must ensure GFX.Screen points to something, but we did that
227         while initializing video output.
228         @return TRUE if we should render the frame.
229  */
230 bool8 S9xInitUpdate ()
231 {
232         scaler->prepare();
233
234         return TRUE;
235 }
236
237 /** Called once a complete SNES screen has been rendered into the GFX.Screen
238         memory buffer.
239
240         Now is your chance to copy the SNES rendered screen to the
241         host computer's screen memory. The problem is that you have to cope with
242         different sized SNES rendered screens. Width is always 256, unless you're
243         supporting SNES hi-res. screen modes (Settings.SupportHiRes is TRUE), in
244         which case it can be 256 or 512. The height parameter can be either 224 or
245         239 if you're only supporting SNES lo-res. screen modes, or 224, 239, 448 or
246         478 if hi-res. SNES screen modes are being supported.
247  */
248 // TODO Above.
249 bool8 S9xDeinitUpdate (int width, int height)
250 {
251         scaler->finish();
252
253 #if CONF_EXIT_BUTTON
254         if (ExitBtnRequiresDraw()) {
255                 scaler->pause();
256                 ExitBtnDraw(screen);
257                 scaler->resume();
258         }
259 #endif
260
261         return TRUE;
262 }
263