Save screenshots as PNG instead of BMP. (Code from rlk, I'm just improvising.)
[neverball] / ball / main.c
1 /*   
2  * Copyright (C) 2003 Robert Kooima
3  *
4  * NEVERBALL is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14
15 /*---------------------------------------------------------------------------*/
16
17 #ifdef WIN32
18 #pragma comment(lib, "SDL_ttf.lib")
19 #pragma comment(lib, "SDL_mixer.lib")
20 #pragma comment(lib, "SDL_image.lib")
21 #pragma comment(lib, "SDL.lib")
22 #pragma comment(lib, "SDLmain.lib")
23 #pragma comment(lib, "opengl32.lib")
24 #endif
25
26 /*---------------------------------------------------------------------------*/
27
28 #include <SDL.h>
29 #include <SDL_image.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <errno.h>
33
34 #include "glext.h"
35 #include "config.h"
36 #include "image.h"
37 #include "audio.h"
38 #include "demo.h"
39 #include "levels.h"
40 #include "game.h"
41 #include "gui.h"
42 #include "set.h"
43
44 #include "st_conf.h"
45 #include "st_title.h"
46 #include "st_demo.h"
47 #include "st_level.h"
48
49 #define TITLE "Neverball"
50 #define VERSION "1.4.1svn"
51
52 /*---------------------------------------------------------------------------*/
53
54 static void shot(void)
55 {
56     static char filename[MAXSTR];
57     static int  num = 0;
58
59     sprintf(filename, _("screen%02d.png"), num++);
60
61     image_snap(filename, config_get_d(CONFIG_WIDTH), config_get_d(CONFIG_HEIGHT));
62 }
63
64 /*---------------------------------------------------------------------------*/
65
66 static void toggle_wire(void)
67 {
68     static int wire = 0;
69
70     if (wire)
71     {
72         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
73         glEnable(GL_TEXTURE_2D);
74         glEnable(GL_LIGHTING);
75         wire = 0;
76     }
77     else
78     {
79         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
80         glDisable(GL_TEXTURE_2D);
81         glDisable(GL_LIGHTING);
82         wire = 1;
83     }
84 }
85
86 static void toggle_fullscreen(void)
87 {
88     int x, y;
89     SDL_GetMouseState(&x, &y);
90     config_mode(!config_get_d(CONFIG_FULLSCREEN), config_get_d(CONFIG_WIDTH), config_get_d(CONFIG_HEIGHT));
91     SDL_WarpMouse(x, y);
92 }
93
94
95 /*---------------------------------------------------------------------------*/
96
97 static int loop(void)
98 {
99     SDL_Event e;
100     int d = 1;
101
102     while (d && SDL_PollEvent(&e))
103     {
104         if (e.type == SDL_QUIT)
105             return 0;
106
107         if (e.type == SDL_KEYDOWN)
108             switch (e.key.keysym.sym)
109             {
110             case SDLK_SPACE: config_tgl_pause();        break;
111             case SDLK_F11:   toggle_fullscreen();       break;
112             case SDLK_F10:   shot();                    break;
113             case SDLK_F9:    config_tgl_d(CONFIG_FPS);  break;
114             case SDLK_F8:    config_tgl_d(CONFIG_NICE); break;
115             case SDLK_F7:    toggle_wire();             break;
116             default: break;
117             }
118
119         if (!config_get_pause())
120             switch (e.type)
121             {
122             case SDL_MOUSEMOTION:
123                 st_point(+e.motion.x,
124                          -e.motion.y + config_get_d(CONFIG_HEIGHT),
125                          +e.motion.xrel,
126                          config_get_d(CONFIG_MOUSE_INVERT)
127                          ? +e.motion.yrel : -e.motion.yrel);
128                 break;
129
130             case SDL_MOUSEBUTTONDOWN:
131                 d = st_click((e.button.button == SDL_BUTTON_LEFT) ? -1 : 1, 1);
132                 break;
133                 
134             case SDL_MOUSEBUTTONUP:
135                 d = st_click((e.button.button == SDL_BUTTON_LEFT) ? -1 : 1, 0);
136                 break;
137
138             case SDL_KEYDOWN:
139                 
140                 switch (e.key.keysym.sym)
141                 {
142                 
143                 case SDLK_RETURN:
144                     d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_A), 1);
145                     break;
146                 case SDLK_ESCAPE:
147                     d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_EXIT), 1);
148                     break;
149                 case SDLK_LEFT:
150                     st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), -JOY_MAX);
151                     break;
152                 case SDLK_RIGHT:
153                     st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), +JOY_MAX);
154                     break;
155                 case SDLK_UP:
156                     st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), -JOY_MAX);
157                     break;
158                 case SDLK_DOWN:
159                     st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), +JOY_MAX);
160                     break;
161                              
162                 default:
163                     if (SDL_EnableUNICODE(-1)) 
164                         d = st_keybd(e.key.keysym.unicode, 1);
165                     else
166                         d = st_keybd(e.key.keysym.sym, 1);
167                 }
168                 break;
169
170             case SDL_KEYUP:
171
172                 switch (e.key.keysym.sym)
173                 {
174                 case SDLK_RETURN:
175                     d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_A), 0);
176                     break;
177                 case SDLK_ESCAPE:
178                     d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_EXIT), 0);
179                     break;
180                 case SDLK_LEFT:
181                 case SDLK_RIGHT:
182                     st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), 1);
183                     break;
184                 case SDLK_DOWN:
185                 case SDLK_UP:
186                     st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), 1);
187                     break;
188
189                 default:
190                     d = st_keybd(e.key.keysym.sym, 0);
191                 }
192
193                 break;
194
195             case SDL_ACTIVEEVENT:
196                 if (e.active.state == SDL_APPINPUTFOCUS)
197                     if (e.active.gain == 0 && config_get_grab())
198                         config_set_pause();
199                 break;
200
201             case SDL_JOYAXISMOTION:
202                 st_stick(e.jaxis.axis, e.jaxis.value);
203                 break;
204
205             case SDL_JOYBUTTONDOWN:
206                 d = st_buttn(e.jbutton.button, 1);
207                 break;
208
209             case SDL_JOYBUTTONUP:
210                 d = st_buttn(e.jbutton.button, 0);
211                 break;
212             }
213     }
214     return d;
215 }
216
217 /*---------------------------------------------------------------------------*/
218
219 /* Option values */
220 static char *data_path    = NULL;
221 static char *replay_path  = NULL;
222 static char *level_path   = NULL;
223 static int   display_info = 0;
224
225 /* Option hangling */
226
227 #define USAGE  _( \
228         "Usage: %s [options ...]\n" \
229         "-r, --replay file         play the replay 'file'.\n" \
230         "-l, --level file.sol      play the level 'file.sol'.\n" \
231         "-i, --info                display info about level or replay.\n" \
232         "    --data dir            use 'dir' as game data directory.\n" \
233         "-v, --version             show version.\n" \
234         "-h, -?, --help            show this usage message.\n")
235
236 static void parse_args(int argc, char ** argv)
237 {
238 #define CASE(x) (strcmp(*argv, (x)) == 0)        /* Check current option */
239 #define MAND    (not_miss = (argv[1] != NULL))   /* Argument is mandatory */
240     char * exec = *(argv++);
241     int not_miss; /* argument is not missing */
242     
243     while (*argv != NULL)
244     {
245         not_miss = 1;
246         if (CASE("-h") || CASE("-?") || CASE("--help"))
247         {
248             printf(USAGE, exec);
249             exit(0);
250         }
251         else if (CASE("-v") || CASE("--version"))
252         {
253             printf(_("%s: %s version %s\n"), exec, TITLE, VERSION);
254             exit(0);
255         }
256         else if (CASE("--data") && MAND)
257             data_path = *(++argv);
258         else if ((CASE("-r") || CASE("--replay")) && MAND)
259             replay_path = *(++argv);
260         else if ((CASE("-l")  || CASE("--level")) && MAND)
261             level_path = *(++argv);
262         else if ((CASE("-i")  || CASE("--info")))
263             display_info = 1;
264         else if (not_miss)
265         {
266             fprintf(stderr, _("%s: unknown option %s\n"), exec, *argv);
267             fprintf(stderr, USAGE, exec);
268             exit(1);
269         }
270         else
271         {
272             fprintf(stderr, _("%s: option %s requires an argument\n"), exec, *argv);
273             fprintf(stderr, USAGE, exec);
274             exit(1);
275         }
276         argv++;
277     }
278     return;
279 }
280
281 int main(int argc, char *argv[])
282 {
283     SDL_Joystick *joy = NULL;
284     int t1, t0;               /* ticks */
285     SDL_Surface *icon;        /* WM icon */
286    
287     language_init("neverball", CONFIG_LOCALE);
288
289     parse_args(argc, argv);
290     
291     if (!config_data_path(data_path, SET_FILE))
292     {
293         fprintf(stderr, _("Failure to establish game data directory\n"));
294         return 1;
295     }
296     
297     if (!config_user_path(NULL))
298     {
299         fprintf(stderr, _("Failure to establish config directory\n"));
300         return 1;
301     }
302     
303     /* Intitialize the configuration */
304     
305     config_init();
306     config_load();
307     
308     /* Initialize the language */
309     
310     language_set(language_from_code(config_simple_get_s(CONFIG_LANG)));
311
312     /* Prepare run without sdl */
313     
314     if (replay_path != NULL)
315     {
316         if (! level_replay(replay_path))
317         {
318             fprintf(stderr, _("Replay file '%s': "), replay_path);
319             if (errno)
320                 perror(NULL);
321             else
322                 fprintf(stderr, _("Not a replay file\n"));
323             return 1;
324         }
325         else if (display_info)
326             demo_replay_dump_info();
327     }
328     
329     if (level_path != NULL)
330     {
331         struct level l;
332         if (! level_load(level_path, &l))
333             return 1;
334         else if (display_info)
335             level_dump_info(&l);
336     }
337
338     if(display_info)
339     {
340         if (replay_path == NULL && level_path == NULL)
341         {
342             fprintf(stderr, _("%s: --info requires --replay or --level\n"), argv[0]);
343             return 1;
344         }
345         else
346            return 0;
347     }
348     
349     /* Initialize SDL system and subsystems */
350     
351     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) == -1)
352     {
353         fprintf(stderr, "%s\n", SDL_GetError());
354         return 1;
355     }
356
357     /* Initialize the joystick. */
358
359     if (SDL_NumJoysticks() > 0)
360     {
361         joy=SDL_JoystickOpen(config_get_d(CONFIG_JOYSTICK_DEVICE));
362         if (joy)
363                 SDL_JoystickEventState(SDL_ENABLE);
364     }
365
366     /* Initialize the audio. */
367
368     audio_bind(AUD_MENU,   3, "snd/menu.wav");
369     audio_bind(AUD_START,  1, "snd/select.ogg");
370     audio_bind(AUD_READY,  1, "snd/ready.ogg");
371     audio_bind(AUD_SET,    1, "snd/set.ogg");
372     audio_bind(AUD_GO,     1, "snd/go.ogg");
373     audio_bind(AUD_BALL,   2, "snd/ball.ogg");
374     audio_bind(AUD_BUMP,   3, "snd/bump.ogg");
375     audio_bind(AUD_COIN,   2, "snd/coin.wav");
376     audio_bind(AUD_TICK,   4, "snd/tick.ogg");
377     audio_bind(AUD_TOCK,   4, "snd/tock.ogg");
378     audio_bind(AUD_SWITCH, 5, "snd/switch.wav");
379     audio_bind(AUD_JUMP,   5, "snd/jump.ogg");
380     audio_bind(AUD_GOAL,   5, "snd/goal.wav");
381     audio_bind(AUD_SCORE,  1, "snd/record.ogg");
382     audio_bind(AUD_FALL,   1, "snd/fall.ogg");
383     audio_bind(AUD_TIME,   1, "snd/time.ogg");
384     audio_bind(AUD_OVER,   1, "snd/over.ogg");
385
386     audio_init();
387
388     /* Require 16-bit double buffer with 16-bit depth buffer. */
389
390     SDL_GL_SetAttribute(SDL_GL_RED_SIZE,     5);
391     SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,   5);
392     SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,    5);
393     SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,  16);
394     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
395
396     /* Initialize the video. */
397
398     if (! config_mode(config_get_d(CONFIG_FULLSCREEN),
399                     config_get_d(CONFIG_WIDTH),
400                     config_get_d(CONFIG_HEIGHT)))
401     {
402         fprintf(stderr, "%s\n", SDL_GetError());
403         return 1;
404     }
405    
406     /* Set the WM icon */ 
407     
408     icon = IMG_Load(config_data("icon/neverball.png"));
409     SDL_WM_SetIcon(icon, NULL);
410     SDL_WM_SetCaption(TITLE, TITLE); 
411
412     /* Initialize the run state. */
413     
414     init_state(&st_null);
415     if (replay_path != NULL)
416     {
417         level_replay(replay_path);
418         goto_demo_play(1);
419     }
420     else if (level_path != NULL)
421     {
422         level_play_single(level_path);
423         goto_state(&st_level);
424     }
425     else
426         goto_state(&st_title);
427
428     /* Run the main game loop. */
429
430     t0 = SDL_GetTicks();
431     while (loop())
432         if ((t1 = SDL_GetTicks()) > t0)
433         {
434             if (config_get_pause())
435             {
436                 st_paint();
437                 gui_blank();
438                 SDL_Delay(10); /* Be nice! */
439             }
440             else
441             {
442                 st_timer((t1 - t0) / 1000.f);
443                 st_paint();
444             }
445             SDL_GL_SwapBuffers();
446
447             t0 = t1;
448
449             if (config_get_d(CONFIG_NICE))
450                 SDL_Delay(1);
451         }
452
453     /* Gracefully close the game */
454
455     if (SDL_JoystickOpened(0))
456         SDL_JoystickClose(joy);
457
458     SDL_Quit();
459     
460     config_save();
461     
462     return 0;
463 }
464
465 /*---------------------------------------------------------------------------*/
466