14 #define DIE(format, ...) do { \
15 fprintf(stderr, "Died at %s:%d: ", __FILE__, __LINE__ ); \
16 fprintf(stderr, format "\n", ## __VA_ARGS__); \
24 static SDL_Rect windowSize, screenSize;
25 static bool gotWindowSize, gotScreenSize;
27 /** The current scaler object */
30 /** Use the current window size to calculate screen size.
31 Useful on "single window" platforms, like Hildon.
33 static void calculateScreenSize()
36 SDL_VERSION(&wminfo.version);
38 if ( SDL_GetWMInfo(&wminfo) ) {
39 Display *dpy = wminfo.info.x11.display;
42 XWindowAttributes xwa;
44 if (Config.fullscreen) {
45 w = wminfo.info.x11.fswindow;
49 w = wminfo.info.x11.wmwindow;
54 XGetWindowAttributes(dpy, w, &xwa);
62 /** Sets the main window title */
63 void S9xSetTitle(const char *title)
65 // This is a Maemo specific hack, but works on most platforms.
67 SDL_VERSION(&info.version);
68 if ( SDL_GetWMInfo(&info) ) {
69 Display *dpy = info.info.x11.display;
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);
80 static void freeVideoSurface()
82 screen = 0; // There's no need to free the screen surface.
85 free(GFX.SubScreen); GFX.SubScreen = 0;
86 free(GFX.ZBuffer); GFX.ZBuffer = 0;
87 free(GFX.SubZBuffer); GFX.SubZBuffer = 0;
89 delete scaler; scaler = 0;
92 static void setupVideoSurface()
95 const unsigned gameWidth = IMAGE_WIDTH;
96 const unsigned gameHeight = IMAGE_HEIGHT;
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();
112 if (Config.fullscreen) {
113 GUI.Width = screenSize.w;
114 GUI.Height = screenSize.h;
116 GUI.Width = windowSize.w;
117 GUI.Height = windowSize.h;
120 GUI.Width = gameWidth;
121 GUI.Height = gameHeight;
128 if (gameHeight > GUI.Height || gameWidth > GUI.Width)
129 DIE("Video is larger than window size!");
131 const ScalerFactory* sFactory = searchForScaler(16, gameWidth, gameHeight);
133 screen = SDL_SetVideoMode(GUI.Width, GUI.Height, 16,
134 SDL_SWSURFACE | (Config.fullscreen ? SDL_FULLSCREEN : 0));
137 DIE("SDL_SetVideoMode: %s", SDL_GetError());
139 SDL_ShowCursor(SDL_DISABLE);
141 scaler = sFactory->instantiate(screen, gameWidth, gameHeight);
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.
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);
154 GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
155 GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
156 GFX.PPL = GFX.Pitch / (screen->format->BitsPerPixel / 8);
158 scaler->getRenderedGUIArea(GUI.RenderX, GUI.RenderY, GUI.RenderW, GUI.RenderH);
159 scaler->getRatio(GUI.ScaleX, GUI.ScaleY);
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",
168 static void drawOnscreenControls()
170 if (Config.touchscreenInput) {
171 S9xInputScreenChanged();
174 if (Config.touchscreenShow) {
176 SDL_FillRect(screen, NULL, 0);
177 S9xInputScreenDraw(screen->pixels, screen->pitch);
183 void S9xInitDisplay(int argc, char ** argv)
185 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
186 DIE("SDL_InitSubSystem(VIDEO): %s", SDL_GetError());
189 drawOnscreenControls();
192 void S9xDeinitDisplay()
195 SDL_QuitSubSystem(SDL_INIT_VIDEO);
198 void S9xVideoToggleFullscreen()
201 Config.fullscreen = !Config.fullscreen;
203 drawOnscreenControls();
206 bool videoEventFilter(const SDL_Event& event)
208 // If we're in power save mode, and this is a defocus event, quit.
210 if (event.type == SDL_ACTIVEEVENT &&
211 (event.active.state & SDL_APPINPUTFOCUS) &&
212 !event.active.gain) {
213 S9xDoAction(kActionQuit);
218 // Forward video event to the active scaler, if any.
220 return scaler->filter(event);
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.
230 bool8 S9xInitUpdate ()
237 /** Called once a complete SNES screen has been rendered into the GFX.Screen
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.
249 bool8 S9xDeinitUpdate (int width, int height)
254 if (ExitBtnRequiresDraw()) {