*/}}
Przeglądaj źródła

Android support

YimingWu 6 miesięcy temu
rodzic
commit
e4308002bf
14 zmienionych plików z 493 dodań i 89 usunięć
  1. 2 1
      CMakeLists.txt
  2. 4 0
      la_5.h
  3. 3 0
      la_data.c
  4. 0 1
      la_data.h
  5. 31 0
      la_interface.h
  6. 307 18
      la_kernel.c
  7. 64 28
      la_tns_kernel.c
  8. 36 8
      la_util.c
  9. 22 15
      la_util.h
  10. 1 1
      resources/la_modelling.c
  11. 9 9
      resources/la_operators.c
  12. 1 1
      resources/la_properties.c
  13. 5 5
      resources/la_widgets.c
  14. 8 2
      resources/la_widgets_viewers.c

+ 2 - 1
CMakeLists.txt

@@ -32,7 +32,7 @@ if((${LuaJIT_FOUND}) AND (${LAGUI_USE_LUAJIT}))
 endif()
 
 SET(LAGUI_USE_PNG true CACHE BOOL "Whether to use PNG in LaGUI")
-if((${PNG_FOUND}) AND (${LAGUI_USE_PNG}))
+if(${LAGUI_USE_PNG})
     add_definitions(-DLA_WITH_PNG)
 endif()
 
@@ -57,6 +57,7 @@ add_definitions(-DLAGUI_FONT_CUSTOM_PATH=\"${LAGUI_FONT_CUSTOM_PATH}\")
 add_definitions(-w)
 
 if(${LAGUI_ANDROID})
+    INCLUDE_DIRECTORIES(${PNG_SRC_DIR})
     INCLUDE_DIRECTORIES(${FREETYPE_SRC_DIR}/include)
     INCLUDE_DIRECTORIES(${ANDROID_NDK}/sources/android/native_app_glue)
 endif()

+ 4 - 0
la_5.h

@@ -55,6 +55,10 @@
 #include <sys/stat.h>
 #include <time.h>
 
+#if defined (LAGUI_ANDROID) || defined (LA_USE_GLES)
+#define NANOVG_GLES3
+#else
 #define NANOVG_GL3
+#endif
 #include "nanovg.h"
 #include "nanovg_gl.h"

+ 3 - 0
la_data.c

@@ -2224,6 +2224,9 @@ int laValidateProperties(){
 //==================================[RW]
 
 void la_GetWorkingDirectoryInternal(){
+#ifdef LAGUI_ANDROID
+    strSafeSet(&MAIN.WorkingDirectory, ""); return;
+#endif
     char mbuf[2048]; getcwd(mbuf,2048);
     int len=strlen(mbuf);if(mbuf[len]!=LA_PATH_SEP){ mbuf[len]=LA_PATH_SEP; mbuf[len+1]=0; }
     strSafeSet(&MAIN.WorkingDirectory, mbuf);

+ 0 - 1
la_data.h

@@ -102,7 +102,6 @@ typedef int (*laActionHolderVerifyF)(void* Holder, laPropContainer* HolderType,
 #define LA_PROP_SUB (1<<8)
 #define LA_PROP_INT (1<<9)
 #define LA_PROP_FLOAT (1<<10)
-#define LA_PROP_STRING (1<<11)
 #define LA_PROP_ENUM (1<<12)
 #define LA_PROP_STRING (1<<13)
 #define LA_PROP_ARRAY (1<<14)

+ 31 - 0
la_interface.h

@@ -21,6 +21,8 @@
 #ifdef LAGUI_ANDROID
     #include <GLES3/gl3.h>
     #include <EGL/egl.h>
+    #include <android/input.h>
+    #include <android/keycodes.h> 
 #else
     #ifdef LA_USE_GLES
     #include <EGL/egl.h>
@@ -144,6 +146,7 @@
 #define XK_F11 11
 #define XK_F12 12
 #endif
+#ifdef LA_LINUX
 #define LA_KEY_F1        XK_F1
 #define LA_KEY_F2        XK_F2
 #define LA_KEY_F3        XK_F3
@@ -156,6 +159,21 @@
 #define LA_KEY_F10       XK_F10
 #define LA_KEY_F11       XK_F11
 #define LA_KEY_F12       XK_F12
+#endif
+#ifdef LAGUI_ANDROID
+#define LA_KEY_F1        AKEYCODE_F1
+#define LA_KEY_F2        AKEYCODE_F2
+#define LA_KEY_F3        AKEYCODE_F3
+#define LA_KEY_F4        AKEYCODE_F4
+#define LA_KEY_F5        AKEYCODE_F5
+#define LA_KEY_F6        AKEYCODE_F6
+#define LA_KEY_F7        AKEYCODE_F7
+#define LA_KEY_F8        AKEYCODE_F8
+#define LA_KEY_F9        AKEYCODE_F9
+#define LA_KEY_F10       AKEYCODE_F10
+#define LA_KEY_F11       AKEYCODE_F11
+#define LA_KEY_F12       AKEYCODE_F12
+#endif
 
 #define LA_KEY_SPECIALS (LA_KEY_CTRL|LA_KEY_SHIFT|LA_KEY_ALT)
 
@@ -417,6 +435,19 @@ STRUCTURE(LA){
     XIM im;
     XIC ic;
     int xi_opcode;
+#endif
+#ifdef LAGUI_ANDROID
+    SYSWINDOW* win;
+    EGLConfig BestFBC;
+    EGLDisplay egl_dpy;
+    EGLSurface egl_surf;
+    struct android_app* app;
+    struct android_poll_source *event_source;
+    int AppWidth,AppHeight;
+    int AppReady,AppEnabled;
+    int ContextRebindRequired;
+    AAssetManager *AssetManager;
+    char *InternalDataPath; 
 #endif
     int InkOrWinTab;
     int WacomDeviceStylus; real StylusPressure, StylusOrientation, StylusDeviation, StylusMaxPressure;

+ 307 - 18
la_kernel.c

@@ -16,7 +16,7 @@
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#ifdef LA_USE_GLES
+#if defined(LA_USE_GLES) || defined(LAGUI_ANDROID)
 #define NANOVG_GLES3_IMPLEMENTATION
 #else
 #define NANOVG_GL3_IMPLEMENTATION
@@ -52,9 +52,31 @@
 #endif
 #ifdef LAGUI_ANDROID
 #include <GLES3/gl3.h>
+#include <android/log.h>
+#include <android/native_activity.h>
+#include <jni.h>
+#include <android/native_window.h>
+#include <android/native_window_jni.h>
+#include <jni.h>
+#include <android_native_app_glue.h>
+#include <android/window.h>
+#include <android/asset_manager.h>
+
+FILE *funopen(const void *cookie, int (*readfn)(void *, char *, int), int (*writefn)(void *, const char *, int),
+              fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *));
+
+static int android_read(void *cookie, char *buf, int size);
+static int android_write(void *cookie, const char *buf, int size);
+static fpos_t android_seek(void *cookie, fpos_t offset, int whence);
+static int android_close(void *cookie);
+
+void la_InitAndroidPlatform(struct android_app *app);
+static void la_AndroidCommandCallback(struct android_app *app, int32_t cmd);
+static int32_t la_AndroidInputCallback(struct android_app *app, AInputEvent *event);
+void la_InitAndroidPlatform(struct android_app *app);
 #endif
 
-LA MAIN;
+LA MAIN={0};
 
 extern tnsMain *T;
 int deb = 0;
@@ -443,6 +465,12 @@ void la_DestroySystemWindowWin32(laWindow* w) {
 };
 #endif
 
+#ifdef LAGUI_ANDROID
+SYSWINDOW la_CreateWindowAndroid(){
+    return 0;
+};
+#endif
+
 #ifdef LA_LINUX
 void la_HandlerSIGSEGV(int sig) {
     void *array[30];
@@ -537,13 +565,16 @@ int la_CreateSystemWindow(laWindow *window, int SyncToVBlank){
     SYSWINDOW hwnd = la_CreateWindowX11(window->X, window->Y, window->W, window->H, window->Title->Ptr, SyncToVBlank, &glc, egl_surf);
 #endif
 #ifdef _WIN32
-    SYSWINDOW hwnd = la_CreateWindowWin32(window->X, window->Y, window->W, window->H, window->Title->Ptr, SyncToVBlank, &glc);
-#endif
-#ifdef _WIN32
-    SYSWINDOW hwnd = la_CreateWindowWin32(window->X, window->Y, window->W, window->H, window->Title->Ptr, SyncToVBlank, &glc);
+    SYSWINDOW hwnd = la_CreateWindowAndroid();
 #endif
+
+#ifdef LAGUI_ANDROID
+    window->win = 1;
+    window->glc = MAIN.glc;
+#else
     window->win = hwnd;
     window->glc = glc;
+#endif
 
 #ifdef _WIN32
     la_SetupGLEnviornment(window, hwnd, SyncToVBlank);
@@ -562,7 +593,7 @@ int la_CreateSystemWindow(laWindow *window, int SyncToVBlank){
     glGenVertexArrays(1,&window->vao); tnsBindVertexArray(window->vao);
     la_SetupWindowGLStates(window);
 
-#ifdef LA_USE_GLES
+#if defined(LA_USE_GLES) || defined(LAGUI_ANDROID)
     window->nvg=nvgCreateGLES3(NVG_STENCIL_STROKES|NVG_DEBUG|NVG_ANTIALIAS);
 #else
     window->nvg=nvgCreateGL3(NVG_STENCIL_STROKES|NVG_DEBUG|NVG_ANTIALIAS);
@@ -576,7 +607,7 @@ int la_CreateSystemWindow(laWindow *window, int SyncToVBlank){
 };
 
 int la_DestroySystemWindow(laWindow* wnd){
-#ifdef LA_USE_GLES
+#if defined(LA_USE_GLES) || defined(LAGUI_ANDROID)
     nvgDeleteGLES3(wnd->nvg);
 #else
     nvgDeleteGL3(wnd->nvg);
@@ -679,6 +710,9 @@ void logPrintTV(int Continued, char* format, va_list v){
     laLogEntry* le=logEnsure(Continued);
     if(MAIN.EnableLogStdOut){ va_list v1; va_copy(v1,v); vprintf(format,v1); }
     strSafePrintV(&le->Content, format, v);
+#ifdef LAGUI_ANDROID
+    __android_log_print(ANDROID_LOG_DEBUG, "LAGUI", "%s",SSTR(le->Content));
+#endif
     laNotifyUsers("la.logs");
 }
 void logPrintT(int Continued, char* format, ...){
@@ -687,6 +721,9 @@ void logPrintT(int Continued, char* format, ...){
     va_list aptr; va_start(aptr, format);
     strSafePrint(&le->Content, format, aptr);
     va_end(aptr);
+#ifdef LAGUI_ANDROID
+    __android_log_print(ANDROID_LOG_DEBUG, "LAGUI", "%s",SSTR(le->Content));
+#endif
     laNotifyUsers("la.logs");
 }
 void logPrint(char* format, ...){
@@ -1196,11 +1233,12 @@ int laGetReadyWith(laInitArguments* ia){
     
     MAIN.FontSize = 0.6;
 
+    int dpi=64;
 #ifdef _WIN32
-    int dpi=la_GetDPI(hwnd);
+    dpi=la_GetDPI(hwnd);
 #endif
 #ifdef LA_LINUX
-    int dpi = la_GetDPI(DefaultRootWindow(MAIN.dpy));
+    dpi = la_GetDPI(DefaultRootWindow(MAIN.dpy));
 #endif
     if((!dpi) || dpi<144){ dpi=144; } if(dpi>300){ dpi=300; }
     int UiSize=(int)(tnsLinearItp(16.0f,24.0f,tnsGetRatiod(96,144,dpi))+0.5);
@@ -1228,7 +1266,7 @@ int laGetReadyWith(laInitArguments* ia){
     LOAD_FONT("NotoSansSymbols2-Regular.ttf");
     //LOAD_FONT("NotoMusic-Regular.ttf");
     //LOAD_FONT("NotoSansEgyptianHieroglyphs-Regular.ttf);
-    if(!tnsLoadSystemFontMono(MAIN.SysFontDir, "NotoSansMono-Regular.ttf")) printf("Can't load font \"NotoSansMono-Regular.ttf\"\n");;
+    if(!tnsLoadSystemFontMono(MAIN.SysFontDir, "NotoSansMono-Regular.ttf")) logPrintNew("Can't load font \"NotoSansMono-Regular.ttf\"\n");;
 
     arrEnsureLength(&MAIN.InputBuf,0,&MAIN.InputBufMax,sizeof(char));
     arrEnsureLength(&MAIN.InputBufU,0,&MAIN.InputBufUMax,sizeof(uint32_t));
@@ -1718,7 +1756,14 @@ void la_UpdateUiPlacement(laWindow *w){
     }
 }
 void la_CommandResizeWindow(SYSWINDOW hwnd, int x, int y, int w, int h){
-    laWindow *window = lstFindItem(hwnd, la_IsThisSysWindow, &MAIN.Windows);
+    laWindow *window;
+#ifdef LAGUI_ANDROID
+    window = MAIN.Windows.pFirst; if (!window) return;
+    window->X=x;window->Y=y;window->W=w;window->H=h;
+    window->CW=w;window->CH=h;
+    la_UpdateUiPlacement(window); return;
+#endif
+    window = lstFindItem(hwnd, la_IsThisSysWindow, &MAIN.Windows);
     if (!window) return;
 #ifdef _WIN32
     RECT rcc; GetClientRect(window->win, &rcc);
@@ -3028,6 +3073,9 @@ laWindow *laDesignWindow(int X, int Y, int W, int H){
 
     strSafeSet(&n->Title, "Empty SYSWINDOW");
     n->X = X; n->Y = Y; n->W = W; n->H = H;
+#ifdef LAGUI_ANDROID
+    n->X=0; n->Y=0; n->W=MAIN.AppWidth; n->H=MAIN.AppHeight;
+#endif
 
     la_CreateSystemWindow(n, MAIN.Windows.pFirst!=0);
 
@@ -3354,7 +3402,7 @@ laPanel *laCreatePanelT(laBlock *b, laUiTemplate* uit){
     laRecalcPanel(p);
     p->FrameDistinguish = 100; //greater than 1 is ok
 
-    p->TitleWidth = tnsStringGetWidth(transLate(p->Title->Ptr), 0, 0);
+    p->TitleWidth = tnsStringGetWidth(transLate(SSTR(p->Title)), 0, 0);
 
     while (b->B1){ b = b->B1; } lstPushItem(&b->Panels, p);
     p->Block = b; b->CurrentPanel = p;
@@ -3900,6 +3948,7 @@ void laRedrawAllWindows(){ if((!MAIN.CurrentWindow) || (!MAIN.CurrentWindow->win
     laWindow* cur=MAIN.CurrentWindow;
     for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){
         MAIN.CurrentWindow=w;
+    __android_log_print(ANDROID_LOG_DEBUG, "huh 5678", "call redraw");
         la_UpdateUiPlacement(w);
     }
     MAIN.CurrentWindow=cur;
@@ -7920,6 +7969,19 @@ int la_ProcessSysMessage(){
     };
     if(!MAIN.Windows.pFirst){ return 0; }
 #endif
+#ifdef LAGUI_ANDROID
+    int pollResult = 0;
+    int pollEvents = 0;
+    while ((pollResult = ALooper_pollAll(MAIN.AppEnabled? 0 : -1, NULL, &pollEvents, (void**)&MAIN.event_source)) >= 0){
+        if (MAIN.event_source != NULL) MAIN.event_source->process(MAIN.app, MAIN.event_source);
+        // NOTE: Never close window, native activity is controlled by the system!
+        if (MAIN.app->destroyRequested != 0)
+        {
+            //CORE.Window.shouldClose = true;
+            //ANativeActivity_finish(MAIN.app->activity);
+        }
+    }
+#endif
 
     for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){
         if(SendDelay) { la_SendTimerEvent(w->win, LA_TIME_DELAY); MAIN.DelayTriggered=1; }
@@ -7941,6 +8003,7 @@ void la_PrintOperatorStack(){
 
 void la_DrawWindow(laWindow *w){
     if(!w->Redraw) return; w->Redraw=0; w->RedrawTouched=1;
+    __android_log_print(ANDROID_LOG_DEBUG, "huh draw", "123 draw");
     MAIN.CurrentWindow = w;
     la_WindowDefDraw(w, 0);
 }
@@ -7972,7 +8035,7 @@ void laMainLoop(){
 
     laSetWindowCursor(LA_ARROW);
     MAIN.DelayTriggered=1;
-
+    
     while (1){
         laRecordTime(&FrameStartTime);
 
@@ -7999,6 +8062,9 @@ void laMainLoop(){
             la_DrawWindow(w);
         }
         for(w=MAIN.Windows.pFirst;w;w=w->Item.pNext){
+#ifdef LAGUI_ANDROID
+            eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf);
+#endif
             if(!w->RedrawTouched) continue; w->RedrawTouched=0;
 #ifdef LA_LINUX
     #ifdef LA_USE_GLES
@@ -8032,11 +8098,234 @@ void laMainLoop(){
     }
 }
 
-#ifdef LA_ANDROID
+#ifdef LAGUI_ANDROID
+
+int la_AndroidInitGraphics(void){
+    MAIN.AppWidth=ANativeWindow_getWidth(MAIN.app->window);
+    MAIN.AppHeight=ANativeWindow_getHeight(MAIN.app->window);
+
+    EGLint samples = 0;
+    EGLint sampleBuffer = 0;
+
+    const EGLint framebufferAttribs[] = {
+        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,      // Type of context support
+        EGL_RED_SIZE, 8,            // RED color bit depth (alternative: 5)
+        EGL_GREEN_SIZE, 8,          // GREEN color bit dept<android/log.h>h (alternative: 6)
+        EGL_BLUE_SIZE, 8,           // BLUE color bit depth (alternative: 5)
+        //EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI)
+        EGL_DEPTH_SIZE, 16,         // Depth buffer size (Required to use Depth testing!)
+        //EGL_STENCIL_SIZE, 8,      // Stencil buffer size
+        EGL_SAMPLE_BUFFERS, sampleBuffer,    // Activate MSAA
+        EGL_SAMPLES, samples,       // 4x Antialiasing if activated (Free on MALI GPUs)
+        EGL_NONE
+    };
+
+    const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE };
+
+    EGLint numConfigs = 0;
+
+    MAIN.egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    if (MAIN.egl_dpy == EGL_NO_DISPLAY){ logPrint("Android no display"); return -1; }
+    if (eglInitialize(MAIN.egl_dpy, NULL, NULL) == EGL_FALSE){ logPrint("Android can't init display");  return -1; }
+    eglChooseConfig(MAIN.egl_dpy, framebufferAttribs, &MAIN.BestFBC, 1, &numConfigs);
+    eglBindAPI(EGL_OPENGL_API);
+
+    MAIN.glc = eglCreateContext(MAIN.egl_dpy, MAIN.BestFBC, EGL_NO_CONTEXT, contextAttribs);
+    if (MAIN.glc == EGL_NO_CONTEXT){ logPrint("Android can't create context");  return -1; }
+
+    EGLint displayFormat = 0;
+    eglGetConfigAttrib(MAIN.egl_dpy, MAIN.BestFBC, EGL_NATIVE_VISUAL_ID, &displayFormat);
+
+    ANativeWindow_setBuffersGeometry(MAIN.app->window, MAIN.AppWidth, MAIN.AppHeight, displayFormat);
+
+    MAIN.egl_surf = eglCreateWindowSurface(MAIN.egl_surf, MAIN.BestFBC, MAIN.app->window, NULL);
+
+    // There must be at least one frame displayed before the buffers are swapped
+    //eglSwapInterval(MAIN.egl_dpy, 1);
+
+    if (eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc) == EGL_FALSE) { logPrint("Android can't make current"); return -1; }
+    
+    glViewport(0,0,MAIN.AppWidth, MAIN.AppHeight);
+    glClearColor(0,1,1,1);
+    glClear(GL_COLOR_BUFFER_BIT);
+    eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf);
+
+    MAIN.AppReady = 1;
+
+    return 0;
+}
+
+static void la_AndroidCommandCallback(struct android_app *app, int32_t cmd){
+    switch (cmd){
+    case APP_CMD_START: break;
+    case APP_CMD_GAINED_FOCUS: MAIN.AppEnabled = 1; break;
+    case APP_CMD_LOST_FOCUS: MAIN.AppEnabled = 0; break;
+    case APP_CMD_RESUME:break;//InitPlatform();break;
+    case APP_CMD_INIT_WINDOW:
+        if (app->window != NULL){
+            if (MAIN.ContextRebindRequired){
+                // Reset screen scaling to full display size
+                EGLint displayFormat = 0;
+                eglGetConfigAttrib(MAIN.egl_dpy, MAIN.BestFBC, EGL_NATIVE_VISUAL_ID, &displayFormat);
+
+                // Adding renderOffset here feels rather hackish, but the viewport scaling is wrong after the
+                // context rebinding if the screen is scaled unless offsets are added. There's probably a more
+                // appropriate way to fix this
+                MAIN.AppWidth=ANativeWindow_getWidth(MAIN.app->window);
+                MAIN.AppHeight=ANativeWindow_getHeight(MAIN.app->window);
+
+                ANativeWindow_setBuffersGeometry(app->window,MAIN.AppWidth,MAIN.AppHeight,
+                    displayFormat);
+
+                // Recreate display surface and re-attach OpenGL context
+                MAIN.egl_surf = eglCreateWindowSurface(MAIN.egl_dpy, MAIN.BestFBC, app->window, NULL);
+                eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc);
+
+                //glViewport(0,0,MAIN.AppWidth,MAIN.AppHeight);
+                //glClearColor(1,0.2,1,1);
+                //glClear(GL_COLOR_BUFFER_BIT);
+                eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf);
+                la_CommandResizeWindow(0,0,0,MAIN.AppWidth,MAIN.AppHeight);
+
+                MAIN.ContextRebindRequired = false;
+            }else{
+                la_AndroidInitGraphics();
+            }
+        }
+        break;
+    case APP_CMD_TERM_WINDOW:
+        // Detach OpenGL context and destroy discom.yiming.helloplay surface
+        // NOTE 1: This case is used when the user exits the app without closing it. We detach the context to ensure everything is recoverable upon resuming.
+        // NOTE 2: Detaching context before destroying display surface avoids losing our resources (textures, shaders, VBOs...)
+        // NOTE 3: In some cases (too many context loaded), OS could unload context automatically... :(
+        if (MAIN.egl_dpy != EGL_NO_DISPLAY) {
+            eglMakeCurrent(MAIN.egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+            if (MAIN.egl_surf != EGL_NO_SURFACE) {
+                eglDestroySurface(MAIN.egl_dpy, MAIN.egl_surf);
+                MAIN.egl_surf = EGL_NO_SURFACE;
+            }
+            MAIN.ContextRebindRequired = true;
+        }
+        // If 'MAIN.egl_dpy' is already set to 'EGL_NO_DISPLAY'
+        // this means that the user has already called 'CloseWindow()'
+        break;
+    case APP_CMD_SAVE_STATE: break;
+    case APP_CMD_STOP: break;
+    case APP_CMD_DESTROY: break;
+    case APP_CMD_CONFIG_CHANGED:
+        MAIN.AppWidth=ANativeWindow_getWidth(MAIN.app->window);
+        MAIN.AppHeight=ANativeWindow_getHeight(MAIN.app->window);
+        la_CommandResizeWindow(0,0,0,MAIN.AppWidth,MAIN.AppHeight);
+        //AConfiguration_fromAssetManager(MAIN.app->config, MAIN.app->activity->assetManager);
+        //print_cur_config(MAIN.app);
+
+        // Check screen orientation here!
+        break;
+    default: break;
+    }
+}
+
+static int32_t la_AndroidInputCallback(struct android_app *app, AInputEvent *event)
+{
+    __android_log_print(ANDROID_LOG_DEBUG, "huh 5678", "123 input");
+    if(!MAIN.AppEnabled){return 0;}
+    laRedrawAllWindows();
+    
+    //static float r=0;
+    //eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc);
+    //glViewport(0,0,MAIN.AppWidth,MAIN.AppHeight);
+    //glClearColor(r,0.2,1,1); r+=0.01; if(r>1){ r=0; }
+    //glClear(GL_COLOR_BUFFER_BIT);
+    //eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf);
+    return 0;
+}
+
+void la_InitAssetManager(AAssetManager *manager, const char *dataPath){
+    MAIN.AssetManager = manager;
+    MAIN.InternalDataPath = dataPath;
+}
+
+static int android_read(void *cookie, char *data, int dataSize){
+    return AAsset_read((AAsset *)cookie, data, dataSize);
+}
+
+static int android_write(void *cookie, const char *data, int dataSize){
+    return 0;
+}
+
+static fpos_t android_seek(void *cookie, fpos_t offset, int whence){
+    return AAsset_seek((AAsset *)cookie, offset, whence);
+}
+
+static int android_close(void *cookie){
+    AAsset_close((AAsset *)cookie);
+    return 0;
+}
+
+// Replacement for fopen()
+// Ref: https://developer.android.com/ndk/reference/group/asset
+FILE *android_fopen(const char *fileName, const char *mode)
+{
+    char buf[1024];
+    if (mode[0] == 'w')
+    {
+        // fopen() is mapped to android_fopen() that only grants read access to
+        // assets directory through AAssetManager but we want to also be able to
+        // write data when required using the standard stdio FILE access functions
+        // Ref: https://stackoverflow.com/questions/11294487/android-writing-saving-files-from-native-code-only
+        #undef fopen
+        sprintf(buf,"%s/%s", MAIN.InternalDataPath, fileName);
+        return fopen(buf, mode);
+        #define fopen(name, mode) android_fopen(name, mode)
+    }
+    else
+    {
+        // NOTE: AAsset provides access to read-only asset
+        AAsset *asset = AAssetManager_open(MAIN.AssetManager, fileName, AASSET_MODE_UNKNOWN);
+
+        if (asset != NULL)
+        {
+            // Get pointer to file in the assets
+            return funopen(asset, android_read, android_write, android_seek, android_close);
+        }
+        else
+        {
+            #undef fopen
+            // Just do a regular open if file is not found in the assets
+            sprintf(buf,"%s/%s", MAIN.InternalDataPath, fileName);
+            return fopen(buf, mode);
+            #define fopen(name, mode) android_fopen(name, mode)
+        }
+    }
+}
+
+void la_InitAndroidPlatform(struct android_app *app){
+    MAIN.app=app;
+
+    ANativeActivity_setWindowFlags(MAIN.app->activity, AWINDOW_FLAG_FULLSCREEN, 1);  //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER
+
+    MAIN.app->onAppCmd = la_AndroidCommandCallback;
+    MAIN.app->onInputEvent = la_AndroidInputCallback;
+
+    la_InitAssetManager(MAIN.app->activity->assetManager, MAIN.app->activity->internalDataPath);
+
+    int pollResult = 0;
+    int pollEvents = 0;
+    while (!MAIN.AppReady){
+        while ((pollResult = ALooper_pollAll(MAIN.AppEnabled? 0 : -1, NULL, &pollEvents, (void**)&MAIN.event_source)) >= 0){
+            // Process this event
+            if (MAIN.event_source != NULL) MAIN.event_source->process(MAIN.app, MAIN.event_source);
+            // NOTE: Never close window, native activity is controlled by the system!
+            //if (MAIN.app->destroyRequested != 0) CORE.Window.shouldClose = true;
+        }
+    }
+}
 
 void android_main(struct android_app *app){
     char arg0[] = "lagui";     // NOTE: argv[] are mutable
-    CORE.Android.app = app;
+
+    la_InitAndroidPlatform(app);
+
     // NOTE: Return from main is ignored
     (void)main(1, (char *[]) { arg0, NULL });
     // Request to end the native activity
@@ -8047,9 +8336,9 @@ void android_main(struct android_app *app){
     // Waiting for application events before complete finishing
     while (!app->destroyRequested)
     {
-        while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void **)&CORE.Android.source)) >= 0)
+        while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void **)&MAIN.event_source)) >= 0)
         {
-            if (CORE.Android.source != NULL) CORE.Android.source->process(app, CORE.Android.source);
+            if ( MAIN.event_source != NULL) MAIN.event_source->process(app, MAIN.event_source);
         }
     }
 }

+ 64 - 28
la_tns_kernel.c

@@ -16,6 +16,8 @@
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#define _GNU_SOURCE 1
+
 #include "la_5.h"
 
 #include <math.h>
@@ -140,6 +142,11 @@ void tnsContextMakeFBOCurrent(tnsOffscreen* off){
     tnsContextMakeCurrent(off->FboContext,off->FboWindow,off->FboSurface);
 }
 void tnsContextMakeWindowCurrent(laWindow* w){
+#ifdef LAGUI_ANDROID
+    T->CurrentContext=MAIN.glc;
+    if (eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc) == EGL_FALSE) { logPrint("Android can't make current"); return; }
+   return;
+#endif
     tnsContextMakeCurrent(w->glc,w->win,w->egl_surf);
 }
 #else
@@ -405,6 +412,7 @@ int tnsNewFragmentShader(char *Content){
     return tnsNewFragmentShaderMaterial(Content,0,0);
 }
 int tnsNewGeometryShader(char *Content){
+#ifndef LAGUI_ANDROID
     int status = 0;
     char error[8192]={0};
     GLuint GeometryShaderObject;
@@ -427,6 +435,8 @@ int tnsNewGeometryShader(char *Content){
     free(UseContent);
     
     return GeometryShaderObject;
+#endif
+    return 0;
 }
 
 tnsShader *tnsNewShaderProgram(int VertexShaderID, int FragmentShaderID, int GeometryShaderID){
@@ -1225,8 +1235,6 @@ void tnsPreTranslate3d(real x, real y, real z){
     real *mat = tnsGetModelMatrix();
     tnsMatrix44d transmat, result;
 
-    //glTranslatef(x, y, z);
-
     tnsMakeTranslationMatrix44d(transmat, x, y, z);
     tnsMultiply44d(result, mat, transmat);
     memcpy(mat, result, sizeof(tnsMatrix44d));
@@ -1258,8 +1266,6 @@ void tnsScale3d(real x, real y, real z){
     real *mat = tnsGetModelMatrix();
     tnsMatrix44d scalemat, normal_scaler, result;
 
-    glScalef(x, y, z);
-
     tnsMakeScaleMatrix44d(scalemat, x, y, z);
 
     tnsMultiply44d(result, mat, scalemat);
@@ -1274,8 +1280,6 @@ void tnsPreScale3d(real x, real y, real z){
     real *mat = tnsGetModelMatrix();
     tnsMatrix44d scalemat, normal_scaler, result;
 
-    glScalef(x, y, z);
-
     tnsMakeScaleMatrix44d(scalemat, x, y, z);
 
     tnsMultiply44d(result, mat, scalemat);
@@ -1620,7 +1624,7 @@ void tnsDrawBatchInitArrayStates(tnsBatch* batch){
     tnsUniformUseTexture(cs, 0, 0);
 }
 int tnsDrawBatch(tnsBatch* batch, const char* OverrideCommand, real* OverrideUniformColor, int OverrideAsArray) {
-	if (!batch) return;
+	if (!batch) return 0;
     int Drawn=0; tnsShader *LastShader=T->BindedShader,*SaveShader=T->BindedShader; int NeedInit=1;
 
     int IsOverrideColor=0; int PointSizeChanged=0,LineWidthChanged=0;
@@ -1701,8 +1705,12 @@ int tnsInit2DTexture(tnsTexture *t, GLint glInternalFormat, int w, int h, int Mu
         t->Width = w;
         t->Height = h;
         t->GLTexBitsType = glInternalFormat;
+#ifdef LAGUI_ANDROID
+        t->GLTexType = GL_TEXTURE_2D;
+#else
         t->GLTexType = Multisample?GL_TEXTURE_2D_MULTISAMPLE:GL_TEXTURE_2D;
         t->Multisample = Multisample;
+#endif
         glGenTextures(1, &t->GLTexHandle);
 
         tnsConfigure2DTexture(t);
@@ -1731,8 +1739,10 @@ void tnsConfigure2DTexture(tnsTexture *t){
             t->GLTexBitsType==GL_DEPTH_COMPONENT24||t->GLTexBitsType==GL_DEPTH_COMPONENT32F;
         int format=isDepth?GL_DEPTH_COMPONENT:(t->GLTexBitsType==GL_R8?GL_RED:(t->GLTexBitsType==GL_RG8?GL_RG:(t->GLTexBitsType==GL_RGB8?GL_RGB:GL_RGBA)));
         int type=GL_UNSIGNED_BYTE;
-        if(t->GLTexBitsType==GL_DEPTH_STENCIL){ format=GL_DEPTH_STENCIL; type=GL_UNSIGNED_INT_24_8_EXT; }
+        if(t->GLTexBitsType==GL_DEPTH_STENCIL){ format=GL_DEPTH_STENCIL; type=GL_UNSIGNED_INT_24_8; }
+#ifndef LAGUI_ANDROID
         if(t->Multisample) glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, t->Multisample, t->GLTexBitsType, t->Width, t->Height, GL_TRUE);
+#endif
         else{ glTexImage2D(GL_TEXTURE_2D, 0, t->GLTexBitsType, t->Width, t->Height, 0, format, type, 0);
             int a=glGetError();
             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -1747,9 +1757,9 @@ void tnsConfigure2DTexture(tnsTexture *t){
 void tnsConfigure3DTexture(tnsTexture *t){
     tnsBindTexture(t);
     glTexImage3D(GL_TEXTURE_3D, 0, t->GLTexBitsType, t->Width, t->Height, t->Slices, 0, GL_RGBA, GL_FLOAT, 0);
-        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
-        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
+        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
         //glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_REPLACE);
@@ -1762,10 +1772,12 @@ void tnsReconfigureTextureParameters(int Multisample){
         for(int i=0;i<4;i++){
             t=o->pColor[i];
             if(t){
-                t->Multisample = Multisample;
                 int recreate=0;
+#ifndef LAGUI_ANDROID
+                t->Multisample = Multisample;
                 if(t->Multisample){ if(t->GLTexType==GL_TEXTURE_2D){t->GLTexType=GL_TEXTURE_2D_MULTISAMPLE; recreate=1;}}
                 else { if(t->GLTexType==GL_TEXTURE_2D_MULTISAMPLE){t->GLTexType=GL_TEXTURE_2D; recreate=1;}}
+#endif
                 if(recreate){
                     glDeleteTextures(1, &t->GLTexHandle);
                     glGenTextures(1, &t->GLTexHandle);
@@ -1776,10 +1788,13 @@ void tnsReconfigureTextureParameters(int Multisample){
             }
         }
         t=o->pDepth;
-        if(t){ int recreate=0; 
+        if(t){
+            int recreate=0; 
+#ifndef LAGUI_ANDROID
             if((!t->Multisample && Multisample)||(t->Multisample && !Multisample)){ recreate=1; }
             if(Multisample){ t->GLTexType=GL_TEXTURE_2D_MULTISAMPLE; }else{ t->GLTexType=GL_TEXTURE_2D; }
             t->Multisample = Multisample;
+#endif
             if(recreate){
                 glDeleteTextures(1, &t->GLTexHandle);
                 glGenTextures(1, &t->GLTexHandle);
@@ -1823,7 +1838,9 @@ void tnsUseMaskTexture(tnsTexture *t){
 void tnsUseTexture(tnsTexture *t){
     if(!t){T->StateTextureMode=0; return;}
     if(t->GLTexType == GL_TEXTURE_2D){ T->StateTexColor = t; T->StateTextureMode=2; }
+#ifndef LAGUI_ANDROID
     else if(t->GLTexType == GL_TEXTURE_2D_MULTISAMPLE){ T->StateTexColor = t; T->StateTextureMode=3; }
+#endif
 }
 void tnsUseNoTexture(){
     tnsUseTexture(0);
@@ -1851,7 +1868,9 @@ void tnsActiveTexture(GLenum tex){
 void tnsBindTexture(tnsTexture *t){
     if ((!t) || T->TexColor==t) return;
     if(t->GLTexType == GL_TEXTURE_2D){ tnsActiveTexture(GL_TEXTURE0); glBindTexture(t->GLTexType, t->GLTexHandle); T->TexColor=t;}
+#ifndef LAGUI_ANDROID
     elif(t->GLTexType == GL_TEXTURE_2D_MULTISAMPLE){ tnsActiveTexture(GL_TEXTURE1); glBindTexture(t->GLTexType, t->GLTexHandle); T->TexColor=t;}
+#endif
 #ifndef LA_USE_GLES
     elif(t->GLTexType == GL_RENDERBUFFER){ glBindRenderbufferEXT(GL_RENDERBUFFER, t->GLTexHandle); T->TexRenderbuffer = t;}
 #endif
@@ -1863,7 +1882,9 @@ void tnsUnbindTexture(){
 #endif
     if(T->TexColor){
         if(T->TexColor->GLTexType == GL_TEXTURE_2D){tnsActiveTexture(GL_TEXTURE0);}
+#ifndef LAGUI_ANDROID
         else if(T->TexColor->GLTexType == GL_TEXTURE_2D_MULTISAMPLE){tnsActiveTexture(GL_TEXTURE1);}
+#endif
         else if(T->TexColor->GLTexType == GL_TEXTURE_3D){tnsActiveTexture(GL_TEXTURE0);}
         glBindTexture(T->TexColor->GLTexType, 0); T->TexColor=0;
     }
@@ -2303,7 +2324,9 @@ void tnsPackAs(GLenum Mode){
 
     memcpy(c->UniformColor, T->StateColor, sizeof(GLfloat) * 4);
 
+#ifndef LAGUI_ANDROID
     if (Mode == GL_QUAD_STRIP || Mode == GL_QUADS) Mode=GL_TRIANGLE_STRIP;
+#endif
     //if (Mode == GL_QUADS) Mode=GL_TRIANGLE_STRIP;
     c->Mode = Mode;
     c->ReplaceShader = T->StateShader;
@@ -2449,7 +2472,7 @@ const GLuint TNS_ATTACHMENT_ARRAY_0_1_2[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTA
 const GLenum TNS_WINDOW_DRAWBUFFER_ARRAY[] = {GL_BACK};
 
 tnsOffscreen *tnsCreateOffscreenHandle(){
-    if(!T->CurrentContext){ printf("tnsCreateOffscreenHandle() called without GL Context. Exiting"); exit(0); }
+    if(!T->CurrentContext){ logPrintNew("tnsCreateOffscreenHandle() called without GL Context. Exiting"); exit(0); }
     tnsOffscreen *toff = CreateNew(tnsOffscreen); toff->FboContext=T->CurrentContext;
 #ifdef LA_USE_GLES
     toff->FboSurface=T->CurrentSurface;
@@ -2679,7 +2702,7 @@ int tnsInvalidateFontCache(){
     int GenHeight=LA_RH*MAIN.FontSize;
     for(int i=0;i<f->NumFaces;i++){
         FT_Set_Char_Size(f->ftface[i], 0, GenHeight << 6, 96, 96);
-        FT_Glyph glyph; int half_adv=0;
+        FT_Glyph glyph; FT_Fixed half_adv=0;
         if(!FT_Get_Advance(f->ftface[i],'a',FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, &half_adv)){
             if (FT_Load_Char(f->ftface[i], 'a', FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)||
                 FT_Get_Glyph(f->ftface[i]->glyph, &glyph)){ SEND_PANIC_ERROR("Monospace font doesn't contain character 'a'"); }
@@ -2714,23 +2737,29 @@ int tnsLoadSystemFontMono(char* from, char* mono){
     tnsFont *f=FM->UsingFont;
     int GenHeight=LA_RH*MAIN.FontSize;
 
-    int full_adv=0,half_adv=0;
+    FT_Fixed full_adv=0,half_adv=0;
     for(int i=0;i<f->NumFaces;i++){
         if(!FT_Get_Advance(f->ftface[i],U'我',FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, &full_adv)) break;
     }
     for(int i=-2;i<11;i++){
         char* option;
         if(i==-2){ sprintf(buf,"%s%s%s",TNS_FONT_CUSTOM,TNS_FONT_CUSTOM[strlen(TNS_FONT_CUSTOM)-1]=='/'?"":"/",mono); }
-        elif(i<9){ option=(i==-1)?from:TNS_FONT_LOAD_OPTIONS[i]; sprintf(buf,"%s%s%s",MAIN.WorkingDirectory->Ptr,option,mono); }
+        elif(i<9){ option=(i==-1)?from:TNS_FONT_LOAD_OPTIONS[i]; sprintf(buf,"%s%s%s",SSTR(MAIN.WorkingDirectory),option,mono); }
         else{ option=TNS_FONT_LOAD_OPTIONS_FROM_HOME[i-9]; sprintf(buf,"%s/%s%s",getenv("HOME"),option,mono); }
-        if (FT_New_Face(f->ftlib, buf, 0, &f->ftfacemono)) continue;
+        FILE* fontfile=fopen(buf,"rb"); if(!fontfile) continue;
+        fseek(fontfile,0,SEEK_END); int filesize=ftell(fontfile);
+        void*fontdata=CreateNewBuffer(char,filesize);
+        fseek(fontfile,0,SEEK_SET); fread(fontdata,filesize,1,fontfile);
+        FT_Face face; FT_Long i,num_faces; FT_Open_Args args; args.flags=FT_OPEN_MEMORY;
+        args.memory_base=fontdata; args.memory_size=filesize;
+        if(FT_Open_Face(f->ftlib, &args, 0, &f->ftfacemono)) continue;
         FT_Select_Charmap(f->ftfacemono, FT_ENCODING_UNICODE);
         FT_Set_Char_Size(f->ftfacemono, 0, GenHeight << 6, 96, 96);
         logPrint("Loaded monospace font: %s\n",buf);
         if(!FT_Get_Advance(f->ftfacemono,'a',FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, &half_adv)){
             f->MonoScale=(real)full_adv/(half_adv*2);
             FT_Set_Char_Size(f->ftfacemono, 0, (GenHeight << 6)*f->MonoScale, 96, 96);
-            logPrint("Monospace font scale: %.2f\n",f->MonoScale); FT_Glyph glyph;
+            logPrintNew("Monospace font scale: %.2f\n",f->MonoScale); FT_Glyph glyph;
             if (FT_Load_Char(f->ftfacemono, 'a', FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)||
                 FT_Get_Glyph(f->ftfacemono->glyph, &glyph)){ SEND_PANIC_ERROR("Monospace font doesn't contain character 'a'"); }
             f->MonoAdvance=(real)f->ftfacemono->glyph->advance.x/64.0;
@@ -2758,20 +2787,26 @@ int tnsLoadSystemFont(char* from, char* name){
     for(int i=-2;i<11;i++){
         char* option;
         if(i==-2){ sprintf(buf,"%s%s%s",TNS_FONT_CUSTOM,TNS_FONT_CUSTOM[strlen(TNS_FONT_CUSTOM)-1]=='/'?"":"/",name); }
-        elif(i<9){ option=(i==-1)?from:TNS_FONT_LOAD_OPTIONS[i]; sprintf(buf,"%s%s%s",MAIN.WorkingDirectory->Ptr,option,name); }
+        elif(i<9){ option=(i==-1)?from:TNS_FONT_LOAD_OPTIONS[i]; sprintf(buf,"%s%s%s",SSTR(MAIN.WorkingDirectory),option,name); }
         else{ option=TNS_FONT_LOAD_OPTIONS_FROM_HOME[i-9]; sprintf(buf,"%s/%s%s",getenv("HOME"),option,name); }
-        FT_Face face; FT_Long i,num_faces; FT_Open_Args args; args.flags=FT_OPEN_PATHNAME; args.pathname=buf;
+        FILE* fontfile=fopen(buf,"rb"); if(!fontfile) continue;
+        fseek(fontfile,0,SEEK_END); int filesize=ftell(fontfile);
+        void*fontdata=CreateNewBuffer(char,filesize);
+        fseek(fontfile,0,SEEK_SET); fread(fontdata,filesize,1,fontfile);
+        FT_Face face; FT_Long i,num_faces; FT_Open_Args args; args.flags=FT_OPEN_MEMORY;
+        args.memory_base=fontdata; args.memory_size=filesize;
         if(FT_Open_Face(f->ftlib, &args, -1, &face )) continue;
+        logPrintNew("stream %d",fontfile);
         num_faces = face->num_faces; FT_Done_Face(face); int found=0;
         for(int fa=0;fa<num_faces;fa++){
             if(FT_Open_Face(f->ftlib,&args,fa,&face)){ continue; }
             if(strstr(face->family_name,"SC")){ found=1; break; }
             FT_Done_Face(face);
         }
-        if(found){ f->ftface[f->NumFaces]=face; }else{ if (FT_New_Face(f->ftlib, buf, 0, &f->ftface[f->NumFaces])) continue; }
+        if(found){ f->ftface[f->NumFaces]=face; }else{ if (FT_Open_Face(f->ftlib, &args, 0, &f->ftface[f->NumFaces])) continue; }
         FT_Select_Charmap(f->ftface[f->NumFaces], FT_ENCODING_UNICODE);
         FT_Set_Char_Size(f->ftface[f->NumFaces], 0, GenHeight << 6, 96, 96);
-        f->NumFaces++; FT_Glyph glyph; int half_adv=0;
+        f->NumFaces++; FT_Glyph glyph; FT_Fixed half_adv=0;
         if(!f->MonoAdvance && !FT_Get_Advance(f->ftface[f->NumFaces],'a',FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, &half_adv)){
             FT_Set_Char_Size(f->ftface[f->NumFaces], 0, (GenHeight << 6)*f->MonoScale, 96, 96);
             if (FT_Load_Char(f->ftface[f->NumFaces], 'a', FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)||
@@ -2911,7 +2946,7 @@ void tnsPopStringClip(){
 };
 
 int tnsStringGetDimension(char* content, uint32_t* contentU, int Count, int WLimit, int* Rows, int UseMono){
-    if((!MAIN.CurrentWindow)||(!MAIN.CurrentWindow->win)) return 0;
+    if((!MAIN.CurrentWindow)||(!MAIN.CurrentWindow->win)||(!FM->UsingFont)) return 0;
     real sx = 0; int sy = FM->UsingFont->height; real MA=FM->UsingFont->MonoAdvance;
     int i, rows=1, advance=1;
     int C = 0;
@@ -2932,6 +2967,7 @@ int tnsStringGetDimension(char* content, uint32_t* contentU, int Count, int WLim
             continue;
         }else{
             fsc = tfntFetchCharacterW(UC, UseMono);
+            if(!fsc){continue;};
             real dx=fsc->advx; if(UseMono){ dx/=MA; if(dx<1.01) dx=1; if(dx>1.01)dx=2; dx*=MA; }
             if(sx+dx > WLimit){ sx = 0; sy += LA_RH; rows++; }
             sx += dx;
@@ -2965,7 +3001,7 @@ int tnsDrawLCD7_ProgressSystem(real x, real y, real Percent){
             if(TNS_LCD_MAP_7[uc][i]){
                 real* seg=TNS_LCD_SEG_7[i];
                 real s1=tnsInterpolate(shear,-shear,seg[1]); real s2=tnsInterpolate(shear,-shear,seg[3]);
-#ifdef __linux__
+#ifdef LA_LINUX
                 XDrawLine(MAIN.dpy,MAIN.Progress.w,MAIN.Progress.gc,
                     tnsInterpolate(x+s1,x+w+s1,seg[0]),tnsInterpolate(y,y+h,seg[1]),
                     tnsInterpolate(x+s2,x+w+s2,seg[2]),tnsInterpolate(y,y+h,seg[3]));
@@ -3073,7 +3109,7 @@ int tns_ClipCharacterT2D(real* v, real* t){
     return 1;
 }
 void tnsDrawStringM(char *content, uint32_t* contentU, real Color[4], int L, int R, int T, int Flags){
-    if(Flags&(LA_TEXT_LCD_16|LA_TEXT_LCD_7)){
+    if(!FM->UsingFont){return;} if(Flags&(LA_TEXT_LCD_16|LA_TEXT_LCD_7)){
         tnsDrawStringLCD(content,contentU,Color,L,R,T,Flags,1.0); return;
     }
     real sx = L; int sy = (LA_RH!=LA_RH0)?(((((real)FM->UsingFont->height/LA_RH0-0.5)/MAIN.UiScale)+0.5)*LA_RH + T):(FM->UsingFont->height+T);
@@ -3100,14 +3136,14 @@ void tnsDrawStringM(char *content, uint32_t* contentU, real Color[4], int L, int
 
         if (UC == U'\n'){ if(!OneLine){sx = L; sy += LA_RH; continue;}else{ UC=' '; } }
 
-        fsc = tfntFetchCharacterW(UC, Flags&LA_TEXT_MONO);
+        fsc = tfntFetchCharacterW(UC, Flags&LA_TEXT_MONO); if(!fsc){continue;}
 
         real dx=fsc->advx; if(UseMono){ dx/=MA; if(dx<1.01) dx=1; if(dx>1.01)dx=2; dx*=MA; }
         if (sx + dx > R+1){
             if(Flags&LA_TEXT_LINE_WRAP){
                 sx=L; sy+=LA_RH;
             }else{
-                if(Flags&LA_TEXT_OVERFLOW_ARROW){ fsc = tfntFetchCharacterW(U'▷', 0); sx=R-fsc->advx; BreakNow=1; }
+                if(Flags&LA_TEXT_OVERFLOW_ARROW){ fsc = tfntFetchCharacterW(U'▷', 0); if(!fsc){continue;} sx=R-fsc->advx; BreakNow=1; }
                 else break;
             }
         }

+ 36 - 8
la_util.c

@@ -62,7 +62,7 @@ struct tm *laGetFullTime(){
 }
 
 void laRecordTime(laTimeRecorder *tr){
-#ifdef __linux__
+#ifdef LA_LINUX
     clock_gettime(CLOCK_REALTIME, &tr->ts);
 #endif
 #ifdef _WIN32
@@ -70,13 +70,16 @@ void laRecordTime(laTimeRecorder *tr){
 #endif
 }
 real laTimeElapsedSecondsf(laTimeRecorder *End, laTimeRecorder *Begin){
-#ifdef __linux__
-    real sec=End->ts.tv_sec-Begin->ts.tv_sec; sec+=((End->ts.tv_nsec-Begin->ts.tv_nsec)/1e9);
+    real sec=0;
+#ifdef LA_LINUX
+    sec=End->ts.tv_sec-Begin->ts.tv_sec; sec+=((End->ts.tv_nsec-Begin->ts.tv_nsec)/1e9);
 #endif
 #ifdef _WIN32
     LARGE_INTEGER perfCnt; QueryPerformanceFrequency(&perfCnt);
-    real sec = ((real)(End->tm.QuadPart - Begin->tm.QuadPart))/ perfCnt.QuadPart;
+    sec = ((real)(End->tm.QuadPart - Begin->tm.QuadPart))/ perfCnt.QuadPart;
 #endif
+#ifdef LAGUI_ANDROID
+#endif 
     return sec;
 }
 
@@ -2325,7 +2328,7 @@ int laCopyFile(char *to, char *from){
 #ifdef _WIN32
     if(CopyFile(from, to, 0)) return 1; return 0;
 #endif
-#ifdef __linux__
+#ifdef LA_LINUX
     int fd_to, fd_from; char buf[4096];
     ssize_t nread; int saved_errno;
 
@@ -2354,7 +2357,7 @@ out_error:
 #endif //linux
 }
 int laEnsureDir(const char *dir) {
-#ifdef __linux__
+#ifdef LA_LINUX
     char tmp[1024]; char *p = NULL; size_t len;
     snprintf(tmp, sizeof(tmp),"%s",dir);
     len = strlen(tmp);
@@ -2440,7 +2443,7 @@ void transState(void *UNUSED, int val){
 
 void laOpenInternetLink(char *url){
     laSafeString* s=0;
-#ifdef __linux__
+#ifdef LA_LINUX
     strSafePrint(&s, "xdg-open %s", url);
 #endif
 #ifdef _WIN32
@@ -2508,7 +2511,7 @@ void laSpinUnlock(SYSLOCK* lock) {
     LeaveCriticalSection(lock);
 }
 #endif
-#ifdef __linux__
+#ifdef LA_LINUX
 void laSpinInit(SYSLOCK* lock) {
     pthread_spin_init(lock, 0);
 }
@@ -2522,6 +2525,20 @@ void laSpinUnlock(SYSLOCK* lock) {
     pthread_spin_unlock(lock);
 }
 #endif
+#ifdef LAGUI_ANDROID
+void laSpinInit(SYSLOCK* lock) {
+    return;
+}
+void laSpinDestroy(SYSLOCK* lock) {
+    return;
+}
+void laSpinLock(SYSLOCK* lock) {
+    return;
+}
+void laSpinUnlock(SYSLOCK* lock) {
+    return;
+}
+#endif
 
 //======================================= lua utils
 
@@ -2671,3 +2688,14 @@ int terLoadLine(char* buf, int firstline){
     logPrint(buf); return 0;
 }
 #endif //luajit
+
+#ifdef LAGUI_ANDROID
+void glPointSize(real a){
+    return;
+}
+void glDrawBuffer(GLenum mode){
+    GLenum b={GL_NONE};
+    glDrawBuffers(1,b);
+}
+
+#endif

+ 22 - 15
la_util.h

@@ -27,18 +27,15 @@
 #define LA_LINUX
 #endif
 
-#ifdef LA_USE_GLES
-#include <EGL/egl.h>
-	#ifdef LAGUI_ANDROID
-	#include <android/window.h>             // Required for: AWINDOW_FLAG_FULLSCREEN definition and others
-    #include <android_native_app_glue.h>    // Required for: android_app struct and activity management
-    #include <jni.h>                        // Required for: JNIEnv and JavaVM [Used in OpenURL()]
-	#include <GLES3/gl3.h>
-	#else
-	#include <GL/gl.h>
-	#endif
+#ifdef LAGUI_ANDROID
+#include <android/window.h>             // Required for: AWINDOW_FLAG_FULLSCREEN definition and others
+#include <android_native_app_glue.h>    // Required for: android_app struct and activity management
+#include <jni.h>                        // Required for: JNIEnv and JavaVM [Used in OpenURL()]
+#include <GLES3/gl3.h>
+#include <stdio.h>
+#define fopen(name, mode) android_fopen(name, mode)
+FILE *android_fopen(const char *fileName, const char *mode);
 #else
-#include <GL/glew.h>
 #include <GL/gl.h>
 #endif
 
@@ -56,9 +53,12 @@
 #include <wchar.h>
 #define SYSWINDOW Window
 #ifdef LA_USE_GLES
-	#define SYSGLCONTEXT EGLContext
+#include <EGL/egl.h>
+#define SYSGLCONTEXT EGLContext
 #else
-	#define SYSGLCONTEXT GLXContext
+#include <GL/glew.h>
+#include <GL/gl.h>
+#define SYSGLCONTEXT GLXContext
 #endif
 #define SYSTEMDC DC
 #define SYSTEMRC RC
@@ -82,7 +82,8 @@ typedef long off_t;
 #endif
 
 #ifdef LAGUI_ANDROID
-#define SYSWINDOW ANativeWindow*
+typedef ANativeWindow* lpsyswindow;
+#define SYSWINDOW lpsyswindow
 #define SYSGLCONTEXT EGLContext
 #define SYSTEMDC EGLSurface
 #define SYSTEMRC EGLDevice
@@ -808,7 +809,7 @@ void toHexString(char* text, char* hex);
 void laOpenInternetLink(char* url);
 
 #define SEND_PANIC_ERROR(msg) \
-	{printf(msg); exit(0);}
+	{logPrintNew(msg); exit(0);}
 
 #ifdef _WIN32
 void usleep(unsigned int usec);
@@ -820,3 +821,9 @@ void laSpinLock(SYSLOCK* lock);
 void laSpinUnlock(SYSLOCK* lock);
 
 int terLoadLine(char* buf, int firstline);
+
+
+#ifdef LAGUI_ANDROID
+void glPointSize(real a);
+void glDrawBuffer(GLenum mode);
+#endif

+ 1 - 1
resources/la_modelling.c

@@ -1934,7 +1934,7 @@ int OPINV_RemoveRootObject(laOperator *a, laEvent *e){
 int OPINV_NewMaterial(laOperator *a, laEvent *e){
     tnsMaterial* mat=tnsCreateMaterial("Material"); laRecordDifferences(0,"tns.world.materials");
     laDetachedTrySet("material",mat); laNotifyUsers("tns.world.materials");
-    if(!a->This || !a->This->EndInstance){ laPushDifferences("New material",0); return; }
+    if(!a->This || !a->This->EndInstance){ laPushDifferences("New material",0); return LA_FINISHED; }
     laPropContainer* pc=la_EnsureSubTarget(a->This->LastPs->p,a->This->EndInstance);
     if(pc==TNS_PC_OBJECT_MESH){
         tnsMeshObject* mo=a->This->EndInstance; if(mo->CurrentMaterial){

+ 9 - 9
resources/la_operators.c

@@ -195,7 +195,7 @@ int la_AcceptFileFormat(laFileBrowser* fb, char* format){
 }
 
 typedef int (*FileSortCompF)(laFileItem* f1,laFileItem* f2);
-#ifdef _WIN32
+#if defined (_WIN32) || defined (LAGUI_ANDROID)
 #define strverscmp strcmp
 #endif
 int la_filecompname(laFileItem* f1,laFileItem* f2){ return strverscmp(f2->Name, f1->Name); }
@@ -242,7 +242,7 @@ void la_FileBrowserRebuildList(laFileBrowser *fb){
     u64bit TotalSpace = 0;
     real Ratio = 0;
 
-#ifdef __linux__
+#ifdef LA_LINUX
     if (fb->Path[len - 1] != U'/') strcat(fb->Path, "/");
     struct dirent **NameList=0;
     int NumFiles=scandir(fb->Path,&NameList,0,versionsort);
@@ -378,7 +378,7 @@ laFileBrowser *la_FileBrowserInit(laOperator *a){
     if ((arg=strGetArgumentString(a->ExtraInstructionsP, "filter_type"))){ sscanf(arg,"%d",&fb->FilterType); }
     if ((arg=strGetArgumentString(a->ExtraInstructionsP, "use_type"))){ sscanf(arg,"%d",&fb->UseType); }
 
-#ifdef __linux__
+#ifdef LA_LINUX
     char BookmarkPath[1024];
     strcat(strcpy(BookmarkPath, getenv("HOME")), "/.config/gtk-3.0/bookmarks");
     FILE* f=fopen(BookmarkPath, "r");
@@ -422,7 +422,7 @@ void la_FileBrowserRefreshThumbnail(laFileBrowser* fb){
             }
         }
     }
-#ifdef __linux__
+#ifdef LA_LINUX
     char buf[2048]="file://"; char md5[128];
     la_FileBrowserGetFullPath(fb,buf+strlen(buf));
     md5String(buf,md5); toHexString(md5,fb->MD5);
@@ -579,7 +579,7 @@ void la_FileBrowserUpLevel(laFileBrowser *fb){
 void la_FileBrowserNewDirectory(laFileBrowser* fb,char* path){
     char* p=fb->Path;
     int len =strlen(p);
-#ifdef __linux__
+#ifdef LA_LINUX
     if (p[len - 1] != U'/') strcat(p, "/");
     char usepath[2048]; sprintf(usepath,"%s%s",p,path);
     if(!mkdir(usepath,S_IRWXU | S_IRWXG | S_IRWXO)){
@@ -675,7 +675,7 @@ int OPINV_FileBrowserConfirm(laOperator *a, laEvent *e){
         laFileBrowser* fb=a->This->EndInstance;
         if(fb->WarnFileExists){
             char path[2048]; la_FileBrowserGetFullPath(fb, path);
-#ifdef __linux__
+#ifdef LA_LINUX
             if(access(path, F_OK)==0)
 #endif
 #ifdef _WIN32
@@ -1246,7 +1246,7 @@ int OPINV_Fullscreen(laOperator *a, laEvent *e){
     int full=1;
     if(strArgumentMatch(a->ExtraInstructionsP,"restore","true")){ full=0; }
     if(strArgumentMatch(a->ExtraInstructionsP,"toggle","true")){ full=w->IsFullScreen?0:1; }
-#ifdef __linux__
+#ifdef LA_LINUX
     XClientMessageEvent msg = {
         .type = ClientMessage, .display = MAIN.dpy, .window = w->win,
         .message_type = XInternAtom(MAIN.dpy, "_NET_WM_STATE", True), .format = 32,
@@ -1775,7 +1775,7 @@ int la_GenericTopPanelProcessing(laOperator* a, laEvent* e){
     return 0;
 }
 int la_GeneratePasteEvent(laWindow* w){
-#ifdef __linux__
+#ifdef LA_LINUX
     XConvertSelection(MAIN.dpy, MAIN.bufid, MAIN.fmtid, MAIN.propid, w->win, CurrentTime);
 #endif
 }
@@ -2307,7 +2307,7 @@ int OPINV_TranslationDumpMisMatch(laOperator *a, laEvent *e){
 }
 
 int OPINV_RefreshScreens(laOperator *a, laEvent *e){
-#ifdef __linux__
+#ifdef LA_LINUX
     la_GetDPI(MAIN.win);
 #endif
 #ifdef _WIN32

+ 1 - 1
resources/la_properties.c

@@ -721,7 +721,7 @@ void lapost_Panel(laPanel *p){
     }
     if(p->IsMenuPanel){ laui_DefaultMenuBarActual(&p->TitleBar, &p->PP, &p->PropLinkPP, 0, 0); }
     //if(p->Title) p->TitleWidth = tnsStringGetWidth(transLate(p->Title->Ptr), 0, 0);
-#ifdef __linux__
+#ifdef LA_LINUX
     XSync(MAIN.dpy,0);
 #endif
 }

+ 5 - 5
resources/la_widgets.c

@@ -1133,7 +1133,7 @@ void la_MultiStringDraw(laUiItem *ui, int h){
         tnsColor4d(LA_COLOR3(laThemeColor(bt,LA_BT_BORDER)),0.8);
         tnsVertex2d(ui->L, ui->U); tnsVertex2d(ui->L+NumberWidth, ui->U);
         tnsVertex2d(ui->L, ui->B); tnsVertex2d(ui->L+NumberWidth, ui->B);
-        tnsPackAs(GL_QUADS);
+        tnsPackAs(GL_TRIANGLE_STRIP);
 
         if(!(se->CursorLine<se->ViewStartLine||se->CursorLine>se->ViewStartLine+se->ViewHeight)){
             int LineU=(se->CursorLine-se->ViewStartLine)*LA_RH+ui->U;
@@ -1145,7 +1145,7 @@ void la_MultiStringDraw(laUiItem *ui, int h){
             tnsColor4dv(ui->State==LA_UI_ACTIVE?laAccentColor(LA_BT_TEXT):laThemeColor(bt,LA_BT_TEXT_NORMAL));
             tnsVertex2d(ui->L, LineU); tnsVertex2d(ui->L+NumberWidth, LineU);
             tnsVertex2d(ui->L, LineU+LA_RH); tnsVertex2d(ui->L+NumberWidth, LineU+LA_RH);
-            tnsPackAs(GL_QUADS);
+            tnsPackAs(GL_TRIANGLE_STRIP);
         }
     }else{
         NumberWidth=bt->LM;
@@ -1181,7 +1181,7 @@ void la_MultiStringDraw(laUiItem *ui, int h){
             tnsColor4dv(ui->State==LA_UI_ACTIVE?laAccentColor(LA_BT_TEXT):laThemeColor(bt,LA_BT_TEXT_NORMAL));
             tnsVertex2d(_L+Dist-w2-d, LineU); tnsVertex2d(_L+Dist+w2-d, LineU);
             tnsVertex2d(_L+Dist-w2-d, LineU+LA_RH); tnsVertex2d(_L+Dist+w2-d, LineU+LA_RH);
-            tnsPackAs(GL_QUADS);
+            tnsPackAs(GL_TRIANGLE_STRIP);
         }
         Line++;
         tnsFlush();
@@ -1294,7 +1294,7 @@ void la_ColorCircleDrawHCY(laUiItem *ui, int h){
     tnsColorArray4d(colors, 26);
     tnsVertexArray2d(verts, 26);
     tnsIndexArray(index, 26);
-    tnsPackAs(GL_QUAD_STRIP);
+    tnsPackAs(GL_TRIANGLE_STRIP);
 
     tnsMakeArc2d(&verts[26], 12, c, ui->U + r, r + bt->LM + h, -pi_4, pi_4);
     tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
@@ -1594,7 +1594,7 @@ void la_ValueMeterType1Draw(laUiItem *ui, int h){
         tnsPackAs(GL_LINE_LOOP);
 
         if(!NoLabel){
-            if(Len==1){ sprintf(buf,ui->PP.LastPs->p->Name); } else{ if(i<8)sprintf(buf,prefix[i]); }
+            if(Len==1){ sprintf(buf,"%s",ui->PP.LastPs->p->Name); } else{ if(i<8)sprintf(buf,"%s",prefix[i]); }
             if(buf[0]) tnsDrawStringAuto(buf, laThemeColor(bt, LA_BT_TEXT), _L + bt->LM, _R - bt->RM, _U, ui->Flags);//, ui->ExtraInstructions);
         }
         if(IsVertical){

+ 8 - 2
resources/la_widgets_viewers.c

@@ -212,9 +212,15 @@ void la_RootObjectDraw(laBoxedTheme *bt, tnsObject *root, laUiItem* ui){
             tnsDrawObjectTree(root,TNS_EVAL_LAYER_SOLID|Do2DInstance,&de,e->AsPlayer);
             
             glLineWidth(7);  tnsUniformUseOffset(T->immShader,-100);
-            glDepthMask(GL_FALSE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+            glDepthMask(GL_FALSE);
+#ifndef LAGUI_ANDROID
+            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+#endif
             tnsDrawObjectTree(root,TNS_EVAL_LAYER_OUTLINE|Do2DInstance,0,e->AsPlayer);
-            glDepthMask(GL_TRUE); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+            glDepthMask(GL_TRUE);
+#ifndef LAGUI_ANDROID
+            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+#endif
             glLineWidth(1); tnsUniformUseOffset(T->immShader,0);
 
             tnsEvaluateData* ed=e->AsPlayer?(&root->EvaluatedPlay):(&root->Evaluated);