+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) );
+ video->ownertag = owner;
+ if( strncmp( name, CLVIDEOPREFIX, sizeof( CLVIDEOPREFIX ) - 1 ) )
+ return NULL;
+ strlcpy( video->cpif.name, name, sizeof(video->cpif.name) );
+
+ if( !OpenStream( video ) )
+ return NULL;
+
+ video->state = CLVIDEO_FIRSTFRAME;
+ video->framenum = -1;
+ video->framerate = video->getframerate( video->stream );
+ video->lasttime = realtime;
+ video->subtitles = 0;
+
+ video->cpif.width = video->getwidth( video->stream );
+ video->cpif.height = video->getheight( video->stream );
+ video->imagedata = Mem_Alloc( cls.permanentmempool, video->cpif.width * video->cpif.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( "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 = 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 ].cpif.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 = 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 = realtime;
+ video->framenum = -1;
+
+ // reopen stream
+ video->close(video->stream);
+ 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)
+ video->close(video->stream);
+ // 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;
+ }
+ video->state = CLVIDEO_UNUSED;
+}
+
+// update all videos
+void CL_Video_Frame(void)
+{
+ clvideo_t *video;
+ int destframe;
+ int i;
+
+ if (!cl_num_videos)
+ return;
+ for (video = cl_videos, i = 0 ; i < cl_num_videos ; video++, i++)
+ {
+ if (video->state != CLVIDEO_UNUSED && !video->suspended)
+ {
+ if (realtime - video->lasttime > CLTHRESHOLD)
+ {
+ SuspendVideo(video);
+ continue;
+ }
+ if (video->state == CLVIDEO_PAUSE)
+ {
+ video->starttime = realtime - video->framenum * video->framerate;
+ continue;
+ }
+ // read video frame from stream if time has come
+ if (video->state == CLVIDEO_FIRSTFRAME )
+ destframe = 0;
+ else
+ destframe = (int)((realtime - video->starttime) * video->framerate);
+ if (destframe < 0)
+ destframe = 0;
+ if (video->framenum < destframe)
+ {
+ do {
+ video->framenum++;
+ if (video->decodeframe(video->stream, video->imagedata, cl_videormask, cl_videogmask, cl_videobmask, cl_videobytesperpixel, cl_videobytesperpixel * video->cpif.width))
+ {
+ // finished?
+ CL_RestartVideo(video);
+ if (video->state == CLVIDEO_PLAY)
+ video->state = CLVIDEO_FIRSTFRAME;
+ return;
+ }
+ } while(video->framenum < destframe);
+ R_MarkDirtyTexture(video->cpif.tex);
+ }
+ }
+ }
+
+ // stop main video
+ if (cl_videos->state == CLVIDEO_FIRSTFRAME)
+ CL_VideoStop();
+
+ // reduce range to exclude unnecessary entries
+ while(cl_num_videos > 0 && cl_videos[cl_num_videos-1].state == CLVIDEO_UNUSED)
+ cl_num_videos--;
+}
+
+void CL_Video_Shutdown( void )
+{
+ int i;
+ for (i = 0 ; i < cl_num_videos ; i++)
+ CL_CloseVideo(&cl_videos[ i ]);
+}
+
+void CL_PurgeOwner( int owner )
+{
+ int i;
+
+ for (i = 0 ; i < cl_num_videos ; i++)
+ if (cl_videos[i].ownertag == owner)
+ CL_CloseVideo(&cl_videos[i]);
+}
+
+typedef struct
+{
+ dp_font_t *font;
+ float x;
+ float y;
+ float width;
+ float height;
+ float alignment; // 0 = left, 0.5 = center, 1 = right
+ float fontsize;
+ float textalpha;
+}
+cl_video_subtitle_info_t;
+
+float CL_DrawVideo_WordWidthFunc(void *passthrough, const char *w, size_t *length, float maxWidth)
+{
+ cl_video_subtitle_info_t *si = (cl_video_subtitle_info_t *) passthrough;
+
+ if(w == NULL)
+ return si->fontsize * si->font->maxwidth;
+ if(maxWidth >= 0)
+ return DrawQ_TextWidth_UntilWidth(w, length, si->fontsize, si->fontsize, false, si->font, -maxWidth); // -maxWidth: we want at least one char
+ else if(maxWidth == -1)
+ return DrawQ_TextWidth(w, *length, si->fontsize, si->fontsize, false, si->font);
+ else
+ return 0;
+}
+
+int CL_DrawVideo_DisplaySubtitleLine(void *passthrough, const char *line, size_t length, float width, qboolean isContinuation)
+{
+ cl_video_subtitle_info_t *si = (cl_video_subtitle_info_t *) passthrough;
+
+ int x = (int) (si->x + (si->width - width) * si->alignment);
+ if (length > 0)
+ DrawQ_String(x, si->y, line, length, si->fontsize, si->fontsize, 1.0, 1.0, 1.0, si->textalpha, 0, NULL, false, si->font);
+ si->y += si->fontsize;
+ return 1;
+}
+
+int cl_videoplaying = false; // old, but still supported
+