Jump to content

Awesomium First Try.. need some help (c++)


Charrua
 Share

Recommended Posts

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:

mouse%20outside.png

 

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

mouse%20over.png

 

 

mouse%20click.png

 

 

thank's in advance

 

jio

Paren el mundo!, me quiero bajar.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

Paren el mundo!, me quiero bajar.

Link to comment
Share on other sites

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
}

Link to comment
Share on other sites

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

Paren el mundo!, me quiero bajar.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

Paren el mundo!, me quiero bajar.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

Paren el mundo!, me quiero bajar.

Link to comment
Share on other sites

  • 1 year later...

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.

Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...