[HOW-TO] [TUTORIAL] Create your own scaleform using Flash + GFxExporter

solution here: Can someone help with getting this Custom Scaleform tutorial project to build properly please? - #2 by manups4e

Hello there! I followed your tutorial and everything went smooth…up until this point:

I can’t seem to make the game load images properly. For instance, I’m rebuilding the whole phone interface, and I tried to add a simple .png background in my scaleform. The scaleform gets successfully loaded into the game, but instead of the phone background, it shows a white rectangle:


(Ignore the black background, it’s just the oversized BOUNDING_BOX, needed to be that big to help me figure out how does it work)

However, back to the .png, this is the directory of my project:

As you can see, the images have been turned into a .tga file from the gfxexporter, rather than a .dds, as you said in the tutorial. Maybe is that the problem?

ok if you want a better way to load pngs inside your scaleform is by doing this

  • First of all… add an empty movie clip inside your project and call it txdLoader
    image
    like this

    the class you wanna link is com.rockstargames.ui.media.ImageLoaderMC
  • Then in your script in the MAIN.as file of your project add these 3 public functions
    function ADD_TXD_REF_RESPONSE(txd, strRef, success)
    {
        com.rockstargames.ui.utils.Debug.log("ADD_TXD_REF_RESPONSE - " + arguments.toString());
        if (success == true)
        {
            var pMC = this.CONTENT;
            var il = com.rockstargames.ui.media.ImageLoaderMC(eval(pMC + "." + strRef));
            if (pMC != undefined)
            {
                il.displayTxdResponse(txd);
            }
        }
    }

    function TXD_HAS_LOADED(txd, success, strRef)
    {
        com.rockstargames.ui.utils.Debug.log("TXD_HAS_LOADED - " + arguments.toString());
        if (success == true)
        {
            var pMC = this.CONTENT;
            var il = com.rockstargames.ui.media.ImageLoaderMC(eval(pMC + "." + strRef));
            if (pMC != undefined)
            {
                il.displayTxdResponse(txd,success);
            }
        }
    }

    function TXD_ALREADY_LOADED(txd, strRef)
    {
        com.rockstargames.ui.utils.Debug.log("TXD_ALREADY_LOADED - " + arguments.toString());
        var pMC = this.CONTENT;
        var il = com.rockstargames.ui.media.ImageLoaderMC(eval(pMC + "." + strRef));
        if (pMC != undefined)
        {
            il.displayTxdResponse(txd,true);
        }
    }
  • Then use the attachMovie() function to add the txdLoader in your code wherever you want…

  • When you want to load any txd, txn (DUI or ingame or streamed) use this function around your code to dynamically load your txd-txn via scaleform natives

function SetClip(targetMC, textureDict, textureName, w, h, callback, scope)
{
	var alreadyLoaded = true;
	if (targetMC.textureFilename != textureName && targetMC.textureDict != textureDict)
	{
		var alreadyLoaded = false;
	}
	targetMC.init("YOUR-GFX-NAME",textureDict,textureName,w,h);
	var splitPath = String(targetMC).split(".");
	var pathWithoutContent = splitPath.slice(2).join(".");
	com.rockstargames.ui.tweenStar.TweenStarLite.removeTweenOf(targetMC);
	targetMC._alpha = 100;
	targetMC.requestTxdRef(pathWithoutContent,alreadyLoaded,callback,scope);
}

I made the function SetClip to dynamically load any texture without the need to Load it before via natives… the scaleform will load it and draw it for you…

SetClip has these parameters:

  • targetMC: the txdLoader movieClip you reference
  • textureDict: the texture dictionary (runtime, dui, ingame, streamed… who cares)
  • textureName: the name of the texture to load
  • w, h: width and height of the texture you wanna draw
  • callback: any function you wanna call whenever the load is finished (optional)
  • scope: i usually use ā€œthisā€ to reference all the class i’m using… for example if i’m drawing a badge in ScaleformUI inside a UIMenuItem i reference this as the whole UIMenuItem isntance inside the function (that’s how flash works :smiley: )

example:
– this function is called inside UIMenuItem in NativeUI-scaleform_flash in my github

	function SetLeftBadge(id)
	{
		this.leftBadgeId = id;
		if (this.leftBadgeId != com.rockstargames.ScaleformUI.utils.Badges.NONE)
		{
			if (this.leftBadgeMC.isLoaded)
			{
				this.leftBadgeMC.removeMovieClip();
			}
			this.leftBadgeMC = this.itemMC.attachMovie("txdLoader", "LeftBadge", this.itemMC.getNextHighestDepth());
			var sprite_name = com.rockstargames.ScaleformUI.utils.Badges.getSpriteNameById(id, this.highlighted);
			var sprite_txd = com.rockstargames.ScaleformUI.utils.Badges.GetSpriteDictionary(id);
			SetClip(this.leftBadgeMC,sprite_txd,sprite_name,24,24,this.leftBadgeLoaded,this);
			this.itemMC.labelMC._x = 28.25;
		}
		else
		{
			if (this.leftBadgeMC.isLoaded)
			{
				this.leftBadgeMC.removeTxdRef();
				this.leftBadgeMC.removeMovieClip();
				this.itemMC.labelMC._x = 5;
			}
		}
		this.updateLabelWidth();
	}

	function leftBadgeLoaded()
	{
		this.leftBadgeMC._visible = true;
		this.leftBadgeMC._width = 24;
		this.leftBadgeMC._height = 24;
		this.leftBadgeMC._x = 0.5;
		this.leftBadgeMC._y = 0.5;
		this.updateLabelWidth();
	}

Also… rebuilding the ingame phone is a big project… i would start from something smaller… and grow step by step…

Oh, finalmente qualcuno che risponde, e anche celermente :smiley:
Anyway, thanks for the quick reply, I appreciate that! I’ll start working on it in the following days. I think :joy:
I know it’s a big project, but I don’t really like the many NUI phones out there (I don’t like NUIs in general, I prefer scaleforms) and the default phone is good, but very limited. So that’s why I had the idea to rebuild it (consider it the upgraded model :joy:)
But anyway, I’m used to hard work, I’m not afraid of the coding part^^ (now, about the graphic part, that’s another story…)

Ahahahah tranquillo se posso rispondo sempre!
:blush:
Anyway the code I provided you gives you should help loading dynamically any texture… you can check ScaleformUI main Readme on GitHub :blush: join my community and we can help you

1 Like

Your code is very clear…except for one part :joy:

SetClip()

From what I understood, I need to call this function to load txds from my scripts, I get that (I guess the appropriate native would be this: CallScaleformMovieMethodWithString)
My only doubt is the scope. How can I pass it as a parameter from, say, a .lua script? All the other parameters are fine, scope is the only one I can’t figure out how to pass

The only thing you pass from lua is TXD,TXN, WIDTH, HEIGHT all other params are internal to flash
Scope is flash way to say ā€œin the callback what can I see outside the callback itself?ā€

Got it. So I need to create an intermediate function that receives the parameters from the script, and then calls SetClip?

Something like this:

function DataFromLua(txd,txn,width,height) {
    SetClip(targetMC, txd, txn, width, height, callback, scope)
}

When I try to add this code to my actionscript file, I get a lot of erros telling me that _componentsForLoadingImages isn’t a thing. IT also tells me that loc2._depth, loc2._mc, loc2._listener, loc2._listener.thisObj, loc2._listener.componentID, loc2._listener.onLoadInit and this.thisObj._componentsForLoadingImages doesn’t exist.

Here is the code I’m trying to add:

function loadTextureIntoMovieClip(txd, texture)
	{
		var thisObj = this;
		var _loc3_ = this._componentsForLoadingImages.length + 1;
		var _loc2_ = new com.rockstargames.ui.core.BaseComponentInfo(_loc3_);
		this._componentsForLoadingImages[_loc3_] = _loc3_;
		_loc2_._depth = _loc3_ + 10;
		_loc2_._mc = this.CONTENT.yourCustomItem; // this is the symbol you created in content like a rectangle turned to symbol
		_loc2_._listener = new Object();
		_loc2_._loader.addListener(this.loaderObject._listener);
		_loc2_._listener.thisObj = thisObj;
		_loc2_._listener.componentID = _loc3_;
		_loc2_._listener.onLoadInit = function(target_mc)
		{
			var _loc2_ = this.thisObj._componentsForLoadingImages[this.componentID];
			_loc2_._loader.removeListener(_loc2_._listener);
			_loc2_._loader = null;
		};
		var _loc5_ = "img://" + txd + "/" + texture;
		_loc2_._loader.loadClip(_loc5_,_loc2_._mc);
	}

Would it be something you could help me with fixing?

Would you also be able to explain how to use it to load an image from a ytd file, if that’s possible?

I also can’t get it to get the exporter to turn the images into .dds files, I can only get it to turn them into .tga files, and when I add them to a custom ytd file it doesn’t load them.

Thanks in advance

I’ll share a better way :blush:
As soon as I get home

ok so:
there are 2 ways of loading a texture inside the scaleform:
1 - build the scaleform with the picture inside it and then when exported you get the generated dds and port it into a ytd.

2 - load the texture on runtime:

method 1

request the dictionary via script (lua/c#/js)… and then load the texture with the scaleform using this chunk of code (callback is used to execute any function after the texture is loaded)

 var txd_loader;
 var callback;
 function LoadClip(targetMC, textureDict, textureName, callback)
 {
 	this.callback = callback;
 	this.txd_loader = new MovieClipLoader();
 	this.txd_loader.addListener(this);
 	var _loc2_ = "img://" + textureDict + "/" + textureName;
 	this.txd_loader.loadClip(_loc2_,targetMC);
 }

 function onLoadInit(targetMC)
 {
 	this.callback.apply(targetMC);
 	this.txd_loader.removeListener(com.rockstargames.ScaleformUI.utils.MovieClipHandler);
 	this.txd_loader = null;
 	this.callback = null;
 }

method 2:

this method doesn’t require you to request the texture dict because it is all done internally via API calls:

  • create an empty movieclip, in its properties add this class in the class reference: com.rockstargames.ui.media.ImageLoaderMC

  • in your MAIN_CLASS (the one extending BaseScriptUI) add these 3 functions (YOU MUST HAVE THEM as they are API CALLBACKS)

	function ADD_TXD_REF_RESPONSE(txd, strRef, success)
	{
		if (success == true)
		{
			var pMC = this.CONTENT;
			var il = com.rockstargames.ui.media.ImageLoaderMC(eval((pMC + ".") + strRef));
			if (pMC != undefined)
			{
				il.displayTxdResponse(txd);
			}
		}
	}

	function TXD_HAS_LOADED(txd, success, strRef)
	{
		if (success == true)
		{
			var pMC = this.CONTENT;
			var il = com.rockstargames.ui.media.ImageLoaderMC(eval((pMC + ".") + strRef));
			if (pMC != undefined)
			{
				il.displayTxdResponse(txd,success);
			}
		}
	}

	function TXD_ALREADY_LOADED(txd, strRef)
	{
		var pMC = this.CONTENT;
		var il = com.rockstargames.ui.media.ImageLoaderMC(eval((pMC + ".") + strRef));
		if (pMC != undefined)
		{
			il.displayTxdResponse(txd,true);
		}
	}
  • step 3… to load any texture on runtime you use this function :slight_smile: it will load the textures and execute the callback you want using the ImageLoaderMC class and internal API calls.
/*
- function SetClip
Load the desired texture into any ImageLoaderMC attached movieclip.
- arguments
targetMC: your ImageLoaderMC instance,
textureDict, textureName: it's obvious what they mean
w,h: the size of the texture you want
callback: any function you want to execute after the texture is loaded
depth: the scope of the callback, usually you always want to input "this" to make sure it's in the same scope as from where you called the main function.
centerItem: if true, the pivot point (0,0) of the texture will be its center, if false its top-left corner.
*/

    function SetClip(targetMC, textureDict, textureName, w, h, callback, depth, centerItem)
	{
		var alreadyLoaded = true;
		if (targetMC.textureFilename != textureName && targetMC.textureDict != textureDict)
		{
			var alreadyLoaded = false;
		}
		var x = 0;
		var y = 0;
		if (centerItem)
		{
			x = -w / 2;
			y = -h / 2;
		}
		targetMC.init("WRITE HERE YOUR OUTPUT GFX FILE NAME (the one used to load in game)",textureDict,textureName,w,h,x,y);
		var splitPath = String(targetMC).split(".");
		var pathWithoutContent = splitPath.slice(2).join(".");
		com.rockstargames.ui.tweenStar.TweenStarLite.removeTweenOf(targetMC);
		targetMC._alpha = 100;
		targetMC.requestTxdRef(pathWithoutContent,alreadyLoaded,callback,depth);
	}

if you need more examples on how to use the second method :slight_smile: i basically use it everywhere in ScaleformUI so you can check in my github here: ScaleformUI-Scaleform/project/com/rockstargames/ScaleformUI at main Ā· manups4e/ScaleformUI-Scaleform Ā· GitHub


Veeery very simple!!
when exporting with gfxexported use this command line: -i DDS
this will specify the exported to create only dds files, also you can use the -share_images option to always use the same generated dds files. i’ll give you my command line batch (.bat) file i use to build my ScaleformUI:

G:\Progetti\Flash\gfxeporter\gfxexport.exe ScaleformUI-Scaleform\SCALEFORMUI.swf -i DDS -share_images -strip_font_shapes

G:\Progetti\Flash\gfxeporter\gfxexport.exe ScaleformUI-Scaleform\SCALEFORMUI.swf -i DDS -share_images -strip_font_shapes -o "L:\FiveM\ManuGamemode\resources\[local]\[streamed]\Assets\stream\scaleforms"

first line is used to export the gfx inside the same folder as the swf,
the second line is used to output the gfx in my test gamemode.
this link
Help
will show you how to use the exporter :slight_smile:

Would this allow me to upload the files to a .ytd file and then load the images onto a signal?

Would you be able to help me a bit with it? Have tried this, but I couldn’t get it to work. I have reverted it to the last somewhat working version. This version can’t load the images, but to my understanding I have all the necessary stuff.

I of course don’t expect you to do it for me, but I think it would be easier for you to help me if we are working with the same codebase.

Here is my scaleform:
MenuScaleform.zip (736.2 KB)

Here is my build scaleform, with font’s as a ressource:
ScaleformScriptAssets.zip (687.7 KB)

Here is my script that loads and handles the scaleform (The code is very messy since it’s just a proof of concept):
ScaleformScript.zip (1.8 KB)

Thanks in advance.

I think the problem is that I’m missing most of the com.rockstargames.ui stuff. I only have a small part of what I see in the final_structure.zip file.

Btw. you don’t happen to have a copy of the scaleform boilerplate mentioned in the docs? The link doesn’t work anymore.

the methods i showed you let you add textures from ytd into the scaleform yeah, you must build the functions for it :slight_smile:

join the discord server there are people like me playing with scaleforms that can help you :slight_smile:

Pretty neat tutorial! I’m really curious how can we play a gif using Scaleform. Could you how us a some example?

1 Like

Thanks!! I will update this guide very soon!
To make it very easy (i’ll use Lua as a reference for this example):

	local txd = CreateRuntimeTxd("scaleformui")
	local duikitty = CreateDui(
	"https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExczA0dXhscDRqbHBmb3I2bmk4dDVzd25uNmhhbHNmMnE5N3hkYTM0MiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/tY27Dk0H8IisGidQv6/giphy.gif",
		480, 480)
	CreateRuntimeTextureFromDuiHandle(txd, "kitty", GetDuiHandle(duikitty))

your txd, txn params to be sent will be "scaleformui", "kitty" and the scaleform will read the gif as a texture


you can take a look at my ScaleformUI repository to check how i do it

1 Like

Thank you for the study and for sharing it with us, but I had a doubt when executing it. How that i can do to the scaleform follow my cam position, not being static. Its a ActionScript config or client.lua config?

Both :thinking: you need to use both game natives and share infos with the scaleform on tick but nothing too hard in the end :smiling_face:

Could you provide a tutorial on how to convert Git to GFX?