bool NetDemo::readMessageHeader(netdemo_message_t &type, uint32_t &len, uint32_t &tic) const { len = tic = 0; message_header_t msgheader; size_t cnt = 0; cnt += sizeof(msgheader.type) * fread(&msgheader.type, sizeof(msgheader.type), 1, demofp); cnt += sizeof(msgheader.length) * fread(&msgheader.length, sizeof(msgheader.length), 1, demofp); cnt += sizeof(msgheader.gametic) * fread(&msgheader.gametic, sizeof(msgheader.gametic), 1, demofp); if (cnt < NetDemo::MESSAGE_HEADER_SIZE) { return false; } // convert the values to native byte order len = LELONG(msgheader.length); tic = LELONG(msgheader.gametic); type = static_cast<netdemo_message_t>(msgheader.type); return true; }
bool NetDemo::readMapIndex() { fseek(demofp, header.map_index_offset, SEEK_SET); for (int i = 0; i < header.map_index_size; i++) { netdemo_index_entry_t entry; size_t cnt = 0; cnt += sizeof(entry.ticnum) * fread(&entry.ticnum, sizeof(entry.ticnum), 1, demofp); cnt += sizeof(entry.offset) * fread(&entry.offset, sizeof(entry.offset), 1, demofp); if (cnt < INDEX_ENTRY_SIZE) return false; // convert from little-endian to native entry.ticnum = LELONG(entry.ticnum); entry.offset = LELONG(entry.offset); map_index.push_back(entry); } return true; }
bool NetDemo::writeSnapshotIndex() { fseek(demofp, header.snapshot_index_offset, SEEK_SET); for (size_t i = 0; i < snapshot_index.size(); i++) { netdemo_index_entry_t entry; // convert to little-endian entry.ticnum = LELONG(snapshot_index[i].ticnum); entry.offset = LELONG(snapshot_index[i].offset); size_t cnt = 0; cnt += sizeof(entry.ticnum) * fwrite(&entry.ticnum, sizeof(entry.ticnum), 1, demofp); cnt += sizeof(entry.offset) * fwrite(&entry.offset, sizeof(entry.offset), 1, demofp); if (cnt < NetDemo::INDEX_ENTRY_SIZE) return false; } return true; }
// // R_ConvertPatch // // Converts a patch that uses post_t posts into a patch that uses tallpost_t. // void R_ConvertPatch(patch_t *newpatch, patch_t *rawpatch) { if (!rawpatch || !newpatch) return; memcpy(newpatch, rawpatch, 8); // copy the patch header unsigned *rawpostofs = (unsigned*)((byte*)rawpatch + 8); unsigned *newpostofs = (unsigned*)((byte*)newpatch + 8); unsigned curofs = 8 + 4 * rawpatch->width(); // keep track of the column offset for (int i = 0; i < rawpatch->width(); i++) { int abs_offset = 0; newpostofs[i] = LELONG(curofs); // write the new offset for this column post_t *rawpost = (post_t*)((byte*)rawpatch + LELONG(rawpostofs[i])); tallpost_t *newpost = (tallpost_t*)((byte*)newpatch + curofs); while (rawpost->topdelta != 0xFF) { // handle DeePsea tall patches where topdelta is treated as a relative // offset instead of an absolute offset if (rawpost->topdelta <= abs_offset) abs_offset += rawpost->topdelta; else abs_offset = rawpost->topdelta; // watch for column overruns int length = rawpost->length; if (abs_offset + length > rawpatch->height()) length = rawpatch->height() - abs_offset; // copy the pixels in the post memcpy(newpost->data(), (byte*)(rawpost) + 3, length); newpost->topdelta = abs_offset; newpost->length = length; curofs += newpost->length + 4; rawpost = (post_t*)((byte*)rawpost + rawpost->length + 4); newpost = newpost->next(); } newpost->writeend(); curofs += 2; } }
bool NetDemo::writeHeader() { strncpy(header.identifier, "ODAD", 4); header.version = NETDEMOVER; header.compression = 0; header.snapshot_spacing = NetDemo::SNAPSHOT_SPACING; netdemo_header_t tmpheader; memcpy(&tmpheader, &header, sizeof(header)); // convert from native byte ordering to little-endian tmpheader.snapshot_index_size = LESHORT(tmpheader.snapshot_index_size); tmpheader.snapshot_index_offset = LELONG(tmpheader.snapshot_index_offset); tmpheader.map_index_size = LESHORT(tmpheader.map_index_size); tmpheader.map_index_offset = LELONG(tmpheader.map_index_offset); tmpheader.snapshot_spacing = LESHORT(tmpheader.snapshot_spacing); tmpheader.starting_gametic = LELONG(tmpheader.starting_gametic); tmpheader.ending_gametic = LELONG(tmpheader.ending_gametic); fseek(demofp, 0, SEEK_SET); size_t cnt = 0; cnt += sizeof(tmpheader.identifier) * fwrite(&tmpheader.identifier, sizeof(tmpheader.identifier), 1, demofp); cnt += sizeof(tmpheader.version) * fwrite(&tmpheader.version, sizeof(tmpheader.version), 1, demofp); cnt += sizeof(tmpheader.compression) * fwrite(&tmpheader.compression, sizeof(tmpheader.compression), 1, demofp); cnt += sizeof(tmpheader.snapshot_index_size) * fwrite(&tmpheader.snapshot_index_size, sizeof(tmpheader.snapshot_index_size), 1, demofp); cnt += sizeof(tmpheader.snapshot_index_offset)* fwrite(&tmpheader.snapshot_index_offset, sizeof(tmpheader.snapshot_index_offset), 1, demofp); cnt += sizeof(tmpheader.map_index_size) * fwrite(&tmpheader.map_index_size, sizeof(tmpheader.map_index_size), 1, demofp); cnt += sizeof(tmpheader.map_index_offset)* fwrite(&tmpheader.map_index_offset, sizeof(tmpheader.map_index_offset), 1, demofp); cnt += sizeof(tmpheader.snapshot_spacing) * fwrite(&tmpheader.snapshot_spacing, sizeof(tmpheader.snapshot_spacing), 1, demofp); cnt += sizeof(tmpheader.starting_gametic) * fwrite(&tmpheader.starting_gametic, sizeof(tmpheader.starting_gametic), 1, demofp); cnt += sizeof(tmpheader.ending_gametic) * fwrite(&tmpheader.ending_gametic, sizeof(tmpheader.ending_gametic), 1, demofp); cnt += sizeof(tmpheader.reserved) * fwrite(&tmpheader.reserved, sizeof(tmpheader.reserved), 1, demofp); if (cnt < NetDemo::HEADER_SIZE) return false; return true; }
int FStringTable::LoadLanguage (DWORD code, bool exactMatch, BYTE *start, BYTE *end) { const DWORD orMask = exactMatch ? 0 : MAKE_ID(0,0,0xff,0); int count = 0; code |= orMask; while (start < end) { const DWORD langLen = LELONG(*(DWORD *)&start[4]); if (((*(DWORD *)start) | orMask) == code) { start[3] = 1; const BYTE *probe = start + 8; while (probe < start + langLen) { int index = probe[0] | (probe[1]<<8); if (Strings[index] == NULL) { Strings[index] = copystring ((const char *)(probe + 2)); ++count; } probe += 3 + strlen ((const char *)(probe + 2)); } } start += langLen + 8; start += (4 - (ptrdiff_t)start) & 3; } return count; }
// // TextureManager::readPNamesDirectory // void TextureManager::readPNamesDirectory() { int lumpnum = W_GetNumForName("PNAMES"); size_t lumplen = W_LumpLength(lumpnum); byte* lumpdata = new byte[lumplen]; W_ReadLump(lumpnum, lumpdata); int num_pname_mappings = LELONG(*((int*)(lumpdata + 0))); mPNameLookup = new int[num_pname_mappings]; for (int i = 0; i < num_pname_mappings; i++) { const char* lumpname = (const char*)(lumpdata + 4 + 8 * i); mPNameLookup[i] = W_CheckNumForName(lumpname); // 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. if (mPNameLookup[i] == -1) mPNameLookup[i] = W_CheckNumForName(lumpname, ns_sprites); } delete [] lumpdata; }
void FStringTable::DoneLoading (BYTE *start, BYTE *end) { while (start < end) { start[3] = 0; start += LELONG(*(DWORD *)&start[4]) + 8; start += (4 - (ptrdiff_t)start) & 3; } }
// // TextureManager::readAnimatedLump // // Reads animation definitions from the ANIMATED lump. // // Load the table of animation definitions, checking for existence of // the start and end of each frame. If the start doesn't exist the sequence // is skipped, if the last doesn't exist, BOOM exits. // // Wall/Flat animation sequences, defined by name of first and last frame, // The full animation sequence is given using all lumps between the start // and end entry, in the order found in the WAD file. // // This routine modified to read its data from a predefined lump or // PWAD lump called ANIMATED rather than a static table in this module to // allow wad designers to insert or modify animation sequences. // // Lump format is an array of byte packed animdef_t structures, terminated // by a structure with istexture == -1. The lump can be generated from a // text source file using SWANTBLS.EXE, distributed with the BOOM utils. // The standard list of switches and animations is contained in the example // source text file DEFSWANI.DAT also in the BOOM util distribution. // // [RH] Rewritten to support BOOM ANIMATED lump but also make absolutely // no assumptions about how the compiler packs the animdefs array. // void TextureManager::readAnimatedLump() { int lumpnum = W_CheckNumForName("ANIMATED"); if (lumpnum == -1) return; size_t lumplen = W_LumpLength(lumpnum); if (lumplen == 0) return; byte* lumpdata = new byte[lumplen]; W_ReadLump(lumpnum, lumpdata); for (byte* ptr = lumpdata; *ptr != 255; ptr += 23) { anim_t anim; Texture::TextureSourceType texture_type = *(ptr + 0) == 1 ? Texture::TEX_WALLTEXTURE : Texture::TEX_FLAT; const char* startname = (const char*)(ptr + 10); const char* endname = (const char*)(ptr + 1); texhandle_t start_texhandle = texturemanager.getHandle(startname, texture_type); texhandle_t end_texhandle = texturemanager.getHandle(endname, texture_type); if (start_texhandle == TextureManager::NOT_FOUND_TEXTURE_HANDLE || start_texhandle == TextureManager::NO_TEXTURE_HANDLE || end_texhandle == TextureManager::NOT_FOUND_TEXTURE_HANDLE || end_texhandle == TextureManager::NO_TEXTURE_HANDLE) continue; anim.basepic = start_texhandle; anim.numframes = end_texhandle - start_texhandle + 1; if (anim.numframes <= 0) continue; anim.curframe = 0; int speed = LELONG(*(int*)(ptr + 19)); anim.countdown = speed - 1; for (int i = 0; i < anim.numframes; i++) { anim.framepic[i] = anim.basepic + i; anim.speedmin[i] = anim.speedmax[i] = speed; } mAnimDefs.push_back(anim); } delete [] lumpdata; }
bool NetDemo::readHeader() { fseek(demofp, 0, SEEK_SET); size_t cnt = 0; cnt += sizeof(header.identifier) * fread(&header.identifier, sizeof(header.identifier), 1, demofp); cnt += sizeof(header.version) * fread(&header.version, sizeof(header.version), 1, demofp); cnt += sizeof(header.compression) * fread(&header.compression, sizeof(header.compression), 1, demofp); cnt += sizeof(header.snapshot_index_size) * fread(&header.snapshot_index_size, sizeof(header.snapshot_index_size), 1, demofp); cnt += sizeof(header.snapshot_index_offset)* fread(&header.snapshot_index_offset, sizeof(header.snapshot_index_offset), 1, demofp); cnt += sizeof(header.map_index_size) * fread(&header.map_index_size, sizeof(header.map_index_size), 1, demofp); cnt += sizeof(header.map_index_offset)* fread(&header.map_index_offset, sizeof(header.map_index_offset), 1, demofp); cnt += sizeof(header.snapshot_spacing) * fread(&header.snapshot_spacing, sizeof(header.snapshot_spacing), 1, demofp); cnt += sizeof(header.starting_gametic) * fread(&header.starting_gametic, sizeof(header.starting_gametic), 1, demofp); cnt += sizeof(header.ending_gametic) * fread(&header.ending_gametic, sizeof(header.ending_gametic), 1, demofp); cnt += sizeof(header.reserved) * fread(&header.reserved, sizeof(header.reserved), 1, demofp); if (cnt < NetDemo::HEADER_SIZE) return false; // convert from little-endian to native byte ordering header.snapshot_index_size = LESHORT(header.snapshot_index_size); header.snapshot_index_offset = LELONG(header.snapshot_index_offset); header.map_index_size = LESHORT(header.map_index_size); header.map_index_offset = LELONG(header.map_index_offset); header.snapshot_spacing = LESHORT(header.snapshot_spacing); header.starting_gametic = LELONG(header.starting_gametic); header.ending_gametic = LELONG(header.ending_gametic); return true; }
void NetDemo::writeChunk(const byte *data, size_t size, netdemo_message_t type) { message_header_t msgheader; memset(&msgheader, 0, sizeof(msgheader)); msgheader.type = static_cast<byte>(type); msgheader.length = LELONG((uint32_t)size); msgheader.gametic = LELONG(gametic); size_t cnt = 0; cnt += sizeof(msgheader.type) * fwrite(&msgheader.type, sizeof(msgheader.type), 1, demofp); cnt += sizeof(msgheader.length) * fwrite(&msgheader.length, sizeof(msgheader.length), 1, demofp); cnt += sizeof(msgheader.gametic) * fwrite(&msgheader.gametic, sizeof(msgheader.gametic), 1, demofp); cnt += fwrite(data, 1, size, demofp); if (cnt < size + NetDemo::MESSAGE_HEADER_SIZE) { error("Unable to write netdemo message chunk\n"); return; } }
// // R_DrawPatchIntoTexture // // Draws a lump in patch_t format into a Texture at the given offset. // static void R_DrawPatchIntoTexture(Texture* texture, const byte* lumpdata, int xoffs, int yoffs) { int texwidth = texture->getWidth(); int texheight = texture->getHeight(); int patchwidth = LESHORT(*(short*)(lumpdata + 0)); const int* colofs = (int*)(lumpdata + 8); int x1 = MAX(xoffs, 0); int x2 = MIN(xoffs + patchwidth - 1, texwidth - 1); for (int x = x1; x <= x2; x++) { int abstopdelta = 0; const byte* post = lumpdata + LELONG(colofs[x - xoffs]); while (*post != 0xFF) { int posttopdelta = *(post + 0); int postlength = *(post + 1); // handle DeePsea tall patches where topdelta is treated as a relative // offset instead of an absolute offset if (posttopdelta <= abstopdelta) abstopdelta += posttopdelta; else abstopdelta = posttopdelta; int topoffset = yoffs + abstopdelta; int y1 = MAX(topoffset, 0); int y2 = MIN(topoffset + postlength - 1, texheight - 1); if (y1 <= y2) { byte* dest = texture->getData() + texheight * x + y1; const byte* source = post + 3; memcpy(dest, source, y2 - y1 + 1); // set up the mask byte* mask = texture->getMaskData() + texheight * x + y1; memset(mask, 1, y2 - y1 + 1); } post += postlength + 4; } } }
// // R_CalculateNewPatchSize // // Helper function for converting raw patches that use post_t into patches // that use tallpost_t. Returns the lump size of the converted patch. // size_t R_CalculateNewPatchSize(patch_t *patch, size_t length) { if (!patch) return 0; // sanity check to see if the postofs array fits in the patch lump if (length < patch->width() * sizeof(unsigned int)) return 0; int numposts = 0, numpixels = 0; unsigned int *postofs = (unsigned int *)((byte*)patch + 8); for (int i = 0; i < patch->width(); i++) { size_t ofs = LELONG(postofs[i]); // check that the offset is valid if (ofs >= length) return 0; post_t *post = (post_t*)((byte*)patch + ofs); while (post->topdelta != 0xFF) { if (ofs + post->length >= length) return 0; // patch is corrupt numposts++; numpixels += post->length; post = (post_t*)((byte*)post + post->length + 4); } } // 8 byte patch header // 4 * width bytes for column offset table // 4 bytes per post for post header // 1 byte per pixel // 2 bytes per column for termination return 8 + 4 * patch->width() + 4 * numposts + numpixels + 2 * patch->width(); }
// // R_InitTextures // Initializes the texture list // with the textures from the world map. // void R_InitTextures (void) { maptexture_t* mtexture; texture_t* texture; mappatch_t* mpatch; texpatch_t* patch; int i; int j; int* maptex; int* maptex2; int* maptex1; int* patchlookup; int totalwidth; int nummappatches; int offset; int maxoff; int maxoff2; int numtextures1; int numtextures2; int* directory; int errors = 0; // Load the patch names from pnames.lmp. { char *names = (char *)W_CacheLumpName ("PNAMES", PU_STATIC); char *name_p = names+4; nummappatches = LELONG ( *((int *)names) ); patchlookup = new int[nummappatches]; for (i = 0; i < nummappatches; i++) { patchlookup[i] = W_CheckNumForName (name_p + i*8); 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_p + i*8, ns_sprites); } } Z_Free (names); } // 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 = (int *)W_CacheLumpName ("TEXTURE1", PU_STATIC); numtextures1 = LELONG(*maptex); maxoff = W_LumpLength (W_GetNumForName ("TEXTURE1")); directory = maptex+1; if (W_CheckNumForName ("TEXTURE2") != -1) { maptex2 = (int *)W_CacheLumpName ("TEXTURE2", PU_STATIC); numtextures2 = LELONG(*maptex2); maxoff2 = W_LumpLength (W_GetNumForName ("TEXTURE2")); } else { maptex2 = NULL; numtextures2 = 0; maxoff2 = 0; } // denis - fix memory leaks for (i = 0; i < numtextures; i++) { delete[] texturecolumnlump[i]; delete[] texturecolumnofs[i]; } // denis - fix memory leaks delete[] textures; delete[] texturecolumnlump; delete[] texturecolumnofs; delete[] texturecomposite; delete[] texturecompositesize; delete[] texturewidthmask; delete[] textureheight; delete[] texturescalex; delete[] texturescaley; numtextures = numtextures1 + numtextures2; textures = new texture_t *[numtextures]; texturecolumnlump = new short *[numtextures]; texturecolumnofs = new unsigned int *[numtextures]; texturecomposite = new byte *[numtextures]; texturecompositesize = new int[numtextures]; texturewidthmask = new int[numtextures]; textureheight = new fixed_t[numtextures]; texturescalex = new fixed_t[numtextures]; texturescaley = new fixed_t[numtextures]; totalwidth = 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 = LELONG(*directory); if (offset > maxoff) I_FatalError ("R_InitTextures: bad texture directory"); mtexture = (maptexture_t *) ( (byte *)maptex + offset); texture = textures[i] = (texture_t *) Z_Malloc (sizeof(texture_t) + sizeof(texpatch_t)*(SAFESHORT(mtexture->patchcount)-1), PU_STATIC, 0); texture->width = SAFESHORT(mtexture->width); texture->height = SAFESHORT(mtexture->height); texture->patchcount = SAFESHORT(mtexture->patchcount); strncpy (texture->name, mtexture->name, 9); // denis - todo string limit? std::transform(texture->name, texture->name + strlen(texture->name), texture->name, toupper); mpatch = &mtexture->patches[0]; patch = &texture->patches[0]; for (j=0 ; j<texture->patchcount ; j++, mpatch++, patch++) { patch->originx = LESHORT(mpatch->originx); patch->originy = LESHORT(mpatch->originy); patch->patch = patchlookup[LESHORT(mpatch->patch)]; if (patch->patch == -1) { Printf (PRINT_HIGH, "R_InitTextures: Missing patch in texture %s\n", texture->name); errors++; } } texturecolumnlump[i] = new short[texture->width]; texturecolumnofs[i] = new unsigned int[texture->width]; for (j = 1; j*2 <= texture->width; j <<= 1) ; texturewidthmask[i] = j-1; textureheight[i] = texture->height << FRACBITS; // [RH] Special for beta 29: Values of 0 will use the tx/ty cvars // to determine scaling instead of defaulting to 8. I will likely // remove this once I finish the betas, because by then, users // should be able to actually create scaled textures. texturescalex[i] = mtexture->scalex ? mtexture->scalex << (FRACBITS - 3) : FRACUNIT; texturescaley[i] = mtexture->scaley ? mtexture->scaley << (FRACBITS - 3) : FRACUNIT; totalwidth += texture->width; } delete[] patchlookup; Z_Free (maptex1); if (maptex2) Z_Free (maptex2); if (errors) I_FatalError ("%d errors in R_InitTextures.", errors); // [RH] Setup hash chains. Go from back to front so that if // duplicates are found, the first one gets used instead // of the last (thus mimicing the original behavior // of R_CheckTextureNumForName(). for (i = 0; i < numtextures; i++) textures[i]->index = -1; for (i = numtextures - 1; i >= 0; i--) { j = 0; //W_LumpNameHash (textures[i]->name) % (unsigned) numtextures; textures[i]->next = textures[j]->index; textures[j]->index = i; } if (clientside) // server doesn't need to load patches ever { // Precalculate whatever possible. for (i = 0; i < numtextures; i++) R_GenerateLookup (i, &errors); } // if (errors) // I_FatalError ("%d errors encountered during texture generation.", errors); // Create translation table for global animation. delete[] texturetranslation; texturetranslation = new int[numtextures+1]; for (i = 0; i < numtextures; i++) texturetranslation[i] = i; }
// // W_AddFile // // All files are optional, but at least one file must be found // (PWAD, if all required lumps are present). // Files with a .wad extension are wadlink files with multiple lumps. // Other files are single lumps with the base filename for the lump name. // // Map reloads are supported through WAD reload so no need for vanilla tilde // reload hack here // std::string W_AddFile(std::string filename) { FILE* handle; filelump_t* fileinfo; FixPathSeparator(filename); if ( (handle = fopen(filename.c_str(), "rb")) == NULL) { Printf(PRINT_HIGH, "couldn't open %s\n", filename.c_str()); return ""; } Printf(PRINT_HIGH, "adding %s", filename.c_str()); size_t newlumps; wadinfo_t header; fread(&header, sizeof(header), 1, handle); header.identification = LELONG(header.identification); if (header.identification != IWAD_ID && header.identification != PWAD_ID) { // raw lump file std::string lumpname; M_ExtractFileBase(filename, lumpname); fileinfo = new filelump_t[1]; fileinfo->filepos = 0; fileinfo->size = M_FileLength(handle); std::transform(lumpname.c_str(), lumpname.c_str() + 8, fileinfo->name, toupper); newlumps = 1; Printf(PRINT_HIGH, " (single lump)\n"); } else { // WAD file header.numlumps = LELONG(header.numlumps); header.infotableofs = LELONG(header.infotableofs); size_t length = header.numlumps * sizeof(filelump_t); if (length > (unsigned)M_FileLength(handle)) { Printf(PRINT_HIGH, "\nbad number of lumps for %s\n", filename.c_str()); fclose(handle); return ""; } fileinfo = new filelump_t[header.numlumps]; fseek(handle, header.infotableofs, SEEK_SET); fread(fileinfo, length, 1, handle); // convert from little-endian to target arch and capitalize lump name for (int i = 0; i < header.numlumps; i++) { fileinfo[i].filepos = LELONG(fileinfo[i].filepos); fileinfo[i].size = LELONG(fileinfo[i].size); std::transform(fileinfo[i].name, fileinfo[i].name + 8, fileinfo[i].name, toupper); } newlumps = header.numlumps; Printf(PRINT_HIGH, " (%d lumps)\n", header.numlumps); } W_AddLumps(handle, fileinfo, newlumps, false); delete [] fileinfo; return W_MD5(filename); }
static void R_GenerateLookup(int texnum, int *const errors) { const texture_t *texture = textures[texnum]; // Composited texture not created yet. short *collump = texturecolumnlump[texnum]; // killough 4/9/98: keep count of posts in addition to patches. // Part of fix for medusa bug for multipatched 2s normals. unsigned short *patchcount = new unsigned short[texture->width]; unsigned short *postcount = new unsigned short[texture->width]; memset(patchcount, 0, sizeof(unsigned short) * texture->width); memset(postcount, 0, sizeof(unsigned short) * texture->width); const texpatch_t *texpatch = texture->patches; for (int i = 0; i < texture->patchcount; i++) { const int patchnum = texpatch->patch; const patch_t *patch = W_CachePatch(patchnum); int x1 = texpatch++->originx, x2 = x1 + patch->width(), x = x1; const int *cofs = patch->columnofs-x1; if (x2 > texture->width) x2 = texture->width; if (x1 < 0) x = 0; for (; x < x2; x++) { // killough 4/9/98: keep a count of the number of posts in column, // to fix Medusa bug while allowing for transparent multipatches. const tallpost_t *post = (tallpost_t*)((byte*)patch + LELONG(cofs[x])); // NOTE: this offset will be rewritten later if a composite is generated // for this texture (eg, there's more than one patch) texturecolumnofs[texnum][x] = (byte *)post - (byte *)patch; patchcount[x]++; collump[x] = patchnum; while (!post->end()) { postcount[x]++; post = post->next(); } } } // Now count the number of columns that are covered by more than one patch. // Fill in the lump / offset, so columns with only a single patch are all done. texturecomposite[texnum] = 0; int csize = 0; // [RH] Always create a composite texture for multipatch textures // or tall textures in order to keep things simpler. bool needcomposite = (texture->patchcount > 1 || texture->height > 254); // [SL] Check for columns without patches. // If a texture has columns without patches, generate a composite for // the texture, which will create empty posts and prevent crashes. for (int x = 0; x < texture->width && !needcomposite; x++) { if (patchcount[x] == 0) needcomposite = true; } if (needcomposite) { int x = texture->width; while (--x >= 0) { // killough 1/25/98, 4/9/98: // // Fix Medusa bug, by adding room for column header // and trailer bytes for each post in merged column. // For now, just allocate conservatively 4 bytes // per post per patch per column, since we don't // yet know how many posts the merged column will // require, and it's bounded above by this limit. collump[x] = -1; // mark lump as multipatched texturecolumnofs[texnum][x] = csize; // 4 header bytes per post + column height + 2 byte terminator csize += 4 * postcount[x] + 2 + texture->height; } } texturecompositesize[texnum] = csize; delete [] patchcount; delete [] postcount; }
// // R_GetPatchColumn // tallpost_t* R_GetPatchColumn(int lumpnum, int colnum) { patch_t* patch = W_CachePatch(lumpnum, PU_CACHE); return (tallpost_t*)((byte*)patch + LELONG(patch->columnofs[colnum])); }
// // TextureManager::addTextureDirectory // // Requires that the PNAMES lump has been read and processed. // void TextureManager::addTextureDirectory(const char* lumpname) { // // Texture definition. // Each texture is composed of one or more patches, // with patches being lumps stored in the WAD. // The lumps are referenced by number, and patched // into the rectangular texture space using origin // and possibly other attributes. // struct mappatch_t { short originx; short originy; short patch; short stepdir; short colormap; }; // // Texture definition. // A DOOM wall texture is a list of patches // which are to be combined in a predefined order. // struct maptexture_t { char name[8]; WORD masked; // [RH] Unused BYTE scalex; // [RH] Scaling (8 is normal) BYTE scaley; // [RH] Same as above short width; short height; byte columndirectory[4]; // OBSOLETE short patchcount; mappatch_t patches[1]; }; int lumpnum = W_CheckNumForName(lumpname); if (lumpnum == -1) { if (iequals("TEXTURE1", lumpname)) I_Error("R_InitTextures: TEXTURE1 lump not found"); return; } size_t lumplen = W_LumpLength(lumpnum); if (lumplen == 0) return; byte* lumpdata = new byte[lumplen]; W_ReadLump(lumpnum, lumpdata); int* texoffs = (int*)(lumpdata + 4); // keep track of the number of texture errors int errors = 0; int count = LELONG(*((int*)(lumpdata + 0))); for (int i = 0; i < count; i++) { maptexture_t* mtexdef = (maptexture_t*)((byte*)lumpdata + LELONG(texoffs[i])); size_t texdefsize = sizeof(texdef_t) + sizeof(texdefpatch_t) * (SAFESHORT(mtexdef->patchcount) - 1); texdef_t* texdef = (texdef_t*)(new byte[texdefsize]); texdef->width = SAFESHORT(mtexdef->width); texdef->height = SAFESHORT(mtexdef->height); texdef->patchcount = SAFESHORT(mtexdef->patchcount); texdef->scalex = mtexdef->scalex; texdef->scaley = mtexdef->scaley; char uname[9]; for (int c = 0; c < 8; c++) uname[c] = toupper(mtexdef->name[c]); uname[8] = 0; mappatch_t* mpatch = &mtexdef->patches[0]; texdefpatch_t* patch = &texdef->patches[0]; for (int j = 0; j < texdef->patchcount; j++, mpatch++, patch++) { patch->originx = LESHORT(mpatch->originx); patch->originy = LESHORT(mpatch->originy); patch->patch = mPNameLookup[LESHORT(mpatch->patch)]; if (patch->patch == -1) { Printf(PRINT_HIGH, "R_InitTextures: Missing patch in texture %s\n", uname); errors++; } } mTextureDefinitions.push_back(texdef); mTextureNameTranslationMap[uname] = mTextureDefinitions.size() - 1; } delete [] lumpdata; }
void R_GenerateComposite (int texnum) { byte *block = (byte *)Z_Malloc (texturecompositesize[texnum], PU_STATIC, (void **) &texturecomposite[texnum]); texture_t *texture = textures[texnum]; // Composite the columns together. texpatch_t *texpatch = texture->patches; short *collump = texturecolumnlump[texnum]; // killough 4/9/98: marks to identify transparent regions in merged textures byte *marks = new byte[texture->width * texture->height]; memset(marks, 0, texture->width * texture->height); for (int i = texture->patchcount; --i >=0; texpatch++) { patch_t *patch = W_CachePatch(texpatch->patch); int x1 = texpatch->originx, x2 = x1 + patch->width(); const int *cofs = patch->columnofs-x1; if (x1<0) x1 = 0; if (x2 > texture->width) x2 = texture->width; for (; x1 < x2 ; x1++) { if (collump[x1] == -1) // Column has multiple patches? { // killough 1/25/98, 4/9/98: Fix medusa bug. tallpost_t *srcpost = (tallpost_t*)((byte*)patch + LELONG(cofs[x1])); tallpost_t *destpost = (tallpost_t*)(block + texturecolumnofs[texnum][x1]); R_DrawColumnInCache(srcpost, destpost->data(), texpatch->originy, texture->height, marks + x1 * texture->height); } } } // killough 4/9/98: Next, convert multipatched columns into true columns, // to fix Medusa bug while still allowing for transparent regions. byte *tmpdata = new byte[texture->height]; // temporary post data for (int i = 0; i < texture->width; i++) { if (collump[i] != -1) // process only multipatched columns continue; tallpost_t *post = (tallpost_t *)(block + texturecolumnofs[texnum][i]); const byte *mark = marks + i * texture->height; int j = 0; // save column in temporary so we can shuffle it around memcpy(tmpdata, post->data(), texture->height); // reconstruct the column by scanning transparency marks while (true) { while (j < texture->height && !mark[j]) // skip transparent pixels j++; if (j >= texture->height) // if at end of column { post->writeend(); // end-of-column marker break; } post->topdelta = j; // starting offset of post // count opaque pixels for (post->length = 0; j < texture->height && mark[j]; j++) post->length++; // copy opaque pixels from the temporary back into the column memcpy(post->data(), tmpdata + post->topdelta, post->length); post = post->next(); } } delete [] marks; delete [] tmpdata; // Now that the texture has been built in column cache, // it is purgable from zone memory. Z_ChangeTag(block, PU_CACHE); }
std::string W_AddFile (std::string filename) { wadinfo_t header; lumpinfo_t* lump_p; size_t i; FILE *handle; size_t length; size_t startlump; size_t res; filelump_t* fileinfo; filelump_t singleinfo; FixPathSeparator (filename); std::string name = filename; M_AppendExtension (name, ".wad"); // open the file if ( (handle = fopen (filename.c_str(), "rb")) == NULL) { Printf (PRINT_HIGH, " couldn't open %s\n", filename.c_str()); return ""; } Printf (PRINT_HIGH, "adding %s\n", filename.c_str()); startlump = numlumps; res = fread (&header, sizeof(header), 1, handle); header.identification = LELONG(header.identification); if (header.identification != IWAD_ID && header.identification != PWAD_ID) { // raw lump file fileinfo = &singleinfo; singleinfo.filepos = 0; singleinfo.size = M_FileLength(handle); M_ExtractFileBase (filename, name); numlumps++; Printf (PRINT_HIGH, " (single lump)\n", header.numlumps); } else { // WAD file header.numlumps = LELONG(header.numlumps); header.infotableofs = LELONG(header.infotableofs); length = header.numlumps*sizeof(filelump_t); if(length > (unsigned)M_FileLength(handle)) { Printf (PRINT_HIGH, " bad number of lumps for %s\n", filename.c_str()); fclose(handle); return ""; } fileinfo = (filelump_t *)Z_Malloc (length, PU_STATIC, 0); fseek (handle, header.infotableofs, SEEK_SET); res = fread (fileinfo, length, 1, handle); numlumps += header.numlumps; Printf (PRINT_HIGH, " (%d lumps)\n", header.numlumps); } // Fill in lumpinfo lumpinfo = (lumpinfo_t *)Realloc (lumpinfo, numlumps*sizeof(lumpinfo_t)); if (!lumpinfo) I_Error ("Couldn't realloc lumpinfo"); lump_p = &lumpinfo[startlump]; for (i=startlump ; i<numlumps ; i++,lump_p++, fileinfo++) { lump_p->handle = handle; lump_p->position = LELONG(fileinfo->filepos); lump_p->size = LELONG(fileinfo->size); strncpy (lump_p->name, fileinfo->name, 8); // W_CheckNumForName needs all lump names in upper case std::transform(lump_p->name, lump_p->name+8, lump_p->name, toupper); } return W_MD5(filename); }
void FStringTable::LoadStrings (int lump, int expectedSize, bool enuOnly) { BYTE *strData = (BYTE *)W_CacheLumpNum (lump, PU_CACHE); int lumpLen = LELONG(((Header *)strData)->FileSize); int nameCount = LESHORT(((Header *)strData)->NameCount); int nameLen = LESHORT(((Header *)strData)->NameLen); int languageStart = sizeof(Header) + nameCount*4 + nameLen; languageStart += (4 - languageStart) & 3; if (expectedSize >= 0 && nameCount != expectedSize) { char name[9]; W_GetLumpName (name, lump); name[8] = 0; I_FatalError ("%s had %d strings.\nThis version of ZDoom expects it to have %d.", name, nameCount, expectedSize); } FreeStandardStrings (); NumStrings = nameCount; LumpNum = lump; if (Strings == NULL) { Strings = new char *[nameCount]; StringStatus = new BYTE[(nameCount+7)/8]; memset (StringStatus, 0, (nameCount+7)/8); // 0 means: from wad (standard) memset (Strings, 0, sizeof(char *)*nameCount); } BYTE *const start = strData + languageStart; BYTE *const end = strData + lumpLen; int loadedCount, i; for (loadedCount = i = 0; i < NumStrings; ++i) { if (Strings[i] != NULL) { ++loadedCount; } } if (!enuOnly) { for (i = 0; i < 4 && loadedCount != nameCount; ++i) { loadedCount += LoadLanguage (LanguageIDs[i], true, start, end); loadedCount += LoadLanguage (LanguageIDs[i] & MAKE_ID(0xff,0xff,0,0), true, start, end); loadedCount += LoadLanguage (LanguageIDs[i], false, start, end); } } // Fill in any missing strings with the default language (enu) if (loadedCount != nameCount) { loadedCount += LoadLanguage (MAKE_ID('e','n','u',0), true, start, end); } DoneLoading (start, end); if (loadedCount != nameCount) { I_FatalError ("Loaded %d strings (expected %d)", loadedCount, nameCount); } }
void R_GenerateComposite (int texnum) { byte *block = (byte *)Z_Malloc (texturecompositesize[texnum], PU_STATIC, (void **) &texturecomposite[texnum]); texture_t *texture = textures[texnum]; // Composite the columns together. texpatch_t *patch = texture->patches; short *collump = texturecolumnlump[texnum]; unsigned *colofs = texturecolumnofs[texnum]; // killough 4/9/98: make 32-bit int i = texture->patchcount; // killough 4/9/98: marks to identify transparent regions in merged textures byte *marks = (byte *)Calloc (texture->width, texture->height), *source; for (; --i >=0; patch++) { patch_t *realpatch = W_CachePatch (patch->patch); int x1 = patch->originx, x2 = x1 + realpatch->width(); const int *cofs = realpatch->columnofs-x1; if (x1<0) x1 = 0; if (x2 > texture->width) x2 = texture->width; for (; x1<x2 ; x1++) if (collump[x1] == -1) // Column has multiple patches? // killough 1/25/98, 4/9/98: Fix medusa bug. R_DrawColumnInCache((column_t*)((byte*)realpatch+LELONG(cofs[x1])), block+colofs[x1],patch->originy,texture->height, marks + x1 * texture->height); } // killough 4/9/98: Next, convert multipatched columns into true columns, // to fix Medusa bug while still allowing for transparent regions. source = (byte *)Malloc (texture->height); // temporary column for (i=0; i < texture->width; i++) if (collump[i] == -1) // process only multipatched columns { column_t *col = (column_t *)(block + colofs[i] - 3); // cached column const byte *mark = marks + i * texture->height; int j = 0; // save column in temporary so we can shuffle it around memcpy(source, (byte *) col + 3, texture->height); for (;;) // reconstruct the column by scanning transparency marks { while (j < texture->height && !mark[j]) // skip transparent cells j++; if (j >= texture->height) // if at end of column { col->topdelta = 255; // end-of-column marker break; } col->topdelta = j; // starting offset of post for (col->length=0; j < texture->height && mark[j]; j++) col->length++; // count opaque cells // copy opaque cells from the temporary back into the column memcpy((byte *) col + 3, source + col->topdelta, col->length); col = (column_t *)((byte *) col + col->length + 4); // next post } } M_Free(source); // free temporary column M_Free(marks); // free transparency marks // Now that the texture has been built in column cache, // it is purgable from zone memory. Z_ChangeTag(block, PU_CACHE); }
static void R_GenerateLookup(int texnum, int *const errors) { const texture_t *texture = textures[texnum]; // Composited texture not created yet. short *collump = texturecolumnlump[texnum]; unsigned *colofs = texturecolumnofs[texnum]; // killough 4/9/98: make 32-bit // killough 4/9/98: keep count of posts in addition to patches. // Part of fix for medusa bug for multipatched 2s normals. struct cs { unsigned short patches, posts; } *count = (cs *)Calloc (sizeof *count, texture->width); int i = texture->patchcount; const texpatch_t *patch = texture->patches; // [RH] Some wads (I forget which!) have single-patch textures 256 // pixels tall that have patch lengths recorded as 0. I can't think of // any good reason for them to do this, and since I didn't make note // of which wad made me hack in support for them, the hack is gone // because I've added support for DeePsea's real tall patches. while (--i >= 0) { int pat = patch->patch; const patch_t *realpatch = W_CachePatch (pat); int x1 = patch++->originx, x2 = x1 + realpatch->width(), x = x1; const int *cofs = realpatch->columnofs-x1; if (x2 > texture->width) x2 = texture->width; if (x1 < 0) x = 0; for (; x < x2; x++) { // killough 4/9/98: keep a count of the number of posts in column, // to fix Medusa bug while allowing for transparent multipatches. const column_t *col = (column_t*)((byte*)realpatch + LELONG(cofs[x])); for (;col->topdelta != 0xff; count[x].posts++) { col = (column_t *)((byte *)col + col->length + 4); // denis - prevent a crash when col goes out of range unsigned int n = (const byte *)col - (const byte *)realpatch; if (n >= W_LumpLength(pat)) { if (texture->height < 256) // bigger textures are assumed to have a single post anyway Printf(PRINT_HIGH, "R_GenerateLookup warning: post truncated for texture %d\n", texnum); count[x].posts--; break; } } count[x].patches++; collump[x] = pat; colofs[x] = LELONG(cofs[x])+3; } } // Now count the number of columns // that are covered by more than one patch. // Fill in the lump / offset, so columns // with only a single patch are all done. texturecomposite[texnum] = 0; int x = texture->width; int height = texture->height; int csize = 0; bool multipatch = (texture->patchcount > 1 || texture->height > 254); // [SL] Check for columns without patches - these should be handled as // multi-patched textures so we can fill in the empty columns with // masked columns while (--x >= 0 && !multipatch) { if (!count[x].patches) multipatch = true; } if (multipatch) { // [RH] Always create a composite texture for multipatch textures // or tall textures in order to keep things simpler. texturetype2[texnum] = 1; x = texture->width; csize = 0; while (--x >= 0) { // killough 1/25/98, 4/9/98: // // Fix Medusa bug, by adding room for column header // and trailer bytes for each post in merged column. // For now, just allocate conservatively 4 bytes // per post per patch per column, since we don't // yet know how many posts the merged column will // require, and it's bounded above by this limit. collump[x] = -1; // mark lump as multipatched colofs[x] = csize + 4; // four header bytes in a column csize += 4*count[x].posts+2+height; // 2 stop bytes plus 4 bytes per post } } else { texturetype2[texnum] = 0; csize = x*height; } texturecompositesize[texnum] = csize; M_Free(count); // killough 4/9/98 }
// // CheckIWAD // // Tries to find an IWAD from a set of know IWAD names, and checks the first // one found's contents to determine whether registered/commercial features // should be executed (notably loading PWAD's). // static bool CheckIWAD (std::string suggestion, std::string &titlestring) { static const char *doomwadnames[] = { "doom2f.wad", "doom2.wad", "plutonia.wad", "tnt.wad", "doomu.wad", // Hack from original Linux version. Not necessary, but I threw it in anyway. "doom.wad", "doom1.wad", "freedoom.wad", "freedm.wad", "chex.wad", // [ML] 1/7/10: Hello Chex Quest! NULL }; std::string iwad; std::string iwad_file; int i; if(suggestion.length()) { std::string found = BaseFileSearch(suggestion, ".WAD"); if(found.length()) iwad = found; else { if(M_FileExists(suggestion.c_str())) iwad = suggestion; } /* [ML] Removed 1/13/10: we can trust the user to provide an iwad if(iwad.length()) { FILE *f; if ( (f = fopen (iwad.c_str(), "rb")) ) { wadinfo_t header; fread (&header, sizeof(header), 1, f); header.identification = LELONG(header.identification); if (header.identification != IWAD_ID) { if(header.identification == PWAD_ID) { Printf(PRINT_HIGH, "Suggested file is a PWAD, not an IWAD: %s \n", iwad.c_str()); } else { Printf(PRINT_HIGH, "Suggested file is not an IWAD: %s \n", iwad.c_str()); } iwad = ""; } fclose(f); } } */ } if(!iwad.length()) { // Search for a pre-defined IWAD from the list above for (i = 0; doomwadnames[i]; i++) { std::string found = BaseFileSearch(doomwadnames[i]); if(found.length()) { iwad = found; break; } } } // Now scan the contents of the IWAD to determine which one it is if (iwad.length()) { #define NUM_CHECKLUMPS 9 static const char checklumps[NUM_CHECKLUMPS][8] = { "E1M1", "E2M1", "E4M1", "MAP01", { 'A','N','I','M','D','E','F','S'}, "FINAL2", "REDTNT2", "CAMO1", { 'E','X','T','E','N','D','E','D'} }; int lumpsfound[NUM_CHECKLUMPS]; wadinfo_t header; FILE *f; M_ExtractFileName(iwad,iwad_file); memset (lumpsfound, 0, sizeof(lumpsfound)); if ( (f = fopen (iwad.c_str(), "rb")) ) { size_t res = fread (&header, sizeof(header), 1, f); header.identification = LELONG(header.identification); if (header.identification == IWAD_ID || header.identification == PWAD_ID) { header.numlumps = LELONG(header.numlumps); if (0 == fseek (f, LELONG(header.infotableofs), SEEK_SET)) { for (i = 0; i < header.numlumps; i++) { filelump_t lump; int j; if (0 == fread (&lump, sizeof(lump), 1, f)) break; for (j = 0; j < NUM_CHECKLUMPS; j++) if (!strnicmp (lump.name, checklumps[j], 8)) lumpsfound[j]++; } } } fclose (f); } gamemode = undetermined; if (lumpsfound[3]) { gamemode = commercial; gameinfo = CommercialGameInfo; if (lumpsfound[6]) { gamemission = pack_tnt; titlestring = "DOOM 2: TNT - Evilution"; } else if (lumpsfound[7]) { gamemission = pack_plut; titlestring = "DOOM 2: Plutonia Experiment"; } else { gamemission = doom2; titlestring = "DOOM 2: Hell on Earth"; } } else if (lumpsfound[0]) { gamemission = doom; if (lumpsfound[1]) { if (lumpsfound[2]) { if (!StdStringCompare(iwad_file,"chex.wad",true)) // [ML] 1/7/10: HACK - There's no unique lumps in the chex quest { // iwad. It's ultimate doom with their stuff replacing most things. gamemission = chex; gamemode = retail_chex; gameinfo = RetailGameInfo; titlestring = "Chex Quest"; } else { gamemode = retail; gameinfo = RetailGameInfo; titlestring = "The Ultimate DOOM"; } } else { gamemode = registered; gameinfo = RegisteredGameInfo; titlestring = "DOOM Registered"; } } else { gamemode = shareware; gameinfo = SharewareGameInfo; titlestring = "DOOM Shareware"; } } } if (gamemode == undetermined) { gameinfo = SharewareGameInfo; } if (iwad.length()) wadfiles.push_back(iwad); else I_Error("Cannot find IWAD (try -waddir)"); return iwad.length() ? true : false; }