void NormalMapIdentification::HandleAssetPostImport( UFactory* InFactory, UObject* InObject ) { UTextureFactory* TextureFactory = Cast<UTextureFactory>(InFactory); UTexture* Texture = Cast<UTexture>(InObject); if(TextureFactory != NULL && Texture != NULL) { // Try to automatically identify a normal map if ( !TextureFactory->bUsingExistingSettings && IsTextureANormalMap( Texture ) ) { // Set the compression settings and no gamma correction for a normal map { Texture->SetFlags(RF_Transactional); const FScopedTransaction Transaction( NSLOCTEXT("AutoNormalMapID", "ImportAsNormalMap", "Import As Normal Map") ); Texture->Modify(); Texture->CompressionSettings = TC_Normalmap; Texture->SRGB = false; Texture->LODGroup = TEXTUREGROUP_WorldNormalMap; Texture->bFlipGreenChannel = TextureFactory->bFlipNormalMapGreenChannel; } // Show the user a notification indicating that this texture will be imported as a normal map. // Offer two options to the user, "OK" dismisses the notification early, "Revert" reverts the settings to that of a diffuse map. TSharedPtr<NormalMapImportNotificationHandler> NormalMapNotificationDelegate(new NormalMapImportNotificationHandler); { NormalMapNotificationDelegate->Texture = Texture; // this is a cheat to make sure the notification keeps the callback thing alive while it's active... FText OKText = LOCTEXT("ImportTexture_OKNormalMapSettings", "OK"); FText OKTooltipText = LOCTEXT("ImportTexture_OKTooltip", "Accept normal map settings"); FText RevertText = LOCTEXT("ImportTexture_RevertNormalMapSettings", "Revert"); FText RevertTooltipText = LOCTEXT("ImportTexture_RevertTooltip", "Revert to diffuse map settings"); FFormatNamedArguments Args; Args.Add( TEXT("TextureName"), FText::FromName(Texture->GetFName()) ); FNotificationInfo NormalMapNotification( FText::Format(LOCTEXT("ImportTexture_IsNormalMap", "Texture {TextureName} was imported as a normal map"), Args ) ); NormalMapNotification.ButtonDetails.Add(FNotificationButtonInfo(OKText, OKTooltipText, FSimpleDelegate::CreateSP(NormalMapNotificationDelegate.Get(), &NormalMapImportNotificationHandler::OKSetting, NormalMapNotificationDelegate))); NormalMapNotification.ButtonDetails.Add(FNotificationButtonInfo(RevertText, RevertTooltipText, FSimpleDelegate::CreateSP(NormalMapNotificationDelegate.Get(), &NormalMapImportNotificationHandler::RevertSetting, NormalMapNotificationDelegate))); NormalMapNotification.bFireAndForget = true; NormalMapNotification.bUseLargeFont = false; NormalMapNotification.bUseSuccessFailIcons = false; NormalMapNotification.bUseThrobber = false; NormalMapNotification.ExpireDuration = 10.0f; NormalMapNotificationDelegate->Notification = FSlateNotificationManager::Get().AddNotification(NormalMapNotification); if ( NormalMapNotificationDelegate->Notification.IsValid() ) { NormalMapNotificationDelegate->Notification.Pin()->SetCompletionState(SNotificationItem::CS_Pending); } } } } }
/** * Useful for stats in the editor. */ void FTextureLODSettings::ComputeInGameMaxResolution(int32 LODBias, UTexture &Texture, uint32 &OutSizeX, uint32 &OutSizeY) const { uint32 ImportedSizeX = FMath::Trunc(Texture.GetSurfaceWidth()); uint32 ImportedSizeY = FMath::Trunc(Texture.GetSurfaceHeight()); const FTextureLODGroup& LODGroup = GetTextureLODGroup((TextureGroup)Texture.LODGroup); uint32 SourceLOD = FMath::Max(FMath::CeilLogTwo(ImportedSizeX), FMath::CeilLogTwo(ImportedSizeY)); uint32 MinLOD = FMath::Max(uint32(UTexture2D::GetMinTextureResidentMipCount() - 1), (uint32)LODGroup.MinLODMipCount); uint32 MaxLOD = FMath::Min(uint32(GMaxTextureMipCount - 1), (uint32)LODGroup.MaxLODMipCount); uint32 GameLOD = FMath::Min(SourceLOD, FMath::Clamp(SourceLOD - LODBias, MinLOD, MaxLOD)); uint32 DeltaLOD = SourceLOD - GameLOD; OutSizeX = ImportedSizeX >> DeltaLOD; OutSizeY = ImportedSizeY >> DeltaLOD; }
/** * Iterate through all textures used by the material and return the maximum texture resolution used * (ideally this could be made dependent of the material property) * * @param MaterialInterface The material to scan for texture size * * @return Size (width and height) */ FIntPoint FindMaxTextureSize(UMaterialInterface* InMaterialInterface, FIntPoint MinimumSize = FIntPoint(1, 1)) const { // static lod settings so that we only initialize them once UTextureLODSettings* GameTextureLODSettings = UDeviceProfileManager::Get().GetActiveProfile()->GetTextureLODSettings(); TArray<UTexture*> MaterialTextures; InMaterialInterface->GetUsedTextures(MaterialTextures, EMaterialQualityLevel::Num, false, GMaxRHIFeatureLevel, false); // find the largest texture in the list (applying it's LOD bias) FIntPoint MaxSize = MinimumSize; for (int32 TexIndex = 0; TexIndex < MaterialTextures.Num(); TexIndex++) { UTexture* Texture = MaterialTextures[TexIndex]; if (Texture == NULL) { continue; } // get the max size of the texture FIntPoint LocalSize(0, 0); if (Texture->IsA(UTexture2D::StaticClass())) { UTexture2D* Tex2D = (UTexture2D*)Texture; LocalSize = FIntPoint(Tex2D->GetSizeX(), Tex2D->GetSizeY()); } else if (Texture->IsA(UTextureCube::StaticClass())) { UTextureCube* TexCube = (UTextureCube*)Texture; LocalSize = FIntPoint(TexCube->GetSizeX(), TexCube->GetSizeY()); } int32 LocalBias = GameTextureLODSettings->CalculateLODBias(Texture); // bias the texture size based on LOD group FIntPoint BiasedLocalSize(LocalSize.X >> LocalBias, LocalSize.Y >> LocalBias); MaxSize.X = FMath::Max(BiasedLocalSize.X, MaxSize.X); MaxSize.Y = FMath::Max(BiasedLocalSize.Y, MaxSize.Y); } return MaxSize; }
void UTextureThumbnailRenderer::GetThumbnailSize(UObject* Object, float Zoom, uint32& OutWidth, uint32& OutHeight) const { UTexture* Texture = Cast<UTexture>(Object); UTextureLightProfile* TextureLightProfile = Cast<UTextureLightProfile>(Object); if (TextureLightProfile) { // otherwise a 1D texture would result in a very boring thumbnail OutWidth = 192; OutHeight = 192; return; } if (Texture != nullptr) { OutWidth = FMath::TruncToInt(Zoom * (float)Texture->GetSurfaceWidth()); OutHeight = FMath::TruncToInt(Zoom * (float)Texture->GetSurfaceHeight()); } else { OutWidth = OutHeight = 0; } }
bool UTexture::ForceUpdateTextureStreaming() { if (!IStreamingManager::HasShutdown()) { #if WITH_EDITOR for( TObjectIterator<UTexture2D> It; It; ++It ) { UTexture* Texture = *It; // Update cached LOD bias. Texture->UpdateCachedLODBias(); } #endif // #if WITH_EDITOR // Make sure we iterate over all textures by setting it to high value. IStreamingManager::Get().SetNumIterationsForNextFrame( 100 ); // Update resource streaming with updated texture LOD bias/ max texture mip count. IStreamingManager::Get().UpdateResourceStreaming( 0 ); // Block till requests are finished. IStreamingManager::Get().BlockTillAllRequestsFinished(); } return true; }
void FTextureLODSettings::GetMipGenSettings( const UTexture& Texture, TextureMipGenSettings& OutMipGenSettings, float& OutSharpen, uint32& OutKernelSize, bool& bOutDownsampleWithAverage, bool& bOutSharpenWithoutColorShift, bool &bOutBorderColorBlack ) const { TextureMipGenSettings Setting = (TextureMipGenSettings)Texture.MipGenSettings; bOutBorderColorBlack = false; // avoiding the color shift assumes we deal with colors which is not true for normalmaps // or we blur where it's good to blur the color as well bOutSharpenWithoutColorShift = !Texture.IsNormalMap(); bOutDownsampleWithAverage = true; // inherit from texture group if(Setting == TMGS_FromTextureGroup) { const FTextureLODGroup& LODGroup = TextureLODGroups[Texture.LODGroup]; Setting = LODGroup.MipGenSettings; } OutMipGenSettings = Setting; // ------------ // default: OutSharpen = 0; OutKernelSize = 2; if(Setting >= TMGS_Sharpen0 && Setting <= TMGS_Sharpen10) { // 0 .. 2.0f OutSharpen = ((int32)Setting - (int32)TMGS_Sharpen0) * 0.2f; OutKernelSize = 8; } else if(Setting >= TMGS_Blur1 && Setting <= TMGS_Blur5) { int32 BlurFactor = ((int32)Setting + 1 - (int32)TMGS_Blur1); OutSharpen = -BlurFactor * 2; OutKernelSize = 2 + 2 * BlurFactor; bOutDownsampleWithAverage = false; bOutSharpenWithoutColorShift = false; bOutBorderColorBlack = true; } }
UObject* USspjFactory::FactoryCreateBinary(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const uint8*& Buffer, const uint8* InBufferEnd, FFeedbackContext* Warn) { bool bReimport = this->IsA(UReimportSspjFactory::StaticClass()); TMap<FString, UTexture*>* ExistImages = NULL; if(bReimport) { ExistImages = &(Cast<UReimportSspjFactory>(this)->ExistImages); } FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools"); FString ProjectNameStr = InName.ToString(); FName ProjectName = InName; UPackage* InParentPackage = Cast<UPackage>(InParent); if(InParentPackage && !bReimport) { FString ProjectPackageName; FString BasePackageName = FPackageName::GetLongPackagePath(InParent->GetOutermost()->GetName()) / ProjectNameStr; AssetToolsModule.Get().CreateUniqueAssetName(BasePackageName, TEXT(""), ProjectPackageName, ProjectNameStr); InParentPackage->Rename(*ProjectPackageName); } // インポート設定の取得 const USsImportSettings* ImportSettings = GetDefault<USsImportSettings>(); // インポート開始 FEditorDelegates::OnAssetPreImport.Broadcast(this, InClass, InParent, ProjectName, Type); // sspj USsProject* NewProject = FSsLoader::LoadSsProject(InParent, ProjectName, Flags, Buffer, (InBufferEnd - Buffer) + 1); NewProject->SetFilepath( GetCurrentFilename() ); if(NewProject) { if(NewProject->AssetImportData == nullptr) { NewProject->AssetImportData = NewObject<UAssetImportData>(NewProject); } NewProject->AssetImportData->Update(CurrentFilename); FString CurPath = FPaths::GetPath(GetCurrentFilename()); TArray<FString> ImagePaths; TArray<SsTexWrapMode::Type> ImageWrapModes; TArray<SsTexFilterMode::Type> ImageFilterModes; // ssce NewProject->CellmapList.Empty(); NewProject->CellmapList.AddZeroed(NewProject->CellmapNames.Num()); for(int i = 0; i < NewProject->CellmapNames.Num(); ++i) { FString FileName = GetFilePath(CurPath, NewProject->Settings.CellMapBaseDirectory, NewProject->CellmapNames[i].ToString()); TArray<uint8> Data; if(FFileHelper::LoadFileToArray(Data, *FileName)) { const uint8* BufferBegin = Data.GetData(); const uint8* BufferEnd = BufferBegin + Data.Num() - 1; if(FSsLoader::LoadSsCellMap(&(NewProject->CellmapList[i]), BufferBegin, (BufferEnd - BufferBegin) + 1)) { NewProject->CellmapList[i].FileName = NewProject->CellmapNames[i]; if(0 < NewProject->CellmapList[i].ImagePath.Len()) { if(INDEX_NONE == ImagePaths.Find(NewProject->CellmapList[i].ImagePath)) { ImagePaths.Add(NewProject->CellmapList[i].ImagePath); if(NewProject->CellmapList[i].OverrideTexSettings) { ImageWrapModes.Add(NewProject->CellmapList[i].WrapMode); ImageFilterModes.Add(NewProject->CellmapList[i].FilterMode); } else { ImageWrapModes.Add(NewProject->Settings.WrapMode); ImageFilterModes.Add(NewProject->Settings.FilterMode); } } } } } } // ssae NewProject->AnimeList.Empty(); NewProject->AnimeList.AddZeroed(NewProject->AnimepackNames.Num()); for(int i = 0; i < NewProject->AnimepackNames.Num(); ++i) { FString FileName = GetFilePath(CurPath, NewProject->Settings.AnimeBaseDirectory, NewProject->AnimepackNames[i].ToString()); TArray<uint8> Data; if(FFileHelper::LoadFileToArray(Data, *FileName)) { const uint8* BufferBegin = Data.GetData(); const uint8* BufferEnd = BufferBegin + Data.Num() - 1; FSsLoader::LoadSsAnimePack(&(NewProject->AnimeList[i]), BufferBegin, (BufferEnd - BufferBegin) + 1); } } // texture for(int i = 0; i < ImagePaths.Num(); ++i) { FString FileName = GetFilePath(CurPath, NewProject->Settings.ImageBaseDirectory, ImagePaths[i]); UTexture* ImportedTexture = NULL; if(ExistImages && ExistImages->Contains(ImagePaths[i])) { ImportedTexture = ExistImages->FindChecked(ImagePaths[i]); } TArray<uint8> Data; if(FFileHelper::LoadFileToArray(Data, *FileName)) { UTextureFactory* TextureFact = NewObject<UTextureFactory>(); TextureFact->AddToRoot(); FString TextureName = FPaths::GetBaseFilename(ImagePaths[i]); UPackage* TexturePackage = NULL; if(ImportedTexture) { TexturePackage = ImportedTexture->GetOutermost(); } else { FString TexturePackageName; FString BasePackageName = FPackageName::GetLongPackagePath(InParent->GetOutermost()->GetName()) / TextureName; AssetToolsModule.Get().CreateUniqueAssetName(BasePackageName, TEXT(""), TexturePackageName, TextureName); TexturePackage = CreatePackage(NULL, *TexturePackageName); } const uint8* BufferBegin = Data.GetData(); const uint8* BufferEnd = BufferBegin + Data.Num(); UTexture2D* NewTexture = (UTexture2D*)TextureFact->FactoryCreateBinary( UTexture2D::StaticClass(), TexturePackage, FName(*TextureName), Flags, NULL, *FPaths::GetExtension(ImagePaths[i]), BufferBegin, BufferEnd, Warn ); if(NewTexture) { if(ImportSettings->bOverwriteMipGenSettings) { NewTexture->MipGenSettings = TMGS_NoMipmaps; } if(ImportSettings->bOverwriteTextureGroup) { NewTexture->LODGroup = ImportSettings->TextureGroup; } if(ImportSettings->bOverwriteCompressionSettings) { NewTexture->CompressionSettings = TextureCompressionSettings::TC_EditorIcon; } if(ImportSettings->bOverwriteTilingMethodFromSspj) { switch(ImageWrapModes[i]) { case SsTexWrapMode::Clamp: { NewTexture->AddressX = NewTexture->AddressY = TA_Clamp; } break; case SsTexWrapMode::Repeat: { NewTexture->AddressX = NewTexture->AddressY = TA_Wrap; } break; case SsTexWrapMode::Mirror: { NewTexture->AddressX = NewTexture->AddressY = TA_Mirror; } break; } } if(ImportSettings->bOverwriteNeverStream) { NewTexture->NeverStream = true; } if(ImportSettings->bOverwriteFilterFromSspj) { switch(ImageFilterModes[i]) { case SsTexFilterMode::Nearest: { NewTexture->Filter = TF_Nearest; } break; case SsTexFilterMode::Linear: { NewTexture->Filter = TF_Bilinear; } break; } } NewTexture->UpdateResource(); FAssetRegistryModule::AssetCreated(NewTexture); TexturePackage->SetDirtyFlag(true); TextureFact->RemoveFromRoot(); ImportedTexture = NewTexture; } } if(ImportedTexture) { for(int ii = 0; ii < NewProject->CellmapList.Num(); ++ii) { if(NewProject->CellmapList[ii].ImagePath == ImagePaths[i]) { NewProject->CellmapList[ii].Texture = ImportedTexture; } } } } } // インポート終了 FEditorDelegates::OnAssetPostImport.Broadcast(this, NewProject); return NewProject; }