1 /*
2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
3 *
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on the
6 * source.
7 *
8 */
9
10
11
12 #include "anim/animplay.h"
13 #include "anim/packunpack.h"
14 #include "bmpman/bmpman.h"
15 #include "graphics/2d.h"
16
17
18 const int packer_code = PACKER_CODE;
19 const int transparent_code = 254;
20
anim_check_for_palette_change(anim_instance * instance)21 void anim_check_for_palette_change(anim_instance *instance) {
22 if ( instance->parent->screen_sig != gr_screen.signature ) {
23 instance->parent->screen_sig = gr_screen.signature;
24 anim_set_palette(instance->parent);
25 }
26 }
27
init_anim_instance(anim * ptr,int bpp)28 anim_instance *init_anim_instance(anim *ptr, int bpp)
29 {
30 anim_instance *inst;
31
32 if (!ptr) {
33 Int3();
34 return NULL;
35 }
36
37 if ( ptr->flags & ANF_STREAMED ) {
38 if ( ptr->file_offset < 0 ) {
39 Int3();
40 return NULL;
41 }
42 } else {
43 if ( !ptr->data ) {
44 Int3();
45 return NULL;
46 }
47 }
48
49 ptr->instance_count++;
50 inst = (anim_instance *) vm_malloc(sizeof(anim_instance));
51 Assert(inst);
52 memset(inst, 0, sizeof(anim_instance));
53 inst->frame_num = -1;
54 inst->last_frame_num = -1;
55 inst->parent = ptr;
56 inst->data = ptr->data;
57 inst->file_offset = ptr->file_offset;
58 inst->stop_now = FALSE;
59 inst->aa_color = NULL;
60
61 inst->frame = (ubyte *) vm_malloc(inst->parent->width * inst->parent->height * (bpp >> 3));
62 Assert( inst->frame != NULL );
63 memset( inst->frame, 0, inst->parent->width * inst->parent->height * (bpp >> 3) );
64
65 return inst;
66 }
67
free_anim_instance(anim_instance * inst)68 void free_anim_instance(anim_instance *inst)
69 {
70 Assert(inst->frame);
71 vm_free(inst->frame);
72 inst->frame = NULL;
73 inst->parent->instance_count--;
74 inst->parent = NULL;
75 inst->data = NULL;
76 inst->file_offset = -1;
77
78 vm_free(inst);
79 }
80
anim_get_next_raw_buffer(anim_instance * inst,int xlate_pal,int aabitmap,int bpp)81 ubyte *anim_get_next_raw_buffer(anim_instance *inst, int xlate_pal, int aabitmap, int bpp)
82 {
83 if ( anim_instance_is_streamed(inst) ) {
84 if ( inst->file_offset < 0 ) {
85 return NULL;
86 }
87 } else {
88 if (!inst->data){
89 return NULL;
90 }
91 }
92
93 inst->frame_num++;
94 if (inst->frame_num >= inst->parent->total_frames) {
95 inst->data = NULL;
96 inst->file_offset = inst->parent->file_offset;
97 return NULL;
98 }
99
100 anim_check_for_palette_change(inst);
101
102 if ( anim_instance_is_streamed(inst) ) {
103 if ( xlate_pal ){
104 inst->file_offset = unpack_frame_from_file(inst, inst->frame, inst->parent->width*inst->parent->height, inst->parent->palette_translation, aabitmap, bpp);
105 } else {
106 inst->file_offset = unpack_frame_from_file(inst, inst->frame, inst->parent->width*inst->parent->height, NULL, aabitmap, bpp);
107 }
108 } else {
109 if ( xlate_pal ){
110 inst->data = unpack_frame(inst, inst->data, inst->frame, inst->parent->width*inst->parent->height, inst->parent->palette_translation, aabitmap, bpp);
111 } else {
112 inst->data = unpack_frame(inst, inst->data, inst->frame, inst->parent->width*inst->parent->height, NULL, aabitmap, bpp);
113 }
114 }
115
116 return inst->frame;
117 }
118
119 /**
120 * @brief Convert a 24 bit value to a 16 bit value
121 * @param bit_24 24 bit value
122 * @param bit_16 16 bit value (output)
123 */
convert_24_to_16(int bit_24,ushort * bit_16)124 void convert_24_to_16(int bit_24, ushort *bit_16)
125 {
126 ubyte *pixel = (ubyte*)&bit_24;
127 ubyte alpha = 1;
128
129 bm_set_components((ubyte*)bit_16, (ubyte*)&pixel[0], (ubyte*)&pixel[1], (ubyte*)&pixel[2], &alpha);
130 }
131
132 /**
133 * @brief Unpack a pixel given the passed index and the anim_instance's palette
134 * @return Bytes stuffed
135 */
unpack_pixel(anim_instance * ai,ubyte * data,ubyte pix,int aabitmap,int bpp)136 int unpack_pixel(anim_instance *ai, ubyte *data, ubyte pix, int aabitmap, int bpp)
137 {
138 int bit_24;
139 ushort bit_16 = 0;
140 ubyte bit_8 = 0;
141 ubyte al = 0;
142 ubyte r, g, b;
143 int pixel_size = (bpp / 8);
144 anim *a = ai->parent;
145 Assert(a);
146
147 // if this is an aabitmap, don't run through the palette
148 if(aabitmap){
149 switch(bpp){
150 case 16 :
151 bit_16 = (ushort)pix;
152 break;
153 case 8:
154 // 8 bit-per-pixel aa bitmaps are a bit special since they only use a palette index value in the range [0, 15]. These
155 // palette indexes must be remapped to alpha values between [0, 255] which is what graphics code expects. Palette
156 // range [0, 14] is a gradient from black to white, and palette index 15 is a special color which indicates the background
157 // area of a HUD gauge. Retail code uses the final alpha value for index 1 for this special index to give gauges a dark
158 // transparent background.
159 if (pix > 15) {
160 bit_8 = 255;
161 }
162 else if (pix == 15) {
163 bit_8 = 18;
164 }
165 else {
166 bit_8 = (ubyte)(pix * 18);
167 }
168
169 break;
170 default:
171 Int3();
172 }
173 } else {
174 // if the pixel value is 255, or is the xparent color, make it so
175 if(((a->palette[pix*3] == a->xparent_r) && (a->palette[pix*3+1] == a->xparent_g) && (a->palette[pix*3+2] == a->xparent_b)) ){
176 if (pixel_size > 2) {
177 bit_24 = 0;
178 } else {
179 r = b = 0;
180 g = 255;
181
182 bm_set_components((ubyte*)&bit_16, &r, &g, &b, &al);
183 }
184 } else {
185 if (pixel_size > 2) {
186 ubyte pixel[4];
187 pixel[0] = ai->parent->palette[pix * 3 + 2];
188 pixel[1] = ai->parent->palette[pix * 3 + 1];
189 pixel[2] = ai->parent->palette[pix * 3];
190 pixel[3] = 255;
191 memcpy(&bit_24, pixel, sizeof(int));
192
193 if (pixel_size == 4) {
194 bit_24 = INTEL_INT(bit_24);
195 }
196 } else {
197 // stuff the 24 bit value
198 memcpy(&bit_24, &ai->parent->palette[pix * 3], 3); //-V512
199
200 // convert to 16 bit
201 convert_24_to_16(bit_24, &bit_16);
202 }
203 }
204 }
205
206 // stuff the pixel
207 switch (bpp) {
208 case 32:
209 case 24:
210 memcpy(data, &bit_24, pixel_size);
211 break;
212
213 case 16:
214 memcpy(data, &bit_16, pixel_size);
215 break;
216
217 case 8:
218 *data = bit_8;
219 break;
220
221 default:
222 Int3();
223 return 0;
224 }
225
226 return pixel_size;
227 }
228
229 /**
230 * @brief Unpack a pixel given the passed index and the anim_instance's palette
231 * @return Bytes stuffed
232 */
unpack_pixel_count(anim_instance * ai,ubyte * data,ubyte pix,int count=0,int aabitmap=0,int bpp=8)233 int unpack_pixel_count(anim_instance *ai, ubyte *data, ubyte pix, int count = 0, int aabitmap = 0, int bpp = 8)
234 {
235 int bit_24;
236 int idx;
237 ubyte al = 0;
238 ushort bit_16 = 0;
239 ubyte bit_8 = 0;
240 anim *a = ai->parent;
241 int pixel_size = (bpp / 8);
242 ubyte r, g, b;
243 Assert(a);
244
245 // if this is an aabitmap, don't run through the palette
246 if(aabitmap){
247 switch(bpp){
248 case 16 :
249 bit_16 = (ushort)pix;
250 break;
251 case 8 :
252 // 8 bit-per-pixel aa bitmaps are a bit special since they only use a palette index value in the range [0, 15]. These
253 // palette indexes must be remapped to alpha values between [0, 255] which is what graphics code expects. Palette
254 // range [0, 14] is a gradient from black to white, and palette index 15 is a special color which indicates the background
255 // area of a HUD gauge. Retail code uses the final alpha value for index 1 for this special index to give gauges a dark
256 // transparent background.
257 if (pix > 15) {
258 bit_8 = 255;
259 }
260 else if (pix == 15) {
261 bit_8 = 18;
262 }
263 else {
264 bit_8 = (ubyte)(pix * 18);
265 }
266
267 break;
268 default :
269 Int3();
270 }
271 } else {
272 // if the pixel value is 255, or is the xparent color, make it so
273 if(((a->palette[pix*3] == a->xparent_r) && (a->palette[pix*3+1] == a->xparent_g) && (a->palette[pix*3+2] == a->xparent_b)) ){
274 if (pixel_size > 2) {
275 bit_24 = 0;
276 } else {
277 r = b = 0;
278 g = 255;
279
280 bm_set_components((ubyte*)&bit_16, &r, &g, &b, &al);
281 }
282 } else {
283 if (pixel_size > 2) {
284 ubyte pixel[4];
285 pixel[0] = ai->parent->palette[pix * 3 + 2];
286 pixel[1] = ai->parent->palette[pix * 3 + 1];
287 pixel[2] = ai->parent->palette[pix * 3];
288 pixel[3] = 255;
289 memcpy(&bit_24, pixel, sizeof(int));
290
291 if (pixel_size == 4) {
292 bit_24 = INTEL_INT(bit_24);
293 }
294 } else {
295 // stuff the 24 bit value
296 memcpy(&bit_24, &ai->parent->palette[pix * 3], 3); //-V512
297
298 // convert to 16 bit
299 convert_24_to_16(bit_24, &bit_16);
300 }
301 }
302 }
303
304 // stuff the pixel
305 for (idx=0; idx<count; idx++) {
306 switch (bpp) {
307 case 32:
308 case 24:
309 memcpy(data + (idx * pixel_size), &bit_24, pixel_size);
310 break;
311
312 case 16:
313 memcpy(data + (idx * pixel_size), &bit_16, pixel_size);
314 break;
315
316 case 8:
317 *(data + idx) = bit_8;
318 break;
319 }
320 }
321
322 return (pixel_size * count);
323 }
324
325 /**
326 * @brief Unpack frame
327 *
328 * @param ai Animation instance
329 * @param ptr Packed data to unpack
330 * @param frame Where to store unpacked data to
331 * @param size Total number of unpacked pixels requested
332 * @param pal_translate Color translation lookup table (NULL if no palette translation desired)
333 * @param aabitmap
334 * @param bpp
335 */
unpack_frame(anim_instance * ai,ubyte * ptr,ubyte * frame,int size,ubyte * pal_translate,int aabitmap,int bpp)336 ubyte *unpack_frame(anim_instance *ai, ubyte *ptr, ubyte *frame, int size, ubyte *pal_translate, int aabitmap, int bpp)
337 {
338 int xlate_pal, value, count = 0;
339 int stuffed;
340 int pixel_size = (bpp / 8);
341
342 if ( pal_translate == NULL ) {
343 xlate_pal = 0;
344 }
345 else {
346 xlate_pal = 1;
347 }
348
349 if (*ptr == PACKING_METHOD_RLE_KEY) { // key frame, Hoffoss's RLE format
350 ptr++;
351 while (size > 0) {
352 value = *ptr++;
353 if (value != packer_code) {
354 if ( xlate_pal ){
355 stuffed = unpack_pixel(ai, frame, pal_translate[value], aabitmap, bpp);
356 } else {
357 stuffed = unpack_pixel(ai, frame, (ubyte)value, aabitmap, bpp);
358 }
359 frame += stuffed;
360 size--;
361 } else {
362 count = *ptr++;
363 if (count < 2){
364 value = packer_code;
365 } else {
366 value = *ptr++;
367 }
368
369 if (++count > size){
370 count = size;
371 }
372
373 if ( xlate_pal ){
374 stuffed = unpack_pixel_count(ai, frame, pal_translate[value], count, aabitmap, bpp);
375 } else {
376 stuffed = unpack_pixel_count(ai, frame, (ubyte)value, count, aabitmap, bpp);
377 }
378
379 frame += stuffed;
380 size -= count;
381 }
382 }
383 }
384 else if ( *ptr == PACKING_METHOD_STD_RLE_KEY) { // key frame, with high bit as count
385 ptr++;
386 while (size > 0) {
387 value = *ptr++;
388 if ( !(value & STD_RLE_CODE) ) {
389 if ( xlate_pal ){
390 stuffed = unpack_pixel(ai, frame, pal_translate[value], aabitmap, bpp);
391 } else {
392 stuffed = unpack_pixel(ai, frame, (ubyte)value, aabitmap, bpp);
393 }
394
395 frame += stuffed;
396 size--;
397 } else {
398 count = value & (~STD_RLE_CODE);
399 value = *ptr++;
400
401 if (count > size)
402 count = size;
403
404 size -= count;
405 Assert(size >= 0);
406
407 if ( xlate_pal ){
408 stuffed = unpack_pixel_count(ai, frame, pal_translate[value], count, aabitmap, bpp);
409 } else {
410 stuffed = unpack_pixel_count(ai, frame, (ubyte)value, count, aabitmap, bpp);
411 }
412
413 frame += stuffed;
414 }
415 }
416 }
417 else if (*ptr == PACKING_METHOD_RLE) { // normal frame, Hoffoss's RLE format
418
419 ptr++;
420 while (size > 0) {
421 value = *ptr++;
422 if (value != packer_code) {
423 if (value != transparent_code) {
424 if ( xlate_pal ){
425 stuffed = unpack_pixel(ai, frame, pal_translate[value], aabitmap, bpp);
426 } else {
427 stuffed = unpack_pixel(ai, frame, (ubyte)value, aabitmap, bpp);
428 }
429 } else {
430 // temporary pixel
431 stuffed = pixel_size;
432 }
433
434 frame += stuffed;
435 size--;
436 } else {
437 count = *ptr++;
438 if (count < 2){
439 value = packer_code;
440 } else {
441 value = *ptr++;
442 }
443
444 if (++count > size){
445 count = size;
446 }
447
448 size -= count;
449 Assert(size >= 0);
450
451 if (value != transparent_code ) {
452 if ( xlate_pal ) {
453 stuffed = unpack_pixel_count(ai, frame, pal_translate[value], count, aabitmap, bpp);
454 } else {
455 stuffed = unpack_pixel_count(ai, frame, (ubyte)value, count, aabitmap, bpp);
456 }
457 } else {
458 stuffed = count * pixel_size;
459 }
460
461 frame += stuffed;
462 }
463 }
464
465 }
466 else if ( *ptr == PACKING_METHOD_STD_RLE) { // normal frame, with high bit as count
467 ptr++;
468 while (size > 0) {
469 value = *ptr++;
470 if ( !(value & STD_RLE_CODE) ) {
471 if (value != transparent_code) {
472 if ( xlate_pal ){
473 stuffed = unpack_pixel(ai, frame, pal_translate[value], aabitmap, bpp);
474 } else {
475 stuffed = unpack_pixel(ai, frame, (ubyte)value, aabitmap, bpp);
476 }
477 } else {
478 stuffed = pixel_size;
479 }
480
481 frame += stuffed;
482 size--;
483 } else {
484 count = value & (~STD_RLE_CODE);
485 value = *ptr++;
486
487 if (count > size)
488 count = size;
489
490 size -= count;
491 Assert(size >= 0);
492
493 if (value != transparent_code) {
494 if ( xlate_pal ){
495 stuffed = unpack_pixel_count(ai, frame, pal_translate[value], count, aabitmap, bpp);
496 } else {
497 stuffed = unpack_pixel_count(ai, frame, (ubyte)value, count, aabitmap, bpp);
498 }
499 } else {
500 stuffed = pixel_size * count;
501 }
502
503 frame += stuffed;
504 }
505 }
506 }
507 else {
508 // unknown packing method
509 return NULL;
510 }
511
512 return ptr;
513 }
514
515 /**
516 * @brief Unpack frame from file
517 *
518 * @param ai Animation instance
519 * @param frame Where to store unpacked data to
520 * @param size Total number of unpacked pixels requested
521 * @param pal_translate Color translation lookup table (NULL if no palette translation desired)
522 * @param aabitmap
523 * @param bpp
524 */
unpack_frame_from_file(anim_instance * ai,ubyte * frame,int size,ubyte * pal_translate,int aabitmap,int bpp)525 int unpack_frame_from_file(anim_instance *ai, ubyte *frame, int size, ubyte *pal_translate, int aabitmap, int bpp)
526 {
527 int xlate_pal, value, count = 0;
528 int offset = 0;
529 int stuffed;
530 int pixel_size = (bpp / 8);
531
532 if ( pal_translate == NULL ) {
533 xlate_pal = 0;
534 }
535 else {
536 xlate_pal = 1;
537 }
538
539 if (anim_instance_get_byte(ai,offset) == PACKING_METHOD_RLE_KEY) { // key frame, Hoffoss's RLE format
540 offset++;
541 while (size > 0) {
542 value = anim_instance_get_byte(ai,offset);
543 offset++;
544 if (value != packer_code) {
545 if ( xlate_pal ){
546 stuffed = unpack_pixel(ai, frame, pal_translate[value], aabitmap, bpp);
547 } else {
548 stuffed = unpack_pixel(ai, frame, (ubyte)value, aabitmap, bpp);
549 }
550
551 frame += stuffed;
552 size--;
553 } else {
554 count = anim_instance_get_byte(ai,offset);
555 offset++;
556 if (count < 2) {
557 value = packer_code;
558 } else {
559 value = anim_instance_get_byte(ai,offset);
560 offset++;
561 }
562
563 if (++count > size){
564 count = size;
565 }
566
567 if ( xlate_pal ){
568 stuffed = unpack_pixel_count(ai, frame, pal_translate[value], count, aabitmap, bpp);
569 } else {
570 stuffed = unpack_pixel_count(ai, frame, (ubyte)value, count, aabitmap, bpp);
571 }
572
573 frame += stuffed;
574 size -= count;
575 }
576 }
577 }
578 else if ( anim_instance_get_byte(ai,offset) == PACKING_METHOD_STD_RLE_KEY) { // key frame, with high bit as count
579 offset++;
580 while (size > 0) {
581 value = anim_instance_get_byte(ai,offset);
582 offset++;
583 if ( !(value & STD_RLE_CODE) ) {
584 if ( xlate_pal ){
585 stuffed = unpack_pixel(ai, frame, pal_translate[value], aabitmap, bpp);
586 } else {
587 stuffed = unpack_pixel(ai, frame, (ubyte)value, aabitmap, bpp);
588 }
589
590 frame += stuffed;
591 size--;
592 } else {
593 count = value & (~STD_RLE_CODE);
594 value = anim_instance_get_byte(ai,offset);
595 offset++;
596
597 if (count > size)
598 count = size;
599
600 size -= count;
601 Assert(size >= 0);
602
603 if ( xlate_pal ){
604 stuffed = unpack_pixel_count(ai, frame, pal_translate[value], count, aabitmap, bpp);
605 } else {
606 stuffed = unpack_pixel_count(ai, frame, (ubyte)value, count, aabitmap, bpp);
607 }
608
609 frame += stuffed;
610 }
611 }
612 }
613 else if (anim_instance_get_byte(ai,offset) == PACKING_METHOD_RLE) { // normal frame, Hoffoss's RLE format
614
615 offset++;
616 while (size > 0) {
617 value = anim_instance_get_byte(ai,offset);
618 offset++;
619 if (value != packer_code) {
620 if (value != transparent_code) {
621 if ( xlate_pal ){
622 stuffed = unpack_pixel(ai, frame, pal_translate[value], aabitmap, bpp);
623 } else {
624 stuffed = unpack_pixel(ai, frame, (ubyte)value, aabitmap, bpp);
625 }
626 } else {
627 stuffed = pixel_size;
628 }
629
630 frame += stuffed;
631 size--;
632 } else {
633 count = anim_instance_get_byte(ai,offset);
634 offset++;
635
636 if (count < 2) {
637 value = packer_code;
638 } else {
639 value = anim_instance_get_byte(ai,offset);
640 offset++;
641 }
642 if (++count > size){
643 count = size;
644 }
645
646 size -= count;
647 Assert(size >= 0);
648
649 if (value != transparent_code ) {
650 if ( xlate_pal ) {
651 stuffed = unpack_pixel_count(ai, frame, pal_translate[value], count, aabitmap, bpp);
652 } else {
653 stuffed = unpack_pixel_count(ai, frame, (ubyte)value, count, aabitmap, bpp);
654 }
655 } else {
656 stuffed = pixel_size * count;
657 }
658
659 frame += stuffed;
660 }
661 }
662
663 }
664 else if ( anim_instance_get_byte(ai,offset) ) { // normal frame, with high bit as count
665 offset++;
666 while (size > 0) {
667 value = anim_instance_get_byte(ai,offset);
668 offset++;
669 if ( !(value & STD_RLE_CODE) ) {
670 if (value != transparent_code) {
671 if ( xlate_pal ){
672 stuffed = unpack_pixel(ai, frame, pal_translate[value], aabitmap, bpp);
673 } else {
674 stuffed = unpack_pixel(ai, frame, (ubyte)value, aabitmap, bpp);
675 }
676 } else {
677 stuffed = pixel_size;
678 }
679
680 frame += stuffed;
681 size--;
682 } else {
683 count = value & (~STD_RLE_CODE);
684 value = anim_instance_get_byte(ai,offset);
685 offset++;
686
687 if (count > size)
688 count = size;
689
690 size -= count;
691 Assert(size >= 0);
692
693 if (value != transparent_code) {
694 if ( xlate_pal ){
695 stuffed = unpack_pixel_count(ai, frame, pal_translate[value], count, aabitmap, bpp);
696 } else {
697 stuffed = unpack_pixel_count(ai, frame, (ubyte)value, count, aabitmap, bpp);
698 }
699 } else {
700 stuffed = pixel_size * count;
701 }
702
703 frame += stuffed;
704 }
705 }
706 }
707 else {
708 // unknown packing method
709 return -1;
710 }
711
712 return ai->file_offset + offset;
713 }
714
715
716 /**
717 * @brief Set animation palette
718 * @todo Actually convert the frame data to correct palette at this point
719 */
anim_set_palette(anim * ptr)720 void anim_set_palette(anim *ptr)
721 {
722 int i, xparent_found = 0;
723
724 // create the palette translation look-up table
725 for ( i = 0; i < 256; i++ ) {
726 ptr->palette_translation[i] = (ubyte)i;
727 }
728
729 if ( xparent_found ) {
730 ptr->flags |= ANF_XPARENT;
731 }
732 else {
733 ptr->flags &= ~ANF_XPARENT;
734 }
735 }
736