Try to fix up FTE's android port.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5445 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2019-04-15 18:43:42 +00:00
parent 12d3e48785
commit 3ee3230f96
38 changed files with 1475 additions and 444 deletions

View file

@ -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

View file

@ -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 <imagename> <placename> <x> <y> <zone> [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.");

View file

@ -2476,9 +2476,11 @@ static void SCR_ScreenShot_f (void)
return;
}
BZ_Free(rgbbuffer);
}
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)
{

View file

@ -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");
}

View file

@ -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

View file

@ -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;

View file

@ -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)
{

View file

@ -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();
}

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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"

View file

@ -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
{

View file

@ -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

View file

@ -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

189
engine/client/snd_opensl.c Normal file
View file

@ -0,0 +1,189 @@
#include "quakedef.h"
#include <SLES/OpenSLES.h>
#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
};

View file

@ -10,11 +10,21 @@
#include <sys/stat.h>
#include <dirent.h>
#include <pthread.h>
#include "glquake.h"
#ifndef ANDROID
#error ANDROID wasnt defined
#endif
#include <android/keycodes.h>
#include <android/native_window_jni.h>
//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;
// if (count < 0)
// count = 0;
// vibrateduration += count*10*sys_vibrate.value;
}
JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_motion(JNIEnv *env, jobject obj,
jint act, jint ptrid, jfloat x, jfloat y, jfloat size)
static int mapkey(int androidkey)
{
if (act)
IN_KeyEvent(ptrid, act==1, K_MOUSE1, 0);
switch(androidkey)
{
// 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);
}
return 0;
}
static int32_t engine_handle_input(struct android_app *app, AInputEvent *event)
{
switch(AInputEvent_getType(event))
{
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)
{
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
IN_MouseMove(ptrid, true, x, y, 0, size);
Host_RunFile(url, strlen(url), NULL);
(*jni)->ReleaseStringUTFChars(jni, data, url);
}
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);
}
//FIXME: do we need to release methodids/objects?
(*app->activity->vm)->DetachCurrentThread(app->activity->vm);
}
}
JNIEXPORT jint JNICALL Java_com_fteqw_FTEDroidEngine_frame(JNIEnv *env, jobject obj)
static qboolean read_apk_path(struct android_app *app, char *out, size_t outsize)
{
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)
qboolean res = false;
jobject act = app->activity->clazz;
JNIEnv *jni;
if (JNI_OK == (*app->activity->vm)->AttachCurrentThread(app->activity->vm, &jni, NULL))
{
Sys_Printf("Crashed: %s\n", errormessage);
return 8;
}
if (!sys_running)
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)
{
Sys_Printf("quit\n");
return 8;
res = true;
Q_strncpyz(out, tmp, outsize);
(*jni)->ReleaseStringUTFChars(jni, result, tmp);
}
// Sys_Printf("starting frame\n");
//FIXME: do we need to release methodids/objects?
(*app->activity->vm)->DetachCurrentThread(app->activity->vm);
}
#ifdef SERVERONLY
SV_Frame();
#else
unsigned int now = Sys_Milliseconds();
double tdelta = (now - sys_lastframe) * 0.001;
Host_Frame(tdelta);
sys_lastframe = now;
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
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;
}
//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 void FTENativeActivity_keypress(JNIEnv *env, jobject this, jint devid, jboolean down, jint keycode, jint unicode)
{
const char *fname = (*env)->GetStringUTFChars(env, openfile, NULL);
if (sys_running)
Host_RunFile(fname, strlen(fname), NULL);
(*env)->ReleaseStringUTFChars(env, openfile, fname);
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<<i))
IN_KeyEvent(devid, buttonbits&(1<<i), qbutton[i], 0);
}
}
static void FTENativeActivity_motion(JNIEnv *env, jobject this, jint ptrid, jint act, jfloat x, jfloat y, jfloat z, jfloat size)
{
// Sys_Printf("FTENativeActivity_motion: d=%i a=%i x=%f y=%f z=%f s=%f\n", ptrid, act, x, y, z, size);
switch(act)
{
case 2: //mouse down
case 3: //mouse up
IN_KeyEvent(ptrid, act==2, K_MOUSE1, 0);
break;
case 1: //relative motion
case 0: //absolute motion (android sucks)
IN_MouseMove(ptrid, act==0, x, y, z, size);
break;
};
}
static void FTENativeActivity_axis(JNIEnv *env, jobject this, jint devid, jint axis, jfloat value)
{
IN_JoystickAxisEvent(devid, axis, value);
}
//static void FTENativeActivity_accelerometer(JNIEnv *env, jobject obj, jint devid, jfloat x, jfloat y, jfloat z)
//{
// IN_Accelerometer(devid, x, y, z);
//}
//static void FTENativeActivity_gryoscope(JNIEnv *env, jobject obj, jint devid, jfloat pitch, jfloat yaw, jfloat roll)
//{
// IN_Gyroscope(devid, pitch, yaw, roll);
//}
static JNINativeMethod methods[] = {
{"keypress", "(IZII)V", FTENativeActivity_keypress},
{"mousepress", "(II)V", FTENativeActivity_mousepress},
{"motion", "(IIFFFF)V", FTENativeActivity_motion},
{"wantrelative", "()Z", FTENativeActivity_wantrelative}, //so the java code knows if it should use (often buggy) relative mouse movement or (limited) abs cursor coords.
{"axis", "(IIF)V", FTENativeActivity_axis},
// {"accelerometer", "(IFFF)V", FTENativeActivity_accelerometer},
// {"gyroscope", "(IFFF)V", FTENativeActivity_gyroscope},
};
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv *jni;
if (JNI_OK == (*vm)->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;
}
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)
void android_main(struct android_app *state)
{
const char *tmp;
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 (*errormessage)
return;
sys_dpi_x = dpix;
sys_dpi_y = dpiy;
if (!sys_running)
if (!host_initialized)
{
const char *args [] =
static const char *args [] =
{
"ftedroid",
"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)
{
unsigned int now = Sys_Milliseconds();
double tdelta = (now - sys_lastframe) * 0.001;
Host_Frame(tdelta);
sys_lastframe = now;
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.
}
sys_running = true;
Sys_Printf("Engine started\n");
for(;;)
{
int ident, events;
struct android_poll_source *source;
while((ident=ALooper_pollAll(vid.activeapp?0:250, NULL, &events, (void**)&source)) >= 0)
{
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);
}
}
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 <android/asset_manager.h>
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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -48,11 +48,6 @@ void Sys_ThreadAbort(void)
pthread_exit(NULL);
}
#ifdef ANDROID
#include <jni.h>
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;
}

View file

@ -4,15 +4,28 @@
android:versionCode="1"
android:versionName="1.05"
android:installLocation="auto">
<uses-sdk android:minSdkVersion="5" android:targetSdkVersion="8"/>
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="24"/>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
<!--
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".FTEDroidActivity"
<activity android:name=".FTEDroidFooBar"
android:label="@string/app_name"
android:configChanges="keyboardHidden|orientation">
-->
<!-- hack the comments to enable only one of the xml blocks above or below this comment -->
<!-- -->
<application android:icon="@drawable/icon" android:label="@string/app_name" android:hasCode="true">
<activity android:name="com.fteqw.FTENativeActivity"
android:label="@string/app_name"
android:configChanges="keyboardHidden|orientation|screenLayout">
<meta-data android:name="android.app.lib_name"
android:value="ftedroid" />
<!-- -->
<!-- launcher icon -->
<intent-filter>

View file

@ -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);
}*/
}

View file

@ -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();

View file

@ -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);

View file

@ -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");
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;
}

View file

@ -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;
}
EGL_ShowConfig(sys_display, config);
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);
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;

View file

@ -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

View file

@ -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.

View file

@ -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;

View file

@ -405,7 +405,7 @@ void GLVID_SwapBuffers (void)
if (!vid_isfullscreen)
{
if (!_windowed_mouse.value)
if (!in_windowed_mouse.value)
{
IN_DeactivateMouse ();
}

View file

@ -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 <GLES/gl.h>
#ifndef GL_CLIP_PLANE0
#define GL_CLIP_PLANE0 0x3000
#endif
#else
#include <GLES2/gl2.h>
#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

View file

@ -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"

View file

@ -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

View file

@ -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},

View file

@ -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

View file

@ -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

View file

@ -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*/