void TypeConstraint::verifyFail(const Func* func, int paramNum, TypedValue* tv) const { JIT::VMRegAnchor _; const StringData* tn = typeName(); if (isSelf()) { selfToTypeName(func, &tn); } else if (isParent()) { parentToTypeName(func, &tn); } auto const givenType = describe_actual_type(tv); auto c = tvToCell(tv); if (isArray() && !isSoft() && !func->mustBeRef(paramNum) && c->m_type == KindOfObject && c->m_data.pobj->isCollection()) { // To ease migration, the 'array' type constraint will implicitly cast // collections to arrays, provided the type constraint is not soft and // the parameter is not by reference. We raise a notice to let the user // know that there was a type mismatch and that an implicit conversion // was performed. raise_notice( folly::format( "Argument {} to {}() must be of type {}, {} given; argument {} was " "implicitly cast to array", paramNum + 1, func->fullName()->data(), fullName(), givenType, paramNum + 1 ).str() ); tvCastToArrayInPlace(tv); return; } if (isExtended() && isSoft()) { // Soft extended type hints raise warnings instead of recoverable // errors, to ease migration. raise_debugging( "Argument %d to %s() must be of type %s, %s given", paramNum + 1, func->fullName()->data(), fullName().c_str(), givenType); } else if (isExtended() && isNullable()) { raise_typehint_error( folly::format( "Argument {} to {}() must be of type {}, {} given", paramNum + 1, func->fullName()->data(), fullName(), givenType ).str() ); } else { raise_typehint_error( folly::format( "Argument {} passed to {}() must be an instance of {}, {} given", paramNum + 1, func->fullName()->data(), tn->data(), givenType ).str() ); } }
void TypeConstraint::verifyFail(const Func* func, int paramNum, const TypedValue* tv) const { Transl::VMRegAnchor _; std::ostringstream fname; fname << func->fullName()->data() << "()"; const StringData* tn = typeName(); if (isSelf()) { selfToTypeName(func, &tn); } else if (isParent()) { parentToTypeName(func, &tn); } auto const givenType = describe_actual_type(tv); if (isExtended()) { // Extended type hints raise warnings instead of recoverable // errors for now, to ease migration (we used to not check these // at all at runtime). assert(nullable() && "only nullable extended type hints are currently supported"); raise_warning( "Argument %d to %s must be of type ?%s, %s given", paramNum + 1, fname.str().c_str(), tn->data(), givenType); } else { raise_recoverable_error( "Argument %d passed to %s must be an instance of %s, %s given", paramNum + 1, fname.str().c_str(), tn->data(), givenType); } }
bool TypeConstraint::compat(const TypeConstraint& other) const { if (other.isExtended() || isExtended()) { /* * Rely on the ahead of time typechecker---checking here can * make it harder to convert a base class or interface to <?hh, * because derived classes that are still <?php would all need * to be modified. */ return true; } if (m_typeName == other.m_typeName) { return true; } if (m_typeName && other.m_typeName) { if (m_typeName->isame(other.m_typeName)) { return true; } const Class* cls = Unit::lookupClass(m_typeName); const Class* otherCls = Unit::lookupClass(other.m_typeName); return cls && otherCls && cls == otherCls; } return false; }
uint32_t CanMessage::getId() const { if (isExtended()) { return _raw_id & id_mask_extended; } else { return _raw_id & id_mask_standard; } }
QString CanMessage::getIdString() const { if (isExtended()) { return QString().sprintf("0x%08X", getId()); } else { return QString().sprintf("0x%03X", getId()); } }
/*! \fn void QPaintEngine::syncState() \internal Updates all dirty states in this engine. This function should ONLY be used when drawing with native handles directly and immediate sync from QPainters state to the native state is required. */ void QPaintEngine::syncState() { Q_ASSERT(state); updateState(*state); if (isExtended()) static_cast<QPaintEngineEx *>(this)->sync(); }
std::string TypeConstraint::displayName(const Func* func /*= nullptr*/) const { const StringData* tn = typeName(); std::string name; if (isSoft()) { name += '@'; } if (isNullable() && isExtended()) { name += '?'; } if (func && isSelf()) { selfToTypeName(func, &tn); name += tn->data(); } else if (func && isParent()) { parentToTypeName(func, &tn); name += tn->data(); } else { const char* str = tn->data(); auto len = tn->size(); if (len > 3 && tolower(str[0]) == 'h' && tolower(str[1]) == 'h' && str[2] == '\\') { bool strip = false; const char* stripped = str + 3; switch (len - 3) { case 3: strip = (!strcasecmp(stripped, "int") || !strcasecmp(stripped, "num")); break; case 4: strip = !strcasecmp(stripped, "bool"); break; case 5: strip = !strcasecmp(stripped, "float"); break; case 6: strip = !strcasecmp(stripped, "string"); break; case 8: strip = (!strcasecmp(stripped, "resource") || !strcasecmp(stripped, "noreturn") || !strcasecmp(stripped, "arraykey")); break; default: break; } if (strip) { str = stripped; } } name += str; } return name; }
void TypeConstraint::verifyFail(const Func* func, int paramNum, const TypedValue* tv) const { Transl::VMRegAnchor _; std::ostringstream fname; fname << func->fullName()->data() << "()"; const StringData* tn = typeName(); if (isSelf()) { selfToTypeName(func, &tn); } else if (isParent()) { parentToTypeName(func, &tn); } auto const givenType = describe_actual_type(tv); if (isExtended()) { if (isSoft()) { // Soft type hints raise warnings instead of recoverable // errors by design, to ease migration. raise_warning( "Argument %d passed to %s must be of type %s, %s given", paramNum + 1, fname.str().c_str(), fullName().c_str(), givenType); } else if (isNullable()) { // This error message is slightly different from the normal case // (fullName() vs tn) raise_recoverable_error( "Argument %d passed to %s must be of type %s, %s given", paramNum + 1, fname.str().c_str(), fullName().c_str(), givenType); } else { assert(false && "Only nullable and soft extended type hints are currently implemented"); } } else { raise_recoverable_error( "Argument %d passed to %s must be an instance of %s, %s given", paramNum + 1, fname.str().c_str(), tn->data(), givenType); } }
//slot void KShortcutsEditorDelegate::itemActivated(QModelIndex index) { //As per our constructor our parent *is* a QTreeWidget QTreeWidget *view = static_cast<QTreeWidget *>(parent()); KShortcutsEditorItem *item = KShortcutsEditorPrivate::itemFromIndex(view, index); if (!item) { //that probably was a non-leaf (type() !=ActionItem) item return; } int column = index.column(); if (column == Name) { // If user click in the name column activate the (Global|Local)Primary // column if possible. if (!view->header()->isSectionHidden(LocalPrimary)) { column = LocalPrimary; } else if (!view->header()->isSectionHidden(GlobalPrimary)) { column = GlobalPrimary; } else { // do nothing. } index = index.sibling(index.row(), column); view->selectionModel()->select(index, QItemSelectionModel::SelectCurrent); } // Check if the models wants us to edit the item at index if (!index.data(ShowExtensionIndicatorRole).value<bool>()) { return; } if (!isExtended(index)) { //we only want maximum ONE extender open at any time. if (m_editingIndex.isValid()) { KShortcutsEditorItem *oldItem = KShortcutsEditorPrivate::itemFromIndex(view, m_editingIndex); Q_ASSERT(oldItem); //here we really expect nothing but a real KShortcutsEditorItem oldItem->setNameBold(false); contractItem(m_editingIndex); } m_editingIndex = index; QWidget *viewport = static_cast<QAbstractItemView *>(parent())->viewport(); if (column >= LocalPrimary && column <= GlobalAlternate) { ShortcutEditWidget *editor = new ShortcutEditWidget(viewport, index.data(DefaultShortcutRole).value<QKeySequence>(), index.data(ShortcutRole).value<QKeySequence>(), m_allowLetterShortcuts); if (column == GlobalPrimary) { QObject *action = index.data(ObjectRole).value<QObject *>(); editor->setAction(action); editor->setMultiKeyShortcutsAllowed(false); QString componentName = action->property("componentName").toString(); if (componentName.isEmpty()) { componentName = QCoreApplication::applicationName(); } editor->setComponentName(componentName); } m_editor = editor; // For global shortcuts check against the kde standard shortcuts if (column == GlobalPrimary || column == GlobalAlternate) { editor->setCheckForConflictsAgainst( KKeySequenceWidget::LocalShortcuts | KKeySequenceWidget::GlobalShortcuts | KKeySequenceWidget::StandardShortcuts); } editor->setCheckActionCollections(m_checkActionCollections); connect(m_editor, SIGNAL(keySequenceChanged(QKeySequence)), this, SLOT(keySequenceChanged(QKeySequence))); connect(m_editor, SIGNAL(stealShortcut(QKeySequence,QAction*)), this, SLOT(stealShortcut(QKeySequence,QAction*))); } else if (column == RockerGesture) {
void TypeConstraint::init() { if (UNLIKELY(s_typeNamesToTypes.empty())) { const struct Pair { const StringData* name; Type type; } pairs[] = { { StringData::GetStaticString("bool"), { KindOfBoolean, MetaType::Precise }}, { StringData::GetStaticString("boolean"), { KindOfBoolean, MetaType::Precise }}, { StringData::GetStaticString("int"), { KindOfInt64, MetaType::Precise }}, { StringData::GetStaticString("integer"), { KindOfInt64, MetaType::Precise }}, { StringData::GetStaticString("real"), { KindOfDouble, MetaType::Precise }}, { StringData::GetStaticString("double"), { KindOfDouble, MetaType::Precise }}, { StringData::GetStaticString("float"), { KindOfDouble, MetaType::Precise }}, { StringData::GetStaticString("string"), { KindOfString, MetaType::Precise }}, { StringData::GetStaticString("array"), { KindOfArray, MetaType::Precise }}, { StringData::GetStaticString("resource"), { KindOfResource, MetaType::Precise }}, { StringData::GetStaticString("self"), { KindOfObject, MetaType::Self }}, { StringData::GetStaticString("parent"), { KindOfObject, MetaType::Parent }}, { StringData::GetStaticString("callable"), { KindOfObject, MetaType::Callable }}, }; for (unsigned i = 0; i < sizeof(pairs) / sizeof(Pair); ++i) { s_typeNamesToTypes[pairs[i].name] = pairs[i].type; } } if (m_typeName && isExtended()) { assert(nullable() && "Only nullable extended type hints are implemented"); } if (blacklistedName(m_typeName)) { m_typeName = nullptr; } if (m_typeName == nullptr) { m_type.m_dt = KindOfInvalid; m_type.m_metatype = MetaType::Precise; return; } Type dtype; TRACE(5, "TypeConstraint: this %p type %s, nullable %d\n", this, m_typeName->data(), nullable()); if (!mapGet(s_typeNamesToTypes, m_typeName, &dtype) || !(hhType() || dtype.m_dt == KindOfArray || dtype.isParent() || dtype.isSelf())) { TRACE(5, "TypeConstraint: this %p no such type %s, treating as object\n", this, m_typeName->data()); m_type = { KindOfObject, MetaType::Precise }; m_namedEntity = Unit::GetNamedEntity(m_typeName); TRACE(5, "TypeConstraint: NamedEntity: %p\n", m_namedEntity); return; } m_type = dtype; assert(m_type.m_dt != KindOfStaticString); assert(IMPLIES(isParent(), m_type.m_dt == KindOfObject)); assert(IMPLIES(isSelf(), m_type.m_dt == KindOfObject)); assert(IMPLIES(isCallable(), m_type.m_dt == KindOfObject)); }
void TypeConstraint::verifyFail(const Func* func, TypedValue* tv, int id, bool useStrictTypes) const { VMRegAnchor _; std::string name = displayName(func); auto const givenType = describe_actual_type(tv, isHHType()); if (UNLIKELY(!useStrictTypes)) { if (auto dt = underlyingDataType()) { // In non-strict mode we may be able to coerce a type failure. For object // typehints there is no possible coercion in the failure case, but HNI // builtins currently only guard on kind not class so the following wil // generate false positives for objects. if (*dt != KindOfObject) { // HNI conversions implicitly unbox references, this behavior is wrong, // in particular it breaks the way type conversion works for PHP 7 // scalar type hints if (tv->m_type == KindOfRef) { auto inner = tv->m_data.pref->var()->asTypedValue(); if (tvCoerceParamInPlace(inner, *dt)) { tvAsVariant(tv) = tvAsVariant(inner); return; } } else { if (tvCoerceParamInPlace(tv, *dt)) return; } } } } else if (UNLIKELY(!func->unit()->isHHFile() && !RuntimeOption::EnableHipHopSyntax)) { // PHP 7 allows for a widening conversion from Int to Float. We still ban // this in HH files. if (auto dt = underlyingDataType()) { if (*dt == KindOfDouble && tv->m_type == KindOfInt64 && tvCoerceParamToDoubleInPlace(tv)) { return; } } } // Handle return type constraint failures if (id == ReturnId) { std::string msg; if (func->isClosureBody()) { msg = folly::format( "Value returned from {}closure must be of type {}, {} given", func->isAsync() ? "async " : "", name, givenType ).str(); } else { msg = folly::format( "Value returned from {}{} {}() must be of type {}, {} given", func->isAsync() ? "async " : "", func->preClass() ? "method" : "function", func->fullName(), name, givenType ).str(); } if (RuntimeOption::EvalCheckReturnTypeHints >= 2 && !isSoft()) { raise_return_typehint_error(msg); } else { raise_warning_unsampled(msg); } return; } // Handle implicit collection->array conversion for array parameter type // constraints auto c = tvToCell(tv); if (isArray() && !isSoft() && !func->mustBeRef(id) && c->m_type == KindOfObject && c->m_data.pobj->isCollection()) { // To ease migration, the 'array' type constraint will implicitly cast // collections to arrays, provided the type constraint is not soft and // the parameter is not by reference. We raise a notice to let the user // know that there was a type mismatch and that an implicit conversion // was performed. raise_notice( folly::format( "Argument {} to {}() must be of type {}, {} given; argument {} was " "implicitly cast to array", id + 1, func->fullName(), name, givenType, id + 1 ).str() ); tvCastToArrayInPlace(tv); return; } // Handle parameter type constraint failures if (isExtended() && isSoft()) { // Soft extended type hints raise warnings instead of recoverable // errors, to ease migration. raise_warning_unsampled( folly::format( "Argument {} to {}() must be of type {}, {} given", id + 1, func->fullName(), name, givenType ).str() ); } else if (isExtended() && isNullable()) { raise_typehint_error( folly::format( "Argument {} to {}() must be of type {}, {} given", id + 1, func->fullName(), name, givenType ).str() ); } else { auto cls = Unit::lookupClass(m_typeName); if (cls && isInterface(cls)) { raise_typehint_error( folly::format( "Argument {} passed to {}() must implement interface {}, {} given", id + 1, func->fullName(), name, givenType ).str() ); } else { raise_typehint_error( folly::format( "Argument {} passed to {}() must be an instance of {}, {} given", id + 1, func->fullName(), name, givenType ).str() ); } } }
void TypeConstraint::init() { if (UNLIKELY(s_typeNamesToTypes.empty())) { const struct Pair { const StringData* name; Type type; } pairs[] = { { makeStaticString("bool"), { KindOfBoolean, MetaType::Precise }}, { makeStaticString("boolean"), { KindOfBoolean, MetaType::Precise }}, { makeStaticString("int"), { KindOfInt64, MetaType::Precise }}, { makeStaticString("integer"), { KindOfInt64, MetaType::Precise }}, { makeStaticString("real"), { KindOfDouble, MetaType::Precise }}, { makeStaticString("double"), { KindOfDouble, MetaType::Precise }}, { makeStaticString("float"), { KindOfDouble, MetaType::Precise }}, { makeStaticString("string"), { KindOfString, MetaType::Precise }}, { makeStaticString("array"), { KindOfArray, MetaType::Precise }}, { makeStaticString("resource"), { KindOfResource, MetaType::Precise }}, { makeStaticString("self"), { KindOfObject, MetaType::Self }}, { makeStaticString("parent"), { KindOfObject, MetaType::Parent }}, { makeStaticString("callable"), { KindOfObject, MetaType::Callable }}, { makeStaticString("num"), { KindOfDouble, MetaType::Number }}, }; for (unsigned i = 0; i < sizeof(pairs) / sizeof(Pair); ++i) { s_typeNamesToTypes[pairs[i].name] = pairs[i].type; } } if (isTypeVar()) { // We kept the type variable type constraint to correctly check child // classes implementing abstract methods or interfaces. m_type.dt = KindOfInvalid; m_type.metatype = MetaType::Precise; return; } if (m_typeName && isExtended()) { assert((isNullable() || isSoft()) && "Only nullable and soft extended type hints are implemented"); } if (m_typeName == nullptr) { m_type.dt = KindOfInvalid; m_type.metatype = MetaType::Precise; return; } Type dtype; TRACE(5, "TypeConstraint: this %p type %s, nullable %d\n", this, m_typeName->data(), isNullable()); auto const mptr = folly::get_ptr(s_typeNamesToTypes, m_typeName); if (mptr) dtype = *mptr; if (!mptr || !(isHHType() || dtype.dt == KindOfArray || dtype.metatype == MetaType::Parent || dtype.metatype == MetaType::Self || dtype.metatype == MetaType::Callable)) { TRACE(5, "TypeConstraint: this %p no such type %s, treating as object\n", this, m_typeName->data()); m_type = { KindOfObject, MetaType::Precise }; m_namedEntity = Unit::GetNamedEntity(m_typeName); TRACE(5, "TypeConstraint: NamedEntity: %p\n", m_namedEntity); return; } m_type = dtype; assert(m_type.dt != KindOfStaticString); assert(IMPLIES(isParent(), m_type.dt == KindOfObject)); assert(IMPLIES(isSelf(), m_type.dt == KindOfObject)); assert(IMPLIES(isCallable(), m_type.dt == KindOfObject)); }
void TypeConstraint::verifyFail(const Func* func, TypedValue* tv, int id) const { VMRegAnchor _; std::string name = displayName(func); auto const givenType = describe_actual_type(tv, isHHType()); // Handle return type constraint failures if (id == ReturnId) { std::string msg; if (func->isClosureBody()) { msg = folly::format( "Value returned from {}closure must be of type {}, {} given", func->isAsync() ? "async " : "", name, givenType ).str(); } else { msg = folly::format( "Value returned from {}{} {}() must be of type {}, {} given", func->isAsync() ? "async " : "", func->preClass() ? "method" : "function", func->fullName()->data(), name, givenType ).str(); } if (RuntimeOption::EvalCheckReturnTypeHints >= 2 && !isSoft() && (!func->isClosureBody() || !RuntimeOption::EvalSoftClosureReturnTypeHints)) { raise_return_typehint_error(msg); } else { raise_debugging(msg); } return; } // Handle implicit collection->array conversion for array parameter type // constraints auto c = tvToCell(tv); if (isArray() && !isSoft() && !func->mustBeRef(id) && c->m_type == KindOfObject && c->m_data.pobj->isCollection()) { // To ease migration, the 'array' type constraint will implicitly cast // collections to arrays, provided the type constraint is not soft and // the parameter is not by reference. We raise a notice to let the user // know that there was a type mismatch and that an implicit conversion // was performed. raise_notice( folly::format( "Argument {} to {}() must be of type {}, {} given; argument {} was " "implicitly cast to array", id + 1, func->fullName()->data(), name, givenType, id + 1 ).str() ); tvCastToArrayInPlace(tv); return; } // Handle parameter type constraint failures if (isExtended() && isSoft()) { // Soft extended type hints raise warnings instead of recoverable // errors, to ease migration. raise_debugging( folly::format( "Argument {} to {}() must be of type {}, {} given", id + 1, func->fullName()->data(), name, givenType ).str() ); } else if (isExtended() && isNullable()) { raise_typehint_error( folly::format( "Argument {} to {}() must be of type {}, {} given", id + 1, func->fullName()->data(), name, givenType ).str() ); } else { auto cls = Unit::lookupClass(m_typeName); if (cls && isInterface(cls)) { raise_typehint_error( folly::format( "Argument {} passed to {}() must implement interface {}, {} given", id + 1, func->fullName()->data(), name, givenType ).str() ); } else { raise_typehint_error( folly::format( "Argument {} passed to {}() must be an instance of {}, {} given", id + 1, func->fullName()->data(), name, givenType ).str() ); } } }
// ----------------------------------------------------------------------------- // (Re)builds lists with information about all currently available resource // textures and flats // ----------------------------------------------------------------------------- void MapTextureManager::buildTexInfoList() { // Clear tex_info_.clear(); flat_info_.clear(); // --- Textures --- // Composite textures vector<TextureResource::Texture*> textures; App::resources().putAllTextures(textures, App::archiveManager().baseResourceArchive()); for (auto& texture : textures) { auto tex = &texture->tex; auto parent = texture->parent; auto long_name = tex->name(); auto path = StrUtil::beforeLast(long_name, '/'); if (tex->isExtended()) { if (StrUtil::equalCI(tex->type(), "texture") || StrUtil::equalCI(tex->type(), "walltexture")) tex_info_.emplace_back(long_name, Category::ZDTextures, parent, path, tex->index(), long_name); else if (StrUtil::equalCI(tex->type(), "define")) tex_info_.emplace_back(long_name, Category::HiRes, parent, path, tex->index(), long_name); else if (StrUtil::equalCI(tex->type(), "flat")) flat_info_.emplace_back(long_name, Category::ZDTextures, parent, path, tex->index(), long_name); // Ignore graphics, patches and sprites } else tex_info_.emplace_back(long_name, Category::TextureX, parent, path, tex->index() + 1, long_name); } // Texture namespace patches (TX_) if (Game::configuration().featureSupported(Game::Feature::TxTextures)) { vector<ArchiveEntry*> patches; App::resources().putAllPatchEntries( patches, nullptr, Game::configuration().featureSupported(Game::Feature::LongNames)); for (auto& patch : patches) { if (patch->isInNamespace("textures") || patch->isInNamespace("hires")) { // Determine texture path if it's in a pk3 auto long_name = patch->path(true).erase(0, 1); auto short_name = StrUtil::truncate(patch->upperNameNoExt(), 8); auto path = patch->path(false); tex_info_.emplace_back(short_name, Category::Tx, patch->parent(), path, 0, long_name); } } } // Flats vector<ArchiveEntry*> flats; App::resources().putAllFlatEntries( flats, nullptr, Game::configuration().featureSupported(Game::Feature::LongNames)); for (auto& flat : flats) { // Determine flat path if it's in a pk3 auto long_name = flat->path(true).erase(0, 1); auto short_name = StrUtil::truncate(flat->upperNameNoExt(), 8); auto path = flat->path(false); flat_info_.emplace_back(short_name, Category::None, flat->parent(), path, 0, long_name); } }
// ----------------------------------------------------------------------------- // Returns the flat matching [name], loading it from resources if necessary. // If [mixed] is true, textures are also searched if no matching flat is found // ----------------------------------------------------------------------------- const MapTextureManager::Texture& MapTextureManager::flat(std::string_view name, bool mixed) { // Get flat matching name auto& mtex = flats_[StrUtil::upper(name)]; // Get desired filter type auto filter = OpenGL::TexFilter::Linear; if (map_tex_filter == 0) filter = OpenGL::TexFilter::NearestLinearMin; else if (map_tex_filter == 1) filter = OpenGL::TexFilter::Linear; else if (map_tex_filter == 2) filter = OpenGL::TexFilter::LinearMipmap; else if (map_tex_filter == 3) filter = OpenGL::TexFilter::NearestMipmap; // If the texture is loaded if (mtex.gl_id) { // If the texture filter matches the desired one, return it auto& tex_info = OpenGL::Texture::info(mtex.gl_id); if (tex_info.filter == filter) return mtex; else { // Otherwise, reload the texture OpenGL::Texture::clear(mtex.gl_id); mtex.gl_id = 0; } } if (mixed) { auto ctex = App::resources().getTexture(name, archive_); if (ctex && ctex->isExtended() && ctex->type() != "WallTexture") { SImage image; if (ctex->toImage(image, archive_, palette_.get(), true)) { mtex.gl_id = OpenGL::Texture::createFromImage(image, palette_.get(), filter); double sx = ctex->scaleX(); if (sx == 0) sx = 1.0; double sy = ctex->scaleY(); if (sy == 0) sy = 1.0; mtex.scale = { 1.0 / sx, 1.0 / sy }; mtex.world_panning = ctex->worldPanning(); return mtex; } } } // Flat not found, look for it // Palette8bit* pal = getResourcePalette(); if (!mtex.gl_id) { auto entry = App::resources().getTextureEntry(name, "hires", archive_); if (entry == nullptr) entry = App::resources().getTextureEntry(name, "flats", archive_); if (entry == nullptr) entry = App::resources().getFlatEntry(name, archive_); if (entry) { SImage image; if (Misc::loadImageFromEntry(&image, entry)) mtex.gl_id = OpenGL::Texture::createFromImage(image, palette_.get(), filter); } } // Not found if (!mtex.gl_id) { // Try textures if mixed if (mixed) return texture(name, false); // Otherwise use missing texture else mtex.gl_id = OpenGL::Texture::missingTexture(); } return mtex; }
// ----------------------------------------------------------------------------- // Checks all texture definitions for problems and alerts the user if any are // found. Returns true if any problems were found, false otherwise // ----------------------------------------------------------------------------- bool TextureXEditor::checkTextures() { wxString problems = wxEmptyString; // Go through all texturex lists for (auto& texture_editor : texture_editors_) { // Go through all textures for (unsigned t = 0; t < texture_editor->txList().size(); t++) { // Get texture auto tex = texture_editor->txList().texture(t); // Check its patches are all valid if (tex->isExtended()) { // Extended texture, check if each patch exists in any open archive (or as a composite texture) for (unsigned p = 0; p < tex->nPatches(); p++) { auto pentry = App::resources().getPatchEntry(tex->patch(p)->name()); auto fentry = App::resources().getFlatEntry(tex->patch(p)->name()); auto ptex = App::resources().getTexture(tex->patch(p)->name()); if (!pentry && !fentry && !ptex) problems += wxString::Format( "Texture %s contains invalid/unknown patch %s\n", tex->name(), tex->patch(p)->name()); } } else { // Regular texture, check the patch table for (unsigned p = 0; p < tex->nPatches(); p++) { if (patch_table_.patchIndex(tex->patch(p)->name()) == -1) problems += wxString::Format( "Texture %s contains invalid/unknown patch %s\n", tex->name(), tex->patch(p)->name()); } } } } // Go through patch table for (unsigned a = 0; a < patch_table_.nPatches(); a++) { // Check patch entry is valid auto& patch = patch_table_.patch(a); auto entry = App::resources().getPatchEntry(patch.name, "patches", archive_); if (!entry) { problems += wxString::Format("Patch %s cannot be found in any open archive\n", patch.name); } else { // Check patch entry type if (entry->type() == EntryType::unknownType()) EntryType::detectEntryType(entry); auto type = entry->type(); if (!type->extraProps().propertyExists("patch")) problems += wxString::Format( "Patch %s is of type \"%s\", which is not a valid gfx format for patches. " "Convert it to either Doom Gfx or PNG\n", patch.name, type->name()); } } // Display a message box with any problems found if (!problems.IsEmpty()) { ExtMessageDialog dlg(this, "Problems Found"); dlg.setMessage("The following problems were found:"); dlg.setExt(problems); dlg.ShowModal(); return true; } else return false; }