]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/qdata_heretic2/video.c
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / video.c
1 /*\r
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.\r
4 \r
5 This file is part of GtkRadiant.\r
6 \r
7 GtkRadiant is free software; you can redistribute it and/or modify\r
8 it under the terms of the GNU General Public License as published by\r
9 the Free Software Foundation; either version 2 of the License, or\r
10 (at your option) any later version.\r
11 \r
12 GtkRadiant is distributed in the hope that it will be useful,\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 GNU General Public License for more details.\r
16 \r
17 You should have received a copy of the GNU General Public License\r
18 along with GtkRadiant; if not, write to the Free Software\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
20 */\r
21 \r
22 // To do\r
23 \r
24 // Sound error handling (when sound too short)\r
25 // rle b4 huffing\r
26 // adpcm encoding of sound\r
27 \r
28 #if     0\r
29 #include "qdata.h"\r
30 #include "flex.h"\r
31 #include "fc.h"\r
32 #include "adpcm.h"\r
33 \r
34 #define MIN_REPT        15\r
35 #define MAX_REPT        0\r
36 #define HUF_TOKENS      (256 + MAX_REPT)\r
37 \r
38 #define BLOCKSIZE       8\r
39 \r
40 #define M_PI            3.14159265358979323846  // matches value in gcc v2 math.h\r
41 #define SQRT2           1.414213562\r
42 \r
43 typedef struct hnode_s\r
44 {\r
45         int                     count;\r
46         qboolean        used;\r
47         int                     children[2];\r
48 } hnode_t;\r
49 \r
50 typedef struct\r
51 {\r
52         int                     rate;\r
53         int                     width;\r
54         int                     channels;\r
55         int                     loopstart;\r
56         int                     samples;\r
57         int                     dataofs;                // chunk starts this many bytes from file start\r
58 } wavinfo_t;\r
59 \r
60 // These weren`t picked out my ass....\r
61 // They were defined at http://www.rahul.net/jfm/dct.html\r
62 // However, I think he plucked them out of his ass.....\r
63 \r
64 float Quantise[BLOCKSIZE * BLOCKSIZE];\r
65 \r
66 float LUT_Quantise[BLOCKSIZE * BLOCKSIZE] =\r
67 {\r
68         16.0F/16.0F, 11.0F/16.0F, 10.0F/16.0F, 16.0F/16.0F, 24.0F/16.0F, 40.0F/16.0F, 51.0F/16.0F, 61.0F/16.0F,\r
69         12.0F/16.0F, 13.0F/16.0F, 14.0F/16.0F, 19.0F/16.0F, 26.0F/16.0F, 58.0F/16.0F, 60.0F/16.0F, 55.0F/16.0F,\r
70         14.0F/16.0F, 13.0F/16.0F, 16.0F/16.0F, 24.0F/16.0F, 40.0F/16.0F, 57.0F/16.0F, 69.0F/16.0F, 56.0F/16.0F,\r
71         14.0F/16.0F, 17.0F/16.0F, 22.0F/16.0F, 29.0F/16.0F, 51.0F/16.0F, 87.0F/16.0F, 80.0F/16.0F, 62.0F/16.0F,\r
72         18.0F/16.0F, 22.0F/16.0F, 37.0F/16.0F, 56.0F/16.0F, 68.0F/16.0F,109.0F/16.0F,103.0F/16.0F, 77.0F/16.0F,\r
73         24.0F/16.0F, 35.0F/16.0F, 55.0F/16.0F, 64.0F/16.0F, 81.0F/16.0F,104.0F/16.0F,113.0F/16.0F, 92.0F/16.0F,\r
74         49.0F/16.0F, 64.0F/16.0F, 78.0F/16.0F, 87.0F/16.0F,103.0F/16.0F,121.0F/16.0F,120.0F/16.0F,101.0F/16.0F,\r
75         72.0F/16.0F, 92.0F/16.0F, 95.0F/16.0F, 98.0F/16.0F,112.0F/16.0F,100.0F/16.0F,103.0F/16.0F, 99.0F/16.0F\r
76 };\r
77 \r
78 int LUT_ZZ[BLOCKSIZE * BLOCKSIZE] =\r
79 {\r
80          0,\r
81          1,  8, \r
82         16,  9,  2,\r
83          3, 10, 17, 24,\r
84         32, 25, 18, 11,  4,\r
85          5, 12, 19, 26, 33, 40,\r
86         48, 41, 34, 27, 20, 13, 6,\r
87          7, 14, 21, 28, 35, 42, 49, 56,\r
88         57, 50, 43, 36, 29, 22, 15,\r
89         23, 30, 37, 44, 51, 58,\r
90         59, 52, 45, 38, 31, \r
91         39, 46, 53, 60,\r
92         61, 54, 47,\r
93         55, 62, \r
94         63\r
95 };\r
96 \r
97 char                    base[32];\r
98 \r
99 byte                    *soundtrack;\r
100 \r
101 byte                    scaled[256][HUF_TOKENS];\r
102 unsigned int    charbits1[256][HUF_TOKENS];\r
103 int                             charbitscount1[256][HUF_TOKENS];\r
104 hnode_t                 hnodes1[256][HUF_TOKENS * 2];\r
105 int                             numhnodes1[256];\r
106 int                             order0counts[256];\r
107 int                             numhnodes;\r
108 hnode_t                 hnodes[512];\r
109 unsigned                charbits[256];\r
110 int                             charbitscount[256];\r
111 \r
112 CineHead_t              cinehead;\r
113 \r
114 byte                    *data_p;\r
115 byte                    *iff_end;\r
116 byte                    *last_chunk;\r
117 byte                    *iff_data;\r
118 int                             iff_chunk_len;\r
119 \r
120 float                   dctbase[BLOCKSIZE][BLOCKSIZE];\r
121 float                   red[BLOCKSIZE * BLOCKSIZE];\r
122 float                   green[BLOCKSIZE * BLOCKSIZE];\r
123 float                   blue[BLOCKSIZE * BLOCKSIZE];\r
124 float                   temp[BLOCKSIZE * BLOCKSIZE];\r
125 \r
126 wavinfo_t               wavinfo;\r
127 adpcm_t                 adpcm;\r
128 \r
129 /*\r
130 ===============================================================================\r
131 \r
132 WAV loading\r
133 \r
134 ===============================================================================\r
135 */\r
136 \r
137 /* Intel ADPCM step variation table */\r
138 static int indexTable[16] = \r
139 {\r
140         -1, -1, -1, -1, 2, 4, 6, 8,\r
141         -1, -1, -1, -1, 2, 4, 6, 8,\r
142 };\r
143 \r
144 static int stepsizeTable[89] = \r
145 {\r
146         7, 8, 9, 10, 11, 12, 13, 14, 16, 17,\r
147         19, 21, 23, 25, 28, 31, 34, 37, 41, 45,\r
148         50, 55, 60, 66, 73, 80, 88, 97, 107, 118,\r
149         130, 143, 157, 173, 190, 209, 230, 253, 279, 307,\r
150         337, 371, 408, 449, 494, 544, 598, 658, 724, 796,\r
151         876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,\r
152         2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,\r
153         5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,\r
154         15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767\r
155 };\r
156 \r
157 #if     0\r
158 static void adpcm_decoder(char *indata, short *outdata, int len, adpcm_state_t *state)\r
159 {\r
160         signed char *inp;               /* Input buffer pointer */\r
161         short *outp;            /* output buffer pointer */\r
162         int sign;                       /* Current adpcm sign bit */\r
163         int delta;                      /* Current adpcm output value */\r
164         int step;                       /* Stepsize */\r
165         int valpred;            /* Predicted value */\r
166         int vpdiff;             /* Current change to valpred */\r
167         int index;                      /* Current step change index */\r
168         int inputbuffer;                /* place to keep next 4-bit value */\r
169         int bufferstep;         /* toggle between inputbuffer/input */\r
170 \r
171         outp = outdata;\r
172         inp = (signed char *)indata;\r
173 \r
174         valpred = state->valprev;\r
175         index = state->index;\r
176         step = stepsizeTable[index];\r
177 \r
178         bufferstep = 0;\r
179         \r
180         for(; len > 0; len--)\r
181         {\r
182                 /* Step 1 - get the delta value */\r
183                 if (bufferstep)\r
184                         delta = inputbuffer & 0xf;\r
185                 else\r
186                 {\r
187                         inputbuffer = *inp++;\r
188                         delta = (inputbuffer >> 4) & 0xf;\r
189                 }\r
190                 bufferstep = !bufferstep;\r
191 \r
192                 /* Step 2 - Find new index value (for later) */\r
193                 index += indexTable[delta];\r
194                 if(index < 0)\r
195                         index = 0;\r
196                 if(index > 88)\r
197                         index = 88;\r
198 \r
199                 /* Step 3 - Separate sign and magnitude */\r
200                 sign = delta & 8;\r
201                 delta = delta & 7;\r
202 \r
203                 /* Step 4 - Compute difference and new predicted value */\r
204                 /*\r
205                 ** Computes 'vpdiff = (delta+0.5)*step/4', but see comment\r
206                 ** in adpcm_coder.\r
207                 */\r
208                 vpdiff = step >> 3;\r
209                 if(delta & 4)\r
210                         vpdiff += step;\r
211                 if(delta & 2)\r
212                         vpdiff += step>>1;\r
213                 if(delta & 1)\r
214                         vpdiff += step>>2;\r
215 \r
216                 if (sign)\r
217                   valpred -= vpdiff;\r
218                 else\r
219                   valpred += vpdiff;\r
220 \r
221                 /* Step 5 - clamp output value */\r
222                 if (valpred > 32767)\r
223                   valpred = 32767;\r
224                 else if (valpred < -32768)\r
225                   valpred = -32768;\r
226 \r
227                 /* Step 6 - Update step value */\r
228                 step = stepsizeTable[index];\r
229 \r
230                 /* Step 7 - Output value */\r
231                 *outp++ = valpred;\r
232         }\r
233 \r
234         state->valprev = valpred;\r
235         state->index = index;\r
236 }\r
237 #endif\r
238 \r
239 void adpcm_coder(short *inp, adpcm_t *adpcm)\r
240 {\r
241         int                             val;                    /* Current input sample value */\r
242         int                             sign;                   /* Current adpcm sign bit */\r
243         int                             delta;                  /* Current adpcm output value */\r
244         int                             diff;                   /* Difference between val and valprev */\r
245         int                             step;                   /* Stepsize */\r
246         int                             valpred;                /* Predicted output value */\r
247         int                             vpdiff;                 /* Current change to valpred */\r
248         int                             index;                  /* Current step change index */\r
249         int                             outputbuffer;   /* place to keep previous 4-bit value */\r
250         int                             bufferstep;     /* toggle between outputbuffer/output */\r
251         adpcm_state_t   *state;\r
252         char                    *outp;\r
253         int                             len;\r
254 \r
255         state = &adpcm->state;\r
256         len = state->count;\r
257         outp = adpcm->adpcm;\r
258 \r
259         valpred = state->in_valprev;\r
260         index = state->in_index;\r
261         step = stepsizeTable[index];\r
262         \r
263         bufferstep = 1;\r
264         while(len--)\r
265         {\r
266                 val = *inp++;\r
267 \r
268                 /* Step 1 - compute difference with previous value */\r
269                 diff = val - valpred;\r
270                 sign = (diff < 0) ? 8 : 0;\r
271                 if (sign)\r
272                         diff = -diff;\r
273 \r
274                 /* Step 2 - Divide and clamp */\r
275                 /* Note:\r
276                 ** This code *approximately* computes:\r
277                 **        delta = diff*4/step;\r
278                 **        vpdiff = (delta+0.5)*step/4;\r
279                 ** but in shift step bits are dropped. The net result of this is\r
280                 ** that even if you have fast mul/div hardware you cannot put it to\r
281                 ** good use since the fixup would be too expensive.\r
282                 */\r
283                 delta = 0;\r
284                 vpdiff = (step >> 3);\r
285                 \r
286                 if (diff >= step)\r
287                 {\r
288                         delta = 4;\r
289                         diff -= step;\r
290                         vpdiff += step;\r
291                 }\r
292                 step >>= 1;\r
293                 if (diff >= step)\r
294                 {\r
295                         delta |= 2;\r
296                         diff -= step;\r
297                         vpdiff += step;\r
298                 }\r
299                 step >>= 1;\r
300                 if (diff >= step)\r
301                 {\r
302                         delta |= 1;\r
303                         vpdiff += step;\r
304                 }\r
305 \r
306                 /* Step 3 - Update previous value */\r
307                 if (sign)\r
308                   valpred -= vpdiff;\r
309                 else\r
310                   valpred += vpdiff;\r
311 \r
312                 /* Step 4 - Clamp previous value to 16 bits */\r
313                 if (valpred > 32767)\r
314                   valpred = 32767;\r
315                 else if (valpred < -32768)\r
316                   valpred = -32768;\r
317 \r
318                 /* Step 5 - Assemble value, update index and step values */\r
319                 delta |= sign;\r
320                 \r
321                 index += indexTable[delta];\r
322                 if (index < 0)\r
323                         index = 0;\r
324                 if (index > 88)\r
325                         index = 88;\r
326                 step = stepsizeTable[index];\r
327 \r
328                 /* Step 6 - Output value */\r
329                 if (bufferstep)\r
330                         outputbuffer = (delta << 4) & 0xf0;\r
331                 else\r
332                         *outp++ = (delta & 0x0f) | outputbuffer;\r
333 \r
334                 bufferstep = !bufferstep;\r
335         }\r
336 \r
337         /* Output last step, if needed */\r
338         if(!bufferstep)\r
339           *outp++ = outputbuffer;\r
340         \r
341         state->out_valprev = valpred;\r
342         state->out_index = index;\r
343 }\r
344 \r
345 void FindNextChunk(char *name)\r
346 {\r
347         while(1)\r
348         {\r
349                 data_p = last_chunk;\r
350 \r
351                 if(data_p >= iff_end)\r
352                 {                                                               // didn't find the chunk\r
353                         data_p = NULL;\r
354                         return;\r
355                 }\r
356                 \r
357                 data_p += 4;\r
358                 iff_chunk_len = *(long *)data_p;\r
359                 data_p += 4;\r
360                 if(iff_chunk_len < 0)\r
361                 {\r
362                         data_p = NULL;\r
363                         return;\r
364                 }\r
365 \r
366                 data_p -= 8;\r
367                 last_chunk = data_p + 8 + ((iff_chunk_len + 1) & ~1);\r
368                 if (!strncmp(data_p, name, 4))\r
369                         return;\r
370         }\r
371 }\r
372 \r
373 void FindChunk(char *name)\r
374 {\r
375         last_chunk = iff_data;\r
376         FindNextChunk (name);\r
377 }\r
378 \r
379 void DumpChunks(void)\r
380 {\r
381         char    str[5];\r
382         \r
383         str[4] = 0;\r
384         data_p = iff_data;\r
385         do\r
386         {\r
387                 memcpy (str, data_p, 4);\r
388                 data_p += 4;\r
389                 iff_chunk_len = *(long *)data_p;\r
390                 data_p += 4;\r
391                 printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);\r
392                 data_p += (iff_chunk_len + 1) & ~1;\r
393         }\r
394         while(data_p < iff_end);\r
395 }\r
396 \r
397 /*\r
398 ============\r
399 GetWavinfo\r
400 ============\r
401 */\r
402 wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)\r
403 {\r
404         wavinfo_t       info;\r
405         int                     i;\r
406         int                     format;\r
407         int                     samples;\r
408 \r
409         memset(&info, 0, sizeof(info));\r
410 \r
411         if (!wav)\r
412                 return(info);\r
413                 \r
414         iff_data = wav;\r
415         iff_end = wav + wavlength;\r
416 \r
417 // find "RIFF" chunk\r
418         FindChunk("RIFF");\r
419         if (!(data_p && !strncmp(data_p + 8, "WAVE", 4)))\r
420         {\r
421                 printf("Missing RIFF/WAVE chunks\n");\r
422                 return(info);\r
423         }\r
424 \r
425 // get "fmt " chunk\r
426         iff_data = data_p + 12;\r
427 \r
428         FindChunk("fmt ");\r
429         if(!data_p)\r
430         {\r
431                 printf("Missing fmt chunk\n");\r
432                 return(info);\r
433         }\r
434         data_p += 8;\r
435         format = *(short *)data_p;\r
436         data_p += 2;\r
437         if (format != 1)\r
438         {\r
439                 printf("Microsoft PCM format only\n");\r
440                 return(info);\r
441         }\r
442 \r
443         info.channels = *(short *)data_p;\r
444         data_p += 2;\r
445         info.rate = *(long *)data_p;\r
446         data_p += 4;\r
447         data_p += 6;\r
448         info.width = *(short *)data_p / 8;\r
449         data_p += 2;\r
450 \r
451 // get cue chunk\r
452         FindChunk("cue ");\r
453         if(data_p)\r
454         {\r
455                 data_p += 32;\r
456                 info.loopstart = *(long *)data_p;\r
457                 data_p += 4;\r
458 \r
459 // if the next chunk is a LIST chunk, look for a cue length marker\r
460                 FindNextChunk ("LIST");\r
461                 if(data_p)\r
462                 {\r
463 // this is not a proper parse, but it works with cooledit...\r
464                         if (!strncmp (data_p + 28, "mark", 4))\r
465                         {\r
466                                 data_p += 24;\r
467                                 i = *(long *)data_p;                                    // samples in loop\r
468                                 data_p += 4;\r
469                                 info.samples = info.loopstart + i;\r
470                         }\r
471                 }\r
472         }\r
473         else\r
474                 info.loopstart = -1;\r
475 \r
476 // find data chunk\r
477         FindChunk("data");\r
478         if (!data_p)\r
479         {\r
480                 printf("Missing data chunk\n");\r
481                 return(info);\r
482         }\r
483 \r
484         data_p += 4;\r
485         samples = *(long *)data_p;\r
486         data_p += 4;\r
487 \r
488         if (info.samples)\r
489         {\r
490                 if(samples < info.samples)\r
491                         Error ("Sound %s has a bad loop length", name);\r
492         }\r
493         else\r
494                 info.samples = samples;\r
495 \r
496         info.dataofs = data_p - wav;\r
497         return(info);\r
498 }\r
499 \r
500 // ==============\r
501 // LoadSoundtrack\r
502 // ==============\r
503 \r
504 void LoadSoundtrack()\r
505 {\r
506         char    name[1024];\r
507         FILE    *f;\r
508         int             len;\r
509 \r
510         soundtrack = NULL;\r
511         sprintf (name, "%svideo/%s/%s.wav", gamedir, base, base);\r
512         printf ("\nLoading sound    : %s\n", name);\r
513         f = fopen (name, "rb");\r
514         if (!f)\r
515         {\r
516                 printf ("\nNo soundtrack for %s\n", base);\r
517                 return;\r
518         }\r
519         len = Q_filelength(f);\r
520         soundtrack = SafeMalloc(len, "LoadSoundtrack");\r
521         fread(soundtrack, 1, len, f);\r
522         fclose(f);\r
523 \r
524         wavinfo = GetWavinfo(name, soundtrack, len);\r
525         adpcm.state.out_valprev = 0;\r
526         adpcm.state.out_index = 0;\r
527 }\r
528 \r
529 // ==================\r
530 // WriteSound\r
531 // ==================\r
532 \r
533 int WriteSound(FILE *output, int frame, int numframes)\r
534 {\r
535         int             start, end;\r
536         int             count;\r
537         int             empty = 0;\r
538         int             width;\r
539         char    *work;\r
540 \r
541         width = wavinfo.width * wavinfo.channels;\r
542         start = ((frame * wavinfo.rate / 14) + 31) & 0xffffffe0;                                // start sample\r
543         end = (((frame + numframes) * wavinfo.rate / 14) + 31) & 0xffffffe0;    // end sample\r
544         count = end - start;\r
545 \r
546         work = soundtrack + wavinfo.dataofs + (start * width);\r
547         adpcm.state.count = count * wavinfo.channels;                   // Number of samples\r
548         adpcm.state.in_valprev = adpcm.state.out_valprev;\r
549         adpcm.state.in_index = adpcm.state.out_index;\r
550         adpcm_coder((short *)work, &adpcm);\r
551         WriteHeader(output, FC_SOUND_22KMADPCM, FC_ADPCM_VERSION, (adpcm.state.count / 2) + sizeof(adpcm_state_t), (char *)&adpcm);\r
552         return(count / 2);\r
553 }\r
554 // ==============================\r
555 // Basic run length encoder\r
556 // ==============================\r
557 \r
558 char *RLEZZ(char *in, char *out)\r
559 {\r
560         int             srun;\r
561         char    count;\r
562         int             idx = 0;\r
563 \r
564         while(idx < 64)\r
565         {\r
566                 srun = idx;                                                             // Start of run\r
567 \r
568                 while(idx < 63)\r
569                 {\r
570                         if(in[LUT_ZZ[idx]] != in[LUT_ZZ[idx + 1]])\r
571                                 break;\r
572                         idx++;\r
573                 }\r
574                 count = (char)(idx - srun);                             // count of repeated bytes\r
575 \r
576                 if(!count)\r
577                 {\r
578                         while(idx < 63)\r
579                         {\r
580                                 if(in[LUT_ZZ[idx]] == in[LUT_ZZ[idx + 1]])\r
581                                         break;\r
582                                 idx++;\r
583                         }\r
584                         if(idx == 63)\r
585                                 idx++;\r
586 \r
587                         count = (char)(idx - srun);                     // count of unique bytes\r
588                         *out++ = count;\r
589                         while(count--)\r
590                                 *out++ = in[LUT_ZZ[srun++]];\r
591                 }\r
592                 else\r
593                 {\r
594                         *out++ = -(count + 1);\r
595                         *out++ = in[LUT_ZZ[idx]];\r
596                         idx++;\r
597                 }\r
598         }\r
599         return(out);\r
600 }\r
601 \r
602 // ==============================\r
603 // Discrete Cosine Transformation\r
604 // ==============================\r
605 \r
606 void init_base(float quant)\r
607 {\r
608         int                     y, x;\r
609 \r
610         for(y = 0; y < BLOCKSIZE; y++)\r
611                 for(x = 0; x < BLOCKSIZE; x++)\r
612                 {\r
613                         if(y == 0)\r
614                                 dctbase[y][x] = 1;\r
615                         else\r
616                                 dctbase[y][x] = SQRT2 * cos(((x * 2 + 1) * y * M_PI) / (BLOCKSIZE * 2));\r
617                 }\r
618 \r
619         for(y = 0; y < BLOCKSIZE * BLOCKSIZE; y++)\r
620                 Quantise[y] = LUT_Quantise[y] / quant;\r
621 }\r
622 \r
623 void SplitComponents(byte *src, int width, int height)\r
624 {\r
625         int             i, j;\r
626         float   *tr = red;\r
627         float   *tg = green;\r
628         float   *tb = blue;\r
629 \r
630         for(i = 0; i < BLOCKSIZE; i++, src += (width - BLOCKSIZE) * 4)\r
631                 for(j = 0; j < BLOCKSIZE; j++)\r
632                 {\r
633                         *tr++ = ((float)*src++) - 128.0F;\r
634                         *tg++ = ((float)*src++) - 128.0F;\r
635                         *tb++ = ((float)*src++) - 128.0F;\r
636                         src++;\r
637                 }\r
638 }\r
639 \r
640 void transferH(float *src, float *dst)\r
641 {\r
642         int             y, dx, dy;\r
643         float   sum;\r
644         float   *work;\r
645 \r
646         for(y = 0; y < BLOCKSIZE; y++, src += BLOCKSIZE)\r
647         {\r
648                 for(dy = 0; dy < BLOCKSIZE; dy++)\r
649                 {\r
650                         sum = 0;\r
651                         work = src;\r
652                         for(dx = 0; dx < BLOCKSIZE; dx++, work++)\r
653                                 sum += dctbase[dy][dx] * *work;\r
654 \r
655                         *dst++ = sum / BLOCKSIZE;\r
656                 }\r
657         }\r
658 }\r
659 \r
660 void transferV(float *src, float *dst)\r
661 {\r
662         int             x, dy, fy;\r
663         float   sum;\r
664         float   *work;\r
665 \r
666         for(x = 0; x < BLOCKSIZE; x++, src++, dst++)\r
667         {\r
668                 for(fy = 0; fy < BLOCKSIZE; fy++)\r
669                 {\r
670                         sum = 0;\r
671                         work = src;\r
672                         for(dy = 0; dy < BLOCKSIZE; dy++, work += BLOCKSIZE)\r
673                                 sum += dctbase[fy][dy] * *work;\r
674 \r
675                         dst[fy * BLOCKSIZE] = sum / BLOCKSIZE;\r
676                 }\r
677         }\r
678 }\r
679 \r
680 char *Combine(byte *dst, float *p, float *q)\r
681 {\r
682         int             i, j;\r
683         byte    rlesrc[BLOCKSIZE * BLOCKSIZE];\r
684         int             c;\r
685         byte    *work;\r
686 \r
687         work = rlesrc;\r
688         for(j = 0; j < BLOCKSIZE; j++)\r
689                 for(i = 0; i < BLOCKSIZE; i++)\r
690                 {\r
691                         c = (int)((*p++ / *q++) + 128.5F);\r
692                         c -= 128;\r
693 \r
694                         if(c < -128)\r
695                                 c = -128;\r
696                         if(c > 127)\r
697                                 c = 127;\r
698 \r
699                         *work++ = (char)c;\r
700                 }\r
701 \r
702         dst = RLEZZ(rlesrc, dst);\r
703         return(dst);\r
704 }\r
705 \r
706 char *CombineComponents(char *dst, int width, int height)\r
707 {\r
708         dst = Combine(dst, red, Quantise);\r
709         dst = Combine(dst, green, Quantise);\r
710         dst = Combine(dst, blue, Quantise);\r
711         return(dst);\r
712 }\r
713 \r
714 void DCT(cblock_t *out, cblock_t in, int width, int height)\r
715 {\r
716         int             x, y;\r
717         char    *cursrc;\r
718         char    *curdst;\r
719 \r
720         curdst = out->data;\r
721         for(y = 0; y < height; y += BLOCKSIZE)\r
722                 for(x = 0; x < width; x += BLOCKSIZE)\r
723                 {\r
724                         cursrc = in.data + ((y * width) + x) * 4;\r
725                         SplitComponents(cursrc, width, height);\r
726                         transferH(red, temp);\r
727                         transferV(temp, red);\r
728                         transferH(green, temp);\r
729                         transferV(temp, green);\r
730                         transferH(blue, temp);\r
731                         transferV(temp, blue);\r
732                         curdst = CombineComponents(curdst, width, height);\r
733                 }\r
734         out->count = curdst - out->data;\r
735 }\r
736 \r
737 // ==================\r
738 // BuildChars1\r
739 // ==================\r
740 \r
741 void BuildChars1(int prev, int nodenum, unsigned bits, int bitcount)\r
742 {\r
743         hnode_t         *node;\r
744 \r
745         if(nodenum < HUF_TOKENS)\r
746         {\r
747                 if (bitcount > 32)\r
748                         Error("bitcount > 32");\r
749                 charbits1[prev][nodenum] = bits;\r
750                 charbitscount1[prev][nodenum] = bitcount;\r
751                 return;\r
752         }\r
753 \r
754         node = &hnodes1[prev][nodenum];\r
755         bits <<= 1;\r
756         BuildChars1(prev, node->children[0], bits, bitcount+1);\r
757         bits |= 1;\r
758         BuildChars1(prev, node->children[1], bits, bitcount+1);\r
759 }\r
760 \r
761 // ==================\r
762 // SmallestNode1\r
763 // ==================\r
764 \r
765 int     SmallestNode1(hnode_t *hnodes, int numhnodes)\r
766 {\r
767         int             i;\r
768         int             best, bestnode;\r
769 \r
770         best = 99999999;\r
771         bestnode = -1;\r
772         for(i = 0; i < numhnodes; i++)\r
773         {\r
774                 if(hnodes[i].used)\r
775                         continue;\r
776                 if(!hnodes[i].count)\r
777                         continue;\r
778                 if(hnodes[i].count < best)\r
779                 {\r
780                         best = hnodes[i].count;\r
781                         bestnode = i;\r
782                 }\r
783         }\r
784 \r
785         if (bestnode == -1)\r
786                 return(-1);\r
787 \r
788         hnodes[bestnode].used = true;\r
789         return(bestnode);\r
790 }\r
791 \r
792 // ==================\r
793 // BuildTree1\r
794 // ==================\r
795 \r
796 void BuildTree1(int prev)\r
797 {\r
798         hnode_t         *node, *nodebase;\r
799         int                     numhnodes;\r
800 \r
801         // build the nodes\r
802         numhnodes = HUF_TOKENS;\r
803         nodebase = hnodes1[prev];\r
804         while(1)\r
805         {\r
806                 node = &nodebase[numhnodes];\r
807 \r
808                 // pick two lowest counts\r
809                 node->children[0] = SmallestNode1 (nodebase, numhnodes);\r
810                 if (node->children[0] == -1)\r
811                         break;  // no more\r
812 \r
813                 node->children[1] = SmallestNode1 (nodebase, numhnodes);\r
814                 if (node->children[1] == -1)\r
815                         break;\r
816 \r
817                 node->count = nodebase[node->children[0]].count + \r
818                         nodebase[node->children[1]].count;\r
819                 numhnodes++;\r
820         }\r
821         numhnodes1[prev] = numhnodes-1;\r
822         BuildChars1 (prev, numhnodes-1, 0, 0);\r
823 }\r
824 \r
825 // ==================\r
826 // Huffman1_Count\r
827 // ==================\r
828 \r
829 void Huffman1_Count(cblock_t in)\r
830 {\r
831         int             i;\r
832         int             prev;\r
833         int             v;\r
834         int             rept;\r
835 \r
836         prev = 0;\r
837         for(i = 0; i < in.count; i++)\r
838         {\r
839                 v = in.data[i];\r
840                 order0counts[v]++;\r
841                 hnodes1[prev][v].count++;\r
842                 prev = v;\r
843 \r
844                 for(rept = 1; (i + rept < in.count) && (rept < MAX_REPT); rept++)\r
845                         if(in.data[i+rept] != v)\r
846                                 break;\r
847                 if(rept > MIN_REPT)\r
848                 {\r
849                         hnodes1[prev][255 + rept].count++;\r
850                         i += rept - 1;\r
851                 }\r
852         }\r
853 }\r
854 \r
855 // ==================\r
856 // Huffman1_Build\r
857 // ==================\r
858 \r
859 void Huffman1_Build()\r
860 {\r
861         int             i, j, v;\r
862         int             max;\r
863         int             total;\r
864 \r
865         for(i = 0; i < 256; i++)\r
866         {\r
867 // normalize and save the counts\r
868                 max = 0;\r
869                 for (j = 0; j < HUF_TOKENS; j++)\r
870                 {\r
871                         if (hnodes1[i][j].count > max)\r
872                                 max = hnodes1[i][j].count;\r
873                 }\r
874                 if (max == 0)\r
875                         max = 1;\r
876                 total = 0;\r
877 // easy to overflow 32 bits here!\r
878                 for(j = 0; j < HUF_TOKENS; j++)\r
879                 {\r
880                         v = (hnodes1[i][j].count * (double) 255 + max - 1) / max;\r
881                         if (v > 255)\r
882                                 Error ("v > 255");\r
883                         scaled[i][j] = hnodes1[i][j].count = v;\r
884                         if (v)\r
885                                 total++;\r
886                 }\r
887                 if (total == 1)\r
888                 {       // must have two tokens\r
889                         if (!scaled[i][0])\r
890                                 scaled[i][0] = hnodes1[i][0].count = 1;\r
891                         else\r
892                                 scaled[i][1] = hnodes1[i][1].count = 1;\r
893                 }\r
894                 BuildTree1 (i);\r
895         }\r
896 }\r
897 \r
898 // ==================\r
899 // Huffman1\r
900 // Order 1 compression with pre-built table\r
901 // ==================\r
902 \r
903 cblock_t Huffman1(cblock_t in)\r
904 {\r
905         int                     i;\r
906         int                     outbits, c;\r
907         unsigned        bits;\r
908         byte            *out_p;\r
909         cblock_t        out;\r
910         int                     prev;\r
911         int                     v;\r
912         int                     rept;\r
913 \r
914         out_p = out.data = SafeMalloc((in.count * 2) + 1024 + 4, "Huffman");\r
915         memset(out_p, 0, (in.count * 2) + 1024 + 4);\r
916 \r
917         // leave space for compressed count\r
918         out_p += 4;\r
919         // write count\r
920         *(long *)out_p = in.count;\r
921         out_p += 4;\r
922 \r
923         // write bits\r
924         outbits = 0;\r
925         prev = 0;\r
926         for(i = 0; i < in.count; i++)\r
927         {\r
928                 v = in.data[i];\r
929 \r
930                 c = charbitscount1[prev][v];\r
931                 bits = charbits1[prev][v];\r
932                 if (!c)\r
933                         Error ("!bits");\r
934                 while (c)\r
935                 {\r
936                         c--;\r
937                         if (bits & (1 << c))\r
938                                 out_p[outbits>>3] |= 1 << (outbits & 7);\r
939                         outbits++;\r
940                 }\r
941 \r
942                 prev = v;\r
943                 // check for repeat encodes\r
944                 for(rept = 1; (i + rept < in.count) && (rept < MAX_REPT); rept++)\r
945                         if(in.data[i + rept] != v)\r
946                                 break;\r
947                 if (rept > MIN_REPT)\r
948                 {\r
949                         c = charbitscount1[prev][255 + rept];\r
950                         bits = charbits1[prev][255 + rept];\r
951                         if (!c)\r
952                                 Error ("!bits");\r
953                         while (c)\r
954                         {\r
955                                 c--;\r
956                                 if(bits & (1 << c))\r
957                                         out_p[outbits >> 3] |= 1 << (outbits & 7);\r
958                                 outbits++;\r
959                         }\r
960                         i += rept - 1;\r
961                 }\r
962         }\r
963         out_p += (outbits + 7) >> 3;\r
964         out.count = out_p - out.data;\r
965 \r
966         out_p = out.data;\r
967         *(long *)out_p = out.count;\r
968         return(out);\r
969 }\r
970 // ===================\r
971 // LoadFrame\r
972 // ===================\r
973 \r
974 void LoadFrame(cblock_t *out, char *base, int frame)\r
975 {\r
976         cblock_t        in;\r
977         int                     width, height;\r
978         char            name[1024];\r
979         FILE            *f;\r
980 \r
981         in.data = NULL;\r
982         in.count = -1;\r
983         sprintf (name, "%svideo/%s/%s%04i.tga", gamedir, base, base, frame);\r
984 \r
985         f = fopen(name, "rb");\r
986         if (!f)\r
987         {\r
988                 out->data = NULL;\r
989                 return;\r
990         }\r
991         fclose (f);\r
992 \r
993         LoadTGA(name, &in.data, &width, &height);\r
994         if((width != cinehead.Width) || (height != cinehead.Height))\r
995         {\r
996                 free(in.data);\r
997                 printf("Invalid picture size\n");\r
998                 out->data = NULL;\r
999                 return;\r
1000         }\r
1001         out->data = SafeMalloc(width * height * 3, "LoadFrame");                // rle could possibly expand file so this not 100% safe (however DCT should force a lot of compression)\r
1002         DCT(out, in, width, height);\r
1003         free(in.data);\r
1004 }\r
1005 \r
1006 // ==================================\r
1007 // Cmd_Video\r
1008 // \r
1009 // video <directory> <framedigits>\r
1010 // ==================================\r
1011 \r
1012 void Cmd_Video()\r
1013 {\r
1014         char            savename[256];\r
1015         char            name[256];\r
1016         FILE            *output;\r
1017         int                     frame;\r
1018         int                     width, height;\r
1019         cblock_t        in, huffman;\r
1020         int                     size;\r
1021         float           dctconst;\r
1022         int                     maxsize, ssize;\r
1023         int                     min_rle_size, warnings;\r
1024         int                     ave_image, ave_sound;\r
1025 \r
1026         GetScriptToken(false);\r
1027         strcpy(base, token);\r
1028         if (g_release)\r
1029                 return;\r
1030 \r
1031         GetScriptToken(false);\r
1032         dctconst = atof(token);\r
1033         GetScriptToken(false);\r
1034         maxsize = atoi(token);\r
1035 \r
1036         sprintf (savename, "%svideo/%s.cin", gamedir, base);\r
1037 \r
1038         // clear stuff\r
1039         memset(charbits1, 0, sizeof(charbits1));\r
1040         memset(charbitscount1, 0, sizeof(charbitscount1));\r
1041         memset(hnodes1, 0, sizeof(hnodes1));\r
1042         memset(numhnodes1, 0, sizeof(numhnodes1));\r
1043         memset(order0counts, 0, sizeof(order0counts));\r
1044 \r
1045         // load the entire sound wav file if present\r
1046         LoadSoundtrack();\r
1047 \r
1048         cinehead.SndRate = wavinfo.rate;\r
1049         cinehead.SndWidth = wavinfo.width;\r
1050         cinehead.SndChannels = wavinfo.channels;\r
1051 \r
1052         sprintf(name, "%svideo/%s/%s0000.tga", gamedir, base, base);\r
1053         printf("Loading sequence : %s\n", name);\r
1054         printf("DCT constant     : %f\n", dctconst);\r
1055 \r
1056         LoadTGA (name, NULL, &width, &height);\r
1057 \r
1058         output = fopen (savename, "wb");\r
1059         if (!output)\r
1060                 Error ("Can't open %s", savename);\r
1061 \r
1062         if((width % BLOCKSIZE) || (height % BLOCKSIZE))\r
1063                 Error("Width and height must be a multiple of %d", BLOCKSIZE);\r
1064 \r
1065         cinehead.Width = width;\r
1066         cinehead.Height = height;\r
1067         init_base(dctconst);\r
1068 \r
1069         // build the dictionary\r
1070         printf("Counting         : ");\r
1071         min_rle_size = 0;\r
1072         for (frame = 0;  ; frame++)\r
1073         {\r
1074                 printf(".");\r
1075                 LoadFrame(&in, base, frame);\r
1076                 if(!in.data)\r
1077                         break;\r
1078                 Huffman1_Count(in);\r
1079                 if(in.count > min_rle_size)\r
1080                         min_rle_size = in.count;\r
1081                 free(in.data);\r
1082         }\r
1083         printf ("\n");\r
1084         cinehead.NumFrames = frame;\r
1085         printf("Num Frames       : %d\n", frame);\r
1086         cinehead.MaxRleSize = (min_rle_size + 0x1f) & 0xfffffe0;\r
1087         cinehead.MaxSndSize = ((4 * wavinfo.rate * wavinfo.channels / 14) + 0x1f) & 0xffffffe0;\r
1088 \r
1089         WriteHeader(output, FC_HEADER_NAME, FC_HEADER_VERSION, sizeof(CineHead_t), &cinehead);\r
1090 \r
1091         // build nodes and write counts\r
1092         Huffman1_Build();\r
1093         WriteHeader(output, FC_HUFFBITS_NAME, FC_HUFFBITS_VERSION, sizeof(scaled), scaled);\r
1094         WriteHeader(output, FC_QUANT_NAME, FC_QUANT_VERSION, sizeof(Quantise), Quantise);\r
1095 \r
1096         ave_image = 0;\r
1097         ave_sound = 0;\r
1098         warnings = 0;\r
1099         // compress it with the dictionary\r
1100         if(soundtrack)\r
1101         {\r
1102                 ssize = WriteSound(output, frame, 4);\r
1103                 ave_sound += ssize;\r
1104         }\r
1105 \r
1106         for (frame = 0; frame < cinehead.NumFrames; frame++)\r
1107         {\r
1108                 // save some sound samples\r
1109                 printf ("Packing          : ", frame);\r
1110                 LoadFrame(&in, base, frame);\r
1111 \r
1112                 // save the image\r
1113                 huffman = Huffman1(in);\r
1114                 printf ("%d bytes rle, %d bytes huffman", in.count, huffman.count);\r
1115                 size = (huffman.count + 3) & 0xfffffffc;                                        // round up to longwords\r
1116                 if(size > maxsize)\r
1117                 {\r
1118                         printf(" ** WARNING **");\r
1119                         warnings++;\r
1120                 }\r
1121                 printf("\n");\r
1122                 ave_image += huffman.count;\r
1123 \r
1124                 WriteHeader(output, FC_IMAGE_NAME, FC_IMAGE_VERSION, size, huffman.data);\r
1125                 if(soundtrack)\r
1126                 {\r
1127                         ssize = WriteSound(output, frame + 4, 1);\r
1128                         ave_sound += ssize;\r
1129                 }\r
1130 \r
1131                 free (in.data);\r
1132                 free (huffman.data);\r
1133         }\r
1134         printf("\nTotal size: %d (headers + %d image + %d sound)\n", ftell(output), ave_image, ave_sound);\r
1135         printf("Data rate : %d bytes per sec (image and sound)\n", (ave_image + ave_sound) / cinehead.NumFrames);\r
1136         printf("Cin created ok with %d warnings.\n", warnings);\r
1137         fclose (output);\r
1138 \r
1139         if (soundtrack)\r
1140                 free (soundtrack);\r
1141 }\r
1142 #endif\r
1143 \r
1144 void Cmd_Video()\r
1145 {\r
1146 }\r
1147 \r
1148 // end\r
1149 \r