1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 Sam Lantinga
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19    Sam Lantinga
20    slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24#include "SDL_ph_modes_c.h"
25
26static PgVideoModeInfo_t mode_info;
27static PgVideoModes_t mode_list;
28
29/* The current list of available video modes */
30SDL_Rect  SDL_modelist[PH_MAX_VIDEOMODES];
31SDL_Rect* SDL_modearray[PH_MAX_VIDEOMODES];
32
33static int compare_modes_by_res(const void* mode1, const void* mode2)
34{
35    PgVideoModeInfo_t mode1_info;
36    PgVideoModeInfo_t mode2_info;
37
38    if (PgGetVideoModeInfo(*(unsigned short*)mode1, &mode1_info) < 0)
39    {
40        return 0;
41    }
42
43    if (PgGetVideoModeInfo(*(unsigned short*)mode2, &mode2_info) < 0)
44    {
45        return 0;
46    }
47
48    if (mode1_info.width == mode2_info.width)
49    {
50        return mode2_info.height - mode1_info.height;
51    }
52    else
53    {
54        return mode2_info.width - mode1_info.width;
55    }
56}
57
58SDL_Rect **ph_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
59{
60    int i = 0;
61    int j = 0;
62    SDL_Rect Amodelist[PH_MAX_VIDEOMODES];
63
64    for (i=0; i<PH_MAX_VIDEOMODES; i++)
65    {
66        SDL_modearray[i]=&SDL_modelist[i];
67    }
68
69    if (PgGetVideoModeList(&mode_list) < 0)
70    {
71       SDL_SetError("ph_ListModes(): PgGetVideoModeList() function failed !\n");
72       return NULL;
73    }
74
75    mode_info.bits_per_pixel = 0;
76
77    for (i=0; i < mode_list.num_modes; i++)
78    {
79        if (PgGetVideoModeInfo(mode_list.modes[i], &mode_info) < 0)
80        {
81            SDL_SetError("ph_ListModes(): PgGetVideoModeInfo() function failed on mode: 0x%X.\n", mode_list.modes[i]);
82            return NULL;
83        }
84        if(mode_info.bits_per_pixel == format->BitsPerPixel)
85        {
86            Amodelist[j].w = mode_info.width;
87            Amodelist[j].h = mode_info.height;
88            Amodelist[j].x = 0;
89            Amodelist[j].y = 0;
90            j++;
91        }
92    }
93
94    /* reorder biggest for smallest, assume width dominates */
95
96    for(i=0; i<j; i++)
97    {
98        SDL_modelist[i].w = Amodelist[j - i - 1].w;
99        SDL_modelist[i].h = Amodelist[j - i - 1].h;
100        SDL_modelist[i].x = Amodelist[j - i - 1].x;
101        SDL_modelist[i].y = Amodelist[j - i - 1].y;
102    }
103    SDL_modearray[j]=NULL;
104
105    return SDL_modearray;
106}
107
108void ph_FreeVideoModes(_THIS)
109{
110   return;
111}
112
113/* return the mode associated with width, height and bpp */
114/* if there is no mode then zero is returned             */
115int ph_GetVideoMode(int width, int height, int bpp)
116{
117    int i;
118    int modestage=0;
119    int closestmode=0;
120
121    if (PgGetVideoModeList(&mode_list) < 0)
122    {
123        return -1;
124    }
125
126    /* special case for the double-sized 320x200 mode */
127    if ((width==640) && (height==400))
128    {
129       modestage=1;
130    }
131
132    /* search list for exact match */
133    for (i=0; i<mode_list.num_modes; i++)
134    {
135        if (PgGetVideoModeInfo(mode_list.modes[i], &mode_info) < 0)
136        {
137            return 0;
138        }
139
140        if ((mode_info.width == width) && (mode_info.height == height) &&
141            (mode_info.bits_per_pixel == bpp))
142        {
143            return mode_list.modes[i];
144        }
145        else
146        {
147           if ((modestage) && (mode_info.width == width) && (mode_info.height == height+80) &&
148               (mode_info.bits_per_pixel == bpp))
149           {
150              modestage=2;
151              closestmode=mode_list.modes[i];
152           }
153        }
154    }
155
156    /* if we are here, then no 640x400xbpp mode found and we'll emulate it via 640x480xbpp mode */
157    if (modestage==2)
158    {
159       return closestmode;
160    }
161
162    return (i == mode_list.num_modes) ? 0 : mode_list.modes[i];
163}
164
165/* return the mode associated with width, height and bpp               */
166/* if requested bpp is not found the mode with closest bpp is returned */
167int get_mode_any_format(int width, int height, int bpp)
168{
169    int i, closest, delta, min_delta;
170
171    if (PgGetVideoModeList(&mode_list) < 0)
172    {
173        return -1;
174    }
175
176    SDL_qsort(mode_list.modes, mode_list.num_modes, sizeof(unsigned short), compare_modes_by_res);
177
178    for(i=0;i<mode_list.num_modes;i++)
179    {
180        if (PgGetVideoModeInfo(mode_list.modes[i], &mode_info) < 0)
181        {
182            return 0;
183        }
184        if ((mode_info.width == width) && (mode_info.height == height))
185        {
186           break;
187        }
188    }
189
190    if (i<mode_list.num_modes)
191    {
192        /* get closest bpp */
193        closest = i++;
194        if (mode_info.bits_per_pixel == bpp)
195        {
196            return mode_list.modes[closest];
197        }
198
199        min_delta = abs(mode_info.bits_per_pixel - bpp);
200
201        while(1)
202        {
203            if (PgGetVideoModeInfo(mode_list.modes[i], &mode_info) < 0)
204            {
205                return 0;
206            }
207
208            if ((mode_info.width != width) || (mode_info.height != height))
209            {
210                break;
211            }
212            else
213            {
214                if (mode_info.bits_per_pixel == bpp)
215                {
216                    closest = i;
217                    break;
218                }
219                else
220                {
221                    delta = abs(mode_info.bits_per_pixel - bpp);
222                    if (delta < min_delta)
223                    {
224                        closest = i;
225                        min_delta = delta;
226                    }
227                    i++;
228                }
229            }
230        }
231        return mode_list.modes[closest];
232    }
233
234    return 0;
235}
236
237int ph_ToggleFullScreen(_THIS, int on)
238{
239    return -1;
240}
241
242int ph_EnterFullScreen(_THIS, SDL_Surface* screen, int fmode)
243{
244    PgDisplaySettings_t settings;
245    int mode;
246    char* refreshrate;
247    int refreshratenum;
248
249    if (!currently_fullscreen)
250    {
251        /* Get the video mode and set it */
252        if (screen->flags & SDL_ANYFORMAT)
253        {
254            if ((mode = get_mode_any_format(screen->w, screen->h, screen->format->BitsPerPixel)) == 0)
255            {
256                SDL_SetError("ph_EnterFullScreen(): can't find appropriate video mode !\n");
257                return 0;
258            }
259        }
260        else
261        {
262            if ((mode = ph_GetVideoMode(screen->w, screen->h, screen->format->BitsPerPixel)) == 0)
263            {
264                SDL_SetError("ph_EnterFullScreen(): can't find appropriate video mode !\n");
265                return 0;
266            }
267            if (PgGetVideoModeInfo(mode, &mode_info) < 0)
268            {
269                SDL_SetError("ph_EnterFullScreen(): can't get video mode capabilities !\n");
270                return 0;
271            }
272            if (mode_info.height != screen->h)
273            {
274               if ((mode_info.height==480) && (screen->h==400))
275               {
276                  videomode_emulatemode=1;
277               }
278            }
279            else
280            {
281               videomode_emulatemode=0;
282            }
283        }
284
285        /* save old video mode caps */
286        PgGetVideoMode(&settings);
287        old_video_mode=settings.mode;
288        old_refresh_rate=settings.refresh;
289
290        /* setup new video mode */
291        settings.mode = mode;
292        settings.refresh = 0;
293        settings.flags = 0;
294
295        refreshrate=SDL_getenv("SDL_PHOTON_FULLSCREEN_REFRESH");
296        if (refreshrate!=NULL)
297        {
298           if (SDL_sscanf(refreshrate, "%d", &refreshratenum)==1)
299           {
300               settings.refresh = refreshratenum;
301           }
302        }
303
304        if (PgSetVideoMode(&settings) < 0)
305        {
306            SDL_SetError("ph_EnterFullScreen(): PgSetVideoMode() call failed !\n");
307            return 0;
308        }
309
310        if (this->screen)
311        {
312            if ((this->screen->flags & SDL_OPENGL)==SDL_OPENGL)
313            {
314#if !SDL_VIDEO_OPENGL || (_NTO_VERSION < 630)
315                return 0; /* 6.3.0 */
316#endif
317            }
318        }
319
320        if (fmode==0)
321        {
322            if (OCImage.direct_context==NULL)
323            {
324                OCImage.direct_context=(PdDirectContext_t*)PdCreateDirectContext();
325                if (!OCImage.direct_context)
326                {
327                    SDL_SetError("ph_EnterFullScreen(): Can't create direct context !\n");
328                    ph_LeaveFullScreen(this);
329                    return 0;
330                }
331            }
332            OCImage.oldDC=PdDirectStart(OCImage.direct_context);
333        }
334
335        currently_fullscreen = 1;
336    }
337    PgFlush();
338
339    return 1;
340}
341
342int ph_LeaveFullScreen(_THIS)
343{
344    PgDisplaySettings_t oldmode_settings;
345
346    if (currently_fullscreen)
347    {
348        if ((this->screen) && ((this->screen->flags & SDL_OPENGL)==SDL_OPENGL))
349        {
350#if !SDL_VIDEO_OPENGL || (_NTO_VERSION < 630)
351            return 0;
352#endif
353        }
354
355        /* release routines starts here */
356        {
357            if (OCImage.direct_context)
358            {
359                PdDirectStop(OCImage.direct_context);
360                PdReleaseDirectContext(OCImage.direct_context);
361                OCImage.direct_context=NULL;
362            }
363            if (OCImage.oldDC)
364            {
365                PhDCSetCurrent(OCImage.oldDC);
366                OCImage.oldDC=NULL;
367            }
368
369            currently_fullscreen=0;
370
371            /* Restore old video mode */
372            if (old_video_mode != -1)
373            {
374                oldmode_settings.mode = (unsigned short) old_video_mode;
375                oldmode_settings.refresh = (unsigned short) old_refresh_rate;
376                oldmode_settings.flags = 0;
377
378                if (PgSetVideoMode(&oldmode_settings) < 0)
379                {
380                    SDL_SetError("Ph_LeaveFullScreen(): PgSetVideoMode() function failed !\n");
381                    return 0;
382                }
383            }
384
385            old_video_mode=-1;
386            old_refresh_rate=-1;
387        }
388    }
389    return 1;
390}
391