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