Implementing Awesomium

Awesomium is a free (to non-commercial users) SDK that allows you to embed WebKit in your project. It offers a .NET and C++ API, and can be easily added to the Source Engine.
Source 2007 does include an HTML control, but it uses the Internet Explorer rendering engine, and doesn't support JavaScript. Using Awesomium allows you to take advantage of CSS3, HTML Canvas, and WebGL. It also allows you to bridge the gap between the browser and the game world, as you can call JavaScript functions inside the game, and can call game methods from JavaScript.
HTML is a mature presentation layer, so it makes sense to use it for in-game UI that would otherwise be difficult to construct using the VGUI library alone. Counter-Strike: Global Offensive's UI previously used an implementation of Adobe Flash called Scaleform for instance.
== Pre-requisites ==
=== Awesomium Linked & Included ===
First, you'll need to install the Awesomium SDK, and link it up in your Client project. There's a really easy to follow tutorial on the site on how to do that, so I won't cover that again: Setting up Awesomium in your C++ project
=== The VAwesomium Code ===
Second, you'll need the business end of the device- VAwesomium. VAwesomium wraps up the Awesomium functionality into an extensible VGUI Panel that you can plonk into your mod and go. I'm currently using it in my mod Estranged, where we're working on in-engine puzzles and backstory elements composed in HTML.
To use it, simply download or check out the source code, and add it to your Client project: https://github.com/alanedwardes/VAwesomium
== Basic Usage ==
Here's an example of it being used in a vgui::Panel element:
Header:
class MyPanel : public vgui::Panel
{
public:
 MyPanel(vgui::Panel *parent, const char *panelName);
 [...]
private:
 VAwesomium *m_Browser;
};
CPP:
MyPanel::MyPanel(vgui::Panel *parent, const char *panelName) : vgui::Panel(parent, panelName)
{
 m_Browser = new VAwesomium(this, "VAwesomium");
 m_Browser->SetSize(GetWidth(), GetTall());
 m_Browser->OpenURL("https://developer.valvesoftware.com/wiki/Main_Page");
}
== Advanced Usage ==
If you want to add JavaScript functions that your page can call to interface with the engine, you'll need to inherit from the VAwesomium class.
Header:
#include "VAwesomium.h"
#define EXIT_COMMAND "ExitMyVAwesomium"
#include <vgui/VGUI.h>
#include <vgui_controls/Panel.h>
class MyVAwesomium : public VAwesomium
{
 DECLARE_CLASS_SIMPLE(MyVAwesomium, VAwesomium);
public:
 MyVAwesomium(vgui::Panel *parent, const char *panelName) : VAwesomium(parent, panelName){};
 virtual void OnDocumentReady(Awesomium::WebView* caller, const Awesomium::WebURL& url);
 virtual void OnMethodCall(Awesomium::WebView* caller, unsigned int remote_object_id, const Awesomium::WebString& method_name, const Awesomium::JSArray& args);
};
CPP:
using namespace Awesomium;
#ifdef PostMessage
#undef PostMessage
#endif
void MyVAwesomium::OnDocumentReady(WebView* caller, const WebURL& url)
{
 JSValue result = caller->CreateGlobalJavascriptObject(WSLit("MyObject"));
 JSObject &myObject = result.ToObject();
 myObject.SetCustomMethod(WSLit("ReturnToGame"), false);
 caller->ExecuteJavascript(WSLit("AwesomiumInitialized()"), WSLit(""));
}
void MyVAwesomium::OnMethodCall(Awesomium::WebView* caller, unsigned int remote_object_id, const Awesomium::WebString& method_name, const Awesomium::JSArray& args)
{
 if (method_name == WSLit("ReturnToGame"))
 {
 BaseClass::GetParent()->PostMessage(BaseClass::GetParent(), new KeyValues("command", "command", EXIT_COMMAND));
 }
}
With the Above, MyObject.ReturnToGame() will be available to your HTML page.
=== More JavaScript ===
The JavaScript interface is very powerful, you can execute JavaScript methods that return data from the page, and you can call methods in-browser that return data from the game. To find out more, see the JavaScript pages on the Awesomium wiki.
=== JavaScript Gotchas ===
The implementation isn't perfect, as with Awesomium you have to wait until the OnDocumentReady method has fired to add JavaScript objects to the page. That's why at the end of that method I execute the JavaScript method AwesomiumInitialized() - it allows me to notify my page that the JavaScript objects I just created in the C++ are now available on the page.
== Contributing ==
My class is far from perfect, and is bound to be lacking in certain features or include bugs just waiting to be fixed. I put the project up on GitHub, so please feel free to contribute to the project, and if you're using it, make sure you update it now and again before you distribute it.
VAwesomium on GitHub: https://github.com/alanedwardes/VAwesomium
Category: Programming
Category: Free source code