2 * Copyright (c) 2007-2013, Czirkos Zoltan http://code.google.com/p/gdash/
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 #ifndef GD_REPLAYSAVERACTIVITY
17 #define GD_REPLAYSAVERACTIVITY
20 /* the replay saver thing only works in the sdl version */
23 #include "framework/app.hpp"
24 #include "gfx/cellrenderer.hpp"
25 #include "sdl/sdlscreen.hpp"
26 #include "sdl/sdlpixbuffactory.hpp"
27 #include "cave/gamerender.hpp"
28 #include "gfx/fontmanager.hpp"
35 * This activity plays a replay, and saves every animation frame to
36 * a PNG file, along with the sound to a WAV file.
38 * This is implemented using a normal GameControl object, but it is given
39 * a special kind of Screen which can be saved to a PNG file. Also
40 * the normal sound stream is closed, and a special stream is requested
41 * from SDL with the dummy audio driver. A mixer callback func is also
42 * registered for SDL_Mixer, which will save the audio data.
44 * During saving the replay, the normal timer events which are forwarded
45 * from the App are not used for the timing of the cave. The mixer callback
46 * registered to SDL_Mixer also pushes SDL events (SDL_USEREVENT+1), which
47 * are then sent to App::timer2_event() in sdlmain.cpp. This is used
48 * to iterate the cave. The size of
49 * the sound buffer is set to hold 20ms of sound data, so SDL_Mixer is
50 * forced to generate us the events every 20ms - thus we can do an 50fps
53 * During saving the replay, the image is shown to the user, but it is not
54 * scaled, and there will be no sound. (As sound goes only to the memory
55 * and the WAV file.) This does not take too much CPU power; compressing
56 * the PNG files is eats much more.
58 * The whole thing only works in the SDL version, it is not implemented
59 * in the GTK game. Maybe it would be nice to put it in the GTK version
61 class ReplaySaverActivity
: public Activity
{
64 * The created Activity, when pushed, will start to record the replay.
65 * When finishing, it will automatically quit. There is no way for
66 * the user to cancel the saving.
67 * @param app The parent app.
68 * @param cave The cave which has the replay to record.
69 * @param replay The replay to record to the files.
70 * @param filename_prefix A filename prefix of the output files,
71 * to which .wav and _xxxxxx.png will be appended. */
72 ReplaySaverActivity(App
*app
, CaveStored
*cave
, CaveReplay
*replay
, std::string
const &filename_prefix
);
74 * Has many things to do - write a WAV header, reinstall the normal mixer etc. */
75 ~ReplaySaverActivity();
76 virtual void redraw_event();
78 * When the Activity is shown, it will install its own sound mixer. */
79 virtual void shown_event();
80 /** The timer2 event generated by the sound mixer will do the cave timing. */
81 virtual void timer2_event();
84 /** The SDL_Mixer post mixing callback, which saves the WAV file
85 * and sends SDL_USEREVENT+1-s to do the cave timing. */
86 static void mixfunc(void *udata
, Uint8
*stream
, int len
);
87 /** Save sound preferences of the user, restart the SDL audio subsystem
88 * with the required settings and install the mixer callbacks. */
89 void install_own_mixer();
90 /** Revert to the original sound preferences of the user. */
91 void uninstall_own_mixer();
93 /** Bytes written to the wav file. */
95 /** Number of image frames written. */
97 /** Sound settings reported by SDL. */
98 int frequency
, channels
, bits
;
99 std::string filename_prefix
;
100 /** The WAV file opened for writing. */
104 /** User's sound preference to be restored after replay saving. */
105 bool saved_gd_sdl_sound
;
106 /** User's sound preference to be restored after replay saving. */
107 bool saved_gd_sdl_44khz_mixing
;
108 /** User's sound preference to be restored after replay saving. */
109 bool saved_gd_sdl_16bit_mixing
;
110 /** User's sound preference to be restored after replay saving. */
111 bool saved_gd_show_name_of_game
;
112 /** User's sound preference to be restored after replay saving. */
113 bool saved_gd_sound_stereo
;
114 /** SDL sound environment variable saved, to be restored after replay saving. */
115 std::string saved_driver
;
117 /** This is a special SDL screen, which is a bitmap in memory.
118 * During the replay, the drawing routine draws on this, and it can be saved to disk. */
119 class SDLInmemoryScreen
: public SDLAbstractScreen
{
121 SDLInmemoryScreen() {}
122 virtual void set_title(char const *);
123 virtual void configure_size();
124 ~SDLInmemoryScreen();
125 void save(char const *filename
);
128 /** GameControl object which plays the replay. */
130 /** A PixbufFactory set to no scaling, no pal emulation. */
132 /** A font manager, which uses the pf PixbufFactory. */
134 /** A Screen, which is much like an image in memory, so it can be saved to PNG */
135 SDLInmemoryScreen pm
;
136 /** A CellRenderer needed by the GameControl object. */
137 CellRenderer cellrenderer
;
138 /** A GameRenderer, which will draw the cave. */
139 GameRenderer gamerenderer
;
142 #endif /* IFDEF HAVE_SDL */