Add emscripten

This commit is contained in:
Miloslav Ciz 2025-05-04 18:08:28 +02:00
parent 68df5326d7
commit 70d5e11719
4 changed files with 189 additions and 39 deletions

95
HTMLshell.html Normal file
View file

@ -0,0 +1,95 @@
<!doctype html>
<!--
HTML template for the emscripten page. Unlike emscipten's official minimal
frontend, this one is really minimal.
by Miloslav Ciz (drummyfish)
Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/)
plus a waiver of all other intellectual property. The goal of this work is
be and remain completely in the public domain forever, available for any use
whatsoever.
-->
<html>
<head>
<meta charset="utf-8">
<title>game</title>
<style>
table
{
width: 100%;
}
td
{
width: 11%;
padding: 0;
margin: 0;
}
button
{
width: 100%;
}
canvas
{
display: block;
margin: 10px auto 30px;
}
</style>
</head>
<body>
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
<script type='text/javascript'>
Module = {
print:
function(what)
{
console.log(what);
},
printErr:
function(what)
{
console.error(what);
},
canvas:
(
function()
{
return document.getElementById('canvas');
}
)(),
onRuntimeInitialized: function()
{
pressFunc = Module.cwrap('webButton','', ['number','number']);
}
};
function down(button)
{
pressFunc(button,1);
}
function up(button)
{
pressFunc(button,0);
}
</script>
{{{ SCRIPT }}}
<table style="user-select:none; -moz-user-select: none; -ms-user-select:none; -webkit-user-select: none; -o-user-select:none;" onselectstart="return false;" unselectable="on">
<tr> <td></td> <td><button onmousedown="down(0)" ontouchstart="down(0)" onmouseup="up(0)" ontouchend="up(0)" onmouseout="up(0)" ontouchleave="(0)">U</button></td> <td></td> <td></td> <td><button onmousedown="down(4)" ontouchstart="down(4)" onmouseup="up(4)" ontouchend="up(4)" onmouseout="up(4)" ontouchleave="(4)">A</button></td> <td></td> <td></td> </tr>
<tr> <td><button onmousedown="down(3)" ontouchstart="down(3)" onmouseup="up(3)" ontouchend="up(3)" onmouseout="up(3)" ontouchleave="(3)">L</button></td> <td></td> <td><button onmousedown="down(1)" ontouchstart="down(1)" onmouseup="up(1)" ontouchend="up(1)" onmouseout="up(1)" ontouchleave="(1)">R</button></td> <td></td> <td></td> <td><button onmousedown="down(5)" ontouchstart="down(5)" onmouseup="up(5)" ontouchend="up(5)" onmouseout="up(5)" ontouchleave="(5)">B</button></td> <td></td> </tr>
<tr> <td></td> <td><button onmousedown="down(2)" ontouchstart="down(2)" onmouseup="up(2)" ontouchend="up(2)" onmouseout="up(2)" ontouchleave="(2)">D</button></td> <td></td> <td></td> <td></td> <td></td> <td></td> </tr>
</table>
</body>
</html>

View file

@ -2,6 +2,7 @@ fuck issue trackers :D
=========== GENERAL ==============
- 640x480 with resolution subdiv has bad sized menu item highlight
- LOD blocks in lower res look too small
- hitting ramps at higher speed still often bugs, try to fiddle with physics
again (reshape iterations, tension, ...)

View file

@ -11,6 +11,15 @@
#define LCR_FPS_GET_MS SDL_GetTicks() // uncomment for FPS measuring
#ifdef __EMSCRIPTEN__
#define LCR_SETTING_RESOLUTION_X 640
#define LCR_SETTING_RESOLUTION_Y 480
#define LCR_SETTING_MUSIC 0
#define LCR_SETTING_CAR_SHADOW 0
#define LCR_SETTING_TEXTURE_SUBSAMPLE 4
#define LCR_SETTING_RESOLUTION_SUBDIVIDE 2
#endif
#include "game.h"
SDL_Window *window;
@ -18,6 +27,8 @@ SDL_Renderer *renderer;
SDL_Texture *texture;
SDL_Surface *screenSurface;
uint8_t running = 1, fullscreen = 1;
#if LCR_SETTING_332_COLOR
uint8_t
#else
@ -30,6 +41,9 @@ FILE *dataFile = 0;
char LCR_getNextDataFileChar(void)
{
#ifdef __EMSCRIPTEN__
return 0;
#else
if (!dataFile)
return 0;
@ -42,10 +56,12 @@ char LCR_getNextDataFileChar(void)
}
return c;
#endif
}
void LCR_appendDataStr(const char *str)
{
#ifndef __EMSCRIPTEN__
if (!dataFile)
return;
@ -68,6 +84,9 @@ void LCR_appendDataStr(const char *str)
dataFile = fopen(DATA_FILE_NAME,"r");
}
}
#else
printf("%s",str);
#endif
}
void audioFillCallback(void *userdata, uint8_t *s, int l)
@ -116,11 +135,26 @@ uint8_t LCR_keyPressed(uint8_t key)
return 0;
}
#ifdef __EMSCRIPTEN__
typedef void (*em_callback_func)(void);
void emscripten_set_main_loop(
em_callback_func func, int fps, int simulate_infinite_loop);
#endif
void LCR_sleep(uint16_t timeMs)
{
#ifndef __EMSCRIPTEN__
SDL_Delay(timeMs);
#endif
}
#ifdef __EMSCRIPTEN__
void webButton(uint8_t key, uint8_t down) // HTML button pressed
{
// TODO
}
#endif
void LCR_drawPixel(unsigned long index, uint16_t color)
{
screen[index] = color;
@ -140,10 +174,36 @@ void printHelp(void)
LCR_ARG_HELP_STR);
}
void mainLoopIteration(void)
{
SDL_Event event;
running = 1;
while (SDL_PollEvent(&event))
if (event.type == SDL_QUIT)
running = 0;
keyboardState = SDL_GetKeyboardState(NULL);
running &= LCR_gameStep(SDL_GetTicks());
SDL_UpdateTexture(texture,NULL,screen,
LCR_SETTING_RESOLUTION_X * sizeof(
#if LCR_SETTING_332_COLOR
uint8_t
#else
uint16_t
#endif
));
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer,texture,NULL,NULL);
SDL_RenderPresent(renderer);
}
int main(int argc, char *argv[])
{
uint8_t running = 1, fullscreen = 1;
for (int i = 0; i < argc; ++i)
if (argv[i][0] == '-')
switch (argv[i][1])
@ -160,11 +220,20 @@ int main(int argc, char *argv[])
default: break;
}
#ifdef __EMSCRIPTEN__
fullscreen = 0;
#else
dataFile = fopen(DATA_FILE_NAME,"r");
if (!dataFile)
LCR_log("couldn't open data file");
musicFile = fopen("assets/music","rb");
if (!musicFile)
fputs("could not open music file",stderr);
#endif
LCR_log("initializing game");
LCR_gameInit(argc,(const char **) argv);
@ -175,21 +244,21 @@ int main(int argc, char *argv[])
SDL_AudioSpec audioSpec;
SDL_memset(&audioSpec,0,sizeof(audioSpec));
audioSpec.callback = audioFillCallback;
audioSpec.channels = 1;
audioSpec.freq = 8000;
audioSpec.format = AUDIO_U8;
audioSpec.channels = 1;
#ifdef __EMSCRIPTEN__
audioSpec.samples = 1024;
#else
audioSpec.samples = 64;
#endif
if (SDL_OpenAudio(&audioSpec,NULL) < 0)
fputs("could not initialize audio",stderr);
SDL_PauseAudio(0);
musicFile = fopen("assets/music","rb");
if (!musicFile)
fputs("could not open music file",stderr);
window =
SDL_CreateWindow("Licar", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, LCR_SETTING_RESOLUTION_X, LCR_SETTING_RESOLUTION_Y,
@ -237,41 +306,22 @@ int main(int argc, char *argv[])
LCR_log("starting game loop");
while (running)
{
SDL_Event event;
running = 1;
while (SDL_PollEvent(&event))
if (event.type == SDL_QUIT)
running = 0;
keyboardState = SDL_GetKeyboardState(NULL);
running &= LCR_gameStep(SDL_GetTicks());
SDL_UpdateTexture(texture,NULL,screen,
LCR_SETTING_RESOLUTION_X * sizeof(
#if LCR_SETTING_332_COLOR
uint8_t
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(mainLoopIteration,0,1);
#else
uint16_t
while (running)
mainLoopIteration();
#endif
));
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer,texture,NULL,NULL);
SDL_RenderPresent(renderer);
}
LCR_log("ending");
if (musicFile)
fclose(musicFile);
#ifndef __EMSCRIPTEN__
if (dataFile)
fclose(dataFile);
#endif
SDL_PauseAudio(1);
SDL_CloseAudio();

12
make.sh
View file

@ -35,10 +35,14 @@ if [ $PLATFORM = "sdl" ]; then
# - SDL2 (dev) package
SDL_FLAGS=`sdl2-config --cflags --libs`
COMMAND="${COMPILER} ${C_FLAGS} frontend_sdl.c -I/usr/local/include ${SDL_FLAGS}"
${COMPILER} ${C_FLAGS} frontend_sdl.c -I/usr/local/include ${SDL_FLAGS}
elif [ $PLATFORM = "emscripten" ]; then
# emscripten (browser Javascript) build, requires:
# - emscripten
# COMMAND="../emsdk/upstream/emscripten/emcc ./frontend_sdl.c -s USE_SDL=2 -O3 -lopenal --shell-file HTMLshell.html -o licar.html -s EXPORTED_FUNCTIONS=\'[\"_main\",\"_webButton\"]\' -s EXPORTED_RUNTIME_METHODS=\'[\"ccall\",\"cwrap\"]\'"
../emsdk/upstream/emscripten/emcc ./frontend_sdl.c -s USE_SDL=2 -O3 -lopenal --shell-file HTMLshell.html -o licar.html -s EXPORTED_FUNCTIONS='["_main","_webButton"]' -s EXPORTED_RUNTIME_METHODS='["ccall","cwrap"]'
else
echo "unknown frontend"
fi
echo ${COMMAND}
${COMMAND}
echo "done"