2 * This file is part of NumptyPhysics
3 * Copyright (C) 2008 Tim Edmonds
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.
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.
26 #include "PythonInput.h"
32 #include <SDL/SDL_mixer.h>
35 class App
: private WidgetParent
43 Array
<const char*> m_files
;
44 Array
<Widget
*> m_layers
;
47 PythonInput
*m_python_input
;
50 App(int argc
, char** argv
)
51 : m_width(SCREEN_WIDTH
),
52 m_height(SCREEN_HEIGHT
),
55 m_thumbnailMode(false),
59 , m_python_input(NULL
)
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 ) {
67 } else if ( strcmp(argv
[i
],"-fullscreen")==0 ) {
69 } else if ( strcmp(argv
[i
],"-geometry")==0 && i
<argc
-1) {
71 if ( sscanf(argv
[i
+1],"%dx%d",&ww
,&hh
) ==2 ) {
77 m_files
.append( argv
[i
] );
86 delete m_python_input
;
92 if ( m_thumbnailMode
) {
93 for ( int i
=0; i
<m_files
.size(); i
++ ) {
94 renderThumbnail( m_files
[i
], m_width
, m_height
);
97 runGame( m_files
, m_width
, m_height
, m_fullscreen
);
105 if ( m_thumbnailMode
) {
106 putenv((char*)"SDL_VIDEODRIVER=dummy");
108 putenv((char*)"SDL_VIDEO_X11_WMCLASS=NPhysics");
110 if ( mkdir( (std::string(getenv("HOME"))+"/"USER_BASE_PATH
).c_str(),
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
);
125 m_python_input
= new PythonInput(m_width
, m_height
);
130 void renderThumbnail( const char* file
, int width
, int height
)
132 configureScreenTransform( width
, height
);
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
);
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
] );
170 if ( stat("Game.cpp",&st
)==0 ) {
171 levels
->addPath( "data" );
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();
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() ) {
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
)
213 if ( ev
.key
.keysym
.sym
== SDLK_q
) {
221 void dispatchEvents( int lastTick
)
223 for ( int i
=0; i
<m_layers
.size(); i
++ ) {
224 m_layers
[i
]->onTick( lastTick
);
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
) ) {
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;
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
;
262 int sleepMs
= lastTick
+ 1000/renderRate
- SDL_GetTicks();
264 if ( sleepMs
> 1 && renderRate
< MAX_RENDER_RATE
) {
266 // printf("increasing render rate to %dfps\n",renderRate);
267 sleepMs
= lastTick
+ 1000/renderRate
- SDL_GetTicks();
271 SDL_Delay( sleepMs
);
273 // printf("overrun %dms\n",-sleepMs);
274 if ( renderRate
> MIN_RENDER_RATE
) {
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
)
296 } catch ( const char* e
) {
297 fprintf(stderr
,"*** CAUGHT: %s",e
);