/* BITMAP_EXTRACT.C symbols in this file: 00061EA0 0130: _extract_initialize (0000) 00061FD0 0120: _extract_find_sequence_bounds (0000) 000620F0 0080: _extract_warn_about_horizontal_border (0000) 00062170 0340: _extract_plateless_cube_map (0000) 000624B0 0190: _extract_find_bitmap_bounds (0000) 00062640 0240: _code_00062640 (0000) 00062880 03b0: _code_00062880 (0000) 00062C30 0210: _code_00062c30 (0000) 00062E40 0260: _code_00062e40 (0000) 000630A0 0580: _extract_build_debug_plate (0000) 00063620 03d0: _code_00063620 (0000) 000639F0 02b0: _extract_add_bitmap (0000) 00063CA0 01d0: _extract_3d_textures (0000) 00063E70 0220: _extract_cube_maps (0000) 00064090 0450: _extract_sprites (0000) 000644E0 0490: _extract_bitmap (0000) 00064970 0110: _extract_without_sequences (0000) 00064A80 02d0: _extract_sequence (0000) 00064D50 00b0: _extract_sequences (0000) 00064E00 02e0: _bitmaps_extract (0000) 000650E0 0130: _bitmaps_extract_from_plate (0000) 00251290 000e: ??_C@_0O@IOJAHIHH@top_reference?$AA@ (0000) 002512A0 0028: ??_C@_0CI@MDNPJHJC@c?3?2halo?2SOURCE?2bitmaps?2bitmap_ex@ (0000) 002512C8 0034: ??_C@_0DE@MPBEDKDP@?$CD?$CD?$CD?5WARNING?5horizontal?5border?5br@ (0000) 00251300 0045: ??_C@_0EF@HOBDLMPH@?$CD?$CD?$CD?5ERROR?5extract?3?5plateless?5cub@ (0000) 00251348 0042: ??_C@_0EC@CNAGFICN@?$CD?$CD?$CD?5ERROR?5extract?3?5can?8t?5handle?5@ (0000) 0025138C 0037: ??_C@_0DH@JLCLDNBC@?$CD?$CD?$CD?5ERROR?5extract?3?5failed?5to?5all@ (0000) 002513C4 001c: ??_C@_0BM@HDLJMFAA@bitmap_verify?$CIbitmap?0?5TRUE?$CJ?$AA@ (0000) 002513E0 001a: ??_C@_0BK@OPAPKIME@adjusted_bounds_reference?$AA@ (0000) 002513FC 0007: ??_C@_06CGBPGGIE@bounds?$AA@ (0000) 00251404 0033: ??_C@_0DD@OAKGMMJC@?$CD?$CD?$CD?5ERROR?5extract?3?5unsupported?5b@ (0000) 00251438 0024: ??_C@_0CE@MAGCMLBE@?$CD?$CD?$CD?5ERROR?5unsupported?5bitmap?5for@ (0000) 0025145C 003c: ??_C@_0DM@JCMHMNJE@?$CBTEST_FLAG?$CIdestination_bitmap?9?$DOf@ (0000) 00251498 005a: ??_C@_0FK@KAGBNKPE@destination_mipmap_index?$DO?$DN0?5?$CG?$CG?5d@ (0000) 002514F4 002e: ??_C@_0CO@MKAFAHJI@destination_bitmap?9?$DOtype?$DN?$DNsource@ (0000) 00251524 0029: ??_C@_0CJ@PMPPCDAH@bitmap_verify?$CIdestination_bitmap@ (0000) 00251550 0054: ??_C@_0FE@NNBMCEJD@source_bitmap?9?$DOdepth?5?$DN?$DNMAX?$CI1?0?5de@ (0000) 002515A8 0054: ??_C@_0FE@NIAAMOKD@source_bitmap?9?$DOheight?$DN?$DNMAX?$CI1?0?5de@ (0000) 00251600 0054: ??_C@_0FE@OGKNFLAG@source_bitmap?9?$DOwidth?5?$DN?$DNMAX?$CI1?0?5de@ (0000) 00251654 0023: ??_C@_0CD@ECDENEFB@bitmap_verify?$CIsource_bitmap?0?5TRU@ (0000) 00251678 004b: ??_C@_0EL@CICFBLGI@source_mipmap_index?$DO?$DN0?5?$CG?$CG?5source@ (0000) 002516C4 002e: ??_C@_0CO@LIKJMDNH@source_bitmap?9?$DOtype?$DN?$DNdestination@ (0000) 002516F4 0024: ??_C@_0CE@HECEPIHL@bitmap_verify?$CIsource_bitmap?0?5FAL@ (0000) 00251718 004f: ??_C@_0EP@JCFKDNGM@destination_bitmap?9?$DOdepth?5?$DN?$DNMAX?$CI@ (0000) 00251768 004f: ??_C@_0EP@KOPMFNGM@destination_bitmap?9?$DOheight?$DN?$DNMAX?$CI@ (0000) 002517B8 004f: ??_C@_0EP@OEMHGOAI@destination_bitmap?9?$DOwidth?5?$DN?$DNMAX?$CI@ (0000) 00251808 0028: ??_C@_0CI@JBLFEOIJ@bitmap_verify?$CIdestination_bitmap@ (0000) 00251830 0024: ??_C@_0CE@LCCMCEAJ@sequence?5spanned?5?$CFd?5texture?5page@ (0000) 00251854 0030: ??_C@_0DA@BOIOHNMC@?$CD?$CD?$CD?5ERROR?5failed?5to?5allocate?5deb@ (0000) 00251884 0030: ??_C@_0DA@NMPFGKNI@?$CD?$CD?$CD?5ERROR?5failed?5to?5allocate?5deb@ (0000) 002518B4 002a: ??_C@_0CK@DMHGHFA@?$CD?$CD?$CD?5ERROR?5failed?5to?5allocate?5deb@ (0000) 002518E0 0022: ??_C@_0CC@DECIGGNF@?$CD?$CD?$CD?5ERROR?5unsupported?5bitmap?5typ@ (0000) 00251904 0024: ??_C@_0CE@BAFBIHF@alpha_bias?$DO?$DN?9255?5?$CG?$CG?5alpha_bias?$DM?$DN@ (0000) 00251928 0030: ??_C@_0DA@KOPAIHGJ@destination_bitmap?9?$DOdepth?$DN?$DNsourc@ (0000) 00251958 0032: ??_C@_0DC@IECBCEHB@destination_bitmap?9?$DOheight?$DN?$DNsour@ (0000) 0025198C 0030: ??_C@_0DA@LLNHMAL@destination_bitmap?9?$DOwidth?$DN?$DNsourc@ (0000) 002519BC 0021: ??_C@_0CB@CLPJEELI@destination_bitmap?9?$DObase_address@ (0000) 002519E0 0013: ??_C@_0BD@JMEMKNJH@destination_bitmap?$AA@ (0000) 002519F4 0029: ??_C@_0CJ@PEGGHKHE@bitmap?5created?3?5?$CD?$CFdx?$CD?$CFd?0?5?$CFs?0?5?$CFdK@ (0000) 00251A20 002d: ??_C@_0CN@MGDDLHDM@bitmap?5created?3?5?$CD?$CFdx?$CD?$CFdx?$CD?$CFd?0?5?$CFs?0@ (0000) 00251A50 0028: ??_C@_0CI@GPIJKLOM@?$CD?$CD?$CD?5ERROR?5unsupported?5bitmap?5gro@ (0000) 00251A78 0036: ??_C@_0DG@OFJIKCDA@?$CD?$CD?$CD?5WARNING?5tried?5to?5smooth?5an?5i@ (0000) 00251AB0 002b: ??_C@_0CL@CJDNFNLC@?$CD?$CD?$CD?5WARNING?5tried?5to?5smooth?5a?5sp@ (0000) 00251ADC 0003: ??_C@_02PCIJFNDE@?$AN?6?$AA@ (0000) 00251AE0 0038: ??_C@_0DI@GIJPOGBA@skipping?53D?5texture?5with?5non?5pow@ (0000) 00251B18 002f: ??_C@_0CP@OCGAOEDI@skipping?53D?5texture?5with?5incompa@ (0000) 00251B48 0035: ??_C@_0DF@CHABNBMJ@?$CD?$CD?$CD?5ERROR?5extract?3?5failed?5to?5cre@ (0000) 00251B80 002b: ??_C@_0CL@KIGCKIOC@skipping?5cube?5map?5which?5spanned?5@ (0000) 00251BAC 0031: ??_C@_0DB@JFFHMOLJ@skipping?5cube?5map?5with?5incompati@ (0000) 00251BE0 002d: ??_C@_0CN@GHMACEEI@skipping?5cube?5map?5with?5less?5than@ (0000) 00251C10 002a: ??_C@_0CK@MAFGCHJA@skipping?5cube?5map?5with?5non?9squar@ (0000) 00251C3C 0012: ??_C@_0BC@OIPPCJDD@?$CBtemporary_bitmap?$AA@ (0000) 00251C50 002b: ??_C@_0CL@MNFLENMO@?$CD?$CD?$CD?5ERROR?5sprite?5budget?5exceeded@ (0000) 00251C7C 001e: ??_C@_0BO@PEKHFDDE@sprite?5budget?5met?5?$CI?$CF3?40f?$CF?$CF?$CJ?$AN?6?$AA@ (0000) 00251C9C 0023: ??_C@_0CD@PAPLMEDP@?$CD?$CD?$CD?5WARNING?5no?5sprite?5budget?5set@ (0000) 00251CC0 002e: ??_C@_0CO@CKBCALDJ@texture?5page?5created?5?$CD?$CFdx?$CD?$CFd?5?$CI?$CF3@ (0000) 00251CF0 0041: ??_C@_0EB@GJMFGLDP@?$CD?$CD?$CD?5ERROR?5extract_sprite?3?5failed@ (0000) 00251D38 0084: ??_C@_0IE@MKAIONEP@?$CD?$CD?$CD?5ERROR?5hey?5?9?5don?8t?5even?5try?5i@ (0000) 00251DC0 0044: ??_C@_0EE@DCBFAMBD@?$CD?$CD?$CD?5ERROR?5one?5or?5more?5sprites?5do@ (0000) 00251E04 0037: ??_C@_0DH@NFCBCMJC@?$CD?$CD?$CD?5WARNING?5skipped?5a?5bitmap?5whi@ (0000) 00251E3C 0034: ??_C@_0DE@MGADPMCF@?$CD?$CD?$CD?5ERROR?5extract?3?5failed?5to?5add@ (0000) 00251E70 0097: ??_C@_0JH@OBKFAPGC@?$CD?$CD?$CD?5ERROR?5extract?3?5tried?5to?5extr@ (0000) 00251F08 003b: ??_C@_0DL@FLDEAMAO@?$CD?$CD?$CD?5ERROR?5interface?1linear?5bitma@ (0000) 00251F48 0054: ??_C@_0FE@BCCMGDBK@?$DN?$DN?$DO?5?$CB?$CBWARNING?$CB?$CB?5bitmap?5with?5grea@ (0000) 00251FA0 0052: ??_C@_0FC@GFFGPBON@?$DN?$DN?$DO?5?$CB?$CBWARNING?$CB?$CB?5usage?5set?5to?5alp@ (0000) 00251FF4 0036: ??_C@_0DG@DKLFGIJN@?$CD?$CD?$CD?5ERROR?5can?8t?5extract?5sprites?5@ (0000) 0025202C 003a: ??_C@_0DK@PBJHAOGB@?$CD?$CD?$CD?5ERROR?5can?8t?5extract?53D?5textu@ (0000) 00252068 0053: ??_C@_0FD@OJBFAEHG@?$CD?$CD?$CD?5ERROR?5extract?3?5compressed?5co@ (0000) 002520BC 0023: ??_C@_0CD@LJHCCFGP@bottom?$DM?$DNextract_data?4plate?9?$DOheig@ (0000) 002520E0 000c: ??_C@_0M@NNAAFJDK@bottom?$DO?$DNtop?$AA@ (0000) 002520EC 0007: ??_C@_06JJMFEGFL@top?$DO?$DN0?$AA@ (0000) 002520F4 002f: ??_C@_0CP@LHGGIDHB@?$CD?$CD?$CD?5ERROR?5extract?3?5failed?5to?5all@ (0000) 00252124 0032: ??_C@_0DC@MGLFJBKA@?$CD?$CD?$CD?5ERROR?5extract?3?5failed?5to?5all@ (0000) 00252158 0034: ??_C@_0DE@BGBBNNDB@?$CD?$CD?$CD?5ERROR?5extract?3?5failed?5to?5dec@ (0000) 00252190 0052: ??_C@_0FC@OEKPABF@decompressed_plate_size?$DN?$DNsizeof?$CI@ (0000) 002521E4 003e: ??_C@_0DO@EDMJDNFC@?$CD?$CD?$CD?5ERROR?5extract?3?5failed?5to?5res@ (0000) 00252224 0033: ??_C@_0DD@FAIEDAFJ@?$CD?$CD?$CD?5ERROR?5extract?3?5failed?5to?5all@ (0000) 00252258 0040: ??_C@_0EA@PFFINKKO@group?9?$DOusage?5?$DO?$DN0?5?$CG?$CG?5group?9?$DOusage@ (0000) 00252298 0041: ??_C@_0EB@OKMLMBHL@group?9?$DOformat?$DO?$DN0?5?$CG?$CG?5group?9?$DOforma@ (0000) 002522DC 003d: ??_C@_0DN@FIMFNAFO@group?9?$DOtype?5?$DO?$DN0?5?$CG?$CG?5group?9?$DOtype?5?$DM@ (0000) 0025231C 0006: ??_C@_05MGJOOGAJ@group?$AA@ (0000) 00252324 0037: ??_C@_0DH@BHCBHGEP@?$CD?$CD?$CD?5ERROR?5extract?3?5failed?5to?5all@ (0000) 0025235C 0032: ??_C@_0DC@MDFBMDEG@?$CD?$CD?$CD?5ERROR?5extract?3?5failed?5to?5com@ (0000) 00252390 0031: ??_C@_0DB@KLKAOHKM@?$CD?$CD?$CD?5ERROR?5extract?3?5failed?5to?5rea@ (0000) 002523C4 001b: ??_C@_0BL@KAAMGFCF@bitmap_verify?$CIplate?0?5TRUE?$CJ?$AA@ (0000) 0031BED4 002c: _extract_data (0000) */ /* ---------- headers */ #include "cseries.h" #include "bitmaps/bitmap_group.h" #include "bitmaps/bitmaps.h" #include "bitmaps/bitmaps_internal.h" #include "cache/cache_files.h" #include "cseries/errors.h" #include "math/integer_math.h" #include "memory/data_compress.h" /* ---------- constants */ enum { _bitmap_group_type_2d_textures, _bitmap_group_type_3d_textures, _bitmap_group_type_cube_maps, _bitmap_group_type_sprites, _bitmap_group_type_interface_bitmaps, NUMBER_OF_BITMAP_GROUP_TYPES }; enum { _bitmap_group_format_compressed_color_key_transparency, _bitmap_group_format_compressed_explicit_alpha, _bitmap_group_format_compressed_interpolated_alpha, _bitmap_group_format_16bit_color, _bitmap_group_format_32bit_color, _bitmap_group_format_monochrome, NUMBER_OF_BITMAP_GROUP_FORMATS }; enum { _bitmap_group_usage_alpha_blend, _bitmap_group_usage_default, _bitmap_group_usage_height_map, _bitmap_group_usage_detail_map, _bitmap_group_usage_light_map, _bitmap_group_usage_vector_map, NUMBER_OF_BITMAP_GROUP_USAGES }; enum { _bitmap_format_a8r8g8b8 = 11, }; enum { _bitmap_group_extract_sprites_filthy_bug_fix_bit = 3, }; /* ---------- macros */ /* ---------- structures */ struct bitmap_group_sprite { short bitmap_index; word bitmap_pad; long unused; real_rectangle2d bounds; real_point2d registration_point; }; struct bitmap_group_sequence { char name[32]; short first_bitmap_index; short bitmap_count; long unused[4]; struct tag_block sprites; }; struct bitmap_extract_data { struct bitmap_extract_entry *bitmaps; short bitmap_count; pixel32 top_reference; pixel32 bottom_reference; pixel32 adjusted_bounds_reference; boolean extract_sequences; boolean single_sequence; struct bitmap_group *group; struct bitmap_data *plate; long build_debug_plate; struct bitmap_group_sequence *sequence; short sequence_index; short bitmap_index; }; struct bitmap_extract_entry { struct bitmap_data *bitmap; short sequence_index; short sprite_index; short page_index; word unused; long page_entry_index; }; typedef char bitmap_group_sprite_size_assert[ sizeof(struct bitmap_group_sprite) == 0x20 ? 1 : -1]; typedef char bitmap_group_sequence_size_assert[ sizeof(struct bitmap_group_sequence) == 0x40 ? 1 : -1]; typedef char bitmap_extract_entry_size_assert[ sizeof(struct bitmap_extract_entry) == 0x10 ? 1 : -1]; typedef char bitmap_extract_data_size_assert[ sizeof(struct bitmap_extract_data) == 0x2C ? 1 : -1]; /* ---------- prototypes */ static void extract_initialize( void); static short extract_find_sequence_bounds( short *top_reference); static void extract_warn_about_horizontal_border( short bottom); static boolean extract_find_bitmap_bounds( rectangle2d const *bounds, rectangle2d *adjusted_bounds_reference); static boolean extract_sequences( void); static boolean extract_without_sequences( void); boolean extract_plateless_cube_map( struct bitmap_data *bitmap); short extract_add_bitmap( struct bitmap_data *bitmap); boolean extract_3d_textures( void); boolean extract_cube_maps( void); boolean extract_sprites( void); static boolean extract_bitmap( rectangle2d const *bounds); boolean extract_sequence( short top, short bottom); /* ---------- globals */ static struct bitmap_extract_data extract_data; /* ---------- public code */ boolean bitmaps_extract( struct bitmap_group *group, long build_debug_plate) { unsigned long decompressed_plate_size; boolean should_extract_sequences; boolean result; match_assert("c:\\halo\\SOURCE\\bitmaps\\bitmap_extract.c", 0xB4, group); match_assert( "c:\\halo\\SOURCE\\bitmaps\\bitmap_extract.c", 0xB5, group->type >=0 && group->type format>=0 && group->formatusage >=0 && group->usage bitmap_data, 0) && tag_block_resize(&group->sequences, 0) && tag_data_resize(&group->pixel_data, 0)) { extract_data.sequence = NULL; extract_data.sequence_index = NONE; extract_data.group = group; extract_data.plate = bitmap_2d_new( group->import_width, group->import_height, 0, _bitmap_format_a8r8g8b8); if (!extract_data.plate) { error(_error_silent, "### ERROR extract: failed to allocate color plate"); result = FALSE; } else { decompressed_plate_size = data_decompressed_size( group->import_bitmap.address, group->import_bitmap.size); match_assert( "c:\\halo\\SOURCE\\bitmaps\\bitmap_extract.c", 0x104, decompressed_plate_size == sizeof(pixel32) * group->import_width * group->import_height); if (data_decompress( group->import_bitmap.address, group->import_bitmap.size, bitmap_mipmap_address(extract_data.plate, 0), &decompressed_plate_size, decompressed_plate_size)) { extract_initialize(); should_extract_sequences = extract_data.extract_sequences; extract_data.build_debug_plate = build_debug_plate; if (should_extract_sequences) result = extract_sequences(); else result = extract_without_sequences(); bitmap_delete(extract_data.plate); if (result) { switch (extract_data.group->type) { case _bitmap_group_type_2d_textures: case _bitmap_group_type_interface_bitmaps: break; case _bitmap_group_type_3d_textures: result = extract_3d_textures(); break; case _bitmap_group_type_cube_maps: result = extract_cube_maps(); break; case _bitmap_group_type_sprites: result = extract_sprites(); break; default: match_vassert( "c:\\halo\\SOURCE\\bitmaps\\bitmap_extract.c", 0x137, FALSE, "### ERROR unsupported bitmap group type"); } } } else { error(_error_silent, "### ERROR extract: failed to decompress color plate"); result = FALSE; } } goto cleanup; } error(_error_silent, "### ERROR extract: failed to resize bitmap group tags to zero"); result = FALSE; cleanup: if (extract_data.bitmaps) { match_free( "c:\\halo\\SOURCE\\bitmaps\\bitmap_extract.c", 0x13D, extract_data.bitmaps); } return result; } boolean bitmaps_extract_from_plate( struct bitmap_data *plate, struct bitmap_group *group, long build_debug_plate) { long compressed_color_plate_size; void *compressed_color_plate; match_assert("c:\\halo\\SOURCE\\bitmaps\\bitmap_extract.c", 0x83, bitmap_verify(plate, TRUE)); match_assert("c:\\halo\\SOURCE\\bitmaps\\bitmap_extract.c", 0x84, group); compressed_color_plate_size = bitmap_get_pixel_data_size(plate); group->import_width = plate->width; group->import_height = plate->height; group->import_bitmap.address = match_malloc( "c:\\halo\\SOURCE\\bitmaps\\bitmap_extract.c", 0x8A, compressed_color_plate_size); if (group->import_bitmap.address) { if (data_compress( bitmap_mipmap_address(plate, 0), compressed_color_plate_size, group->import_bitmap.address, &compressed_color_plate_size, compressed_color_plate_size)) { compressed_color_plate = match_realloc( "c:\\halo\\SOURCE\\bitmaps\\bitmap_extract.c", 0x90, group->import_bitmap.address, compressed_color_plate_size); if (compressed_color_plate) { group->import_bitmap.address = compressed_color_plate; group->import_bitmap.size = compressed_color_plate_size; return bitmaps_extract(group, build_debug_plate); } error(_error_silent, "### ERROR extract: failed to realloc color plate"); return FALSE; } error(_error_silent, "### ERROR extract: failed to compress color plate"); return FALSE; } error(_error_silent, "### ERROR extract: failed to allocate temporary buffer"); return FALSE; } /* ---------- private code */ static void extract_initialize( void) { short x; extract_data.extract_sequences = TRUE; extract_data.single_sequence = FALSE; extract_data.top_reference = *(pixel32 *)bitmap_2d_address(extract_data.plate, 0, 0, 0) & 0xFFFFFF; extract_data.bottom_reference = *(pixel32 *)bitmap_2d_address(extract_data.plate, 1, 0, 0) & 0xFFFFFF; extract_data.adjusted_bounds_reference = *(pixel32 *)bitmap_2d_address(extract_data.plate, 2, 0, 0) & 0xFFFFFF; if (extract_data.adjusted_bounds_reference == extract_data.bottom_reference && extract_data.bottom_reference != 0xFF) { extract_data.extract_sequences = FALSE; } if (extract_data.top_reference == extract_data.bottom_reference) { extract_data.adjusted_bounds_reference = 0xFFFF; extract_data.single_sequence = TRUE; } for (x = 3; x < extract_data.plate->width; x++) { pixel32 top = *(pixel32 *)bitmap_2d_address(extract_data.plate, x, 0, 0) & 0xFFFFFF; pixel32 bottom = *(pixel32 *)bitmap_2d_address(extract_data.plate, x, 1, 0) & 0xFFFFFF; if (top != extract_data.top_reference && bottom != extract_data.bottom_reference) { extract_data.extract_sequences = FALSE; } } if (!extract_data.extract_sequences) { extract_data.adjusted_bounds_reference = 0xFF000000; extract_data.bottom_reference = 0xFF000000; extract_data.top_reference = 0xFF000000; } return; } static short extract_find_sequence_bounds( short *top_reference) { short bottom; match_assert( "c:\\halo\\SOURCE\\bitmaps\\bitmap_extract.c", 0x1D9, top_reference); if (extract_data.single_sequence) { boolean found_sequence = FALSE; for (bottom = *top_reference; bottom < extract_data.plate->height; bottom++) { short x; boolean found_sequence_pixel = FALSE; for (x = 0; x < extract_data.plate->width; x++) { pixel32 color = *(pixel32 *)bitmap_2d_address( extract_data.plate, x, bottom, 0) & 0xFFFFFF; if (color != extract_data.top_reference) found_sequence_pixel = TRUE; } if (found_sequence_pixel) { found_sequence = TRUE; } else if (found_sequence) { break; } else { *top_reference = bottom + 1; } } } else { boolean found_top_reference = FALSE; for (bottom = *top_reference; bottom < extract_data.plate->height; bottom++) { pixel32 color = *(pixel32 *)bitmap_2d_address( extract_data.plate, 0, bottom, 0) & 0xFFFFFF; if (color == extract_data.top_reference) { found_top_reference = TRUE; } else if (color == extract_data.bottom_reference && found_top_reference) { break; } else { *top_reference = bottom + 1; } } } return bottom; } static void extract_warn_about_horizontal_border( short bottom) { if (VALID_INDEX(bottom, extract_data.plate->height)) { short x; for (x = 0; x < extract_data.plate->width; x++) { pixel32 color = *(pixel32 *)bitmap_2d_address( extract_data.plate, x, bottom, 0) & 0xFFFFFF; if (color != extract_data.bottom_reference) { fprintf(stdout, "### WARNING horizontal border broken at (#%d,#%d)\r\n", x, bottom); fflush(stdout); break; } } } return; } static boolean extract_find_bitmap_bounds( rectangle2d const *bounds, rectangle2d *adjusted_bounds_reference) { boolean result = FALSE; short y; match_assert( "c:\\halo\\SOURCE\\bitmaps\\bitmap_extract.c", 0x3F7, bounds); match_assert( "c:\\halo\\SOURCE\\bitmaps\\bitmap_extract.c", 0x3F8, adjusted_bounds_reference); adjusted_bounds_reference->y0 = SHORT_MAX; adjusted_bounds_reference->x0 = SHORT_MAX; adjusted_bounds_reference->y1 = SHORT_MIN; adjusted_bounds_reference->x1 = SHORT_MIN; for (y = bounds->y0; y < bounds->y1; y++) { short x; for (x = bounds->x0; x < bounds->x1; x++) { if (VALID_INDEX(x, extract_data.plate->width) && VALID_INDEX(y, extract_data.plate->height)) { pixel32 color = *(pixel32 *)bitmap_2d_address(extract_data.plate, x, y, 0); pixel32 rgb = color & 0xFFFFFF; boolean contains_data = TRUE; if (extract_data.extract_sequences) { if (rgb == extract_data.top_reference || rgb == extract_data.bottom_reference || rgb == extract_data.adjusted_bounds_reference) { contains_data = FALSE; } else if (extract_data.group->usage == _bitmap_group_usage_alpha_blend && !(color & 0xFF000000)) { contains_data = FALSE; } } if (contains_data) { adjusted_bounds_reference->x0 = MIN(x, adjusted_bounds_reference->x0); adjusted_bounds_reference->y0 = MIN(y, adjusted_bounds_reference->y0); adjusted_bounds_reference->x1 = MAX(x, adjusted_bounds_reference->x1); adjusted_bounds_reference->y1 = MAX(y, adjusted_bounds_reference->y1); result = TRUE; } } } } adjusted_bounds_reference->x1++; adjusted_bounds_reference->y1++; return result; } static boolean extract_bitmap( rectangle2d const *bounds) { boolean result = TRUE; boolean warned_about_zero_alpha = FALSE; boolean warned_about_dxt1_alpha = FALSE; rectangle2d adjusted_bounds; struct bitmap_data *bitmap; short source_y; short destination_y; match_assert( "c:\\halo\\SOURCE\\bitmaps\\bitmap_extract.c", 0x322, bounds); if (extract_find_bitmap_bounds(bounds, &adjusted_bounds)) { bitmap = bitmap_2d_new( adjusted_bounds.x1 - adjusted_bounds.x0, adjusted_bounds.y1 - adjusted_bounds.y0, 0, _bitmap_format_a8r8g8b8); if (bitmap) { if (TEST_FLAG( extract_data.group->flags, _bitmap_group_extract_sprites_filthy_bug_fix_bit)) { bitmap->registration_point_x = bounds->x0 + bounds->x1 - 2 * adjusted_bounds.x0; bitmap->registration_point_y = bounds->y0 + bounds->y1 - 2 * adjusted_bounds.y0; } else { bitmap->registration_point_x = (bounds->x0 + bounds->x1) / 2 - adjusted_bounds.x0; bitmap->registration_point_y = (bounds->y0 + bounds->y1) / 2 - adjusted_bounds.y0; } for ( source_y = adjusted_bounds.y0, destination_y = 0; source_y < adjusted_bounds.y1; source_y++, destination_y++) { pixel32 *destination = bitmap_2d_address(bitmap, 0, destination_y, 0); short source_x; for (source_x = adjusted_bounds.x0; source_x < adjusted_bounds.x1; source_x++) { pixel32 color = *(pixel32 *)bitmap_2d_address( extract_data.plate, source_x, source_y, 0); if (extract_data.extract_sequences) { pixel32 rgb = color & 0xFFFFFF; if (rgb == extract_data.top_reference || rgb == extract_data.adjusted_bounds_reference || rgb == extract_data.bottom_reference) { color = 0; } } if (extract_data.group->usage == _bitmap_group_usage_alpha_blend && !(color & 0xFF000000) && (color & 0xFFFFFF) && !warned_about_zero_alpha) { fprintf( stdout, "==> !!WARNING!! usage set to alpha; non-zero color overlaps with zero-alpha <==\r\n"); fflush(stdout); warned_about_zero_alpha = TRUE; } if (extract_data.group->format == _bitmap_group_format_compressed_color_key_transparency) { unsigned long alpha = color >> 24; if (alpha != 0 && alpha != 255 && !warned_about_dxt1_alpha) { fprintf( stdout, "==> !!WARNING!! bitmap with greater than 1-bit alpha being compressed as DXT1 <==\r\n"); fflush(stdout); warned_about_dxt1_alpha = TRUE; } if (!alpha && ((color & 0xFFFFFF) == extract_data.adjusted_bounds_reference || !extract_data.extract_sequences)) { color = 0; } else { color |= 0xFF000000; } } if ((extract_data.group->format == _bitmap_group_format_compressed_color_key_transparency || extract_data.group->format == _bitmap_group_format_compressed_explicit_alpha || extract_data.group->format == _bitmap_group_format_compressed_interpolated_alpha) && extract_data.group->type == _bitmap_group_type_interface_bitmaps) { error( _error_immediate, "### ERROR interface/linear bitmap cannot be DXT-compressed"); } *destination++ = color; } } if (extract_data.group->type == _bitmap_group_type_2d_textures || extract_data.group->type == _bitmap_group_type_interface_bitmaps) { short bitmap_index = extract_add_bitmap(bitmap); if (bitmap_index != NONE) { if (extract_data.sequence->first_bitmap_index == NONE) { extract_data.sequence->first_bitmap_index = bitmap_index; extract_data.sequence->bitmap_count = 0; } extract_data.sequence->bitmap_count++; } bitmap_delete(bitmap); return result; } if (!extract_data.extract_sequences) { if (extract_data.group->type == _bitmap_group_type_cube_maps) { extract_plateless_cube_map(bitmap); } else { error( _error_silent, "### ERROR extract: tried to extract non-2d textures without a valid place but they weren't cube maps and/or EXTRACT_PLATELESS_CUBE_MAPS aren't allowed"); result = FALSE; } bitmap_delete(bitmap); return result; } if (extract_data.bitmap_count < 0x400) { struct bitmap_extract_entry *entry = &extract_data.bitmaps[extract_data.bitmap_count++]; entry->bitmap = bitmap; entry->sequence_index = extract_data.sequence_index; entry->sprite_index = NONE; entry->page_index = NONE; entry->page_entry_index = NONE; if (extract_data.group->type == _bitmap_group_type_sprites) { short sprite_index = (short)tag_block_add_element(&extract_data.sequence->sprites); struct bitmap_group_sprite *sprite; if (sprite_index == NONE) { error(_error_silent, "### ERROR extract: failed to add sprite to sequence"); return FALSE; } sprite = TAG_BLOCK_GET_ELEMENT( &extract_data.sequence->sprites, sprite_index, struct bitmap_group_sprite); sprite->bitmap_index = NONE; if (TEST_FLAG( extract_data.group->flags, _bitmap_group_extract_sprites_filthy_bug_fix_bit)) { sprite->registration_point.x = (real)bitmap->registration_point_x * 0.5f; sprite->registration_point.y = (real)bitmap->registration_point_y * 0.5f; } else { sprite->registration_point.x = (real)bitmap->registration_point_x; sprite->registration_point.y = (real)bitmap->registration_point_y; } entry->sprite_index = sprite_index; } return result; } error( _error_silent, "### ERROR extract: can't handle more than (#%d) temporary bitmaps", 0x400); return FALSE; } error(_error_silent, "### ERROR extract: failed to allocate temporary bitmap"); result = FALSE; } else { fprintf(stdout, "### WARNING skipped a bitmap which contained no data\r\n"); fflush(stdout); } return result; } static boolean extract_without_sequences( void) { rectangle2d bounds; struct bitmap_group *group = extract_data.group; boolean result = TRUE; if (group->format == _bitmap_group_format_compressed_color_key_transparency && extract_data.extract_sequences) { error( _error_silent, "### ERROR extract: compressed color-key transparency format must use a valid plate"); result = FALSE; } else { switch (group->type) { case _bitmap_group_type_2d_textures: case _bitmap_group_type_cube_maps: case _bitmap_group_type_interface_bitmaps: { short plate_width; short plate_height; short sequence_index; bounds.y0 = 0; bounds.x0 = 0; plate_width = extract_data.plate->width; plate_height = extract_data.plate->height; bounds.x1 = plate_width; bounds.y1 = plate_height; sequence_index = (short)tag_block_add_element(&group->sequences); extract_data.sequence_index = sequence_index; extract_data.sequence = tag_block_get_element_with_size( &extract_data.group->sequences, sequence_index, sizeof(struct bitmap_group_sequence)); extract_data.sequence->first_bitmap_index = NONE; extract_bitmap(&bounds); break; } case _bitmap_group_type_3d_textures: error(_error_silent, "### ERROR can't extract 3D textures without a valid plate"); result = FALSE; break; case _bitmap_group_type_sprites: error(_error_silent, "### ERROR can't extract sprites without a valid plate"); result = FALSE; break; default: match_vassert( "c:\\halo\\SOURCE\\bitmaps\\bitmap_extract.c", 0x1A6, FALSE, "### ERROR unsupported bitmap group type"); break; } } return result; } static boolean extract_sequences( void) { boolean result = TRUE; short top = 1; while (result && top < extract_data.plate->height) { short bottom; short sequence_index; bottom = extract_find_sequence_bounds(&top); extract_warn_about_horizontal_border(bottom); sequence_index = (short)tag_block_add_element(&extract_data.group->sequences); if (sequence_index == NONE) { error(_error_silent, "### ERROR extract: failed to allocate sequence"); return FALSE; } extract_data.sequence_index = sequence_index; extract_data.sequence = tag_block_get_element_with_size( &extract_data.group->sequences, sequence_index, sizeof(struct bitmap_group_sequence)); extract_data.sequence->first_bitmap_index = NONE; extract_data.sequence->bitmap_count = 0; result = extract_sequence(top, bottom); top = bottom + 1; } return result; }