ref: e2c0f46e4f64f7970005a66056be85a6929b5227
dir: /src/w_merge.c/
// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // $Id: w_merge.c 179 2005-10-09 00:25:49Z fraggle $ // // Copyright(C) 2005 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. // // $Log$ // Revision 1.2 2005/10/09 00:25:49 fraggle // Improved sprite merging // // Revision 1.1 2005/10/08 18:23:18 fraggle // WAD merging code // // // DESCRIPTION: // Handles merging of PWADs, similar to deutex's -merge option // // Ideally this should work exactly the same as in deutex, but trying to // read the deutex source code made my brain hurt. // //----------------------------------------------------------------------------- #include <stdlib.h> #include <string.h> #include "i_system.h" #include "w_wad.h" #include "z_zone.h" typedef enum { SECTION_NORMAL, SECTION_FLATS, SECTION_SPRITES, } section_t; typedef struct { lumpinfo_t *lumps; int numlumps; } searchlist_t; typedef struct { char sprname[4]; char frame; int angles; } replace_frame_t; static searchlist_t iwad; static searchlist_t pwad; static searchlist_t iwad_flats; static searchlist_t pwad_sprites; static searchlist_t pwad_flats; // lumps with these sprites must be replaced in the IWAD static replace_frame_t *replace_frames; static int num_replace_frames; static int replace_frames_alloced; // Search in a list to find a lump with a particular name // Linear search (slow!) // // Returns -1 if not found static int FindInList(searchlist_t *list, char *name) { int i; for (i=0; i<list->numlumps; ++i) { if (!strncasecmp(list->lumps[i].name, name, 8)) return i; } return -1; } // Sets up the sprite/flat search lists static void SetupLists(void) { int startlump, endlump; // IWAD // look for the flats section startlump = FindInList(&iwad, "F_START"); endlump = FindInList(&iwad, "F_END"); if (startlump < 0 || endlump < 0) { I_Error("Flats section not found in IWAD"); } iwad_flats.lumps = iwad.lumps + startlump + 1; iwad_flats.numlumps = endlump - startlump - 1; // PWAD // look for a flats section pwad_flats.numlumps = 0; startlump = FindInList(&pwad, "FF_START"); if (startlump < 0) { startlump = FindInList(&pwad, "F_START"); } if (startlump >= 0) { endlump = FindInList(&pwad, "FF_END"); if (endlump < 0) { endlump = FindInList(&pwad, "F_END"); } if (endlump > startlump) { pwad_flats.lumps = pwad.lumps + startlump + 1; pwad_flats.numlumps = endlump - startlump - 1; } } // look for a sprites section pwad_sprites.numlumps = 0; startlump = FindInList(&pwad, "SS_START"); if (startlump < 0) { startlump = FindInList(&pwad, "S_START"); } if (startlump >= 0) { endlump = FindInList(&pwad, "SS_END"); if (endlump < startlump) { endlump = FindInList(&pwad, "S_END"); } if (endlump > startlump) { pwad_sprites.lumps = pwad.lumps + startlump + 1; pwad_sprites.numlumps = endlump - startlump - 1; } } } // Initialise the replace list static void InitReplaceList(void) { if (replace_frames == NULL) { replace_frames_alloced = 128; replace_frames = Z_Malloc(sizeof(*replace_frames) * replace_frames_alloced, PU_STATIC, NULL); } num_replace_frames = 0; } // Add new sprite to the replace list static void AddReplaceFrame(replace_frame_t *frame) { int i; // Find if this is already in the list for (i=0; i<num_replace_frames; ++i) { if (!strncasecmp(replace_frames[i].sprname, frame->sprname, 4) && replace_frames[i].frame == frame->frame) { replace_frames[i].angles |= frame->angles; return; } } // Need to add to the list if (num_replace_frames >= replace_frames_alloced) { replace_frame_t *newframes; newframes = Z_Malloc(replace_frames_alloced * 2 * sizeof(*replace_frames), PU_STATIC, NULL); memcpy(newframes, replace_frames, replace_frames_alloced * sizeof(*replace_frames)); Z_Free(replace_frames); replace_frames_alloced *= 2; replace_frames = newframes; } // Add to end of list replace_frames[num_replace_frames++] = *frame; } // Converts a sprite name into an replace_frame_t static void ParseSpriteName(char *name, replace_frame_t *result) { int angle_num; strncpy(result->sprname, name, 4); result->frame = name[4]; angle_num = name[5] - '0'; if (angle_num == 0) { // '0' sprites are used for all angles result->angles = 0xffff; } else { result->angles = 1 << angle_num; } if (name[6] != '\0') { // second angle angle_num = name[7] - '0'; if (angle_num == 0) { result->angles = 0xffff; } else { result->angles |= 1 << angle_num; } } } // Check if a sprite is in the replace list static boolean InReplaceList(char *name) { replace_frame_t igsprite; int i; ParseSpriteName(name, &igsprite); for (i=0; i<num_replace_frames; ++i) { if (!strncasecmp(replace_frames[i].sprname, igsprite.sprname, 4) && replace_frames[i].frame == igsprite.frame && (replace_frames[i].angles & igsprite.angles) != 0) { return true; } } return false; } // Generate the list. Run at the start, before merging static void GenerateReplaceList(void) { replace_frame_t igsprite; int i; InitReplaceList(); for (i=0; i<pwad_sprites.numlumps; ++i) { ParseSpriteName(pwad_sprites.lumps[i].name, &igsprite); AddReplaceFrame(&igsprite); } } // Perform the merge. // // The merge code creates a new lumpinfo list, adding entries from the // IWAD first followed by the PWAD. // // For the IWAD: // * Flats are added. If a flat with the same name is in the PWAD, // it is ignored(deleted). At the end of the section, all flats in the // PWAD are inserted. This is consistent with the behavior of // deutex/deusf. // * Sprites are added. The "replace list" is generated before the merge // from the list of sprites in the PWAD. Any sprites in the IWAD found // to match the replace list are removed. At the end of the section, // the sprites from the PWAD are inserted. // // For the PWAD: // * All Sprites and Flats are ignored, with the assumption they have // already been merged into the IWAD's sections. static void DoMerge(void) { section_t current_section; lumpinfo_t *newlumps; int num_newlumps; int lumpindex; int i, n; // Can't ever have more lumps than we already have newlumps = malloc(sizeof(lumpinfo_t) * numlumps); num_newlumps = 0; // Add IWAD lumps current_section = SECTION_NORMAL; for (i=0; i<iwad.numlumps; ++i) { lumpinfo_t *lump = &iwad.lumps[i]; switch (current_section) { case SECTION_NORMAL: if (!strncasecmp(lump->name, "F_START", 8)) { current_section = SECTION_FLATS; } else if (!strncasecmp(lump->name, "S_START", 8)) { current_section = SECTION_SPRITES; } newlumps[num_newlumps++] = *lump; break; case SECTION_FLATS: // Have we reached the end of the section? if (!strncasecmp(lump->name, "F_END", 8)) { // Add all new flats from the PWAD to the end // of the section for (n=0; n<pwad_flats.numlumps; ++n) { newlumps[num_newlumps++] = pwad_flats.lumps[n]; } newlumps[num_newlumps++] = *lump; // back to normal reading current_section = SECTION_NORMAL; } else { // If there is a flat in the PWAD with the same name, // do not add it now. All PWAD flats are added to the // end of the section. Otherwise, if it is only in the // IWAD, add it now lumpindex = FindInList(&pwad_flats, lump->name); if (lumpindex < 0) { newlumps[num_newlumps++] = *lump; } } break; case SECTION_SPRITES: // Have we reached the end of the section? if (!strncasecmp(lump->name, "S_END", 8)) { // add all the pwad sprites for (n=0; n<pwad_sprites.numlumps; ++n) { newlumps[num_newlumps++] = pwad_sprites.lumps[n]; } // copy the ending newlumps[num_newlumps++] = *lump; // back to normal reading current_section = SECTION_NORMAL; } else { // Is this lump holding a sprite to be replaced in the // PWAD? If so, wait until the end to add it. if (!InReplaceList(lump->name)) { newlumps[num_newlumps++] = *lump; } } break; } } // Add PWAD lumps current_section = SECTION_NORMAL; for (i=0; i<pwad.numlumps; ++i) { lumpinfo_t *lump = &pwad.lumps[i]; switch (current_section) { case SECTION_NORMAL: if (!strncasecmp(lump->name, "F_START", 8) || !strncasecmp(lump->name, "FF_START", 8)) { current_section = SECTION_FLATS; } else if (!strncasecmp(lump->name, "S_START", 8) || !strncasecmp(lump->name, "SS_START", 8)) { current_section = SECTION_SPRITES; } else { // Don't include the headers of sections newlumps[num_newlumps++] = *lump; } break; case SECTION_FLATS: // PWAD flats are ignored (already merged) if (!strncasecmp(lump->name, "FF_END", 8) || !strncasecmp(lump->name, "F_END", 8)) { // end of section current_section = SECTION_NORMAL; } break; case SECTION_SPRITES: // PWAD sprites are ignored (already merged) if (!strncasecmp(lump->name, "SS_END", 8) || !strncasecmp(lump->name, "S_END", 8)) { // end of section current_section = SECTION_NORMAL; } break; } } // Switch to the new lumpinfo, and free the old one free(lumpinfo); lumpinfo = newlumps; numlumps = num_newlumps; } // Merge in a file by name void W_MergeFile(char *filename) { int old_numlumps; old_numlumps = numlumps; W_AddFile(filename); // failed to load? if (numlumps == old_numlumps) return; printf(" merging %s\n", filename); // iwad is at the start, pwad was appended to the end iwad.lumps = lumpinfo; iwad.numlumps = old_numlumps; pwad.lumps = lumpinfo + old_numlumps; pwad.numlumps = numlumps - old_numlumps; // Setup sprite/flat lists SetupLists(); // Generate list of sprites to be replaced by the PWAD GenerateReplaceList(); // Perform the merge DoMerge(); }