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 =
133 searchForScaler(Settings.SixteenBit ? 16 : 8, gameWidth, gameHeight);
135 screen = SDL_SetVideoMode(GUI.Width, GUI.Height,
136 Settings.SixteenBit ? 16 : 8,
138 (Config.fullscreen ? SDL_FULLSCREEN : 0));
140 DIE("SDL_SetVideoMode: %s", SDL_GetError());
142 SDL_ShowCursor(SDL_DISABLE);
144 scaler = sFactory->instantiate(screen, gameWidth, gameHeight);
146 // Each scaler may have its own pitch
147 GFX.RealPitch = GFX.Pitch = scaler->getDrawBufferPitch();
148 GFX.ZPitch = GFX.Pitch / 2; // gfx & tile.cpp depend on this, unfortunately.
149 GFX.PixSize = screen->format->BitsPerPixel / 8;
151 GFX.Screen = scaler->getDrawBuffer();
152 GFX.SubScreen = (uint8 *) malloc(GFX.Pitch * IMAGE_HEIGHT);
153 GFX.ZBuffer = (uint8 *) malloc(GFX.ZPitch * IMAGE_HEIGHT);
154 GFX.SubZBuffer = (uint8 *) malloc(GFX.ZPitch * IMAGE_HEIGHT);
156 GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
157 GFX.PPL = GFX.Pitch >> 1;
158 GFX.PPLx2 = GFX.Pitch;
160 scaler->getRenderedGUIArea(GUI.RenderX, GUI.RenderY, GUI.RenderW, GUI.RenderH);
161 scaler->getRatio(GUI.ScaleX, GUI.ScaleY);
163 printf("Video: %dx%d (%dx%d output), %hu bits per pixel, %s, %s\n",
164 gameWidth, gameHeight,
165 screen->w, screen->h, screen->format->BitsPerPixel,
166 Config.fullscreen ? "fullscreen" : "windowed",
170 static void drawOnscreenControls()
172 if (Config.touchscreenInput) {
173 S9xInputScreenChanged();
176 if (Config.touchscreenShow) {
178 SDL_FillRect(screen, NULL, 0);
179 S9xInputScreenDraw(Settings.SixteenBit ? 2 : 1,
180 screen->pixels, screen->pitch);
186 void S9xInitDisplay(int argc, char ** argv)
188 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
189 DIE("SDL_InitSubSystem(VIDEO): %s", SDL_GetError());
192 drawOnscreenControls();
195 void S9xDeinitDisplay()
198 SDL_QuitSubSystem(SDL_INIT_VIDEO);
201 void S9xVideoToggleFullscreen()
204 Config.fullscreen = !Config.fullscreen;
206 drawOnscreenControls();
209 void processVideoEvent(const SDL_Event& event)
211 // If we're in power save mode, and this is a defocus event, quit.
213 if (event.type == SDL_ACTIVEEVENT &&
214 (event.active.state & SDL_APPINPUTFOCUS) &&
215 !event.active.gain) {
216 S9xDoAction(kActionQuit);
221 // Forward video event to the active scaler, if any.
223 scaler->filter(event);
226 // This is here for completeness, but palette mode is mostly useless (slow).
227 void S9xSetPalette ()
229 if (Settings.SixteenBit) return;
231 SDL_Color colors[256];
232 int brightness = IPPU.MaxBrightness *138;
233 for (int i = 0; i < 256; i++)
235 colors[i].r = ((PPU.CGDATA[i] >> 0) & 0x1F) * brightness;
236 colors[i].g = ((PPU.CGDATA[i] >> 5) & 0x1F) * brightness;
237 colors[i].b = ((PPU.CGDATA[i] >> 10) & 0x1F) * brightness;
240 SDL_SetColors(screen, colors, 0, 256);
243 /** Called before rendering a frame.
244 This function must ensure GFX.Screen points to something, but we did that
245 while initializing video output.
246 @return TRUE if we should render the frame.
248 bool8_32 S9xInitUpdate ()
255 /** Called once a complete SNES screen has been rendered into the GFX.Screen
258 Now is your chance to copy the SNES rendered screen to the
259 host computer's screen memory. The problem is that you have to cope with
260 different sized SNES rendered screens. Width is always 256, unless you're
261 supporting SNES hi-res. screen modes (Settings.SupportHiRes is TRUE), in
262 which case it can be 256 or 512. The height parameter can be either 224 or
263 239 if you're only supporting SNES lo-res. screen modes, or 224, 239, 448 or
264 478 if hi-res. SNES screen modes are being supported.
267 bool8_32 S9xDeinitUpdate (int width, int height, bool8_32 sixteenBit)
272 if (ExitBtnRequiresDraw()) {