示例#1
0
文件: w_wad.c 项目: derek57/research
void W_GenerateHashTable(void)
{
    lumpindex_t i;

    // Free the old hash table, if there is one:
    if (lumphash != NULL)
    {
        Z_Free(lumphash);
    }

    // Generate hash table
    if (numlumps > 0)
    {
        lumphash = Z_Malloc(sizeof(lumpindex_t) * numlumps, PU_STATIC, NULL);

        for (i = 0; i < numlumps; ++i)
        {
            lumphash[i] = -1;
        }

        for (i = 0; i < numlumps; ++i)
        {
            unsigned int hash;

            hash = W_LumpNameHash(lumpinfo[i]->name) % numlumps;

            // Hook into the hash table

            lumpinfo[i]->next = lumphash[hash];
            lumphash[hash] = i;
        }
    }

    // All done!
}
示例#2
0
文件: w_wad.c 项目: mdgunn/doomretro
//
// W_CheckNumForName
// Returns -1 if name not found.
//
lumpindex_t W_CheckNumForName(char *name)
{
    lumpindex_t i;

    // Do we have a hash table yet?
    if (lumphash)
    {
        int     hash;

        // We do! Excellent.
        hash = W_LumpNameHash(name) % numlumps;

        for (i = lumphash[hash]; i != -1; i = lumpinfo[i]->next)
            if (!strncasecmp(lumpinfo[i]->name, name, 8))
                return i;
    }
    else
    {
        // We don't have a hash table generate yet. Linear search :-(
        // scan backwards so patch lump files take precedence
        for (i = numlumps - 1; i >= 0; --i)
            if (!strncasecmp(lumpinfo[i]->name, name, 8))
                return i;
    }

    // TFB. Not found.
    return -1;
}
示例#3
0
void W_GenerateHashTable(void)
{
    unsigned int i;

    // Free the old hash table, if there is one

    if (lumphash != NULL)
    {
        Z_Free(lumphash);
    }

    // Generate hash table
    if (numlumps > 0)
    {
        lumphash = Z_Malloc(sizeof(lumpinfo_t *) * numlumps, PU_STATIC, NULL);
        memset(lumphash, 0, sizeof(lumpinfo_t *) * numlumps);

        for (i=0; i<numlumps; ++i)
        {
            unsigned int hash;

            hash = W_LumpNameHash(lumpinfo[i].name) % numlumps;

            // Hook into the hash table

            lumpinfo[i].next = lumphash[hash];
            lumphash[hash] = &lumpinfo[i];
        }
    }

    // All done!
}
示例#4
0
文件: w_wad.c 项目: CaptainHIT/prboom
// W_FindNumFromName, an iterative version of W_CheckNumForName
// returns list of lump numbers for a given name (latest first)
//
int (W_FindNumFromName)(const char *name, int li_namespace, int i)
{
  // Hash function maps the name to one of possibly numlump chains.
  // It has been tuned so that the average chain length never exceeds 2.

  // proff 2001/09/07 - check numlumps==0, this happens when called before WAD loaded
  if (numlumps == 0)
    i = -1;
  else
  {
    if (i < 0)
      i = lumpinfo[W_LumpNameHash(name) % (unsigned) numlumps].index;
    else
      i = lumpinfo[i].next;

  // We search along the chain until end, looking for case-insensitive
  // matches which also match a namespace tag. Separate hash tables are
  // not used for each namespace, because the performance benefit is not
  // worth the overhead, considering namespace collisions are rare in
  // Doom wads.

  while (i >= 0 && (strncasecmp(lumpinfo[i].name, name, 8) ||
                    lumpinfo[i].li_namespace != li_namespace))
    i = lumpinfo[i].next;
  }

  // Return the matching lump, or -1 if none found.

  return i;
}
示例#5
0
static void GenerateTextureHashTable(void)
{
    texture_t   **rover;
    int         i;
    int         key;

    textures_hashtable = (texture_t **)Z_Malloc(sizeof(texture_t *) * numtextures, PU_STATIC, 0);

    memset(textures_hashtable, 0, sizeof(texture_t *) * numtextures);

    // Add all textures to hash table
    for (i = 0; i < numtextures; ++i)
    {
        // Store index
        textures[i]->index = i;

        // Vanilla Doom does a linear search of the texures array
        // and stops at the first entry it finds.  If there are two
        // entries with the same name, the first one in the array
        // wins. The new entry must therefore be added at the end
        // of the hash chain, so that earlier entries win.
        key = W_LumpNameHash(textures[i]->name) % numtextures;

        rover = &textures_hashtable[key];

        while (*rover != NULL)
            rover = &(*rover)->next;

        // Hook into hash table
        textures[i]->next = NULL;
        *rover = textures[i];
    }
}
static void GenerateTextureHashTable(void)
{
    int i;
    int key;

    textures_hashtable 
            = Z_Malloc(sizeof(texture_t *) * numtextures, PU_STATIC, 0);

    memset(textures_hashtable, 0, sizeof(texture_t *) * numtextures);

    // Add all textures to hash table

    for (i=0; i<numtextures; ++i)
    {
        // Store index

        textures[i]->index = i;

        // Hook into hash table

        key = W_LumpNameHash(textures[i]->name) % numtextures;

        textures[i]->next = textures_hashtable[key];
        textures_hashtable[key] = textures[i];
    }
}
示例#7
0
文件: r_data.c 项目: jeffdoggett/Doom
int R_CheckFlatNumForName (const char* name)
{
  int 	i;

  i = flatinfo[W_LumpNameHash(name) % (unsigned int)numflats].index;
  while (i >= 0 && strncasecmp(flatinfo[i].name, name, 8))
    i = flatinfo[i].next;

  return i;
}
示例#8
0
文件: w_wad.c 项目: aagallag/psDooM
//
// W_CheckNumForName
// Returns -1 if name not found.
//
// Rewritten by Lee Killough for Boom, to use hash table for performance.
//
int W_CheckNumForName(char *name)
{
    register int	i;

    i = lumpinfo[W_LumpNameHash(name) % (unsigned)numlumps].index;
    while (i >= 0 && strncasecmp(lumpinfo[i].name, name, 8))
	i = lumpinfo[i].next;

    return i;
}
示例#9
0
文件: r_data.c 项目: AlexMax/d2k
int PUREFUNC R_CheckTextureNumForName(const char *name)
{
  int i = NO_TEXTURE;
  if (*name != '-')     // "NoTexture" marker.
    {
      i = textures[W_LumpNameHash(name) % (unsigned) numtextures]->index;
      while (i >= 0 && strncasecmp(textures[i]->name,name,8))
        i = textures[i]->next;
    }
  return i;
}
示例#10
0
文件: r_data.c 项目: jeffdoggett/Doom
//
// R_CheckTextureNumForName
// Check whether texture is available.
// Filter out NoTexture indicator.
//
int R_CheckTextureNumForName (const char *name)
{
    int i = 0; //NO_TEXTURE;

    if (*name != '-')
    {
	i = textures[W_LumpNameHash(name) % (unsigned int)numtextures]->index;
	while (i >= 0 && strncasecmp(textures[i]->name, name, 8))
	    i = textures[i]->next;
    }
    return i;
}
示例#11
0
文件: r_data.c 项目: jeffdoggett/Doom
//
// R_InitTextures
// Initializes the texture list
//  with the textures from the world map.
//
static void R_InitTextures (void)
{
    int i;

    textures = NULL;
    textureheight = NULL;
    numtextures = 0;

    R_MergeTextures ();

    textures = Z_Realloc (textures, numtextures * sizeof(*textures), PU_STATIC, 0);
    textureheight = Z_Realloc (textureheight, numtextures * sizeof(*textureheight), PU_STATIC, 0);

    // Create translation table for global animation.
    // killough 4/9/98: make column offsets 32-bit;
    // clean up malloc-ing to use sizeof
    texturetranslation = Z_Malloc((numtextures + 1) * sizeof(*texturetranslation), PU_STATIC, 0);

    for (i = 0; i < numtextures; ++i)
	texturetranslation[i] = i;

    while (--i >= 0)
    {
	int j;

	j = W_LumpNameHash(textures[i]->name) % (unsigned int)numtextures;
	textures[i]->next = textures[j]->index; // Prepend to chain
	textures[j]->index = i;
    }
#if 0
    // [BH] Initialize partially fullbright textures.
    texturefullbright = Z_Malloc(numtextures * sizeof(*texturefullbright), PU_STATIC, 0);

    memset(texturefullbright, 0, numtextures * sizeof(*texturefullbright));
    if (r_brightmaps)
    {
	i = 0;
	while (fullbright[i].colormask)
	{
	    if (fullbright[i].texture)
	    {
		int num = R_CheckTextureNumForName(fullbright[i].texture);

		if (num != -1)
		    texturefullbright[num] = fullbright[i].colormask;
		i++;
	    }
	}
    }
#endif
}
示例#12
0
文件: w_wad.c 项目: aagallag/psDooM
//
// Initialize the lump hash chains
//
void W_InitLumpHash(void)
{
    int		i;

    for (i = 0; i < numlumps; i++)
	lumpinfo[i].index = -1;

    for (i = 0; i < numlumps; i++)
    {
	int	j = W_LumpNameHash(lumpinfo[i].name) % (unsigned)numlumps;

	lumpinfo[i].next = lumpinfo[j].index;
	lumpinfo[j].index = i;
    }
}
示例#13
0
//
// W_HashLumps
//
// killough 1/31/98: Initialize lump hash table
// [SL] taken from prboom-plus
//
void W_HashLumps(void)
{
	for (unsigned int i = 0; i < numlumps; i++)
		lumpinfo[i].index = -1;			// mark slots empty

	// Insert nodes to the beginning of each chain, in first-to-last
	// lump order, so that the last lump of a given name appears first
	// in any chain, observing pwad ordering rules. killough

	for (unsigned int i = 0; i < numlumps; i++)
	{
		unsigned int j = W_LumpNameHash(lumpinfo[i].name) % (unsigned int)numlumps;
		lumpinfo[i].next = lumpinfo[j].index;     // Prepend to list
		lumpinfo[j].index = i;
	}
}
示例#14
0
int W_CheckNumForName (char* name)
{
    lumpinfo_t *lump_p;
    int i;

    // Do we have a hash table yet?

    if (lumphash != NULL)
    {
        int hash;
        
        // We do! Excellent.

        hash = W_LumpNameHash(name) % numlumps;
        
        for (lump_p = lumphash[hash]; lump_p != NULL; lump_p = lump_p->next)
        {
            if (!strncasecmp(lump_p->name, name, 8))
            {
                return lump_p - lumpinfo;
            }
        }
    } 
    else
    {
        // We don't have a hash table generate yet. Linear search :-(
        // 
        // scan backwards so patch lump files take precedence

        for (i=numlumps-1; i >= 0; --i)
        {
            if (!strncasecmp(lumpinfo[i].name, name, 8))
            {
                return i;
            }
        }
    }

    // TFB. Not found.

    return -1;
}
示例#15
0
//
// W_CheckNumForName
// Returns -1 if name not found.
//
// Rewritten by Lee Killough to use hash table for performance. Significantly
// cuts down on time -- increases Doom performance over 300%. This is the
// single most important optimization of the original Doom sources, because
// lump name lookup is used so often, and the original Doom used a sequential
// search. For large wads with > 1000 lumps this meant an average of over
// 500 were probed during every search. Now the average is under 2 probes per
// search. There is no significant benefit to packing the names into longwords
// with this new hashing algorithm, because the work to do the packing is
// just as much work as simply doing the string comparisons with the new
// algorithm, which minimizes the expected number of comparisons to under 2.
//
// [SL] taken from prboom-plus
//
int W_CheckNumForName(const char *name, int namespc)
{
	// Hash function maps the name to one of possibly numlump chains.
	// It has been tuned so that the average chain length never exceeds 2.

	// proff 2001/09/07 - check numlumps==0, this happens when called before WAD loaded
	register int i = (numlumps==0)?(-1):(lumpinfo[W_LumpNameHash(name) % numlumps].index);

	// We search along the chain until end, looking for case-insensitive
	// matches which also match a namespace tag. Separate hash tables are
	// not used for each namespace, because the performance benefit is not
	// worth the overhead, considering namespace collisions are rare in
	// Doom wads.

	while (i >= 0 && (strnicmp(lumpinfo[i].name, name, 8) ||
				lumpinfo[i].namespc != namespc))
		i = lumpinfo[i].next;

	// Return the matching lump, or -1 if none found.
	return i;
}
//
// R_CheckTextureNumForName
// Check whether texture is available.
// Filter out NoTexture indicator.
//
int	R_CheckTextureNumForName (char *name)
{
    texture_t *texture;
    int key;

    // "NoTexture" marker.
    if (name[0] == '-')		
	return 0;
		
    key = W_LumpNameHash(name) % numtextures;

    texture=textures_hashtable[key]; 
    
    while (texture != NULL)
    {
	if (!strncasecmp (texture->name, name, 8) )
	    return texture->index;

        texture = texture->next;
    }
    
    return -1;
}
示例#17
0
文件: r_data.c 项目: jeffdoggett/Doom
//
// R_InitFlats
//
static void R_InitFlats (void)
{
  int		i;
  unsigned int	lump;
  unsigned int	loading;
  lumpinfo_t*	lump_ptr;
  flatinfo_t*   flatinfo_ptr;

  numflats = R_CountEntities ("F_START", "F_END", 0);

  // Create translation table for global animation.
  flatinfo = Z_Calloc ((numflats+1)*sizeof(*flatinfo), PU_STATIC, 0);

  i = 0;
  lump = 0;
  loading = 0;
  lump_ptr = lumpinfo;
  flatinfo_ptr = flatinfo;
  do
  {
    if (loading == 0)
    {
      if (strncasecmp (lump_ptr->name, "F_START", 8) == 0)
	loading = 1;
    }
    else if ((strncasecmp (lump_ptr->name, "F_END", 8) == 0)
	  || (lump_ptr->handle != (lump_ptr-1)->handle))
    {
      loading = 0;
    }
    else
    if ((lump_ptr->name[0]))
#ifdef MIN_SIZE_LUMP
     && (lump_ptr->size >= MIN_SIZE_LUMP)
#endif
    {
      if (!(i&63))
	putchar ('.');
      if (i < numflats)
      {
	memcpy (flatinfo_ptr->name, lump_ptr->name, sizeof (flatinfo_ptr->name));
	flatinfo_ptr->lump = lump;
	flatinfo_ptr->translation = i;
	flatinfo_ptr->index = -1;
	memset (lump_ptr -> name, 0, sizeof (lump_ptr -> name));
	flatinfo_ptr++;
      }
      i++;
    }
    lump_ptr++;
  } while (++lump < numlumps);

  if (numflats != i)
  {
    printf ("\nnumflats = %u, found = %u\n", numflats, i);
    if (i < numflats)
      numflats = i;
  }

  while (--i >= 0)
  {
	int j;

	j = W_LumpNameHash(flatinfo[i].name) % (unsigned int)numflats;
	flatinfo[i].next = flatinfo[j].index; // Prepend to chain
	flatinfo[j].index = i;
  }
}
示例#18
0
文件: r_data.c 项目: AlexMax/d2k
static void R_InitTextures (void)
{
  const maptexture_t *mtexture;
  texture_t    *texture;
  const mappatch_t   *mpatch;
  texpatch_t   *patch;
  int  i, j;
  int         maptex_lump[2] = {-1, -1};
  const int  *maptex;
  const int  *maptex1, *maptex2;
  char name[9];
  int names_lump; // cph - new wad lump handling
  const char *names; // cph -
  const char *name_p;// const*'s
  int  *patchlookup;
  int  nummappatches;
  int  offset;
  int  maxoff, maxoff2;
  int  numtextures1, numtextures2;
  const int *directory;
  int  errors = 0;

  // Load the patch names from pnames.lmp.
  name[8] = 0;
  names = W_CacheLumpNum(names_lump = W_GetNumForName("PNAMES"));
  nummappatches = LittleLong(*((const int *)names));
  name_p = names+4;
  patchlookup = malloc(nummappatches*sizeof(*patchlookup));  // killough

  for (i=0 ; i<nummappatches ; i++)
    {
      strncpy (name,name_p+i*8, 8);
      patchlookup[i] = W_CheckNumForName(name);
      if (patchlookup[i] == -1)
        {
          // killough 4/17/98:
          // Some wads use sprites as wall patches, so repeat check and
          // look for sprites this time, but only if there were no wall
          // patches found. This is the same as allowing for both, except
          // that wall patches always win over sprites, even when they
          // appear first in a wad. This is a kludgy solution to the wad
          // lump namespace problem.

          patchlookup[i] = (W_CheckNumForName)(name, ns_sprites);

          if (patchlookup[i] == -1 && devparm)
            //jff 8/3/98 use logical output routine
            lprintf(LO_WARN,"\nWarning: patch %.8s, index %d does not exist",name,i);
        }
    }
  W_UnlockLumpNum(names_lump); // cph - release the lump

  // Load the map texture definitions from textures.lmp.
  // The data is contained in one or two lumps,
  //  TEXTURE1 for shareware, plus TEXTURE2 for commercial.

  maptex = maptex1 = W_CacheLumpNum(maptex_lump[0] = W_GetNumForName("TEXTURE1"));
  numtextures1 = LittleLong(*maptex);
  maxoff = W_LumpLength(maptex_lump[0]);
  directory = maptex+1;

  if (W_CheckNumForName("TEXTURE2") != -1)
    {
      maptex2 = W_CacheLumpNum(maptex_lump[1] = W_GetNumForName("TEXTURE2"));
      numtextures2 = LittleLong(*maptex2);
      maxoff2 = W_LumpLength(maptex_lump[1]);
    }
  else
    {
      maptex2 = NULL;
      numtextures2 = 0;
      maxoff2 = 0;
    }
  numtextures = numtextures1 + numtextures2;

  // killough 4/9/98: make column offsets 32-bit;
  // clean up malloc-ing to use sizeof

  textures = Z_Malloc(numtextures*sizeof*textures, PU_STATIC, 0);
  textureheight = Z_Malloc(numtextures*sizeof*textureheight, PU_STATIC, 0);

  for (i=0 ; i<numtextures ; i++, directory++)
    {
      if (i == numtextures1)
        {
          // Start looking in second texture file.
          maptex = maptex2;
          maxoff = maxoff2;
          directory = maptex+1;
        }

      offset = LittleLong(*directory);

      if (offset > maxoff)
        I_Error("R_InitTextures: Bad texture directory");

      mtexture = (const maptexture_t *) ( (const byte *)maptex + offset);

      texture = textures[i] =
        Z_Malloc(sizeof(texture_t) +
                 sizeof(texpatch_t)*(LittleShort(mtexture->patchcount)-1),
                 PU_STATIC, 0);

      texture->width = LittleShort(mtexture->width);
      texture->height = LittleShort(mtexture->height);
      texture->patchcount = LittleShort(mtexture->patchcount);

        /* Mattias Engdegård emailed me of the following explenation of
         * why memcpy doesnt work on some systems:
         * "I suppose it is the mad unaligned allocation
         * going on (and which gcc in some way manages to cope with
         * through the __attribute__ ((packed))), and which it forgets
         * when optimizing memcpy (to a single word move) since it appears
         * to be aligned. Technically a gcc bug, but I can't blame it when
         * it's stressed with that amount of
         * non-standard nonsense."
   * So in short the unaligned struct confuses gcc's optimizer so
   * i took the memcpy out alltogether to avoid future problems-Jess
         */
      /* The above was #ifndef SPARC, but i got a mail from
       * Putera Joseph F NPRI <*****@*****.**> containing:
       *   I had to use the memcpy function on a sparc machine.  The
       *   other one would give me a core dump.
       * cph - I find it hard to believe that sparc memcpy is broken,
       * but I don't believe the pointers to memcpy have to be aligned
       * either. Use fast memcpy on other machines anyway.
       */
/*
  proff - I took this out, because Oli Kraus ([email protected]) told
  me the memcpy produced a buserror. Since this function isn't time-
  critical I'm using the for loop now.
*/
/*
#ifndef GCC
      memcpy(texture->name, mtexture->name, sizeof(texture->name));
#else
*/
      {
        size_t j;
        for(j=0;j<sizeof(texture->name);j++)
          texture->name[j]=mtexture->name[j];
      }
/* #endif */

      mpatch = mtexture->patches;
      patch = texture->patches;

      for (j=0 ; j<texture->patchcount ; j++, mpatch++, patch++)
        {
          patch->originx = LittleShort(mpatch->originx);
          patch->originy = LittleShort(mpatch->originy);
          patch->patch = patchlookup[LittleShort(mpatch->patch)];
          if (patch->patch == -1)
            {
              //jff 8/3/98 use logical output routine
              lprintf(LO_ERROR,"\nR_InitTextures: Missing patch %d in texture %.8s",
                     LittleShort(mpatch->patch), texture->name); // killough 4/17/98
              ++errors;
            }
        }

      for (j=1; j*2 <= texture->width; j<<=1)
        ;
      texture->widthmask = j-1;
      textureheight[i] = texture->height<<FRACBITS;
    }

  free(patchlookup);         // killough

  for (i=0; i<2; i++) // cph - release the TEXTUREx lumps
    if (maptex_lump[i] != -1)
      W_UnlockLumpNum(maptex_lump[i]);

  if (errors)
  {
    const lumpinfo_t* info = W_GetLumpInfoByNum(names_lump);
    wadfile_info_t *wf = M_CBufGet(&resource_files_buf, info->wadfile);

    if (wf == NULL) {
      I_Error(
        "R_InitTextures: Bad wadfile for %s (%d)\n", info->name, info->wadfile
      );
    }

    lprintf(LO_INFO,
      "\nR_InitTextures: The file %s seems to be incompatible with \"%s\".\n",
      wf->name,
      (doomverstr ? doomverstr : "DOOM"));
    I_Error("R_InitTextures: %d errors", errors);
  }

  // Precalculate whatever possible.
  if (devparm) // cph - If in development mode, generate now so all errors are found at once
  {
    R_InitPatches(); //e6y
    for (i=0 ; i<numtextures ; i++)
    {
      // proff - This is for the new renderer now
      R_CacheTextureCompositePatchNum(i);
      R_UnlockTextureCompositePatchNum(i);
    }
  }

  if (errors)
    I_Error("R_InitTextures: %d errors", errors);

  // Create translation table for global animation.
  // killough 4/9/98: make column offsets 32-bit;
  // clean up malloc-ing to use sizeof

  texturetranslation =
    Z_Malloc((numtextures+1)*sizeof*texturetranslation, PU_STATIC, 0);

  for (i=0 ; i<numtextures ; i++)
    texturetranslation[i] = i;

  // killough 1/31/98: Initialize texture hash table
  for (i = 0; i<numtextures; i++)
    textures[i]->index = -1;
  while (--i >= 0)
    {
      int j = W_LumpNameHash(textures[i]->name) % (unsigned) numtextures;
      textures[i]->next = textures[j]->index;   // Prepend to chain
      textures[j]->index = i;
    }
}
示例#19
0
文件: r_data.c 项目: mdgunn/doomretro
//
// R_InitTextures
// Initializes the texture list
//  with the textures from the world map.
//
void R_InitTextures(void)
{
    const maptexture_t  *mtexture;
    texture_t           *texture;
    int                 i, j;
    int                 maptex_lump[2] = { -1, -1 };
    const int           *maptex1;
    const int           *maptex2;
    char                name[9];
    int                 names_lump; // cph - new wad lump handling
    const char          *names; // cph -
    const char          *name_p;// const*'s
    int                 *patchlookup;
    int                 nummappatches;
    int                 maxoff, maxoff2;
    int                 numtextures1, numtextures2;
    const int           *directory;

    // Load the patch names from pnames.lmp.
    name[8] = '\0';
    names = W_CacheLumpNum(names_lump = W_GetNumForName("PNAMES"), PU_STATIC);
    nummappatches = LONG(*((const int *)names));
    name_p = names + 4;
    patchlookup = malloc(nummappatches * sizeof(*patchlookup));   // killough

    for (i = 0; i < nummappatches; i++)
    {
        strncpy(name, name_p + i * 8, 8);
        patchlookup[i] = W_CheckNumForName(name);
    }
    W_ReleaseLumpNum(names_lump);       // cph - release the lump

    // Load the map texture definitions from textures.lmp.
    // The data is contained in one or two lumps,
    //  TEXTURE1 for shareware, plus TEXTURE2 for commercial.
    maptex_lump[0] = W_GetNumForName("TEXTURE1");
    maptex1 = W_CacheLumpNum(maptex_lump[0], PU_STATIC);
    numtextures1 = LONG(*maptex1);
    maxoff = W_LumpLength(maptex_lump[0]);
    directory = maptex1 + 1;

    if (W_CheckNumForName("TEXTURE2") != -1)
    {
        maptex_lump[1] = W_GetNumForName("TEXTURE2");
        maptex2 = W_CacheLumpNum(maptex_lump[1], PU_STATIC);
        numtextures2 = LONG(*maptex2);
        maxoff2 = W_LumpLength(maptex_lump[1]);
    }
    else
    {
        maptex2 = NULL;
        numtextures2 = 0;
        maxoff2 = 0;
    }
    numtextures = numtextures1 + numtextures2;

    // killough 4/9/98: make column offsets 32-bit;
    // clean up malloc-ing to use sizeof
    textures = Z_Malloc(numtextures * sizeof(*textures), PU_STATIC, 0);
    textureheight = Z_Malloc(numtextures * sizeof(*textureheight), PU_STATIC, 0);

    for (i = 0; i < numtextures; ++i, ++directory)
    {
        const mappatch_t        *mpatch;
        texpatch_t              *patch;
        int                     offset;

        if (i == numtextures1)
        {
            // Start looking in second texture file.
            maptex1 = maptex2;
            maxoff = maxoff2;
            directory = maptex1 + 1;
        }

        offset = LONG(*directory);

        if (offset > maxoff)
            I_Error("R_InitTextures: Bad texture directory");

        mtexture = (const maptexture_t *)((const byte *)maptex1 + offset);

        texture = textures[i] = Z_Malloc(sizeof(texture_t) + sizeof(texpatch_t)
            * (SHORT(mtexture->patchcount) - 1), PU_STATIC, 0);

        texture->width = SHORT(mtexture->width);
        texture->height = SHORT(mtexture->height);
        texture->patchcount = SHORT(mtexture->patchcount);

        {
            size_t      j;

            for (j = 0; j < sizeof(texture->name); ++j)
                texture->name[j] = mtexture->name[j];
        }

        mpatch = mtexture->patches;
        patch = texture->patches;

        for (j = 0; j < texture->patchcount; ++j, ++mpatch, ++patch)
        {
            patch->originx = SHORT(mpatch->originx);
            patch->originy = SHORT(mpatch->originy);
            patch->patch = patchlookup[SHORT(mpatch->patch)];
            if (patch->patch == -1)
                C_Warning("Patch %d is missing in the %.8s texture.", SHORT(mpatch->patch),
                    texture->name);     // killough 4/17/98
        }

        for (j = 1; j * 2 <= texture->width; j <<= 1);
        texture->widthmask = j - 1;
        textureheight[i] = texture->height << FRACBITS;
    }

    free(patchlookup);          // killough

    for (i = 0; i < 2; ++i)     // cph - release the TEXTUREx lumps
        if (maptex_lump[i] != -1)
            W_ReleaseLumpNum(maptex_lump[i]);

    // Create translation table for global animation.
    // killough 4/9/98: make column offsets 32-bit;
    // clean up malloc-ing to use sizeof
    texturetranslation = Z_Malloc((numtextures + 1) * sizeof(*texturetranslation), PU_STATIC, 0);

    for (i = 0; i < numtextures; ++i)
        texturetranslation[i] = i;

    // killough 1/31/98: Initialize texture hash table
    for (i = 0; i < numtextures; ++i)
        textures[i]->index = -1;
    while (--i >= 0)
    {
        int     j = W_LumpNameHash(textures[i]->name) % (unsigned int)numtextures;

        textures[i]->next = textures[j]->index; // Prepend to chain
        textures[j]->index = i;
    }

    // [BH] Initialize partially fullbright textures.
    texturefullbright = Z_Malloc(numtextures * sizeof(*texturefullbright), PU_STATIC, 0);

    memset(texturefullbright, 0, numtextures * sizeof(*texturefullbright));
    if (r_brightmaps)
    {
        i = 0;
        while (fullbright[i].colormask)
        {
            if (fullbright[i].texture)
            {
                int num = R_CheckTextureNumForName(fullbright[i].texture);

                if (num != -1)
                    texturefullbright[num] = fullbright[i].colormask;
                i++;
            }
        }
    }
}