static void DrawInventory(player_t * CPlayer, int x,int y) { AInventory * rover; int numitems = (hudwidth - 2*x) / 32; int i; CPlayer->mo->InvFirst = rover = StatusBar->ValidateInvFirst(numitems); if (rover!=NULL) { if(rover->PrevInv()) { screen->DrawTexture(invgems[!!(level.time&4)], x-10, y, DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, 0x6666, TAG_DONE); } for(i=0;i<numitems && rover;rover=rover->NextInv()) { if (rover->Amount>0) { FTextureID AltIcon = GetHUDIcon(rover->GetClass()); if (AltIcon.Exists() && (rover->Icon.isValid() || AltIcon.isValid()) ) { int trans = rover==CPlayer->mo->InvSel ? FRACUNIT : 0x6666; DrawImageToBox(TexMan[AltIcon.isValid()? AltIcon : rover->Icon], x, y, 19, 25, trans); if (rover->Amount>1) { char buffer[10]; int xx; mysnprintf(buffer, countof(buffer), "%d", rover->Amount); if (rover->Amount>=1000) xx = 32 - IndexFont->StringWidth(buffer); else xx = 22; screen->DrawText(IndexFont, CR_GOLD, x+xx, y+20, buffer, DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, trans, TAG_DONE); } x+=32; i++; } } } if(rover) { screen->DrawTexture(invgems[2 + !!(level.time&4)], x-10, y, DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, 0x6666, TAG_DONE); } } }
static void DrawOneWeapon(player_t * CPlayer, int x, int & y, AWeapon * weapon) { int trans; // Powered up weapons and inherited sister weapons are not displayed. if (weapon->WeaponFlags & WIF_POWERED_UP) return; if (weapon->SisterWeapon && weapon->IsKindOf(weapon->SisterWeapon->GetClass())) return; trans=0x6666; if (CPlayer->ReadyWeapon) { if (weapon==CPlayer->ReadyWeapon || weapon==CPlayer->ReadyWeapon->SisterWeapon) trans=0xd999; } FTextureID picnum = GetInventoryIcon(weapon, DI_ALTICONFIRST); if (picnum.isValid()) { FTexture * tex = TexMan[picnum]; int w = tex->GetWidth(); int h = tex->GetHeight(); int rh; if (w>h) rh=8; else rh=16,y-=8; // don't draw tall sprites too small! DrawImageToBox(tex, x-24, y, 20, rh, trans); y-=10; } }
void FTextureManager::ParseWarp(FScanner &sc) { const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny | TEXMAN_ShortNameOnly; bool isflat = false; bool type2 = sc.Compare ("warp2"); // [GRB] sc.MustGetString (); if (sc.Compare ("flat")) { isflat = true; sc.MustGetString (); } else if (sc.Compare ("texture")) { isflat = false; sc.MustGetString (); } else { sc.ScriptError (NULL); } FTextureID picnum = CheckForTexture (sc.String, isflat ? FTexture::TEX_Flat : FTexture::TEX_Wall, texflags); if (picnum.isValid()) { FTexture *warper = Texture(picnum); // don't warp a texture more than once if (!warper->bWarped) { if (type2) warper = new FWarp2Texture (warper); else warper = new FWarpTexture (warper); ReplaceTexture (picnum, warper, false); } if (sc.CheckFloat()) { static_cast<FWarpTexture*>(warper)->SetSpeed(float(sc.Float)); } // No decals on warping textures, by default. // Warping information is taken from the last warp // definition for this texture. warper->bNoDecals = true; if (sc.GetString ()) { if (sc.Compare ("allowdecals")) { warper->bNoDecals = false; } else { sc.UnGet (); } } } }
static void DrawOneWeapon(player_t * CPlayer, int x, int & y, AWeapon * weapon) { int trans; FTextureID picnum; // Powered up weapons and inherited sister weapons are not displayed. if (weapon->WeaponFlags & WIF_POWERED_UP) return; if (weapon->SisterWeapon && weapon->IsKindOf(RUNTIME_TYPE(weapon->SisterWeapon))) return; trans=0x6666; if (CPlayer->ReadyWeapon) { if (weapon==CPlayer->ReadyWeapon || weapon==CPlayer->ReadyWeapon->SisterWeapon) trans=0xd999; } FState * state=NULL, *ReadyState; FTextureID AltIcon = GetHUDIcon(weapon->GetClass()); picnum = !AltIcon.isNull()? AltIcon : weapon->Icon; if (picnum.isNull()) { if (weapon->SpawnState && weapon->SpawnState->sprite!=0) { state = weapon->SpawnState; } // no spawn state - now try the ready state else if ((ReadyState = weapon->FindState(NAME_Ready)) && ReadyState->sprite!=0) { state = ReadyState; } if (state && (unsigned)state->sprite < (unsigned)sprites.Size ()) { spritedef_t * sprdef = &sprites[state->sprite]; spriteframe_t * sprframe = &SpriteFrames[sprdef->spriteframes + state->GetFrame()]; picnum = sprframe->Texture[0]; } } if (picnum.isValid()) { FTexture * tex = TexMan[picnum]; int w = tex->GetWidth(); int h = tex->GetHeight(); int rh; if (w>h) rh=8; else rh=16,y-=8; // don't draw tall sprites too small! DrawImageToBox(tex, x-24, y, 20, rh, trans); y-=10; } }
static inline void CheckShortestTex (FTextureID texnum, fixed_t &minsize) { if (texnum.isValid() || (texnum.isNull() && (i_compatflags & COMPATF_SHORTTEX))) { FTexture *tex = TexMan[texnum]; if (tex != NULL) { fixed_t h = tex->GetScaledHeight()<<FRACBITS; if (h < minsize) { minsize = h; } } } }
static void DrawOneKey(int xo, int & x, int & y, int & c, AInventory * inv) { FTextureID icon = FNullTextureID(); FTextureID AltIcon = GetHUDIcon(inv->GetClass()); if (!AltIcon.Exists()) return; if (AltIcon.isValid()) { icon = AltIcon; } else if (inv->SpawnState && inv->SpawnState->sprite!=0) { FState * state = inv->SpawnState; if (state && (unsigned)state->sprite < (unsigned)sprites.Size ()) { spritedef_t * sprdef = &sprites[state->sprite]; spriteframe_t * sprframe = &SpriteFrames[sprdef->spriteframes + state->GetFrame()]; icon = sprframe->Texture[0]; } } if (icon.isNull()) icon = inv->Icon; if (icon.isValid()) { x -= 9; DrawImageToBox(TexMan[icon], x, y, 8, 10); c++; if (c>=10) { x=xo; y-=11; c=0; } } }
static bool isBright(DPSprite *psp) { if (psp != nullptr && psp->GetState() != nullptr) { bool disablefullbright = false; FTextureID lump = gl_GetSpriteFrame(psp->GetSprite(), psp->GetFrame(), 0, 0, NULL); if (lump.isValid()) { FMaterial * tex = FMaterial::ValidateTexture(lump, false, false); if (tex) disablefullbright = tex->tex->gl_info.bDisableFullbright; } return psp->GetState()->GetFullbright() && !disablefullbright; } return false; }
void gl_ParseVavoomSkybox() { int lump = Wads.CheckNumForName("SKYBOXES"); if (lump < 0) return; FScanner sc(lump); while (sc.GetString()) { int facecount=0; int maplump = -1; FSkyBox * sb = new FSkyBox; uppercopy(sb->Name, sc.String); sb->Name[8]=0; sb->fliptop = true; sc.MustGetStringName("{"); while (!sc.CheckString("}")) { if (facecount<6) { sc.MustGetStringName("{"); sc.MustGetStringName("map"); sc.MustGetString(); maplump = Wads.CheckNumForFullName(sc.String, true); if (maplump==-1) Printf("Texture '%s' not found in Vavoom skybox '%s'\n", sc.String, sb->Name); FTextureID tex = TexMan.FindTextureByLumpNum(maplump); if (!tex.isValid()) { tex = TexMan.CreateTexture(maplump, FTexture::TEX_MiscPatch); } sb->faces[facecount] = TexMan[tex]; sc.MustGetStringName("}"); } facecount++; } if (facecount != 6) { sc.ScriptError("%s: Skybox definition requires 6 faces", sb->Name); } sb->SetSize(); TexMan.AddTexture(sb); } }
void FTextureManager::ParsePicAnim (FScanner &sc, FTextureID picnum, int usetype, bool missing, TArray<FAnimDef::FAnimFrame> &frames) { FTextureID framenum; DWORD min = 1, max = 1; framenum = ParseFramenum (sc, picnum, usetype, missing); ParseTime (sc, min, max); if (picnum.isValid()) { FAnimDef::FAnimFrame frame; frame.SpeedMin = min; frame.SpeedRange = max - min; frame.FramePic = framenum; frames.Push (frame); } }
void TimedPicCommand (bool helphack) { ParseTimedCommand (helphack); // // update the screen, and wait for time delay // VW_UpdateScreen (); // // wait for time // Delay(picdelay); // // draw pic // if(picnum.isValid()) VWB_DrawGraphic (TexMan(picnum), picx&~7, picy, MENU_CENTER); }
// [MH] Mainly for mugshots with skins and SBARINFO void FImageCollection::Add (const char **patchNames, int numPatches, int namespc) { int OldCount = ImageMap.Size(); ImageMap.Resize(OldCount + numPatches); for (int i = 0; i < numPatches; ++i) { FTextureID picnum = TexMan.CheckForTexture(patchNames[i], namespc); if (!picnum.isValid()) { int lumpnum = Wads.CheckNumForName(patchNames[i], namespc); if (lumpnum >= 0) { picnum = TexMan.CreateTexture(lumpnum, namespc); } } ImageMap[OldCount + i] = picnum; } }
FTexture * LoadSkin(const char * path, const char * fn) { FString buffer; buffer.Format("%s%s", path, fn); int texlump = FindGFXFile(buffer); if (texlump>=0) { FTextureID texno = TexMan.FindTextureByLumpNum(texlump); if (!texno.isValid()) { FTexture *tex = FTexture::CreateTexture("", texlump, FTexture::TEX_Override); TexMan.AddTexture(tex); return tex; } return TexMan[texno]; } else { return NULL; } }
void FGLRenderer::DrawPSprite (player_t * player,DPSprite *psp, float sx, float sy, bool hudModelStep, int OverrideShader, bool alphatexture) { float fU1,fV1; float fU2,fV2; float tx; float x1,y1,x2,y2; float scale; float scalex; float ftexturemid; // 4:3 16:9 16:10 17:10 5:4 17:10 21:9 static float xratio[] = {1.f, 3.f/4, 5.f/6, 40.f/51, 1.f, 40.f/51, 4.f/7}; // [BB] In the HUD model step we just render the model and break out. if ( hudModelStep ) { gl_RenderHUDModel(psp, sx, sy); return; } // decide which patch to use bool mirror; FTextureID lump = gl_GetSpriteFrame(psp->GetSprite(), psp->GetFrame(), 0, 0, &mirror); if (!lump.isValid()) return; FMaterial * tex = FMaterial::ValidateTexture(lump, true, false); if (!tex) return; gl_RenderState.SetMaterial(tex, CLAMP_XY_NOMIP, 0, OverrideShader, alphatexture); float vw = (float)viewwidth; float vh = (float)viewheight; FloatRect r; tex->GetSpriteRect(&r); // calculate edges of the shape scalex = xratio[WidescreenRatio] * vw / 320; tx = sx - (160 - r.left); x1 = tx * scalex + vw/2; if (x1 > vw) return; // off the right side x1 += viewwindowx; tx += r.width; x2 = tx * scalex + vw / 2; if (x2 < 0) return; // off the left side x2 += viewwindowx; // killough 12/98: fix psprite positioning problem ftexturemid = 100.f - sy - r.top; AWeapon * wi=player->ReadyWeapon; if (wi && wi->YAdjust != 0) { float fYAd = wi->YAdjust; if (screenblocks >= 11) { ftexturemid -= fYAd; } else if (!st_scale) { ftexturemid -= StatusBar->GetDisplacement () * fYAd; } } scale = (SCREENHEIGHT*vw) / (SCREENWIDTH * 200.0f); y1 = viewwindowy + vh / 2 - (ftexturemid * scale); y2 = y1 + (r.height * scale) + 1; if (!mirror) { fU1=tex->GetSpriteUL(); fV1=tex->GetSpriteVT(); fU2=tex->GetSpriteUR(); fV2=tex->GetSpriteVB(); } else { fU2=tex->GetSpriteUL(); fV1=tex->GetSpriteVT(); fU1=tex->GetSpriteUR(); fV2=tex->GetSpriteVB(); } if (tex->GetTransparent() || OverrideShader != -1) { gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); } gl_RenderState.Apply(); FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); ptr->Set(x1, y1, 0, fU1, fV1); ptr++; ptr->Set(x1, y2, 0, fU1, fV2); ptr++; ptr->Set(x2, y1, 0, fU2, fV1); ptr++; ptr->Set(x2, y2, 0, fU2, fV2); ptr++; GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f); }
void FGLInterface::Precache(BYTE *texhitlist, TMap<PClassActor*, bool> &actorhitlist) { SpriteHits *spritelist = new SpriteHits[sprites.Size()]; SpriteHits **spritehitlist = new SpriteHits*[TexMan.NumTextures()]; TMap<PClassActor*, bool>::Iterator it(actorhitlist); TMap<PClassActor*, bool>::Pair *pair; BYTE *modellist = new BYTE[Models.Size()]; memset(modellist, 0, Models.Size()); memset(spritehitlist, 0, sizeof(SpriteHits**) * TexMan.NumTextures()); // this isn't done by the main code so it needs to be done here first: // check skybox textures and mark the separate faces as used for (int i = 0; i<TexMan.NumTextures(); i++) { // HIT_Wall must be checked for MBF-style sky transfers. if (texhitlist[i] & (FTextureManager::HIT_Sky | FTextureManager::HIT_Wall)) { FTexture *tex = TexMan.ByIndex(i); if (tex->gl_info.bSkybox) { FSkyBox *sb = static_cast<FSkyBox*>(tex); for (int i = 0; i<6; i++) { if (sb->faces[i]) { int index = sb->faces[i]->id.GetIndex(); texhitlist[index] |= FTextureManager::HIT_Flat; } } } } } // Check all used actors. // 1. mark all sprites associated with its states // 2. mark all model data and skins associated with its states while (it.NextPair(pair)) { PClassActor *cls = pair->Key; int gltrans = GLTranslationPalette::GetInternalTranslation(GetDefaultByType(cls)->Translation); for (int i = 0; i < cls->NumOwnedStates; i++) { spritelist[cls->OwnedStates[i].sprite].Insert(gltrans, true); FSpriteModelFrame * smf = gl_FindModelFrame(cls, cls->OwnedStates[i].sprite, cls->OwnedStates[i].Frame, false); if (smf != NULL) { for (int i = 0; i < MAX_MODELS_PER_FRAME; i++) { if (smf->skinIDs[i].isValid()) { texhitlist[smf->skinIDs[i].GetIndex()] |= FTexture::TEX_Flat; } else if (smf->modelIDs[i] != -1) { Models[smf->modelIDs[i]]->PushSpriteMDLFrame(smf, i); Models[smf->modelIDs[i]]->AddSkins(texhitlist); } if (smf->modelIDs[i] != -1) { modellist[smf->modelIDs[i]] = 1; } } } } } // mark all sprite textures belonging to the marked sprites. for (int i = (int)(sprites.Size() - 1); i >= 0; i--) { if (spritelist[i].CountUsed()) { int j, k; for (j = 0; j < sprites[i].numframes; j++) { const spriteframe_t *frame = &SpriteFrames[sprites[i].spriteframes + j]; for (k = 0; k < 16; k++) { FTextureID pic = frame->Texture[k]; if (pic.isValid()) { spritehitlist[pic.GetIndex()] = &spritelist[i]; } } } } } // delete everything unused before creating any new resources to avoid memory usage peaks. // delete unused models for (unsigned i = 0; i < Models.Size(); i++) { if (!modellist[i]) Models[i]->DestroyVertexBuffer(); } // delete unused textures int cnt = TexMan.NumTextures(); for (int i = cnt - 1; i >= 0; i--) { FTexture *tex = TexMan.ByIndex(i); if (tex != nullptr) { if (!texhitlist[i]) { if (tex->gl_info.Material[0]) tex->gl_info.Material[0]->Clean(true); } if (spritehitlist[i] == nullptr || (*spritehitlist[i]).CountUsed() == 0) { if (tex->gl_info.Material[1]) tex->gl_info.Material[1]->Clean(true); } } } if (gl_precache) { // cache all used textures for (int i = cnt - 1; i >= 0; i--) { FTexture *tex = TexMan.ByIndex(i); if (tex != nullptr) { PrecacheTexture(tex, texhitlist[i]); if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CountUsed() > 0) { PrecacheSprite(tex, *spritehitlist[i]); } } } // cache all used models for (unsigned i = 0; i < Models.Size(); i++) { if (modellist[i]) Models[i]->BuildVertexBuffer(); } } delete[] spritehitlist; delete[] spritelist; delete[] modellist; }
static int DrawAmmo(player_t *CPlayer, int x, int y) { int i,j,k; char buf[256]; AInventory *inv; AWeapon *wi=CPlayer->ReadyWeapon; orderedammos.Clear(); if (0 == hud_showammo) { // Show ammo for current weapon if any if (wi) AddAmmoToList(wi); } else { // Order ammo by use of weapons in the weapon slots for (k = 0; k < NUM_WEAPON_SLOTS; k++) for(j = 0; j < CPlayer->weapons.Slots[k].Size(); j++) { PClassActor *weap = CPlayer->weapons.Slots[k].GetWeapon(j); if (weap) { // Show ammo for available weapons if hud_showammo CVAR is 1 // or show ammo for all weapons if hud_showammo is greater than 1 if (hud_showammo > 1 || CPlayer->mo->FindInventory(weap)) { AddAmmoToList((AWeapon*)GetDefaultByType(weap)); } } } // Now check for the remaining weapons that are in the inventory but not in the weapon slots for(inv=CPlayer->mo->Inventory;inv;inv=inv->Inventory) { if (inv->IsKindOf(RUNTIME_CLASS(AWeapon))) { AddAmmoToList((AWeapon*)inv); } } } // ok, we got all ammo types. Now draw the list back to front (bottom to top) int def_width = ConFont->StringWidth("000/000"); x-=def_width; int yadd = ConFont->GetHeight(); for(i=orderedammos.Size()-1;i>=0;i--) { PClassAmmo * type = orderedammos[i]; AAmmo * ammoitem = (AAmmo*)CPlayer->mo->FindInventory(type); AAmmo * inv = ammoitem? ammoitem : (AAmmo*)GetDefaultByType(orderedammos[i]); FTextureID AltIcon = GetHUDIcon(type); FTextureID icon = !AltIcon.isNull()? AltIcon : inv->Icon; if (!icon.isValid()) continue; int trans= (wi && (type==wi->AmmoType1 || type==wi->AmmoType2)) ? 0xc000:0x6000; int maxammo = inv->MaxAmount; int ammo = ammoitem? ammoitem->Amount : 0; mysnprintf(buf, countof(buf), "%3d/%3d", ammo, maxammo); int tex_width= clamp<int>(ConFont->StringWidth(buf)-def_width, 0, 1000); int fontcolor=( !maxammo ? CR_GRAY : ammo < ( (maxammo * hud_ammo_red) / 100) ? CR_RED : ammo < ( (maxammo * hud_ammo_yellow) / 100) ? CR_GOLD : CR_GREEN ); DrawHudText(ConFont, fontcolor, buf, x-tex_width, y+yadd, trans); DrawImageToBox(TexMan[icon], x-20, y, 16, 8, trans); y-=10; } return y; }
void FTextureManager::ParseAnim (FScanner &sc, int usetype) { const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; TArray<FAnimDef::FAnimFrame> frames (32); FTextureID picnum; int defined = 0; bool optional = false, missing = false; FAnimDef *ani = NULL; BYTE type = FAnimDef::ANIM_Forward; sc.MustGetString (); if (sc.Compare ("optional")) { optional = true; sc.MustGetString (); } picnum = CheckForTexture (sc.String, usetype, texflags); if (!picnum.Exists()) { if (optional) { missing = true; } else { Printf (PRINT_BOLD, "ANIMDEFS: Can't find %s\n", sc.String); } } // no decals on animating textures, by default if (picnum.isValid()) { Texture(picnum)->bNoDecals = true; } while (sc.GetString ()) { if (sc.Compare ("allowdecals")) { if (picnum.isValid()) { Texture(picnum)->bNoDecals = false; } continue; } else if (sc.Compare ("Oscillate")) { if (type == FAnimDef::ANIM_Random) { sc.ScriptError ("You cannot use \"random\" and \"oscillate\" together in a single animation."); } type = FAnimDef::ANIM_OscillateUp; } else if (sc.Compare("Random")) { if (type == FAnimDef::ANIM_OscillateUp) { sc.ScriptError ("You cannot use \"random\" and \"oscillate\" together in a single animation."); } type = FAnimDef::ANIM_Random; } else if (sc.Compare ("range")) { if (picnum.Exists() && Texture(picnum)->Name.IsEmpty()) { // long texture name: We cannot do ranged anims on these because they have no defined order sc.ScriptError ("You cannot use \"range\" for long texture names."); } if (defined == 2) { sc.ScriptError ("You cannot use \"pic\" and \"range\" together in a single animation."); } if (defined == 1) { sc.ScriptError ("You can only use one \"range\" per animation."); } defined = 1; ani = ParseRangeAnim (sc, picnum, usetype, missing); } else if (sc.Compare ("pic")) { if (defined == 1) { sc.ScriptError ("You cannot use \"pic\" and \"range\" together in a single animation."); } defined = 2; ParsePicAnim (sc, picnum, usetype, missing, frames); } else { sc.UnGet (); break; } } // If base pic is not present, don't add this anim // ParseRangeAnim adds the anim itself, but ParsePicAnim does not. if (picnum.isValid() && defined == 2) { if (frames.Size() < 2) { sc.ScriptError ("Animation needs at least 2 frames"); } ani = AddComplexAnim (picnum, frames); } if (ani != NULL && type != FAnimDef::ANIM_Forward) { if (ani->AnimType == FAnimDef::ANIM_Backward && type == FAnimDef::ANIM_OscillateUp) ani->AnimType = FAnimDef::ANIM_OscillateDown; else ani->AnimType = type; } }
void HUD_InitHud() { switch (gameinfo.gametype) { case GAME_Heretic: case GAME_Hexen: healthpic = TexMan.FindTexture("ARTIPTN2"); HudFont=FFont::FindFont("HUDFONT_RAVEN"); break; case GAME_Strife: healthpic = TexMan.FindTexture("I_MDKT"); HudFont=BigFont; // Strife doesn't have anything nice so use the standard font break; default: healthpic = TexMan.FindTexture("MEDIA0"); berserkpic = TexMan.FindTexture("PSTRA0"); HudFont=FFont::FindFont("HUDFONT_DOOM"); break; } IndexFont = V_GetFont("INDEXFONT"); if (HudFont == NULL) HudFont = BigFont; if (IndexFont == NULL) IndexFont = ConFont; // Emergency fallback invgems[0] = TexMan.FindTexture("INVGEML1"); invgems[1] = TexMan.FindTexture("INVGEML2"); invgems[2] = TexMan.FindTexture("INVGEMR1"); invgems[3] = TexMan.FindTexture("INVGEMR2"); fragpic = TexMan.FindTexture("HU_FRAGS"); // Sadly, I don't have anything usable for this. :( KeyTypes.Clear(); UnassignedKeyTypes.Clear(); statspace = SmallFont->StringWidth("Ac:"); // Now read custom icon overrides int lump, lastlump = 0; while ((lump = Wads.FindLump ("ALTHUDCF", &lastlump)) != -1) { FScanner sc(lump); while (sc.GetString()) { if (sc.Compare("Health")) { sc.MustGetString(); FTextureID tex = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); if (tex.isValid()) healthpic = TexMan[tex]; } else if (sc.Compare("Berserk")) { sc.MustGetString(); FTextureID tex = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); if (tex.isValid()) berserkpic = TexMan[tex]; } else { PClass *ti = PClass::FindClass(sc.String); if (!ti) { Printf("Unknown item class '%s' in ALTHUDCF\n", sc.String); } else if (!ti->IsDescendantOf(RUNTIME_CLASS(AInventory))) { Printf("Invalid item class '%s' in ALTHUDCF\n", sc.String); ti=NULL; } sc.MustGetString(); FTextureID tex; if (!sc.Compare("0") && !sc.Compare("NULL") && !sc.Compare("")) { tex = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); } else tex.SetInvalid(); if (ti) SetHUDIcon(static_cast<PClassInventory*>(ti), tex); } } } }
void FTextureManager::ParseWarp(FScanner &sc) { const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; bool isflat = false; bool type2 = sc.Compare ("warp2"); // [GRB] sc.MustGetString (); if (sc.Compare ("flat")) { isflat = true; sc.MustGetString (); } else if (sc.Compare ("texture")) { isflat = false; sc.MustGetString (); } else { sc.ScriptError (NULL); } FTextureID picnum = CheckForTexture (sc.String, isflat ? FTexture::TEX_Flat : FTexture::TEX_Wall, texflags); if (picnum.isValid()) { FTexture *warper = Texture(picnum); if (warper->Name.IsEmpty()) { // long texture name: We cannot do warps on these due to the way the texture manager implements warping as a texture replacement. sc.ScriptError ("You cannot use \"warp\" for long texture names."); } // don't warp a texture more than once if (!warper->bWarped) { warper = new FWarpTexture (warper, type2? 2:1); ReplaceTexture (picnum, warper, false); } if (sc.CheckFloat()) { static_cast<FWarpTexture*>(warper)->SetSpeed(float(sc.Float)); } // No decals on warping textures, by default. // Warping information is taken from the last warp // definition for this texture. warper->bNoDecals = true; if (sc.GetString ()) { if (sc.Compare ("allowdecals")) { warper->bNoDecals = false; } else { sc.UnGet (); } } } }
void FTextureManager::ParseAnim (FScanner &sc, int usetype) { const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; TArray<FAnimDef::FAnimFrame> frames (32); FTextureID picnum; int defined = 0; bool optional = false, missing = false; sc.MustGetString (); if (sc.Compare ("optional")) { optional = true; sc.MustGetString (); } picnum = CheckForTexture (sc.String, usetype, texflags); if (!picnum.Exists()) { if (optional) { missing = true; } else { Printf (PRINT_BOLD, "ANIMDEFS: Can't find %s\n", sc.String); } } // no decals on animating textures, by default if (picnum.isValid()) { Texture(picnum)->bNoDecals = true; } while (sc.GetString ()) { if (sc.Compare ("allowdecals")) { if (picnum.isValid()) { Texture(picnum)->bNoDecals = false; } continue; } else if (sc.Compare ("range")) { if (defined == 2) { sc.ScriptError ("You cannot use \"pic\" and \"range\" together in a single animation."); } if (defined == 1) { sc.ScriptError ("You can only use one \"range\" per animation."); } defined = 1; ParseRangeAnim (sc, picnum, usetype, missing); } else if (sc.Compare ("pic")) { if (defined == 1) { sc.ScriptError ("You cannot use \"pic\" and \"range\" together in a single animation."); } defined = 2; ParsePicAnim (sc, picnum, usetype, missing, frames); } else { sc.UnGet (); break; } } // If base pic is not present, don't add this anim // ParseRangeAnim adds the anim itself, but ParsePicAnim does not. if (picnum.isValid() && defined == 2) { if (frames.Size() < 2) { sc.ScriptError ("Animation needs at least 2 frames"); } AddComplexAnim (picnum, frames); } }
static void R_InitAnimDefs () { const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; int lump, lastlump = 0; while ((lump = Wads.FindLump ("ANIMDEFS", &lastlump)) != -1) { FScanner sc(lump); while (sc.GetString ()) { if (sc.Compare ("flat")) { ParseAnim (sc, false); } else if (sc.Compare ("texture")) { ParseAnim (sc, true); } else if (sc.Compare ("switch")) { P_ProcessSwitchDef (sc); } // [GRB] Added warping type 2 else if (sc.Compare ("warp") || sc.Compare ("warp2")) { bool isflat = false; bool type2 = sc.Compare ("warp2"); // [GRB] sc.MustGetString (); if (sc.Compare ("flat")) { isflat = true; sc.MustGetString (); } else if (sc.Compare ("texture")) { isflat = false; sc.MustGetString (); } else { sc.ScriptError (NULL); } FTextureID picnum = TexMan.CheckForTexture (sc.String, isflat ? FTexture::TEX_Flat : FTexture::TEX_Wall, texflags); if (picnum.isValid()) { FTexture * warper = TexMan[picnum]; // don't warp a texture more than once if (!warper->bWarped) { if (type2) // [GRB] warper = new FWarp2Texture (warper); else warper = new FWarpTexture (warper); TexMan.ReplaceTexture (picnum, warper, false); } if (sc.CheckFloat()) { static_cast<FWarpTexture*>(warper)->SetSpeed(float(sc.Float)); } // No decals on warping textures, by default. // Warping information is taken from the last warp // definition for this texture. warper->bNoDecals = true; if (sc.GetString ()) { if (sc.Compare ("allowdecals")) { warper->bNoDecals = false; } else { sc.UnGet (); } } } } else if (sc.Compare ("cameratexture")) { int width, height; int fitwidth, fitheight; FString picname; sc.MustGetString (); picname = sc.String; sc.MustGetNumber (); width = sc.Number; sc.MustGetNumber (); height = sc.Number; FTextureID picnum = TexMan.CheckForTexture (picname, FTexture::TEX_Flat, texflags); FTexture *viewer = new FCanvasTexture (picname, width, height); if (picnum.Exists()) { FTexture *oldtex = TexMan[picnum]; fitwidth = oldtex->GetScaledWidth (); fitheight = oldtex->GetScaledHeight (); viewer->UseType = oldtex->UseType; TexMan.ReplaceTexture (picnum, viewer, true); } else { fitwidth = width; fitheight = height; // [GRB] No need for oldtex viewer->UseType = FTexture::TEX_Wall; TexMan.AddTexture (viewer); } if (sc.GetString()) { if (sc.Compare ("fit")) { sc.MustGetNumber (); fitwidth = sc.Number; sc.MustGetNumber (); fitheight = sc.Number; } else { sc.UnGet (); } } viewer->SetScaledSize(fitwidth, fitheight); } else if (sc.Compare ("animatedDoor")) { P_ParseAnimatedDoor (sc); } else if (sc.Compare("skyoffset")) { sc.MustGetString (); FTextureID picnum = TexMan.CheckForTexture (sc.String, FTexture::TEX_Wall, texflags); sc.MustGetNumber(); if (picnum.Exists()) { FTexture *tex = TexMan[picnum]; tex->SkyOffset = sc.Number; } } else { sc.ScriptError (NULL); } } } }
FTexture *FTextureManager::FindTexture(const char *texname, int usetype, BITFIELD flags) { FTextureID texnum = CheckForTexture (texname, usetype, flags); return !texnum.isValid()? NULL : Textures[texnum.GetIndex()].Texture; }
FFont::FFont (const char *name, const char *nametemplate, const char *filetemplate, int lfirst, int lcount, int start, int fdlump, int spacewidth, bool notranslate, bool iwadonly) { int i; FTextureID lump; char buffer[12]; int maxyoffs; bool doomtemplate = (nametemplate && (gameinfo.gametype & GAME_DoomChex)) ? strncmp (nametemplate, "STCFN", 5) == 0 : false; DVector2 Scale = { 1, 1 }; noTranslate = notranslate; Lump = fdlump; GlobalKerning = false; FontName = name; Next = FirstFont; FirstFont = this; Cursor = '_'; ActiveColors = 0; SpaceWidth = 0; FontHeight = 0; uint8_t pp = 0; for (auto &p : PatchRemap) p = pp++; translateUntranslated = false; int FixedWidth = 0; maxyoffs = 0; TMap<int, FTexture*> charMap; int minchar = INT_MAX; int maxchar = INT_MIN; // Read the font's configuration. // This will not be done for the default fonts, because they are not atomic and the default content does not need it. TArray<FolderEntry> folderdata; if (filetemplate != nullptr) { FStringf path("fonts/%s/", filetemplate); // If a name template is given, collect data from all resource files. // For anything else, each folder is being treated as an atomic, self-contained unit and mixing from different glyph sets is blocked. Wads.GetLumpsInFolder(path, folderdata, nametemplate == nullptr); //if (nametemplate == nullptr) { FStringf infpath("fonts/%s/font.inf", filetemplate); unsigned index = folderdata.FindEx([=](const FolderEntry &entry) { return infpath.CompareNoCase(entry.name) == 0; }); if (index < folderdata.Size()) { FScanner sc; sc.OpenLumpNum(folderdata[index].lumpnum); while (sc.GetToken()) { sc.TokenMustBe(TK_Identifier); if (sc.Compare("Kerning")) { sc.MustGetValue(false); GlobalKerning = sc.Number; } else if (sc.Compare("Scale")) { sc.MustGetValue(true); Scale.Y = Scale.X = sc.Float; if (sc.CheckToken(',')) { sc.MustGetValue(true); Scale.Y = sc.Float; } } else if (sc.Compare("SpaceWidth")) { sc.MustGetValue(false); SpaceWidth = sc.Number; } else if (sc.Compare("FontHeight")) { sc.MustGetValue(false); FontHeight = sc.Number; } else if (sc.Compare("CellSize")) { sc.MustGetValue(false); FixedWidth = sc.Number; sc.MustGetToken(','); sc.MustGetValue(false); FontHeight = sc.Number; } else if (sc.Compare("Translationtype")) { sc.MustGetToken(TK_Identifier); if (sc.Compare("console")) { TranslationType = 1; } else if (sc.Compare("standard")) { TranslationType = 0; } else { sc.ScriptError("Unknown translation type %s", sc.String); } } } } } } if (FixedWidth > 0) { ReadSheetFont(folderdata, FixedWidth, FontHeight, Scale); Type = Folder; } else { if (nametemplate != nullptr) { if (!iwadonly) { for (i = 0; i < lcount; i++) { int position = lfirst + i; mysnprintf(buffer, countof(buffer), nametemplate, i + start); lump = TexMan.CheckForTexture(buffer, ETextureType::MiscPatch); if (doomtemplate && lump.isValid() && i + start == 121) { // HACKHACK: Don't load STCFN121 in doom(2), because // it's not really a lower-case 'y' but a '|'. // Because a lot of wads with their own font seem to foolishly // copy STCFN121 and make it a '|' themselves, wads must // provide STCFN120 (x) and STCFN122 (z) for STCFN121 to load as a 'y'. if (!TexMan.CheckForTexture("STCFN120", ETextureType::MiscPatch).isValid() || !TexMan.CheckForTexture("STCFN122", ETextureType::MiscPatch).isValid()) { // insert the incorrectly named '|' graphic in its correct position. position = 124; } } if (lump.isValid()) { Type = Multilump; if (position < minchar) minchar = position; if (position > maxchar) maxchar = position; charMap.Insert(position, TexMan.GetTexture(lump)); } } } else { FTexture *texs[256] = {}; if (lcount > 256 - start) lcount = 256 - start; for (i = 0; i < lcount; i++) { TArray<FTextureID> array; mysnprintf(buffer, countof(buffer), nametemplate, i + start); TexMan.ListTextures(buffer, array, true); for (auto entry : array) { FTexture *tex = TexMan.GetTexture(entry, false); if (tex && tex->SourceLump >= 0 && Wads.GetLumpFile(tex->SourceLump) <= Wads.GetIwadNum() && tex->UseType == ETextureType::MiscPatch) { texs[i] = tex; } } } if (doomtemplate) { // Handle the misplaced '|'. if (texs[121 - '!'] && !texs[120 - '!'] && !texs[122 - '!'] && !texs[124 - '!']) { texs[124 - '!'] = texs[121 - '!']; texs[121 - '!'] = nullptr; } } for (i = 0; i < lcount; i++) { if (texs[i]) { int position = lfirst + i; Type = Multilump; if (position < minchar) minchar = position; if (position > maxchar) maxchar = position; charMap.Insert(position, texs[i]); } } } } if (folderdata.Size() > 0) { // all valid lumps must be named with a hex number that represents its Unicode character index. for (auto &entry : folderdata) { char *endp; auto base = ExtractFileBase(entry.name); auto position = strtoll(base.GetChars(), &endp, 16); if ((*endp == 0 || (*endp == '.' && position >= '!' && position < 0xffff))) { auto lump = TexMan.CheckForTexture(entry.name, ETextureType::MiscPatch); if (lump.isValid()) { if ((int)position < minchar) minchar = (int)position; if ((int)position > maxchar) maxchar = (int)position; auto tex = TexMan.GetTexture(lump); tex->SetScale(Scale); charMap.Insert((int)position, tex); Type = Folder; } } } } FirstChar = minchar; LastChar = maxchar; auto count = maxchar - minchar + 1; Chars.Resize(count); int fontheight = 0; for (i = 0; i < count; i++) { auto lump = charMap.CheckKey(FirstChar + i); if (lump != nullptr) { FTexture *pic = *lump; if (pic != nullptr) { int height = pic->GetDisplayHeight(); int yoffs = pic->GetDisplayTopOffset(); if (yoffs > maxyoffs) { maxyoffs = yoffs; } height += abs(yoffs); if (height > fontheight) { fontheight = height; } } pic->SetUseType(ETextureType::FontChar); if (!noTranslate) { Chars[i].OriginalPic = pic; Chars[i].TranslatedPic = new FImageTexture(new FFontChar1(pic->GetImage()), ""); Chars[i].TranslatedPic->CopySize(pic); Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); TexMan.AddTexture(Chars[i].TranslatedPic); } else { Chars[i].TranslatedPic = pic; } Chars[i].XMove = Chars[i].TranslatedPic->GetDisplayWidth(); } else { Chars[i].TranslatedPic = nullptr; Chars[i].XMove = INT_MIN; } } if (SpaceWidth == 0) // An explicit override from the .inf file must always take precedence { if (spacewidth != -1) { SpaceWidth = spacewidth; } else if ('N' - FirstChar >= 0 && 'N' - FirstChar < count && Chars['N' - FirstChar].TranslatedPic != nullptr) { SpaceWidth = (Chars['N' - FirstChar].XMove + 1) / 2; } else { SpaceWidth = 4; } } if (FontHeight == 0) FontHeight = fontheight; FixXMoves(); } if (!noTranslate) LoadTranslations(); }
void FMultiPatchTexture::ResolvePatches() { if (Inits != nullptr) { for (int i = 0; i < NumParts; i++) { FTextureID texno = TexMan.CheckForTexture(Inits[i].TexName, Inits[i].UseType); if (texno == id) // we found ourselves. Try looking for another one with the same name which is not a multipatch texture itself. { TArray<FTextureID> list; TexMan.ListTextures(Inits[i].TexName, list, true); for (int i = list.Size() - 1; i >= 0; i--) { if (list[i] != id && !TexMan[list[i]]->bMultiPatch) { texno = list[i]; break; } } if (texno == id) { if (Inits[i].HasLine) Inits[i].sc.Message(MSG_WARNING, "Texture '%s' references itself as patch\n", Inits[i].TexName.GetChars()); else Printf(TEXTCOLOR_YELLOW "Texture '%s' references itself as patch\n", Inits[i].TexName.GetChars()); continue; } else { // If it could be resolved, just print a developer warning. DPrintf(DMSG_WARNING, "Resolved self-referencing texture by picking an older entry for %s\n", Inits[i].TexName.GetChars()); } } if (!texno.isValid()) { if (!Inits[i].Silent) { if (Inits[i].HasLine) Inits[i].sc.Message(MSG_WARNING, "Unknown patch '%s' in texture '%s'\n", Inits[i].TexName.GetChars(), Name.GetChars()); else Printf(TEXTCOLOR_YELLOW "Unknown patch '%s' in texture '%s'\n", Inits[i].TexName.GetChars(), Name.GetChars()); } } else { Parts[i].Texture = TexMan[texno]; bComplex |= Parts[i].Texture->bComplex; Parts[i].Texture->bKeepAround = true; if (Inits[i].UseOffsets) { Parts[i].OriginX -= Parts[i].Texture->GetLeftOffset(0); Parts[i].OriginY -= Parts[i].Texture->GetTopOffset(0); } } } for (int i = 0; i < NumParts; i++) { if (Parts[i].Texture == nullptr) { memcpy(&Parts[i], &Parts[i + 1], (NumParts - i - 1) * sizeof(TexPart)); i--; NumParts--; } } } delete[] Inits; Inits = nullptr; CheckForHacks(); // If this texture is just a wrapper around a single patch, we can simply // forward GetPixels() and GetColumn() calls to that patch. if (NumParts == 1) { if (Parts->OriginX == 0 && Parts->OriginY == 0 && Parts->Texture->GetWidth() == Width && Parts->Texture->GetHeight() == Height && Parts->Rotate == 0 && !bComplex) { bRedirect = true; } } }
void HandleCommand (bool helphack) { int i,margin,top,bottom; int picmid; switch (toupper(*++text)) { case 'B': { double bx = ParseNumber(); double by = ParseNumber(); double bw = ParseNumber(); double bh = ParseNumber(); MenuToRealCoords(bx, by, bw, bh, MENU_CENTER); VWB_DrawFill(backgroundFlat, (int)bx, (int)by, (int)(bx+bw), (int)(by+bh)); RipToEOL(); break; } case ';': // comment RipToEOL(); break; case 'P': // ^P is start of next page, ^E is end of file case 'E': layoutdone = true; text--; // back up to the '^' break; case 'C': // ^c<hex digit> changes text color i = toupper(*++text); if(i == '[') // Textcolo translation { fontcolor = 255; const BYTE *colorname = (const BYTE *)(text); textcolor = V_ParseFontColor(colorname, CR_UNTRANSLATED, CR_UNTRANSLATED+1); while(*text++ != ']'); } else { textcolor = CR_UNTRANSLATED; if (i>='0' && i<='9') fontcolor = i-'0'; else if (i>='A' && i<='F') fontcolor = i-'A'+10; fontcolor *= 16; i = toupper(*++text); if (i>='0' && i<='9') fontcolor += i-'0'; else if (i>='A' && i<='F') fontcolor += i-'A'+10; text++; } break; case '>': px = 160; text++; break; case 'L': py=ParseNumber(); rowon = (py-TOPMARGIN)/FONTHEIGHT; py = TOPMARGIN+rowon*FONTHEIGHT; px=ParseNumber(); while (*text++ != '\n') // scan to end of line ; break; case 'T': // ^Tyyy,xxx,ppp,ttt waits ttt tics, then draws pic TimedPicCommand (helphack); break; case 'G': // ^Gyyy,xxx,ppp draws graphic { ParsePicCommand (helphack); if(!picnum.isValid()) break; FTexture *picture = TexMan(picnum); VWB_DrawGraphic (picture, picx&~7,picy, MENU_CENTER); // // adjust margins // picmid = picx + picture->GetScaledWidth()/2; if (picmid > SCREENMID) margin = picx-PICMARGIN; // new right margin else margin = picx+picture->GetScaledWidth()+PICMARGIN; // new left margin top = (picy-TOPMARGIN)/FONTHEIGHT; if (top<0) top = 0; bottom = (picy+picture->GetScaledHeight()-TOPMARGIN)/FONTHEIGHT; if (bottom>=TEXTROWS) bottom = TEXTROWS-1; for (i=top; i<=bottom; i++) if (picmid > SCREENMID) rightmargin[i] = margin; else leftmargin[i] = margin; // // adjust this line if needed // if (px < (int) leftmargin[rowon]) px = leftmargin[rowon]; break; } } }