diff --git a/engine/Makefile b/engine/Makefile index 71a328205..711c74bc7 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -202,7 +202,9 @@ DO_CMAKE=cmake -DCMAKE_C_COMPILER="$(firstword $(CC))" -DCMAKE_C_FLAGS="$(wordli ifeq ($(DROID_ARCH),) #armeabi armeabi-v7a arm64-v8a x86 x86_64 mips mips64 - DROID_ARCH=x86 armeabi-v7a + DROID_ARCH=armeabi-v7a + DROID_ARCH+=x86 + #DROID_ARCH+=x86_64 #starting with DROID_API_LEVEL 21 endif ifeq ($(FTE_TARGET),droid) #figure out the host system, required to find a usable compiler @@ -244,9 +246,9 @@ ifeq ($(FTE_TARGET),droid) DROID_ABI_ARCH___x86=x86 DROID_ABI_VER____x86?=$(DROID_ABI_VER) DROID_ABI_CFLAGS_x86=-march=i686 -mssse3 -mfpmath=sse -m32 -Os - DROID_ABI_NAME___x86_64=$(DROID_ABI_NAME___x86) - DROID_ABI_PREFIX_x86_64=$(DROID_ABI_PREFIX_x86) - DROID_ABI_ARCH___x86_64=$(DROID_ABI_ARCH___x86) + DROID_ABI_NAME___x86_64=x86_64 + DROID_ABI_PREFIX_x86_64=x86_64-linux-android + DROID_ABI_ARCH___x86_64=x86_64 DROID_ABI_VER____x86_64=$(DROID_ABI_VER____x86) DROID_ABI_CFLAGS_x86_64=-march=x86-64 -msse4.2 -mpopcnt -m64 -Os #DROID_ABI_NAME___mips=mipsel-linux-android @@ -272,6 +274,10 @@ ifeq ($(FTE_TARGET),droid) #google fecked up. anything before api_level 9 will fail to compile on x86 DROID_API_LEVEL=9 endif + ifeq ($(DROID_ARCH),x86_64) + #google fecked up. anything before api_level 9 will fail to compile on x86 + DROID_API_LEVEL=21 + endif DROID_API_NAME?=android-$(DROID_API_LEVEL) DROID_PLAT_INC=arch-$(DROID_ABI_ARCH___$(DROID_ARCH)) DROIDSYSROOT=$(realpath $(ANDROID_NDK_ROOT)/platforms/$(DROID_API_NAME)/$(DROID_PLAT_INC)) @@ -1584,14 +1590,15 @@ ifeq ($(FTE_TARGET),droid) SV_EXE_NAME=libftedroid.so GL_CFLAGS=$(GLCFLAGS) - GL_LDFLAGS=$(GLLDFLAGS) -landroid -lEGL + GL_LDFLAGS=$(GLLDFLAGS) -landroid GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(GL_DROID_O) cd_null.o snd_droid.o GLB_DIR=gl_droid-$(DROID_ARCH) GL_EXE_NAME=libftedroid.so M_CFLAGS=$(VKCFLAGS) $(GLCFLAGS) -DMULTITHREAD - M_LDFLAGS=$(GLLDFLAGS) -landroid -lEGL - MCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(GL_DROID_O) cd_null.o snd_droid.o + M_LDFLAGS=$(GLLDFLAGS) -landroid -lEGL -lOpenSLES + MCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(GL_DROID_O) cd_null.o snd_opensl.o +#snd_droid.o MB_DIR=m_droid-$(DROID_ARCH) M_EXE_NAME=libftedroid.so endif @@ -2116,6 +2123,7 @@ endif droid-rel: $(MAKE) FTE_TARGET=droid droid/build.xml droid/ftekeystore $(foreach a, $(DROID_ARCH), $(MAKE) FTE_TARGET=droid m-rel DROID_ARCH=$a; ) + -rm -rf droid/libs @$(foreach a, $(DROID_ARCH), mkdir -p droid/libs/$a; ) -@$(foreach a, $(DROID_ARCH), cp $(RELEASE_DIR)/m_droid-$a/libftedroid.so droid/libs/$a/libftedroid.so; ) @@ -2152,6 +2160,7 @@ droid-opt: droid-dbg: $(MAKE) FTE_TARGET=droid droid/build.xml $(foreach a, $(DROID_ARCH), $(MAKE) FTE_TARGET=droid m-dbg DROID_ARCH=$a; ) + -rm -rf droid/libs @$(foreach a, $(DROID_ARCH), mkdir -p droid/libs/$a; ) -@$(foreach a, $(DROID_ARCH), cp $(DEBUG_DIR)/m_droid-$a/libftedroid.so droid/libs/$a/libftedroid.so; ) @cd droid && $(ANT) debug #&& $(ANT) debug install diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 2f1b10c16..358e1745c 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -4300,7 +4300,11 @@ void CL_Fog_f(void) void CL_CrashMeEndgame_f(void) { - Host_EndGame("crashme!"); + Host_EndGame("crashme! %s", Cmd_Args()); +} +void CL_CrashMeError_f(void) +{ + Sys_Error("crashme! %s", Cmd_Args()); } void CL_Status_f(void) @@ -4660,6 +4664,7 @@ void CL_Init (void) Cmd_AddCommandD ("demo_nudge", CL_DemoNudge_f, "Nudge the demo by one frame. Argument should be +1 or -1. Nudging backwards is limited."); Cmd_AddCommandAD ("timedemo", CL_TimeDemo_f, CL_DemoList_c, NULL); Cmd_AddCommand ("crashme_endgame", CL_CrashMeEndgame_f); + Cmd_AddCommand ("crashme_error", CL_CrashMeError_f); Cmd_AddCommandD ("showpic", SCR_ShowPic_Script_f, "showpic [width] [height] [touchcommand]\nDisplays an image onscreen, that potentially has a key binding attached to it when clicked/touched.\nzone should be one of: TL, TR, BL, BR, MM, TM, BM, ML, MR. This serves as an extra offset to move the image around the screen without any foreknowledge of the screen resolution."); Cmd_AddCommandD ("showpic_removeall", SCR_ShowPic_Remove_f, "removes any pictures inserted with the showpic command."); diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 13a8fb699..e7ba99dba 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -2476,8 +2476,10 @@ static void SCR_ScreenShot_f (void) return; } BZ_Free(rgbbuffer); + Con_Printf (CON_ERROR "Couldn't write %s\n", sysname); } - Con_Printf (CON_ERROR "Couldn't write %s\n", sysname); + else + Con_Printf (CON_ERROR "Couldn't get colour buffer for screenshot\n"); } void *SCR_ScreenShot_Capture(int fbwidth, int fbheight, int *stride, enum uploadfmt *fmt, qboolean no2d) diff --git a/engine/client/clhl_game.c b/engine/client/clhl_game.c index 35553dee0..13490f492 100644 --- a/engine/client/clhl_game.c +++ b/engine/client/clhl_game.c @@ -1014,9 +1014,8 @@ void QDECL CLGHL_setsysmousepos(int x, int y) } void QDECL CLGHL_setmouseenable(qboolean enable) { - extern cvar_t _windowed_mouse; bi_trace(); - Cvar_Set(&_windowed_mouse, enable?"1":"0"); + Cvar_Set(&in_windowed_mouse, enable?"1":"0"); } diff --git a/engine/client/client.h b/engine/client/client.h index 81115d16c..7e088dc7c 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -1013,8 +1013,6 @@ extern cvar_t m_yaw; extern cvar_t m_forward; extern cvar_t m_side; -extern cvar_t _windowed_mouse; - #ifndef SERVERONLY extern cvar_t name; #endif diff --git a/engine/client/in_generic.c b/engine/client/in_generic.c index b74696e44..b6a3d3683 100644 --- a/engine/client/in_generic.c +++ b/engine/client/in_generic.c @@ -690,7 +690,7 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame //if they're strafing, calculate the speed to move at based upon their displacement if (mouse->held) { - if (m_touchstrafe.ival) //left side + if (m_touchstrafe.ival == 2) //left side mx = mouse->oldpos[0] - (vid.pixelwidth*1)/4.0; else //right side mx = mouse->oldpos[0] - (vid.pixelwidth*3)/4.0; diff --git a/engine/client/in_morphos.c b/engine/client/in_morphos.c index b79621e2e..272167a8d 100644 --- a/engine/client/in_morphos.c +++ b/engine/client/in_morphos.c @@ -50,8 +50,6 @@ static struct MsgPort *inputport = 0; static struct IOStdReq *inputreq = 0; static BYTE inputret = -1; -extern cvar_t _windowed_mouse; - #define DEBUGRING(x) void INS_Shutdown(void) @@ -192,7 +190,7 @@ void INS_ProcessInputMessage(struct InputEvent *msg, qboolean consumemotion) else if (msg->ie_Code == (IECODE_MBUTTON|IECODE_UP_PREFIX)) IN_KeyEvent(0, false, K_MOUSE3, 0); - if (_windowed_mouse.ival) + if (in_windowed_mouse.ival) { if (consumemotion) { diff --git a/engine/client/in_win.c b/engine/client/in_win.c index 290548da2..776d80d00 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -602,7 +602,7 @@ void INS_UpdateGrabs(int fullscreen, int activeapp) if (!activeapp) grabmouse = false; - else if (fullscreen || in_simulatemultitouch.ival || _windowed_mouse.value) + else if (fullscreen || in_simulatemultitouch.ival || in_windowed_mouse.value) { if (!Key_MouseShouldBeFree()) grabmouse = true; @@ -618,7 +618,7 @@ void INS_UpdateGrabs(int fullscreen, int activeapp) #ifdef TEXTEDITOR !editormodal && #endif - !SCR_HardwareCursorIsActive() && (fullscreen || in_simulatemultitouch.ival || _windowed_mouse.value) && (fullscreen || (current_mouse_pos.x >= window_rect.left && current_mouse_pos.y >= window_rect.top && current_mouse_pos.x <= window_rect.right && current_mouse_pos.y <= window_rect.bottom))) + !SCR_HardwareCursorIsActive() && (fullscreen || in_simulatemultitouch.ival || in_windowed_mouse.value) && (fullscreen || (current_mouse_pos.x >= window_rect.left && current_mouse_pos.y >= window_rect.top && current_mouse_pos.x <= window_rect.right && current_mouse_pos.y <= window_rect.bottom))) { INS_HideMouse(); } diff --git a/engine/client/input.h b/engine/client/input.h index 20c4cea8a..5831dfcbd 100644 --- a/engine/client/input.h +++ b/engine/client/input.h @@ -78,5 +78,6 @@ extern cvar_t cl_rollspeed; extern cvar_t cl_prydoncursor; extern cvar_t cl_instantrotate; extern cvar_t in_xflip; +extern cvar_t in_windowed_mouse; //if 0, uses absolute mouse coords allowing the mouse to be used for other programs too. ignored when fullscreen (and reliable). extern cvar_t prox_inmenu; extern cvar_t cl_forceseat; diff --git a/engine/client/m_items.c b/engine/client/m_items.c index 37ea9244c..8d043069d 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -1583,6 +1583,13 @@ void MC_Slider_Key(menuslider_t *option, int key) } option->current = range; } + else if (key == K_DEL || key == K_BACKSPACE) + { + if (option->var && option->var->defaultstr) + option->current = atof(option->var->defaultstr); + else + option->current = (option->max-option->min)/2; + } else return; diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 6dbab1c4b..f4fd87e72 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -311,7 +311,7 @@ void M_Menu_Options_f (void) MB_CHECKBOXFUNC("Invert Mouse", M_Options_InvertMouse, 0, "Invert vertical mouse movement."), MB_CHECKBOXCVAR("Lookspring", lookspring, 0), MB_CHECKBOXCVAR("Lookstrafe", lookstrafe, 0), - MB_CHECKBOXCVAR("Windowed Mouse", _windowed_mouse, 0), + MB_CHECKBOXCVAR("Windowed Mouse", in_windowed_mouse, 0), #if !defined(CLIENTONLY) && defined(SAVEDGAMES) MB_COMBOCVAR("Auto Save", sv_autosave, autosaveopts, autosavevals, NULL), #endif @@ -3042,12 +3042,13 @@ void M_Menu_Video_f (void) MB_SPACING(4), MB_CMD("Apply Settings", M_VideoApply, "Restart video and apply renderer, display, and 2D resolution options."), MB_SPACING(4), - MB_SLIDER("View Size", scr_viewsize, 30, 120, 10, NULL), + MB_COMBOCVAR("sRGB", vid_srgb, srgbopts, srgbvalues, "Controls the colour space to try to use."), MB_COMBOCVAR("Gamma Mode", v_gamma, gammamodeopts, gammamodevalues, "Controls how gamma is applied"), MB_SLIDER("Gamma", v_gamma, 1.5, 0.25, -0.05, NULL), - MB_COMBOCVAR("Gamma Mode", vid_srgb, srgbopts, srgbvalues, "Controls the colour space to try to use."), MB_SLIDER("Contrast", v_contrast, 0.8, 3, 0.05, NULL), - + MB_SLIDER("Brightness", v_brightness, 0.0, 0.5, 0.05, NULL), + MB_SPACING(4), + MB_SLIDER("View Size", scr_viewsize, 30, 120, 10, NULL), MB_COMBOCVAR("VSync", vid_vsync, vsyncopts, vsyncvalues, "Controls whether to wait for rendering to finish."), MB_EDITCVARSLIM("Framerate Limiter", cl_maxfps.name, "Limits the maximum framerate. Set to 0 for none."), MB_CHECKBOXCVARTIP("Yield CPU", cl_yieldcpu, 1, "Reduce CPU usage between frames.\nShould probably be off when using vsync."), @@ -3090,7 +3091,7 @@ void M_Menu_Video_f (void) MC_AddCheckBox(menu, 16, y, " Preserve Gamma", &vid_preservegamma,0); y+=8; MC_AddSlider(menu, 16, y, " Contrast", &v_contrast, 1, 3, 0.05); y+=8; y+=8; - MC_AddCheckBox(menu, 16, y, " Windowed Mouse", &_windowed_mouse,0); y+=8; + MC_AddCheckBox(menu, 16, y, " Windowed Mouse", &in_windowed_mouse,0); y+=8; menu->selecteditem = (union menuoption_s *)info->renderer; menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 152, menu->selecteditem->common.posy, NULL, false); @@ -3994,14 +3995,19 @@ static void Mods_Draw(int x, int y, struct menucustom_s *c, struct menu_s *m) if (!mods->nummods) { - Draw_FunString(x, y+0, "No games or mods known"); + float scale[] = {8,8}; + R_DrawTextField(0, y, vid.width, vid.height - y, + va( + "No games or mods known.\n" #if defined(FTE_TARGET_WEB) || defined(NACL) - Draw_FunString(x, y+8, "Connection issue or bad server config"); + "Connection issue or bad server config.\n" #else - Draw_FunString(x, y+8, "You may need to use"); - Draw_FunString(x, y+16, " -basedir $PATHTOGAME"); - Draw_FunString(x, y+24, " on the commandline"); + #ifndef ANDROID + "You may need to use -basedir $PATHTOGAME on the commandline.\n" + #endif + "\nExpected data path:\n^a%s", com_gamepath #endif + ), CON_WHITEMASK, 0, font_console, scale); return; } diff --git a/engine/client/r_partset.c b/engine/client/r_partset.c index c9608da6a..a76f44183 100644 --- a/engine/client/r_partset.c +++ b/engine/client/r_partset.c @@ -1740,7 +1740,7 @@ char *particle_set_high = "scoord = ftetransform();\n" "tcoord = (v_texcoord.st - 0.5)*2.0;\n" "alph = v_colour.a;\n" -"gl_Position = scoord;\n" +"gl_Position = ftetransform();\n" "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 81b9b7f2d..2793a1838 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -3702,6 +3702,8 @@ int Surf_NewLightmaps(int count, int width, int height, uploadfmt_t fmt, qboolea int i; unsigned int pixbytes, pixw, pixh; + unsigned int dpixbytes, dpixw, dpixh; + uploadfmt_t dfmt; if (!count) return -1; @@ -3715,6 +3717,12 @@ int Surf_NewLightmaps(int count, int width, int height, uploadfmt_t fmt, qboolea Image_BlockSizeForEncoding(fmt, &pixbytes, &pixw, &pixh); if (pixw != 1 || pixh != 1) return -1; //compressed formats are unsupported + dfmt = PTI_BGRX8; + if (!sh_config.texfmt[dfmt]) + dfmt = PTI_RGBX8; + if (!sh_config.texfmt[dfmt]) + dfmt = PTI_RGB8; + Image_BlockSizeForEncoding(dfmt, &dpixbytes, &dpixw, &dpixh); Sys_LockMutex(com_resourcemutex); @@ -3726,16 +3734,14 @@ int Surf_NewLightmaps(int count, int width, int height, uploadfmt_t fmt, qboolea if (deluxe && ((i - numlightmaps)&1)) { //deluxemaps always use a specific format. - int pixbytes = 4; - uploadfmt_t fmt = PTI_BGRX8; //deluxemaps have limited format choices. we should probably use RG textures or something, but mneh. - lightmap[i] = Z_Malloc(sizeof(*lightmap[i]) + (sizeof(qbyte)*pixbytes)*width*height); + lightmap[i] = Z_Malloc(sizeof(*lightmap[i]) + (sizeof(qbyte)*dpixbytes)*width*height); lightmap[i]->width = width; lightmap[i]->height = height; lightmap[i]->lightmaps = (qbyte*)(lightmap[i]+1); lightmap[i]->stainmaps = NULL; lightmap[i]->hasdeluxe = false; - lightmap[i]->pixbytes = pixbytes; - lightmap[i]->fmt = fmt; + lightmap[i]->pixbytes = dpixbytes; + lightmap[i]->fmt = dfmt; } else { diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 2841165e9..d6e64cc3a 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -79,7 +79,7 @@ cvar_t vid_vsync = CVARAF ("vid_vsync", "0", "vid_wait", CVAR_ARCHIVE); #endif -cvar_t _windowed_mouse = CVARF ("in_windowed_mouse","1", +cvar_t in_windowed_mouse = CVARF ("in_windowed_mouse","1", CVAR_ARCHIVE); //renamed this, because of freecs users complaining that it doesn't work. I don't personally see why you'd want it set to 0, but that's winquake's default so boo hiss to that. cvar_t con_ocranaleds = CVAR ("con_ocranaleds", "2"); @@ -788,7 +788,7 @@ void Renderer_Init(void) #if defined(_WIN32) && defined(MULTITHREAD) Cvar_Register (&vid_winthread, VIDCOMMANDGROUP); #endif - Cvar_Register (&_windowed_mouse, VIDCOMMANDGROUP); + Cvar_Register (&in_windowed_mouse, VIDCOMMANDGROUP); Cvar_Register (&vid_renderer, VIDCOMMANDGROUP); vid_renderer_opts.enginevalue = #ifdef GLQUAKE diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 094b397e6..273a104c1 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -1766,7 +1766,8 @@ extern sounddriver_t WaveOut_Output; sounddriver_t MacOS_AudioOutput; //prefered on mac #endif #ifdef ANDROID -sounddriver_t Droid_AudioOutput; //prefered on android (java thread) +sounddriver_t OSL_Output; //general audio library, but android has all kinds of quirks. +sounddriver_t Droid_AudioOutput; #endif #if defined(__MORPHOS__) sounddriver_t AHI_AudioOutput; //prefered on morphos @@ -1811,7 +1812,7 @@ static sounddriver_t *outputdrivers[] = &MacOS_AudioOutput, //prefered on mac #endif #ifdef ANDROID - &Droid_AudioOutput, //prefered on android (java thread) + &OSL_Output, //opensl(es) #endif #if defined(__MORPHOS__) &AHI_AudioOutput, //prefered on morphos diff --git a/engine/client/snd_opensl.c b/engine/client/snd_opensl.c new file mode 100644 index 000000000..fc7330649 --- /dev/null +++ b/engine/client/snd_opensl.c @@ -0,0 +1,189 @@ +#include "quakedef.h" + +#include + +#define AUDIODRIVERNAME "OpenSLES" + +static void QDECL OSL_RegisterCvars(void) +{ +} + +static void *OSL_Lock(soundcardinfo_t *sc, unsigned int *startoffset) +{ + return sc->sn.buffer; +} +static void OSL_Unlock(soundcardinfo_t *sc, void *buffer) +{ + //no need to do anything +} +static void OSL_Submit(soundcardinfo_t *sc, int start, int end) +{ + //submit happens outside the mixer +} +static unsigned int OSL_GetDMAPos(soundcardinfo_t *sc) +{ + sc->sn.samplepos = sc->snd_sent; + return sc->sn.samplepos; +} + +typedef struct +{ + SLObjectItf sl; + SLEngineItf engine; + SLPlayItf play; + SLObjectItf player; + SLObjectItf output; + SLBufferQueueItf bufferqueue; + + + unsigned char *buffer; + size_t buffersegmentsize; + size_t buffersegments; + size_t buffersegment; +} osl_data_t; + +//assumption: that each buffer is released in sequence. +static void buffercallback(SLBufferQueueItf queue, void *ctx) +{ + soundcardinfo_t *sc = ctx; + osl_data_t *p = sc->handle; + //we got the buffer back. + if (sc->Shutdown) + { //we're not shutting down yet, so paint more stuff into the buffer and throw it back. + sc->sn.buffer = p->buffer + (p->buffersegment%p->buffersegments)*p->buffersegmentsize; + sc->sn.samples = p->buffersegmentsize/sc->sn.samplebytes;//numFramesAvailable * sc->sn.numchannels; + sc->samplequeue = sc->sn.samples; + S_MixerThread(sc); + sc->snd_sent = p->buffersegment++*p->buffersegmentsize; + + (*queue)->Enqueue(queue, sc->sn.buffer, p->buffersegmentsize); + } +} + +static void OSL_Shutdown(soundcardinfo_t *sc) +{ + osl_data_t *p = sc->handle; + sc->Shutdown = NULL; //stop posting new buffers + if (p) + { + if (p->play) + (*p->play)->SetPlayState(p->play, SL_PLAYSTATE_STOPPED); + if (p->player) + (*p->player)->Destroy(p->player); + if (p->output) + (*p->output)->Destroy(p->output); + if (p->sl) + (*p->sl)->Destroy(p->sl); + sc->handle = NULL; + Z_Free(p); + } +} + +static qboolean QDECL OSL_InitCard (soundcardinfo_t *sc, const char *cardname) +{ + osl_data_t *p; + size_t segments = 4; //lets cycle through 4 segments in our single logical buffer + size_t segmentframes = 256; //with X frames per segment + //FIXME: mixahead + + sc->sn.numchannels = 2; + sc->sn.sampleformat = QSF_S16; + switch(sc->sn.sampleformat) + { + case QSF_U8: + //case QSF_S8; + sc->sn.samplebytes = 1; + break; + case QSF_S16: + sc->sn.samplebytes = 2; + break; + //case QSF_F32: + //sc->sn.samplebytes = 4; + //break; + default: + return false; +// sc->sn.sampleformat = QSF_INVALID; +// sc->sn.samplebytes = 0; +// break; + } + + Con_DPrintf("Opening OpenSLES, %.1fkhz\n", sc->sn.speed/1000.0); + + sc->Shutdown = OSL_Shutdown; + sc->Lock = OSL_Lock; + sc->Unlock = OSL_Unlock; + sc->Submit = OSL_Submit; + sc->GetDMAPos = OSL_GetDMAPos; + sc->handle = p = Z_Malloc(sizeof(*p) + segmentframes*segments*sc->sn.samplebytes*sc->sn.numchannels); + if (p) + { + p->buffer = (unsigned char*)(p+1); + p->buffersegments = segments; + p->buffersegmentsize = segmentframes*sc->sn.samplebytes*sc->sn.numchannels; + sc->selfpainting = true; + Q_strncpyz(sc->name, cardname?cardname:"", sizeof(sc->name)); + + SLEngineOption options[] = + { + {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32)SL_BOOLEAN_TRUE}, + // {(SLuint32) SL_ENGINEOPTION_MAJORVERSION, (SLuint32)1}, + // {(SLuint32) SL_ENGINEOPTION_MINORVERSION, (SLuint32)1}, + }; + slCreateEngine(&p->sl, countof(options), options, 0, NULL, NULL); + if (p->sl) + { + (*p->sl)->Realize(p->sl, SL_BOOLEAN_FALSE); + (*p->sl)->GetInterface(p->sl, SL_IID_ENGINE, &p->engine); + if (p->engine) + { + (*p->engine)->CreateOutputMix(p->engine, &p->output, 0, NULL, NULL); + if (p->output) + { + SLboolean TRUE_ = true; + SLDataLocator_BufferQueue loc_bufferqueue = {SL_DATALOCATOR_BUFFERQUEUE, segments}; + SLDataFormat_PCM pcmformat = {SL_DATAFORMAT_PCM, sc->sn.numchannels, sc->sn.speed*1000, sc->sn.samplebytes*8, sc->sn.samplebytes*8/*+pad*/, SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT, SL_BYTEORDER_LITTLEENDIAN}; + SLDataSource audiosource = {&loc_bufferqueue, &pcmformat}; + SLDataLocator_OutputMix loc_outputmix = {SL_DATALOCATOR_OUTPUTMIX, p->output}; + SLDataSink audiosink = {&loc_outputmix, NULL}; + (*p->output)->Realize(p->output, false); + (*p->engine)->CreateAudioPlayer(p->engine, &p->player, &audiosource, &audiosink, 1, &SL_IID_BUFFERQUEUE, &TRUE_); + if (p->player) + { + (*p->player)->Realize(p->player, false); + (*p->player)->GetInterface(p->player, SL_IID_PLAY, &p->play); + (*p->player)->GetInterface(p->player, SL_IID_BUFFERQUEUE, &p->bufferqueue); + if (p->bufferqueue) + { + (*p->bufferqueue)->RegisterCallback(p->bufferqueue, buffercallback, sc); + buffercallback(p->bufferqueue, sc); + buffercallback(p->bufferqueue, sc); + buffercallback(p->bufferqueue, sc); + if (SL_RESULT_SUCCESS == (*p->play)->SetPlayState(p->play, SL_PLAYSTATE_PLAYING)) + { + //should now be playing our buffers, and recycling them when one terminates.i + return true; + } + } + } + } + } + } + } + OSL_Shutdown(sc); + return false; +} + +static qboolean QDECL OSL_Enumerate (void (QDECL *callback) (const char *drivername, const char *devicecode, const char *readablename)) +{ + //callback(AUDIODRIVERNAME, internalname, nicename); + return false; +} + +sounddriver_t OSL_Output = +{ + AUDIODRIVERNAME, + OSL_InitCard, + OSL_Enumerate, + OSL_RegisterCvars +}; + diff --git a/engine/client/sys_droid.c b/engine/client/sys_droid.c index 1fee18833..d06478b6a 100644 --- a/engine/client/sys_droid.c +++ b/engine/client/sys_droid.c @@ -10,11 +10,21 @@ #include #include #include +#include "glquake.h" #ifndef ANDROID #error ANDROID wasnt defined #endif +#include +#include +//NOTE: This is apache 2.0, which means GPL3.0+ ONLY, no gpl2. +//#include <../../../../../sources/android/native_app_glue/android_native_app_glue.h> //Fucking frameworks suck big hairy donkey balls. +//JNIEXPORT void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize); +//#include <../../../../../sources/android/native_app_glue/android_native_app_glue.c> //Fucking frameworks suck big hairy donkey balls. +//FIXME: remove that shit. android's standard NativeActivity class is buggy and basically fucked. +// ANativeWindow_fromSurface((jobject)getSurfaceHolder().getSurface()) + #ifndef isDedicated #ifdef SERVERONLY qboolean isDedicated = true; @@ -22,68 +32,38 @@ qboolean isDedicated = true; qboolean isDedicated = false; #endif #endif -static int sys_running = false; extern int r_blockvidrestart; float sys_dpi_x, sys_dpi_y; -int sys_soundflags; /*1 means active. 2 means reset (so claim that its not active for one frame to force a reset)*/ static void *sys_memheap; -static unsigned int sys_lastframe; -static unsigned int vibrateduration; -static char errormessage[256]; +//static unsigned int vibrateduration; static char sys_basedir[MAX_OSPATH]; static char sys_basepak[MAX_OSPATH]; extern jmp_buf host_abort; -JNIEnv *sys_jenv; -JavaVM *sys_jvm; +extern qboolean r_forceheadless; +static qboolean r_forcevidrestart; +ANativeWindow *sys_nativewindow; +static struct android_app *android_app_state; //basically used only for errors. -cvar_t sys_vibrate = CVARFD("sys_vibrate", "1", CVAR_ARCHIVE, "Enables the system vibrator for damage events and such things. The value provided is a duration scaler."); +//cvar_t sys_vibrate = CVARFD("sys_vibrate", "1", CVAR_ARCHIVE, "Enables the system vibrator for damage events and such things. The value provided is a duration scaler."); cvar_t sys_osk = CVAR("sys_osk", "0"); //to be toggled cvar_t sys_keepscreenon = CVARFD("sys_keepscreenon", "1", CVAR_ARCHIVE, "If set, the screen will never darken. This might cost some extra battery power, but then so will running a 3d engine."); //to be toggled cvar_t sys_orientation = CVARFD("sys_orientation", "landscape", CVAR_ARCHIVE, "Specifies what angle to render quake at.\nValid values are: sensor (autodetect), landscape, portrait, reverselandscape, reverseportrait"); extern cvar_t vid_conautoscale; void VID_Register(void); - +#undef LOGI +#undef LOGW +#undef LOGE +#ifndef LOGI #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, DISTRIBUTION"Droid", __VA_ARGS__)) +#endif +#ifndef LOGW #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, DISTRIBUTION"Droid", __VA_ARGS__)) +#endif +#ifndef LOGE #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, DISTRIBUTION"Droid", __VA_ARGS__)) +#endif -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) -{ - sys_jvm = vm; - - return JNI_VERSION_1_2; -} - -void Sys_Vibrate(float count) -{ - if (count < 0) - count = 0; - vibrateduration += count*10*sys_vibrate.value; -} -void Sys_Vibrate_f(void) -{ - //input is in seconds, because this is quake. output is in ms. - vibrateduration += atof(Cmd_Argv(1)) * 1000; -} -JNIEXPORT jint JNICALL Java_com_fteqw_FTEDroidEngine_getvibrateduration(JNIEnv *env, jobject obj) -{ - unsigned int dur = vibrateduration; - vibrateduration = 0; - return dur; -} - -JNIEXPORT jstring JNICALL Java_com_fteqw_FTEDroidEngine_geterrormessage(JNIEnv *env, jobject obj) -{ - return (*env)->NewStringUTF(env, errormessage); -} -JNIEXPORT jstring JNICALL Java_com_fteqw_FTEDroidEngine_getpreferedorientation(JNIEnv *env, jobject obj) -{ - sys_orientation.modified = false; - return (*env)->NewStringUTF(env, sys_orientation.string); -} - -/*the java passes in all input directly via a 'UI' thread. we don't need to poll it at all*/ void INS_Move(void) { } @@ -102,161 +82,580 @@ void INS_ReInit(void) void INS_Shutdown(void) { } -JNIEXPORT int JNICALL Java_com_fteqw_FTEDroidEngine_keypress(JNIEnv *env, jobject obj, - jint down, jint keycode, jint unicode) +void Sys_Vibrate(float count) { - IN_KeyEvent(0, down, keycode, unicode); - return true; -} -JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_motion(JNIEnv *env, jobject obj, - jint act, jint ptrid, jfloat x, jfloat y, jfloat size) -{ - if (act) - IN_KeyEvent(ptrid, act==1, K_MOUSE1, 0); - else - IN_MouseMove(ptrid, true, x, y, 0, size); -} -JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_accelerometer(JNIEnv *env, jobject obj, - jfloat x, jfloat y, jfloat z) -{ - IN_Accelerometer(0, x, y, z); -} -JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_gryoscope(JNIEnv *env, jobject obj, - jfloat pitch, jfloat yaw, jfloat roll) -{ - IN_Gyroscope(0, pitch, yaw, roll); +// if (count < 0) +// count = 0; +// vibrateduration += count*10*sys_vibrate.value; } -JNIEXPORT jint JNICALL Java_com_fteqw_FTEDroidEngine_frame(JNIEnv *env, jobject obj) +static int mapkey(int androidkey) { - int ret; - -// Sys_Printf("run frame\n"); - - sys_jenv = env; - - //if we had an error, don't even run a frame any more. - if (*errormessage) + switch(androidkey) { - Sys_Printf("Crashed: %s\n", errormessage); - return 8; +// case AKEYCODE_SOFT_LEFT: return K_; +// case AKEYCODE_SOFT_RIGHT: return K_; +// case AKEYCODE_HOME: return K_; +// case AKEYCODE_BACK: return K_; +// case AKEYCODE_CALL: return K_; +// case AKEYCODE_ENDCALL: return K_; + case AKEYCODE_0: return '0'; + case AKEYCODE_1: return '1'; + case AKEYCODE_2: return '2'; + case AKEYCODE_3: return '3'; + case AKEYCODE_4: return '4'; + case AKEYCODE_5: return '5'; + case AKEYCODE_6: return '6'; + case AKEYCODE_7: return '7'; + case AKEYCODE_8: return '8'; + case AKEYCODE_9: return '9'; +// case AKEYCODE_STAR: return K_; +// case AKEYCODE_POUND: return K_; //americans don't know what a pound symbol looks like. + case AKEYCODE_DPAD_UP: return K_GP_DPAD_UP; + case AKEYCODE_DPAD_DOWN: return K_GP_DPAD_DOWN; + case AKEYCODE_DPAD_LEFT: return K_GP_DPAD_LEFT; + case AKEYCODE_DPAD_RIGHT: return K_GP_DPAD_RIGHT; + case AKEYCODE_DPAD_CENTER: return K_ENTER; + case AKEYCODE_VOLUME_UP: return K_VOLUP; + case AKEYCODE_VOLUME_DOWN: return K_VOLDOWN; + case AKEYCODE_POWER: return K_POWER; +// case AKEYCODE_CAMERA: return K_CAMERA; +// case AKEYCODE_CLEAR: return K_; + case AKEYCODE_A: return 'a'; + case AKEYCODE_B: return 'b'; + case AKEYCODE_C: return 'c'; + case AKEYCODE_D: return 'd'; + case AKEYCODE_E: return 'e'; + case AKEYCODE_F: return 'f'; + case AKEYCODE_G: return 'g'; + case AKEYCODE_H: return 'h'; + case AKEYCODE_I: return 'i'; + case AKEYCODE_J: return 'j'; + case AKEYCODE_K: return 'k'; + case AKEYCODE_L: return 'l'; + case AKEYCODE_M: return 'm'; + case AKEYCODE_N: return 'n'; + case AKEYCODE_O: return 'o'; + case AKEYCODE_P: return 'p'; + case AKEYCODE_Q: return 'q'; + case AKEYCODE_R: return 'r'; + case AKEYCODE_S: return 's'; + case AKEYCODE_T: return 't'; + case AKEYCODE_U: return 'u'; + case AKEYCODE_V: return 'v'; + case AKEYCODE_W: return 'w'; + case AKEYCODE_X: return 'x'; + case AKEYCODE_Y: return 'y'; + case AKEYCODE_Z: return 'z'; + case AKEYCODE_COMMA: return ','; + case AKEYCODE_PERIOD: return '.'; + case AKEYCODE_ALT_LEFT: return K_LALT; + case AKEYCODE_ALT_RIGHT: return K_RALT; + case AKEYCODE_SHIFT_LEFT: return K_LSHIFT; + case AKEYCODE_SHIFT_RIGHT: return K_RSHIFT; + case AKEYCODE_TAB : return K_TAB; + case AKEYCODE_SPACE: return K_SPACE; +// case AKEYCODE_SYM: return K_; +// case AKEYCODE_EXPLORER : return K_; +// case AKEYCODE_ENVELOPE: return K_; + case AKEYCODE_ENTER: return K_ENTER; + case AKEYCODE_DEL: return K_BACKSPACE; + case AKEYCODE_GRAVE: return '`'; + case AKEYCODE_MINUS: return '-'; + case AKEYCODE_EQUALS: return '='; + case AKEYCODE_LEFT_BRACKET: return '['; + case AKEYCODE_RIGHT_BRACKET: return ']'; + case AKEYCODE_BACKSLASH: return '#'; //this kinda sums up keymaps like this. + case AKEYCODE_SEMICOLON: return ';'; + case AKEYCODE_APOSTROPHE: return '\''; + case AKEYCODE_SLASH: return '/'; +// case AKEYCODE_AT: return K_; +// case AKEYCODE_NUM: return K_; +// case AKEYCODE_HEADSETHOOK: return K_; +// case AKEYCODE_FOCUS: return K_; +// case AKEYCODE_PLUS: return K_; + case AKEYCODE_MENU: return K_APP; +// case AKEYCODE_NOTIFICATION: return K_; + case AKEYCODE_SEARCH: return K_SEARCH; +// case AKEYCODE_MEDIA_PLAY_PAUSE: return K_; +// case AKEYCODE_MEDIA_STOP: return K_; +// case AKEYCODE_MEDIA_NEXT: return K_; +// case AKEYCODE_MEDIA_PREVIOUS: return K_; +// case AKEYCODE_MEDIA_REWIND: return K_; +// case AKEYCODE_MEDIA_FAST_FORWARD: return K_; +// case AKEYCODE_MUTE: return K_; + case AKEYCODE_PAGE_UP: return K_PGUP; + case AKEYCODE_PAGE_DOWN: return K_PGDN; +// case AKEYCODE_PICTSYMBOLS: return K_; +// case AKEYCODE_SWITCH_CHARSET: return K_; + case AKEYCODE_BUTTON_A: return K_GP_A; + case AKEYCODE_BUTTON_B: return K_GP_B; +// case AKEYCODE_BUTTON_C: return K_GP_C; + case AKEYCODE_BUTTON_X: return K_GP_X; + case AKEYCODE_BUTTON_Y: return K_GP_Y; +// case AKEYCODE_BUTTON_Z: return K_GP_Z; + case AKEYCODE_BUTTON_L1: return K_GP_LEFT_SHOULDER; + case AKEYCODE_BUTTON_R1: return K_GP_RIGHT_SHOULDER; + case AKEYCODE_BUTTON_L2: return K_GP_LEFT_TRIGGER; + case AKEYCODE_BUTTON_R2: return K_GP_RIGHT_TRIGGER; + case AKEYCODE_BUTTON_THUMBL: return K_GP_LEFT_THUMB; + case AKEYCODE_BUTTON_THUMBR: return K_GP_RIGHT_THUMB; + case AKEYCODE_BUTTON_START: return K_GP_START; + case AKEYCODE_BUTTON_SELECT: return K_GP_BACK; + case AKEYCODE_BUTTON_MODE: return K_GP_GUIDE; + +//And this is the part where you start to see quite why I hate android so much + case 111: return K_ESCAPE; + case 112: return K_DEL; + case 113: return K_LCTRL; + case 114: return K_RCTRL; + case 115: return K_CAPSLOCK; + case 116: return K_SCRLCK; + case 117: return K_LWIN; + case 118: return K_RWIN; +// case 119: return K_FUNCTION; +// case 120: return K_SYSRQ; + case 121: return K_PAUSE; + case 122: return K_HOME; + case 123: return K_END; + case 124: return K_INS; +// case 125: return K_FORWARD; +// case 126: return K_MEDIA_PLAY; +// case 127: return K_MEDIA_PAUSE; +// case 128: return K_MEDIA_CLOSE; +// case 129: return K_MEDIA_EJECT; +// case 130: return K_MEDIA_RECORD; + case 131: return K_F1; + case 132: return K_F2; + case 133: return K_F3; + case 134: return K_F4; + case 135: return K_F5; + case 136: return K_F6; + case 137: return K_F7; + case 138: return K_F8; + case 139: return K_F9; + case 140: return K_F10; + case 141: return K_F11; + case 142: return K_F12; + case 143: return K_KP_NUMLOCK; + case 144: return K_KP_INS; + case 145: return K_KP_END; + case 146: return K_KP_DOWNARROW; + case 147: return K_KP_PGDN; + case 148: return K_KP_LEFTARROW; + case 149: return K_KP_5; + case 150: return K_KP_RIGHTARROW; + case 151: return K_KP_HOME; + case 152: return K_KP_UPARROW; + case 153: return K_KP_PGUP; + case 154: return K_KP_SLASH; + case 155: return K_KP_STAR; + case 156: return K_KP_MINUS; + case 157: return K_KP_PLUS; + case 158: return K_KP_DEL; + case 160: return K_KP_ENTER; + + default: + Con_DPrintf("Android keycode %i is not supported\n", androidkey); } - if (!sys_running) - { - Sys_Printf("quit\n"); - return 8; - } - -// Sys_Printf("starting frame\n"); - - #ifdef SERVERONLY - SV_Frame(); - #else - unsigned int now = Sys_Milliseconds(); - double tdelta = (now - sys_lastframe) * 0.001; - Host_Frame(tdelta); - sys_lastframe = now; - #endif - - ret = 0; - if (Key_Dest_Has(kdm_console|kdm_message) || (!Key_Dest_Has(~kdm_game) && cls.state == ca_disconnected) || sys_osk.ival) - ret |= 1; - if (vibrateduration) - ret |= 2; - if (sys_keepscreenon.ival) - ret |= 4; - if (*errormessage || !sys_running) - ret |= 8; - if (sys_orientation.modified) - ret |= 16; - if (sys_soundflags) - { - if (sys_soundflags & 2) - sys_soundflags &= ~2; - else - ret |= 32; - } -// Sys_Printf("frame ended\n"); - return ret; + return 0; } -//called when the user tries to use us to open one of our file types -JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_openfile(JNIEnv *env, jobject obj, - jstring openfile) +static int32_t engine_handle_input(struct android_app *app, AInputEvent *event) { - const char *fname = (*env)->GetStringUTFChars(env, openfile, NULL); - if (sys_running) - Host_RunFile(fname, strlen(fname), NULL); - (*env)->ReleaseStringUTFChars(env, openfile, fname); -} - -qboolean r_forceheadless = true; - -//called for init or resizes -JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_init(JNIEnv *env, jobject obj, - jfloat dpix, jfloat dpiy, jstring japkpath, jstring jusrpath) -{ - const char *tmp; - - if (*errormessage) - return; - - sys_dpi_x = dpix; - sys_dpi_y = dpiy; - if (!sys_running) + switch(AInputEvent_getType(event)) { - const char *args [] = + case AINPUT_EVENT_TYPE_MOTION: + case AINPUT_EVENT_TYPE_KEY: + return 0; //we handle these in the java code, so shouldn't ever see them. + } + return 0; //no idea what sort of event it is. +} +static void engine_handle_cmd(struct android_app *app, int32_t cmd) +{ + switch(cmd) + { + case APP_CMD_SAVE_STATE: + //FIXME: implement save-game-to-memory... + break; + case APP_CMD_INIT_WINDOW: + if (sys_nativewindow != app->window) { - "ftedroid", + sys_nativewindow = app->window; + r_forceheadless = (sys_nativewindow==NULL); + + r_forcevidrestart = true; + } + break; + case APP_CMD_TERM_WINDOW: + r_forceheadless = true; + if (qrenderer && !r_forcevidrestart && sys_nativewindow) + R_RestartRenderer_f(); + sys_nativewindow = NULL; + break; + case APP_CMD_GAINED_FOCUS: + vid.activeapp = true; + break; + case APP_CMD_LOST_FOCUS: + vid.activeapp = false; + break; + } +} + +static void run_intent_url(struct android_app *app) +{ + jobject act = app->activity->clazz; + JNIEnv *jni; + if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL)) + { + jobject intent = (*jni)->CallObjectMethod(jni, act, (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, act), "getIntent", "()Landroid/content/Intent;")); + if (intent) + { + jstring data = (*jni)->CallObjectMethod(jni, intent, (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, intent), "getDataString", "()Ljava/lang/String;")); + if (data) + { + const char *url = (*jni)->GetStringUTFChars(jni, data, NULL); + if (url) + { + if (!strncmp(url, "content:", 8)) + { + /*Java: + Cursor cursor = this.getContentResolver().query(data, null, null, null, null); + cursor.moveToFirst(); + String myloc = cursor.getString(0); + cursor.close(); + */ + } + else + Host_RunFile(url, strlen(url), NULL); + (*jni)->ReleaseStringUTFChars(jni, data, url); + } + } + } + //FIXME: do we need to release methodids/objects? + (*app->activity->vm)->DetachCurrentThread(app->activity->vm); + } +} + +static qboolean read_apk_path(struct android_app *app, char *out, size_t outsize) +{ + qboolean res = false; + jobject act = app->activity->clazz; + JNIEnv *jni; + if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL)) + { + jstring result = (*jni)->CallObjectMethod(jni, act, (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, act), "getPackageCodePath", "()Ljava/lang/String;")); + const char *tmp = (*jni)->GetStringUTFChars(jni, result, NULL); + if (tmp) + { + res = true; + Q_strncpyz(out, tmp, outsize); + (*jni)->ReleaseStringUTFChars(jni, result, tmp); + } + + //FIXME: do we need to release methodids/objects? + (*app->activity->vm)->DetachCurrentThread(app->activity->vm); + } + + return res; +} + +static void setsoftkeyboard(struct android_app *app, int flags) +{ //the NDK is unusably buggy when it comes to keyboards, so call into java. + jobject act = app->activity->clazz; + JNIEnv *jni; + if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL)) + { + jmethodID func = (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, act), "showKeyboard", "(I)V" ); + if (func) + (*jni)->CallVoidMethod(jni, act, func, flags); + + (*app->activity->vm)->DetachCurrentThread(app->activity->vm); + } +} +static void showMessageAndQuit(struct android_app *app, const char *errormsg) +{ //no nice way to do this from native. + jobject act = app->activity->clazz; + JNIEnv *jni; + if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL)) + { + jmethodID func = (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, act), "showMessageAndQuit", "(Ljava/lang/String;)V" ); + if (func) + (*jni)->CallVoidMethod(jni, act, func, (*jni)->NewStringUTF(jni, errormsg)); + (*app->activity->vm)->DetachCurrentThread(app->activity->vm); + } +} +static void updateOrientation(struct android_app *app, const char *neworientation) +{ //no nice way to do this from native. + jobject act = app->activity->clazz; + JNIEnv *jni; + if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL)) + { + jmethodID func = (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, act), "updateOrientation", "(Ljava/lang/String;)V" ); + if (func) + (*jni)->CallVoidMethod(jni, act, func, (*jni)->NewStringUTF(jni, neworientation)); + (*app->activity->vm)->DetachCurrentThread(app->activity->vm); + } +} +static void updateScreenKeepOn(struct android_app *app, jboolean keepon) +{ //the NDK is unusably buggy when it comes to keyboards, so call into java. + jobject act = app->activity->clazz; + JNIEnv *jni; + if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL)) + { + jmethodID func = (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, act), "updateScreenKeepOn", "(Z)V" ); + if (func) + (*jni)->CallVoidMethod(jni, act, func, keepon); + + (*app->activity->vm)->DetachCurrentThread(app->activity->vm); + } +} + +static void setCursorVisibility(struct android_app *app, jboolean visible) +{ //this is meant to use the nvidia-added setCursorVisibility function + //but its fatal if it doesn't exist, and it doesn't seem to exist. +#if 0 + jobject act = app->activity->clazz; + JNIEnv *jni; + if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL)) + { + jobject inputManager = NULL; + jmethodID setvis = NULL; + jmethodID func = (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, act), "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;" ); + if (func) + inputManager = (*jni)->CallObjectMethod(jni, act, func, (*jni)->NewStringUTF(jni, "input")); + if (inputManager) + setvis = (*jni)->GetMethodID(jni, (*jni)->GetObjectClass(jni, inputManager), "setCursorVisibility", "(Z)V" ); + if (setvis) + (*jni)->CallVoidMethod(jni, inputManager, setvis, visible); + + (*app->activity->vm)->DetachCurrentThread(app->activity->vm); + } +#endif +} + +static void FTENativeActivity_keypress(JNIEnv *env, jobject this, jint devid, jboolean down, jint keycode, jint unicode) +{ + int qkeycode = mapkey(keycode); +// Sys_Printf("FTENativeActivity_keypress: d=%i s=%i a=%i,q=%i u=%i\n", devid, down, keycode, qkeycode, unicode); + IN_KeyEvent(devid, down, qkeycode, unicode); +} +static jboolean FTENativeActivity_wantrelative(JNIEnv *env, jobject this) +{ + if (!in_windowed_mouse.ival) //emulators etc have no grabs so we're effectively always windowed in such situations. + return false; + return !Key_MouseShouldBeFree(); +} +static void FTENativeActivity_mousepress(JNIEnv *env, jobject this, jint devid, jint buttonbits) +{ + static int heldbuttons; + jint changed = buttonbits^heldbuttons; +// Sys_Printf("FTENativeActivity_mousepress: d=%i bits=%x (changed=%x)\n", devid, buttonbits, changed); + static int qbutton[] = { + K_MOUSE1, //primary + K_MOUSE2, //secondary + K_MOUSE3, //tertiary + K_MOUSE4, //back + K_MOUSE5, //forward + K_MOUSE1, //stylus_primary + K_MOUSE2, //stylus_secondary + }; + size_t i; + heldbuttons = buttonbits; + if (changed) + for (i = 0; i < countof(qbutton); i++) + { + if (changed&(1<GetEnv(vm, (void**)&jni, JNI_VERSION_1_2)) + { + jclass naclass = (*jni)->FindClass(jni, "com.fteqw.FTENativeActivity"); + if (naclass) + { + (*jni)->RegisterNatives(jni, naclass, methods, countof(methods)); + return JNI_VERSION_1_2; + } + } + return -1; +} + +void android_main(struct android_app *state) +{ + static pthread_mutex_t onemainthread = PTHREAD_MUTEX_INITIALIZER; //android likes spawning multiple 'main' threads + int osk = 0, wantgrabs = 0, t; + double ltime,ctime,tdelta; + pthread_mutex_lock(&onemainthread); + android_app_state = state; + state->userData = NULL; + state->onAppCmd = engine_handle_cmd; + state->onInputEvent = engine_handle_input; + r_forceheadless = true; + sys_nativewindow = NULL; + + if (!host_initialized) + { + static const char *args [] = + { + "ftedroid", /*binary name, not really meaningful*/ "-basepack", sys_basepak, /*filled in later*/ "", "" }; - quakeparms_t parms; - Sys_Printf("reinit\n"); + static quakeparms_t parms; if (sys_memheap) free(sys_memheap); memset(&parms, 0, sizeof(parms)); parms.basedir = sys_basedir; /*filled in later*/ - parms.argc = 3; + parms.argc = read_apk_path(state, sys_basepak, sizeof(sys_basepak))?3:1; parms.argv = args; #ifdef CONFIG_MANIFEST_TEXT parms.manifest = CONFIG_MANIFEST_TEXT; #endif + sys_dpi_x = 72; //no idea + sys_dpi_y = 72; //no idea - tmp = (*env)->GetStringUTFChars(env, japkpath, NULL); - Q_strncpyz(sys_basepak, tmp, sizeof(sys_basepak)); - (*env)->ReleaseStringUTFChars(env, japkpath, tmp); +#if 0 //google made this a fucking pain. + Q_strncpyz(sys_basedir, getenv("EXTERNAL_STORAGE"), sizeof(sys_basedir)); + Q_strncatz(sys_basedir, "/fte", sizeof(sys_basedir)); +#else //so now users have to use some big long path to install stuff instead + Q_strncatz(sys_basedir, state->activity->externalDataPath, sizeof(sys_basedir)); +#endif - tmp = (*env)->GetStringUTFChars(env, jusrpath, NULL); - Q_strncpyz(sys_basedir, tmp, sizeof(sys_basedir)); - (*env)->ReleaseStringUTFChars(env, jusrpath, tmp); - - - Sys_Printf("Starting up (apk=%s, usr=%s)\n", args[2], parms.basedir); + Sys_Printf("Starting up (apk=%s, usr=%s)\n", sys_basepak, parms.basedir); VID_Register(); COM_InitArgv(parms.argc, parms.argv); TL_InitLanguages(sys_basedir); - #ifdef SERVERONLY - SV_Init(&parms); - #else - Host_Init(&parms); - #endif - sys_lastframe = Sys_Milliseconds(); - sys_orientation.modified = true; - while(r_blockvidrestart == 1) + Host_Init(&parms); + Sys_Printf("Host Inited\n"); + } + else + Sys_Printf("Restarting up!\n"); + ltime = Sys_DoubleTime(); + + sys_orientation.modified = false; + updateOrientation(state, sys_orientation.string); + sys_keepscreenon.modified = false; + updateScreenKeepOn(state, sys_keepscreenon.ival); + + run_intent_url(state); + if (state->savedState != NULL) + { //oh look, we're pretending to already be running... + //oh. + } + + for(;;) + { + int ident, events; + struct android_poll_source *source; + while((ident=ALooper_pollAll(vid.activeapp?0:250, NULL, &events, (void**)&source)) >= 0) { - unsigned int now = Sys_Milliseconds(); - double tdelta = (now - sys_lastframe) * 0.001; - Host_Frame(tdelta); - sys_lastframe = now; + if (source != NULL) + source->process(state, source); + + //FIXME: sensor crap + + if (state->destroyRequested != 0) + { + Sys_Printf("Shutdown requested\n"); + Host_Shutdown (); + + pthread_mutex_unlock(&onemainthread); + return; + } + } + if (host_initialized) + { + if (r_forcevidrestart) + { + if (qrenderer) + R_RestartRenderer_f(); + r_forcevidrestart = false; + } + if (sys_nativewindow) + { + ctime = Sys_DoubleTime(); + tdelta = ctime-ltime; + ltime = ctime; + Host_Frame(tdelta); + } } - sys_running = true; - Sys_Printf("Engine started\n"); + + t = 0; + if (Key_Dest_Has(kdm_console|kdm_message)) + t |= ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT; + if (!Key_Dest_Has(~kdm_game) && cls.state == ca_disconnected) + t |= ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT; + if (sys_osk.ival) + t |= ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED; + if (osk != t) + { + setsoftkeyboard(state, t); + osk = t; + } + + if (sys_orientation.modified) + { + sys_orientation.modified = false; + updateOrientation(state, sys_orientation.string); + } + + if (sys_keepscreenon.modified) + { + sys_keepscreenon.modified = false; + updateScreenKeepOn(state, sys_keepscreenon.ival); + } + + t = FTENativeActivity_wantrelative(NULL,NULL); + if (wantgrabs != t) + { + wantgrabs = t; + setCursorVisibility(state, wantgrabs); + } } } @@ -332,8 +731,8 @@ void Sys_Quit(void) SV_Shutdown(); #endif - sys_running = false; LOGI("%s", "quitting"); + showMessageAndQuit(android_app_state, ""); longjmp(host_abort, 1); exit(0); @@ -350,10 +749,11 @@ void Sys_Error (const char *error, ...) if (!*string) strcpy(string, "no error"); - Q_strncpyz(errormessage, string, sizeof(errormessage)); - LOGE("e: %s", string); + showMessageAndQuit(android_app_state, string); + host_initialized = false; //don't keep calling Host_Frame, because it'll screw stuff up more. Can't trust Host_Shutdown either. :( + vid.activeapp = false; //make sure we don't busyloop. longjmp(host_abort, 1); exit(1); } @@ -362,8 +762,11 @@ void Sys_Printf (char *fmt, ...) va_list argptr; char *e; - static char linebuf[2048]; //android doesn't do \ns properly *sigh* - static char *endbuf = linebuf; //android doesn't do \ns properly *sigh* + //android doesn't do \ns properly *sigh* + //this means we have to buffer+split it ourselves. + //and because of lots of threads, we have to mutex it too. + static char linebuf[2048]; + static char *endbuf = linebuf; static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&lock); @@ -459,11 +862,9 @@ void Sys_SendKeyEvents(void) } void Sys_Init(void) { - Cmd_AddCommandD("sys_vibratetime", Sys_Vibrate_f, "Provides gamecode with a way to explicitly invoke the hardware vibrator in a simple way."); - Cvar_Register(&sys_vibrate, "android stuff"); - Cvar_Register(&sys_osk, "android stuff"); Cvar_Register(&sys_keepscreenon, "android stuff"); Cvar_Register(&sys_orientation, "android stuff"); + Cvar_Register(&sys_osk, "android stuff"); } qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refreshrate) @@ -605,87 +1006,3 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const return true; } -#if 0 -#include -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *), void *parm) -{ - qboolean go = true; - const char *f; - - struct AAssetDir *ad; - ad = AAssetManager_openDir(assetmgr, gpath); - - while(go && (f = AAssetDir_getNextFileName(ad))) - { - if (wildcmp(match, f)) - { -Sys_Printf("Found %s\n", f); - go = func(f, 0, parm); - } - } - - AAssetDir_close(ad); - return 0; -} - -typedef struct -{ - vfsfile_t funcs; - AAsset *handle; -} assetfile_t; -static int AF_ReadBytes(vfsfile_t *h, void *buf, int len) -{ - assetfile_t *f = (assetfile_t*)h; - return AAsset_read(f->handle, buf, len); -} -static qboolean AF_Seek(vfsfile_t *h, unsigned long offs) -{ - assetfile_t *f = (assetfile_t*)h; - AAsset_seek(f->handle, offs, SEEK_SET); - return true; -} -static unsigned long AF_Tell(vfsfile_t *h) -{ - assetfile_t *f = (assetfile_t*)h; - return AAsset_seek(f->handle, 0, SEEK_CUR); -} -static unsigned long AF_GetSize(vfsfile_t *h) -{ - assetfile_t *f = (assetfile_t*)h; - return AAsset_getLength(f->handle); -} - -static void AF_Close(vfsfile_t *h) -{ - assetfile_t *f = (assetfile_t*)h; - AAsset_close(f->handle); - Z_Free(f); -} -static void AF_Flush(vfsfile_t *h) -{ -} -vfsfile_t *Sys_OpenAsset(char *fname) -{ - assetfile_t *file; - AAsset *a; - a = AAssetManager_open(assetmgr, fname, AASSET_MODE_UNKNOWN); - if (!a) - { - Sys_Printf("Unable to open asset %s\n", fname); - return NULL; - } - Sys_Printf("opened asset %s\n", fname); - - file = Z_Malloc(sizeof(assetfile_t)); - file->funcs.ReadBytes = AF_ReadBytes; - file->funcs.WriteBytes = NULL; - file->funcs.Seek = AF_Seek; - file->funcs.Tell = AF_Tell; - file->funcs.GetLen = AF_GetSize; - file->funcs.Close = AF_Close; - file->funcs.Flush = AF_Flush; - file->handle = a; - - return (vfsfile_t*)file; -} -#endif diff --git a/engine/client/view.c b/engine/client/view.c index a3006415e..0f84c5505 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -336,7 +336,7 @@ cvar_t v_gamma = CVARFCD("gamma", "1.0", CVAR_ARCHIVE|CVAR_RENDERERCALLBACK, V_ cvar_t v_gammainverted = CVARFCD("v_gammainverted", "0", CVAR_ARCHIVE, V_Gamma_Callback, "Boolean that controls whether the gamma should be inverted (like quake) or not."); cvar_t v_contrast = CVARAFCD("contrast", "1.0", "v_contrast", CVAR_ARCHIVE, V_Gamma_Callback, "Scales colour values linearly to make your screen easier to see. Setting this to anything but 1 without hardware gamma will reduce your framerates a little."); cvar_t v_contrastboost = CVARFCD("v_contrastboost", "1.0", CVAR_ARCHIVE, V_Gamma_Callback, "Amplifies contrast in dark areas"); -cvar_t v_brightness = CVARAFCD("brightness", "0.0", "v_contrast", CVAR_ARCHIVE, V_Gamma_Callback, "Brightness is how much 'white' to add to each and every pixel on the screen."); +cvar_t v_brightness = CVARAFCD("brightness", "0.0", "v_brightness", CVAR_ARCHIVE, V_Gamma_Callback, "Brightness is how much 'white' to add to each and every pixel on the screen."); qbyte gammatable[256]; // palette is sent through this diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 875504c41..e005ae225 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -103,7 +103,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include STRINGIFY(CONFIG_FILE_NAME) - #ifndef MSVCLIBSPATH #ifdef MSVCLIBPATH #define MSVCLIBSPATH STRINGIFY(MSVCLIBPATH) diff --git a/engine/common/common.c b/engine/common/common.c index 91dd04e24..a6ce93126 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -5193,7 +5193,7 @@ static void COM_ErrorMe_f(void) #ifdef LOADERTHREAD static void QDECL COM_WorkerCount_Change(cvar_t *var, char *oldvalue); cvar_t worker_flush = CVARD("worker_flush", "1", "If set, process the entire load queue, loading stuff faster but at the risk of stalling the main thread."); -static cvar_t worker_count = CVARFCD("worker_count", "", CVAR_NOTFROMSERVER, COM_WorkerCount_Change, "Specifies the number of worker threads to utilise."); +static cvar_t worker_count = CVARFCD("worker_count", "0", CVAR_NOTFROMSERVER, COM_WorkerCount_Change, "Specifies the number of worker threads to utilise."); static cvar_t worker_sleeptime = CVARFD("worker_sleeptime", "0", CVAR_NOTFROMSERVER, "Causes workers to sleep for a period of time after each job."); #define WORKERTHREADS 16 //max diff --git a/engine/common/sys_linux_threads.c b/engine/common/sys_linux_threads.c index 7ed7928fb..b0d9b9f61 100644 --- a/engine/common/sys_linux_threads.c +++ b/engine/common/sys_linux_threads.c @@ -48,11 +48,6 @@ void Sys_ThreadAbort(void) pthread_exit(NULL); } -#ifdef ANDROID -#include -extern JavaVM *sys_jvm; -#endif - #if 1 typedef struct { int (*func)(void *); @@ -63,17 +58,8 @@ static void *Sys_CreatedThread(void *v) qthread_t *qthread = v; qintptr_t r; -#ifdef ANDROID - JNIEnv* env; - (*sys_jvm)->AttachCurrentThread(sys_jvm, &env, NULL); -#endif - r = qthread->func(qthread->args); -#ifdef ANDROID - (*sys_jvm)->DetachCurrentThread(sys_jvm); -#endif - return (void*)r; } diff --git a/engine/droid/AndroidManifest.xml b/engine/droid/AndroidManifest.xml index 0eb1101a4..922874ae1 100644 --- a/engine/droid/AndroidManifest.xml +++ b/engine/droid/AndroidManifest.xml @@ -4,15 +4,28 @@ android:versionCode="1" android:versionName="1.05" android:installLocation="auto"> - + + + + + + + + + + diff --git a/engine/droid/src/com/fteqw/FTENativeActivity.java b/engine/droid/src/com/fteqw/FTENativeActivity.java new file mode 100644 index 000000000..c53af9bc1 --- /dev/null +++ b/engine/droid/src/com/fteqw/FTENativeActivity.java @@ -0,0 +1,368 @@ +package com.fteqw; +import android.view.inputmethod.InputMethodManager; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.InputDevice; +import android.view.WindowManager; + +public class FTENativeActivity extends android.app.Activity +{ + private static native void keypress(int devid, boolean down, int androidkey, int unicode); + private static native void mousepress(int devid, int buttonbits); + private static native void motion(int devid, int action, float x, float y, float z, float size); + private static native boolean wantrelative(); + private static native void axis(int devid, int axisid, float value); + static + { + System.loadLibrary("ftedroid"); + } + + //called by C code on errors / quitting. + public void showMessageAndQuit(String errormessage) + { + final android.app.Activity act = this; + final String errormsg = errormessage; + if (errormsg.equals("")) + { //just quit + finish(); + System.exit(0); + } + else runOnUiThread(new Runnable() + { //show an error message, then quit. + public void run() + { +// act.getView().setVisibility(android.view.View.GONE); + android.app.AlertDialog ad = new android.app.AlertDialog.Builder(act).create(); + ad.setTitle("Fatal Error"); + ad.setMessage(errormsg); + ad.setCancelable(false); + ad.setButton("Ok", new android.content.DialogInterface.OnClickListener() + { + public void onClick(android.content.DialogInterface dialog, int which) + { + finish(); + System.exit(0); + } + }); + ad.show(); + } + }); + } + public void updateScreenKeepOn(final boolean keepon) + { + final android.app.Activity act = this; + runOnUiThread(new Runnable() + { + public void run() + { + if (keepon) + act.getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + else + act.getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + }); + } + + + //called by C code to set orientation. + public void updateOrientation(String orientation) + { + final String ors = orientation; + runOnUiThread(new Runnable() + { + public void run() + { + int ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR; + if (ors.equalsIgnoreCase("unspecified")) + ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + else if (ors.equalsIgnoreCase("landscape")) + ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; + else if (ors.equalsIgnoreCase("portrait")) + ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; + else if (ors.equalsIgnoreCase("user")) + ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER; + else if (ors.equalsIgnoreCase("behind")) + ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; + else if (ors.equalsIgnoreCase("sensor")) + ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR; + else if (ors.equalsIgnoreCase("nosensor")) + ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; + //the following are api level 9+ + else if (ors.equalsIgnoreCase("sensorlandscape")) + ori = 6;//android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE; + else if (ors.equalsIgnoreCase("sensorportrait")) + ori = 7;//android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT; + else if (ors.equalsIgnoreCase("reverselandscape")) + ori = 8;//android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; + else if (ors.equalsIgnoreCase("reverseportrait")) + ori = 9;//android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; + else if (ors.equalsIgnoreCase("fullsensor")) + ori = 10;//android.content.pm.ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR; + //and the default, because specifying it again is always useless. + else + ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR; + android.util.Log.i("FTEDroid", "Orientation changed to " + ori + " (" + ors + ")."); + setRequestedOrientation(ori); + } + }); + }; + + + //keyboard stuff, called from C. + public void showKeyboard(int softkeyflags) + { //needed because the ndk's ANativeActivity_showSoftInput is defective + final android.app.Activity act = this; + final int flags = softkeyflags; + runOnUiThread(new Runnable() + { + public void run() + { + if (flags != 0) + { + InputMethodManager imm = (InputMethodManager)getSystemService(android.content.Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(act.getWindow().getDecorView(), InputMethodManager.SHOW_FORCED); + } + else + { + InputMethodManager imm = (InputMethodManager)getSystemService(android.content.Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(act.getWindow().getDecorView().getWindowToken(), 0); + } + } + }); + } + + @Override + protected void onCreate(android.os.Bundle savedInstanceState) + { + mIMM = getSystemService(InputMethodManager.class); + getWindow().takeSurface(this); + getWindow().setFormat(PixelFormat.RGB_565); + getWindow().setSoftInputMode( + WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED + | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + mNativeContentView = new NativeContentView(this); + mNativeContentView.mActivity = this; + setContentView(mNativeContentView); + mNativeContentView.requestFocus(); + mNativeContentView.getViewTreeObserver().addOnGlobalLayoutListener(this); + + byte[] nativeSavedState = savedInstanceState != null + ? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null; + mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(), + getAbsolutePath(getFilesDir()), getAbsolutePath(getObbDir()), + getAbsolutePath(getExternalFilesDir(null)), + Build.VERSION.SDK_INT, getAssets(), nativeSavedState, + classLoader, classLoader.getLdLibraryPath()); + + super.onCreate(savedInstanceState); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) + { + int act = event.getAction(); + if (act == KeyEvent.ACTION_DOWN) + { + int metastate = event.getMetaState(); + int unichar = event.getUnicodeChar(metastate); + if (unichar == 0) + unichar = event.getUnicodeChar(); + if (unichar == 0) + unichar = event.getDisplayLabel(); + + keypress(event.getDeviceId(), true, event.getKeyCode(), unichar); + return true; + } + else if (act == KeyEvent.ACTION_UP) + { + keypress(event.getDeviceId(), false, event.getKeyCode(), 0); + return true; + } + else + android.util.Log.i("FTEDroid", "other type of event"); + //ignore ACTION_MULTIPLE or whatever it is, apparently its deprecated anyway. + + return super.dispatchKeyEvent(event); + } + + private static boolean canrelative; + private static int AXIS_RELATIVE_X;//MotionEvent 24 + private static int AXIS_RELATIVE_Y;//MotionEvent 24 + private static java.lang.reflect.Method MotionEvent_getAxisValueP; //MotionEvent 12 + private static int SOURCE_MOUSE; //InputDevice + private static boolean canbuttons; + private static java.lang.reflect.Method MotionEvent_getButtonState; //MotionEvent 14 + + private static boolean canjoystick; + private static java.lang.reflect.Method MotionEvent_getAxisValueJ; + private static java.lang.reflect.Method InputDevice_getMotionRange; + private static int SOURCE_JOYSTICK; //InputDevice + private static int AXIS_X; + private static int AXIS_Y; + private static int AXIS_LTRIGGER; + private static int AXIS_Z; + private static int AXIS_RZ; + private static int AXIS_RTRIGGER; + static + { + //if (android.os.Build.VERSION.SDK_INT >= 12) + try + { + MotionEvent_getAxisValueP = MotionEvent.class.getMethod("getAxisValue", int.class, int.class); //api12 + java.lang.reflect.Field relX = MotionEvent.class.getField("AXIS_RELATIVE_X"); //api24ish + java.lang.reflect.Field relY = MotionEvent.class.getField("AXIS_RELATIVE_Y"); //api24ish + AXIS_RELATIVE_X = (Integer)relX.get(null); + AXIS_RELATIVE_Y = (Integer)relY.get(null); + SOURCE_MOUSE = (Integer)InputDevice.class.getField("SOURCE_MOUSE").get(null); + canrelative = true; //yay, no exceptions. + android.util.Log.i("FTEDroid", "relative mouse supported"); + + MotionEvent_getButtonState = MotionEvent.class.getMethod("getButtonState"); + canbuttons = true; + android.util.Log.i("FTEDroid", "mouse buttons supported"); + } catch(Exception e) { + canrelative = false; + android.util.Log.i("FTEDroid", "relative mouse not supported"); + } + try + { + MotionEvent_getAxisValueJ = MotionEvent.class.getMethod("getAxisValue", int.class); //api12 + InputDevice_getMotionRange = InputDevice.class.getMethod("getMotionRange", int.class); //api12 + AXIS_X = (Integer)MotionEvent.class.getField("AXIS_X").get(null); + AXIS_Y = (Integer)MotionEvent.class.getField("AXIS_Y").get(null); + AXIS_LTRIGGER = (Integer)MotionEvent.class.getField("AXIS_LTRIGGER").get(null); + AXIS_Z = (Integer)MotionEvent.class.getField("AXIS_Z").get(null); + AXIS_RZ = (Integer)MotionEvent.class.getField("AXIS_RZ").get(null); + AXIS_RTRIGGER = (Integer)MotionEvent.class.getField("AXIS_RTRIGGER").get(null); + SOURCE_JOYSTICK = (Integer)InputDevice.class.getField("SOURCE_JOYSTICK").get(null); + canjoystick = true; + android.util.Log.i("FTEDroid", "gamepad supported"); + } catch(Exception e) { + canjoystick = false; + android.util.Log.i("FTEDroid", "gamepad not supported"); + } + } + private static void handleJoystickAxis(MotionEvent event, InputDevice dev, int aaxis, int qaxis) + { + try + { + final InputDevice.MotionRange range = (InputDevice.MotionRange)InputDevice_getMotionRange.invoke(dev, aaxis, event.getSource()); + if (range != null) + { + final float flat = range.getFlat(); + float v = (Float)MotionEvent_getAxisValueJ.invoke(event, aaxis, 0); + if (Math.abs(v) < flat) + v = 0; //read as 0 if its within the deadzone. + axis(event.getDeviceId(), qaxis, v); + } + } + catch(Exception e) + { + } + } + private boolean motionEvent(MotionEvent event) + { + int id; + float x, y, size; + final int act = event.getAction(); + + //handle gamepad axis + if ((event.getSource() & SOURCE_JOYSTICK)!=0 && event.getAction() == MotionEvent.ACTION_MOVE) + { + InputDevice dev = event.getDevice(); + handleJoystickAxis(event, dev, AXIS_X, 0); + handleJoystickAxis(event, dev, AXIS_Y, 1); + handleJoystickAxis(event, dev, AXIS_LTRIGGER, 2); + + handleJoystickAxis(event, dev, AXIS_Z, 3); + handleJoystickAxis(event, dev, AXIS_RZ, 4); + handleJoystickAxis(event, dev, AXIS_RTRIGGER, 5); + + return true; + } + + final int pointerCount = event.getPointerCount(); + int i; + for (i = 0; i < pointerCount; i++) + { + if (canrelative && event.getSource() == SOURCE_MOUSE && wantrelative()) + { + try + { + x = (Float)MotionEvent_getAxisValueP.invoke(event, AXIS_RELATIVE_X, i); + y = (Float)MotionEvent_getAxisValueP.invoke(event, AXIS_RELATIVE_Y, i); + motion(event.getPointerId(i), 1, x, y, 0, event.getSize(i)); + } + catch(Exception e) + { + android.util.Log.i("FTEDroid", "exception using relative mouse"); + canrelative=false; + } + } + else + { + motion(event.getPointerId(i), 0, event.getX(i), event.getY(i), 0, event.getSize(i)); + } + } + + switch(act & event.ACTION_MASK) + { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + id = ((act&event.ACTION_POINTER_ID_MASK) >> event.ACTION_POINTER_ID_SHIFT); + x = event.getX(id); + y = event.getY(id); + size = event.getSize(id); + id = event.getPointerId(id); + if (canbuttons) + { + try {mousepress(id, (Integer)MotionEvent_getButtonState.invoke(event));} + catch(Exception e){} + } + else + motion(id, 2, x, y, 0, size); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + id = ((act&event.ACTION_POINTER_ID_MASK) >> event.ACTION_POINTER_ID_SHIFT); + x = event.getX(id); + y = event.getY(id); + size = event.getSize(id); + id = event.getPointerId(id); + if (canbuttons) + { + try {mousepress(id, (Integer)MotionEvent_getButtonState.invoke(event));} + catch(Exception e){} + } + else + motion(id, 3, x, y, 0, size); + break; + case MotionEvent.ACTION_MOVE: + break; + default: + return false; + } + return true; + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) + { //works when mouse is pressed... + return motionEvent(event); + } +// @Override + public boolean dispatchGenericMotionEvent(MotionEvent event) + { //works even when mouse is not pressed + return motionEvent(event); + } + + + //launching stuff + /*private static native int unicodeKeyPress(int unicode); + @Override + void onNewIntent(Intent intent) + { + super.onNewIntent(intent); + }*/ +} + diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 51782be79..ef65486fb 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -1793,6 +1793,8 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype) g->failed = true; + TRACE(("Loading program %s...\n", g->name)); + basicname[1] = 0; Q_strncpyz(basicname, g->name, sizeof(basicname)); h = strchr(basicname+1, '#'); @@ -1839,6 +1841,7 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype) if (file) { + TRACE(("Loading from disk (%s)\n", g->name)); // Con_DPrintf("Loaded %s from disk\n", sh_config.progpath?va(sh_config.progpath, basicname):basicname); g->failed = !Shader_LoadPermutations(g->name, &g->prog, file, qrtype, 0, blobname); FS_FreeFile(file); @@ -1857,6 +1860,7 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype) if (!(qrenderer==QR_OPENGL&&ver==110)) continue; + TRACE(("Loading Embedded %s\n", g->name)); g->failed = !Shader_LoadPermutations(g->name, &g->prog, sbuiltins[i].body, qrtype, ver, blobname); if (g->failed) @@ -1865,6 +1869,7 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype) return; } } + TRACE(("Program unloadable %s\n", g->name)); } } @@ -7616,6 +7621,7 @@ void Shader_DoReload(void) } shader_reload_needed = false; R2D_ImageColours(1,1,1,1); + TRACE(("Reloading generics\n")); Shader_ReloadGenerics(); for (i = 0; i < r_numshaders; i++) @@ -7631,6 +7637,7 @@ void Shader_DoReload(void) if (argsstart) *argsstart = 0; COM_StripExtension (cleanname, shortname, sizeof(shortname)); + TRACE(("reparsing %s\n", s->name)); if (ruleset_allow_shaders.ival && !(s->usageflags & SUR_FORCEFALLBACK)) { if (sh_config.shadernamefmt) @@ -7658,6 +7665,8 @@ void Shader_DoReload(void) } } + TRACE(("Resorting shaders\n")); + if (resort) { Mod_ResortShaders(); diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index b965dc47d..762ac5292 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -3240,7 +3240,7 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], } #endif - if (qglStencilOpSeparateATI) + if (qglStencilOpSeparate) { //ATI/GLES/ARB method sref/=2; @@ -3250,11 +3250,11 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], qglStencilFunc(GL_ALWAYS, 0, ~0); - qglStencilOpSeparateATI(GL_BACK, GL_KEEP, sbackfail, GL_KEEP); - qglStencilOpSeparateATI(GL_FRONT, GL_KEEP, sfrontfail, GL_KEEP); + qglStencilOpSeparate(GL_BACK, GL_KEEP, sbackfail, GL_KEEP); + qglStencilOpSeparate(GL_FRONT, GL_KEEP, sfrontfail, GL_KEEP); Sh_DrawStencilLightShadows(dl, lvis, vvis, false); - qglStencilOpSeparateATI(GL_FRONT_AND_BACK, GL_KEEP, GL_KEEP, GL_KEEP); + qglStencilOpSeparate(GL_FRONT_AND_BACK, GL_KEEP, GL_KEEP, GL_KEEP); GL_CullFace(SHADER_CULL_FRONT); @@ -4066,4 +4066,4 @@ void Sh_RegisterCvars(void) Cvar_Register (&r_sun_dir, REALTIMELIGHTING); Cvar_Register (&r_sun_colour, REALTIMELIGHTING); #endif -} \ No newline at end of file +} diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index ccd79637c..ec52cddee 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -87,7 +87,7 @@ FTEPFNGLVERTEXATTRIB4FARBPROC qglVertexAttrib4f; FTEPFNGLGETVERTEXATTRIBIV qglGetVertexAttribiv; FTEPFNGLENABLEVERTEXATTRIBARRAY qglEnableVertexAttribArray; FTEPFNGLDISABLEVERTEXATTRIBARRAY qglDisableVertexAttribArray; -void (APIENTRY *qglStencilOpSeparateATI) (GLenum face, GLenum fail, GLenum zfail, GLenum zpass); +void (APIENTRY *qglStencilOpSeparate) (GLenum face, GLenum fail, GLenum zfail, GLenum zpass); void (APIENTRY *qglGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint * params); void (APIENTRY *qglGetVertexAttribPointerv) (GLuint index, GLenum pname, GLvoid* *pointer); @@ -798,11 +798,11 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) gl_config.ext_stencil_wrap = true; #ifndef GL_STATIC - qglStencilOpSeparateATI = NULL; + qglStencilOpSeparate = NULL; if ((gl_config.gles && gl_config.glversion >= 2) || (!gl_config.gles && gl_config.glversion >= 3)) //theoretically that should be a 2 not 3. - qglStencilOpSeparateATI = (void *) getglext("glStencilOpSeparate"); + qglStencilOpSeparate = (void *) getglext("glStencilOpSeparate"); else if (GL_CheckExtension("GL_ATI_separate_stencil")) - qglStencilOpSeparateATI = (void *) getglext("glStencilOpSeparateATI"); + qglStencilOpSeparate = (void *) getglext("glStencilOpSeparateATI"); #endif qglActiveStencilFaceEXT = NULL; if (GL_CheckExtension("GL_EXT_stencil_two_side")) @@ -1008,7 +1008,6 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) else if (gl_config.glversion >= 2)// && (gl_config.gles || 0)) { /*core names are different from extension names (more functions too)*/ - gl_config.arb_shader_objects = true; qglCreateProgramObjectARB = (void *)getglext( "glCreateProgram"); qglDeleteProgramObject_ = (void *)getglext( "glDeleteProgram"); qglDeleteShaderObject_ = (void *)getglext( "glDeleteShader"); @@ -1042,7 +1041,14 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) qglEnableVertexAttribArray = (void *)getglext("glEnableVertexAttribArray"); qglDisableVertexAttribArray = (void *)getglext("glDisableVertexAttribArray"); qglGetShaderSource = (void *)getglext("glGetShaderSource"); - Con_DPrintf("GLSL available\n"); + + if (qglCreateProgramObjectARB && qglLinkProgramARB) + { + Con_DPrintf("GLSL available\n"); + gl_config.arb_shader_objects = true; + } + else + Con_Printf(CON_ERROR"GL version specifies GLSL support, but GLSL functions are not available\n"); } else if (GL_CheckExtension("GL_ARB_fragment_shader") && GL_CheckExtension("GL_ARB_vertex_shader") @@ -3114,7 +3120,7 @@ void GL_ForgetPointers(void) #ifndef GL_STATIC - qglStencilOpSeparateATI = NULL; + qglStencilOpSeparate = NULL; #endif qglActiveStencilFaceEXT = NULL; @@ -3276,55 +3282,15 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) qglPolygonOffset = (void *)getglext("glPolygonOffset"); qglLineWidth = (void *)getglcore("glLineWidth"); #endif + #ifndef FTE_TARGET_WEB - qglAlphaFunc = (void *)getglcore("glAlphaFunc"); - qglBegin = (void *)getglcore("glBegin"); - qglClearDepth = (void *)getglcore("glClearDepth"); - qglClipPlane = (void *)getglcore("glClipPlane"); -// qglColor3f = (void *)getglcore("glColor3f"); -// qglColor3ub = (void *)getglcore("glColor3ub"); - qglColor4f = (void *)getglcore("glColor4f"); - qglColor4fv = (void *)getglext("glColor4fv"); - if (!qglColor4fv) - qglColor4fv = GL_Color4fv_Emul; //can be missing in gles1 -// qglColor4ub = (void *)getglcore("glColor4ub"); -// qglColor4ubv = (void *)getglcore("glColor4ubv"); -// qglDepthRange = (void *)getglcore("glDepthRange"); - qglDrawBuffer = (void *)getglcore("glDrawBuffer"); - qglDrawPixels = (void *)getglcore("glDrawPixels"); - qglEnd = (void *)getglcore("glEnd"); - qglFrustum = (void *)getglcore("glFrustum"); qglGetTexLevelParameteriv = (void *)getglcore("glGetTexLevelParameteriv"); - qglLoadIdentity = (void *)getglcore("glLoadIdentity"); - qglLoadMatrixf = (void *)getglcore("glLoadMatrixf"); - qglNormal3f = (void *)getglcore("glNormal3f"); - qglNormal3fv = (void *)getglcore("glNormal3fv"); - qglMatrixMode = (void *)getglcore("glMatrixMode"); - qglMultMatrixf = (void *)getglcore("glMultMatrixf"); -// qglOrtho = (void *)getglcore("glOrtho"); - qglPolygonMode = (void *)getglcore("glPolygonMode"); - qglPopMatrix = (void *)getglcore("glPopMatrix"); - qglPushMatrix = (void *)getglcore("glPushMatrix"); qglReadBuffer = (void *)getglcore("glReadBuffer"); - qglRotatef = (void *)getglcore("glRotatef"); - qglScalef = (void *)getglcore("glScalef"); - qglShadeModel = (void *)getglcore("glShadeModel"); - qglTexCoord1f = (void *)getglcore("glTexCoord1f"); - qglTexCoord2f = (void *)getglcore("glTexCoord2f"); - qglTexCoord2fv = (void *)getglcore("glTexCoord2fv"); - qglTexEnvf = (void *)getglcore("glTexEnvf"); - qglTexEnvfv = (void *)getglcore("glTexEnvfv"); - qglTexEnvi = (void *)getglcore("glTexEnvi"); - qglTexGeni = (void *)getglcore("glTexGeni"); - qglTexGenfv = (void *)getglcore("glTexGenfv"); qglTexImage3D = (void *)getglext("glTexImage3D"); qglTexSubImage3D = (void *)getglext("glTexSubImage3D"); - qglTranslatef = (void *)getglcore("glTranslatef"); - qglVertex2f = (void *)getglcore("glVertex2f"); - qglVertex3f = (void *)getglcore("glVertex3f"); - qglVertex3fv = (void *)getglcore("glVertex3fv"); #endif + //various vertex array stuff. qglArrayElement = (void *)getglcore("glArrayElement"); qglVertexPointer = (void *)getglcore("glVertexPointer"); @@ -3340,27 +3306,12 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) qglMultiDrawElements = (void *)getglext("glMultiDrawElements"); //since gl2 - //fixme: definatly make non-core - qglPushAttrib = (void *)getglcore("glPushAttrib"); - qglPopAttrib = (void *)getglcore("glPopAttrib"); - - //does this need to be non-core as well? - qglFogi = (void *)getglcore("glFogi"); - qglFogf = (void *)getglcore("glFogf"); - qglFogfv = (void *)getglcore("glFogfv"); - qglGetTexEnviv = (void *)getglext("glGetTexEnviv"); qglGetPointerv = (void *)getglext("glGetPointerv"); qglGetStringi = (void *)getglext("glGetStringi"); - //used by heightmaps - qglGenLists = (void*)getglcore("glGenLists"); - qglNewList = (void*)getglcore("glNewList"); - qglEndList = (void*)getglcore("glEndList"); - qglCallList = (void*)getglcore("glCallList"); - #ifndef GL_STATIC qglBindBufferARB = (void *)getglext("glBindBufferARB"); if (!qglBindBufferARB) @@ -3384,6 +3335,69 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) GL_CheckExtensions (getglfunction); +#ifndef FTE_TARGET_WEB + if (!gl_config.gles) + { + qglAlphaFunc = (void *)getglcore("glAlphaFunc"); + qglBegin = (void *)getglcore("glBegin"); + qglClearDepth = (void *)getglcore("glClearDepth"); + qglClipPlane = (void *)getglcore("glClipPlane"); +// qglColor3f = (void *)getglcore("glColor3f"); +// qglColor3ub = (void *)getglcore("glColor3ub"); + qglColor4f = (void *)getglcore("glColor4f"); + qglColor4fv = (void *)getglext("glColor4fv"); +// qglColor4ub = (void *)getglcore("glColor4ub"); +// qglColor4ubv = (void *)getglcore("glColor4ubv"); +// qglDepthRange = (void *)getglcore("glDepthRange"); + qglDrawBuffer = (void *)getglcore("glDrawBuffer"); + qglDrawPixels = (void *)getglcore("glDrawPixels"); + qglEnd = (void *)getglcore("glEnd"); + qglFrustum = (void *)getglcore("glFrustum"); + qglLoadIdentity = (void *)getglcore("glLoadIdentity"); + qglLoadMatrixf = (void *)getglcore("glLoadMatrixf"); + qglNormal3f = (void *)getglcore("glNormal3f"); + qglNormal3fv = (void *)getglcore("glNormal3fv"); + qglMatrixMode = (void *)getglcore("glMatrixMode"); + qglMultMatrixf = (void *)getglcore("glMultMatrixf"); +// qglOrtho = (void *)getglcore("glOrtho"); + qglPolygonMode = (void *)getglcore("glPolygonMode"); + qglPopMatrix = (void *)getglcore("glPopMatrix"); + qglPushMatrix = (void *)getglcore("glPushMatrix"); + qglRotatef = (void *)getglcore("glRotatef"); + qglScalef = (void *)getglcore("glScalef"); + qglShadeModel = (void *)getglcore("glShadeModel"); + qglTexCoord1f = (void *)getglcore("glTexCoord1f"); + qglTexCoord2f = (void *)getglcore("glTexCoord2f"); + qglTexCoord2fv = (void *)getglcore("glTexCoord2fv"); + qglTexEnvf = (void *)getglcore("glTexEnvf"); + qglTexEnvfv = (void *)getglcore("glTexEnvfv"); + qglTexEnvi = (void *)getglcore("glTexEnvi"); + qglTexGeni = (void *)getglcore("glTexGeni"); + qglTexGenfv = (void *)getglcore("glTexGenfv"); + qglTranslatef = (void *)getglcore("glTranslatef"); + qglVertex2f = (void *)getglcore("glVertex2f"); + qglVertex3f = (void *)getglcore("glVertex3f"); + qglVertex3fv = (void *)getglcore("glVertex3fv"); + + //fixme: definatly make non-core + qglPushAttrib = (void *)getglcore("glPushAttrib"); + qglPopAttrib = (void *)getglcore("glPopAttrib"); + + //does this need to be non-core as well? + qglFogi = (void *)getglcore("glFogi"); + qglFogf = (void *)getglcore("glFogf"); + qglFogfv = (void *)getglcore("glFogfv"); + + //used by heightmaps + qglGenLists = (void*)getglcore("glGenLists"); + qglNewList = (void*)getglcore("glNewList"); + qglEndList = (void*)getglcore("glEndList"); + qglCallList = (void*)getglcore("glCallList"); + } + if (!qglColor4fv) + qglColor4fv = GL_Color4fv_Emul; //can be missing in gles1 +#endif + if ((gl_config.gles && gl_config.glversion >= 3) || (!gl_config.gles && gl_config.glversion >= 2)) qglDrawBuffers = (void *)getglext("glDrawBuffers"); else @@ -3502,7 +3516,7 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) sh_config.progs_supported = gl_config.arb_shader_objects; sh_config.progs_required = gl_config_nofixedfunc; - if (gl_config.arb_shader_objects) + if (sh_config.progs_supported) { sh_config.pDeleteProg = GLSlang_DeleteProg; sh_config.pLoadBlob = qglProgramBinary?GLSlang_LoadBlob:NULL; @@ -3524,6 +3538,9 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) sh_config.env_add = gl_config.env_add; } + +// Con_Printf("sh_config.progs supported: %i, required: %i, vers: %i - %i\n", sh_config.progs_supported, sh_config.progs_required, sh_config.minver, sh_config.maxver); + return true; } diff --git a/engine/gl/gl_viddroid.c b/engine/gl/gl_viddroid.c index 2f07905f4..67147d985 100644 --- a/engine/gl/gl_viddroid.c +++ b/engine/gl/gl_viddroid.c @@ -29,6 +29,9 @@ static rendererinfo_t gles1rendererinfo; static void *GLES_GetSymbol(char *symname) { + //Can't use android's eglGetProcAddress + //1) it gives less efficient stubs + //2) it has a limited number of such stubs, and the limit is too low for core functions too void *ret; ret = Sys_GetAddressForName(sys_gl_module, symname); @@ -50,28 +53,7 @@ static void *GLES_GetSymbol(char *symname) static EGLDisplay sys_display; static EGLSurface sys_surface; static EGLContext sys_context; -static jobject sys_jsurface; -extern JNIEnv *sys_jenv; - -extern qboolean r_forceheadless; -JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_setwindow(JNIEnv *env, jobject obj, - jobject surface) -{ - if (sys_jsurface) - (*env)->DeleteGlobalRef(sys_jenv, sys_jsurface); - sys_jenv = env; - sys_jsurface = surface?(*env)->NewGlobalRef(sys_jenv, surface):NULL; - - r_forceheadless = (sys_jsurface == NULL); - - if (r_forceheadless) - Sys_Printf("Running without a window\n"); - else - Sys_Printf("Got a window\n"); - - if (qrenderer) //if the window changed then we need to restart everything to match it, BEFORE we return from this function... :( - R_RestartRenderer_f(); -} +ANativeWindow *sys_nativewindow; void GLVID_DeInit(void) { @@ -94,11 +76,63 @@ void GLVID_DeInit(void) Sys_Printf("GLVID_DeInited\n"); } +static void EGL_ShowConfig(EGLDisplay egldpy, EGLConfig cfg) +{ + struct + { + EGLint attr; + const char *attrname; + } eglattrs[] = + { + {EGL_ALPHA_SIZE, "EGL_ALPHA_SIZE"}, + {EGL_ALPHA_MASK_SIZE, "EGL_ALPHA_MASK_SIZE"}, + {EGL_BIND_TO_TEXTURE_RGB, "EGL_BIND_TO_TEXTURE_RGB"}, + {EGL_BIND_TO_TEXTURE_RGBA, "EGL_BIND_TO_TEXTURE_RGBA"}, + {EGL_BLUE_SIZE, "EGL_BLUE_SIZE"}, + {EGL_BUFFER_SIZE, "EGL_BUFFER_SIZE"}, + {EGL_COLOR_BUFFER_TYPE, "EGL_COLOR_BUFFER_TYPE"}, + {EGL_CONFIG_CAVEAT, "EGL_CONFIG_CAVEAT"}, + {EGL_CONFIG_ID, "EGL_CONFIG_ID"}, + {EGL_CONFORMANT, "EGL_CONFORMANT"}, + {EGL_DEPTH_SIZE, "EGL_DEPTH_SIZE"}, + {EGL_GREEN_SIZE, "EGL_GREEN_SIZE"}, + {EGL_LEVEL, "EGL_LEVEL"}, + {EGL_LUMINANCE_SIZE, "EGL_LUMINANCE_SIZE"}, + {EGL_MAX_PBUFFER_WIDTH, "EGL_MAX_PBUFFER_WIDTH"}, + {EGL_MAX_PBUFFER_HEIGHT, "EGL_MAX_PBUFFER_HEIGHT"}, + {EGL_MAX_PBUFFER_PIXELS, "EGL_MAX_PBUFFER_PIXELS"}, + {EGL_MAX_SWAP_INTERVAL, "EGL_MAX_SWAP_INTERVAL"}, + {EGL_MIN_SWAP_INTERVAL, "EGL_MIN_SWAP_INTERVAL"}, + {EGL_NATIVE_RENDERABLE, "EGL_NATIVE_RENDERABLE"}, + {EGL_NATIVE_VISUAL_ID, "EGL_NATIVE_VISUAL_ID"}, + {EGL_NATIVE_VISUAL_TYPE, "EGL_NATIVE_VISUAL_TYPE"}, + {EGL_RED_SIZE, "EGL_RED_SIZE"}, + {EGL_RENDERABLE_TYPE, "EGL_RENDERABLE_TYPE"}, + {EGL_SAMPLE_BUFFERS, "EGL_SAMPLE_BUFFERS"}, + {EGL_SAMPLES, "EGL_SAMPLES"}, + {EGL_STENCIL_SIZE, "EGL_STENCIL_SIZE"}, + {EGL_SURFACE_TYPE, "EGL_SURFACE_TYPE"}, + {EGL_TRANSPARENT_TYPE, "EGL_TRANSPARENT_TYPE"}, + {EGL_TRANSPARENT_RED_VALUE, "EGL_TRANSPARENT_RED_VALUE"}, + {EGL_TRANSPARENT_GREEN_VALUE, "EGL_TRANSPARENT_GREEN_VALUE"}, + {EGL_TRANSPARENT_BLUE_VALUE, "EGL_TRANSPARENT_BLUE_VALUE"}, + }; + size_t i; + EGLint val; + + for (i = 0; i < countof(eglattrs); i++) + { + if (eglGetConfigAttrib(egldpy, cfg, eglattrs[i].attr, &val)) + Sys_Printf("%i.%s: %i\n", (int)cfg, eglattrs[i].attrname, val); + else + Sys_Printf("%i.%s: UNKNOWN\n", (int)cfg, eglattrs[i].attrname); + } +}; qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) { Sys_Printf("GLVID_Initing...\n"); - if (!sys_jsurface) + if (!sys_nativewindow) { Sys_Printf("GLVID_Init failed: no window known yet\n"); return false; //not at this time... @@ -172,23 +206,15 @@ Sys_Printf("GLVID_Initing...\n"); Sys_Printf("Creating gles %i context\n", glesversion); - sys_gl_module = Sys_LoadLibrary((glesversion>=2)?"libGLESv2.so":"libGLESv1_CM.so", NULL); - if (!sys_gl_module) - { - GLVID_DeInit(); - return false; - } - - eglGetConfigAttrib(sys_display, config, EGL_NATIVE_VISUAL_ID, &format); - ANativeWindow *anwindow = ANativeWindow_fromSurface(sys_jenv, sys_jsurface); - ANativeWindow_setBuffersGeometry(anwindow, 0, 0, format); - - sys_surface = eglCreateWindowSurface(sys_display, config, anwindow, NULL); - ANativeWindow_release(anwindow); + EGL_ShowConfig(sys_display, config); + + sys_surface = eglCreateWindowSurface(sys_display, config, sys_nativewindow, NULL); if (!sys_surface) return false; EGLint ctxattribs[] = {EGL_CONTEXT_CLIENT_VERSION, glesversion, EGL_NONE}; - sys_context = eglCreateContext(sys_display, config, NULL, glesversion>1?ctxattribs:NULL); + sys_context = eglCreateContext(sys_display, config, NULL, ctxattribs); + if (!sys_context) + return false; if (eglMakeCurrent(sys_display, sys_surface, sys_surface, sys_context) == EGL_FALSE) @@ -199,6 +225,28 @@ Sys_Printf("GLVID_Initing...\n"); vid.pixelwidth = w; vid.pixelheight = h; + /*now that the context is created, load the dll so that we don't have to crash from eglGetProcAddress issues*/ + unsigned int gl_major_version = 0; + const char *(*eglGetString)(GLenum) = (void*)eglGetProcAddress("glGetString"); + const char *s = eglGetString(GL_VERSION); + while (*s && (*s < '0' || *s > '9')) + s++; + gl_major_version = atoi(s); + const char *driver; + if (gl_major_version>=3) + driver = "libGLESv3.so"; + else if (gl_major_version>=2) + driver = "libGLESv2.so"; + else + driver = "libGLESv1_CM.so"; + Sys_Printf("Loading %s\n", driver); + sys_gl_module = Sys_LoadLibrary(driver, NULL); + if (!sys_gl_module) + { + GLVID_DeInit(); + return false; + } + if (!GL_Init(info, GLES_GetSymbol)) return false; Sys_Printf("GLVID_Inited...\n"); @@ -217,9 +265,11 @@ void GLVID_SwapBuffers(void) else interval = 1; //default is to always vsync, according to EGL docs, so lets just do that. eglSwapInterval(sys_display, interval); + Sys_Printf("Swap interval changed\n"); } eglSwapBuffers(sys_display, sys_surface); + TRACE(("Swap Buffers\n")); EGLint w, h; eglQuerySurface(sys_display, sys_surface, EGL_WIDTH, &w); @@ -230,6 +280,7 @@ void GLVID_SwapBuffers(void) vid.pixelheight = h; extern cvar_t vid_conautoscale; Cvar_ForceCallback(&vid_conautoscale); + Sys_Printf("Video Resized\n"); } } @@ -264,9 +315,8 @@ static qboolean VKVID_CreateSurface(void) VkResult err; VkAndroidSurfaceCreateInfoKHR createInfo = {VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR}; createInfo.flags = 0; - createInfo.window = ANativeWindow_fromSurface(sys_jenv, sys_jsurface); + createInfo.window = sys_nativewindow; err = vkCreateAndroidSurfaceKHR(vk.instance, &createInfo, NULL, &vk.surface); - ANativeWindow_release(createInfo.window); switch(err) { default: @@ -284,7 +334,7 @@ static qboolean VKVID_Init (rendererstate_t *info, unsigned char *palette) //(android surfaces can be resized/resampled separately from their window, and are always 'fullscreen' anyway, so this isn't actually an issue for once) const char *extnames[] = {VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, NULL}; Sys_Printf("initialising vulkan...\n"); - if (!sys_jsurface) + if (!sys_nativewindow) { Sys_Printf("VKVID_Init failed: no window known yet\n"); return false; diff --git a/engine/gl/gl_videgl.c b/engine/gl/gl_videgl.c index d47fbe74d..ccfaa4f20 100644 --- a/engine/gl/gl_videgl.c +++ b/engine/gl/gl_videgl.c @@ -197,6 +197,59 @@ void EGL_Shutdown(void) eglsurf = EGL_NO_SURFACE; } +static void EGL_ShowConfig(EGLDisplay egldpy, EGLConfig cfg) +{ + struct + { + EGLint attr; + const char *attrname; + } eglattrs[] = + { + {EGL_ALPHA_SIZE, "EGL_ALPHA_SIZE"}, + {EGL_ALPHA_MASK_SIZE, "EGL_ALPHA_MASK_SIZE"}, + {EGL_BIND_TO_TEXTURE_RGB, "EGL_BIND_TO_TEXTURE_RGB"}, + {EGL_BIND_TO_TEXTURE_RGBA, "EGL_BIND_TO_TEXTURE_RGBA"}, + {EGL_BLUE_SIZE, "EGL_BLUE_SIZE"}, + {EGL_BUFFER_SIZE, "EGL_BUFFER_SIZE"}, + {EGL_COLOR_BUFFER_TYPE, "EGL_COLOR_BUFFER_TYPE"}, + {EGL_CONFIG_CAVEAT, "EGL_CONFIG_CAVEAT"}, + {EGL_CONFIG_ID, "EGL_CONFIG_ID"}, + {EGL_CONFORMANT, "EGL_CONFORMANT"}, + {EGL_DEPTH_SIZE, "EGL_DEPTH_SIZE"}, + {EGL_GREEN_SIZE, "EGL_GREEN_SIZE"}, + {EGL_LEVEL, "EGL_LEVEL"}, + {EGL_LUMINANCE_SIZE, "EGL_LUMINANCE_SIZE"}, + {EGL_MAX_PBUFFER_WIDTH, "EGL_MAX_PBUFFER_WIDTH"}, + {EGL_MAX_PBUFFER_HEIGHT, "EGL_MAX_PBUFFER_HEIGHT"}, + {EGL_MAX_PBUFFER_PIXELS, "EGL_MAX_PBUFFER_PIXELS"}, + {EGL_MAX_SWAP_INTERVAL, "EGL_MAX_SWAP_INTERVAL"}, + {EGL_MIN_SWAP_INTERVAL, "EGL_MIN_SWAP_INTERVAL"}, + {EGL_NATIVE_RENDERABLE, "EGL_NATIVE_RENDERABLE"}, + {EGL_NATIVE_VISUAL_ID, "EGL_NATIVE_VISUAL_ID"}, + {EGL_NATIVE_VISUAL_TYPE, "EGL_NATIVE_VISUAL_TYPE"}, + {EGL_RED_SIZE, "EGL_RED_SIZE"}, + {EGL_RENDERABLE_TYPE, "EGL_RENDERABLE_TYPE"}, + {EGL_SAMPLE_BUFFERS, "EGL_SAMPLE_BUFFERS"}, + {EGL_SAMPLES, "EGL_SAMPLES"}, + {EGL_STENCIL_SIZE, "EGL_STENCIL_SIZE"}, + {EGL_SURFACE_TYPE, "EGL_SURFACE_TYPE"}, + {EGL_TRANSPARENT_TYPE, "EGL_TRANSPARENT_TYPE"}, + {EGL_TRANSPARENT_RED_VALUE, "EGL_TRANSPARENT_RED_VALUE"}, + {EGL_TRANSPARENT_GREEN_VALUE, "EGL_TRANSPARENT_GREEN_VALUE"}, + {EGL_TRANSPARENT_BLUE_VALUE, "EGL_TRANSPARENT_BLUE_VALUE"}, + }; + size_t i; + EGLint val; + + for (i = 0; i < countof(eglattrs); i++) + { + if (eglGetContifAttrib(egldpy, cfg, eglattrs[i].attr, &val)) + Con_Printf("%i.%s: %i\n", cfg, eglattrs[i].attrname, val); + else + Con_Printf("%i.%s: UNKNOWN\n", cfg, eglattrs[i].attrname); + } +} + static void EGL_UpdateSwapInterval(void) { int interval; @@ -220,6 +273,8 @@ void EGL_SwapBuffers (void) qeglSwapBuffers(egldpy, eglsurf); /* TODO: check result? */ TRACE(("EGL_SwapBuffers done\n")); + + Con_Printf("EGL_SwapBuffers\n"); } qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, int eglplat, void *nwindow, void *ndpy, EGLNativeWindowType windowid, EGLNativeDisplayType dpyid) @@ -306,6 +361,8 @@ qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, int eglplat, v return false; } + EGL_ShowConfig(egldpy, cfg); + if (qeglCreatePlatformWindowSurface) eglsurf = qeglCreatePlatformWindowSurface(egldpy, cfg, nwindow, info->srgb?wndattrib:NULL); else diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index 37f3c8e96..b09b846bd 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -1042,9 +1042,6 @@ static void XRandR_SelectMode(const char *devicename, int *x, int *y, int *width -extern cvar_t _windowed_mouse; - - static float mouse_grabbed = 0; static enum @@ -2525,7 +2522,7 @@ static void UpdateGrabs(void) qboolean wantmgrabs, allownullcursor; Cursor wantcursor; - wantmgrabs = (fullscreenflags&FULLSCREEN_ACTIVE) || !!_windowed_mouse.value; + wantmgrabs = (fullscreenflags&FULLSCREEN_ACTIVE) || !!in_windowed_mouse.value; if (!vid.activeapp) wantmgrabs = false; allownullcursor = wantmgrabs; //this says whether we can possibly want it. if false then we disallow the null cursor. Yes, this might break mods that do their own sw cursors. such mods are flawed in other ways too. diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index cdd0b926b..713b46957 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -170,7 +170,6 @@ extern float gammapending; extern cvar_t vid_mode; // Note that 3 is MODE_FULLSCREEN_DEFAULT extern cvar_t vid_vsync; -extern cvar_t _windowed_mouse; extern cvar_t vid_hardwaregamma; extern cvar_t vid_desktopgamma; extern cvar_t gl_lateswap; diff --git a/engine/gl/gl_vidsdl.c b/engine/gl/gl_vidsdl.c index bb37ec264..aaac36789 100644 --- a/engine/gl/gl_vidsdl.c +++ b/engine/gl/gl_vidsdl.c @@ -405,7 +405,7 @@ void GLVID_SwapBuffers (void) if (!vid_isfullscreen) { - if (!_windowed_mouse.value) + if (!in_windowed_mouse.value) { IN_DeactivateMouse (); } diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 71c811dcb..ae4fdff10 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -57,14 +57,13 @@ void Mod_LightmapAllocBlock(lmalloc_t *lmallocator, int w, int h, unsigned short #ifdef GLQUAKE #if defined(ANDROID) /*FIXME: actually just to use standard GLES headers instead of full GL*/ - #if 1 + #ifndef GLSLONLY #include #ifndef GL_CLIP_PLANE0 #define GL_CLIP_PLANE0 0x3000 #endif #else #include - #define GL_TEXTURE_COORD_ARRAY 0 #endif /*gles has no doubles*/ #define GLclampd GLclampf @@ -197,7 +196,7 @@ typedef void (APIENTRY * FTEPFNGLUNLOCKARRAYSEXTPROC) (void); extern BINDTEXFUNCPTR qglBindTexture; extern DELTEXFUNCPTR delTexFunc; extern TEXSUBIMAGEPTR TexSubImage2DFunc; -extern void (APIENTRY *qglStencilOpSeparateATI) (GLenum face, GLenum fail, GLenum zfail, GLenum zpass); +extern void (APIENTRY *qglStencilOpSeparate) (GLenum face, GLenum fail, GLenum zfail, GLenum zpass); #endif extern FTEPFNGLPNTRIANGLESIATIPROC qglPNTrianglesiATI; extern FTEPFNGLPNTRIANGLESFATIPROC qglPNTrianglesfATI; @@ -588,7 +587,6 @@ void R_NetGraph (void); #define qglVertexAttribPointer glVertexAttribPointer #define qglViewport glViewport -#define qglStencilOpSeparateATI qglStencilOpSeparate #define qglGenFramebuffersEXT qglGenFramebuffers #define qglDeleteFramebuffersEXT qglDeleteFramebuffers #define qglBindFramebufferEXT qglBindFramebuffer diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index 073c5b123..a53d981d7 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -441,7 +441,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "tf = ftetransform();\n" "norm = v_normal;\n" "eye = e_eyepos - v_position.xyz;\n" -"gl_Position = tf;\n" +"gl_Position = ftetransform();\n" "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" @@ -7505,7 +7505,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "void main ()\n" "{\n" "vec3 t = texture2D(s_t0, tc).rgb;\n" -"t = vc.a * t/((vc.a-1)*t + 1);\n" +"t = vc.a * t/((vc.a-1.0)*t + 1.0);\n" "gl_FragColor = vec4(pow(t, vec3(vc.r))*vc.g + vc.b, 1.0);\n" "}\n" "#endif\n" diff --git a/engine/partcfgs/high.cfg b/engine/partcfgs/high.cfg index 67419d777..caf311741 100644 --- a/engine/partcfgs/high.cfg +++ b/engine/partcfgs/high.cfg @@ -441,7 +441,7 @@ r_part te_teleport scoord = ftetransform(); tcoord = (v_texcoord.st - 0.5)*2.0; alph = v_colour.a; - gl_Position = scoord; + gl_Position = ftetransform(); } #endif #ifdef FRAGMENT_SHADER diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 20cc918e5..b25f6512b 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -12552,7 +12552,7 @@ void PR_DumpPlatform_f(void) {"IE_KEYDOWN", "const float", CS, D("Specifies that a key was pressed. Second argument is the scan code. Third argument is the unicode (printable) char value. Fourth argument denotes which keyboard(or mouse, if its a mouse 'scan' key) the event came from. Note that some systems may completely separate scan codes and unicode values, with a 0 value for the unspecified argument."), CSIE_KEYDOWN}, {"IE_KEYUP", "const float", CS, D("Specifies that a key was released. Arguments are the same as IE_KEYDOWN. On some systems, this may be fired instantly after IE_KEYDOWN was fired."), CSIE_KEYUP}, - {"IE_MOUSEDELTA", "const float", CS, D("Specifies that a mouse was moved (touch screens and tablets typically give IE_MOUSEABS events instead, use _windowed_mouse 0 to test code to cope with either). Second argument is the X displacement, third argument is the Y displacement. Fourth argument is which mouse or touch event triggered the event."), CSIE_MOUSEDELTA}, + {"IE_MOUSEDELTA", "const float", CS, D("Specifies that a mouse was moved (touch screens and tablets typically give IE_MOUSEABS events instead, use in_windowed_mouse 0 to test code to cope with either). Second argument is the X displacement, third argument is the Y displacement. Fourth argument is which mouse or touch event triggered the event."), CSIE_MOUSEDELTA}, {"IE_MOUSEABS", "const float", CS, D("Specifies that a mouse cursor or touch event was moved to a specific location relative to the virtual screen space. Second argument is the new X position, third argument is the new Y position. Fourth argument is which mouse or touch event triggered the event."), CSIE_MOUSEABS}, {"IE_ACCELEROMETER", "const float", CS, NULL, CSIE_ACCELEROMETER}, {"IE_FOCUS", "const float", CS, D("Specifies that input focus was given. parama says mouse focus, paramb says keyboard focus. If either are -1, then it is unchanged."), CSIE_FOCUS}, diff --git a/engine/shaders/glsl/altwater.glsl b/engine/shaders/glsl/altwater.glsl index ca221c385..282a63841 100644 --- a/engine/shaders/glsl/altwater.glsl +++ b/engine/shaders/glsl/altwater.glsl @@ -83,7 +83,7 @@ void main (void) tf = ftetransform(); norm = v_normal; eye = e_eyepos - v_position.xyz; - gl_Position = tf; + gl_Position = ftetransform(); } #endif #ifdef FRAGMENT_SHADER diff --git a/engine/shaders/glsl/defaultgammacb.glsl b/engine/shaders/glsl/defaultgammacb.glsl index f1d44674c..0016679e6 100644 --- a/engine/shaders/glsl/defaultgammacb.glsl +++ b/engine/shaders/glsl/defaultgammacb.glsl @@ -19,7 +19,7 @@ void main () void main () { vec3 t = texture2D(s_t0, tc).rgb; - t = vc.a * t/((vc.a-1)*t + 1); + t = vc.a * t/((vc.a-1.0)*t + 1.0); gl_FragColor = vec4(pow(t, vec3(vc.r))*vc.g + vc.b, 1.0); } #endif diff --git a/engine/web/gl_vidweb.c b/engine/web/gl_vidweb.c index ca89b89d3..3077a8cf7 100644 --- a/engine/web/gl_vidweb.c +++ b/engine/web/gl_vidweb.c @@ -319,7 +319,7 @@ void GLVID_SwapBuffers (void) /* if (!vid_isfullscreen) { - if (!_windowed_mouse.value) + if (!in_windowed_mouse.value) { if (mouseactive) { @@ -352,7 +352,7 @@ void Sys_SendKeyEvents(void) { /*most callbacks happen outside our code, we don't need to poll for events - except for joysticks*/ qboolean shouldbefree = Key_MouseShouldBeFree(); - emscriptenfte_updatepointerlock(_windowed_mouse.ival && !shouldbefree, shouldbefree); + emscriptenfte_updatepointerlock(in_windowed_mouse.ival && !shouldbefree, shouldbefree); emscriptenfte_polljoyevents(); } /*various stuff for joysticks, which we don't support in this port*/