/* SImage::getRGBAData * Loads the image as RGBA data into <mc>. Returns false if image is * invalid, true otherwise *******************************************************************/ bool SImage::getRGBAData(MemChunk& mc, Palette8bit* pal) { // Check the image is valid if (!isValid()) return false; // Init rgba data mc.reSize(width * height * 4, false); // If data is already in RGBA format just return a copy if (type == RGBA) { mc.importMem(data, width * height * 4); return true; } // Convert paletted else if (type == PALMASK) { // Get palette to use if (has_palette || !pal) pal = &palette; uint8_t rgba[4]; for (int a = 0; a < width * height; a++) { // Get colour rgba_t col = pal->colour(data[a]); // Set alpha if (mask) col.a = mask[a]; else col.a = 255; col.write(rgba); // Write colour to array mc.write(rgba, 4); // Write array to MemChunk } return true; } // Convert if alpha map else if (type == ALPHAMAP) { uint8_t rgba[4]; rgba_t col; for (int a = 0; a < width * height; a++) { // Get pixel as colour (greyscale) col.set(data[a], data[a], data[a], data[a]); col.write(rgba); // Write colour to array mc.write(rgba, 4); // Write array to MemChunk } } return false; // Invalid image type }
/* MemChunk::exportMemChunk * Writes the MemChunk data to another MemChunk, starting from * [start] to [start+size]. If [size] is 0, writes from [start] to * the end of the data *******************************************************************/ bool MemChunk::exportMemChunk(MemChunk& mc, uint32_t start, uint32_t size) { // Check data exists if (!hasData()) return false; // Check parameters if (start >= this->size || start + size > this->size) return false; // Check size if (size == 0) size = this->size - start; // Write data to MemChunk mc.reSize(size, false); return mc.importMem(data+start, size); }
/* AudioEntryPanel::open * Opens the current entry and performs the appropriate conversions *******************************************************************/ bool AudioEntryPanel::open() { // Check if already opened if (opened) return true; // Stop if sound currently playing resetStream(); subsong = 0; num_tracks = 1; // Get entry data MemChunk& mcdata = entry->getMCData(); // Setup temp filename wxFileName path(appPath(entry->getName(), DIR_TEMP)); // Add extension if missing if (path.GetExt().IsEmpty()) path.SetExt(entry->getType()->getExtension()); // Convert if necessary, then write to file MemChunk convdata; if (entry->getType()->getFormat() == "snd_doom" || // Doom Sound -> WAV entry->getType()->getFormat() == "snd_doom_mac") Conversions::doomSndToWav(mcdata, convdata); else if (entry->getType()->getFormat() == "snd_speaker") // Doom PC Speaker Sound -> WAV Conversions::spkSndToWav(mcdata, convdata); else if (entry->getType()->getFormat() == "snd_audiot") // AudioT PC Speaker Sound -> WAV Conversions::spkSndToWav(mcdata, convdata, true); else if (entry->getType()->getFormat() == "snd_wolf") // Wolfenstein 3D Sound -> WAV Conversions::wolfSndToWav(mcdata, convdata); else if (entry->getType()->getFormat() == "snd_voc") // Creative Voice File -> WAV Conversions::vocToWav(mcdata, convdata); else if (entry->getType()->getFormat() == "snd_jaguar") // Jaguar Doom Sound -> WAV Conversions::jagSndToWav(mcdata, convdata); else if (entry->getType()->getFormat() == "snd_bloodsfx") // Blood Sound -> WAV Conversions::bloodToWav(entry, convdata); else if (entry->getType()->getFormat() == "midi_mus") // MUS -> MIDI { Conversions::musToMidi(mcdata, convdata); path.SetExt("mid"); } else if (entry->getType()->getFormat() == "midi_xmi" || // HMI/HMP/XMI -> MIDI entry->getType()->getFormat() == "midi_hmi" || entry->getType()->getFormat() == "midi_hmp") { Conversions::zmusToMidi(mcdata, convdata, 0, &num_tracks); path.SetExt("mid"); } else if (entry->getType()->getFormat() == "midi_gmid") // GMID -> MIDI { Conversions::gmidToMidi(mcdata, convdata); path.SetExt("mid"); } else convdata.importMem(mcdata.getData(), mcdata.getSize()); // MIDI format if (entry->getType()->getFormat().StartsWith("midi_")) { audio_type = AUTYPE_MIDI; openMidi(convdata, path.GetFullPath()); } // MOD format else if (entry->getType()->getFormat().StartsWith("mod_")) openMod(convdata); // Other format else openAudio(convdata, path.GetFullPath()); // Keep filename so we can delete it later prevfile = path.GetFullPath(); txt_title->SetLabel(entry->getPath(true)); txt_track->SetLabel(S_FMT("%d/%d", subsong+1, num_tracks)); updateInfo(); // Disable prev/next track buttons if only one track is available if (num_tracks < 2) { btn_prev->Disable(); btn_next->Disable(); } opened = true; return true; }
/* TextEditor::getRawText * Writes the raw ASCII text to [mc] *******************************************************************/ void TextEditor::getRawText(MemChunk& mc) { mc.clear(); string text = GetText(); bool result = mc.importMem((const uint8_t*)text.ToUTF8().data(), text.ToUTF8().length()); }
/* RffArchive::open * Reads grp format data from a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool RffArchive::open(MemChunk& mc) { // Check data was given if (!mc.hasData()) return false; // Read grp header uint8_t magic[4]; uint32_t version, dir_offset, num_lumps; mc.seek(0, SEEK_SET); mc.read(magic, 4); // Should be "RFF\x18" mc.read(&version, 4); // 0x01 0x03 \x00 \x00 mc.read(&dir_offset, 4); // Offset to directory mc.read(&num_lumps, 4); // No. of lumps in rff // Byteswap values for big endian if needed dir_offset = wxINT32_SWAP_ON_BE(dir_offset); num_lumps = wxINT32_SWAP_ON_BE(num_lumps); version = wxINT32_SWAP_ON_BE(version); // Check the header if (magic[0] != 'R' || magic[1] != 'F' || magic[2] != 'F' || magic[3] != 0x1A || version != 0x301) { wxLogMessage("RffArchive::openFile: File %s has invalid header", filename); Global::error = "Invalid rff header"; return false; } // Stop announcements (don't want to be announcing modification due to entries being added etc) setMuted(true); // Read the directory RFFLump* lumps = new RFFLump[num_lumps]; mc.seek(dir_offset, SEEK_SET); theSplashWindow->setProgressMessage("Reading rff archive data"); mc.read (lumps, num_lumps * sizeof(RFFLump)); BloodCrypt (lumps, dir_offset, num_lumps * sizeof(RFFLump)); for (uint32_t d = 0; d < num_lumps; d++) { // Update splash window progress theSplashWindow->setProgress(((float)d / (float)num_lumps)); // Read lump info char name[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint32_t offset = wxINT32_SWAP_ON_BE(lumps[d].FilePos); uint32_t size = wxINT32_SWAP_ON_BE(lumps[d].Size); // Reconstruct name int i, j = 0; for (i = 0; i < 8; ++i) { if (lumps[d].Name[i] == 0) break; name[i] = lumps[d].Name[i]; } for (name[i++] = '.'; j < 3; ++j) name[i+j] = lumps[d].Extension[j]; // If the lump data goes past the end of the file, // the rfffile is invalid if (offset + size > mc.getSize()) { wxLogMessage("RffArchive::open: rff archive is invalid or corrupt"); Global::error = "Archive is invalid and/or corrupt"; setMuted(false); return false; } // Create & setup lump ArchiveEntry* nlump = new ArchiveEntry(wxString::FromAscii(name), size); nlump->setLoaded(false); nlump->exProp("Offset") = (int)offset; nlump->setState(0); // Is the entry encrypted? if (lumps[d].Flags & 0x10) nlump->setEncryption(ENC_BLOOD); // Add to entry list getRoot()->addEntry(nlump); } delete[] lumps; // Detect all entry types MemChunk edata; theSplashWindow->setProgressMessage("Detecting entry types"); for (size_t a = 0; a < numEntries(); a++) { // Update splash window progress theSplashWindow->setProgress((((float)a / (float)num_lumps))); // Get entry ArchiveEntry* entry = getEntry(a); // Read entry data if it isn't zero-sized if (entry->getSize() > 0) { // Read the entry data mc.exportMemChunk(edata, getEntryOffset(entry), entry->getSize()); // If the entry is encrypted, decrypt it if (entry->isEncrypted()) { uint8_t* cdata = new uint8_t[entry->getSize()]; memcpy(cdata, edata.getData(), entry->getSize()); int cryptlen = entry->getSize() < 256 ? entry->getSize() : 256; BloodCrypt(cdata, 0, cryptlen); edata.importMem(cdata, entry->getSize()); delete[] cdata; } // Import data entry->importMemChunk(edata); } // Detect entry type EntryType::detectEntryType(entry); // Unload entry data if needed if (!archive_load_data) entry->unloadData(); // Set entry to unchanged entry->setState(0); } // Detect maps (will detect map entry types) //theSplashWindow->setProgressMessage("Detecting maps"); //detectMaps(); // Setup variables setMuted(false); setModified(false); announce("opened"); theSplashWindow->setProgressMessage(""); return true; }
GLTexture* MapTextureManager::getSprite(string name, string translation, string palette) { // Don't bother looking for nameless sprites if (name.IsEmpty()) return NULL; // Get sprite matching name string hashname = name.Upper(); if (!translation.IsEmpty()) hashname += translation.Lower(); if (!palette.IsEmpty()) hashname += palette.Upper(); map_tex_t& mtex = sprites[hashname]; // Get desired filter type int filter = 1; if (map_tex_filter == 0) filter = GLTexture::NEAREST_LINEAR_MIN; else if (map_tex_filter == 1) filter = GLTexture::LINEAR; else if (map_tex_filter == 2) filter = GLTexture::LINEAR; else if (map_tex_filter == 3) filter = GLTexture::NEAREST_MIPMAP; // If the texture is loaded if (mtex.texture) { // If the texture filter matches the desired one, return it if (mtex.texture->getFilter() == filter) return mtex.texture; else { // Otherwise, reload the texture delete mtex.texture; mtex.texture = NULL; } } // Sprite not found, look for it bool found = false; bool mirror = false; SImage image; Palette8bit* pal = getResourcePalette(); ArchiveEntry* entry = theResourceManager->getPatchEntry(name, "sprites", archive); if (!entry) entry = theResourceManager->getPatchEntry(name, "", archive); if (!entry && name.length() == 8) { string newname = name; newname[4] = name[6]; newname[5] = name[7]; newname[6] = name[4]; newname[7] = name[5]; entry = theResourceManager->getPatchEntry(newname, "sprites", archive); if (entry) mirror = true; } if (entry) { found = true; Misc::loadImageFromEntry(&image, entry); } else // Try composite textures then { CTexture* ctex = theResourceManager->getTexture(name, archive); if (ctex && ctex->toImage(image, archive, pal)) found = true; } // We have a valid image either from an entry or a composite texture. if (found) { // Apply translation if (!translation.IsEmpty()) image.applyTranslation(translation, pal); // Apply palette override if (!palette.IsEmpty()) { ArchiveEntry* newpal = theResourceManager->getPaletteEntry(palette, archive); if (newpal && newpal->getSize() == 768) { // Why is this needed? // Copying data in pal->loadMem shouldn't // change it in the original entry... // We shouldn't need to copy the data in a temporary place first. pal = image.getPalette(); MemChunk mc; mc.importMem(newpal->getData(), newpal->getSize()); pal->loadMem(mc); } } // Apply mirroring if (mirror) image.mirror(false); // Turn into GL texture mtex.texture = new GLTexture(false); mtex.texture->setFilter(filter); mtex.texture->setTiling(false); mtex.texture->loadImage(&image, pal); return mtex.texture; } else if (name.EndsWith("?")) { name.RemoveLast(1); GLTexture* sprite = getSprite(name + '0', translation, palette); if (!sprite) sprite = getSprite(name + '1', translation, palette); if (sprite) return sprite; if (!sprite && name.length() == 5) { for (char chr = 'A'; chr <= ']'; ++chr) { sprite = getSprite(name + '0' + chr + '0', translation, palette); if (sprite) return sprite; sprite = getSprite(name + '1' + chr + '1', translation, palette); if (sprite) return sprite; } } } return NULL; }