Developer Headers and Packaging

After running into an issue packaging some code that included the open file dialog for windows platforms, I just want a clarification on what is or is not allowed in a final product. The EULA mentions “The Product may not contain any Engine Tools or any Marketplace Content Distributed in uncooked source format.”, and that Engine Tools refers to “any code and modules in either the Developer or Editor folders, including in object code format, whether statically or dynamically linked”.

This means that any calls to that code is not allowed? I’m currently using a bit of code (based on some code I found somewhere else on the forums) that is using IImageWrapper.h and IImageWrapperModule.h to dynamically load photographs for display. Does this mean I need to remove that and find another solution?

The code in question:

	TArray<uint8> FileData;

	IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
	IImageWrapperPtr ImageWrapper;

	if (path.EndsWith("png") || path.EndsWith("PNG"))
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString("Using PNG loader"));
		ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
	}
	else
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString("Using JPEG loader"));
		ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::JPEG);
	}



	UTexture2D* mytex;

	//GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString("Attempting to load file: ") + path);
	if (FFileHelper::LoadFileToArray(FileData, *path, 0))
	{
		if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(FileData.GetData(), FileData.Num()))
		{
			const TArray<uint8>* UncompressedBGRA = NULL;

			if (ImageWrapper->GetRaw(ERGBFormat::BGRA, 8, UncompressedBGRA))
			{
				mytex = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_B8G8R8A8);
				void* TextureData = mytex->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
				FMemory::Memcpy(TextureData, UncompressedBGRA->GetData(), UncompressedBGRA->Num());
				mytex->PlatformData->Mips[0].BulkData.Unlock();
				mytex->UpdateResource();

				USlateBrushAsset::StaticClass();
				USlateBrushAsset* NewSlateBrushAsset = CastChecked<USlateBrushAsset>(StaticConstructObject(USlateBrushAsset::StaticClass(), GetTransientPackage(), NAME_None, EObjectFlags::RF_NoFlags));
				NewSlateBrushAsset->Brush = mytex != NULL ? FSlateDynamicImageBrush(mytex, FVector2D(mytex->GetImportedSize()), NAME_None) : FSlateBrush();
				NewSlateBrushAsset->Brush.ImageSize.X = mytex->PlatformData->SizeX;
				NewSlateBrushAsset->Brush.ImageSize.Y = mytex->PlatformData->SizeY;

				BrushLibrary.Add(path, NewSlateBrushAsset);

				NewSlateBrushAsset->AddToRoot();

				return NewSlateBrushAsset;
			}
			else
			{
				GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Couldn't get texture data"));
			}
		}
		else
		{
			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Problem with ImageWrapper"));
		}
	}
	else
	{
		GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Red, TEXT("Failed to load file: ")+path);
	}

This means that any calls to that code is not allowed?

Unfortunately, you are correct. Source code in the Developer and Editor folders were designed for Unreal Editor and the auxiliary tools used during development only. That code is not designed to be shipped in your games, and the EULA disallows it because we explicitly don’t want developers to use our code to create products that resemble the editor itself.

Does this mean I need to remove that and find another solution?

Correct. However, we want to help you out if we can. We realize that there are many useful systems in the Developer/Editor folders that might be suitable for use in runtime games, and aren’t really a core part of the editor itself. If you let us know about specific features that you think any game would want to use, we’ll discuss it here and try to get the source code moved into the Runtime folder for an upcoming release!

–Mike

Ok, thanks for the clarification.

Our use case might be a bit Atypical: we are developing a bridge inspection app for the Michigan Department of Transportation. We are using UE4 because of the cross platform rendering capabilities that we needed to display a bridge model. In that sense the app won’t be for the general public, but there’s a chance other States may wish to purchase use of the app if we are successful.

The inspectors take a lot of photos of the bridges and it would be natural for them to use the mobile devices built in camera and have the photo load right into the app. I used the code I posted previously using the ImageWrapper module to do that so naturally that’s the feature I’m interested in. In terms of general use I can certainly think of reasons a game might want to load an image though such as player profile images, custom UI themes, or sprite sets for 2D games.

That makes sense. I’ll talk to folks here about moving the image loading features into Runtime. The main downside is that it pulls in third party libraries which then need to be vetted on all of our runtime platforms. So it is a little more complicated than a normal engine runtime feature.

In the meantime, you might want to take a look at the DevIL image library (http://openil.sourceforge.net/, GitHub - DentonW/DevIL: Developer's Image Library (DevIL) is a cross-platform image library utilizing a simple syntax to load, save, convert, manipulate, filter, and display a variety of images with ease. It is highly portable and has been ported to several platforms.) or something similar. Chances are those actually support a much broader range of formats that we currently do for texture importing. I know the team had discussed switching over to using a library like that for the editor itself, too.

–Mike

stb_image might be easier to integrate, though it may not handle as many formats as DevIL.

Great suggestion! Probably 99.9% of the images our application will ever need to deal with are JPG or PNG, and this was pretty easy to integrate (I have confirmed it is working on both Windows and Android).