]> git.xonotic.org Git - xonotic/darkplaces.git/blob - cl_video_jamdecode.c
use both .items2 and serverflags in items stat, to finally fix the runes
[xonotic/darkplaces.git] / cl_video_jamdecode.c
1 // JAM format decoder, used by Blood Omnicide
2
3 typedef struct jamdecodestream_s
4 {
5         int error;
6
7         qfile_t *file;
8         double info_framerate;
9         unsigned int info_frames;
10         unsigned int info_imagewidth;
11         unsigned int info_imageheight;
12         int doubleres;
13         float colorscale;
14         unsigned char colorsub;
15         float stipple;
16
17         // info used durign decoding
18         unsigned char *videopixels;
19         unsigned char *compressed;
20         unsigned char *framedata;
21         unsigned char *prevframedata;
22         unsigned char colormap[768];
23         unsigned int framesize;
24         unsigned int framenum;
25
26         // channel the sound file is being played on
27         int sndchan;
28 }
29 jamdecodestream_t;
30
31 #define JAMDECODEERROR_NONE                0
32 #define JAMDECODEERROR_EOF                 1
33 #define JAMDECODEERROR_READERROR           2
34 #define JAMDECODEERROR_BAD_FRAME_HEADER    3
35 #define JAMDECODEERROR_BAD_OUTPUT_SIZE     4
36 #define JAMDECODEERROR_BAD_COLORMAP        5
37
38 // opens a stream
39 void jam_close(void *stream);
40 unsigned int jam_getwidth(void *stream);
41 unsigned int jam_getheight(void *stream);
42 double jam_getframerate(void *stream);
43 int jam_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow);
44 static void *jam_open(clvideo_t *video, char *filename, const char **errorstring)
45 {
46         unsigned char jamHead[16];
47         char *wavename;
48         jamdecodestream_t *s;
49         qfile_t *file;
50
51         s = (jamdecodestream_t *)Z_Malloc(sizeof(jamdecodestream_t));
52         if (s != NULL)
53         {
54                 if ((file = FS_OpenVirtualFile(filename, false)))
55                 {
56                         s->file = file;
57                         if (FS_Read(s->file, &jamHead, 16))
58                         {
59                                 if (!memcmp(jamHead, "JAM", 3))
60                                 {
61                                         s->info_imagewidth = LittleLong(*(jamHead + 4));
62                                         s->info_imageheight = LittleLong(*(jamHead + 8));
63                                         s->info_frames = LittleLong(*(jamHead + 12));
64                                         s->info_framerate = 15;
65                                         s->doubleres = 0;
66                                         s->colorscale = 0.70;
67                                         s->colorsub = 8;
68                                         s->stipple = 0.4;
69                                         s->framesize = s->info_imagewidth * s->info_imageheight;
70                                         if (s->framesize > 0)
71                                         {
72                                                 s->compressed = (unsigned char *)Z_Malloc(s->framesize);
73                                                 s->framedata = (unsigned char *)Z_Malloc(s->framesize * 2);
74                                                 s->prevframedata = (unsigned char *)Z_Malloc(s->framesize * 2);
75                                                 s->videopixels = (unsigned char *)Z_Malloc(s->framesize * 4); // bgra, doubleres
76                                                 if (s->compressed != NULL && s->framedata != NULL && s->prevframedata != NULL && s->videopixels != NULL)
77                                                 {
78                                                         size_t namelen;
79
80                                                         namelen = strlen(filename) + 10;
81                                                         wavename = (char *)Z_Malloc(namelen);
82                                                         if (wavename)
83                                                         {
84                                                                 sfx_t* sfx;
85
86                                                                 FS_StripExtension(filename, wavename, namelen);
87                                                                 strlcat(wavename, ".wav", namelen);
88                                                                 sfx = S_PrecacheSound(wavename, false, false);
89                                                                 if (sfx != NULL)
90                                                                         s->sndchan = S_StartSound (-1, 0, sfx, vec3_origin, 1.0f, 0);
91                                                                 else
92                                                                         s->sndchan = -1;
93                                                                 Z_Free(wavename);
94                                                         }
95                                                         // all is well...
96                                                         // set the module functions
97                                                         s->framenum = 0;
98                                                         video->close = jam_close;
99                                                         video->getwidth = jam_getwidth;
100                                                         video->getheight = jam_getheight;
101                                                         video->getframerate = jam_getframerate;
102                                                         video->decodeframe = jam_video;
103                                                         return s;
104                                                 }
105                                                 else if (errorstring != NULL)
106                                                         *errorstring = "unable to allocate memory for stream info structure";
107                                                 if (s->compressed != NULL)
108                                                         Z_Free(s->compressed);
109                                                 if (s->framedata != NULL)
110                                                         Z_Free(s->framedata);
111                                                 if (s->prevframedata != NULL)
112                                                         Z_Free(s->prevframedata);
113                                                 if (s->videopixels != NULL)
114                                                         Z_Free(s->videopixels);
115                                         }
116                                         else if (errorstring != NULL)
117                                                 *errorstring = "bad framesize";
118                                 }
119                                 else if (errorstring != NULL)
120                                         *errorstring = "not JAM videofile";
121                         }
122                         else if (errorstring != NULL)
123                                 *errorstring = "unexpected EOF";
124                         FS_Close(file);
125                 }
126                 else if (errorstring != NULL)
127                         *errorstring = "unable to open videofile";
128                 Z_Free(s);
129         }
130         else if (errorstring != NULL)
131                 *errorstring = "unable to allocate memory for stream info structure";
132         return NULL;
133 }
134
135 // closes a stream
136 void jam_close(void *stream)
137 {
138         jamdecodestream_t *s = (jamdecodestream_t *)stream;
139         if (s == NULL)
140                 return;
141         Z_Free(s->compressed);
142         Z_Free(s->framedata);
143         Z_Free(s->prevframedata);
144         Z_Free(s->videopixels);
145         if (s->sndchan != -1)
146                 S_StopChannel(s->sndchan, true, true);
147         if (s->file)
148                 FS_Close(s->file);
149         Z_Free(s);
150 }
151
152 // returns the width of the image data
153 unsigned int jam_getwidth(void *stream)
154 {
155         jamdecodestream_t *s = (jamdecodestream_t *)stream;
156         if (s->doubleres)
157                 return s->info_imagewidth * 2;
158         return s->info_imagewidth;
159 }
160
161 // returns the height of the image data
162 unsigned int jam_getheight(void *stream)
163 {
164         jamdecodestream_t *s = (jamdecodestream_t *)stream;
165         if (s->doubleres)
166                 return s->info_imageheight * 2;
167         return s->info_imageheight;
168 }
169
170 // returns the framerate of the stream
171 double jam_getframerate(void *stream)
172 {
173         jamdecodestream_t *s = (jamdecodestream_t *)stream;
174         return s->info_framerate;
175 }
176
177
178 // decode JAM frame
179 static void jam_decodeframe(unsigned char *inbuf, unsigned char *outbuf, unsigned char *prevbuf, int outsize, int frametype)
180 {
181         unsigned char *srcptr, *destptr, *prevptr;
182         int bytesleft;
183         unsigned int mark;
184         unsigned short int bits;
185         int rep;
186         int backoffs;
187         unsigned char *back;
188         int i;
189
190         srcptr = inbuf;
191         destptr = outbuf;
192         prevptr = prevbuf;
193         bytesleft = outsize;
194
195         if (frametype == 2)
196         {
197                 memcpy(outbuf, inbuf, outsize);
198                 return;
199         }
200         while(bytesleft > 0)
201         {
202                 memcpy(&mark, srcptr, 4);
203                 srcptr += 4;
204                 for(i=0; i<32 && bytesleft > 0; i++,mark=mark>>1)
205                 {
206                         if(mark & 1)
207                         {
208                                 *destptr = *srcptr;
209                                 destptr ++;
210                                 prevptr ++;
211                                 srcptr ++;
212                                 bytesleft --;
213                         }
214                         else
215                         {
216                                 bits = srcptr[0] + 256*srcptr[1];
217                                 rep = (bits >> 11) + 3;
218                                 if(frametype == 1)
219                                 {
220                                         backoffs = 0x821 - (bits & 0x7ff);
221                                         back = destptr - backoffs;
222                                 }
223                                 else
224                                 {
225                                         backoffs = 0x400 - (bits & 0x7ff);
226                                         back = prevptr - backoffs;
227                                 }
228                                 srcptr += 2;
229                                 memcpy(destptr, back, rep);
230                                 destptr += rep;
231                                 prevptr += rep;
232                                 bytesleft -= rep;
233                         }
234                 }
235         }
236 }
237
238 // decodes a video frame to the supplied output pixels
239 int jam_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow)
240 {
241         unsigned char frameHead[16], *b;
242         unsigned int compsize, outsize, i, j;
243         jamdecodestream_t *s = (jamdecodestream_t *)stream;
244
245         s->error = DPVSIMPLEDECODEERROR_NONE;
246         if (s->framenum < s->info_frames)
247         {
248 readframe:
249                 if (FS_Read(s->file, &frameHead, 16))
250                 {
251                         compsize = LittleLong(*(frameHead + 8)) - 16;
252                         outsize = LittleLong(*(frameHead + 12));
253                         if (compsize > s->framesize || outsize > s->framesize)
254                                 s->error = JAMDECODEERROR_BAD_FRAME_HEADER;
255                         else if (FS_Read(s->file, s->compressed, compsize))
256                         {
257                                 // palette goes interleaved with special flag
258                                 if (frameHead[0] == 2)
259                                 {
260                                         if (compsize == 768)
261                                         {
262                                                 memcpy(s->colormap, s->compressed, 768);
263                                                 for(i = 0; i < 768; i++)
264                                                         s->colormap[i] = (unsigned char)(bound(0, (s->colormap[i] * s->colorscale) - s->colorsub, 255));
265                                                 goto readframe;
266                                         }
267                                         //else
268                                         //      s->error = JAMDECODEERROR_BAD_COLORMAP;
269                                 }
270                                 else
271                                 {
272                                         // decode frame
273                                         // shift buffers to provide current and previous one, decode
274                                         b = s->prevframedata;
275                                         s->prevframedata = s->framedata;
276                                         s->framedata = b;
277                                         jam_decodeframe(s->compressed, s->framedata, s->prevframedata, outsize, frameHead[4]);
278                                         // make 32bit imagepixels from 8bit palettized frame
279                                         if (s->doubleres)
280                                                 b = s->videopixels;
281                                         else
282                                                 b = (unsigned char *)imagedata;
283                                         for(i = 0; i < s->framesize; i++)
284                                         {
285                                                 // bgra
286                                                 *b++ = s->colormap[s->framedata[i]*3 + 2];
287                                                 *b++ = s->colormap[s->framedata[i]*3 + 1];
288                                                 *b++ = s->colormap[s->framedata[i]*3];
289                                                 *b++ = 255;
290                                         }
291                                         // nearest 2x
292                                         if (s->doubleres)
293                                         {
294                                                 for (i = 0; i < s->info_imageheight; i++)
295                                                 {
296                                                         b = (unsigned char *)imagedata + (s->info_imagewidth*2*4)*(i*2);
297                                                         for (j = 0; j < s->info_imagewidth; j++)
298                                                         {
299                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];
300                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];
301                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];
302                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];
303                                                                 //
304                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];
305                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];
306                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];
307                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];
308                                                         }
309                                                         b = (unsigned char *)imagedata + (s->info_imagewidth*2*4)*(i*2 + 1);
310                                                         for (j = 0; j < s->info_imagewidth; j++)
311                                                         {
312                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];
313                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];
314                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];
315                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];
316                                                                 //
317                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];
318                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];
319                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];
320                                                                 *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];
321                                                         }
322                                                 }
323                                                 // do stippling
324                                                 if (s->stipple)
325                                                 {
326                                                         for (i = 0; i < s->info_imageheight; i++)
327                                                         {
328                                                                 b = (unsigned char *)imagedata + (s->info_imagewidth * 4 * 2 * 2 * i);
329                                                                 for (j = 0; j < s->info_imagewidth; j++)
330                                                                 {
331                                                                         b[0] = b[0] * s->stipple;
332                                                                         b[1] = b[1] * s->stipple;
333                                                                         b[2] = b[2] * s->stipple;
334                                                                         b += 4;
335                                                                         b[0] = b[0] * s->stipple;
336                                                                         b[1] = b[1] * s->stipple;
337                                                                         b[2] = b[2] * s->stipple;
338                                                                         b += 4;
339                                                                 }
340                                                         }
341                                                 }
342                                         }
343
344                                 }
345                         }
346                         else
347                                 s->error = JAMDECODEERROR_READERROR;
348                 }
349                 else
350                         s->error = JAMDECODEERROR_READERROR;
351         }
352         else
353                 s->error = DPVSIMPLEDECODEERROR_EOF;
354         return s->error;
355 }