Charrua Posted December 30, 2015 Share Posted December 30, 2015 Hi, i was trying to get awesomium to work with leadwerks. Mi knowledge about javascript and html are almost nothing, (ok, my knowledge of c++ isn't too much also) I need a ui for leadwerks, which is a must, i guess. The following code is what i could make to work: 1) load a local html file 2) on every loop send mouse events to the html "web view" get how it look on a leadwerks texture show it on the screen (context->DrawImage) What i miss is how to bind java events to c++ functions Does someone has a simple example of how to do that. A snapshoot: here the complete source: /* Awesomium - Leadwerks tests by Juan Ignacio Odriozola, aka charrua http://wiki.awesomium.com/getting-started/ What this code does load a simple html page: just a label and a button get what it show and copy that info to a Leadwerks texture Send to the html mouse events Display the texture on screen with a cube rotating on the 3d space if you hover the button, mouse down or mouse up, the control draws as spected. What it doesn't the code do not bind button press and do not call any c++ function OnMouseHit SO I'm asking if anyone has a simple code to showme how to do that. I'm know nothing about html neither javascript, i will try to learn abot them if i got awesomium to work with leadwerks! Hope this code will catch interest in other about awesomium or short the learning path that's the html source of "boton.html": <html> <body> <h1>Awesomium Test</h1> <button onclick="app.sayHello()">Say Hello</button> </body> </html> */ #include "App.h" #include <Awesomium/WebCore.h> #include <Awesomium/BitmapSurface.h> #include <Awesomium/STLHelpers.h> using namespace Awesomium; WebCore* web_core = NULL; WebView* my_web_view = NULL; BitmapSurface* uiSurface = NULL; Texture* uiTex = NULL; unsigned char* pixels = NULL; using namespace Leadwerks; App::App() : window(NULL), context(NULL), world(NULL), camera(NULL) {} App::~App() { delete world; delete window; } Model* model = NULL; JSValue jsResult; bool App::Start() { window = Window::Create(); context = Context::Create(window); world = World::Create(); camera = Camera::Create(); camera->Move(0, 0, -3); Light* light = DirectionalLight::Create(); light->SetRotation(35, 35, 0); // Create the WebCore singleton with default configuration web_core = WebCore::Initialize(WebConfig()); // al salir: WebCore::Shutdown(); my_web_view = web_core->CreateWebView(320, 200); WebURL url(WSLit("file:///./boton.html")); //acceso al dir local! my_web_view->LoadURL(url); uiTex = Texture::Create(320, 200); pixels = (unsigned char*)malloc(uiTex->GetMipmapSize(0)); // Wait for our WebView to finish loading while (my_web_view->IsLoading()) web_core->Update(); Sleep(300); web_core->Update(); uiSurface = (BitmapSurface*)my_web_view->surface(); // para esto hay que: #include <Awesomium/BitmapSurface.h> if (uiSurface != 0) { uiSurface->SaveToJPEG(WSLit("./result.jpg")); //just to verify html was loaded and how it look! uiSurface->CopyTo(pixels, uiTex->GetWidth() * 4, 4, true, false); uiTex->SetPixels((char*)pixels); } // now a cube and btw texture it with the html view //Create a material Material* material = Material::Create(); //use uiTex as texture material->SetTexture(uiTex); //Load and apply a shader Shader* shader = Shader::Load("Shaders/Model/diffuse.shader"); material->SetShader(shader); shader->Release(); //Create a model and apply the material model = Model::Box(); model->SetMaterial(material); model->SetPosition(0, 0, 1); return true; } bool mouseLeftDown = false; bool App::Loop() { if (window->Closed() || window->KeyDown(Key::Escape)) { free(pixels); my_web_view->Destroy(); WebCore::Shutdown(); return false; } model->Turn(Time::GetSpeed()/3, Time::GetSpeed()/4, Time::GetSpeed() / 2); //get new pixel data from html view if (uiSurface != 0) { uiSurface->CopyTo(pixels, uiTex->GetWidth() * 4, 4, true, false); uiTex->SetPixels((char*)pixels); } // Inject a mouse-movement my_web_view->InjectMouseMove(window->MouseX(), window->MouseY()); if (window->MouseDown(1)){ // Inject a left-mouse-button down event my_web_view->InjectMouseDown(kMouseButton_Left); mouseLeftDown = true; } else { if (mouseLeftDown) { mouseLeftDown = false; // Inject a left-mouse-button up event my_web_view->InjectMouseUp(kMouseButton_Left); } } web_core->Update(); Time::Update(); world->Update(); world->Render(); context->DrawImage(uiTex, 0, 0); context->Sync(); return true; } more snapshoots, when mouse hover the button and when i'ts clicked thank's in advance jio Quote Paren el mundo!, me quiero bajar. Link to comment Share on other sites More sharing options...
Rick Posted December 30, 2015 Share Posted December 30, 2015 I've gotten this working before. A couple things. 1. In my main loop the way I get the data to an LE texture is slightly different than what you have: // draw awesomium BitmapSurface* surface = (BitmapSurface*)webView->surface(); if (surface->is_dirty()) webTexture->SetPixels((const char*)surface->buffer()); context->DrawImage(webTexture, 0, 0); webTexture is an LE Texture object. 2. Here is my UI Input function for the mouse (I haven't figured out keyboard but if you do that would be nice to share with everyone) void App::UIInput() { webView->Focus(); Vec3 mpos = window->GetMousePosition(); webView->InjectMouseMove(mpos.x, mpos.y); if (window->MouseDown(1) && leftMouseDown == false) { webView->InjectMouseDown(kMouseButton_Left); leftMouseDown = true; } else if (window->MouseDown(1) == false && leftMouseDown == true) { webView->InjectMouseUp(kMouseButton_Left); leftMouseDown = false; } if (window->MouseDown(2) && rightMouseDown == false) { webView->InjectMouseDown(kMouseButton_Right); rightMouseDown = true; } else if (window->MouseDown(2) == false && rightMouseDown == true) { webView->InjectMouseUp(kMouseButton_Right); rightMouseDown = false; } } 3. Here is how you link javascript functions to C++ functions so when these functions are called in Javascript they will call the C++ function. MethodDispatcher dispatcher; // bind functions JSValue result = webView->CreateGlobalJavascriptObject(WSLit("app")); if (result.IsObject()) { JSObject& app = result.ToObject(); //dispatcher.Bind(app, WSLit("sayHello"), JSDelegate(this, &App::Client_SayHello)); // this C++ function must have a return type of JSValue //dispatcher.BindWithRetval(app, WSLit("test"), JSDelegateWithRetval(this, &App::Client_Test)); dispatcher.Bind(app, WSLit("exitGame"), JSDelegate(this, &App::Client_ExitGame)); dispatcher.Bind(app, WSLit("loadMap"), JSDelegate(this, &App::Client_LoadMap)); } webView->set_js_method_handler(&dispatcher); C++ The function itself looks like (must have these exact params): void App::Client_ExitGame(WebView* caller, const JSArray& args) { quit = false; } If you have arguments passed into the C++ from javascript then: void App::Client_SayHello(WebView* caller, const JSArray& args) { WebString name = args[0].ToString(); WebString msg = args[1].ToString(); int value = args[2].ToInteger(); string _name = ToString(name); string _msg = ToString(msg); } I'm using JQuery so in javascript the way you could call these would be: $(function(){ $("#exit").click(function(){ clicksound.playclip(); app.exitGame(); }); // passing a param $("#newGame").click(function(){ clicksound.playclip(); // tell C++ what map to load app.loadMap($("#maps").val()); }); }); 4. If you want to call a javascript function from C++ then: Javascript side: / this is getting called from C++ function helloWorld(e) { // add each map to the select list for(var i in e){ $('#maps').append($('<option>', { value: e[i], text: e[i] })); } // this is calling a C++ function with a return value //var value = app.test(); // this is calling a C++ function with no return value //app.sayHello(name, msg, value); // this function that C++ called also returns a value return e[1]; } The C++ side: // call a javascript function with args and a return value JSValue window = webView->ExecuteJavascriptWithResult(WSLit("window"), WSLit("")); if (window.IsObject()) { JSArray args; JSArray e; vector<string> files; FileSystem::LoadDir("maps", files); for(auto f : files) { string ext = FileSystem::ExtractExt(f); if (ext == "map") { e.Push(WSLit(f.c_str())); } } args.Push(e); JSValue v = window.ToObject().Invoke(WSLit("helloWorld"), args); string t = ToString(v.ToString()); } I do extra things for testing purposes. Like returning from this helloWorld() function doesn't make much sense but I was just testing how that's done. As a side note, I needed to start from Lua and tell the UI information (in our game Dead Anyway hunger would tick away every few seconds and that was done in Lua, but the UI was obviously in html). So I linked a lua function to a C function and then the C function called a C++ function which then called a Javascript function to update the UI. Note I had to call this lua registering stuff at the top of App:Start(). Anywhere else and it wouldn't work. bool App::Start() { // must call this before calling lua functions for some reason int size = Interpreter::GetStackSize(); // register lua to c++ functions lua_pushcfunction(Interpreter::L, UpdateStat); lua_setglobal(Interpreter::L, "UpdateStat"); } The UpdateStat C function looks like: static int UpdateStat(lua_State* L) { string statName = lua_tostring(L, 1); double value = lua_tonumber(L, 2); app->OnStatUpdate(statName, value); return 0; } Then I just had it call the App objects OnStatUpdate function because I prefer to do things in objects instead of normal C functions but this is the easy way to link C++ & Lua. Then in my OnStatUpdate method I tell Javascript what happened. void App::OnStatUpdate(string statName, int value) { // call the javascript function that will update the html UI JSValue window = webView->ExecuteJavascriptWithResult(WSLit("window"), WSLit("")); if (window.IsObject()) { JSArray args; JSValue stat = JSValue(WSLit(statName.c_str())); JSValue v = JSValue(value); args.Push(stat); args.Push(v); JSValue v1 = window.ToObject().Invoke(WSLit("updateStat"), args); bool r = v1.ToBoolean(); //string t = ToString(v1.ToString()); } } Then my javascript function: // event from C++ which ultimately is coming from lua which is tracking the decay of these stats function updateStat(stat, value){ // change the value of the stat if($("#" + stat).length){ $("#" + stat).text(value); return true; } return false; } There is a ton of information here I know so if you need anything clarified just let me know and we can work through it. Again, if you can get the keyboard events working that would be great to share, and if you can think of any way to package this entire thing up in a nice system where it's maybe a class that people can just use instead of a bunch of embedded parts that would be good for the community I think. I'm still a strong believer that this is how UI's should be, but like you I just don't know HTML/CSS to make any cool UI's that work well on every aspect ratio/screen res. Quote Link to comment Share on other sites More sharing options...
Charrua Posted December 30, 2015 Author Share Posted December 30, 2015 forgot to include an executable for you to try if you change the boton.html for another more elaborated html it should work also. but i'm only using 300x200 pixels for the ui texture, so not too much space for being much creative. int the app dir, a snapshoot of the html as is after loaded is saved as result.jpg here the 7z file: https://dl.dropboxusercontent.com/u/78894295/leadwerks/awe.7z enjoy jio Quote Paren el mundo!, me quiero bajar. Link to comment Share on other sites More sharing options...
Rick Posted December 30, 2015 Share Posted December 30, 2015 Here is another C++ function called from Javascript where from the UI a person clicked on which map to load. Might be helpful in understanding as well. // called from Javascript void App::Client_LoadMap(WebView* caller, const JSArray& args) { WebString map = args[0].ToString(); string _map = ToString(map); std::string mapname = "Maps/" + _map; Map::Load(mapname); webView->LoadURL(WebURL(WSLit("file:///UI//HUD.html"))); // used to let the page load before we show anything while (webView->IsLoading()) webCore->Update(); Sleep(300); webCore->Update(); // draw awesomium BitmapSurface* surface = (BitmapSurface*)webView->surface(); if (surface->is_dirty()) webTexture->SetPixels((const char*)surface->buffer()); Material* mat = Material::Create(); mat->SetTexture(webTexture); Shader* shader = Shader::Load("Shaders/Dynamic/diffuse.shader"); mat->SetShader(shader); Entity* console = world->FindEntity("Console"); console->SetMaterial(mat); //webTexture } Quote Link to comment Share on other sites More sharing options...
Charrua Posted December 30, 2015 Author Share Posted December 30, 2015 rick, i was writing my second post when you answer my first thank's for your input, i have to read it carefully about keyboard input... je je, the docs say not to much... even tells us to read some other doc which has no link! would be nice if some one else has a code for that jio Quote Paren el mundo!, me quiero bajar. Link to comment Share on other sites More sharing options...
Rick Posted December 30, 2015 Share Posted December 30, 2015 Yeah, I noticed that dead link too What would be nice is to have a generic C++ interface that allows communication from Lua to Javascript and back without having to add/edit any C++ code once it's in place. That way one could add this little C++ code, compile their exe, and never have to mess with it again and now they just do things in Lua and Javascript to hook up communications. I think this can be done. Quote Link to comment Share on other sites More sharing options...
Charrua Posted December 30, 2015 Author Share Posted December 30, 2015 at least should be goo to get a working all included example to start with I'll will update this thread as soon as i get something new to show. (too much information for me to digest.. it will take a while...) thank's again jio Quote Paren el mundo!, me quiero bajar. Link to comment Share on other sites More sharing options...
Rick Posted December 30, 2015 Share Posted December 30, 2015 Had an idea on how to make a generic messaging system back and forth between lua and javascript back in the Dead Anyway days (doing both ways). Don't have much free time this week but I think the idea would work. This would allow you to have 1 C++ function and never have to touch it again (as it would act as a generic interface between lua and javascript) and then just define functions in javascript and lua and send messages to call those functions. Would make for a slick and easy way to get functions called between the 2 so you can have 2 way communication very easily and dynamically. Quote Link to comment Share on other sites More sharing options...
Charrua Posted December 30, 2015 Author Share Posted December 30, 2015 OK, thank's to Rick y now have a complete working example of integrating leadwerks and awesomium the example now has 2 buttons, one to SayHello the other to exit the application and work as expected! 7z file has the Source folder with all the source files needed, those files which came from awesomium form part of one of the tutorials general gelp on awesomium: http://wiki.awesomium.com/getting-started/ tut files: https://github.com/awesomium/tutorial-framework/archive/master.zip complete c++ source and executable for you to try: https://dl.dropboxusercontent.com/u/78894295/leadwerks/awe1.7z had happens to me that the first time i run seem not to respond to mouse down events... but works ok if exit and run again do not know why can it be! enjoy jio Quote Paren el mundo!, me quiero bajar. Link to comment Share on other sites More sharing options...
Shhn86p Posted January 26, 2017 Share Posted January 26, 2017 Such manful enhancement supplements can be purchased and acclimated to without the have need of on a prescription, kamagra and man unquestionable owner testimonials asseverate to the claimed benefits of these herbal supplements. Of course, kamagra oral jelly as with all supplements, it is foremost to research each fallout on the eve of making any purchases. To make this function easier, we’ve taken the without delay to provide basic bumf on what to foresee from virile enhancement supplements. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.