Home | History | Annotate | Download | only in jni
      1 /*
      2 Copyright (C) 1996-1997 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 
     21 // System functions for Android OS.
     22 // Based on sys_linux.c
     23 
     24 #include <unistd.h>
     25 #include <signal.h>
     26 #include <stdlib.h>
     27 #include <limits.h>
     28 #include <sys/time.h>
     29 #include <sys/types.h>
     30 #include <unistd.h>
     31 #include <fcntl.h>
     32 #include <stdarg.h>
     33 #include <stdio.h>
     34 // #include <sys/ipc.h>
     35 // #include <sys/shm.h>
     36 #include <sys/stat.h>
     37 #include <string.h>
     38 #include <ctype.h>
     39 #include <sys/wait.h>
     40 #include <sys/mman.h>
     41 #include <errno.h>
     42 #include <dirent.h>
     43 
     44 #include <android/log.h>
     45 
     46 #include "quakedef.h"
     47 
     48 #define LOG_TAG "Quake sys_android"
     49 #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
     50 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
     51 
     52 qboolean			isDedicated;
     53 
     54 int noconinput = 0;
     55 int nostdout = 0;
     56 
     57 // Look for data on either the sdcard or the internal data store.
     58 // (We look at the sdcard first
     59 
     60 static const char *basedir1 = "/sdcard/data/quake";
     61 static const char *basedir2 = "/data/quake";
     62 
     63 static const char *cachedir = "/tmp";
     64 
     65 cvar_t  sys_linerefresh = CVAR2("sys_linerefresh","0");// set for entity display
     66 
     67 // =======================================================================
     68 // General routines
     69 // =======================================================================
     70 
     71 void Sys_DebugNumber(int y, int val)
     72 {
     73 }
     74 
     75 /*
     76 void Sys_Printf (char *fmt, ...)
     77 {
     78   va_list		argptr;
     79   char		text[1024];
     80 
     81   va_start (argptr,fmt);
     82   vsprintf (text,fmt,argptr);
     83   va_end (argptr);
     84   fprintf(stderr, "%s", text);
     85 
     86   Con_Print (text);
     87 }
     88 
     89 void Sys_Printf (char *fmt, ...)
     90 {
     91 
     92     va_list     argptr;
     93     char        text[1024], *t_p;
     94     int         l, r;
     95 
     96     if (nostdout)
     97         return;
     98 
     99     va_start (argptr,fmt);
    100     vsprintf (text,fmt,argptr);
    101     va_end (argptr);
    102 
    103     l = strlen(text);
    104     t_p = text;
    105 
    106 // make sure everything goes through, even though we are non-blocking
    107     while (l)
    108     {
    109         r = write (1, text, l);
    110         if (r != l)
    111             sleep (0);
    112         if (r > 0)
    113         {
    114             t_p += r;
    115             l -= r;
    116         }
    117     }
    118 
    119 }
    120 */
    121 
    122 #define USE_PMPEVENT
    123 
    124 void Sys_Printf (const char *fmt, ...)
    125 {
    126   va_list		argptr;
    127   char		text[2048];
    128   unsigned char		*p;
    129 
    130   va_start (argptr,fmt);
    131   vsnprintf (text, sizeof(text), fmt,argptr);
    132   va_end (argptr);
    133 
    134   text[sizeof(text)-1] = 0;
    135   LOGI("%s", text);
    136 
    137 #ifdef USE_PMPEVENT
    138     PMPEVENT(("%s", text));
    139 #else
    140     if (nostdout)
    141         return;
    142 
    143   for (p = (unsigned char *)text; *p; p++)
    144     if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9)
    145       printf("[%02x]", *p);
    146     else
    147       putc(*p, stdout);
    148 #endif
    149 }
    150 
    151 qboolean soft_quit;
    152 
    153 void Sys_Quit (void)
    154 {
    155   Host_Shutdown();
    156 #ifdef USE_PMPEVENT
    157   PMPERROR(("Sys_Quit - exiting."));
    158 #else
    159   printf("Sys_Quit - exiting.\n");
    160 #endif
    161     // fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
    162   if (soft_quit) {
    163     return;
    164   }
    165     exit(0);
    166 }
    167 
    168 void Sys_Init(void)
    169 {
    170 
    171 }
    172 
    173 void Sys_Error (const char *error, ...)
    174 {
    175     va_list     argptr;
    176     char        string[1024];
    177 
    178 // change stdin to non blocking
    179     // fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
    180 
    181     va_start (argptr,error);
    182     vsprintf (string,error,argptr);
    183     va_end (argptr);
    184 #ifdef USE_PMPEVENT
    185   PMPERROR(("Error: %s\n", string));
    186 #else
    187   fprintf(stderr, "Error: %s\n", string);
    188 #endif
    189   Host_Shutdown ();
    190 #ifdef USE_PMPEVENT
    191   PMPERROR(("Sys_Error - exiting."));
    192 #else
    193   printf("Sys_Error - exiting.\n");
    194 #endif
    195   exit (1);
    196 
    197 }
    198 
    199 void Sys_Warn (const char *warning, ...)
    200 {
    201     va_list     argptr;
    202     char        string[1024];
    203 
    204     va_start (argptr,warning);
    205     vsprintf (string,warning,argptr);
    206     va_end (argptr);
    207 #ifdef USE_PMPEVENT
    208   PMPWARNING(("Warning: %s", string));
    209 #else
    210   fprintf(stderr, "Warning: %s\n", string);
    211 #endif
    212 }
    213 
    214 /*
    215 ============
    216 Sys_FileTime
    217 
    218 returns -1 if not present
    219 ============
    220 */
    221 int	Sys_FileTime (const char *path)
    222 {
    223   struct	stat	buf;
    224 
    225   if (stat (path,&buf) == -1)
    226     return -1;
    227 
    228   return buf.st_mtime;
    229 }
    230 
    231 
    232 void Sys_mkdir (const char *path)
    233 {
    234     mkdir (path, 0777);
    235 }
    236 
    237 int Sys_FileOpenRead (const char *path, int *handle)
    238 {
    239   int	h;
    240   struct stat	fileinfo;
    241 
    242 
    243   h = open (path, O_RDONLY, 0666);
    244   *handle = h;
    245   if (h == -1)
    246     return -1;
    247 
    248   if (fstat (h,&fileinfo) == -1)
    249     Sys_Error ("Error fstating %s", path);
    250 
    251   return fileinfo.st_size;
    252 }
    253 
    254 int Sys_FileOpenWrite (const char *path)
    255 {
    256   int     handle;
    257 
    258   umask (0);
    259 
    260   handle = open(path,O_RDWR | O_CREAT | O_TRUNC
    261   , 0666);
    262 
    263   if (handle == -1)
    264     Sys_Error ("Error opening %s: %s", path,strerror(errno));
    265 
    266   return handle;
    267 }
    268 
    269 int Sys_FileWrite (int handle, const void *src, int count)
    270 {
    271   return write (handle, src, count);
    272 }
    273 
    274 void Sys_FileClose (int handle)
    275 {
    276   close (handle);
    277 }
    278 
    279 void Sys_FileSeek (int handle, int position)
    280 {
    281   lseek (handle, position, SEEK_SET);
    282 }
    283 
    284 int Sys_FileRead (int handle, void *dest, int count)
    285 {
    286     return read (handle, dest, count);
    287 }
    288 
    289 void Sys_DebugLog(const char *file, char *fmt, ...)
    290 {
    291     va_list argptr;
    292     static char data[1024];
    293     int fd;
    294 
    295     va_start(argptr, fmt);
    296     vsprintf(data, fmt, argptr);
    297     va_end(argptr);
    298 //    fd = open(file, O_WRONLY | O_BINARY | O_CREAT | O_APPEND, 0666);
    299     fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);
    300     write(fd, data, strlen(data));
    301     close(fd);
    302 }
    303 
    304 void Sys_EditFile(const char *filename)
    305 {
    306 
    307   char cmd[256];
    308   char *term;
    309   const char *editor;
    310 
    311   term = getenv("TERM");
    312   if (term && !strcmp(term, "xterm"))
    313   {
    314     editor = getenv("VISUAL");
    315     if (!editor)
    316       editor = getenv("EDITOR");
    317     if (!editor)
    318       editor = getenv("EDIT");
    319     if (!editor)
    320       editor = "vi";
    321     sprintf(cmd, "xterm -e %s %s", editor, filename);
    322     system(cmd);
    323   }
    324 
    325 }
    326 
    327 double Sys_FloatTime (void)
    328 {
    329     struct timeval tp;
    330     struct timezone tzp;
    331     static int      secbase;
    332 
    333     gettimeofday(&tp, &tzp);
    334 
    335     if (!secbase)
    336     {
    337         secbase = tp.tv_sec;
    338         return tp.tv_usec/1000000.0;
    339     }
    340 
    341     return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
    342 }
    343 
    344 // =======================================================================
    345 // Sleeps for microseconds
    346 // =======================================================================
    347 
    348 static volatile int oktogo;
    349 
    350 void alarm_handler(int x)
    351 {
    352   oktogo=1;
    353 }
    354 
    355 void Sys_LineRefresh(void)
    356 {
    357 }
    358 
    359 void floating_point_exception_handler(int whatever)
    360 {
    361 //	Sys_Warn("floating point exception\n");
    362   signal(SIGFPE, floating_point_exception_handler);
    363 }
    364 
    365 char *Sys_ConsoleInput(void)
    366 {
    367 #if 0
    368     static char text[256];
    369     int     len;
    370 
    371   if (cls.state == ca_dedicated) {
    372     len = read (0, text, sizeof(text));
    373     if (len < 1)
    374       return NULL;
    375     text[len-1] = 0;    // rip off the /n and terminate
    376 
    377     return text;
    378   }
    379 #endif
    380   return NULL;
    381 }
    382 
    383 #if !id386
    384 void Sys_HighFPPrecision (void)
    385 {
    386 }
    387 
    388 void Sys_LowFPPrecision (void)
    389 {
    390 }
    391 #endif
    392 
    393 int		skipframes;
    394 
    395 // The following APIs are called from the Java activity
    396 
    397 double g_oldtime;
    398 
    399 extern int scr_width;
    400 extern int scr_height;
    401 
    402 qboolean direxists(const char* path)
    403 {
    404   struct stat sb;
    405   if(stat(path, &sb))
    406   {
    407     return 0;	// error
    408   }
    409   if(sb.st_mode & S_IFDIR)
    410   {
    411      return 1;
    412   }
    413   return 0;
    414 }
    415 
    416 // Remove all files in path. Recurses into subdirectories
    417 
    418 void rmDir(const char* path) {
    419   DIR* dir = opendir(path);
    420   if(!dir) {
    421     return;
    422   }
    423   struct dirent * dp;
    424   while((dp = readdir(dir)) != NULL) {
    425     const char* name = dp->d_name;
    426     if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
    427       continue;
    428     }
    429     char filePath[1024];
    430     if ((int) (sizeof(filePath)-1) < snprintf(filePath, sizeof(filePath), "%s/%s", path, name)) {
    431       continue; // buffer overflow
    432     }
    433     if(direxists(filePath)) {
    434       rmDir(filePath);
    435     }
    436     else {
    437       unlink(filePath);
    438     }
    439   }
    440   closedir(dir);
    441   rmdir(path);
    442 }
    443 
    444 // Increment this number whenever the data format of any of the files stored in glquake changes:
    445 
    446 typedef unsigned long GLCacheVersion;
    447 
    448 static const GLCacheVersion kCurrentCacheVersion = 0x3a914000; // The numbers mean nothing special
    449 
    450 // #define FORCE_INVALIDATE_CACHE // Useful for testing
    451 
    452 #define GLQUAKE_RELPATH "/id1/glquake"
    453 void CheckGLCacheVersion(const char* baseDir)
    454 {
    455   char cachePath[1024];
    456   if ((int) (sizeof(cachePath)-1) < snprintf(cachePath, sizeof(cachePath), "%s" GLQUAKE_RELPATH "/cacheversion", baseDir)) {
    457     return; // buffer overflow
    458   }
    459   bool validCache = false;
    460   {
    461     GLCacheVersion vernum = 0;
    462     FILE* f = fopen(cachePath, "rb");
    463     if (f) {
    464       if (1 == fread(&vernum, sizeof(vernum), 1, f)) {
    465         if (vernum == kCurrentCacheVersion) {
    466           validCache = true;
    467         }
    468       }
    469       fclose(f);
    470     }
    471   }
    472 
    473 #ifdef FORCE_INVALIDATE_CACHE
    474   validCache = false;
    475 #endif
    476 
    477   if(!validCache) {
    478     PMPLOG(("Invalidating glquake cache."));
    479     char cacheDirPath[1024];
    480     if ( (int)(sizeof(cacheDirPath)-1) < snprintf(cacheDirPath, sizeof(cacheDirPath), "%s" GLQUAKE_RELPATH, baseDir)) {
    481       return; // Ran out ot memory
    482     }
    483     rmDir(cacheDirPath);
    484     Sys_mkdir(cacheDirPath);
    485     FILE* f = fopen(cachePath, "wb");
    486     if (f) {
    487       GLCacheVersion vernum = kCurrentCacheVersion;
    488       fwrite(&vernum, sizeof(vernum), 1, f);
    489       fclose(f);
    490     } else {
    491         PMPLOG(("Could not write %s %d.\n", cachePath, errno));
    492     }
    493   }
    494 }
    495 
    496 static int gArgc;
    497 static char** gArgv;
    498 
    499 void AndroidInitArgs(int argc, char** argv) {
    500     gArgc = argc;
    501     gArgv = argv;
    502 }
    503 
    504 static qboolean gDoubleInitializeGuard;
    505 static qboolean gInitialized;
    506 void GL_ReInit();
    507 
    508 #if !defined(__clang__)
    509 bool AndroidInit()
    510 #else
    511 extern "C" bool AndroidInit_LLVM()
    512 #endif
    513 {
    514   PMPLOG(("AndroidInit"));
    515 
    516   PMPLOG(("This function was compiled on " __DATE__ " at " __TIME__));
    517 
    518   if (gDoubleInitializeGuard && gInitialized)
    519   {
    520     GL_ReInit();
    521   }
    522 
    523   gDoubleInitializeGuard = true;
    524   return true;
    525 }
    526 
    527 
    528 // Note: Needs a valid OpenGL context
    529 
    530 void AndroidInit2(int width, int height)
    531 {
    532   PMPLOG(("AndroidInit2 %d,%d", width, height));
    533 
    534   gInitialized = true;
    535   PMPBEGIN(("AndroidInit2"));
    536   quakeparms_t parms;
    537   int j;
    538   int c = 0;
    539   const char* v[] = {"quake", (char*) 0};
    540 
    541   scr_width = width;
    542   scr_height = height;
    543 
    544 //	static char cwd[1024];
    545 
    546 //	signal(SIGFPE, floating_point_exception_handler);
    547 //  signal(SIGFPE, SIG_IGN);
    548 
    549   memset(&parms, 0, sizeof(parms));
    550 
    551   if (gArgc) {
    552       COM_InitArgv(gArgc, (const char**) gArgv);
    553   }
    554   else {
    555       COM_InitArgv(c, (const char**) v);
    556   }
    557 
    558   parms.argc = com_argc;
    559   parms.argv = com_argv;
    560 
    561   parms.memsize = 16*1024*1024;
    562 
    563   j = COM_CheckParm("-mem");
    564   if (j)
    565     parms.memsize = (int) (Q_atof(com_argv[j+1]) * 1024 * 1024);
    566   parms.membase = malloc (parms.memsize);
    567 
    568   const char* basedir = basedir2;
    569   if(direxists(basedir1))
    570   {
    571     basedir = basedir1;
    572   }
    573   else if(direxists(basedir2))
    574   {
    575     basedir = basedir2;
    576   }
    577   else
    578   {
    579     Sys_Error("Could not find data directories %s or %s", basedir1, basedir2);
    580   }
    581   parms.basedir = basedir;
    582 
    583   CheckGLCacheVersion(basedir);
    584 
    585 // caching is disabled by default, use -cachedir to enable
    586 //	parms.cachedir = cachedir;
    587 
    588 #if 0 // FNDELAY not implemented
    589   noconinput = COM_CheckParm("-noconinput");
    590   if (!noconinput)
    591     fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
    592 #endif
    593 
    594   if (COM_CheckParm("-nostdout"))
    595     nostdout = 1;
    596 
    597   Sys_Init();
    598 
    599     Host_Init(&parms);
    600 
    601     g_oldtime = Sys_FloatTime ();
    602   PMPEND(("AndroidInit2"));
    603 }
    604 
    605 static int currentFrame;
    606 frameTime fastestFrame;
    607 frameTime slowestFrame;
    608 
    609 void InitFrameTimes()
    610 {
    611     currentFrame = 0;
    612   fastestFrame.time = 1e6;
    613   fastestFrame.frame = 0;
    614   slowestFrame.time = -1;
    615   slowestFrame.frame = 0;
    616 }
    617 
    618 static void UpdateFrameTimes(float time)
    619 {
    620     if (currentFrame > 0) {
    621 
    622     if (fastestFrame.time > time) {
    623       fastestFrame.time = time;
    624       fastestFrame.frame = currentFrame;
    625     }
    626     if (slowestFrame.time < time) {
    627       slowestFrame.time = time;
    628       slowestFrame.frame = currentFrame;
    629     }
    630   }
    631   currentFrame++;
    632 }
    633 
    634 int AndroidStepImp(int width, int height)
    635 {
    636   // PMPBEGIN(("AndroidStep"));
    637   double time, newtime;
    638   static int TotalCount = 0;
    639   static double TotalFPS = 0.0;
    640   if(!gInitialized)
    641     AndroidInit2(width, height);
    642 
    643   scr_width = width;
    644   scr_height = height;
    645 
    646   // find time spent rendering last frame
    647   newtime = Sys_FloatTime ();
    648   time = newtime - g_oldtime;
    649 
    650   UpdateFrameTimes(time);
    651  #if 0
    652    // Disable the following because given a series of Ti representing time spent per frame
    653    // 1/(sum(Ti)/n) isn't quite the same as sum(1/Ti)/n, especially when Ti has large variance.
    654    // See LOGI in host.cpp::Host_Frame for better implementation
    655   double fps = 1.0/time;
    656   if (fps > 0.0 && fps < 200.0) { // Sometimes it
    657     TotalCount += 1;
    658     TotalFPS += fps;
    659     LOGI("Quake fps: %3.2lf, Average: %3.2lf", fps, TotalFPS/TotalCount);
    660   }
    661  #endif
    662   Host_Frame(time);
    663   g_oldtime = newtime;
    664   // PMPEND(("AndroidStep"));
    665   return key_dest == key_game;
    666 }
    667 
    668 #if !defined(__clang__)
    669 int AndroidStep(int width, int height)
    670 #else
    671 extern "C" int AndroidStep_LLVM(int width, int height)
    672 #endif
    673 {
    674   for(;;) {
    675     host_framethrottled = false;
    676     int result = AndroidStepImp(width, height);
    677     if (!host_framethrottled) {
    678         return result;
    679     }
    680     usleep(1000);
    681     //LOGI("%s", "host_framethrottled");
    682   }
    683 }
    684 
    685 extern void Host_Quit();
    686 
    687 
    688 #if !defined(__clang__)
    689 void AndroidQuit() {
    690 #else
    691 extern "C" void AndroidQuit_LLVM() {
    692 #endif
    693   soft_quit = true;
    694   Host_Quit();
    695   soft_quit = false; // In case we live on after returning.
    696 }
    697