• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Sys_DebugNumber(int y,int val)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 
Sys_Printf(const char * fmt,...)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 
Sys_Quit(void)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 
Sys_Init(void)168 void Sys_Init(void)
169 {
170 
171 }
172 
Sys_Error(const char * error,...)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 
Sys_Warn(const char * warning,...)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 */
Sys_FileTime(const char * path)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 
Sys_mkdir(const char * path)232 void Sys_mkdir (const char *path)
233 {
234     mkdir (path, 0777);
235 }
236 
Sys_FileOpenRead(const char * path,int * handle)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 
Sys_FileOpenWrite(const char * path)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 
Sys_FileWrite(int handle,const void * src,int count)269 int Sys_FileWrite (int handle, const void *src, int count)
270 {
271   return write (handle, src, count);
272 }
273 
Sys_FileClose(int handle)274 void Sys_FileClose (int handle)
275 {
276   close (handle);
277 }
278 
Sys_FileSeek(int handle,int position)279 void Sys_FileSeek (int handle, int position)
280 {
281   lseek (handle, position, SEEK_SET);
282 }
283 
Sys_FileRead(int handle,void * dest,int count)284 int Sys_FileRead (int handle, void *dest, int count)
285 {
286     return read (handle, dest, count);
287 }
288 
Sys_DebugLog(const char * file,char * fmt,...)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 
Sys_EditFile(const char * filename)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 
Sys_FloatTime(void)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 
alarm_handler(int x)350 void alarm_handler(int x)
351 {
352   oktogo=1;
353 }
354 
Sys_LineRefresh(void)355 void Sys_LineRefresh(void)
356 {
357 }
358 
floating_point_exception_handler(int whatever)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 
Sys_ConsoleInput(void)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
Sys_HighFPPrecision(void)384 void Sys_HighFPPrecision (void)
385 {
386 }
387 
Sys_LowFPPrecision(void)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 
direxists(const char * path)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 
rmDir(const char * path)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"
CheckGLCacheVersion(const char * baseDir)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 
AndroidInitArgs(int argc,char ** argv)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__)
AndroidInit()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 
AndroidInit2(int width,int height)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 
InitFrameTimes()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 
UpdateFrameTimes(float time)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 
AndroidStepImp(int width,int height)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__)
AndroidStep(int width,int height)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__)
AndroidQuit()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