Пример #1
0
void run_example(
	const char* screenshot_path,
	int argc,
	char ** argv
)
{
	const GLuint width = 800, height = 600;

	SDLInitializer sdl_initializer("OGLplus example", width, height);
	GLAPIInitializer api_init;

	ExampleParams params(argc, argv);
	setupExample(params);
	params.Check();

	std::unique_ptr<Example> example(makeExample(params));

	example->Reshape(width, height);
	example->MouseMove(width/2, height/2, width, height);

	if(screenshot_path)
	{
		make_screenshot(
			example,
			width,
			height,
			screenshot_path
		);
	}
	else run_loop(example, width, height);
}
Пример #2
0
void command_executor_default::map_screenshot()
{
	make_screenshot(_("Map-Screenshot"), get_video(),
		[this](const std::string& filename, const CVideo&)
	{
		return get_display().screenshot(filename, true);
	});
}
Пример #3
0
void run_example(
	const char* screenshot_path,
	int argc,
	char** argv
)
{
	GLFWInitializer glfw_initializer;

	const GLuint width = 800, height = 600;

	GLFWwindow* window = glfwCreateWindow(
		width,
		height,
		"OGLplus example",
		NULL,
		NULL
	);
	if(!window)
	{
		throw std::runtime_error("Error creating GLFW3 window");
	}
	else
	{
		glfwMakeContextCurrent(window);
		GLAPIInitializer api_init;

		ExampleParams params(argc, argv);
		setupExample(params);
		params.Check();

		std::unique_ptr<Example> example(makeExample(params));

		example->Reshape(width, height);
		example->MouseMove(width/2, height/2, width, height);

		if(screenshot_path)
		{
			make_screenshot(
				example,
				window,
				width,
				height,
				screenshot_path
			);
		}
		else run_loop(example, window, width, height);
	}
}
Пример #4
0
void bumpmapping_app::onKey(int key, int action)
{
    if (action)
    {
        switch (key)
        {
            case 'R': 
                load_shaders();
                break;
            case 'S':
                make_screenshot();
                break;
            case 'P':
                paused = !paused;
                break;
        }
    }
}
Пример #5
0
void run_example(
	const char* screenshot_path,
	int argc,
	char** argv
)
{
	GLFWInitializer glfw_initializer;

	const GLuint width = 800, height = 600;

	if(!glfwOpenWindow(
		width,
		height,
		8, 8, 8, 8,
		32, 8,
		GLFW_WINDOW
	)) throw std::runtime_error("Error creating GLFW window");
	else
	{
		glfwSetWindowTitle("OGLplus example");
		GLAPIInitializer api_init;

		ExampleParams params(argc, argv);
		setupExample(params);
		params.Check();

		std::unique_ptr<Example> example(makeExample(params));

		example->Reshape(width, height);
		example->MouseMove(width/2, height/2, width, height);

		if(screenshot_path)
		{
			make_screenshot(
				example,
				width,
				height,
				screenshot_path
			);
		}
		else run_loop(example, width, height);
	}
}
Пример #6
0
void
VideoSystem::do_take_screenshot()
{
  SDLSurfacePtr surface = make_screenshot();
  if (!surface) {
    log_warning << "Creating the screenshot has failed" << std::endl;
    return;
  }

  const std::string screenshots_dir = "/screenshots";
  if (!PHYSFS_exists(screenshots_dir.c_str())) {
    if (!PHYSFS_mkdir(screenshots_dir.c_str())) {
      log_warning << "Creating '" << screenshots_dir << "' failed" << std::endl;
      return;
    }
  }

  auto find_filename = [&]() -> boost::optional<std::string>
    {
      for (int num = 0; num < 1000000; ++num)
      {
        std::ostringstream oss;
        oss << "screenshot" << std::setw(6) << std::setfill('0') << num << ".png";
        const std::string screenshot_filename = FileSystem::join(screenshots_dir, oss.str());
        if (!PHYSFS_exists(screenshot_filename.c_str())) {
          return screenshot_filename;
        }
      }
      return boost::none;
    };

  auto filename = find_filename();
  if (!filename)
  {
    log_info << "Failed to find filename to save screenshot" << std::endl;
  }
  else
  {
    if (SDLSurface::save_png(*surface, *filename)) {
      log_info << "Wrote screenshot to \"" << *filename << "\"" << std::endl;
    }
  }
}
Пример #7
0
void run_example(
	const x11::Display& display,
	const char* screenshot_path,
	const char* framedump_prefix,
	int argc,
	char ** argv
)
{
	static int visual_attribs[] =
	{
		GLX_X_RENDERABLE    , True,
		GLX_DRAWABLE_TYPE   , GLX_WINDOW_BIT,
		GLX_RENDER_TYPE     , GLX_RGBA_BIT,
		GLX_X_VISUAL_TYPE   , GLX_TRUE_COLOR,
		GLX_RED_SIZE        , 8,
		GLX_GREEN_SIZE      , 8,
		GLX_BLUE_SIZE       , 8,
		GLX_ALPHA_SIZE      , 8,
		GLX_DEPTH_SIZE      , 24,
		GLX_STENCIL_SIZE    , 8,
		GLX_DOUBLEBUFFER    , True,
		None
	};
	glx::Version version(display);
	version.AssertAtLeast(1, 3);

	glx::FBConfig fbc = glx::FBConfigs(
		display,
		visual_attribs
	).FindBest(display);

	x11::VisualInfo vi(display, fbc);

	const GLuint width = framedump_prefix?852:800;
	const GLuint height = framedump_prefix?480:600;

	x11::Window win(
		display,
		vi,
		x11::Colormap(display, vi),
		"OGLplus example",
		width, height
	);

	x11::ScreenNames screen_names;

	ExampleParams params(argc, argv);
	if(framedump_prefix) params.quality = 1.0;
	params.max_threads = 128;
	params.num_gpus = screen_names.size(); // TODO: something more reliable
	setupExample(params);
	params.Check();

	glx::Context ctx(display, fbc, 3, 3);

	ctx.MakeCurrent(win);

	// The clock for animation timing
	ExampleClock clock;

	std::vector<std::thread> threads;
	ThreadSemaphore thread_ready, master_ready;
	ExampleThreadData::Common example_thread_common_data = {
		nullptr,
		params,
		clock,
		screen_names,
		display,
		vi,
		fbc,
		ctx,
		thread_ready,
		master_ready,
		false /*failure*/,
		false /*done*/
	};
	try
	{
		// Initialize the GL API library (GLEW/GL3W/...)
		oglplus::GLAPIInitializer api_init;

		// things required for multi-threaded examples
		std::vector<ExampleThreadData> thread_data;

		// prepare the example data
		for(unsigned t=0; t!=params.num_threads; ++t)
		{
			ExampleThreadData example_thread_data = {
				t, nullptr, std::string(),
				&example_thread_common_data
			};
			thread_data.push_back(example_thread_data);
		}

		// start the examples and let them
		// create their own contexts shared with
		// the main context
		for(unsigned t=0; t!=params.num_threads; ++t)
		{
			threads.emplace_back(
				call_example_thread_main,
				std::ref(thread_data[t])
			);
			// wait for the thread to create
			// an off-screen context
			thread_ready.Wait();
			// check for errors
			if(!thread_data[t].error_message.empty())
			{
				example_thread_common_data.failure = true;
				example_thread_common_data.master_ready.Signal(t);
				throw std::runtime_error(
					thread_data[t].error_message
				);
			}
		}

		// make the example
		std::unique_ptr<Example> example(makeExample(params));

		// tell the threads about the example
		// and let them call makeExampleThread
		example_thread_common_data.example = example.get();
		for(unsigned t=0; t!=params.num_threads; ++t)
		{
			// signal that the example is ready
			master_ready.Signal();
			// wait for the threads to call makeExampleThread
			thread_ready.Wait();
		}
		// check for potential errors and let
		// the example do additional thread-related preparations
		for(unsigned t=0; t!=params.num_threads; ++t)
		{
			if(!thread_data[t].error_message.empty())
			{
				example_thread_common_data.failure = true;
				example_thread_common_data.master_ready.Signal(
					params.num_threads
				);
				throw std::runtime_error(
					thread_data[t].error_message
				);
			}
			assert(thread_data[t].example_thread);
			example->PrepareThread(t,*thread_data[t].example_thread);
		}
		// signal that the example threads may start
		// rendering
		master_ready.Signal(params.num_threads);

		example->Reshape(width, height);
		example->MouseMove(width/2, height/2, width, height);

		if(screenshot_path)
		{
			make_screenshot(
				display,
				win,
				ctx,
				example,
				clock,
				width,
				height,
				screenshot_path
			);
		}
		else if(framedump_prefix)
		{
			run_framedump_loop(
				display,
				win,
				ctx,
				example,
				clock,
				width,
				height,
				framedump_prefix
			);
		}
		else
		{
			run_example_loop(
				display,
				win,
				ctx,
				example,
				example_thread_common_data,
				clock,
				width,
				height
			);
		}
		example_thread_common_data.done = true;
		// cancel the example threads
		for(unsigned t=0; t!=params.num_threads; ++t)
		{
			if(thread_data[t].example_thread)
				thread_data[t].example_thread->Cancel();
		}
		// join the example threads
		for(unsigned t=0; t!=params.num_threads; ++t)
		{
			threads[t].join();
		}

		for(unsigned t=0; t!=params.num_threads; ++t)
		{
			if(!thread_data[t].error_message.empty())
				throw std::runtime_error(
					thread_data[t].error_message
				);
		}
	}
	catch(...)
	{
		example_thread_common_data.failure = true;
		master_ready.Signal(params.num_threads);
		try {for(auto& thread : threads) thread.join(); }
		catch(...){ }
		throw;
	}
	ctx.Release(display);
}
Пример #8
0
void execute_command(const hotkey_command& command, command_executor* executor, int index, bool press)
{
	if (executor != nullptr) {
		if (!executor->can_execute_command(command, index)
				|| executor->execute_command(command, index, press)) {
			return;
		}
	}

	if (!press) {
		return; // none of the commands here respond to a key release
    }

	switch (command.id) {

		case HOTKEY_MINIMAP_DRAW_TERRAIN:
			preferences::toggle_minimap_draw_terrain();
			executor->recalculate_minimap();
			break;
		case HOTKEY_MINIMAP_CODING_TERRAIN:
			preferences::toggle_minimap_terrain_coding();
			executor->recalculate_minimap();
			break;
		case HOTKEY_MINIMAP_CODING_UNIT:
			preferences::toggle_minimap_movement_coding();
			executor->recalculate_minimap();
			break;
		case HOTKEY_MINIMAP_DRAW_UNITS:
			preferences::toggle_minimap_draw_units();
			executor->recalculate_minimap();
			break;
		case HOTKEY_MINIMAP_DRAW_VILLAGES:
			preferences::toggle_minimap_draw_villages();
			executor->recalculate_minimap();
			break;
		case HOTKEY_FULLSCREEN:
			executor->get_video().set_fullscreen(!preferences::fullscreen());
			break;
		case HOTKEY_SCREENSHOT:
			make_screenshot(_("Screenshot"), executor->get_video(), &::screenshot);
			break;
		case HOTKEY_ANIMATE_MAP:
			preferences::set_animate_map(!preferences::animate_map());
			break;
		case HOTKEY_MOUSE_SCROLL:
			preferences::enable_mouse_scroll(!preferences::mouse_scroll_enabled());
			break;
		case HOTKEY_MUTE:
			{
				// look if both is not playing
				static struct before_muted_s
				{
					bool playing_sound,playing_music;
					before_muted_s() : playing_sound(false),playing_music(false){}
				} before_muted;
				if (preferences::music_on() || preferences::sound_on())
				{
					// then remember settings and mute both
					before_muted.playing_sound = preferences::sound_on();
					before_muted.playing_music = preferences::music_on();
					preferences::set_sound(false);
					preferences::set_music(false);
				}
				else
				{
					// then set settings before mute
					preferences::set_sound(before_muted.playing_sound);
					preferences::set_music(before_muted.playing_music);
				}
			}
			break;
		default:
			DBG_G << "command_executor: unknown command number " << command.id << ", ignoring.\n";
			break;
	}
}
Пример #9
0
void run_example(
	const eglplus::Display& display,
	ExampleOptions& opts,
	int argc,
	char ** argv
)
{
	eglplus::Configs configs(
		display,
		eglplus::ConfigAttribs()
			.Add(eglplus::ConfigAttrib::RedSize, 8)
			.Add(eglplus::ConfigAttrib::GreenSize, 8)
			.Add(eglplus::ConfigAttrib::BlueSize, 8)
			.Add(eglplus::ConfigAttrib::DepthSize, 24)
			.Add(eglplus::ConfigAttrib::StencilSize, 8)
			.Add(eglplus::ConfigAttrib::SampleBuffers, opts.samples>0?1:0)
			.Add(eglplus::ConfigAttrib::Samples, opts.samples>0?opts.samples:0)
			.Add(eglplus::ColorBufferType::RGBBuffer)
			.Add(eglplus::RenderableTypeBit::OpenGL)
			.Add(eglplus::SurfaceTypeBit::Pbuffer)
			.Get()
	);

	eglplus::Config config = configs.First();


	eglplus::SurfaceAttribs surface_attribs = eglplus::SurfaceAttribs()
			.Add(eglplus::SurfaceAttrib::Width, GLint(opts.width))
			.Add(eglplus::SurfaceAttrib::Height, GLint(opts.height));

	eglplus::Surface surface = eglplus::Surface::Pbuffer(
		display,
		config,
		surface_attribs.Get()
	);

	eglplus::BindAPI(eglplus::RenderingAPI::OpenGL);

	eglplus::ContextAttribs context_attribs =
		eglplus::ContextAttribs()
			.Add(eglplus::ContextAttrib::MajorVersion, 3)
			.Add(eglplus::ContextAttrib::MinorVersion, 3)
			.Add(eglplus::OpenGLProfileBit::Core);

	eglplus::Context context(
		display,
		config,
		context_attribs.Get()
	);

	context.MakeCurrent(surface);

	ExampleParams params(argc, argv);
	params.quality = 1.0;
	params.max_threads = 128;
	params.num_gpus = 1;
	setupExample(params);
	params.Check();

	ExampleClock clock;

	std::vector<std::thread> threads;
	ThreadSemaphore thread_ready, master_ready;
	ExampleThreadData::Common example_thread_common_data = {
		nullptr,
		params,
		clock,
		display,
		config,
		surface_attribs,
		context_attribs,
		context,
		thread_ready,
		master_ready,
		false, //failure
		false //done
	};
	try
	{
		// Initialize the GL API library (GLEW/GL3W/...)
		oglplus::GLAPIInitializer api_init;

		// things required for multi-threaded examples
		std::vector<ExampleThreadData> thread_data;

		// prepare the example data
		for(unsigned t=0; t!=params.num_threads; ++t)
		{
			ExampleThreadData example_thread_data = {
				t, nullptr, std::string(),
				&example_thread_common_data
			};
			thread_data.push_back(example_thread_data);
		}

		// start the examples and let them
		// create their own contexts shared with
		// the main context
		for(unsigned t=0; t!=params.num_threads; ++t)
		{
			threads.emplace_back(
				call_example_thread_main,
				std::ref(thread_data[t])
			);
			// wait for the thread to create
			// an off-screen context
			thread_ready.Wait();
			// check for errors
			if(!thread_data[t].error_message.empty())
			{
				example_thread_common_data.failure = true;
				example_thread_common_data.master_ready.Signal(t);
				throw std::runtime_error(
					thread_data[t].error_message
				);
			}
		}

		// make the example
		std::unique_ptr<Example> example(makeExample(params));

		// tell the threads about the example
		// and let them call makeExampleThread
		example_thread_common_data.example = example.get();
		for(unsigned t=0; t!=params.num_threads; ++t)
		{
			// signal that the example is ready
			master_ready.Signal();
			// wait for the threads to call makeExampleThread
			thread_ready.Wait();
		}
		// check for potential errors and let
		// the example do additional thread-related preparations
		for(unsigned t=0; t!=params.num_threads; ++t)
		{
			if(!thread_data[t].error_message.empty())
			{
				example_thread_common_data.failure = true;
				example_thread_common_data.master_ready.Signal(
					params.num_threads
				);
				throw std::runtime_error(
					thread_data[t].error_message
				);
			}
			assert(thread_data[t].example_thread);
			example->PrepareThread(t,*thread_data[t].example_thread);
		}
		// signal that the example threads may start
		// rendering
		master_ready.Signal(params.num_threads);

		example->Reshape(opts.width, opts.height);
		example->MouseMove(opts.width/2, opts.height/2, opts.width, opts.height);

		if(opts.screenshot_path)
		{
			make_screenshot(surface, example, clock, opts);
		}
		else if(opts.framedump_prefix)
		{
			run_framedump_loop(surface, example, clock, opts);
		}
		else assert(!"Never should get here!");

		example_thread_common_data.done = true;
		// cancel the example threads
		for(unsigned t=0; t!=params.num_threads; ++t)
		{
			if(thread_data[t].example_thread)
			{
				thread_data[t].example_thread->Cancel();
			}
		}
		// join the example threads
		for(unsigned t=0; t!=params.num_threads; ++t)
		{
			threads[t].join();
		}

		for(unsigned t=0; t!=params.num_threads; ++t)
		{
			if(!thread_data[t].error_message.empty())
			{
				throw std::runtime_error(
					thread_data[t].error_message
				);
			}
		}
	}
	catch(...)
	{
		example_thread_common_data.failure = true;
		master_ready.Signal(params.num_threads);
		try {for(auto& thread : threads) thread.join(); }
		catch(...){ }
		throw;
	}
}
Пример #10
0
static void pmp_input(volatile struct pmp_play_struct *p, SceCtrlData *previous_controller)
	{
	scePowerTick(0);


	SceCtrlData controller;
	sceCtrlReadBufferPositive(&controller, 1);
	if(1)
		{
		if (((controller.Buttons & PSP_CTRL_TRIANGLE) == 0) && (previous_controller->Buttons & PSP_CTRL_TRIANGLE))
			{
			p->return_request = 1;
			//add by cooleyes 2007/01/16
			p->return_result = "exit: manual";
			//add end
			}
		else
			{
			if (p->paused == 1)
				{
				p->seek = 0;

				if ((controller.Buttons & PSP_CTRL_SQUARE) && ((previous_controller->Buttons & PSP_CTRL_SQUARE) == 0))
					{
					p->paused = 0;
					}
				else if ((controller.Buttons & PSP_CTRL_CIRCLE) && ((previous_controller->Buttons & PSP_CTRL_CIRCLE) == 0)) 
					{
					make_screenshot();
					}
				}
			else
				{
				if (controller.Buttons & PSP_CTRL_CROSS)
					{
					if (controller.Buttons & PSP_CTRL_RIGHT)
						{
						p->seek = 2;
						}
					else if (controller.Buttons & PSP_CTRL_LEFT)
						{
						p->seek = -2;
						}
					else
						{
						p->seek = 0;

						if ((controller.Buttons & PSP_CTRL_UP) && ((previous_controller->Buttons & PSP_CTRL_UP) == 0))
							{
							if (p->zoom != 200)
								{
								p->zoom += 5;
								}
							}
						else if ((controller.Buttons & PSP_CTRL_DOWN) && ((previous_controller->Buttons & PSP_CTRL_DOWN) == 0))
							{
							if (p->zoom != 100)
								{
								p->zoom -= 5;
								}
							}
						else if ((controller.Buttons & PSP_CTRL_RTRIGGER) && ((previous_controller->Buttons & PSP_CTRL_RTRIGGER) == 0))
							{
							if (p->loop == 0)
								{
								p->loop = 1;
								}
							else
								{
								p->loop = 0;
								}
							}
						else if ((controller.Buttons & PSP_CTRL_LTRIGGER) && ((previous_controller->Buttons & PSP_CTRL_LTRIGGER) == 0))
							{
							if (p->subtitle_count)
								{
								p->subtitle = (p->subtitle + 1)%(p->subtitle_count+1);
								if (p->subtitle)
									snprintf(info_string,512,"[i]%s[/i]", subtitle_parser[p->subtitle-1].filename);
								else
									snprintf(info_string,512,"[i]no subtitle[/i]");
								info_count = 60;
								}
							}
						//remove by cooleyes 2007/02/01
						/*/
						else if ((controller.Buttons & PSP_CTRL_SELECT) && ((previous_controller->Buttons & PSP_CTRL_SELECT) == 0))
							{
							p->subtitle_format ^= 1;
							if (p->subtitle_format)
								snprintf(info_string,512,"[i]UTF-8[/i]");
							else
								snprintf(info_string,512,"[i]ASCII[/i]");
							info_count = 60;
							}
						//*/
						//remove end
						else if ((controller.Buttons & PSP_CTRL_SQUARE) && ((previous_controller->Buttons & PSP_CTRL_SQUARE) == 0))
							{
							p->subtitle_fontcolor = (p->subtitle_fontcolor+1)%NUMBER_OF_FONTCOLORS;
							gu_font_color_set( FONTCOLORS[p->subtitle_fontcolor] );
							}
						else if ((controller.Buttons & PSP_CTRL_CIRCLE) && ((previous_controller->Buttons & PSP_CTRL_CIRCLE) == 0))
							{
							p->subtitle_bordercolor = (p->subtitle_bordercolor+1)%NUMBER_OF_BORDERCOLORS;
							gu_font_border_color_set( BORDERCOLORS[p->subtitle_bordercolor] );
							}
						//add by cooleyes 2007/02/01
						else if ((controller.Buttons & PSP_CTRL_SELECT) && ((previous_controller->Buttons & PSP_CTRL_SELECT) == 0))
							{
							if(p->audio_channel > -1)
								{
								p->audio_channel--;
								}
							else
								{
								p->audio_channel = 1;
								}
							}
						//add end
						else if ((controller.Buttons & PSP_CTRL_START) && ((previous_controller->Buttons & PSP_CTRL_START) == 0)) 
							{
							gu_lcd_output_inversion_set();
							}
						}
					}
				else if ((controller.Buttons & PSP_CTRL_SQUARE) && ((previous_controller->Buttons & PSP_CTRL_SQUARE) == 0))
					{
					p->paused = 1;
					p->seek   = 0;
					}
				else if (controller.Buttons & PSP_CTRL_RIGHT)
					{
					p->seek = 1;
					}
				else if (controller.Buttons & PSP_CTRL_LEFT)
					{
					p->seek = -1;
					}
				else if ((controller.Buttons & PSP_CTRL_SELECT) && ((previous_controller->Buttons & PSP_CTRL_SELECT) == 0))
					{
					if (p->audio_stream + 1 == p->decoder.reader.file.header.audio.number_of_streams)
						{
						p->audio_stream = 0;
						}
					else
						{
						p->audio_stream ++;
						}
					}
				else if ((controller.Buttons & PSP_CTRL_UP) && ((previous_controller->Buttons & PSP_CTRL_UP) == 0))
					{
					if (p->volume_boost != 6)
						{
						p->volume_boost ++;
						}
					pcm_set_normalize_ratio(p->volume_boost);
					}
				else if ((controller.Buttons & PSP_CTRL_DOWN) && ((previous_controller->Buttons & PSP_CTRL_DOWN) == 0))
					{
					if (p->volume_boost != 0)
						{
						p->volume_boost --;
						}
					pcm_set_normalize_ratio(p->volume_boost);
					}
				else if ((controller.Buttons & PSP_CTRL_RTRIGGER) && ((previous_controller->Buttons & PSP_CTRL_RTRIGGER) == 0))
					{
					if (p->luminosity_boost != (number_of_luminosity_boosts - 1))
						{
						p->luminosity_boost ++;
						}
					}
				else if ((controller.Buttons & PSP_CTRL_LTRIGGER) && ((previous_controller->Buttons & PSP_CTRL_LTRIGGER) == 0))
					{
					if (p->luminosity_boost != 0)
						{
						p->luminosity_boost --;
						}
					}
				else if ((controller.Buttons & PSP_CTRL_START) && ((previous_controller->Buttons & PSP_CTRL_START) == 0))
					{
					if (p->aspect_ratio != (number_of_aspect_ratios - 1))
						{
						p->aspect_ratio ++;
						}
					else
						{
						p->aspect_ratio = 0;
						}
					}
				else if ((controller.Buttons & PSP_CTRL_CIRCLE) && ((previous_controller->Buttons & PSP_CTRL_CIRCLE) == 0))
					{
					if (p->show_interface == 0)
						{
						p->show_interface = 1;
						}
					else
						{
						p->show_interface = 0;
						}
					}
				else
					{
					p->seek = 0;
					}
				}
			}
		}


	*previous_controller = controller;
	}
Пример #11
0
static void game_loop()
{
  BITMAP *buffer = create_bitmap(GFX_W, GFX_H);

  // initialize the player input
  the_input = new Input();

  // start the game
  the_game = new Game();
  the_game->start();

  while (continuing) {
    while (beats > 0 && continuing) {
      // update game logic
      continuing = the_game->update();
      --beats;
    }
    the_game->draw(buffer);

    // flip to screen (double buffering technique)
    vsync();
    stretch_blit(buffer, screen, 0, 0, GFX_W, GFX_H, 0, 0, SCREEN_W, SCREEN_H);

    // switch graphics mode
    if (key[KEY_F11] || gfx_switched) {
      int old_beats = beats;

      if (!gfx_switched) {
	gfx_widescreen = !gfx_widescreen;
      }
      else {
	gfx_switched = false;
      }
      switch_widescreen();

      destroy_bitmap(buffer);
      buffer = create_bitmap(GFX_W, GFX_H);

      do {
	poll_keyboard();
      } while (key[KEY_F11]);
      beats = old_beats;
    }

    // screen shot
    if (key[KEY_F12]) {
      int old_beats = beats;
      make_screenshot(buffer);
      do {
	poll_keyboard();
      } while (key[KEY_F12]);
      beats = old_beats;
    }
  }

  // destroy the game
  delete the_game;
  the_game = NULL;

  delete the_input;

  destroy_bitmap(buffer);
}