15 #define DIE(format, ...) do { \
16 fprintf(stderr, "Died at %s:%d: ", __FILE__, __LINE__ ); \
17 fprintf(stderr, format "\n", ## __VA_ARGS__); \
25 static SDL_Rect windowSize, screenSize;
26 static bool gotWindowSize, gotScreenSize;
28 /** The current scaler object */
31 /** Use the current window size to calculate screen size.
32 Useful on "single window" platforms, like Hildon.
34 static void calculateScreenSize()
37 SDL_VERSION(&wminfo.version);
39 if ( SDL_GetWMInfo(&wminfo) ) {
40 Display *dpy = wminfo.info.x11.display;
43 XWindowAttributes xwa;
45 if (Config.fullscreen) {
46 w = wminfo.info.x11.fswindow;
50 w = wminfo.info.x11.wmwindow;
55 XGetWindowAttributes(dpy, w, &xwa);
63 /** Sets the main window title */
64 void S9xSetTitle(const char *title)
66 // This is a Maemo specific hack, but works on most platforms.
68 SDL_VERSION(&info.version);
69 if ( SDL_GetWMInfo(&info) ) {
70 Display *dpy = info.info.x11.display;
73 win = info.info.x11.fswindow;
74 if (win) XStoreName(dpy, win, title);
75 win = info.info.x11.wmwindow;
76 if (win) XStoreName(dpy, win, title);
81 static void freeVideoSurface()
83 screen = 0; // There's no need to free the screen surface.
86 free(GFX.SubScreen); GFX.SubScreen = 0;
87 free(GFX.ZBuffer); GFX.ZBuffer = 0;
88 free(GFX.SubZBuffer); GFX.SubZBuffer = 0;
90 delete scaler; scaler = 0;
93 static void setupVideoSurface()
96 const unsigned gameWidth = IMAGE_WIDTH;
97 const unsigned gameHeight = IMAGE_HEIGHT;
100 // Under Maemo we know that the window manager will automatically
101 // resize our windows to fullscreen.
102 // Thus we can use that to detect the screen size.
103 // Of course, this causes flicker, so we try to avoid it when
104 // changing between modes.
105 if ((Config.fullscreen && !gotScreenSize) ||
106 (!Config.fullscreen && !gotWindowSize)) {
107 screen = SDL_SetVideoMode(gameWidth, gameHeight, 16,
108 SDL_SWSURFACE | SDL_RESIZABLE |
109 (Config.fullscreen ? SDL_FULLSCREEN : 0));
110 if (!screen) DIE("SDL_SetVideoMode: %s", SDL_GetError());
111 calculateScreenSize();
113 if (Config.fullscreen) {
114 GUI.Width = screenSize.w;
115 GUI.Height = screenSize.h;
117 GUI.Width = windowSize.w;
118 GUI.Height = windowSize.h;
121 GUI.Width = gameWidth;
122 GUI.Height = gameHeight;
129 if (gameHeight > GUI.Height || gameWidth > GUI.Width)
130 DIE("Video is larger than window size!");
132 const ScalerFactory* sFactory = searchForScaler(16, gameWidth, gameHeight);
134 screen = SDL_SetVideoMode(GUI.Width, GUI.Height, 16,
135 SDL_SWSURFACE | (Config.fullscreen ? SDL_FULLSCREEN : 0));
138 DIE("SDL_SetVideoMode: %s", SDL_GetError());
140 SDL_ShowCursor(SDL_DISABLE);
142 scaler = sFactory->instantiate(screen, gameWidth, gameHeight);
144 // Each scaler may have its own pitch
145 GFX.Pitch = scaler->getDrawBufferPitch();
146 GFX.ZPitch = GFX.Pitch / 2;
147 // gfx & tile.cpp depend on the zbuffer pitch being always half of the color buffer pitch.
148 // Which is a pity, since the color buffer might be much larger.
150 GFX.Screen = scaler->getDrawBuffer();
151 GFX.SubScreen = (uint8 *) malloc(GFX.Pitch * IMAGE_HEIGHT);
152 GFX.ZBuffer = (uint8 *) malloc(GFX.ZPitch * IMAGE_HEIGHT);
153 GFX.SubZBuffer = (uint8 *) malloc(GFX.ZPitch * IMAGE_HEIGHT);
155 GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
156 GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
157 GFX.PPL = GFX.Pitch / (screen->format->BitsPerPixel / 8);
159 scaler->getRenderedGUIArea(GUI.RenderX, GUI.RenderY, GUI.RenderW, GUI.RenderH);
160 scaler->getRatio(GUI.ScaleX, GUI.ScaleY);
162 printf("Video: %dx%d (%dx%d output), %hu bits per pixel, %s, %s\n",
163 gameWidth, gameHeight,
164 screen->w, screen->h, screen->format->BitsPerPixel,
165 Config.fullscreen ? "fullscreen" : "windowed",
169 static void drawOnscreenControls()
171 if (Config.touchscreenInput) {
172 S9xInputScreenChanged();
175 if (Config.touchscreenShow) {
177 SDL_FillRect(screen, NULL, 0);
178 S9xInputScreenDraw(screen->pixels, screen->pitch);
184 void S9xInitDisplay(int argc, char ** argv)
186 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
187 DIE("SDL_InitSubSystem(VIDEO): %s", SDL_GetError());
190 drawOnscreenControls();
193 void S9xDeinitDisplay()
196 SDL_QuitSubSystem(SDL_INIT_VIDEO);
199 void S9xVideoToggleFullscreen()
202 Config.fullscreen = !Config.fullscreen;
204 drawOnscreenControls();
207 bool videoEventFilter(const SDL_Event& event)
209 // If we're in power save mode, and this is a defocus event, quit.
211 if (event.type == SDL_ACTIVEEVENT &&
212 (event.active.state & SDL_APPINPUTFOCUS) &&
213 !event.active.gain) {
214 S9xDoAction(kActionQuit);
219 // Forward video event to the active scaler, if any.
221 return scaler->filter(event);
226 /** Called before rendering a frame.
227 This function must ensure GFX.Screen points to something, but we did that
228 while initializing video output.
229 @return TRUE if we should render the frame.
231 bool8_32 S9xInitUpdate ()
238 /** Called once a complete SNES screen has been rendered into the GFX.Screen
241 Now is your chance to copy the SNES rendered screen to the
242 host computer's screen memory. The problem is that you have to cope with
243 different sized SNES rendered screens. Width is always 256, unless you're
244 supporting SNES hi-res. screen modes (Settings.SupportHiRes is TRUE), in
245 which case it can be 256 or 512. The height parameter can be either 224 or
246 239 if you're only supporting SNES lo-res. screen modes, or 224, 239, 448 or
247 478 if hi-res. SNES screen modes are being supported.
250 bool8_32 S9xDeinitUpdate (int width, int height)
255 if (ExitBtnRequiresDraw()) {