1 /**************************************************************************
2 * PipeWalker game (http://pipewalker.sourceforge.net) *
3 * Copyright (C) 2007-2012 by Artem Senichev <artemsen@gmail.com> *
4 * *
5 * This program is free software: you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation, either version 3 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program 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 *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 **************************************************************************/
18
19 #include "common.h"
20 #include "game.h"
21 #include "image.h"
22 #include "settings.h"
23 #include "../extra/pipewalker.xpm"
24
25 #ifdef WIN32
26 #include <SDL/SDL_syswm.h>
27
28 //! SDL window procedure
29 WNDPROC sdl_wnd_proc = NULL;
30
31 //! Own WNDPROC
32 LRESULT pw_win32_wnd_proc(HWND wnd, UINT msg, WPARAM w_param, LPARAM l_param);
33 #endif // WIN32
34
35
36 /**
37 * Parse command line parameters
38 * \param argc number of parameters
39 * \param argv parameters array
40 * \param lvl_id start level id
41 * \param lvl_sz start level map size
42 * \param lvl_wrap start level wrap mode
43 * \return true if we need to close application
44 */
45 bool parse_cmd_params(int argc, char* argv[], unsigned long& lvl_id, level::size& lvl_sz, bool& lvl_wrap);
46
47
48 /**
49 * SDL timer callback
50 */
51 Uint32 timer_callback(Uint32 interval);
52
53
54 /**
55 * ANSI main entry point
56 */
main(int argc,char * argv[])57 int main(int argc, char* argv[])
58 {
59 unsigned long lvl_id;
60 level::size lvl_sz;
61 bool lvl_wrap;
62 if (parse_cmd_params(argc, argv, lvl_id, lvl_sz, lvl_wrap))
63 return 0; //Help or version was shown
64
65 //Initialization
66 if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO) != 0) {
67 fprintf(stderr, "Critical error\nSDL_Init failed: %s\n", SDL_GetError());
68 return 1;
69 }
70
71 //Let's get some video information
72 const SDL_VideoInfo* vinfo = SDL_GetVideoInfo();
73 if (!vinfo) {
74 fprintf(stderr, "Critical error\nUnable to get video information: %s\n", SDL_GetError());
75 return 1;
76 }
77
78 //Save desktop size
79 const int desktop_width = vinfo->current_w;
80 const int desktop_height = vinfo->current_h;
81
82 //Calculate minimum window sizes
83 const int wnd_min_width = PW_SCREEN_WIDTH / 3;
84 const int wnd_min_height = PW_SCREEN_HEIGHT / 3;
85
86 //Create window
87 if (!SDL_SetVideoMode(PW_SCREEN_WIDTH, PW_SCREEN_HEIGHT, 0, SDL_OPENGL | SDL_RESIZABLE)) {
88 fprintf(stderr, "Critical error\nUnable to set video mode: %s\n", SDL_GetError());
89 return 1;
90 }
91 SDL_WM_SetCaption(PACKAGE_NAME, PACKAGE_NAME);
92 image wnd_icon;
93 if (wnd_icon.load_XPM(pipewalker_xpm, sizeof(pipewalker_xpm) / sizeof(pipewalker_xpm[0])))
94 SDL_WM_SetIcon(wnd_icon.get_surface(), NULL);
95
96 game& game_instance = game::instance();
97 if (!game_instance.initialize(lvl_id, lvl_sz, lvl_wrap))
98 return 1;
99
100 //Timer - about 25 fps
101 SDL_SetTimer(40, &timer_callback);
102
103 #ifdef WIN32
104 SDL_SysWMinfo wmi;
105 SDL_VERSION(&wmi.version);
106 if (SDL_GetWMInfo(&wmi)) {
107 //Set own window procedure
108 sdl_wnd_proc = reinterpret_cast<WNDPROC>(SetWindowLongPtr(wmi.window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&pw_win32_wnd_proc)));
109 //Set normal icon
110 static HICON icon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(0));
111 if (icon)
112 SetClassLongPtr(wmi.window, GCL_HICON, reinterpret_cast<LONG>(icon));
113 }
114 #endif // WIN32
115
116 bool done = false;
117 Uint8 last_mouse_state = 0;
118
119 while (!done) {
120 SDL_Event event;
121 if (SDL_WaitEvent(&event) == 0) {
122 fprintf(stderr, "Critical error\nSDL_WaitEvent failed: %s\n", SDL_GetError());
123 return 1;
124 }
125 switch (event.type) {
126 case SDL_MOUSEMOTION:
127 {
128 Sint32 x, y;
129 SDL_GetMouseState(&x, &y);
130 game_instance.on_mouse_move(x, y);
131 }
132 break;
133 case SDL_MOUSEBUTTONDOWN:
134 //We need to save buttons state - in the SDL_MOUSEBUTTONUP event doesn't have this information
135 last_mouse_state = SDL_GetMouseState(NULL, NULL);
136 break;
137 case SDL_MOUSEBUTTONUP:
138 if (last_mouse_state) {
139 game_instance.on_mouse_click(last_mouse_state);
140 last_mouse_state = 0;
141 }
142 break;
143 case SDL_KEYDOWN:
144 if (event.key.keysym.sym == SDLK_F4 && (SDL_GetModState() == KMOD_LALT || SDL_GetModState() == KMOD_RALT))
145 done = true; //Alt+F4 pressed
146 else
147 done = game_instance.on_key_press(event.key.keysym.sym);
148 break;
149 case SDL_QUIT:
150 done = true;
151 break;
152 case SDL_VIDEOEXPOSE:
153 game_instance.draw_scene();
154 break;
155 case SDL_VIDEORESIZE:
156 if (event.resize.w && event.resize.h) {
157 int wnd_width = event.resize.w;
158 int wnd_height = event.resize.h;
159
160 //Set correct aspect ratio
161 if (wnd_width != desktop_width && wnd_height != desktop_height) {
162 if (wnd_height != vinfo->current_h)
163 wnd_width = static_cast<int>(static_cast<float>(wnd_height) / PW_ASPECT_RATIO);
164 else if (wnd_width != vinfo->current_w)
165 wnd_height = static_cast<int>(static_cast<float>(wnd_width) * PW_ASPECT_RATIO);
166 if (wnd_width < wnd_min_width || wnd_height < wnd_min_height) {
167 //Set minimum window size
168 wnd_width = wnd_min_width;
169 wnd_height = wnd_min_height;
170 }
171 }
172
173 SDL_SetVideoMode(wnd_width, wnd_height, 0, SDL_OPENGL | SDL_RESIZABLE);
174 game_instance.on_window_resize(wnd_width, wnd_height);
175 SDL_Event expose_event;
176 expose_event.type = SDL_VIDEOEXPOSE;
177 SDL_PushEvent(&expose_event);
178 }
179 break;
180 }
181 }
182
183 game_instance.finalize();
184
185 SDL_Quit();
186 return 0;
187 }
188
189
190 #ifdef WIN32
191 /**
192 * MS Windows entry point (See MSDN for more information)
193 */
WinMain(HINSTANCE,HINSTANCE,LPSTR,int)194 int APIENTRY WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nCmdShow*/)
195 {
196 #ifndef NDEBUG
197 //Create console for debug session
198 if (!AttachConsole(ATTACH_PARENT_PROCESS))
199 AllocConsole();
200 freopen("CONOUT$", "wb", stdout);
201 freopen("CONOUT$", "wb", stderr);
202 #endif //NDEBUG
203
204 const int rc = main(__argc, __argv);
205
206 #ifndef NDEBUG
207 FreeConsole();
208 #endif //NDEBUG
209
210 return rc;
211 }
212 #endif // WIN32
213
214
parse_cmd_params(int argc,char * argv[],unsigned long & lvl_id,level::size & lvl_sz,bool & lvl_wrap)215 bool parse_cmd_params(int argc, char* argv[], unsigned long& lvl_id, level::size& lvl_sz, bool& lvl_wrap)
216 {
217 bool app_exit = false;
218
219 lvl_id = 0;
220 lvl_sz = level::sz_normal;
221 lvl_wrap = true;
222
223 for (int i = 1 /* skip executable file name */; !app_exit && i < argc; ++i) {
224 const char* param_val = argv[i];
225 while (*param_val && (*param_val == '-' || *param_val == '/'))
226 ++param_val;
227 if (strcmp(param_val, "help") == 0 || strcmp(param_val, "?") == 0) {
228 const char* msg =
229 "Command line parameters:\n"
230 " -help: this help\n"
231 " -version: show information about version\n"
232 " -id: start level with specified id (number from 1 to 99999999)\n"
233 " -wrap: set wrap mode (0: disable, 1: enable (default))\n"
234 " -size: set level map size (small, normal (default), big or extra)\n"
235 "\nUsage example:\n"
236 " pipewalker -id=1234 -wrap=0 -size=big\n";
237 #ifdef WIN32
238 MessageBoxA(NULL, msg, "PipeWalker " PACKAGE_VERSION, MB_OK | MB_ICONINFORMATION);
239 #else
240 printf("PipeWalker version " PACKAGE_VERSION "\n");
241 printf(msg);
242 #endif // WIN32
243 app_exit = true;
244 }
245 else if (strcmp(param_val, "version") == 0) {
246 #ifdef WIN32
247 MessageBoxA(NULL, "PipeWalker version " PACKAGE_VERSION, "PipeWalker " PACKAGE_VERSION, MB_OK | MB_ICONINFORMATION);
248 #else
249 printf("PipeWalker version " PACKAGE_VERSION "\n");
250 #endif // WIN32
251 app_exit = true;
252 }
253 else if (strcmp(param_val, "debug") == 0)
254 settings::debug_mode(true);
255 else if (strncmp(param_val, "id=", sizeof("id=") - 1) == 0) {
256 lvl_id = static_cast<unsigned long>(atoi(param_val + sizeof("id=") - 1));
257 if (lvl_id > PW_MAX_LEVEL_NUMBER)
258 lvl_id = 0;
259 }
260 else if (strncmp(param_val, "wrap=", sizeof("wrap=") - 1) == 0)
261 lvl_wrap = *(param_val + sizeof("id=") - 1) && atoi(param_val + sizeof("id=") - 1) != 0;
262 else if (strncmp(param_val, "size=", sizeof("size=") - 1) == 0) {
263 const char* level_size = param_val + sizeof("size=") - 1;
264 if (strcmp(level_size, "small") == 0)
265 lvl_sz = level::sz_small;
266 else if (strcmp(level_size, "normal") == 0)
267 lvl_sz = level::sz_normal;
268 else if (strcmp(level_size, "big") == 0)
269 lvl_sz = level::sz_big;
270 else if (strcmp(level_size, "extra") == 0)
271 lvl_sz = level::sz_extra;
272 }
273 }
274
275 return app_exit;
276 }
277
278
timer_callback(Uint32 interval)279 Uint32 timer_callback(Uint32 interval)
280 {
281 if (game::instance().need_redisplay()) {
282 //draw_scene();
283 SDL_Event expose_event;
284 expose_event.type = SDL_VIDEOEXPOSE;
285 SDL_PushEvent(&expose_event);
286 }
287 return interval;
288 }
289
290
291 #ifdef WIN32
pw_win32_wnd_proc(HWND wnd,UINT msg,WPARAM w_param,LPARAM l_param)292 LRESULT pw_win32_wnd_proc(HWND wnd, UINT msg, WPARAM w_param, LPARAM l_param)
293 {
294 assert(sdl_wnd_proc);
295
296 if (msg == WM_GETMINMAXINFO) {
297 static LONG max_width = 0;
298 static LONG max_height = 0;
299 if (!max_height) {
300 max_height = GetSystemMetrics(SM_CYMAXIMIZED);
301 //Calculate correct aspect ratio
302 RECT aspect;
303 aspect.top = aspect.left = 0;
304 aspect.right = PW_SCREEN_WIDTH;
305 aspect.bottom = PW_SCREEN_HEIGHT;
306 AdjustWindowRectEx(&aspect, GetWindowLongPtr(wnd, GWL_STYLE), FALSE, GetWindowLongPtr(wnd, GWL_EXSTYLE));
307 const float need_aspect = static_cast<float>(aspect.bottom - aspect.top) / static_cast<float>(aspect.right - aspect.left);
308 max_width = static_cast<LONG>(static_cast<float>(max_height) / need_aspect);
309 }
310
311 LPMINMAXINFO mmi = reinterpret_cast<LPMINMAXINFO>(l_param);
312 mmi->ptMaxSize.x = mmi->ptMaxTrackSize.x = max_width;
313 mmi->ptMaxSize.y = mmi->ptMaxTrackSize.y = max_height;
314 mmi->ptMinTrackSize.x = PW_SCREEN_WIDTH / 3;
315 mmi->ptMinTrackSize.y = PW_SCREEN_HEIGHT / 3;
316 return 0;
317 }
318
319 return CallWindowProc(sdl_wnd_proc, wnd, msg, w_param, l_param);
320 }
321 #endif // WIN32
322