Emscripten
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:
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>