• 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 <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 
Sys_DebugNumber(int y,int val)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 
Sys_Printf(const char * fmt,...)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 
Sys_Quit(void)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 
Sys_Init(void)163 void Sys_Init(void)
164 {
165 
166 }
167 
Sys_Error(const char * error,...)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 
Sys_Warn(const char * warning,...)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 */
Sys_FileTime(const char * path)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 
Sys_mkdir(const char * path)227 void Sys_mkdir (const char *path)
228 {
229     mkdir (path, 0777);
230 }
231 
Sys_FileOpenRead(const char * path,int * handle)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 
Sys_FileOpenWrite(const char * path)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 
Sys_FileWrite(int handle,const void * src,int count)264 int Sys_FileWrite (int handle, const void *src, int count)
265 {
266   return write (handle, src, count);
267 }
268 
Sys_FileClose(int handle)269 void Sys_FileClose (int handle)
270 {
271   close (handle);
272 }
273 
Sys_FileSeek(int handle,int position)274 void Sys_FileSeek (int handle, int position)
275 {
276   lseek (handle, position, SEEK_SET);
277 }
278 
Sys_FileRead(int handle,void * dest,int count)279 int Sys_FileRead (int handle, void *dest, int count)
280 {
281     return read (handle, dest, count);
282 }
283 
Sys_DebugLog(const char * file,char * fmt,...)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 
Sys_EditFile(const char * filename)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 
Sys_FloatTime(void)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 
alarm_handler(int x)345 void alarm_handler(int x)
346 {
347   oktogo=1;
348 }
349 
Sys_LineRefresh(void)350 void Sys_LineRefresh(void)
351 {
352 }
353 
floating_point_exception_handler(int whatever)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 
Sys_ConsoleInput(void)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
Sys_HighFPPrecision(void)379 void Sys_HighFPPrecision (void)
380 {
381 }
382 
Sys_LowFPPrecision(void)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 
direxists(const char * path)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 
rmDir(const char * path)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"
CheckGLCacheVersion(const char * baseDir)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 
AndroidInitArgs(int argc,char ** argv)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 
AndroidInit()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 
AndroidInit2(int width,int height)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 
InitFrameTimes()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 
UpdateFrameTimes(float time)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 
AndroidStepImp(int width,int height)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 
AndroidStep(int width,int height)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();
AndroidQuit()661 void AndroidQuit() {
662   soft_quit = true;
663   Host_Quit();
664   soft_quit = false; // In case we live on after returning.
665 }
666