Rex Rhino

Ludei Cocoonjs XML / bitmap font workaround?

Recommended Posts

Hey all,

 

Right now, Ludei Cocoonjs doesn't load and parse XML files... Which means that we can't load bitmap font data.

 

I am wondering if anyone else has figured out a workaround to this issue?

Share this post


Link to post
Share on other sites

Yup, I did a hacky workaround. I replaced the BitmapFont XML Loader logic with JSON Loader logic. In order to make this work with the xml code exported from AngelCodes Font Generator I converted the XML bitmap font data into a json array using a tool like this http://www.freeformatter.com/xml-to-json-converter.html (if I remember it correctly - I used the default settings of the tool).
 

The hacky workaround code for the BitmapFont Loader looks like this:

/** * Loads the XML font data * * @method load */PIXI.BitmapFontLoader.prototype.load = function(){    this.ajaxRequest = new AjaxRequest();    var scope = this;    this.ajaxRequest.onreadystatechange = function () {            scope.onJSONLoaded();    };    this.ajaxRequest.open("GET", this.url, true);    if (this.ajaxRequest.overrideMimeType) this.ajaxRequest.overrideMimeType("application/json");    this.ajaxRequest.send(null);};/** * Invoked when XML file is loaded, parses the data * * Modified method to use json instead for CocoonJS * with json conversion seen here: * http://www.freeformatter.com/xml-to-json-converter.htm * * @method onXMLLoaded * @private */PIXI.BitmapFontLoader.prototype.onJSONLoaded = function(){    if (this.ajaxRequest.readyState == 4) {        if (this.ajaxRequest.status == 200 || window.location.href.indexOf("http") == -1) {                        this.json = JSON.parse(this.ajaxRequest.responseText);                        var textureUrl = "assets/" + this.json.pages[0]['@file'];            var image = new PIXI.ImageLoader(textureUrl, this.crossorigin);            this.texture = image.texture.baseTexture;                        var data = {};            data.font = this.json.info[ '@face' ];            data.size = parseInt( this.json.info[ '@size' ], 10 );            data.lineHeight = parseInt( this.json.common[ '@lineHeight' ], 10 );            data.chars = {};            var letters = this.json.chars.char;            for (var i = 0; i < letters.length; i++)            {                var charCode = parseInt(letters[i]["@id"], 10);                var textureRect = {                    x: parseInt(letters[i]["@x"], 10),                    y: parseInt(letters[i]["@y"], 10),                    width: parseInt(letters[i]["@width"], 10),                    height: parseInt(letters[i]["@height"], 10)                };                PIXI.TextureCache[charCode] = new PIXI.Texture(this.texture, textureRect);                                data.chars[charCode] = {                    xOffset: parseInt(letters[i]["@xoffset"], 10),                     yOffset: parseInt(letters[i]["@yoffset"], 10),                     xAdvance: parseInt(letters[i]["@xadvance"], 10),                     kerning: {},                    texture:new PIXI.Texture(this.texture, textureRect)                };                                            }                        if ( this.json.kernings && this.json.kernings.kerning ) {                var kernings = this.json.kernings.kerning;                for (i = 0; i < kernings.length; i++)                {                   var first = parseInt(kernings[i]["@first"], 10);                   var second = parseInt(kernings[i]["@second"], 10);                   var amount = parseInt(kernings[i]["@amount"], 10);                   data.chars[second].kerning[first] = amount;                }                                        }                                    PIXI.BitmapText.fonts[data.font] = data;            var scope = this;            image.addEventListener("loaded", function() {                scope.onLoaded();            });            image.load();                         }        else        {            this.onError();        }    }        };/** * Invoked when all files are loaded (xml/fnt and texture) * * @method onLoaded * @private */PIXI.BitmapFontLoader.prototype.onLoaded = function(){    this.dispatchEvent({type: "loaded", content: this});};

Hope this helps you. At least this way worked for me with my game Yummy Plate . I tried out different approaches (like using an javascript XML parser) - but nothing really seems to work. This is really hacky - but it works. So, basically what you need to do is:

 

1.) Replace PIXI's original BitmapFontLoader code with code above

2.) Convert XML bitmap font data into json structure with online tool

3.) Important - keep the suffix as .xml in order to trigger the correct loader code

4.) Cross your fingers that nothing explodes ;-)

 

Let me know if you need any more info.

 

Best,

benny!

Share this post


Link to post
Share on other sites

@sergil:

Cleanest solution would be to add somekind of polyfill for XML parsing and not to hack around in the core libs (like Phaser, PIXI).

 

Unfortunately, it did not worked in my tests. Mostly it seems that the js-xml parsers couldnt handle large xml files.

 

But if you find a clean solution - please let me know. As I said above - this way is really hacky and definately not something I would recommend to do in general.

Share this post


Link to post
Share on other sites

Hi guys,

I was playing with this topic last weekend and came out with small hack.

Basically, the idea is to recognize the environment using navigator.isCocoonJS and depending on that:

- override window.DOMParser with own parser implementation

- load bitmap font data from JSON instead of XML

 

Ladies and gents, let me introduce to you.. DOMishParser  :D

if (navigator.isCocoonJS) {    window.DOMParser = DOMishParser;}function DOMishParser() {}DOMishParser.prototype.parseFromString = function (data) {    return new DOMishObject(JSON.parse(data));};function DOMishAttributes() {}DOMishAttributes.prototype.getNamedItem = function (name) {    return {        nodeValue: this[name] || null    };};function makeDOMishObject(data) {    return new DOMishObject(data);}function DOMishObject(data) {    this.attributes = this.convertContent(data);    this.length = Object.keys(this.attributes).length;}DOMishObject.prototype.documentElement = document;DOMishObject.prototype.convertContent = function (obj) {    var attributes = new DOMishAttributes(),        prop;    for (prop in obj) {        if (obj[prop] !== null && typeof obj[prop] === 'object') {            attributes[prop] = Array.isArray(obj[prop]) ?                obj[prop].map(makeDOMishObject) : new DOMishObject(obj[prop]);        } else {            attributes[prop] = obj[prop];        }    }    return attributes;};DOMishObject.prototype.getElementsByTagName = function(name) {    return this.attributes[name] ?        Array.isArray(this.attributes[name]) ?        this.attributes[name] : [this.attributes[name]] : [];};

Looks a bit ugly but does the trick - you can check it on my simple blocks game http://gpabian.pl/blocks/ (still under development).

On browsers it loads bitmap font data from XML, on Cocoon uses JSON...

 

Forgot to mention - the JSON file was made of BMFont's XML output using xml2js library and node.js.

Share this post


Link to post
Share on other sites
Ludei guys told me that at the moment the DOMParser is not implemented in cocoonjs. This feature is in the backlog but didn't exists for the moment. Right now, the solution is to implement a window.DOMParser from JavaScript like the one posted in this post.

 

It should work without problems.

Share this post


Link to post
Share on other sites

Forgive me if I'm wrong, but doesn't Cocoon offer a WebView as well? Doesn't the DOMParser exist in that?

 

They definately offer a WebView, that's true. However, I cannot say how communication works between both environments. But it might be also worthwhile to check out.

Share this post


Link to post
Share on other sites
dTb    2
It's not too difficult, we have a lot of functions to call stuff in the other context, (from webview to canvas and vice-versa) with callbacks where you don't have to care much from which context are coming the data. You cannot transfer functions/prototypes I think, you can transfer just text based info, but that's enough in most of the cases I think.

 

On my side I'm using it to access the photo roll via an <input type="file"> and to send the photo data as a string to the canvas.

 

See the 3 CocoonJs_App files here :


Share this post


Link to post
Share on other sites

Forgive me if I'm wrong, but doesn't Cocoon offer a WebView as well? Doesn't the DOMParser exist in that?

 

Yes it does, but it will only be available if one is initialized the webview by loading a html file into it. Here is an webview example how can it be done https://cocoonjsservice.ludei.com/cocoonjslaunchersvr/demo-list/ ). Until then, there's not much functionality available at the 'dark side', however a fancy proxy thing can be build up this way that comes handy later ->

 

They definately offer a WebView, that's true. However, I cannot say how communication works between both environments. But it might be also worthwhile to check out.

 

That would be a JSON-ish thing, and it works synchronously as well as asynchronously. I prefer the synchronous way this time.

- First, one have to pass the XML document (as a plain string) to the webview environment by using the provided var retObject = CocoonJS.App.forward() method.

- Next, at the webview side pick a new DOMParser() and feed it with the XML content, or just create a new xhtml document ( document.implementation.createDocument() ) and inject the received XML document into it by passing it to the innerHTML property. It's up to you which method you prefer, since both ways the XML will be translated immediately and can be traversed to pick the needed childNodes and attributes which both have to be saved into an js object.

- Then, this js object have to be JSONified as a string before passed back to the - let's call it - gaming environment there it is received as an decoded object (into the retObject), so no need to parse at the receiver end.

By traversing the received object a new object can be build up that will mimic the document's behavior, including the methods that will be essential for Phaser to access the content. Since a user-defined DOMParser() class can also be defined (it wont do any bad, since it is completely missing on the gaming side) in order to provide the needed functionalities for Phaser, therefore the engine can be left completely intact and no need to subclass/hijack/overwrite etc any parts of it (that's what i prefer imo  ^_^) - Just think something that GregP shown us a little up here (that example gave me the idea as well, thanks! B) )

 

Still a hacky one i admit, but not that bad since it uses the native methods of webview to parse the XML, jsonify the thing etc. (the whole thing takes only a moment for my yet oldie 2.3.7 android vodafone smart ii - and boy this is a veeery slow handy)

 

Anyway, the above solution is the only i found so far to get rid the XML problems in the cocoon js environment. I hope however they will come up with a less ugly way that would be the good solution.

Share this post


Link to post
Share on other sites

Had a hard time using converted xml JSON files to work with Phaser on CocoonJS. Either there is an exception when loading the .json or the bitmapfont text is not visible at all.

 

The solution I'm using includes DOMishParser (thanks GregP) and the following nodejs script I hacked (based on the following blog post):

var fs = require('fs'),	eyes = require('eyes'),	xml2js = require('xml2js');var parser = new xml2js.Parser({ explicitRoot: false, mergeAttrs: true, explicitArray: false });parser.on('end', function(result) {	result.char = result.chars.char;	delete result.chars;	var json = JSON.stringify(result);	fs.writeFile(__dirname + "/output.json", json, function(err) {    	if(err) {        	console.log(err);    	} else {        	console.log("The file was saved!");    	}    });});fs.readFile(__dirname + '/font.xml', function(err, data) {	parser.parseString(data); });

Do you know an easier solution to generate working .json files from .xml font descriptors ?

Share this post


Link to post
Share on other sites

It's part of the roadmap. We want to bed down the features (and we're very nearly there) and then will start making it seamless for Cocoon, Firefox OS, etc. Q1 2014 is our target for starting this work.

 

Have you started working in Cocoon full integration for Phaser?

 

Thanks

Share this post


Link to post
Share on other sites

Hi All,

 

I am new to Phaser. I have build one game using this framework which is working fine on browser. 

 

But I now am trying to load on Cocoonjs, the only problem I am facing is showing any text using bitmap font. I have tried the hack of using "DOMishParser" with json which is suggested in this post but I am not able to see the text rendered on the screen.

There is no error in console as well.

 

Can someone help me out please, as this is getting very difficult for me now to figure out what could be the issue. 

Share this post


Link to post
Share on other sites

Hi All,

 

I am new to Phaser. I have build one game using this framework which is working fine on browser. 

 

But I now am trying to load on Cocoonjs, the only problem I am facing is showing any text using bitmap font. I have tried the hack of using "DOMishParser" with json which is suggested in this post but I am not able to see the text rendered on the screen.

There is no error in console as well.

 

Can someone help me out please, as this is getting very difficult for me now to figure out what could be the issue. 

 

I have the same issue, I am loading a json file in CocoonJS for bitmap fonts instead of XML using the DOMishParser too (no errors in console), the other sprites are displayed correctly, I have to add an empty sprite at the end to show the last sprite, all it's working, except Bitmap Fonts =/

 

Solved, the json file was converted incorrectly...

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.