DarkPlaces
Game engine based on the Quake 1 engine by id Software, developed by LadyHavoc
 
sys_wasm.c
Go to the documentation of this file.
1/*
2 * Include this BEFORE darkplaces.h because it breaks wrapping
3 * _Static_assert. Cloudwalk has no idea how or why so don't ask.
4 */
5#include <SDL.h>
6
7#include "darkplaces.h"
8#include "fs.h"
9#include "vid.h"
10
11#include <emscripten.h>
12#include <emscripten/html5.h>
13#include <string.h>
14
15
16EM_JS(float, js_GetViewportWidth, (void), {
17 return document.documentElement.clientWidth
18});
19EM_JS(float, js_GetViewportHeight, (void), {
20 return document.documentElement.clientHeight
21});
22static EM_BOOL em_on_resize(int etype, const EmscriptenUiEvent *event, void *UData)
23{
25 {
26 Cvar_SetValueQuick(&vid_width, js_GetViewportWidth());
27 Cvar_SetValueQuick(&vid_height, js_GetViewportHeight());
29 }
30 return EM_FALSE;
31}
32
33
34// =======================================================================
35// General routines
36// =======================================================================
37
38#ifdef WASM_USER_ADJUSTABLE
39EM_JS(char *, js_listfiles, (const char *directory), {
40 if(UTF8ToString(directory) == "")
41 {
42 console.log("listing cwd");
43 return stringToNewUTF8(FS.readdir(FS.cwd()).toString());
44 }
45
46 try
47 {
48 return stringToNewUTF8(FS.readdir(UTF8ToString(directory)).toString());
49 }
50 catch (error)
51 {
52 return stringToNewUTF8("directory not found");
53 }
54});
55static void em_listfiles_f(cmd_state_t *cmd)
56{
57 char *output = js_listfiles(Cmd_Argc(cmd) == 2 ? Cmd_Argv(cmd, 1) : "");
58
59 Con_Printf("%s\n", output);
60 free(output);
61}
62
63EM_JS(char *, js_upload, (const char *todirectory), {
64 if (UTF8ToString(todirectory).slice(-1) != "/")
65 {
66 currentname = UTF8ToString(todirectory) + "/";
67 }
68 else
69 {
70 currentname = UTF8ToString(todirectory);
71 }
72
73 file_selector.click();
74 return stringToNewUTF8("Upload started");
75});
76static void em_upload_f(cmd_state_t *cmd)
77{
78 char *output = js_upload(Cmd_Argc(cmd) == 2 ? Cmd_Argv(cmd, 1) : fs_basedir);
79
80 Con_Printf("%s\n", output);
81 free(output);
82}
83
84EM_JS(char *, js_rm, (const char *path), {
85 const mode = FS.lookupPath(UTF8ToString(path)).node.mode;
86
87 if (FS.isFile(mode))
88 {
89 FS.unlink(UTF8ToString(path));
90 return stringToNewUTF8("File removed");
91 }
92
93 return stringToNewUTF8(UTF8ToString(path)+" is not a File.");
94});
95static void em_rm_f(cmd_state_t *cmd)
96{
97 if (Cmd_Argc(cmd) != 2)
98 Con_Printf("No file to remove\n");
99 else
100 {
101 char *output = js_rm(Cmd_Argv(cmd, 1));
102 Con_Printf("%s\n", output);
103 free(output);
104 }
105}
106
107EM_JS(char *, js_rmdir, (const char *path), {
108 const mode = FS.lookupPath(UTF8ToString(path)).node.mode;
109 if (FS.isDir(mode))
110 {
111 try
112 {
113 FS.rmdir(UTF8ToString(path));
114 }
115 catch (error)
116 {
117 return stringToNewUTF8("Unable to remove directory. Is it not empty?");
118 }
119 return stringToNewUTF8("Directory removed");
120 }
121
122 return stringToNewUTF8(UTF8ToString(path)+" is not a directory.");
123});
124static void em_rmdir_f(cmd_state_t *cmd)
125{
126 if (Cmd_Argc(cmd) != 2)
127 Con_Printf("No directory to remove\n");
128 else
129 {
130 char *output = js_rmdir(Cmd_Argv(cmd, 1));
131 Con_Printf("%s\n", output);
132 free(output);
133 }
134}
135
136EM_JS(char *, js_mkd, (const char *path), {
137 try
138 {
139 FS.mkdir(UTF8ToString(path));
140 }
141 catch (error)
142 {
143 return stringToNewUTF8("Unable to create directory. Does it already exist?");
144 }
145 return stringToNewUTF8(UTF8ToString(path)+" directory was created.");
146});
147static void em_mkdir_f(cmd_state_t *cmd)
148{
149 if (Cmd_Argc(cmd) != 2)
150 Con_Printf("No directory to create\n");
151 else
152 {
153 char *output = js_mkd(Cmd_Argv(cmd, 1));
154 Con_Printf("%s\n", output);
155 free(output);
156 }
157}
158
159EM_JS(char *, js_move, (const char *oldpath, const char *newpath), {
160 try
161 {
162 FS.rename(UTF8ToString(oldpath),UTF8ToString(newpath))
163 }
164 catch (error)
165 {
166 return stringToNewUTF8("unable to move.");
167 }
168 return stringToNewUTF8("File Moved");
169});
170static void em_mv_f(cmd_state_t *cmd)
171{
172 if (Cmd_Argc(cmd) != 3)
173 Con_Printf("Nothing to move\n");
174 else
175 {
176 char *output = js_move(Cmd_Argv(cmd,1), Cmd_Argv(cmd,2));
177 Con_Printf("%s\n", output);
178 free(output);
179 }
180}
181
182static void em_wss_f(cmd_state_t *cmd)
183{
184 if (Cmd_Argc(cmd) != 3)
185 Con_Printf("Not Enough Arguments (Expected URL and subprotocol)\n");
186 else
187 {
188 if(strcmp(Cmd_Argv(cmd,2),"binary") == 0 || strcmp(Cmd_Argv(cmd,2),"text") == 0)
189 Con_Printf("Set Websocket URL to %s and subprotocol to %s.\n", Cmd_Argv(cmd,1), Cmd_Argv(cmd,2));
190 else
191 Con_Printf("subprotocol must be either binary or text\n");
192 }
193}
194#endif // WASM_USER_ADJUSTABLE
195
196EM_JS(bool, js_syncFS, (bool populate), {
197 FS.syncfs(populate, function(err) {
198 if(err)
199 {
200 alert("FileSystem Save Error: " + err);
201 return false;
202 }
203
204 alert("Filesystem Saved!");
205 return true;
206 });
207});
209{
210 Con_Printf("Saving Files\n");
211 js_syncFS(false);
212}
213
215{
216 js_syncFS(false);
217 SDL_Quit();
218}
219
220// Sys_Abort early in startup might screw with automated
221// workflows or something if we show the dialog by default.
222static qbool nocrashdialog = true;
223void Sys_SDL_Dialog(const char *title, const char *string)
224{
225 if(!nocrashdialog)
226 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, string, NULL);
227}
228
229// In a browser the clipboard can only be read asynchronously
230// doing this efficiently and cleanly requires JSPI
231// enable in makefile.inc with emcc option: -s JSPI
232/* TODO: enable this code when JSPI is enabled by default in browsers
233EM_ASYNC_JS(char *, js_getclipboard, (void),
234{
235 try
236 {
237 const text = await navigator.clipboard.readText();
238 return stringToNewUTF8(text);
239 }
240 catch (err)
241 {
242 return stringToNewUTF8("clipboard error: ", err);
243 }
244}); */
245EM_JS(char *, js_getclipboard, (void), {
246 return stringToNewUTF8("clipboard access requires JSPI which is not currently enabled.");
247});
249{
250 char *data = NULL;
251 char *cliptext;
252
253 // SDL_GetClipboardText() does nothing in a browser, see above
254 cliptext = js_getclipboard();
255 if (cliptext != NULL) {
256 size_t allocsize;
257 allocsize = min(MAX_INPUTLINE, strlen(cliptext) + 1);
258 data = (char *)Z_Malloc (allocsize);
259 dp_strlcpy (data, cliptext, allocsize);
260 free(cliptext);
261 }
262
263 return data;
264}
265
266void Sys_SDL_Init(void)
267{
268 if (SDL_Init(0) < 0)
269 Sys_Error("SDL_Init failed: %s\n", SDL_GetError());
270
271 // we don't know which systems we'll want to init, yet...
272 // COMMANDLINEOPTION: sdl: -nocrashdialog disables "Engine Error" crash dialog boxes
273 if(!Sys_CheckParm("-nocrashdialog"))
274 nocrashdialog = false;
275
276 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, EM_FALSE, em_on_resize);
277}
278
280{
281#ifdef WASM_USER_ADJUSTABLE
282 Cmd_AddCommand(CF_SHARED, "em_ls", em_listfiles_f, "Lists Files in specified directory defaulting to the current working directory (Emscripten Only)");
283 Cmd_AddCommand(CF_SHARED, "em_upload", em_upload_f, "Upload file to specified directory defaulting to basedir (Emscripten Only)");
284 Cmd_AddCommand(CF_SHARED, "em_rm", em_rm_f, "Remove a file from game Filesystem (Emscripten Only)");
285 Cmd_AddCommand(CF_SHARED, "em_rmdir", em_rmdir_f, "Remove a directory from game Filesystem (Emscripten Only)");
286 Cmd_AddCommand(CF_SHARED, "em_mkdir", em_mkdir_f, "Make a directory in game Filesystem (Emscripten Only)");
287 Cmd_AddCommand(CF_SHARED, "em_mv", em_mv_f, "Rename or Move an item in game Filesystem (Emscripten only)");
288 Cmd_AddCommand(CF_SHARED, "em_wss", em_wss_f, "Set Websocket URL and Protocol (Emscripten Only)");
289#endif
290 Cmd_AddCommand(CF_SHARED, "em_save", em_savefs_f, "Save file changes to browser (Emscripten Only)");
291}
292
294unsigned int Sys_SDL_GetTicks(void)
295{
296 return SDL_GetTicks();
297}
298
299void Sys_SDL_Delay(unsigned int milliseconds)
300{
301 SDL_Delay(milliseconds);
302}
303
304int main(int argc, char *argv[])
305{
306 return Sys_Main(argc, argv);
307}
void Cmd_AddCommand(unsigned flags, const char *cmd_name, xcommand_t function, const char *description)
called by the init functions of other parts of the program to register commands and functions to call...
Definition cmd.c:1661
#define CF_SHARED
Definition cmd.h:67
static int Cmd_Argc(cmd_state_t *cmd)
Definition cmd.h:249
static const char * Cmd_Argv(cmd_state_t *cmd, int arg)
Cmd_Argv(cmd, ) will return an empty string (not a NULL) if arg > argc, so string operations are alwa...
Definition cmd.h:254
#define dp_strlcpy(dst, src, dsize)
Definition common.h:303
void Con_Printf(const char *fmt,...)
Prints to all appropriate console targets.
Definition console.c:1514
void Cvar_SetValueQuick(cvar_t *var, float value)
Definition cvar.c:473
void Cvar_SetQuick(cvar_t *var, const char *value)
Definition cvar.c:436
char fs_basedir[MAX_OSPATH]
Definition fs.c:444
GLenum mode
Definition glquake.h:718
GLsizeiptr const GLvoid * data
Definition glquake.h:639
#define min(A, B)
Definition mathlib.h:37
float strlen(string s)
void error(string err,...)
void cmd(string command,...)
string argv(float n)
#define MAX_INPUTLINE
maximum size of console commandline, QuakeC strings, and many other text processing buffers
Definition qdefs.h:94
#define NULL
Definition qtypes.h:12
bool qbool
Definition qtypes.h:9
void main(void)\n"
command interpreter state - the tokenizing and execution of commands, as well as pointers to which cv...
Definition cmd.h:127
int integer
Definition cvar.h:73
void Sys_Error(const char *error,...) DP_FUNC_PRINTF(1) DP_FUNC_NORETURN
Causes the entire program to exit ASAP.
Definition sys_shared.c:724
int Sys_Main(int argc, char *argv[])
main() but renamed so we can wrap it in sys_sdl.c and sys_null.c to avoid needing to include SDL....
int Sys_CheckParm(const char *parm)
Definition sys_shared.c:327
void Sys_SDL_Init(void)
Definition sys_wasm.c:266
static qbool nocrashdialog
Definition sys_wasm.c:222
unsigned int Sys_SDL_GetTicks(void)
Definition sys_wasm.c:294
void Sys_SDL_Dialog(const char *title, const char *string)
Definition sys_wasm.c:223
char * Sys_SDL_GetClipboardData(void)
Definition sys_wasm.c:248
void Sys_SDL_Shutdown(void)
INFO: This is only called by Host_Shutdown so we dont need testing for recursion.
Definition sys_wasm.c:214
void Sys_SDL_Delay(unsigned int milliseconds)
Definition sys_wasm.c:299
static EM_BOOL em_on_resize(int etype, const EmscriptenUiEvent *event, void *UData)
Definition sys_wasm.c:22
static void em_savefs_f(cmd_state_t *cmd)
Definition sys_wasm.c:208
EM_JS(float, js_GetViewportWidth,(void), { return document.documentElement.clientWidth })
void Sys_EM_Register_Commands(void)
Definition sys_wasm.c:279
qbool sys_supportsdlgetticks
Definition sys_wasm.c:293
cvar_t vid_width
Definition vid_shared.c:136
cvar_t vid_height
Definition vid_shared.c:137
cvar_t vid_resizable
Definition vid_shared.c:164
cvar_t vid_fullscreen
Definition vid_shared.c:134
#define Z_Malloc(size)
Definition zone.h:161