コード例 #1
0
ファイル: mng.cpp プロジェクト: AMDmi3/Wyrmgus
/**
**  Load a MNG
**
**  @param name  Name of the MNG file
*/
int Mng::Load(const std::string &name)
{
	this->name = LibraryFileName(name.c_str());
	handle = mng_initialize(this, my_alloc, my_free, MNG_NULL);
	if (handle == MNG_NULL) {
		return -1;
	}
	mng_setcb_openstream(handle, my_openstream);
	mng_setcb_closestream(handle, my_closestream);
	mng_setcb_readdata(handle, my_readdata);
	mng_setcb_processheader(handle, my_processheader);
	mng_setcb_processmend(handle, my_processmend);
	mng_setcb_getcanvasline(handle, my_getcanvasline);
	mng_setcb_refresh(handle, my_refresh);
	mng_setcb_gettickcount(handle, my_gettickcount);
	mng_setcb_settimer(handle, my_settimer);
	mng_setcb_errorproc(handle, my_errorproc);

	mng_read(handle);
	if (surface && iteration != 0x7fffffff) {
		mng_display(handle);
	}

	if (!surface || iteration == 0x7fffffff) {
		return -1;
	}
	return 0;
}
コード例 #2
0
/**
**  Load a MNG
**
**  @param name  Name of the MNG file
*/
int Mng::Load(const char *name)
{
	mng_retcode myretcode;
	char buf[PATH_MAX];

	LibraryFileName(name, buf, sizeof(buf));

	this->name = new_strdup(buf);
	handle = mng_initialize(this, my_alloc, my_free, MNG_NULL);
	if (handle == MNG_NULL) {
		return -1;
	}
	mng_setcb_openstream(handle, my_openstream);
	mng_setcb_closestream(handle, my_closestream);
	mng_setcb_readdata(handle, my_readdata);
	mng_setcb_processheader(handle, my_processheader);
	mng_setcb_processmend(handle, my_processmend);
	mng_setcb_getcanvasline(handle, my_getcanvasline);
	mng_setcb_refresh(handle, my_refresh);
	mng_setcb_gettickcount(handle, my_gettickcount);
	mng_setcb_settimer(handle, my_settimer);
	mng_setcb_errorproc(handle, my_errorproc);

	mng_read(handle);
	if (surface && iteration != 0x7fffffff) {
		myretcode = mng_display(handle);
	}

	if (!surface || iteration == 0x7fffffff) {
		return -1;
	}
	return 0;
}
コード例 #3
0
ファイル: iolib.cpp プロジェクト: AMDmi3/Wyrmgus
bool CanAccessFile(const char *filename)
{
	if (filename && filename[0] != '\0') {
		char name[PATH_MAX];
		name[0] = '\0';
		LibraryFileName(filename, name);
		return (name[0] != '\0' && 0 == access(name, R_OK));
	}
	return false;
}
コード例 #4
0
ファイル: sound_server.cpp プロジェクト: onkrot/stratagus
/**
**  Load a sample
**
**  @param name  File name of sample (short version).
**
**  @return      General sample loaded from file into memory.
**
**  @todo  Add streaming, caching support.
*/
CSample *LoadSample(const std::string &name)
{
	const std::string filename = LibraryFileName(name.c_str());
	CSample *sample = LoadSample(filename.c_str(), PlayAudioLoadInMemory);

	if (sample == NULL) {
		fprintf(stderr, "Can't load the sound '%s'\n", name.c_str());
	}
	return sample;
}
コード例 #5
0
ファイル: script.cpp プロジェクト: infsega/boswars-playbook
/**
**  Load a file and execute it.
**
**  @param l  Lua state.
**
**  @return   0 in success, else exit.
*/
static int CclLoad(lua_State *l)
{
	char buf[1024];

	LuaCheckArgs(l, 1);
	LibraryFileName(LuaToString(l, 1), buf, sizeof(buf));
	if (LuaLoadFile(buf) == -1) {
		DebugPrint("Load failed: %s\n" _C_ LuaToString(l, 1));
	}
	return 0;
}
コード例 #6
0
ファイル: script_map.cpp プロジェクト: meiavy/Wyrmgus
/**
** Load the lua file which will define the tile models
**
**  @param l  Lua state.
*/
static int CclLoadTileModels(lua_State *l)
{
	if (lua_gettop(l) != 1) {
		LuaError(l, "incorrect argument");
	}
	Map.TileModelsFileName = LuaToString(l, 1);
	const std::string filename = LibraryFileName(Map.TileModelsFileName.c_str());
	if (LuaLoadFile(filename) == -1) {
		DebugPrint("Load failed: %s\n" _C_ filename.c_str());
	}
	return 0;
}
コード例 #7
0
/**
** Load the lua file which will define the tile models
**
**  @param l  Lua state.
*/
static int CclLoadTileModels(lua_State *l)
{
	char buf[1024];

	if (lua_gettop(l) != 1) {
		LuaError(l, "incorrect argument");
	}
	strcpy_s(Map.TileModelsFileName, sizeof(Map.TileModelsFileName), LuaToString(l, 1));
	LibraryFileName(Map.TileModelsFileName, buf, sizeof(buf));
	if (LuaLoadFile(buf) == -1) {
		DebugPrint("Load failed: %s\n" _C_ LuaToString(l, 1));
	}
	return 0;
}
コード例 #8
0
ファイル: script.cpp プロジェクト: infsega/boswars-playbook
/**
**  Load a file into a buffer and return it.
**
**  @param l  Lua state.
**
**  @return   buffer or nil on failure
*/
static int CclLoadBuffer(lua_State *l)
{
	char file[1024];
	std::string buf;

	LuaCheckArgs(l, 1);
	LibraryFileName(LuaToString(l, 1), file, sizeof(file));
	LuaLoadBuffer(file, buf);
	if (!buf.empty()) {
		lua_pushstring(l, buf.c_str());
		return 1;
	}
	return 0;
}
コード例 #9
0
ファイル: sound_server.cpp プロジェクト: onkrot/stratagus
/**
**  Play a music file.
**
**  @param file  Name of music file, format is automatically detected.
**
**  @return      0 if music is playing, -1 if not.
*/
int PlayMusic(const std::string &file)
{
	if (!SoundEnabled() || !IsMusicEnabled()) {
		return -1;
	}
	const std::string name = LibraryFileName(file.c_str());
	DebugPrint("play music %s\n" _C_ name.c_str());
	CSample *sample = LoadSample(name.c_str(), PlayAudioStream);

	if (sample) {
		StopMusic();
		MusicChannel.Sample = sample;
		MusicPlaying = true;
		return 0;
	} else {
		DebugPrint("Could not play %s\n" _C_ file.c_str());
		return -1;
	}
}
コード例 #10
0
ファイル: script.cpp プロジェクト: infsega/boswars-playbook
/**
**  Load stratagus config file.
*/
void LoadCcl(void)
{
	char buf[PATH_MAX];

	//
	//  Load and evaluate configuration file
	//
	CclInConfigFile = 1;
	LibraryFileName(CclStartFile.c_str(), buf, sizeof(buf));
	if (access(buf, R_OK)) {
		fprintf(stderr, "Maybe you need to specify another gamepath with '-d /path/to/datadir'?\n");
		ExitFatal(-1);
	}

	ShowLoadProgress("Script %s\n", buf);
	LuaLoadFile(buf);
	CclInConfigFile = 0;
	CclGarbageCollect(0);  // Cleanup memory after load
}
コード例 #11
0
ファイル: stratagus.cpp プロジェクト: realhidden/stratagus
/**
**  Run the guichan main menus loop.
**
**  @return          0 for success, else exit.
*/
static int MenuLoop()
{
    int status;

    initGuichan();
    InterfaceState = IfaceStateMenu;
    //  Clear screen
    Video.ClearScreen();
    Invalidate();

    ButtonUnderCursor = -1;
    CursorState = CursorStatePoint;
    GameCursor = UI.Point.Cursor;

    // FIXME delete this when switching to full guichan GUI
    const std::string filename = LibraryFileName("scripts/guichan.lua");
    status = LuaLoadFile(filename);

    // We clean up later in Exit
    return status;
}
コード例 #12
0
ファイル: stratagus.cpp プロジェクト: ajaykon/Stratagus
/**
**  Run the guichan main menus loop.
**
**  @return          0 for success, else exit.
*/
static int MenuLoop()
{
	char buf[1024];
	int status;

	initGuichan();
	InterfaceState = IfaceStateMenu;
	//  Clear screen
	Video.ClearScreen();
	Invalidate();

	ButtonUnderCursor = -1;
	CursorState = CursorStatePoint;
	GameCursor = UI.Point.Cursor;

	// FIXME delete this when switching to full guichan GUI
	LibraryFileName("scripts/guichan.lua", buf, sizeof(buf));
	status = LuaLoadFile(buf);

	// We clean up later in Exit
	return status;
}
コード例 #13
0
ファイル: iolib.cpp プロジェクト: AMDmi3/Wyrmgus
extern std::string LibraryFileName(const char *file)
{
	char buffer[PATH_MAX];
	LibraryFileName(file, buffer);
	return buffer;
}
コード例 #14
0
ファイル: movie.cpp プロジェクト: infsega/boswars-playbook
/**
**  Play a video file.
**
**  @param name   Filename of movie file.
**
**  @return       Non-zero if file isn't a supported movie.
*/
int PlayMovie(const std::string &name)
{
    OggData data;
    CFile f;
    SDL_Rect rect;
    SDL_Overlay *yuv_overlay;
    CSample *sample;
    const EventCallback *old_callbacks;
    EventCallback callbacks;
    unsigned int start_ticks;
    int need_data;
    int diff;
    char buffer[PATH_MAX];

    LibraryFileName(name.c_str(), buffer, sizeof(buffer));

    if (f.open(buffer, CL_OPEN_READ) == -1) {
        fprintf(stderr, "Can't open file `%s'\n", name.c_str());
        return -1;
    }

    memset(&data, 0, sizeof(data));
    if (OggInit(&f, &data) || !data.video) {
        OggFree(&data);
        f.close();
        return -1;
    }

    data.File = &f;

    if (data.tinfo.frame_width * 300 / 4 > data.tinfo.frame_height * 100) {
        rect.w = Video.Width;
        rect.h = Video.Width * data.tinfo.frame_height / data.tinfo.frame_width;
        rect.x = 0;
        rect.y = (Video.Height - rect.h) / 2;
    } else {
        rect.w = Video.Height * data.tinfo.frame_width / data.tinfo.frame_height;
        rect.h = Video.Height;
        rect.x = (Video.Width - rect.w) / 2;
        rect.y = 0;
    }

    yuv_overlay = SDL_CreateYUVOverlay(data.tinfo.frame_width,
                                       data.tinfo.frame_height, SDL_YV12_OVERLAY, TheScreen);

    if (yuv_overlay == NULL) {
        fprintf(stderr, "SDL_CreateYUVOverlay: %s\n", SDL_GetError());
        OggFree(&data);
        f.close();
        return 0;
    }

    StopMusic();
    if ((sample = LoadVorbis(buffer, PlayAudioStream))) {
        if ((sample->Channels != 1 && sample->Channels != 2) ||
                sample->SampleSize != 16) {
            fprintf(stderr, "Unsupported sound format in movie\n");
            delete sample;
            SDL_FreeYUVOverlay(yuv_overlay);
            OggFree(&data);
            f.close();
            return 0;
        }
        PlayMusic(sample);
    }

    callbacks.ButtonPressed = MovieCallbackButtonPressed;
    callbacks.ButtonReleased = MovieCallbackButtonReleased;
    callbacks.MouseMoved = MovieCallbackMouseMove;
    callbacks.MouseExit = MovieCallbackMouseExit;
    callbacks.KeyPressed = MovieCallbackKeyPressed;
    callbacks.KeyReleased = MovieCallbackKeyReleased;
    callbacks.KeyRepeated = MovieCallbackKeyRepeated;
    callbacks.NetworkEvent = NetworkEvent;

    old_callbacks = GetCallbacks();
    SetCallbacks(&callbacks);

    Invalidate();
    RealizeVideoMemory();

    MovieStop = false;
    start_ticks = SDL_GetTicks();
    need_data = 1;
    while (!MovieStop) {
        if (need_data) {
            if (TheoraProcessData(&data)) {
                break;
            }
            need_data = 0;
        }

        diff = SDL_GetTicks() - start_ticks - static_cast<int>(
                   theora_granule_time(&data.tstate, data.tstate.granulepos) * 1000);

        if (diff > 100) {
            // too far behind, skip some frames
            need_data = 1;
            continue;
        }
        if (diff > 0) {
            OutputTheora(&data, yuv_overlay, &rect);
            need_data = 1;
        }

        WaitEventsOneFrame();
    }

    StopMusic();
    SDL_FreeYUVOverlay(yuv_overlay);

    OggFree(&data);
    f.close();

    SetCallbacks(old_callbacks);

    return 0;
}
コード例 #15
0
ファイル: game.cpp プロジェクト: k1643/StratagusAI
/**
**  CreateGame.
**
**  Load map, graphics, sounds, etc
**
**  @param filename  map filename
**  @param map       map loaded
**
**  @todo FIXME: use in this function InitModules / LoadModules!!!
*/
void CreateGame(const char *filename, CMap *map)
{
	int i;

	if (SaveGameLoading) {
		SaveGameLoading = 0;
		// Load game, already created game with Init/LoadModules
		CommandLog(NULL, NoUnitP, FlushCommands, -1, -1, NoUnitP, NULL, -1);
		return;
	}

	InitVisionTable(); // build vision table for fog of war
	InitPlayers();
	
	if (Map.Info.Filename.empty() && filename) {
		char path[PATH_MAX];
		
		Assert(filename);
		LibraryFileName(filename, path, sizeof(path));
		if(strcasestr(filename, ".smp")) {
			LuaLoadFile(path);
		}
	}

	for (i = 0; i < PlayerMax; ++i) {
		int playertype = Map.Info.PlayerType[i];
		// Network games only:
		if (GameSettings.Presets[i].Type != SettingsPresetMapDefault) {
			playertype = GameSettings.Presets[i].Type;
		}
		CreatePlayer(playertype);
	}

	if (filename) {
		if (CurrentMapPath != filename) {
			strcpy_s(CurrentMapPath, sizeof(CurrentMapPath), filename);
		}

		//
		// Load the map.
		//
		InitUnitTypes(1);
		LoadMap(filename, map);
		
		// HARDCODING FOG OF WAR TRUE.  It doesn't currently use preferences on a game restart - Should be changed 
		map->NoFogOfWar = true;
		Map.Reveal();
	}

	GameCycle = 0;
	FastForwardCycle = 0;
	SyncHash = 0;
	InitSyncRand();

	if (IsNetworkGame()) { // Prepare network play
		DebugPrint("Client setup: Calling InitNetwork2\n");
		InitNetwork2();
	} else {
		if (LocalPlayerName && strcmp(LocalPlayerName, "Anonymous")) {
		  ThisPlayer->SetName(LocalPlayerName);
		}
	}

	CallbackMusicOn();

#if 0
	GamePaused = true;
#endif

	if (FlagRevealMap) {
		Map.Reveal();
	}

	//
	// Setup game types
	//
	// FIXME: implement more game types
	if (GameSettings.GameType != SettingsGameTypeMapDefault) {
		switch (GameSettings.GameType) {
			case SettingsGameTypeMelee:
				break;
			case SettingsGameTypeFreeForAll:
				GameTypeFreeForAll();
				break;
			case SettingsGameTypeTopVsBottom:
				GameTypeTopVsBottom();
				break;
			case SettingsGameTypeLeftVsRight:
				GameTypeLeftVsRight();
				break;
			case SettingsGameTypeManVsMachine:
				GameTypeManVsMachine();
				break;
			case SettingsGameTypeManTeamVsMachine:
				GameTypeManTeamVsMachine();

			// Future game type ideas
#if 0
			case SettingsGameTypeOneOnOne:
				break;
			case SettingsGameTypeCaptureTheFlag:
				break;
			case SettingsGameTypeGreed:
				break;
			case SettingsGameTypeSlaughter:
				break;
			case SettingsGameTypeSuddenDeath:
				break;
			case SettingsGameTypeTeamMelee:
				break;
			case SettingsGameTypeTeamCaptureTheFlag:
				break;
#endif
		}
	}

	//
	// Graphic part
	//
	SetPlayersPalette();
	InitIcons();
	LoadIcons();

	LoadCursors(PlayerRaces.Name[ThisPlayer->Race]);
	UnitUnderCursor = NoUnitP;

	InitMissileTypes();
#ifndef DYNAMIC_LOAD
	LoadMissileSprites();
#endif
	InitConstructions();
	LoadConstructions();
	LoadUnitTypes();
	LoadDecorations();

	InitSelections();

	InitUserInterface();
	UI.Load();

	UI.Minimap.Create();
	Map.Init();
	PreprocessMap();

	//
	// Sound part
	//
	LoadUnitSounds();
	MapUnitSounds();
	if (SoundEnabled()) {
		InitSoundClient();
	}

	//
	// Spells
	//
	InitSpells();

	//
	// Init units' groups
	//
	InitGroups();

	//
	// Init players?
	//
	DebugPlayers();
	PlayersInitAi();

	//
	// Upgrades
	//
	InitUpgrades();

	//
	// Dependencies
	//
	InitDependencies();

	//
	// Buttons (botpanel)
	//
	InitButtons();

	//
	// Triggers
	//
	InitTriggers();

	SetDefaultTextColors(UI.NormalFontColor, UI.ReverseFontColor);

#if 0
	if (!UI.SelectedViewport) {
		UI.SelectedViewport = UI.Viewports;
	}
#endif
	UI.SelectedViewport->Center(
		ThisPlayer->StartX, ThisPlayer->StartY, TileSizeX / 2, TileSizeY / 2);

	//
	// Various hacks wich must be done after the map is loaded.
	//
	// FIXME: must be done after map is loaded
	InitAStar();
	//
	// FIXME: The palette is loaded after the units are created.
	// FIXME: This loops fixes the colors of the units.
	//
	for (i = 0; i < NumUnits; ++i) {
		// I don't really think that there can be any rescued
		// units at this point.
		if (Units[i]->RescuedFrom) {
			Units[i]->Colors = &Units[i]->RescuedFrom->UnitColors;
		} else {
			Units[i]->Colors = &Units[i]->Player->UnitColors;
		}
	}

	GameResult = GameNoResult;

	CommandLog(NULL, NoUnitP, FlushCommands, -1, -1, NoUnitP, NULL, -1);
	Video.ClearScreen();
}
コード例 #16
0
ファイル: translate.cpp プロジェクト: landswellsong/Stratagus
/**
**  Load a .po file
*/
void LoadPO(const char *file)
{
	FILE *fd;
	char buf[4096];
	enum { MSGNONE, MSGID, MSGSTR } state;
	char msgid[16 * 1024];
	char msgstr[16 * 1024];
	char *s;
	char *currmsg = NULL;
	char fullfile[1024];

	if (!file || !*file) {
		return;
	}

	LibraryFileName(file, fullfile, sizeof(fullfile));
	fd = fopen(fullfile, "rb");
	if (!fd) {
		fprintf(stderr, "Could not open file: %s\n", file);
		return;
	}

	state = MSGNONE;
	msgid[0] = msgstr[0] = '\0';

	// skip 0xEF utf8 intro if found
	char c = fgetc(fd);
	if (c == (char)0xEF) {
		fgetc(fd);
		fgetc(fd);
	} else {
		rewind(fd);
	}

	while (fgets(buf, sizeof(buf), fd)) {
		// Comment
		if (buf[0] == '#') {
			continue;
		}

		s = buf;

		// msgid or msgstr
		if (!strncmp(s, "msgid ", 6)) {
			if (state == MSGSTR) {
				*currmsg = '\0';
				if (*msgid != '\0') {
					AddTranslation(msgid, msgstr);
				}
			}
			state = MSGID;
			currmsg = msgid;
			*currmsg = '\0';
			s += 6;
			while (*s == ' ') ++s;
		} else if (!strncmp(s, "msgstr ", 7)) {
			if (state == MSGID) {
				*currmsg = '\0';
			}
			state = MSGSTR;
			currmsg = msgstr;
			*currmsg = '\0';
			s += 7;
			while (*s == ' ') ++s;
		}

		// String
		if (*s == '"') {
			++s;
			while (*s && *s != '"') {
				if (*s == '\\') {
					++s;
					if (*s) {
						if (*s == 'n') {
							*currmsg++ = '\n';
						} else if (*s == 't') {
							*currmsg++ = '\t';
						} else if (*s == 'r') {
							*currmsg++ = '\r';
						} else if (*s == '"') {
							*currmsg++ = '"';
						} else if (*s == '\\') {
							*currmsg++ = '\\';
						} else {
							fprintf(stderr, "Invalid escape character: %c\n", *s);
						}
						++s;
					} else {
						fprintf(stderr, "Unterminated string\n");
					}
				} else {
					*currmsg++ = *s++;
				}
			}
			continue;
		}
	}
	if (state == MSGSTR) {
		*currmsg = '\0';
		AddTranslation(msgid, msgstr);
	}

	fclose(fd);
}
コード例 #17
0
ファイル: movie.cpp プロジェクト: KroArtem/Wyrmgus
/**
**  Play a video file.
**
**  @param name   Filename of movie file.
**
**  @return       Non-zero if file isn't a supported movie.
*/
int PlayMovie(const std::string &name)
{
	int videoWidth, videoHeight;
#if defined(USE_OPENGL) || defined(USE_GLES)
	videoWidth  = Video.ViewportWidth;
	videoHeight = Video.ViewportHeight;
#else
	videoWidth  = Video.Width;
	videoHeight = Video.Height;
#endif

	const std::string filename = LibraryFileName(name.c_str());

	CFile f;
	if (f.open(filename.c_str(), CL_OPEN_READ) == -1) {
		fprintf(stderr, "Can't open file '%s'\n", name.c_str());
		return 0;
	}

	OggData data;
	memset(&data, 0, sizeof(data));
	if (OggInit(&f, &data) || !data.video) {
		OggFree(&data);
		f.close();
		return -1;
	}

	data.File = &f;
	SDL_Rect rect;

	if (data.tinfo.frame_width * 300 / 4 > data.tinfo.frame_height * 100) {
		rect.w = videoWidth;
		rect.h = videoWidth * data.tinfo.frame_height / data.tinfo.frame_width;
		rect.x = 0;
		rect.y = (videoHeight - rect.h) / 2;
	} else {
		rect.w = videoHeight * data.tinfo.frame_width / data.tinfo.frame_height;
		rect.h = videoHeight;
		rect.x = (videoWidth - rect.w) / 2;
		rect.y = 0;
	}

#ifdef USE_OPENGL
	// When SDL_OPENGL is used, it is not possible to call SDL_CreateYUVOverlay, so turn temporary OpenGL off
	// With GLES is all ok
	if (UseOpenGL) {
		SDL_SetVideoMode(Video.ViewportWidth, Video.ViewportHeight, Video.Depth, SDL_GetVideoSurface()->flags & ~SDL_OPENGL);
	}
#endif

	SDL_FillRect(SDL_GetVideoSurface(), NULL, 0);
	Video.ClearScreen();
	SDL_Overlay *yuv_overlay = SDL_CreateYUVOverlay(data.tinfo.frame_width, data.tinfo.frame_height, SDL_YV12_OVERLAY, TheScreen);

	if (yuv_overlay == NULL) {
		fprintf(stderr, "SDL_CreateYUVOverlay: %s\n", SDL_GetError());
		OggFree(&data);
		f.close();
		return 0;
	}

	StopMusic();
	CSample *sample = LoadVorbis(filename.c_str(), PlayAudioStream);
	if (sample) {
		if ((sample->Channels != 1 && sample->Channels != 2) || sample->SampleSize != 16) {
			fprintf(stderr, "Unsupported sound format in movie\n");
			delete sample;
			SDL_FreeYUVOverlay(yuv_overlay);
			OggFree(&data);
			f.close();
			return 0;
		}
		PlayMusic(sample);
	}

	EventCallback callbacks;

	callbacks.ButtonPressed = MovieCallbackButtonPressed;
	callbacks.ButtonReleased = MovieCallbackButtonReleased;
	callbacks.MouseMoved = MovieCallbackMouseMove;
	callbacks.MouseExit = MovieCallbackMouseExit;
	callbacks.KeyPressed = MovieCallbackKeyPressed;
	callbacks.KeyReleased = MovieCallbackKeyReleased;
	callbacks.KeyRepeated = MovieCallbackKeyRepeated;
	callbacks.NetworkEvent = NetworkEvent;

	const EventCallback *old_callbacks = GetCallbacks();
	SetCallbacks(&callbacks);

	Invalidate();
	RealizeVideoMemory();

	MovieStop = false;
	const unsigned int start_ticks = SDL_GetTicks();
	bool need_data = true;
	while (!MovieStop) {
		if (need_data) {
			if (TheoraProcessData(&data)) {
				break;
			}
			need_data = false;
		}

		const int diff = SDL_GetTicks() - start_ticks
						 - static_cast<int>(theora_granule_time(&data.tstate, data.tstate.granulepos) * 1000);

		if (diff > 100) {
			// too far behind, skip some frames
			need_data = true;
			continue;
		}
		if (diff > 0) {
			OutputTheora(&data, yuv_overlay, &rect);
			need_data = true;
		}

		WaitEventsOneFrame();
	}

	StopMusic();
	SDL_FreeYUVOverlay(yuv_overlay);

	OggFree(&data);
	f.close();

#ifdef USE_OPENGL
	if (UseOpenGL) {
		SDL_SetVideoMode(Video.ViewportWidth, Video.ViewportHeight, Video.Depth, SDL_GetVideoSurface()->flags | SDL_OPENGL);
		ReloadOpenGL();
	}
#endif

	SetCallbacks(old_callbacks);

	return 0;
}