1 /*
2  *  JLib - Jacob's Library.
3  *  Copyright (C) 2003, 2004  Juan Carlos Seijo P�rez
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Library General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 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  *  Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Library General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *  Juan Carlos Seijo P�rez
20  *  jacob@mainreactor.net
21  */
22 
23 /** Base application class. Allows to init SDL and the other subsystems as sound.
24  * @file    JApp.h
25  * @author  Juan Carlos Seijo P�rez
26  * @date    01/04/2003
27  * @version 0.0.1 - First version - 01/04/2003
28  */
29 
30 #ifndef _JAPP_INCLUDED
31 #define _JAPP_INCLUDED
32 
33 #include <JLib/Util/JTypes.h>
34 #include <JLib/Util/JString.h>
35 #include <JLib/Util/JTimer.h>
36 #include <JLib/Graphics/JFont.h>
37 #include <JLib/Sound/JMixer.h>
38 #include <SDL.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 
42 #ifdef _WIN32
43 #else
44 #include <unistd.h>
45 #define _sleep sleep
46 #endif
47 
48 /** Application base class. You should inherit from this class and override
49  * the Update and Draw methods to create an application. The following example
50  * creates a 400x300 window and fills the window with a diferent color each frame:
51  * You can try to execute it with the '-h' option to see what standard parameters a JApp
52  * accepts by default.
53  * <pre>
54  *
55  * #include <JLib/Util/JApp.h>
56  * #include <SDL_keysym.h>
57  * #include <stdio.h>
58  *
59  * class MyApp : public JApp
60  * {
61  *   int myData;
62  *
63  * public:
64  *   MyApp() :   JApp("App window title", 400, 300, false, 16), myData(0)
65  *   {}
66  *
67  *   bool Update()
68  *   {
69  *     UpdateEvents();
70  *
71  *     ++myData;
72  *     if (Keys()[SDLK_ESCAPE] != 0)
73  *     {
74  *       Exit();
75  *     }
76  *   }
77  *
78  *   bool Draw() {SDL_FillRect(screen, 0, myData); Flip();}
79  * };
80  *
81  * int main(int argc, char **argv)
82  * {
83  *   MyApp app;
84  *
85  *   // Optionally, parses the command line
86  *   app.ParseArgs(argc, argv);
87  *
88  *   // Initializes SDL.
89  *   if (!app.Init())
90  *   {
91  *     printf("Error initializing app.\n");
92  *     return -1;
93  *   }
94  *
95  *   // The aplication stays here until Exit() is called.
96  *   return app.MainLoop();
97  * }
98  *
99  * </pre>
100  */
101 class JApp
102 {
103 protected:
104   bool active;                    /**< Is the application active (first plane)? */
105   bool paused;                    /**< Is paused the application? */
106   bool endLoop;                   /**< Must exit the app? */
107   JString title;                  /**< Window title */
108   s32 width;                      /**< Window width */
109   s32 height;                     /**< Window height */
110   s32 depth;                      /**< Color depth */
111   bool fullScreen;                /**< Fullscreen flag */
112   bool doInput;                   /**< Must capture events (keyboard, mouse, WM)? */
113   u32 flags;                      /**< SDL additional flags */
114   u32 appPauseTime;               /**< Time at which the application is paused */
115 	u8 *keys;                       /**< Keyboard state */
116 	SDLMod keyMods;                 /**< Key modifiers state (Shift, Ctrl, etc.) */
117 	s32 numKeys;                    /**< Number of keyboard keys */
118 	s32 mouseX;                     /**< Mouse X position */
119 	s32 mouseY;                     /**< Mouse Y position */
120 	u8 mouseBt;                     /**< Mouse button mask */
121 	s32 mouseRelX;                  /**< Mouse X relative increment */
122 	s32 mouseRelY;                  /**< Mouse Y relative increment */
123 	s16 joyAxisX;                   /**< Joystick X offset */
124 	s16 joyAxisY;                   /**< Joystick Y offset */
125 	u8 joyButton;                   /**< Joystick button */
126 	JTimer timer;                   /**< Application timer */
127 	s32 fps;                        /**< Frames per second */
128 	bool dumpVideoInfo;             /**< Must dump video info at init? */
129 
130 	JMixer mixer;                   /**< Audio mixer */
131 	bool soundEnabled;              /**< Is sound enabled? */
132 
133 	char *iconName;                 /**< Application icon filename */
134 
135 	static JApp* thisApp;           /**< Pointer to this application */
136 
137   void (*__OnActive)(bool active, s32 state);                         /**< Active event callback */
138   void (*__OnKeyUp )(SDL_keysym key);                                 /**< Key up event callback */
139   void (*__OnKeyDown)(SDL_keysym key);                                /**< Key down event callback */
140   void (*__OnMouseMove)(s32 x, s32 y, s32 bt, s32 xRel, s32 yRel);    /**< Mouse move event callback */
141   void (*__OnMouseDown)(s32 bt, s32 x, s32 y);                        /**< Mouse button down event callback */
142   void (*__OnMouseUp)(s32 bt, s32 x, s32 y);                          /**< Mouse button up event callback */
143   void (*__OnJoyMove)(s32 joyNum, s32 axis, s32 value);               /**< Joystick move event callback */
144   void (*__OnJoyBall)(s32 joyNum, s32 ballIndex, s32 xRel, s32 yRel); /**< Joystick ball event callback */
145   void (*__OnJoyHat)(s32 joyNum, s32 hatIndex, s32 value);            /**< Joystick hat event callback */
146   void (*__OnJoyUp)(s32 joyNum, s32 btIndex);                         /**< Joystick button up event callback */
147   void (*__OnJoyDown)(s32 joyNum, s32 btIndex);                       /**< Joystick button down event callback */
148   void (*__OnQuit)();                                                 /**< Quit event callback */
149   void (*__OnSysWM)();                                                /**< Window manager event callback */
150   void (*__OnResize)(s32 w, s32 h);                                   /**< Resize event callback */
151   void (*__OnExpose)();                                               /**< Window exposure (unhide) event callback */
152   void (*__OnUser)(s32 code, void *data1, void *data2);               /**< User event callback */
153 
154   SDL_Surface *screen;            /**< Primary surface as of SDL_GetVideoSurface() */
155   SDL_Joystick *joystick;         /**< Joystick device */
156 
157 public:
158   /** Creates the application. The audio mixer must be initialized in the child class.
159    * @param  strTitle Window title.
160    * @param  w Window width.
161    * @param  h Window height.
162    * @param  fullScr Fullscreen flag.
163    * @param  _depth Bits per pixel (color depth, 8, 16, 24, 32, etc.)
164    * @param  otherFlags SDL Additional flags
165    */
166   JApp(const JString& strTitle, s32 w = 1024, s32 h = 768, bool fullScr = true, s32 _depth = 16, u32 otherFlags = 0);
167 
168   /** Checks for events to process. In case the associated callback is registered, calls it.
169    * @return <b>true</b> if event polling succeded, <b>false</b> if not.
170    */
171   virtual bool UpdateEvents();
172 
173   /** Initializes the app. Creates the window with the paraameters given at construction time.
174    * Normally the child application class overrides this method to initialize its objects and calls the parent (this class)
175    * to do the SDL initialization stuff.
176    * @return <b>true</b> if the creation succeded <b>false</b> if not.
177    */
178   virtual bool Init();
179 
180   /** Updates the application objects (graphics, sounds, A.I., etc.). Must be implemented in the child class.
181    * JApp will call this method before Draw in the child class (by means of MainLoop().
182    * @return <b>true</b> if success, <b>false</b> else.
183    */
184   virtual bool Update() = 0;
185 
186   /** Draws the application. As Update(), must be implemented in the child class.
187    * @return <b>true</b> if ok, <b>false</b> else.
188    */
189   virtual bool Draw() = 0;
190 
191 	/** Main loop. The default implementation calls Update() and if it succeded then calls Draw. The application remains
192    * here until Exit() is called or Update() or Draw() fail.
193    * @return Application exit code.
194    */
195 	virtual s32 MainLoop();
196 
197   /** Returns the window width.
198    * @return Window width.
199    */
Width()200   s32 Width() {return width;}
201 
202   /** Returns the window height.
203    * @return Window Height.
204    */
Height()205   s32 Height() {return height;}
206 
207   /** Changes the window size.
208    * @param  w New width.
209    * @param  h New height.
210    * @param  _fullScreen <b>true</b> if the app must be fullscreen, <b>false</b> if windowed.
211    */
212   void Resize(s32 w, s32 h, bool _fullScreen);
213 
214   /** Returns the fullscreen flag.
215    * @return <b>true</b> if fullscreen, <b>false</b> if windowed.
216    */
IsFullscreen()217   bool IsFullscreen() {return fullScreen;}
218 
219   /** Returns the color depth.
220    * @return Color depth in bits (normally 8, 16, 24 or 32).
221    */
Depth()222   s32 Depth() {return depth;}
223 
224   /** Ends the application, exiting from the main loop.
225    */
Exit()226   void Exit() {endLoop = true;}
227 
228   /** Returns the active flag.
229    * @return <b>true</b> if the application is active (foreground) <b>false</b> if not.
230    */
IsActive()231   bool IsActive() {return active;}
232 
233   /** Returns the pause state of the application.
234    * @return <b>true</b> if paused <b>false</b> otherwise.
235    */
IsPaused()236   bool IsPaused() {return paused;}
237 
238   /** Pauses or resumes the application.
239    * @param  doPause <b>true</b> pauses the application, <b>false</b> resumes.
240    * @return if pausing (doPause is <b>true</b>), returns the number
241    * of milliseconds from the start of the application. If resuming,
242    * (doPause <b>false</b>), returns the number of milliseconds
243    * during pause mode.
244    */
245   u32 Pause(bool doPause);
246 
247   /** Returns the window title.
248    * @return Window title.
249    */
Title()250   const JString &Title() {return title;}
251 
252   /** Sets the window title.
253    * @param  newTitle New window title..
254    */
Title(JString & newTitle)255   void Title(JString &newTitle) {title = newTitle; SDL_WM_SetCaption(title, 0);}
256 
257   /** Returns the execution time in milliseconds.
258    * @return Execution time in milliseconds.
259    */
AppTime()260   u32 AppTime() {return SDL_GetTicks();}
261 
262   /** Returns the main SDL surface. The surface is created after Init()
263    * @return SDL main surface.
264    */
Screen()265   SDL_Surface * Screen() {return screen;}
266 
267   /** Establishes if events must be captured.
268    * @param  b <b>true</b> if they must be <b>false</b> otherwise.
269    */
DoInput(bool b)270   void DoInput(bool b) {doInput = b;}
271 
272   /** Determines if events must be captured.
273    * @return <b>true</b> if so <b>false</b> if not.
274    */
DoInput()275   bool DoInput() {return doInput;}
276 
277   /** Sets the active event callback.
278 	 * @param _OnActive Callback.
279 	 */
SetOnActive(void (* _OnActive)(bool active,s32 state))280   void SetOnActive    (void (*_OnActive)(bool active, s32 state))
281 	{__OnActive = _OnActive;}
282 
283   /** Sets the kay up event callback.
284 	 * @param  _OnKeyUp Callback.
285 	 */
SetOnKeyUp(void (* _OnKeyUp)(SDL_keysym key))286   void SetOnKeyUp     (void (*_OnKeyUp )(SDL_keysym key))
287 	{__OnKeyUp  = _OnKeyUp ;}
288 
289   /** Sets the key down event callback.
290 	 * @param  _OnKeyDown Callback.
291 	 */
SetOnKeyDown(void (* _OnKeyDown)(SDL_keysym key))292   void SetOnKeyDown   (void (*_OnKeyDown)(SDL_keysym key))
293 	{__OnKeyDown = _OnKeyDown;}
294 
295   /** Sets the mouse move event callback.
296 	 * @param  _OnMouseMove Callback.
297 	 */
SetOnMouseMove(void (* _OnMouseMove)(s32 x,s32 y,s32 bt,s32 xRel,s32 yRel))298   void SetOnMouseMove (void (*_OnMouseMove)(s32 x, s32 y, s32 bt, s32 xRel, s32 yRel))
299 	{__OnMouseMove = _OnMouseMove;}
300 
301   /** Sets the mouse button down event callback.
302 	 * @param  _OnMouseDown Callback.
303 	 */
SetOnMouseDown(void (* _OnMouseDown)(s32 bt,s32 x,s32 y))304   void SetOnMouseDown (void (*_OnMouseDown)(s32 bt, s32 x, s32 y))
305 	{__OnMouseDown = _OnMouseDown;}
306 
307   /** Sets the mouse button up event callback.
308 	 * @param  _OnMouseUp Callback.
309 	 */
SetOnMouseUp(void (* _OnMouseUp)(s32 bt,s32 x,s32 y))310   void SetOnMouseUp   (void (*_OnMouseUp)(s32 bt, s32 x, s32 y))
311 	{__OnMouseUp = _OnMouseUp;}
312 
313   /** Sets the joystick move event callback.
314 	 * @param  _OnJoyMove Callback.
315 	 */
SetOnJoyMove(void (* _OnJoyMove)(s32 joyNum,s32 axis,s32 value))316   void SetOnJoyMove   (void (*_OnJoyMove)(s32 joyNum, s32 axis, s32 value))
317 	{__OnJoyMove = _OnJoyMove;}
318 
319   /** Sets the joystick ball event callback.
320 	 * @param  _OnJoyBall Callback.
321 	 */
SetOnJoyBall(void (* _OnJoyBall)(s32 joyNum,s32 ballIndex,s32 xRel,s32 yRel))322   void SetOnJoyBall   (void (*_OnJoyBall)(s32 joyNum, s32 ballIndex, s32 xRel, s32 yRel))
323 	{__OnJoyBall = _OnJoyBall;}
324 
325   /** Sets the joystick hat event callback.
326 	 * @param  _OnJoyHat Callback.
327 	 */
SetOnJoyHat(void (* _OnJoyHat)(s32 joyNum,s32 hatIndex,s32 value))328   void SetOnJoyHat    (void (*_OnJoyHat)(s32 joyNum, s32 hatIndex, s32 value))
329 	{__OnJoyHat = _OnJoyHat;}
330 
331   /** Sets the joystick button up event callback.
332 	 * @param  _OnJoyUp Callback.
333 	 */
SetOnJoyUp(void (* _OnJoyUp)(s32 joyNum,s32 btIndex))334   void SetOnJoyUp     (void (*_OnJoyUp)(s32 joyNum, s32 btIndex))
335 	{__OnJoyUp = _OnJoyUp;}
336 
337   /** Sets the joystick button down event callback.
338 	 * @param  _OnJoyDown Callback.
339 	 */
SetOnJoyDown(void (* _OnJoyDown)(s32 joyNum,s32 btIndex))340   void SetOnJoyDown   (void (*_OnJoyDown)(s32 joyNum, s32 btIndex))
341 	{__OnJoyDown = _OnJoyDown;}
342 
343   /** Sets the quit event callback.
344 	 * @param  _OnQuit Callback.
345 	 */
SetOnQuit(void (* _OnQuit)())346   void SetOnQuit      (void (*_OnQuit)())
347 	{__OnQuit = _OnQuit;}
348 
349   /** Sets the window manager event callback.
350 	 * @param  _OnSysWM Callback.
351 	 */
SetOnSysWM(void (* _OnSysWM)())352   void SetOnSysWM     (void (*_OnSysWM)())
353 	{__OnSysWM = _OnSysWM;}
354 
355   /** Sets the resize event callback.
356 	 * @param  _OnResize Callback.
357 	 */
SetOnResize(void (* _OnResize)(s32 w,s32 h))358   void SetOnResize    (void (*_OnResize)(s32 w, s32 h))
359 	{__OnResize = _OnResize;}
360 
361   /** Sets the video expose event callback.
362 	 * @param  _OnExpose Callback.
363 	 */
SetOnExpose(void (* _OnExpose)())364   void SetOnExpose    (void (*_OnExpose)())
365 	{__OnExpose = _OnExpose;}
366 
367   /** Sets the user event callback.
368 	 * @param  _OnUser Callback.
369 	 */
SetOnUser(void (* _OnUser)(s32 code,void * data1,void * data2))370   void SetOnUser(void (*_OnUser)(s32 code, void *data1, void *data2))
371 	{__OnUser = _OnUser;}
372 
373   /** Returns mouse X position.
374 	 * @return Mouse X position.
375 	 */
MouseX()376 	s32 MouseX() {return mouseX;}
377 
378   /** Returns mouse Y position.
379 	 * @return Mouse Y position.
380 	 */
MouseY()381 	s32 MouseY() {return mouseY;}
382 
383 	/** Returns the relative X mouse position (since the last move).
384 	 * @return Relative X mouse position.
385 	 */
MouseRelX()386 	s32 MouseRelX() {return mouseRelX;}
387 
388 	/** Returns the relative Y mouse position (since the last move).
389 	 * @return Relative Y mouse position.
390 	 */
MouseRelY()391 	s32 MouseRelY() {return mouseRelY;}
392 
393 	/** Returns the mouse button press mask.
394 	 * @return Mouse button state mask.
395 	 */
MouseBt()396 	u8 MouseBt() {return mouseBt;}
397 
398 	/** Returns the keyboard key state. The state for a certain key is determined
399 	 * with Keys()[SDLK_XXX], where SDLK_XXX is the key to query.
400 	 * If the value is 0, the key is not pressed, else, it is pressed.
401 	 * @return Key state array.
402 	 */
Keys()403 	u8 * Keys() {return keys;}
404 
405 	/** Returns the key modifier mask. The bits of this mask are those for SDL
406 	 * KMOD_XXX, with XXX=LCTRL, LSHIFT, etc.
407 	 * @return Key modifiers bit mask.
408 	 */
KeyMods()409 	SDLMod KeyMods() {return keyMods;}
410 
411 	/** Returns the joystick X axis
412 	 * @return joystick X axis
413 	 */
JoystickX()414 	s16 JoystickX() {return joyAxisX;}
415 
416 	/** Returns the joystick Y axis
417 	 * @return joystick Y axis
418 	 */
JoystickY()419 	s16 JoystickY() {return joyAxisY;}
420 
421 	/** Returns the joystick buttonstate. Note: It does not differentiate between buttons.
422 	 * @return joystick button
423 	 */
JoystickButton()424 	u8 JoystickButton() {return joyButton;}
425 
426 	/** Updates the given region of the primary surface. If all parameters are 0,
427 	 * the whole window is updated. This is simply a wrapper for SDL_UpdateRect(...).
428 	 * @param  x X position of the rectangle to update.
429 	 * @param  y Y position of the rectangle to update.
430 	 * @param  w Width of the rectangle to update.
431 	 * @param  h Height of the rectangle to update..
432 	 */
UpdateRect(s32 x,s32 y,s32 w,s32 h)433 	void UpdateRect(s32 x, s32 y, s32 w, s32 h) {SDL_UpdateRect(screen, x, y, w, h);}
434 
435 	/** Update the given rects. As UpdateRect() is only a wrapper for SDL_UpdateRects().
436 	 * @param  num Number of rects to update.
437 	 * @param  rc Array with the rects to update.
438 	 */
UpdateRects(s32 num,SDL_Rect * rc)439 	void UpdateRects(s32 num, SDL_Rect *rc) {SDL_UpdateRects(screen, num, rc);}
440 
441 	/** Swaps front and back buffer (if SDL_DOUBLEBUF is used as flag during SDL initializacion)
442 	 * or updates the whole screen. This is a wrapper for SDL_Flip().
443 	 * @return <b>true</b> if ok, <b>false</b> if an error ocurred..
444 	 */
Flip()445 	bool Flip() {return -1 != SDL_Flip(screen);}
446 
447 	/** Returns the audio mixer. Must be initialized in the child class.
448 	 * @return Audio mixer.
449 	 */
Mixer()450 	JMixer & Mixer() {return mixer;}
451 
452 	/** Returns this application instance.
453 	 * @return Pointer to this application.
454 	 */
App()455 	static JApp * App() {return thisApp;}
456 
457 	/** Sets the number of frames per second (FPS). Its the maximum number of times Draw() is called per second.
458 	 * @param  newFPS New FPS value.
459 	 */
460 	void FPS(s32 newFPS);
461 
462 	/** Returns the FPS (frames per second). Its the maximum number of times Draw() is called per second.
463 	 * @return FPS value.
464 	 */
FPS()465 	s32 FPS() {return fps;}
466 
467 	/** Returns a pointer to the current video mode video info. Is Exactly a wrapper for SDL_GetVideoInfo().
468 	 * If called before Init() or Resize() it contains the 'best' intended video mode.
469 	 * @return Information about the current video mode or about the video system in general.
470 	 */
VideoInfo()471 	const SDL_VideoInfo *VideoInfo() {return SDL_GetVideoInfo();}
472 
473 	/** Show the video info in the standard output.
474 	 */
475 	void DumpVideoInfo();
476 
477 	/** Parses the application argument.
478 	 * @param  args Command line arguments.
479 	 * @param  argc Arguments left.
480 	 * @return Number of parameters used.
481 	 */
482 	virtual int ParseArg(char *args[], int argc);
483 
484 	/** Shows the usage string. It contains the default arguments a JApp can be passed.
485    * @param  program Program's name.
486 	 */
487 	virtual void PrintUsage(char *program);
488 
489 	/** Parses the application arguments.
490 	 * @param  argc Command line argument count.
491 	 * @param  argv Command line arguments.
492 	 */
493 	void ParseArgs(s32 argc, char **argv);
494 
495 	/** Enables or disables sound playback.
496    * @param  enable <b>true</b> if it must be enabled, <b>false</b> if not.
497 	 */
SoundEnabled(bool enable)498 	void SoundEnabled(bool enable) {soundEnabled = (enable && mixer.Valid());}
499 
500 	/** Shows or hides the mouse cursor.
501 	 * @param b <b>true</b> to show, <b>false</b> to hide.
502 	 */
MouseCursor(bool b)503 	void MouseCursor(bool b) {SDL_ShowCursor(b ? SDL_ENABLE : SDL_DISABLE);}
504 
505 	/** Returns the viewing state of the mouse cursor.
506 	 * @param b <b>true</b> if showing, <b>false</b> if not.
507 	 */
MouseCursor()508 	bool MouseCursor() {return SDL_ENABLE == SDL_ShowCursor(SDL_QUERY);}
509 
510 	/** Sets the file name of the icon to be used for the window. Must be called before init.
511 	 * In Windows must have exactly 32x32 pixels.
512 	 * @param  filename Filename of the icon, 0 to use the default icon.
513 	 */
514 	void Icon(const char *filename);
515 
516 	/** Returns the sound mixer state.
517 	 * @return <b>true</b> if active, <b>false</b> if not or the mixer couldn't be initialized properly.
518 	 * @see JMixer::Valid(), Mixer().
519 	 */
SoundEnabled()520 	bool SoundEnabled() {return soundEnabled;}
521 
522   /** Destroys this application, frees resources and quits the SDL subsystems initialized.
523    */
524   void Destroy();
525 
526   /** Destroys the object.
527    */
528   virtual ~JApp();
529 };
530 
531 #endif  // JAPP_INCLUDED
532