Emscripten

  • 8 October 2017
  • GeeX

Vor ein paar Jahren wollte mein Sohn wissen wie man Spiele programmiert.

Damals habe ich ein einfaches Tutorial (jnrdev jump'n run, leider nicht mehr online) in C++ gesucht, um ihm das zu zeigen.

Da ich zu der Zeit auch mit Emscripten beschäftigt wegen einer TTS Engine war, habe ich 

versucht dieses Tutorial über Emscripten nach Javascript zu kompilieren.

Zunächst muss erst müssen erst mal die richtigen Versionen der SDL Bibiliotheken installiert werden,

was gar nicht so einfach ist, da Emscripten SDL1.2 emuliert und 2.0 zur Zeit noch nicht richtig

implementiert ist.

So hat es funktioniert, damit ich meine Gameloop auf allen Maschinen kompilieren konnte:

  Emscripten SDL2

 

Gameloop für Emscripten:

minimal.c

#include <stdio.h>
#include <math.h>
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif

int int_sqrt(int x) {
  return sqrt(x);
}

struct cnt
{
    int x;
};

void loop(void *arg)
{
    struct cnt *ctx = arg;
    printf("x: %d\n", ctx->x);
    if (ctx->x >= 100)
    {
        /**
         * After 101 iterations, stop looping
         */
#ifdef __EMSCRIPTEN__
        emscripten_cancel_main_loop();
#else
       exit(0);
#endif
        printf("got here...\n");
        return;
    }

    ctx->x += 1;
}
int main() {
	 struct cnt ctx;
	    int simulate_infinite_loop = 1;
	    ctx.x = 0;
#ifdef __EMSCRIPTEN__
	    emscripten_set_main_loop_arg(loop, &ctx, -1, simulate_infinite_loop);
#else
loop();
#endif
  printf("hello, world!\n");
  return 0;
}

 

Wie man sieht werden nicht viele Änderungen benötigt um diese loop nach JS zu portieren.

Kompilieren:

kompiliert das Programm zu a.out.js

emcc minimal.c

kompiliert das Programm zu a.out.js

node a.out.js

startet das Programm im NODE WORKER

emcc minimal.c -o html

kompiliert das Programm in a.out.js und erstellt minimal.html für den Browser in der das Program geladen wird

hier ist eine runtergestrippte Version der html Datei welche nur die Konsole(Taxtarea) anzeigt.

minimal.html

 <html>
  <head>
  </head>
  <body>
  <div class="spinner" id='spinner'></div>
    <div class="emscripten" id="status">Downloading...</div>
    <div class="emscripten">
      <progress value="0" max="100" id="progress" hidden=1></progress>
    </div>
    <h1>Ausgabe:</h1>
    <textarea id="output" rows="8"></textarea>
   <input type="button" onclick="DoSomething();" value="DoIt!"/>
    <script type='text/javascript'>
    function DoSomething(){
    	Module.print("Done!");
    	Module.printErr("Done printErr!");
    	console.log(Module);    	
    	Module.setWindowTitle("HAHAHAHAHAHA!");
    	//alert(Module._int_sqrt(50));
    	int_sqrt = Module.cwrap('int_sqrt', 'number', ['number'])
    	alert(int_sqrt(12));
    	alert(int_sqrt(28));
    	
    };
    </script>
    <script async type="text/javascript" src="a.out.js"></script>
    </body>
</html>

res.cpp

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

extern "C" void print_string_to_heap(char* s1);
extern "C" {
EMSCRIPTEN_KEEPALIVE
    void printString(char* s1) {
	  printf("%s\n", s1);
//        std::cout << str << std::endl;
    }
}

extern "C" void write_string_to_heap(char* s1);
extern "C" void EMSCRIPTEN_KEEPALIVE get_js_string(char* s1, char* s2) {
    printf("%s - %s\n", s1, s2);
};

res.js

var em_module = require('./a.out.js');

var str="NODE TEST";
em_module.ccall('printString', 'null',['string'], [str]);
                                                   
var str2 = "TESTBuffer";
var buffer = em_module._malloc(str2.length + 1);
em_module.writeStringToMemory(str2, buffer);
//Buffer enthält den Pointer zum String!!!
console.log(buffer);
//Darum ist hier der Parameter Number!!!;
em_module.ccall('printString', 'null',['number'], [buffer])

res.html

<!doctype html>
<html>
  <script src="a.out.js"></script>
  <script>
//  console.log(Module);
var write_string_to_heap= function(_string_dest_in_c) {
    Module.ccall('get_js_string', 'null',['string','string'], [_string_dest_in_c, "Hello from JS."]);
}

var print_string_to_heap= function(_string_dest_in_c) {
//Buffer
	var buffer = Module._malloc(_string_dest_in_c.length + 1);
  Module.writeStringToMemory(_string_dest_in_c, buffer);
  Module.ccall('printString', 'null',['number'], [buffer]);
  //Direkt
    Module.ccall('printString', 'null',['string'], [_string_dest_in_c]);
}
write_string_to_heap("Robert");
print_string_to_heap("Hallo Welt");
  </script>
</html>