HELP - Converting some C++ Logic to Javascript

It’s not easy

So basically you need a texture that supports access it’s pixel data, I remember someone created a CCTexture2DMutable A while ago, not sure if it still works… Add that to your project and use js-binding generator to generate the api you need.

Or depends on your game, you can make creative use of things like tilemap, have a transparent tile and you can test the id of it…

Thanks Nite, I think I might investigate that CCTexture2DMutable.

Unfortunately I am not too experienced with Cocos.
When you say “Add that to your project” would I add the CCTexture2dMutable.h and CCTexture2dMutable.cpp into:

root/frameworks/js-bindings/cocos2d-x/cocos/renderer ?

Also, if you don’t mind me asking for resources/document links, what is the js-binding generator?

In v2.x, gl.readPixels is how to read the colour of pixels.

Unfortunately, while the function works in v3.x, it doesn’t appear to work well for your intended use. There are a number of topics about per-pixel touch that are trying to use the technique in this code and they find the same thing; the render texture image isn’t available immediately after renderTexture.end() is called. (If I remember correctly, it’s something like because the render texture sends draw commands to the draw queue or something like that, you have to wait until the renderer has rendered everything before the render texture is updated.)

If you are using v3.0, you will either have to use nite’s suggested method or find a v3.0 compatible method, which will probably involve writing C++ code and binding it to JavaScript.

Hi grim. Funny you mention that… because for the past 3 hours I have been unable to figure out why this simple code isn’t working: I am expecting the following result:

JS: {“0”:0,“1”:0,“2”:255,“3”:255}

but I keep getting:

JS: {“0”:0,“1”:0,“2”:0,“3”:255}

var renderTexture = new cc.RenderTexture(winSize.width, winSize.height);
  renderTexture.begin();
  blue.visit(); // this adds a full screen layercolor to the texture (of rgba 0,0,255,255)

  var pixel = new Uint8Array(4);
  gl.readPixels(winSize.width/2, winSize.height/2, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
  cc.log(JSON.stringify(pixel));

  renderTexture.end();

As you mentioned, it may have something to do with the draw commands being in queue. NOW, from other sources I have read that gl.readPixels actually reads the buffer? And if I haven’t sent a texture to the buffer, then the readPixels won’t give me accurate results.

Can you help me add a gl.buffer? (I don’t know the syntax).

Here is the blue layer if you want to debug my code to see your results:

    var winSize = cc.winSize;
    
    if( 'opengl' in cc.sys.capabilities ) {
        
        
        var blue = new cc.LayerColor(cc.color(0, 0, 255, 255));

        blue.scale = 2;
        blue.x = -winSize.width / 4;
        blue.y = -winSIze.height / 4;

        blue.visit();
        this.addChild(blue);
    }

What do you mean by adding gl.buffer?

Hi Marteh, please, did you succeed?
More than one week I’m trying to get out from same troubles… Reading pixels from RenderTexture and wondering what the hell is there in. Currently I asked [here][1]
I hope you did it and you could share your discovery :smiley:

Thank you,
Zbynek
[1]: RenderTexture does not clear buffer

you can draw the texture as a sprite to ideally a render texture, then you can use glread pixel

Only if you don’t want to use glReadPixels immediately after drawing to the render texture.

Yes, that’s the problem. I need to use glReadPixels immediately. In C++ we could call Director::getInstance()->getRenderer()->render(); to force the renderer to proceed pending commands immediately. But in javaScript I can not find way to obtain this renderer nor to call its functions. I develop for native platforms like Android, iOS and win32, not for browsers. I investigate how to use JSB but not succeed yet. I wonder that I can not find a way to obtain a director’s renderer through the Runtime’s calls. Folks what do you think about this approach?

Well, one problem with doing it through JSB is that the renderer doesn’t appear to have bindings, so to do it “properly” you would have to create bindings for the renderer and then bind the director’s getRenderer() function. Or you could create your own C++ helper class, add a function to call the renderer and then just create bindings for your helper class.

Or you could resort to a quick hack: Add a static function to the JSB for the director to call the renderer’s render function. I have no idea about using the bindings generator (or if it would work for this), but I can tell you how to change the JSB files to achieve this. If you would be comfortable messing around with them, there’s the 3 steps involved. (Hopefully there’s no reason why they didn’t choose to bind the renderer.)

Step 1:
In jsb_cocos2dx_auto.hpp, find the line bool js_cocos2dx_Director_getInstance(JSContext *cx, uint32_t argc, jsval *vp);. Copy and paste directly underneath it and change getInstance to render, so you now have:

bool js_cocos2dx_Director_getInstance(JSContext *cx, uint32_t argc, jsval *vp);
bool js_cocos2dx_Director_render(JSContext *cx, uint32_t argc, jsval *vp);

Step 2:
In jsb_cocos2dx_auto.cpp (may take a couple seconds to load because it has over 60,000 lines of code), search for the js_cocos2dx_Director_getInstance function. Under this function, add:

bool js_cocos2dx_Director_render(JSContext *cx, uint32_t argc, jsval *vp)
{
	if (argc == 0) {
		cocos2d::Director::getInstance()->getRenderer()->render();
		JS_SET_RVAL(cx, vp, JSVAL_VOID);
		return true;
	}
	JS_ReportError(cx, "js_cocos2dx_Director_render : wrong number of arguments");
	return false;
}

Step 3:
2 functions down from Step 2 there should be the function js_register_cocos2dx_Director. Inside this you will find the line

static JSFunctionSpec st_funcs[] = {
	JS_FN("getInstance", js_cocos2dx_Director_getInstance, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),        
	JS_FS_END
};

Change this to:

static JSFunctionSpec st_funcs[] = {
	JS_FN("getInstance", js_cocos2dx_Director_getInstance, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
        JS_FN("render", js_cocos2dx_Director_render, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
	JS_FS_END
};

And you’re done. Step 1 adds the function declaration to the JSB header file. Step 2 adds the code that calls the renderer. And Step 3 basically adds the function to Javascript.

After this, you should be able to call cc.Director.render();

I think it could should work.

Wow! Thank you grimfate very very much!
Actually last two days I’ve been trying to call own C++ helper class from js. I came out from approach on http://www.cocos2d-x.org/wiki/How_to_bind_C++_to_Javascript where a tutorial is available and downloadable from https://github.com/iTyran/Tutorials/tree/master/jsb/JSBTest
Unfortunately I was not able to build the Runtime with this example. Beside other problems I crashed with JSBool type undefined… that I was not able to find.

Back to your suggested hack. It is perfect to test quickly if the render() function solve my issue. It also helps to understand better what is happening inside JSB. I’m trying it. I can build Runtime successfully.
But calling cc.Director.render(); from my js I got “TypeError: cc.Director.render is not a function”
Trying whatever - restarting cocos IDE, rebuilding Runtime, running in simulator as well as on device… still same error.

Grimfate, would you please have some suggestions? I guess some step 4 is missing.
Thank you very much.

Step 3 is the step that adds the function to JavaScript and allows you to call cc.Director.render(). Can you please double check you did this step correctly? Make sure you added the render line to st_funcs[] and not funcs[]?

Yes, I’m sure.

static JSFunctionSpec st_funcs[] = {
    JS_FN("getInstance", js_cocos2dx_Director_getInstance, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
    JS_FN("render", js_cocos2dx_Director_render, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
    JS_FS_END
};

The cpp file I have here ./frameworks/js-bindings/bindings/auto

but I also see subfolder “api” there and there is a file jsb_cocos2dx_auto_api.js
In it I can find some functions like “getInstance” on Director too.
Like this

/**
 * @method getInstance
 * @return {cc.Director}
 */
getInstance : function (
)
{
    return cc.Director;
},

};

May be the render() needs be here too?

I added it there and it did not help. Same result.

I didn’t add anything to that file, but you could try it. Try cc.director.render() too just in case.

I took another project I have with Cocos-JS 3.2 and copied and pasted my 3 steps, and it works for me. (I got the same error as you did until I realised I copied the “before” code instead of the “after” code.) I have tested in XCode on Mac and iPad.

Which version of Cocos are you using? And which platform are you testing on?

I work on Windows 8.1, Cocos Code IDE, cocos2d-x 3.3, cocos2d-js 3.2
testing on Android Nexus 5 and in runtime on windows directly from IDE.

I also tested cc.director.render(). Same error.
I even tested cc.Director._render(); Why: it seem strange but for example when I’m typing in IDE cc.Director. I got pop-up with functions and properties and there I can find _getInstance() but NOT getInstance()… Anyway, if I want to get the instance I have to use getInstance() version. Don’t know why.
Anyway thank you for your support.

Sorry, but I did not understand what you mean by copying “before” vs. “after” …

By “before” and “after” I mean that in Step 3 I posted the code that is there BEFORE you change it and what it should look like AFTER you change it. Maybe try cleaning and rebuilding? Other than that, I’m unsure why this is happening.

Oh yes. It must be that problem. it probably does not build the runtime. It seems building it, finally messaging the success, but in ./runtime/android as well as in ./runtime/win32 the files have one month old dates. So either it does not succeed or result is placed somewhere else… But if I remove PrebuiltRuntimeJs.apk and try to run project from IDE the IDE is requiring to enter a new location of the prebuild runtime.
Grimfate thanks a lot. Realy. I’ll keep elaborate and perhaps force the IDE to build it.

Well, the IDE built an apk file which was named by my project name and not by “PrebuiltRuntimeJs.apk”… I’ve chosen this apk when IDE required me to enter the path to prebuilt runtime. Well, it started on the device and the render() function was invoked!!

Ok. The behaving is somehow strange. I do not understand why IDE builds runtime such a way. May be it is a proper way. I do not know.

Anyway. I got cleared buffer from renderTexture now. So, thank you Grimfate very much again.

Unfortunately nothing is perfect. It had some side effect :slight_smile: My scene has scaled down to some quarter of the screen… Now I’m really surprised. Also it does not run on the runtime on windows yet. I’ll keep elaborating…
Thank you.