-Added the console command prvm_globalset
[xonotic/darkplaces.git] / cl_video.c
1
2 #include "quakedef.h"
3 #include "cl_video.h"
4 #include "dpvsimpledecode.h"
5
6 // constants (and semi-constants)
7 static int  cl_videormask;
8 static int  cl_videobmask;
9 static int  cl_videogmask;
10 static int      cl_videobytesperpixel;
11
12 static clvideo_t videoarray[ MAXCLVIDEOS ];
13 static mempool_t *cl_videomempool;
14 static rtexturepool_t *cl_videotexturepool;
15
16 static clvideo_t *FindUnusedVid( void )
17 {
18         int i;
19         for( i = 1 ; i < MAXCLVIDEOS ; i++ )
20                 if( videoarray[ i ].state == CLVIDEO_UNUSED )
21                         return &videoarray[ i ];
22         return NULL;
23 }
24
25 static qboolean OpenStream( clvideo_t * video )
26 {
27         char *errorstring;
28         video->stream = dpvsimpledecode_open( video->filename, &errorstring);
29         if (!video->stream )
30         {
31                 Con_Printf("unable to open \"%s\", error: %s\n", video->filename, errorstring);
32                 return false;
33         }
34         return true;
35 }
36
37 static void SuspendVideo( clvideo_t * video )
38 {
39         if( video->suspended )
40                 return;
41         video->suspended = true;
42         // free the texture
43         R_FreeTexture( video->cpif.tex );
44         // free the image data
45         Mem_Free( video->imagedata );
46         // if we are in firstframe mode, also close the stream
47         if( video->state == CLVIDEO_FIRSTFRAME ) 
48                 dpvsimpledecode_close( video->stream ); 
49 }
50
51 static qboolean WakeVideo( clvideo_t * video )
52 {
53         if( !video->suspended )
54                 return true;
55         video->suspended = false;
56         
57         if( video->state == CLVIDEO_FIRSTFRAME )
58                 if( !OpenStream( video ) ) {
59                         video->state = CLVIDEO_UNUSED;
60                         return false;
61                 }
62                 
63         video->imagedata = Mem_Alloc( cl_videomempool, video->cpif.width * video->cpif.height * cl_videobytesperpixel );
64         video->cpif.tex = R_LoadTexture2D( cl_videotexturepool, video->cpif.name, 
65                 video->cpif.width, video->cpif.height, NULL, TEXTYPE_RGBA, 0, NULL );    
66
67         // update starttime
68         video->starttime += realtime - video->lasttime;
69         return true;
70 }
71
72 static clvideo_t* OpenVideo( clvideo_t *video, char *filename, char *name, int owner )
73 {
74         strncpy( video->filename, filename, MAX_QPATH );
75         video->ownertag = owner;
76         strncpy( video->cpif.name, CLVIDEOPREFIX, MAX_QPATH );
77         strncat( video->cpif.name, name, MAX_QPATH - sizeof( CLVIDEOPREFIX ) );
78
79         if( !OpenStream( video ) )
80                 return NULL;
81
82         video->state = CLVIDEO_FIRSTFRAME;
83         video->framenum = -1;
84         video->framerate = dpvsimpledecode_getframerate( video->stream );
85         video->lasttime = realtime;
86
87         video->cpif.width = dpvsimpledecode_getwidth( video->stream );
88         video->cpif.height = dpvsimpledecode_getheight( video->stream );
89         video->cpif.tex = R_LoadTexture2D( cl_videotexturepool, video->cpif.name, 
90                 video->cpif.width, video->cpif.height, NULL, TEXTYPE_RGBA, 0, NULL );
91
92     video->imagedata = Mem_Alloc( cl_videomempool, video->cpif.width * video->cpif.height * cl_videobytesperpixel );
93
94         return video;
95 }
96
97 clvideo_t* CL_OpenVideo( char *filename, char *name, int owner )
98 {
99         clvideo_t *video;
100
101         video = FindUnusedVid();
102         if( !video ) {
103                 Con_Printf( "unable to open video \"%s\" - video limit reached\n", filename );
104                 return NULL;
105         }
106         return OpenVideo( video, filename, name, owner );
107 }
108
109 clvideo_t* CL_GetVideo( char *name )
110 {
111         int i;
112         clvideo_t *video;
113
114         for( i = 0 ; i < MAXCLVIDEOS ; i++ )
115                 if( videoarray[ i ].state != CLVIDEO_UNUSED 
116                         &&      !strcmp( videoarray[ i ].cpif.name , name ) )
117                         break;
118         if( i == MAXCLVIDEOS )
119                 return NULL;
120         video = &videoarray[ i ];
121
122         if( video->suspended )
123                 if( !WakeVideo( video ) )
124                         return NULL;
125         video->lasttime = realtime;
126
127         return video;
128 }
129
130 void CL_StartVideo( clvideo_t * video )
131 {
132         if( !video )
133                 return;
134
135         video->starttime = video->lasttime = realtime;
136         video->framenum = -1;
137         video->state = CLVIDEO_PLAY;
138 }
139
140 void CL_LoopVideo( clvideo_t * video )
141 {
142         if( !video )
143                 return;
144
145         video->starttime = video->lasttime = realtime;
146         video->framenum = -1;
147         video->state = CLVIDEO_LOOP;
148 }
149
150 void CL_PauseVideo( clvideo_t * video )
151 {
152         if( !video )
153                 return;
154
155         video->state = CLVIDEO_PAUSE;
156         video->lasttime = realtime;
157 }
158
159 void CL_RestartVideo( clvideo_t *video )
160 {
161         if( !video )
162                 return;
163     
164         video->starttime = video->lasttime = realtime;
165         video->framenum = -1;
166 }
167
168 void CL_StopVideo( clvideo_t * video )
169 {
170         if( !video )
171                 return;
172
173         video->lasttime = realtime;
174         video->framenum = -1;
175         video->state = CLVIDEO_FIRSTFRAME;
176 }
177
178 void CL_CloseVideo( clvideo_t * video )
179 {
180         if( !video || video->state == CLVIDEO_UNUSED )
181                 return;
182
183         video->state = CLVIDEO_UNUSED;
184         
185         if( !video->suspended || video->state != CLVIDEO_FIRSTFRAME )
186                 dpvsimpledecode_close( video->stream );
187         if( !video->suspended ) {
188                 Mem_Free( video->imagedata );
189                 R_FreeTexture( video->cpif.tex );
190         }
191 }
192
193 static void VideoFrame( clvideo_t *video )
194 {
195         int destframe;
196
197         if( video->state == CLVIDEO_FIRSTFRAME )
198                 destframe = 0;
199         else
200                 destframe = (realtime - video->starttime) * video->framerate;
201         if( destframe < 0 )
202                 destframe = 0;
203         if( video->framenum < destframe ) {
204                 do {
205                         video->framenum++;
206                         if( dpvsimpledecode_video( video->stream, video->imagedata, cl_videormask, 
207                                 cl_videogmask, cl_videobmask, cl_videobytesperpixel, 
208                                 cl_videobytesperpixel * video->cpif.width ) 
209                                 ) { // finished?
210                                 video->framenum = -1;
211                                 if( video->state == CLVIDEO_LOOP )
212                                                 video->starttime = realtime;
213                                 else if( video->state == CLVIDEO_PLAY )
214                                                 video->state = CLVIDEO_FIRSTFRAME;
215                                 return;
216                         }
217                 } while( video->framenum < destframe );
218                 R_UpdateTexture( video->cpif.tex, video->imagedata );
219         }                                       
220 }
221
222 void CL_VideoFrame( void ) // update all videos
223 {
224         int i;
225         clvideo_t *video;
226
227         for( video = videoarray, i = 0 ; i < MAXCLVIDEOS ; video++, i++ )
228                 if( video->state != CLVIDEO_UNUSED && !video->suspended )
229                         if( realtime - video->lasttime > CLTHRESHOLD )
230                                 SuspendVideo( video );
231                         else if( video->state == CLVIDEO_PAUSE )
232                                 video->starttime = realtime + video->framenum * video->framerate;
233                         else 
234                                 VideoFrame( video );
235
236         if( videoarray->state == CLVIDEO_FIRSTFRAME )
237                 CL_VideoStop();
238 }
239
240 void CL_Video_Shutdown( void )
241 {
242         int i;
243         for( i = 0 ; i < MAXCLVIDEOS ; i++ )
244                 CL_CloseVideo( &videoarray[ i ] );
245
246         R_FreeTexturePool( &cl_videotexturepool );
247         Mem_FreePool( &cl_videomempool );
248 }
249
250 void CL_PurgeOwner( int owner )
251 {
252         int i;
253         for( i = 0 ; i < MAXCLVIDEOS ; i++ )
254                 if( videoarray[ i ].ownertag == owner )
255                         CL_CloseVideo( &videoarray[ i ] );
256 }
257
258 int cl_videoplaying = false; // old, but still supported
259
260 void CL_DrawVideo(void)
261 {
262         if (cl_videoplaying)
263                 DrawQ_Pic(0, 0, videoarray->cpif.name, vid.conwidth, vid.conheight, 1, 1, 1, 1, 0);
264 }
265
266 void CL_VideoStart(char *filename)
267 {
268         if( videoarray->state != CLVIDEO_UNUSED )
269                 CL_CloseVideo( videoarray );
270         if( !OpenVideo( videoarray, filename, filename, 0 ) )
271                 return;
272
273         cl_videoplaying = true;
274
275         CL_StartVideo( videoarray );
276 }
277
278 void CL_VideoStop(void)
279 {
280         cl_videoplaying = false;
281
282         CL_CloseVideo( videoarray );
283 }
284
285 static void CL_PlayVideo_f(void)
286 {
287         char name[1024];
288
289         if (Cmd_Argc() != 2)
290         {
291                 Con_Print("usage: playvideo <videoname>\nplays video named video/<videoname>.dpv\n");
292                 return;
293         }
294
295         sprintf(name, "video/%s.dpv", Cmd_Argv(1));
296         CL_VideoStart(name);
297 }
298
299 static void CL_StopVideo_f(void)
300 {
301         CL_VideoStop();
302 }
303
304 void CL_Video_Init( void )
305 {
306         cl_videobytesperpixel = 4;
307         cl_videormask = BigLong(0xFF000000);
308         cl_videogmask = BigLong(0x00FF0000);
309         cl_videobmask = BigLong(0x0000FF00);
310
311         cl_videomempool = Mem_AllocPool( "CL_Video", 0, NULL );
312         cl_videotexturepool = R_AllocTexturePool();
313
314         Cmd_AddCommand( "playvideo", CL_PlayVideo_f );
315         Cmd_AddCommand( "stopvideo", CL_StopVideo_f );
316 }