1 // Hyperbolic Rogue for Android
2 // Copyright (C) 2012-2018 Zeno Rogue
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.  See the
12 // GNU General Public License for more details.
13 
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 
18 #define ISANDROID 1
19 #define GL_ES
20 #define CAP_ACHIEVE 1
21 #define CAP_SHADER 1
22 #define CAP_VERTEXBUFFER 0
23 #define CAP_TIMEOFDAY 1
24 #define NO_STD_HYPOT
25 #define NOMAIN
26 
27 #define HNEW 1
28 
29 #define MOBPAR_FORMAL JNIEnv *env, jobject thiz
30 #define MOBPAR_ACTUAL env, thiz
31 
32 #include <android/log.h>
33 #include <stdio.h>
34 
35 char android_log_buf[1000000];
36 int android_log_bufpos = 0;
37 
38 FILE *slog;
39 
40 #define SPECIAL_LOGGER
41 
42 void special_log(char c);
43 
44 #include <jni.h>
45 #include <string>
46 
47 namespace hr {
48 std::string get_asset(const std::string &str);
49 void gdpush(int t);
50 
51 void shareScore(MOBPAR_FORMAL);
52 
53 const char *scorefile;
54 
55 bool settingsChanged = false;
56 
57 struct transmatrix getOrientation();
58 }
59 
60 #include "../../../../../hyper.cpp"
61 
special_log(char c)62 void special_log(char c) {
63   if(slog) fprintf(slog, "%c", c), fflush(slog); /*
64   if(c == 10 || android_log_bufpos == 999999) {
65     android_log_buf[android_log_bufpos] = 0;
66     __android_log_print(ANDROID_LOG_VERBOSE, "HRLOG", "%s", android_log_buf);
67     android_log_bufpos = 0;
68     }
69   else {
70     android_log_buf[android_log_bufpos++] = c;
71     } */
72   }
73 
74 
75 namespace hr {
76 
77 // #define delref env->DeleteLocalRef(_thiz)
78 
79 int semaphore = 0;
80 bool crash = false;
81 
82 #define LOCK(s, x) \
83   semaphore++; const char *xs = x; if(semaphore > 1) { crash = true; \
84     __android_log_print(ANDROID_LOG_WARN, "HyperRogue", "concurrency crash in %s\n", x); semaphore--; fflush(stdout); return s; }
85 #define UNLOCK semaphore--; if(crash) { crash = false; __android_log_print(ANDROID_LOG_WARN, "HyperRogue", "concurrency crashed with %s\n", xs); fflush(stdout); }
86 
87 
88 extern "C" jintArray
Java_com_roguetemple_hyperroid_HyperRogue_loadMap(MOBPAR_FORMAL)89 Java_com_roguetemple_hyperroid_HyperRogue_loadMap
90   ( MOBPAR_FORMAL)
91 {
92 //  if(debfile) fprintf(debfile, "loadmap started.\n"), fflush(debfile);
93     LOCK(NULL, "loadMap")
94 
95     jintArray result;
96     result = env->NewIntArray(isize(graphdata));
97     if(result == NULL) return NULL;
98 
99     env->SetIntArrayRegion(result, 0, isize(graphdata), &*graphdata.begin());
100     // delref;
101 //  env->DeleteLocalRef(result);
102 //  if(debfile) fprintf(debfile, "loadmap finished.\n"), fflush(debfile);
103 
104     UNLOCK
105     return result;
106 }
107 
108 extern "C" bool
Java_com_roguetemple_hyperroid_HyperRogue_captureBack(MOBPAR_FORMAL)109 Java_com_roguetemple_hyperroid_HyperRogue_captureBack
110   ( MOBPAR_FORMAL) {
111     if(cmode & sm::NORMAL) return false;
112     popScreenAll();
113     return true;
114   }
115 
116 void uploadAll(MOBPAR_FORMAL);
117 
118 extern "C" bool
Java_com_roguetemple_hyperroid_HyperRogue_keepinmemory(MOBPAR_FORMAL)119 Java_com_roguetemple_hyperroid_HyperRogue_keepinmemory
120   ( MOBPAR_FORMAL) {
121   if(!casual) saveStats(true);
122   uploadAll(MOBPAR_ACTUAL);
123   if(!canmove) return false;
124   if(items[itOrbSafety]) return false;
125   return gold() >= 10 || tkills() >= 50;
126   }
127 
128 extern "C" int
Java_com_roguetemple_hyperroid_HyperRogue_getland(MOBPAR_FORMAL)129 Java_com_roguetemple_hyperroid_HyperRogue_getland
130   ( MOBPAR_FORMAL)
131 {
132     return getCurrentLandForMusic();
133     }
134 
135 extern "C" int
Java_com_roguetemple_hyperroid_HyperRogue_getLanguage(MOBPAR_FORMAL)136 Java_com_roguetemple_hyperroid_HyperRogue_getLanguage
137   ( MOBPAR_FORMAL)
138 {
139     return vid.language;
140     }
141 
142 extern "C" int
Java_com_roguetemple_hyperroid_HyperRogue_getMusicVolume(MOBPAR_FORMAL)143 Java_com_roguetemple_hyperroid_HyperRogue_getMusicVolume
144   ( MOBPAR_FORMAL)
145 {
146     return musicvolume;
147     }
148 
149 extern "C" int
Java_com_roguetemple_hyperroid_HyperRogue_getEffVolume(MOBPAR_FORMAL)150 Java_com_roguetemple_hyperroid_HyperRogue_getEffVolume
151   ( MOBPAR_FORMAL)
152 {
153     return effvolume;
154     }
155 
156 extern "C" int
Java_com_roguetemple_hyperroid_HyperRogue_getImmersive(MOBPAR_FORMAL)157 Java_com_roguetemple_hyperroid_HyperRogue_getImmersive(MOBPAR_FORMAL)
158 {
159     return vid.full;
160     }
161 
162 extern "C" int
Java_com_roguetemple_hyperroid_HyperRogue_getGL(MOBPAR_FORMAL)163 Java_com_roguetemple_hyperroid_HyperRogue_getGL(MOBPAR_FORMAL)
164 {
165     return vid.usingGL;
166     }
167 
168 extern "C" void
Java_com_roguetemple_hyperroid_HyperRogue_glhrinit(MOBPAR_FORMAL)169 Java_com_roguetemple_hyperroid_HyperRogue_glhrinit(MOBPAR_FORMAL)
170 {
171     __android_log_print(ANDROID_LOG_WARN, "HyperRogue", "glhr::init %d\n", 0);
172     #if HNEW
173     // matched_programs get clobbered on activity destruction -- force their re-creation
174     if (!matched_programs.empty()) matched_programs.clear();
175     glhr::init();
176     #endif
177     __android_log_print(ANDROID_LOG_WARN, "HyperRogue", "glhr::init done %d\n", 0);
178     }
179 
180 extern "C" int
Java_com_roguetemple_hyperroid_HyperRogue_getaPosition(MOBPAR_FORMAL)181 Java_com_roguetemple_hyperroid_HyperRogue_getaPosition(MOBPAR_FORMAL)
182 {
183   return aPosition;
184   }
185 
186 extern "C" int
Java_com_roguetemple_hyperroid_HyperRogue_getaTexture(MOBPAR_FORMAL)187 Java_com_roguetemple_hyperroid_HyperRogue_getaTexture(MOBPAR_FORMAL)
188 {
189   return aTexture;
190   }
191 
192 extern "C" int
Java_com_roguetemple_hyperroid_HyperRogue_getuColor(MOBPAR_FORMAL)193 Java_com_roguetemple_hyperroid_HyperRogue_getuColor(MOBPAR_FORMAL)
194 {
195   return glhr::current_glprogram->uColor;
196   }
197 
198 string sscorefile, sconffile, scachefile;
199 
200 #include <sys/stat.h>
201 
202 extern "C" void
Java_com_roguetemple_hyperroid_HyperRogue_setFilesDir(MOBPAR_FORMAL,jstring dir)203 Java_com_roguetemple_hyperroid_HyperRogue_setFilesDir(MOBPAR_FORMAL, jstring dir)
204 {
205   const char *nativeString = env->GetStringUTFChars(dir, 0);
206   sscorefile = nativeString; sscorefile += "/hyperrogue.log";
207   sconffile = nativeString; sconffile += "/hyperrogue.ini";
208   scachefile = nativeString; scachefile += "/scorecache.txt";
209   levelfile = nativeString; levelfile += "/hyperrogue.lev";
210   picfile = nativeString; picfile += "/hyperrogue.pic";
211   scorefile = sscorefile.c_str();
212   conffile = sconffile.c_str();
213   chmod(scorefile, 0777);
214   chmod(conffile, 0777);
215   chmod(nativeString, 0777);
216   chmod((string(nativeString)+"/..").c_str(), 0777);
217   env->ReleaseStringUTFChars(dir, nativeString);
218   }
219 
220 bool gamerunning;
221 
222 extern "C"
223 jint
Java_com_roguetemple_hyperroid_HyperRogue_initGame(MOBPAR_FORMAL)224 Java_com_roguetemple_hyperroid_HyperRogue_initGame(MOBPAR_FORMAL) {
225 
226 //  debfile = fopen("/sdcard/hyperdebug.txt", "wt");
227 //  if(!debfile) debfile = fopen("/storage/simulated/0/hyperdebug.txt", "wt");
228 
229 //  if(debfile) fprintf(debfile, "initgame started.\n"), fflush(debfile);
230 
231 
232   __android_log_print(ANDROID_LOG_VERBOSE, "HyperRogue", "Initializing game, gamerunning = %d\n", gamerunning);
233   printf("test\n");
234   fflush(stdout);
235   if(gamerunning) return 1;
236   gamerunning = true;
237   initAll();
238   if(showstartmenu) pushScreen(showStartMenu);
239   uploadAll(MOBPAR_ACTUAL);
240   __android_log_print(ANDROID_LOG_VERBOSE, "HyperRogue", "Game initialized, gamerunning = %d\n", gamerunning);
241   return 0;
242   }
243 
244 JNIEnv *tw_env; jobject tw_thiz;
245 
get_asset(const string & str)246 string get_asset(const string &str) {
247   jclass cls = tw_env->GetObjectClass(tw_thiz);
248   jmethodID mid = tw_env->GetMethodID(cls, "getAsset", "(Ljava/lang/String;)[B");
249   jobject jstr = tw_env->NewStringUTF(str.c_str());
250   jbyteArray arr = (jbyteArray) tw_env->CallObjectMethod(tw_thiz, mid, jstr);
251   tw_env->DeleteLocalRef(jstr);
252   tw_env->DeleteLocalRef(cls);
253   jsize len = tw_env->GetArrayLength(arr);
254   jbyte* data = tw_env->GetByteArrayElements(arr, NULL);
255   string s((char*) & (data[0]), len);
256   tw_env->DeleteLocalRef(arr);
257   return s;
258   }
259 
textwidth(int siz,const string & str)260 int textwidth(int siz, const string &str) {
261   jclass cls = tw_env->GetObjectClass(tw_thiz);
262   jmethodID mid = tw_env->GetMethodID(cls, "getTextWidth", "(Ljava/lang/String;I)I");
263   jobject jstr = tw_env->NewStringUTF(str.c_str());
264   int res = tw_env->CallIntMethod(tw_thiz, mid, jstr, siz);
265   tw_env->DeleteLocalRef(jstr);
266   tw_env->DeleteLocalRef(cls);
267   return res;
268   }
269 
270 bool achievementsConnected = false;
271 string doViewLeaderboard;
272 bool doViewAchievements;
273 bool doOpenURL;
274 
currentlyConnecting()275 bool currentlyConnecting() { return false; }
currentlyConnected()276 bool currentlyConnected() { return false; }
277 
viewLeaderboard(string what)278 void viewLeaderboard(string what) { doViewLeaderboard = what; }
viewAchievements()279 void viewAchievements() { doViewAchievements = true; }
280 
281 vector<pair<int, int> > scoresToUpload;
282 vector<const char *> achievementsToUpload;
283 vector<pair<string, int> > soundsToPlay;
284 
openURL()285 void openURL() {
286   doOpenURL = true;
287   }
288 
289 int last_upload[NUMLEADER];
290 
shareScore(MOBPAR_FORMAL)291 void shareScore(MOBPAR_FORMAL) {
292   string s = buildScoreDescription();
293   jclass cls = env->GetObjectClass(thiz);
294   jmethodID mid = env->GetMethodID(cls, "shareScore", "(Ljava/lang/String;)V");
295   jobject str = env->NewStringUTF(s.c_str());
296   env->CallVoidMethod(thiz, mid, str);
297   env->DeleteLocalRef(str);
298   env->DeleteLocalRef(cls);
299   }
300 
Java_com_roguetemple_hyperroid_HyperRogue_draw(MOBPAR_FORMAL)301 extern "C" void Java_com_roguetemple_hyperroid_HyperRogue_draw(MOBPAR_FORMAL) {
302 //  if(debfile) fprintf(debfile, "draw started.\n"), fflush(debfile);
303 
304   LOCK(, "draw")
305   /* static int infoticks;
306   if(getticks() - infoticks > 10000 && !timerghost)  {
307     addMessage("ticks: " + its(getticks()));
308     infoticks = getticks();
309     } */
310   tw_thiz = thiz; tw_env = env;
311 
312   #if HNEW
313   glhr::be_textured();
314   glhr::be_nontextured();
315 
316   #if CAP_SHADER
317   glEnableVertexAttribArray(aPosition);
318   #else
319   glEnableClientState(GL_VERTEX_ARRAY);
320   #endif
321   #endif
322 
323   mobile_draw(MOBPAR_ACTUAL);
324   uploadAll(MOBPAR_ACTUAL);
325 
326   #if HNEW
327   // text is drawn with 'textured'
328   dynamicval<eModel> p(pmodel, mdManual);
329   current_display->next_shader_flags = GF_TEXTURE;
330   current_display->set_all(0, 0);
331   glhr::set_depthtest(false);
332   current_display->set_viewport(0);
333   current_display->set_mask(0);
334   glhr::new_projection();
335   glhr::projection_multiply(glhr::translate(-1,-1,0));
336   glhr::projection_multiply(glhr::ortho(vid.xres/2, vid.yres/2, 1));
337   glhr::set_modelview(glhr::id);
338     glhr::color2(0xC08040F0);
339   #endif
340 
341   UNLOCK
342   }
343 
Java_com_roguetemple_hyperroid_HyperRogue_drawScreenshot(MOBPAR_FORMAL)344 extern "C" void Java_com_roguetemple_hyperroid_HyperRogue_drawScreenshot(MOBPAR_FORMAL) {
345   dynamicval<bool> d(vid.usingGL, false);
346   Java_com_roguetemple_hyperroid_HyperRogue_draw(MOBPAR_ACTUAL);
347   }
348 
Java_com_roguetemple_hyperroid_HyperRogue_handleKey(MOBPAR_FORMAL,jint keycode)349 extern "C" void Java_com_roguetemple_hyperroid_HyperRogue_handleKey(MOBPAR_FORMAL, jint keycode) {
350   flashMessages(); mousing = false;
351   handlekey(keycode, keycode);
352   }
353 
Java_com_roguetemple_hyperroid_HyperRogue_update(MOBPAR_FORMAL,jint xres,jint yres,jint _ticks,jint _mousex,jint _mousey,jboolean _clicked)354 extern "C" void Java_com_roguetemple_hyperroid_HyperRogue_update
355   ( MOBPAR_FORMAL,
356     jint xres, jint yres, jint _ticks,
357     jint _mousex, jint _mousey, jboolean _clicked) {
358 
359   LOCK(, "update")
360 
361 //  if(debfile) fprintf(debfile, "update started.\n"), fflush(debfile);
362 
363   if(xres != vid.xres || yres != vid.yres)
364     vid.killreduction = 0;
365 
366   vid.xres = xres;
367   vid.yres = yres;
368   vid.fsize = (min(vid.xres, vid.yres) * vid.fontscale + 50) / 3200;
369 
370   mousex = _mousex;
371   mousey = _mousey;
372   clicked = _clicked;
373   uploadAll(MOBPAR_ACTUAL);
374   UNLOCK
375   // delref;
376 //  if(debfile) fprintf(debfile, "update stopped.\n"), fflush(debfile);
377   }
378 
resetmusic()379 void resetmusic() {}
380 
playSound(cell * c,const string & fname,int vol)381 void playSound(cell *c, const string& fname, int vol) {
382   LATE( hr::playSound(c, fname, vol); )
383   soundsToPlay.push_back(make_pair(fname, vol));
384   }
385 
386 transmatrix orientation = Id;
387 bool orientation_requested;
388 
getOrientation()389 transmatrix getOrientation() {
390   orientation_requested = true;
391   return orientation;
392   }
393 
uploadAll(JNIEnv * env,jobject thiz)394 void uploadAll(JNIEnv *env, jobject thiz) {
395 
396   jclass cls = env->GetObjectClass(thiz);
397 
398   if(orientation_requested) {
399     jmethodID mid = env->GetMethodID(cls, "getOrientation", "(II)D");
400     for(int i=0; i<3; i++)
401     for(int j=0; j<3; j++)
402       orientation[i][j] = env->CallDoubleMethod(thiz, mid, i, j);
403     for(int i=0; i<3; i++)
404       orientation[i][3] = orientation[3][i] = 0;
405     orientation[3][3] = 1;
406     orientation_requested = false;
407     }
408 
409   for(int i=0; i<isize(soundsToPlay); i++) {
410     jmethodID mid = env->GetMethodID(cls, "playSound", "(Ljava/lang/String;I)V");
411     jobject str = env->NewStringUTF(soundsToPlay[i].first.c_str());
412     env->CallVoidMethod(thiz, mid, str, soundsToPlay[i].second);
413     env->DeleteLocalRef(str);
414     }
415   soundsToPlay.clear();
416 
417   if(settingsChanged) {
418     jmethodID mid = env->GetMethodID(cls, "applyUserSettings", "()V");
419     env->CallVoidMethod(thiz, mid);
420     settingsChanged = false;
421     }
422 
423   if(doOpenURL) {
424     jmethodID mid = env->GetMethodID(cls, "openWebsite", "()V");
425     env->CallVoidMethod(thiz, mid);
426     doOpenURL = false;
427     }
428 
429   env->DeleteLocalRef(cls);
430   }
431 
achievement_init()432 void achievement_init() {}
achievement_close()433 void achievement_close() {}
achievement_gain(const char * s,char flags)434 void achievement_gain(const char* s, char flags) {}
435 
436 }
437 
438