[SOLVED] Need to patch the way how engine loads font files

I’m looking for a way to patch how the engine loads font files, the problem is simple:

  new pc.Asset('fontJson', 'font', { url: '.../someFont.json' }), 

The engine then loads a texture file in this way: Searches for a someFont.png (same file name) in the same folder.

I want to specify direct paths to font .json and .png files, what’s could be done? I’m gonna be using just 1 font in the entire app.

Thanks for any info.

Doing a little workaround here, but seems like im missing something :thinking:

loading assets:

  new pc.Asset('fontjson', 'json', { url: '..font.json' }), 
  new pc.Asset('fontpng', 'texture', { url: ..font.png' }),  

creating font:
var font = new pc.Font(pc.app.assets.find('fontpng').resource, pc.app.assets.find('fontjson').resource);
entity;

    var text = new pc.Entity();
    	text.addComponent("element", {
		type: pc.ELEMENTTYPE_TEXT,
        anchor: new pc.Vec4(0.5,0.5,0.5,0.5),
        pivot: new pc.Vec2(0.5,0.5),
        alignment: new pc.Vec2(0.5,0.5),
        lineHeight: 32,
        autoWidth: true,
        autoHeight: true,
        fontAsset: font,
        fontSize: 0.5,
        color: new pc.Color().fromString("#FFFFFF"),
	});
    text.element.text = 'Hello, world!';
    app.root.addChild(text);
    console.log(text);

after examining entities text element, font appears to be ‘null’, fontAsset is font object

okay, seems like I’m getting somewhere

 var font = new pc.Font(pc.app.assets.find('fontpng').resources[0], pc.app.assets.find('fontjson').resource);
            var fontAsset = new pc.Asset('PixelFont', 'font', {url: ''});
            fontAsset._data = font._data;
            fontAsset._resources.push(font);
            fontAsset.loaded = true;
            app.assets.add(fontAsset);

            console.log(font);
            console.log(fontAsset);

    var text = new pc.Entity();
    	text.addComponent("element", {
		type: pc.ELEMENTTYPE_TEXT,
        anchor: new pc.Vec4(0.5,0.5,0.5,0.5),
        pivot: new pc.Vec2(0.5,0.5),
        alignment: new pc.Vec2(0.5,0.5),
        lineHeight: 32,
        autoWidth: true,
        autoHeight: true,
        fontAsset: fontAsset,
        fontSize: 0.5,
        color: new pc.Color().fromString("#FFFFFF"),
	});
    text.element.text = 'Hello, world!';
    app.root.addChild(text);
Uncaught (in promise) TypeError: Q is undefined

I dont get it, everything seems to be right,
examining entity and its element, font and fontAsset appears as it would from editor based entity

var font = new pc.Font(pc.app.assets.find('fontpng').resource,pc.app.assets.find('fontjson').resource)

console.log(font); 

var fontAsset = new pc.Asset('myFont', 'font', null, {
    textures: [pc.app.assets.find('fontpng').resource], // Array of texture asset IDs
    data: pc.app.assets.find('fontjson').resource       // Font JSON asset ID
});
app.assets.add(fontAsset);
app.assets.load(fontAsset);


console.log(fontAsset);

    var text = new pc.Entity();
    	text.setPosition(0, 0.5, 0);
    	text.addComponent("element", {
		type: pc.ELEMENTTYPE_TEXT,
        anchor: new pc.Vec4(0.5,0.5,0.5,0.5),
        pivot: new pc.Vec2(0.5,0.5),
        alignment: new pc.Vec2(0.5,0.5),
        lineHeight: 32,
        autoWidth: true,
        autoHeight: true,
        fontAsset: pc.app.assets.find('myFont'),
        fontSize: 5,
        color: new pc.Color().fromString("#FFFFFF"),
	});
    text.element.text = 'Hello, world!';


    app.root.addChild(text);
    console.log(text);

What I’m missing? Its engine only project

Okay I’m running out of ideas…
Made function on top of FontHandler

function loadFontFromFiles(jsonUrl, pngUrl, callback) {
    var fontHandler = new pc.FontHandler(app);

    if (jsonUrl.endsWith('.json')) {
        fetch(jsonUrl)
            .then(response => response.json())
            .then(data => {
                fontHandler._loadTextures(pngUrl, data, function (err, textures) {
                    if (err) return callback(err);

                    var asset = {
                        data: data,
                        textures: textures,
                        resource: null // Will be assigned after creating the font object
                    };

                    var font = fontHandler.open(jsonUrl, asset);
                    asset.resource = font; // Assign the created font object

                    // Create the final response similar to original FontHandler
                    var fontResponse = {
                        data: asset.data,
                        textures: asset.textures
                    };

                    callback(null, fontResponse);
                });
            })
            .catch(err => {
                callback("Error loading font resource: " + jsonUrl + " [" + err + "]");
            });
    }
}

// Usage example
var fontJsonUrl = 'font.json';
var fontPngUrl = 'font.png';

loadFontFromFiles(fontJsonUrl, fontPngUrl, function (err, fontResponse) {
    if (err) {
        console.error(err);
        return;
    }

    // Now you can use the 'fontResponse' object which mimics the original FontHandler response
    console.log("Loaded Font:", fontResponse);
	  var fontAsset = new pc.Asset('myFont', 'font', null, {
        textures: [fontResponse.textures[0]], // Assuming textures is an array
        data: fontResponse.data
    });
	  pc.app.assets.add(fontAsset);
	  pc.app.assets.load(fontAsset);
});

Capture
Same story, everything looks right, really can’t figure this out…

Okay, I have’t gave up and did this in source code (inside FontHandler)

		_proto.load = function load(url, callback, asset) {
		var parts = url.load.split("|");
		var jsonUrl = parts[0];
		var pngUrl = parts[1];
			var self = this;
				http.get(jsonUrl, {
					retry: this.maxRetries > 0,
					maxRetries: this.maxRetries
				}, function (err, response) {
					if (!err) {
						var data = upgradeDataSchema(response);
						self._loadTextures(pngUrl, data, function (err, textures) {
							if (err) return callback(err);
							callback(null, {
								data: data,
								textures: textures
							});
						});
					} else {
						callback("Error loading font resource: " + url.original + " [" + err + "]");
					}
				});
		};

Now i can load font assets as:

new pc.Asset('fontjson', 'font', { url: 'font.json|test/font.png' }),

The question now is, how can i patch whole

	var FontHandler = function () {

chunk, without actually modifying the source code? Ideally I’d like to create a script and just attach to app root that would patch it, any ideas?

Hi @Newbie_Coder I’m not sure about patching an existing handler. Check this post, it’s quite old but it may be useful to get an idea on how to add your own custom resource handler:

1 Like

Patched

        const app = new pc.Application(canvas, {
            mouse: new pc.Mouse(document.body),
            keyboard: new pc.Keyboard(window)
        });

//Other stuff

var FontHandlerPatch = function(url, callback, asset) {
    function upgradeDataSchema(data) {
		if (data.version < 3) {
			if (data.version < 2) {
				data.info.maps = data.info.maps || [{
					width: data.info.width,
					height: data.info.height
				}];
			}
			data.chars = Object.keys(data.chars || {}).reduce(function (newChars, key) {
				var existing = data.chars[key];
				var newKey = existing.letter !== undefined ? existing.letter : string.fromCodePoint(key);
				if (data.version < 2) {
					existing.map = existing.map || 0;
				}
				newChars[newKey] = existing;
				return newChars;
			}, {});
			data.version = 3;
		}
		return data;
    }
		var parts = url.load.split("|");
		var jsonUrl = parts[0];
		var pngUrl = parts[1];
			var self = this;
				pc.http.get(jsonUrl, {
					retry: this.maxRetries > 0,
					maxRetries: this.maxRetries
				}, function (err, response) {
					if (!err) {
						var data = upgradeDataSchema(response);
						self._loadTextures(pngUrl, data, function (err, textures) {
							if (err) return callback(err);
							callback(null, {
								data: data,
								textures: textures
							});
						});
					} else {
						callback("Error loading font resource " + err);
					}
				});
};


var originalFontHandler = Object.create(pc.FontHandler.prototype);
originalFontHandler.load = FontHandlerPatch;
Object.assign(pc.FontHandler.prototype, originalFontHandler);


		const assets = [
			  new pc.Asset('fontjson', 'font', { url: 'font/font.json|test/font.png' }), 	

...
1 Like