void FTextureManager::InitPalettedVersions() { int lump, lastlump = 0; PalettedVersions.Clear(); while ((lump = Wads.FindLump("PALVERS", &lastlump)) != -1) { FMemLump data = Wads.ReadLump(lump); Scanner sc((const char*)data.GetMem(), data.GetSize()); while (sc.GetNextToken()) { FTextureID pic1 = CheckForTexture(sc->str, FTexture::TEX_Any); if (!pic1.isValid()) { sc.ScriptMessage(Scanner::WARNING, "Unknown texture %s to replace", sc->str.GetChars()); } sc.GetNextToken(); FTextureID pic2 = CheckForTexture(sc->str, FTexture::TEX_Any); if (!pic2.isValid()) { sc.ScriptMessage(Scanner::WARNING, "Unknown texture %s to use as replacement", sc->str.GetChars()); } if (pic1.isValid() && pic2.isValid()) { PalettedVersions[pic1.GetIndex()] = pic2.GetIndex(); } } } }
/* Blake Stone strings are stored in text chunks. They're referenced by an * index. Strings are stored separated by ^XX at the end of a line. */ void Language::SetupBlakeStrings(const char* lumpname, const char* prefix) { int lumpnum = Wads.CheckNumForName(lumpname); if(lumpnum == -1) return; FMemLump wadLump = Wads.ReadLump(lumpnum); unsigned int num = 1; // Start at prefix_1 unsigned int pos = 0; unsigned int start = 0; const char* data = reinterpret_cast<const char*>(wadLump.GetMem()); static const WORD endToken = ('X'<<8)|'X'; // Since both chars are the same this should be endian safe while(pos+2 < wadLump.GetSize()) { if(data[pos] == '^' && *(WORD*)(data+pos+1) == endToken) { FString name; FString str(data+start, pos-start); name.Format("%s%d", prefix, num++); strings[name] = str; pos += 3; while((data[pos] == '\n' || data[pos] == '\r') && pos < wadLump.GetSize()) ++pos; start = pos; } else ++pos; } }
void FScanner :: OpenLumpNum (int lump) { Close (); { FMemLump mem = Wads.ReadLump(lump); ScriptBuffer = mem.GetString(); } ScriptName = Wads.GetLumpFullPath(lump); LumpNum = lump; PrepareScript (); }
static void R_CreateSkinTranslation (const char *palname) { FMemLump lump = Wads.ReadLump (palname); const BYTE *otherPal = (BYTE *)lump.GetMem(); for (int i = 0; i < 256; ++i) { OtherGameSkinRemap[i] = ColorMatcher.Pick (otherPal[0], otherPal[1], otherPal[2]); OtherGameSkinPalette[i] = PalEntry(otherPal[0], otherPal[1], otherPal[2]); otherPal += 3; } }
static FModel * FindModel(const char * path, const char * modelfile) { FModel * model; FString fullname; fullname.Format("%s%s", path, modelfile); int lump = Wads.CheckNumForFullName(fullname); if (lump<0) { Printf("FindModel: '%s' not found\n", fullname.GetChars()); return NULL; } for(int i = 0; i< (int)Models.Size(); i++) { if (!stricmp(fullname, Models[i]->filename)) return Models[i]; } int len = Wads.LumpLength(lump); FMemLump lumpd = Wads.ReadLump(lump); char * buffer = (char*)lumpd.GetMem(); if (!memcmp(buffer, "DMDM", 4)) { model = new FDMDModel; } else if (!memcmp(buffer, "IDP2", 4)) { model = new FMD2Model; } else if (!memcmp(buffer, "IDP3", 4)) { model = new FMD3Model; } else { Printf("LoadModel: Unknown model format in '%s'\n", fullname.GetChars()); delete buffer; return NULL; } if (!model->Load(path, buffer, len)) { delete model; delete buffer; return NULL; } model->filename = copystring(fullname); Models.Push(model); return model; }
/* ================= = = HelpScreens = ================= */ void HelpScreens (void) { int lumpNum = Wads.CheckNumForName("HELPART", ns_global); if(lumpNum != -1) { FMemLump lump = Wads.ReadLump(lumpNum); backgroundFlat = TexMan(gameinfo.FinaleFlat); ShowArticle((char*)lump.GetMem()); } VW_FadeOut(); }
// Fix for certain special patches on single-patch textures. void FPatchTexture::HackHack (int newheight) { BYTE *out; int x; Unload (); if (Spans != NULL) { FreeSpans (Spans); } { FMemLump lump = Wads.ReadLump (SourceLump); const patch_t *patch = (const patch_t *)lump.GetMem(); Width = LittleShort(patch->width); Height = newheight; LeftOffset = 0; TopOffset = 0; Pixels = new BYTE[Width * Height]; // Draw the image to the buffer for (x = 0, out = Pixels; x < Width; ++x) { const BYTE *in = (const BYTE *)patch + LittleLong(patch->columnofs[x]) + 3; for (int y = newheight; y > 0; --y) { *out = *in != 255 ? *in : Near255; out++, in++; } out += newheight; } } // Create the spans Spans = (Span **)M_Malloc (sizeof(Span *)*Width + sizeof(Span)*Width*2); Span *span = (Span *)&Spans[Width]; for (x = 0; x < Width; ++x) { Spans[x] = span; span[0].Length = newheight; span[0].TopOffset = 0; span[1].Length = 0; span[1].TopOffset = 0; span += 2; } }
void FTextureManager::AddTexturesLumps (int lump1, int lump2, int patcheslump) { int firstdup = (int)Textures.Size(); if (lump1 >= 0) { FMemLump texdir = Wads.ReadLump (lump1); AddTexturesLump (texdir.GetMem(), Wads.LumpLength (lump1), lump1, patcheslump, firstdup, true); } if (lump2 >= 0) { FMemLump texdir = Wads.ReadLump (lump2); AddTexturesLump (texdir.GetMem(), Wads.LumpLength (lump2), lump2, patcheslump, firstdup, false); } }
void FAutomapTexture::MakeTexture () { int x, y; FMemLump data = Wads.ReadLump (SourceLump); const BYTE *indata = (const BYTE *)data.GetMem(); Pixels = new BYTE[Width * Height]; for (x = 0; x < Width; ++x) { for (y = 0; y < Height; ++y) { Pixels[x*Height+y] = indata[x+320*y]; } } }
void FMD3Model::LoadGeometry() { FMemLump lumpdata = Wads.ReadLump(mLumpNum); const char *buffer = (const char *)lumpdata.GetMem(); md3_header_t * hdr = (md3_header_t *)buffer; md3_surface_t * surf = (md3_surface_t*)(buffer + LittleLong(hdr->Ofs_Surfaces)); for(int i=0;i<numSurfaces;i++) { MD3Surface * s = &surfaces[i]; md3_surface_t * ss = surf; surf = (md3_surface_t *)(((char*)surf) + LittleLong(surf->Ofs_End)); // copy triangle indices md3_triangle_t * tris = (md3_triangle_t*)(((char*)ss)+LittleLong(ss->Ofs_Triangles)); s->tris = new MD3Triangle[s->numTriangles]; for(int i=0;i<s->numTriangles;i++) for (int j=0;j<3;j++) { s->tris[i].VertIndex[j]=LittleLong(tris[i].vt_index[j]); } // Load texture coordinates md3_texcoord_t * tc = (md3_texcoord_t*)(((char*)ss)+LittleLong(ss->Ofs_Texcoord)); s->texcoords = new MD3TexCoord[s->numVertices]; for(int i=0;i<s->numVertices;i++) { s->texcoords[i].s = tc[i].s; s->texcoords[i].t = tc[i].t; } // Load vertices and texture coordinates md3_vertex_t * vt = (md3_vertex_t*)(((char*)ss)+LittleLong(ss->Ofs_XYZNormal)); s->vertices = new MD3Vertex[s->numVertices * numFrames]; for(int i=0;i<s->numVertices * numFrames;i++) { s->vertices[i].x = LittleShort(vt[i].x)/64.f; s->vertices[i].y = LittleShort(vt[i].y)/64.f; s->vertices[i].z = LittleShort(vt[i].z)/64.f; UnpackVector( LittleShort(vt[i].n), s->vertices[i].nx, s->vertices[i].ny, s->vertices[i].nz); } } }
byte* SD_PrepareSound(int which) { int size = Wads.LumpLength(which); if(size == 0) return NULL; FMemLump soundLump = Wads.ReadLump(which); byte* out = reinterpret_cast<byte*> (Mix_LoadWAV_RW(SDL_RWFromMem(soundLump.GetMem(), size), 1)); if(!out) return NULL; // TEMPORARY WORK AROUND FOR MEMORY ERROR byte* nout = new byte[sizeof(Mix_Chunk)]; memcpy(nout, out, sizeof(Mix_Chunk)); return nout; }
TArray<uint8_t> FAutomapTexture::CreatePalettedPixels(int conversion) { int x, y; FMemLump data = Wads.ReadLump (SourceLump); const uint8_t *indata = (const uint8_t *)data.GetMem(); TArray<uint8_t> Pixels(Width * Height, true); const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance); for (x = 0; x < Width; ++x) { for (y = 0; y < Height; ++y) { auto p = indata[x + 320 * y]; Pixels[x*Height + y] = remap[p]; } } return Pixels; }
void FPatchTexture::HackHack (int newheight) { // Check if this patch is likely to be a problem. // It must be 256 pixels tall, and all its columns must have exactly // one post, where each post has a supposed length of 0. FMemLump lump = Wads.ReadLump (SourceLump); const patch_t *realpatch = (patch_t *)lump.GetMem(); const DWORD *cofs = realpatch->columnofs; int x, x2 = LittleShort(realpatch->width); if (LittleShort(realpatch->height) == 256) { for (x = 0; x < x2; ++x) { const column_t *col = (column_t*)((BYTE*)realpatch+LittleLong(cofs[x])); if (col->topdelta != 0 || col->length != 0) { break; // It's not bad! } col = (column_t *)((BYTE *)col + 256 + 4); if (col->topdelta != 0xFF) { break; // More than one post in a column! } } if (x == x2) { // If all the columns were checked, it needs fixing. Unload (); if (Spans != NULL) { FreeSpans (Spans); } Height = newheight; LeftOffset = 0; TopOffset = 0; hackflag = true; bMasked = false; // Hacked textures don't have transparent parts. } } }
void FTextureManager::InitSwitchList () { const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; int lump = Wads.CheckNumForName ("SWITCHES"); if (lump != -1) { FMemLump lumpdata = Wads.ReadLump (lump); const char *alphSwitchList = (const char *)lumpdata.GetMem(); const char *list_p; FSwitchDef *def1, *def2; for (list_p = alphSwitchList; list_p[18] || list_p[19]; list_p += 20) { // [RH] Check for switches that aren't really switches if (stricmp (list_p, list_p+9) == 0) { Printf ("Switch %s in SWITCHES has the same 'on' state\n", list_p); continue; } // [RH] Skip this switch if its textures can't be found. if (CheckForTexture (list_p /* .name1 */, FTexture::TEX_Wall, texflags).Exists() && CheckForTexture (list_p + 9 /* .name2 */, FTexture::TEX_Wall, texflags).Exists()) { def1 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef)); def2 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef)); def1->PreTexture = def2->frames[0].Texture = CheckForTexture (list_p /* .name1 */, FTexture::TEX_Wall, texflags); def2->PreTexture = def1->frames[0].Texture = CheckForTexture (list_p + 9, FTexture::TEX_Wall, texflags); def1->Sound = def2->Sound = 0; def1->NumFrames = def2->NumFrames = 1; def1->frames[0].TimeMin = def2->frames[0].TimeMin = 0; def1->frames[0].TimeRnd = def2->frames[0].TimeRnd = 0; AddSwitchPair(def1, def2); } } } mSwitchDefs.ShrinkToFit (); qsort (&mSwitchDefs[0], mSwitchDefs.Size(), sizeof(FSwitchDef *), SortSwitchDefs); }
void FIMGZTexture::MakeTexture () { FMemLump lump = Wads.ReadLump (SourceLump); const ImageHeader *imgz = (const ImageHeader *)lump.GetMem(); const BYTE *data = (const BYTE *)&imgz[1]; if (Width != 0xFFFF) { Width = LittleShort(imgz->Width); Height = LittleShort(imgz->Height); LeftOffset = LittleShort(imgz->LeftOffset); TopOffset = LittleShort(imgz->TopOffset); } BYTE *dest_p; int dest_adv = Height; int dest_rew = Width * Height - 1; CalcBitSize (); Pixels = new BYTE[Width*Height]; dest_p = Pixels; // Convert the source image from row-major to column-major format if (!imgz->Compression) { for (int y = Height; y != 0; --y) { for (int x = Width; x != 0; --x) { *dest_p = *data; dest_p += dest_adv; data++; } dest_p -= dest_rew; } } else { // IMGZ compression is the same RLE used by IFF ILBM files int runlen = 0, setlen = 0; BYTE setval = 0; // Shut up, GCC for (int y = Height; y != 0; --y) { for (int x = Width; x != 0; ) { if (runlen != 0) { BYTE color = *data; *dest_p = color; dest_p += dest_adv; data++; x--; runlen--; } else if (setlen != 0) { *dest_p = setval; dest_p += dest_adv; x--; setlen--; } else { SBYTE code = *data++; if (code >= 0) { runlen = code + 1; } else if (code != -128) { setlen = (-code) + 1; setval = *data++; } } } dest_p -= dest_rew; } } }
void FTextureManager::LoadTextureDefs(int wadnum, const char *lumpname) { int remapLump, lastLump; char src[9]; //bool is32bit; //int width, height; //int type, mode; TArray<FTextureID> tlist; lastLump = 0; src[8] = '\0'; while ((remapLump = Wads.FindLump(lumpname, &lastLump)) != -1) { if (Wads.GetLumpFile(remapLump) == wadnum) { FMemLump lmp = Wads.ReadLump(remapLump); Scanner sc((const char*)lmp.GetMem(), lmp.GetSize()); sc.SetScriptIdentifier(Wads.GetLumpFullName(remapLump)); while (sc.CheckToken(TK_Identifier)) { /*if (sc.Compare("remap")) // remap an existing texture { sc.MustGetString(); // allow selection by type if (sc.Compare("wall")) type=FTexture::TEX_Wall, mode=FTextureManager::TEXMAN_Overridable; else if (sc.Compare("flat")) type=FTexture::TEX_Flat, mode=FTextureManager::TEXMAN_Overridable; else if (sc.Compare("sprite")) type=FTexture::TEX_Sprite, mode=0; else type = FTexture::TEX_Any, mode = 0; if (type != FTexture::TEX_Any) sc.MustGetString(); sc.String[8]=0; tlist.Clear(); int amount = ListTextures(sc.String, tlist); FName texname = sc.String; sc.MustGetString(); int lumpnum = Wads.CheckNumForFullName(sc.String, true, ns_patches); if (lumpnum == -1) lumpnum = Wads.CheckNumForFullName(sc.String, true, ns_graphics); if (tlist.Size() == 0) { Printf("Attempting to remap non-existent texture %s to %s\n", texname.GetChars(), sc.String); } else if (lumpnum == -1) { Printf("Attempting to remap texture %s to non-existent lump %s\n", texname.GetChars(), sc.String); } else { for(unsigned int i = 0; i < tlist.Size(); i++) { FTexture * oldtex = Textures[tlist[i].GetIndex()].Texture; int sl; // only replace matching types. For sprites also replace any MiscPatches // based on the same lump. These can be created for icons. if (oldtex->UseType == type || type == FTexture::TEX_Any || (mode == TEXMAN_Overridable && oldtex->UseType == FTexture::TEX_Override) || (type == FTexture::TEX_Sprite && oldtex->UseType == FTexture::TEX_MiscPatch && (sl=oldtex->GetSourceLump()) >= 0 && Wads.GetLumpNamespace(sl) == ns_sprites) ) { FTexture * newtex = FTexture::CreateTexture (lumpnum, FTexture::TEX_Any); if (newtex != NULL) { // Replace the entire texture and adjust the scaling and offset factors. newtex->bWorldPanning = true; newtex->SetScaledSize(oldtex->GetScaledWidth(), oldtex->GetScaledHeight()); newtex->LeftOffset = FixedMul(oldtex->GetScaledLeftOffset(), newtex->xScale); newtex->TopOffset = FixedMul(oldtex->GetScaledTopOffset(), newtex->yScale); ReplaceTexture(tlist[i], newtex, true); } } } } } else if (sc.Compare("define")) // define a new "fake" texture { sc.GetString(); FString base = ExtractFileBase(sc.String, false); if (!base.IsEmpty()) { strncpy(src, base, 8); int lumpnum = Wads.CheckNumForFullName(sc.String, true, ns_patches); if (lumpnum == -1) lumpnum = Wads.CheckNumForFullName(sc.String, true, ns_graphics); sc.GetString(); is32bit = !!sc.Compare("force32bit"); if (!is32bit) sc.UnGet(); sc.GetNumber(); width = sc.Number; sc.GetNumber(); height = sc.Number; if (lumpnum>=0) { FTexture *newtex = FTexture::CreateTexture(lumpnum, FTexture::TEX_Override); if (newtex != NULL) { // Replace the entire texture and adjust the scaling and offset factors. newtex->bWorldPanning = true; newtex->SetScaledSize(width, height); memcpy(newtex->Name, src, sizeof(newtex->Name)); FTextureID oldtex = TexMan.CheckForTexture(src, FTexture::TEX_MiscPatch); if (oldtex.isValid()) { ReplaceTexture(oldtex, newtex, true); newtex->UseType = FTexture::TEX_Override; } else AddTexture(newtex); } } } //else Printf("Unable to define hires texture '%s'\n", tex->Name); } else */if (sc->str.CompareNoCase("texture") == 0) { ParseXTexture(sc, FTexture::TEX_Override); } else if (sc->str.CompareNoCase("sprite") == 0) { ParseXTexture(sc, FTexture::TEX_Sprite); } else if (sc->str.CompareNoCase("walltexture") == 0) { ParseXTexture(sc, FTexture::TEX_Wall); } else if (sc->str.CompareNoCase("flat") == 0) { ParseXTexture(sc, FTexture::TEX_Flat); } else if (sc->str.CompareNoCase("graphic") == 0) { ParseXTexture(sc, FTexture::TEX_MiscPatch); } else if(sc->str.CompareNoCase("artindex") == 0) { sc.MustGetToken(TK_IntConst); int index = sc->number; sc.MustGetToken(','); sc.MustGetToken(TK_StringConst); if(index > 255) sc.ScriptMessage(Scanner::ERROR, "Can't assign art index over 255.\n"); artIndex[index].textureName = sc->str; } else { sc.ScriptMessage(Scanner::ERROR, "Texture definition expected, found '%s'", sc->str.GetChars()); } } } } }
static unsigned FindModel(const char * path, const char * modelfile) { FModel * model = nullptr; FString fullname; fullname.Format("%s%s", path, modelfile); int lump = Wads.CheckNumForFullName(fullname); if (lump<0) { Printf("FindModel: '%s' not found\n", fullname.GetChars()); return -1; } for(unsigned i = 0; i< Models.Size(); i++) { if (!Models[i]->mFileName.CompareNoCase(fullname)) return i; } int len = Wads.LumpLength(lump); FMemLump lumpd = Wads.ReadLump(lump); char * buffer = (char*)lumpd.GetMem(); if (!memcmp(buffer, "DMDM", 4)) { model = new FDMDModel; } else if (!memcmp(buffer, "IDP2", 4)) { model = new FMD2Model; } else if (!memcmp(buffer, "IDP3", 4)) { model = new FMD3Model; } if (model != nullptr) { if (!model->Load(path, lump, buffer, len)) { delete model; return -1; } } else { // try loading as a voxel FVoxel *voxel = R_LoadKVX(lump); if (voxel != nullptr) { model = new FVoxelModel(voxel, true); } else { Printf("LoadModel: Unknown model format in '%s'\n", fullname.GetChars()); return -1; } } // The vertex buffer cannot be initialized here because this gets called before OpenGL is initialized model->mFileName = fullname; return Models.Push(model); }
void R_InitPicAnims (void) { const BITFIELD texflags = FTextureManager::TEXMAN_Overridable; // I think better not! This is only for old ANIMATED definition that // don't know about ZDoom's more flexible texture system. // | FTextureManager::TEXMAN_TryAny; if (Wads.CheckNumForName ("ANIMATED") != -1) { FMemLump animatedlump = Wads.ReadLump ("ANIMATED"); const char *animdefs = (const char *)animatedlump.GetMem(); const char *anim_p; FTextureID pic1, pic2; int animtype; DWORD animspeed; // Init animation animtype = FAnimDef::ANIM_Forward; for (anim_p = animdefs; *anim_p != -1; anim_p += 23) { if (*anim_p /* .istexture */ & 1) { // different episode ? if (!(pic1 = TexMan.CheckForTexture (anim_p + 10 /* .startname */, FTexture::TEX_Wall, texflags)).Exists() || !(pic2 = TexMan.CheckForTexture (anim_p + 1 /* .endname */, FTexture::TEX_Wall, texflags)).Exists()) continue; // [RH] Bit 1 set means allow decals on walls with this texture TexMan[pic2]->bNoDecals = TexMan[pic1]->bNoDecals = !(*anim_p & 2); } else { if (!(pic1 = TexMan.CheckForTexture (anim_p + 10 /* .startname */, FTexture::TEX_Flat, texflags)).Exists() || !(pic2 = TexMan.CheckForTexture (anim_p + 1 /* .startname */, FTexture::TEX_Flat, texflags)).Exists()) continue; } if (pic1 == pic2) { // This animation only has one frame. Skip it. (Doom aborted instead.) Printf ("Animation %s in ANIMATED has only one frame", anim_p + 10); continue; } FTexture *tex1 = TexMan[pic1]; FTexture *tex2 = TexMan[pic2]; if (tex1->UseType != tex2->UseType) { // not the same type - continue; } if (debuganimated) { Printf("Defining animation '%s' (texture %d, lump %d, file %d) to '%s' (texture %d, lump %d, file %d)\n", tex1->Name, pic1.GetIndex(), tex1->GetSourceLump(), Wads.GetLumpFile(tex1->GetSourceLump()), tex2->Name, pic2.GetIndex(), tex2->GetSourceLump(), Wads.GetLumpFile(tex2->GetSourceLump())); } // [RH] Allow for backward animations as well as forward. if (pic1 > pic2) { swap (pic1, pic2); animtype = FAnimDef::ANIM_Backward; } // Speed is stored as tics, but we want ms so scale accordingly. animspeed = /* .speed */ Scale ((BYTE(anim_p[19]) << 0) | (BYTE(anim_p[20]) << 8) | (BYTE(anim_p[21]) << 16) | (BYTE(anim_p[22]) << 24), 1000, 35); R_AddSimpleAnim (pic1, pic2 - pic1 + 1, animtype, animspeed); } } // [RH] Load any ANIMDEFS lumps R_InitAnimDefs (); Anims.FixAnimations (); }
void FPatchTexture::MakeTexture () { BYTE *remap, remaptable[256]; int numspans; const column_t *maxcol; int x; FMemLump lump = Wads.ReadLump (SourceLump); const patch_t *patch = (const patch_t *)lump.GetMem(); maxcol = (const column_t *)((const BYTE *)patch + Wads.LumpLength (SourceLump) - 3); // Check for badly-sized patches #if 0 // Such textures won't be created so there's no need to check here if (LittleShort(patch->width) <= 0 || LittleShort(patch->height) <= 0) { lump = Wads.ReadLump ("-BADPATC"); patch = (const patch_t *)lump.GetMem(); Printf (PRINT_BOLD, "Patch %s has a non-positive size.\n", Name); } else if (LittleShort(patch->width) > 2048 || LittleShort(patch->height) > 2048) { lump = Wads.ReadLump ("-BADPATC"); patch = (const patch_t *)lump.GetMem(); Printf (PRINT_BOLD, "Patch %s is too big.\n", Name); } #endif if (bNoRemap0) { memcpy (remaptable, GPalette.Remap, 256); remaptable[0] = 0; remap = remaptable; } else { remap = GPalette.Remap; } if (hackflag) { Pixels = new BYTE[Width * Height]; BYTE *out; // Draw the image to the buffer for (x = 0, out = Pixels; x < Width; ++x) { const BYTE *in = (const BYTE *)patch + LittleLong(patch->columnofs[x]) + 3; for (int y = Height; y > 0; --y) { *out = remap[*in]; out++, in++; } } return; } // Add a little extra space at the end if the texture's height is not // a power of 2, in case somebody accidentally makes it repeat vertically. int numpix = Width * Height + (1 << HeightBits) - Height; numspans = Width; Pixels = new BYTE[numpix]; memset (Pixels, 0, numpix); // Draw the image to the buffer for (x = 0; x < Width; ++x) { BYTE *outtop = Pixels + x*Height; const column_t *column = (const column_t *)((const BYTE *)patch + LittleLong(patch->columnofs[x])); int top = -1; while (column < maxcol && column->topdelta != 0xFF) { if (column->topdelta <= top) { top += column->topdelta; } else { top = column->topdelta; } int len = column->length; BYTE *out = outtop + top; if (len != 0) { if (top + len > Height) // Clip posts that extend past the bottom { len = Height - top; } if (len > 0) { numspans++; const BYTE *in = (const BYTE *)column + 3; for (int i = 0; i < len; ++i) { out[i] = remap[in[i]]; } } } column = (const column_t *)((const BYTE *)column + column->length + 4); } } }
void FTextureManager::InitAnimated (void) { const BITFIELD texflags = TEXMAN_Overridable; // I think better not! This is only for old ANIMATED definitions that // don't know about ZDoom's more flexible texture system. // | FTextureManager::TEXMAN_TryAny; int lumpnum = Wads.CheckNumForName ("ANIMATED"); if (lumpnum != -1) { FMemLump animatedlump = Wads.ReadLump (lumpnum); int animatedlen = Wads.LumpLength(lumpnum); const char *animdefs = (const char *)animatedlump.GetMem(); const char *anim_p; FTextureID pic1, pic2; int animtype; DWORD animspeed; // Init animation animtype = FAnimDef::ANIM_Forward; for (anim_p = animdefs; *anim_p != -1; anim_p += 23) { // make sure the current chunk of data is inside the lump boundaries. if (anim_p + 22 >= animdefs + animatedlen) { I_Error("Tried to read past end of ANIMATED lump."); } if (*anim_p /* .istexture */ & 1) { // different episode ? if (!(pic1 = CheckForTexture (anim_p + 10 /* .startname */, FTexture::TEX_Wall, texflags)).Exists() || !(pic2 = CheckForTexture (anim_p + 1 /* .endname */, FTexture::TEX_Wall, texflags)).Exists()) continue; // [RH] Bit 1 set means allow decals on walls with this texture Texture(pic2)->bNoDecals = Texture(pic1)->bNoDecals = !(*anim_p & 2); } else { if (!(pic1 = CheckForTexture (anim_p + 10 /* .startname */, FTexture::TEX_Flat, texflags)).Exists() || !(pic2 = CheckForTexture (anim_p + 1 /* .startname */, FTexture::TEX_Flat, texflags)).Exists()) continue; } FTexture *tex1 = Texture(pic1); FTexture *tex2 = Texture(pic2); animspeed = (BYTE(anim_p[19]) << 0) | (BYTE(anim_p[20]) << 8) | (BYTE(anim_p[21]) << 16) | (BYTE(anim_p[22]) << 24); // SMMU-style swirly hack? Don't apply on already-warping texture if (animspeed > 65535 && tex1 != NULL && !tex1->bWarped) { FTexture *warper = new FWarp2Texture (tex1); ReplaceTexture (pic1, warper, false); } // These tests were not really relevant for swirling textures, or even potentially // harmful, so they have been moved to the else block. else { if (tex1->UseType != tex2->UseType) { // not the same type - continue; } if (debuganimated) { Printf("Defining animation '%s' (texture %d, lump %d, file %d) to '%s' (texture %d, lump %d, file %d)\n", tex1->Name, pic1.GetIndex(), tex1->GetSourceLump(), Wads.GetLumpFile(tex1->GetSourceLump()), tex2->Name, pic2.GetIndex(), tex2->GetSourceLump(), Wads.GetLumpFile(tex2->GetSourceLump())); } if (pic1 == pic2) { // This animation only has one frame. Skip it. (Doom aborted instead.) Printf ("Animation %s in ANIMATED has only one frame\n", anim_p + 10); continue; } // [RH] Allow for backward animations as well as forward. else if (pic1 > pic2) { swapvalues (pic1, pic2); animtype = FAnimDef::ANIM_Backward; } // Speed is stored as tics, but we want ms so scale accordingly. AddSimpleAnim (pic1, pic2 - pic1 + 1, animtype, Scale (animspeed, 1000, 35)); } } } }
static void R_CreatePlayerTranslation (float h, float s, float v, const FPlayerColorSet *colorset, FPlayerSkin *skin, FRemapTable *table, FRemapTable *alttable, FRemapTable *pillartable) { int i; BYTE start = skin->range0start; BYTE end = skin->range0end; float r, g, b; float bases, basev; float sdelta, vdelta; float range; // Set up the base translation for this skin. If the skin was created // for the current game, then this is just an identity translation. // Otherwise, it remaps the colors from the skin's original palette to // the current one. if (skin->othergame) { memcpy (table->Remap, OtherGameSkinRemap, table->NumEntries); memcpy (table->Palette, OtherGameSkinPalette, sizeof(*table->Palette) * table->NumEntries); } else { for (i = 0; i < table->NumEntries; ++i) { table->Remap[i] = i; } memcpy(table->Palette, GPalette.BaseColors, sizeof(*table->Palette) * table->NumEntries); } for (i = 1; i < table->NumEntries; ++i) { table->Palette[i].a = 255; } // [GRB] Don't translate skins with color range 0-0 (APlayerPawn default) if (start == 0 && end == 0) { table->Inactive = true; table->UpdateNative(); return; } table->Inactive = false; range = (float)(end-start+1); bases = s; basev = v; if (colorset != NULL && colorset->Lump >= 0 && Wads.LumpLength(colorset->Lump) < 256) { // Bad table length. Ignore it. colorset = NULL; } if (colorset != NULL) { bool identity = true; // Use the pre-defined range instead of a custom one. if (colorset->Lump < 0) { identity &= SetRange(table, start, end, colorset->FirstColor, colorset->LastColor); for (i = 0; i < colorset->NumExtraRanges; ++i) { identity &= SetRange(table, colorset->Extra[i].RangeStart, colorset->Extra[i].RangeEnd, colorset->Extra[i].FirstColor, colorset->Extra[i].LastColor); } } else { FMemLump translump = Wads.ReadLump(colorset->Lump); const BYTE *trans = (const BYTE *)translump.GetMem(); for (i = start; i <= end; ++i) { table->Remap[i] = GPalette.Remap[trans[i]]; identity &= (trans[i] == i); table->Palette[i] = GPalette.BaseColors[table->Remap[i]]; table->Palette[i].a = 255; } } // If the colorset created an identity translation mark it as inactive table->Inactive = identity; } else if (gameinfo.gametype & GAME_DoomStrifeChex) { // Build player sprite translation s -= 0.23f; v += 0.1f; sdelta = 0.23f / range; vdelta = -0.94112f / range; for (i = start; i <= end; i++) { float uses, usev; uses = clamp (s, 0.f, 1.f); usev = clamp (v, 0.f, 1.f); HSVtoRGB (&r, &g, &b, h, uses, usev); SetRemap(table, i, r, g, b); s += sdelta; v += vdelta; } } else if (gameinfo.gametype == GAME_Heretic) { float vdelta = 0.418916f / range; // Build player sprite translation for (i = start; i <= end; i++) { v = vdelta * (float)(i - start) + basev - 0.2352937f; v = clamp (v, 0.f, 1.f); HSVtoRGB (&r, &g, &b, h, s, v); SetRemap(table, i, r, g, b); } // Build rain/lifegem translation if (alttable) { bases = MIN (bases*1.3f, 1.f); basev = MIN (basev*1.3f, 1.f); for (i = 145; i <= 168; i++) { s = MIN (bases, 0.8965f - 0.0962f*(float)(i - 161)); v = MIN (1.f, (0.2102f + 0.0489f*(float)(i - 144)) * basev); HSVtoRGB (&r, &g, &b, h, s, v); SetRemap(alttable, i, r, g, b); SetPillarRemap(pillartable, i, h, s, v); } alttable->UpdateNative(); } } else if (gameinfo.gametype == GAME_Hexen) { if (memcmp (sprites[skin->sprite].name, "PLAY", 4) == 0) { // The fighter is different! He gets a brown hairy loincloth, but the other // two have blue capes. float vs[9] = { .28f, .32f, .38f, .42f, .47f, .5f, .58f, .71f, .83f }; // Build player sprite translation //h = 45.f; v = MAX (0.1f, v); for (i = start; i <= end; i++) { HSVtoRGB (&r, &g, &b, h, s, vs[(i-start)*9/(int)range]*basev); SetRemap(table, i, r, g, b); } } else { float ms[18] = { .95f, .96f, .89f, .97f, .97f, 1.f, 1.f, 1.f, .97f, .99f, .87f, .77f, .69f, .62f, .57f, .47f, .43f }; float mv[18] = { .16f, .19f, .22f, .25f, .31f, .35f, .38f, .41f, .47f, .54f, .60f, .65f, .71f, .77f, .83f, .89f, .94f, 1.f }; // Build player sprite translation v = MAX (0.1f, v); for (i = start; i <= end; i++) { HSVtoRGB (&r, &g, &b, h, ms[(i-start)*18/(int)range]*bases, mv[(i-start)*18/(int)range]*basev); SetRemap(table, i, r, g, b); } } } if (gameinfo.gametype == GAME_Hexen && alttable != NULL) { // Build Hexen's lifegem translation. // Is the player's translation range the same as the gem's and we are using a // predefined translation? If so, then use the same one for the gem. Otherwise, // build one as per usual. if (colorset != NULL && start == 164 && end == 185) { *alttable = *table; } else { for (i = 164; i <= 185; ++i) { const PalEntry *base = &GPalette.BaseColors[i]; float dummy; RGBtoHSV (base->r/255.f, base->g/255.f, base->b/255.f, &dummy, &s, &v); HSVtoRGB (&r, &g, &b, h, s*bases, v*basev); SetRemap(alttable, i, r, g, b); } } alttable->UpdateNative(); } table->UpdateNative(); }
void FPatchTexture::MakeTexture () { BYTE *remap, remaptable[256]; Span *spanstuffer, *spanstarter; const column_t *maxcol; bool warned; int numspans; int x; FMemLump lump = Wads.ReadLump (SourceLump); const patch_t *patch = (const patch_t *)lump.GetMem(); maxcol = (const column_t *)((const BYTE *)patch + Wads.LumpLength (SourceLump) - 3); // Check for badly-sized patches if (LittleShort(patch->width) <= 0 || LittleShort(patch->height) <= 0) { lump = Wads.ReadLump ("-BADPATC"); patch = (const patch_t *)lump.GetMem(); Printf (PRINT_BOLD, "Patch %s has a non-positive size.\n", Name); } else if (LittleShort(patch->width) > 2048 || LittleShort(patch->height) > 2048) { lump = Wads.ReadLump ("-BADPATC"); patch = (const patch_t *)lump.GetMem(); Printf (PRINT_BOLD, "Patch %s is too big.\n", Name); } // Add a little extra space at the end if the texture's height is not // a power of 2, in case somebody accidentally makes it repeat vertically. int numpix = Width * Height + (1 << HeightBits) - Height; numspans = Width; Pixels = new BYTE[numpix]; memset (Pixels, 0, numpix); if (bNoRemap0) { memcpy (remaptable, GPalette.Remap, 256); remaptable[0] = 0; remap = remaptable; } else { remap = GPalette.Remap; } // Draw the image to the buffer for (x = 0; x < Width; ++x) { BYTE *outtop = Pixels + x*Height; const column_t *column = (const column_t *)((const BYTE *)patch + LittleLong(patch->columnofs[x])); int top = -1; while (column < maxcol && column->topdelta != 0xFF) { if (column->topdelta <= top) { top += column->topdelta; } else { top = column->topdelta; } int len = column->length; BYTE *out = outtop + top; if (len != 0) { if (top + len > Height) // Clip posts that extend past the bottom { len = Height - top; } if (len > 0) { numspans++; const BYTE *in = (const BYTE *)column + 3; for (int i = 0; i < len; ++i) { out[i] = remap[in[i]]; } } } column = (const column_t *)((const BYTE *)column + column->length + 4); } } // Create the spans if (Spans != NULL) { return; } Spans = (Span **)M_Malloc (sizeof(Span*)*Width + sizeof(Span)*numspans); spanstuffer = (Span *)((BYTE *)Spans + sizeof(Span*)*Width); warned = false; for (x = 0; x < Width; ++x) { const column_t *column = (const column_t *)((const BYTE *)patch + LittleLong(patch->columnofs[x])); int top = -1; Spans[x] = spanstuffer; spanstarter = spanstuffer; while (column < maxcol && column->topdelta != 0xFF) { if (column->topdelta <= top) { top += column->topdelta; } else { top = column->topdelta; } int len = column->length; if (len != 0) { if (top + len > Height) // Clip posts that extend past the bottom { len = Height - top; } if (len > 0) { // There is something of this post to draw. If it starts at the same // place where the previous span ends, add it to that one. If it starts // before the other one ends, that's bad, but deal with it. If it starts // after the previous one ends, create another span. // Assume we need to create another span. spanstuffer->TopOffset = top; spanstuffer->Length = len; // Now check if that's really the case. if (spanstuffer > spanstarter) { if ((spanstuffer - 1)->TopOffset + (spanstuffer - 1)->Length == top) { (--spanstuffer)->Length += len; } else { int prevbot; while (spanstuffer > spanstarter && spanstuffer->TopOffset < (prevbot = (spanstuffer - 1)->TopOffset + (spanstuffer - 1)->Length)) { if (spanstuffer->TopOffset < (spanstuffer - 1)->TopOffset) { (spanstuffer - 1)->TopOffset = spanstuffer->TopOffset; } (spanstuffer - 1)->Length = MAX(prevbot, spanstuffer->TopOffset + spanstuffer->Length) - (spanstuffer - 1)->TopOffset; spanstuffer--; if (!warned) { warned = true; Printf (PRINT_BOLD, "Patch %s is malformed.\n", Name); } } } } spanstuffer++; } } column = (const column_t *)((const BYTE *)column + column->length + 4); } spanstuffer->Length = spanstuffer->TopOffset = 0; spanstuffer++; } }
void DIntermissionScreen::Init(FIntermissionAction *desc, bool first) { int lumpnum; if (desc->mCdTrack == 0 || !S_ChangeCDMusic (desc->mCdTrack, desc->mCdId)) { if (desc->mMusic.IsEmpty()) { // only start the default music if this is the first action in an intermission if (first) S_ChangeMusic (gameinfo.finaleMusic, gameinfo.finaleOrder, desc->mMusicLooping); } else { S_ChangeMusic (desc->mMusic, desc->mMusicOrder, desc->mMusicLooping); } } mDuration = desc->mDuration; const char *texname = desc->mBackground; if (*texname == '@') { char *pp; unsigned int v = strtoul(texname+1, &pp, 10) - 1; if (*pp == 0 && v < gameinfo.finalePages.Size()) { texname = gameinfo.finalePages[v].GetChars(); } else if (gameinfo.finalePages.Size() > 0) { texname = gameinfo.finalePages[0].GetChars(); } else { texname = gameinfo.TitlePage.GetChars(); } } else if (*texname == '$') { texname = GStrings[texname+1]; } if (texname[0] != 0) { mBackground = TexMan.CheckForTexture(texname, FTexture::TEX_MiscPatch); mFlatfill = desc->mFlatfill; } S_Sound (CHAN_VOICE | CHAN_UI, desc->mSound, 1.0f, ATTN_NONE); if (desc->mPalette.IsNotEmpty() && (lumpnum = Wads.CheckNumForFullName(desc->mPalette, true)) > 0) { PalEntry *palette; const BYTE *orgpal; FMemLump lump; int i; lump = Wads.ReadLump (lumpnum); orgpal = (BYTE *)lump.GetMem(); palette = screen->GetPalette (); for (i = 256; i > 0; i--, orgpal += 3) { *palette++ = PalEntry (orgpal[0], orgpal[1], orgpal[2]); } screen->UpdatePalette (); mPaletteChanged = true; NoWipe = 1; M_EnableMenu(false); } mOverlays.Resize(desc->mOverlays.Size()); for (unsigned i=0; i < mOverlays.Size(); i++) { mOverlays[i].x = desc->mOverlays[i].x; mOverlays[i].y = desc->mOverlays[i].y; mOverlays[i].mCondition = desc->mOverlays[i].mCondition; mOverlays[i].mPic = TexMan.CheckForTexture(desc->mOverlays[i].mName, FTexture::TEX_MiscPatch); } mTicker = 0; }
void Language::ReadLump(int lump, const char* language) { FMemLump wadLump = Wads.ReadLump(lump); Scanner sc((const char*)(wadLump.GetMem()), wadLump.GetSize()); sc.SetScriptIdentifier(Wads.GetLumpFullName(lump)); int token = TK_NoToken; bool skip = false; bool noReplace = false; while(sc.GetNextToken()) { token = sc->token; if(token == '[') { // match with language sc.MustGetToken(TK_Identifier); if(sc->str.Compare(language) != 0) skip = true; else { skip = false; noReplace = false; } if(sc.CheckToken(TK_Identifier)) { if(sc->str.Compare("default") == 0) { // if not the correct language, go in no replace mode. if(skip) { skip = false; noReplace = true; } } else { printf("Unexpected identifier '%s'\n", sc->str.GetChars()); exit(0); } } sc.MustGetToken(']'); } else if(token == TK_Identifier) { FName index = sc->str; sc.MustGetToken('='); sc.MustGetToken(TK_StringConst); if(!skip) { if(!noReplace || (noReplace && strings.CheckKey(index) == NULL)) strings[index] = sc->str; } sc.MustGetToken(';'); } else { sc.ScriptMessage(Scanner::ERROR, "Unexpected token.\n"); exit(0); } } }