FTextureID FTextureManager::AddTexture (FTexture *texture) { int bucket; int hash; if (texture == NULL) return FTextureID(-1); // Later textures take precedence over earlier ones // Textures without name can't be looked for if (texture->Name[0] != 0) { bucket = int(MakeKey (texture->Name) % HASH_SIZE); hash = HashFirst[bucket]; } else { bucket = -1; hash = -1; } TextureHash hasher = { texture, hash }; int trans = Textures.Push (hasher); Translation.Push (trans); if (bucket >= 0) HashFirst[bucket] = trans; return (texture->id = FTextureID(trans)); }
FTextureID FTextureManager::CreateTexture (int lumpnum, int usetype) { if (lumpnum != -1) { FTexture *out = FTexture::CreateTexture(lumpnum, usetype); if (out != NULL) return AddTexture (out); else { if(Wads.LumpLength(lumpnum) > 0) Printf (TEXTCOLOR_ORANGE "Invalid data encountered for texture %s\n", Wads.GetLumpFullPath(lumpnum).GetChars()); return FTextureID(-1); } } return FTextureID(-1); }
FTextureID FTextureManager::FindTextureByLumpNum (int lumpnum) { if (lumpnum < 0) { return FTextureID(-1); } // This can't use hashing because using ReplaceTexture would break the hash chains. :( for(unsigned i = 0; i <Textures.Size(); i++) { if (Textures[i].Texture->SourceLump == lumpnum) { return FTextureID(i); } } return FTextureID(-1); }
FTextureID FTextureManager::GetTexture (const char *name, int usetype, BITFIELD flags) { FTextureID i; if (name == NULL || name[0] == 0) { return FTextureID(0); } else { i = CheckForTexture (name, usetype, flags | TEXMAN_TryAny); } if (!i.Exists()) { // Use a default texture instead of aborting like Doom did Printf ("Unknown texture: \"%s\"\n", name); i = DefaultTexture; } return FTextureID(i); }
int FTextureManager::ListTextures (const char *name, TArray<FTextureID> &list) { int i; if (name == NULL || name[0] == '\0') { return 0; } // [RH] Doom counted anything beginning with '-' as "no texture". // Hopefully nobody made use of that and had textures like "-EMPTY", // because -NOFLAT- is a valid graphic for ZDoom. if (name[0] == '-' && name[1] == '\0') { return 0; } i = HashFirst[MakeKey (name) % HASH_SIZE]; while (i != HASH_END) { const FTexture *tex = Textures[i].Texture; if (stricmp (tex->Name, name) == 0) { // NULL textures must be ignored. if (tex->UseType!=FTexture::TEX_Null) { unsigned int j; for(j = 0; j < list.Size(); j++) { // Check for overriding definitions from newer WADs if (Textures[list[j].GetIndex()].Texture->UseType == tex->UseType) break; } if (j==list.Size()) list.Push(FTextureID(i)); } } i = Textures[i].HashNext; } return list.Size(); }
FTextureID FTextureManager::CheckForTexture (const char *name, int usetype, BITFIELD flags) { int i; int firstfound = -1; int firsttype = FTexture::TEX_Null; if (name == NULL || name[0] == '\0') { return FTextureID(-1); } // [RH] Doom counted anything beginning with '-' as "no texture". // Hopefully nobody made use of that and had textures like "-EMPTY", // because -NOFLAT- is a valid graphic for ZDoom. if (name[0] == '-' && name[1] == '\0') { return FTextureID(0); } i = HashFirst[MakeKey (name) % HASH_SIZE]; while (i != HASH_END) { const FTexture *tex = Textures[i].Texture; if (stricmp (tex->Name, name) == 0) { // The name matches, so check the texture type if (usetype == FTexture::TEX_Any) { // All NULL textures should actually return 0 if (tex->UseType == FTexture::TEX_FirstDefined && !(flags & TEXMAN_ReturnFirst)) return 0; return FTextureID(tex->UseType==FTexture::TEX_Null? 0 : i); } else if ((flags & TEXMAN_Overridable) && tex->UseType == FTexture::TEX_Override) { return FTextureID(i); } else if (tex->UseType == usetype) { return FTextureID(i); } else if (tex->UseType == FTexture::TEX_FirstDefined && usetype == FTexture::TEX_Wall) { if (!(flags & TEXMAN_ReturnFirst)) return FTextureID(0); else return FTextureID(i); } else if (tex->UseType == FTexture::TEX_Null && usetype == FTexture::TEX_Wall) { // We found a NULL texture on a wall -> return 0 return FTextureID(0); } else { if (firsttype == FTexture::TEX_Null || (firsttype == FTexture::TEX_MiscPatch && tex->UseType != firsttype && tex->UseType != FTexture::TEX_Null) ) { firstfound = i; firsttype = tex->UseType; } } } i = Textures[i].HashNext; } size_t namelen = strlen(name); if(name[0] == '#' && namelen == 7) { FTexture *solidTex = SolidTexture_TryCreate(name+1); solidTex->UseType = FTexture::TEX_Flat; return AddTexture(solidTex); } // Handle font look ups (FONTNAME:XX) if(namelen > 3 && name[namelen-3] == ':') { FString fontName(name, namelen-3); FFont *font = V_GetFont(fontName); if(font) { return font->GetCharID(ParseHex(name+namelen-2)); } } if ((flags & TEXMAN_TryAny) && usetype != FTexture::TEX_Any) { // Never return the index of NULL textures. if (firstfound != -1) { if (firsttype == FTexture::TEX_Null) return FTextureID(0); if (firsttype == FTexture::TEX_FirstDefined && !(flags & TEXMAN_ReturnFirst)) return FTextureID(0); } return FTextureID(firstfound); } return FTextureID(-1); }
void R_InitSpriteDefs () { struct Hasher { int Head, Next; } *hashes; struct VHasher { int Head, Next, Name, Spin; char Frame; } *vhashes; unsigned int i, j, smax, vmax; DWORD intname; spriteframewithrotate sprtemp[MAX_SPRITE_FRAMES]; // Create a hash table to speed up the process smax = TexMan.NumTextures(); hashes = new Hasher[smax]; memset(hashes, -1, sizeof(Hasher)*smax); for (i = 0; i < smax; ++i) { FTexture *tex = TexMan.ByIndex(i); if (tex->UseType == FTexture::TEX_Sprite && strlen(tex->Name) >= 6) { size_t bucket = TEX_DWNAME(tex) % smax; hashes[i].Next = hashes[bucket].Head; hashes[bucket].Head = i; } } // Repeat, for voxels vmax = Wads.GetNumLumps(); vhashes = new VHasher[vmax]; memset(vhashes, -1, sizeof(VHasher)*vmax); for (i = 0; i < vmax; ++i) { if (Wads.GetLumpNamespace(i) == ns_voxels) { char name[9]; size_t namelen; int spin; int sign; Wads.GetLumpName(name, i); name[8] = 0; namelen = strlen(name); if (namelen < 4) { // name is too short continue; } if (name[4] != '\0' && name[4] != ' ' && (name[4] < 'A' || name[4] >= 'A' + MAX_SPRITE_FRAMES)) { // frame char is invalid continue; } spin = 0; sign = 2; // 2 to convert from deg/halfsec to deg/sec j = 5; if (j < namelen && name[j] == '-') { // a minus sign is okay, but only before any digits j++; sign = -2; } for (; j < namelen; ++j) { // the remainder to the end of the name must be digits if (name[j] >= '0' && name[j] <= '9') { spin = spin * 10 + name[j] - '0'; } else { break; } } if (j < namelen) { // the spin part is invalid continue; } memcpy(&vhashes[i].Name, name, 4); vhashes[i].Frame = name[4]; vhashes[i].Spin = spin * sign; size_t bucket = vhashes[i].Name % vmax; vhashes[i].Next = vhashes[bucket].Head; vhashes[bucket].Head = i; } } // scan all the lump names for each of the names, noting the highest frame letter. for (i = 0; i < sprites.Size(); ++i) { memset (sprtemp, 0xFF, sizeof(sprtemp)); for (j = 0; j < MAX_SPRITE_FRAMES; ++j) { sprtemp[j].Flip = 0; sprtemp[j].Voxel = NULL; } int maxframe = -1; intname = sprites[i].dwName; // scan the lumps, filling in the frames for whatever is found int hash = hashes[intname % smax].Head; while (hash != -1) { FTexture *tex = TexMan[hash]; if (TEX_DWNAME(tex) == intname) { bool res = R_InstallSpriteLump (FTextureID(hash), tex->Name[4] - 'A', tex->Name[5], false, sprtemp, maxframe); if (tex->Name[6] && res) R_InstallSpriteLump (FTextureID(hash), tex->Name[6] - 'A', tex->Name[7], true, sprtemp, maxframe); } hash = hashes[hash].Next; } // repeat, for voxels hash = vhashes[intname % vmax].Head; while (hash != -1) { VHasher *vh = &vhashes[hash]; if (vh->Name == (int)intname) { FVoxelDef *voxdef = R_LoadVoxelDef(hash, vh->Spin); if (voxdef != NULL) { if (vh->Frame == ' ' || vh->Frame == '\0') { // voxel applies to every sprite frame for (j = 0; j < MAX_SPRITE_FRAMES; ++j) { if (sprtemp[j].Voxel == NULL) { sprtemp[j].Voxel = voxdef; } } maxframe = MAX_SPRITE_FRAMES-1; } else { // voxel applies to a specific frame j = vh->Frame - 'A'; sprtemp[j].Voxel = voxdef; maxframe = MAX<int>(maxframe, j); } } } hash = vh->Next; } R_InstallSprite ((int)i, sprtemp, maxframe); } delete[] hashes; delete[] vhashes; }