How to Transform Your Games C/C++ for the Web with EmScripten (SDL2)

This article shows how to install EmScripten and how to transform it into JavaScript and WebAssembly, we will transform an SDL2 example with C++.


How to Transform Your Games C/C++ for the Web with EmScripten (SDL2)

Emscripten is a compiler that translates code written in C and C++ to WebAssembly, or to a subset of JavaScript known as asm.js).

Applications compiled with Emscripten are more performant and therefore faster than interpreted or dynamically compiled JavaScript.


How to install Emscripten

Dependencies: CMake, gcc and Python.

On Unix-based systems:

git clone https://github.com/emscripten-core/emsdk ~/.emsdk
cd .emsdk
git pull
./emsdk install latest
./emsdk activate latest
echo 'source "${HOME}/.emsdk/emsdk_env.sh" 2>&-' >> ~/.bashrc
exec $SHELL

Test with the command:

em++ --version

If using Windows, see here.


Example of use

Suppose you have this code:

main.cpp

#include <SDL2/SDL.h>

int main(int argc, char** argv) {
  SDL_Window* window = NULL;
  window = SDL_CreateWindow(
      "SDL2 It's Work!",
      SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
      640, 480,
      SDL_WINDOW_SHOWN
      );
  SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
  SDL_SetRenderDrawColor(renderer, 9, 20, 33, 255);
  while(true){
    SDL_Event event;
    while(SDL_PollEvent(&event)){
      if( event.type == SDL_QUIT ){
        exit(0);
      }
    }
    SDL_RenderClear(renderer);
    SDL_RenderPresent(renderer);
  }
  SDL_DestroyRenderer(renderer);
  SDL_DestroyWindow(window);
  //SDL_Quit();
  return 0;
}

Save this image: SDL2

Compile and run:

Need SDL2 installed!

g++ main.cpp -lSDL2
./a.out

Now let’s transform this code to compile for the Web.

Modify the code above and make it look like this:

#include <SDL2/SDL.h>
#include <emscripten.h>
#include <iostream>

struct Context {
  std::string title;
  int width, height;
  SDL_Renderer * renderer;
  SDL_Event event;
  SDL_Rect rect, rect2;
  SDL_Texture * logo;
};

void callback(void * arg){
  Context * context = static_cast<Context*>(arg);
    while(SDL_PollEvent(&context->event)){
      if( context->event.type == SDL_QUIT ){
        exit(0);
      }else if( context->event.type == SDL_MOUSEBUTTONDOWN ){
        context->rect2.x -= 20;
      }
    }

    SDL_RenderClear(context->renderer);
    SDL_SetRenderDrawColor(context->renderer, 255, 255, 255, 255);
    //SDL_RenderDrawRect(renderer, &rect2);
    SDL_RenderFillRect(context->renderer, &context->rect2);
    SDL_SetRenderDrawColor(context->renderer, 9, 20, 33, 255);
    SDL_RenderCopy(context->renderer, context->logo, NULL, &context->rect);
    SDL_RenderPresent(context->renderer);
}

int main(int argc, char** argv) {
  Context context;
  SDL_Init(SDL_INIT_EVERYTHING);

  context.title = "SDL2 It's Works!";
  context.width = 1280;
  context.height = 720;

  SDL_Window* window = SDL_CreateWindow(
      context.title.c_str(),
      50, 30,
      context.width, context.height,
      SDL_WINDOW_SHOWN
      );

  SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
  context.renderer = renderer;


  SDL_Surface * surface = SDL_LoadBMP("./sdl.bmp");
  context.logo = SDL_CreateTextureFromSurface(renderer, surface);
  SDL_FreeSurface(surface);

  context.rect.x = 50;
  context.rect.y = 20;
  context.rect.w = surface->w;
  context.rect.h = surface->h;

  context.rect2.x = 800;
  context.rect2.y = 20;
  context.rect2.w = 300;
  context.rect2.h = 300;

  emscripten_set_main_loop_arg(callback, &context, -1, 1);

  SDL_DestroyTexture(context.logo);
  SDL_DestroyRenderer(renderer);
  SDL_DestroyWindow(window);
  SDL_Quit();
  return 0;
}

Compile with the following command:

em++ main.cpp -s WASM=1 -s USE_SDL=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS='["bmp"]' --preload-files sdl.bmp -o index.js

Create a new index.html file and insert this content:

If the file already exists, remove all content from it and paste this code inside.

<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <center>
      <canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas>
      <script type='text/javascript'>
        var Module = {
          canvas: (function() { return document.getElementById('canvas'); })()
        };
      </script>
      <script src="index.js"></script>
    </center>
  </body>
</html>

And now view and use in your browser!

After running this command the game will automatically open in your default browser.

emrun index.html

For more information visit the official website of Emscripten:

https://emscripten.org/


gamedev cpp sdl2 web


Share


YouTube channel

Subscribe


Marcos Oliveira

Marcos Oliveira

Software developer
https://github.com/terroo

Related articles