/* TextureXPanel::exportAsPNG * Converts [texture] to a PNG image (if possible) and saves the PNG * data to a file [filename]. Does not alter the texture data itself *******************************************************************/ bool TextureXPanel::exportAsPNG(CTexture* texture, string filename, bool force_rgba) { // Check entry was given if (!texture) return false; // Create image from entry SImage image; if (!texture->toImage(image, NULL, texture_editor->getPalette(), force_rgba)) { wxLogMessage("Error converting %s: %s", texture->getName(), Global::error); return false; } // Write png data MemChunk png; SIFormat* fmt_png = SIFormat::getFormat("png"); if (!fmt_png->saveImage(image, png, texture_editor->getPalette())) { wxLogMessage("Error converting %s", texture->getName()); return false; } // Export file return png.exportFile(filename); }
/* ChasmBinArchive::isChasmBinArchive * Checks if the given data is a valid Chasm bin archive *******************************************************************/ bool ChasmBinArchive::isChasmBinArchive(MemChunk& mc) { // Check given data is valid if (mc.getSize() < HEADER_SIZE) { return false; } // Read bin header and check it char magic[4] = {}; mc.read(magic, sizeof magic); if ( magic[0] != 'C' || magic[1] != 'S' || magic[2] != 'i' || magic[3] != 'd') { return false; } uint16_t num_entries = 0; mc.read(&num_entries, sizeof num_entries); num_entries = wxUINT16_SWAP_ON_BE(num_entries); return num_entries > MAX_ENTRY_COUNT || (HEADER_SIZE + ENTRY_SIZE * MAX_ENTRY_COUNT) <= mc.getSize(); }
// ----------------------------------------------------------------------------- // Handles announcements from any announcers listened to // ----------------------------------------------------------------------------- void MapTextureManager::onAnnouncement(Announcer* announcer, std::string_view event_name, MemChunk& event_data) { // Only interested in the resource manager, // archive manager and palette chooser. if (announcer != &App::resources() && announcer != theMainWindow->paletteChooser() && announcer != &App::archiveManager()) return; // If the map's archive is being closed, // we need to close the map editor if (event_name == "archive_closing") { event_data.seek(0, SEEK_SET); int32_t ac_index; event_data.read(&ac_index, 4); if (App::archiveManager().getArchive(ac_index) == archive_) { MapEditor::windowWx()->Hide(); MapEditor::editContext().clearMap(); archive_ = nullptr; } } // If the resources have been updated if (event_name == "resources_updated") refreshResources(); if (event_name == "main_palette_changed") refreshResources(); }
/* AnimatedEntryPanel::saveEntry * Saves any changes made to the entry *******************************************************************/ bool AnimatedEntryPanel::saveEntry() { MemChunk mc; mc.seek(0, SEEK_SET); animated_t anim; for (uint32_t a = 0; a < animated.nEntries(); a++) { AnimatedEntry* ent = animated.getEntry(a); for (size_t i = 0; i < 9; ++i) { if (ent->getFirst().length() > i) anim.first[i] = ent->getFirst()[i]; else anim.first[i] = 0; if (ent->getLast().length() > i) anim.last[i] = ent->getLast()[i]; else anim.last[i] = 0; } anim.speed = ent->getSpeed(); anim.type = ent->getType(); if (ent->getDecals()) anim.type |= ANIM_DECALS; mc.write(&anim, 23); } anim.type = 255; mc.write(&anim, 1); bool success = entry->importMemChunk(mc); if (success) { for (uint32_t a = 0; a < animated.nEntries(); a++) list_entries->setItemStatus(a, LV_STATUS_NORMAL); } return success; }
/* SImage::getIndexedData * Loads the image as index data into <mc>. Returns false if image is * invalid, true otherwise *******************************************************************/ bool SImage::getIndexedData(MemChunk& mc) { // Check the image is valid if (!isValid()) return false; // Init rgb data mc.reSize(width * height, false); // Cannot do this for trucolor graphics. if (type == RGBA) return false; else if (type == PALMASK) { mc.write(data, width * height); return true; } else if (type == ALPHAMAP) { mc.write(data, width * height); return true; } return false; // Invalid image type }
// ----------------------------------------------------------------------------- // Renames [dir] to [new_name]. // Returns false if [dir] isn't part of the archive, true otherwise // ----------------------------------------------------------------------------- bool Archive::renameDir(ArchiveTreeNode* dir, string_view new_name) { // Abort if read only if (read_only_) return false; // Check the directory is part of this archive if (!dir || dir->archive() != this) return false; // Rename the directory if needed if (dir->name() == new_name) { if (UndoRedo::currentlyRecording()) UndoRedo::currentManager()->recordUndoStep(std::make_unique<DirRenameUS>(dir, new_name)); dir->setName(new_name); dir->dirEntry()->setState(ArchiveEntry::State::Modified); } else return true; // Announce MemChunk mc; wxUIntPtr ptr = wxPtrToUInt(dir); mc.write(&ptr, sizeof(wxUIntPtr)); announce("directory_modified", mc); // Update variables etc setModified(true); return true; }
/* AudioEntryPanel::openMod * Opens a Module file for playback *******************************************************************/ bool AudioEntryPanel::openMod(MemChunk& data) { // Attempt to load the mod if (mod->loadFromMemory(data.getData(), data.getSize())) { audio_type = AUTYPE_MOD; // Enable playback controls slider_volume->Enable(); btn_play->Enable(); btn_pause->Enable(); btn_stop->Enable(); setAudioDuration(mod->getDuration().asMilliseconds()); return true; } else { // Disable playback controls slider_volume->Enable(); btn_play->Enable(); btn_pause->Enable(); btn_stop->Enable(); setAudioDuration(0); return false; } return false; }
void MapTextureManager::onAnnouncement(Announcer* announcer, string event_name, MemChunk& event_data) { // Only interested in the resource manager, // archive manager and palette chooser. if (announcer != theResourceManager && announcer != thePaletteChooser && announcer != theArchiveManager) return; // If the map's archive is being closed, // we need to close the map editor if (event_name == "archive_closing") { event_data.seek(0, SEEK_SET); int32_t ac_index; event_data.read(&ac_index, 4); if (theArchiveManager->getArchive(ac_index) == archive) { theMapEditor->Hide(); theMapEditor->mapEditor().clearMap(); archive = NULL; } } // If the resources have been updated if (event_name == "resources_updated") refreshResources(); if (event_name == "main_palette_changed") refreshResources(); }
/* PaletteManager::loadCustomPalettes * Loads any files in the '<userdir>/palettes' directory as palettes, * with names from the files (minus the file extension) *******************************************************************/ bool PaletteManager::loadCustomPalettes() { // If the directory doesn't exist create it if (!wxDirExists(appPath("palettes", DIR_USER))) wxMkdir(appPath("palettes", DIR_USER)); // Open the custom palettes directory wxDir res_dir; res_dir.Open(appPath("palettes", DIR_USER)); // Go through each file in the directory string filename = wxEmptyString; bool files = res_dir.GetFirst(&filename, wxEmptyString, wxDIR_FILES); while (files) { // Load palette data Palette8bit* pal = new Palette8bit(); MemChunk mc; mc.importFile(res_dir.GetName() + "/" + filename); pal->loadMem(mc); // Add the palette wxFileName fn(filename); addPalette(pal, fn.GetName()); // Next file files = res_dir.GetNext(&filename); } return true; }
// ----------------------------------------------------------------------------- // Called when an announcement is recieved from one of the archives in the list // ----------------------------------------------------------------------------- void ArchiveManager::onAnnouncement(Announcer* announcer, const string& event_name, MemChunk& event_data) { // Reset event data for reading event_data.seek(0, SEEK_SET); // Check that the announcement came from an archive in the list int32_t index = archiveIndex((Archive*)announcer); if (index >= 0) { // If the archive was saved if (event_name == "saved") { MemChunk mc; mc.write(&index, 4); announce("archive_saved", mc); } // If the archive was modified if (event_name == "modified" || event_name == "entry_modified") { MemChunk mc; mc.write(&index, 4); announce("archive_modified", mc); } } }
void * FixedAllocator::Allocate() { if (!last_alloc_ || last_alloc_->blocks_available_ == 0) { // no memory available in the cached chunk, try to find one. Chunks::iterator e = chunks_.end(); Chunks::iterator i = chunks_.begin(); for (; i!=e; ++i) { if (i->blocks_available_ > 0) { // found a chunk! last_alloc_ = &*i; break; } } if (i == e) { // no chunks have blocks available, add a new one. chunks_.reserve(chunks_.size()+1); MemChunk chunk; chunk.Init(block_size_, blocks_); chunks_.push_back(chunk); last_alloc_ = &chunks_.back(); last_dealloc_ = &chunks_.back(); } } // chunk pointer vaild check assert(last_alloc_ != NULL); assert(last_alloc_->blocks_available_ > 0); return last_alloc_->Allocate(block_size_); }
void MaterializedArray::materialize(const shared_ptr<Query>& query, MemChunk& materializedChunk, ConstChunk const& chunk, MaterializeFormat format) { nMaterializedChunks += 1; materializedChunk.initialize(chunk); materializedChunk.setBitmapChunk((Chunk*)chunk.getBitmapChunk()); boost::shared_ptr<ConstChunkIterator> src = chunk.getConstIterator(ChunkIterator::IGNORE_DEFAULT_VALUES|ChunkIterator::IGNORE_EMPTY_CELLS| (chunk.isSolid() ? ChunkIterator::INTENDED_TILE_MODE : 0)); boost::shared_ptr<ChunkIterator> dst = materializedChunk.getIterator(query, (src->getMode() & ChunkIterator::TILE_MODE)|ChunkIterator::ChunkIterator::NO_EMPTY_CHECK|ChunkIterator::SEQUENTIAL_WRITE); size_t count = 0; while (!src->end()) { if (!dst->setPosition(src->getPosition())) throw SYSTEM_EXCEPTION(SCIDB_SE_MERGE, SCIDB_LE_OPERATION_FAILED) << "setPosition"; dst->writeItem(src->getItem()); count += 1; ++(*src); } if (!(src->getMode() & ChunkIterator::TILE_MODE) && !chunk.getArrayDesc().hasOverlap()) { materializedChunk.setCount(count); } dst->flush(); }
ConstChunk const& getChunk(AttributeID attr, size_t rowIndex) { _chunkAddress.coords[1] = _rowIndex -1; shared_ptr<Query> query = Query::getValidQueryPtr(_query); _chunk.initialize(this, &super::getArrayDesc(), _chunkAddress, 0); shared_ptr<ChunkIterator> chunkIt = _chunk.getIterator(query, ChunkIterator::SEQUENTIAL_WRITE | ChunkIterator::NO_EMPTY_CHECK); Value v; if(_buffer[_bufferSize-1] == _delimiter) //add the null-termination character; replace the last delimiter character if one is present { v.setSize(_bufferSize); char *d = (char*) v.data(); memcpy(d, _buffer, _bufferSize); d[_bufferSize-1] = 0; } else { v.setSize(_bufferSize+1); char *d = (char*) v.data(); memcpy(d, _buffer, _bufferSize); d[_bufferSize] = 0; } chunkIt->writeItem(v); chunkIt->flush(); return _chunk; }
void updateEntry() { // Read file MemChunk data; data.importFile(filename); // Read image SImage image; image.open(data, 0, "png"); image.convertPaletted(&palette); // Convert image to entry gfx format SIFormat* format = SIFormat::getFormat(gfx_format); if (format) { MemChunk conv_data; if (format->saveImage(image, conv_data, &palette)) { // Update entry data entry->importMemChunk(conv_data); EntryOperations::setGfxOffsets(entry, offsets.x, offsets.y); } else { LOG_MESSAGE(1, "Unable to convert external png to %s", format->getName()); } } }
// ----------------------------------------------------------------------------- // Reads an archive from disk // Returns true if successful, false otherwise // ----------------------------------------------------------------------------- bool Archive::open(string_view filename) { // Read the file into a MemChunk MemChunk mc; if (!mc.importFile(filename)) { Global::error = "Unable to open file. Make sure it isn't in use by another program."; return false; } // Update filename before opening auto backupname = filename_; filename_ = filename; // Load from MemChunk sf::Clock timer; if (open(mc)) { Log::info(2, "Archive::open took {}ms", timer.getElapsedTime().asMilliseconds()); on_disk_ = true; return true; } else { filename_ = backupname; return false; } }
/* Archive::open * Reads an archive from disk * Returns true if successful, false otherwise *******************************************************************/ bool Archive::open(string filename) { // Read the file into a MemChunk MemChunk mc; if (!mc.importFile(filename)) { Global::error = "Unable to open file. Make sure it isn't in use by another program."; return false; } // Update filename before opening string backupname = this->filename; this->filename = filename; // Load from MemChunk sf::Clock timer; if (open(mc)) { LOG_MESSAGE(2, "Archive::open took %dms", timer.getElapsedTime().asMilliseconds()); this->on_disk = true; return true; } else { this->filename = backupname; return false; } }
/* SwitchesEntryPanel::saveEntry * Saves any changes made to the entry *******************************************************************/ bool SwitchesEntryPanel::saveEntry() { MemChunk mc; mc.seek(0, SEEK_SET); switches_t swch; for (uint32_t a = 0; a < switches.nEntries(); a++) { SwitchesEntry* ent = switches.getEntry(a); for (size_t i = 0; i < 9; ++i) { if (ent->getOff().length() > i) swch.off[i] = ent->getOff()[i]; else swch.off[i] = 0; if (ent->getOn().length() > i) swch.on[i] = ent->getOn()[i]; else swch.on[i] = 0; } swch.type = ent->getType(); mc.write(&swch, 20); } memset(&swch, 0, 20); mc.write(&swch, 20); bool success = entry->importMemChunk(mc); if (success) { for (uint32_t a = 0; a < switches.nEntries(); a++) list_entries->setItemStatus(a, LV_STATUS_NORMAL); } return success; }
/* EntryOperations::exportAsPNG * Converts [entry] to a PNG image (if possible) and saves the PNG * data to a file [filename]. Does not alter the entry data itself *******************************************************************/ bool EntryOperations::exportAsPNG(ArchiveEntry* entry, string filename) { // Check entry was given if (!entry) return false; // Create image from entry SImage image; if (!Misc::loadImageFromEntry(&image, entry)) { wxLogMessage("Error converting %s: %s", entry->getName(), Global::error); return false; } // Write png data MemChunk png; SIFormat* fmt_png = SIFormat::getFormat("png"); if (!fmt_png->saveImage(image, png, theMainWindow->getPaletteChooser()->getSelectedPalette(entry))) { wxLogMessage("Error converting %s", entry->getName()); return false; } // Export file return png.exportFile(filename); }
/* Archive::renameDir * Renames [dir] to [new_name]. Returns false if [dir] isn't part of * the archive, true otherwise *******************************************************************/ bool Archive::renameDir(ArchiveTreeNode* dir, string new_name) { // Abort if read only if (read_only) return false; // Check the directory is part of this archive if (dir->getArchive() != this) return false; // Rename the directory if needed if (!(S_CMPNOCASE(dir->getName(), new_name))) { if (UndoRedo::currentlyRecording()) UndoRedo::currentManager()->recordUndoStep(new DirRenameUS(dir, new_name)); dir->setName(new_name); dir->getDirEntry()->setState(1); } else return true; // Announce MemChunk mc; wxUIntPtr ptr = wxPtrToUInt(dir); mc.write(&ptr, sizeof(wxUIntPtr)); announce("directory_modified", mc); // Update variables etc setModified(true); return true; }
/* Archive::createDir * Creates a directory at [path], starting from [base]. If * [base] is NULL, the root directory is used. Returns the created * directory. If the directory requested to be created already * exists, it will be returned *******************************************************************/ ArchiveTreeNode* Archive::createDir(string path, ArchiveTreeNode* base) { // Abort if read only if (read_only) return dir_root; // If no base dir specified, set it to root if (!base) base = dir_root; if (path.IsEmpty()) return base; // Create the directory ArchiveTreeNode* dir = (ArchiveTreeNode*)((STreeNode*)base)->addChild(path); // Record undo step if (UndoRedo::currentlyRecording()) UndoRedo::currentManager()->recordUndoStep(new DirCreateDeleteUS(true, dir)); // Set the archive state to modified setModified(true); // Announce MemChunk mc; wxUIntPtr ptr = wxPtrToUInt(dir); mc.write(&ptr, sizeof(wxUIntPtr)); announce("directory_added", mc); return dir; }
/* 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 }
/* ADatArchive::write * Writes the dat archive to a file * Returns true if successful, false otherwise *******************************************************************/ bool ADatArchive::write(string filename, bool update) { // Write to a MemChunk, then export it to a file MemChunk mc; if (write(mc, true)) return mc.exportFile(filename); else return false; }
// ----------------------------------------------------------------------------- // Application exit, shuts down and cleans everything up. // If [save_config] is true, saves all configuration related files // ----------------------------------------------------------------------------- void App::exit(bool save_config) { exiting = true; if (save_config) { // Save configuration saveConfigFile(); // Save text style configuration StyleSet::saveCurrent(); // Save colour configuration MemChunk ccfg; ColourConfiguration::writeConfiguration(ccfg); ccfg.exportFile(App::path("colours.cfg", App::Dir::User)); // Save game exes wxFile f; f.Open(App::path("executables.cfg", App::Dir::User), wxFile::write); f.Write(Executables::writeExecutables()); f.Close(); // Save custom special presets Game::saveCustomSpecialPresets(); // Save custom scripts ScriptManager::saveUserScripts(); } // Close all open archives archive_manager.closeAll(); // Clean up EntryType::cleanupEntryTypes(); Drawing::cleanupFonts(); OpenGL::Texture::clearAll(); // Clear temp folder std::error_code error; for (auto& item : std::filesystem::directory_iterator{ App::path("", App::Dir::Temp) }) { if (!item.is_regular_file()) continue; if (!std::filesystem::remove(item, error)) Log::warning("Could not clean up temporary file \"{}\": {}", item.path().string(), error.message()); } // Close lua Lua::close(); // Close DUMB dumb_exit(); // Exit wx Application wxGetApp().Exit(); }
// ---------------------------------------------------------------------------- // Tokenizer::openMem // // Opens text from a MemChunk [mc] // ---------------------------------------------------------------------------- bool Tokenizer::openMem(const MemChunk& mc, const string& source) { source_ = source; data_.assign(mc.getData(), mc.getData() + mc.getSize()); reset(); return true; }
bool isThisFormat(MemChunk& mc) { FIMEMORY* mem = FreeImage_OpenMemory((BYTE*)mc.getData(), mc.getSize()); FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeFromMemory(mem, 0); FreeImage_CloseMemory(mem); if (fif == FIF_UNKNOWN) return false; else return true; }
// ----------------------------------------------------------------------------- // Opens [dir] as a DirArchive and adds it to the list. // Returns a pointer to the archive or nullptr if an error occurred. // ----------------------------------------------------------------------------- Archive* ArchiveManager::openDirArchive(const string& dir, bool manage, bool silent) { auto new_archive = getArchive(dir); LOG_MESSAGE(1, "Opening directory %s as archive", dir); // If the archive is already open, just return it if (new_archive) { // Announce open if (!silent) { MemChunk mc; uint32_t index = archiveIndex(new_archive); mc.write(&index, 4); announce("archive_opened", mc); } return new_archive; } new_archive = new DirArchive(); // If it opened successfully, add it to the list if needed & return it, // Otherwise, delete it and return nullptr if (new_archive->open(dir)) { if (manage) { // Add the archive addArchive(new_archive); // Announce open if (!silent) { MemChunk mc; uint32_t index = archiveIndex(new_archive); mc.write(&index, 4); announce("archive_opened", mc); } // Add to recent files addRecentFile(dir); } // Return the opened archive return new_archive; } else { LOG_MESSAGE(1, "Error: " + Global::error); delete new_archive; return nullptr; } }
/* ArchiveEntry::importMemChunk * Imports data from a MemChunk object into the entry, resizing it * and clearing any currently existing data. * Returns false if the MemChunk has no data, or true otherwise. *******************************************************************/ bool ArchiveEntry::importMemChunk(MemChunk& mc) { // Check that the given MemChunk has data if (mc.hasData()) { // Copy the data from the MemChunk into the entry return importMem(mc.getData(), mc.getSize()); } else return false; }
/* Archive::removeEntry * Removes [entry] from the archive. If [delete_entry] is true, the * entry will also be deleted. Returns true if the removal succeeded *******************************************************************/ bool Archive::removeEntry(ArchiveEntry* entry, bool delete_entry) { // Abort if read only if (read_only) return false; // Check entry if (!checkEntry(entry)) return false; // Check if entry is locked if (entry->isLocked()) return false; // Get its directory ArchiveTreeNode* dir = entry->getParentDir(); // Error if entry has no parent directory if (!dir) return false; // Create undo step if (UndoRedo::currentlyRecording()) UndoRedo::currentManager()->recordUndoStep(new EntryCreateDeleteUS(false, entry)); // Get the entry index int index = dir->entryIndex(entry); // Announce (before actually removing in case entry is still needed) MemChunk mc; wxUIntPtr ptr = wxPtrToUInt(entry); mc.write(&index, sizeof(int)); mc.write(&ptr, sizeof(wxUIntPtr)); announce("entry_removing", mc); // Remove it from its directory bool ok = dir->removeEntry(index); // If it was removed ok if (ok) { // Announce removed announce("entry_removed", mc); // Delete if necessary if (delete_entry) delete entry; // Update variables etc setModified(true); } return ok; }
bool exportEntry() { wxFileName fn(appPath(entry->getName(), DIR_TEMP)); fn.SetExt("mid"); // Convert to WAV data MemChunk convdata; // Doom Sound if (entry->getType()->getFormat() == "snd_doom" || entry->getType()->getFormat() == "snd_doom_mac") Conversions::doomSndToWav(entry->getMCData(), convdata); // Doom PC Speaker Sound else if (entry->getType()->getFormat() == "snd_speaker") Conversions::spkSndToWav(entry->getMCData(), convdata); // AudioT PC Speaker Sound else if (entry->getType()->getFormat() == "snd_audiot") Conversions::spkSndToWav(entry->getMCData(), convdata, true); // Wolfenstein 3D Sound else if (entry->getType()->getFormat() == "snd_wolf") Conversions::wolfSndToWav(entry->getMCData(), convdata); // Creative Voice File else if (entry->getType()->getFormat() == "snd_voc") Conversions::vocToWav(entry->getMCData(), convdata); // Jaguar Doom Sound else if (entry->getType()->getFormat() == "snd_jaguar") Conversions::jagSndToWav(entry->getMCData(), convdata); // Blood Sound else if (entry->getType()->getFormat() == "snd_bloodsfx") Conversions::bloodToWav(entry, convdata); else { Global::error = S_FMT("Type %s can not be converted to WAV", CHR(entry->getType()->getName())); return false; } // Export file and start monitoring if successful filename = fn.GetFullPath(); if (convdata.exportFile(filename)) { file_modified = wxFileModificationTime(filename); Start(1000); return true; } return false; }
/* GLTexture::loadImage * Loads SImage data to the texture. If the dimensions are invalid * for the system opengl implementation, the data will be split into * 128x128 squares. Returns false if the given data is invalid, true * otherwise *******************************************************************/ bool GLTexture::loadImage(SImage* image, Palette8bit* pal) { // Check image was given if (!image) return false; // Check image is valid if (!image->isValid()) return false; // Clear current texture clear(); // Check image dimensions if (OpenGL::validTexDimension(image->getWidth()) && OpenGL::validTexDimension(image->getHeight())) { // If the image dimensions are valid for OpenGL on this system, just load it as a single texture // Get RGBA image data MemChunk rgba; image->getRGBAData(rgba, pal); // Generate GL texture from rgba data return loadData(rgba.getData(), image->getWidth(), image->getHeight()); } else { // Otherwise split the image into 128x128 chunks int top = 0; while (top < image->getHeight()) { int left = 0; while (left < image->getWidth()) { // Load 128x128 portion of image loadImagePortion(image, rect_t(left, top, left + 128, top + 128), pal, true); // Move right 128px left += 128; } // Move down 128px top += 128; } // Update variables width = image->getWidth(); height = image->getHeight(); scale_x = scale_y = 1.0; return true; } }