1 /*
2  * Copyright (C) 2004 Ivo Danihelka (ivo@danihelka.net)
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  */
9 #include "VideoAgent.h"
10 
11 #include "Log.h"
12 #include "Path.h"
13 #include "ImgException.h"
14 #include "SDLException.h"
15 #include "LogicException.h"
16 #include "AgentPack.h"
17 #include "SimpleMsg.h"
18 #include "StringMsg.h"
19 #include "UnknownMsgException.h"
20 #include "OptionAgent.h"
21 #include "SysVideo.h"
22 
23 #include "SDL_image.h"
24 #include <stdlib.h> // atexit()
25 
26 //-----------------------------------------------------------------
27 /**
28  * Init SDL and grafic window.
29  * Register watcher for "fullscren" and "screen_*" options.
30  * @throws SDLException if there is no usuable video mode
31  */
32     void
own_init()33 VideoAgent::own_init()
34 {
35     m_screen = NULL;
36     m_fullscreen = false;
37     if (SDL_Init(SDL_INIT_VIDEO) < 0) {
38         throw SDLException(ExInfo("Init"));
39     }
40     atexit(SDL_Quit);
41 
42     setIcon(Path::dataReadPath("images/icon.png"));
43 
44     registerWatcher("fullscreen");
45     initVideoMode();
46 }
47 //-----------------------------------------------------------------
48 /**
49  * Draw all drawer from list.
50  * First will be drawed first.
51  */
52     void
own_update()53 VideoAgent::own_update()
54 {
55     drawOn(m_screen);
56     SDL_Flip(m_screen);
57 }
58 //-----------------------------------------------------------------
59 /**
60  * Shutdown SDL.
61  */
62     void
own_shutdown()63 VideoAgent::own_shutdown()
64 {
65     SDL_Quit();
66 }
67 
68 //-----------------------------------------------------------------
69 /**
70  * Load and set icon.
71  * @throws ImgException
72  */
73     void
setIcon(const Path & file)74 VideoAgent::setIcon(const Path &file)
75 {
76     SDL_Surface *icon = IMG_Load(file.getNative().c_str());
77     if (NULL == icon) {
78         throw ImgException(ExInfo("Load")
79                 .addInfo("file", file.getNative()));
80     }
81 
82     SDL_WM_SetIcon(icon, NULL);
83     SDL_FreeSurface(icon);
84 }
85 
86 //-----------------------------------------------------------------
87 /**
88  * Init video mode along options.
89  * Change window only when necessary.
90  *
91  * @throws SDLException when video mode cannot be made,
92  * the old video mode remain usable
93  */
94     void
initVideoMode()95 VideoAgent::initVideoMode()
96 {
97     OptionAgent *options = OptionAgent::agent();
98     int screen_width = options->getAsInt("screen_width", 640);
99     int screen_height = options->getAsInt("screen_height", 480);
100 
101     SysVideo::setCaption(options->getParam("caption", "A game"));
102     if (NULL == m_screen
103             || m_screen->w != screen_width
104             || m_screen->h != screen_height)
105     {
106         changeVideoMode(screen_width, screen_height);
107     }
108 }
109 //-----------------------------------------------------------------
110 /**
111  * Init new video mode.
112  * NOTE: m_screen pointer will change
113  */
114     void
changeVideoMode(int screen_width,int screen_height)115 VideoAgent::changeVideoMode(int screen_width, int screen_height)
116 {
117     OptionAgent *options = OptionAgent::agent();
118     int screen_bpp = options->getAsInt("screen_bpp", 32);
119     int videoFlags = getVideoFlags();
120     m_fullscreen = options->getAsBool("fullscreen", false);
121     if (m_fullscreen) {
122         videoFlags |= SDL_FULLSCREEN;
123     }
124 
125     //TODO: check VideoModeOK and available ListModes
126     SDL_Surface *newScreen =
127         SDL_SetVideoMode(screen_width, screen_height, screen_bpp, videoFlags);
128     if (NULL == newScreen && (videoFlags & SDL_FULLSCREEN)) {
129         LOG_WARNING(ExInfo("unable to use fullscreen resolution, trying windowed")
130                 .addInfo("width", screen_width)
131                 .addInfo("height", screen_height)
132                 .addInfo("bpp", screen_bpp));
133 
134         videoFlags = videoFlags & ~SDL_FULLSCREEN;
135         newScreen = SDL_SetVideoMode(screen_width, screen_height, screen_bpp,
136                 videoFlags);
137     }
138 
139     if (newScreen) {
140         m_screen = newScreen;
141         //NOTE: must be two times to change MouseState
142         SDL_WarpMouse(screen_width / 2, screen_height / 2);
143         SDL_WarpMouse(screen_width / 2, screen_height / 2);
144     }
145     else {
146         throw SDLException(ExInfo("SetVideoMode")
147                 .addInfo("width", screen_width)
148                 .addInfo("height", screen_height)
149                 .addInfo("bpp", screen_bpp));
150     }
151 }
152 //-----------------------------------------------------------------
153 /**
154  * Obtain video information about best video mode.
155  * @return best video flags
156  */
157     int
getVideoFlags()158 VideoAgent::getVideoFlags()
159 {
160     int videoFlags  = 0;
161     videoFlags |= SDL_HWPALETTE;
162     videoFlags |= SDL_ANYFORMAT;
163     videoFlags |= SDL_SWSURFACE;
164 
165     return videoFlags;
166 }
167 //-----------------------------------------------------------------
168 /**
169  *  Toggle fullscreen.
170  */
171     void
toggleFullScreen()172 VideoAgent::toggleFullScreen()
173 {
174     int success = SDL_WM_ToggleFullScreen(m_screen);
175     if (success) {
176         m_fullscreen = !m_fullscreen;
177     }
178     else {
179         //NOTE: some platforms need reinit video
180         changeVideoMode(m_screen->w, m_screen->h);
181     }
182 }
183 //-----------------------------------------------------------------
184 /**
185  * Handle incoming message.
186  * Messages:
187  * - fullscreen ... toggle fullscreen
188  *
189  * @throws UnknownMsgException
190  */
191     void
receiveSimple(const SimpleMsg * msg)192 VideoAgent::receiveSimple(const SimpleMsg *msg)
193 {
194     if (msg->equalsName("fullscreen")) {
195         OptionAgent *options = OptionAgent::agent();
196         bool toggle = !(options->getAsBool("fullscreen"));
197         options->setPersistent("fullscreen", toggle);
198     }
199     else {
200         throw UnknownMsgException(msg);
201     }
202 }
203 //-----------------------------------------------------------------
204 /**
205  * Handle incoming message.
206  * Messages:
207  * - param_changed(fullscreen) ... handle fullscreen
208  *
209  * @throws UnknownMsgException
210  */
211     void
receiveString(const StringMsg * msg)212 VideoAgent::receiveString(const StringMsg *msg)
213 {
214     if (msg->equalsName("param_changed")) {
215         std::string param = msg->getValue();
216         if ("fullscreen" == param) {
217             bool fs = OptionAgent::agent()->getAsBool("fullscreen");
218             if (fs != m_fullscreen) {
219                 toggleFullScreen();
220             }
221         }
222         else {
223             throw UnknownMsgException(msg);
224         }
225     }
226     else {
227         throw UnknownMsgException(msg);
228     }
229 }
230 
231