+ if (!subtitle_text)
+ subtitle_text = (char *)FS_LoadFile(subtitlesfile, cls.permanentmempool, false, NULL);
+ }
+ else
+ {
+ subtitle_text = (char *)FS_LoadFile(subtitlesfile, cls.permanentmempool, false, NULL);
+ }
+ if (!subtitle_text)
+ {
+ Con_DPrintf( "LoadSubtitles: can't open subtitle file '%s'!\n", subtitlesfile );
+ return;
+ }
+
+ // parse subtitle_text
+ // line is: x y "text" where
+ // x - start time
+ // y - seconds last (if 0 - last thru next sub, if negative - last to next sub - this amount of seconds)
+
+ data = subtitle_text;
+ for (;;)
+ {
+ if (!COM_ParseToken_QuakeC(&data, false))
+ break;
+ subtime = atof( com_token );
+ if (!COM_ParseToken_QuakeC(&data, false))
+ break;
+ sublen = atof( com_token );
+ if (!COM_ParseToken_QuakeC(&data, false))
+ break;
+ if (!com_token[0])
+ continue;
+ // check limits
+ if (video->subtitles == CLVIDEO_MAX_SUBTITLES)
+ {
+ Con_Printf(CON_WARN "WARNING: CLVIDEO_MAX_SUBTITLES = %i reached when reading subtitles from '%s'\n", CLVIDEO_MAX_SUBTITLES, subtitlesfile);
+ break;
+ }
+ // add a sub
+ video->subtitle_text[numsubs] = (char *) Mem_Alloc(cls.permanentmempool, strlen(com_token) + 1);
+ memcpy(video->subtitle_text[numsubs], com_token, strlen(com_token) + 1);
+ video->subtitle_start[numsubs] = subtime;
+ video->subtitle_end[numsubs] = sublen;
+ if (numsubs > 0) // make true len for prev sub, autofix overlapping subtitles
+ {
+ if (video->subtitle_end[numsubs-1] <= 0)
+ video->subtitle_end[numsubs-1] = max(video->subtitle_start[numsubs-1], video->subtitle_start[numsubs] + video->subtitle_end[numsubs-1]);
+ else
+ video->subtitle_end[numsubs-1] = min(video->subtitle_start[numsubs-1] + video->subtitle_end[numsubs-1], video->subtitle_start[numsubs]);
+ }
+ numsubs++;
+ // todo: check timing for consistency?
+ }
+ if (numsubs > 0) // make true len for prev sub, autofix overlapping subtitles
+ {
+ if (video->subtitle_end[numsubs-1] <= 0)
+ video->subtitle_end[numsubs-1] = (float)99999999; // fixme: make it end when video ends?
+ else
+ video->subtitle_end[numsubs-1] = video->subtitle_start[numsubs-1] + video->subtitle_end[numsubs-1];
+ }
+ Z_Free( subtitle_text );
+ video->subtitles = numsubs;
+/*
+ Con_Printf( "video->subtitles: %i\n", video->subtitles );
+ for (numsubs = 0; numsubs < video->subtitles; numsubs++)
+ Con_Printf( " %03.2f %03.2f : %s\n", video->subtitle_start[numsubs], video->subtitle_end[numsubs], video->subtitle_text[numsubs] );
+*/
+}
+
+static clvideo_t* OpenVideo( clvideo_t *video, const char *filename, const char *name, int owner, const char *subtitlesfile )
+{
+ strlcpy(video->filename, filename, sizeof(video->filename));
+ dpsnprintf(video->name, sizeof(video->name), CLVIDEOPREFIX "%s", name);
+ video->ownertag = owner;
+ if( strncmp( name, CLVIDEOPREFIX, sizeof( CLVIDEOPREFIX ) - 1 ) )
+ return NULL;
+ video->cachepic = Draw_CachePic_Flags(name, CACHEPICFLAG_NOTPERSISTENT | CACHEPICFLAG_QUIET);
+
+ if( !OpenStream( video ) )
+ return NULL;
+
+ video->state = CLVIDEO_FIRSTFRAME;
+ video->framenum = -1;
+ video->framerate = video->getframerate( video->stream );
+ video->lasttime = host.realtime;
+ video->subtitles = 0;
+
+ video->width = video->getwidth( video->stream );
+ video->height = video->getheight( video->stream );
+ video->imagedata = Mem_Alloc( cls.permanentmempool, video->width * video->height * cl_videobytesperpixel );
+ LinkVideoTexture( video );
+
+ // VorteX: load simple subtitle_text file
+ if (subtitlesfile[0])
+ LoadSubtitles( video, subtitlesfile );
+
+ return video;
+}
+
+clvideo_t* CL_OpenVideo( const char *filename, const char *name, int owner, const char *subtitlesfile )
+{
+ clvideo_t *video;
+ // sanity check
+ if( !name || !*name || strncmp( name, CLVIDEOPREFIX, sizeof( CLVIDEOPREFIX ) - 1 ) != 0 ) {
+ Con_DPrintf( "CL_OpenVideo: Bad video texture name '%s'!\n", name );
+ return NULL;
+ }
+
+ video = FindUnusedVid();
+ if( !video ) {
+ Con_Printf(CON_ERROR "CL_OpenVideo: unable to open video \"%s\" - video limit reached\n", filename );
+ return NULL;
+ }
+ video = OpenVideo( video, filename, name, owner, subtitlesfile );
+ // expand the active range to include the new entry
+ if (video) {
+ cl_num_videos = max(cl_num_videos, (int)(video - cl_videos) + 1);
+ }
+ return video;
+}
+
+static clvideo_t* CL_GetVideoBySlot( int slot )
+{
+ clvideo_t *video = &cl_videos[ slot ];
+
+ if( video->suspended )
+ {
+ if( !WakeVideo( video ) )
+ return NULL;
+ else if( video->state == CLVIDEO_RESETONWAKEUP )
+ video->framenum = -1;
+ }
+
+ video->lasttime = host.realtime;
+
+ return video;
+}
+
+clvideo_t *CL_GetVideoByName( const char *name )
+{
+ int i;
+
+ for( i = 0 ; i < cl_num_videos ; i++ )
+ if( cl_videos[ i ].state != CLVIDEO_UNUSED
+ && !strcmp( cl_videos[ i ].name , name ) )
+ break;
+ if( i != cl_num_videos )
+ return CL_GetVideoBySlot( i );
+ else
+ return NULL;
+}
+
+void CL_SetVideoState(clvideo_t *video, clvideostate_t state)
+{
+ if (!video)
+ return;
+
+ video->lasttime = host.realtime;
+ video->state = state;
+ if (state == CLVIDEO_FIRSTFRAME)
+ CL_RestartVideo(video);
+}
+
+void CL_RestartVideo(clvideo_t *video)
+{
+ if (!video)
+ return;
+
+ // reset time
+ video->starttime = video->lasttime = host.realtime;
+ video->framenum = -1;
+
+ // reopen stream
+ if (video->stream)
+ video->close(video->stream);
+ video->stream = NULL;
+ if (!OpenStream(video))
+ video->state = CLVIDEO_UNUSED;
+}
+
+// close video
+void CL_CloseVideo(clvideo_t * video)
+{
+ int i;
+
+ if (!video || video->state == CLVIDEO_UNUSED)
+ return;
+
+ // close stream
+ if (!video->suspended || video->state != CLVIDEO_FIRSTFRAME)
+ {
+ if (video->stream)
+ video->close(video->stream);
+ video->stream = NULL;
+ }
+ // unlink texture
+ if (!video->suspended)
+ UnlinkVideoTexture(video);
+ // purge subtitles
+ if (video->subtitles)
+ {
+ for (i = 0; i < video->subtitles; i++)
+ Z_Free( video->subtitle_text[i] );
+ video->subtitles = 0;