Load texture with generic file extension at runtime

I need to load a texture file at runtime.
I have no problem if the file has a recognized extension (jpg, png, etc.) but I need to load files with a generic extension (bin) that has the format in the content-type header and in this case it does not work.
By modifying a part of the engine code I managed to get what I wanted but is there a solution that allows me to get the same result without modifying the engine?

Please, can someone give any indication about it?

Any reason not to not use a modified version of the engine or to monkey patch it?

What’s the change you would need to make?

Thanks for your answer @yaustar

To avoid possible problems in the various future engine updates.

I need to use textures reachable via url that do not have a recognized extension, so I need to discriminate them for the content-type of the answer.

Would you be able to post the patch/diff of the code that you need to change?

I changed a piece of texture.js adding the content type as callback parameter

var x = pc.http.get(url, options, function(err, response) {
	if (!err) {
		callback(null, response, x.getResponseHeader('content-type'));
	} else {

and loader.js to catch and use this parameter

if(pc.path.getExtension(url).toLowerCase() == '.bin'){
	contentType = extra;
	if (contentType.includes("jpg"))
		url = url + '.jpg';
	else if (contentType.includes("png"))
		url = url + '.png';

It works, but i hope there is a better way to do this.

Looking at the loader code, are you adding .jpg/.png to the url so the actual path to the texture is filename.bin.jpg for example?

I added the code above in loader.js just before

var resource = handler.open(url, data, asset);

so the texture “load” function (that use http get) use real file name (filename.bin) and the texture “open” function use the url patched to correctly read the image, for example filename.bin.jpg

In any case, I return to my question, is there a way to do it without modifying the engine?

I was trying to understand as much of the problem and solution you have made to see if it could be solved another way as I was guessing the extension was linked to logic flow in the engine.

Looking at the code in the engine, it doesn’t look like you can get away without modifying the engine as it depends on the extension to load the texture in a specific pixel format.

Is there a reason for them to be .bins in the first place? I’m a bit concerned about changing the URL as there may be issues if any application code or engine code actually needs the true URL to the asset after being loaded.

Edit: Thinking about it, you might be able to add your own texture asset handler to handle .bin as well in application.js (i.e you can do this in your application rather than modifying the engine) which would be cleaner and that way, you wouldn’t have to worry about any future changes to the engine too much.

Edit2: Actually this would be pretty close to monkey patching which feels like the ‘right’ option in this case as you wouldn’t have to maintain your own engine branch.

Edit3: Going on a thought train here. I personally think monkey patching texture.js load function would be the right call here to handle .bin correctly. Changing the loader seems wrong as you shouldn’t change the URL.

Thank you so much Steven for your answers!

I thought about it too and it seemed to me the most correct solution, but in this case I can not use the standard asset loading process

var asset = new pc.Asset(name, 'customhandler', file, data);

for the textures because in the handler I have no way to have the content type of the http request. :sweat:
Or… did I miss something?

Can you provide a .bin image file? I might have a go at this.

You can use a standard jpg with bin extension and served with image/jpg content type like this

I’ve got a version that uses it’s own resource loader ‘piggy backs’ on the texture handler.

I’m not sure this is much better than what you got, but it does mean that there’s no patching of the engine: https://playcanvas.com/editor/scene/625819

There’s probably a few bugs around so use with caution if at all.


Thanks Steven! Yes, I think it’s definitely better than modifying the engine! For example you can use it in the editor! :slightly_smiling_face::slightly_smiling_face:

The only issue is that you have to take into account the order of scripts that initialize to ensure that the handler gets add first before all your textures attempt to load.

An easy way to get around this is to add the handler in initialize and load the textures in postInitialize or update.

Good luck!

I have this error
patch.js?id=13386297&branchId=19759b27-22fd-4af3-a479-902d799e3d82:26]: Uncaught TypeError: Cannot read property ‘includes’ of null

TypeError: Cannot read property ‘includes’ of null
at Object.callback (https://launch.playcanvas.com/api/assets/files/patch.js?id=13386297&branchId=19759b27-22fd-4af3-a479-902d799e3d82:26:37)
at Http._onSuccess (https://code.playcanvas.com/playcanvas-stable.dbg.js:21711:13)
at Http._onReadyStateChange (https://code.playcanvas.com/playcanvas-stable.dbg.js:21664:20)
at Http. (https://code.playcanvas.com/playcanvas-stable.dbg.js:21628:12)

[patch.js?id=13386297&branchId=19759b27-22fd-4af3-a479-902d799e3d82:26]: Uncaught TypeError: Cannot read property ‘includes’ of null

TypeError: Cannot read property ‘includes’ of null
at Object.callback (https://launch.playcanvas.com/api/assets/files/patch.js?id=13386297&branchId=19759b27-22fd-4af3-a479-902d799e3d82:26:37)
at Http._onError (https://code.playcanvas.com/playcanvas-stable.dbg.js:21713:13)
at Http. (https://code.playcanvas.com/playcanvas-stable.dbg.js:21631:12)

Can you share the project link please? The project I made still works so I’m not sure where those errors are coming from.

My guess is that if either can’t access the URL it’s been given or that there is no content-type in the header (more likely) which is what the OP had.

Might be a bit off but in a similar case i downloaded the file. Used the Linux ‘file’ command to determine the file name, then renamed it accordingly and worked with it.
Is that an option ?