Add pointlog2svg utility for the thesis
[numtypysics.git] / App.cpp
blob127a1fd02c655791a7923aac4f28bdde547863f3
1 /*
2 * This file is part of NumptyPhysics
3 * Copyright (C) 2008 Tim Edmonds
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
17 #include "Common.h"
18 #include "Array.h"
19 #include "Config.h"
20 #include "Game.h"
21 #include "Scene.h"
22 #include "Levels.h"
23 #include "Canvas.h"
24 #include "Ui.h"
26 #include "PythonInput.h"
28 #include <cstdio>
29 #include <string>
30 #include <sys/stat.h>
31 #include <SDL/SDL.h>
32 #include <SDL/SDL_mixer.h>
35 class App : private WidgetParent
37 int m_width;
38 int m_height;
39 bool m_rotate;
40 bool m_fullscreen;
41 bool m_thumbnailMode;
42 bool m_quit;
43 Array<const char*> m_files;
44 Array<Widget *> m_layers;
45 Window *m_window;
46 #ifdef HAVE_PYTHON
47 PythonInput *m_python_input;
48 #endif
49 public:
50 App(int argc, char** argv)
51 : m_width(SCREEN_WIDTH),
52 m_height(SCREEN_HEIGHT),
53 m_rotate(false),
54 m_fullscreen(false),
55 m_thumbnailMode(false),
56 m_quit(false),
57 m_window(NULL)
58 #ifdef HAVE_PYTHON
59 , m_python_input(NULL)
60 #endif
62 for ( int i=1; i<argc; i++ ) {
63 if ( strcmp(argv[i],"-bmp")==0 ) {
64 m_thumbnailMode = true;
65 } else if ( strcmp(argv[i],"-rotate")==0 ) {
66 m_rotate = true;
67 } else if ( strcmp(argv[i],"-fullscreen")==0 ) {
68 m_fullscreen = true;
69 } else if ( strcmp(argv[i],"-geometry")==0 && i<argc-1) {
70 int ww, hh;
71 if ( sscanf(argv[i+1],"%dx%d",&ww,&hh) ==2 ) {
72 m_width = ww;
73 m_height = hh;
75 i++;
76 } else {
77 m_files.append( argv[i] );
80 init();
83 ~App()
85 #ifdef HAVE_PYTHON
86 delete m_python_input;
87 #endif
90 void run()
92 if ( m_thumbnailMode ) {
93 for ( int i=0; i<m_files.size(); i++ ) {
94 renderThumbnail( m_files[i], m_width, m_height );
96 } else {
97 runGame( m_files, m_width, m_height, m_fullscreen );
101 private:
103 void init()
105 if ( m_thumbnailMode ) {
106 putenv((char*)"SDL_VIDEODRIVER=dummy");
107 } else {
108 putenv((char*)"SDL_VIDEO_X11_WMCLASS=NPhysics");
110 if ( mkdir( (std::string(getenv("HOME"))+"/"USER_BASE_PATH).c_str(),
111 0755)!=0 ) {
112 fprintf(stderr,"failed to create user dir\n");
116 if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_AUDIO) < 0) {
117 throw "Couldn't initialize SDL";
120 assert(Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 1024)==0);
121 assert(Mix_AllocateChannels(10)==10);
122 Mix_Volume(-1, MIX_MAX_VOLUME);
124 #ifdef HAVE_PYTHON
125 m_python_input = new PythonInput(m_width, m_height);
126 #endif
130 void renderThumbnail( const char* file, int width, int height )
132 configureScreenTransform( width, height );
133 Scene scene( true );
134 if ( scene.load( file ) ) {
135 printf("generating bmp %s\n", file);
136 Canvas temp( width, height );
137 scene.draw( temp, FULLSCREEN_RECT );
138 std::string bmp( file );
139 bmp += ".bmp";
140 temp.writeBMP( bmp.c_str() );
145 void add( Widget* w )
147 m_layers.append( w );
148 w->setParent( this );
151 void remove( Widget* w )
153 if ( m_layers.indexOf( w ) >= 0 ) {
154 m_layers.erase( m_layers.indexOf( w ) );
155 w->setParent( NULL );
160 void runGame( Array<const char*>& files, int width, int height, bool fullscreen )
162 Levels* levels = new Levels();
164 if ( files.size() > 0 ) {
165 for ( int i=0; i<files.size(); i++ ) {
166 levels->addPath( files[i] );
168 } else {
169 struct stat st;
170 if ( stat("Game.cpp",&st)==0 ) {
171 levels->addPath( "data" );
172 } else {
173 levels->addPath( DEFAULT_LEVEL_PATH );
175 levels->addPath( Config::userDataDir().c_str() );
178 Widget* game = createGameLayer(levels, width, height, fullscreen);
179 m_window = game->getWindow();
180 add(game);
181 mainLoop();
184 void renderLayers()
186 Rect area = m_layers[0]->dirtyArea();
188 for ( int i=1; i<m_layers.size(); i++ ) {
189 Rect dirt = m_layers[i]->dirtyArea();
190 if ( !dirt.isEmpty() ) {
191 if ( area.isEmpty() ) {
192 area = dirt;
193 } else {
194 area.expand( dirt );
198 for ( int i=0; i<m_layers.size(); i++ ) {
199 m_layers[i]->draw( *m_window, area );
201 //m_window->drawRect( area, 0x00ff00, false );
202 m_window->update( area );
206 bool handleGameEvent( SDL_Event &ev )
208 switch( ev.type ) {
209 case SDL_QUIT:
210 m_quit = true;
211 return true;
212 case SDL_KEYDOWN:
213 if ( ev.key.keysym.sym == SDLK_q ) {
214 m_quit = true;
215 return true;
218 return false;
221 void dispatchEvents( int lastTick )
223 for ( int i=0; i<m_layers.size(); i++ ) {
224 m_layers[i]->onTick( lastTick );
227 SDL_Event ev;
228 while ( SDL_PollEvent(&ev) ) {
229 if ( !handleGameEvent(ev) ) {
230 for ( int i=m_layers.size()-1; i>=0; i-- ) {
231 if ( m_layers[i]->handleEvent(ev) ) {
232 break;
239 void mainLoop()
241 renderLayers();
243 int renderRate = (MIN_RENDER_RATE+MAX_RENDER_RATE)/2;
244 int iterationRate = ITERATION_RATE;
245 int iterateCounter = 0;
246 int lastTick = SDL_GetTicks();
247 bool isComplete = false;
249 while ( !m_quit ) {
251 //assumes RENDER_RATE <= ITERATION_RATE
252 //TODO dynamic tick scaling for improved sleep
253 while ( iterateCounter < iterationRate ) {
254 dispatchEvents( lastTick );
255 if ( m_quit ) return;
256 iterateCounter += renderRate;
258 iterateCounter -= iterationRate;
260 renderLayers();
262 int sleepMs = lastTick + 1000/renderRate - SDL_GetTicks();
264 if ( sleepMs > 1 && renderRate < MAX_RENDER_RATE ) {
265 renderRate++;
266 // printf("increasing render rate to %dfps\n",renderRate);
267 sleepMs = lastTick + 1000/renderRate - SDL_GetTicks();
270 if ( sleepMs > 0 ) {
271 SDL_Delay( sleepMs );
272 } else {
273 // printf("overrun %dms\n",-sleepMs);
274 if ( renderRate > MIN_RENDER_RATE ) {
275 renderRate--;
276 // printf("decreasing render rate to %dfps\n",renderRate);
277 } else if ( iterationRate > 30 ) {
278 //slow down simulation time to maintain fps??
281 lastTick = SDL_GetTicks();
291 int npmain(int argc, char** argv)
293 try {
294 App app(argc,argv);
295 app.run();
296 } catch ( const char* e ) {
297 fprintf(stderr,"*** CAUGHT: %s",e);
299 return 0;