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.Pitch = scaler->getDrawBufferPitch();
148 GFX.ZPitch = GFX.Pitch / 2;
149 // gfx & tile.cpp depend on the zbuffer pitch being always half of the color buffer pitch.
150 // Which is a pity, since the color buffer might be much larger.
152 GFX.Screen = scaler->getDrawBuffer();
153 GFX.SubScreen = (uint8 *) malloc(GFX.Pitch * IMAGE_HEIGHT);
154 GFX.ZBuffer = (uint8 *) malloc(GFX.ZPitch * IMAGE_HEIGHT);
155 GFX.SubZBuffer = (uint8 *) malloc(GFX.ZPitch * IMAGE_HEIGHT);
157 GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
158 GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
159 GFX.PPL = GFX.Pitch / (screen->format->BitsPerPixel / 8);
161 scaler->getRenderedGUIArea(GUI.RenderX, GUI.RenderY, GUI.RenderW, GUI.RenderH);
162 scaler->getRatio(GUI.ScaleX, GUI.ScaleY);
164 printf("Video: %dx%d (%dx%d output), %hu bits per pixel, %s, %s\n",
165 gameWidth, gameHeight,
166 screen->w, screen->h, screen->format->BitsPerPixel,
167 Config.fullscreen ? "fullscreen" : "windowed",
171 static void drawOnscreenControls()
173 if (Config.touchscreenInput) {
174 S9xInputScreenChanged();
177 if (Config.touchscreenShow) {
179 SDL_FillRect(screen, NULL, 0);
180 S9xInputScreenDraw(Settings.SixteenBit ? 2 : 1,
181 screen->pixels, screen->pitch);
187 void S9xInitDisplay(int argc, char ** argv)
189 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
190 DIE("SDL_InitSubSystem(VIDEO): %s", SDL_GetError());
193 drawOnscreenControls();
196 void S9xDeinitDisplay()
199 SDL_QuitSubSystem(SDL_INIT_VIDEO);
202 void S9xVideoToggleFullscreen()
205 Config.fullscreen = !Config.fullscreen;
207 drawOnscreenControls();
210 bool videoEventFilter(const SDL_Event& event)
212 // If we're in power save mode, and this is a defocus event, quit.
214 if (event.type == SDL_ACTIVEEVENT &&
215 (event.active.state & SDL_APPINPUTFOCUS) &&
216 !event.active.gain) {
217 S9xDoAction(kActionQuit);
222 // Forward video event to the active scaler, if any.
224 return scaler->filter(event);
229 // This is here for completeness, but palette mode is mostly useless (slow).
230 void S9xSetPalette ()
232 if (Settings.SixteenBit) return;
234 SDL_Color colors[256];
235 int brightness = IPPU.MaxBrightness *138;
236 for (int i = 0; i < 256; i++)
238 colors[i].r = ((PPU.CGDATA[i] >> 0) & 0x1F) * brightness;
239 colors[i].g = ((PPU.CGDATA[i] >> 5) & 0x1F) * brightness;
240 colors[i].b = ((PPU.CGDATA[i] >> 10) & 0x1F) * brightness;
243 SDL_SetColors(screen, colors, 0, 256);
246 /** Called before rendering a frame.
247 This function must ensure GFX.Screen points to something, but we did that
248 while initializing video output.
249 @return TRUE if we should render the frame.
251 bool8_32 S9xInitUpdate ()
258 /** Called once a complete SNES screen has been rendered into the GFX.Screen
261 Now is your chance to copy the SNES rendered screen to the
262 host computer's screen memory. The problem is that you have to cope with
263 different sized SNES rendered screens. Width is always 256, unless you're
264 supporting SNES hi-res. screen modes (Settings.SupportHiRes is TRUE), in
265 which case it can be 256 or 512. The height parameter can be either 224 or
266 239 if you're only supporting SNES lo-res. screen modes, or 224, 239, 448 or
267 478 if hi-res. SNES screen modes are being supported.
270 bool8_32 S9xDeinitUpdate (int width, int height, bool8_32 sixteenBit)
275 if (ExitBtnRequiresDraw()) {